diff options
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/Kconfig | 15 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/ad1980.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/ad73311.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/cs47l15.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/cs47l24.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/cs47l35.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/cs47l85.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/cs47l90.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/cs47l92.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/dmic.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/rt1308-sdw.c | 4 | ||||
-rw-r--r-- | sound/soc/codecs/wcd9335.c | 44 | ||||
-rw-r--r-- | sound/soc/codecs/wcd934x.c | 30 | ||||
-rw-r--r-- | sound/soc/codecs/wm5102.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm5110.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/wm8782.c | 2 | ||||
-rw-r--r-- | sound/soc/codecs/wm8900.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.c | 98 | ||||
-rw-r--r-- | sound/soc/codecs/wm8991.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 8 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 18 | ||||
-rw-r--r-- | sound/soc/codecs/zl38060.c | 638 |
24 files changed, 753 insertions, 216 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index e60e0b6a689c..81341c70d563 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -272,6 +272,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_WM9712 imply SND_SOC_WM9713 imply SND_SOC_WSA881X + imply SND_SOC_ZL38060 help Normally ASoC codec drivers are only built if a machine driver which uses them is also built since they are only usable with a machine @@ -717,7 +718,7 @@ config SND_SOC_L3 config SND_SOC_DA7210 tristate - depends on I2C + depends on SND_SOC_I2C_AND_SPI config SND_SOC_DA7213 tristate "Dialog DA7213 CODEC" @@ -1569,7 +1570,7 @@ config SND_SOC_WM8978 config SND_SOC_WM8983 tristate - depends on I2C + depends on SND_SOC_I2C_AND_SPI config SND_SOC_WM8985 tristate "Wolfson Microelectronics WM8985 and WM8758 codec driver" @@ -1645,6 +1646,16 @@ config SND_SOC_WSA881X This enables support for Qualcomm WSA8810/WSA8815 Class-D Smart Speaker Amplifier. +config SND_SOC_ZL38060 + tristate "Microsemi ZL38060 Connected Home Audio Processor" + depends on SPI_MASTER + select GPIOLIB + select REGMAP + help + Support for ZL38060 Connected Home Audio Processor from Microsemi, + which consists of a Digital Signal Processor (DSP), several Digital + Audio Interfaces (DAIs), analog outputs, and a block of 14 GPIOs. + config SND_SOC_ZX_AUD96P22 tristate "ZTE ZX AUD96P22 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 03533157cda6..a603532c7af5 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -288,6 +288,7 @@ snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o snd-soc-wsa881x-objs := wsa881x.o +snd-soc-zl38060-objs := zl38060.o snd-soc-zx-aud96p22-objs := zx_aud96p22.o # Amp snd-soc-max9877-objs := max9877.o @@ -588,6 +589,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o obj-$(CONFIG_SND_SOC_WSA881X) += snd-soc-wsa881x.o +obj-$(CONFIG_SND_SOC_ZL38060) += snd-soc-zl38060.o obj-$(CONFIG_SND_SOC_ZX_AUD96P22) += snd-soc-zx-aud96p22.o # Amp diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index c4414c725c1f..43b1337bac37 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -2,7 +2,7 @@ /* * ad1980.c -- ALSA Soc AD1980 codec support * - * Copyright: Analog Device Inc. + * Copyright: Analog Devices Inc. * Author: Roy Huang <roy.huang@analog.com> * Cliff Cai <cliff.cai@analog.com> */ diff --git a/sound/soc/codecs/ad73311.c b/sound/soc/codecs/ad73311.c index 10daf61f0294..b98bf19f594e 100644 --- a/sound/soc/codecs/ad73311.c +++ b/sound/soc/codecs/ad73311.c @@ -2,7 +2,7 @@ /* * ad73311.c -- ALSA Soc AD73311 codec support * - * Copyright: Analog Device Inc. + * Copyright: Analog Devices Inc. * Author: Cliff Cai <cliff.cai@analog.com> */ diff --git a/sound/soc/codecs/cs47l15.c b/sound/soc/codecs/cs47l15.c index 8d1869bf7f9c..402c6b7c7014 100644 --- a/sound/soc/codecs/cs47l15.c +++ b/sound/soc/codecs/cs47l15.c @@ -1229,11 +1229,10 @@ static struct snd_soc_dai_driver cs47l15_dai[] = { }, }; -static int cs47l15_open(struct snd_compr_stream *stream) +static int cs47l15_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct cs47l15 *cs47l15 = snd_soc_component_get_drvdata(component); struct madera_priv *priv = &cs47l15->core; struct madera *madera = priv->madera; @@ -1329,7 +1328,7 @@ static unsigned int cs47l15_digital_vu[] = { MADERA_DAC_DIGITAL_VOLUME_5R, }; -static const struct snd_compr_ops cs47l15_compr_ops = { +static const struct snd_compress_ops cs47l15_compress_ops = { .open = &cs47l15_open, .free = &wm_adsp_compr_free, .set_params = &wm_adsp_compr_set_params, @@ -1345,7 +1344,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l15 = { .set_sysclk = &madera_set_sysclk, .set_pll = &cs47l15_set_fll, .name = DRV_NAME, - .compr_ops = &cs47l15_compr_ops, + .compress_ops = &cs47l15_compress_ops, .controls = cs47l15_snd_controls, .num_controls = ARRAY_SIZE(cs47l15_snd_controls), .dapm_widgets = cs47l15_dapm_widgets, diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 6b0570f59630..f6d173d0120e 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1068,10 +1068,10 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { }, }; -static int cs47l24_open(struct snd_compr_stream *stream) +static int cs47l24_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct cs47l24_priv *priv = snd_soc_component_get_drvdata(component); struct arizona *arizona = priv->core.arizona; int n_adsp; @@ -1178,7 +1178,7 @@ static unsigned int cs47l24_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_4L, }; -static struct snd_compr_ops cs47l24_compr_ops = { +static struct snd_compress_ops cs47l24_compress_ops = { .open = cs47l24_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, @@ -1194,7 +1194,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l24 = { .set_sysclk = arizona_set_sysclk, .set_pll = cs47l24_set_fll, .name = DRV_NAME, - .compr_ops = &cs47l24_compr_ops, + .compress_ops = &cs47l24_compress_ops, .controls = cs47l24_snd_controls, .num_controls = ARRAY_SIZE(cs47l24_snd_controls), .dapm_widgets = cs47l24_dapm_widgets, diff --git a/sound/soc/codecs/cs47l35.c b/sound/soc/codecs/cs47l35.c index 18839807c9d1..d7538d50bbd3 100644 --- a/sound/soc/codecs/cs47l35.c +++ b/sound/soc/codecs/cs47l35.c @@ -1504,11 +1504,10 @@ static struct snd_soc_dai_driver cs47l35_dai[] = { }, }; -static int cs47l35_open(struct snd_compr_stream *stream) +static int cs47l35_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct cs47l35 *cs47l35 = snd_soc_component_get_drvdata(component); struct madera_priv *priv = &cs47l35->core; struct madera *madera = priv->madera; @@ -1622,7 +1621,7 @@ static unsigned int cs47l35_digital_vu[] = { MADERA_DAC_DIGITAL_VOLUME_5R, }; -static const struct snd_compr_ops cs47l35_compr_ops = { +static const struct snd_compress_ops cs47l35_compress_ops = { .open = &cs47l35_open, .free = &wm_adsp_compr_free, .set_params = &wm_adsp_compr_set_params, @@ -1638,7 +1637,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l35 = { .set_sysclk = &madera_set_sysclk, .set_pll = &cs47l35_set_fll, .name = DRV_NAME, - .compr_ops = &cs47l35_compr_ops, + .compress_ops = &cs47l35_compress_ops, .controls = cs47l35_snd_controls, .num_controls = ARRAY_SIZE(cs47l35_snd_controls), .dapm_widgets = cs47l35_dapm_widgets, diff --git a/sound/soc/codecs/cs47l85.c b/sound/soc/codecs/cs47l85.c index a575113207f0..9de991adad74 100644 --- a/sound/soc/codecs/cs47l85.c +++ b/sound/soc/codecs/cs47l85.c @@ -2447,11 +2447,10 @@ static struct snd_soc_dai_driver cs47l85_dai[] = { }, }; -static int cs47l85_open(struct snd_compr_stream *stream) +static int cs47l85_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct cs47l85 *cs47l85 = snd_soc_component_get_drvdata(component); struct madera_priv *priv = &cs47l85->core; struct madera *madera = priv->madera; @@ -2566,7 +2565,7 @@ static const unsigned int cs47l85_digital_vu[] = { MADERA_DAC_DIGITAL_VOLUME_6R, }; -static const struct snd_compr_ops cs47l85_compr_ops = { +static const struct snd_compress_ops cs47l85_compress_ops = { .open = &cs47l85_open, .free = &wm_adsp_compr_free, .set_params = &wm_adsp_compr_set_params, @@ -2582,7 +2581,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l85 = { .set_sysclk = &madera_set_sysclk, .set_pll = &cs47l85_set_fll, .name = DRV_NAME, - .compr_ops = &cs47l85_compr_ops, + .compress_ops = &cs47l85_compress_ops, .controls = cs47l85_snd_controls, .num_controls = ARRAY_SIZE(cs47l85_snd_controls), .dapm_widgets = cs47l85_dapm_widgets, diff --git a/sound/soc/codecs/cs47l90.c b/sound/soc/codecs/cs47l90.c index 81a1311b14e6..2715b5da0415 100644 --- a/sound/soc/codecs/cs47l90.c +++ b/sound/soc/codecs/cs47l90.c @@ -2358,11 +2358,10 @@ static struct snd_soc_dai_driver cs47l90_dai[] = { }, }; -static int cs47l90_open(struct snd_compr_stream *stream) +static int cs47l90_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct cs47l90 *cs47l90 = snd_soc_component_get_drvdata(component); struct madera_priv *priv = &cs47l90->core; struct madera *madera = priv->madera; @@ -2473,7 +2472,7 @@ static unsigned int cs47l90_digital_vu[] = { MADERA_DAC_DIGITAL_VOLUME_5R, }; -static const struct snd_compr_ops cs47l90_compr_ops = { +static const struct snd_compress_ops cs47l90_compress_ops = { .open = &cs47l90_open, .free = &wm_adsp_compr_free, .set_params = &wm_adsp_compr_set_params, @@ -2489,7 +2488,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l90 = { .set_sysclk = &madera_set_sysclk, .set_pll = &cs47l90_set_fll, .name = DRV_NAME, - .compr_ops = &cs47l90_compr_ops, + .compress_ops = &cs47l90_compress_ops, .controls = cs47l90_snd_controls, .num_controls = ARRAY_SIZE(cs47l90_snd_controls), .dapm_widgets = cs47l90_dapm_widgets, diff --git a/sound/soc/codecs/cs47l92.c b/sound/soc/codecs/cs47l92.c index 15fc213d178d..108d28007185 100644 --- a/sound/soc/codecs/cs47l92.c +++ b/sound/soc/codecs/cs47l92.c @@ -1830,11 +1830,10 @@ static struct snd_soc_dai_driver cs47l92_dai[] = { }, }; -static int cs47l92_open(struct snd_compr_stream *stream) +static int cs47l92_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = - snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct cs47l92 *cs47l92 = snd_soc_component_get_drvdata(component); struct madera_priv *priv = &cs47l92->core; struct madera *madera = priv->madera; @@ -1933,7 +1932,7 @@ static unsigned int cs47l92_digital_vu[] = { MADERA_DAC_DIGITAL_VOLUME_5R, }; -static const struct snd_compr_ops cs47l92_compr_ops = { +static const struct snd_compress_ops cs47l92_compress_ops = { .open = &cs47l92_open, .free = &wm_adsp_compr_free, .set_params = &wm_adsp_compr_set_params, @@ -1949,7 +1948,7 @@ static const struct snd_soc_component_driver soc_component_dev_cs47l92 = { .set_sysclk = &madera_set_sysclk, .set_pll = &cs47l92_set_fll, .name = DRV_NAME, - .compr_ops = &cs47l92_compr_ops, + .compress_ops = &cs47l92_compress_ops, .controls = cs47l92_snd_controls, .num_controls = ARRAY_SIZE(cs47l92_snd_controls), .dapm_widgets = cs47l92_dapm_widgets, diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index f5560a49b9e5..5d079d90fd3b 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -59,14 +59,14 @@ static int dmic_aif_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: if (dmic->gpio_en) - gpiod_set_value(dmic->gpio_en, 1); + gpiod_set_value_cansleep(dmic->gpio_en, 1); if (dmic->wakeup_delay) msleep(dmic->wakeup_delay); break; case SND_SOC_DAPM_POST_PMD: if (dmic->gpio_en) - gpiod_set_value(dmic->gpio_en, 0); + gpiod_set_value_cansleep(dmic->gpio_en, 0); break; } diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index a5a7e46de246..1502a22b0d4a 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -235,9 +235,9 @@ static int rt1308_io_init(struct device *dev, struct sdw_slave *slave) efuse_c_btl_r = tmp; regmap_read(rt1308->regmap, 0xc872, &tmp); efuse_c_btl_r = efuse_c_btl_r | (tmp << 8); - dev_info(&slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__, + dev_dbg(&slave->dev, "%s m_btl_l=0x%x, m_btl_r=0x%x\n", __func__, efuse_m_btl_l, efuse_m_btl_r); - dev_info(&slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__, + dev_dbg(&slave->dev, "%s c_btl_l=0x%x, c_btl_r=0x%x\n", __func__, efuse_c_btl_l, efuse_c_btl_r); /* initial settings */ diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 700cc1212770..fb073f4dc7ed 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1919,7 +1919,7 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream, __func__, params_rate(params)); return -EINVAL; - }; + } ret = wcd9335_set_decimator_rate(dai, tx_fs_rate, params_rate(params)); @@ -1935,13 +1935,13 @@ static int wcd9335_hw_params(struct snd_pcm_substream *substream, dev_err(wcd->dev, "%s: Invalid format 0x%x\n", __func__, params_width(params)); return -EINVAL; - }; + } break; default: dev_err(wcd->dev, "Invalid stream type %d\n", substream->stream); return -EINVAL; - }; + } wcd->dai[dai->id].sconfig.rate = params_rate(params); wcd9335_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream); @@ -2216,7 +2216,7 @@ static int wcd9335_set_compander(struct snd_kcontrol *kc, break; default: break; - }; + } return 0; } @@ -2565,7 +2565,7 @@ static int wcd9335_micbias_control(struct snd_soc_component *component, 0xC0, 0x00); } break; - }; + } return 0; } @@ -2603,7 +2603,7 @@ static int __wcd9335_codec_enable_micbias(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMD: wcd9335_micbias_control(comp, micb_num, MICB_DISABLE, true); break; - }; + } return 0; } @@ -2846,7 +2846,7 @@ static int wcd9335_codec_enable_dec(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMD: snd_soc_component_update_bits(comp, tx_vol_ctl_reg, 0x10, 0x00); break; - }; + } out: kfree(wname); return ret; @@ -2952,7 +2952,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, dev_err(comp->dev, "%s: Invalid DMIC Selection\n", __func__); return -EINVAL; - }; + } switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -2985,7 +2985,7 @@ static int wcd9335_codec_enable_dmic(struct snd_soc_dapm_widget *w, dmic_rate_val << dmic_rate_shift); } break; - }; + } return 0; } @@ -3076,7 +3076,7 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w, dev_err(comp->dev, "%s: No gain register avail for %s\n", __func__, w->name); return 0; - }; + } switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -3086,7 +3086,7 @@ static int wcd9335_codec_enable_mix_path(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: break; - }; + } return 0; } @@ -3141,7 +3141,7 @@ static u16 wcd9335_interp_get_primary_reg(u16 reg, u16 *ind) prim_int_reg = WCD9335_CDC_RX8_RX_PATH_CTL; *ind = 8; break; - }; + } return prim_int_reg; } @@ -3229,7 +3229,7 @@ static int wcd9335_codec_enable_prim_interpolator( wcd9335_codec_hd2_control(comp, prim_int_reg, event); } break; - }; + } return 0; } @@ -3352,7 +3352,7 @@ static int wcd9335_codec_enable_interpolator(struct snd_soc_dapm_widget *w, wcd9335_config_compander(comp, w->shift, event); wcd9335_codec_enable_prim_interpolator(comp, reg, event); break; - }; + } return 0; } @@ -3575,7 +3575,7 @@ static int wcd9335_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, ((hph_mode == CLS_H_LOHIFI) ? CLS_H_HIFI : hph_mode)); break; - }; + } return 0; } @@ -3616,7 +3616,7 @@ static int wcd9335_codec_ear_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_EAR, CLS_H_NORMAL); break; - }; + } return 0; } @@ -3725,7 +3725,7 @@ static int wcd9335_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, WCD_CLSH_STATE_HPHR, ((hph_mode == CLS_H_LOHIFI) ? CLS_H_HIFI : hph_mode)); break; - }; + } return 0; } @@ -3773,7 +3773,7 @@ static int wcd9335_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, */ usleep_range(5000, 5500); break; - }; + } return 0; } @@ -3829,7 +3829,7 @@ static int wcd9335_codec_enable_lineout_pa(struct snd_soc_dapm_widget *w, */ usleep_range(5000, 5500); break; - }; + } return 0; } @@ -3875,7 +3875,7 @@ static int wcd9335_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, WCD9335_ANA_RX_BIAS_ENABLE_MASK, WCD9335_ANA_RX_BIAS_DISABLE); break; - }; + } return 0; } @@ -3921,7 +3921,7 @@ static int wcd9335_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, */ usleep_range(5000, 5500); break; - }; + } return 0; } @@ -3957,7 +3957,7 @@ static int wcd9335_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, usleep_range(5000, 5500); break; - }; + } return 0; } diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 5269857e2746..531b8b79e55f 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -1787,7 +1787,7 @@ static int wcd934x_hw_params(struct snd_pcm_substream *substream, params_rate(params)); return -EINVAL; - }; + } ret = wcd934x_set_decimator_rate(dai, tx_fs_rate, params_rate(params)); @@ -1803,13 +1803,13 @@ static int wcd934x_hw_params(struct snd_pcm_substream *substream, dev_err(wcd->dev, "Invalid format 0x%x\n", params_width(params)); return -EINVAL; - }; + } break; default: dev_err(wcd->dev, "Invalid stream type %d\n", substream->stream); return -EINVAL; - }; + } wcd->dai[dai->id].sconfig.rate = params_rate(params); wcd934x_slim_set_hw_params(wcd, &wcd->dai[dai->id], substream->stream); @@ -2489,7 +2489,7 @@ static int wcd934x_compander_set(struct snd_kcontrol *kc, break; default: break; - }; + } return 0; } @@ -3539,7 +3539,7 @@ static int wcd934x_codec_enable_mix_path(struct snd_soc_dapm_widget *w, val += offset_val; snd_soc_component_write(comp, gain_reg, val); break; - }; + } return 0; } @@ -3593,7 +3593,7 @@ static int wcd934x_codec_enable_main_path(struct snd_soc_dapm_widget *w, snd_soc_component_write(comp, gain_reg, snd_soc_component_read32(comp, gain_reg)); break; - }; + } return 0; } @@ -3618,7 +3618,7 @@ static int wcd934x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_ctrl_set_state(wcd->clsh_ctrl, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_EAR, CLS_H_NORMAL); break; - }; + } return 0; } @@ -3670,7 +3670,7 @@ static int wcd934x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, break; default: break; - }; + } return 0; } @@ -3720,7 +3720,7 @@ static int wcd934x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, break; default: break; - }; + } return 0; } @@ -3801,7 +3801,7 @@ static int wcd934x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, */ usleep_range(20000, 20100); break; - }; + } return 0; } @@ -3863,7 +3863,7 @@ static int wcd934x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, */ usleep_range(20000, 20100); break; - }; + } return 0; } @@ -3878,7 +3878,7 @@ static u32 wcd934x_get_dmic_sample_rate(struct snd_soc_component *comp, u16 adc_mux_ctl_reg, tx_fs_reg; u32 dmic_fs; - while (dec_found == 0 && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) { + while (!dec_found && adc_mux_index < WCD934X_MAX_VALID_ADC_MUX) { if (adc_mux_index < 4) { adc_mux_ctl_reg = WCD934X_CDC_TX_INP_MUX_ADC_MUX0_CFG0 + (adc_mux_index * 2); @@ -4015,7 +4015,7 @@ static int wcd934x_codec_enable_dmic(struct snd_soc_dapm_widget *w, dev_err(comp->dev, "%s: Invalid DMIC Selection\n", __func__); return -EINVAL; - }; + } switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -4040,7 +4040,7 @@ static int wcd934x_codec_enable_dmic(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(comp, dmic_clk_reg, dmic_clk_en, 0); break; - }; + } return 0; } @@ -4267,7 +4267,7 @@ static int wcd934x_codec_enable_dec(struct snd_soc_dapm_widget *w, WCD934X_DEC_PWR_LVL_MASK, WCD934X_DEC_PWR_LVL_DF); break; - }; + } out: kfree(wname); return ret; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index d6d4b4121369..2ed3fa67027d 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1909,10 +1909,9 @@ static struct snd_soc_dai_driver wm5102_dai[] = { }, }; -static int wm5102_open(struct snd_compr_stream *stream) +static int wm5102_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { - struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct wm5102_priv *priv = snd_soc_component_get_drvdata(component); return wm_adsp_compr_open(&priv->core.adsp[0], stream); @@ -1992,7 +1991,7 @@ static unsigned int wm5102_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_5R, }; -static struct snd_compr_ops wm5102_compr_ops = { +static struct snd_compress_ops wm5102_compress_ops = { .open = wm5102_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, @@ -2008,7 +2007,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5102 = { .set_sysclk = arizona_set_sysclk, .set_pll = wm5102_set_fll, .name = DRV_NAME, - .compr_ops = &wm5102_compr_ops, + .compress_ops = &wm5102_compress_ops, .controls = wm5102_snd_controls, .num_controls = ARRAY_SIZE(wm5102_snd_controls), .dapm_widgets = wm5102_dapm_widgets, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 499e87d1dfcc..44de44bff423 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2237,10 +2237,10 @@ static struct snd_soc_dai_driver wm5110_dai[] = { }, }; -static int wm5110_open(struct snd_compr_stream *stream) +static int wm5110_open(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME); struct wm5110_priv *priv = snd_soc_component_get_drvdata(component); struct arizona *arizona = priv->core.arizona; int n_adsp; @@ -2355,7 +2355,7 @@ static unsigned int wm5110_digital_vu[] = { ARIZONA_DAC_DIGITAL_VOLUME_6R, }; -static struct snd_compr_ops wm5110_compr_ops = { +static struct snd_compress_ops wm5110_compress_ops = { .open = wm5110_open, .free = wm_adsp_compr_free, .set_params = wm_adsp_compr_set_params, @@ -2371,7 +2371,7 @@ static const struct snd_soc_component_driver soc_component_dev_wm5110 = { .set_sysclk = arizona_set_sysclk, .set_pll = wm5110_set_fll, .name = DRV_NAME, - .compr_ops = &wm5110_compr_ops, + .compress_ops = &wm5110_compress_ops, .controls = wm5110_snd_controls, .num_controls = ARRAY_SIZE(wm5110_snd_controls), .dapm_widgets = wm5110_dapm_widgets, diff --git a/sound/soc/codecs/wm8782.c b/sound/soc/codecs/wm8782.c index aa5577e364d0..f89855c616eb 100644 --- a/sound/soc/codecs/wm8782.c +++ b/sound/soc/codecs/wm8782.c @@ -7,7 +7,7 @@ * Author: Johannes Stezenbach <js@sig21.net> * * based on ad73311.c - * Copyright: Analog Device Inc. + * Copyright: Analog Devices Inc. * Author: Cliff Cai <cliff.cai@analog.com> */ diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 271235a69c01..3e239fa9bc8d 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -443,12 +443,6 @@ SOC_SINGLE("LINEOUT2 LP -12dB", WM8900_REG_LOUTMIXCTL1, }; -static const struct snd_kcontrol_new wm8900_dapm_loutput2_control = -SOC_DAPM_SINGLE("LINEOUT2L Switch", WM8900_REG_POWER3, 6, 1, 0); - -static const struct snd_kcontrol_new wm8900_dapm_routput2_control = -SOC_DAPM_SINGLE("LINEOUT2R Switch", WM8900_REG_POWER3, 5, 1, 0); - static const struct snd_kcontrol_new wm8900_loutmix_controls[] = { SOC_DAPM_SINGLE("LINPUT3 Bypass Switch", WM8900_REG_LOUTMIXCTL1, 7, 1, 0), SOC_DAPM_SINGLE("AUX Bypass Switch", WM8900_REG_AUXOUT_CTL, 7, 1, 0), diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index cfe7892696dd..499a29b47d5e 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -32,93 +32,14 @@ struct wm8990_priv { unsigned int pcmclk; }; -static bool wm8990_volatile_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case WM8990_RESET: - return true; - default: - return false; - } -} - -static const struct reg_default wm8990_reg_defaults[] = { - { 1, 0x0000 }, /* R1 - Power Management (1) */ - { 2, 0x6000 }, /* R2 - Power Management (2) */ - { 3, 0x0000 }, /* R3 - Power Management (3) */ - { 4, 0x4050 }, /* R4 - Audio Interface (1) */ - { 5, 0x4000 }, /* R5 - Audio Interface (2) */ - { 6, 0x01C8 }, /* R6 - Clocking (1) */ - { 7, 0x0000 }, /* R7 - Clocking (2) */ - { 8, 0x0040 }, /* R8 - Audio Interface (3) */ - { 9, 0x0040 }, /* R9 - Audio Interface (4) */ - { 10, 0x0004 }, /* R10 - DAC CTRL */ - { 11, 0x00C0 }, /* R11 - Left DAC Digital Volume */ - { 12, 0x00C0 }, /* R12 - Right DAC Digital Volume */ - { 13, 0x0000 }, /* R13 - Digital Side Tone */ - { 14, 0x0100 }, /* R14 - ADC CTRL */ - { 15, 0x00C0 }, /* R15 - Left ADC Digital Volume */ - { 16, 0x00C0 }, /* R16 - Right ADC Digital Volume */ - - { 18, 0x0000 }, /* R18 - GPIO CTRL 1 */ - { 19, 0x1000 }, /* R19 - GPIO1 & GPIO2 */ - { 20, 0x1010 }, /* R20 - GPIO3 & GPIO4 */ - { 21, 0x1010 }, /* R21 - GPIO5 & GPIO6 */ - { 22, 0x8000 }, /* R22 - GPIOCTRL 2 */ - { 23, 0x0800 }, /* R23 - GPIO_POL */ - { 24, 0x008B }, /* R24 - Left Line Input 1&2 Volume */ - { 25, 0x008B }, /* R25 - Left Line Input 3&4 Volume */ - { 26, 0x008B }, /* R26 - Right Line Input 1&2 Volume */ - { 27, 0x008B }, /* R27 - Right Line Input 3&4 Volume */ - { 28, 0x0000 }, /* R28 - Left Output Volume */ - { 29, 0x0000 }, /* R29 - Right Output Volume */ - { 30, 0x0066 }, /* R30 - Line Outputs Volume */ - { 31, 0x0022 }, /* R31 - Out3/4 Volume */ - { 32, 0x0079 }, /* R32 - Left OPGA Volume */ - { 33, 0x0079 }, /* R33 - Right OPGA Volume */ - { 34, 0x0003 }, /* R34 - Speaker Volume */ - { 35, 0x0003 }, /* R35 - ClassD1 */ - - { 37, 0x0100 }, /* R37 - ClassD3 */ - { 38, 0x0079 }, /* R38 - ClassD4 */ - { 39, 0x0000 }, /* R39 - Input Mixer1 */ - { 40, 0x0000 }, /* R40 - Input Mixer2 */ - { 41, 0x0000 }, /* R41 - Input Mixer3 */ - { 42, 0x0000 }, /* R42 - Input Mixer4 */ - { 43, 0x0000 }, /* R43 - Input Mixer5 */ - { 44, 0x0000 }, /* R44 - Input Mixer6 */ - { 45, 0x0000 }, /* R45 - Output Mixer1 */ - { 46, 0x0000 }, /* R46 - Output Mixer2 */ - { 47, 0x0000 }, /* R47 - Output Mixer3 */ - { 48, 0x0000 }, /* R48 - Output Mixer4 */ - { 49, 0x0000 }, /* R49 - Output Mixer5 */ - { 50, 0x0000 }, /* R50 - Output Mixer6 */ - { 51, 0x0180 }, /* R51 - Out3/4 Mixer */ - { 52, 0x0000 }, /* R52 - Line Mixer1 */ - { 53, 0x0000 }, /* R53 - Line Mixer2 */ - { 54, 0x0000 }, /* R54 - Speaker Mixer */ - { 55, 0x0000 }, /* R55 - Additional Control */ - { 56, 0x0000 }, /* R56 - AntiPOP1 */ - { 57, 0x0000 }, /* R57 - AntiPOP2 */ - { 58, 0x0000 }, /* R58 - MICBIAS */ - - { 60, 0x0008 }, /* R60 - PLL1 */ - { 61, 0x0031 }, /* R61 - PLL2 */ - { 62, 0x0026 }, /* R62 - PLL3 */ -}; - #define wm8990_reset(c) snd_soc_component_write(c, WM8990_RESET, 0) -static const DECLARE_TLV_DB_SCALE(rec_mix_tlv, -1500, 600, 0); - static const DECLARE_TLV_DB_SCALE(in_pga_tlv, -1650, 3000, 0); static const DECLARE_TLV_DB_SCALE(out_mix_tlv, 0, -2100, 0); static const DECLARE_TLV_DB_SCALE(out_pga_tlv, -7300, 600, 0); -static const DECLARE_TLV_DB_SCALE(out_omix_tlv, -600, 0, 0); - static const DECLARE_TLV_DB_SCALE(out_dac_tlv, -7163, 0, 0); static const DECLARE_TLV_DB_SCALE(in_adc_tlv, -7163, 1763, 0); @@ -486,14 +407,6 @@ static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum, static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); -/* RXVOICE */ -static const struct snd_kcontrol_new wm8990_dapm_rxvoice_controls[] = { -SOC_DAPM_SINGLE_TLV("LIN4/RXN", WM8990_INPUT_MIXER5, WM8990_LR4BVOL_SHIFT, - WM8990_LR4BVOL_MASK, 0, in_mix_tlv), -SOC_DAPM_SINGLE_TLV("RIN4/RXP", WM8990_INPUT_MIXER6, WM8990_RL4BVOL_SHIFT, - WM8990_RL4BVOL_MASK, 0, in_mix_tlv), -}; - /* LOMIX */ static const struct snd_kcontrol_new wm8990_dapm_lomix_controls[] = { SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8990_OUTPUT_MIXER1, @@ -1306,17 +1219,6 @@ static const struct snd_soc_component_driver soc_component_dev_wm8990 = { .non_legacy_dai_naming = 1, }; -static const struct regmap_config wm8990_regmap = { - .reg_bits = 8, - .val_bits = 16, - - .max_register = WM8990_PLL3, - .volatile_reg = wm8990_volatile_register, - .reg_defaults = wm8990_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(wm8990_reg_defaults), - .cache_type = REGCACHE_RBTREE, -}; - static int wm8990_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 93c156782d59..f8375d67e901 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -476,14 +476,6 @@ static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum, static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls = SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum); -/* RXVOICE */ -static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls[] = { - SOC_DAPM_SINGLE_TLV("LIN4RXN", WM8991_INPUT_MIXER5, WM8991_LR4BVOL_SHIFT, - WM8991_LR4BVOL_MASK, 0, in_mix_tlv), - SOC_DAPM_SINGLE_TLV("RIN4RXP", WM8991_INPUT_MIXER6, WM8991_RL4BVOL_SHIFT, - WM8991_RL4BVOL_MASK, 0, in_mix_tlv), -}; - /* LOMIX */ static const struct snd_kcontrol_new wm8991_dapm_lomix_controls[] = { SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER1, diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 15ce64a48a87..55d0b9be6ff0 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -285,7 +285,6 @@ static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0); static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); -static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0); #define WM8994_DRC_SWITCH(xname, reg, shift) \ SOC_SINGLE_EXT(xname, reg, shift, 1, 0, \ @@ -733,13 +732,6 @@ SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume", 7, 1, ng_tlv), }; -static const struct snd_kcontrol_new wm1811_snd_controls[] = { -SOC_SINGLE_TLV("MIXINL IN1LP Boost Volume", WM8994_INPUT_MIXER_1, 7, 1, 0, - mixin_boost_tlv), -SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0, - mixin_boost_tlv), -}; - /* We run all mode setting through a function to enforce audio mode */ static void wm1811_jackdet_set_mode(struct snd_soc_component *component, u16 mode) { diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 1ef69409ccd1..519ca2e69637 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -3509,7 +3509,8 @@ out: } EXPORT_SYMBOL_GPL(wm_adsp_compr_open); -int wm_adsp_compr_free(struct snd_compr_stream *stream) +int wm_adsp_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *stream) { struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp *dsp = compr->dsp; @@ -3583,7 +3584,8 @@ static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr) return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; } -int wm_adsp_compr_set_params(struct snd_compr_stream *stream, +int wm_adsp_compr_set_params(struct snd_soc_component *component, + struct snd_compr_stream *stream, struct snd_compr_params *params) { struct wm_adsp_compr *compr = stream->runtime->private_data; @@ -3610,7 +3612,8 @@ int wm_adsp_compr_set_params(struct snd_compr_stream *stream, } EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); -int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, +int wm_adsp_compr_get_caps(struct snd_soc_component *component, + struct snd_compr_stream *stream, struct snd_compr_caps *caps) { struct wm_adsp_compr *compr = stream->runtime->private_data; @@ -3976,7 +3979,8 @@ static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) return 0; } -int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) +int wm_adsp_compr_trigger(struct snd_soc_component *component, + struct snd_compr_stream *stream, int cmd) { struct wm_adsp_compr *compr = stream->runtime->private_data; struct wm_adsp *dsp = compr->dsp; @@ -4139,7 +4143,8 @@ static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) buf->irq_count); } -int wm_adsp_compr_pointer(struct snd_compr_stream *stream, +int wm_adsp_compr_pointer(struct snd_soc_component *component, + struct snd_compr_stream *stream, struct snd_compr_tstamp *tstamp) { struct wm_adsp_compr *compr = stream->runtime->private_data; @@ -4297,7 +4302,8 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr, return ntotal; } -int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, +int wm_adsp_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *stream, char __user *buf, size_t count) { struct wm_adsp_compr *compr = stream->runtime->private_data; diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 4c481cf20275..1996350b817e 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -190,16 +190,22 @@ int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream); -int wm_adsp_compr_free(struct snd_compr_stream *stream); -int wm_adsp_compr_set_params(struct snd_compr_stream *stream, +int wm_adsp_compr_free(struct snd_soc_component *component, + struct snd_compr_stream *stream); +int wm_adsp_compr_set_params(struct snd_soc_component *component, + struct snd_compr_stream *stream, struct snd_compr_params *params); -int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, +int wm_adsp_compr_get_caps(struct snd_soc_component *component, + struct snd_compr_stream *stream, struct snd_compr_caps *caps); -int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); +int wm_adsp_compr_trigger(struct snd_soc_component *component, + struct snd_compr_stream *stream, int cmd); int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); -int wm_adsp_compr_pointer(struct snd_compr_stream *stream, +int wm_adsp_compr_pointer(struct snd_soc_component *component, + struct snd_compr_stream *stream, struct snd_compr_tstamp *tstamp); -int wm_adsp_compr_copy(struct snd_compr_stream *stream, +int wm_adsp_compr_copy(struct snd_soc_component *component, + struct snd_compr_stream *stream, char __user *buf, size_t count); int wm_adsp_write_ctl(struct wm_adsp *dsp, const char *name, int type, unsigned int alg, void *buf, size_t len); diff --git a/sound/soc/codecs/zl38060.c b/sound/soc/codecs/zl38060.c new file mode 100644 index 000000000000..927ad849ad2d --- /dev/null +++ b/sound/soc/codecs/zl38060.c @@ -0,0 +1,638 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Codec driver for Microsemi ZL38060 Connected Home Audio Processor. +// +// Copyright(c) 2020 Sven Van Asbroeck + +// The ZL38060 is very flexible and configurable. This driver implements only a +// tiny subset of the chip's possible configurations: +// +// - DSP block bypassed: DAI routed straight to DACs +// microphone routed straight to DAI +// - chip's internal clock is driven by a 12 MHz external crystal +// - chip's DAI connected to CPU is I2S, and bit + frame clock master +// - chip must be strapped for "host boot": in this mode, firmware will be +// provided by this driver. + +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> +#include <linux/property.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> +#include <linux/module.h> +#include <linux/ihex.h> + +#include <sound/pcm_params.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/soc.h> + +#define DRV_NAME "zl38060" + +#define ZL38_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_48000) +#define ZL38_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +#define HBI_FIRMWARE_PAGE 0xFF +#define ZL38_MAX_RAW_XFER 0x100 + +#define REG_TDMA_CFG_CLK 0x0262 +#define CFG_CLK_PCLK_SHIFT 4 +#define CFG_CLK_PCLK_MASK (0x7ff << CFG_CLK_PCLK_SHIFT) +#define CFG_CLK_PCLK(bits) ((bits - 1) << CFG_CLK_PCLK_SHIFT) +#define CFG_CLK_MASTER BIT(15) +#define CFG_CLK_FSRATE_MASK 0x7 +#define CFG_CLK_FSRATE_8KHZ 0x1 +#define CFG_CLK_FSRATE_16KHZ 0x2 +#define CFG_CLK_FSRATE_48KHZ 0x6 + +#define REG_CLK_CFG 0x0016 +#define CLK_CFG_SOURCE_XTAL BIT(15) + +#define REG_CLK_STATUS 0x0014 +#define CLK_STATUS_HWRST BIT(0) + +#define REG_PARAM_RESULT 0x0034 +#define PARAM_RESULT_READY 0xD3D3 + +#define REG_PG255_BASE_HI 0x000C +#define REG_PG255_OFFS(addr) ((HBI_FIRMWARE_PAGE << 8) | (addr & 0xFF)) +#define REG_FWR_EXEC 0x012C + +#define REG_CMD 0x0032 +#define REG_HW_REV 0x0020 +#define REG_FW_PROD 0x0022 +#define REG_FW_REV 0x0024 + +#define REG_SEMA_FLAGS 0x0006 +#define SEMA_FLAGS_BOOT_CMD BIT(0) +#define SEMA_FLAGS_APP_REBOOT BIT(1) + +#define REG_HW_REV 0x0020 +#define REG_FW_PROD 0x0022 +#define REG_FW_REV 0x0024 +#define REG_GPIO_DIR 0x02DC +#define REG_GPIO_DAT 0x02DA + +#define BOOTCMD_LOAD_COMPLETE 0x000D +#define BOOTCMD_FW_GO 0x0008 + +#define FIRMWARE_MAJOR 2 +#define FIRMWARE_MINOR 2 + +struct zl38_codec_priv { + struct device *dev; + struct regmap *regmap; + bool is_stream_in_use[2]; + struct gpio_chip *gpio_chip; +}; + +static int zl38_fw_issue_command(struct regmap *regmap, u16 cmd) +{ + unsigned int val; + int err; + + err = regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val, + !(val & SEMA_FLAGS_BOOT_CMD), 10000, + 10000 * 100); + if (err) + return err; + err = regmap_write(regmap, REG_CMD, cmd); + if (err) + return err; + err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_BOOT_CMD, + SEMA_FLAGS_BOOT_CMD); + if (err) + return err; + + return regmap_read_poll_timeout(regmap, REG_CMD, val, !val, 10000, + 10000 * 100); +} + +static int zl38_fw_go(struct regmap *regmap) +{ + int err; + + err = zl38_fw_issue_command(regmap, BOOTCMD_LOAD_COMPLETE); + if (err) + return err; + + return zl38_fw_issue_command(regmap, BOOTCMD_FW_GO); +} + +static int zl38_fw_enter_boot_mode(struct regmap *regmap) +{ + unsigned int val; + int err; + + err = regmap_update_bits(regmap, REG_CLK_STATUS, CLK_STATUS_HWRST, + CLK_STATUS_HWRST); + if (err) + return err; + + return regmap_read_poll_timeout(regmap, REG_PARAM_RESULT, val, + val == PARAM_RESULT_READY, 1000, 50000); +} + +static int +zl38_fw_send_data(struct regmap *regmap, u32 addr, const void *data, u16 len) +{ + __be32 addr_base = cpu_to_be32(addr & ~0xFF); + int err; + + err = regmap_raw_write(regmap, REG_PG255_BASE_HI, &addr_base, + sizeof(addr_base)); + if (err) + return err; + return regmap_raw_write(regmap, REG_PG255_OFFS(addr), data, len); +} + +static int zl38_fw_send_xaddr(struct regmap *regmap, const void *data) +{ + /* execution address from ihex: 32-bit little endian. + * device register expects 32-bit big endian. + */ + u32 addr = le32_to_cpup(data); + __be32 baddr = cpu_to_be32(addr); + + return regmap_raw_write(regmap, REG_FWR_EXEC, &baddr, sizeof(baddr)); +} + +static int zl38_load_firmware(struct device *dev, struct regmap *regmap) +{ + const struct ihex_binrec *rec; + const struct firmware *fw; + u32 addr; + u16 len; + int err; + + /* how to get this firmware: + * 1. request and download chip firmware from Microsemi + * (provided by Microsemi in srec format) + * 2. convert downloaded firmware from srec to ihex. Simple tool: + * https://gitlab.com/TheSven73/s3-to-irec + * 3. convert ihex to binary (.fw) using ihex2fw tool which is included + * with the Linux kernel sources + */ + err = request_ihex_firmware(&fw, "zl38060.fw", dev); + if (err) + return err; + err = zl38_fw_enter_boot_mode(regmap); + if (err) + goto out; + rec = (const struct ihex_binrec *)fw->data; + while (rec) { + addr = be32_to_cpu(rec->addr); + len = be16_to_cpu(rec->len); + if (addr) { + /* regular data ihex record */ + err = zl38_fw_send_data(regmap, addr, rec->data, len); + } else if (len == 4) { + /* execution address ihex record */ + err = zl38_fw_send_xaddr(regmap, rec->data); + } else { + err = -EINVAL; + } + if (err) + goto out; + /* next ! */ + rec = ihex_next_binrec(rec); + } + err = zl38_fw_go(regmap); + +out: + release_firmware(fw); + return err; +} + + +static int zl38_software_reset(struct regmap *regmap) +{ + unsigned int val; + int err; + + err = regmap_update_bits(regmap, REG_SEMA_FLAGS, SEMA_FLAGS_APP_REBOOT, + SEMA_FLAGS_APP_REBOOT); + if (err) + return err; + + /* wait for host bus interface to settle. + * Not sure if this is required: Microsemi's vendor driver does this, + * but the firmware manual does not mention it. Leave it in, there's + * little downside, apart from a slower reset. + */ + msleep(50); + + return regmap_read_poll_timeout(regmap, REG_SEMA_FLAGS, val, + !(val & SEMA_FLAGS_APP_REBOOT), 10000, + 10000 * 100); +} + +static int zl38_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai); + int err; + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + /* firmware default is normal i2s */ + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + /* firmware default is normal bitclock and frame */ + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + /* always 32 bits per frame (= 16 bits/channel, 2 channels) */ + err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK, + CFG_CLK_MASTER | CFG_CLK_PCLK_MASK, + CFG_CLK_MASTER | CFG_CLK_PCLK(32)); + if (err) + return err; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int zl38_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int fsrate; + int err; + + /* We cannot change hw_params while the dai is already in use - the + * software reset will corrupt the audio. However, this is not required, + * as the chip's TDM buses are fully symmetric, which mandates identical + * rates, channels, and samplebits for record and playback. + */ + if (priv->is_stream_in_use[!tx]) + goto skip_setup; + + switch (params_rate(params)) { + case 8000: + fsrate = CFG_CLK_FSRATE_8KHZ; + break; + case 16000: + fsrate = CFG_CLK_FSRATE_16KHZ; + break; + case 48000: + fsrate = CFG_CLK_FSRATE_48KHZ; + break; + default: + return -EINVAL; + }; + + err = regmap_update_bits(priv->regmap, REG_TDMA_CFG_CLK, + CFG_CLK_FSRATE_MASK, fsrate); + if (err) + return err; + + /* chip requires a software reset to apply audio register changes */ + err = zl38_software_reset(priv->regmap); + if (err) + return err; + +skip_setup: + priv->is_stream_in_use[tx] = true; + + return 0; +} + +static int zl38_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zl38_codec_priv *priv = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + + priv->is_stream_in_use[tx] = false; + + return 0; +} + +/* stereo bypass with no AEC */ +static const struct reg_sequence cp_config_stereo_bypass[] = { + /* interconnects must be programmed first */ + { 0x0210, 0x0005 }, /* DAC1 in <= I2S1-L */ + { 0x0212, 0x0006 }, /* DAC2 in <= I2S1-R */ + { 0x0214, 0x0001 }, /* I2S1-L in <= MIC1 */ + { 0x0216, 0x0001 }, /* I2S1-R in <= MIC1 */ + { 0x0224, 0x0000 }, /* AEC-S in <= n/a */ + { 0x0226, 0x0000 }, /* AEC-R in <= n/a */ + /* output enables must be programmed next */ + { 0x0202, 0x000F }, /* enable I2S1 + DAC */ +}; + +static const struct snd_soc_dai_ops zl38_dai_ops = { + .set_fmt = zl38_set_fmt, + .hw_params = zl38_hw_params, + .hw_free = zl38_hw_free, +}; + +static struct snd_soc_dai_driver zl38_dai = { + .name = "zl38060-tdma", + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ZL38_RATES, + .formats = ZL38_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = ZL38_RATES, + .formats = ZL38_FORMATS, + }, + .ops = &zl38_dai_ops, + .symmetric_rates = 1, + .symmetric_samplebits = 1, + .symmetric_channels = 1, +}; + +static const struct snd_soc_dapm_widget zl38_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("DAC1"), + SND_SOC_DAPM_OUTPUT("DAC2"), + + SND_SOC_DAPM_INPUT("DMICL"), +}; + +static const struct snd_soc_dapm_route zl38_dapm_routes[] = { + { "DAC1", NULL, "Playback" }, + { "DAC2", NULL, "Playback" }, + + { "Capture", NULL, "DMICL" }, +}; + +static const struct snd_soc_component_driver zl38_component_dev = { + .dapm_widgets = zl38_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(zl38_dapm_widgets), + .dapm_routes = zl38_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(zl38_dapm_routes), + .endianness = 1, + .non_legacy_dai_naming = 1, +}; + +static void chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) +{ + struct regmap *regmap = gpiochip_get_data(c); + unsigned int mask = BIT(offset); + + regmap_update_bits(regmap, REG_GPIO_DAT, mask, val ? mask : 0); +} + +static int chip_gpio_get(struct gpio_chip *c, unsigned int offset) +{ + struct regmap *regmap = gpiochip_get_data(c); + unsigned int mask = BIT(offset); + unsigned int val; + int err; + + err = regmap_read(regmap, REG_GPIO_DAT, &val); + if (err) + return err; + + return !!(val & mask); +} + +static int chip_direction_input(struct gpio_chip *c, unsigned int offset) +{ + struct regmap *regmap = gpiochip_get_data(c); + unsigned int mask = BIT(offset); + + return regmap_update_bits(regmap, REG_GPIO_DIR, mask, 0); +} + +static int +chip_direction_output(struct gpio_chip *c, unsigned int offset, int val) +{ + struct regmap *regmap = gpiochip_get_data(c); + unsigned int mask = BIT(offset); + + chip_gpio_set(c, offset, val); + return regmap_update_bits(regmap, REG_GPIO_DIR, mask, mask); +} + +static const struct gpio_chip template_chip = { + .owner = THIS_MODULE, + .label = DRV_NAME, + + .base = -1, + .ngpio = 14, + .direction_input = chip_direction_input, + .direction_output = chip_direction_output, + .get = chip_gpio_get, + .set = chip_gpio_set, + + .can_sleep = true, +}; + +static int zl38_check_revision(struct device *dev, struct regmap *regmap) +{ + unsigned int hwrev, fwprod, fwrev; + int fw_major, fw_minor, fw_micro; + int err; + + err = regmap_read(regmap, REG_HW_REV, &hwrev); + if (err) + return err; + err = regmap_read(regmap, REG_FW_PROD, &fwprod); + if (err) + return err; + err = regmap_read(regmap, REG_FW_REV, &fwrev); + if (err) + return err; + + fw_major = (fwrev >> 12) & 0xF; + fw_minor = (fwrev >> 8) & 0xF; + fw_micro = fwrev & 0xFF; + dev_info(dev, "hw rev 0x%x, fw product code %d, firmware rev %d.%d.%d", + hwrev & 0x1F, fwprod, fw_major, fw_minor, fw_micro); + + if (fw_major != FIRMWARE_MAJOR || fw_minor < FIRMWARE_MINOR) { + dev_err(dev, "unsupported firmware. driver supports %d.%d", + FIRMWARE_MAJOR, FIRMWARE_MINOR); + return -EINVAL; + } + + return 0; +} + +static int zl38_bus_read(void *context, + const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_size) +{ + struct spi_device *spi = context; + const u8 *reg_buf8 = reg_buf; + size_t len = 0; + u8 offs, page; + u8 txbuf[4]; + + if (reg_size != 2 || val_size > ZL38_MAX_RAW_XFER) + return -EINVAL; + + offs = reg_buf8[1] >> 1; + page = reg_buf8[0]; + + if (page) { + txbuf[len++] = 0xFE; + txbuf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1; + txbuf[len++] = offs; + txbuf[len++] = val_size / 2 - 1; + } else { + txbuf[len++] = offs | 0x80; + txbuf[len++] = val_size / 2 - 1; + } + + return spi_write_then_read(spi, txbuf, len, val_buf, val_size); +} + +static int zl38_bus_write(void *context, const void *data, size_t count) +{ + struct spi_device *spi = context; + u8 buf[4 + ZL38_MAX_RAW_XFER]; + size_t val_len, len = 0; + const u8 *data8 = data; + u8 offs, page; + + if (count > (2 + ZL38_MAX_RAW_XFER) || count < 4) + return -EINVAL; + val_len = count - 2; + offs = data8[1] >> 1; + page = data8[0]; + + if (page) { + buf[len++] = 0xFE; + buf[len++] = page == HBI_FIRMWARE_PAGE ? 0xFF : page - 1; + buf[len++] = offs; + buf[len++] = (val_len / 2 - 1) | 0x80; + } else { + buf[len++] = offs | 0x80; + buf[len++] = (val_len / 2 - 1) | 0x80; + } + memcpy(buf + len, data8 + 2, val_len); + len += val_len; + + return spi_write(spi, buf, len); +} + +static const struct regmap_bus zl38_regmap_bus = { + .read = zl38_bus_read, + .write = zl38_bus_write, + .max_raw_write = ZL38_MAX_RAW_XFER, + .max_raw_read = ZL38_MAX_RAW_XFER, +}; + +static const struct regmap_config zl38_regmap_conf = { + .reg_bits = 16, + .val_bits = 16, + .reg_stride = 2, + .use_single_read = true, + .use_single_write = true, +}; + +static int zl38_spi_probe(struct spi_device *spi) +{ + struct device *dev = &spi->dev; + struct zl38_codec_priv *priv; + struct gpio_desc *reset_gpio; + int err; + + /* get the chip to a known state by putting it in reset */ + reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(reset_gpio)) + return PTR_ERR(reset_gpio); + if (reset_gpio) { + /* datasheet: need > 10us for a digital + analog reset */ + usleep_range(15, 50); + /* take the chip out of reset */ + gpiod_set_value_cansleep(reset_gpio, 0); + /* datasheet: need > 3ms for digital section to become stable */ + usleep_range(3000, 10000); + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->dev = dev; + dev_set_drvdata(dev, priv); + priv->regmap = devm_regmap_init(dev, &zl38_regmap_bus, spi, + &zl38_regmap_conf); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + err = zl38_load_firmware(dev, priv->regmap); + if (err) + return err; + + err = zl38_check_revision(dev, priv->regmap); + if (err) + return err; + + priv->gpio_chip = devm_kmemdup(dev, &template_chip, + sizeof(template_chip), GFP_KERNEL); + if (!priv->gpio_chip) + return -ENOMEM; +#ifdef CONFIG_OF_GPIO + priv->gpio_chip->of_node = dev->of_node; +#endif + err = devm_gpiochip_add_data(dev, priv->gpio_chip, priv->regmap); + if (err) + return err; + + /* setup the cross-point switch for stereo bypass */ + err = regmap_multi_reg_write(priv->regmap, cp_config_stereo_bypass, + ARRAY_SIZE(cp_config_stereo_bypass)); + if (err) + return err; + /* setup for 12MHz crystal connected to the chip */ + err = regmap_update_bits(priv->regmap, REG_CLK_CFG, CLK_CFG_SOURCE_XTAL, + CLK_CFG_SOURCE_XTAL); + if (err) + return err; + + return devm_snd_soc_register_component(dev, &zl38_component_dev, + &zl38_dai, 1); +} + +static const struct of_device_id zl38_dt_ids[] = { + { .compatible = "mscc,zl38060", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, zl38_dt_ids); + +static const struct spi_device_id zl38_spi_ids[] = { + { "zl38060", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(spi, zl38_spi_ids); + +static struct spi_driver zl38060_spi_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = of_match_ptr(zl38_dt_ids), + }, + .probe = zl38_spi_probe, + .id_table = zl38_spi_ids, +}; +module_spi_driver(zl38060_spi_driver); + +MODULE_DESCRIPTION("ASoC ZL38060 driver"); +MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>"); +MODULE_LICENSE("GPL v2"); |