M: James Schulman <james.schulman@cirrus.com>
M: David Rhodes <david.rhodes@cirrus.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+L: patches@opensource.cirrus.com
S: Maintained
F: sound/soc/codecs/cs*
{ "HPOUT1 Demux", NULL, "OUT1R" },
{ "OUT1R", NULL, "HPOUT1 Mono Mux" },
+ { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" },
{ "HPOUTL", "HPOUT", "HPOUT1 Demux" },
{ "HPOUTR", "HPOUT", "HPOUT1 Demux" },
static const struct snd_soc_dapm_route cs47l15_mono_routes[] = {
{ "HPOUT1 Mono Mux", "HPOUT", "OUT1L" },
- { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" },
};
static int cs47l15_component_probe(struct snd_soc_component *component)
{ "SPKOUTP", NULL, "OUT4L" },
{ "OUT1R", NULL, "HPOUT1 Mono Mux" },
+ { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" },
{ "HPOUTL", "HPOUT", "HPOUT1 Demux" },
{ "HPOUTR", "HPOUT", "HPOUT1 Demux" },
static const struct snd_soc_dapm_route cs47l35_mono_routes[] = {
{ "HPOUT1 Mono Mux", "HPOUT", "OUT1L" },
- { "HPOUT1 Mono Mux", "EPOUT", "OUT1L" },
};
static int cs47l35_component_probe(struct snd_soc_component *component)
return 0;
}
+static void rt1015_calibrate(struct rt1015_priv *rt1015)
+{
+ struct snd_soc_component *component = rt1015->component;
+ struct regmap *regmap = rt1015->regmap;
+
+ snd_soc_dapm_mutex_lock(&component->dapm);
+ regcache_cache_bypass(regmap, true);
+
+ regmap_write(regmap, RT1015_PWR1, 0xd7df);
+ regmap_write(regmap, RT1015_PWR4, 0x00b2);
+ regmap_write(regmap, RT1015_CLSD_INTERNAL8, 0x2008);
+ regmap_write(regmap, RT1015_CLSD_INTERNAL9, 0x0140);
+ regmap_write(regmap, RT1015_GAT_BOOST, 0x0efe);
+ regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000d);
+ regmap_write(regmap, RT1015_PWR_STATE_CTRL, 0x000e);
+ regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a00);
+ regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a01);
+ regmap_write(regmap, RT1015_DC_CALIB_CLSD1, 0x5a05);
+ msleep(500);
+ regmap_write(regmap, RT1015_PWR1, 0x0);
+
+ regcache_cache_bypass(regmap, false);
+ regcache_mark_dirty(regmap);
+ regcache_sync(regmap);
+ snd_soc_dapm_mutex_unlock(&component->dapm);
+}
+
static int rt1015_bypass_boost_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
if (!rt1015->dac_is_used) {
rt1015->bypass_boost = ucontrol->value.integer.value[0];
- if (rt1015->bypass_boost == RT1015_Bypass_Boost) {
- snd_soc_component_write(component,
- RT1015_PWR4, 0x00b2);
- snd_soc_component_write(component,
- RT1015_CLSD_INTERNAL8, 0x2008);
- snd_soc_component_write(component,
- RT1015_CLSD_INTERNAL9, 0x0140);
- snd_soc_component_write(component,
- RT1015_GAT_BOOST, 0x0efe);
- snd_soc_component_write(component,
- RT1015_PWR_STATE_CTRL, 0x000d);
- msleep(500);
- snd_soc_component_write(component,
- RT1015_PWR_STATE_CTRL, 0x000e);
+ if (rt1015->bypass_boost == RT1015_Bypass_Boost &&
+ !rt1015->cali_done) {
+ rt1015_calibrate(rt1015);
+ rt1015->cali_done = 1;
+
+ regmap_write(rt1015->regmap, RT1015_MONO_DYNA_CTRL, 0x0010);
}
} else
dev_err(component->dev, "DAC is being used!\n");
return 0;
}
+static void rt1015_flush_work(struct work_struct *work)
+{
+ struct rt1015_priv *rt1015 = container_of(work, struct rt1015_priv,
+ flush_work.work);
+ struct snd_soc_component *component = rt1015->component;
+ unsigned int val, i = 0, count = 20;
+
+ while (i < count) {
+ usleep_range(1000, 1500);
+ dev_dbg(component->dev, "Flush DAC (retry:%u)\n", i);
+ regmap_read(rt1015->regmap, RT1015_CLK_DET, &val);
+ if (val & 0x800)
+ break;
+ i++;
+ }
+
+ regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597);
+ regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x05f7);
+ regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x0028);
+
+ if (val & 0x800)
+ dev_dbg(component->dev, "Flush DAC completed.\n");
+ else
+ dev_warn(component->dev, "Fail to flush DAC data.\n");
+}
+
static const struct snd_kcontrol_new rt1015_snd_controls[] = {
SOC_SINGLE_TLV("DAC Playback Volume", RT1015_DAC1, RT1015_DAC_VOL_SFT,
127, 0, dac_vol_tlv),
break;
case SND_SOC_DAPM_POST_PMU:
- if (rt1015->bypass_boost == RT1015_Bypass_Boost) {
- regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x00a8);
- regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x0597);
- regmap_write(rt1015->regmap, RT1015_SYS_RST1, 0x05f7);
- regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x0028);
- }
+ regmap_write(rt1015->regmap, RT1015_MAN_I2C, 0x00a8);
break;
case SND_SOC_DAPM_POST_PMD:
RT1015_SYS_RST1, 0x05f5);
}
rt1015->dac_is_used = 0;
+
+ cancel_delayed_work_sync(&rt1015->flush_work);
break;
default:
return 0;
}
+static int rt1015_amp_drv_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_component *component =
+ snd_soc_dapm_to_component(w->dapm);
+ struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (rt1015->hw_config == RT1015_HW_28)
+ schedule_delayed_work(&rt1015->flush_work, msecs_to_jiffies(10));
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt1015_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("LDO2", RT1015_PWR1, RT1015_PWR_LDO2_BIT, 0,
NULL, 0),
r1015_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
SND_SOC_DAPM_POST_PMD),
+ SND_SOC_DAPM_OUT_DRV_E("Amp Drv", SND_SOC_NOPM, 0, 0, NULL, 0,
+ rt1015_amp_drv_event, SND_SOC_DAPM_POST_PMU),
SND_SOC_DAPM_OUTPUT("SPO"),
};
{ "DAC", NULL, "MIXERV" },
{ "DAC", NULL, "SUMV" },
{ "DAC", NULL, "VREFLV" },
- { "SPO", NULL, "DAC" },
+ { "Amp Drv", NULL, "DAC" },
+ { "SPO", NULL, "Amp Drv" },
};
static int rt1015_hw_params(struct snd_pcm_substream *substream,
rt1015->component = component;
rt1015->bclk_ratio = 0;
+ rt1015->cali_done = 0;
snd_soc_component_write(component, RT1015_BAT_RPO_STEP1, 0x061c);
+ INIT_DELAYED_WORK(&rt1015->flush_work, rt1015_flush_work);
+
return 0;
}
{
struct rt1015_priv *rt1015 = snd_soc_component_get_drvdata(component);
+ cancel_delayed_work_sync(&rt1015->flush_work);
regmap_write(rt1015->regmap, RT1015_RESET, 0);
}
return ret;
}
+ rt1015->hw_config = (i2c->addr == 0x29) ? RT1015_HW_29 : RT1015_HW_28;
+
regmap_read(rt1015->regmap, RT1015_DEVICE_ID, &val);
if ((val != RT1015_DEVICE_ID_VAL) && (val != RT1015_DEVICE_ID_VAL2)) {
dev_err(&i2c->dev,
RT1015_Bypass_Boost,
};
+enum {
+ RT1015_HW_28 = 0,
+ RT1015_HW_29,
+};
+
struct rt1015_priv {
struct snd_soc_component *component;
struct regmap *regmap;
int bypass_boost;
int amp_ver;
int dac_is_used;
+ int cali_done;
+ int hw_config;
+ struct delayed_work flush_work;
};
#endif /* __RT1015_H__ */
if (!rt700->hw_init)
return 0;
+ cancel_delayed_work_sync(&rt700->jack_detect_work);
+ cancel_delayed_work_sync(&rt700->jack_btn_check_work);
+
regcache_cache_only(rt700->regmap, true);
return 0;
if (!rt711->hw_init)
return 0;
+ cancel_delayed_work_sync(&rt711->jack_detect_work);
+ cancel_delayed_work_sync(&rt711->jack_btn_check_work);
+ cancel_work_sync(&rt711->calibration_work);
+
regcache_cache_only(rt711->regmap, true);
return 0;
TAS2770_PWR_CTRL_MASK,
TAS2770_PWR_CTRL_ACTIVE);
break;
-
+ case SND_SOC_BIAS_STANDBY:
+ case SND_SOC_BIAS_PREPARE:
+ snd_soc_component_update_bits(component,
+ TAS2770_PWR_CTRL,
+ TAS2770_PWR_CTRL_MASK, TAS2770_PWR_CTRL_MUTE);
+ break;
case SND_SOC_BIAS_OFF:
snd_soc_component_update_bits(component,
TAS2770_PWR_CTRL,
TAS2770_PWR_CTRL,
TAS2770_PWR_CTRL_MASK,
TAS2770_PWR_CTRL_MUTE);
- if (ret)
- goto end;
break;
case SND_SOC_DAPM_PRE_PMD:
ret = snd_soc_component_update_bits(component,
TAS2770_PWR_CTRL,
TAS2770_PWR_CTRL_MASK,
TAS2770_PWR_CTRL_SHUTDOWN);
- if (ret)
- goto end;
break;
default:
dev_err(tas2770->dev, "Not supported evevt\n");
return -EINVAL;
}
-end:
if (ret < 0)
return ret;
return -EINVAL;
}
+ if (ret < 0)
+ return ret;
+
tas2770->channel_size = bitwidth;
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG5_50_MASK,
TAS2770_TDM_CFG_REG5_VSNS_ENABLE |
tas2770->v_sense_slot);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG6,
TAS2770_TDM_CFG_REG6_ISNS_MASK |
TAS2770_TDM_CFG_REG6_50_MASK,
TAS2770_TDM_CFG_REG6_ISNS_ENABLE |
tas2770->i_sense_slot);
-
-end:
if (ret < 0)
return ret;
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_SMP_MASK,
TAS2770_TDM_CFG_REG0_SMP_48KHZ);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_31_MASK,
TAS2770_TDM_CFG_REG0_31_44_1_48KHZ);
- if (ret)
- goto end;
break;
case 44100:
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_SMP_MASK,
TAS2770_TDM_CFG_REG0_SMP_44_1KHZ);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_31_MASK,
TAS2770_TDM_CFG_REG0_31_44_1_48KHZ);
- if (ret)
- goto end;
break;
case 96000:
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_SMP_MASK,
TAS2770_TDM_CFG_REG0_SMP_48KHZ);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_31_MASK,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_SMP_MASK,
TAS2770_TDM_CFG_REG0_SMP_44_1KHZ);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_31_MASK,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_SMP_MASK,
TAS2770_TDM_CFG_REG0_SMP_48KHZ);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_31_MASK,
TAS2770_TDM_CFG_REG0_31_176_4_192KHZ);
- if (ret)
- goto end;
break;
case 17640:
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_SMP_MASK,
TAS2770_TDM_CFG_REG0_SMP_44_1KHZ);
- if (ret)
- goto end;
+ if (ret < 0)
+ return ret;
+
ret = snd_soc_component_update_bits(component,
TAS2770_TDM_CFG_REG0,
TAS2770_TDM_CFG_REG0_31_MASK,
ret = -EINVAL;
}
-end:
if (ret < 0)
return ret;
tas2770->component = component;
+ tas2770_reset(tas2770);
+
return 0;
}
rc = fwnode_property_read_u32(dev->fwnode, "ti,asi-format",
&tas2770->asi_format);
if (rc) {
- dev_err(tas2770->dev, "Looking up %s property failed %d\n",
- "ti,asi-format", rc);
- goto end;
+ dev_info(tas2770->dev, "Property %s is missing setting default slot\n",
+ "ti,asi-format");
+ tas2770->asi_format = 0;
}
rc = fwnode_property_read_u32(dev->fwnode, "ti,imon-slot-no",
&tas2770->i_sense_slot);
if (rc) {
- dev_err(tas2770->dev, "Looking up %s property failed %d\n",
- "ti,imon-slot-no", rc);
- goto end;
+ dev_info(tas2770->dev, "Property %s is missing setting default slot\n",
+ "ti,imon-slot-no");
+ tas2770->i_sense_slot = 0;
}
rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no",
&tas2770->v_sense_slot);
if (rc) {
- dev_err(tas2770->dev, "Looking up %s property failed %d\n",
- "ti,vmon-slot-no", rc);
- goto end;
+ dev_info(tas2770->dev, "Property %s is missing setting default slot\n",
+ "ti,vmon-slot-no");
+ tas2770->v_sense_slot = 2;
}
-end:
- return rc;
+ return 0;
}
static int tas2770_i2c_probe(struct i2c_client *client,
tas2770->channel_size = 0;
tas2770->slot_width = 0;
- tas2770_reset(tas2770);
-
result = tas2770_register_codec(tas2770);
if (result)
dev_err(tas2770->dev, "Register codec failed.\n");
struct regmap *regmap;
struct device *dev;
- int micbias_vg;
+ bool micbias_vg;
unsigned int dai_fmt;
unsigned int tdm_delay;
};
/* Digital Volume control. From -100 to 27 dB in 0.5 dB steps */
-static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10000, 50, 0);
+static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10050, 50, 0);
/* ADC gain. From 0 to 42 dB in 1 dB steps */
static DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0);
return ret;
}
+static void adcx140_pwr_ctrl(struct adcx140_priv *adcx140, bool power_state)
+{
+ int pwr_ctrl = 0;
+
+ if (power_state)
+ pwr_ctrl = ADCX140_PWR_CFG_ADC_PDZ | ADCX140_PWR_CFG_PLL_PDZ;
+
+ if (adcx140->micbias_vg && power_state)
+ pwr_ctrl |= ADCX140_PWR_CFG_BIAS_PDZ;
+
+ regmap_update_bits(adcx140->regmap, ADCX140_PWR_CFG,
+ ADCX140_PWR_CTRL_MSK, pwr_ctrl);
+}
+
static int adcx140_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_component *component = dai->component;
+ struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
u8 data = 0;
switch (params_width(params)) {
return -EINVAL;
}
+ adcx140_pwr_ctrl(adcx140, false);
+
snd_soc_component_update_bits(component, ADCX140_ASI_CFG0,
ADCX140_WORD_LEN_MSK, data);
+ adcx140_pwr_ctrl(adcx140, true);
+
return 0;
}
u8 iface_reg1 = 0;
u8 iface_reg2 = 0;
int offset = 0;
- int width = adcx140->slot_width;
+ bool inverted_bclk = false;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
return -EINVAL;
}
- /* signal polarity */
- switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
- case SND_SOC_DAIFMT_NB_IF:
- iface_reg1 |= ADCX140_FSYNCINV_BIT;
- break;
- case SND_SOC_DAIFMT_IB_IF:
- iface_reg1 |= ADCX140_BCLKINV_BIT | ADCX140_FSYNCINV_BIT;
- break;
- case SND_SOC_DAIFMT_IB_NF:
- iface_reg1 |= ADCX140_BCLKINV_BIT;
- break;
- case SND_SOC_DAIFMT_NB_NF:
- break;
- default:
- dev_err(component->dev, "Invalid DAI clock signal polarity\n");
- return -EINVAL;
- }
-
/* interface format */
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
iface_reg1 |= ADCX140_LEFT_JUST_BIT;
break;
case SND_SOC_DAIFMT_DSP_A:
- offset += (adcx140->tdm_delay * width + 1);
+ offset = 1;
+ inverted_bclk = true;
break;
case SND_SOC_DAIFMT_DSP_B:
- offset += adcx140->tdm_delay * width;
+ inverted_bclk = true;
break;
default:
dev_err(component->dev, "Invalid DAI interface format\n");
return -EINVAL;
}
+ /* signal polarity */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_IB_NF:
+ case SND_SOC_DAIFMT_IB_IF:
+ inverted_bclk = !inverted_bclk;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ iface_reg1 |= ADCX140_FSYNCINV_BIT;
+ break;
+ case SND_SOC_DAIFMT_NB_NF:
+ break;
+ default:
+ dev_err(component->dev, "Invalid DAI clock signal polarity\n");
+ return -EINVAL;
+ }
+
+ if (inverted_bclk)
+ iface_reg1 |= ADCX140_BCLKINV_BIT;
+
adcx140->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+ adcx140_pwr_ctrl(adcx140, false);
+
snd_soc_component_update_bits(component, ADCX140_ASI_CFG0,
ADCX140_FSYNCINV_BIT |
ADCX140_BCLKINV_BIT |
snd_soc_component_update_bits(component, ADCX140_ASI_CFG1,
ADCX140_TX_OFFSET_MASK, offset);
+ adcx140_pwr_ctrl(adcx140, true);
return 0;
}
ret = device_property_read_u32(adcx140->dev, "ti,mic-bias-source",
&bias_source);
- if (ret)
+ if (ret || bias_source > ADCX140_MIC_BIAS_VAL_AVDD) {
bias_source = ADCX140_MIC_BIAS_VAL_VREF;
-
- if (bias_source > ADCX140_MIC_BIAS_VAL_AVDD) {
- dev_err(adcx140->dev, "Mic Bias source value is invalid\n");
- return -EINVAL;
+ adcx140->micbias_vg = false;
+ } else {
+ adcx140->micbias_vg = true;
}
ret = device_property_read_u32(adcx140->dev, "ti,vref-source",
ADCX140_MIC_BIAS_VREF_MSK, bias_cfg);
if (ret)
dev_err(adcx140->dev, "setting MIC bias failed %d\n", ret);
+
+ adcx140_pwr_ctrl(adcx140, true);
out:
return ret;
}
enum snd_soc_bias_level level)
{
struct adcx140_priv *adcx140 = snd_soc_component_get_drvdata(component);
- int pwr_cfg = 0;
switch (level) {
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
case SND_SOC_BIAS_STANDBY:
- pwr_cfg = ADCX140_PWR_CFG_BIAS_PDZ | ADCX140_PWR_CFG_PLL_PDZ |
- ADCX140_PWR_CFG_ADC_PDZ;
+ adcx140_pwr_ctrl(adcx140, true);
break;
case SND_SOC_BIAS_OFF:
- pwr_cfg = 0x0;
+ adcx140_pwr_ctrl(adcx140, false);
break;
}
- return regmap_write(adcx140->regmap, ADCX140_PWR_CFG, pwr_cfg);
+ return 0;
}
static const struct snd_soc_component_driver soc_codec_driver_adcx140 = {
#define ADCX140_MIC_BIAS_VREF_1375V 2
#define ADCX140_MIC_BIAS_VREF_MSK GENMASK(1, 0)
+#define ADCX140_PWR_CTRL_MSK GENMASK(7, 5)
#define ADCX140_PWR_CFG_BIAS_PDZ BIT(7)
#define ADCX140_PWR_CFG_ADC_PDZ BIT(6)
#define ADCX140_PWR_CFG_PLL_PDZ BIT(5)
#define ADCX140_GPO_CFG_MAX 4
#define ADCX140_GPO_DRV_MAX 5
+
#endif /* _TLV320ADCX140_ */
if (ret < 0)
return -EINVAL;
- return clk_aic32x4_pll_set_muldiv(pll, &settings);
+ ret = clk_aic32x4_pll_set_muldiv(pll, &settings);
+ if (ret)
+ return ret;
+
+ /* 10ms is the delay to wait before the clocks are stable */
+ msleep(10);
+
+ return 0;
}
static int clk_aic32x4_pll_set_parent(struct clk_hw *hw, u8 index)
}
static int aic32x4_setup_clocks(struct snd_soc_component *component,
- unsigned int sample_rate)
+ unsigned int sample_rate, unsigned int channels)
{
u8 aosr;
u16 dosr;
dosr);
clk_set_rate(clocks[5].clk,
- sample_rate * 32);
+ sample_rate * 32 *
+ channels);
+
return 0;
}
}
u8 iface1_reg = 0;
u8 dacsetup_reg = 0;
- aic32x4_setup_clocks(component, params_rate(params));
+ aic32x4_setup_clocks(component, params_rate(params),
+ params_channels(params));
switch (params_width(params)) {
case 16:
AIC32X4_LADC_EN | AIC32X4_RADC_EN);
snd_soc_component_write(component, AIC32X4_ADCSETUP, tmp_reg);
+ /*
+ * Enable the fast charging feature and ensure the needed 40ms ellapsed
+ * before using the analog circuits.
+ */
+ snd_soc_component_write(component, AIC32X4_REFPOWERUP,
+ AIC32X4_REFPOWERUP_40MS);
+ msleep(40);
+
return 0;
}
#define AIC32X4_FLOATINGINPUT AIC32X4_REG(1, 58)
#define AIC32X4_LMICPGAVOL AIC32X4_REG(1, 59)
#define AIC32X4_RMICPGAVOL AIC32X4_REG(1, 60)
+#define AIC32X4_REFPOWERUP AIC32X4_REG(1, 123)
/* Bits, masks, and shifts */
#define AIC32X4_RMICPGANIN_IN1L_10K 0x10
#define AIC32X4_RMICPGANIN_CM1R_10K 0x40
+/* AIC32X4_REFPOWERUP */
+#define AIC32X4_REFPOWERUP_SLOW 0x04
+#define AIC32X4_REFPOWERUP_40MS 0x05
+#define AIC32X4_REFPOWERUP_80MS 0x06
+#define AIC32X4_REFPOWERUP_120MS 0x07
+
/* Common mask and enable for all of the dividers */
#define AIC32X4_DIVEN BIT(7)
#define AIC32X4_DIV_MASK GENMASK(6, 0)
{
struct wm_coeff_ctl *ctl;
struct snd_kcontrol *kcontrol;
+ char ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int ret;
ctl = wm_adsp_get_ctl(dsp, name, type, alg);
return -EINVAL;
ret = wm_coeff_write_ctrl(ctl, buf, len);
+ if (ret)
+ return ret;
+
+ if (ctl->flags & WMFW_CTL_FLAG_SYS)
+ return 0;
+
+ if (dsp->component->name_prefix)
+ snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s %s",
+ dsp->component->name_prefix, ctl->name);
+ else
+ snprintf(ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s",
+ ctl->name);
+
+ kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl_name);
+ if (!kcontrol) {
+ adsp_err(dsp, "Can't find kcontrol %s\n", ctl_name);
+ return -EINVAL;
+ }
- kcontrol = snd_soc_card_get_kcontrol(dsp->component->card, ctl->name);
snd_ctl_notify(dsp->component->card->snd_card,
SNDRV_CTL_EVENT_MASK_VALUE, &kcontrol->id);
static const struct snd_kcontrol_new fsl_audmix_snd_controls[] = {
/* FSL_AUDMIX_CTR controls */
- SOC_ENUM_EXT("Mixing Clock Source", fsl_audmix_enum[0],
- snd_soc_get_enum_double, fsl_audmix_put_mix_clk_src),
- SOC_ENUM_EXT("Output Source", fsl_audmix_enum[1],
- snd_soc_get_enum_double, fsl_audmix_put_out_src),
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Mixing Clock Source",
+ .info = snd_soc_info_enum_double,
+ .access = SNDRV_CTL_ELEM_ACCESS_WRITE,
+ .put = fsl_audmix_put_mix_clk_src,
+ .private_value = (unsigned long)&fsl_audmix_enum[0] },
+ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Output Source",
+ .info = snd_soc_info_enum_double,
+ .access = SNDRV_CTL_ELEM_ACCESS_WRITE,
+ .put = fsl_audmix_put_out_src,
+ .private_value = (unsigned long)&fsl_audmix_enum[1] },
SOC_ENUM("Output Width", fsl_audmix_enum[2]),
SOC_ENUM("Frame Rate Diff Error", fsl_audmix_enum[3]),
SOC_ENUM("Clock Freq Diff Error", fsl_audmix_enum[4]),
return 0;
}
-static struct snd_soc_dai_driver fsl_sai_dai = {
+static struct snd_soc_dai_driver fsl_sai_dai_template = {
.probe = fsl_sai_dai_probe,
.playback = {
.stream_name = "CPU-Playback",
return ret;
}
+ memcpy(&sai->cpu_dai_drv, &fsl_sai_dai_template,
+ sizeof(fsl_sai_dai_template));
+
/* Sync Tx with Rx as default by following old DT binding */
sai->synchronous[RX] = true;
sai->synchronous[TX] = false;
- fsl_sai_dai.symmetric_rates = 1;
- fsl_sai_dai.symmetric_channels = 1;
- fsl_sai_dai.symmetric_samplebits = 1;
+ sai->cpu_dai_drv.symmetric_rates = 1;
+ sai->cpu_dai_drv.symmetric_channels = 1;
+ sai->cpu_dai_drv.symmetric_samplebits = 1;
if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) &&
of_find_property(np, "fsl,sai-asynchronous", NULL)) {
/* Discard all settings for asynchronous mode */
sai->synchronous[RX] = false;
sai->synchronous[TX] = false;
- fsl_sai_dai.symmetric_rates = 0;
- fsl_sai_dai.symmetric_channels = 0;
- fsl_sai_dai.symmetric_samplebits = 0;
+ sai->cpu_dai_drv.symmetric_rates = 0;
+ sai->cpu_dai_drv.symmetric_channels = 0;
+ sai->cpu_dai_drv.symmetric_samplebits = 0;
}
if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) &&
regcache_cache_only(sai->regmap, true);
ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component,
- &fsl_sai_dai, 1);
+ &sai->cpu_dai_drv, 1);
if (ret)
goto err_pm_disable;
unsigned int bclk_ratio;
const struct fsl_sai_soc_data *soc_data;
+ struct snd_soc_dai_driver cpu_dai_drv;
struct snd_dmaengine_dai_dma_data dma_params_rx;
struct snd_dmaengine_dai_dma_data dma_params_tx;
};
if (card == &mt8183_da7219_max98357_card) {
dai_link->be_hw_params_fixup =
mt8183_i2s_hw_params_fixup;
- dai_link->ops = &mt8183_mt6358_i2s_ops;
+ dai_link->ops = &mt8183_da7219_i2s_ops;
dai_link->cpus = i2s3_max98357a_cpus;
dai_link->num_cpus =
ARRAY_SIZE(i2s3_max98357a_cpus);
k->info = snd_soc_bytes_info_ext;
k->tlv.c = snd_soc_bytes_tlv_callback;
+ /*
+ * When a topology-based implementation abuses the
+ * control interface and uses bytes_ext controls of
+ * more than 512 bytes, we need to disable the size
+ * checks, otherwise accesses to such controls will
+ * return an -EINVAL error and prevent the card from
+ * being configured.
+ */
+ if (IS_ENABLED(CONFIG_SND_CTL_VALIDATION) && sbe->max > 512)
+ k->access |= SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK;
+
ext_ops = tplg->bytes_ext_ops;
num_ops = tplg->bytes_ext_ops_count;
for (i = 0; i < num_ops; i++) {