From 86834511c2acd23e214d5739e9ea58e31b975d1f Mon Sep 17 00:00:00 2001 From: Adam Thomson Date: Mon, 3 Oct 2016 11:21:01 +0100 Subject: ASoC: da7219: Improve pop/click performance for sensitive HPs Currently on some headsets slight pops can be heard during DAPM power-up/down. This can also be witnessed during the HP detect procedure. This patch addresses the issue by adjusting DAPM power sequencing slightly, the introduction of delays and use of minimum HP gain to avoid such noise artefacts. Signed-off-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da7219-aad.c | 18 ++++-- sound/soc/codecs/da7219.c | 139 ++++++++++++++++++++++++++++++++++++------ sound/soc/codecs/da7219.h | 5 ++ 3 files changed, 140 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 2b8914dd5990..6274d79c1353 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c @@ -204,10 +204,19 @@ static void da7219_aad_hptest_work(struct work_struct *work) snd_soc_update_bits(codec, DA7219_MIXOUT_R_CTRL, DA7219_MIXOUT_R_AMP_EN_MASK, DA7219_MIXOUT_R_AMP_EN_MASK); - snd_soc_write(codec, DA7219_HP_L_CTRL, - DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); - snd_soc_write(codec, DA7219_HP_R_CTRL, - DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK, + DA7219_HP_L_AMP_OE_MASK | DA7219_HP_L_AMP_EN_MASK); + snd_soc_update_bits(codec, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK, + DA7219_HP_R_AMP_OE_MASK | DA7219_HP_R_AMP_EN_MASK); + msleep(DA7219_SETTLING_DELAY); + snd_soc_update_bits(codec, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_MUTE_EN_MASK | + DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, 0); + snd_soc_update_bits(codec, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_MUTE_EN_MASK | + DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, 0); /* * If we're running from the internal oscillator then give audio paths @@ -244,6 +253,7 @@ static void da7219_aad_hptest_work(struct work_struct *work) regcache_mark_dirty(da7219->regmap); regcache_sync_region(da7219->regmap, DA7219_HP_L_CTRL, DA7219_HP_R_CTRL); + msleep(DA7219_SETTLING_DELAY); regcache_sync_region(da7219->regmap, DA7219_MIXOUT_L_CTRL, DA7219_MIXOUT_R_CTRL); regcache_sync_region(da7219->regmap, DA7219_DROUTING_ST_OUTFILT_1L, diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 1152aa5e7c39..2610fc5cff68 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -823,6 +823,85 @@ static int da7219_dai_event(struct snd_soc_dapm_widget *w, } } +static int da7219_settling_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + msleep(DA7219_SETTLING_DELAY); + break; + default: + break; + } + + return 0; +} + +static int da7219_mixout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u8 hp_ctrl, min_gain_mask; + + switch (w->reg) { + case DA7219_MIXOUT_L_CTRL: + hp_ctrl = DA7219_HP_L_CTRL; + min_gain_mask = DA7219_HP_L_AMP_MIN_GAIN_EN_MASK; + break; + case DA7219_MIXOUT_R_CTRL: + hp_ctrl = DA7219_HP_R_CTRL; + min_gain_mask = DA7219_HP_R_AMP_MIN_GAIN_EN_MASK; + break; + default: + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + /* Enable minimum gain on HP to avoid pops */ + snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, + min_gain_mask); + + msleep(DA7219_MIN_GAIN_DELAY); + + break; + case SND_SOC_DAPM_POST_PMU: + /* Remove minimum gain on HP */ + snd_soc_update_bits(codec, hp_ctrl, min_gain_mask, 0); + + break; + } + + return 0; +} + +static int da7219_gain_ramp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct da7219_priv *da7219 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_PRE_PMD: + /* Ensure nominal gain ramping for DAPM sequence */ + da7219->gain_ramp_ctrl = + snd_soc_read(codec, DA7219_GAIN_RAMP_CTRL); + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, + DA7219_GAIN_RAMP_RATE_NOMINAL); + break; + case SND_SOC_DAPM_POST_PMU: + case SND_SOC_DAPM_POST_PMD: + /* Restore previous gain ramp settings */ + snd_soc_write(codec, DA7219_GAIN_RAMP_CTRL, + da7219->gain_ramp_ctrl); + break; + } + + return 0; +} + /* * DAPM Widgets @@ -906,30 +985,46 @@ static const struct snd_soc_dapm_widget da7219_dapm_widgets[] = { ARRAY_SIZE(da7219_st_out_filtr_mix_controls)), /* DACs */ - SND_SOC_DAPM_DAC("DACL", NULL, DA7219_DAC_L_CTRL, DA7219_DAC_L_EN_SHIFT, - DA7219_NO_INVERT), - SND_SOC_DAPM_DAC("DACR", NULL, DA7219_DAC_R_CTRL, DA7219_DAC_R_EN_SHIFT, - DA7219_NO_INVERT), + SND_SOC_DAPM_DAC_E("DACL", NULL, DA7219_DAC_L_CTRL, + DA7219_DAC_L_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_DAC_E("DACR", NULL, DA7219_DAC_R_CTRL, + DA7219_DAC_R_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* Output PGAs */ - SND_SOC_DAPM_PGA("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, - DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, - NULL, 0), - SND_SOC_DAPM_PGA("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, - DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, - NULL, 0), - SND_SOC_DAPM_PGA("Headphone Left PGA", DA7219_HP_L_CTRL, - DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), - SND_SOC_DAPM_PGA("Headphone Right PGA", DA7219_HP_R_CTRL, - DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, NULL, 0), + SND_SOC_DAPM_PGA_E("Mixout Left PGA", DA7219_MIXOUT_L_CTRL, + DA7219_MIXOUT_L_AMP_EN_SHIFT, DA7219_NO_INVERT, + NULL, 0, da7219_mixout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_PGA_E("Mixout Right PGA", DA7219_MIXOUT_R_CTRL, + DA7219_MIXOUT_R_AMP_EN_SHIFT, DA7219_NO_INVERT, + NULL, 0, da7219_mixout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_SUPPLY_S("Headphone Left PGA", 1, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("Headphone Right PGA", 1, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), /* Output Supplies */ - SND_SOC_DAPM_SUPPLY("Charge Pump", DA7219_CP_CTRL, DA7219_CP_EN_SHIFT, - DA7219_NO_INVERT, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("Charge Pump", 0, DA7219_CP_CTRL, + DA7219_CP_EN_SHIFT, DA7219_NO_INVERT, + da7219_settling_event, + SND_SOC_DAPM_POST_PMU), /* Outputs */ SND_SOC_DAPM_OUTPUT("HPL"), SND_SOC_DAPM_OUTPUT("HPR"), + + /* Pre/Post Power */ + SND_SOC_DAPM_PRE("Pre Power Gain Ramp", da7219_gain_ramp_event), + SND_SOC_DAPM_POST("Post Power Gain Ramp", da7219_gain_ramp_event), }; @@ -1002,8 +1097,8 @@ static const struct snd_soc_dapm_route da7219_audio_map[] = { {"Mixout Left PGA", NULL, "DACL"}, {"Mixout Right PGA", NULL, "DACR"}, - {"Headphone Left PGA", NULL, "Mixout Left PGA"}, - {"Headphone Right PGA", NULL, "Mixout Right PGA"}, + {"HPL", NULL, "Mixout Left PGA"}, + {"HPR", NULL, "Mixout Right PGA"}, {"HPL", NULL, "Headphone Left PGA"}, {"HPR", NULL, "Headphone Right PGA"}, @@ -1711,6 +1806,14 @@ static int da7219_probe(struct snd_soc_codec *codec) DA7219_HP_R_AMP_RAMP_EN_MASK, DA7219_HP_R_AMP_RAMP_EN_MASK); + /* Default minimum gain on HP to avoid pops during DAPM sequencing */ + snd_soc_update_bits(codec, DA7219_HP_L_CTRL, + DA7219_HP_L_AMP_MIN_GAIN_EN_MASK, + DA7219_HP_L_AMP_MIN_GAIN_EN_MASK); + snd_soc_update_bits(codec, DA7219_HP_R_CTRL, + DA7219_HP_R_AMP_MIN_GAIN_EN_MASK, + DA7219_HP_R_AMP_MIN_GAIN_EN_MASK); + /* Default infinite tone gen, start/stop by Kcontrol */ snd_soc_write(codec, DA7219_TONE_GEN_CYCLES, DA7219_BEEP_CYCLES_MASK); diff --git a/sound/soc/codecs/da7219.h b/sound/soc/codecs/da7219.h index 66d3bad86739..6baba7455fa1 100644 --- a/sound/soc/codecs/da7219.h +++ b/sound/soc/codecs/da7219.h @@ -777,6 +777,10 @@ #define DA7219_SYS_STAT_CHECK_RETRIES 6 #define DA7219_SYS_STAT_CHECK_DELAY 50 +/* Power up/down Delays */ +#define DA7219_SETTLING_DELAY 40 +#define DA7219_MIN_GAIN_DELAY 30 + enum da7219_clk_src { DA7219_CLKSRC_MCLK = 0, DA7219_CLKSRC_MCLK_SQR, @@ -814,6 +818,7 @@ struct da7219_priv { bool master; bool alc_en; + u8 gain_ramp_ctrl; }; #endif /* __DA7219_H */ -- cgit v1.2.3-59-g8ed1b From 9a58725ba533b46db31d10a6dcc5ab7f9fa370ed Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Thu, 6 Oct 2016 08:51:21 +0530 Subject: ASoC: Intel: Skylake: Use DPIB to update position for Playback stream DPIB is read currently from a buffer position in memory (indicated by the registers DPIB[U|L]BASE).Driver reads the position buffer on BDL completion interrupts to report the DMA position. But the BDL completion interrupt only indicates the last DMA transfer of the buffer is completed at the Intel HD Audio subsystem boundary. The periodic DMA Position-in-Buffer writes may be scheduled at the same time or later than the MSI and does not guarantee to reflect the position of the last buffer that was transferred. Whereas DPIB register in HDA space(vendor specific register indicated by SDxDPIB) reflects the actual data that is transferred. Hence update the position based on DPIB for playback. Signed-off-by: Dharageswari R Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..c966b40da180 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1031,10 +1031,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer (struct snd_pcm_substream *substream) { struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); unsigned int pos; - /* use the position buffer as default */ - pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + /* + * Use DPIB for Playback stream as the periodic DMA Position-in- + * Buffer Writes may be scheduled at the same time or later than + * the MSI and does not guarantee to reflect the Position of the + * last buffer that was transferred. Whereas DPIB register in + * HAD space reflects the actual data that is transferred. + * Use the position buffer for capture, as DPIB write gets + * completed earlier than the actual data written to the DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(hstream)->index)); + else + pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); if (pos >= hdac_stream(hstream)->bufsize) pos = 0; -- cgit v1.2.3-59-g8ed1b From 90554f2e2d53f80fb6200e277d5a20884531e945 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Mon, 3 Oct 2016 11:40:38 +0100 Subject: ASoC: wm_adsp: Remove duplicate set of kcontrol->iface Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index b943dde8dbe5..7320fcacd86a 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -967,7 +967,6 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); if (!kcontrol) return -ENOMEM; - kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kcontrol->name = ctl->name; kcontrol->info = wm_coeff_info; -- cgit v1.2.3-59-g8ed1b From c1124c09e1035cabdbc17d4538ae6f922086fec9 Mon Sep 17 00:00:00 2001 From: Paul Handrigan Date: Wed, 12 Oct 2016 13:53:28 -0500 Subject: ASoC: cs35l34: Initial commit of the cs35l34 CODEC driver. Initial commit of the Cirrus Logic cs35l34 8V boosted class D amplifier. Signed-off-by: Paul Handrigan Signed-off-by: Mark Brown --- include/sound/cs35l34.h | 35 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs35l34.c | 1252 ++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs35l34.h | 269 ++++++++++ 5 files changed, 1563 insertions(+) create mode 100644 include/sound/cs35l34.h create mode 100644 sound/soc/codecs/cs35l34.c create mode 100644 sound/soc/codecs/cs35l34.h (limited to 'sound') diff --git a/include/sound/cs35l34.h b/include/sound/cs35l34.h new file mode 100644 index 000000000000..9c927cffbe46 --- /dev/null +++ b/include/sound/cs35l34.h @@ -0,0 +1,35 @@ +/* + * linux/sound/cs35l34.h -- Platform data for CS35l34 + * + * Copyright (c) 2016 Cirrus Logic Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __CS35L34_H +#define __CS35L34_H + +struct cs35l34_platform_data { + /* Set AIF to half drive strength */ + bool aif_half_drv; + /* Digital Soft Ramp Disable */ + bool digsft_disable; + /* Amplifier Invert */ + bool amp_inv; + /* Peak current (mA) */ + unsigned int boost_peak; + /* Boost inductor value (nH) */ + unsigned int boost_ind; + /* Boost Controller Voltage Setting (mV) */ + unsigned int boost_vtge; + /* Gain Change Zero Cross */ + bool gain_zc_disable; + /* SDIN Left/Right Selection */ + unsigned int i2s_sdinloc; + /* TDM Rising Edge */ + bool tdm_rising_edge; +}; + +#endif /* __CS35L34_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..bf2f26dddfab 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -48,6 +48,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C + select SND_SOC_CS35L34 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT @@ -399,6 +400,10 @@ config SND_SOC_CS35L33 tristate "Cirrus Logic CS35L33 CODEC" depends on I2C +config SND_SOC_CS35L34 + tristate "Cirrus Logic CS35L34 CODEC" + depends on I2C + config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 958cd4912fbc..3f0cd9047f09 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -38,6 +38,7 @@ snd-soc-bt-sco-objs := bt-sco.o snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o +snd-soc-cs35l34-objs := cs35l34.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -263,6 +264,7 @@ obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o +obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c new file mode 100644 index 000000000000..404538379586 --- /dev/null +++ b/sound/soc/codecs/cs35l34.c @@ -0,0 +1,1252 @@ +/* + * cs35l34.c -- CS35l34 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Paul Handrigan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs35l34.h" + +#define PDN_DONE_ATTEMPTS 10 +#define CS35L34_START_DELAY 50 + +struct cs35l34_private { + struct snd_soc_codec *codec; + struct cs35l34_platform_data pdata; + struct regmap *regmap; + struct regulator_bulk_data core_supplies[2]; + int num_core_supplies; + int mclk_int; + bool tdm_mode; + struct gpio_desc *reset_gpio; /* Active-low reset GPIO */ +}; + +static const struct reg_default cs35l34_reg[] = { + {CS35L34_PWRCTL1, 0x01}, + {CS35L34_PWRCTL2, 0x19}, + {CS35L34_PWRCTL3, 0x01}, + {CS35L34_ADSP_CLK_CTL, 0x08}, + {CS35L34_MCLK_CTL, 0x11}, + {CS35L34_AMP_INP_DRV_CTL, 0x01}, + {CS35L34_AMP_DIG_VOL_CTL, 0x12}, + {CS35L34_AMP_DIG_VOL, 0x00}, + {CS35L34_AMP_ANLG_GAIN_CTL, 0x0F}, + {CS35L34_PROTECT_CTL, 0x06}, + {CS35L34_AMP_KEEP_ALIVE_CTL, 0x04}, + {CS35L34_BST_CVTR_V_CTL, 0x00}, + {CS35L34_BST_PEAK_I, 0x10}, + {CS35L34_BST_RAMP_CTL, 0x87}, + {CS35L34_BST_CONV_COEF_1, 0x24}, + {CS35L34_BST_CONV_COEF_2, 0x24}, + {CS35L34_BST_CONV_SLOPE_COMP, 0x4E}, + {CS35L34_BST_CONV_SW_FREQ, 0x08}, + {CS35L34_CLASS_H_CTL, 0x0D}, + {CS35L34_CLASS_H_HEADRM_CTL, 0x0D}, + {CS35L34_CLASS_H_RELEASE_RATE, 0x08}, + {CS35L34_CLASS_H_FET_DRIVE_CTL, 0x41}, + {CS35L34_CLASS_H_STATUS, 0x05}, + {CS35L34_VPBR_CTL, 0x0A}, + {CS35L34_VPBR_VOL_CTL, 0x90}, + {CS35L34_VPBR_TIMING_CTL, 0x6A}, + {CS35L34_PRED_MAX_ATTEN_SPK_LOAD, 0x95}, + {CS35L34_PRED_BROWNOUT_THRESH, 0x1C}, + {CS35L34_PRED_BROWNOUT_VOL_CTL, 0x00}, + {CS35L34_PRED_BROWNOUT_RATE_CTL, 0x10}, + {CS35L34_PRED_WAIT_CTL, 0x10}, + {CS35L34_PRED_ZVP_INIT_IMP_CTL, 0x08}, + {CS35L34_PRED_MAN_SAFE_VPI_CTL, 0x80}, + {CS35L34_VPBR_ATTEN_STATUS, 0x00}, + {CS35L34_PRED_BRWNOUT_ATT_STATUS, 0x00}, + {CS35L34_SPKR_MON_CTL, 0xC6}, + {CS35L34_ADSP_I2S_CTL, 0x00}, + {CS35L34_ADSP_TDM_CTL, 0x00}, + {CS35L34_TDM_TX_CTL_1_VMON, 0x00}, + {CS35L34_TDM_TX_CTL_2_IMON, 0x04}, + {CS35L34_TDM_TX_CTL_3_VPMON, 0x03}, + {CS35L34_TDM_TX_CTL_4_VBSTMON, 0x07}, + {CS35L34_TDM_TX_CTL_5_FLAG1, 0x08}, + {CS35L34_TDM_TX_CTL_6_FLAG2, 0x09}, + {CS35L34_TDM_TX_SLOT_EN_1, 0x00}, + {CS35L34_TDM_TX_SLOT_EN_2, 0x00}, + {CS35L34_TDM_TX_SLOT_EN_3, 0x00}, + {CS35L34_TDM_TX_SLOT_EN_4, 0x00}, + {CS35L34_TDM_RX_CTL_1_AUDIN, 0x40}, + {CS35L34_TDM_RX_CTL_3_ALIVE, 0x04}, + {CS35L34_MULT_DEV_SYNCH1, 0x00}, + {CS35L34_MULT_DEV_SYNCH2, 0x80}, + {CS35L34_PROT_RELEASE_CTL, 0x00}, + {CS35L34_DIAG_MODE_REG_LOCK, 0x00}, + {CS35L34_DIAG_MODE_CTL_1, 0x00}, + {CS35L34_DIAG_MODE_CTL_2, 0x00}, + {CS35L34_INT_MASK_1, 0xFF}, + {CS35L34_INT_MASK_2, 0xFF}, + {CS35L34_INT_MASK_3, 0xFF}, + {CS35L34_INT_MASK_4, 0xFF}, + {CS35L34_INT_STATUS_1, 0x30}, + {CS35L34_INT_STATUS_2, 0x05}, + {CS35L34_INT_STATUS_3, 0x00}, + {CS35L34_INT_STATUS_4, 0x00}, + {CS35L34_OTP_TRIM_STATUS, 0x00}, +}; + +static bool cs35l34_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L34_DEVID_AB: + case CS35L34_DEVID_CD: + case CS35L34_DEVID_E: + case CS35L34_FAB_ID: + case CS35L34_REV_ID: + case CS35L34_INT_STATUS_1: + case CS35L34_INT_STATUS_2: + case CS35L34_INT_STATUS_3: + case CS35L34_INT_STATUS_4: + case CS35L34_CLASS_H_STATUS: + case CS35L34_VPBR_ATTEN_STATUS: + case CS35L34_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l34_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L34_CHIP_ID: + case CS35L34_DEVID_AB: + case CS35L34_DEVID_CD: + case CS35L34_DEVID_E: + case CS35L34_FAB_ID: + case CS35L34_REV_ID: + case CS35L34_PWRCTL1: + case CS35L34_PWRCTL2: + case CS35L34_PWRCTL3: + case CS35L34_ADSP_CLK_CTL: + case CS35L34_MCLK_CTL: + case CS35L34_AMP_INP_DRV_CTL: + case CS35L34_AMP_DIG_VOL_CTL: + case CS35L34_AMP_DIG_VOL: + case CS35L34_AMP_ANLG_GAIN_CTL: + case CS35L34_PROTECT_CTL: + case CS35L34_AMP_KEEP_ALIVE_CTL: + case CS35L34_BST_CVTR_V_CTL: + case CS35L34_BST_PEAK_I: + case CS35L34_BST_RAMP_CTL: + case CS35L34_BST_CONV_COEF_1: + case CS35L34_BST_CONV_COEF_2: + case CS35L34_BST_CONV_SLOPE_COMP: + case CS35L34_BST_CONV_SW_FREQ: + case CS35L34_CLASS_H_CTL: + case CS35L34_CLASS_H_HEADRM_CTL: + case CS35L34_CLASS_H_RELEASE_RATE: + case CS35L34_CLASS_H_FET_DRIVE_CTL: + case CS35L34_CLASS_H_STATUS: + case CS35L34_VPBR_CTL: + case CS35L34_VPBR_VOL_CTL: + case CS35L34_VPBR_TIMING_CTL: + case CS35L34_PRED_MAX_ATTEN_SPK_LOAD: + case CS35L34_PRED_BROWNOUT_THRESH: + case CS35L34_PRED_BROWNOUT_VOL_CTL: + case CS35L34_PRED_BROWNOUT_RATE_CTL: + case CS35L34_PRED_WAIT_CTL: + case CS35L34_PRED_ZVP_INIT_IMP_CTL: + case CS35L34_PRED_MAN_SAFE_VPI_CTL: + case CS35L34_VPBR_ATTEN_STATUS: + case CS35L34_PRED_BRWNOUT_ATT_STATUS: + case CS35L34_SPKR_MON_CTL: + case CS35L34_ADSP_I2S_CTL: + case CS35L34_ADSP_TDM_CTL: + case CS35L34_TDM_TX_CTL_1_VMON: + case CS35L34_TDM_TX_CTL_2_IMON: + case CS35L34_TDM_TX_CTL_3_VPMON: + case CS35L34_TDM_TX_CTL_4_VBSTMON: + case CS35L34_TDM_TX_CTL_5_FLAG1: + case CS35L34_TDM_TX_CTL_6_FLAG2: + case CS35L34_TDM_TX_SLOT_EN_1: + case CS35L34_TDM_TX_SLOT_EN_2: + case CS35L34_TDM_TX_SLOT_EN_3: + case CS35L34_TDM_TX_SLOT_EN_4: + case CS35L34_TDM_RX_CTL_1_AUDIN: + case CS35L34_TDM_RX_CTL_3_ALIVE: + case CS35L34_MULT_DEV_SYNCH1: + case CS35L34_MULT_DEV_SYNCH2: + case CS35L34_PROT_RELEASE_CTL: + case CS35L34_DIAG_MODE_REG_LOCK: + case CS35L34_DIAG_MODE_CTL_1: + case CS35L34_DIAG_MODE_CTL_2: + case CS35L34_INT_MASK_1: + case CS35L34_INT_MASK_2: + case CS35L34_INT_MASK_3: + case CS35L34_INT_MASK_4: + case CS35L34_INT_STATUS_1: + case CS35L34_INT_STATUS_2: + case CS35L34_INT_STATUS_3: + case CS35L34_INT_STATUS_4: + case CS35L34_OTP_TRIM_STATUS: + return true; + default: + return false; + } +} + +static bool cs35l34_precious_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L34_INT_STATUS_1: + case CS35L34_INT_STATUS_2: + case CS35L34_INT_STATUS_3: + case CS35L34_INT_STATUS_4: + return true; + default: + return false; + } +} + +static int cs35l34_sdin_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (priv->tdm_mode) + regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, + CS35L34_PDN_TDM, 0x00); + + ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, 0); + if (ret < 0) { + dev_err(codec->dev, "Cannot set Power bits %d\n", ret); + return ret; + } + usleep_range(5000, 5100); + break; + case SND_SOC_DAPM_POST_PMD: + if (priv->tdm_mode) { + regmap_update_bits(priv->regmap, CS35L34_PWRCTL3, + CS35L34_PDN_TDM, CS35L34_PDN_TDM); + } + ret = regmap_update_bits(priv->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, CS35L34_PDN_ALL); + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static int cs35l34_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + unsigned int reg, bit_pos; + int slot, slot_num; + + if (slot_width != 8) + return -EINVAL; + + priv->tdm_mode = true; + /* scan rx_mask for aud slot */ + slot = ffs(rx_mask) - 1; + if (slot >= 0) + snd_soc_update_bits(codec, CS35L34_TDM_RX_CTL_1_AUDIN, + CS35L34_X_LOC, slot); + + /* scan tx_mask: vmon(2 slots); imon (2 slots); vpmon (1 slot) + * vbstmon (1 slot) + */ + slot = ffs(tx_mask) - 1; + slot_num = 0; + + /* disable vpmon/vbstmon: enable later if set in tx_mask */ + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON, + CS35L34_X_STATE | CS35L34_X_LOC, + CS35L34_X_STATE | CS35L34_X_LOC); + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_4_VBSTMON, + CS35L34_X_STATE | CS35L34_X_LOC, + CS35L34_X_STATE | CS35L34_X_LOC); + + /* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/ + while (slot >= 0) { + /* configure VMON_TX_LOC */ + if (slot_num == 0) + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_1_VMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + + /* configure IMON_TX_LOC */ + if (slot_num == 4) { + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_2_IMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + } + /* configure VPMON_TX_LOC */ + if (slot_num == 3) { + snd_soc_update_bits(codec, CS35L34_TDM_TX_CTL_3_VPMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + } + /* configure VBSTMON_TX_LOC */ + if (slot_num == 7) { + snd_soc_update_bits(codec, + CS35L34_TDM_TX_CTL_4_VBSTMON, + CS35L34_X_STATE | CS35L34_X_LOC, slot); + } + + /* Enable the relevant tx slot */ + reg = CS35L34_TDM_TX_SLOT_EN_4 - (slot/8); + bit_pos = slot - ((slot / 8) * (8)); + snd_soc_update_bits(codec, reg, + 1 << bit_pos, 1 << bit_pos); + + tx_mask &= ~(1 << slot); + slot = ffs(tx_mask) - 1; + slot_num++; + } + + return 0; +} + +static int cs35l34_main_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, + CS35L34_BST_CVTL_MASK, priv->pdata.boost_vtge); + usleep_range(5000, 5100); + regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, + CS35L34_MUTE, 0); + break; + case SND_SOC_DAPM_POST_PMD: + regmap_update_bits(priv->regmap, CS35L34_BST_CVTR_V_CTL, + CS35L34_BST_CVTL_MASK, 0); + regmap_update_bits(priv->regmap, CS35L34_PROTECT_CTL, + CS35L34_MUTE, CS35L34_MUTE); + usleep_range(5000, 5100); + break; + default: + pr_err("Invalid event = 0x%x\n", event); + } + return 0; +} + +static DECLARE_TLV_DB_SCALE(dig_vol_tlv, -10200, 50, 0); + +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 300, 100, 0); + + +static const struct snd_kcontrol_new cs35l34_snd_controls[] = { + SOC_SINGLE_SX_TLV("Digital Volume", CS35L34_AMP_DIG_VOL, + 0, 0x34, 0xE4, dig_vol_tlv), + SOC_SINGLE_TLV("Amp Gain Volume", CS35L34_AMP_ANLG_GAIN_CTL, + 0, 0xF, 0, amp_gain_tlv), +}; + + +static int cs35l34_mclk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + int ret, i; + unsigned int reg; + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + ret = regmap_read(priv->regmap, CS35L34_AMP_DIG_VOL_CTL, + ®); + if (ret != 0) { + pr_err("%s regmap read failure %d\n", __func__, ret); + return ret; + } + if (reg & CS35L34_AMP_DIGSFT) + msleep(40); + else + usleep_range(2000, 2100); + + for (i = 0; i < PDN_DONE_ATTEMPTS; i++) { + ret = regmap_read(priv->regmap, CS35L34_INT_STATUS_2, + ®); + if (ret != 0) { + pr_err("%s regmap read failure %d\n", + __func__, ret); + return ret; + } + if (reg & CS35L34_PDN_DONE) + break; + + usleep_range(5000, 5100); + } + if (i == PDN_DONE_ATTEMPTS) + pr_err("%s Device did not power down properly\n", + __func__); + break; + default: + pr_err("Invalid event = 0x%x\n", event); + break; + } + return 0; +} + +static const struct snd_soc_dapm_widget cs35l34_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L34_PWRCTL3, + 1, 1, cs35l34_sdin_event, + SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L34_PWRCTL3, 2, 1), + + SND_SOC_DAPM_SUPPLY("EXTCLK", CS35L34_PWRCTL3, 7, 1, + cs35l34_mclk_event, SND_SOC_DAPM_PRE_PMD), + + SND_SOC_DAPM_OUTPUT("SPK"), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VPST"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L34_PWRCTL2, 7, 1), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L34_PWRCTL2, 6, 1), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L34_PWRCTL3, 3, 1), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L34_PWRCTL3, 4, 1), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L34_PWRCTL2, 5, 1), + SND_SOC_DAPM_ADC("BOOST", NULL, CS35L34_PWRCTL2, 2, 1), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L34_PWRCTL2, 0, 1, NULL, 0, + cs35l34_main_amp_event, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), +}; + +static const struct snd_soc_dapm_route cs35l34_audio_map[] = { + {"SDIN", NULL, "AMP Playback"}, + {"BOOST", NULL, "SDIN"}, + {"CLASS H", NULL, "BOOST"}, + {"Main AMP", NULL, "CLASS H"}, + {"SPK", NULL, "Main AMP"}, + + {"VPMON ADC", NULL, "CLASS H"}, + {"VBSTMON ADC", NULL, "CLASS H"}, + {"SPK", NULL, "VPMON ADC"}, + {"SPK", NULL, "VBSTMON ADC"}, + + {"IMON ADC", NULL, "ISENSE"}, + {"VMON ADC", NULL, "VSENSE"}, + {"SDOUT", NULL, "IMON ADC"}, + {"SDOUT", NULL, "VMON ADC"}, + {"AMP Capture", NULL, "SDOUT"}, + + {"SDIN", NULL, "EXTCLK"}, + {"SDOUT", NULL, "EXTCLK"}, +}; + +struct cs35l34_mclk_div { + int mclk; + int srate; + u8 adsp_rate; +}; + +static struct cs35l34_mclk_div cs35l34_mclk_coeffs[] = { + + /* MCLK, Sample Rate, adsp_rate */ + + {5644800, 11025, 0x1}, + {5644800, 22050, 0x4}, + {5644800, 44100, 0x7}, + + {6000000, 8000, 0x0}, + {6000000, 11025, 0x1}, + {6000000, 12000, 0x2}, + {6000000, 16000, 0x3}, + {6000000, 22050, 0x4}, + {6000000, 24000, 0x5}, + {6000000, 32000, 0x6}, + {6000000, 44100, 0x7}, + {6000000, 48000, 0x8}, + + {6144000, 8000, 0x0}, + {6144000, 11025, 0x1}, + {6144000, 12000, 0x2}, + {6144000, 16000, 0x3}, + {6144000, 22050, 0x4}, + {6144000, 24000, 0x5}, + {6144000, 32000, 0x6}, + {6144000, 44100, 0x7}, + {6144000, 48000, 0x8}, +}; + +static int cs35l34_get_mclk_coeff(int mclk, int srate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l34_mclk_coeffs); i++) { + if (cs35l34_mclk_coeffs[i].mclk == mclk && + cs35l34_mclk_coeffs[i].srate == srate) + return i; + } + return -EINVAL; +} + +static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, + 0x80, 0x80); + break; + case SND_SOC_DAIFMT_CBS_CFS: + regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, + 0x80, 0x00); + break; + default: + return -EINVAL; + } + return 0; +} + +static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l34_private *priv = snd_soc_codec_get_drvdata(codec); + int srate = params_rate(params); + int ret; + + int coeff = cs35l34_get_mclk_coeff(priv->mclk_int, srate); + + if (coeff < 0) { + dev_err(codec->dev, "ERROR: Invalid mclk %d and/or srate %d\n", + priv->mclk_int, srate); + return coeff; + } + + ret = regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, + CS35L34_ADSP_RATE, cs35l34_mclk_coeffs[coeff].adsp_rate); + if (ret != 0) + dev_err(codec->dev, "Failed to set clock state %d\n", ret); + + return ret; +} + +static unsigned int cs35l34_src_rates[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + + +static struct snd_pcm_hw_constraint_list cs35l34_constraints = { + .count = ARRAY_SIZE(cs35l34_src_rates), + .list = cs35l34_src_rates, +}; + +static int cs35l34_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + + snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &cs35l34_constraints); + return 0; +} + + +static int cs35l34_set_tristate(struct snd_soc_dai *dai, int tristate) +{ + + struct snd_soc_codec *codec = dai->codec; + + if (tristate) + snd_soc_update_bits(codec, CS35L34_PWRCTL3, + CS35L34_PDN_SDOUT, CS35L34_PDN_SDOUT); + else + snd_soc_update_bits(codec, CS35L34_PWRCTL3, + CS35L34_PDN_SDOUT, 0); + return 0; +} + +static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec); + unsigned int value; + + switch (freq) { + case CS35L34_MCLK_5644: + value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_5P6448; + cs35l34->mclk_int = freq; + break; + case CS35L34_MCLK_6: + value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_6P0000; + cs35l34->mclk_int = freq; + break; + case CS35L34_MCLK_6144: + value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_6P1440; + cs35l34->mclk_int = freq; + break; + case CS35L34_MCLK_11289: + value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_5P6448; + cs35l34->mclk_int = freq / 2; + break; + case CS35L34_MCLK_12: + value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P0000; + cs35l34->mclk_int = freq / 2; + break; + case CS35L34_MCLK_12288: + value = CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_6P1440; + cs35l34->mclk_int = freq / 2; + break; + default: + dev_err(codec->dev, "ERROR: Invalid Frequency %d\n", freq); + cs35l34->mclk_int = 0; + return -EINVAL; + } + regmap_update_bits(cs35l34->regmap, CS35L34_MCLK_CTL, + CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK, value); + return 0; +} + +static const struct snd_soc_dai_ops cs35l34_ops = { + .startup = cs35l34_pcm_startup, + .set_tristate = cs35l34_set_tristate, + .set_fmt = cs35l34_set_dai_fmt, + .hw_params = cs35l34_pcm_hw_params, + .set_sysclk = cs35l34_dai_set_sysclk, + .set_tdm_slot = cs35l34_set_tdm_slot, +}; + +static struct snd_soc_dai_driver cs35l34_dai = { + .name = "cs35l34", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 8, + .rates = CS35L34_RATES, + .formats = CS35L34_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = CS35L34_RATES, + .formats = CS35L34_FORMATS, + }, + .ops = &cs35l34_ops, + .symmetric_rates = 1, +}; + +static int cs35l34_boost_inductor(struct cs35l34_private *cs35l34, + unsigned int inductor) +{ + struct snd_soc_codec *codec = cs35l34->codec; + + switch (inductor) { + case 1000: /* 1 uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x24); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x24); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x4E); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 0); + break; + case 1200: /* 1.2 uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x47); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 1); + break; + case 1500: /* 1.5uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x20); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x3C); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 2); + break; + case 2200: /* 2.2uH */ + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_1, 0x19); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_COEF_2, 0x25); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SLOPE_COMP, + 0x23); + regmap_write(cs35l34->regmap, CS35L34_BST_CONV_SW_FREQ, 3); + break; + default: + dev_err(codec->dev, "%s Invalid Inductor Value %d uH\n", + __func__, inductor); + return -EINVAL; + } + return 0; +} + +static int cs35l34_probe(struct snd_soc_codec *codec) +{ + int ret = 0; + struct cs35l34_private *cs35l34 = snd_soc_codec_get_drvdata(codec); + + pm_runtime_get_sync(codec->dev); + + /* Set over temperature warning attenuation to 6 dB */ + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_OTW_ATTN_MASK, 0x8); + + /* Set Power control registers 2 and 3 to have everything + * powered down at initialization + */ + regmap_write(cs35l34->regmap, CS35L34_PWRCTL2, 0xFD); + regmap_write(cs35l34->regmap, CS35L34_PWRCTL3, 0x1F); + + /* Set mute bit at startup */ + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_MUTE, CS35L34_MUTE); + + /* Set Platform Data */ + if (cs35l34->pdata.boost_peak) + regmap_update_bits(cs35l34->regmap, CS35L34_BST_PEAK_I, + CS35L34_BST_PEAK_MASK, + cs35l34->pdata.boost_peak); + + if (cs35l34->pdata.gain_zc_disable) + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_GAIN_ZC_MASK, 0); + else + regmap_update_bits(cs35l34->regmap, CS35L34_PROTECT_CTL, + CS35L34_GAIN_ZC_MASK, CS35L34_GAIN_ZC_MASK); + + if (cs35l34->pdata.aif_half_drv) + regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_CLK_CTL, + CS35L34_ADSP_DRIVE, 0); + + if (cs35l34->pdata.digsft_disable) + regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, + CS35L34_AMP_DIGSFT, 0); + + if (cs35l34->pdata.amp_inv) + regmap_update_bits(cs35l34->regmap, CS35L34_AMP_DIG_VOL_CTL, + CS35L34_INV, CS35L34_INV); + + if (cs35l34->pdata.boost_ind) + ret = cs35l34_boost_inductor(cs35l34, cs35l34->pdata.boost_ind); + + if (cs35l34->pdata.i2s_sdinloc) + regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_I2S_CTL, + CS35L34_I2S_LOC_MASK, + cs35l34->pdata.i2s_sdinloc << CS35L34_I2S_LOC_SHIFT); + + if (cs35l34->pdata.tdm_rising_edge) + regmap_update_bits(cs35l34->regmap, CS35L34_ADSP_TDM_CTL, + 1, 1); + + pm_runtime_put_sync(codec->dev); + + return ret; +} + + +static struct snd_soc_codec_driver soc_codec_dev_cs35l34 = { + .probe = cs35l34_probe, + + .component_driver = { + .dapm_widgets = cs35l34_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l34_dapm_widgets), + .dapm_routes = cs35l34_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l34_audio_map), + .controls = cs35l34_snd_controls, + .num_controls = ARRAY_SIZE(cs35l34_snd_controls), + }, +}; + +static struct regmap_config cs35l34_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS35L34_MAX_REGISTER, + .reg_defaults = cs35l34_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l34_reg), + .volatile_reg = cs35l34_volatile_register, + .readable_reg = cs35l34_readable_register, + .precious_reg = cs35l34_precious_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs35l34_handle_of_data(struct i2c_client *i2c_client, + struct cs35l34_platform_data *pdata) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + + if (of_property_read_u32(np, "cirrus,boost-vtge-millivolt", + &val) >= 0) { + /* Boost Voltage has a maximum of 8V */ + if (val > 8000 || (val < 3300 && val > 0)) { + dev_err(&i2c_client->dev, + "Invalid Boost Voltage %d mV\n", val); + return -EINVAL; + } + if (val == 0) + pdata->boost_vtge = 0; /* Use VP */ + else + pdata->boost_vtge = ((val - 3300)/100) + 1; + } else { + dev_warn(&i2c_client->dev, + "Boost Voltage not specified. Using VP\n"); + } + + if (of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val) >= 0) { + pdata->boost_ind = val; + } else { + dev_err(&i2c_client->dev, "Inductor not specified.\n"); + return -EINVAL; + } + + if (of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val) >= 0) { + if (val > 3840 || val < 1200) { + dev_err(&i2c_client->dev, + "Invalid Boost Peak Current %d mA\n", val); + return -EINVAL; + } + pdata->boost_peak = ((val - 1200)/80) + 1; + } + + pdata->aif_half_drv = of_property_read_bool(np, + "cirrus,aif-half-drv"); + pdata->digsft_disable = of_property_read_bool(np, + "cirrus,digsft-disable"); + + pdata->gain_zc_disable = of_property_read_bool(np, + "cirrus,gain-zc-disable"); + pdata->amp_inv = of_property_read_bool(np, "cirrus,amp-inv"); + + if (of_property_read_u32(np, "cirrus,i2s-sdinloc", &val) >= 0) + pdata->i2s_sdinloc = val; + if (of_property_read_u32(np, "cirrus,tdm-rising-edge", &val) >= 0) + pdata->tdm_rising_edge = val; + + return 0; +} + +static irqreturn_t cs35l34_irq_thread(int irq, void *data) +{ + struct cs35l34_private *cs35l34 = data; + struct snd_soc_codec *codec = cs35l34->codec; + unsigned int sticky1, sticky2, sticky3, sticky4; + unsigned int mask1, mask2, mask3, mask4, current1; + + + /* ack the irq by reading all status registers */ + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_4, &sticky4); + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_3, &sticky3); + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_2, &sticky2); + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, &sticky1); + + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_4, &mask4); + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_3, &mask3); + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_2, &mask2); + regmap_read(cs35l34->regmap, CS35L34_INT_MASK_1, &mask1); + + if (!(sticky1 & ~mask1) && !(sticky2 & ~mask2) && !(sticky3 & ~mask3) + && !(sticky4 & ~mask4)) + return IRQ_NONE; + + regmap_read(cs35l34->regmap, CS35L34_INT_STATUS_1, ¤t1); + + if (sticky1 & CS35L34_CAL_ERR) { + dev_err(codec->dev, "Cal error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_CAL_ERR)) { + dev_dbg(codec->dev, "Cal error release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_CAL_ERR_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_CAL_ERR_RLS, + CS35L34_CAL_ERR_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_CAL_ERR_RLS, 0); + /* note: amp will re-calibrate on next resume */ + } + } + + if (sticky1 & CS35L34_ALIVE_ERR) + dev_err(codec->dev, "Alive error\n"); + + if (sticky1 & CS35L34_AMP_SHORT) { + dev_crit(codec->dev, "Amp short error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_AMP_SHORT)) { + dev_dbg(codec->dev, + "Amp short error release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_SHORT_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_SHORT_RLS, + CS35L34_SHORT_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_SHORT_RLS, 0); + } + } + + if (sticky1 & CS35L34_OTW) { + dev_crit(codec->dev, "Over temperature warning\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_OTW)) { + dev_dbg(codec->dev, + "Over temperature warning release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTW_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTW_RLS, + CS35L34_OTW_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTW_RLS, 0); + } + } + + if (sticky1 & CS35L34_OTE) { + dev_crit(codec->dev, "Over temperature error\n"); + + /* error is no longer asserted; safe to reset */ + if (!(current1 & CS35L34_OTE)) { + dev_dbg(codec->dev, + "Over temperature error release\n"); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTE_RLS, 0); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTE_RLS, + CS35L34_OTE_RLS); + regmap_update_bits(cs35l34->regmap, + CS35L34_PROT_RELEASE_CTL, + CS35L34_OTE_RLS, 0); + } + } + + if (sticky3 & CS35L34_BST_HIGH) { + dev_crit(codec->dev, "VBST too high error; powering off!\n"); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, + CS35L34_PDN_AMP, CS35L34_PDN_AMP); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, CS35L34_PDN_ALL); + } + + if (sticky3 & CS35L34_LBST_SHORT) { + dev_crit(codec->dev, "LBST short error; powering off!\n"); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL2, + CS35L34_PDN_AMP, CS35L34_PDN_AMP); + regmap_update_bits(cs35l34->regmap, CS35L34_PWRCTL1, + CS35L34_PDN_ALL, CS35L34_PDN_ALL); + } + + return IRQ_HANDLED; +} + +static const char * const cs35l34_core_supplies[] = { + "VA", + "VP", +}; + +static int cs35l34_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs35l34_private *cs35l34; + struct cs35l34_platform_data *pdata = + dev_get_platdata(&i2c_client->dev); + int i; + int ret; + unsigned int devid = 0; + unsigned int reg; + + cs35l34 = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l34_private), + GFP_KERNEL); + if (!cs35l34) { + dev_err(&i2c_client->dev, "could not allocate codec\n"); + return -ENOMEM; + } + + i2c_set_clientdata(i2c_client, cs35l34); + cs35l34->regmap = devm_regmap_init_i2c(i2c_client, &cs35l34_regmap); + if (IS_ERR(cs35l34->regmap)) { + ret = PTR_ERR(cs35l34->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + cs35l34->num_core_supplies = ARRAY_SIZE(cs35l34_core_supplies); + for (i = 0; i < ARRAY_SIZE(cs35l34_core_supplies); i++) + cs35l34->core_supplies[i].supply = cs35l34_core_supplies[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + cs35l34->num_core_supplies, + cs35l34->core_supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request core supplies %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable core supplies: %d\n", ret); + return ret; + } + + if (pdata) { + cs35l34->pdata = *pdata; + } else { + pdata = devm_kzalloc(&i2c_client->dev, + sizeof(struct cs35l34_platform_data), + GFP_KERNEL); + if (!pdata) { + dev_err(&i2c_client->dev, + "could not allocate pdata\n"); + return -ENOMEM; + } + if (i2c_client->dev.of_node) { + ret = cs35l34_handle_of_data(i2c_client, pdata); + if (ret != 0) + return ret; + + } + cs35l34->pdata = *pdata; + } + + ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, + cs35l34_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs35l34", cs35l34); + if (ret != 0) + dev_err(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); + + cs35l34->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset-gpios", GPIOD_OUT_LOW); + if (IS_ERR(cs35l34->reset_gpio)) + return PTR_ERR(cs35l34->reset_gpio); + + gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); + + msleep(CS35L34_START_DELAY); + + ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_AB, ®); + + devid = (reg & 0xFF) << 12; + ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + ret = regmap_read(cs35l34->regmap, CS35L34_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS35L34_CHIP_ID) { + dev_err(&i2c_client->dev, + "CS35l34 Device ID (%X). Expected ID %X\n", + devid, CS35L34_CHIP_ID); + ret = -ENODEV; + goto err_regulator; + } + + ret = regmap_read(cs35l34->regmap, CS35L34_REV_ID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + goto err_regulator; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS35l34 (%x), Revision: %02X\n", devid, + reg & 0xFF); + + /* Unmask critical interrupts */ + regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_1, + CS35L34_M_CAL_ERR | CS35L34_M_ALIVE_ERR | + CS35L34_M_AMP_SHORT | CS35L34_M_OTW | + CS35L34_M_OTE, 0); + regmap_update_bits(cs35l34->regmap, CS35L34_INT_MASK_3, + CS35L34_M_BST_HIGH | CS35L34_M_LBST_SHORT, 0); + + pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100); + pm_runtime_use_autosuspend(&i2c_client->dev); + pm_runtime_set_active(&i2c_client->dev); + pm_runtime_enable(&i2c_client->dev); + + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs35l34, &cs35l34_dai, 1); + if (ret < 0) { + dev_err(&i2c_client->dev, + "%s: Register codec failed\n", __func__); + goto err_regulator; + } + + return 0; + +err_regulator: + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return ret; +} + +static int cs35l34_i2c_remove(struct i2c_client *client) +{ + struct cs35l34_private *cs35l34 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + + if (cs35l34->reset_gpio) + gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + + pm_runtime_disable(&client->dev); + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return 0; +} + +static int __maybe_unused cs35l34_runtime_resume(struct device *dev) +{ + struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + int ret; + + ret = regulator_bulk_enable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + if (ret != 0) { + dev_err(dev, "Failed to enable core supplies: %d\n", + ret); + return ret; + } + + regcache_cache_only(cs35l34->regmap, false); + + gpiod_set_value_cansleep(cs35l34->reset_gpio, 1); + msleep(CS35L34_START_DELAY); + + ret = regcache_sync(cs35l34->regmap); + if (ret != 0) { + dev_err(dev, "Failed to restore register cache\n"); + goto err; + } + return 0; +err: + regcache_cache_only(cs35l34->regmap, true); + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return ret; +} + +static int __maybe_unused cs35l34_runtime_suspend(struct device *dev) +{ + struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); + + regcache_cache_only(cs35l34->regmap, true); + regcache_mark_dirty(cs35l34->regmap); + + gpiod_set_value_cansleep(cs35l34->reset_gpio, 0); + + regulator_bulk_disable(cs35l34->num_core_supplies, + cs35l34->core_supplies); + + return 0; +} + +static const struct dev_pm_ops cs35l34_pm_ops = { + SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend, + cs35l34_runtime_resume, + NULL) +}; + +static const struct of_device_id cs35l34_of_match[] = { + {.compatible = "cirrus,cs35l34"}, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l34_of_match); + +static const struct i2c_device_id cs35l34_id[] = { + {"cs35l34", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, cs35l34_id); + +static struct i2c_driver cs35l34_i2c_driver = { + .driver = { + .name = "cs35l34", + .pm = &cs35l34_pm_ops, + .of_match_table = cs35l34_of_match, + + }, + .id_table = cs35l34_id, + .probe = cs35l34_i2c_probe, + .remove = cs35l34_i2c_remove, + +}; + +static int __init cs35l34_modinit(void) +{ + int ret; + + ret = i2c_add_driver(&cs35l34_i2c_driver); + if (ret != 0) { + pr_err("Failed to register CS35l34 I2C driver: %d\n", ret); + return ret; + } + return 0; +} +module_init(cs35l34_modinit); + +static void __exit cs35l34_exit(void) +{ + i2c_del_driver(&cs35l34_i2c_driver); +} +module_exit(cs35l34_exit); + +MODULE_DESCRIPTION("ASoC CS35l34 driver"); +MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs35l34.h b/sound/soc/codecs/cs35l34.h new file mode 100644 index 000000000000..bcd54f127559 --- /dev/null +++ b/sound/soc/codecs/cs35l34.h @@ -0,0 +1,269 @@ +/* + * cs35l34.h -- CS35L34 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: Paul Handrigan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS35L34_H__ +#define __CS35L34_H__ + +#define CS35L34_CHIP_ID 0x00035A34 +#define CS35L34_DEVID_AB 0x01 /* Device ID A & B [RO] */ +#define CS35L34_DEVID_CD 0x02 /* Device ID C & D [RO] */ +#define CS35L34_DEVID_E 0x03 /* Device ID E [RO] */ +#define CS35L34_FAB_ID 0x04 /* Fab ID [RO] */ +#define CS35L34_REV_ID 0x05 /* Revision ID [RO] */ +#define CS35L34_PWRCTL1 0x06 /* Power Ctl 1 */ +#define CS35L34_PWRCTL2 0x07 /* Power Ctl 2 */ +#define CS35L34_PWRCTL3 0x08 /* Power Ctl 3 */ +#define CS35L34_ADSP_CLK_CTL 0x0A /* (ADSP) Clock Ctl */ +#define CS35L34_MCLK_CTL 0x0B /* Master Clocking Ctl */ +#define CS35L34_AMP_INP_DRV_CTL 0x14 /* Amp Input Drive Ctl */ +#define CS35L34_AMP_DIG_VOL_CTL 0x15 /* Amplifier Dig Volume Ctl */ +#define CS35L34_AMP_DIG_VOL 0x16 /* Amplifier Dig Volume */ +#define CS35L34_AMP_ANLG_GAIN_CTL 0x17 /* Amplifier Analog Gain Ctl */ +#define CS35L34_PROTECT_CTL 0x18 /* Amp Gain - Prot Ctl Param */ +#define CS35L34_AMP_KEEP_ALIVE_CTL 0x1A /* Amplifier Keep Alive Ctl */ +#define CS35L34_BST_CVTR_V_CTL 0x1D /* Boost Conv Voltage Ctl */ +#define CS35L34_BST_PEAK_I 0x1E /* Boost Conv Peak Current */ +#define CS35L34_BST_RAMP_CTL 0x20 /* Boost Conv Soft Ramp Ctl */ +#define CS35L34_BST_CONV_COEF_1 0x21 /* Boost Conv Coefficients 1 */ +#define CS35L34_BST_CONV_COEF_2 0x22 /* Boost Conv Coefficients 2 */ +#define CS35L34_BST_CONV_SLOPE_COMP 0x23 /* Boost Conv Slope Comp */ +#define CS35L34_BST_CONV_SW_FREQ 0x24 /* Boost Conv L BST SW Freq */ +#define CS35L34_CLASS_H_CTL 0x30 /* CLS H Control */ +#define CS35L34_CLASS_H_HEADRM_CTL 0x31 /* CLS H Headroom Ctl */ +#define CS35L34_CLASS_H_RELEASE_RATE 0x32 /* CLS H Release Rate */ +#define CS35L34_CLASS_H_FET_DRIVE_CTL 0x33 /* CLS H Weak FET Drive Ctl */ +#define CS35L34_CLASS_H_STATUS 0x38 /* CLS H Status */ +#define CS35L34_VPBR_CTL 0x3A /* VPBR Ctl */ +#define CS35L34_VPBR_VOL_CTL 0x3B /* VPBR Volume Ctl */ +#define CS35L34_VPBR_TIMING_CTL 0x3C /* VPBR Timing Ctl */ +#define CS35L34_PRED_MAX_ATTEN_SPK_LOAD 0x40 /* PRD Max Atten / Spkr Load */ +#define CS35L34_PRED_BROWNOUT_THRESH 0x41 /* PRD Brownout Threshold */ +#define CS35L34_PRED_BROWNOUT_VOL_CTL 0x42 /* PRD Brownout Volume Ctl */ +#define CS35L34_PRED_BROWNOUT_RATE_CTL 0x43 /* PRD Brownout Rate Ctl */ +#define CS35L34_PRED_WAIT_CTL 0x44 /* PRD Wait Ctl */ +#define CS35L34_PRED_ZVP_INIT_IMP_CTL 0x46 /* PRD ZVP Initial Imp Ctl */ +#define CS35L34_PRED_MAN_SAFE_VPI_CTL 0x47 /* PRD Manual Safe VPI Ctl */ +#define CS35L34_VPBR_ATTEN_STATUS 0x4B /* VPBR Attenuation Status */ +#define CS35L34_PRED_BRWNOUT_ATT_STATUS 0x4C /* PRD Brownout Atten Status */ +#define CS35L34_SPKR_MON_CTL 0x4E /* Speaker Monitoring Ctl */ +#define CS35L34_ADSP_I2S_CTL 0x50 /* ADSP I2S Ctl */ +#define CS35L34_ADSP_TDM_CTL 0x51 /* ADSP TDM Ctl */ +#define CS35L34_TDM_TX_CTL_1_VMON 0x52 /* TDM TX Ctl 1 (VMON) */ +#define CS35L34_TDM_TX_CTL_2_IMON 0x53 /* TDM TX Ctl 2 (IMON) */ +#define CS35L34_TDM_TX_CTL_3_VPMON 0x54 /* TDM TX Ctl 3 (VPMON) */ +#define CS35L34_TDM_TX_CTL_4_VBSTMON 0x55 /* TDM TX Ctl 4 (VBSTMON) */ +#define CS35L34_TDM_TX_CTL_5_FLAG1 0x56 /* TDM TX Ctl 5 (FLAG1) */ +#define CS35L34_TDM_TX_CTL_6_FLAG2 0x57 /* TDM TX Ctl 6 (FLAG2) */ +#define CS35L34_TDM_TX_SLOT_EN_1 0x5A /* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_2 0x5B /* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_3 0x5C /* TDM TX Slot Enable */ +#define CS35L34_TDM_TX_SLOT_EN_4 0x5D /* TDM TX Slot Enable */ +#define CS35L34_TDM_RX_CTL_1_AUDIN 0x5E /* TDM RX Ctl 1 */ +#define CS35L34_TDM_RX_CTL_3_ALIVE 0x60 /* TDM RX Ctl 3 (ALIVE) */ +#define CS35L34_MULT_DEV_SYNCH1 0x62 /* Multidevice Synch */ +#define CS35L34_MULT_DEV_SYNCH2 0x63 /* Multidevice Synch 2 */ +#define CS35L34_PROT_RELEASE_CTL 0x64 /* Protection Release Ctl */ +#define CS35L34_DIAG_MODE_REG_LOCK 0x68 /* Diagnostic Mode Reg Lock */ +#define CS35L34_DIAG_MODE_CTL_1 0x69 /* Diagnostic Mode Ctl 1 */ +#define CS35L34_DIAG_MODE_CTL_2 0x6A /* Diagnostic Mode Ctl 2 */ +#define CS35L34_INT_MASK_1 0x70 /* Interrupt Mask 1 */ +#define CS35L34_INT_MASK_2 0x71 /* Interrupt Mask 2 */ +#define CS35L34_INT_MASK_3 0x72 /* Interrupt Mask 3 */ +#define CS35L34_INT_MASK_4 0x73 /* Interrupt Mask 4 */ +#define CS35L34_INT_STATUS_1 0x74 /* Interrupt Status 1 */ +#define CS35L34_INT_STATUS_2 0x75 /* Interrupt Status 2 */ +#define CS35L34_INT_STATUS_3 0x76 /* Interrupt Status 3 */ +#define CS35L34_INT_STATUS_4 0x77 /* Interrupt Status 4 */ +#define CS35L34_OTP_TRIM_STATUS 0x7E /* OTP Trim Status */ + +#define CS35L34_MAX_REGISTER 0x7F +#define CS35L34_REGISTER_COUNT 0x4E + +#define CS35L34_MCLK_5644 5644800 +#define CS35L34_MCLK_6144 6144000 +#define CS35L34_MCLK_6 6000000 +#define CS35L34_MCLK_11289 11289600 +#define CS35L34_MCLK_12 12000000 +#define CS35L34_MCLK_12288 12288000 + +/* CS35L34_PWRCTL1 */ +#define CS35L34_SFT_RST (1 << 7) +#define CS35L34_DISCHG_FLT (1 << 1) +#define CS35L34_PDN_ALL 1 + +/* CS35L34_PWRCTL2 */ +#define CS35L34_PDN_VMON (1 << 7) +#define CS35L34_PDN_IMON (1 << 6) +#define CS35L34_PDN_CLASSH (1 << 5) +#define CS35L34_PDN_VPBR (1 << 4) +#define CS35L34_PDN_PRED (1 << 3) +#define CS35L34_PDN_BST (1 << 2) +#define CS35L34_PDN_AMP 1 + +/* CS35L34_PWRCTL3 */ +#define CS35L34_MCLK_DIS (1 << 7) +#define CS35L34_PDN_VBSTMON_OUT (1 << 4) +#define CS35L34_PDN_VMON_OUT (1 << 3) +/* Tristate the ADSP SDOUT when in I2C mode */ +#define CS35L34_PDN_SDOUT (1 << 2) +#define CS35L34_PDN_SDIN (1 << 1) +#define CS35L34_PDN_TDM 1 + +/* CS35L34_ADSP_CLK_CTL */ +#define CS35L34_ADSP_RATE 0xF +#define CS35L34_ADSP_DRIVE (1 << 4) +#define CS35L34_ADSP_M_S (1 << 7) + +/* CS35L34_MCLK_CTL */ +#define CS35L34_MCLK_DIV (1 << 4) +#define CS35L34_MCLK_RATE_MASK 0x7 +#define CS35L34_MCLK_RATE_6P1440 0x2 +#define CS35L34_MCLK_RATE_6P0000 0x1 +#define CS35L34_MCLK_RATE_5P6448 0x0 +#define CS35L34_MCLKDIS (1 << 7) +#define CS35L34_MCLKDIV2 (1 << 6) +#define CS35L34_SDOUT_3ST_TDM (1 << 5) +#define CS35L34_INT_FS_RATE (1 << 4) +#define CS35L34_ADSP_FS 0xF + +/* CS35L34_AMP_INP_DRV_CTL */ +#define CS35L34_DRV_STR_SRC (1 << 1) +#define CS35L34_DRV_STR 1 + +/* CS35L34_AMP_DIG_VOL_CTL */ +#define CS35L34_AMP_DSR_RATE_MASK 0xF0 +#define CS35L34_AMP_DSR_RATE_SHIFT (1 << 4) +#define CS35L34_NOTCH_DIS (1 << 3) +#define CS35L34_AMP_DIGSFT (1 << 1) +#define CS35L34_INV 1 + +/* CS35L34_PROTECT_CTL */ +#define CS35L34_OTW_ATTN_MASK 0xC +#define CS35L34_OTW_THRD_MASK 0x3 +#define CS35L34_MUTE (1 << 5) +#define CS35L34_GAIN_ZC (1 << 4) +#define CS35L34_GAIN_ZC_MASK 0x10 +#define CS35L34_GAIN_ZC_SHIFT 4 + +/* CS35L34_AMP_KEEP_ALIVE_CTL */ +#define CS35L34_ALIVE_WD_DIS (1 << 2) + +/* CS35L34_BST_CVTR_V_CTL */ +#define CS35L34_BST_CVTL_MASK 0x3F + +/* CS35L34_BST_PEAK_I */ +#define CS35L34_BST_PEAK_MASK 0x3F + +/* CS35L34_ADSP_I2S_CTL */ +#define CS35L34_I2S_LOC_MASK 0xC +#define CS35L34_I2S_LOC_SHIFT 2 + +/* CS35L34_MULT_DEV_SYNCH2 */ +#define CS35L34_SYNC2_MASK 0xF + +/* CS35L34_PROT_RELEASE_CTL */ +#define CS35L34_CAL_ERR_RLS (1 << 7) +#define CS35L34_SHORT_RLS (1 << 2) +#define CS35L34_OTW_RLS (1 << 1) +#define CS35L34_OTE_RLS 1 + +/* CS35L34_INT_MASK_1 */ +#define CS35L34_M_CAL_ERR_SHIFT 7 +#define CS35L34_M_CAL_ERR (1 << CS35L34_M_CAL_ERR_SHIFT) +#define CS35L34_M_ALIVE_ERR_SHIFT 5 +#define CS35L34_M_ALIVE_ERR (1 << CS35L34_M_ALIVE_ERR_SHIFT) +#define CS35L34_M_ADSP_CLK_SHIFT 4 +#define CS35L34_M_ADSP_CLK_ERR (1 << CS35L34_M_ADSP_CLK_SHIFT) +#define CS35L34_M_MCLK_SHIFT 3 +#define CS35L34_M_MCLK_ERR (1 << CS35L34_M_MCLK_SHIFT) +#define CS35L34_M_AMP_SHORT_SHIFT 2 +#define CS35L34_M_AMP_SHORT (1 << CS35L34_M_AMP_SHORT_SHIFT) +#define CS35L34_M_OTW_SHIFT 1 +#define CS35L34_M_OTW (1 << CS35L34_M_OTW_SHIFT) +#define CS35L34_M_OTE_SHIFT 0 +#define CS35L34_M_OTE (1 << CS35L34_M_OTE_SHIFT) + +/* CS35L34_INT_MASK_2 */ +#define CS35L34_M_PDN_DONE_SHIFT 4 +#define CS35L34_M_PDN_DONE (1 << CS35L34_M_PDN_DONE_SHIFT) +#define CS35L34_M_PRED_SHIFT 3 +#define CS35L34_M_PRED_ERR (1 << CS35L34_M_PRED_SHIFT) +#define CS35L34_M_PRED_CLR_SHIFT 2 +#define CS35L34_M_PRED_CLR (1 << CS35L34_M_PRED_CLR_SHIFT) +#define CS35L34_M_VPBR_SHIFT 1 +#define CS35L34_M_VPBR_ERR (1 << CS35L34_M_VPBR_SHIFT) +#define CS35L34_M_VPBR_CLR_SHIFT 0 +#define CS35L34_M_VPBR_CLR (1 << CS35L34_M_VPBR_CLR_SHIFT) + +/* CS35L34_INT_MASK_3 */ +#define CS35L34_M_BST_HIGH_SHIFT 4 +#define CS35L34_M_BST_HIGH (1 << CS35L34_M_BST_HIGH_SHIFT) +#define CS35L34_M_BST_HIGH_FLAG_SHIFT 3 +#define CS35L34_M_BST_HIGH_FLAG (1 << CS35L34_M_BST_HIGH_FLAG_SHIFT) +#define CS35L34_M_BST_IPK_FLAG_SHIFT 2 +#define CS35L34_M_BST_IPK_FLAG (1 << CS35L34_M_BST_IPK_FLAG_SHIFT) +#define CS35L34_M_LBST_SHORT_SHIFT 0 +#define CS35L34_M_LBST_SHORT (1 << CS35L34_M_LBST_SHORT_SHIFT) + +/* CS35L34_INT_MASK_4 */ +#define CS35L34_M_VMON_OVFL_SHIFT 3 +#define CS35L34_M_VMON_OVFL (1 << CS35L34_M_VMON_OVFL_SHIFT) +#define CS35L34_M_IMON_OVFL_SHIFT 2 +#define CS35L34_M_IMON_OVFL (1 << CS35L34_M_IMON_OVFL_SHIFT) +#define CS35L34_M_VPMON_OVFL_SHIFT 1 +#define CS35L34_M_VPMON_OVFL (1 << CS35L34_M_VPMON_OVFL_SHIFT) +#define CS35L34_M_VBSTMON_OVFL_SHIFT 1 +#define CS35L34_M_VBSTMON_OVFL (1 << CS35L34_M_VBSTMON_OVFL_SHIFT) + +/* CS35L34_INT_1 */ +#define CS35L34_CAL_ERR (1 << CS35L34_M_CAL_ERR_SHIFT) +#define CS35L34_ALIVE_ERR (1 << CS35L34_M_ALIVE_ERR_SHIFT) +#define CS35L34_M_ADSP_CLK_ERR (1 << CS35L34_M_ADSP_CLK_SHIFT) +#define CS35L34_MCLK_ERR (1 << CS35L34_M_MCLK_SHIFT) +#define CS35L34_AMP_SHORT (1 << CS35L34_M_AMP_SHORT_SHIFT) +#define CS35L34_OTW (1 << CS35L34_M_OTW_SHIFT) +#define CS35L34_OTE (1 << CS35L34_M_OTE_SHIFT) + +/* CS35L34_INT_2 */ +#define CS35L34_PDN_DONE (1 << CS35L34_M_PDN_DONE_SHIFT) +#define CS35L34_PRED_ERR (1 << CS35L34_M_PRED_SHIFT) +#define CS35L34_PRED_CLR (1 << CS35L34_M_PRED_CLR_SHIFT) +#define CS35L34_VPBR_ERR (1 << CS35L34_M_VPBR_SHIFT) +#define CS35L34_VPBR_CLR (1 << CS35L34_M_VPBR_CLR_SHIFT) + +/* CS35L34_INT_3 */ +#define CS35L34_BST_HIGH (1 << CS35L34_M_BST_HIGH_SHIFT) +#define CS35L34_BST_HIGH_FLAG (1 << CS35L34_M_BST_HIGH_FLAG_SHIFT) +#define CS35L34_BST_IPK_FLAG (1 << CS35L34_M_BST_IPK_FLAG_SHIFT) +#define CS35L34_LBST_SHORT (1 << CS35L34_M_LBST_SHORT_SHIFT) + +/* CS35L34_INT_4 */ +#define CS35L34_VMON_OVFL (1 << CS35L34_M_VMON_OVFL_SHIFT) +#define CS35L34_IMON_OVFL (1 << CS35L34_M_IMON_OVFL_SHIFT) +#define CS35L34_VPMON_OVFL (1 << CS35L34_M_VPMON_OVFL_SHIFT) +#define CS35L34_VBSTMON_OVFL (1 << CS35L34_M_VBSTMON_OVFL_SHIFT) + +/* CS35L34_{RX,TX}_X */ +#define CS35L34_X_STATE_SHIFT 7 +#define CS35L34_X_STATE (1 << CS35L34_X_STATE_SHIFT) +#define CS35L34_X_LOC_SHIFT 0 +#define CS35L34_X_LOC (0x1F << CS35L34_X_LOC_SHIFT) + +#define CS35L34_RATES (SNDRV_PCM_RATE_48000 | \ + SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_32000) +#define CS35L34_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#endif -- cgit v1.2.3-59-g8ed1b From a31b466f9541048fd00e0d2d282091c5693d79d0 Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Tue, 4 Oct 2016 10:33:20 -0700 Subject: ASoC: Intel: report JACK_LINEOUT event This patch updates Jack type bitmask to include SND_JACK_LINEOUT while creating a new jack, so that LINEOUT events are reported properly. Signed-off-by: Sathyanarayana Nujella Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6532b8f0ab2f..865a21e557cc 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -130,8 +130,8 @@ static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) */ ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | - SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset, - NULL, 0); + SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, + &broxton_headset, NULL, 0); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; -- cgit v1.2.3-59-g8ed1b From 7e7e76bd5693dc940dfea7df9e7b58655f0eae00 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Mon, 3 Oct 2016 10:43:27 +0800 Subject: ASoC: Add jd function for rt5663. Add initial setting for rt5663 jd to irq. Signed-off-by: Jack Yu Signed-off-by: Mark Brown --- sound/soc/codecs/rt5663.c | 11 ++++++++++- sound/soc/codecs/rt5663.h | 10 ++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 01a18d88f1eb..f30e0b461602 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -3140,12 +3140,21 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); break; case CODEC_TYPE_RT5663: + regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, + RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); + regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, + RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); + regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, + RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, + RT5663_GPIO1_TYPE_MASK, RT5663_GPIO1_TYPE_EN); regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); msleep(20); regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, - RT5663_GP1_PIN_CONF_MASK, RT5663_GP1_PIN_CONF_OUTPUT); + RT5663_GP1_PIN_CONF_MASK | RT5663_SEL_GPIO1_MASK, + RT5663_GP1_PIN_CONF_OUTPUT | RT5663_SEL_GPIO1_EN); /* DACREF LDO control */ regmap_update_bits(rt5663->regmap, RT5663_DACREF_LDO, 0x3e0e, 0x3a0a); diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index 2cc8f28080f6..252c2761791e 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -996,11 +996,21 @@ #define RT5663_EN_IRQ_INLINE_NOR (0x1 << 3) #define RT5663_EN_IRQ_INLINE_BYP (0x0 << 3) +/* RT5663: GPIO Control 1 (0x00c0) */ +#define RT5663_GPIO1_TYPE_MASK (0x1 << 15) +#define RT5663_GPIO1_TYPE_SHIFT 15 +#define RT5663_GPIO1_TYPE_EN (0x1 << 15) +#define RT5663_GPIO1_TYPE_DIS (0x0 << 15) + /* RT5663: IRQ Control 1 (0x00c1) */ #define RT5663_EN_IRQ_JD1_MASK (0x1 << 6) #define RT5663_EN_IRQ_JD1_SHIFT 6 #define RT5663_EN_IRQ_JD1_EN (0x1 << 6) #define RT5663_EN_IRQ_JD1_DIS (0x0 << 6) +#define RT5663_SEL_GPIO1_MASK (0x1 << 2) +#define RT5663_SEL_GPIO1_SHIFT 6 +#define RT5663_SEL_GPIO1_EN (0x1 << 2) +#define RT5663_SEL_GPIO1_DIS (0x0 << 2) /* RT5663: Inline Command Function 2 (0x00dc) */ #define RT5663_PWR_MIC_DET_MASK (0x1) -- cgit v1.2.3-59-g8ed1b From b4f4f2eba4e8f717ccd1bb2a35c602ad00dcdfe0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 30 Sep 2016 19:27:29 +0200 Subject: ASoC: wm9712: Convert to regmap Currently the wm9712 driver still uses custom snd_soc_codec_driver IO callbacks. This has been deprecated for a while, so convert the wm9712 driver to use regmap for its IO. Signed-off-by: Lars-Peter Clausen Tested-by: Marek Vasut Acked-by: Marek Vasut Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/wm9712.c | 143 +++++++++++++++++++++++++--------------------- 2 files changed, 79 insertions(+), 65 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..f472254a575d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1057,6 +1057,7 @@ config SND_SOC_WM9705 config SND_SOC_WM9712 tristate + select REGMAP_AC97 config SND_SOC_WM9713 tristate diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 557709eac698..d2d0d2bb4412 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -32,31 +33,66 @@ struct wm9712_priv { struct mutex lock; }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg); -static int ac97_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int val); +static const struct reg_default wm9712_reg_defaults[] = { + { 0x02, 0x8000 }, + { 0x04, 0x8000 }, + { 0x06, 0x8000 }, + { 0x08, 0x0f0f }, + { 0x0a, 0xaaa0 }, + { 0x0c, 0xc008 }, + { 0x0e, 0x6808 }, + { 0x10, 0xe808 }, + { 0x12, 0xaaa0 }, + { 0x14, 0xad00 }, + { 0x16, 0x8000 }, + { 0x18, 0xe808 }, + { 0x1a, 0x3000 }, + { 0x1c, 0x8000 }, + { 0x20, 0x0000 }, + { 0x22, 0x0000 }, + { 0x26, 0x000f }, + { 0x28, 0x0605 }, + { 0x2a, 0x0410 }, + { 0x2c, 0xbb80 }, + { 0x2e, 0xbb80 }, + { 0x32, 0xbb80 }, + { 0x34, 0x2000 }, + { 0x4c, 0xf83e }, + { 0x4e, 0xffff }, + { 0x50, 0x0000 }, + { 0x52, 0x0000 }, + { 0x56, 0xf83e }, + { 0x58, 0x0008 }, + { 0x5c, 0x0000 }, + { 0x60, 0xb032 }, + { 0x62, 0x3e00 }, + { 0x64, 0x0000 }, + { 0x76, 0x0006 }, + { 0x78, 0x0001 }, + { 0x7a, 0x0000 }, +}; -/* - * WM9712 register cache - */ -static const u16 wm9712_reg[] = { - 0x6174, 0x8000, 0x8000, 0x8000, /* 6 */ - 0x0f0f, 0xaaa0, 0xc008, 0x6808, /* e */ - 0xe808, 0xaaa0, 0xad00, 0x8000, /* 16 */ - 0xe808, 0x3000, 0x8000, 0x0000, /* 1e */ - 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ - 0x0405, 0x0410, 0xbb80, 0xbb80, /* 2e */ - 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ - 0x0000, 0x2000, 0x0000, 0x0000, /* 3e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 46 */ - 0x0000, 0x0000, 0xf83e, 0xffff, /* 4e */ - 0x0000, 0x0000, 0x0000, 0xf83e, /* 56 */ - 0x0008, 0x0000, 0x0000, 0x0000, /* 5e */ - 0xb032, 0x3e00, 0x0000, 0x0000, /* 66 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ - 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ - 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ +static bool wm9712_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case AC97_REC_GAIN: + return true; + default: + return regmap_ac97_default_volatile(dev, reg); + } +} + +static const struct regmap_config wm9712_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x7e, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = wm9712_volatile_reg, + + .reg_defaults = wm9712_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm9712_reg_defaults), }; #define HPL_MIXER 0x0 @@ -488,35 +524,13 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { - struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || - reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || - reg == AC97_REC_GAIN) - return soc_ac97_ops->read(wm9712->ac97, reg); - else { - reg = reg >> 1; - - if (reg >= (ARRAY_SIZE(wm9712_reg))) - return -EIO; - - return cache[reg]; - } + return snd_soc_read(codec, reg); } static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { - struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - soc_ac97_ops->write(wm9712->ac97, reg, val); - reg = reg >> 1; - if (reg < (ARRAY_SIZE(wm9712_reg))) - cache[reg] = val; - - return 0; + return snd_soc_write(codec, reg, val); } static int ac97_prepare(struct snd_pcm_substream *substream, @@ -619,8 +633,7 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, static int wm9712_soc_resume(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - int i, ret; - u16 *cache = codec->reg_cache; + int ret; ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID, WM9712_VENDOR_ID_MASK); @@ -629,15 +642,8 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); - if (ret == 0) { - /* Sync reg_cache with the hardware after cold reset */ - for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i += 2) { - if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || - (i > 0x58 && i != 0x5c)) - continue; - soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]); - } - } + if (ret == 0) + regcache_sync(codec->component.regmap); return ret; } @@ -645,6 +651,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) static int wm9712_soc_probe(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); + struct regmap *regmap; int ret; wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID, @@ -655,16 +662,28 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) return ret; } + regmap = regmap_init_ac97(wm9712->ac97, &wm9712_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_free_ac97_codec; + } + + snd_soc_codec_init_regmap(codec, regmap); + /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); return 0; +err_free_ac97_codec: + snd_soc_free_ac97_codec(wm9712->ac97); + return ret; } static int wm9712_soc_remove(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(wm9712->ac97); return 0; } @@ -673,14 +692,8 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm9712 = { .probe = wm9712_soc_probe, .remove = wm9712_soc_remove, .resume = wm9712_soc_resume, - .read = ac97_read, - .write = ac97_write, .set_bias_level = wm9712_set_bias_level, .suspend_bias_off = true, - .reg_cache_size = ARRAY_SIZE(wm9712_reg), - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, - .reg_cache_default = wm9712_reg, .component_driver = { .controls = wm9712_snd_ac97_controls, -- cgit v1.2.3-59-g8ed1b From 7e845e76e656967366be04646d80d815e8704914 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 30 Sep 2016 19:27:30 +0200 Subject: ASoC: wm9712: Remove ac97_read/ac97_write wrappers Since the regmap conversion ac97_read/ac97_write are just simple wrappers around snd_soc_read/snd_soc_write. Use those instead directly and remove the wrappers. Also use snd_soc_update_bits() were appropriate. Signed-off-by: Lars-Peter Clausen Tested-by: Marek Vasut Acked-by: Marek Vasut Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index d2d0d2bb4412..20b2e8216336 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -521,53 +521,36 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { {"ROUT2", NULL, "Speaker PGA"}, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return snd_soc_read(codec, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - return snd_soc_write(codec, reg, val); -} - static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; int reg; - u16 vra; struct snd_pcm_runtime *runtime = substream->runtime; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = AC97_PCM_FRONT_DAC_RATE; else reg = AC97_PCM_LR_ADC_RATE; - return ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int ac97_aux_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - u16 vra, xsle; struct snd_pcm_runtime *runtime = substream->runtime; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); - xsle = ac97_read(codec, AC97_PCI_SID); - ac97_write(codec, AC97_PCI_SID, xsle | 0x8000); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1); + snd_soc_update_bits(codec, AC97_PCI_SID, 0x8000, 0x8000); if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) return -ENODEV; - return ac97_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); + return snd_soc_write(codec, AC97_PCM_SURR_DAC_RATE, runtime->rate); } #define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ @@ -619,12 +602,12 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - ac97_write(codec, AC97_POWERDOWN, 0x0000); + snd_soc_write(codec, AC97_POWERDOWN, 0x0000); break; case SND_SOC_BIAS_OFF: /* disable everything including AC link */ - ac97_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); - ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_write(codec, AC97_EXTENDED_MSTATUS, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); break; } return 0; @@ -671,7 +654,7 @@ static int wm9712_soc_probe(struct snd_soc_codec *codec) snd_soc_codec_init_regmap(codec, regmap); /* set alc mux to none */ - ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); + snd_soc_update_bits(codec, AC97_VIDEO, 0x3000, 0x3000); return 0; err_free_ac97_codec: -- cgit v1.2.3-59-g8ed1b From 7a4413d0dc964eecbed8dcb0e0d0b6e0aa9051f1 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 21 Oct 2016 14:15:57 +0100 Subject: ASoC: arizona: Add gating for clock when used for direct MCLK Whilst ultimately we would like to move all the clocking over to the clock framework, as an intermediate step to get people going for now gating the source clocks for SYSCLK/ASYNCCLK when they are configured to come directly from an MCLK pin. Signed-off-by: Charles Keepax Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 40 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 2 ++ sound/soc/codecs/cs47l24.c | 6 ++++-- sound/soc/codecs/wm5102.c | 9 +++++++-- sound/soc/codecs/wm5110.c | 10 +++++++--- sound/soc/codecs/wm8997.c | 9 +++++++-- sound/soc/codecs/wm8998.c | 6 ++++-- 7 files changed, 71 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 846ca079845f..10be50ae2f76 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1233,6 +1233,46 @@ static int arizona_set_opclk(struct snd_soc_codec *codec, unsigned int clk, return -EINVAL; } +int arizona_clk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + unsigned int val; + int clk_idx; + int ret; + + ret = regmap_read(arizona->regmap, w->reg, &val); + if (ret) { + dev_err(codec->dev, "Failed to check clock source: %d\n", ret); + return ret; + } + + val = (val & ARIZONA_SYSCLK_SRC_MASK) >> ARIZONA_SYSCLK_SRC_SHIFT; + + switch (val) { + case ARIZONA_CLK_SRC_MCLK1: + clk_idx = ARIZONA_MCLK1; + break; + case ARIZONA_CLK_SRC_MCLK2: + clk_idx = ARIZONA_MCLK2; + break; + default: + return 0; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + return clk_prepare_enable(arizona->mclk[clk_idx]); + case SND_SOC_DAPM_POST_PMD: + clk_disable_unprepare(arizona->mclk[clk_idx]); + return 0; + default: + return 0; + } +} +EXPORT_SYMBOL_GPL(arizona_clk_ev); + int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 850aa338ba29..9d0997bec870 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -273,6 +273,8 @@ extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +extern int arizona_clk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 5b22564f037c..7df6a6769038 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -335,9 +335,11 @@ static const struct snd_kcontrol_new cs47l24_aec_loopback_mux = static const struct snd_soc_dapm_widget cs47l24_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, - ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 93876c6d48ee..bb3de5b3d816 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -607,6 +607,9 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: break; + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_clk_ev(w, kcontrol, event); default: return 0; } @@ -1077,9 +1080,11 @@ static const struct snd_kcontrol_new wm5102_aec_loopback_mux = static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, wm5102_sysclk_ev, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 06bae3b23fce..407dc4a43b07 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -183,7 +183,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, regmap_write_async(regmap, patch[i].reg, patch[i].def); break; - + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_clk_ev(w, kcontrol, event); default: break; } @@ -1073,9 +1075,11 @@ static const struct snd_kcontrol_new wm5110_output_anc_src[] = { static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, - 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU), + 0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 2f2821b3382f..f5f5d4352670 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -108,6 +108,9 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: break; + case SND_SOC_DAPM_PRE_PMU: + case SND_SOC_DAPM_POST_PMD: + return arizona_clk_ev(w, kcontrol, event); default: return 0; } @@ -408,9 +411,11 @@ static const struct snd_kcontrol_new wm8997_aec_loopback_mux = static const struct snd_soc_dapm_widget wm8997_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, 0, wm8997_sysclk_ev, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index bcc2e1060a6c..3eaa3615b82e 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -541,9 +541,11 @@ static const struct snd_kcontrol_new wm8998_aec_loopback_mux[] = { static const struct snd_soc_dapm_widget wm8998_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, - ARIZONA_SYSCLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_SYSCLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, - ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), + ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, arizona_clk_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("OPCLK", ARIZONA_OUTPUT_SYSTEM_CLOCK, ARIZONA_OPCLK_ENA_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ASYNCOPCLK", ARIZONA_OUTPUT_ASYNC_CLOCK, -- cgit v1.2.3-59-g8ed1b From ae1ea48c5c5998c5730cebaa2374ab02ad4d7d4f Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 21 Oct 2016 14:15:58 +0100 Subject: ASoC: arizona: Add gating for source clocks of the FLLs Whilst ultimately we would like to move all the clocking over to the clock framework, as an intermediate step to get people going for now enable the source clocks for FLLs as they are powered up. Signed-off-by: Charles Keepax Tested-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 60 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 10be50ae2f76..7f7d4b31a7fd 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2282,6 +2282,42 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll, int base) return reg & ARIZONA_FLL1_ENA; } +static int arizona_set_fll_clks(struct arizona_fll *fll, int base, bool ena) +{ + struct arizona *arizona = fll->arizona; + unsigned int val; + struct clk *clk; + int ret; + + ret = regmap_read(arizona->regmap, base + 6, &val); + if (ret != 0) { + arizona_fll_err(fll, "Failed to read current source: %d\n", + ret); + return ret; + } + + val &= ARIZONA_FLL1_CLK_REF_SRC_MASK; + val >>= ARIZONA_FLL1_CLK_REF_SRC_SHIFT; + + switch (val) { + case ARIZONA_FLL_SRC_MCLK1: + clk = arizona->mclk[ARIZONA_MCLK1]; + break; + case ARIZONA_FLL_SRC_MCLK2: + clk = arizona->mclk[ARIZONA_MCLK2]; + break; + default: + return 0; + } + + if (ena) { + return clk_prepare_enable(clk); + } else { + clk_disable_unprepare(clk); + return 0; + } +} + static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; @@ -2304,6 +2340,10 @@ static int arizona_enable_fll(struct arizona_fll *fll) udelay(32); regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x9, ARIZONA_FLL1_GAIN_MASK, 0); + + if (arizona_is_enabled_fll(fll, fll->base + 0x10) > 0) + arizona_set_fll_clks(fll, fll->base + 0x10, false); + arizona_set_fll_clks(fll, fll->base, false); } /* @@ -2358,10 +2398,13 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (!already_enabled) pm_runtime_get_sync(arizona->dev); - if (use_sync) + if (use_sync) { + arizona_set_fll_clks(fll, fll->base + 0x10, true); regmap_update_bits_async(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + } + arizona_set_fll_clks(fll, fll->base, true); regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); @@ -2394,19 +2437,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) static void arizona_disable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - bool change; + bool ref_change, sync_change; regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, ARIZONA_FLL1_FREERUN); regmap_update_bits_check(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_ENA, 0, &change); - regmap_update_bits(arizona->regmap, fll->base + 0x11, - ARIZONA_FLL1_SYNC_ENA, 0); + ARIZONA_FLL1_ENA, 0, &ref_change); + regmap_update_bits_check(arizona->regmap, fll->base + 0x11, + ARIZONA_FLL1_SYNC_ENA, 0, &sync_change); regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); - if (change) + if (sync_change) + arizona_set_fll_clks(fll, fll->base + 0x10, false); + + if (ref_change) { + arizona_set_fll_clks(fll, fll->base, false); pm_runtime_put_autosuspend(arizona->dev); + } } int arizona_set_fll_refclk(struct arizona_fll *fll, int source, -- cgit v1.2.3-59-g8ed1b From 206964e8265c4aeeda8338a3c1cec9814a90647b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 21 Oct 2016 10:27:07 +0200 Subject: ASoC: wm9705: Convert to regmap Currently the wm9712 driver still uses custom snd_soc_codec_driver IO callbacks. This has been deprecated for a while, so convert the wm9705 driver to use regmap for its IO. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/wm9705.c | 123 ++++++++++++++++++++++++---------------------- 2 files changed, 64 insertions(+), 60 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..109e27327b1a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1054,6 +1054,7 @@ config SND_SOC_WM9090 config SND_SOC_WM9705 tristate + select REGMAP_AC97 config SND_SOC_WM9712 tristate diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index dcdd055db57b..70ab6077fa55 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,26 +26,48 @@ #define WM9705_VENDOR_ID 0x574d4c05 #define WM9705_VENDOR_ID_MASK 0xffffffff -/* - * WM9705 register cache - */ -static const u16 wm9705_reg[] = { - 0x6150, 0x8000, 0x8000, 0x8000, /* 0x0 */ - 0x0000, 0x8000, 0x8008, 0x8008, /* 0x8 */ - 0x8808, 0x8808, 0x8808, 0x8808, /* 0x10 */ - 0x8808, 0x0000, 0x8000, 0x0000, /* 0x18 */ - 0x0000, 0x0000, 0x0000, 0x000f, /* 0x20 */ - 0x0605, 0x0000, 0xbb80, 0x0000, /* 0x28 */ - 0x0000, 0xbb80, 0x0000, 0x0000, /* 0x30 */ - 0x0000, 0x2000, 0x0000, 0x0000, /* 0x38 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x40 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x48 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x50 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x58 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x60 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 0x68 */ - 0x0000, 0x0808, 0x0000, 0x0006, /* 0x70 */ - 0x0000, 0x0000, 0x574d, 0x4c05, /* 0x78 */ +static const struct reg_default wm9705_reg_defaults[] = { + { 0x02, 0x8000 }, + { 0x04, 0x8000 }, + { 0x06, 0x8000 }, + { 0x0a, 0x8000 }, + { 0x0c, 0x8008 }, + { 0x0e, 0x8008 }, + { 0x10, 0x8808 }, + { 0x12, 0x8808 }, + { 0x14, 0x8808 }, + { 0x16, 0x8808 }, + { 0x18, 0x8808 }, + { 0x1a, 0x0000 }, + { 0x1c, 0x8000 }, + { 0x20, 0x0000 }, + { 0x22, 0x0000 }, + { 0x26, 0x000f }, + { 0x28, 0x0605 }, + { 0x2a, 0x0000 }, + { 0x2c, 0xbb80 }, + { 0x32, 0xbb80 }, + { 0x34, 0x2000 }, + { 0x5a, 0x0000 }, + { 0x5c, 0x0000 }, + { 0x72, 0x0808 }, + { 0x74, 0x0000 }, + { 0x76, 0x0006 }, + { 0x78, 0x0000 }, + { 0x7a, 0x0000 }, +}; + +static const struct regmap_config wm9705_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x7e, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = regmap_ac97_default_volatile, + + .reg_defaults = wm9705_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(wm9705_reg_defaults), }; static const struct snd_kcontrol_new wm9705_snd_ac97_controls[] = { @@ -203,39 +226,15 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = { {"Right ADC", NULL, "ADC PGA"}, }; -/* We use a register cache to enhance read performance. */ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - switch (reg) { - case AC97_RESET: - case AC97_VENDOR_ID1: - case AC97_VENDOR_ID2: - return soc_ac97_ops->read(ac97, reg); - default: - reg = reg >> 1; - - if (reg >= (ARRAY_SIZE(wm9705_reg))) - return -EIO; - - return cache[reg]; - } + return snd_soc_read(codec, reg); } static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - soc_ac97_ops->write(ac97, reg, val); - reg = reg >> 1; - if (reg < (ARRAY_SIZE(wm9705_reg))) - cache[reg] = val; - - return 0; + return snd_soc_write(codec, reg, val); } static int ac97_prepare(struct snd_pcm_substream *substream, @@ -299,9 +298,9 @@ static struct snd_soc_dai_driver wm9705_dai[] = { #ifdef CONFIG_PM static int wm9705_soc_suspend(struct snd_soc_codec *codec) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - - soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff); + regcache_cache_bypass(codec->component.regmap, true); + ac97_write(codec, AC97_POWERDOWN, 0xffff); + regcache_cache_bypass(codec->component.regmap, false); return 0; } @@ -309,17 +308,14 @@ static int wm9705_soc_suspend(struct snd_soc_codec *codec) static int wm9705_soc_resume(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - int i, ret; - u16 *cache = codec->reg_cache; + int ret; ret = snd_ac97_reset(ac97, true, WM9705_VENDOR_ID, WM9705_VENDOR_ID_MASK); if (ret < 0) return ret; - for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { - soc_ac97_ops->write(ac97, i, cache[i>>1]); - } + regcache_sync(codec->component.regmap); return 0; } @@ -331,6 +327,8 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) static int wm9705_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; + struct regmap *regmap; + int ret; ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID, WM9705_VENDOR_ID_MASK); @@ -339,15 +337,26 @@ static int wm9705_soc_probe(struct snd_soc_codec *codec) return PTR_ERR(ac97); } + regmap = regmap_init_ac97(ac97, &wm9705_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_free_ac97_codec; + } + snd_soc_codec_set_drvdata(codec, ac97); + snd_soc_codec_init_regmap(codec, regmap); return 0; +err_free_ac97_codec: + snd_soc_free_ac97_codec(ac97); + return ret; } static int wm9705_soc_remove(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(ac97); return 0; } @@ -357,12 +366,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm9705 = { .remove = wm9705_soc_remove, .suspend = wm9705_soc_suspend, .resume = wm9705_soc_resume, - .read = ac97_read, - .write = ac97_write, - .reg_cache_size = ARRAY_SIZE(wm9705_reg), - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, - .reg_cache_default = wm9705_reg, .component_driver = { .controls = wm9705_snd_ac97_controls, -- cgit v1.2.3-59-g8ed1b From 1457de3b8766045b815d1b37b7edc7b7c17c9dbc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 21 Oct 2016 10:27:08 +0200 Subject: ASoC: wm9705: Remove ac97_read/ac97_write wrappers Since the regmap conversion ac97_read/ac97_write are just simple wrappers around snd_soc_read/snd_soc_write. Use those instead directly and remove the wrappers. Also use snd_soc_update_bits() where appropriate. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9705.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 70ab6077fa55..e73ff6176622 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -226,33 +226,20 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = { {"Right ADC", NULL, "ADC PGA"}, }; -static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) -{ - return snd_soc_read(codec, reg); -} - -static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - return snd_soc_write(codec, reg, val); -} - static int ac97_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; int reg; - u16 vra; - vra = ac97_read(codec, AC97_EXTENDED_STATUS); - ac97_write(codec, AC97_EXTENDED_STATUS, vra | 0x1); + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x1, 0x1); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = AC97_PCM_FRONT_DAC_RATE; else reg = AC97_PCM_LR_ADC_RATE; - return ac97_write(codec, reg, substream->runtime->rate); + return snd_soc_write(codec, reg, substream->runtime->rate); } #define WM9705_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \ @@ -299,7 +286,7 @@ static struct snd_soc_dai_driver wm9705_dai[] = { static int wm9705_soc_suspend(struct snd_soc_codec *codec) { regcache_cache_bypass(codec->component.regmap, true); - ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); regcache_cache_bypass(codec->component.regmap, false); return 0; -- cgit v1.2.3-59-g8ed1b From 73444723b2b5b53ca2759daeecda90c9c7fa3629 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 21 Oct 2016 11:02:28 +0800 Subject: ASoC: rt5663: rename rt5668 as rt5663 v2 The "rt5668" codec supported in this driver is actually a revision of "rt5663". So the patch is renamed to "rt5663 v2" Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5663.txt | 6 +- sound/soc/codecs/rt5663.c | 1130 ++++++++++--------- sound/soc/codecs/rt5663.h | 1154 ++++++++++---------- 3 files changed, 1140 insertions(+), 1150 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/rt5663.txt b/Documentation/devicetree/bindings/sound/rt5663.txt index 7d3c974c6e2e..70eaeaed2b18 100644 --- a/Documentation/devicetree/bindings/sound/rt5663.txt +++ b/Documentation/devicetree/bindings/sound/rt5663.txt @@ -1,10 +1,10 @@ -RT5663/RT5668 audio CODEC +RT5663 audio CODEC This device supports I2C only. Required properties: -- compatible : One of "realtek,rt5663" or "realtek,rt5668". +- compatible : "realtek,rt5663". - reg : The I2C address of the device. @@ -12,7 +12,7 @@ Required properties: Optional properties: -Pins on the device (for linking into audio routes) for RT5663/RT5668: +Pins on the device (for linking into audio routes) for RT5663: * IN1P * IN1N diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index f30e0b461602..ff968d93f31f 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -1,5 +1,5 @@ /* - * rt5663.c -- RT5668/RT5663 ALSA SoC audio codec driver + * rt5663.c -- RT5663 ALSA SoC audio codec driver * * Copyright 2016 Realtek Semiconductor Corp. * Author: Jack Yu @@ -30,12 +30,12 @@ #include "rt5663.h" #include "rl6231.h" -#define RT5668_DEVICE_ID 0x6451 -#define RT5663_DEVICE_ID 0x6406 +#define RT5663_DEVICE_ID_2 0x6451 +#define RT5663_DEVICE_ID_1 0x6406 enum { - CODEC_TYPE_RT5668, - CODEC_TYPE_RT5663, + CODEC_VER_1, + CODEC_VER_0, }; struct rt5663_priv { @@ -45,7 +45,7 @@ struct rt5663_priv { struct snd_soc_jack *hs_jack; struct timer_list btn_check_timer; - int codec_type; + int codec_ver; int sysclk; int sysclk_src; int lrck; @@ -57,7 +57,7 @@ struct rt5663_priv { int jack_type; }; -static const struct reg_default rt5668_reg[] = { +static const struct reg_default rt5663_v2_reg[] = { { 0x0000, 0x0000 }, { 0x0001, 0xc8c8 }, { 0x0002, 0x8080 }, @@ -730,7 +730,7 @@ static bool rt5663_volatile_register(struct device *dev, unsigned int reg) case RT5663_ADC_EQ_1: case RT5663_INT_ST_1: case RT5663_INT_ST_2: - case RT5663_GPIO_STA: + case RT5663_GPIO_STA1: case RT5663_SIN_GEN_1: case RT5663_IL_CMD_1: case RT5663_IL_CMD_5: @@ -846,7 +846,7 @@ static bool rt5663_readable_register(struct device *dev, unsigned int reg) case RT5663_INT_ST_2: case RT5663_GPIO_1: case RT5663_GPIO_2: - case RT5663_GPIO_STA: + case RT5663_GPIO_STA1: case RT5663_SIN_GEN_1: case RT5663_SIN_GEN_2: case RT5663_SIN_GEN_3: @@ -1036,23 +1036,23 @@ static bool rt5663_readable_register(struct device *dev, unsigned int reg) } } -static bool rt5668_volatile_register(struct device *dev, unsigned int reg) +static bool rt5663_v2_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { case RT5663_RESET: - case RT5668_CBJ_TYPE_2: - case RT5668_PDM_OUT_CTL: - case RT5668_PDM_I2C_DATA_CTL1: - case RT5668_PDM_I2C_DATA_CTL4: - case RT5668_ALC_BK_GAIN: + case RT5663_CBJ_TYPE_2: + case RT5663_PDM_OUT_CTL: + case RT5663_PDM_I2C_DATA_CTL1: + case RT5663_PDM_I2C_DATA_CTL4: + case RT5663_ALC_BK_GAIN: case RT5663_PLL_2: case RT5663_MICBIAS_1: case RT5663_ADC_EQ_1: case RT5663_INT_ST_1: - case RT5668_GPIO_STA: + case RT5663_GPIO_STA2: case RT5663_IL_CMD_1: case RT5663_IL_CMD_5: - case RT5668_A_JD_CTRL: + case RT5663_A_JD_CTRL: case RT5663_JD_CTRL2: case RT5663_VENDOR_ID: case RT5663_VENDOR_ID_1: @@ -1061,15 +1061,15 @@ static bool rt5668_volatile_register(struct device *dev, unsigned int reg) case RT5663_STO_DRE_5: case RT5663_STO_DRE_6: case RT5663_STO_DRE_7: - case RT5668_MONO_DYNA_6: - case RT5668_STO1_SIL_DET: - case RT5668_MONOL_SIL_DET: - case RT5668_MONOR_SIL_DET: - case RT5668_STO2_DAC_SIL: - case RT5668_MONO_AMP_CAL_ST1: - case RT5668_MONO_AMP_CAL_ST2: - case RT5668_MONO_AMP_CAL_ST3: - case RT5668_MONO_AMP_CAL_ST4: + case RT5663_MONO_DYNA_6: + case RT5663_STO1_SIL_DET: + case RT5663_MONOL_SIL_DET: + case RT5663_MONOR_SIL_DET: + case RT5663_STO2_DAC_SIL: + case RT5663_MONO_AMP_CAL_ST1: + case RT5663_MONO_AMP_CAL_ST2: + case RT5663_MONO_AMP_CAL_ST3: + case RT5663_MONO_AMP_CAL_ST4: case RT5663_HP_IMP_SEN_2: case RT5663_HP_IMP_SEN_3: case RT5663_HP_IMP_SEN_4: @@ -1083,218 +1083,218 @@ static bool rt5668_volatile_register(struct device *dev, unsigned int reg) case RT5663_HP_CALIB_ST7: case RT5663_HP_CALIB_ST8: case RT5663_HP_CALIB_ST9: - case RT5668_HP_CALIB_ST10: - case RT5668_HP_CALIB_ST11: + case RT5663_HP_CALIB_ST10: + case RT5663_HP_CALIB_ST11: return true; default: return false; } } -static bool rt5668_readable_register(struct device *dev, unsigned int reg) +static bool rt5663_v2_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case RT5668_LOUT_CTRL: - case RT5668_HP_AMP_2: - case RT5668_MONO_OUT: - case RT5668_MONO_GAIN: - case RT5668_AEC_BST: - case RT5668_IN1_IN2: - case RT5668_IN3_IN4: - case RT5668_INL1_INR1: - case RT5668_CBJ_TYPE_2: - case RT5668_CBJ_TYPE_3: - case RT5668_CBJ_TYPE_4: - case RT5668_CBJ_TYPE_5: - case RT5668_CBJ_TYPE_8: - case RT5668_DAC3_DIG_VOL: - case RT5668_DAC3_CTRL: - case RT5668_MONO_ADC_DIG_VOL: - case RT5668_STO2_ADC_DIG_VOL: - case RT5668_MONO_ADC_BST_GAIN: - case RT5668_STO2_ADC_BST_GAIN: - case RT5668_SIDETONE_CTRL: - case RT5668_MONO1_ADC_MIXER: - case RT5668_STO2_ADC_MIXER: - case RT5668_MONO_DAC_MIXER: - case RT5668_DAC2_SRC_CTRL: - case RT5668_IF_3_4_DATA_CTL: - case RT5668_IF_5_DATA_CTL: - case RT5668_PDM_OUT_CTL: - case RT5668_PDM_I2C_DATA_CTL1: - case RT5668_PDM_I2C_DATA_CTL2: - case RT5668_PDM_I2C_DATA_CTL3: - case RT5668_PDM_I2C_DATA_CTL4: - case RT5668_RECMIX1_NEW: - case RT5668_RECMIX1L_0: - case RT5668_RECMIX1L: - case RT5668_RECMIX1R_0: - case RT5668_RECMIX1R: - case RT5668_RECMIX2_NEW: - case RT5668_RECMIX2_L_2: - case RT5668_RECMIX2_R: - case RT5668_RECMIX2_R_2: - case RT5668_CALIB_REC_LR: - case RT5668_ALC_BK_GAIN: - case RT5668_MONOMIX_GAIN: - case RT5668_MONOMIX_IN_GAIN: - case RT5668_OUT_MIXL_GAIN: - case RT5668_OUT_LMIX_IN_GAIN: - case RT5668_OUT_RMIX_IN_GAIN: - case RT5668_OUT_RMIX_IN_GAIN1: - case RT5668_LOUT_MIXER_CTRL: - case RT5668_PWR_VOL: - case RT5668_ADCDAC_RST: - case RT5668_I2S34_SDP: - case RT5668_I2S5_SDP: - case RT5668_TDM_5: - case RT5668_TDM_6: - case RT5668_TDM_7: - case RT5668_TDM_8: - case RT5668_ASRC_3: - case RT5668_ASRC_6: - case RT5668_ASRC_7: - case RT5668_PLL_TRK_13: - case RT5668_I2S_M_CLK_CTL: - case RT5668_FDIV_I2S34_M_CLK: - case RT5668_FDIV_I2S34_M_CLK2: - case RT5668_FDIV_I2S5_M_CLK: - case RT5668_FDIV_I2S5_M_CLK2: - case RT5668_IRQ_4: - case RT5668_GPIO_3: - case RT5668_GPIO_4: - case RT5668_GPIO_STA: - case RT5668_HP_AMP_DET1: - case RT5668_HP_AMP_DET2: - case RT5668_HP_AMP_DET3: - case RT5668_MID_BD_HP_AMP: - case RT5668_LOW_BD_HP_AMP: - case RT5668_SOF_VOL_ZC2: - case RT5668_ADC_STO2_ADJ1: - case RT5668_ADC_STO2_ADJ2: - case RT5668_A_JD_CTRL: - case RT5668_JD1_TRES_CTRL: - case RT5668_JD2_TRES_CTRL: - case RT5668_JD_CTRL2: - case RT5668_DUM_REG_2: - case RT5668_DUM_REG_3: + case RT5663_LOUT_CTRL: + case RT5663_HP_AMP_2: + case RT5663_MONO_OUT: + case RT5663_MONO_GAIN: + case RT5663_AEC_BST: + case RT5663_IN1_IN2: + case RT5663_IN3_IN4: + case RT5663_INL1_INR1: + case RT5663_CBJ_TYPE_2: + case RT5663_CBJ_TYPE_3: + case RT5663_CBJ_TYPE_4: + case RT5663_CBJ_TYPE_5: + case RT5663_CBJ_TYPE_8: + case RT5663_DAC3_DIG_VOL: + case RT5663_DAC3_CTRL: + case RT5663_MONO_ADC_DIG_VOL: + case RT5663_STO2_ADC_DIG_VOL: + case RT5663_MONO_ADC_BST_GAIN: + case RT5663_STO2_ADC_BST_GAIN: + case RT5663_SIDETONE_CTRL: + case RT5663_MONO1_ADC_MIXER: + case RT5663_STO2_ADC_MIXER: + case RT5663_MONO_DAC_MIXER: + case RT5663_DAC2_SRC_CTRL: + case RT5663_IF_3_4_DATA_CTL: + case RT5663_IF_5_DATA_CTL: + case RT5663_PDM_OUT_CTL: + case RT5663_PDM_I2C_DATA_CTL1: + case RT5663_PDM_I2C_DATA_CTL2: + case RT5663_PDM_I2C_DATA_CTL3: + case RT5663_PDM_I2C_DATA_CTL4: + case RT5663_RECMIX1_NEW: + case RT5663_RECMIX1L_0: + case RT5663_RECMIX1L: + case RT5663_RECMIX1R_0: + case RT5663_RECMIX1R: + case RT5663_RECMIX2_NEW: + case RT5663_RECMIX2_L_2: + case RT5663_RECMIX2_R: + case RT5663_RECMIX2_R_2: + case RT5663_CALIB_REC_LR: + case RT5663_ALC_BK_GAIN: + case RT5663_MONOMIX_GAIN: + case RT5663_MONOMIX_IN_GAIN: + case RT5663_OUT_MIXL_GAIN: + case RT5663_OUT_LMIX_IN_GAIN: + case RT5663_OUT_RMIX_IN_GAIN: + case RT5663_OUT_RMIX_IN_GAIN1: + case RT5663_LOUT_MIXER_CTRL: + case RT5663_PWR_VOL: + case RT5663_ADCDAC_RST: + case RT5663_I2S34_SDP: + case RT5663_I2S5_SDP: + case RT5663_TDM_6: + case RT5663_TDM_7: + case RT5663_TDM_8: + case RT5663_TDM_9: + case RT5663_ASRC_3: + case RT5663_ASRC_6: + case RT5663_ASRC_7: + case RT5663_PLL_TRK_13: + case RT5663_I2S_M_CLK_CTL: + case RT5663_FDIV_I2S34_M_CLK: + case RT5663_FDIV_I2S34_M_CLK2: + case RT5663_FDIV_I2S5_M_CLK: + case RT5663_FDIV_I2S5_M_CLK2: + case RT5663_V2_IRQ_4: + case RT5663_GPIO_3: + case RT5663_GPIO_4: + case RT5663_GPIO_STA2: + case RT5663_HP_AMP_DET1: + case RT5663_HP_AMP_DET2: + case RT5663_HP_AMP_DET3: + case RT5663_MID_BD_HP_AMP: + case RT5663_LOW_BD_HP_AMP: + case RT5663_SOF_VOL_ZC2: + case RT5663_ADC_STO2_ADJ1: + case RT5663_ADC_STO2_ADJ2: + case RT5663_A_JD_CTRL: + case RT5663_JD1_TRES_CTRL: + case RT5663_JD2_TRES_CTRL: + case RT5663_V2_JD_CTRL2: + case RT5663_DUM_REG_2: + case RT5663_DUM_REG_3: case RT5663_VENDOR_ID: case RT5663_VENDOR_ID_1: case RT5663_VENDOR_ID_2: - case RT5668_DACADC_DIG_VOL2: - case RT5668_DIG_IN_PIN2: - case RT5668_PAD_DRV_CTL1: - case RT5668_SOF_RAM_DEPOP: - case RT5668_VOL_TEST: - case RT5668_TEST_MODE_3: - case RT5668_TEST_MODE_4: + case RT5663_DACADC_DIG_VOL2: + case RT5663_DIG_IN_PIN2: + case RT5663_PAD_DRV_CTL1: + case RT5663_SOF_RAM_DEPOP: + case RT5663_VOL_TEST: + case RT5663_TEST_MODE_4: + case RT5663_TEST_MODE_5: case RT5663_STO_DRE_9: - case RT5668_MONO_DYNA_1: - case RT5668_MONO_DYNA_2: - case RT5668_MONO_DYNA_3: - case RT5668_MONO_DYNA_4: - case RT5668_MONO_DYNA_5: - case RT5668_MONO_DYNA_6: - case RT5668_STO1_SIL_DET: - case RT5668_MONOL_SIL_DET: - case RT5668_MONOR_SIL_DET: - case RT5668_STO2_DAC_SIL: - case RT5668_PWR_SAV_CTL1: - case RT5668_PWR_SAV_CTL2: - case RT5668_PWR_SAV_CTL3: - case RT5668_PWR_SAV_CTL4: - case RT5668_PWR_SAV_CTL5: - case RT5668_PWR_SAV_CTL6: - case RT5668_MONO_AMP_CAL1: - case RT5668_MONO_AMP_CAL2: - case RT5668_MONO_AMP_CAL3: - case RT5668_MONO_AMP_CAL4: - case RT5668_MONO_AMP_CAL5: - case RT5668_MONO_AMP_CAL6: - case RT5668_MONO_AMP_CAL7: - case RT5668_MONO_AMP_CAL_ST1: - case RT5668_MONO_AMP_CAL_ST2: - case RT5668_MONO_AMP_CAL_ST3: - case RT5668_MONO_AMP_CAL_ST4: - case RT5668_MONO_AMP_CAL_ST5: - case RT5668_HP_IMP_SEN_13: - case RT5668_HP_IMP_SEN_14: - case RT5668_HP_IMP_SEN_6: - case RT5668_HP_IMP_SEN_7: - case RT5668_HP_IMP_SEN_8: - case RT5668_HP_IMP_SEN_9: - case RT5668_HP_IMP_SEN_10: - case RT5668_HP_LOGIC_3: - case RT5668_HP_CALIB_ST10: - case RT5668_HP_CALIB_ST11: - case RT5668_PRO_REG_TBL_4: - case RT5668_PRO_REG_TBL_5: - case RT5668_PRO_REG_TBL_6: - case RT5668_PRO_REG_TBL_7: - case RT5668_PRO_REG_TBL_8: - case RT5668_PRO_REG_TBL_9: - case RT5668_SAR_ADC_INL_1: - case RT5668_SAR_ADC_INL_2: - case RT5668_SAR_ADC_INL_3: - case RT5668_SAR_ADC_INL_4: - case RT5668_SAR_ADC_INL_5: - case RT5668_SAR_ADC_INL_6: - case RT5668_SAR_ADC_INL_7: - case RT5668_SAR_ADC_INL_8: - case RT5668_SAR_ADC_INL_9: - case RT5668_SAR_ADC_INL_10: - case RT5668_SAR_ADC_INL_11: - case RT5668_SAR_ADC_INL_12: - case RT5668_DRC_CTRL_1: - case RT5668_DRC1_CTRL_2: - case RT5668_DRC1_CTRL_3: - case RT5668_DRC1_CTRL_4: - case RT5668_DRC1_CTRL_5: - case RT5668_DRC1_CTRL_6: - case RT5668_DRC1_HD_CTRL_1: - case RT5668_DRC1_HD_CTRL_2: - case RT5668_DRC1_PRI_REG_1: - case RT5668_DRC1_PRI_REG_2: - case RT5668_DRC1_PRI_REG_3: - case RT5668_DRC1_PRI_REG_4: - case RT5668_DRC1_PRI_REG_5: - case RT5668_DRC1_PRI_REG_6: - case RT5668_DRC1_PRI_REG_7: - case RT5668_DRC1_PRI_REG_8: - case RT5668_ALC_PGA_CTL_1: - case RT5668_ALC_PGA_CTL_2: - case RT5668_ALC_PGA_CTL_3: - case RT5668_ALC_PGA_CTL_4: - case RT5668_ALC_PGA_CTL_5: - case RT5668_ALC_PGA_CTL_6: - case RT5668_ALC_PGA_CTL_7: - case RT5668_ALC_PGA_CTL_8: - case RT5668_ALC_PGA_REG_1: - case RT5668_ALC_PGA_REG_2: - case RT5668_ALC_PGA_REG_3: - case RT5668_ADC_EQ_RECOV_1: - case RT5668_ADC_EQ_RECOV_2: - case RT5668_ADC_EQ_RECOV_3: - case RT5668_ADC_EQ_RECOV_4: - case RT5668_ADC_EQ_RECOV_5: - case RT5668_ADC_EQ_RECOV_6: - case RT5668_ADC_EQ_RECOV_7: - case RT5668_ADC_EQ_RECOV_8: - case RT5668_ADC_EQ_RECOV_9: - case RT5668_ADC_EQ_RECOV_10: - case RT5668_ADC_EQ_RECOV_11: - case RT5668_ADC_EQ_RECOV_12: - case RT5668_ADC_EQ_RECOV_13: - case RT5668_VID_HIDDEN: - case RT5668_VID_CUSTOMER: - case RT5668_SCAN_MODE: - case RT5668_I2C_BYPA: + case RT5663_MONO_DYNA_1: + case RT5663_MONO_DYNA_2: + case RT5663_MONO_DYNA_3: + case RT5663_MONO_DYNA_4: + case RT5663_MONO_DYNA_5: + case RT5663_MONO_DYNA_6: + case RT5663_STO1_SIL_DET: + case RT5663_MONOL_SIL_DET: + case RT5663_MONOR_SIL_DET: + case RT5663_STO2_DAC_SIL: + case RT5663_PWR_SAV_CTL1: + case RT5663_PWR_SAV_CTL2: + case RT5663_PWR_SAV_CTL3: + case RT5663_PWR_SAV_CTL4: + case RT5663_PWR_SAV_CTL5: + case RT5663_PWR_SAV_CTL6: + case RT5663_MONO_AMP_CAL1: + case RT5663_MONO_AMP_CAL2: + case RT5663_MONO_AMP_CAL3: + case RT5663_MONO_AMP_CAL4: + case RT5663_MONO_AMP_CAL5: + case RT5663_MONO_AMP_CAL6: + case RT5663_MONO_AMP_CAL7: + case RT5663_MONO_AMP_CAL_ST1: + case RT5663_MONO_AMP_CAL_ST2: + case RT5663_MONO_AMP_CAL_ST3: + case RT5663_MONO_AMP_CAL_ST4: + case RT5663_MONO_AMP_CAL_ST5: + case RT5663_V2_HP_IMP_SEN_13: + case RT5663_V2_HP_IMP_SEN_14: + case RT5663_V2_HP_IMP_SEN_6: + case RT5663_V2_HP_IMP_SEN_7: + case RT5663_V2_HP_IMP_SEN_8: + case RT5663_V2_HP_IMP_SEN_9: + case RT5663_V2_HP_IMP_SEN_10: + case RT5663_HP_LOGIC_3: + case RT5663_HP_CALIB_ST10: + case RT5663_HP_CALIB_ST11: + case RT5663_PRO_REG_TBL_4: + case RT5663_PRO_REG_TBL_5: + case RT5663_PRO_REG_TBL_6: + case RT5663_PRO_REG_TBL_7: + case RT5663_PRO_REG_TBL_8: + case RT5663_PRO_REG_TBL_9: + case RT5663_SAR_ADC_INL_1: + case RT5663_SAR_ADC_INL_2: + case RT5663_SAR_ADC_INL_3: + case RT5663_SAR_ADC_INL_4: + case RT5663_SAR_ADC_INL_5: + case RT5663_SAR_ADC_INL_6: + case RT5663_SAR_ADC_INL_7: + case RT5663_SAR_ADC_INL_8: + case RT5663_SAR_ADC_INL_9: + case RT5663_SAR_ADC_INL_10: + case RT5663_SAR_ADC_INL_11: + case RT5663_SAR_ADC_INL_12: + case RT5663_DRC_CTRL_1: + case RT5663_DRC1_CTRL_2: + case RT5663_DRC1_CTRL_3: + case RT5663_DRC1_CTRL_4: + case RT5663_DRC1_CTRL_5: + case RT5663_DRC1_CTRL_6: + case RT5663_DRC1_HD_CTRL_1: + case RT5663_DRC1_HD_CTRL_2: + case RT5663_DRC1_PRI_REG_1: + case RT5663_DRC1_PRI_REG_2: + case RT5663_DRC1_PRI_REG_3: + case RT5663_DRC1_PRI_REG_4: + case RT5663_DRC1_PRI_REG_5: + case RT5663_DRC1_PRI_REG_6: + case RT5663_DRC1_PRI_REG_7: + case RT5663_DRC1_PRI_REG_8: + case RT5663_ALC_PGA_CTL_1: + case RT5663_ALC_PGA_CTL_2: + case RT5663_ALC_PGA_CTL_3: + case RT5663_ALC_PGA_CTL_4: + case RT5663_ALC_PGA_CTL_5: + case RT5663_ALC_PGA_CTL_6: + case RT5663_ALC_PGA_CTL_7: + case RT5663_ALC_PGA_CTL_8: + case RT5663_ALC_PGA_REG_1: + case RT5663_ALC_PGA_REG_2: + case RT5663_ALC_PGA_REG_3: + case RT5663_ADC_EQ_RECOV_1: + case RT5663_ADC_EQ_RECOV_2: + case RT5663_ADC_EQ_RECOV_3: + case RT5663_ADC_EQ_RECOV_4: + case RT5663_ADC_EQ_RECOV_5: + case RT5663_ADC_EQ_RECOV_6: + case RT5663_ADC_EQ_RECOV_7: + case RT5663_ADC_EQ_RECOV_8: + case RT5663_ADC_EQ_RECOV_9: + case RT5663_ADC_EQ_RECOV_10: + case RT5663_ADC_EQ_RECOV_11: + case RT5663_ADC_EQ_RECOV_12: + case RT5663_ADC_EQ_RECOV_13: + case RT5663_VID_HIDDEN: + case RT5663_VID_CUSTOMER: + case RT5663_SCAN_MODE: + case RT5663_I2C_BYPA: return true; case RT5663_TDM_1: case RT5663_DEPOP_3: case RT5663_ASRC_11_2: case RT5663_INT_ST_2: - case RT5663_GPIO_STA: + case RT5663_GPIO_STA1: case RT5663_SIN_GEN_1: case RT5663_SIN_GEN_2: case RT5663_SIN_GEN_3: @@ -1344,7 +1344,7 @@ static bool rt5668_readable_register(struct device *dev, unsigned int reg) } static const DECLARE_TLV_DB_SCALE(rt5663_hp_vol_tlv, -2400, 150, 0); -static const DECLARE_TLV_DB_SCALE(rt5668_hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(rt5663_v2_hp_vol_tlv, -2250, 150, 0); static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); @@ -1374,57 +1374,57 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec, if (enable) { snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_EN); + RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_EN); /* reset in-line command */ snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_RESET); + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_RESET); snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_NOR); - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_NOR); + switch (rt5663->codec_ver) { + case CODEC_VER_1: snd_soc_update_bits(codec, RT5663_IRQ_3, - RT5668_EN_IRQ_INLINE_MASK, - RT5668_EN_IRQ_INLINE_NOR); + RT5663_V2_EN_IRQ_INLINE_MASK, + RT5663_V2_EN_IRQ_INLINE_NOR); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: snd_soc_update_bits(codec, RT5663_IRQ_2, RT5663_EN_IRQ_INLINE_MASK, RT5663_EN_IRQ_INLINE_NOR); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } else { - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: snd_soc_update_bits(codec, RT5663_IRQ_3, - RT5668_EN_IRQ_INLINE_MASK, - RT5668_EN_IRQ_INLINE_BYP); + RT5663_V2_EN_IRQ_INLINE_MASK, + RT5663_V2_EN_IRQ_INLINE_BYP); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: snd_soc_update_bits(codec, RT5663_IRQ_2, RT5663_EN_IRQ_INLINE_MASK, RT5663_EN_IRQ_INLINE_BYP); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_EN_4BTN_INL_MASK, RT5668_EN_4BTN_INL_DIS); + RT5663_EN_4BTN_INL_MASK, RT5663_EN_4BTN_INL_DIS); /* reset in-line command */ snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_RESET); + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_RESET); snd_soc_update_bits(codec, RT5663_IL_CMD_6, - RT5668_RESET_4BTN_INL_MASK, - RT5668_RESET_4BTN_INL_NOR); + RT5663_RESET_4BTN_INL_MASK, + RT5663_RESET_4BTN_INL_NOR); } } /** - * rt5668_jack_detect - Detect headset. + * rt5663_v2_jack_detect - Detect headset. * @codec: SoC audio codec device. * @jack_insert: Jack insert or not. * @@ -1433,16 +1433,16 @@ static void rt5663_enable_push_button_irq(struct snd_soc_codec *codec, * Returns detect status. */ -static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) +static int rt5663_v2_jack_detect(struct snd_soc_codec *codec, int jack_insert) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); int val, i = 0, sleep_time[5] = {300, 150, 100, 50, 30}; dev_dbg(codec->dev, "%s jack_insert:%d\n", __func__, jack_insert); if (jack_insert) { - snd_soc_write(codec, RT5668_CBJ_TYPE_2, 0x8040); - snd_soc_write(codec, RT5668_CBJ_TYPE_3, 0x1484); + snd_soc_write(codec, RT5663_CBJ_TYPE_2, 0x8040); + snd_soc_write(codec, RT5663_CBJ_TYPE_3, 0x1484); snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); snd_soc_dapm_force_enable_pin(dapm, "MICBIAS2"); @@ -1450,12 +1450,12 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_force_enable_pin(dapm, "CBJ Power"); snd_soc_dapm_sync(dapm); snd_soc_update_bits(codec, RT5663_RC_CLK, - RT5668_DIG_1M_CLK_MASK, RT5668_DIG_1M_CLK_EN); + RT5663_DIG_1M_CLK_MASK, RT5663_DIG_1M_CLK_EN); snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x8); while (i < 5) { msleep(sleep_time[i]); - val = snd_soc_read(codec, RT5668_CBJ_TYPE_2) & 0x0003; + val = snd_soc_read(codec, RT5663_CBJ_TYPE_2) & 0x0003; if (val == 0x1 || val == 0x2 || val == 0x3) break; dev_dbg(codec->dev, "%s: MX-0011 val=%x sleep %d\n", @@ -1466,7 +1466,7 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) switch (val) { case 1: case 2: - rt5668->jack_type = SND_JACK_HEADSET; + rt5663->jack_type = SND_JACK_HEADSET; rt5663_enable_push_button_irq(codec, true); break; default: @@ -1475,13 +1475,13 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); snd_soc_dapm_disable_pin(dapm, "CBJ Power"); snd_soc_dapm_sync(dapm); - rt5668->jack_type = SND_JACK_HEADPHONE; + rt5663->jack_type = SND_JACK_HEADPHONE; break; } } else { snd_soc_update_bits(codec, RT5663_RECMIX, 0x8, 0x0); - if (rt5668->jack_type == SND_JACK_HEADSET) { + if (rt5663->jack_type == SND_JACK_HEADSET) { rt5663_enable_push_button_irq(codec, false); snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); snd_soc_dapm_disable_pin(dapm, "MICBIAS2"); @@ -1489,11 +1489,11 @@ static int rt5668_jack_detect(struct snd_soc_codec *codec, int jack_insert) snd_soc_dapm_disable_pin(dapm, "CBJ Power"); snd_soc_dapm_sync(dapm); } - rt5668->jack_type = 0; + rt5663->jack_type = 0; } - dev_dbg(codec->dev, "jack_type = %d\n", rt5668->jack_type); - return rt5668->jack_type; + dev_dbg(codec->dev, "jack_type = %d\n", rt5663->jack_type); + return rt5663->jack_type; } /** @@ -1514,11 +1514,11 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (jack_insert) { snd_soc_update_bits(codec, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); + RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5663_SI_HP_MASK | RT5668_OSW_HP_L_MASK | - RT5668_OSW_HP_R_MASK, RT5663_SI_HP_EN | - RT5668_OSW_HP_L_DIS | RT5668_OSW_HP_R_DIS); + RT5663_SI_HP_MASK | RT5663_OSW_HP_L_MASK | + RT5663_OSW_HP_R_MASK, RT5663_SI_HP_EN | + RT5663_OSW_HP_L_DIS | RT5663_OSW_HP_R_DIS); snd_soc_update_bits(codec, RT5663_DUMMY_1, RT5663_EMB_CLK_MASK | RT5663_HPA_CPL_BIAS_MASK | RT5663_HPA_CPR_BIAS_MASK, RT5663_EMB_CLK_EN | @@ -1530,17 +1530,17 @@ static int rt5663_jack_detect(struct snd_soc_codec *codec, int jack_insert) RT5663_PWR_MIC_DET_MASK, RT5663_PWR_MIC_DET_ON); /* BST1 power on for JD */ snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, - RT5668_PWR_BST1_MASK, RT5668_PWR_BST1_ON); + RT5663_PWR_BST1_MASK, RT5663_PWR_BST1_ON); snd_soc_update_bits(codec, RT5663_EM_JACK_TYPE_1, RT5663_CBJ_DET_MASK | RT5663_EXT_JD_MASK | RT5663_POL_EXT_JD_MASK, RT5663_CBJ_DET_EN | RT5663_EXT_JD_EN | RT5663_POL_EXT_JD_EN); snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_MB_MASK | RT5668_LDO1_DVO_MASK | - RT5668_AMP_HP_MASK, RT5668_PWR_MB | - RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + RT5663_PWR_MB_MASK | RT5663_LDO1_DVO_MASK | + RT5663_AMP_HP_MASK, RT5663_PWR_MB | + RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X); snd_soc_update_bits(codec, RT5663_AUTO_1MRC_CLK, - RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); + RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); snd_soc_update_bits(codec, RT5663_IRQ_1, RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); while (i < 5) { @@ -1619,13 +1619,13 @@ static bool rt5663_check_jd_status(struct snd_soc_codec *codec) dev_dbg(codec->dev, "%s val=%x\n", __func__, val); /* JD1 */ - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: return !(val & 0x2000); - case CODEC_TYPE_RT5663: + case CODEC_VER_0: return !(val & 0x1000); default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } return false; @@ -1645,15 +1645,16 @@ static void rt5663_jack_detect_work(struct work_struct *work) /* jack in */ if (rt5663->jack_type == 0) { /* jack was out, report jack type */ - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - report = rt5668_jack_detect(rt5663->codec, 1); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + report = rt5663_v2_jack_detect( + rt5663->codec, 1); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: report = rt5663_jack_detect(rt5663->codec, 1); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } else { /* jack is already in, report button event */ @@ -1702,15 +1703,15 @@ static void rt5663_jack_detect_work(struct work_struct *work) } } else { /* jack out */ - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - report = rt5668_jack_detect(rt5663->codec, 0); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + report = rt5663_v2_jack_detect(rt5663->codec, 0); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: report = rt5663_jack_detect(rt5663->codec, 0); break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } dev_dbg(codec->dev, "%s jack report: 0x%04x\n", __func__, report); @@ -1722,24 +1723,24 @@ static void rt5663_jack_detect_work(struct work_struct *work) static const struct snd_kcontrol_new rt5663_snd_controls[] = { /* DAC Digital Volume */ SOC_DOUBLE_TLV("DAC Playback Volume", RT5663_STO1_DAC_DIG_VOL, - RT5668_DAC_L1_VOL_SHIFT + 1, RT5668_DAC_R1_VOL_SHIFT + 1, + RT5663_DAC_L1_VOL_SHIFT + 1, RT5663_DAC_R1_VOL_SHIFT + 1, 87, 0, dac_vol_tlv), /* ADC Digital Volume Control */ SOC_DOUBLE("ADC Capture Switch", RT5663_STO1_ADC_DIG_VOL, - RT5668_ADC_L_MUTE_SHIFT, RT5668_ADC_R_MUTE_SHIFT, 1, 1), + RT5663_ADC_L_MUTE_SHIFT, RT5663_ADC_R_MUTE_SHIFT, 1, 1), SOC_DOUBLE_TLV("ADC Capture Volume", RT5663_STO1_ADC_DIG_VOL, - RT5668_ADC_L_VOL_SHIFT + 1, RT5668_ADC_R_VOL_SHIFT + 1, + RT5663_ADC_L_VOL_SHIFT + 1, RT5663_ADC_R_VOL_SHIFT + 1, 63, 0, adc_vol_tlv), }; -static const struct snd_kcontrol_new rt5668_specific_controls[] = { +static const struct snd_kcontrol_new rt5663_v2_specific_controls[] = { /* Headphone Output Volume */ SOC_DOUBLE_R_TLV("Headphone Playback Volume", RT5663_HP_LCH_DRE, - RT5663_HP_RCH_DRE, RT5668_GAIN_HP_SHIFT, 15, 1, - rt5668_hp_vol_tlv), + RT5663_HP_RCH_DRE, RT5663_GAIN_HP_SHIFT, 15, 1, + rt5663_v2_hp_vol_tlv), /* Mic Boost Volume */ - SOC_SINGLE_TLV("IN1 Capture Volume", RT5668_AEC_BST, - RT5668_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN1 Capture Volume", RT5663_AEC_BST, + RT5663_GAIN_CBJ_SHIFT, 8, 0, in_bst_tlv), }; static const struct snd_kcontrol_new rt5663_specific_controls[] = { @@ -1775,15 +1776,15 @@ static int rt5663_is_using_asrc(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { switch (w->shift) { - case RT5668_ADC_STO1_ASRC_SHIFT: - reg = RT5668_ASRC_3; - shift = RT5668_AD_STO1_TRACK_SHIFT; + case RT5663_ADC_STO1_ASRC_SHIFT: + reg = RT5663_ASRC_3; + shift = RT5663_V2_AD_STO1_TRACK_SHIFT; break; - case RT5668_DAC_STO1_ASRC_SHIFT: + case RT5663_DAC_STO1_ASRC_SHIFT: reg = RT5663_ASRC_2; - shift = RT5668_DA_STO1_TRACK_SHIFT; + shift = RT5663_DA_STO1_TRACK_SHIFT; break; default: return 0; @@ -1820,17 +1821,17 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, da_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & RT5663_DA_STO1_TRACK_MASK) ? 1 : 0; - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - ad_asrc_en = (snd_soc_read(codec, RT5668_ASRC_3) & - RT5668_AD_STO1_TRACK_MASK) ? 1 : 0; + switch (rt5663->codec_ver) { + case CODEC_VER_1: + ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_3) & + RT5663_V2_AD_STO1_TRACK_MASK) ? 1 : 0; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: ad_asrc_en = (snd_soc_read(codec, RT5663_ASRC_2) & RT5663_AD_STO1_TRACK_MASK) ? 1 : 0; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); return 1; } @@ -1849,7 +1850,7 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, * @filter_mask: mask of filters. * @clk_src: clock source * - * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5668 can + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5663 can * only support standard 32fs or 64fs i2s format, ASRC should be enabled to * support special i2s clock format such as Intel's 100fs(100 * sampling rate). * ASRC function will track i2s clock and generate a corresponding system clock @@ -1860,7 +1861,7 @@ static int rt5663_i2s_use_asrc(struct snd_soc_dapm_widget *source, int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, unsigned int filter_mask, unsigned int clk_src) { - struct rt5663_priv *rt5668 = snd_soc_codec_get_drvdata(codec); + struct rt5663_priv *rt5663 = snd_soc_codec_get_drvdata(codec); unsigned int asrc2_mask = 0; unsigned int asrc2_value = 0; unsigned int asrc3_mask = 0; @@ -1876,22 +1877,22 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, } if (filter_mask & RT5663_DA_STEREO_FILTER) { - asrc2_mask |= RT5668_DA_STO1_TRACK_MASK; - asrc2_value |= clk_src << RT5668_DA_STO1_TRACK_SHIFT; + asrc2_mask |= RT5663_DA_STO1_TRACK_MASK; + asrc2_value |= clk_src << RT5663_DA_STO1_TRACK_SHIFT; } if (filter_mask & RT5663_AD_STEREO_FILTER) { - switch (rt5668->codec_type) { - case CODEC_TYPE_RT5668: - asrc3_mask |= RT5668_AD_STO1_TRACK_MASK; - asrc3_value |= clk_src << RT5668_AD_STO1_TRACK_SHIFT; + switch (rt5663->codec_ver) { + case CODEC_VER_1: + asrc3_mask |= RT5663_V2_AD_STO1_TRACK_MASK; + asrc3_value |= clk_src << RT5663_V2_AD_STO1_TRACK_SHIFT; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: asrc2_mask |= RT5663_AD_STO1_TRACK_MASK; asrc2_value |= clk_src << RT5663_AD_STO1_TRACK_SHIFT; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); } } @@ -1900,7 +1901,7 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, asrc2_value); if (asrc3_mask) - snd_soc_update_bits(codec, RT5668_ASRC_3, asrc3_mask, + snd_soc_update_bits(codec, RT5663_ASRC_3, asrc3_mask, asrc3_value); return 0; @@ -1908,82 +1909,82 @@ int rt5663_sel_asrc_clk_src(struct snd_soc_codec *codec, EXPORT_SYMBOL_GPL(rt5663_sel_asrc_clk_src); /* Analog Mixer */ -static const struct snd_kcontrol_new rt5668_recmix1l[] = { - SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1L, - RT5668_RECMIX1L_BST2_SHIFT, 1, 1), - SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5668_RECMIX1L, - RT5668_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), +static const struct snd_kcontrol_new rt5663_recmix1l[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1L, + RT5663_RECMIX1L_BST2_SHIFT, 1, 1), + SOC_DAPM_SINGLE("BST1 CBJ Switch", RT5663_RECMIX1L, + RT5663_RECMIX1L_BST1_CBJ_SHIFT, 1, 1), }; -static const struct snd_kcontrol_new rt5668_recmix1r[] = { - SOC_DAPM_SINGLE("BST2 Switch", RT5668_RECMIX1R, - RT5668_RECMIX1R_BST2_SHIFT, 1, 1), +static const struct snd_kcontrol_new rt5663_recmix1r[] = { + SOC_DAPM_SINGLE("BST2 Switch", RT5663_RECMIX1R, + RT5663_RECMIX1R_BST2_SHIFT, 1, 1), }; /* Digital Mixer */ static const struct snd_kcontrol_new rt5663_sto1_adc_l_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_L1_SHIFT, 1, 1), + RT5663_M_STO1_ADC_L1_SHIFT, 1, 1), SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_L2_SHIFT, 1, 1), + RT5663_M_STO1_ADC_L2_SHIFT, 1, 1), }; -static const struct snd_kcontrol_new rt5668_sto1_adc_r_mix[] = { +static const struct snd_kcontrol_new rt5663_sto1_adc_r_mix[] = { SOC_DAPM_SINGLE("ADC1 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_R1_SHIFT, 1, 1), + RT5663_M_STO1_ADC_R1_SHIFT, 1, 1), SOC_DAPM_SINGLE("ADC2 Switch", RT5663_STO1_ADC_MIXER, - RT5668_M_STO1_ADC_R2_SHIFT, 1, 1), + RT5663_M_STO1_ADC_R2_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_adda_l_mix[] = { SOC_DAPM_SINGLE("ADC L Switch", RT5663_AD_DA_MIXER, - RT5668_M_ADCMIX_L_SHIFT, 1, 1), + RT5663_M_ADCMIX_L_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC L Switch", RT5663_AD_DA_MIXER, - RT5668_M_DAC1_L_SHIFT, 1, 1), + RT5663_M_DAC1_L_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_adda_r_mix[] = { SOC_DAPM_SINGLE("ADC R Switch", RT5663_AD_DA_MIXER, - RT5668_M_ADCMIX_R_SHIFT, 1, 1), + RT5663_M_ADCMIX_R_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC R Switch", RT5663_AD_DA_MIXER, - RT5668_M_DAC1_R_SHIFT, 1, 1), + RT5663_M_DAC1_R_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_sto1_dac_l_mix[] = { SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_L1_STO_L_SHIFT, 1, 1), + RT5663_M_DAC_L1_STO_L_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_R1_STO_L_SHIFT, 1, 1), + RT5663_M_DAC_R1_STO_L_SHIFT, 1, 1), }; static const struct snd_kcontrol_new rt5663_sto1_dac_r_mix[] = { SOC_DAPM_SINGLE("DAC L Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_L1_STO_R_SHIFT, 1, 1), + RT5663_M_DAC_L1_STO_R_SHIFT, 1, 1), SOC_DAPM_SINGLE("DAC R Switch", RT5663_STO_DAC_MIXER, - RT5668_M_DAC_R1_STO_R_SHIFT, 1, 1), + RT5663_M_DAC_R1_STO_R_SHIFT, 1, 1), }; /* Out Switch */ -static const struct snd_kcontrol_new rt5668_hpo_switch = - SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5668_HP_AMP_2, - RT5668_EN_DAC_HPO_SHIFT, 1, 0); +static const struct snd_kcontrol_new rt5663_hpo_switch = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5663_HP_AMP_2, + RT5663_EN_DAC_HPO_SHIFT, 1, 0); /* Stereo ADC source */ -static const char * const rt5668_sto1_adc_src[] = { +static const char * const rt5663_sto1_adc_src[] = { "ADC L", "ADC R" }; -static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_L_SRC_SHIFT, rt5668_sto1_adc_src); +static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcl_enum, RT5663_STO1_ADC_MIXER, + RT5663_STO1_ADC_L_SRC_SHIFT, rt5663_sto1_adc_src); -static const struct snd_kcontrol_new rt5668_sto1_adcl_mux = - SOC_DAPM_ENUM("STO1 ADC L Mux", rt5668_sto1_adcl_enum); +static const struct snd_kcontrol_new rt5663_sto1_adcl_mux = + SOC_DAPM_ENUM("STO1 ADC L Mux", rt5663_sto1_adcl_enum); -static SOC_ENUM_SINGLE_DECL(rt5668_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_R_SRC_SHIFT, rt5668_sto1_adc_src); +static SOC_ENUM_SINGLE_DECL(rt5663_sto1_adcr_enum, RT5663_STO1_ADC_MIXER, + RT5663_STO1_ADC_R_SRC_SHIFT, rt5663_sto1_adc_src); -static const struct snd_kcontrol_new rt5668_sto1_adcr_mux = - SOC_DAPM_ENUM("STO1 ADC R Mux", rt5668_sto1_adcr_enum); +static const struct snd_kcontrol_new rt5663_sto1_adcr_mux = + SOC_DAPM_ENUM("STO1 ADC R Mux", rt5663_sto1_adcr_enum); /* RT5663: Analog DACL1 input source */ static const char * const rt5663_alg_dacl_src[] = { @@ -2015,12 +2016,12 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5668_SEL_PM_HP_SHIFT, RT5668_SEL_PM_HP_HIGH); + RT5663_SEL_PM_HP_SHIFT, RT5663_SEL_PM_HP_HIGH); snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, - RT5668_HP_SIG_SRC1_MASK, - RT5668_HP_SIG_SRC1_SILENCE); + RT5663_HP_SIG_SRC1_MASK, + RT5663_HP_SIG_SRC1_SILENCE); } else { snd_soc_write(codec, RT5663_DEPOP_2, 0x3003); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, @@ -2028,7 +2029,7 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0030); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_DIS); + RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_DIS); snd_soc_write(codec, RT5663_HP_CHARGE_PUMP_2, 0x1371); snd_soc_write(codec, RT5663_HP_BIAS, 0xabba); snd_soc_write(codec, RT5663_CHARGE_PUMP_1, 0x2224); @@ -2041,14 +2042,14 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_HP_LOGIC_2, - RT5668_HP_SIG_SRC1_MASK, - RT5668_HP_SIG_SRC1_REG); + RT5663_HP_SIG_SRC1_MASK, + RT5663_HP_SIG_SRC1_REG); } else { snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x3000, 0x0); snd_soc_update_bits(codec, RT5663_HP_CHARGE_PUMP_1, - RT5668_OVCD_HP_MASK, RT5668_OVCD_HP_EN); + RT5663_OVCD_HP_MASK, RT5663_OVCD_HP_EN); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x0030, 0x0); snd_soc_update_bits(codec, RT5663_DEPOP_1, 0x000b, 0x000b); @@ -2062,7 +2063,7 @@ static int rt5663_hp_event(struct snd_soc_dapm_widget *w, return 0; } -static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, +static int rt5663_bst2_power(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); @@ -2070,13 +2071,13 @@ static int rt5668_bst2_power(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, - RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, - RT5668_PWR_BST2 | RT5668_PWR_BST2_OP); + RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, + RT5663_PWR_BST2 | RT5663_PWR_BST2_OP); break; case SND_SOC_DAPM_PRE_PMD: snd_soc_update_bits(codec, RT5663_PWR_ANLG_2, - RT5668_PWR_BST2_MASK | RT5668_PWR_BST2_OP_MASK, 0); + RT5663_PWR_BST2_MASK | RT5663_PWR_BST2_OP_MASK, 0); break; default: @@ -2110,14 +2111,14 @@ static int rt5663_pre_div_power(struct snd_soc_dapm_widget *w, } static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { - SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5668_PWR_PLL_SHIFT, 0, + SND_SOC_DAPM_SUPPLY("PLL", RT5663_PWR_ANLG_3, RT5663_PWR_PLL_SHIFT, 0, NULL, 0), /* micbias */ SND_SOC_DAPM_MICBIAS("MICBIAS1", RT5663_PWR_ANLG_2, - RT5668_PWR_MB1_SHIFT, 0), + RT5663_PWR_MB1_SHIFT, 0), SND_SOC_DAPM_MICBIAS("MICBIAS2", RT5663_PWR_ANLG_2, - RT5668_PWR_MB2_SHIFT, 0), + RT5663_PWR_MB2_SHIFT, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("IN1P"), @@ -2125,14 +2126,14 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* REC Mixer Power */ SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5663_PWR_ANLG_2, - RT5668_PWR_RECMIX1_SHIFT, 0, NULL, 0), + RT5663_PWR_RECMIX1_SHIFT, 0, NULL, 0), /* ADCs */ SND_SOC_DAPM_ADC("ADC L", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC L Power", RT5663_PWR_DIG_1, - RT5668_PWR_ADC_L1_SHIFT, 0, NULL, 0), + RT5663_PWR_ADC_L1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC Clock", RT5663_CHOP_ADC, - RT5668_CKGEN_ADCC_SHIFT, 0, NULL, 0), + RT5663_CKGEN_ADCC_SHIFT, 0, NULL, 0), /* ADC Mixer */ SND_SOC_DAPM_MIXER("STO1 ADC MIXL", SND_SOC_NOPM, @@ -2141,10 +2142,10 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* ADC Filter Power */ SND_SOC_DAPM_SUPPLY("STO1 ADC Filter", RT5663_PWR_DIG_2, - RT5668_PWR_ADC_S1F_SHIFT, 0, NULL, 0), + RT5663_PWR_ADC_S1F_SHIFT, 0, NULL, 0), /* Digital Interface */ - SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5668_PWR_I2S1_SHIFT, 0, + SND_SOC_DAPM_SUPPLY("I2S", RT5663_PWR_DIG_1, RT5663_PWR_I2S1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("IF DAC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -2166,7 +2167,7 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* DAC Mixer */ SND_SOC_DAPM_SUPPLY("STO1 DAC Filter", RT5663_PWR_DIG_2, - RT5668_PWR_DAC_S1F_SHIFT, 0, NULL, 0), + RT5663_PWR_DAC_S1F_SHIFT, 0, NULL, 0), SND_SOC_DAPM_MIXER("STO1 DAC MIXL", SND_SOC_NOPM, 0, 0, rt5663_sto1_dac_l_mix, ARRAY_SIZE(rt5663_sto1_dac_l_mix)), SND_SOC_DAPM_MIXER("STO1 DAC MIXR", SND_SOC_NOPM, 0, 0, @@ -2174,9 +2175,9 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { /* DACs */ SND_SOC_DAPM_SUPPLY("STO1 DAC L Power", RT5663_PWR_DIG_1, - RT5668_PWR_DAC_L1_SHIFT, 0, NULL, 0), + RT5663_PWR_DAC_L1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("STO1 DAC R Power", RT5663_PWR_DIG_1, - RT5668_PWR_DAC_R1_SHIFT, 0, NULL, 0), + RT5663_PWR_DAC_R1_SHIFT, 0, NULL, 0), SND_SOC_DAPM_DAC("DAC L", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_DAC("DAC R", NULL, SND_SOC_NOPM, 0, 0), @@ -2189,21 +2190,21 @@ static const struct snd_soc_dapm_widget rt5663_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("HPOR"), }; -static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { +static const struct snd_soc_dapm_widget rt5663_v2_specific_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT5663_PWR_ANLG_3, - RT5668_PWR_LDO2_SHIFT, 0, NULL, 0), - SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5668_PWR_VOL, - RT5668_PWR_MIC_DET_SHIFT, 0, NULL, 0), + RT5663_PWR_LDO2_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5663_PWR_VOL, + RT5663_V2_PWR_MIC_DET_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("LDO DAC", RT5663_PWR_DIG_1, - RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), /* ASRC */ SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, - RT5668_I2S1_ASRC_SHIFT, 0, NULL, 0), + RT5663_I2S1_ASRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DAC ASRC", RT5663_ASRC_1, - RT5668_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), + RT5663_DAC_STO1_ASRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("ADC ASRC", RT5663_ASRC_1, - RT5668_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), + RT5663_ADC_STO1_ASRC_SHIFT, 0, NULL, 0), /* Input Lines */ SND_SOC_DAPM_INPUT("IN2P"), @@ -2212,51 +2213,51 @@ static const struct snd_soc_dapm_widget rt5668_specific_dapm_widgets[] = { /* Boost */ SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("CBJ Power", RT5663_PWR_ANLG_3, - RT5668_PWR_CBJ_SHIFT, 0, NULL, 0), + RT5663_PWR_CBJ_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("BST2 Power", SND_SOC_NOPM, 0, 0, - rt5668_bst2_power, SND_SOC_DAPM_PRE_PMD | + rt5663_bst2_power, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), /* REC Mixer */ - SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5668_recmix1l, - ARRAY_SIZE(rt5668_recmix1l)), - SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5668_recmix1r, - ARRAY_SIZE(rt5668_recmix1r)), + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5663_recmix1l, + ARRAY_SIZE(rt5663_recmix1l)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5663_recmix1r, + ARRAY_SIZE(rt5663_recmix1r)), SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5663_PWR_ANLG_2, - RT5668_PWR_RECMIX2_SHIFT, 0, NULL, 0), + RT5663_PWR_RECMIX2_SHIFT, 0, NULL, 0), /* ADC */ SND_SOC_DAPM_ADC("ADC R", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_SUPPLY("ADC R Power", RT5663_PWR_DIG_1, - RT5668_PWR_ADC_R1_SHIFT, 0, NULL, 0), + RT5663_PWR_ADC_R1_SHIFT, 0, NULL, 0), /* ADC Mux */ SND_SOC_DAPM_PGA("STO1 ADC L1", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), + RT5663_STO1_ADC_L1_SRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("STO1 ADC R1", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), + RT5663_STO1_ADC_R1_SRC_SHIFT, 0, NULL, 0), SND_SOC_DAPM_PGA("STO1 ADC L2", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), + RT5663_STO1_ADC_L2_SRC_SHIFT, 1, NULL, 0), SND_SOC_DAPM_PGA("STO1 ADC R2", RT5663_STO1_ADC_MIXER, - RT5668_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), + RT5663_STO1_ADC_R2_SRC_SHIFT, 1, NULL, 0), SND_SOC_DAPM_MUX("STO1 ADC L Mux", SND_SOC_NOPM, 0, 0, - &rt5668_sto1_adcl_mux), + &rt5663_sto1_adcl_mux), SND_SOC_DAPM_MUX("STO1 ADC R Mux", SND_SOC_NOPM, 0, 0, - &rt5668_sto1_adcr_mux), + &rt5663_sto1_adcr_mux), /* ADC Mix */ SND_SOC_DAPM_MIXER("STO1 ADC MIXR", SND_SOC_NOPM, 0, 0, - rt5668_sto1_adc_r_mix, ARRAY_SIZE(rt5668_sto1_adc_r_mix)), + rt5663_sto1_adc_r_mix, ARRAY_SIZE(rt5663_sto1_adc_r_mix)), /* Analog DAC Clock */ SND_SOC_DAPM_SUPPLY("DAC Clock", RT5663_CHOP_DAC_L, - RT5668_CKGEN_DAC1_SHIFT, 0, NULL, 0), + RT5663_CKGEN_DAC1_SHIFT, 0, NULL, 0), /* Headphone out */ SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, - &rt5668_hpo_switch), + &rt5663_hpo_switch), }; static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { @@ -2267,7 +2268,7 @@ static const struct snd_soc_dapm_widget rt5663_specific_dapm_widgets[] = { /* LDO */ SND_SOC_DAPM_SUPPLY("LDO ADC", RT5663_PWR_DIG_1, - RT5668_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), + RT5663_PWR_LDO_DACREF_SHIFT, 0, NULL, 0), /* ASRC */ SND_SOC_DAPM_SUPPLY("I2S ASRC", RT5663_ASRC_1, @@ -2341,7 +2342,7 @@ static const struct snd_soc_dapm_route rt5663_dapm_routes[] = { { "HP Amp", NULL, "DAC R" }, }; -static const struct snd_soc_dapm_route rt5668_specific_dapm_routes[] = { +static const struct snd_soc_dapm_route rt5663_v2_specific_dapm_routes[] = { { "MICBIAS1", NULL, "LDO2" }, { "MICBIAS2", NULL, "LDO2" }, @@ -2440,26 +2441,26 @@ static int rt5663_hw_params(struct snd_pcm_substream *substream, switch (params_width(params)) { case 8: - val_len = RT5668_I2S_DL_8; + val_len = RT5663_I2S_DL_8; break; case 16: - val_len = RT5668_I2S_DL_16; + val_len = RT5663_I2S_DL_16; break; case 20: - val_len = RT5668_I2S_DL_20; + val_len = RT5663_I2S_DL_20; break; case 24: - val_len = RT5668_I2S_DL_24; + val_len = RT5663_I2S_DL_24; break; default: return -EINVAL; } snd_soc_update_bits(codec, RT5663_I2S1_SDP, - RT5668_I2S_DL_MASK, val_len); + RT5663_I2S_DL_MASK, val_len); snd_soc_update_bits(codec, RT5663_ADDA_CLK_1, - RT5668_I2S_PD1_MASK, pre_div << RT5668_I2S_PD1_SHIFT); + RT5663_I2S_PD1_MASK, pre_div << RT5663_I2S_PD1_SHIFT); return 0; } @@ -2473,7 +2474,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_CBM_CFM: break; case SND_SOC_DAIFMT_CBS_CFS: - reg_val |= RT5668_I2S_MS_S; + reg_val |= RT5663_I2S_MS_S; break; default: return -EINVAL; @@ -2483,7 +2484,7 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_IB_NF: - reg_val |= RT5668_I2S_BP_INV; + reg_val |= RT5663_I2S_BP_INV; break; default: return -EINVAL; @@ -2493,20 +2494,20 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) case SND_SOC_DAIFMT_I2S: break; case SND_SOC_DAIFMT_LEFT_J: - reg_val |= RT5668_I2S_DF_LEFT; + reg_val |= RT5663_I2S_DF_LEFT; break; case SND_SOC_DAIFMT_DSP_A: - reg_val |= RT5668_I2S_DF_PCM_A; + reg_val |= RT5663_I2S_DF_PCM_A; break; case SND_SOC_DAIFMT_DSP_B: - reg_val |= RT5668_I2S_DF_PCM_B; + reg_val |= RT5663_I2S_DF_PCM_B; break; default: return -EINVAL; } - snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5668_I2S_MS_MASK | - RT5668_I2S_BP_MASK | RT5668_I2S_DF_MASK, reg_val); + snd_soc_update_bits(codec, RT5663_I2S1_SDP, RT5663_I2S_MS_MASK | + RT5663_I2S_BP_MASK | RT5663_I2S_DF_MASK, reg_val); return 0; } @@ -2535,7 +2536,7 @@ static int rt5663_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); return -EINVAL; } - snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5668_SCLK_SRC_MASK, + snd_soc_update_bits(codec, RT5663_GLB_CLK, RT5663_SCLK_SRC_MASK, reg_val); rt5663->sysclk = freq; rt5663->sysclk_src = clk_id; @@ -2569,17 +2570,17 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, return 0; } - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - mask = RT5668_PLL1_SRC_MASK; - shift = RT5668_PLL1_SRC_SHIFT; + switch (rt5663->codec_ver) { + case CODEC_VER_1: + mask = RT5663_V2_PLL1_SRC_MASK; + shift = RT5663_V2_PLL1_SRC_SHIFT; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: mask = RT5663_PLL1_SRC_MASK; shift = RT5663_PLL1_SRC_SHIFT; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); return -EINVAL; } @@ -2607,10 +2608,10 @@ static int rt5663_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, pll_code.k_code); snd_soc_write(codec, RT5663_PLL_1, - pll_code.n_code << RT5668_PLL_N_SHIFT | pll_code.k_code); + pll_code.n_code << RT5663_PLL_N_SHIFT | pll_code.k_code); snd_soc_write(codec, RT5663_PLL_2, - (pll_code.m_bp ? 0 : pll_code.m_code) << RT5668_PLL_M_SHIFT | - pll_code.m_bp << RT5668_PLL_M_BP_SHIFT); + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5663_PLL_M_SHIFT | + pll_code.m_bp << RT5663_PLL_M_BP_SHIFT); rt5663->pll_in = freq_in; rt5663->pll_out = freq_out; @@ -2627,20 +2628,20 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int val = 0, reg; if (rx_mask || tx_mask) - val |= RT5668_TDM_MODE_TDM; + val |= RT5663_TDM_MODE_TDM; switch (slots) { case 4: - val |= RT5668_TDM_IN_CH_4; - val |= RT5668_TDM_OUT_CH_4; + val |= RT5663_TDM_IN_CH_4; + val |= RT5663_TDM_OUT_CH_4; break; case 6: - val |= RT5668_TDM_IN_CH_6; - val |= RT5668_TDM_OUT_CH_6; + val |= RT5663_TDM_IN_CH_6; + val |= RT5663_TDM_OUT_CH_6; break; case 8: - val |= RT5668_TDM_IN_CH_8; - val |= RT5668_TDM_OUT_CH_8; + val |= RT5663_TDM_IN_CH_8; + val |= RT5663_TDM_OUT_CH_8; break; case 2: break; @@ -2650,16 +2651,16 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, switch (slot_width) { case 20: - val |= RT5668_TDM_IN_LEN_20; - val |= RT5668_TDM_OUT_LEN_20; + val |= RT5663_TDM_IN_LEN_20; + val |= RT5663_TDM_OUT_LEN_20; break; case 24: - val |= RT5668_TDM_IN_LEN_24; - val |= RT5668_TDM_OUT_LEN_24; + val |= RT5663_TDM_IN_LEN_24; + val |= RT5663_TDM_OUT_LEN_24; break; case 32: - val |= RT5668_TDM_IN_LEN_32; - val |= RT5668_TDM_OUT_LEN_32; + val |= RT5663_TDM_IN_LEN_32; + val |= RT5663_TDM_OUT_LEN_32; break; case 16: break; @@ -2667,21 +2668,21 @@ static int rt5663_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, return -EINVAL; } - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: reg = RT5663_TDM_2; break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: reg = RT5663_TDM_1; break; default: - dev_err(codec->dev, "Unknown CODEC_TYPE\n"); + dev_err(codec->dev, "Unknown CODEC Version\n"); return -EINVAL; } - snd_soc_update_bits(codec, reg, RT5668_TDM_MODE_MASK | - RT5668_TDM_IN_CH_MASK | RT5668_TDM_OUT_CH_MASK | - RT5668_TDM_IN_LEN_MASK | RT5668_TDM_OUT_LEN_MASK, val); + snd_soc_update_bits(codec, reg, RT5663_TDM_MODE_MASK | + RT5663_TDM_IN_CH_MASK | RT5663_TDM_OUT_CH_MASK | + RT5663_TDM_IN_LEN_MASK | RT5663_TDM_OUT_LEN_MASK, val); return 0; } @@ -2694,8 +2695,8 @@ static int rt5663_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) dev_dbg(codec->dev, "%s ratio = %d\n", __func__, ratio); - if (rt5663->codec_type == CODEC_TYPE_RT5668) - reg = RT5668_TDM_8; + if (rt5663->codec_ver == CODEC_VER_1) + reg = RT5663_TDM_9; else reg = RT5663_TDM_5; @@ -2736,47 +2737,47 @@ static int rt5663_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK, - RT5668_PWR_FV1 | RT5668_PWR_FV2); + RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK, + RT5663_PWR_FV1 | RT5663_PWR_FV2); break; case SND_SOC_BIAS_PREPARE: - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, - RT5668_DIG_GATE_CTRL_EN); + RT5663_DIG_GATE_CTRL_MASK, + RT5663_DIG_GATE_CTRL_EN); snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, - RT5668_EN_ANA_CLK_DET_MASK | - RT5668_PWR_CLK_DET_MASK, - RT5668_EN_ANA_CLK_DET_AUTO | - RT5668_PWR_CLK_DET_EN); + RT5663_EN_ANA_CLK_DET_MASK | + RT5663_PWR_CLK_DET_MASK, + RT5663_EN_ANA_CLK_DET_AUTO | + RT5663_PWR_CLK_DET_EN); } break; case SND_SOC_BIAS_STANDBY: - if (rt5663->codec_type == CODEC_TYPE_RT5668) + if (rt5663->codec_ver == CODEC_VER_1) snd_soc_update_bits(codec, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, - RT5668_DIG_GATE_CTRL_DIS); + RT5663_DIG_GATE_CTRL_MASK, + RT5663_DIG_GATE_CTRL_DIS); snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | - RT5668_PWR_FV1_MASK | RT5668_PWR_FV2_MASK | - RT5668_PWR_MB_MASK, RT5668_PWR_VREF1 | - RT5668_PWR_VREF2 | RT5668_PWR_MB); + RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK | + RT5663_PWR_FV1_MASK | RT5663_PWR_FV2_MASK | + RT5663_PWR_MB_MASK, RT5663_PWR_VREF1 | + RT5663_PWR_VREF2 | RT5663_PWR_MB); usleep_range(10000, 10005); - if (rt5663->codec_type == CODEC_TYPE_RT5668) { + if (rt5663->codec_ver == CODEC_VER_1) { snd_soc_update_bits(codec, RT5663_SIG_CLK_DET, - RT5668_EN_ANA_CLK_DET_MASK | - RT5668_PWR_CLK_DET_MASK, - RT5668_EN_ANA_CLK_DET_DIS | - RT5668_PWR_CLK_DET_DIS); + RT5663_EN_ANA_CLK_DET_MASK | + RT5663_PWR_CLK_DET_MASK, + RT5663_EN_ANA_CLK_DET_DIS | + RT5663_PWR_CLK_DET_DIS); } break; case SND_SOC_BIAS_OFF: snd_soc_update_bits(codec, RT5663_PWR_ANLG_1, - RT5668_PWR_VREF1_MASK | RT5668_PWR_VREF2_MASK | - RT5668_PWR_FV1 | RT5668_PWR_FV2, 0x0); + RT5663_PWR_VREF1_MASK | RT5663_PWR_VREF2_MASK | + RT5663_PWR_FV1 | RT5663_PWR_FV2, 0x0); break; default: @@ -2793,18 +2794,18 @@ static int rt5663_probe(struct snd_soc_codec *codec) rt5663->codec = codec; - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: snd_soc_dapm_new_controls(dapm, - rt5668_specific_dapm_widgets, - ARRAY_SIZE(rt5668_specific_dapm_widgets)); + rt5663_v2_specific_dapm_widgets, + ARRAY_SIZE(rt5663_v2_specific_dapm_widgets)); snd_soc_dapm_add_routes(dapm, - rt5668_specific_dapm_routes, - ARRAY_SIZE(rt5668_specific_dapm_routes)); - snd_soc_add_codec_controls(codec, rt5668_specific_controls, - ARRAY_SIZE(rt5668_specific_controls)); + rt5663_v2_specific_dapm_routes, + ARRAY_SIZE(rt5663_v2_specific_dapm_routes)); + snd_soc_add_codec_controls(codec, rt5663_v2_specific_controls, + ARRAY_SIZE(rt5663_v2_specific_controls)); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: snd_soc_dapm_new_controls(dapm, rt5663_specific_dapm_widgets, ARRAY_SIZE(rt5663_specific_dapm_widgets)); @@ -2905,16 +2906,16 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5663 = { } }; -static const struct regmap_config rt5668_regmap = { +static const struct regmap_config rt5663_v2_regmap = { .reg_bits = 16, .val_bits = 16, .use_single_rw = true, .max_register = 0x07fa, - .volatile_reg = rt5668_volatile_register, - .readable_reg = rt5668_readable_register, + .volatile_reg = rt5663_v2_volatile_register, + .readable_reg = rt5663_v2_readable_register, .cache_type = REGCACHE_RBTREE, - .reg_defaults = rt5668_reg, - .num_reg_defaults = ARRAY_SIZE(rt5668_reg), + .reg_defaults = rt5663_v2_reg, + .num_reg_defaults = ARRAY_SIZE(rt5663_v2_reg), }; static const struct regmap_config rt5663_regmap = { @@ -2939,7 +2940,6 @@ static const struct regmap_config temp_regmap = { }; static const struct i2c_device_id rt5663_i2c_id[] = { - { "rt5668", 0 }, { "rt5663", 0 }, {} }; @@ -2947,7 +2947,6 @@ MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt5663_of_match[] = { - { .compatible = "realtek,rt5668", }, { .compatible = "realtek,rt5663", }, {}, }; @@ -2956,80 +2955,79 @@ MODULE_DEVICE_TABLE(of, rt5663_of_match); #ifdef CONFIG_ACPI static struct acpi_device_id rt5663_acpi_match[] = { - { "10EC5668", 0}, { "10EC5663", 0}, {}, }; MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match); #endif -static void rt5668_calibrate(struct rt5663_priv *rt5668) +static void rt5663_v2_calibrate(struct rt5663_priv *rt5663) { - regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0xa402); - regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x0100); - regmap_write(rt5668->regmap, RT5663_RECMIX, 0x4040); - regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x0001); - regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0380); - regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); - regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1000); - regmap_write(rt5668->regmap, RT5663_CHOP_DAC_L, 0x3030); - regmap_write(rt5668->regmap, RT5663_CALIB_ADC, 0x3c05); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa23e); + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x0100); + regmap_write(rt5663->regmap, RT5663_RECMIX, 0x4040); + regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x0001); + regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0380); + regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1000); + regmap_write(rt5663->regmap, RT5663_CHOP_DAC_L, 0x3030); + regmap_write(rt5663->regmap, RT5663_CALIB_ADC, 0x3c05); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa23e); msleep(40); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf23e); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x0321); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0xfc00); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf23e); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x0321); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0xfc00); msleep(500); } -static void rt5663_calibrate(struct rt5663_priv *rt5668) +static void rt5663_calibrate(struct rt5663_priv *rt5663) { int value, count; - regmap_write(rt5668->regmap, RT5663_RC_CLK, 0x0280); - regmap_write(rt5668->regmap, RT5663_GLB_CLK, 0x8000); - regmap_write(rt5668->regmap, RT5663_DIG_MISC, 0x8001); - regmap_write(rt5668->regmap, RT5663_VREF_RECMIX, 0x0032); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xa2be); + regmap_write(rt5663->regmap, RT5663_RC_CLK, 0x0280); + regmap_write(rt5663->regmap, RT5663_GLB_CLK, 0x8000); + regmap_write(rt5663->regmap, RT5663_DIG_MISC, 0x8001); + regmap_write(rt5663->regmap, RT5663_VREF_RECMIX, 0x0032); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xa2be); msleep(20); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_1, 0xf2be); - regmap_write(rt5668->regmap, RT5663_PWR_DIG_2, 0x8400); - regmap_write(rt5668->regmap, RT5663_CHOP_ADC, 0x3000); - regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); - regmap_write(rt5668->regmap, RT5663_PWR_DIG_1, 0x8df8); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_2, 0x0003); - regmap_write(rt5668->regmap, RT5663_PWR_ANLG_3, 0x018c); - regmap_write(rt5668->regmap, RT5663_ADDA_CLK_1, 0x1111); - regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); - regmap_write(rt5668->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); - regmap_write(rt5668->regmap, RT5663_DEPOP_2, 0x3003); - regmap_write(rt5668->regmap, RT5663_DEPOP_1, 0x003b); - regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); - regmap_write(rt5668->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); - regmap_write(rt5668->regmap, RT5663_DACREF_LDO, 0x3b0b); - regmap_write(rt5668->regmap, RT5663_STO_DAC_MIXER, 0x2080); - regmap_write(rt5668->regmap, RT5663_BYPASS_STO_DAC, 0x000c); - regmap_write(rt5668->regmap, RT5663_HP_BIAS, 0xabba); - regmap_write(rt5668->regmap, RT5663_CHARGE_PUMP_1, 0x2224); - regmap_write(rt5668->regmap, RT5663_HP_OUT_EN, 0x8088); - regmap_write(rt5668->regmap, RT5663_STO_DRE_9, 0x0017); - regmap_write(rt5668->regmap, RT5663_STO_DRE_10, 0x0017); - regmap_write(rt5668->regmap, RT5663_STO1_ADC_MIXER, 0x4040); - regmap_write(rt5668->regmap, RT5663_RECMIX, 0x0005); - regmap_write(rt5668->regmap, RT5663_ADDA_RST, 0xc000); - regmap_write(rt5668->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_2, 0x00c9); - regmap_write(rt5668->regmap, RT5663_DUMMY_1, 0x004c); - regmap_write(rt5668->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); - regmap_write(rt5668->regmap, RT5663_BIAS_CUR_8, 0x4702); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_1, 0xf2be); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_2, 0x8400); + regmap_write(rt5663->regmap, RT5663_CHOP_ADC, 0x3000); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5663->regmap, RT5663_PWR_DIG_1, 0x8df8); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_2, 0x0003); + regmap_write(rt5663->regmap, RT5663_PWR_ANLG_3, 0x018c); + regmap_write(rt5663->regmap, RT5663_ADDA_CLK_1, 0x1111); + regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_1, 0xffff); + regmap_write(rt5663->regmap, RT5663_PRE_DIV_GATING_2, 0xffff); + regmap_write(rt5663->regmap, RT5663_DEPOP_2, 0x3003); + regmap_write(rt5663->regmap, RT5663_DEPOP_1, 0x003b); + regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_1, 0x1e32); + regmap_write(rt5663->regmap, RT5663_HP_CHARGE_PUMP_2, 0x1371); + regmap_write(rt5663->regmap, RT5663_DACREF_LDO, 0x3b0b); + regmap_write(rt5663->regmap, RT5663_STO_DAC_MIXER, 0x2080); + regmap_write(rt5663->regmap, RT5663_BYPASS_STO_DAC, 0x000c); + regmap_write(rt5663->regmap, RT5663_HP_BIAS, 0xabba); + regmap_write(rt5663->regmap, RT5663_CHARGE_PUMP_1, 0x2224); + regmap_write(rt5663->regmap, RT5663_HP_OUT_EN, 0x8088); + regmap_write(rt5663->regmap, RT5663_STO_DRE_9, 0x0017); + regmap_write(rt5663->regmap, RT5663_STO_DRE_10, 0x0017); + regmap_write(rt5663->regmap, RT5663_STO1_ADC_MIXER, 0x4040); + regmap_write(rt5663->regmap, RT5663_RECMIX, 0x0005); + regmap_write(rt5663->regmap, RT5663_ADDA_RST, 0xc000); + regmap_write(rt5663->regmap, RT5663_STO1_HPF_ADJ1, 0x3320); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_2, 0x00c9); + regmap_write(rt5663->regmap, RT5663_DUMMY_1, 0x004c); + regmap_write(rt5663->regmap, RT5663_ANA_BIAS_CUR_1, 0x7766); + regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0x4702); msleep(200); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1, 0x0069); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_3, 0x06c2); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0x7b00); - regmap_write(rt5668->regmap, RT5663_HP_CALIB_1_1, 0xfb00); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1, 0x0069); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_3, 0x06c2); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0x7b00); + regmap_write(rt5663->regmap, RT5663_HP_CALIB_1_1, 0xfb00); count = 0; while (true) { - regmap_read(rt5668->regmap, RT5663_HP_CALIB_1_1, &value); + regmap_read(rt5663->regmap, RT5663_HP_CALIB_1_1, &value); if (value & 0x8000) usleep_range(10000, 10005); else @@ -3066,17 +3064,17 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, } regmap_read(regmap, RT5663_VENDOR_ID_2, &val); switch (val) { - case RT5668_DEVICE_ID: - rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5668_regmap); - rt5663->codec_type = CODEC_TYPE_RT5668; + case RT5663_DEVICE_ID_2: + rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_v2_regmap); + rt5663->codec_ver = CODEC_VER_1; break; - case RT5663_DEVICE_ID: + case RT5663_DEVICE_ID_1: rt5663->regmap = devm_regmap_init_i2c(i2c, &rt5663_regmap); - rt5663->codec_type = CODEC_TYPE_RT5663; + rt5663->codec_ver = CODEC_VER_0; break; default: dev_err(&i2c->dev, - "Device with ID register %#x is not rt5663 or rt5668\n", + "Device with ID register %#x is not rt5663\n", val); return -ENODEV; } @@ -3091,11 +3089,11 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, /* reset and calibrate */ regmap_write(rt5663->regmap, RT5663_RESET, 0); regcache_cache_bypass(rt5663->regmap, true); - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: - rt5668_calibrate(rt5663); + switch (rt5663->codec_ver) { + case CODEC_VER_1: + rt5663_v2_calibrate(rt5663); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: rt5663_calibrate(rt5663); break; default: @@ -3106,44 +3104,44 @@ static int rt5663_i2c_probe(struct i2c_client *i2c, dev_dbg(&i2c->dev, "calibrate done\n"); /* GPIO1 as IRQ */ - regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5668_GP1_PIN_MASK, - RT5668_GP1_PIN_IRQ); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, RT5663_GP1_PIN_MASK, + RT5663_GP1_PIN_IRQ); /* 4btn inline command debounce */ regmap_update_bits(rt5663->regmap, RT5663_IL_CMD_5, - RT5668_4BTN_CLK_DEB_MASK, RT5668_4BTN_CLK_DEB_65MS); + RT5663_4BTN_CLK_DEB_MASK, RT5663_4BTN_CLK_DEB_65MS); - switch (rt5663->codec_type) { - case CODEC_TYPE_RT5668: + switch (rt5663->codec_ver) { + case CODEC_VER_1: regmap_write(rt5663->regmap, RT5663_BIAS_CUR_8, 0xa402); /* JD1 */ regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, - RT5668_IRQ_POW_SAV_MASK | RT5668_IRQ_POW_SAV_JD1_MASK, - RT5668_IRQ_POW_SAV_EN | RT5668_IRQ_POW_SAV_JD1_EN); + RT5663_IRQ_POW_SAV_MASK | RT5663_IRQ_POW_SAV_JD1_MASK, + RT5663_IRQ_POW_SAV_EN | RT5663_IRQ_POW_SAV_JD1_EN); regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_2, - RT5668_PWR_JD1_MASK, RT5668_PWR_JD1); + RT5663_PWR_JD1_MASK, RT5663_PWR_JD1); regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, - RT5668_EN_CB_JD_MASK, RT5668_EN_CB_JD_EN); + RT5663_EN_CB_JD_MASK, RT5663_EN_CB_JD_EN); regmap_update_bits(rt5663->regmap, RT5663_HP_LOGIC_2, - RT5668_HP_SIG_SRC1_MASK, RT5668_HP_SIG_SRC1_REG); + RT5663_HP_SIG_SRC1_MASK, RT5663_HP_SIG_SRC1_REG); regmap_update_bits(rt5663->regmap, RT5663_RECMIX, - RT5668_VREF_BIAS_MASK | RT5668_CBJ_DET_MASK | - RT5668_DET_TYPE_MASK, RT5668_VREF_BIAS_REG | - RT5668_CBJ_DET_EN | RT5668_DET_TYPE_QFN); + RT5663_VREF_BIAS_MASK | RT5663_CBJ_DET_MASK | + RT5663_DET_TYPE_MASK, RT5663_VREF_BIAS_REG | + RT5663_CBJ_DET_EN | RT5663_DET_TYPE_QFN); /* Set GPIO4 and GPIO8 as input for combo jack */ regmap_update_bits(rt5663->regmap, RT5663_GPIO_2, - RT5668_GP4_PIN_CONF_MASK, RT5668_GP4_PIN_CONF_INPUT); - regmap_update_bits(rt5663->regmap, RT5668_GPIO_3, - RT5668_GP8_PIN_CONF_MASK, RT5668_GP8_PIN_CONF_INPUT); + RT5663_GP4_PIN_CONF_MASK, RT5663_GP4_PIN_CONF_INPUT); + regmap_update_bits(rt5663->regmap, RT5663_GPIO_3, + RT5663_GP8_PIN_CONF_MASK, RT5663_GP8_PIN_CONF_INPUT); regmap_update_bits(rt5663->regmap, RT5663_PWR_ANLG_1, - RT5668_LDO1_DVO_MASK | RT5668_AMP_HP_MASK, - RT5668_LDO1_DVO_0_9V | RT5668_AMP_HP_3X); + RT5663_LDO1_DVO_MASK | RT5663_AMP_HP_MASK, + RT5663_LDO1_DVO_0_9V | RT5663_AMP_HP_3X); break; - case CODEC_TYPE_RT5663: + case CODEC_VER_0: regmap_update_bits(rt5663->regmap, RT5663_DIG_MISC, - RT5668_DIG_GATE_CTRL_MASK, RT5668_DIG_GATE_CTRL_EN); + RT5663_DIG_GATE_CTRL_MASK, RT5663_DIG_GATE_CTRL_EN); regmap_update_bits(rt5663->regmap, RT5663_AUTO_1MRC_CLK, - RT5668_IRQ_POW_SAV_MASK, RT5668_IRQ_POW_SAV_EN); + RT5663_IRQ_POW_SAV_MASK, RT5663_IRQ_POW_SAV_EN); regmap_update_bits(rt5663->regmap, RT5663_IRQ_1, RT5663_EN_IRQ_JD1_MASK, RT5663_EN_IRQ_JD1_EN); regmap_update_bits(rt5663->regmap, RT5663_GPIO_1, diff --git a/sound/soc/codecs/rt5663.h b/sound/soc/codecs/rt5663.h index 252c2761791e..d77fae619f2f 100644 --- a/sound/soc/codecs/rt5663.h +++ b/sound/soc/codecs/rt5663.h @@ -18,655 +18,652 @@ #define RT5663_VENDOR_ID_1 0x00fe #define RT5663_VENDOR_ID_2 0x00ff -#define RT5668_LOUT_CTRL 0x0001 -#define RT5668_HP_AMP_2 0x0003 -#define RT5668_MONO_OUT 0x0004 -#define RT5668_MONO_GAIN 0x0007 - -#define RT5668_AEC_BST 0x000b -#define RT5668_IN1_IN2 0x000c -#define RT5668_IN3_IN4 0x000d -#define RT5668_INL1_INR1 0x000f -#define RT5668_CBJ_TYPE_2 0x0011 -#define RT5668_CBJ_TYPE_3 0x0012 -#define RT5668_CBJ_TYPE_4 0x0013 -#define RT5668_CBJ_TYPE_5 0x0014 -#define RT5668_CBJ_TYPE_8 0x0017 +#define RT5663_LOUT_CTRL 0x0001 +#define RT5663_HP_AMP_2 0x0003 +#define RT5663_MONO_OUT 0x0004 +#define RT5663_MONO_GAIN 0x0007 + +#define RT5663_AEC_BST 0x000b +#define RT5663_IN1_IN2 0x000c +#define RT5663_IN3_IN4 0x000d +#define RT5663_INL1_INR1 0x000f +#define RT5663_CBJ_TYPE_2 0x0011 +#define RT5663_CBJ_TYPE_3 0x0012 +#define RT5663_CBJ_TYPE_4 0x0013 +#define RT5663_CBJ_TYPE_5 0x0014 +#define RT5663_CBJ_TYPE_8 0x0017 /* I/O - ADC/DAC/DMIC */ -#define RT5668_DAC3_DIG_VOL 0x001a -#define RT5668_DAC3_CTRL 0x001b -#define RT5668_MONO_ADC_DIG_VOL 0x001d -#define RT5668_STO2_ADC_DIG_VOL 0x001e -#define RT5668_MONO_ADC_BST_GAIN 0x0020 -#define RT5668_STO2_ADC_BST_GAIN 0x0021 -#define RT5668_SIDETONE_CTRL 0x0024 +#define RT5663_DAC3_DIG_VOL 0x001a +#define RT5663_DAC3_CTRL 0x001b +#define RT5663_MONO_ADC_DIG_VOL 0x001d +#define RT5663_STO2_ADC_DIG_VOL 0x001e +#define RT5663_MONO_ADC_BST_GAIN 0x0020 +#define RT5663_STO2_ADC_BST_GAIN 0x0021 +#define RT5663_SIDETONE_CTRL 0x0024 /* Mixer - D-D */ -#define RT5668_MONO1_ADC_MIXER 0x0027 -#define RT5668_STO2_ADC_MIXER 0x0028 -#define RT5668_MONO_DAC_MIXER 0x002b -#define RT5668_DAC2_SRC_CTRL 0x002e -#define RT5668_IF_3_4_DATA_CTL 0x002f -#define RT5668_IF_5_DATA_CTL 0x0030 -#define RT5668_PDM_OUT_CTL 0x0031 -#define RT5668_PDM_I2C_DATA_CTL1 0x0032 -#define RT5668_PDM_I2C_DATA_CTL2 0x0033 -#define RT5668_PDM_I2C_DATA_CTL3 0x0034 -#define RT5668_PDM_I2C_DATA_CTL4 0x0035 +#define RT5663_MONO1_ADC_MIXER 0x0027 +#define RT5663_STO2_ADC_MIXER 0x0028 +#define RT5663_MONO_DAC_MIXER 0x002b +#define RT5663_DAC2_SRC_CTRL 0x002e +#define RT5663_IF_3_4_DATA_CTL 0x002f +#define RT5663_IF_5_DATA_CTL 0x0030 +#define RT5663_PDM_OUT_CTL 0x0031 +#define RT5663_PDM_I2C_DATA_CTL1 0x0032 +#define RT5663_PDM_I2C_DATA_CTL2 0x0033 +#define RT5663_PDM_I2C_DATA_CTL3 0x0034 +#define RT5663_PDM_I2C_DATA_CTL4 0x0035 /*Mixer - Analog*/ -#define RT5668_RECMIX1_NEW 0x003a -#define RT5668_RECMIX1L_0 0x003b -#define RT5668_RECMIX1L 0x003c -#define RT5668_RECMIX1R_0 0x003d -#define RT5668_RECMIX1R 0x003e -#define RT5668_RECMIX2_NEW 0x003f -#define RT5668_RECMIX2_L_2 0x0041 -#define RT5668_RECMIX2_R 0x0042 -#define RT5668_RECMIX2_R_2 0x0043 -#define RT5668_CALIB_REC_LR 0x0044 -#define RT5668_ALC_BK_GAIN 0x0049 -#define RT5668_MONOMIX_GAIN 0x004a -#define RT5668_MONOMIX_IN_GAIN 0x004b -#define RT5668_OUT_MIXL_GAIN 0x004d -#define RT5668_OUT_LMIX_IN_GAIN 0x004e -#define RT5668_OUT_RMIX_IN_GAIN 0x004f -#define RT5668_OUT_RMIX_IN_GAIN1 0x0050 -#define RT5668_LOUT_MIXER_CTRL 0x0052 +#define RT5663_RECMIX1_NEW 0x003a +#define RT5663_RECMIX1L_0 0x003b +#define RT5663_RECMIX1L 0x003c +#define RT5663_RECMIX1R_0 0x003d +#define RT5663_RECMIX1R 0x003e +#define RT5663_RECMIX2_NEW 0x003f +#define RT5663_RECMIX2_L_2 0x0041 +#define RT5663_RECMIX2_R 0x0042 +#define RT5663_RECMIX2_R_2 0x0043 +#define RT5663_CALIB_REC_LR 0x0044 +#define RT5663_ALC_BK_GAIN 0x0049 +#define RT5663_MONOMIX_GAIN 0x004a +#define RT5663_MONOMIX_IN_GAIN 0x004b +#define RT5663_OUT_MIXL_GAIN 0x004d +#define RT5663_OUT_LMIX_IN_GAIN 0x004e +#define RT5663_OUT_RMIX_IN_GAIN 0x004f +#define RT5663_OUT_RMIX_IN_GAIN1 0x0050 +#define RT5663_LOUT_MIXER_CTRL 0x0052 /* Power */ -#define RT5668_PWR_VOL 0x0067 +#define RT5663_PWR_VOL 0x0067 -#define RT5668_ADCDAC_RST 0x006d +#define RT5663_ADCDAC_RST 0x006d /* Format - ADC/DAC */ -#define RT5668_I2S34_SDP 0x0071 -#define RT5668_I2S5_SDP 0x0072 -/* Format - TDM Control */ -#define RT5668_TDM_5 0x007c -#define RT5668_TDM_6 0x007d -#define RT5668_TDM_7 0x007e -#define RT5668_TDM_8 0x007f +#define RT5663_I2S34_SDP 0x0071 +#define RT5663_I2S5_SDP 0x0072 /* Function - Analog */ -#define RT5668_ASRC_3 0x0085 -#define RT5668_ASRC_6 0x0088 -#define RT5668_ASRC_7 0x0089 -#define RT5668_PLL_TRK_13 0x0099 -#define RT5668_I2S_M_CLK_CTL 0x00a0 -#define RT5668_FDIV_I2S34_M_CLK 0x00a1 -#define RT5668_FDIV_I2S34_M_CLK2 0x00a2 -#define RT5668_FDIV_I2S5_M_CLK 0x00a3 -#define RT5668_FDIV_I2S5_M_CLK2 0x00a4 +#define RT5663_ASRC_3 0x0085 +#define RT5663_ASRC_6 0x0088 +#define RT5663_ASRC_7 0x0089 +#define RT5663_PLL_TRK_13 0x0099 +#define RT5663_I2S_M_CLK_CTL 0x00a0 +#define RT5663_FDIV_I2S34_M_CLK 0x00a1 +#define RT5663_FDIV_I2S34_M_CLK2 0x00a2 +#define RT5663_FDIV_I2S5_M_CLK 0x00a3 +#define RT5663_FDIV_I2S5_M_CLK2 0x00a4 /* Function - Digital */ -#define RT5668_IRQ_4 0x00b9 -#define RT5668_GPIO_3 0x00c2 -#define RT5668_GPIO_4 0x00c3 -#define RT5668_GPIO_STA 0x00c4 -#define RT5668_HP_AMP_DET1 0x00d0 -#define RT5668_HP_AMP_DET2 0x00d1 -#define RT5668_HP_AMP_DET3 0x00d2 -#define RT5668_MID_BD_HP_AMP 0x00d3 -#define RT5668_LOW_BD_HP_AMP 0x00d4 -#define RT5668_SOF_VOL_ZC2 0x00da -#define RT5668_ADC_STO2_ADJ1 0x00ee -#define RT5668_ADC_STO2_ADJ2 0x00ef +#define RT5663_V2_IRQ_4 0x00b9 +#define RT5663_GPIO_3 0x00c2 +#define RT5663_GPIO_4 0x00c3 +#define RT5663_GPIO_STA2 0x00c4 +#define RT5663_HP_AMP_DET1 0x00d0 +#define RT5663_HP_AMP_DET2 0x00d1 +#define RT5663_HP_AMP_DET3 0x00d2 +#define RT5663_MID_BD_HP_AMP 0x00d3 +#define RT5663_LOW_BD_HP_AMP 0x00d4 +#define RT5663_SOF_VOL_ZC2 0x00da +#define RT5663_ADC_STO2_ADJ1 0x00ee +#define RT5663_ADC_STO2_ADJ2 0x00ef /* General Control */ -#define RT5668_A_JD_CTRL 0x00f0 -#define RT5668_JD1_TRES_CTRL 0x00f1 -#define RT5668_JD2_TRES_CTRL 0x00f2 -#define RT5668_JD_CTRL2 0x00f7 -#define RT5668_DUM_REG_2 0x00fb -#define RT5668_DUM_REG_3 0x00fc - - -#define RT5668_DACADC_DIG_VOL2 0x0101 -#define RT5668_DIG_IN_PIN2 0x0133 -#define RT5668_PAD_DRV_CTL1 0x0136 -#define RT5668_SOF_RAM_DEPOP 0x0138 -#define RT5668_VOL_TEST 0x013f -#define RT5668_TEST_MODE_3 0x0147 -#define RT5668_TEST_MODE_4 0x0148 -#define RT5668_MONO_DYNA_1 0x0170 -#define RT5668_MONO_DYNA_2 0x0171 -#define RT5668_MONO_DYNA_3 0x0172 -#define RT5668_MONO_DYNA_4 0x0173 -#define RT5668_MONO_DYNA_5 0x0174 -#define RT5668_MONO_DYNA_6 0x0175 -#define RT5668_STO1_SIL_DET 0x0190 -#define RT5668_MONOL_SIL_DET 0x0191 -#define RT5668_MONOR_SIL_DET 0x0192 -#define RT5668_STO2_DAC_SIL 0x0193 -#define RT5668_PWR_SAV_CTL1 0x0194 -#define RT5668_PWR_SAV_CTL2 0x0195 -#define RT5668_PWR_SAV_CTL3 0x0196 -#define RT5668_PWR_SAV_CTL4 0x0197 -#define RT5668_PWR_SAV_CTL5 0x0198 -#define RT5668_PWR_SAV_CTL6 0x0199 -#define RT5668_MONO_AMP_CAL1 0x01a0 -#define RT5668_MONO_AMP_CAL2 0x01a1 -#define RT5668_MONO_AMP_CAL3 0x01a2 -#define RT5668_MONO_AMP_CAL4 0x01a3 -#define RT5668_MONO_AMP_CAL5 0x01a4 -#define RT5668_MONO_AMP_CAL6 0x01a5 -#define RT5668_MONO_AMP_CAL7 0x01a6 -#define RT5668_MONO_AMP_CAL_ST1 0x01a7 -#define RT5668_MONO_AMP_CAL_ST2 0x01a8 -#define RT5668_MONO_AMP_CAL_ST3 0x01a9 -#define RT5668_MONO_AMP_CAL_ST4 0x01aa -#define RT5668_MONO_AMP_CAL_ST5 0x01ab -#define RT5668_HP_IMP_SEN_13 0x01b9 -#define RT5668_HP_IMP_SEN_14 0x01ba -#define RT5668_HP_IMP_SEN_6 0x01bb -#define RT5668_HP_IMP_SEN_7 0x01bc -#define RT5668_HP_IMP_SEN_8 0x01bd -#define RT5668_HP_IMP_SEN_9 0x01be -#define RT5668_HP_IMP_SEN_10 0x01bf -#define RT5668_HP_LOGIC_3 0x01dc -#define RT5668_HP_CALIB_ST10 0x01f3 -#define RT5668_HP_CALIB_ST11 0x01f4 -#define RT5668_PRO_REG_TBL_4 0x0203 -#define RT5668_PRO_REG_TBL_5 0x0204 -#define RT5668_PRO_REG_TBL_6 0x0205 -#define RT5668_PRO_REG_TBL_7 0x0206 -#define RT5668_PRO_REG_TBL_8 0x0207 -#define RT5668_PRO_REG_TBL_9 0x0208 -#define RT5668_SAR_ADC_INL_1 0x0210 -#define RT5668_SAR_ADC_INL_2 0x0211 -#define RT5668_SAR_ADC_INL_3 0x0212 -#define RT5668_SAR_ADC_INL_4 0x0213 -#define RT5668_SAR_ADC_INL_5 0x0214 -#define RT5668_SAR_ADC_INL_6 0x0215 -#define RT5668_SAR_ADC_INL_7 0x0216 -#define RT5668_SAR_ADC_INL_8 0x0217 -#define RT5668_SAR_ADC_INL_9 0x0218 -#define RT5668_SAR_ADC_INL_10 0x0219 -#define RT5668_SAR_ADC_INL_11 0x021a -#define RT5668_SAR_ADC_INL_12 0x021b -#define RT5668_DRC_CTRL_1 0x02ff -#define RT5668_DRC1_CTRL_2 0x0301 -#define RT5668_DRC1_CTRL_3 0x0302 -#define RT5668_DRC1_CTRL_4 0x0303 -#define RT5668_DRC1_CTRL_5 0x0304 -#define RT5668_DRC1_CTRL_6 0x0305 -#define RT5668_DRC1_HD_CTRL_1 0x0306 -#define RT5668_DRC1_HD_CTRL_2 0x0307 -#define RT5668_DRC1_PRI_REG_1 0x0310 -#define RT5668_DRC1_PRI_REG_2 0x0311 -#define RT5668_DRC1_PRI_REG_3 0x0312 -#define RT5668_DRC1_PRI_REG_4 0x0313 -#define RT5668_DRC1_PRI_REG_5 0x0314 -#define RT5668_DRC1_PRI_REG_6 0x0315 -#define RT5668_DRC1_PRI_REG_7 0x0316 -#define RT5668_DRC1_PRI_REG_8 0x0317 -#define RT5668_ALC_PGA_CTL_1 0x0330 -#define RT5668_ALC_PGA_CTL_2 0x0331 -#define RT5668_ALC_PGA_CTL_3 0x0332 -#define RT5668_ALC_PGA_CTL_4 0x0333 -#define RT5668_ALC_PGA_CTL_5 0x0334 -#define RT5668_ALC_PGA_CTL_6 0x0335 -#define RT5668_ALC_PGA_CTL_7 0x0336 -#define RT5668_ALC_PGA_CTL_8 0x0337 -#define RT5668_ALC_PGA_REG_1 0x0338 -#define RT5668_ALC_PGA_REG_2 0x0339 -#define RT5668_ALC_PGA_REG_3 0x033a -#define RT5668_ADC_EQ_RECOV_1 0x03c0 -#define RT5668_ADC_EQ_RECOV_2 0x03c1 -#define RT5668_ADC_EQ_RECOV_3 0x03c2 -#define RT5668_ADC_EQ_RECOV_4 0x03c3 -#define RT5668_ADC_EQ_RECOV_5 0x03c4 -#define RT5668_ADC_EQ_RECOV_6 0x03c5 -#define RT5668_ADC_EQ_RECOV_7 0x03c6 -#define RT5668_ADC_EQ_RECOV_8 0x03c7 -#define RT5668_ADC_EQ_RECOV_9 0x03c8 -#define RT5668_ADC_EQ_RECOV_10 0x03c9 -#define RT5668_ADC_EQ_RECOV_11 0x03ca -#define RT5668_ADC_EQ_RECOV_12 0x03cb -#define RT5668_ADC_EQ_RECOV_13 0x03cc -#define RT5668_VID_HIDDEN 0x03fe -#define RT5668_VID_CUSTOMER 0x03ff -#define RT5668_SCAN_MODE 0x07f0 -#define RT5668_I2C_BYPA 0x07fa +#define RT5663_A_JD_CTRL 0x00f0 +#define RT5663_JD1_TRES_CTRL 0x00f1 +#define RT5663_JD2_TRES_CTRL 0x00f2 +#define RT5663_V2_JD_CTRL2 0x00f7 +#define RT5663_DUM_REG_2 0x00fb +#define RT5663_DUM_REG_3 0x00fc + + +#define RT5663_DACADC_DIG_VOL2 0x0101 +#define RT5663_DIG_IN_PIN2 0x0133 +#define RT5663_PAD_DRV_CTL1 0x0136 +#define RT5663_SOF_RAM_DEPOP 0x0138 +#define RT5663_VOL_TEST 0x013f +#define RT5663_MONO_DYNA_1 0x0170 +#define RT5663_MONO_DYNA_2 0x0171 +#define RT5663_MONO_DYNA_3 0x0172 +#define RT5663_MONO_DYNA_4 0x0173 +#define RT5663_MONO_DYNA_5 0x0174 +#define RT5663_MONO_DYNA_6 0x0175 +#define RT5663_STO1_SIL_DET 0x0190 +#define RT5663_MONOL_SIL_DET 0x0191 +#define RT5663_MONOR_SIL_DET 0x0192 +#define RT5663_STO2_DAC_SIL 0x0193 +#define RT5663_PWR_SAV_CTL1 0x0194 +#define RT5663_PWR_SAV_CTL2 0x0195 +#define RT5663_PWR_SAV_CTL3 0x0196 +#define RT5663_PWR_SAV_CTL4 0x0197 +#define RT5663_PWR_SAV_CTL5 0x0198 +#define RT5663_PWR_SAV_CTL6 0x0199 +#define RT5663_MONO_AMP_CAL1 0x01a0 +#define RT5663_MONO_AMP_CAL2 0x01a1 +#define RT5663_MONO_AMP_CAL3 0x01a2 +#define RT5663_MONO_AMP_CAL4 0x01a3 +#define RT5663_MONO_AMP_CAL5 0x01a4 +#define RT5663_MONO_AMP_CAL6 0x01a5 +#define RT5663_MONO_AMP_CAL7 0x01a6 +#define RT5663_MONO_AMP_CAL_ST1 0x01a7 +#define RT5663_MONO_AMP_CAL_ST2 0x01a8 +#define RT5663_MONO_AMP_CAL_ST3 0x01a9 +#define RT5663_MONO_AMP_CAL_ST4 0x01aa +#define RT5663_MONO_AMP_CAL_ST5 0x01ab +#define RT5663_V2_HP_IMP_SEN_13 0x01b9 +#define RT5663_V2_HP_IMP_SEN_14 0x01ba +#define RT5663_V2_HP_IMP_SEN_6 0x01bb +#define RT5663_V2_HP_IMP_SEN_7 0x01bc +#define RT5663_V2_HP_IMP_SEN_8 0x01bd +#define RT5663_V2_HP_IMP_SEN_9 0x01be +#define RT5663_V2_HP_IMP_SEN_10 0x01bf +#define RT5663_HP_LOGIC_3 0x01dc +#define RT5663_HP_CALIB_ST10 0x01f3 +#define RT5663_HP_CALIB_ST11 0x01f4 +#define RT5663_PRO_REG_TBL_4 0x0203 +#define RT5663_PRO_REG_TBL_5 0x0204 +#define RT5663_PRO_REG_TBL_6 0x0205 +#define RT5663_PRO_REG_TBL_7 0x0206 +#define RT5663_PRO_REG_TBL_8 0x0207 +#define RT5663_PRO_REG_TBL_9 0x0208 +#define RT5663_SAR_ADC_INL_1 0x0210 +#define RT5663_SAR_ADC_INL_2 0x0211 +#define RT5663_SAR_ADC_INL_3 0x0212 +#define RT5663_SAR_ADC_INL_4 0x0213 +#define RT5663_SAR_ADC_INL_5 0x0214 +#define RT5663_SAR_ADC_INL_6 0x0215 +#define RT5663_SAR_ADC_INL_7 0x0216 +#define RT5663_SAR_ADC_INL_8 0x0217 +#define RT5663_SAR_ADC_INL_9 0x0218 +#define RT5663_SAR_ADC_INL_10 0x0219 +#define RT5663_SAR_ADC_INL_11 0x021a +#define RT5663_SAR_ADC_INL_12 0x021b +#define RT5663_DRC_CTRL_1 0x02ff +#define RT5663_DRC1_CTRL_2 0x0301 +#define RT5663_DRC1_CTRL_3 0x0302 +#define RT5663_DRC1_CTRL_4 0x0303 +#define RT5663_DRC1_CTRL_5 0x0304 +#define RT5663_DRC1_CTRL_6 0x0305 +#define RT5663_DRC1_HD_CTRL_1 0x0306 +#define RT5663_DRC1_HD_CTRL_2 0x0307 +#define RT5663_DRC1_PRI_REG_1 0x0310 +#define RT5663_DRC1_PRI_REG_2 0x0311 +#define RT5663_DRC1_PRI_REG_3 0x0312 +#define RT5663_DRC1_PRI_REG_4 0x0313 +#define RT5663_DRC1_PRI_REG_5 0x0314 +#define RT5663_DRC1_PRI_REG_6 0x0315 +#define RT5663_DRC1_PRI_REG_7 0x0316 +#define RT5663_DRC1_PRI_REG_8 0x0317 +#define RT5663_ALC_PGA_CTL_1 0x0330 +#define RT5663_ALC_PGA_CTL_2 0x0331 +#define RT5663_ALC_PGA_CTL_3 0x0332 +#define RT5663_ALC_PGA_CTL_4 0x0333 +#define RT5663_ALC_PGA_CTL_5 0x0334 +#define RT5663_ALC_PGA_CTL_6 0x0335 +#define RT5663_ALC_PGA_CTL_7 0x0336 +#define RT5663_ALC_PGA_CTL_8 0x0337 +#define RT5663_ALC_PGA_REG_1 0x0338 +#define RT5663_ALC_PGA_REG_2 0x0339 +#define RT5663_ALC_PGA_REG_3 0x033a +#define RT5663_ADC_EQ_RECOV_1 0x03c0 +#define RT5663_ADC_EQ_RECOV_2 0x03c1 +#define RT5663_ADC_EQ_RECOV_3 0x03c2 +#define RT5663_ADC_EQ_RECOV_4 0x03c3 +#define RT5663_ADC_EQ_RECOV_5 0x03c4 +#define RT5663_ADC_EQ_RECOV_6 0x03c5 +#define RT5663_ADC_EQ_RECOV_7 0x03c6 +#define RT5663_ADC_EQ_RECOV_8 0x03c7 +#define RT5663_ADC_EQ_RECOV_9 0x03c8 +#define RT5663_ADC_EQ_RECOV_10 0x03c9 +#define RT5663_ADC_EQ_RECOV_11 0x03ca +#define RT5663_ADC_EQ_RECOV_12 0x03cb +#define RT5663_ADC_EQ_RECOV_13 0x03cc +#define RT5663_VID_HIDDEN 0x03fe +#define RT5663_VID_CUSTOMER 0x03ff +#define RT5663_SCAN_MODE 0x07f0 +#define RT5663_I2C_BYPA 0x07fa /* Headphone Amp Control 2 (0x0003) */ -#define RT5668_EN_DAC_HPO_MASK (0x1 << 14) -#define RT5668_EN_DAC_HPO_SHIFT 14 -#define RT5668_EN_DAC_HPO_DIS (0x0 << 14) -#define RT5668_EN_DAC_HPO_EN (0x1 << 14) +#define RT5663_EN_DAC_HPO_MASK (0x1 << 14) +#define RT5663_EN_DAC_HPO_SHIFT 14 +#define RT5663_EN_DAC_HPO_DIS (0x0 << 14) +#define RT5663_EN_DAC_HPO_EN (0x1 << 14) /*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ -#define RT5668_GAIN_HP (0x1f << 8) -#define RT5668_GAIN_HP_SHIFT 8 +#define RT5663_GAIN_HP (0x1f << 8) +#define RT5663_GAIN_HP_SHIFT 8 /* AEC BST Control (0x000b) */ -#define RT5668_GAIN_CBJ_MASK (0xf << 8) -#define RT5668_GAIN_CBJ_SHIFT 8 +#define RT5663_GAIN_CBJ_MASK (0xf << 8) +#define RT5663_GAIN_CBJ_SHIFT 8 /* IN1 Control / MIC GND REF (0x000c) */ -#define RT5668_IN1_DF_MASK (0x1 << 15) -#define RT5668_IN1_DF_SHIFT 15 +#define RT5663_IN1_DF_MASK (0x1 << 15) +#define RT5663_IN1_DF_SHIFT 15 /* Combo Jack and Type Detection Control 1 (0x0010) */ -#define RT5668_CBJ_DET_MASK (0x1 << 15) -#define RT5668_CBJ_DET_SHIFT 15 -#define RT5668_CBJ_DET_DIS (0x0 << 15) -#define RT5668_CBJ_DET_EN (0x1 << 15) -#define RT5668_DET_TYPE_MASK (0x1 << 12) -#define RT5668_DET_TYPE_SHIFT 12 -#define RT5668_DET_TYPE_WLCSP (0x0 << 12) -#define RT5668_DET_TYPE_QFN (0x1 << 12) -#define RT5668_VREF_BIAS_MASK (0x1 << 6) -#define RT5668_VREF_BIAS_SHIFT 6 -#define RT5668_VREF_BIAS_FSM (0x0 << 6) -#define RT5668_VREF_BIAS_REG (0x1 << 6) +#define RT5663_CBJ_DET_MASK (0x1 << 15) +#define RT5663_CBJ_DET_SHIFT 15 +#define RT5663_CBJ_DET_DIS (0x0 << 15) +#define RT5663_CBJ_DET_EN (0x1 << 15) +#define RT5663_DET_TYPE_MASK (0x1 << 12) +#define RT5663_DET_TYPE_SHIFT 12 +#define RT5663_DET_TYPE_WLCSP (0x0 << 12) +#define RT5663_DET_TYPE_QFN (0x1 << 12) +#define RT5663_VREF_BIAS_MASK (0x1 << 6) +#define RT5663_VREF_BIAS_SHIFT 6 +#define RT5663_VREF_BIAS_FSM (0x0 << 6) +#define RT5663_VREF_BIAS_REG (0x1 << 6) /* REC Left Mixer Control 2 (0x003c) */ -#define RT5668_RECMIX1L_BST1_CBJ (0x1 << 7) -#define RT5668_RECMIX1L_BST1_CBJ_SHIFT 7 -#define RT5668_RECMIX1L_BST2 (0x1 << 4) -#define RT5668_RECMIX1L_BST2_SHIFT 4 +#define RT5663_RECMIX1L_BST1_CBJ (0x1 << 7) +#define RT5663_RECMIX1L_BST1_CBJ_SHIFT 7 +#define RT5663_RECMIX1L_BST2 (0x1 << 4) +#define RT5663_RECMIX1L_BST2_SHIFT 4 /* REC Right Mixer Control 2 (0x003e) */ -#define RT5668_RECMIX1R_BST2 (0x1 << 4) -#define RT5668_RECMIX1R_BST2_SHIFT 4 +#define RT5663_RECMIX1R_BST2 (0x1 << 4) +#define RT5663_RECMIX1R_BST2_SHIFT 4 /* DAC1 Digital Volume (0x0019) */ -#define RT5668_DAC_L1_VOL_MASK (0xff << 8) -#define RT5668_DAC_L1_VOL_SHIFT 8 -#define RT5668_DAC_R1_VOL_MASK (0xff) -#define RT5668_DAC_R1_VOL_SHIFT 0 +#define RT5663_DAC_L1_VOL_MASK (0xff << 8) +#define RT5663_DAC_L1_VOL_SHIFT 8 +#define RT5663_DAC_R1_VOL_MASK (0xff) +#define RT5663_DAC_R1_VOL_SHIFT 0 /* ADC Digital Volume Control (0x001c) */ -#define RT5668_ADC_L_MUTE_MASK (0x1 << 15) -#define RT5668_ADC_L_MUTE_SHIFT 15 -#define RT5668_ADC_L_VOL_MASK (0x7f << 8) -#define RT5668_ADC_L_VOL_SHIFT 8 -#define RT5668_ADC_R_MUTE_MASK (0x1 << 7) -#define RT5668_ADC_R_MUTE_SHIFT 7 -#define RT5668_ADC_R_VOL_MASK (0x7f) -#define RT5668_ADC_R_VOL_SHIFT 0 +#define RT5663_ADC_L_MUTE_MASK (0x1 << 15) +#define RT5663_ADC_L_MUTE_SHIFT 15 +#define RT5663_ADC_L_VOL_MASK (0x7f << 8) +#define RT5663_ADC_L_VOL_SHIFT 8 +#define RT5663_ADC_R_MUTE_MASK (0x1 << 7) +#define RT5663_ADC_R_MUTE_SHIFT 7 +#define RT5663_ADC_R_VOL_MASK (0x7f) +#define RT5663_ADC_R_VOL_SHIFT 0 /* Stereo ADC Mixer Control (0x0026) */ -#define RT5668_M_STO1_ADC_L1 (0x1 << 15) -#define RT5668_M_STO1_ADC_L1_SHIFT 15 -#define RT5668_M_STO1_ADC_L2 (0x1 << 14) -#define RT5668_M_STO1_ADC_L2_SHIFT 14 -#define RT5668_STO1_ADC_L1_SRC (0x1 << 13) -#define RT5668_STO1_ADC_L1_SRC_SHIFT 13 -#define RT5668_STO1_ADC_L2_SRC (0x1 << 12) -#define RT5668_STO1_ADC_L2_SRC_SHIFT 12 -#define RT5668_STO1_ADC_L_SRC (0x3 << 10) -#define RT5668_STO1_ADC_L_SRC_SHIFT 10 -#define RT5668_M_STO1_ADC_R1 (0x1 << 7) -#define RT5668_M_STO1_ADC_R1_SHIFT 7 -#define RT5668_M_STO1_ADC_R2 (0x1 << 6) -#define RT5668_M_STO1_ADC_R2_SHIFT 6 -#define RT5668_STO1_ADC_R1_SRC (0x1 << 5) -#define RT5668_STO1_ADC_R1_SRC_SHIFT 5 -#define RT5668_STO1_ADC_R2_SRC (0x1 << 4) -#define RT5668_STO1_ADC_R2_SRC_SHIFT 4 -#define RT5668_STO1_ADC_R_SRC (0x3 << 2) -#define RT5668_STO1_ADC_R_SRC_SHIFT 2 +#define RT5663_M_STO1_ADC_L1 (0x1 << 15) +#define RT5663_M_STO1_ADC_L1_SHIFT 15 +#define RT5663_M_STO1_ADC_L2 (0x1 << 14) +#define RT5663_M_STO1_ADC_L2_SHIFT 14 +#define RT5663_STO1_ADC_L1_SRC (0x1 << 13) +#define RT5663_STO1_ADC_L1_SRC_SHIFT 13 +#define RT5663_STO1_ADC_L2_SRC (0x1 << 12) +#define RT5663_STO1_ADC_L2_SRC_SHIFT 12 +#define RT5663_STO1_ADC_L_SRC (0x3 << 10) +#define RT5663_STO1_ADC_L_SRC_SHIFT 10 +#define RT5663_M_STO1_ADC_R1 (0x1 << 7) +#define RT5663_M_STO1_ADC_R1_SHIFT 7 +#define RT5663_M_STO1_ADC_R2 (0x1 << 6) +#define RT5663_M_STO1_ADC_R2_SHIFT 6 +#define RT5663_STO1_ADC_R1_SRC (0x1 << 5) +#define RT5663_STO1_ADC_R1_SRC_SHIFT 5 +#define RT5663_STO1_ADC_R2_SRC (0x1 << 4) +#define RT5663_STO1_ADC_R2_SRC_SHIFT 4 +#define RT5663_STO1_ADC_R_SRC (0x3 << 2) +#define RT5663_STO1_ADC_R_SRC_SHIFT 2 /* ADC Mixer to DAC Mixer Control (0x0029) */ -#define RT5668_M_ADCMIX_L (0x1 << 15) -#define RT5668_M_ADCMIX_L_SHIFT 15 -#define RT5668_M_DAC1_L (0x1 << 14) -#define RT5668_M_DAC1_L_SHIFT 14 -#define RT5668_M_ADCMIX_R (0x1 << 7) -#define RT5668_M_ADCMIX_R_SHIFT 7 -#define RT5668_M_DAC1_R (0x1 << 6) -#define RT5668_M_DAC1_R_SHIFT 6 +#define RT5663_M_ADCMIX_L (0x1 << 15) +#define RT5663_M_ADCMIX_L_SHIFT 15 +#define RT5663_M_DAC1_L (0x1 << 14) +#define RT5663_M_DAC1_L_SHIFT 14 +#define RT5663_M_ADCMIX_R (0x1 << 7) +#define RT5663_M_ADCMIX_R_SHIFT 7 +#define RT5663_M_DAC1_R (0x1 << 6) +#define RT5663_M_DAC1_R_SHIFT 6 /* Stereo DAC Mixer Control (0x002a) */ -#define RT5668_M_DAC_L1_STO_L (0x1 << 15) -#define RT5668_M_DAC_L1_STO_L_SHIFT 15 -#define RT5668_M_DAC_R1_STO_L (0x1 << 13) -#define RT5668_M_DAC_R1_STO_L_SHIFT 13 -#define RT5668_M_DAC_L1_STO_R (0x1 << 7) -#define RT5668_M_DAC_L1_STO_R_SHIFT 7 -#define RT5668_M_DAC_R1_STO_R (0x1 << 5) -#define RT5668_M_DAC_R1_STO_R_SHIFT 5 +#define RT5663_M_DAC_L1_STO_L (0x1 << 15) +#define RT5663_M_DAC_L1_STO_L_SHIFT 15 +#define RT5663_M_DAC_R1_STO_L (0x1 << 13) +#define RT5663_M_DAC_R1_STO_L_SHIFT 13 +#define RT5663_M_DAC_L1_STO_R (0x1 << 7) +#define RT5663_M_DAC_L1_STO_R_SHIFT 7 +#define RT5663_M_DAC_R1_STO_R (0x1 << 5) +#define RT5663_M_DAC_R1_STO_R_SHIFT 5 /* Power Management for Digital 1 (0x0061) */ -#define RT5668_PWR_I2S1 (0x1 << 15) -#define RT5668_PWR_I2S1_SHIFT 15 -#define RT5668_PWR_DAC_L1 (0x1 << 11) -#define RT5668_PWR_DAC_L1_SHIFT 11 -#define RT5668_PWR_DAC_R1 (0x1 << 10) -#define RT5668_PWR_DAC_R1_SHIFT 10 -#define RT5668_PWR_LDO_DACREF_MASK (0x1 << 8) -#define RT5668_PWR_LDO_DACREF_SHIFT 8 -#define RT5668_PWR_LDO_DACREF_ON (0x1 << 8) -#define RT5668_PWR_LDO_DACREF_DOWN (0x0 << 8) -#define RT5668_PWR_LDO_SHIFT 8 -#define RT5668_PWR_ADC_L1 (0x1 << 4) -#define RT5668_PWR_ADC_L1_SHIFT 4 -#define RT5668_PWR_ADC_R1 (0x1 << 3) -#define RT5668_PWR_ADC_R1_SHIFT 3 +#define RT5663_PWR_I2S1 (0x1 << 15) +#define RT5663_PWR_I2S1_SHIFT 15 +#define RT5663_PWR_DAC_L1 (0x1 << 11) +#define RT5663_PWR_DAC_L1_SHIFT 11 +#define RT5663_PWR_DAC_R1 (0x1 << 10) +#define RT5663_PWR_DAC_R1_SHIFT 10 +#define RT5663_PWR_LDO_DACREF_MASK (0x1 << 8) +#define RT5663_PWR_LDO_DACREF_SHIFT 8 +#define RT5663_PWR_LDO_DACREF_ON (0x1 << 8) +#define RT5663_PWR_LDO_DACREF_DOWN (0x0 << 8) +#define RT5663_PWR_LDO_SHIFT 8 +#define RT5663_PWR_ADC_L1 (0x1 << 4) +#define RT5663_PWR_ADC_L1_SHIFT 4 +#define RT5663_PWR_ADC_R1 (0x1 << 3) +#define RT5663_PWR_ADC_R1_SHIFT 3 /* Power Management for Digital 2 (0x0062) */ -#define RT5668_PWR_ADC_S1F (0x1 << 15) -#define RT5668_PWR_ADC_S1F_SHIFT 15 -#define RT5668_PWR_DAC_S1F (0x1 << 10) -#define RT5668_PWR_DAC_S1F_SHIFT 10 +#define RT5663_PWR_ADC_S1F (0x1 << 15) +#define RT5663_PWR_ADC_S1F_SHIFT 15 +#define RT5663_PWR_DAC_S1F (0x1 << 10) +#define RT5663_PWR_DAC_S1F_SHIFT 10 /* Power Management for Analog 1 (0x0063) */ -#define RT5668_PWR_VREF1 (0x1 << 15) -#define RT5668_PWR_VREF1_MASK (0x1 << 15) -#define RT5668_PWR_VREF1_SHIFT 15 -#define RT5668_PWR_FV1 (0x1 << 14) -#define RT5668_PWR_FV1_MASK (0x1 << 14) -#define RT5668_PWR_FV1_SHIFT 14 -#define RT5668_PWR_VREF2 (0x1 << 13) -#define RT5668_PWR_VREF2_MASK (0x1 << 13) -#define RT5668_PWR_VREF2_SHIFT 13 -#define RT5668_PWR_FV2 (0x1 << 12) -#define RT5668_PWR_FV2_MASK (0x1 << 12) -#define RT5668_PWR_FV2_SHIFT 12 -#define RT5668_PWR_MB (0x1 << 9) -#define RT5668_PWR_MB_MASK (0x1 << 9) -#define RT5668_PWR_MB_SHIFT 9 -#define RT5668_AMP_HP_MASK (0x3 << 2) -#define RT5668_AMP_HP_SHIFT 2 -#define RT5668_AMP_HP_1X (0x0 << 2) -#define RT5668_AMP_HP_3X (0x1 << 2) -#define RT5668_AMP_HP_5X (0x3 << 2) -#define RT5668_LDO1_DVO_MASK (0x3) -#define RT5668_LDO1_DVO_SHIFT 0 -#define RT5668_LDO1_DVO_0_9V (0x0) -#define RT5668_LDO1_DVO_1_0V (0x1) -#define RT5668_LDO1_DVO_1_2V (0x2) -#define RT5668_LDO1_DVO_1_4V (0x3) +#define RT5663_PWR_VREF1 (0x1 << 15) +#define RT5663_PWR_VREF1_MASK (0x1 << 15) +#define RT5663_PWR_VREF1_SHIFT 15 +#define RT5663_PWR_FV1 (0x1 << 14) +#define RT5663_PWR_FV1_MASK (0x1 << 14) +#define RT5663_PWR_FV1_SHIFT 14 +#define RT5663_PWR_VREF2 (0x1 << 13) +#define RT5663_PWR_VREF2_MASK (0x1 << 13) +#define RT5663_PWR_VREF2_SHIFT 13 +#define RT5663_PWR_FV2 (0x1 << 12) +#define RT5663_PWR_FV2_MASK (0x1 << 12) +#define RT5663_PWR_FV2_SHIFT 12 +#define RT5663_PWR_MB (0x1 << 9) +#define RT5663_PWR_MB_MASK (0x1 << 9) +#define RT5663_PWR_MB_SHIFT 9 +#define RT5663_AMP_HP_MASK (0x3 << 2) +#define RT5663_AMP_HP_SHIFT 2 +#define RT5663_AMP_HP_1X (0x0 << 2) +#define RT5663_AMP_HP_3X (0x1 << 2) +#define RT5663_AMP_HP_5X (0x3 << 2) +#define RT5663_LDO1_DVO_MASK (0x3) +#define RT5663_LDO1_DVO_SHIFT 0 +#define RT5663_LDO1_DVO_0_9V (0x0) +#define RT5663_LDO1_DVO_1_0V (0x1) +#define RT5663_LDO1_DVO_1_2V (0x2) +#define RT5663_LDO1_DVO_1_4V (0x3) /* Power Management for Analog 2 (0x0064) */ -#define RT5668_PWR_BST1 (0x1 << 15) -#define RT5668_PWR_BST1_MASK (0x1 << 15) -#define RT5668_PWR_BST1_SHIFT 15 -#define RT5668_PWR_BST1_OFF (0x0 << 15) -#define RT5668_PWR_BST1_ON (0x1 << 15) -#define RT5668_PWR_BST2 (0x1 << 14) -#define RT5668_PWR_BST2_MASK (0x1 << 14) -#define RT5668_PWR_BST2_SHIFT 14 -#define RT5668_PWR_MB1 (0x1 << 11) -#define RT5668_PWR_MB1_SHIFT 11 -#define RT5668_PWR_MB2 (0x1 << 10) -#define RT5668_PWR_MB2_SHIFT 10 -#define RT5668_PWR_BST2_OP (0x1 << 6) -#define RT5668_PWR_BST2_OP_MASK (0x1 << 6) -#define RT5668_PWR_BST2_OP_SHIFT 6 -#define RT5668_PWR_JD1 (0x1 << 3) -#define RT5668_PWR_JD1_MASK (0x1 << 3) -#define RT5668_PWR_JD1_SHIFT 3 -#define RT5668_PWR_JD2 (0x1 << 2) -#define RT5668_PWR_JD2_MASK (0x1 << 2) -#define RT5668_PWR_JD2_SHIFT 2 -#define RT5668_PWR_RECMIX1 (0x1 << 1) -#define RT5668_PWR_RECMIX1_SHIFT 1 -#define RT5668_PWR_RECMIX2 (0x1) -#define RT5668_PWR_RECMIX2_SHIFT 0 +#define RT5663_PWR_BST1 (0x1 << 15) +#define RT5663_PWR_BST1_MASK (0x1 << 15) +#define RT5663_PWR_BST1_SHIFT 15 +#define RT5663_PWR_BST1_OFF (0x0 << 15) +#define RT5663_PWR_BST1_ON (0x1 << 15) +#define RT5663_PWR_BST2 (0x1 << 14) +#define RT5663_PWR_BST2_MASK (0x1 << 14) +#define RT5663_PWR_BST2_SHIFT 14 +#define RT5663_PWR_MB1 (0x1 << 11) +#define RT5663_PWR_MB1_SHIFT 11 +#define RT5663_PWR_MB2 (0x1 << 10) +#define RT5663_PWR_MB2_SHIFT 10 +#define RT5663_PWR_BST2_OP (0x1 << 6) +#define RT5663_PWR_BST2_OP_MASK (0x1 << 6) +#define RT5663_PWR_BST2_OP_SHIFT 6 +#define RT5663_PWR_JD1 (0x1 << 3) +#define RT5663_PWR_JD1_MASK (0x1 << 3) +#define RT5663_PWR_JD1_SHIFT 3 +#define RT5663_PWR_JD2 (0x1 << 2) +#define RT5663_PWR_JD2_MASK (0x1 << 2) +#define RT5663_PWR_JD2_SHIFT 2 +#define RT5663_PWR_RECMIX1 (0x1 << 1) +#define RT5663_PWR_RECMIX1_SHIFT 1 +#define RT5663_PWR_RECMIX2 (0x1) +#define RT5663_PWR_RECMIX2_SHIFT 0 /* Power Management for Analog 3 (0x0065) */ -#define RT5668_PWR_CBJ_MASK (0x1 << 9) -#define RT5668_PWR_CBJ_SHIFT 9 -#define RT5668_PWR_CBJ_OFF (0x0 << 9) -#define RT5668_PWR_CBJ_ON (0x1 << 9) -#define RT5668_PWR_PLL (0x1 << 6) -#define RT5668_PWR_PLL_SHIFT 6 -#define RT5668_PWR_LDO2 (0x1 << 2) -#define RT5668_PWR_LDO2_SHIFT 2 +#define RT5663_PWR_CBJ_MASK (0x1 << 9) +#define RT5663_PWR_CBJ_SHIFT 9 +#define RT5663_PWR_CBJ_OFF (0x0 << 9) +#define RT5663_PWR_CBJ_ON (0x1 << 9) +#define RT5663_PWR_PLL (0x1 << 6) +#define RT5663_PWR_PLL_SHIFT 6 +#define RT5663_PWR_LDO2 (0x1 << 2) +#define RT5663_PWR_LDO2_SHIFT 2 /* Power Management for Volume (0x0067) */ -#define RT5668_PWR_MIC_DET (0x1 << 5) -#define RT5668_PWR_MIC_DET_SHIFT 5 +#define RT5663_V2_PWR_MIC_DET (0x1 << 5) +#define RT5663_V2_PWR_MIC_DET_SHIFT 5 /* MCLK and System Clock Detection Control (0x006b) */ -#define RT5668_EN_ANA_CLK_DET_MASK (0x1 << 15) -#define RT5668_EN_ANA_CLK_DET_SHIFT 15 -#define RT5668_EN_ANA_CLK_DET_DIS (0x0 << 15) -#define RT5668_EN_ANA_CLK_DET_AUTO (0x1 << 15) -#define RT5668_PWR_CLK_DET_MASK (0x1) -#define RT5668_PWR_CLK_DET_SHIFT 0 -#define RT5668_PWR_CLK_DET_DIS (0x0) -#define RT5668_PWR_CLK_DET_EN (0x1) +#define RT5663_EN_ANA_CLK_DET_MASK (0x1 << 15) +#define RT5663_EN_ANA_CLK_DET_SHIFT 15 +#define RT5663_EN_ANA_CLK_DET_DIS (0x0 << 15) +#define RT5663_EN_ANA_CLK_DET_AUTO (0x1 << 15) +#define RT5663_PWR_CLK_DET_MASK (0x1) +#define RT5663_PWR_CLK_DET_SHIFT 0 +#define RT5663_PWR_CLK_DET_DIS (0x0) +#define RT5663_PWR_CLK_DET_EN (0x1) /* I2S1 Audio Serial Data Port Control (0x0070) */ -#define RT5668_I2S_MS_MASK (0x1 << 15) -#define RT5668_I2S_MS_SHIFT 15 -#define RT5668_I2S_MS_M (0x0 << 15) -#define RT5668_I2S_MS_S (0x1 << 15) -#define RT5668_I2S_BP_MASK (0x1 << 8) -#define RT5668_I2S_BP_SHIFT 8 -#define RT5668_I2S_BP_NOR (0x0 << 8) -#define RT5668_I2S_BP_INV (0x1 << 8) -#define RT5668_I2S_DL_MASK (0x3 << 4) -#define RT5668_I2S_DL_SHIFT 4 -#define RT5668_I2S_DL_16 (0x0 << 4) -#define RT5668_I2S_DL_20 (0x1 << 4) -#define RT5668_I2S_DL_24 (0x2 << 4) -#define RT5668_I2S_DL_8 (0x3 << 4) -#define RT5668_I2S_DF_MASK (0x7) -#define RT5668_I2S_DF_SHIFT 0 -#define RT5668_I2S_DF_I2S (0x0) -#define RT5668_I2S_DF_LEFT (0x1) -#define RT5668_I2S_DF_PCM_A (0x2) -#define RT5668_I2S_DF_PCM_B (0x3) -#define RT5668_I2S_DF_PCM_A_N (0x6) -#define RT5668_I2S_DF_PCM_B_N (0x7) +#define RT5663_I2S_MS_MASK (0x1 << 15) +#define RT5663_I2S_MS_SHIFT 15 +#define RT5663_I2S_MS_M (0x0 << 15) +#define RT5663_I2S_MS_S (0x1 << 15) +#define RT5663_I2S_BP_MASK (0x1 << 8) +#define RT5663_I2S_BP_SHIFT 8 +#define RT5663_I2S_BP_NOR (0x0 << 8) +#define RT5663_I2S_BP_INV (0x1 << 8) +#define RT5663_I2S_DL_MASK (0x3 << 4) +#define RT5663_I2S_DL_SHIFT 4 +#define RT5663_I2S_DL_16 (0x0 << 4) +#define RT5663_I2S_DL_20 (0x1 << 4) +#define RT5663_I2S_DL_24 (0x2 << 4) +#define RT5663_I2S_DL_8 (0x3 << 4) +#define RT5663_I2S_DF_MASK (0x7) +#define RT5663_I2S_DF_SHIFT 0 +#define RT5663_I2S_DF_I2S (0x0) +#define RT5663_I2S_DF_LEFT (0x1) +#define RT5663_I2S_DF_PCM_A (0x2) +#define RT5663_I2S_DF_PCM_B (0x3) +#define RT5663_I2S_DF_PCM_A_N (0x6) +#define RT5663_I2S_DF_PCM_B_N (0x7) /* ADC/DAC Clock Control 1 (0x0073) */ -#define RT5668_I2S_PD1_MASK (0x7 << 12) -#define RT5668_I2S_PD1_SHIFT 12 -#define RT5668_M_I2S_DIV_MASK (0x7 << 8) -#define RT5668_M_I2S_DIV_SHIFT 8 -#define RT5668_CLK_SRC_MASK (0x3 << 4) -#define RT5668_CLK_SRC_MCLK (0x0 << 4) -#define RT5668_CLK_SRC_PLL_OUT (0x1 << 4) -#define RT5668_CLK_SRC_DIV (0x2 << 4) -#define RT5668_CLK_SRC_RC (0x3 << 4) -#define RT5668_DAC_OSR_MASK (0x3 << 2) -#define RT5668_DAC_OSR_SHIFT 2 -#define RT5668_DAC_OSR_128 (0x0 << 2) -#define RT5668_DAC_OSR_64 (0x1 << 2) -#define RT5668_DAC_OSR_32 (0x2 << 2) -#define RT5668_ADC_OSR_MASK (0x3) -#define RT5668_ADC_OSR_SHIFT 0 -#define RT5668_ADC_OSR_128 (0x0) -#define RT5668_ADC_OSR_64 (0x1) -#define RT5668_ADC_OSR_32 (0x2) +#define RT5663_I2S_PD1_MASK (0x7 << 12) +#define RT5663_I2S_PD1_SHIFT 12 +#define RT5663_M_I2S_DIV_MASK (0x7 << 8) +#define RT5663_M_I2S_DIV_SHIFT 8 +#define RT5663_CLK_SRC_MASK (0x3 << 4) +#define RT5663_CLK_SRC_MCLK (0x0 << 4) +#define RT5663_CLK_SRC_PLL_OUT (0x1 << 4) +#define RT5663_CLK_SRC_DIV (0x2 << 4) +#define RT5663_CLK_SRC_RC (0x3 << 4) +#define RT5663_DAC_OSR_MASK (0x3 << 2) +#define RT5663_DAC_OSR_SHIFT 2 +#define RT5663_DAC_OSR_128 (0x0 << 2) +#define RT5663_DAC_OSR_64 (0x1 << 2) +#define RT5663_DAC_OSR_32 (0x2 << 2) +#define RT5663_ADC_OSR_MASK (0x3) +#define RT5663_ADC_OSR_SHIFT 0 +#define RT5663_ADC_OSR_128 (0x0) +#define RT5663_ADC_OSR_64 (0x1) +#define RT5663_ADC_OSR_32 (0x2) /* TDM1 control 1 (0x0078) */ -#define RT5668_TDM_MODE_MASK (0x1 << 15) -#define RT5668_TDM_MODE_SHIFT 15 -#define RT5668_TDM_MODE_I2S (0x0 << 15) -#define RT5668_TDM_MODE_TDM (0x1 << 15) -#define RT5668_TDM_IN_CH_MASK (0x3 << 10) -#define RT5668_TDM_IN_CH_SHIFT 10 -#define RT5668_TDM_IN_CH_2 (0x0 << 10) -#define RT5668_TDM_IN_CH_4 (0x1 << 10) -#define RT5668_TDM_IN_CH_6 (0x2 << 10) -#define RT5668_TDM_IN_CH_8 (0x3 << 10) -#define RT5668_TDM_OUT_CH_MASK (0x3 << 8) -#define RT5668_TDM_OUT_CH_SHIFT 8 -#define RT5668_TDM_OUT_CH_2 (0x0 << 8) -#define RT5668_TDM_OUT_CH_4 (0x1 << 8) -#define RT5668_TDM_OUT_CH_6 (0x2 << 8) -#define RT5668_TDM_OUT_CH_8 (0x3 << 8) -#define RT5668_TDM_IN_LEN_MASK (0x3 << 6) -#define RT5668_TDM_IN_LEN_SHIFT 6 -#define RT5668_TDM_IN_LEN_16 (0x0 << 6) -#define RT5668_TDM_IN_LEN_20 (0x1 << 6) -#define RT5668_TDM_IN_LEN_24 (0x2 << 6) -#define RT5668_TDM_IN_LEN_32 (0x3 << 6) -#define RT5668_TDM_OUT_LEN_MASK (0x3 << 4) -#define RT5668_TDM_OUT_LEN_SHIFT 4 -#define RT5668_TDM_OUT_LEN_16 (0x0 << 4) -#define RT5668_TDM_OUT_LEN_20 (0x1 << 4) -#define RT5668_TDM_OUT_LEN_24 (0x2 << 4) -#define RT5668_TDM_OUT_LEN_32 (0x3 << 4) +#define RT5663_TDM_MODE_MASK (0x1 << 15) +#define RT5663_TDM_MODE_SHIFT 15 +#define RT5663_TDM_MODE_I2S (0x0 << 15) +#define RT5663_TDM_MODE_TDM (0x1 << 15) +#define RT5663_TDM_IN_CH_MASK (0x3 << 10) +#define RT5663_TDM_IN_CH_SHIFT 10 +#define RT5663_TDM_IN_CH_2 (0x0 << 10) +#define RT5663_TDM_IN_CH_4 (0x1 << 10) +#define RT5663_TDM_IN_CH_6 (0x2 << 10) +#define RT5663_TDM_IN_CH_8 (0x3 << 10) +#define RT5663_TDM_OUT_CH_MASK (0x3 << 8) +#define RT5663_TDM_OUT_CH_SHIFT 8 +#define RT5663_TDM_OUT_CH_2 (0x0 << 8) +#define RT5663_TDM_OUT_CH_4 (0x1 << 8) +#define RT5663_TDM_OUT_CH_6 (0x2 << 8) +#define RT5663_TDM_OUT_CH_8 (0x3 << 8) +#define RT5663_TDM_IN_LEN_MASK (0x3 << 6) +#define RT5663_TDM_IN_LEN_SHIFT 6 +#define RT5663_TDM_IN_LEN_16 (0x0 << 6) +#define RT5663_TDM_IN_LEN_20 (0x1 << 6) +#define RT5663_TDM_IN_LEN_24 (0x2 << 6) +#define RT5663_TDM_IN_LEN_32 (0x3 << 6) +#define RT5663_TDM_OUT_LEN_MASK (0x3 << 4) +#define RT5663_TDM_OUT_LEN_SHIFT 4 +#define RT5663_TDM_OUT_LEN_16 (0x0 << 4) +#define RT5663_TDM_OUT_LEN_20 (0x1 << 4) +#define RT5663_TDM_OUT_LEN_24 (0x2 << 4) +#define RT5663_TDM_OUT_LEN_32 (0x3 << 4) /* Global Clock Control (0x0080) */ -#define RT5668_SCLK_SRC_MASK (0x3 << 14) -#define RT5668_SCLK_SRC_SHIFT 14 -#define RT5668_SCLK_SRC_MCLK (0x0 << 14) -#define RT5668_SCLK_SRC_PLL1 (0x1 << 14) -#define RT5668_SCLK_SRC_RCCLK (0x2 << 14) -#define RT5668_PLL1_SRC_MASK (0x7 << 8) -#define RT5668_PLL1_SRC_SHIFT 8 -#define RT5668_PLL1_SRC_MCLK (0x0 << 8) -#define RT5668_PLL1_SRC_BCLK1 (0x1 << 8) -#define RT5668_PLL1_PD_MASK (0x1 << 4) -#define RT5668_PLL1_PD_SHIFT 4 - -#define RT5668_PLL_INP_MAX 40000000 -#define RT5668_PLL_INP_MIN 256000 +#define RT5663_SCLK_SRC_MASK (0x3 << 14) +#define RT5663_SCLK_SRC_SHIFT 14 +#define RT5663_SCLK_SRC_MCLK (0x0 << 14) +#define RT5663_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5663_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5663_PLL1_SRC_MASK (0x7 << 11) +#define RT5663_PLL1_SRC_SHIFT 11 +#define RT5663_PLL1_SRC_MCLK (0x0 << 11) +#define RT5663_PLL1_SRC_BCLK1 (0x1 << 11) +#define RT5663_V2_PLL1_SRC_MASK (0x7 << 8) +#define RT5663_V2_PLL1_SRC_SHIFT 8 +#define RT5663_V2_PLL1_SRC_MCLK (0x0 << 8) +#define RT5663_V2_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5663_PLL1_PD_MASK (0x1 << 4) +#define RT5663_PLL1_PD_SHIFT 4 + +#define RT5663_PLL_INP_MAX 40000000 +#define RT5663_PLL_INP_MIN 256000 /* PLL M/N/K Code Control 1 (0x0081) */ -#define RT5668_PLL_N_MAX 0x001ff -#define RT5668_PLL_N_MASK (RT5668_PLL_N_MAX << 7) -#define RT5668_PLL_N_SHIFT 7 -#define RT5668_PLL_K_MAX 0x001f -#define RT5668_PLL_K_MASK (RT5668_PLL_K_MAX) -#define RT5668_PLL_K_SHIFT 0 +#define RT5663_PLL_N_MAX 0x001ff +#define RT5663_PLL_N_MASK (RT5663_PLL_N_MAX << 7) +#define RT5663_PLL_N_SHIFT 7 +#define RT5663_PLL_K_MAX 0x001f +#define RT5663_PLL_K_MASK (RT5663_PLL_K_MAX) +#define RT5663_PLL_K_SHIFT 0 /* PLL M/N/K Code Control 2 (0x0082) */ -#define RT5668_PLL_M_MAX 0x00f -#define RT5668_PLL_M_MASK (RT5668_PLL_M_MAX << 12) -#define RT5668_PLL_M_SHIFT 12 -#define RT5668_PLL_M_BP (0x1 << 11) -#define RT5668_PLL_M_BP_SHIFT 11 +#define RT5663_PLL_M_MAX 0x00f +#define RT5663_PLL_M_MASK (RT5663_PLL_M_MAX << 12) +#define RT5663_PLL_M_SHIFT 12 +#define RT5663_PLL_M_BP (0x1 << 11) +#define RT5663_PLL_M_BP_SHIFT 11 /* PLL tracking mode 1 (0x0083) */ -#define RT5668_I2S1_ASRC_MASK (0x1 << 13) -#define RT5668_I2S1_ASRC_SHIFT 13 -#define RT5668_DAC_STO1_ASRC_MASK (0x1 << 12) -#define RT5668_DAC_STO1_ASRC_SHIFT 12 -#define RT5668_ADC_STO1_ASRC_MASK (0x1 << 4) -#define RT5668_ADC_STO1_ASRC_SHIFT 4 +#define RT5663_V2_I2S1_ASRC_MASK (0x1 << 13) +#define RT5663_V2_I2S1_ASRC_SHIFT 13 +#define RT5663_V2_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5663_V2_DAC_STO1_ASRC_SHIFT 12 +#define RT5663_V2_ADC_STO1_ASRC_MASK (0x1 << 4) +#define RT5663_V2_ADC_STO1_ASRC_SHIFT 4 /* PLL tracking mode 2 (0x0084)*/ -#define RT5668_DA_STO1_TRACK_MASK (0x7 << 12) -#define RT5668_DA_STO1_TRACK_SHIFT 12 -#define RT5668_DA_STO1_TRACK_SYSCLK (0x0 << 12) -#define RT5668_DA_STO1_TRACK_I2S1 (0x1 << 12) +#define RT5663_DA_STO1_TRACK_MASK (0x7 << 12) +#define RT5663_DA_STO1_TRACK_SHIFT 12 +#define RT5663_DA_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5663_DA_STO1_TRACK_I2S1 (0x1 << 12) /* PLL tracking mode 3 (0x0085)*/ -#define RT5668_AD_STO1_TRACK_MASK (0x7 << 12) -#define RT5668_AD_STO1_TRACK_SHIFT 12 -#define RT5668_AD_STO1_TRACK_SYSCLK (0x0 << 12) -#define RT5668_AD_STO1_TRACK_I2S1 (0x1 << 12) +#define RT5663_V2_AD_STO1_TRACK_MASK (0x7 << 12) +#define RT5663_V2_AD_STO1_TRACK_SHIFT 12 +#define RT5663_V2_AD_STO1_TRACK_SYSCLK (0x0 << 12) +#define RT5663_V2_AD_STO1_TRACK_I2S1 (0x1 << 12) /* HPOUT Charge pump control 1 (0x0091) */ -#define RT5668_OSW_HP_L_MASK (0x1 << 11) -#define RT5668_OSW_HP_L_SHIFT 11 -#define RT5668_OSW_HP_L_EN (0x1 << 11) -#define RT5668_OSW_HP_L_DIS (0x0 << 11) -#define RT5668_OSW_HP_R_MASK (0x1 << 10) -#define RT5668_OSW_HP_R_SHIFT 10 -#define RT5668_OSW_HP_R_EN (0x1 << 10) -#define RT5668_OSW_HP_R_DIS (0x0 << 10) -#define RT5668_SEL_PM_HP_MASK (0x3 << 8) -#define RT5668_SEL_PM_HP_SHIFT 8 -#define RT5668_SEL_PM_HP_0_6 (0x0 << 8) -#define RT5668_SEL_PM_HP_0_9 (0x1 << 8) -#define RT5668_SEL_PM_HP_1_8 (0x2 << 8) -#define RT5668_SEL_PM_HP_HIGH (0x3 << 8) -#define RT5668_OVCD_HP_MASK (0x1 << 2) -#define RT5668_OVCD_HP_SHIFT 2 -#define RT5668_OVCD_HP_EN (0x1 << 2) -#define RT5668_OVCD_HP_DIS (0x0 << 2) +#define RT5663_OSW_HP_L_MASK (0x1 << 11) +#define RT5663_OSW_HP_L_SHIFT 11 +#define RT5663_OSW_HP_L_EN (0x1 << 11) +#define RT5663_OSW_HP_L_DIS (0x0 << 11) +#define RT5663_OSW_HP_R_MASK (0x1 << 10) +#define RT5663_OSW_HP_R_SHIFT 10 +#define RT5663_OSW_HP_R_EN (0x1 << 10) +#define RT5663_OSW_HP_R_DIS (0x0 << 10) +#define RT5663_SEL_PM_HP_MASK (0x3 << 8) +#define RT5663_SEL_PM_HP_SHIFT 8 +#define RT5663_SEL_PM_HP_0_6 (0x0 << 8) +#define RT5663_SEL_PM_HP_0_9 (0x1 << 8) +#define RT5663_SEL_PM_HP_1_8 (0x2 << 8) +#define RT5663_SEL_PM_HP_HIGH (0x3 << 8) +#define RT5663_OVCD_HP_MASK (0x1 << 2) +#define RT5663_OVCD_HP_SHIFT 2 +#define RT5663_OVCD_HP_EN (0x1 << 2) +#define RT5663_OVCD_HP_DIS (0x0 << 2) /* RC Clock Control (0x0094) */ -#define RT5668_DIG_25M_CLK_MASK (0x1 << 9) -#define RT5668_DIG_25M_CLK_SHIFT 9 -#define RT5668_DIG_25M_CLK_DIS (0x0 << 9) -#define RT5668_DIG_25M_CLK_EN (0x1 << 9) -#define RT5668_DIG_1M_CLK_MASK (0x1 << 8) -#define RT5668_DIG_1M_CLK_SHIFT 8 -#define RT5668_DIG_1M_CLK_DIS (0x0 << 8) -#define RT5668_DIG_1M_CLK_EN (0x1 << 8) +#define RT5663_DIG_25M_CLK_MASK (0x1 << 9) +#define RT5663_DIG_25M_CLK_SHIFT 9 +#define RT5663_DIG_25M_CLK_DIS (0x0 << 9) +#define RT5663_DIG_25M_CLK_EN (0x1 << 9) +#define RT5663_DIG_1M_CLK_MASK (0x1 << 8) +#define RT5663_DIG_1M_CLK_SHIFT 8 +#define RT5663_DIG_1M_CLK_DIS (0x0 << 8) +#define RT5663_DIG_1M_CLK_EN (0x1 << 8) /* Auto Turn On 1M RC CLK (0x009f) */ -#define RT5668_IRQ_POW_SAV_MASK (0x1 << 15) -#define RT5668_IRQ_POW_SAV_SHIFT 15 -#define RT5668_IRQ_POW_SAV_DIS (0x0 << 15) -#define RT5668_IRQ_POW_SAV_EN (0x1 << 15) -#define RT5668_IRQ_POW_SAV_JD1_MASK (0x1 << 14) -#define RT5668_IRQ_POW_SAV_JD1_SHIFT 14 -#define RT5668_IRQ_POW_SAV_JD1_DIS (0x0 << 14) -#define RT5668_IRQ_POW_SAV_JD1_EN (0x1 << 14) +#define RT5663_IRQ_POW_SAV_MASK (0x1 << 15) +#define RT5663_IRQ_POW_SAV_SHIFT 15 +#define RT5663_IRQ_POW_SAV_DIS (0x0 << 15) +#define RT5663_IRQ_POW_SAV_EN (0x1 << 15) +#define RT5663_IRQ_POW_SAV_JD1_MASK (0x1 << 14) +#define RT5663_IRQ_POW_SAV_JD1_SHIFT 14 +#define RT5663_IRQ_POW_SAV_JD1_DIS (0x0 << 14) +#define RT5663_IRQ_POW_SAV_JD1_EN (0x1 << 14) /* IRQ Control 1 (0x00b6) */ -#define RT5668_EN_CB_JD_MASK (0x1 << 3) -#define RT5668_EN_CB_JD_SHIFT 3 -#define RT5668_EN_CB_JD_EN (0x1 << 3) -#define RT5668_EN_CB_JD_DIS (0x0 << 3) +#define RT5663_EN_CB_JD_MASK (0x1 << 3) +#define RT5663_EN_CB_JD_SHIFT 3 +#define RT5663_EN_CB_JD_EN (0x1 << 3) +#define RT5663_EN_CB_JD_DIS (0x0 << 3) /* IRQ Control 3 (0x00b8) */ -#define RT5668_EN_IRQ_INLINE_MASK (0x1 << 6) -#define RT5668_EN_IRQ_INLINE_SHIFT 6 -#define RT5668_EN_IRQ_INLINE_BYP (0x0 << 6) -#define RT5668_EN_IRQ_INLINE_NOR (0x1 << 6) +#define RT5663_V2_EN_IRQ_INLINE_MASK (0x1 << 6) +#define RT5663_V2_EN_IRQ_INLINE_SHIFT 6 +#define RT5663_V2_EN_IRQ_INLINE_BYP (0x0 << 6) +#define RT5663_V2_EN_IRQ_INLINE_NOR (0x1 << 6) /* GPIO Control 1 (0x00c0) */ -#define RT5668_GP1_PIN_MASK (0x1 << 15) -#define RT5668_GP1_PIN_SHIFT 15 -#define RT5668_GP1_PIN_GPIO1 (0x0 << 15) -#define RT5668_GP1_PIN_IRQ (0x1 << 15) +#define RT5663_GP1_PIN_MASK (0x1 << 15) +#define RT5663_GP1_PIN_SHIFT 15 +#define RT5663_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5663_GP1_PIN_IRQ (0x1 << 15) /* GPIO Control 2 (0x00c1) */ -#define RT5668_GP4_PIN_CONF_MASK (0x1 << 5) -#define RT5668_GP4_PIN_CONF_SHIFT 5 -#define RT5668_GP4_PIN_CONF_INPUT (0x0 << 5) -#define RT5668_GP4_PIN_CONF_OUTPUT (0x1 << 5) +#define RT5663_GP4_PIN_CONF_MASK (0x1 << 5) +#define RT5663_GP4_PIN_CONF_SHIFT 5 +#define RT5663_GP4_PIN_CONF_INPUT (0x0 << 5) +#define RT5663_GP4_PIN_CONF_OUTPUT (0x1 << 5) /* GPIO Control 2 (0x00c2) */ -#define RT5668_GP8_PIN_CONF_MASK (0x1 << 13) -#define RT5668_GP8_PIN_CONF_SHIFT 13 -#define RT5668_GP8_PIN_CONF_INPUT (0x0 << 13) -#define RT5668_GP8_PIN_CONF_OUTPUT (0x1 << 13) +#define RT5663_GP8_PIN_CONF_MASK (0x1 << 13) +#define RT5663_GP8_PIN_CONF_SHIFT 13 +#define RT5663_GP8_PIN_CONF_INPUT (0x0 << 13) +#define RT5663_GP8_PIN_CONF_OUTPUT (0x1 << 13) /* 4 Buttons Inline Command Function 1 (0x00df) */ -#define RT5668_4BTN_CLK_DEB_MASK (0x3 << 2) -#define RT5668_4BTN_CLK_DEB_SHIFT 2 -#define RT5668_4BTN_CLK_DEB_8MS (0x0 << 2) -#define RT5668_4BTN_CLK_DEB_16MS (0x1 << 2) -#define RT5668_4BTN_CLK_DEB_32MS (0x2 << 2) -#define RT5668_4BTN_CLK_DEB_65MS (0x3 << 2) +#define RT5663_4BTN_CLK_DEB_MASK (0x3 << 2) +#define RT5663_4BTN_CLK_DEB_SHIFT 2 +#define RT5663_4BTN_CLK_DEB_8MS (0x0 << 2) +#define RT5663_4BTN_CLK_DEB_16MS (0x1 << 2) +#define RT5663_4BTN_CLK_DEB_32MS (0x2 << 2) +#define RT5663_4BTN_CLK_DEB_65MS (0x3 << 2) /* Inline Command Function 6 (0x00e0) */ -#define RT5668_EN_4BTN_INL_MASK (0x1 << 15) -#define RT5668_EN_4BTN_INL_SHIFT 15 -#define RT5668_EN_4BTN_INL_DIS (0x0 << 15) -#define RT5668_EN_4BTN_INL_EN (0x1 << 15) -#define RT5668_RESET_4BTN_INL_MASK (0x1 << 14) -#define RT5668_RESET_4BTN_INL_SHIFT 14 -#define RT5668_RESET_4BTN_INL_RESET (0x0 << 14) -#define RT5668_RESET_4BTN_INL_NOR (0x1 << 14) +#define RT5663_EN_4BTN_INL_MASK (0x1 << 15) +#define RT5663_EN_4BTN_INL_SHIFT 15 +#define RT5663_EN_4BTN_INL_DIS (0x0 << 15) +#define RT5663_EN_4BTN_INL_EN (0x1 << 15) +#define RT5663_RESET_4BTN_INL_MASK (0x1 << 14) +#define RT5663_RESET_4BTN_INL_SHIFT 14 +#define RT5663_RESET_4BTN_INL_RESET (0x0 << 14) +#define RT5663_RESET_4BTN_INL_NOR (0x1 << 14) /* Digital Misc Control (0x00fa) */ -#define RT5668_DIG_GATE_CTRL_MASK 0x1 -#define RT5668_DIG_GATE_CTRL_SHIFT (0) -#define RT5668_DIG_GATE_CTRL_DIS 0x0 -#define RT5668_DIG_GATE_CTRL_EN 0x1 +#define RT5663_DIG_GATE_CTRL_MASK 0x1 +#define RT5663_DIG_GATE_CTRL_SHIFT (0) +#define RT5663_DIG_GATE_CTRL_DIS 0x0 +#define RT5663_DIG_GATE_CTRL_EN 0x1 /* Chopper and Clock control for DAC L (0x013a)*/ -#define RT5668_CKXEN_DAC1_MASK (0x1 << 13) -#define RT5668_CKXEN_DAC1_SHIFT 13 -#define RT5668_CKGEN_DAC1_MASK (0x1 << 12) -#define RT5668_CKGEN_DAC1_SHIFT 12 +#define RT5663_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5663_CKXEN_DAC1_SHIFT 13 +#define RT5663_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5663_CKGEN_DAC1_SHIFT 12 /* Chopper and Clock control for ADC (0x013b)*/ -#define RT5668_CKXEN_ADCC_MASK (0x1 << 13) -#define RT5668_CKXEN_ADCC_SHIFT 13 -#define RT5668_CKGEN_ADCC_MASK (0x1 << 12) -#define RT5668_CKGEN_ADCC_SHIFT 12 +#define RT5663_CKXEN_ADCC_MASK (0x1 << 13) +#define RT5663_CKXEN_ADCC_SHIFT 13 +#define RT5663_CKGEN_ADCC_MASK (0x1 << 12) +#define RT5663_CKGEN_ADCC_SHIFT 12 /* HP Behavior Logic Control 2 (0x01db) */ -#define RT5668_HP_SIG_SRC1_MASK (0x3) -#define RT5668_HP_SIG_SRC1_SHIFT 0 -#define RT5668_HP_SIG_SRC1_HP_DC (0x0) -#define RT5668_HP_SIG_SRC1_HP_CALIB (0x1) -#define RT5668_HP_SIG_SRC1_REG (0x2) -#define RT5668_HP_SIG_SRC1_SILENCE (0x3) +#define RT5663_HP_SIG_SRC1_MASK (0x3) +#define RT5663_HP_SIG_SRC1_SHIFT 0 +#define RT5663_HP_SIG_SRC1_HP_DC (0x0) +#define RT5663_HP_SIG_SRC1_HP_CALIB (0x1) +#define RT5663_HP_SIG_SRC1_REG (0x2) +#define RT5663_HP_SIG_SRC1_SILENCE (0x3) /* RT5663 specific register */ #define RT5663_HP_OUT_EN 0x0002 @@ -707,6 +704,10 @@ #define RT5663_TDM_3 0x0079 #define RT5663_TDM_4 0x007a #define RT5663_TDM_5 0x007b +#define RT5663_TDM_6 0x007c +#define RT5663_TDM_7 0x007d +#define RT5663_TDM_8 0x007e +#define RT5663_TDM_9 0x007f #define RT5663_GLB_CLK 0x0080 #define RT5663_PLL_1 0x0081 #define RT5663_PLL_2 0x0082 @@ -739,7 +740,7 @@ #define RT5663_INT_ST_2 0x00bf #define RT5663_GPIO_1 0x00c0 #define RT5663_GPIO_2 0x00c1 -#define RT5663_GPIO_STA 0x00c5 +#define RT5663_GPIO_STA1 0x00c5 #define RT5663_SIN_GEN_1 0x00cb #define RT5663_SIN_GEN_2 0x00cc #define RT5663_SIN_GEN_3 0x00cd @@ -800,6 +801,8 @@ #define RT5663_TEST_MODE_1 0x0144 #define RT5663_TEST_MODE_2 0x0145 #define RT5663_TEST_MODE_3 0x0146 +#define RT5663_TEST_MODE_4 0x0147 +#define RT5663_TEST_MODE_5 0x0148 #define RT5663_STO_DRE_1 0x0160 #define RT5663_STO_DRE_2 0x0161 #define RT5663_STO_DRE_3 0x0162 @@ -921,19 +924,19 @@ #define RT5663_ADC_EQ_POST_VOL_L 0x03f2 #define RT5663_ADC_EQ_POST_VOL_R 0x03f3 -/* RT5663: RECMIX Control (0x0010) */ +/* RECMIX Control (0x0010) */ #define RT5663_RECMIX1_BST1_MASK (0x1) #define RT5663_RECMIX1_BST1_SHIFT 0 #define RT5663_RECMIX1_BST1_ON (0x0) #define RT5663_RECMIX1_BST1_OFF (0x1) -/* RT5663: Bypass Stereo1 DAC Mixer Control (0x002d) */ +/* Bypass Stereo1 DAC Mixer Control (0x002d) */ #define RT5663_DACL1_SRC_MASK (0x1 << 3) #define RT5663_DACL1_SRC_SHIFT 3 #define RT5663_DACR1_SRC_MASK (0x1 << 2) #define RT5663_DACR1_SRC_SHIFT 2 -/* RT5663: TDM control 2 (0x0078) */ +/* TDM control 2 (0x0078) */ #define RT5663_DATA_SWAP_ADCDAT1_MASK (0x3 << 14) #define RT5663_DATA_SWAP_ADCDAT1_SHIFT 14 #define RT5663_DATA_SWAP_ADCDAT1_LR (0x0 << 14) @@ -941,7 +944,7 @@ #define RT5663_DATA_SWAP_ADCDAT1_LL (0x2 << 14) #define RT5663_DATA_SWAP_ADCDAT1_RR (0x3 << 14) -/* RT5663: TDM control 5 (0x007b) */ +/* TDM control 5 (0x007b) */ #define RT5663_TDM_LENGTN_MASK (0x3) #define RT5663_TDM_LENGTN_SHIFT 0 #define RT5663_TDM_LENGTN_16 (0x0) @@ -949,17 +952,6 @@ #define RT5663_TDM_LENGTN_24 (0x2) #define RT5663_TDM_LENGTN_32 (0x3) -/* RT5663: Global Clock Control (0x0080) */ -#define RT5663_SCLK_SRC_MASK (0x3 << 14) -#define RT5663_SCLK_SRC_SHIFT 14 -#define RT5663_SCLK_SRC_MCLK (0x0 << 14) -#define RT5663_SCLK_SRC_PLL1 (0x1 << 14) -#define RT5663_SCLK_SRC_RCCLK (0x2 << 14) -#define RT5663_PLL1_SRC_MASK (0x7 << 11) -#define RT5663_PLL1_SRC_SHIFT 11 -#define RT5663_PLL1_SRC_MCLK (0x0 << 11) -#define RT5663_PLL1_SRC_BCLK1 (0x1 << 11) - /* PLL tracking mode 1 (0x0083) */ #define RT5663_I2S1_ASRC_MASK (0x1 << 11) #define RT5663_I2S1_ASRC_SHIFT 11 @@ -978,31 +970,31 @@ #define RT5663_AD_STO1_TRACK_SYSCLK (0x0) #define RT5663_AD_STO1_TRACK_I2S1 (0x1) -/* RT5663: HPOUT Charge pump control 1 (0x0091) */ +/* HPOUT Charge pump control 1 (0x0091) */ #define RT5663_SI_HP_MASK (0x1 << 12) #define RT5663_SI_HP_SHIFT 12 #define RT5663_SI_HP_EN (0x1 << 12) #define RT5663_SI_HP_DIS (0x0 << 12) -/* RT5663: GPIO Control 2 (0x00b6) */ +/* GPIO Control 2 (0x00b6) */ #define RT5663_GP1_PIN_CONF_MASK (0x1 << 2) #define RT5663_GP1_PIN_CONF_SHIFT 2 #define RT5663_GP1_PIN_CONF_OUTPUT (0x1 << 2) #define RT5663_GP1_PIN_CONF_INPUT (0x0 << 2) -/* RT5663: GPIO Control 2 (0x00b7) */ +/* GPIO Control 2 (0x00b7) */ #define RT5663_EN_IRQ_INLINE_MASK (0x1 << 3) #define RT5663_EN_IRQ_INLINE_SHIFT 3 #define RT5663_EN_IRQ_INLINE_NOR (0x1 << 3) #define RT5663_EN_IRQ_INLINE_BYP (0x0 << 3) -/* RT5663: GPIO Control 1 (0x00c0) */ +/* GPIO Control 1 (0x00c0) */ #define RT5663_GPIO1_TYPE_MASK (0x1 << 15) #define RT5663_GPIO1_TYPE_SHIFT 15 #define RT5663_GPIO1_TYPE_EN (0x1 << 15) #define RT5663_GPIO1_TYPE_DIS (0x0 << 15) -/* RT5663: IRQ Control 1 (0x00c1) */ +/* IRQ Control 1 (0x00c1) */ #define RT5663_EN_IRQ_JD1_MASK (0x1 << 6) #define RT5663_EN_IRQ_JD1_SHIFT 6 #define RT5663_EN_IRQ_JD1_EN (0x1 << 6) @@ -1012,13 +1004,13 @@ #define RT5663_SEL_GPIO1_EN (0x1 << 2) #define RT5663_SEL_GPIO1_DIS (0x0 << 2) -/* RT5663: Inline Command Function 2 (0x00dc) */ +/* Inline Command Function 2 (0x00dc) */ #define RT5663_PWR_MIC_DET_MASK (0x1) #define RT5663_PWR_MIC_DET_SHIFT 0 #define RT5663_PWR_MIC_DET_ON (0x1) #define RT5663_PWR_MIC_DET_OFF (0x0) -/* RT5663: Embeeded Jack and Type Detection Control 1 (0x00e6)*/ +/* Embeeded Jack and Type Detection Control 1 (0x00e6)*/ #define RT5663_CBJ_DET_MASK (0x1 << 15) #define RT5663_CBJ_DET_SHIFT 15 #define RT5663_CBJ_DET_DIS (0x0 << 15) @@ -1032,17 +1024,17 @@ #define RT5663_POL_EXT_JD_EN (0x1 << 10) #define RT5663_POL_EXT_JD_DIS (0x0 << 10) -/* RT5663: DACREF LDO Control (0x0112)*/ +/* DACREF LDO Control (0x0112)*/ #define RT5663_PWR_LDO_DACREFL_MASK (0x1 << 9) #define RT5663_PWR_LDO_DACREFL_SHIFT 9 #define RT5663_PWR_LDO_DACREFR_MASK (0x1 << 1) #define RT5663_PWR_LDO_DACREFR_SHIFT 1 -/* RT5663: Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ +/* Stereo Dynamic Range Enhancement Control 9 (0x0168, 0x0169)*/ #define RT5663_DRE_GAIN_HP_MASK (0x1f) #define RT5663_DRE_GAIN_HP_SHIFT 0 -/* RT5663: Combo Jack Control (0x0250) */ +/* Combo Jack Control (0x0250) */ #define RT5663_INBUF_CBJ_BST1_MASK (0x1 << 11) #define RT5663_INBUF_CBJ_BST1_SHIFT 11 #define RT5663_INBUF_CBJ_BST1_ON (0x1 << 11) @@ -1052,11 +1044,11 @@ #define RT5663_CBJ_SENSE_BST1_L (0x1 << 10) #define RT5663_CBJ_SENSE_BST1_R (0x0 << 10) -/* RT5663: Combo Jack Control (0x0251) */ +/* Combo Jack Control (0x0251) */ #define RT5663_GAIN_BST1_MASK (0xf) #define RT5663_GAIN_BST1_SHIFT 0 -/* RT5663: Dummy register 1 (0x02fa) */ +/* Dummy register 1 (0x02fa) */ #define RT5663_EMB_CLK_MASK (0x1 << 9) #define RT5663_EMB_CLK_SHIFT 9 #define RT5663_EMB_CLK_EN (0x1 << 9) -- cgit v1.2.3-59-g8ed1b From 585e881e5b9e9b495978e93fcf4ed3fedb0b8cdb Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 20 Oct 2016 15:20:45 +0100 Subject: ASoC: codecs: Add msm8916-wcd analog codec msm8916-wcd codec is found in Qualcomm msm8916 and apq8016 processors. This codec IP is split in to two parts (Digital & Analog). Analog part is integrated in to PMIC PM8916 and the digital part is integrated into Application processor. Data transfer between Analog and Digital Die is done via a internal bus called PDM. This patch adds support to Analog part of the Codec which is integrated into PMIC PM8916. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- .../bindings/sound/qcom,msm8916-wcd-analog.txt | 85 ++ sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 3 +- sound/soc/codecs/msm8916-wcd-analog.c | 890 +++++++++++++++++++++ 4 files changed, 981 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt create mode 100644 sound/soc/codecs/msm8916-wcd-analog.c (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt new file mode 100644 index 000000000000..ccb401cfef9d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-analog.txt @@ -0,0 +1,85 @@ +msm8916 analog audio CODEC + +Bindings for codec Analog IP which is integrated in pmic pm8916, + +## Bindings for codec core on pmic: + +Required properties + - compatible = "qcom,pm8916-wcd-analog-codec"; + - reg: represents the slave base address provided to the peripheral. + - interrupt-parent : The parent interrupt controller. + - interrupts: List of interrupts in given SPMI peripheral. + - interrupt-names: Names specified to above list of interrupts in same + order. List of supported interrupt names are: + "cdc_spk_cnp_int" - Speaker click and pop interrupt. + "cdc_spk_clip_int" - Speaker clip interrupt. + "cdc_spk_ocp_int" - Speaker over current protect interrupt. + "mbhc_ins_rem_det1" - jack insert removal detect interrupt 1. + "mbhc_but_rel_det" - button release interrupt. + "mbhc_but_press_det" - button press event + "mbhc_ins_rem_det" - jack insert removal detect interrupt. + "mbhc_switch_int" - multi button headset interrupt. + "cdc_ear_ocp_int" - Earphone over current protect interrupt. + "cdc_hphr_ocp_int" - Headphone R over current protect interrupt. + "cdc_hphl_ocp_det" - Headphone L over current protect interrupt. + "cdc_ear_cnp_int" - earphone cnp interrupt. + "cdc_hphr_cnp_int" - hphr click and pop interrupt. + "cdc_hphl_cnp_int" - hphl click and pop interrupt. + + - clocks: Handle to mclk. + - clock-names: should be "mclk" + - vdd-cdc-io-supply: phandle to VDD_CDC_IO regulator DT node. + - vdd-cdc-tx-rx-cx-supply: phandle to VDD_CDC_TX/RX/CX regulator DT node. + - vdd-micbias-supply: phandle of VDD_MICBIAS supply's regulator DT node. + +Optional Properties: +- qcom,micbias1-ext-cap: boolean, present if micbias1 has external capacitor + connected. +- qcom,micbias2-ext-cap: boolean, present if micbias2 has external capacitor + connected. + +Example: + +spmi_bus { + ... + audio-codec@f000{ + compatible = "qcom,pm8916-wcd-analog-codec"; + reg = <0xf000 0x200>; + reg-names = "pmic-codec-core"; + clocks = <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "mclk"; + interrupt-parent = <&spmi_bus>; + interrupts = <0x1 0xf0 0x0 IRQ_TYPE_NONE>, + <0x1 0xf0 0x1 IRQ_TYPE_NONE>, + <0x1 0xf0 0x2 IRQ_TYPE_NONE>, + <0x1 0xf0 0x3 IRQ_TYPE_NONE>, + <0x1 0xf0 0x4 IRQ_TYPE_NONE>, + <0x1 0xf0 0x5 IRQ_TYPE_NONE>, + <0x1 0xf0 0x6 IRQ_TYPE_NONE>, + <0x1 0xf0 0x7 IRQ_TYPE_NONE>, + <0x1 0xf1 0x0 IRQ_TYPE_NONE>, + <0x1 0xf1 0x1 IRQ_TYPE_NONE>, + <0x1 0xf1 0x2 IRQ_TYPE_NONE>, + <0x1 0xf1 0x3 IRQ_TYPE_NONE>, + <0x1 0xf1 0x4 IRQ_TYPE_NONE>, + <0x1 0xf1 0x5 IRQ_TYPE_NONE>; + interrupt-names = "cdc_spk_cnp_int", + "cdc_spk_clip_int", + "cdc_spk_ocp_int", + "mbhc_ins_rem_det1", + "mbhc_but_rel_det", + "mbhc_but_press_det", + "mbhc_ins_rem_det", + "mbhc_switch_int", + "cdc_ear_ocp_int", + "cdc_hphr_ocp_int", + "cdc_hphl_ocp_det", + "cdc_ear_cnp_int", + "cdc_hphr_cnp_int", + "cdc_hphl_cnp_int"; + VDD-CDC-IO-supply = <&pm8916_l5>; + VDD-CDC-TX-RX-CX-supply = <&pm8916_l5>; + VDD-MICBIAS-supply = <&pm8916_l13>; + #sound-dai-cells = <1>; + }; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..4a98ce65b993 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -581,6 +581,10 @@ config SND_SOC_MAX9860 depends on I2C select REGMAP_I2C +config SND_SOC_MSM8916_WCD_ANALOG + tristate "Qualcomm MSM8916 WCD Analog Codec" + depends on SPMI || COMPILE_TEST + config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 958cd4912fbc..32d90184f764 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -86,6 +86,7 @@ snd-soc-max9850-objs := max9850.o snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o snd-soc-nau8810-objs := nau8810.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o @@ -214,7 +215,6 @@ snd-soc-wm9705-objs := wm9705.o snd-soc-wm9712-objs := wm9712.o snd-soc-wm9713-objs := wm9713.o snd-soc-wm-hubs-objs := wm_hubs.o - # Amp snd-soc-max9877-objs := max9877.o snd-soc-max98504-objs := max98504.o @@ -310,6 +310,7 @@ obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c new file mode 100644 index 000000000000..d9f999b14b28 --- /dev/null +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -0,0 +1,890 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CDC_D_REVISION1 (0xf000) +#define CDC_D_PERPH_SUBTYPE (0xf005) +#define CDC_D_CDC_RST_CTL (0xf046) +#define RST_CTL_DIG_SW_RST_N_MASK BIT(7) +#define RST_CTL_DIG_SW_RST_N_RESET 0 +#define RST_CTL_DIG_SW_RST_N_REMOVE_RESET BIT(7) + +#define CDC_D_CDC_TOP_CLK_CTL (0xf048) +#define TOP_CLK_CTL_A_MCLK_MCLK2_EN_MASK (BIT(2) | BIT(3)) +#define TOP_CLK_CTL_A_MCLK_EN_ENABLE BIT(2) +#define TOP_CLK_CTL_A_MCLK2_EN_ENABLE BIT(3) + +#define CDC_D_CDC_ANA_CLK_CTL (0xf049) +#define ANA_CLK_CTL_EAR_HPHR_CLK_EN_MASK BIT(0) +#define ANA_CLK_CTL_EAR_HPHR_CLK_EN BIT(0) +#define ANA_CLK_CTL_EAR_HPHL_CLK_EN BIT(1) +#define ANA_CLK_CTL_SPKR_CLK_EN_MASK BIT(4) +#define ANA_CLK_CTL_SPKR_CLK_EN BIT(4) +#define ANA_CLK_CTL_TXA_CLK25_EN BIT(5) + +#define CDC_D_CDC_DIG_CLK_CTL (0xf04A) +#define DIG_CLK_CTL_RXD1_CLK_EN BIT(0) +#define DIG_CLK_CTL_RXD2_CLK_EN BIT(1) +#define DIG_CLK_CTL_RXD3_CLK_EN BIT(3) +#define DIG_CLK_CTL_TXD_CLK_EN BIT(4) +#define DIG_CLK_CTL_NCP_CLK_EN_MASK BIT(6) +#define DIG_CLK_CTL_NCP_CLK_EN BIT(6) +#define DIG_CLK_CTL_RXD_PDM_CLK_EN_MASK BIT(7) +#define DIG_CLK_CTL_RXD_PDM_CLK_EN BIT(7) + +#define CDC_D_CDC_CONN_TX1_CTL (0xf050) +#define CONN_TX1_SERIAL_TX1_MUX GENMASK(1, 0) +#define CONN_TX1_SERIAL_TX1_ADC_1 0x0 +#define CONN_TX1_SERIAL_TX1_RX_PDM_LB 0x1 +#define CONN_TX1_SERIAL_TX1_ZERO 0x2 + +#define CDC_D_CDC_CONN_TX2_CTL (0xf051) +#define CONN_TX2_SERIAL_TX2_MUX GENMASK(1, 0) +#define CONN_TX2_SERIAL_TX2_ADC_2 0x0 +#define CONN_TX2_SERIAL_TX2_RX_PDM_LB 0x1 +#define CONN_TX2_SERIAL_TX2_ZERO 0x2 +#define CDC_D_CDC_CONN_HPHR_DAC_CTL (0xf052) +#define CDC_D_CDC_CONN_RX1_CTL (0xf053) +#define CDC_D_CDC_CONN_RX2_CTL (0xf054) +#define CDC_D_CDC_CONN_RX3_CTL (0xf055) +#define CDC_D_CDC_CONN_RX_LB_CTL (0xf056) +#define CDC_D_SEC_ACCESS (0xf0D0) +#define CDC_D_PERPH_RESET_CTL3 (0xf0DA) +#define CDC_D_PERPH_RESET_CTL4 (0xf0DB) +#define CDC_A_REVISION1 (0xf100) +#define CDC_A_REVISION2 (0xf101) +#define CDC_A_REVISION3 (0xf102) +#define CDC_A_REVISION4 (0xf103) +#define CDC_A_PERPH_TYPE (0xf104) +#define CDC_A_PERPH_SUBTYPE (0xf105) +#define CDC_A_INT_RT_STS (0xf110) +#define CDC_A_INT_SET_TYPE (0xf111) +#define CDC_A_INT_POLARITY_HIGH (0xf112) +#define CDC_A_INT_POLARITY_LOW (0xf113) +#define CDC_A_INT_LATCHED_CLR (0xf114) +#define CDC_A_INT_EN_SET (0xf115) +#define CDC_A_INT_EN_CLR (0xf116) +#define CDC_A_INT_LATCHED_STS (0xf118) +#define CDC_A_INT_PENDING_STS (0xf119) +#define CDC_A_INT_MID_SEL (0xf11A) +#define CDC_A_INT_PRIORITY (0xf11B) +#define CDC_A_MICB_1_EN (0xf140) +#define MICB_1_EN_MICB_ENABLE BIT(7) +#define MICB_1_EN_BYP_CAP_MASK BIT(6) +#define MICB_1_EN_NO_EXT_BYP_CAP BIT(6) +#define MICB_1_EN_EXT_BYP_CAP 0 +#define MICB_1_EN_PULL_DOWN_EN_MASK BIT(5) +#define MICB_1_EN_PULL_DOWN_EN_ENABLE BIT(5) +#define MICB_1_EN_OPA_STG2_TAIL_CURR_MASK GENMASK(3, 1) +#define MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA (0x4) +#define MICB_1_EN_PULL_UP_EN_MASK BIT(4) +#define MICB_1_EN_TX3_GND_SEL_MASK BIT(0) +#define MICB_1_EN_TX3_GND_SEL_TX_GND 0 + +#define CDC_A_MICB_1_VAL (0xf141) +#define MICB_1_VAL_MICB_OUT_VAL_MASK GENMASK(7, 3) +#define MICB_1_VAL_MICB_OUT_VAL_V2P70V ((0x16) << 3) +#define CDC_A_MICB_1_CTL (0xf142) + +#define MICB_1_CTL_CFILT_REF_SEL_MASK BIT(1) +#define MICB_1_CTL_CFILT_REF_SEL_HPF_REF BIT(1) +#define MICB_1_CTL_EXT_PRECHARG_EN_MASK BIT(5) +#define MICB_1_CTL_EXT_PRECHARG_EN_ENABLE BIT(5) +#define MICB_1_CTL_INT_PRECHARG_BYP_MASK BIT(6) +#define MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL BIT(6) + +#define CDC_A_MICB_1_INT_RBIAS (0xf143) +#define MICB_1_INT_TX1_INT_RBIAS_EN_MASK BIT(7) +#define MICB_1_INT_TX1_INT_RBIAS_EN_ENABLE BIT(7) +#define MICB_1_INT_TX1_INT_RBIAS_EN_DISABLE 0 + +#define MICB_1_INT_TX1_INT_PULLUP_EN_MASK BIT(6) +#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(6) +#define MICB_1_INT_TX1_INT_PULLUP_EN_TX1N_TO_GND 0 + +#define MICB_1_INT_TX2_INT_RBIAS_EN_MASK BIT(4) +#define MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE BIT(4) +#define MICB_1_INT_TX2_INT_RBIAS_EN_DISABLE 0 +#define MICB_1_INT_TX2_INT_PULLUP_EN_MASK BIT(3) +#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(3) +#define MICB_1_INT_TX2_INT_PULLUP_EN_TX1N_TO_GND 0 + +#define MICB_1_INT_TX3_INT_RBIAS_EN_MASK BIT(1) +#define MICB_1_INT_TX3_INT_RBIAS_EN_ENABLE BIT(1) +#define MICB_1_INT_TX3_INT_RBIAS_EN_DISABLE 0 +#define MICB_1_INT_TX3_INT_PULLUP_EN_MASK BIT(0) +#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_MICBIAS BIT(0) +#define MICB_1_INT_TX3_INT_PULLUP_EN_TX1N_TO_GND 0 + +#define CDC_A_MICB_2_EN (0xf144) +#define CDC_A_TX_1_2_ATEST_CTL_2 (0xf145) +#define CDC_A_MASTER_BIAS_CTL (0xf146) +#define CDC_A_TX_1_EN (0xf160) +#define CDC_A_TX_2_EN (0xf161) +#define CDC_A_TX_1_2_TEST_CTL_1 (0xf162) +#define CDC_A_TX_1_2_TEST_CTL_2 (0xf163) +#define CDC_A_TX_1_2_ATEST_CTL (0xf164) +#define CDC_A_TX_1_2_OPAMP_BIAS (0xf165) +#define CDC_A_TX_3_EN (0xf167) +#define CDC_A_NCP_EN (0xf180) +#define CDC_A_NCP_CLK (0xf181) +#define CDC_A_NCP_FBCTRL (0xf183) +#define CDC_A_NCP_FBCTRL_FB_CLK_INV_MASK BIT(5) +#define CDC_A_NCP_FBCTRL_FB_CLK_INV BIT(5) +#define CDC_A_NCP_BIAS (0xf184) +#define CDC_A_NCP_VCTRL (0xf185) +#define CDC_A_NCP_TEST (0xf186) +#define CDC_A_NCP_CLIM_ADDR (0xf187) +#define CDC_A_RX_CLOCK_DIVIDER (0xf190) +#define CDC_A_RX_COM_OCP_CTL (0xf191) +#define CDC_A_RX_COM_OCP_COUNT (0xf192) +#define CDC_A_RX_COM_BIAS_DAC (0xf193) +#define RX_COM_BIAS_DAC_RX_BIAS_EN_MASK BIT(7) +#define RX_COM_BIAS_DAC_RX_BIAS_EN_ENABLE BIT(7) +#define RX_COM_BIAS_DAC_DAC_REF_EN_MASK BIT(0) +#define RX_COM_BIAS_DAC_DAC_REF_EN_ENABLE BIT(0) + +#define CDC_A_RX_HPH_BIAS_PA (0xf194) +#define CDC_A_RX_HPH_BIAS_LDO_OCP (0xf195) +#define CDC_A_RX_HPH_BIAS_CNP (0xf196) +#define CDC_A_RX_HPH_CNP_EN (0xf197) +#define CDC_A_RX_HPH_L_PA_DAC_CTL (0xf19B) +#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_MASK BIT(1) +#define RX_HPA_L_PA_DAC_CTL_DATA_RESET_RESET BIT(1) +#define CDC_A_RX_HPH_R_PA_DAC_CTL (0xf19D) +#define RX_HPH_R_PA_DAC_CTL_DATA_RESET BIT(1) +#define RX_HPH_R_PA_DAC_CTL_DATA_RESET_MASK BIT(1) + +#define CDC_A_RX_EAR_CTL (0xf19E) +#define RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK BIT(0) +#define RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE BIT(0) + +#define CDC_A_SPKR_DAC_CTL (0xf1B0) +#define SPKR_DAC_CTL_DAC_RESET_MASK BIT(4) +#define SPKR_DAC_CTL_DAC_RESET_NORMAL 0 + +#define CDC_A_SPKR_DRV_CTL (0xf1B2) +#define SPKR_DRV_CTL_DEF_MASK 0xEF +#define SPKR_DRV_CLASSD_PA_EN_MASK BIT(7) +#define SPKR_DRV_CLASSD_PA_EN_ENABLE BIT(7) +#define SPKR_DRV_CAL_EN BIT(6) +#define SPKR_DRV_SETTLE_EN BIT(5) +#define SPKR_DRV_FW_EN BIT(3) +#define SPKR_DRV_BOOST_SET BIT(2) +#define SPKR_DRV_CMFB_SET BIT(1) +#define SPKR_DRV_GAIN_SET BIT(0) +#define SPKR_DRV_CTL_DEF_VAL (SPKR_DRV_CLASSD_PA_EN_ENABLE | \ + SPKR_DRV_CAL_EN | SPKR_DRV_SETTLE_EN | \ + SPKR_DRV_FW_EN | SPKR_DRV_BOOST_SET | \ + SPKR_DRV_CMFB_SET | SPKR_DRV_GAIN_SET) +#define CDC_A_SPKR_OCP_CTL (0xf1B4) +#define CDC_A_SPKR_PWRSTG_CTL (0xf1B5) +#define SPKR_PWRSTG_CTL_DAC_EN_MASK BIT(0) +#define SPKR_PWRSTG_CTL_DAC_EN BIT(0) +#define SPKR_PWRSTG_CTL_MASK 0xE0 +#define SPKR_PWRSTG_CTL_BBM_MASK BIT(7) +#define SPKR_PWRSTG_CTL_BBM_EN BIT(7) +#define SPKR_PWRSTG_CTL_HBRDGE_EN_MASK BIT(6) +#define SPKR_PWRSTG_CTL_HBRDGE_EN BIT(6) +#define SPKR_PWRSTG_CTL_CLAMP_EN_MASK BIT(5) +#define SPKR_PWRSTG_CTL_CLAMP_EN BIT(5) + +#define CDC_A_SPKR_DRV_DBG (0xf1B7) +#define CDC_A_CURRENT_LIMIT (0xf1C0) +#define CDC_A_BOOST_EN_CTL (0xf1C3) +#define CDC_A_SLOPE_COMP_IP_ZERO (0xf1C4) +#define CDC_A_SEC_ACCESS (0xf1D0) +#define CDC_A_PERPH_RESET_CTL3 (0xf1DA) +#define CDC_A_PERPH_RESET_CTL4 (0xf1DB) + +#define MSM8916_WCD_ANALOG_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000) +#define MSM8916_WCD_ANALOG_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +static const char * const supply_names[] = { + "vdd-cdc-io", + "vdd-cdc-tx-rx-cx", +}; + +struct pm8916_wcd_analog_priv { + u16 pmic_rev; + u16 codec_version; + struct clk *mclk; + struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; + bool micbias1_cap_mode; + bool micbias2_cap_mode; +}; + +static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; +static const char *const rdac2_mux_text[] = { "ZERO", "RX2", "RX1" }; +static const char *const hph_text[] = { "ZERO", "Switch", }; + +static const struct soc_enum hph_enum = SOC_ENUM_SINGLE_VIRT( + ARRAY_SIZE(hph_text), hph_text); + +static const struct snd_kcontrol_new hphl_mux = SOC_DAPM_ENUM("HPHL", hph_enum); +static const struct snd_kcontrol_new hphr_mux = SOC_DAPM_ENUM("HPHR", hph_enum); + +/* ADC2 MUX */ +static const struct soc_enum adc2_enum = SOC_ENUM_SINGLE_VIRT( + ARRAY_SIZE(adc2_mux_text), adc2_mux_text); + +/* RDAC2 MUX */ +static const struct soc_enum rdac2_mux_enum = SOC_ENUM_SINGLE( + CDC_D_CDC_CONN_HPHR_DAC_CTL, 0, 3, rdac2_mux_text); + +static const struct snd_kcontrol_new spkr_switch[] = { + SOC_DAPM_SINGLE("Switch", CDC_A_SPKR_DAC_CTL, 7, 1, 0) +}; + +static const struct snd_kcontrol_new rdac2_mux = SOC_DAPM_ENUM( + "RDAC2 MUX Mux", rdac2_mux_enum); +static const struct snd_kcontrol_new tx_adc2_mux = SOC_DAPM_ENUM( + "ADC2 MUX Mux", adc2_enum); + +/* Analog Gain control 0 dB to +24 dB in 6 dB steps */ +static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 600, 0); + +static const struct snd_kcontrol_new pm8916_wcd_analog_snd_controls[] = { + SOC_SINGLE_TLV("ADC1 Volume", CDC_A_TX_1_EN, 3, 8, 0, analog_gain), + SOC_SINGLE_TLV("ADC2 Volume", CDC_A_TX_2_EN, 3, 8, 0, analog_gain), + SOC_SINGLE_TLV("ADC3 Volume", CDC_A_TX_3_EN, 3, 8, 0, analog_gain), +}; + +static void pm8916_wcd_analog_micbias_enable(struct snd_soc_codec *codec) +{ + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_EXT_PRECHARG_EN_MASK | + MICB_1_CTL_INT_PRECHARG_BYP_MASK, + MICB_1_CTL_INT_PRECHARG_BYP_EXT_PRECHRG_SEL + | MICB_1_CTL_EXT_PRECHARG_EN_ENABLE); + + snd_soc_write(codec, CDC_A_MICB_1_VAL, MICB_1_VAL_MICB_OUT_VAL_V2P70V); + /* + * Special headset needs MICBIAS as 2.7V so wait for + * 50 msec for the MICBIAS to reach 2.7 volts. + */ + msleep(50); + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_EXT_PRECHARG_EN_MASK | + MICB_1_CTL_INT_PRECHARG_BYP_MASK, 0); + +} + +static int pm8916_wcd_analog_enable_micbias_ext(struct snd_soc_codec + *codec, int event, + int reg, u32 cap_mode) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + pm8916_wcd_analog_micbias_enable(codec); + snd_soc_update_bits(codec, CDC_A_MICB_1_EN, + MICB_1_EN_BYP_CAP_MASK, cap_mode); + break; + } + + return 0; +} + +static int pm8916_wcd_analog_enable_micbias_int(struct snd_soc_codec + *codec, int event, + int reg, u32 cap_mode) +{ + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, CDC_A_MICB_1_INT_RBIAS, + MICB_1_INT_TX2_INT_RBIAS_EN_MASK, + MICB_1_INT_TX2_INT_RBIAS_EN_ENABLE); + snd_soc_update_bits(codec, reg, MICB_1_EN_PULL_DOWN_EN_MASK, 0); + snd_soc_update_bits(codec, CDC_A_MICB_1_EN, + MICB_1_EN_OPA_STG2_TAIL_CURR_MASK, + MICB_1_EN_OPA_STG2_TAIL_CURR_1_60UA); + + break; + case SND_SOC_DAPM_POST_PMU: + pm8916_wcd_analog_micbias_enable(codec); + snd_soc_update_bits(codec, CDC_A_MICB_1_EN, + MICB_1_EN_BYP_CAP_MASK, cap_mode); + break; + } + + return 0; +} + +static int pm8916_wcd_analog_enable_micbias_ext1(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg, + wcd->micbias1_cap_mode); +} + +static int pm8916_wcd_analog_enable_micbias_ext2(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_ext(codec, event, w->reg, + wcd->micbias2_cap_mode); + +} + +static int pm8916_wcd_analog_enable_micbias_int2(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, + wcd->micbias2_cap_mode); +} + +static int pm8916_wcd_analog_enable_micbias_int1(struct + snd_soc_dapm_widget + *w, struct snd_kcontrol + *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); + + return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, + wcd->micbias2_cap_mode); +} + +static int pm8916_wcd_analog_enable_adc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + u16 adc_reg = CDC_A_TX_1_2_TEST_CTL_2; + u8 init_bit_shift; + + if (w->reg == CDC_A_TX_1_EN) + init_bit_shift = 5; + else + init_bit_shift = 4; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (w->reg == CDC_A_TX_2_EN) + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_CFILT_REF_SEL_MASK, + MICB_1_CTL_CFILT_REF_SEL_HPF_REF); + /* + * Add delay of 10 ms to give sufficient time for the voltage + * to shoot up and settle so that the txfe init does not + * happen when the input voltage is changing too much. + */ + usleep_range(10000, 10010); + snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, + 1 << init_bit_shift); + switch (w->reg) { + case CDC_A_TX_1_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL, + CONN_TX1_SERIAL_TX1_MUX, + CONN_TX1_SERIAL_TX1_ADC_1); + break; + case CDC_A_TX_2_EN: + case CDC_A_TX_3_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL, + CONN_TX2_SERIAL_TX2_MUX, + CONN_TX2_SERIAL_TX2_ADC_2); + break; + } + break; + case SND_SOC_DAPM_POST_PMU: + /* + * Add delay of 12 ms before deasserting the init + * to reduce the tx pop + */ + usleep_range(12000, 12010); + snd_soc_update_bits(codec, adc_reg, 1 << init_bit_shift, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + switch (w->reg) { + case CDC_A_TX_1_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX1_CTL, + CONN_TX1_SERIAL_TX1_MUX, + CONN_TX1_SERIAL_TX1_ZERO); + break; + case CDC_A_TX_2_EN: + snd_soc_update_bits(codec, CDC_A_MICB_1_CTL, + MICB_1_CTL_CFILT_REF_SEL_MASK, 0); + case CDC_A_TX_3_EN: + snd_soc_update_bits(codec, CDC_D_CDC_CONN_TX2_CTL, + CONN_TX2_SERIAL_TX2_MUX, + CONN_TX2_SERIAL_TX2_ZERO); + break; + } + + + break; + } + return 0; +} + +static int pm8916_wcd_analog_enable_spk_pa(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL, + SPKR_PWRSTG_CTL_DAC_EN_MASK | + SPKR_PWRSTG_CTL_BBM_MASK | + SPKR_PWRSTG_CTL_HBRDGE_EN_MASK | + SPKR_PWRSTG_CTL_CLAMP_EN_MASK, + SPKR_PWRSTG_CTL_DAC_EN| + SPKR_PWRSTG_CTL_BBM_EN | + SPKR_PWRSTG_CTL_HBRDGE_EN | + SPKR_PWRSTG_CTL_CLAMP_EN); + + snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, + RX_EAR_CTL_SPK_VBAT_LDO_EN_ENABLE); + break; + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, CDC_A_SPKR_DRV_CTL, + SPKR_DRV_CTL_DEF_MASK, + SPKR_DRV_CTL_DEF_VAL); + snd_soc_update_bits(codec, w->reg, + SPKR_DRV_CLASSD_PA_EN_MASK, + SPKR_DRV_CLASSD_PA_EN_ENABLE); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, CDC_A_SPKR_PWRSTG_CTL, + SPKR_PWRSTG_CTL_DAC_EN_MASK| + SPKR_PWRSTG_CTL_BBM_MASK | + SPKR_PWRSTG_CTL_HBRDGE_EN_MASK | + SPKR_PWRSTG_CTL_CLAMP_EN_MASK, 0); + + snd_soc_update_bits(codec, CDC_A_SPKR_DAC_CTL, + SPKR_DAC_CTL_DAC_RESET_MASK, + SPKR_DAC_CTL_DAC_RESET_NORMAL); + snd_soc_update_bits(codec, CDC_A_RX_EAR_CTL, + RX_EAR_CTL_SPK_VBAT_LDO_EN_MASK, 0); + break; + } + return 0; +} + +static const struct reg_default wcd_reg_defaults_2_0[] = { + {CDC_A_RX_COM_OCP_CTL, 0xD1}, + {CDC_A_RX_COM_OCP_COUNT, 0xFF}, + {CDC_D_SEC_ACCESS, 0xA5}, + {CDC_D_PERPH_RESET_CTL3, 0x0F}, + {CDC_A_TX_1_2_OPAMP_BIAS, 0x4F}, + {CDC_A_NCP_FBCTRL, 0x28}, + {CDC_A_SPKR_DRV_CTL, 0x69}, + {CDC_A_SPKR_DRV_DBG, 0x01}, + {CDC_A_BOOST_EN_CTL, 0x5F}, + {CDC_A_SLOPE_COMP_IP_ZERO, 0x88}, + {CDC_A_SEC_ACCESS, 0xA5}, + {CDC_A_PERPH_RESET_CTL3, 0x0F}, + {CDC_A_CURRENT_LIMIT, 0x82}, + {CDC_A_SPKR_DAC_CTL, 0x03}, + {CDC_A_SPKR_OCP_CTL, 0xE1}, + {CDC_A_MASTER_BIAS_CTL, 0x30}, +}; + +static int pm8916_wcd_analog_probe(struct snd_soc_codec *codec) +{ + struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); + int err, reg; + + err = regulator_bulk_enable(ARRAY_SIZE(priv->supplies), priv->supplies); + if (err != 0) { + dev_err(codec->dev, "failed to enable regulators (%d)\n", err); + return err; + } + + snd_soc_codec_set_drvdata(codec, priv); + priv->pmic_rev = snd_soc_read(codec, CDC_D_REVISION1); + priv->codec_version = snd_soc_read(codec, CDC_D_PERPH_SUBTYPE); + + dev_info(codec->dev, "PMIC REV: %d\t CODEC Version: %d\n", + priv->pmic_rev, priv->codec_version); + + snd_soc_write(codec, CDC_D_PERPH_RESET_CTL4, 0x01); + snd_soc_write(codec, CDC_A_PERPH_RESET_CTL4, 0x01); + + for (reg = 0; reg < ARRAY_SIZE(wcd_reg_defaults_2_0); reg++) + snd_soc_write(codec, wcd_reg_defaults_2_0[reg].reg, + wcd_reg_defaults_2_0[reg].def); + + return 0; +} + +static int pm8916_wcd_analog_remove(struct snd_soc_codec *codec) +{ + struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(codec->dev); + + return regulator_bulk_disable(ARRAY_SIZE(priv->supplies), + priv->supplies); +} + +static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { + + {"PDM_RX1", NULL, "PDM Playback"}, + {"PDM_RX2", NULL, "PDM Playback"}, + {"PDM_RX3", NULL, "PDM Playback"}, + {"PDM Capture", NULL, "PDM_TX"}, + + /* ADC Connections */ + {"PDM_TX", NULL, "ADC2"}, + {"PDM_TX", NULL, "ADC3"}, + {"ADC2", NULL, "ADC2 MUX"}, + {"ADC3", NULL, "ADC2 MUX"}, + {"ADC2 MUX", "INP2", "ADC2_INP2"}, + {"ADC2 MUX", "INP3", "ADC2_INP3"}, + + {"PDM_TX", NULL, "ADC1"}, + {"ADC1", NULL, "AMIC1"}, + {"ADC2_INP2", NULL, "AMIC2"}, + {"ADC2_INP3", NULL, "AMIC3"}, + + /* RDAC Connections */ + {"HPHR DAC", NULL, "RDAC2 MUX"}, + {"RDAC2 MUX", "RX1", "PDM_RX1"}, + {"RDAC2 MUX", "RX2", "PDM_RX2"}, + {"HPHL DAC", NULL, "PDM_RX1"}, + {"PDM_RX1", NULL, "RXD1_CLK"}, + {"PDM_RX2", NULL, "RXD2_CLK"}, + {"PDM_RX3", NULL, "RXD3_CLK"}, + + {"PDM_RX1", NULL, "RXD_PDM_CLK"}, + {"PDM_RX2", NULL, "RXD_PDM_CLK"}, + {"PDM_RX3", NULL, "RXD_PDM_CLK"}, + + {"ADC1", NULL, "TXD_CLK"}, + {"ADC2", NULL, "TXD_CLK"}, + {"ADC3", NULL, "TXD_CLK"}, + + {"ADC1", NULL, "TXA_CLK25"}, + {"ADC2", NULL, "TXA_CLK25"}, + {"ADC3", NULL, "TXA_CLK25"}, + + {"PDM_RX1", NULL, "A_MCLK2"}, + {"PDM_RX2", NULL, "A_MCLK2"}, + {"PDM_RX3", NULL, "A_MCLK2"}, + + {"PDM_TX", NULL, "A_MCLK2"}, + {"A_MCLK2", NULL, "A_MCLK"}, + + /* Headset (RX MIX1 and RX MIX2) */ + {"HEADPHONE", NULL, "HPHL PA"}, + {"HEADPHONE", NULL, "HPHR PA"}, + + {"HPHL PA", NULL, "EAR_HPHL_CLK"}, + {"HPHR PA", NULL, "EAR_HPHR_CLK"}, + + {"CP", NULL, "NCP_CLK"}, + + {"HPHL PA", NULL, "HPHL"}, + {"HPHR PA", NULL, "HPHR"}, + {"HPHL PA", NULL, "CP"}, + {"HPHL PA", NULL, "RX_BIAS"}, + {"HPHR PA", NULL, "CP"}, + {"HPHR PA", NULL, "RX_BIAS"}, + {"HPHL", "Switch", "HPHL DAC"}, + {"HPHR", "Switch", "HPHR DAC"}, + + {"RX_BIAS", NULL, "DAC_REF"}, + + {"SPK_OUT", NULL, "SPK PA"}, + {"SPK PA", NULL, "RX_BIAS"}, + {"SPK PA", NULL, "SPKR_CLK"}, + {"SPK PA", NULL, "SPK DAC"}, + {"SPK DAC", "Switch", "PDM_RX3"}, + + {"MIC BIAS Internal1", NULL, "INT_LDO_H"}, + {"MIC BIAS Internal2", NULL, "INT_LDO_H"}, + {"MIC BIAS External1", NULL, "INT_LDO_H"}, + {"MIC BIAS External2", NULL, "INT_LDO_H"}, + {"MIC BIAS Internal1", NULL, "vdd-micbias"}, + {"MIC BIAS Internal2", NULL, "vdd-micbias"}, + {"MIC BIAS External1", NULL, "vdd-micbias"}, + {"MIC BIAS External2", NULL, "vdd-micbias"}, +}; + +static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { + + SND_SOC_DAPM_AIF_IN("PDM_RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("PDM_RX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("PDM_RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("PDM_TX", NULL, 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_INPUT("AMIC1"), + SND_SOC_DAPM_INPUT("AMIC3"), + SND_SOC_DAPM_INPUT("AMIC2"), + SND_SOC_DAPM_OUTPUT("HEADPHONE"), + + /* RX stuff */ + SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), + + SND_SOC_DAPM_PGA("HPHL PA", CDC_A_RX_HPH_CNP_EN, 5, 0, NULL, 0), + SND_SOC_DAPM_MUX("HPHL", SND_SOC_NOPM, 0, 0, &hphl_mux), + SND_SOC_DAPM_MIXER("HPHL DAC", CDC_A_RX_HPH_L_PA_DAC_CTL, 3, 0, NULL, + 0), + SND_SOC_DAPM_PGA("HPHR PA", CDC_A_RX_HPH_CNP_EN, 4, 0, NULL, 0), + SND_SOC_DAPM_MUX("HPHR", SND_SOC_NOPM, 0, 0, &hphr_mux), + SND_SOC_DAPM_MIXER("HPHR DAC", CDC_A_RX_HPH_R_PA_DAC_CTL, 3, 0, NULL, + 0), + SND_SOC_DAPM_MIXER("SPK DAC", SND_SOC_NOPM, 0, 0, + spkr_switch, ARRAY_SIZE(spkr_switch)), + + /* Speaker */ + SND_SOC_DAPM_OUTPUT("SPK_OUT"), + SND_SOC_DAPM_PGA_E("SPK PA", CDC_A_SPKR_DRV_CTL, + 6, 0, NULL, 0, + pm8916_wcd_analog_enable_spk_pa, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_REGULATOR_SUPPLY("vdd-micbias", 0, 0), + SND_SOC_DAPM_SUPPLY("CP", CDC_A_NCP_EN, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DAC_REF", CDC_A_RX_COM_BIAS_DAC, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RX_BIAS", CDC_A_RX_COM_BIAS_DAC, 7, 0, NULL, 0), + + /* TX */ + SND_SOC_DAPM_SUPPLY("MIC BIAS Internal1", CDC_A_MICB_1_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_int1, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS Internal2", CDC_A_MICB_2_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_int2, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SUPPLY("MIC BIAS External1", CDC_A_MICB_1_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_ext1, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("MIC BIAS External2", CDC_A_MICB_2_EN, 7, 0, + pm8916_wcd_analog_enable_micbias_ext2, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_ADC_E("ADC1", NULL, CDC_A_TX_1_EN, 7, 0, + pm8916_wcd_analog_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2_INP2", NULL, CDC_A_TX_2_EN, 7, 0, + pm8916_wcd_analog_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("ADC2_INP3", NULL, CDC_A_TX_3_EN, 7, 0, + pm8916_wcd_analog_enable_adc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX("ADC2 MUX", SND_SOC_NOPM, 0, 0, &tx_adc2_mux), + SND_SOC_DAPM_MUX("RDAC2 MUX", SND_SOC_NOPM, 0, 0, &rdac2_mux), + + /* Analog path clocks */ + SND_SOC_DAPM_SUPPLY("EAR_HPHR_CLK", CDC_D_CDC_ANA_CLK_CTL, 0, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY("EAR_HPHL_CLK", CDC_D_CDC_ANA_CLK_CTL, 1, 0, NULL, + 0), + SND_SOC_DAPM_SUPPLY("SPKR_CLK", CDC_D_CDC_ANA_CLK_CTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TXA_CLK25", CDC_D_CDC_ANA_CLK_CTL, 5, 0, NULL, 0), + + /* Digital path clocks */ + + SND_SOC_DAPM_SUPPLY("RXD1_CLK", CDC_D_CDC_DIG_CLK_CTL, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXD2_CLK", CDC_D_CDC_DIG_CLK_CTL, 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXD3_CLK", CDC_D_CDC_DIG_CLK_CTL, 2, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("TXD_CLK", CDC_D_CDC_DIG_CLK_CTL, 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("NCP_CLK", CDC_D_CDC_DIG_CLK_CTL, 6, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RXD_PDM_CLK", CDC_D_CDC_DIG_CLK_CTL, 7, 0, NULL, + 0), + + /* System Clock source */ + SND_SOC_DAPM_SUPPLY("A_MCLK", CDC_D_CDC_TOP_CLK_CTL, 2, 0, NULL, 0), + /* TX ADC and RX DAC Clock source. */ + SND_SOC_DAPM_SUPPLY("A_MCLK2", CDC_D_CDC_TOP_CLK_CTL, 3, 0, NULL, 0), +}; + +static struct regmap *pm8916_get_regmap(struct device *dev) +{ + return dev_get_regmap(dev->parent, NULL); +} + +static int pm8916_wcd_analog_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, + RST_CTL_DIG_SW_RST_N_MASK, + RST_CTL_DIG_SW_RST_N_REMOVE_RESET); + + return 0; +} + +static void pm8916_wcd_analog_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_update_bits(dai->codec, CDC_D_CDC_RST_CTL, + RST_CTL_DIG_SW_RST_N_MASK, 0); +} + +static struct snd_soc_dai_ops pm8916_wcd_analog_dai_ops = { + .startup = pm8916_wcd_analog_startup, + .shutdown = pm8916_wcd_analog_shutdown, +}; + +static struct snd_soc_dai_driver pm8916_wcd_analog_dai[] = { + [0] = { + .name = "pm8916_wcd_analog_pdm_rx", + .id = 0, + .playback = { + .stream_name = "PDM Playback", + .rates = MSM8916_WCD_ANALOG_RATES, + .formats = MSM8916_WCD_ANALOG_FORMATS, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &pm8916_wcd_analog_dai_ops, + }, + [1] = { + .name = "pm8916_wcd_analog_pdm_tx", + .id = 1, + .capture = { + .stream_name = "PDM Capture", + .rates = MSM8916_WCD_ANALOG_RATES, + .formats = MSM8916_WCD_ANALOG_FORMATS, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &pm8916_wcd_analog_dai_ops, + }, +}; + +static struct snd_soc_codec_driver pm8916_wcd_analog = { + .probe = pm8916_wcd_analog_probe, + .remove = pm8916_wcd_analog_remove, + .get_regmap = pm8916_get_regmap, + .component_driver = { + .controls = pm8916_wcd_analog_snd_controls, + .num_controls = ARRAY_SIZE(pm8916_wcd_analog_snd_controls), + .dapm_widgets = pm8916_wcd_analog_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(pm8916_wcd_analog_dapm_widgets), + .dapm_routes = pm8916_wcd_analog_audio_map, + .num_dapm_routes = ARRAY_SIZE(pm8916_wcd_analog_audio_map), + }, +}; + +static int pm8916_wcd_analog_parse_dt(struct device *dev, + struct pm8916_wcd_analog_priv *priv) +{ + int ret, i; + + if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap")) + priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP; + else + priv->micbias1_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + + if (of_property_read_bool(dev->of_node, "qcom,micbias2-ext-cap")) + priv->micbias2_cap_mode = MICB_1_EN_EXT_BYP_CAP; + else + priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; + + priv->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err(dev, "failed to get mclk\n"); + return PTR_ERR(priv->mclk); + } + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) { + dev_err(dev, "Failed to get regulator supplies %d\n", ret); + return ret; + } + + return 0; +} + +static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) +{ + struct pm8916_wcd_analog_priv *priv; + struct device *dev = &pdev->dev; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + ret = pm8916_wcd_analog_parse_dt(dev, priv); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(dev, "failed to enable mclk %d\n", ret); + return ret; + } + + dev_set_drvdata(dev, priv); + + return snd_soc_register_codec(dev, &pm8916_wcd_analog, + pm8916_wcd_analog_dai, + ARRAY_SIZE(pm8916_wcd_analog_dai)); +} + +static int pm8916_wcd_analog_spmi_remove(struct platform_device *pdev) +{ + struct pm8916_wcd_analog_priv *priv = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(priv->mclk); + + return 0; +} + +static const struct of_device_id pm8916_wcd_analog_spmi_match_table[] = { + { .compatible = "qcom,pm8916-wcd-analog-codec", }, + { } +}; + +static struct platform_driver pm8916_wcd_analog_spmi_driver = { + .driver = { + .name = "qcom,pm8916-wcd-spmi-codec", + .of_match_table = pm8916_wcd_analog_spmi_match_table, + }, + .probe = pm8916_wcd_analog_spmi_probe, + .remove = pm8916_wcd_analog_spmi_remove, +}; + +module_platform_driver(pm8916_wcd_analog_spmi_driver); + +MODULE_AUTHOR("Srinivas Kandagatla "); +MODULE_DESCRIPTION("PMIC PM8916 WCD Analog Codec driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 150db8c5afa10c43597dbc4db1c3e4af630e2ac0 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 20 Oct 2016 15:20:46 +0100 Subject: ASoC: codecs: Add msm8916-wcd digital codec msm8916-wcd codec is found in Qualcomm msm8916 and apq8016 processors. This codec IP is split in to two parts(Digital & Analog). Analog part is integrated in to PMIC PM8916 and the digital part is integrated into Application processor. Data transfer between Analog and Digital Die is done via a internal bus called PDM. This patch adds support to Digital part of the Codec which is integrated into Application Processor. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- .../bindings/sound/qcom,msm8916-wcd-digital.txt | 20 + sound/soc/codecs/Kconfig | 3 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/msm8916-wcd-digital.c | 923 +++++++++++++++++++++ 4 files changed, 948 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt create mode 100644 sound/soc/codecs/msm8916-wcd-digital.c (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt new file mode 100644 index 000000000000..1c8e4cb25176 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,msm8916-wcd-digital.txt @@ -0,0 +1,20 @@ +msm8916 digital audio CODEC + +## Bindings for codec core in lpass: + +Required properties + - compatible = "qcom,msm8916-wcd-digital-codec"; + - reg: address space for lpass codec. + - clocks: Handle to mclk and ahbclk + - clock-names: should be "mclk", "ahbix-clk". + +Example: + +audio-codec@771c000{ + compatible = "qcom,msm8916-wcd-digital-codec"; + reg = <0x0771c000 0x400>; + clocks = <&gcc GCC_ULTAUDIO_AHBFABRIC_IXFABRIC_CLK>, + <&gcc GCC_CODEC_DIGCODEC_CLK>; + clock-names = "ahbix-clk", "mclk"; + #sound-dai-cells = <1>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 4a98ce65b993..28c7b84f13a5 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -585,6 +585,9 @@ config SND_SOC_MSM8916_WCD_ANALOG tristate "Qualcomm MSM8916 WCD Analog Codec" depends on SPMI || COMPILE_TEST +config SND_SOC_MSM8916_WCD_DIGITAL + tristate "Qualcomm MSM8916 WCD DIGITAL Codec" + config SND_SOC_PCM1681 tristate "Texas Instruments PCM1681 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 32d90184f764..472a7720a316 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -87,6 +87,7 @@ snd-soc-max9860-objs := max9860.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o snd-soc-msm8916-analog-objs := msm8916-wcd-analog.o +snd-soc-msm8916-digital-objs := msm8916-wcd-digital.o snd-soc-nau8810-objs := nau8810.o snd-soc-nau8825-objs := nau8825.o snd-soc-hdmi-codec-objs := hdmi-codec.o @@ -311,6 +312,7 @@ obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o obj-$(CONFIG_SND_SOC_MSM8916_WCD_ANALOG) +=snd-soc-msm8916-analog.o +obj-$(CONFIG_SND_SOC_MSM8916_WCD_DIGITAL) +=snd-soc-msm8916-digital.o obj-$(CONFIG_SND_SOC_NAU8810) += snd-soc-nau8810.o obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c new file mode 100644 index 000000000000..e35501af91ab --- /dev/null +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -0,0 +1,923 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define LPASS_CDC_CLK_RX_RESET_CTL (0x000) +#define LPASS_CDC_CLK_TX_RESET_B1_CTL (0x004) +#define CLK_RX_RESET_B1_CTL_TX1_RESET_MASK BIT(0) +#define CLK_RX_RESET_B1_CTL_TX2_RESET_MASK BIT(1) +#define LPASS_CDC_CLK_DMIC_B1_CTL (0x008) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_MASK GENMASK(3, 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV2 (0x0 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3 (0x1 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV4 (0x2 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV6 (0x3 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_SEL_DIV16 (0x4 << 1) +#define DMIC_B1_CTL_DMIC0_CLK_EN_MASK BIT(0) +#define DMIC_B1_CTL_DMIC0_CLK_EN_ENABLE BIT(0) + +#define LPASS_CDC_CLK_RX_I2S_CTL (0x00C) +#define RX_I2S_CTL_RX_I2S_MODE_MASK BIT(5) +#define RX_I2S_CTL_RX_I2S_MODE_16 BIT(5) +#define RX_I2S_CTL_RX_I2S_MODE_32 0 +#define RX_I2S_CTL_RX_I2S_FS_RATE_MASK GENMASK(2, 0) +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ 0x0 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ 0x1 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ 0x2 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ 0x3 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_96_KHZ 0x4 +#define RX_I2S_CTL_RX_I2S_FS_RATE_F_192_KHZ 0x5 +#define LPASS_CDC_CLK_TX_I2S_CTL (0x010) +#define TX_I2S_CTL_TX_I2S_MODE_MASK BIT(5) +#define TX_I2S_CTL_TX_I2S_MODE_16 BIT(5) +#define TX_I2S_CTL_TX_I2S_MODE_32 0 +#define TX_I2S_CTL_TX_I2S_FS_RATE_MASK GENMASK(2, 0) +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ 0x0 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ 0x1 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ 0x2 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ 0x3 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_96_KHZ 0x4 +#define TX_I2S_CTL_TX_I2S_FS_RATE_F_192_KHZ 0x5 + +#define LPASS_CDC_CLK_OTHR_RESET_B1_CTL (0x014) +#define LPASS_CDC_CLK_TX_CLK_EN_B1_CTL (0x018) +#define LPASS_CDC_CLK_OTHR_CTL (0x01C) +#define LPASS_CDC_CLK_RX_B1_CTL (0x020) +#define LPASS_CDC_CLK_MCLK_CTL (0x024) +#define MCLK_CTL_MCLK_EN_MASK BIT(0) +#define MCLK_CTL_MCLK_EN_ENABLE BIT(0) +#define MCLK_CTL_MCLK_EN_DISABLE 0 +#define LPASS_CDC_CLK_PDM_CTL (0x028) +#define LPASS_CDC_CLK_PDM_CTL_PDM_EN_MASK BIT(0) +#define LPASS_CDC_CLK_PDM_CTL_PDM_EN BIT(0) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK BIT(1) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB BIT(1) +#define LPASS_CDC_CLK_PDM_CTL_PDM_CLK_PDM_CLK 0 + +#define LPASS_CDC_CLK_SD_CTL (0x02C) +#define LPASS_CDC_RX1_B1_CTL (0x040) +#define LPASS_CDC_RX2_B1_CTL (0x060) +#define LPASS_CDC_RX3_B1_CTL (0x080) +#define LPASS_CDC_RX1_B2_CTL (0x044) +#define LPASS_CDC_RX2_B2_CTL (0x064) +#define LPASS_CDC_RX3_B2_CTL (0x084) +#define LPASS_CDC_RX1_B3_CTL (0x048) +#define LPASS_CDC_RX2_B3_CTL (0x068) +#define LPASS_CDC_RX3_B3_CTL (0x088) +#define LPASS_CDC_RX1_B4_CTL (0x04C) +#define LPASS_CDC_RX2_B4_CTL (0x06C) +#define LPASS_CDC_RX3_B4_CTL (0x08C) +#define LPASS_CDC_RX1_B5_CTL (0x050) +#define LPASS_CDC_RX2_B5_CTL (0x070) +#define LPASS_CDC_RX3_B5_CTL (0x090) +#define LPASS_CDC_RX1_B6_CTL (0x054) +#define RXn_B6_CTL_MUTE_MASK BIT(0) +#define RXn_B6_CTL_MUTE_ENABLE BIT(0) +#define RXn_B6_CTL_MUTE_DISABLE 0 +#define LPASS_CDC_RX2_B6_CTL (0x074) +#define LPASS_CDC_RX3_B6_CTL (0x094) +#define LPASS_CDC_RX1_VOL_CTL_B1_CTL (0x058) +#define LPASS_CDC_RX2_VOL_CTL_B1_CTL (0x078) +#define LPASS_CDC_RX3_VOL_CTL_B1_CTL (0x098) +#define LPASS_CDC_RX1_VOL_CTL_B2_CTL (0x05C) +#define LPASS_CDC_RX2_VOL_CTL_B2_CTL (0x07C) +#define LPASS_CDC_RX3_VOL_CTL_B2_CTL (0x09C) +#define LPASS_CDC_TOP_GAIN_UPDATE (0x0A0) +#define LPASS_CDC_TOP_CTL (0x0A4) +#define TOP_CTL_DIG_MCLK_FREQ_MASK BIT(0) +#define TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ 0 +#define TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ BIT(0) + +#define LPASS_CDC_DEBUG_DESER1_CTL (0x0E0) +#define LPASS_CDC_DEBUG_DESER2_CTL (0x0E4) +#define LPASS_CDC_DEBUG_B1_CTL_CFG (0x0E8) +#define LPASS_CDC_DEBUG_B2_CTL_CFG (0x0EC) +#define LPASS_CDC_DEBUG_B3_CTL_CFG (0x0F0) +#define LPASS_CDC_IIR1_GAIN_B1_CTL (0x100) +#define LPASS_CDC_IIR2_GAIN_B1_CTL (0x140) +#define LPASS_CDC_IIR1_GAIN_B2_CTL (0x104) +#define LPASS_CDC_IIR2_GAIN_B2_CTL (0x144) +#define LPASS_CDC_IIR1_GAIN_B3_CTL (0x108) +#define LPASS_CDC_IIR2_GAIN_B3_CTL (0x148) +#define LPASS_CDC_IIR1_GAIN_B4_CTL (0x10C) +#define LPASS_CDC_IIR2_GAIN_B4_CTL (0x14C) +#define LPASS_CDC_IIR1_GAIN_B5_CTL (0x110) +#define LPASS_CDC_IIR2_GAIN_B5_CTL (0x150) +#define LPASS_CDC_IIR1_GAIN_B6_CTL (0x114) +#define LPASS_CDC_IIR2_GAIN_B6_CTL (0x154) +#define LPASS_CDC_IIR1_GAIN_B7_CTL (0x118) +#define LPASS_CDC_IIR2_GAIN_B7_CTL (0x158) +#define LPASS_CDC_IIR1_GAIN_B8_CTL (0x11C) +#define LPASS_CDC_IIR2_GAIN_B8_CTL (0x15C) +#define LPASS_CDC_IIR1_CTL (0x120) +#define LPASS_CDC_IIR2_CTL (0x160) +#define LPASS_CDC_IIR1_GAIN_TIMER_CTL (0x124) +#define LPASS_CDC_IIR2_GAIN_TIMER_CTL (0x164) +#define LPASS_CDC_IIR1_COEF_B1_CTL (0x128) +#define LPASS_CDC_IIR2_COEF_B1_CTL (0x168) +#define LPASS_CDC_IIR1_COEF_B2_CTL (0x12C) +#define LPASS_CDC_IIR2_COEF_B2_CTL (0x16C) +#define LPASS_CDC_CONN_RX1_B1_CTL (0x180) +#define LPASS_CDC_CONN_RX1_B2_CTL (0x184) +#define LPASS_CDC_CONN_RX1_B3_CTL (0x188) +#define LPASS_CDC_CONN_RX2_B1_CTL (0x18C) +#define LPASS_CDC_CONN_RX2_B2_CTL (0x190) +#define LPASS_CDC_CONN_RX2_B3_CTL (0x194) +#define LPASS_CDC_CONN_RX3_B1_CTL (0x198) +#define LPASS_CDC_CONN_RX3_B2_CTL (0x19C) +#define LPASS_CDC_CONN_TX_B1_CTL (0x1A0) +#define LPASS_CDC_CONN_EQ1_B1_CTL (0x1A8) +#define LPASS_CDC_CONN_EQ1_B2_CTL (0x1AC) +#define LPASS_CDC_CONN_EQ1_B3_CTL (0x1B0) +#define LPASS_CDC_CONN_EQ1_B4_CTL (0x1B4) +#define LPASS_CDC_CONN_EQ2_B1_CTL (0x1B8) +#define LPASS_CDC_CONN_EQ2_B2_CTL (0x1BC) +#define LPASS_CDC_CONN_EQ2_B3_CTL (0x1C0) +#define LPASS_CDC_CONN_EQ2_B4_CTL (0x1C4) +#define LPASS_CDC_CONN_TX_I2S_SD1_CTL (0x1C8) +#define LPASS_CDC_TX1_VOL_CTL_TIMER (0x280) +#define LPASS_CDC_TX2_VOL_CTL_TIMER (0x2A0) +#define LPASS_CDC_TX1_VOL_CTL_GAIN (0x284) +#define LPASS_CDC_TX2_VOL_CTL_GAIN (0x2A4) +#define LPASS_CDC_TX1_VOL_CTL_CFG (0x288) +#define TX_VOL_CTL_CFG_MUTE_EN_MASK BIT(0) +#define TX_VOL_CTL_CFG_MUTE_EN_ENABLE BIT(0) + +#define LPASS_CDC_TX2_VOL_CTL_CFG (0x2A8) +#define LPASS_CDC_TX1_MUX_CTL (0x28C) +#define TX_MUX_CTL_CUT_OFF_FREQ_MASK GENMASK(5, 4) +#define TX_MUX_CTL_CUT_OFF_FREQ_SHIFT 4 +#define TX_MUX_CTL_CF_NEG_3DB_4HZ (0x0 << 4) +#define TX_MUX_CTL_CF_NEG_3DB_75HZ (0x1 << 4) +#define TX_MUX_CTL_CF_NEG_3DB_150HZ (0x2 << 4) +#define TX_MUX_CTL_HPF_BP_SEL_MASK BIT(3) +#define TX_MUX_CTL_HPF_BP_SEL_BYPASS BIT(3) +#define TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS 0 + +#define LPASS_CDC_TX2_MUX_CTL (0x2AC) +#define LPASS_CDC_TX1_CLK_FS_CTL (0x290) +#define LPASS_CDC_TX2_CLK_FS_CTL (0x2B0) +#define LPASS_CDC_TX1_DMIC_CTL (0x294) +#define LPASS_CDC_TX2_DMIC_CTL (0x2B4) +#define TXN_DMIC_CTL_CLK_SEL_MASK GENMASK(2, 0) +#define TXN_DMIC_CTL_CLK_SEL_DIV2 0x0 +#define TXN_DMIC_CTL_CLK_SEL_DIV3 0x1 +#define TXN_DMIC_CTL_CLK_SEL_DIV4 0x2 +#define TXN_DMIC_CTL_CLK_SEL_DIV6 0x3 +#define TXN_DMIC_CTL_CLK_SEL_DIV16 0x4 + +#define MSM8916_WCD_DIGITAL_RATES (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_32000 | \ + SNDRV_PCM_RATE_48000) +#define MSM8916_WCD_DIGITAL_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S24_LE) + +struct msm8916_wcd_digital_priv { + struct clk *ahbclk, *mclk; +}; + +static const unsigned long rx_gain_reg[] = { + LPASS_CDC_RX1_VOL_CTL_B2_CTL, + LPASS_CDC_RX2_VOL_CTL_B2_CTL, + LPASS_CDC_RX3_VOL_CTL_B2_CTL, +}; + +static const unsigned long tx_gain_reg[] = { + LPASS_CDC_TX1_VOL_CTL_GAIN, + LPASS_CDC_TX2_VOL_CTL_GAIN, +}; + +static const char *const rx_mix1_text[] = { + "ZERO", "IIR1", "IIR2", "RX1", "RX2", "RX3" +}; + +static const char *const dec_mux_text[] = { + "ZERO", "ADC1", "ADC2", "ADC3", "DMIC1", "DMIC2" +}; +static const char *const rx_mix2_text[] = { "ZERO", "IIR1", "IIR2" }; +static const char *const adc2_mux_text[] = { "ZERO", "INP2", "INP3" }; + +/* RX1 MIX1 */ +static const struct soc_enum rx_mix1_inp_enum[] = { + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 0, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B1_CTL, 3, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX1_B2_CTL, 0, 6, rx_mix1_text), +}; + +/* RX1 MIX2 */ +static const struct soc_enum rx_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_RX1_B3_CTL, 0, 3, rx_mix2_text); + +/* RX2 MIX1 */ +static const struct soc_enum rx2_mix1_inp_enum[] = { + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 3, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX2_B1_CTL, 0, 6, rx_mix1_text), +}; + +/* RX2 MIX2 */ +static const struct soc_enum rx2_mix2_inp1_chain_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_RX2_B3_CTL, 0, 3, rx_mix2_text); + +/* RX3 MIX1 */ +static const struct soc_enum rx3_mix1_inp_enum[] = { + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 3, 6, rx_mix1_text), + SOC_ENUM_SINGLE(LPASS_CDC_CONN_RX3_B1_CTL, 0, 6, rx_mix1_text), +}; + +/* DEC */ +static const struct soc_enum dec1_mux_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_TX_B1_CTL, 0, 6, dec_mux_text); +static const struct soc_enum dec2_mux_enum = SOC_ENUM_SINGLE( + LPASS_CDC_CONN_TX_B1_CTL, 3, 6, dec_mux_text); + +/* RDAC2 MUX */ +static const struct snd_kcontrol_new dec1_mux = SOC_DAPM_ENUM( + "DEC1 MUX Mux", dec1_mux_enum); +static const struct snd_kcontrol_new dec2_mux = SOC_DAPM_ENUM( + "DEC2 MUX Mux", dec2_mux_enum); +static const struct snd_kcontrol_new rx_mix1_inp1_mux = SOC_DAPM_ENUM( + "RX1 MIX1 INP1 Mux", rx_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx_mix1_inp2_mux = SOC_DAPM_ENUM( + "RX1 MIX1 INP2 Mux", rx_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx_mix1_inp3_mux = SOC_DAPM_ENUM( + "RX1 MIX1 INP3 Mux", rx_mix1_inp_enum[2]); +static const struct snd_kcontrol_new rx2_mix1_inp1_mux = SOC_DAPM_ENUM( + "RX2 MIX1 INP1 Mux", rx2_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx2_mix1_inp2_mux = SOC_DAPM_ENUM( + "RX2 MIX1 INP2 Mux", rx2_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx2_mix1_inp3_mux = SOC_DAPM_ENUM( + "RX2 MIX1 INP3 Mux", rx2_mix1_inp_enum[2]); +static const struct snd_kcontrol_new rx3_mix1_inp1_mux = SOC_DAPM_ENUM( + "RX3 MIX1 INP1 Mux", rx3_mix1_inp_enum[0]); +static const struct snd_kcontrol_new rx3_mix1_inp2_mux = SOC_DAPM_ENUM( + "RX3 MIX1 INP2 Mux", rx3_mix1_inp_enum[1]); +static const struct snd_kcontrol_new rx3_mix1_inp3_mux = SOC_DAPM_ENUM( + "RX3 MIX1 INP3 Mux", rx3_mix1_inp_enum[2]); + +/* Digital Gain control -38.4 dB to +38.4 dB in 0.3 dB steps */ +static const DECLARE_TLV_DB_SCALE(digital_gain, -3840, 30, 0); + +/* Cutoff Freq for High Pass Filter at -3dB */ +static const char * const hpf_cutoff_text[] = { + "4Hz", "75Hz", "150Hz", +}; + +static SOC_ENUM_SINGLE_DECL(tx1_hpf_cutoff_enum, LPASS_CDC_TX1_MUX_CTL, 4, + hpf_cutoff_text); +static SOC_ENUM_SINGLE_DECL(tx2_hpf_cutoff_enum, LPASS_CDC_TX2_MUX_CTL, 4, + hpf_cutoff_text); + +/* cut off for dc blocker inside rx chain */ +static const char * const dc_blocker_cutoff_text[] = { + "4Hz", "75Hz", "150Hz", +}; + +static SOC_ENUM_SINGLE_DECL(rx1_dcb_cutoff_enum, LPASS_CDC_RX1_B4_CTL, 0, + dc_blocker_cutoff_text); +static SOC_ENUM_SINGLE_DECL(rx2_dcb_cutoff_enum, LPASS_CDC_RX2_B4_CTL, 0, + dc_blocker_cutoff_text); +static SOC_ENUM_SINGLE_DECL(rx3_dcb_cutoff_enum, LPASS_CDC_RX3_B4_CTL, 0, + dc_blocker_cutoff_text); + +static const struct snd_kcontrol_new msm8916_wcd_digital_snd_controls[] = { + SOC_SINGLE_S8_TLV("RX1 Digital Volume", LPASS_CDC_RX1_VOL_CTL_B2_CTL, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("RX2 Digital Volume", LPASS_CDC_RX2_VOL_CTL_B2_CTL, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("RX3 Digital Volume", LPASS_CDC_RX3_VOL_CTL_B2_CTL, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("TX1 Digital Volume", LPASS_CDC_TX1_VOL_CTL_GAIN, + -128, 127, digital_gain), + SOC_SINGLE_S8_TLV("TX2 Digital Volume", LPASS_CDC_TX2_VOL_CTL_GAIN, + -128, 127, digital_gain), + SOC_ENUM("TX1 HPF Cutoff", tx1_hpf_cutoff_enum), + SOC_ENUM("TX2 HPF Cutoff", tx2_hpf_cutoff_enum), + SOC_SINGLE("TX1 HPF Switch", LPASS_CDC_TX1_MUX_CTL, 3, 1, 0), + SOC_SINGLE("TX2 HPF Switch", LPASS_CDC_TX2_MUX_CTL, 3, 1, 0), + SOC_ENUM("RX1 DCB Cutoff", rx1_dcb_cutoff_enum), + SOC_ENUM("RX2 DCB Cutoff", rx2_dcb_cutoff_enum), + SOC_ENUM("RX3 DCB Cutoff", rx3_dcb_cutoff_enum), + SOC_SINGLE("RX1 DCB Switch", LPASS_CDC_RX1_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX2 DCB Switch", LPASS_CDC_RX2_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX3 DCB Switch", LPASS_CDC_RX3_B5_CTL, 2, 1, 0), + SOC_SINGLE("RX1 Mute Switch", LPASS_CDC_RX1_B6_CTL, 0, 1, 0), + SOC_SINGLE("RX2 Mute Switch", LPASS_CDC_RX2_B6_CTL, 0, 1, 0), + SOC_SINGLE("RX3 Mute Switch", LPASS_CDC_RX3_B6_CTL, 0, 1, 0), +}; + +static int msm8916_wcd_digital_enable_interpolator( + struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /* apply the digital gain after the interpolator is enabled */ + usleep_range(10000, 10100); + snd_soc_write(codec, rx_gain_reg[w->shift], + snd_soc_read(codec, rx_gain_reg[w->shift])); + break; + } + return 0; +} + +static int msm8916_wcd_digital_enable_dec(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int decimator = w->shift + 1; + u16 dec_reset_reg, tx_vol_ctl_reg, tx_mux_ctl_reg; + u8 dec_hpf_cut_of_freq; + + dec_reset_reg = LPASS_CDC_CLK_TX_RESET_B1_CTL; + tx_vol_ctl_reg = LPASS_CDC_TX1_VOL_CTL_CFG + 32 * (decimator - 1); + tx_mux_ctl_reg = LPASS_CDC_TX1_MUX_CTL + 32 * (decimator - 1); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* Enable TX digital mute */ + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, + TX_VOL_CTL_CFG_MUTE_EN_ENABLE); + dec_hpf_cut_of_freq = snd_soc_read(codec, tx_mux_ctl_reg) & + TX_MUX_CTL_CUT_OFF_FREQ_MASK; + dec_hpf_cut_of_freq >>= TX_MUX_CTL_CUT_OFF_FREQ_SHIFT; + if (dec_hpf_cut_of_freq != TX_MUX_CTL_CF_NEG_3DB_150HZ) { + /* set cut of freq to CF_MIN_3DB_150HZ (0x1) */ + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_CUT_OFF_FREQ_MASK, + TX_MUX_CTL_CF_NEG_3DB_150HZ); + } + break; + case SND_SOC_DAPM_POST_PMU: + /* enable HPF */ + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_HPF_BP_SEL_MASK, + TX_MUX_CTL_HPF_BP_SEL_NO_BYPASS); + /* apply the digital gain after the decimator is enabled */ + snd_soc_write(codec, tx_gain_reg[w->shift], + snd_soc_read(codec, tx_gain_reg[w->shift])); + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, + TX_VOL_CTL_CFG_MUTE_EN_ENABLE); + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_HPF_BP_SEL_MASK, + TX_MUX_CTL_HPF_BP_SEL_BYPASS); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, + 1 << w->shift); + snd_soc_update_bits(codec, dec_reset_reg, 1 << w->shift, 0x0); + snd_soc_update_bits(codec, tx_mux_ctl_reg, + TX_MUX_CTL_HPF_BP_SEL_MASK, + TX_MUX_CTL_HPF_BP_SEL_BYPASS); + snd_soc_update_bits(codec, tx_vol_ctl_reg, + TX_VOL_CTL_CFG_MUTE_EN_MASK, 0); + break; + } + + return 0; +} + +static int msm8916_wcd_digital_enable_dmic(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int dmic; + int ret; + /* get dmic number out of widget name */ + char *dmic_num = strpbrk(w->name, "12"); + + if (dmic_num == NULL) { + dev_err(codec->dev, "Invalid DMIC\n"); + return -EINVAL; + } + ret = kstrtouint(dmic_num, 10, &dmic); + if (ret < 0 || dmic > 2) { + dev_err(codec->dev, "Invalid DMIC line on the codec\n"); + return -EINVAL; + } + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, LPASS_CDC_CLK_DMIC_B1_CTL, + DMIC_B1_CTL_DMIC0_CLK_SEL_MASK, + DMIC_B1_CTL_DMIC0_CLK_SEL_DIV3); + switch (dmic) { + case 1: + snd_soc_update_bits(codec, LPASS_CDC_TX1_DMIC_CTL, + TXN_DMIC_CTL_CLK_SEL_MASK, + TXN_DMIC_CTL_CLK_SEL_DIV3); + break; + case 2: + snd_soc_update_bits(codec, LPASS_CDC_TX2_DMIC_CTL, + TXN_DMIC_CTL_CLK_SEL_MASK, + TXN_DMIC_CTL_CLK_SEL_DIV3); + break; + } + break; + } + + return 0; +} + +static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { + /*RX stuff */ + SND_SOC_DAPM_AIF_IN("I2S RX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S RX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("I2S RX3", NULL, 0, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("PDM_RX1"), + SND_SOC_DAPM_OUTPUT("PDM_RX2"), + SND_SOC_DAPM_OUTPUT("PDM_RX3"), + + SND_SOC_DAPM_INPUT("LPASS_PDM_TX"), + + SND_SOC_DAPM_MIXER("RX1 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("RX3 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Interpolator */ + SND_SOC_DAPM_MIXER_E("RX1 INT", LPASS_CDC_CLK_RX_B1_CTL, 0, 0, NULL, + 0, msm8916_wcd_digital_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX2 INT", LPASS_CDC_CLK_RX_B1_CTL, 1, 0, NULL, + 0, msm8916_wcd_digital_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MIXER_E("RX3 INT", LPASS_CDC_CLK_RX_B1_CTL, 2, 0, NULL, + 0, msm8916_wcd_digital_enable_interpolator, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX("RX1 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX1 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX1 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx_mix1_inp3_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX2 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx2_mix1_inp3_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP1", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp1_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP2", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp2_mux), + SND_SOC_DAPM_MUX("RX3 MIX1 INP3", SND_SOC_NOPM, 0, 0, + &rx3_mix1_inp3_mux), + + /* TX */ + SND_SOC_DAPM_MIXER("ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_MUX_E("DEC1 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 0, 0, + &dec1_mux, msm8916_wcd_digital_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_MUX_E("DEC2 MUX", LPASS_CDC_CLK_TX_CLK_EN_B1_CTL, 1, 0, + &dec2_mux, msm8916_wcd_digital_enable_dec, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_AIF_OUT("I2S TX1", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S TX2", NULL, 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("I2S TX3", NULL, 0, SND_SOC_NOPM, 0, 0), + + /* Digital Mic Inputs */ + SND_SOC_DAPM_ADC_E("DMIC1", NULL, SND_SOC_NOPM, 0, 0, + msm8916_wcd_digital_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_ADC_E("DMIC2", NULL, SND_SOC_NOPM, 0, 0, + msm8916_wcd_digital_enable_dmic, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY("DMIC_CLK", LPASS_CDC_CLK_DMIC_B1_CTL, 0, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("RX_I2S_CLK", LPASS_CDC_CLK_RX_I2S_CTL, + 4, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("TX_I2S_CLK", LPASS_CDC_CLK_TX_I2S_CTL, 4, 0, + NULL, 0), + + SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("PDM_CLK", LPASS_CDC_CLK_PDM_CTL, 0, 0, NULL, 0), + /* Connectivity Clock */ + SND_SOC_DAPM_SUPPLY_S("CDC_CONN", -2, LPASS_CDC_CLK_OTHR_CTL, 2, 0, + NULL, 0), + +}; + +static int msm8916_wcd_digital_parse_dt(struct platform_device *pdev, + struct msm8916_wcd_digital_priv *priv) +{ + struct device *dev = &pdev->dev; + + priv->ahbclk = devm_clk_get(dev, "ahbix-clk"); + if (IS_ERR(priv->ahbclk)) { + dev_err(dev, "failed to get ahbix clk\n"); + return PTR_ERR(priv->ahbclk); + } + + priv->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err(dev, "failed to get mclk\n"); + return PTR_ERR(priv->mclk); + } + + return 0; +} + +static int msm8916_wcd_digital_codec_probe(struct snd_soc_codec *codec) +{ + struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(codec->dev); + + snd_soc_codec_set_drvdata(codec, priv); + + return 0; +} + +static int msm8916_wcd_digital_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + u8 tx_fs_rate; + u8 rx_fs_rate; + + switch (params_rate(params)) { + case 8000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_8_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_8_KHZ; + break; + case 16000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_16_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_16_KHZ; + break; + case 32000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_32_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_32_KHZ; + break; + case 48000: + tx_fs_rate = TX_I2S_CTL_TX_I2S_FS_RATE_F_48_KHZ; + rx_fs_rate = RX_I2S_CTL_RX_I2S_FS_RATE_F_48_KHZ; + break; + default: + dev_err(dai->codec->dev, "Invalid sampling rate %d\n", + params_rate(params)); + return -EINVAL; + } + + switch (substream->stream) { + case SNDRV_PCM_STREAM_CAPTURE: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, + TX_I2S_CTL_TX_I2S_FS_RATE_MASK, tx_fs_rate); + break; + case SNDRV_PCM_STREAM_PLAYBACK: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, + RX_I2S_CTL_RX_I2S_FS_RATE_MASK, rx_fs_rate); + break; + default: + return -EINVAL; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, + TX_I2S_CTL_TX_I2S_MODE_MASK, + TX_I2S_CTL_TX_I2S_MODE_16); + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, + RX_I2S_CTL_RX_I2S_MODE_MASK, + RX_I2S_CTL_RX_I2S_MODE_16); + break; + case SNDRV_PCM_FORMAT_S24_LE: + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_TX_I2S_CTL, + TX_I2S_CTL_TX_I2S_MODE_MASK, + TX_I2S_CTL_TX_I2S_MODE_32); + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_RX_I2S_CTL, + RX_I2S_CTL_RX_I2S_MODE_MASK, + RX_I2S_CTL_RX_I2S_MODE_32); + break; + default: + dev_err(dai->dev, "%s: wrong format selected\n", __func__); + return -EINVAL; + } + + return 0; +} + +static const struct snd_soc_dapm_route msm8916_wcd_digital_audio_map[] = { + + {"I2S RX1", NULL, "AIF1 Playback"}, + {"I2S RX2", NULL, "AIF1 Playback"}, + {"I2S RX3", NULL, "AIF1 Playback"}, + + {"AIF1 Capture", NULL, "I2S TX1"}, + {"AIF1 Capture", NULL, "I2S TX2"}, + {"AIF1 Capture", NULL, "I2S TX3"}, + + /* Decimator Inputs */ + {"DEC1 MUX", "DMIC1", "DMIC1"}, + {"DEC1 MUX", "DMIC2", "DMIC2"}, + {"DEC1 MUX", "ADC1", "ADC1"}, + {"DEC1 MUX", "ADC2", "ADC2"}, + {"DEC1 MUX", "ADC3", "ADC3"}, + {"DEC1 MUX", NULL, "CDC_CONN"}, + + {"DEC2 MUX", "DMIC1", "DMIC1"}, + {"DEC2 MUX", "DMIC2", "DMIC2"}, + {"DEC2 MUX", "ADC1", "ADC1"}, + {"DEC2 MUX", "ADC2", "ADC2"}, + {"DEC2 MUX", "ADC3", "ADC3"}, + {"DEC2 MUX", NULL, "CDC_CONN"}, + + {"DMIC1", NULL, "DMIC_CLK"}, + {"DMIC2", NULL, "DMIC_CLK"}, + + {"I2S TX1", NULL, "DEC1 MUX"}, + {"I2S TX2", NULL, "DEC2 MUX"}, + + {"I2S TX1", NULL, "TX_I2S_CLK"}, + {"I2S TX2", NULL, "TX_I2S_CLK"}, + + {"TX_I2S_CLK", NULL, "MCLK"}, + {"TX_I2S_CLK", NULL, "PDM_CLK"}, + + {"ADC1", NULL, "LPASS_PDM_TX"}, + {"ADC2", NULL, "LPASS_PDM_TX"}, + {"ADC3", NULL, "LPASS_PDM_TX"}, + + {"I2S RX1", NULL, "RX_I2S_CLK"}, + {"I2S RX2", NULL, "RX_I2S_CLK"}, + {"I2S RX3", NULL, "RX_I2S_CLK"}, + + {"RX_I2S_CLK", NULL, "PDM_CLK"}, + {"RX_I2S_CLK", NULL, "MCLK"}, + {"RX_I2S_CLK", NULL, "CDC_CONN"}, + + /* RX1 PATH.. */ + {"PDM_RX1", NULL, "RX1 INT"}, + {"RX1 INT", NULL, "RX1 MIX1"}, + + {"RX1 MIX1", NULL, "RX1 MIX1 INP1"}, + {"RX1 MIX1", NULL, "RX1 MIX1 INP2"}, + {"RX1 MIX1", NULL, "RX1 MIX1 INP3"}, + + {"RX1 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP1", "RX3", "I2S RX3"}, + + {"RX1 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP2", "RX3", "I2S RX3"}, + + {"RX1 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX1 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX1 MIX1 INP3", "RX3", "I2S RX3"}, + + /* RX2 PATH */ + {"PDM_RX2", NULL, "RX2 INT"}, + {"RX2 INT", NULL, "RX2 MIX1"}, + + {"RX2 MIX1", NULL, "RX2 MIX1 INP1"}, + {"RX2 MIX1", NULL, "RX2 MIX1 INP2"}, + {"RX2 MIX1", NULL, "RX2 MIX1 INP3"}, + + {"RX2 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP1", "RX3", "I2S RX3"}, + + {"RX2 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP2", "RX3", "I2S RX3"}, + + {"RX2 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX2 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX2 MIX1 INP3", "RX3", "I2S RX3"}, + + /* RX3 PATH */ + {"PDM_RX3", NULL, "RX3 INT"}, + {"RX3 INT", NULL, "RX3 MIX1"}, + + {"RX3 MIX1", NULL, "RX3 MIX1 INP1"}, + {"RX3 MIX1", NULL, "RX3 MIX1 INP2"}, + {"RX3 MIX1", NULL, "RX3 MIX1 INP3"}, + + {"RX3 MIX1 INP1", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP1", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP1", "RX3", "I2S RX3"}, + + {"RX3 MIX1 INP2", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP2", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP2", "RX3", "I2S RX3"}, + + {"RX3 MIX1 INP3", "RX1", "I2S RX1"}, + {"RX3 MIX1 INP3", "RX2", "I2S RX2"}, + {"RX3 MIX1 INP3", "RX3", "I2S RX3"}, + +}; + +static int msm8916_wcd_digital_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct msm8916_wcd_digital_priv *msm8916_wcd; + unsigned long mclk_rate; + + msm8916_wcd = snd_soc_codec_get_drvdata(codec); + snd_soc_update_bits(codec, LPASS_CDC_CLK_MCLK_CTL, + MCLK_CTL_MCLK_EN_MASK, + MCLK_CTL_MCLK_EN_ENABLE); + snd_soc_update_bits(codec, LPASS_CDC_CLK_PDM_CTL, + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_FB); + + mclk_rate = clk_get_rate(msm8916_wcd->mclk); + switch (mclk_rate) { + case 12288000: + snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, + TOP_CTL_DIG_MCLK_FREQ_MASK, + TOP_CTL_DIG_MCLK_FREQ_F_12_288MHZ); + break; + case 9600000: + snd_soc_update_bits(codec, LPASS_CDC_TOP_CTL, + TOP_CTL_DIG_MCLK_FREQ_MASK, + TOP_CTL_DIG_MCLK_FREQ_F_9_6MHZ); + break; + default: + dev_err(codec->dev, "Invalid mclk rate %ld\n", mclk_rate); + break; + } + return 0; +} + +static void msm8916_wcd_digital_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + snd_soc_update_bits(dai->codec, LPASS_CDC_CLK_PDM_CTL, + LPASS_CDC_CLK_PDM_CTL_PDM_CLK_SEL_MASK, 0); +} + +static struct snd_soc_dai_ops msm8916_wcd_digital_dai_ops = { + .startup = msm8916_wcd_digital_startup, + .shutdown = msm8916_wcd_digital_shutdown, + .hw_params = msm8916_wcd_digital_hw_params, +}; + +static struct snd_soc_dai_driver msm8916_wcd_digital_dai[] = { + [0] = { + .name = "msm8916_wcd_digital_i2s_rx1", + .id = 0, + .playback = { + .stream_name = "AIF1 Playback", + .rates = MSM8916_WCD_DIGITAL_RATES, + .formats = MSM8916_WCD_DIGITAL_FORMATS, + .channels_min = 1, + .channels_max = 3, + }, + .ops = &msm8916_wcd_digital_dai_ops, + }, + [1] = { + .name = "msm8916_wcd_digital_i2s_tx1", + .id = 1, + .capture = { + .stream_name = "AIF1 Capture", + .rates = MSM8916_WCD_DIGITAL_RATES, + .formats = MSM8916_WCD_DIGITAL_FORMATS, + .channels_min = 1, + .channels_max = 4, + }, + .ops = &msm8916_wcd_digital_dai_ops, + }, +}; + +static struct snd_soc_codec_driver msm8916_wcd_digital = { + .probe = msm8916_wcd_digital_codec_probe, + .component_driver = { + .controls = msm8916_wcd_digital_snd_controls, + .num_controls = ARRAY_SIZE(msm8916_wcd_digital_snd_controls), + .dapm_widgets = msm8916_wcd_digital_dapm_widgets, + .num_dapm_widgets = + ARRAY_SIZE(msm8916_wcd_digital_dapm_widgets), + .dapm_routes = msm8916_wcd_digital_audio_map, + .num_dapm_routes = ARRAY_SIZE(msm8916_wcd_digital_audio_map), + }, +}; + +static const struct regmap_config msm8916_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = LPASS_CDC_TX2_DMIC_CTL, + .cache_type = REGCACHE_FLAT, +}; + +static int msm8916_wcd_digital_probe(struct platform_device *pdev) +{ + struct msm8916_wcd_digital_priv *priv; + struct device *dev = &pdev->dev; + void __iomem *base; + struct resource *mem_res; + struct regmap *digital_map; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem_res); + if (IS_ERR(base)) + return PTR_ERR(base); + + digital_map = + devm_regmap_init_mmio(&pdev->dev, base, + &msm8916_codec_regmap_config); + if (IS_ERR(digital_map)) + return PTR_ERR(digital_map); + + ret = msm8916_wcd_digital_parse_dt(pdev, priv); + if (ret < 0) + return ret; + + ret = clk_prepare_enable(priv->ahbclk); + if (ret < 0) { + dev_err(dev, "failed to enable ahbclk %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(priv->mclk); + if (ret < 0) { + dev_err(dev, "failed to enable mclk %d\n", ret); + return ret; + } + + dev_set_drvdata(dev, priv); + + return snd_soc_register_codec(dev, &msm8916_wcd_digital, + msm8916_wcd_digital_dai, + ARRAY_SIZE(msm8916_wcd_digital_dai)); +} + +static int msm8916_wcd_digital_remove(struct platform_device *pdev) +{ + struct msm8916_wcd_digital_priv *priv = dev_get_drvdata(&pdev->dev); + + snd_soc_unregister_codec(&pdev->dev); + clk_disable_unprepare(priv->mclk); + clk_disable_unprepare(priv->ahbclk); + + return 0; +} + +static const struct of_device_id msm8916_wcd_digital_match_table[] = { + { .compatible = "qcom,msm8916-wcd-digital-codec" }, + { } +}; + +MODULE_DEVICE_TABLE(of, msm8916_wcd_digital_match_table); + +static struct platform_driver msm8916_wcd_digital_driver = { + .driver = { + .name = "msm8916-wcd-digital-codec", + .of_match_table = msm8916_wcd_digital_match_table, + }, + .probe = msm8916_wcd_digital_probe, + .remove = msm8916_wcd_digital_remove, +}; + +module_platform_driver(msm8916_wcd_digital_driver); + +MODULE_AUTHOR("Srinivas Kandagatla "); +MODULE_DESCRIPTION("MSM8916 WCD Digital Codec driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 09065f8b44a3e2a742565368b89b5848387eaf38 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Thu, 20 Oct 2016 15:20:48 +0100 Subject: ASoC: qcom: apq8016-sbc: Add support to multi codec. This patch adds support to multi codec, as the msm8916 codec is now split into two codecs, Analog and Digital. Also update the bindings and example to show that the card supports multicodec. Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt | 4 ++-- sound/soc/qcom/apq8016_sbc.c | 11 +++-------- 2 files changed, 5 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt index 72c192801a69..6a4aadc4ce06 100644 --- a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt +++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt @@ -44,7 +44,7 @@ Required dai-link subnodes: Required CPU/CODEC subnodes properties: -link-name : Name of the dai link. --sound-dai : phandle and port of CPU/CODEC +-sound-dai : phandle/s and port of CPU/CODEC Example: @@ -72,7 +72,7 @@ sound: sound { sound-dai = <&lpass MI2S_PRIMARY>; }; codec { - sound-dai = <&wcd_codec 0>; + sound-dai = <&lpass_codec 0>, <&wcd_codec 0>; }; }; diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c index 07f91e918b23..d084d7468299 100644 --- a/sound/soc/qcom/apq8016_sbc.c +++ b/sound/soc/qcom/apq8016_sbc.c @@ -123,20 +123,15 @@ static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card) return ERR_PTR(-EINVAL); } - link->codec_of_node = of_parse_phandle(codec, "sound-dai", 0); - if (!link->codec_of_node) { - dev_err(card->dev, "error getting codec phandle\n"); - return ERR_PTR(-EINVAL); - } - ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); if (ret) { dev_err(card->dev, "error getting cpu dai name\n"); return ERR_PTR(ret); } - ret = snd_soc_of_get_dai_name(codec, &link->codec_dai_name); - if (ret) { + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + + if (ret < 0) { dev_err(card->dev, "error getting codec dai name\n"); return ERR_PTR(ret); } -- cgit v1.2.3-59-g8ed1b From d01580c394f58dff234a03f0f2f32c051a556f15 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 20 Oct 2016 10:13:44 +0800 Subject: ASoC: rt5660: enable MCLK detection There is a power saving mechanism in rt5660. It will turn off some unused power when MCLK is not present. We call that "MCLK detection" and it should be enabled by default. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5660.c | 4 ++++ sound/soc/codecs/rt5660.h | 3 +++ 2 files changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 9f0933ced804..76cf76a2e9b6 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -1311,6 +1311,10 @@ static int rt5660_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + regmap_update_bits(rt5660->regmap, RT5660_GEN_CTRL1, + RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET, + RT5660_AUTO_DIS_AMP | RT5660_MCLK_DET | RT5660_POW_CLKDET); + if (rt5660->pdata.dmic1_data_pin) { regmap_update_bits(rt5660->regmap, RT5660_GPIO_CTRL1, RT5660_GP1_PIN_MASK, RT5660_GP1_PIN_DMIC1_SCL); diff --git a/sound/soc/codecs/rt5660.h b/sound/soc/codecs/rt5660.h index 6cdb9269ec9e..bba18fb66b6f 100644 --- a/sound/soc/codecs/rt5660.h +++ b/sound/soc/codecs/rt5660.h @@ -810,6 +810,9 @@ /* General Control 1 (0xfa) */ #define RT5660_PWR_VREF_HP (0x1 << 11) #define RT5660_PWR_VREF_HP_SFT 11 +#define RT5660_AUTO_DIS_AMP (0x1 << 6) +#define RT5660_MCLK_DET (0x1 << 5) +#define RT5660_POW_CLKDET (0x1 << 1) #define RT5660_DIG_GATE_CTRL (0x1) #define RT5660_DIG_GATE_CTRL_SFT 0 -- cgit v1.2.3-59-g8ed1b From 5490a109937b19464dc810389e69ff064afedf48 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Oct 2016 03:56:07 +0000 Subject: ASoC: rsnd: remove duplicate define of rsnd_dvc_of_node() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 02d971f69eff..cf8f59cdd8d7 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -48,8 +48,6 @@ struct rsnd_dvc { #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) -#define rsnd_dvc_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") #define rsnd_mod_to_dvc(_mod) \ container_of((_mod), struct rsnd_dvc, mod) -- cgit v1.2.3-59-g8ed1b From 0af5c01a79ade438698af683511803fc11291360 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Oct 2016 03:56:26 +0000 Subject: ASoC: rsnd: amend .probe/.remove call for DPCM commit 1a5658c2131 ("ASoC: rsnd: count .probe/.remove for rsnd_mod_call()") solved multi-resource-free issue, by putting .probe/.remove under count control. But,it breaks sound mixing case (if it was used under DPCM). In such case, it uses MIXn/DVCn/SSIn, and these should be always probed. This patch reverted above patch, and solved the same issue by modifing _rsnd_kctrl_remove() function. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 +++++- sound/soc/sh/rcar/dma.c | 11 +++++++++++ sound/soc/sh/rcar/rsnd.h | 14 +++++++------- sound/soc/sh/rcar/ssi.c | 5 ++++- 4 files changed, 27 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f18141098b50..209e7363bfdd 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -993,7 +993,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) { - snd_ctl_remove(cfg->card, cfg->kctrl); + if (cfg->card && cfg->kctrl) + snd_ctl_remove(cfg->card, cfg->kctrl); + + cfg->card = NULL; + cfg->kctrl = NULL; } int rsnd_kctrl_new_m(struct rsnd_mod *mod, diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 6bc93cbb3049..b3bdd362a511 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -707,6 +707,17 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, return 0; } +void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod) +{ + if (*dma_mod) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + + devm_kfree(dev, *dma_mod); + *dma_mod = NULL; + } +} + int rsnd_dma_probe(struct rsnd_priv *priv) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index a8f61d79333b..901095cb5139 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -200,6 +200,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); */ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); +void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); @@ -276,9 +277,8 @@ struct rsnd_mod { /* * status * - * 0xH0000CBA + * 0xH0000CB0 * - * A 0: probe 1: remove * B 0: init 1: quit * C 0: start 1: stop * @@ -288,19 +288,19 @@ struct rsnd_mod { * H 0: fallback * H 0: hw_params */ -#define __rsnd_mod_shift_probe 0 -#define __rsnd_mod_shift_remove 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 #define __rsnd_mod_shift_stop 8 +#define __rsnd_mod_shift_probe 28 /* always called */ +#define __rsnd_mod_shift_remove 28 /* always called */ #define __rsnd_mod_shift_irq 28 /* always called */ #define __rsnd_mod_shift_pcm_new 28 /* always called */ #define __rsnd_mod_shift_fallback 28 /* always called */ #define __rsnd_mod_shift_hw_params 28 /* always called */ -#define __rsnd_mod_add_probe 1 -#define __rsnd_mod_add_remove -1 +#define __rsnd_mod_add_probe 0 +#define __rsnd_mod_add_remove 0 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -311,7 +311,7 @@ struct rsnd_mod { #define __rsnd_mod_add_hw_params 0 #define __rsnd_mod_call_probe 0 -#define __rsnd_mod_call_remove 1 +#define __rsnd_mod_call_remove 0 #define __rsnd_mod_call_init 0 #define __rsnd_mod_call_quit 1 #define __rsnd_mod_call_start 0 diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 6cb6db005fc4..94a19f975fa2 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -698,7 +698,10 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, int irq = ssi->irq; /* PIO will request IRQ again */ - devm_free_irq(dev, irq, mod); + if (ssi->dma) + devm_free_irq(dev, irq, mod); + + rsnd_dma_detach(mod, &ssi->dma); return 0; } -- cgit v1.2.3-59-g8ed1b From b3ca3fbeb229890e8de569d1b34cd46fcb95826c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Oct 2016 03:56:46 +0000 Subject: ASoC: rsnd: add rsnd_mod_next() for for_each_rsnd_mod_xxx() Current rsnd driver is using too complex macro for for-loop of each mod. In order to simplify this issue, this patch adds new rsnd_mod_next() which is non-macro. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 23 +++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 12 ++++++++++++ 2 files changed, 35 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 209e7363bfdd..c0196f81e082 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -348,6 +348,29 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size) +{ + struct rsnd_mod *mod; + enum rsnd_mod_type type; + int max = array ? array_size : RSND_MOD_MAX; + + for (; *iterator < max; (*iterator)++) { + type = (array) ? array[*iterator] : *iterator; + mod = io->mod[type]; + if (!mod) + continue; + + (*iterator)++; + + return mod; + } + + return NULL; +} + #define rsnd_mod_call(idx, io, func, param...) \ ({ \ struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 901095cb5139..d8f81a4e09e3 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -346,6 +346,18 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, u32 *rsnd_mod_get_status(struct rsnd_dai_stream *io, struct rsnd_mod *mod, enum rsnd_mod_type type); +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size); +#define for_each_rsnd_mod(iterator, pos, io) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, NULL, 0));) +#define for_each_rsnd_mod_arrays(iterator, pos, io, array, size) \ + for (iterator = 0; \ + (pos = rsnd_mod_next(&iterator, io, array, size));) +#define for_each_rsnd_mod_array(iterator, pos, io, array) \ + for_each_rsnd_mod_arrays(iterator, pos, io, array, ARRAY_SIZE(array)) void rsnd_parse_connect_common(struct rsnd_dai *rdai, struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), -- cgit v1.2.3-59-g8ed1b From 5f222a29212cac3b64e7da8657d4404cc8201595 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Oct 2016 03:57:08 +0000 Subject: ASoC: rsnd: use for_each_rsnd_mod_xxx() on rsnd_dai_call() Current rsnd driver is using too complex macro for for-loop of each mod. rsnd_dai_call() is especially defined as very complex macro. It is easier to read just a little bit by using for_each_rsnd_mod_xxx() and new rsnd_status_update() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 83 +++++++++++++++++++++++++----------------------- 1 file changed, 43 insertions(+), 40 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index c0196f81e082..aba49b2b0103 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -371,33 +371,6 @@ struct rsnd_mod *rsnd_mod_next(int *iterator, return NULL; } -#define rsnd_mod_call(idx, io, func, param...) \ -({ \ - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ - struct rsnd_mod *mod = (io)->mod[idx]; \ - struct device *dev = rsnd_priv_to_dev(priv); \ - u32 *status = mod->get_status(io, mod, idx); \ - u32 mask = 0xF << __rsnd_mod_shift_##func; \ - u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ - u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ - int ret = 0; \ - int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ - if (add == 0xF) \ - call = 0; \ - else \ - *status = (*status & ~mask) + \ - (add << __rsnd_mod_shift_##func); \ - dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), \ - *status, call ? #func : ""); \ - if (call) \ - ret = (mod)->ops->func(mod, io, param); \ - if (ret) \ - dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ - ret; \ -}) - static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { { /* CAPTURE */ @@ -432,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, }; -#define rsnd_dai_call(fn, io, param...) \ -({ \ - struct rsnd_mod *mod; \ - int type, is_play = rsnd_io_is_play(io); \ - int ret = 0, i; \ - for (i = 0; i < RSND_MOD_MAX; i++) { \ - type = rsnd_mod_sequence[is_play][i]; \ - mod = (io)->mod[type]; \ - if (!mod) \ - continue; \ - ret |= rsnd_mod_call(type, io, fn, param); \ - } \ - ret; \ +static int rsnd_status_update(u32 *status, + int shift, int add, int timing) +{ + u32 mask = 0xF << shift; + u8 val = (*status >> shift) & 0xF; + u8 next_val = (val + add) & 0xF; + int func_call = (val == timing); + + if (next_val == 0xF) /* underflow case */ + func_call = 0; + else + *status = (*status & ~mask) + (next_val << shift); + + return func_call; +} + +#define rsnd_dai_call(fn, io, param...) \ +({ \ + struct rsnd_priv *priv = rsnd_io_to_priv(io); \ + struct device *dev = rsnd_priv_to_dev(priv); \ + struct rsnd_mod *mod; \ + int is_play = rsnd_io_is_play(io); \ + int ret = 0, i; \ + enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ + for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ + int tmp = 0; \ + u32 *status = mod->get_status(io, mod, types[i]); \ + int func_call = rsnd_status_update(status, \ + __rsnd_mod_shift_##fn, \ + __rsnd_mod_add_##fn, \ + __rsnd_mod_call_##fn); \ + dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ + (func_call && (mod)->ops->fn) ? #fn : ""); \ + if (func_call && (mod)->ops->fn) \ + tmp = (mod)->ops->fn(mod, io, param); \ + if (tmp) \ + dev_err(dev, "%s[%d] : %s error %d\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), \ + #fn, tmp); \ + ret |= tmp; \ + } \ + ret; \ }) int rsnd_dai_connect(struct rsnd_mod *mod, -- cgit v1.2.3-59-g8ed1b From 9b87bfb2e8e1bbd685489a84f4841250cab493ca Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Oct 2016 03:57:27 +0000 Subject: ASoC: rsnd: use for_each_rsnd_mod_xxx() on rsnd_rdai_continuance_probe() Now, we have for_each_rsnd_mod(), let's use it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index aba49b2b0103..ea14a1470de2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1122,6 +1122,7 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, ret = rsnd_dai_call(probe, io, priv); if (ret == -EAGAIN) { struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *mod; int i; /* @@ -1141,8 +1142,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, * remove all mod from io * and, re connect ssi */ - for (i = 0; i < RSND_MOD_MAX; i++) - rsnd_dai_disconnect((io)->mod[i], io, i); + for_each_rsnd_mod(i, mod, io) + rsnd_dai_disconnect(mod, io, i); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* -- cgit v1.2.3-59-g8ed1b From be78cea151afe1fc9d880bf2a3db0bd2deb8c62a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 19 Oct 2016 03:57:47 +0000 Subject: ASoC: rsnd: add rsnd_parse_of_node() and integrate rsnd_xxx_of_node Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d8f81a4e09e3..b3b4d89347be 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -376,6 +376,18 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io); int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io); +/* + * DT + */ +#define rsnd_parse_of_node(priv, node) \ + of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, node) +#define RSND_NODE_DAI "rcar_sound,dai" +#define RSND_NODE_SSI "rcar_sound,ssi" +#define RSND_NODE_SRC "rcar_sound,src" +#define RSND_NODE_CTU "rcar_sound,ctu" +#define RSND_NODE_MIX "rcar_sound,mix" +#define RSND_NODE_DVC "rcar_sound,dvc" + /* * R-Car sound DAI */ @@ -440,8 +452,7 @@ int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io, enum rsnd_mod_type type); -#define rsnd_dai_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") +#define rsnd_dai_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DAI) /* * R-Car Gen1/Gen2 @@ -618,8 +629,7 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io); __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); -#define rsnd_ssi_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") +#define rsnd_ssi_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SSI) void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, struct device_node *playback, struct device_node *capture); @@ -645,8 +655,7 @@ unsigned int rsnd_src_get_rate(struct rsnd_priv *priv, struct rsnd_dai_stream *io, int is_in); -#define rsnd_src_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") +#define rsnd_src_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_SRC) #define rsnd_parse_connect_src(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -659,8 +668,7 @@ int rsnd_ctu_probe(struct rsnd_priv *priv); void rsnd_ctu_remove(struct rsnd_priv *priv); int rsnd_ctu_converted_channel(struct rsnd_mod *mod); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_ctu_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") +#define rsnd_ctu_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_CTU) #define rsnd_parse_connect_ctu(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -672,8 +680,7 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); int rsnd_mix_probe(struct rsnd_priv *priv); void rsnd_mix_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_mix_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") +#define rsnd_mix_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_MIX) #define rsnd_parse_connect_mix(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ @@ -685,8 +692,7 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); int rsnd_dvc_probe(struct rsnd_priv *priv); void rsnd_dvc_remove(struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_of_node(priv) \ - of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") +#define rsnd_dvc_of_node(priv) rsnd_parse_of_node(priv, RSND_NODE_DVC) #define rsnd_parse_connect_dvc(rdai, playback, capture) \ rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ -- cgit v1.2.3-59-g8ed1b From 028f5a5bc85378317099be47995269d1027b0309 Mon Sep 17 00:00:00 2001 From: Matt Flax Date: Thu, 20 Oct 2016 10:29:14 +1100 Subject: ASoC: wm8580: Add the wm8581 codec to the driver This patch adds support for the wm8581 codec to the wm8580 driver. The wm8581 codec hardware adds a fourth DAC and otherwise is compatible with the wm8580 codec. of_device_id data is used to allow the driver to select the suitable DAC count specified in the device tree codec selection. The wm8580_driver_data struct is used to store the number of DACs. The snd_soc_dai_driver no longer lists the channels_max for the playback substream. This variable is set during the i2c probe from the of_device_id supplied wm8580_driver_data struct. With knowledge of the number of DACs in use, the DAC4 controls, widgets and routes are added as required for DAC4. The device tree documentation for the wm8580 is altered to list the wm8581 codec support, as is the Kconfig file. Signed-off-by: Matt Flax Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/wm8580.txt | 4 +- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/wm8580.c | 98 ++++++++++++++++++++-- 3 files changed, 92 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/wm8580.txt b/Documentation/devicetree/bindings/sound/wm8580.txt index 7d9821f348da..78fce9b14954 100644 --- a/Documentation/devicetree/bindings/sound/wm8580.txt +++ b/Documentation/devicetree/bindings/sound/wm8580.txt @@ -1,10 +1,10 @@ -WM8580 audio CODEC +WM8580 and WM8581 audio CODEC This device supports I2C only. Required properties: - - compatible : "wlf,wm8580" + - compatible : "wlf,wm8580", "wlf,wm8581" - reg : the I2C address of the device. diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..199bec88d4ae 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -914,7 +914,7 @@ config SND_SOC_WM8523 depends on I2C config SND_SOC_WM8580 - tristate "Wolfson Microelectronics WM8523 CODEC" + tristate "Wolfson Microelectronics WM8580 and WM8581 CODECs" depends on I2C config SND_SOC_WM8711 diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index faa7287a5253..aecd3c99e604 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1,5 +1,5 @@ /* - * wm8580.c -- WM8580 ALSA Soc Audio driver + * wm8580.c -- WM8580 and WM8581 ALSA Soc Audio driver * * Copyright 2008-12 Wolfson Microelectronics PLC. * @@ -12,6 +12,9 @@ * The WM8580 is a multichannel codec with S/PDIF support, featuring six * DAC channels and two ADC channels. * + * The WM8581 is a multichannel codec with S/PDIF support, featuring eight + * DAC channels and two ADC channels. + * * Currently only the primary audio interface is supported - S/PDIF and * the secondary audio interfaces are not. */ @@ -65,6 +68,8 @@ #define WM8580_DIGITAL_ATTENUATION_DACR2 0x17 #define WM8580_DIGITAL_ATTENUATION_DACL3 0x18 #define WM8580_DIGITAL_ATTENUATION_DACR3 0x19 +#define WM8581_DIGITAL_ATTENUATION_DACL4 0x1A +#define WM8581_DIGITAL_ATTENUATION_DACR4 0x1B #define WM8580_MASTER_DIGITAL_ATTENUATION 0x1C #define WM8580_ADC_CONTROL1 0x1D #define WM8580_SPDTXCHAN0 0x1E @@ -236,12 +241,17 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { "PVDD", }; +struct wm8580_driver_data { + int num_dacs; +}; + /* codec private data */ struct wm8580_priv { struct regmap *regmap; struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; struct pll_state a; struct pll_state b; + const struct wm8580_driver_data *drvdata; int sysclk[2]; }; @@ -306,6 +316,19 @@ SOC_DOUBLE("Capture Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 1), SOC_SINGLE("Capture High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), }; +static const struct snd_kcontrol_new wm8581_snd_controls[] = { +SOC_DOUBLE_R_EXT_TLV("DAC4 Playback Volume", + WM8581_DIGITAL_ATTENUATION_DACL4, + WM8581_DIGITAL_ATTENUATION_DACR4, + 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv), + +SOC_SINGLE("DAC4 Deemphasis Switch", WM8580_DAC_CONTROL3, 3, 1, 0), + +SOC_DOUBLE("DAC4 Invert Switch", WM8580_DAC_CONTROL4, 8, 7, 1, 0), + +SOC_SINGLE("DAC4 Switch", WM8580_DAC_CONTROL5, 3, 1, 1), +}; + static const struct snd_soc_dapm_widget wm8580_dapm_widgets[] = { SND_SOC_DAPM_DAC("DAC1", "Playback", WM8580_PWRDN1, 2, 1), SND_SOC_DAPM_DAC("DAC2", "Playback", WM8580_PWRDN1, 3, 1), @@ -324,6 +347,13 @@ SND_SOC_DAPM_INPUT("AINL"), SND_SOC_DAPM_INPUT("AINR"), }; +static const struct snd_soc_dapm_widget wm8581_dapm_widgets[] = { +SND_SOC_DAPM_DAC("DAC4", "Playback", WM8580_PWRDN1, 5, 1), + +SND_SOC_DAPM_OUTPUT("VOUT4L"), +SND_SOC_DAPM_OUTPUT("VOUT4R"), +}; + static const struct snd_soc_dapm_route wm8580_dapm_routes[] = { { "VOUT1L", NULL, "DAC1" }, { "VOUT1R", NULL, "DAC1" }, @@ -338,6 +368,11 @@ static const struct snd_soc_dapm_route wm8580_dapm_routes[] = { { "ADC", NULL, "AINR" }, }; +static const struct snd_soc_dapm_route wm8581_dapm_routes[] = { + { "VOUT4L", NULL, "DAC4" }, + { "VOUT4R", NULL, "DAC4" }, +}; + /* PLL divisors */ struct _pll_div { u32 prescale:1; @@ -815,10 +850,21 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, return 0; } +static int wm8580_playback_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + + return snd_pcm_hw_constraint_minmax(substream->runtime, + SNDRV_PCM_HW_PARAM_CHANNELS, 1, wm8580->drvdata->num_dacs * 2); +} + #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) static const struct snd_soc_dai_ops wm8580_dai_ops_playback = { + .startup = wm8580_playback_startup, .set_sysclk = wm8580_set_sysclk, .hw_params = wm8580_paif_hw_params, .set_fmt = wm8580_set_paif_dai_fmt, @@ -842,7 +888,6 @@ static struct snd_soc_dai_driver wm8580_dai[] = { .playback = { .stream_name = "Playback", .channels_min = 1, - .channels_max = 6, .rates = SNDRV_PCM_RATE_8000_192000, .formats = WM8580_FORMATS, }, @@ -865,8 +910,22 @@ static struct snd_soc_dai_driver wm8580_dai[] = { static int wm8580_probe(struct snd_soc_codec *codec) { struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); int ret = 0; + switch (wm8580->drvdata->num_dacs) { + case 4: + snd_soc_add_codec_controls(codec, wm8581_snd_controls, + ARRAY_SIZE(wm8581_snd_controls)); + snd_soc_dapm_new_controls(dapm, wm8581_dapm_widgets, + ARRAY_SIZE(wm8581_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, wm8581_dapm_routes, + ARRAY_SIZE(wm8581_dapm_routes)); + break; + default: + break; + } + ret = regulator_bulk_enable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); if (ret != 0) { @@ -914,12 +973,6 @@ static const struct snd_soc_codec_driver soc_codec_dev_wm8580 = { }, }; -static const struct of_device_id wm8580_of_match[] = { - { .compatible = "wlf,wm8580" }, - { }, -}; -MODULE_DEVICE_TABLE(of, wm8580_of_match); - static const struct regmap_config wm8580_regmap = { .reg_bits = 7, .val_bits = 9, @@ -932,10 +985,26 @@ static const struct regmap_config wm8580_regmap = { .volatile_reg = wm8580_volatile, }; +const struct wm8580_driver_data wm8580_data = { + .num_dacs = 3, +}; + +const struct wm8580_driver_data wm8581_data = { + .num_dacs = 4, +}; + +static const struct of_device_id wm8580_of_match[] = { + { .compatible = "wlf,wm8580", .data = &wm8580_data }, + { .compatible = "wlf,wm8581", .data = &wm8581_data }, + { }, +}; +MODULE_DEVICE_TABLE(of, wm8580_of_match); + #if IS_ENABLED(CONFIG_I2C) static int wm8580_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + const struct of_device_id *of_id; struct wm8580_priv *wm8580; int ret, i; @@ -960,6 +1029,15 @@ static int wm8580_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, wm8580); + of_id = of_match_device(wm8580_of_match, &i2c->dev); + if (of_id) + wm8580->drvdata = of_id->data; + + if (!wm8580->drvdata) { + dev_err(&i2c->dev, "failed to find driver data\n"); + return -EINVAL; + } + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8580, wm8580_dai, ARRAY_SIZE(wm8580_dai)); @@ -973,7 +1051,8 @@ static int wm8580_i2c_remove(struct i2c_client *client) } static const struct i2c_device_id wm8580_i2c_id[] = { - { "wm8580", 0 }, + { "wm8580", (kernel_ulong_t)&wm8580_data }, + { "wm8581", (kernel_ulong_t)&wm8581_data }, { } }; MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); @@ -1014,4 +1093,5 @@ module_exit(wm8580_exit); MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown "); +MODULE_AUTHOR("Matt Flax "); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 89c03ddbb9aafe370e7d1ebe07258ae755588bdc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 17 Oct 2016 23:02:56 +0100 Subject: ASoC: sst-bxt-da7219_max98357a: fix obsoleted initializer for array Smatch reports below warnings: bxt_da7219_max98357a.c:352:9: warning: obsolete array initializer, use C99 syntax An earlier commit cleaned up similar warnings, however, a recent commit 43c02ede76a60de ("ASoC: Intel: Add DMIC channel constraint for bxt machine") re-introduced the older initializer style. So fix this warning to make the code consistent. Signed-off-by: Colin Ian King Reviewed-by: Takashi Sakamoto Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 865a21e557cc..bff80b467262 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -348,7 +348,7 @@ static struct snd_soc_dai_link broxton_dais[] = { .dynamic = 1, .ops = &broxton_refcap_ops, }, - [BXT_DPCM_AUDIO_DMIC_CP] + [BXT_DPCM_AUDIO_DMIC_CP] = { .name = "Bxt Audio DMIC cap", .stream_name = "dmiccap", -- cgit v1.2.3-59-g8ed1b From 818f76831992198121c8949789c71a1adb02e329 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:15:18 +0000 Subject: ASoC: rk3399_gru_sound: Fix non static symbol warning Fixes the following sparse warning: sound/soc/rockchip/rk3399_gru_sound.c:41:14: warning: symbol 'rt5514_dmic_delay' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3399_gru_sound.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 9ed735a6cf49..0cbd23555ba4 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -38,7 +38,7 @@ #define SOUND_FS 256 -unsigned int rt5514_dmic_delay; +static unsigned int rt5514_dmic_delay; static struct snd_soc_jack rockchip_sound_jack; -- cgit v1.2.3-59-g8ed1b From 25fb7062484a219174baab0761e06bbfd8fa3b07 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 17 Oct 2016 19:14:04 +0800 Subject: ASoC: rt5640: enable MCLK detection There is a power saving mechanism in rt5640. It will turn off some unused power when MCLK is not present. We call that "MCLK detection" and it should be enabled by default. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 3 +++ sound/soc/codecs/rt5640.h | 2 ++ 2 files changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 3cc1135fc2cd..0a7378f81acb 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2407,6 +2407,9 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + regmap_update_bits(rt5640->regmap, RT5640_DUMMY1, + RT5640_MCLK_DET, RT5640_MCLK_DET); + if (rt5640->pdata.in1_diff) regmap_update_bits(rt5640->regmap, RT5640_IN1_IN2, RT5640_IN_DF1, RT5640_IN_DF1); diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 90c88711c72a..22c017c58d5b 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1970,6 +1970,8 @@ #define RT5640_ZCD_HP_DIS (0x0 << 15) #define RT5640_ZCD_HP_EN (0x1 << 15) +/* General Control 1 (0xfa) */ +#define RT5640_MCLK_DET (0x1 << 11) /* Codec Private Register definition */ /* 3D Speaker Control (0x63) */ -- cgit v1.2.3-59-g8ed1b From a5d93da13c8671f6453ae273cbf1d5c61b897a33 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 17 Oct 2016 19:27:16 +0800 Subject: ASoC: rt5670: Enable MCLK detection There is a power saving mechanism in rt5670. It will turn off some unused power when MCLK is not present. We call that "MCLK detection" and it should be enabled by default. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 4 +++- sound/soc/codecs/rt5670.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 49caf1393aeb..6caac92143d4 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2889,6 +2889,9 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, if (ret != 0) dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); + regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, + RT5670_MCLK_DET, RT5670_MCLK_DET); + if (rt5670->pdata.in2_diff) regmap_update_bits(rt5670->regmap, RT5670_IN2, RT5670_IN_DF2, RT5670_IN_DF2); @@ -2903,7 +2906,6 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, RT5670_GP1_PIN_MASK, RT5670_GP1_PIN_IRQ); regmap_update_bits(rt5670->regmap, RT5670_GPIO_CTRL2, RT5670_GP1_PF_MASK, RT5670_GP1_PF_OUT); - regmap_update_bits(rt5670->regmap, RT5670_DIG_MISC, 0x8, 0x8); } if (rt5670->pdata.jd_mode) { diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index 3f1b0f1df809..5ba485cae4e6 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h @@ -1914,6 +1914,7 @@ enum { #define RT5670_IF1_ADC1_IN2_SFT 11 #define RT5670_IF1_ADC2_IN1_SEL (0x1 << 10) #define RT5670_IF1_ADC2_IN1_SFT 10 +#define RT5670_MCLK_DET (0x1 << 3) /* General Control2 (0xfb) */ #define RT5670_RXDC_SRC_MASK (0x1 << 7) -- cgit v1.2.3-59-g8ed1b From d5bc18c148fd3d3ab7cbd3d976f7e27226f74dd8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:45 +0200 Subject: ASoC: intel: broadwell: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o file is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 3865 2784 384 7033 1b79 sound/soc/intel/boards/broadwell.o 3929 2720 384 7033 1b79 sound/soc/intel/boards/broadwell.o Signed-off-by: Julia Lawall Acked-by: Jie Yang Signed-off-by: Mark Brown --- sound/soc/intel/boards/broadwell.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7486a0022fde..5bb64d164877 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -126,7 +126,7 @@ static int broadwell_rt286_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops broadwell_rt286_ops = { +static const struct snd_soc_ops broadwell_rt286_ops = { .hw_params = broadwell_rt286_hw_params, }; -- cgit v1.2.3-59-g8ed1b From 28549313da65cc8711401ee5466c526bd67de5f1 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:46 +0200 Subject: ASoC: atmel_wm8904: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o file is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 2611 1536 0 4147 1033 sound/soc/atmel/atmel_wm8904.o 2675 1480 0 4155 103b sound/soc/atmel/atmel_wm8904.o Signed-off-by: Julia Lawall Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_wm8904.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel_wm8904.c b/sound/soc/atmel/atmel_wm8904.c index fdd28ed3e0b9..fbc10f61eb55 100644 --- a/sound/soc/atmel/atmel_wm8904.c +++ b/sound/soc/atmel/atmel_wm8904.c @@ -53,7 +53,7 @@ static int atmel_asoc_wm8904_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops atmel_asoc_wm8904_ops = { +static const struct snd_soc_ops atmel_asoc_wm8904_ops = { .hw_params = atmel_asoc_wm8904_hw_params, }; -- cgit v1.2.3-59-g8ed1b From 705e9994a437bbdaf655612f3526e3567db56bdd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:47 +0200 Subject: ASoC: rockchip: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o files is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 5027 2488 416 7931 1efb sound/soc/rockchip/rk3399_gru_sound.o 5219 2312 416 7947 1f0b sound/soc/rockchip/rk3399_gru_sound.o text data bss dec hex filename 3499 1648 384 5531 159b sound/soc/rockchip/rockchip_max98090.o 3563 1584 384 5531 159b sound/soc/rockchip/rockchip_max98090.o text data bss dec hex filename 3455 1536 384 5375 14ff sound/soc/rockchip/rockchip_rt5645.o 3519 1480 384 5383 1507 sound/soc/rockchip/rockchip_rt5645.o Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/rockchip/rk3399_gru_sound.c | 6 +++--- sound/soc/rockchip/rockchip_max98090.c | 2 +- sound/soc/rockchip/rockchip_rt5645.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 0cbd23555ba4..3475c61a5fa0 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -228,15 +228,15 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd) return 0; } -static struct snd_soc_ops rockchip_sound_max98357a_ops = { +static const struct snd_soc_ops rockchip_sound_max98357a_ops = { .hw_params = rockchip_sound_max98357a_hw_params, }; -static struct snd_soc_ops rockchip_sound_rt5514_ops = { +static const struct snd_soc_ops rockchip_sound_rt5514_ops = { .hw_params = rockchip_sound_rt5514_hw_params, }; -static struct snd_soc_ops rockchip_sound_da7219_ops = { +static const struct snd_soc_ops rockchip_sound_da7219_ops = { .hw_params = rockchip_sound_da7219_hw_params, }; diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index e70ffad07184..789d6f1e2b5f 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -119,7 +119,7 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops rk_aif1_ops = { +static const struct snd_soc_ops rk_aif1_ops = { .hw_params = rk_aif1_hw_params, }; diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 440a8026346a..9e0c17805807 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -135,7 +135,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) &headset_jack); } -static struct snd_soc_ops rk_aif1_ops = { +static const struct snd_soc_ops rk_aif1_ops = { .hw_params = rk_aif1_hw_params, }; -- cgit v1.2.3-59-g8ed1b From 251fc7a58eca13e4af385cc6458b5533596ddb10 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:48 +0200 Subject: ASoC: qcom: storm: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o file is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 1420 512 0 1932 78c sound/soc/qcom/storm.o 1484 456 0 1940 794 sound/soc/qcom/storm.o Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/qcom/storm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c index 2d833bffdba0..8fcac2ac3aa6 100644 --- a/sound/soc/qcom/storm.c +++ b/sound/soc/qcom/storm.c @@ -58,7 +58,7 @@ static int storm_ops_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops storm_soc_ops = { +static const struct snd_soc_ops storm_soc_ops = { .hw_params = storm_ops_hw_params, }; -- cgit v1.2.3-59-g8ed1b From 8a7a282b780154c2669ce7d4f47a15bf3d287d49 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:51 +0200 Subject: ASoC: tegra: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o files is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 3143 1888 384 5415 1527 sound/soc/tegra/tegra_alc5632.o 3191 1840 384 5415 1527 sound/soc/tegra/tegra_alc5632.o text data bss dec hex filename 3672 2176 768 6616 19d8 sound/soc/tegra/tegra_max98090.o 3720 2128 768 6616 19d8 sound/soc/tegra/tegra_max98090.o text data bss dec hex filename 2770 1856 384 5010 1392 sound/soc/tegra/tegra_rt5640.o 2818 1808 384 5010 1392 sound/soc/tegra/tegra_rt5640.o text data bss dec hex filename 4412 2176 768 7356 1cbc sound/soc/tegra/tegra_rt5677.o 4460 2128 768 7356 1cbc sound/soc/tegra/tegra_rt5677.o text data bss dec hex filename 2442 1536 0 3978 f8a sound/soc/tegra/tegra_sgtl5000.o 2490 1480 0 3970 f82 sound/soc/tegra/tegra_sgtl5000.o text data bss dec hex filename 2105 1536 0 3641 e39 sound/soc/tegra/tegra_wm8753.o 2153 1480 0 3633 e31 sound/soc/tegra/tegra_wm8753.o text data bss dec hex filename 3755 1888 768 6411 190b sound/soc/tegra/tegra_wm8903.o 3803 1840 768 6411 190b sound/soc/tegra/tegra_wm8903.o text data bss dec hex filename 2121 1536 0 3657 e49 sound/soc/tegra/trimslice.o 2169 1480 0 3649 e41 sound/soc/tegra/trimslice.o Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/tegra/tegra_alc5632.c | 2 +- sound/soc/tegra/tegra_max98090.c | 2 +- sound/soc/tegra/tegra_rt5640.c | 2 +- sound/soc/tegra/tegra_rt5677.c | 2 +- sound/soc/tegra/tegra_sgtl5000.c | 2 +- sound/soc/tegra/tegra_wm8753.c | 2 +- sound/soc/tegra/tegra_wm8903.c | 2 +- sound/soc/tegra/trimslice.c | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index deb597f7c302..eead6e7f205b 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c @@ -65,7 +65,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_alc5632_asoc_ops = { +static const struct snd_soc_ops tegra_alc5632_asoc_ops = { .hw_params = tegra_alc5632_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index 902da36581d1..a403db6d563e 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c @@ -93,7 +93,7 @@ static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_max98090_ops = { +static const struct snd_soc_ops tegra_max98090_ops = { .hw_params = tegra_max98090_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index e5ef4e9c4ac5..25b9fc03ba62 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c @@ -76,7 +76,7 @@ static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_rt5640_ops = { +static const struct snd_soc_ops tegra_rt5640_ops = { .hw_params = tegra_rt5640_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_rt5677.c b/sound/soc/tegra/tegra_rt5677.c index 1470873ecde6..ebf58d0e0f10 100644 --- a/sound/soc/tegra/tegra_rt5677.c +++ b/sound/soc/tegra/tegra_rt5677.c @@ -93,7 +93,7 @@ static int tegra_rt5677_event_hp(struct snd_soc_dapm_widget *w, return 0; } -static struct snd_soc_ops tegra_rt5677_ops = { +static const struct snd_soc_ops tegra_rt5677_ops = { .hw_params = tegra_rt5677_asoc_hw_params, }; diff --git a/sound/soc/tegra/tegra_sgtl5000.c b/sound/soc/tegra/tegra_sgtl5000.c index 1e76869dd488..4bbab098f50b 100644 --- a/sound/soc/tegra/tegra_sgtl5000.c +++ b/sound/soc/tegra/tegra_sgtl5000.c @@ -82,7 +82,7 @@ static int tegra_sgtl5000_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_sgtl5000_ops = { +static const struct snd_soc_ops tegra_sgtl5000_ops = { .hw_params = tegra_sgtl5000_hw_params, }; diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index f0cd01dbfc38..bdedd1028569 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c @@ -89,7 +89,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_wm8753_ops = { +static const struct snd_soc_ops tegra_wm8753_ops = { .hw_params = tegra_wm8753_hw_params, }; diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index e485278e027a..2013e9c4bba0 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -96,7 +96,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops tegra_wm8903_ops = { +static const struct snd_soc_ops tegra_wm8903_ops = { .hw_params = tegra_wm8903_hw_params, }; diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 2cea203c4f5f..870f84ab5005 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c @@ -74,7 +74,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops trimslice_asoc_ops = { +static const struct snd_soc_ops trimslice_asoc_ops = { .hw_params = trimslice_asoc_hw_params, }; -- cgit v1.2.3-59-g8ed1b From 9b6fdef62b37714af9495d09eab1d0c8ba0509bd Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:49 +0200 Subject: ASoC: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o files is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 4500 696 0 5196 144c sound/soc/generic/simple-card.o 4564 632 0 5196 144c sound/soc/generic/simple-card.o text data bss dec hex filename 3018 608 0 3626 e2a sound/soc/generic/simple-scu-card.o 3074 544 0 3618 e22 sound/soc/generic/simple-scu-card.o text data bss dec hex filename 4148 2448 768 7364 1cc4 sound/soc/intel/boards/bdw-rt5677.o 4212 2384 768 7364 1cc4 sound/soc/intel/boards/bdw-rt5677.o text data bss dec hex filename 5403 4628 384 10415 28af sound/soc/intel/boards/bxt_da7219_max98357a.o 5531 4516 384 10431 28bf sound/soc/intel/boards/bxt_da7219_max98357a.o text data bss dec hex filename 5275 4496 384 10155 27ab sound/soc/intel/boards/bxt_rt298.o 5403 4368 384 10155 27ab sound/soc/intel/boards/bxt_rt298.o text data bss dec hex filename 10017 2344 48 12409 3079 sound/soc/intel/boards/bytcr_rt5640.o 10145 2232 48 12425 3089 sound/soc/intel/boards/bytcr_rt5640.o text data bss dec hex filename 3719 2356 0 6075 17bb sound/soc/intel/boards/bytcr_rt5651.o 3847 2244 0 6091 17cb sound/soc/intel/boards/bytcr_rt5651.o text data bss dec hex filename 3598 2392 0 5990 1766 sound/soc/intel/boards/cht_bsw_max98090_ti.o 3726 2280 0 6006 1776 sound/soc/intel/boards/cht_bsw_max98090_ti.o text data bss dec hex filename 5343 3624 16 8983 2317 sound/soc/intel/boards/cht_bsw_rt5645.o 5471 3496 16 8983 2317 sound/soc/intel/boards/cht_bsw_rt5645.o text data bss dec hex filename 4662 2592 384 7638 1dd6 sound/soc/intel/boards/cht_bsw_rt5672.o 4790 2464 384 7638 1dd6 sound/soc/intel/boards/cht_bsw_rt5672.o text data bss dec hex filename 1595 2528 0 4123 101b sound/soc/intel/boards/haswell.o 1659 2472 0 4131 1023 sound/soc/intel/boards/haswell.o text data bss dec hex filename 6272 4760 416 11448 2cb8 sound/soc/intel/boards/skl_nau88l25_max98357a.o 6464 4568 416 11448 2cb8 sound/soc/intel/boards/skl_nau88l25_max98357a.o text data bss dec hex filename 7075 4888 416 12379 305b sound/soc/intel/boards/skl_nau88l25_ssm4567.o 7267 4696 416 12379 305b sound/soc/intel/boards/skl_nau88l25_ssm4567.o text data bss dec hex filename 5659 4496 384 10539 292b sound/soc/intel/boards/skl_rt286.o 5787 4368 384 10539 292b sound/soc/intel/boards/skl_rt286.o text data bss dec hex filename 1721 2048 0 3769 eb9 sound/soc/kirkwood/armada-370-db.o 1769 1976 0 3745 ea1 sound/soc/kirkwood/armada-370-db.o text data bss dec hex filename 1363 1792 0 3155 c53 sound/soc/mxs/mxs-sgtl5000.o 1427 1728 0 3155 c53 sound/soc/mxs/mxs-sgtl5000.o Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 2 +- sound/soc/generic/simple-scu-card.c | 2 +- sound/soc/intel/boards/bdw-rt5677.c | 2 +- sound/soc/intel/boards/bxt_da7219_max98357a.c | 4 ++-- sound/soc/intel/boards/bxt_rt298.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5640.c | 4 ++-- sound/soc/intel/boards/bytcr_rt5651.c | 4 ++-- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5645.c | 4 ++-- sound/soc/intel/boards/cht_bsw_rt5672.c | 4 ++-- sound/soc/intel/boards/haswell.c | 2 +- sound/soc/intel/boards/skl_nau88l25_max98357a.c | 6 +++--- sound/soc/intel/boards/skl_nau88l25_ssm4567.c | 6 +++--- sound/soc/intel/boards/skl_rt286.c | 4 ++-- sound/soc/kirkwood/armada-370-db.c | 2 +- sound/soc/mxs/mxs-sgtl5000.c | 2 +- 16 files changed, 28 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index f608f8d23f3d..a385ff6bfa4b 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -174,7 +174,7 @@ err: return ret; } -static struct snd_soc_ops asoc_simple_card_ops = { +static const struct snd_soc_ops asoc_simple_card_ops = { .startup = asoc_simple_card_startup, .shutdown = asoc_simple_card_shutdown, .hw_params = asoc_simple_card_hw_params, diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index b9973a56bcb0..fe3d3ca45b39 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -59,7 +59,7 @@ static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) clk_disable_unprepare(dai_props->clk); } -static struct snd_soc_ops asoc_simple_card_ops = { +static const struct snd_soc_ops asoc_simple_card_ops = { .startup = asoc_simple_card_startup, .shutdown = asoc_simple_card_shutdown, }; diff --git a/sound/soc/intel/boards/bdw-rt5677.c b/sound/soc/intel/boards/bdw-rt5677.c index 547e6705bf6d..53c6b4cbb1e1 100644 --- a/sound/soc/intel/boards/bdw-rt5677.c +++ b/sound/soc/intel/boards/bdw-rt5677.c @@ -156,7 +156,7 @@ static int bdw_rt5677_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops bdw_rt5677_ops = { +static const struct snd_soc_ops bdw_rt5677_ops = { .hw_params = bdw_rt5677_hw_params, }; diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index 6532b8f0ab2f..ddf45c0f711d 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -248,7 +248,7 @@ static int broxton_da7219_hw_free(struct snd_pcm_substream *substream) return ret; } -static struct snd_soc_ops broxton_da7219_ops = { +static const struct snd_soc_ops broxton_da7219_ops = { .hw_params = broxton_da7219_hw_params, .hw_free = broxton_da7219_hw_free, }; @@ -295,7 +295,7 @@ static int broxton_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); }; -static struct snd_soc_ops broxton_refcap_ops = { +static const struct snd_soc_ops broxton_refcap_ops = { .startup = broxton_refcap_startup, }; diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index d610bdca1608..1309405b3808 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c @@ -181,7 +181,7 @@ static int broxton_rt298_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops broxton_rt298_ops = { +static const struct snd_soc_ops broxton_rt298_ops = { .hw_params = broxton_rt298_hw_params, }; @@ -230,7 +230,7 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops broxton_dmic_ops = { +static const struct snd_soc_ops broxton_dmic_ops = { .startup = broxton_dmic_startup, }; diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bff77a1f27fc..751e009801c5 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -597,11 +597,11 @@ static int byt_rt5640_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops byt_rt5640_aif1_ops = { +static const struct snd_soc_ops byt_rt5640_aif1_ops = { .startup = byt_rt5640_aif1_startup, }; -static struct snd_soc_ops byt_rt5640_be_ssp2_ops = { +static const struct snd_soc_ops byt_rt5640_be_ssp2_ops = { .hw_params = byt_rt5640_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/bytcr_rt5651.c b/sound/soc/intel/boards/bytcr_rt5651.c index 35f591eab3c9..2d24dc04b597 100644 --- a/sound/soc/intel/boards/bytcr_rt5651.c +++ b/sound/soc/intel/boards/bytcr_rt5651.c @@ -219,11 +219,11 @@ static int byt_rt5651_aif1_startup(struct snd_pcm_substream *substream) &constraints_48000); } -static struct snd_soc_ops byt_rt5651_aif1_ops = { +static const struct snd_soc_ops byt_rt5651_aif1_ops = { .startup = byt_rt5651_aif1_startup, }; -static struct snd_soc_ops byt_rt5651_be_ssp2_ops = { +static const struct snd_soc_ops byt_rt5651_be_ssp2_ops = { .hw_params = byt_rt5651_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index cdcced9f32b6..742bc0d4e681 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -204,11 +204,11 @@ static int cht_max98090_headset_init(struct snd_soc_component *component) return ts3a227e_enable_jack_detect(component, &ctx->jack); } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = { .startup = cht_aif1_startup, }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = { .hw_params = cht_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 56056ed7fcfd..d6f4ccaf6474 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -250,11 +250,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = { .startup = cht_aif1_startup, }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = { .hw_params = cht_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index df9d254baa18..71d578cfe740 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -225,11 +225,11 @@ static int cht_aif1_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, 48000); } -static struct snd_soc_ops cht_aif1_ops = { +static const struct snd_soc_ops cht_aif1_ops = { .startup = cht_aif1_startup, }; -static struct snd_soc_ops cht_be_ssp2_ops = { +static const struct snd_soc_ops cht_be_ssp2_ops = { .hw_params = cht_aif1_hw_params, }; diff --git a/sound/soc/intel/boards/haswell.c b/sound/soc/intel/boards/haswell.c index 863f1d5e2a2c..5e1ea0371c90 100644 --- a/sound/soc/intel/boards/haswell.c +++ b/sound/soc/intel/boards/haswell.c @@ -81,7 +81,7 @@ static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops haswell_rt5640_ops = { +static const struct snd_soc_ops haswell_rt5640_ops = { .hw_params = haswell_rt5640_hw_params, }; diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index 25db5be7fdfa..fddd1cd12f13 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c @@ -332,7 +332,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops skylake_nau8825_ops = { +static const struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; @@ -382,7 +382,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; @@ -416,7 +416,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylaye_refcap_ops = { .startup = skylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index 69c5d5da4e86..8ab865ee0cad 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c @@ -394,7 +394,7 @@ static int skylake_nau8825_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops skylake_nau8825_ops = { +static const struct snd_soc_ops skylake_nau8825_ops = { .hw_params = skylake_nau8825_hw_params, }; @@ -430,7 +430,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; @@ -464,7 +464,7 @@ static int skylake_refcap_startup(struct snd_pcm_substream *substream) &constraints_16000); } -static struct snd_soc_ops skylaye_refcap_ops = { +static const struct snd_soc_ops skylaye_refcap_ops = { .startup = skylake_refcap_startup, }; diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 88c61e8cb87f..dc5c3611a6ff 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c @@ -250,7 +250,7 @@ static int skylake_rt286_hw_params(struct snd_pcm_substream *substream, return ret; } -static struct snd_soc_ops skylake_rt286_ops = { +static const struct snd_soc_ops skylake_rt286_ops = { .hw_params = skylake_rt286_hw_params, }; @@ -289,7 +289,7 @@ static int skylake_dmic_startup(struct snd_pcm_substream *substream) SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); } -static struct snd_soc_ops skylake_dmic_ops = { +static const struct snd_soc_ops skylake_dmic_ops = { .startup = skylake_dmic_startup, }; diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c index e0304d544f26..677a48d7b891 100644 --- a/sound/soc/kirkwood/armada-370-db.c +++ b/sound/soc/kirkwood/armada-370-db.c @@ -42,7 +42,7 @@ static int a370db_hw_params(struct snd_pcm_substream *substream, return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN); } -static struct snd_soc_ops a370db_ops = { +static const struct snd_soc_ops a370db_ops = { .hw_params = a370db_hw_params, }; diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 2b23ffbac6b1..a96276e77332 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -68,7 +68,7 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops mxs_sgtl5000_hifi_ops = { +static const struct snd_soc_ops mxs_sgtl5000_hifi_ops = { .hw_params = mxs_sgtl5000_hw_params, }; -- cgit v1.2.3-59-g8ed1b From ddba7fa4cfd16b10adcbe24fa1d3b7de470af863 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 16:55:50 +0200 Subject: ASoC: constify snd_soc_ops structures Check for snd_soc_ops structures that are only stored in the ops field of a snd_soc_dai_link structure. This field is declared const, so snd_soc_ops structures that have this property can be declared as const also. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @r disable optional_qualifier@ identifier i; position p; @@ static struct snd_soc_ops i@p = { ... }; @ok1@ identifier r.i; struct snd_soc_dai_link e; position p; @@ e.ops = &i@p; @ok2@ identifier r.i, e; position p; @@ struct snd_soc_dai_link e[] = { ..., { .ops = &i@p, }, ..., }; @bad@ position p != {r.p,ok1.p,ok2.p}; identifier r.i; struct snd_soc_ops e; @@ e@i@p @depends on !bad disable optional_qualifier@ identifier r.i; @@ static +const struct snd_soc_ops i = { ... }; // The effect on the layout of the .o files is shown by the following output of the size command, first before then after the transformation: text data bss dec hex filename 8748 1024 0 9772 262c sound/soc/fsl/fsl-asoc-card.o 8812 952 0 9764 2624 sound/soc/fsl/fsl-asoc-card.o text data bss dec hex filename 4165 264 8 4437 1155 sound/soc/fsl/imx-wm8962.o 4229 200 8 4437 1155 sound/soc/fsl/imx-wm8962.o Signed-off-by: Julia Lawall Signed-off-by: Mark Brown --- sound/soc/fsl/fsl-asoc-card.c | 2 +- sound/soc/fsl/imx-wm8962.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index dffd549a0e2a..9998aea23597 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -183,7 +183,7 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops fsl_asoc_card_ops = { +static const struct snd_soc_ops fsl_asoc_card_ops = { .hw_params = fsl_asoc_card_hw_params, }; diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 201a70d1027a..1b60958e2080 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -61,7 +61,7 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops imx_hifi_ops = { +static const struct snd_soc_ops imx_hifi_ops = { .hw_params = imx_hifi_hw_params, }; -- cgit v1.2.3-59-g8ed1b From 0d895e14dff0af1838ca79a82f2c0cee7b8bf7ef Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 19:32:52 +0200 Subject: ASoC: wm9712: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. The last user of these defines was removed in commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support"). So remove the defines as well. This also means the wm9712.h file no longer has any content and can be removed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 1 - sound/soc/codecs/wm9712.h | 11 ----------- sound/soc/pxa/e800_wm9712.c | 1 - sound/soc/pxa/em-x270.c | 1 - sound/soc/pxa/palm27x.c | 1 - sound/soc/pxa/tosa.c | 1 - 6 files changed, 16 deletions(-) delete mode 100644 sound/soc/codecs/wm9712.h (limited to 'sound') diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 20b2e8216336..5ed484eb47b2 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -22,7 +22,6 @@ #include #include #include -#include "wm9712.h" #define WM9712_VENDOR_ID 0x574d4c12 #define WM9712_VENDOR_ID_MASK 0xffffffff diff --git a/sound/soc/codecs/wm9712.h b/sound/soc/codecs/wm9712.h deleted file mode 100644 index fb69c3aa4ed0..000000000000 --- a/sound/soc/codecs/wm9712.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * wm9712.h -- WM9712 Soc Audio driver - */ - -#ifndef _WM9712_H -#define _WM9712_H - -#define WM9712_DAI_AC97_HIFI 0 -#define WM9712_DAI_AC97_AUX 1 - -#endif diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 41bf71466a7b..07b9c6e17df9 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c @@ -21,7 +21,6 @@ #include #include -#include "../codecs/wm9712.h" #include "pxa2xx-ac97.h" static int e800_spk_amp_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/pxa/em-x270.c b/sound/soc/pxa/em-x270.c index 64743a05aeae..966163d1c813 100644 --- a/sound/soc/pxa/em-x270.c +++ b/sound/soc/pxa/em-x270.c @@ -30,7 +30,6 @@ #include #include -#include "../codecs/wm9712.h" #include "pxa2xx-ac97.h" static struct snd_soc_dai_link em_x270_dai[] = { diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index bcc81e920a67..387492d46b6c 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c @@ -27,7 +27,6 @@ #include #include -#include "../codecs/wm9712.h" #include "pxa2xx-ac97.h" static struct snd_soc_jack hs_jack; diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c508f024ecfb..daed981f02dd 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -31,7 +31,6 @@ #include #include -#include "../codecs/wm9712.h" #include "pxa2xx-ac97.h" #define TOSA_HP 0 -- cgit v1.2.3-59-g8ed1b From 50d12367811a26dd8d5f7090d5578c3edecb795d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 19:32:53 +0200 Subject: ASoC: wm9713: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. The last user of these defines was removed in commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support"). So remove the defines as well. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index 53df11b1f727..7ecffc563016 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h @@ -41,8 +41,4 @@ #define WM9713_PCMBCLK_DIV_8 (3 << 9) #define WM9713_PCMBCLK_DIV_16 (4 << 9) -#define WM9713_DAI_AC97_HIFI 0 -#define WM9713_DAI_AC97_AUX 1 -#define WM9713_DAI_PCM_VOICE 2 - #endif -- cgit v1.2.3-59-g8ed1b From 68b24a20cbf0a9fb691031506ff7ea1e7b210a2c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 19:32:54 +0200 Subject: ASoC: wm8753: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. These particular IDs were never used and presumably never will be, so remove them. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8753.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8753.h b/sound/soc/codecs/wm8753.h index 94edac144bcb..8b39e3677ac8 100644 --- a/sound/soc/codecs/wm8753.h +++ b/sound/soc/codecs/wm8753.h @@ -112,7 +112,4 @@ #define WM8753_VXCLK_DIV_8 (3 << 6) #define WM8753_VXCLK_DIV_16 (4 << 6) -#define WM8753_DAI_HIFI 0 -#define WM8753_DAI_VOICE 1 - #endif -- cgit v1.2.3-59-g8ed1b From d41a5b4a08607c4219654bbe9b382944cd92eec7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 19:32:51 +0200 Subject: ASoC: wm9705: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. The last user of these defines was removed in commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support"). So remove the defines as well. This also means the wm9705.h file no longer has any content and can be removed. Signed-off-by: Lars-Peter Clausen Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm9705.c | 2 -- sound/soc/codecs/wm9705.h | 11 ----------- sound/soc/pxa/e740_wm9705.c | 1 - sound/soc/pxa/e750_wm9705.c | 1 - 4 files changed, 15 deletions(-) delete mode 100644 sound/soc/codecs/wm9705.h (limited to 'sound') diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index e73ff6176622..f6d5c0f2aea5 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -21,8 +21,6 @@ #include #include -#include "wm9705.h" - #define WM9705_VENDOR_ID 0x574d4c05 #define WM9705_VENDOR_ID_MASK 0xffffffff diff --git a/sound/soc/codecs/wm9705.h b/sound/soc/codecs/wm9705.h deleted file mode 100644 index 23ea9ce47359..000000000000 --- a/sound/soc/codecs/wm9705.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * wm9705.h -- WM9705 Soc Audio driver - */ - -#ifndef _WM9705_H -#define _WM9705_H - -#define WM9705_DAI_AC97_HIFI 0 -#define WM9705_DAI_AC97_AUX 1 - -#endif diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 1de876529aa1..086c37a85630 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c @@ -22,7 +22,6 @@ #include -#include "../codecs/wm9705.h" #include "pxa2xx-ac97.h" diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index b7eb7cd5df7d..7823278012a6 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c @@ -22,7 +22,6 @@ #include -#include "../codecs/wm9705.h" #include "pxa2xx-ac97.h" static int e750_spk_amp_event(struct snd_soc_dapm_widget *w, -- cgit v1.2.3-59-g8ed1b From 78d70675a4c7a3800ef5a49b6727cee0fdff5222 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 19:32:56 +0200 Subject: ASoC: pxa2xx-i2s: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. This particular ID was never used and presumably never will be, so remove it. Signed-off-by: Lars-Peter Clausen Acked-by: Robert Jarzmik Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h index 070f3c6059fe..7e218e2105a9 100644 --- a/sound/soc/pxa/pxa2xx-i2s.h +++ b/sound/soc/pxa/pxa2xx-i2s.h @@ -9,9 +9,6 @@ #ifndef _PXA2XX_I2S_H #define _PXA2XX_I2S_H -/* pxa2xx DAI ID's */ -#define PXA2XX_DAI_I2S 0 - /* I2S clock */ #define PXA2XX_I2S_SYSCLK 0 -- cgit v1.2.3-59-g8ed1b From 3f7fab0d7c61efaeee68b17e6ddc8069922d20aa Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 19:32:57 +0200 Subject: ASoC: pxa-ssp: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. The last user of these defines was removed in commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support"). So remove the defines as well. Signed-off-by: Lars-Peter Clausen Acked-by: Robert Jarzmik Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/pxa-ssp.h b/sound/soc/pxa/pxa-ssp.h index bc79da221c0d..abf6ec080258 100644 --- a/sound/soc/pxa/pxa-ssp.h +++ b/sound/soc/pxa/pxa-ssp.h @@ -9,12 +9,6 @@ #ifndef _PXA_SSP_H #define _PXA_SSP_H -/* pxa DAI SSP IDs */ -#define PXA_DAI_SSP1 0 -#define PXA_DAI_SSP2 1 -#define PXA_DAI_SSP3 2 -#define PXA_DAI_SSP4 3 - /* SSP clock sources */ #define PXA_SSP_CLK_PLL 0 #define PXA_SSP_CLK_EXT 1 -- cgit v1.2.3-59-g8ed1b From 0f40132d5d68a3226085013e24ac02aa37586850 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 21:17:16 +0200 Subject: ASoC: es8328: Remove some unused defines The es8328 drivers seems to have used the wm8753 driver as a template. Its header file contains a few defines that are copied verbatim from the wm8753 header that do not really apply to this driver and are unused. So remove those defines. This seems safe as they deal with PLL and clock divider settings and the es8328 driver neither implements a set_pll() nor a set_clkdiv() callback. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/es8328.h | 37 ------------------------------------- 1 file changed, 37 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h index 1a736e72a929..8930322d712b 100644 --- a/sound/soc/codecs/es8328.h +++ b/sound/soc/codecs/es8328.h @@ -278,43 +278,6 @@ int es8328_probe(struct device *dev, struct regmap *regmap); #define ES8328_REG_MAX 0x35 -#define ES8328_PLL1 0 -#define ES8328_PLL2 1 - -/* clock inputs */ -#define ES8328_MCLK 0 -#define ES8328_PCMCLK 1 - -/* clock divider id's */ -#define ES8328_PCMDIV 0 -#define ES8328_BCLKDIV 1 -#define ES8328_VXCLKDIV 2 - -/* PCM clock dividers */ -#define ES8328_PCM_DIV_1 (0 << 6) -#define ES8328_PCM_DIV_3 (2 << 6) -#define ES8328_PCM_DIV_5_5 (3 << 6) -#define ES8328_PCM_DIV_2 (4 << 6) -#define ES8328_PCM_DIV_4 (5 << 6) -#define ES8328_PCM_DIV_6 (6 << 6) -#define ES8328_PCM_DIV_8 (7 << 6) - -/* BCLK clock dividers */ -#define ES8328_BCLK_DIV_1 (0 << 7) -#define ES8328_BCLK_DIV_2 (1 << 7) -#define ES8328_BCLK_DIV_4 (2 << 7) -#define ES8328_BCLK_DIV_8 (3 << 7) - -/* VXCLK clock dividers */ -#define ES8328_VXCLK_DIV_1 (0 << 6) -#define ES8328_VXCLK_DIV_2 (1 << 6) -#define ES8328_VXCLK_DIV_4 (2 << 6) -#define ES8328_VXCLK_DIV_8 (3 << 6) -#define ES8328_VXCLK_DIV_16 (4 << 6) - -#define ES8328_DAI_HIFI 0 -#define ES8328_DAI_VOICE 1 - #define ES8328_1536FS 1536 #define ES8328_1024FS 1024 #define ES8328_768FS 768 -- cgit v1.2.3-59-g8ed1b From fe75e14f15f408abde03c00409ab52304a3b3ca2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 21:32:39 +0200 Subject: ASoC: ak4641: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. This driver was merged after the change of DAIs are matched was made and the IDs were never used and presumably never will be, so remove them. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4641.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h index 4a263248efea..38b9e93e97a4 100644 --- a/sound/soc/codecs/ak4641.h +++ b/sound/soc/codecs/ak4641.h @@ -38,10 +38,4 @@ #define AK4641_CACHEREGNUM 0x14 - - -#define AK4641_DAI_HIFI 0 -#define AK4641_DAI_VOICE 1 - - #endif -- cgit v1.2.3-59-g8ed1b From 5fdc402ab58f729ff9813b197e92e3d684a1b6a0 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 21:32:40 +0200 Subject: ASoC: ak4641: Remove unused AK4641_CACHEREGNUM define The last user was removed in commit 4f534777c130 ("ASoC: ak4641: Convert to direct regmap API usage"). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4641.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h index 38b9e93e97a4..e00af5c62160 100644 --- a/sound/soc/codecs/ak4641.h +++ b/sound/soc/codecs/ak4641.h @@ -36,6 +36,4 @@ #define AK4641_EQHI 0x12 #define AK4641_BTIF 0x13 -#define AK4641_CACHEREGNUM 0x14 - #endif -- cgit v1.2.3-59-g8ed1b From 5841ce10154e40151dd82eedf3e22e588d87c18b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 15 Oct 2016 21:32:41 +0200 Subject: ASoC: ak4641: Move register defines to main source The ak4641 driver only has a few register defines. As they are only used in the one main driver file there is not really a need to keep them in a separate header. Moving them to the main source file allows to remove the now empty header file completely. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4641.c | 22 +++++++++++++++++++++- sound/soc/codecs/ak4641.h | 39 --------------------------------------- sound/soc/pxa/hx4700.c | 2 -- 3 files changed, 21 insertions(+), 42 deletions(-) delete mode 100644 sound/soc/codecs/ak4641.h (limited to 'sound') diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index c91717d08513..ebdaf56c1d61 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -27,7 +27,27 @@ #include #include -#include "ak4641.h" +/* AK4641 register space */ +#define AK4641_PM1 0x00 +#define AK4641_PM2 0x01 +#define AK4641_SIG1 0x02 +#define AK4641_SIG2 0x03 +#define AK4641_MODE1 0x04 +#define AK4641_MODE2 0x05 +#define AK4641_DAC 0x06 +#define AK4641_MIC 0x07 +#define AK4641_TIMER 0x08 +#define AK4641_ALC1 0x09 +#define AK4641_ALC2 0x0a +#define AK4641_PGA 0x0b +#define AK4641_LATT 0x0c +#define AK4641_RATT 0x0d +#define AK4641_VOL 0x0e +#define AK4641_STATUS 0x0f +#define AK4641_EQLO 0x10 +#define AK4641_EQMID 0x11 +#define AK4641_EQHI 0x12 +#define AK4641_BTIF 0x13 /* codec private data */ struct ak4641_priv { diff --git a/sound/soc/codecs/ak4641.h b/sound/soc/codecs/ak4641.h deleted file mode 100644 index e00af5c62160..000000000000 --- a/sound/soc/codecs/ak4641.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * ak4641.h -- AK4641 SoC Audio driver - * - * Copyright 2008 Harald Welte - * - * Based on ak4535.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _AK4641_H -#define _AK4641_H - -/* AK4641 register space */ - -#define AK4641_PM1 0x00 -#define AK4641_PM2 0x01 -#define AK4641_SIG1 0x02 -#define AK4641_SIG2 0x03 -#define AK4641_MODE1 0x04 -#define AK4641_MODE2 0x05 -#define AK4641_DAC 0x06 -#define AK4641_MIC 0x07 -#define AK4641_TIMER 0x08 -#define AK4641_ALC1 0x09 -#define AK4641_ALC2 0x0a -#define AK4641_PGA 0x0b -#define AK4641_LATT 0x0c -#define AK4641_RATT 0x0d -#define AK4641_VOL 0x0e -#define AK4641_STATUS 0x0f -#define AK4641_EQLO 0x10 -#define AK4641_EQMID 0x11 -#define AK4641_EQHI 0x12 -#define AK4641_BTIF 0x13 - -#endif diff --git a/sound/soc/pxa/hx4700.c b/sound/soc/pxa/hx4700.c index ecbf2873b7ff..85483049b916 100644 --- a/sound/soc/pxa/hx4700.c +++ b/sound/soc/pxa/hx4700.c @@ -27,8 +27,6 @@ #include #include "pxa2xx-i2s.h" -#include "../codecs/ak4641.h" - static struct snd_soc_jack hs_jack; /* Headphones jack detection DAPM pin */ -- cgit v1.2.3-59-g8ed1b From 5faf071d08ddd1c1be66deaa93a09ccf43f5b538 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 21 Oct 2016 14:18:48 +0100 Subject: ASoC: samsung: i2s: Fixup last IRQ unsafe spin lock call Unfortunately, I seem to have missed a case where an IRQ safe spinlock was required, in samsung_i2s_dai_remove, when I fixed up the other calls in this patch: 316fa9e09ad7 ("ASoC: samsung: Use IRQ safe spin lock calls") This causes a lockdep warning when unbinding and rebinding the audio card: [ 104.357664] CPU0 CPU1 [ 104.362174] ---- ---- [ 104.366692] lock(&(&pri_dai->spinlock)->rlock); [ 104.371372] local_irq_disable(); [ 104.377283] lock(&(&substream->self_group.lock)->rlock); [ 104.385259] lock(&(&pri_dai->spinlock)->rlock); [ 104.392469] [ 104.395072] lock(&(&substream->self_group.lock)->rlock); [ 104.400710] [ 104.400710] *** DEADLOCK *** Fixes: ce8bcdbb61d9 ("ASoC: samsung: i2s: Protect more registers with a spinlock") Signed-off-by: Charles Keepax Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 7e32cf4581f8..588aa0160a3f 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1029,12 +1029,13 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) { struct i2s_dai *i2s = snd_soc_dai_get_drvdata(dai); + unsigned long flags; if (!is_secondary(i2s)) { if (i2s->quirks & QUIRK_NEED_RSTCLR) { - spin_lock(i2s->lock); + spin_lock_irqsave(i2s->lock, flags); writel(0, i2s->addr + I2SCON); - spin_unlock(i2s->lock); + spin_unlock_irqrestore(i2s->lock, flags); } } -- cgit v1.2.3-59-g8ed1b From 892ccf0f2173a9ede5448411e9475616fb21fb51 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 25 Oct 2016 12:57:57 +0200 Subject: ASoC: s3c24xx_uda134x: Move global variables to driver's data structure Gather all driver's private variables in common data structure and allocate the data structure dynamically. Also unused ENFORCE_RATES symbol and local variable (leftovers from an erroneous rebase) are removed. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx_uda134x.c | 79 ++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 7853fbe6ccc9..81a78940967c 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c @@ -19,9 +19,15 @@ #include #include "regs-iis.h" - #include "s3c24xx-i2s.h" +struct s3c24xx_uda134x { + struct clk *xtal; + struct clk *pclk; + struct mutex clk_lock; + int clk_users; +}; + /* #define ENFORCE_RATES 1 */ /* Unfortunately the S3C24XX in master mode has a limited capacity of @@ -36,15 +42,6 @@ possible an error will be returned. */ -static struct clk *xtal; -static struct clk *pclk; -/* this is need because we don't have a place where to keep the - * pointers to the clocks in each substream. We get the clocks only - * when we are actually using them so we don't block stuff like - * frequency change or oscillator power-off */ -static int clk_users; -static DEFINE_MUTEX(clk_lock); - static unsigned int rates[33 * 2]; #ifdef ENFORCE_RATES static struct snd_pcm_hw_constraint_list hw_constraints_rates = { @@ -57,26 +54,24 @@ static struct snd_pcm_hw_constraint_list hw_constraints_rates = { static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *cpu_dai = rtd->cpu_dai; -#ifdef ENFORCE_RATES - struct snd_pcm_runtime *runtime = substream->runtime; -#endif int ret = 0; - mutex_lock(&clk_lock); + mutex_lock(&priv->clk_lock); - if (clk_users == 0) { - xtal = clk_get(rtd->dev, "xtal"); - if (IS_ERR(xtal)) { + if (priv->clk_users == 0) { + priv->xtal = clk_get(rtd->dev, "xtal"); + if (IS_ERR(priv->xtal)) { dev_err(rtd->dev, "%s cannot get xtal\n", __func__); - ret = PTR_ERR(xtal); + ret = PTR_ERR(priv->xtal); } else { - pclk = clk_get(cpu_dai->dev, "iis"); - if (IS_ERR(pclk)) { + priv->pclk = clk_get(cpu_dai->dev, "iis"); + if (IS_ERR(priv->pclk)) { dev_err(rtd->dev, "%s cannot get pclk\n", __func__); - clk_put(xtal); - ret = PTR_ERR(pclk); + clk_put(priv->xtal); + ret = PTR_ERR(priv->pclk); } } if (!ret) { @@ -85,18 +80,19 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) for (i = 0; i < 2; i++) { int fs = i ? 256 : 384; - rates[i*33] = clk_get_rate(xtal) / fs; + rates[i*33] = clk_get_rate(priv->xtal) / fs; for (j = 1; j < 33; j++) - rates[i*33 + j] = clk_get_rate(pclk) / + rates[i*33 + j] = clk_get_rate(priv->pclk) / (j * fs); } } } - clk_users += 1; - mutex_unlock(&clk_lock); + priv->clk_users += 1; + mutex_unlock(&priv->clk_lock); + if (!ret) { #ifdef ENFORCE_RATES - ret = snd_pcm_hw_constraint_list(runtime, 0, + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); if (ret < 0) @@ -109,15 +105,18 @@ static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream) static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream) { - mutex_lock(&clk_lock); - clk_users -= 1; - if (clk_users == 0) { - clk_put(xtal); - xtal = NULL; - clk_put(pclk); - pclk = NULL; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card); + + mutex_lock(&priv->clk_lock); + priv->clk_users -= 1; + if (priv->clk_users == 0) { + clk_put(priv->xtal); + priv->xtal = NULL; + clk_put(priv->pclk); + priv->pclk = NULL; } - mutex_unlock(&clk_lock); + mutex_unlock(&priv->clk_lock); } static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream, @@ -228,10 +227,18 @@ static struct snd_soc_card snd_soc_s3c24xx_uda134x = { static int s3c24xx_uda134x_probe(struct platform_device *pdev) { struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x; + struct s3c24xx_uda134x *priv; int ret; - platform_set_drvdata(pdev, card); + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->clk_lock); + card->dev = &pdev->dev; + platform_set_drvdata(pdev, card); + snd_soc_card_set_drvdata(card, priv); ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) -- cgit v1.2.3-59-g8ed1b From a5461fd6c8f70b3d897f5f76612e890ad47a5b93 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 25 Oct 2016 19:27:26 +0800 Subject: ASoC: rt5514: Add the DMIC initial delay to wait it ready. Due to the DMIC that needs time to initial after the MCLK is provided, the field of delay time is implemented by the platform data. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5514.txt | 3 +++ include/sound/rt5514.h | 20 ++++++++++++++++++++ sound/soc/codecs/rt5514.c | 17 +++++++++++++++++ sound/soc/codecs/rt5514.h | 2 ++ 4 files changed, 42 insertions(+) create mode 100644 include/sound/rt5514.h (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/rt5514.txt b/Documentation/devicetree/bindings/sound/rt5514.txt index 9cabfc18cb57..929ca6756b02 100644 --- a/Documentation/devicetree/bindings/sound/rt5514.txt +++ b/Documentation/devicetree/bindings/sound/rt5514.txt @@ -13,6 +13,9 @@ Optional properties: - clocks: The phandle of the master clock to the CODEC - clock-names: Should be "mclk" +- realtek,dmic-init-delay-ms + Set the DMIC initial delay (ms) to wait it ready. + Pins on the device (for linking into audio routes) for RT5514: * DMIC1L diff --git a/include/sound/rt5514.h b/include/sound/rt5514.h new file mode 100644 index 000000000000..ef18494769ee --- /dev/null +++ b/include/sound/rt5514.h @@ -0,0 +1,20 @@ +/* + * linux/sound/rt5514.h -- Platform data for RT5514 + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Oder Chiou + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_RT5514_H +#define __LINUX_SND_RT5514_H + +struct rt5514_platform_data { + unsigned int dmic_init_delay; +}; + +#endif + diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index f24b7cfd3a89..b281a46d769d 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -452,6 +452,9 @@ static int rt5514_set_dmic_clk(struct snd_soc_dapm_widget *w, RT5514_CLK_DMIC_OUT_SEL_MASK, idx << RT5514_CLK_DMIC_OUT_SEL_SFT); + if (rt5514->pdata.dmic_init_delay) + msleep(rt5514->pdata.dmic_init_delay); + return idx; } @@ -1073,9 +1076,18 @@ static const struct of_device_id rt5514_of_match[] = { MODULE_DEVICE_TABLE(of, rt5514_of_match); #endif +static int rt5514_parse_dt(struct rt5514_priv *rt5514, struct device *dev) +{ + device_property_read_u32(dev, "realtek,dmic-init-delay-ms", + &rt5514->pdata.dmic_init_delay); + + return 0; +} + static int rt5514_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct rt5514_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5514_priv *rt5514; int ret; unsigned int val; @@ -1087,6 +1099,11 @@ static int rt5514_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, rt5514); + if (pdata) + rt5514->pdata = *pdata; + else if (i2c->dev.of_node) + rt5514_parse_dt(rt5514, &i2c->dev); + rt5514->i2c_regmap = devm_regmap_init_i2c(i2c, &rt5514_i2c_regmap); if (IS_ERR(rt5514->i2c_regmap)) { ret = PTR_ERR(rt5514->i2c_regmap); diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 229de0e2c88c..5d343fb6d125 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h @@ -13,6 +13,7 @@ #define __RT5514_H__ #include +#include #define RT5514_DEVICE_ID 0x10ec5514 @@ -243,6 +244,7 @@ enum { }; struct rt5514_priv { + struct rt5514_platform_data pdata; struct snd_soc_codec *codec; struct regmap *i2c_regmap, *regmap; struct clk *mclk; -- cgit v1.2.3-59-g8ed1b From b99305d20122174c9fd0469bae036f0c401999b5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Oct 2016 00:36:13 +0000 Subject: ASoC: rsnd: remove non DT support for DMA Current Renesas Sound driver is based on DeviceTree, and no one is using this driver from non DT. Non-DT support is no longer needed. Let's remove it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 21 ++++++--------------- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 2 +- sound/soc/sh/rcar/ssi.c | 3 +-- 4 files changed, 9 insertions(+), 19 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index b3bdd362a511..e0761cac0ab7 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -191,7 +191,7 @@ static int rsnd_dmaen_remove(struct rsnd_mod *mod, } static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_mod *mod = rsnd_mod_get(dma); @@ -208,17 +208,8 @@ static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, return -EIO; } - if (dev->of_node) { - dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - } else { - dma_cap_mask_t mask; - - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); + dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - dmaen->chan = dma_request_channel(mask, shdma_chan_filter, - (void *)(uintptr_t)id); - } if (IS_ERR_OR_NULL(dmaen->chan)) { dmaen->chan = NULL; dev_err(dev, "can't get dma channel\n"); @@ -394,7 +385,7 @@ static int rsnd_dmapp_start(struct rsnd_mod *mod, } static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, - struct rsnd_dma *dma, int id, + struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); @@ -627,7 +618,7 @@ static void rsnd_dma_of_path(struct rsnd_mod *this, } int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, - struct rsnd_mod **dma_mod, int id) + struct rsnd_mod **dma_mod) { struct rsnd_mod *mod_from = NULL; struct rsnd_mod *mod_to = NULL; @@ -636,7 +627,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct rsnd_mod_ops *ops; enum rsnd_mod_type type; - int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); int is_play = rsnd_io_is_play(io); int ret, dma_id; @@ -695,7 +686,7 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); - ret = attach(io, dma, id, mod_from, mod_to); + ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index b3b4d89347be..2460d1fbf775 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -199,7 +199,7 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); * R-Car DMA */ int rsnd_dma_attach(struct rsnd_dai_stream *io, - struct rsnd_mod *mod, struct rsnd_mod **dma_mod, int id); + struct rsnd_mod *mod, struct rsnd_mod **dma_mod); void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 969a5169de25..e13d6d439b32 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -475,7 +475,7 @@ static int rsnd_src_probe_(struct rsnd_mod *mod, return ret; } - ret = rsnd_dma_attach(io, mod, &src->dma, 0); + ret = rsnd_dma_attach(io, mod, &src->dma); return ret; } diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 94a19f975fa2..59cd9824d8a4 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -669,7 +669,6 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - int dma_id = 0; /* not needed */ int ret; /* @@ -684,7 +683,7 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, return ret; /* SSI probe might be called many times in MUX multi path */ - ret = rsnd_dma_attach(io, mod, &ssi->dma, dma_id); + ret = rsnd_dma_attach(io, mod, &ssi->dma); return ret; } -- cgit v1.2.3-59-g8ed1b From 701172dca15ba9860ba73d3e18082fbd2a78f2c9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Oct 2016 00:36:34 +0000 Subject: ASoC: rsnd: don't use devm_request_irq() for SSI SSI will use DMA mode, and migh be fallback to PIO mode. Using devm_request_irq() makes its operation more complex when it fallbacks to PIO mode. Let's use manual request_irq()/free_irq() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 59cd9824d8a4..b0338d0a4cde 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -644,10 +644,14 @@ static int rsnd_ssi_common_probe(struct rsnd_mod *mod, if (ret < 0) return ret; - ret = devm_request_irq(dev, ssi->irq, - rsnd_ssi_interrupt, - IRQF_SHARED, - dev_name(dev), mod); + /* + * SSI might be called again as PIO fallback + * It is easy to manual handling for IRQ request/free + */ + ret = request_irq(ssi->irq, + rsnd_ssi_interrupt, + IRQF_SHARED, + dev_name(dev), mod); return ret; } @@ -693,12 +697,9 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, struct rsnd_priv *priv) { struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); - struct device *dev = rsnd_priv_to_dev(priv); - int irq = ssi->irq; /* PIO will request IRQ again */ - if (ssi->dma) - devm_free_irq(dev, irq, mod); + free_irq(ssi->irq, mod); rsnd_dma_detach(mod, &ssi->dma); -- cgit v1.2.3-59-g8ed1b From dae4b83295ae50a86b5e3c60e7b6e2c597a1b69d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Oct 2016 00:36:56 +0000 Subject: ASoC: rsnd: remove rsnd_dma_detach() DMA mod is now connected to stream via rsnd_dai_connect(). This means DMA mod can use .remove for its clearance. rsnd_dma_detach() is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 11 ----------- sound/soc/sh/rcar/rsnd.h | 1 - sound/soc/sh/rcar/ssi.c | 2 -- 3 files changed, 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index e0761cac0ab7..c85a55111392 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -698,17 +698,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, return 0; } -void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod) -{ - if (*dma_mod) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - devm_kfree(dev, *dma_mod); - *dma_mod = NULL; - } -} - int rsnd_dma_probe(struct rsnd_priv *priv) { struct platform_device *pdev = rsnd_priv_to_pdev(priv); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 2460d1fbf775..c1cee1ab3e62 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -200,7 +200,6 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); */ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, struct rsnd_mod **dma_mod); -void rsnd_dma_detach(struct rsnd_mod *mod, struct rsnd_mod **dma_mod); int rsnd_dma_probe(struct rsnd_priv *priv); struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name); diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index b0338d0a4cde..e23e07b54d8c 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -701,8 +701,6 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, /* PIO will request IRQ again */ free_irq(ssi->irq, mod); - rsnd_dma_detach(mod, &ssi->dma); - return 0; } -- cgit v1.2.3-59-g8ed1b From 161ba1f1a5c99c4525eb39cc71ec984e0a39e6d7 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Oct 2016 00:37:18 +0000 Subject: ASoC: rsnd: don't call unneeded of_node_put() on dma.c Current rsnd_dmaen_start() is calling of_node_put() for np, but it is not needed if it goes through this loop. This patch tidyup it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index c85a55111392..2f0327714625 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -143,19 +143,17 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, struct rsnd_mod *mod, char *name) { - struct dma_chan *chan; + struct dma_chan *chan = NULL; struct device_node *np; int i = 0; for_each_child_of_node(of_node, np) { - if (i == rsnd_mod_id(mod)) - break; + if (i == rsnd_mod_id(mod) && (!chan)) + chan = of_dma_request_slave_channel(np, name); i++; } - chan = of_dma_request_slave_channel(np, name); - - of_node_put(np); + /* It should call of_node_put(), since, it is rsnd_xxx_of_node() */ of_node_put(of_node); return chan; -- cgit v1.2.3-59-g8ed1b From 10a9cca13220888c20a259abbd42ea117cddfdb0 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 25 Oct 2016 00:37:35 +0000 Subject: ASoC: rsnd: add nolock_start/stop callback Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. To fixup this issue, it should request/release DMA channel on each playback/recorde timing. But, DMA channel request/release function uses mutex lock inside. This means it will breaks current spinlock's interrupt protect. To solve this issue, DMA channel request/release function needs to be called from non-spinlock area. This patch adds its callback. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 26 ++++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 15 ++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ea14a1470de2..9ffa29941ceb 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -716,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } +static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + return rsnd_dai_call(nolock_start, io, priv); +} + +static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); + struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + rsnd_dai_call(nolock_stop, io, priv); +} + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c1cee1ab3e62..422b5344b687 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -259,6 +259,12 @@ struct rsnd_mod_ops { int (*fallback)(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv); + int (*nolock_start)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); + int (*nolock_stop)(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv); }; struct rsnd_dai_stream; @@ -276,8 +282,9 @@ struct rsnd_mod { /* * status * - * 0xH0000CB0 + * 0xH0000CBA * + * A 0: nolock_start 1: nolock_stop * B 0: init 1: quit * C 0: start 1: stop * @@ -287,6 +294,8 @@ struct rsnd_mod { * H 0: fallback * H 0: hw_params */ +#define __rsnd_mod_shift_nolock_start 0 +#define __rsnd_mod_shift_nolock_stop 0 #define __rsnd_mod_shift_init 4 #define __rsnd_mod_shift_quit 4 #define __rsnd_mod_shift_start 8 @@ -300,6 +309,8 @@ struct rsnd_mod { #define __rsnd_mod_add_probe 0 #define __rsnd_mod_add_remove 0 +#define __rsnd_mod_add_nolock_start 1 +#define __rsnd_mod_add_nolock_stop -1 #define __rsnd_mod_add_init 1 #define __rsnd_mod_add_quit -1 #define __rsnd_mod_add_start 1 @@ -319,6 +330,8 @@ struct rsnd_mod { #define __rsnd_mod_call_pcm_new 0 #define __rsnd_mod_call_fallback 0 #define __rsnd_mod_call_hw_params 0 +#define __rsnd_mod_call_nolock_start 0 +#define __rsnd_mod_call_nolock_stop 1 #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) -- cgit v1.2.3-59-g8ed1b From 03d2ec460f126d8f4409d137b5865bc4eca253c0 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 25 Oct 2016 16:42:29 +0100 Subject: ASoC: cs42xx8: Mark chip ID as volatile and remove cache bypass Rather than manually enabling cache bypass when reading the ID registers simply remove the default which will cause the first read to go to the hardware. The old code worked this is simply the more standard way to implement this. There is a comment included in the code that claims the chip ID register also contains the right input volume, however this is clearly not the case from the rest of the driver. Further investigation reveals exactly the same comment in the wm8962 driver, where this is the case, so this is almost certainly a copy and paste error from when the driver was created. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index b4d87379d2bc..c1785bd4ff19 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -321,7 +321,6 @@ static struct snd_soc_dai_driver cs42xx8_dai = { }; static const struct reg_default cs42xx8_reg[] = { - { 0x01, 0x01 }, /* Chip I.D. and Revision Register */ { 0x02, 0x00 }, /* Power Control */ { 0x03, 0xF0 }, /* Functional Mode */ { 0x04, 0x46 }, /* Interface Formats */ @@ -498,13 +497,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) /* Make sure hardware reset done */ msleep(5); - /* - * We haven't marked the chip revision as volatile due to - * sharing a register with the right input volume; explicitly - * bypass the cache to read it. - */ - regcache_cache_bypass(cs42xx8->regmap, true); - /* Validate the chip ID */ ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val); if (ret < 0) { @@ -523,8 +515,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) dev_info(dev, "found device, revision %X\n", val & CS42XX8_CHIPID_REV_ID_MASK); - regcache_cache_bypass(cs42xx8->regmap, false); - cs42xx8_dai.name = cs42xx8->drvdata->name; /* Each adc supports stereo input */ -- cgit v1.2.3-59-g8ed1b From da5eb41763c750d1660ca0a962f15f268821b3e6 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 25 Oct 2016 16:42:30 +0100 Subject: ASoC: cs42l56: Make ID registers volatile and remove cache bypass Rather than manually enabling cache bypass when reading the ID registers simply remove the default which will cause the first read to go to the hardware. The old code worked this is simply the more standard way to implement this. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 54c1768bc818..3e2c04642f1e 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -64,8 +64,6 @@ struct cs42l56_private { }; static const struct reg_default cs42l56_reg_defaults[] = { - { 1, 0x56 }, /* r01 - ID 1 */ - { 2, 0x04 }, /* r02 - ID 2 */ { 3, 0x7f }, /* r03 - Power Ctl 1 */ { 4, 0xff }, /* r04 - Power Ctl 2 */ { 5, 0x00 }, /* ro5 - Clocking Ctl 1 */ @@ -1262,8 +1260,6 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, return ret; } - regcache_cache_bypass(cs42l56->regmap, true); - ret = regmap_read(cs42l56->regmap, CS42L56_CHIP_ID_1, ®); devid = reg & CS42L56_CHIP_ID_MASK; if (devid != CS42L56_DEVID) { @@ -1279,8 +1275,6 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, dev_info(&i2c_client->dev, "Alpha Rev %X Metal Rev %X\n", alpha_rev, metal_rev); - regcache_cache_bypass(cs42l56->regmap, false); - if (cs42l56->pdata.ain1a_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, CS42L56_AIN1A_REF_MASK, 1); -- cgit v1.2.3-59-g8ed1b From ca493dabbc77a20c1df9a386f192126b863a2437 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 25 Oct 2016 16:42:31 +0100 Subject: ASoC: cs42l73: Remove cache bypass for read of ID registers Don't manually enable cache_bypass for reading the ID registers they don't have a default anyway so the first read will always hit the hardware. The old code worked this is simply the more standard way to implement this. Signed-off-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 71ba5605495f..3df2c473ab88 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1337,8 +1337,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, gpio_set_value_cansleep(cs42l73->pdata.reset_gpio, 1); } - regcache_cache_bypass(cs42l73->regmap, true); - /* initialize codec */ ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); devid = (reg & 0xFF) << 12; @@ -1366,8 +1364,6 @@ static int cs42l73_i2c_probe(struct i2c_client *i2c_client, dev_info(&i2c_client->dev, "Cirrus Logic CS42L73, Revision: %02X\n", reg & 0xFF); - regcache_cache_bypass(cs42l73->regmap, false); - ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_dev_cs42l73, cs42l73_dai, ARRAY_SIZE(cs42l73_dai)); -- cgit v1.2.3-59-g8ed1b From cdaf9af1eaeb539e32bfd6da6310b41ad6c3ba23 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 25 Oct 2016 17:08:38 +0200 Subject: ASoC: samsung: Remove unneeded initialization of chan_name This patch updates the I2S drivers to always use chan_names[] field of struct snd_dmaengine_pcm_config for specifying DMA channel names, rather than using struct snd_dmaengine_dai_dma_data. This allows us to subsequently drop the SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag, now when the last use of that flag is removed. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/dmaengine.c | 8 ++------ sound/soc/samsung/i2s.c | 3 --- sound/soc/samsung/s3c2412-i2s.c | 2 -- sound/soc/samsung/s3c24xx-i2s.c | 2 -- 4 files changed, 2 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 9104c98deeb7..cda656e4afc6 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c @@ -37,12 +37,8 @@ int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; pcm_conf->compat_filter_fn = filter; - if (dev->of_node) { - pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; - pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; - } else { - flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME; - } + pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; + pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags); } diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 7e32cf4581f8..7a9ee48a5c04 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1304,8 +1304,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) } pri_dai->dma_playback.addr = regs_base + I2STXD; pri_dai->dma_capture.addr = regs_base + I2SRXD; - pri_dai->dma_playback.chan_name = "tx"; - pri_dai->dma_capture.chan_name = "rx"; pri_dai->dma_playback.addr_width = 4; pri_dai->dma_capture.addr_width = 4; pri_dai->quirks = quirks; @@ -1325,7 +1323,6 @@ static int samsung_i2s_probe(struct platform_device *pdev) sec_dai->lock = &pri_dai->spinlock; sec_dai->variant_regs = pri_dai->variant_regs; sec_dai->dma_playback.addr = regs_base + I2STXDS; - sec_dai->dma_playback.chan_name = "tx-sec"; if (!np) { sec_dai->dma_playback.filter_data = i2s_pdata->dma_play_sec; diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 3e89fbc0c51d..40331a060a02 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c @@ -35,12 +35,10 @@ #include static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = { - .chan_name = "tx", .addr_width = 4, }; static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = { - .chan_name = "rx", .addr_width = 4, }; diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index c78a936a3099..d59a47d8ca0f 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -33,12 +33,10 @@ #include static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { - .chan_name = "tx", .addr_width = 2, }; static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_in = { - .chan_name = "rx", .addr_width = 2, }; -- cgit v1.2.3-59-g8ed1b From c6644119a3f80ea644bde10009d5e1013b5aff29 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 25 Oct 2016 17:08:39 +0200 Subject: ASoC: Drop SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag Since commit 194c7dea00c68c1b1f8ff26304fa937a006f66dd "ASoC: dmaengine: add custom DMA config to snd_dmaengine_pcm_config" custom DMA channels can be also specified in chan_names[] field of struct snd_dmaengine_pcm_config. This patch removes chan_name field of struct snd_dmaengine_dai_dma_data as it is now unused. Signed-off-by: Sylwester Nawrocki Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 6 ------ sound/soc/soc-generic-dmaengine-pcm.c | 13 +------------ 2 files changed, 1 insertion(+), 18 deletions(-) (limited to 'sound') diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 67be2445941a..1c8f9e1ef2a5 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -71,7 +71,6 @@ struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) * @slave_id: Slave requester id for the DMA channel. * @filter_data: Custom DMA channel filter data, this will usually be used when * requesting the DMA channel. - * @chan_name: Custom channel name to use when requesting DMA channel. * @fifo_size: FIFO size of the DAI controller in bytes * @flags: PCM_DAI flags, only SND_DMAENGINE_PCM_DAI_FLAG_PACK for now */ @@ -81,7 +80,6 @@ struct snd_dmaengine_dai_dma_data { u32 maxburst; unsigned int slave_id; void *filter_data; - const char *chan_name; unsigned int fifo_size; unsigned int flags; }; @@ -107,10 +105,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) -/* - * The PCM streams have custom channel names specified. - */ -#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6cef3977507a..17eb14935577 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -263,7 +263,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = rtd->platform->dev; - struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -278,19 +277,11 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) max_buffer_size = SIZE_MAX; } - for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) { substream = rtd->pcm->streams[i].substream; if (!substream) continue; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - if (!pcm->chan[i] && - (pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) - pcm->chan[i] = dma_request_slave_channel(dev, - dma_data->chan_name); - if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, substream); @@ -359,9 +350,7 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, const char *name; struct dma_chan *chan; - if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - !dev->of_node) + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || !dev->of_node) return 0; if (config && config->dma_dev) { -- cgit v1.2.3-59-g8ed1b From b57a089bd4213b5e33007f8293bf83a8b14e4729 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 25 Oct 2016 17:08:40 +0200 Subject: ASoC: samsung: s3c24xx-i2s: Don't use platform_data for DMA parameters Since the s3c24xx-dma is converted to use DMA map we can rely on the DMA subsystem to match DMA channels and slave devices, rather than passing DMA details from platform_data. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx-i2s.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index d59a47d8ca0f..29196a9933a6 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -30,8 +30,6 @@ #include "dma.h" #include "s3c24xx-i2s.h" -#include - static struct snd_dmaengine_dai_dma_data s3c24xx_i2s_pcm_stereo_out = { .addr_width = 2, }; @@ -449,14 +447,8 @@ static const struct snd_soc_component_driver s3c24xx_i2s_component = { static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { - int ret = 0; struct resource *res; - struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev); - - if (!pdata) { - dev_err(&pdev->dev, "missing platform data"); - return -ENXIO; - } + int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { @@ -468,9 +460,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return PTR_ERR(s3c24xx_i2s.regs); s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; - s3c24xx_i2s_pcm_stereo_out.filter_data = pdata->dma_playback; s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; - s3c24xx_i2s_pcm_stereo_in.filter_data = pdata->dma_capture; ret = devm_snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); @@ -479,8 +469,7 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) return ret; } - ret = samsung_asoc_dma_platform_register(&pdev->dev, - pdata->dma_filter, + ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, NULL, NULL); if (ret) pr_err("failed to register the dma: %d\n", ret); -- cgit v1.2.3-59-g8ed1b From 2ef9555bd13d00c63fdbe3cdca6ab0e2ded42695 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 25 Oct 2016 17:08:41 +0200 Subject: ASoC: samsung: s3c24xx-i2s: Debug/error trace cleanup pr_err() are replaced with dev_err() so information about device the error logs refer to is also included. pr_debug() at beginning of each function are removed as they are likely very rarely used and can always be added again when doing any serious debugging. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx-i2s.c | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 29196a9933a6..7c7061bc0ded 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -54,8 +54,6 @@ static void s3c24xx_snd_txctrl(int on) u32 iiscon; u32 iismod; - pr_debug("Entered %s\n", __func__); - iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -99,8 +97,6 @@ static void s3c24xx_snd_rxctrl(int on) u32 iiscon; u32 iismod; - pr_debug("Entered %s\n", __func__); - iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); @@ -147,8 +143,6 @@ static int s3c24xx_snd_lrsync(void) u32 iiscon; int timeout = 50; /* 5ms */ - pr_debug("Entered %s\n", __func__); - while (1) { iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); if (iiscon & S3C2410_IISCON_LRINDEX) @@ -167,8 +161,6 @@ static int s3c24xx_snd_lrsync(void) */ static inline int s3c24xx_snd_is_clkmaster(void) { - pr_debug("Entered %s\n", __func__); - return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1; } @@ -180,8 +172,6 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, { u32 iismod; - pr_debug("Entered %s\n", __func__); - iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params r: IISMOD: %x \n", iismod); @@ -209,6 +199,7 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params w: IISMOD: %x \n", iismod); + return 0; } @@ -219,8 +210,6 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_dmaengine_dai_dma_data *dma_data; u32 iismod; - pr_debug("Entered %s\n", __func__); - dma_data = snd_soc_dai_get_dma_data(dai, substream); /* Working copies of register */ @@ -242,6 +231,7 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream, writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD); pr_debug("hw_params w: IISMOD: %x\n", iismod); + return 0; } @@ -250,8 +240,6 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, { int ret = 0; - pr_debug("Entered %s\n", __func__); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -293,8 +281,6 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, { u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); - pr_debug("Entered %s\n", __func__); - iismod &= ~S3C2440_IISMOD_MPLL; switch (clk_id) { @@ -319,8 +305,6 @@ static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, { u32 reg; - pr_debug("Entered %s\n", __func__); - switch (div_id) { case S3C24XX_DIV_BCLK: reg = readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & ~S3C2410_IISMOD_FS_MASK; @@ -354,8 +338,6 @@ EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate); static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) { - pr_debug("Entered %s\n", __func__); - snd_soc_dai_init_dma_data(dai, &s3c24xx_i2s_pcm_stereo_out, &s3c24xx_i2s_pcm_stereo_in); @@ -381,8 +363,6 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) #ifdef CONFIG_PM static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) { - pr_debug("Entered %s\n", __func__); - s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON); s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD); s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON); @@ -395,7 +375,6 @@ static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai) static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) { - pr_debug("Entered %s\n", __func__); clk_prepare_enable(s3c24xx_i2s.iis_clk); writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON); @@ -410,7 +389,6 @@ static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai) #define s3c24xx_i2s_resume NULL #endif - #define S3C24XX_I2S_RATES \ (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ @@ -465,14 +443,14 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); if (ret) { - pr_err("failed to register the dai\n"); + dev_err(&pdev->dev, "Failed to register the DAI\n"); return ret; } ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, NULL, NULL); if (ret) - pr_err("failed to register the dma: %d\n", ret); + dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret); return ret; } -- cgit v1.2.3-59-g8ed1b From 55060feefcdff692ace47b1a2346998dfcd4bcb5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 25 Oct 2016 22:39:36 +0800 Subject: ASoC: cs35l34: Remove CS35L34_CHIP_ID from cs35l34_readable_register CS35L34_CHIP_ID is not a register address, it's the value read from CS35L34_DEVID_AB/CD/E registers. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 404538379586..e0f672af1d84 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -145,7 +145,6 @@ static bool cs35l34_volatile_register(struct device *dev, unsigned int reg) static bool cs35l34_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS35L34_CHIP_ID: case CS35L34_DEVID_AB: case CS35L34_DEVID_CD: case CS35L34_DEVID_E: -- cgit v1.2.3-59-g8ed1b From 31833ead95c2c0a374f35a8ae8148c00459a0d49 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 26 Oct 2016 10:59:57 +0100 Subject: ASoC: arizona: Move request of speaker IRQs into bus probe It is more idiomatic to request all resources in the bus level probe, this patch moves the request of the speaker thermal event IRQs from the ASoC level probe into the bus level probe. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 17 +++++++++++------ sound/soc/codecs/arizona.h | 3 ++- sound/soc/codecs/cs47l24.c | 19 +++++++++++++++---- sound/soc/codecs/wm5102.c | 20 ++++++++++++++++---- sound/soc/codecs/wm5110.c | 20 ++++++++++++++++---- sound/soc/codecs/wm8997.c | 26 +++++++++++++++++++++----- sound/soc/codecs/wm8998.c | 28 +++++++++++++++++++++++----- 7 files changed, 104 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 7f7d4b31a7fd..99ce6a0e73de 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -191,6 +191,14 @@ int arizona_init_spk(struct snd_soc_codec *codec) break; } + return 0; +} +EXPORT_SYMBOL_GPL(arizona_init_spk); + +int arizona_init_spk_irqs(struct arizona *arizona) +{ + int ret; + ret = arizona_request_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, "Thermal warning", arizona_thermal_warn, arizona); @@ -209,19 +217,16 @@ int arizona_init_spk(struct snd_soc_codec *codec) return 0; } -EXPORT_SYMBOL_GPL(arizona_init_spk); +EXPORT_SYMBOL_GPL(arizona_init_spk_irqs); -int arizona_free_spk(struct snd_soc_codec *codec) +int arizona_free_spk_irqs(struct arizona *arizona) { - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT_WARN, arizona); arizona_free_irq(arizona, ARIZONA_IRQ_SPK_OVERHEAT, arizona); return 0; } -EXPORT_SYMBOL_GPL(arizona_free_spk); +EXPORT_SYMBOL_GPL(arizona_free_spk_irqs); static const struct snd_soc_dapm_route arizona_mono_routes[] = { { "OUT1R", NULL, "OUT1L" }, diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 9d0997bec870..34d65d1eafba 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -317,7 +317,8 @@ extern int arizona_init_gpio(struct snd_soc_codec *codec); extern int arizona_init_mono(struct snd_soc_codec *codec); extern int arizona_init_notifiers(struct snd_soc_codec *codec); -extern int arizona_free_spk(struct snd_soc_codec *codec); +extern int arizona_init_spk_irqs(struct arizona *arizona); +extern int arizona_free_spk_irqs(struct arizona *arizona); extern int arizona_init_dai(struct arizona_priv *priv, int dai); diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 7df6a6769038..17e52c1599e4 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1170,8 +1170,6 @@ static int cs47l24_codec_remove(struct snd_soc_codec *codec) arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - arizona_free_spk(codec); - return 0; } @@ -1287,19 +1285,30 @@ static int cs47l24_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - return ret; + goto err_spk_irqs; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_cs47l24, cs47l24_dai, ARRAY_SIZE(cs47l24_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); + goto err_platform; } + return ret; + +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: + arizona_free_spk_irqs(arizona); + return ret; } @@ -1314,6 +1323,8 @@ static int cs47l24_remove(struct platform_device *pdev) wm_adsp2_remove(&cs47l24->core.adsp[1]); wm_adsp2_remove(&cs47l24->core.adsp[2]); + arizona_free_spk_irqs(arizona); + return 0; } diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index bb3de5b3d816..6f40ee6f0bbc 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1978,8 +1978,6 @@ static int wm5102_codec_remove(struct snd_soc_codec *codec) arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - arizona_free_spk(codec); - return 0; } @@ -2097,25 +2095,37 @@ static int wm5102_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - return ret; + goto err_spk_irqs; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102, wm5102_dai, ARRAY_SIZE(wm5102_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); + goto err_platform; } + return ret; + +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: + arizona_free_spk_irqs(arizona); + return ret; } static int wm5102_remove(struct platform_device *pdev) { struct wm5102_priv *wm5102 = platform_get_drvdata(pdev); + struct arizona *arizona = wm5102->core.arizona; snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); @@ -2123,6 +2133,8 @@ static int wm5102_remove(struct platform_device *pdev) wm_adsp2_remove(&wm5102->core.adsp[0]); + arizona_free_spk_irqs(arizona); + return 0; } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 407dc4a43b07..667fc25dd094 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2330,8 +2330,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - arizona_free_spk(codec); - return 0; } @@ -2453,25 +2451,37 @@ static int wm5110_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform); if (ret < 0) { dev_err(&pdev->dev, "Failed to register platform: %d\n", ret); - return ret; + goto err_spk_irqs; } ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, wm5110_dai, ARRAY_SIZE(wm5110_dai)); if (ret < 0) { dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); - snd_soc_unregister_platform(&pdev->dev); + goto err_platform; } + return ret; + +err_platform: + snd_soc_unregister_platform(&pdev->dev); +err_spk_irqs: + arizona_free_spk_irqs(arizona); + return ret; } static int wm5110_remove(struct platform_device *pdev) { struct wm5110_priv *wm5110 = platform_get_drvdata(pdev); + struct arizona *arizona = wm5110->core.arizona; int i; snd_soc_unregister_platform(&pdev->dev); @@ -2481,6 +2491,8 @@ static int wm5110_remove(struct platform_device *pdev) for (i = 0; i < WM5110_NUM_ADSP; i++) wm_adsp2_remove(&wm5110->core.adsp[i]); + arizona_free_spk_irqs(arizona); + return 0; } diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index f5f5d4352670..600595c54fe7 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1077,8 +1077,6 @@ static int wm8997_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; - arizona_free_spk(codec); - return 0; } @@ -1124,7 +1122,7 @@ static int wm8997_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm8997_priv *wm8997; - int i; + int i, ret; wm8997 = devm_kzalloc(&pdev->dev, sizeof(struct wm8997_priv), GFP_KERNEL); @@ -1164,15 +1162,33 @@ static int wm8997_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, - wm8997_dai, ARRAY_SIZE(wm8997_dai)); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8997, + wm8997_dai, ARRAY_SIZE(wm8997_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + goto err_spk_irqs; + } + +err_spk_irqs: + arizona_free_spk_irqs(arizona); + + return ret; } static int wm8997_remove(struct platform_device *pdev) { + struct wm8997_priv *wm8997 = platform_get_drvdata(pdev); + struct arizona *arizona = wm8997->core.arizona; + snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); + arizona_free_spk_irqs(arizona); + return 0; } diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 3eaa3615b82e..4cccaae6dcfa 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1337,8 +1337,6 @@ static int wm8998_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; - arizona_free_spk(codec); - return 0; } @@ -1387,7 +1385,7 @@ static int wm8998_probe(struct platform_device *pdev) { struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); struct wm8998_priv *wm8998; - int i; + int i, ret; wm8998 = devm_kzalloc(&pdev->dev, sizeof(struct wm8998_priv), GFP_KERNEL); @@ -1419,15 +1417,35 @@ static int wm8998_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); - return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998, - wm8998_dai, ARRAY_SIZE(wm8998_dai)); + ret = arizona_init_spk_irqs(arizona); + if (ret < 0) + return ret; + + ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm8998, + wm8998_dai, ARRAY_SIZE(wm8998_dai)); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register codec: %d\n", ret); + goto err_spk_irqs; + } + + return ret; + +err_spk_irqs: + arizona_free_spk_irqs(arizona); + + return ret; } static int wm8998_remove(struct platform_device *pdev) { + struct wm8998_priv *wm8998 = platform_get_drvdata(pdev); + struct arizona *arizona = wm8998->core.arizona; + snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev); + arizona_free_spk_irqs(arizona); + return 0; } -- cgit v1.2.3-59-g8ed1b From 0809492e894f18cb19f8811f202e95d08e83b7af Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 26 Oct 2016 10:59:58 +0100 Subject: ASoC: arizona: Move request of DSP IRQ into bus probe It is more idiomatic to request all resources in the bus level probe, this patch moves the request of the DSP compressed data IRQ from the ASoC level probe into the bus level probe. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 26 +++++++++++++------------- sound/soc/codecs/wm5102.c | 26 +++++++++++++------------- sound/soc/codecs/wm5110.c | 28 +++++++++++++--------------- 3 files changed, 39 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 17e52c1599e4..c5c5a2d9d84e 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1116,7 +1116,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int ret; priv->core.arizona->dapm = dapm; @@ -1126,14 +1125,6 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) arizona_init_mono(codec); arizona_init_notifiers(codec); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, - "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, - priv); - if (ret != 0) { - dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; - } - ret = wm_adsp2_codec_probe(&priv->core.adsp[1], codec); if (ret) goto err_adsp2_codec_probe; @@ -1161,15 +1152,12 @@ err_adsp2_codec_probe: static int cs47l24_codec_remove(struct snd_soc_codec *codec) { struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; wm_adsp2_codec_remove(&priv->core.adsp[1], codec); wm_adsp2_codec_remove(&priv->core.adsp[2], codec); priv->core.arizona->dapm = NULL; - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - return 0; } @@ -1285,9 +1273,17 @@ static int cs47l24_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, + cs47l24); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + ret = arizona_init_spk_irqs(arizona); if (ret < 0) - return ret; + goto err_dsp_irq; ret = snd_soc_register_platform(&pdev->dev, &cs47l24_compr_platform); if (ret < 0) { @@ -1308,6 +1304,8 @@ err_platform: snd_soc_unregister_platform(&pdev->dev); err_spk_irqs: arizona_free_spk_irqs(arizona); +err_dsp_irq: + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24); return ret; } @@ -1325,6 +1323,8 @@ static int cs47l24_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, cs47l24); + return 0; } diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 6f40ee6f0bbc..a80a680d1b5b 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1932,17 +1932,8 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int ret; - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, - "ADSP2 Compressed IRQ", wm5102_adsp2_irq, - priv); - if (ret != 0) { - dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; - } - ret = wm_adsp2_codec_probe(&priv->core.adsp[0], codec); if (ret) return ret; @@ -1970,14 +1961,11 @@ err_adsp2_codec_probe: static int wm5102_codec_remove(struct snd_soc_codec *codec) { struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; wm_adsp2_codec_remove(&priv->core.adsp[0], codec); priv->core.arizona->dapm = NULL; - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - return 0; } @@ -2095,9 +2083,17 @@ static int wm5102_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5102_adsp2_irq, + wm5102); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + ret = arizona_init_spk_irqs(arizona); if (ret < 0) - return ret; + goto err_dsp_irq; ret = snd_soc_register_platform(&pdev->dev, &wm5102_compr_platform); if (ret < 0) { @@ -2118,6 +2114,8 @@ err_platform: snd_soc_unregister_platform(&pdev->dev); err_spk_irqs: arizona_free_spk_irqs(arizona); +err_dsp_irq: + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); return ret; } @@ -2135,6 +2133,8 @@ static int wm5102_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5102); + return 0; } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 667fc25dd094..f1a41139caf6 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2274,7 +2274,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int i, ret; priv->core.arizona->dapm = dapm; @@ -2284,14 +2283,6 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_mono(codec); arizona_init_notifiers(codec); - ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, - "ADSP2 Compressed IRQ", wm5110_adsp2_irq, - priv); - if (ret != 0) { - dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); - return ret; - } - for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) @@ -2312,15 +2303,12 @@ err_adsp2_codec_probe: for (--i; i >= 0; --i) wm_adsp2_codec_remove(&priv->core.adsp[i], codec); - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->core.arizona; int i; for (i = 0; i < WM5110_NUM_ADSP; ++i) @@ -2328,8 +2316,6 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; - arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); - return 0; } @@ -2451,9 +2437,17 @@ static int wm5110_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_idle(&pdev->dev); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5110_adsp2_irq, + wm5110); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + ret = arizona_init_spk_irqs(arizona); if (ret < 0) - return ret; + goto err_dsp_irq; ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform); if (ret < 0) { @@ -2474,6 +2468,8 @@ err_platform: snd_soc_unregister_platform(&pdev->dev); err_spk_irqs: arizona_free_spk_irqs(arizona); +err_dsp_irq: + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); return ret; } @@ -2493,6 +2489,8 @@ static int wm5110_remove(struct platform_device *pdev) arizona_free_spk_irqs(arizona); + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, wm5110); + return 0; } -- cgit v1.2.3-59-g8ed1b From c8eabf821cac120afb78ca251b07cbf520406a7e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2016 11:55:48 +0300 Subject: ASoC: Intel: Skylake: Fix a shift wrapping bug "*val" is a u64. It definitely looks like we intend to use the high 32 bits as well. Fixes: 700a9a63f9c1 ("ASoC: Intel: Skylake: Add module instance id generation APIs") Signed-off-by: Dan Carpenter Acked-by: Vinod Koul Tested-by: Kranthi G Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c index 8dc03039b311..ea162fbf68e5 100644 --- a/sound/soc/intel/skylake/skl-sst-utils.c +++ b/sound/soc/intel/skylake/skl-sst-utils.c @@ -179,7 +179,7 @@ static inline int skl_getid_32(struct uuid_module *module, u64 *val, index = ffz(mask_val); pvt_id = index + word1_mask + word2_mask; if (pvt_id <= (max_inst - 1)) { - *val |= 1 << (index + word1_mask); + *val |= 1ULL << (index + word1_mask); return pvt_id; } } -- cgit v1.2.3-59-g8ed1b From e1b790a8720192e1cfdd46a9b20d0f56de99c73d Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 15 Oct 2016 00:53:36 +0300 Subject: SoC: mxs-saif: check validity of ids in mxs_saif_probe() There is a check for validity of one of ids in mxs_saif_probe(), while array dereferece is made by the other id. The patch adds the check for the second saif id. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Mark Brown --- sound/soc/mxs/mxs-saif.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 13631003cb7c..a002ab892772 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c @@ -735,6 +735,11 @@ static int mxs_saif_probe(struct platform_device *pdev) else saif->id = ret; + if (saif->id >= ARRAY_SIZE(mxs_saif)) { + dev_err(&pdev->dev, "get wrong saif id\n"); + return -EINVAL; + } + /* * If there is no "fsl,saif-master" phandle, it's a saif * master. Otherwise, it's a slave and its phandle points @@ -749,11 +754,11 @@ static int mxs_saif_probe(struct platform_device *pdev) return ret; else saif->master_id = ret; - } - if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { - dev_err(&pdev->dev, "get wrong master id\n"); - return -EINVAL; + if (saif->master_id >= ARRAY_SIZE(mxs_saif)) { + dev_err(&pdev->dev, "get wrong master id\n"); + return -EINVAL; + } } mxs_saif[saif->id] = saif; -- cgit v1.2.3-59-g8ed1b From 748abba8f3a93cee13a56350386e59457ffa600d Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 24 Oct 2016 16:42:51 +0200 Subject: ASoC: sti: fix errors management Add missing error messages. Propagate error of uni_reader_init and uni_reader_init. Add return at end of dev_err strings. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 20 ++++++++------ sound/soc/sti/uniperif_player.c | 58 +++++++++++++++++++++++------------------ sound/soc/sti/uniperif_reader.c | 25 +++++++++--------- 3 files changed, 58 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 549fac349fa0..ee91ae5f812a 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -293,7 +293,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) /* The uniperipheral should be in stopped state */ if (uni->state != UNIPERIF_STATE_STOPPED) { - dev_err(uni->dev, "%s: invalid uni state( %d)", + dev_err(uni->dev, "%s: invalid uni state( %d)\n", __func__, (int)uni->state); return -EBUSY; } @@ -301,7 +301,7 @@ static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) /* Pinctrl: switch pinstate to sleep */ ret = pinctrl_pm_select_sleep_state(uni->dev); if (ret) - dev_err(uni->dev, "%s: failed to select pinctrl state", + dev_err(uni->dev, "%s: failed to select pinctrl state\n", __func__); return ret; @@ -322,7 +322,7 @@ static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) /* pinctrl: switch pinstate to default */ ret = pinctrl_pm_select_default_state(uni->dev); if (ret) - dev_err(uni->dev, "%s: failed to select pinctrl state", + dev_err(uni->dev, "%s: failed to select pinctrl state\n", __func__); return ret; @@ -366,11 +366,12 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, const struct of_device_id *of_id; const struct sti_uniperiph_dev_data *dev_data; const char *mode; + int ret; /* Populate data structure depending on compatibility */ of_id = of_match_node(snd_soc_sti_match, node); if (!of_id->data) { - dev_err(dev, "data associated to device is missing"); + dev_err(dev, "data associated to device is missing\n"); return -EINVAL; } dev_data = (struct sti_uniperiph_dev_data *)of_id->data; @@ -389,7 +390,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); if (!uni->mem_region) { - dev_err(dev, "Failed to get memory resource"); + dev_err(dev, "Failed to get memory resource\n"); return -ENODEV; } @@ -403,7 +404,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, uni->irq = platform_get_irq(priv->pdev, 0); if (uni->irq < 0) { - dev_err(dev, "Failed to get IRQ resource"); + dev_err(dev, "Failed to get IRQ resource\n"); return -ENXIO; } @@ -421,12 +422,15 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, dai_data->stream = dev_data->stream; if (priv->dai_data.stream == SNDRV_PCM_STREAM_PLAYBACK) { - uni_player_init(priv->pdev, uni); + ret = uni_player_init(priv->pdev, uni); stream = &dai->playback; } else { - uni_reader_init(priv->pdev, uni); + ret = uni_reader_init(priv->pdev, uni); stream = &dai->capture; } + if (ret < 0) + return ret; + dai->ops = uni->dai_ops; stream->stream_name = dai->name; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 1bc8ebc2528e..c9b4670b772b 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -67,7 +67,7 @@ static inline int reset_player(struct uniperif *player) } if (!count) { - dev_err(player->dev, "Failed to reset uniperif"); + dev_err(player->dev, "Failed to reset uniperif\n"); return -EIO; } @@ -97,7 +97,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for fifo error (underrun) */ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { - dev_err(player->dev, "FIFO underflow error detected"); + dev_err(player->dev, "FIFO underflow error detected\n"); /* Interrupt is just for information when underflow recovery */ if (player->underflow_enabled) { @@ -119,7 +119,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for dma error (overrun) */ if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { - dev_err(player->dev, "DMA error detected"); + dev_err(player->dev, "DMA error detected\n"); /* Disable interrupt so doesn't continually fire */ SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); @@ -135,11 +135,14 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check for underflow recovery done */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { if (!player->underflow_enabled) { - dev_err(player->dev, "unexpected Underflow recovering"); + dev_err(player->dev, + "unexpected Underflow recovering\n"); return -EPERM; } /* Read the underflow recovery duration */ tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); + dev_dbg(player->dev, "Underflow recovered (%d LR clocks max)\n", + tmp); /* Clear the underflow recovery duration */ SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); @@ -153,7 +156,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) /* Check if underflow recovery failed */ if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { - dev_err(player->dev, "Underflow recovery failed"); + dev_err(player->dev, "Underflow recovery failed\n"); /* Stop the player */ snd_pcm_stream_lock(player->substream); @@ -336,7 +339,7 @@ static int uni_player_prepare_iec958(struct uniperif *player, /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ if ((clk_div % 128) || (clk_div <= 0)) { - dev_err(player->dev, "%s: invalid clk_div %d", + dev_err(player->dev, "%s: invalid clk_div %d\n", __func__, clk_div); return -EINVAL; } @@ -359,7 +362,7 @@ static int uni_player_prepare_iec958(struct uniperif *player, SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); break; default: - dev_err(player->dev, "format not supported"); + dev_err(player->dev, "format not supported\n"); return -EINVAL; } @@ -448,12 +451,12 @@ static int uni_player_prepare_pcm(struct uniperif *player, * for 16 bits must be a multiple of 64 */ if ((slot_width == 32) && (clk_div % 128)) { - dev_err(player->dev, "%s: invalid clk_div", __func__); + dev_err(player->dev, "%s: invalid clk_div\n", __func__); return -EINVAL; } if ((slot_width == 16) && (clk_div % 64)) { - dev_err(player->dev, "%s: invalid clk_div", __func__); + dev_err(player->dev, "%s: invalid clk_div\n", __func__); return -EINVAL; } @@ -471,7 +474,7 @@ static int uni_player_prepare_pcm(struct uniperif *player, SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); break; default: - dev_err(player->dev, "subframe format not supported"); + dev_err(player->dev, "subframe format not supported\n"); return -EINVAL; } @@ -491,7 +494,7 @@ static int uni_player_prepare_pcm(struct uniperif *player, break; default: - dev_err(player->dev, "format not supported"); + dev_err(player->dev, "format not supported\n"); return -EINVAL; } @@ -504,7 +507,7 @@ static int uni_player_prepare_pcm(struct uniperif *player, /* Number of channelsmust be even*/ if ((runtime->channels % 2) || (runtime->channels < 2) || (runtime->channels > 10)) { - dev_err(player->dev, "%s: invalid nb of channels", __func__); + dev_err(player->dev, "%s: invalid nb of channels\n", __func__); return -EINVAL; } @@ -758,7 +761,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, /* The player should be stopped */ if (player->state != UNIPERIF_STATE_STOPPED) { - dev_err(player->dev, "%s: invalid player state %d", __func__, + dev_err(player->dev, "%s: invalid player state %d\n", __func__, player->state); return -EINVAL; } @@ -787,7 +790,8 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, /* Trigger limit must be an even number */ if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { - dev_err(player->dev, "invalid trigger limit %d", trigger_limit); + dev_err(player->dev, "invalid trigger limit %d\n", + trigger_limit); return -EINVAL; } @@ -808,7 +812,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, ret = uni_player_prepare_tdm(player, runtime); break; default: - dev_err(player->dev, "invalid player type"); + dev_err(player->dev, "invalid player type\n"); return -EINVAL; } @@ -848,7 +852,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); break; default: - dev_err(player->dev, "format not supported"); + dev_err(player->dev, "format not supported\n"); return -EINVAL; } @@ -866,13 +870,13 @@ static int uni_player_start(struct uniperif *player) /* The player should be stopped */ if (player->state != UNIPERIF_STATE_STOPPED) { - dev_err(player->dev, "%s: invalid player state", __func__); + dev_err(player->dev, "%s: invalid player state\n", __func__); return -EINVAL; } ret = clk_prepare_enable(player->clk); if (ret) { - dev_err(player->dev, "%s: Failed to enable clock", __func__); + dev_err(player->dev, "%s: Failed to enable clock\n", __func__); return ret; } @@ -934,7 +938,7 @@ static int uni_player_stop(struct uniperif *player) /* The player should not be in stopped state */ if (player->state == UNIPERIF_STATE_STOPPED) { - dev_err(player->dev, "%s: invalid player state", __func__); + dev_err(player->dev, "%s: invalid player state\n", __func__); return -EINVAL; } @@ -969,7 +973,7 @@ int uni_player_resume(struct uniperif *player) ret = regmap_field_write(player->clk_sel, 1); if (ret) { dev_err(player->dev, - "%s: Failed to select freq synth clock", + "%s: Failed to select freq synth clock\n", __func__); return ret; } @@ -1066,7 +1070,7 @@ int uni_player_init(struct platform_device *pdev, ret = uni_player_parse_dt_audio_glue(pdev, player); if (ret < 0) { - dev_err(player->dev, "Failed to parse DeviceTree"); + dev_err(player->dev, "Failed to parse DeviceTree\n"); return ret; } @@ -1081,15 +1085,17 @@ int uni_player_init(struct platform_device *pdev, /* Get uniperif resource */ player->clk = of_clk_get(pdev->dev.of_node, 0); - if (IS_ERR(player->clk)) + if (IS_ERR(player->clk)) { + dev_err(player->dev, "Failed to get clock\n"); ret = PTR_ERR(player->clk); + } /* Select the frequency synthesizer clock */ if (player->clk_sel) { ret = regmap_field_write(player->clk_sel, 1); if (ret) { dev_err(player->dev, - "%s: Failed to select freq synth clock", + "%s: Failed to select freq synth clock\n", __func__); return ret; } @@ -1101,7 +1107,7 @@ int uni_player_init(struct platform_device *pdev, ret = regmap_field_write(player->valid_sel, player->id); if (ret) { dev_err(player->dev, - "%s: unable to connect to tdm bus", __func__); + "%s: unable to connect to tdm bus\n", __func__); return ret; } } @@ -1109,8 +1115,10 @@ int uni_player_init(struct platform_device *pdev, ret = devm_request_irq(&pdev->dev, player->irq, uni_player_irq_handler, IRQF_SHARED, dev_name(&pdev->dev), player); - if (ret < 0) + if (ret < 0) { + dev_err(player->dev, "unable to request IRQ %d\n", player->irq); return ret; + } mutex_init(&player->ctrl_lock); diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 0e1c3ee56675..09314f8be841 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -52,7 +52,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) if (reader->state == UNIPERIF_STATE_STOPPED) { /* Unexpected IRQ: do nothing */ - dev_warn(reader->dev, "unexpected IRQ "); + dev_warn(reader->dev, "unexpected IRQ\n"); return IRQ_HANDLED; } @@ -62,7 +62,7 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) /* Check for fifo overflow error */ if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { - dev_err(reader->dev, "FIFO error detected"); + dev_err(reader->dev, "FIFO error detected\n"); snd_pcm_stream_lock(reader->substream); snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); @@ -105,7 +105,7 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader); break; default: - dev_err(reader->dev, "subframe format not supported"); + dev_err(reader->dev, "subframe format not supported\n"); return -EINVAL; } @@ -125,14 +125,14 @@ static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, break; default: - dev_err(reader->dev, "format not supported"); + dev_err(reader->dev, "format not supported\n"); return -EINVAL; } /* Number of channels must be even */ if ((runtime->channels % 2) || (runtime->channels < 2) || (runtime->channels > 10)) { - dev_err(reader->dev, "%s: invalid nb of channels", __func__); + dev_err(reader->dev, "%s: invalid nb of channels\n", __func__); return -EINVAL; } @@ -190,7 +190,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, /* The reader should be stopped */ if (reader->state != UNIPERIF_STATE_STOPPED) { - dev_err(reader->dev, "%s: invalid reader state %d", __func__, + dev_err(reader->dev, "%s: invalid reader state %d\n", __func__, reader->state); return -EINVAL; } @@ -219,7 +219,8 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { - dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); + dev_err(reader->dev, "invalid trigger limit %d\n", + trigger_limit); return -EINVAL; } @@ -246,7 +247,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); break; default: - dev_err(reader->dev, "format not supported"); + dev_err(reader->dev, "format not supported\n"); return -EINVAL; } @@ -294,7 +295,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, count--; } if (!count) { - dev_err(reader->dev, "Failed to reset uniperif"); + dev_err(reader->dev, "Failed to reset uniperif\n"); return -EIO; } @@ -305,7 +306,7 @@ static int uni_reader_start(struct uniperif *reader) { /* The reader should be stopped */ if (reader->state != UNIPERIF_STATE_STOPPED) { - dev_err(reader->dev, "%s: invalid reader state", __func__); + dev_err(reader->dev, "%s: invalid reader state\n", __func__); return -EINVAL; } @@ -325,7 +326,7 @@ static int uni_reader_stop(struct uniperif *reader) { /* The reader should not be in stopped state */ if (reader->state == UNIPERIF_STATE_STOPPED) { - dev_err(reader->dev, "%s: invalid reader state", __func__); + dev_err(reader->dev, "%s: invalid reader state\n", __func__); return -EINVAL; } @@ -423,7 +424,7 @@ int uni_reader_init(struct platform_device *pdev, uni_reader_irq_handler, IRQF_SHARED, dev_name(&pdev->dev), reader); if (ret < 0) { - dev_err(&pdev->dev, "Failed to request IRQ"); + dev_err(&pdev->dev, "Failed to request IRQ\n"); return -EBUSY; } -- cgit v1.2.3-59-g8ed1b From 4c88f89f9c255d0a754e38ff1a55a6f8cef362e8 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 24 Oct 2016 16:42:53 +0200 Subject: ASoC: sti: reset refactoring Reset is common to player and reader, migrate function in sti_uniperif.c Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 23 +++++++++++++++++++++++ sound/soc/sti/uniperif.h | 2 ++ sound/soc/sti/uniperif_player.c | 34 +++------------------------------- sound/soc/sti/uniperif_reader.c | 15 +-------------- 4 files changed, 29 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index ee91ae5f812a..98eb205a0b62 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -7,6 +7,7 @@ #include #include +#include #include "uniperif.h" @@ -97,6 +98,28 @@ static const struct of_device_id snd_soc_sti_match[] = { {}, }; +int sti_uniperiph_reset(struct uniperif *uni) +{ + int count = 10; + + /* Reset uniperipheral uni */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(uni); + + if (uni->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { + while (GET_UNIPERIF_SOFT_RST_SOFT_RST(uni) && count) { + udelay(5); + count--; + } + } + + if (!count) { + dev_err(uni->dev, "Failed to reset uniperif\n"); + return -EIO; + } + + return 0; +} + int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index 1993c655fb79..d487dd2ef016 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1397,6 +1397,8 @@ static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni) return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8); } +int sti_uniperiph_reset(struct uniperif *uni); + int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index c9b4670b772b..00022aa48280 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -6,7 +6,6 @@ */ #include -#include #include #include @@ -55,25 +54,6 @@ static const struct snd_pcm_hardware uni_player_pcm_hw = { .buffer_bytes_max = 256 * PAGE_SIZE }; -static inline int reset_player(struct uniperif *player) -{ - int count = 10; - - if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { - while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { - udelay(5); - count--; - } - } - - if (!count) { - dev_err(player->dev, "Failed to reset uniperif\n"); - return -EIO; - } - - return 0; -} - /* * uni_player_irq_handler * In case of error audio stream is stopped; stop action is protected via PCM @@ -858,10 +838,8 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); - /* Reset uniperipheral player */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - return reset_player(player); + return sti_uniperiph_reset(player); } static int uni_player_start(struct uniperif *player) @@ -893,10 +871,7 @@ static int uni_player_start(struct uniperif *player) SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); } - /* Reset uniperipheral player */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - - ret = reset_player(player); + ret = sti_uniperiph_reset(player); if (ret < 0) { clk_disable_unprepare(player->clk); return ret; @@ -945,10 +920,7 @@ static int uni_player_stop(struct uniperif *player) /* Turn the player off */ SET_UNIPERIF_CTRL_OPERATION_OFF(player); - /* Soft reset the player */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(player); - - ret = reset_player(player); + ret = sti_uniperiph_reset(player); if (ret < 0) return ret; diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 09314f8be841..59043f7a0e5c 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -6,7 +6,6 @@ */ #include -#include #include #include @@ -186,7 +185,6 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, struct uniperif *reader = priv->dai_data.uni; struct snd_pcm_runtime *runtime = substream->runtime; int transfer_size, trigger_limit, ret; - int count = 10; /* The reader should be stopped */ if (reader->state != UNIPERIF_STATE_STOPPED) { @@ -288,18 +286,7 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, } /* Reset uniperipheral reader */ - SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); - - while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) { - udelay(5); - count--; - } - if (!count) { - dev_err(reader->dev, "Failed to reset uniperif\n"); - return -EIO; - } - - return 0; + return sti_uniperiph_reset(reader); } static int uni_reader_start(struct uniperif *reader) -- cgit v1.2.3-59-g8ed1b From 4db61af068f50948a41b32a32fc3361f7ad152df Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 24 Oct 2016 16:42:54 +0200 Subject: ASoC: sti: clean unused include Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif_player.c | 1 - sound/soc/sti/uniperif_reader.c | 3 --- 2 files changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 00022aa48280..bea352a1504e 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -6,7 +6,6 @@ */ #include -#include #include #include diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 59043f7a0e5c..5992c6ab3833 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -5,9 +5,6 @@ * License terms: GNU General Public License (GPL), version 2 */ -#include -#include - #include #include "uniperif.h" -- cgit v1.2.3-59-g8ed1b From 165a57a3df0206b5609502d37e907944d8eb06ee Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 24 Oct 2016 16:42:55 +0200 Subject: ASoC: sti-sas: clean legacy in sti-sas stih416 is no more supported, clean associated code. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 169 ++++----------------------------------------- 1 file changed, 15 insertions(+), 154 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 7b31ee9b82bc..1488f4fb1c5e 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -14,28 +14,8 @@ #include #include -/* chipID supported */ -#define CHIPID_STIH416 0 -#define CHIPID_STIH407 1 - /* DAC definitions */ -/* stih416 DAC registers */ -/* sysconf 2517: Audio-DAC-Control */ -#define STIH416_AUDIO_DAC_CTRL 0x00000814 -/* sysconf 2519: Audio-Gue-Control */ -#define STIH416_AUDIO_GLUE_CTRL 0x0000081C - -#define STIH416_DAC_NOT_STANDBY 0x3 -#define STIH416_DAC_SOFTMUTE 0x4 -#define STIH416_DAC_ANA_NOT_PWR 0x5 -#define STIH416_DAC_NOT_PNDBG 0x6 - -#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY) -#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE) -#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR) -#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG) - /* stih407 DAC registers */ /* sysconf 5041: Audio-Gue-Control */ #define STIH407_AUDIO_GLUE_CTRL 0x000000A4 @@ -63,14 +43,9 @@ enum { STI_SAS_DAI_ANALOG_OUT, }; -static const struct reg_default stih416_sas_reg_defaults[] = { - { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, - { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, -}; - static const struct reg_default stih407_sas_reg_defaults[] = { - { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, - { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, + { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, + { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, }; struct sti_dac_audio { @@ -89,7 +64,6 @@ struct sti_spdif_audio { /* device data structure */ struct sti_sas_dev_data { - const int chipid; /* IC version */ const struct regmap_config *regmap; const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ @@ -155,43 +129,19 @@ static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, } /* Init DAC configuration */ - switch (data->dev_data->chipid) { - case CHIPID_STIH407: - /* init configuration */ - ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, - STIH407_DAC_STANDBY_MASK, - STIH407_DAC_STANDBY_MASK); - - if (!ret) - ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, - STIH407_DAC_STANDBY_ANA_MASK, - STIH407_DAC_STANDBY_ANA_MASK); - if (!ret) - ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, - STIH407_DAC_SOFTMUTE_MASK, - STIH407_DAC_SOFTMUTE_MASK); - break; - case CHIPID_STIH416: - ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_STANDBY_MASK, 0); - if (!ret) - ret = snd_soc_update_bits(codec, - STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_ANA_NOT_PWR, 0); - if (!ret) - ret = snd_soc_update_bits(codec, - STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_PNDBG_MASK, - 0); - if (!ret) - ret = snd_soc_update_bits(codec, - STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_SOFTMUTE_MASK, - STIH416_DAC_SOFTMUTE_MASK); - break; - default: - return -EINVAL; - } + /* init configuration */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_MASK, + STIH407_DAC_STANDBY_MASK); + + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_ANA_MASK, + STIH407_DAC_STANDBY_ANA_MASK); + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + STIH407_DAC_SOFTMUTE_MASK); if (ret < 0) { dev_err(codec->dev, "Failed to update DAC registers"); @@ -217,37 +167,6 @@ static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static int stih416_dac_probe(struct snd_soc_dai *dai) -{ - struct snd_soc_codec *codec = dai->codec; - struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); - struct sti_dac_audio *dac = &drvdata->dac; - - /* Get reset control */ - dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); - if (IS_ERR(dac->rst)) { - dev_err(dai->codec->dev, - "%s: ERROR: DAC reset control not defined !\n", - __func__); - dac->rst = NULL; - return -EFAULT; - } - /* Put the DAC into reset */ - reset_control_assert(dac->rst); - - return 0; -} - -static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { - SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), - SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), - SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_NOT_STANDBY, 0), - SND_SOC_DAPM_OUTPUT("DAC Output"), -}; - static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, STIH407_DAC_STANDBY_ANA, 1, NULL, 0), @@ -256,30 +175,11 @@ static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DAC Output"), }; -static const struct snd_soc_dapm_route stih416_sas_route[] = { - {"DAC Output", NULL, "DAC bandgap"}, - {"DAC Output", NULL, "DAC standby ana"}, - {"DAC standby ana", NULL, "DAC standby"}, -}; - static const struct snd_soc_dapm_route stih407_sas_route[] = { {"DAC Output", NULL, "DAC standby ana"}, {"DAC standby ana", NULL, "DAC standby"}, }; -static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) -{ - struct snd_soc_codec *codec = dai->codec; - - if (mute) { - return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_SOFTMUTE_MASK, - STIH416_DAC_SOFTMUTE_MASK); - } else { - return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, - STIH416_DAC_SOFTMUTE_MASK, 0); - } -} static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) { @@ -407,13 +307,6 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream, return 0; } -static const struct snd_soc_dai_ops stih416_dac_ops = { - .set_fmt = sti_sas_dac_set_fmt, - .mute_stream = stih416_sas_dac_mute, - .prepare = sti_sas_prepare, - .set_sysclk = sti_sas_set_sysclk, -}; - static const struct snd_soc_dai_ops stih407_dac_ops = { .set_fmt = sti_sas_dac_set_fmt, .mute_stream = stih407_sas_dac_mute, @@ -434,31 +327,7 @@ static const struct regmap_config stih407_sas_regmap = { .reg_write = sti_sas_write_reg, }; -static const struct regmap_config stih416_sas_regmap = { - .reg_bits = 32, - .val_bits = 32, - - .max_register = STIH416_AUDIO_DAC_CTRL, - .reg_defaults = stih416_sas_reg_defaults, - .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), - .volatile_reg = sti_sas_volatile_register, - .cache_type = REGCACHE_RBTREE, - .reg_read = sti_sas_read_reg, - .reg_write = sti_sas_write_reg, -}; - -static const struct sti_sas_dev_data stih416_data = { - .chipid = CHIPID_STIH416, - .regmap = &stih416_sas_regmap, - .dac_ops = &stih416_dac_ops, - .dapm_widgets = stih416_sas_dapm_widgets, - .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), - .dapm_routes = stih416_sas_route, - .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), -}; - static const struct sti_sas_dev_data stih407_data = { - .chipid = CHIPID_STIH407, .regmap = &stih407_sas_regmap, .dac_ops = &stih407_dac_ops, .dapm_widgets = stih407_sas_dapm_widgets, @@ -532,10 +401,6 @@ static struct snd_soc_codec_driver sti_sas_driver = { }; static const struct of_device_id sti_sas_dev_match[] = { - { - .compatible = "st,stih416-sas-codec", - .data = &stih416_data, - }, { .compatible = "st,stih407-sas-codec", .data = &stih407_data, @@ -584,10 +449,6 @@ static int sti_sas_driver_probe(struct platform_device *pdev) } drvdata->spdif.regmap = drvdata->dac.regmap; - /* Set DAC dai probe */ - if (drvdata->dev_data->chipid == CHIPID_STIH416) - sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; - sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; /* Set dapms*/ -- cgit v1.2.3-59-g8ed1b From 92591efabc013fa791f96df881aafcc104ba759d Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 24 Oct 2016 16:42:56 +0200 Subject: ASoC: sti-sas: add missing return in messages strings Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 1488f4fb1c5e..21d087be2e93 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -124,7 +124,7 @@ static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, SPDIF_BIPHASE_IDLE_MASK, 0); if (ret < 0) { - dev_err(codec->dev, "Failed to update SPDIF registers"); + dev_err(codec->dev, "Failed to update SPDIF registers\n"); return ret; } @@ -144,7 +144,7 @@ static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, STIH407_DAC_SOFTMUTE_MASK); if (ret < 0) { - dev_err(codec->dev, "Failed to update DAC registers"); + dev_err(codec->dev, "Failed to update DAC registers\n"); return ret; } @@ -292,13 +292,13 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream, switch (dai->id) { case STI_SAS_DAI_SPDIF_OUT: if ((drvdata->spdif.mclk / runtime->rate) != 128) { - dev_err(codec->dev, "unexpected mclk-fs ratio"); + dev_err(codec->dev, "unexpected mclk-fs ratio\n"); return -EINVAL; } break; case STI_SAS_DAI_ANALOG_OUT: if ((drvdata->dac.mclk / runtime->rate) != 256) { - dev_err(codec->dev, "unexpected mclk-fs ratio"); + dev_err(codec->dev, "unexpected mclk-fs ratio\n"); return -EINVAL; } break; @@ -423,7 +423,7 @@ static int sti_sas_driver_probe(struct platform_device *pdev) /* Populate data structure depending on compatibility */ of_id = of_match_node(sti_sas_dev_match, pnode); if (!of_id->data) { - dev_err(&pdev->dev, "data associated to device is missing"); + dev_err(&pdev->dev, "data associated to device is missing\n"); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 609c94865adcef3dba070a2d3905e4b67b4e6919 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Oct 2016 04:12:34 +0000 Subject: ASoC: rsnd: depends on OF Current Renesas sound driver is completely depends on CONFIG_OF Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 6db6405d952f..610fa85b3acd 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -37,6 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK + depends on OF select SND_SIMPLE_CARD select REGMAP_MMIO help -- cgit v1.2.3-59-g8ed1b From e144e5d06d0207c0b1631545fc1821565ee0fe6b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Oct 2016 04:12:53 +0000 Subject: ASoC: rsnd: enable COMPILE_TEST Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 610fa85b3acd..147ebecfed94 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -1,5 +1,5 @@ menu "SoC Audio support for SuperH" - depends on SUPERH || ARCH_SHMOBILE + depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST config SND_SOC_PCM_SH7760 tristate "SoC Audio support for Renesas SH7760" @@ -37,7 +37,7 @@ config SND_SOC_SH4_SIU config SND_SOC_RCAR tristate "R-Car series SRU/SCU/SSIU/SSI support" depends on COMMON_CLK - depends on OF + depends on OF || COMPILE_TEST select SND_SIMPLE_CARD select REGMAP_MMIO help -- cgit v1.2.3-59-g8ed1b From 91495329dcf83f126791be20c493bacf6c2d550a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 26 Oct 2016 14:29:27 +0100 Subject: ASoC: cs47l24: Fixup missing variable typo Fixes: 31833ead95c2 ("ASoC: arizona: Move request of speaker IRQs into bus probe") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index c5c5a2d9d84e..f9e720b65454 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1313,6 +1313,7 @@ err_dsp_irq: static int cs47l24_remove(struct platform_device *pdev) { struct cs47l24_priv *cs47l24 = platform_get_drvdata(pdev); + struct arizona *arizona = cs47l24->core.arizona; snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); -- cgit v1.2.3-59-g8ed1b From 1095e281559d61ed05c1b33aa4c6b305fcc211df Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 26 Oct 2016 17:06:40 +0100 Subject: ASoC: arizona: Access driver data through platform from compressed ops As the compressed ops run on the platform side of things we should really access the driver data through the platform pointer rather than the CODEC pointer. As the compressed DAIs in our systems always connect our CODEC to our platform this has never been an issue, but should still be corrected. Additionally it clears the way for future core refactoring work. Reported-by: Lars-Peter Clausen Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/cs47l24.c | 2 +- sound/soc/codecs/wm5102.c | 2 +- sound/soc/codecs/wm5110.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index f9e720b65454..1ed1329c31cc 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1066,7 +1066,7 @@ static struct snd_soc_dai_driver cs47l24_dai[] = { static int cs47l24_open(struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct cs47l24_priv *priv = snd_soc_platform_get_drvdata(rtd->platform); struct arizona *arizona = priv->core.arizona; int n_adsp; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index a80a680d1b5b..0136234e6e66 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1908,7 +1908,7 @@ static struct snd_soc_dai_driver wm5102_dai[] = { static int wm5102_open(struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct wm5102_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct wm5102_priv *priv = snd_soc_platform_get_drvdata(rtd->platform); return wm_adsp_compr_open(&priv->core.adsp[0], stream); } diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index f1a41139caf6..a9a8bc98fb29 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2224,7 +2224,7 @@ static struct snd_soc_dai_driver wm5110_dai[] = { static int wm5110_open(struct snd_compr_stream *stream) { struct snd_soc_pcm_runtime *rtd = stream->private_data; - struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec); + struct wm5110_priv *priv = snd_soc_platform_get_drvdata(rtd->platform); struct arizona *arizona = priv->core.arizona; int n_adsp; -- cgit v1.2.3-59-g8ed1b From f0b20e7120849ea68b2d7f0ec36ea45643265b09 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Oct 2016 04:27:22 +0000 Subject: ASoC: rsnd: remove "Gen2 only" comment Gen1 support had been removed. "Gen2 only" comment is no longer needed. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 62 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 422b5344b687..ff8c03601810 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -44,16 +44,16 @@ */ enum rsnd_reg { /* SCU (SRC/SSIU/MIX/CTU/DVC) */ - RSND_REG_SSI_MODE, /* Gen2 only */ + RSND_REG_SSI_MODE, RSND_REG_SSI_MODE0, RSND_REG_SSI_MODE1, RSND_REG_SSI_MODE2, RSND_REG_SSI_CONTROL, - RSND_REG_SSI_CTRL, /* Gen2 only */ - RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */ - RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ - RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */ - RSND_REG_SSI_INT_ENABLE, /* Gen2 only */ + RSND_REG_SSI_CTRL, + RSND_REG_SSI_BUSIF_MODE, + RSND_REG_SSI_BUSIF_ADINR, + RSND_REG_SSI_BUSIF_DALIGN, + RSND_REG_SSI_INT_ENABLE, RSND_REG_SRC_I_BUSIF_MODE, RSND_REG_SRC_O_BUSIF_MODE, RSND_REG_SRC_ROUTE_MODE0, @@ -63,29 +63,29 @@ enum rsnd_reg { RSND_REG_SRC_IFSCR, RSND_REG_SRC_IFSVR, RSND_REG_SRC_SRCCR, - RSND_REG_SRC_CTRL, /* Gen2 only */ - RSND_REG_SRC_BSDSR, /* Gen2 only */ - RSND_REG_SRC_BSISR, /* Gen2 only */ - RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */ - RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */ - RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */ - RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */ + RSND_REG_SRC_CTRL, + RSND_REG_SRC_BSDSR, + RSND_REG_SRC_BSISR, + RSND_REG_SRC_INT_ENABLE0, + RSND_REG_SRC_BUSIF_DALIGN, + RSND_REG_SRCIN_TIMSEL0, + RSND_REG_SRCIN_TIMSEL1, + RSND_REG_SRCIN_TIMSEL2, + RSND_REG_SRCIN_TIMSEL3, + RSND_REG_SRCIN_TIMSEL4, + RSND_REG_SRCOUT_TIMSEL0, + RSND_REG_SRCOUT_TIMSEL1, + RSND_REG_SRCOUT_TIMSEL2, + RSND_REG_SRCOUT_TIMSEL3, + RSND_REG_SRCOUT_TIMSEL4, RSND_REG_SCU_SYS_STATUS0, - RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */ + RSND_REG_SCU_SYS_STATUS1, RSND_REG_SCU_SYS_INT_EN0, - RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ - RSND_REG_CMD_CTRL, /* Gen2 only */ - RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ + RSND_REG_SCU_SYS_INT_EN1, + RSND_REG_CMD_CTRL, + RSND_REG_CMD_BUSIF_DALIGN, RSND_REG_CMD_ROUTE_SLCT, - RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ + RSND_REG_CMDOUT_TIMSEL, RSND_REG_CTU_SWRSR, RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, @@ -147,18 +147,18 @@ enum rsnd_reg { RSND_REG_DVC_VOL6R, RSND_REG_DVC_VOL7R, RSND_REG_DVC_DVUER, - RSND_REG_DVC_VRCTR, /* Gen2 only */ - RSND_REG_DVC_VRPDR, /* Gen2 only */ - RSND_REG_DVC_VRDBR, /* Gen2 only */ + RSND_REG_DVC_VRCTR, + RSND_REG_DVC_VRPDR, + RSND_REG_DVC_VRDBR, /* ADG */ RSND_REG_BRRA, RSND_REG_BRRB, RSND_REG_SSICKR, - RSND_REG_DIV_EN, /* Gen2 only */ + RSND_REG_DIV_EN, RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, - RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */ + RSND_REG_AUDIO_CLK_SEL2, /* SSI */ RSND_REG_SSICR, -- cgit v1.2.3-59-g8ed1b From bb7927c793e1036bc15f67a8fd10e803f56c6760 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Oct 2016 04:28:06 +0000 Subject: ASoC: rsnd: rsnd_reg cleanup for SSIU R-Car Gen1 didn't have SSIU IP, and it was part of SRU. In Gen2, SSIU was created and it has original register. Let's cleanup rsnd_reg for SSIU, because this driver doesn't support Gen1 SRU any more. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index ff8c03601810..678a9914c96f 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -43,17 +43,7 @@ * see gen1/gen2 for detail */ enum rsnd_reg { - /* SCU (SRC/SSIU/MIX/CTU/DVC) */ - RSND_REG_SSI_MODE, - RSND_REG_SSI_MODE0, - RSND_REG_SSI_MODE1, - RSND_REG_SSI_MODE2, - RSND_REG_SSI_CONTROL, - RSND_REG_SSI_CTRL, - RSND_REG_SSI_BUSIF_MODE, - RSND_REG_SSI_BUSIF_ADINR, - RSND_REG_SSI_BUSIF_DALIGN, - RSND_REG_SSI_INT_ENABLE, + /* SCU (MIX/CTU/DVC) */ RSND_REG_SRC_I_BUSIF_MODE, RSND_REG_SRC_O_BUSIF_MODE, RSND_REG_SRC_ROUTE_MODE0, @@ -160,6 +150,18 @@ enum rsnd_reg { RSND_REG_AUDIO_CLK_SEL1, RSND_REG_AUDIO_CLK_SEL2, + /* SSIU */ + RSND_REG_SSI_MODE, + RSND_REG_SSI_MODE0, + RSND_REG_SSI_MODE1, + RSND_REG_SSI_MODE2, + RSND_REG_SSI_CONTROL, + RSND_REG_SSI_CTRL, + RSND_REG_SSI_BUSIF_MODE, + RSND_REG_SSI_BUSIF_ADINR, + RSND_REG_SSI_BUSIF_DALIGN, + RSND_REG_SSI_INT_ENABLE, + /* SSI */ RSND_REG_SSICR, RSND_REG_SSISR, -- cgit v1.2.3-59-g8ed1b From 42b197e794dbe961cbcebd9e4963252c96cc77f9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Oct 2016 04:28:42 +0000 Subject: ASoC: rsnd: fixup SCU_SYS_STATUSx access SCU_SYS_STATUSx is the register that writing 1 initializes the bit, and writing 0 is ignored. So, it should use rsnd_mod_write() instead of rsnd_mod_bset(), otherwise all bit will be cleared. Thanks Shimoda-san Reported-by: Yoshihiro Shimoda Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index e13d6d439b32..aa24258b9b14 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -327,8 +327,8 @@ static void rsnd_src_status_clear(struct rsnd_mod *mod) { u32 val = OUF_SRC(rsnd_mod_id(mod)); - rsnd_mod_bset(mod, SCU_SYS_STATUS0, val, val); - rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); + rsnd_mod_write(mod, SCU_SYS_STATUS0, val); + rsnd_mod_write(mod, SCU_SYS_STATUS1, val); } static bool rsnd_src_error_occurred(struct rsnd_mod *mod) -- cgit v1.2.3-59-g8ed1b From 814efe3ed72d1cad926e21b8d0869a1ea74bb9dd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 26 Oct 2016 04:29:21 +0000 Subject: ASoC: rsnd: clear SSI_SYS_STATUSx every time Renesas sound SSIU has SSI_SYS_STATUS register whick will be changed if over/under run was occurred. Current rsnd driver is handling over/under run error on SSI/SRC, but doesn't on SSIU. HW guys can't guarantee correct behavior if it already had error bit on status register when it start. Thus, it should be cleared every start timing. This patch do it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 8 ++++++++ sound/soc/sh/rcar/rsnd.h | 8 ++++++++ sound/soc/sh/rcar/ssiu.c | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+) (limited to 'sound') diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 7d2fdf8dd188..d653cf488f73 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -211,6 +211,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) RSND_GEN_S_REG(SSI_MODE1, 0x804), RSND_GEN_S_REG(SSI_MODE2, 0x808), RSND_GEN_S_REG(SSI_CONTROL, 0x810), + RSND_GEN_S_REG(SSI_SYS_STATUS0, 0x840), + RSND_GEN_S_REG(SSI_SYS_STATUS1, 0x844), + RSND_GEN_S_REG(SSI_SYS_STATUS2, 0x848), + RSND_GEN_S_REG(SSI_SYS_STATUS3, 0x84c), + RSND_GEN_S_REG(SSI_SYS_STATUS4, 0x880), + RSND_GEN_S_REG(SSI_SYS_STATUS5, 0x884), + RSND_GEN_S_REG(SSI_SYS_STATUS6, 0x888), + RSND_GEN_S_REG(SSI_SYS_STATUS7, 0x88c), /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 678a9914c96f..d6bb53009123 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -161,6 +161,14 @@ enum rsnd_reg { RSND_REG_SSI_BUSIF_ADINR, RSND_REG_SSI_BUSIF_DALIGN, RSND_REG_SSI_INT_ENABLE, + RSND_REG_SSI_SYS_STATUS0, + RSND_REG_SSI_SYS_STATUS1, + RSND_REG_SSI_SYS_STATUS2, + RSND_REG_SSI_SYS_STATUS3, + RSND_REG_SSI_SYS_STATUS4, + RSND_REG_SSI_SYS_STATUS5, + RSND_REG_SSI_SYS_STATUS6, + RSND_REG_SSI_SYS_STATUS7, /* SSI */ RSND_REG_SSICR, diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c index 6f9b388ec5a8..4e817c8a18c0 100644 --- a/sound/soc/sh/rcar/ssiu.c +++ b/sound/soc/sh/rcar/ssiu.c @@ -33,6 +33,26 @@ static int rsnd_ssiu_init(struct rsnd_mod *mod, u32 mask1, val1; u32 mask2, val2; + /* clear status */ + switch (id) { + case 0: + case 1: + case 2: + case 3: + case 4: + rsnd_mod_write(mod, SSI_SYS_STATUS0, 0xf << (id * 4)); + rsnd_mod_write(mod, SSI_SYS_STATUS2, 0xf << (id * 4)); + rsnd_mod_write(mod, SSI_SYS_STATUS4, 0xf << (id * 4)); + rsnd_mod_write(mod, SSI_SYS_STATUS6, 0xf << (id * 4)); + break; + case 9: + rsnd_mod_write(mod, SSI_SYS_STATUS1, 0xf << 4); + rsnd_mod_write(mod, SSI_SYS_STATUS3, 0xf << 4); + rsnd_mod_write(mod, SSI_SYS_STATUS5, 0xf << 4); + rsnd_mod_write(mod, SSI_SYS_STATUS7, 0xf << 4); + break; + } + /* * SSI_MODE0 */ -- cgit v1.2.3-59-g8ed1b From c8c6f0d81de67198522e3f31142986c27d3cba81 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 27 Oct 2016 13:21:54 +0800 Subject: ASoC: rt5670: increse LDO power Inrecse LDO power for better performance. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 6caac92143d4..12d3bc14a558 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2618,7 +2618,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, RT5670_OSW_L_DIS | RT5670_OSW_R_DIS); snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x1); snd_soc_update_bits(codec, RT5670_PWR_ANLG1, - RT5670_LDO_SEL_MASK, 0x3); + RT5670_LDO_SEL_MASK, 0x5); } break; case SND_SOC_BIAS_STANDBY: @@ -2626,7 +2626,7 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); snd_soc_update_bits(codec, RT5670_PWR_ANLG1, - RT5670_LDO_SEL_MASK, 0x1); + RT5670_LDO_SEL_MASK, 0x3); break; case SND_SOC_BIAS_OFF: if (rt5670->pdata.jd_mode) -- cgit v1.2.3-59-g8ed1b From 67923f779b8d9d210c5ec98ffb68d9fe5a68df18 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 27 Oct 2016 01:05:21 +0000 Subject: ASoC: rsnd: enable SRC sync even FIN = FOUT Current SRC (= Sampling Rate Converter) is supporting SYNC mode and ASYNC mode. Current src.c cares SRC if FIN != FOUT. Here, SYNC mode will be used for tweak, so it will be used even FIN = FOUT. This patch enables SRC sync in such situation Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Tested-by: Yuichi Takagi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index aa24258b9b14..3a8f65bd1bf9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,6 +189,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct device *dev = rsnd_priv_to_dev(priv); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + int use_src = 0; u32 fin, fout; u32 ifscr, fsrate, adinr; u32 cr, route; @@ -214,6 +215,8 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, return; } + use_src = (fin != fout) | rsnd_src_sync_is_enabled(mod); + /* * SRC_ADINR */ @@ -225,7 +228,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, */ ifscr = 0; fsrate = 0; - if (fin != fout) { + if (use_src) { u64 n; ifscr = 1; @@ -239,7 +242,7 @@ static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, */ cr = 0x00011110; route = 0x0; - if (fin != fout) { + if (use_src) { route = 0x1; if (rsnd_src_sync_is_enabled(mod)) { -- cgit v1.2.3-59-g8ed1b From fa80b4eca6b383604da3a04f8c9de67bbb89f3b6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 27 Oct 2016 08:44:23 +0000 Subject: ASoC: max98504: Add missing MAX98504 on SND_SOC_ALL_CODECS commit 4c5d1469297d ("ASoC: max98504: Add max98504 speaker amplifier driver") added new max98504, but this patch didn't add it to SND_SOC_ALL_CODECS. This patch adds it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..b51d490ba325 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -83,6 +83,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX98095 if I2C select SND_SOC_MAX98357A if GPIOLIB select SND_SOC_MAX98371 if I2C + select SND_SOC_MAX98504 if I2C select SND_SOC_MAX9867 if I2C select SND_SOC_MAX98925 if I2C select SND_SOC_MAX98926 if I2C -- cgit v1.2.3-59-g8ed1b From b058b176dd26546bcef8f8b774f1542b2907af5f Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 7 Oct 2016 10:59:51 +0300 Subject: ASoC: rl6347a: Use dev_err for I2C communication error prints It's difficult to guess from bunch of "ret=-121" errors what driver and device actually caused them. Since struct i2c_client has the dev pointer use that for dev_err() with meaningful error message. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rl6347a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c index a4b910efbd45..8f571cf8edd4 100644 --- a/sound/soc/codecs/rl6347a.c +++ b/sound/soc/codecs/rl6347a.c @@ -51,7 +51,7 @@ int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value) if (ret == 4) return 0; else - pr_err("ret=%d\n", ret); + dev_err(&client->dev, "I2C error %d\n", ret); if (ret < 0) return ret; else -- cgit v1.2.3-59-g8ed1b From ca590c1c45d1d06f842a82f6a591b94af95952b0 Mon Sep 17 00:00:00 2001 From: Dharageswari R Date: Thu, 6 Oct 2016 08:51:21 +0530 Subject: ASoC: Intel: Skylake: Use DPIB to update position for Playback stream DPIB is read currently from a buffer position in memory (indicated by the registers DPIB[U|L]BASE).Driver reads the position buffer on BDL completion interrupts to report the DMA position. But the BDL completion interrupt only indicates the last DMA transfer of the buffer is completed at the Intel HD Audio subsystem boundary. The periodic DMA Position-in-Buffer writes may be scheduled at the same time or later than the MSI and does not guarantee to reflect the position of the last buffer that was transferred. Whereas DPIB register in HDA space(vendor specific register indicated by SDxDPIB) reflects the actual data that is transferred. Hence update the position based on DPIB for playback. Signed-off-by: Dharageswari R Signed-off-by: Jeeja KP Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 58c728662600..c966b40da180 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1031,10 +1031,24 @@ static snd_pcm_uframes_t skl_platform_pcm_pointer (struct snd_pcm_substream *substream) { struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); + struct hdac_ext_bus *ebus = get_bus_ctx(substream); unsigned int pos; - /* use the position buffer as default */ - pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + /* + * Use DPIB for Playback stream as the periodic DMA Position-in- + * Buffer Writes may be scheduled at the same time or later than + * the MSI and does not guarantee to reflect the Position of the + * last buffer that was transferred. Whereas DPIB register in + * HAD space reflects the actual data that is transferred. + * Use the position buffer for capture, as DPIB write gets + * completed earlier than the actual data written to the DDR. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + pos = readl(ebus->bus.remap_addr + AZX_REG_VS_SDXDPIB_XBASE + + (AZX_REG_VS_SDXDPIB_XINTERVAL * + hdac_stream(hstream)->index)); + else + pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); if (pos >= hdac_stream(hstream)->bufsize) pos = 0; -- cgit v1.2.3-59-g8ed1b From 6a7f5e41128de638fae7522262d18a6ef9cf1096 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Fri, 28 Oct 2016 16:32:50 +0200 Subject: ASoC: Intel: atom: Add debug information related to FW version This patch is adding debug information related to SST FW version. Signed-off-by: Sebastien Guiriec Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_ipc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index bfc889950bb2..7934a0047384 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -236,6 +236,11 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, retval = init->result; goto ret; } + dev_info(sst_drv_ctx->dev, "FW Version %02x.%02x.%02x.%02x\n", + init->fw_version.type, init->fw_version.major, + init->fw_version.minor, init->fw_version.build); + dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", + init->build_info.date, init->build_info.time); ret: sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); -- cgit v1.2.3-59-g8ed1b From f999d1fd69ede11012a872cbdba33bd9c9c2e386 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 26 Sep 2016 11:05:28 +0530 Subject: ASoC: Intel: Add check_dsp_lp_on callback on IPC Some controllers support power modes which can't communicate using IPC. So add a callback to check and wake DSP before sending IPC and then put to sleep if it is in these power modes. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-ipc.c | 19 ++++++++++++++++++- sound/soc/intel/common/sst-ipc.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 6c672ac79cce..45a85190a081 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -190,8 +190,25 @@ static void ipc_tx_msgs(struct kthread_work *work) int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) { - return ipc_tx_message(ipc, header, tx_data, tx_bytes, + int ret; + + /* + * DSP maybe in lower power active state, so + * check if the DSP supports DSP lp On method + * if so invoke that before sending IPC + */ + if (ipc->ops.check_dsp_lp_on) + if (ipc->ops.check_dsp_lp_on(ipc->dsp, true)) + return -EIO; + + ret = ipc_tx_message(ipc, header, tx_data, tx_bytes, rx_data, rx_bytes, 1); + + if (ipc->ops.check_dsp_lp_on) + if (ipc->ops.check_dsp_lp_on(ipc->dsp, false)) + return -EIO; + + return ret; } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_wait); diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index ceb7e468a3fa..46871a5dff1d 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -52,6 +52,7 @@ struct sst_plat_ipc_ops { void (*tx_data_copy)(struct ipc_message *, char *, size_t); u64 (*reply_msg_match)(u64 header, u64 *mask); bool (*is_dsp_busy)(struct sst_dsp *dsp); + int (*check_dsp_lp_on)(struct sst_dsp *dsp, bool state); }; /* SST generic IPC data */ -- cgit v1.2.3-59-g8ed1b From 3e58690b8dbddefb4422295b57a6f214e8aa03fd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 28 Oct 2016 04:12:40 +0000 Subject: ASoC: rsnd: use BRGCKR instead of SSICKR Current register name of "SSICKR" was came from R-Car Gen1 which is very old style. It is called as "BRGCKR" on R-Car Gen2/Gen3. Let's rename it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 6 +++--- sound/soc/sh/rcar/gen.c | 4 ++-- sound/soc/sh/rcar/rsnd.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2145957d0229..545377dc15ed 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -366,7 +366,7 @@ found_clock: if (0 == (rate % 8000)) ckr = 0x80000000; - rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr); + rsnd_mod_bset(adg_mod, BRGCKR, 0x80000000, ckr); } dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", @@ -532,13 +532,13 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } } - rsnd_mod_bset(adg_mod, SSICKR, 0x80FF0000, ckr); + rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, ckr); rsnd_mod_write(adg_mod, BRRA, rbga); rsnd_mod_write(adg_mod, BRRB, rbgb); for_each_rsnd_clkout(clk, adg, i) dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); - dev_dbg(dev, "SSICKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", + dev_dbg(dev, "BRGCKR = 0x%08x, BRRA/BRRB = 0x%x/0x%x\n", ckr, rbga, rbgb); } diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index d653cf488f73..63b6d3c28021 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -319,7 +319,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) static const struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(SSICKR, 0x08), + RSND_GEN_S_REG(BRGCKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), RSND_GEN_S_REG(AUDIO_CLK_SEL2, 0x14), @@ -370,7 +370,7 @@ static int rsnd_gen1_probe(struct rsnd_priv *priv) static const struct rsnd_regmap_field_conf conf_adg[] = { RSND_GEN_S_REG(BRRA, 0x00), RSND_GEN_S_REG(BRRB, 0x04), - RSND_GEN_S_REG(SSICKR, 0x08), + RSND_GEN_S_REG(BRGCKR, 0x08), RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d6bb53009123..d9e550211c09 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -144,7 +144,7 @@ enum rsnd_reg { /* ADG */ RSND_REG_BRRA, RSND_REG_BRRB, - RSND_REG_SSICKR, + RSND_REG_BRGCKR, RSND_REG_DIV_EN, RSND_REG_AUDIO_CLK_SEL0, RSND_REG_AUDIO_CLK_SEL1, -- cgit v1.2.3-59-g8ed1b From 15a190ffec3b3f5e632faaa01b92f4cef32d63a3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 28 Oct 2016 03:37:26 +0000 Subject: ASoC: simple-scu-card: code sync: follow to simple family style simple sound card family are using very similar style, but because of its historical reason, there are small differences. For example pointer style, function name, caller postion etc... This patch synchronized simple card style to other simple card family Current simple-scu-card function naming is different from other simple card family. And related to it, the necessary operation position is also different. This patch synchronize these to other simple card family. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 99 ++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 56 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index b9973a56bcb0..b8d8437ef3dd 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -101,7 +101,7 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, return 0; } -static int asoc_simple_card_parse_links(struct device_node *np, +static int asoc_simple_card_dai_link_of(struct device_node *np, struct asoc_simple_card_priv *priv, unsigned int daifmt, int idx, bool is_fe) @@ -195,22 +195,35 @@ static int asoc_simple_card_parse_links(struct device_node *np, return 0; } -static int asoc_simple_card_dai_link_of(struct device_node *node, - struct asoc_simple_card_priv *priv) +static int asoc_simple_card_parse_of(struct device_node *node, + struct asoc_simple_card_priv *priv) + { struct device *dev = simple_priv_to_dev(priv); struct device_node *np; unsigned int daifmt = 0; - int ret, i; bool is_fe; + int ret, i; + + if (!node) + return -EINVAL; + + ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); + if (ret < 0) + return ret; + + /* sampling rate convert */ + of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); + + /* channels transfer */ + of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); /* find 1st codec */ np = of_get_child_by_name(node, PREFIX "codec"); if (!np) return -ENODEV; - ret = asoc_simple_card_parse_daifmt(dev, node, np, - PREFIX, &daifmt); + ret = asoc_simple_card_parse_daifmt(dev, node, np, PREFIX, &daifmt); if (ret < 0) return ret; @@ -220,58 +233,12 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, if (strcmp(np->name, PREFIX "cpu") == 0) is_fe = true; - ret = asoc_simple_card_parse_links(np, priv, daifmt, i, is_fe); + ret = asoc_simple_card_dai_link_of(np, priv, daifmt, i, is_fe); if (ret < 0) return ret; i++; } - return 0; -} - -static int asoc_simple_card_parse_of(struct device_node *node, - struct asoc_simple_card_priv *priv, - struct device *dev) -{ - struct asoc_simple_dai *props; - struct snd_soc_dai_link *links; - int ret; - int num; - - if (!node) - return -EINVAL; - - num = of_get_child_count(node); - props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); - links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); - if (!props || !links) - return -ENOMEM; - - priv->dai_props = props; - priv->dai_link = links; - - /* Init snd_soc_card */ - priv->snd_card.owner = THIS_MODULE; - priv->snd_card.dev = dev; - priv->snd_card.dai_link = priv->dai_link; - priv->snd_card.num_links = num; - priv->snd_card.codec_conf = &priv->codec_conf; - priv->snd_card.num_configs = 1; - - ret = snd_soc_of_parse_audio_routing(&priv->snd_card, PREFIX "routing"); - if (ret < 0) - return ret; - - /* sampling rate convert */ - of_property_read_u32(node, PREFIX "convert-rate", &priv->convert_rate); - - /* channels transfer */ - of_property_read_u32(node, PREFIX "convert-channels", &priv->convert_channels); - - ret = asoc_simple_card_dai_link_of(node, priv); - if (ret < 0) - return ret; - ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); if (ret < 0) return ret; @@ -287,16 +254,36 @@ static int asoc_simple_card_parse_of(struct device_node *node, static int asoc_simple_card_probe(struct platform_device *pdev) { struct asoc_simple_card_priv *priv; - struct device_node *np = pdev->dev.of_node; + struct snd_soc_dai_link *links; + struct asoc_simple_dai *props; struct device *dev = &pdev->dev; - int ret; + struct device_node *np = pdev->dev.of_node; + int num, ret; /* Allocate the private data */ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; - ret = asoc_simple_card_parse_of(np, priv, dev); + num = of_get_child_count(np); + + props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); + links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); + if (!props || !links) + return -ENOMEM; + + priv->dai_props = props; + priv->dai_link = links; + + /* Init snd_soc_card */ + priv->snd_card.owner = THIS_MODULE; + priv->snd_card.dev = dev; + priv->snd_card.dai_link = priv->dai_link; + priv->snd_card.num_links = num; + priv->snd_card.codec_conf = &priv->codec_conf; + priv->snd_card.num_configs = 1; + + ret = asoc_simple_card_parse_of(np, priv); if (ret < 0) { if (ret != -EPROBE_DEFER) dev_err(dev, "parse error %d\n", ret); -- cgit v1.2.3-59-g8ed1b From 6910e8679ff4d256028003be2451deb31f13948e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 28 Oct 2016 03:37:44 +0000 Subject: ASoC: simple-scu-card: code sync: rename asoc_simple_card_priv simple sound card family are using very similar style, but because of its historical reason, there are small differences. For example pointer style, function name, caller postion etc... This patch synchronized simple card style to other simple card family This patch renames asoc_simple_card_priv to simple_card_data, same as other simple card family. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index b8d8437ef3dd..1704b187f6ee 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -22,7 +22,7 @@ #include #include -struct asoc_simple_card_priv { +struct simple_card_data { struct snd_soc_card snd_card; struct snd_soc_codec_conf codec_conf; struct asoc_simple_dai *dai_props; @@ -42,7 +42,7 @@ struct asoc_simple_card_priv { static int asoc_simple_card_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, rtd->num); @@ -52,7 +52,7 @@ static int asoc_simple_card_startup(struct snd_pcm_substream *substream) static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct asoc_simple_dai *dai_props = simple_priv_to_props(priv, rtd->num); @@ -66,7 +66,7 @@ static struct snd_soc_ops asoc_simple_card_ops = { static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) { - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *dai; struct snd_soc_dai_link *dai_link; struct asoc_simple_dai *dai_props; @@ -84,7 +84,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, struct snd_pcm_hw_params *params) { - struct asoc_simple_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); + struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct snd_interval *rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, @@ -102,7 +102,7 @@ static int asoc_simple_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, } static int asoc_simple_card_dai_link_of(struct device_node *np, - struct asoc_simple_card_priv *priv, + struct simple_card_data *priv, unsigned int daifmt, int idx, bool is_fe) { @@ -196,7 +196,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *np, } static int asoc_simple_card_parse_of(struct device_node *node, - struct asoc_simple_card_priv *priv) + struct simple_card_data *priv) { struct device *dev = simple_priv_to_dev(priv); @@ -253,7 +253,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, static int asoc_simple_card_probe(struct platform_device *pdev) { - struct asoc_simple_card_priv *priv; + struct simple_card_data *priv; struct snd_soc_dai_link *links; struct asoc_simple_dai *props; struct device *dev = &pdev->dev; -- cgit v1.2.3-59-g8ed1b From 193599264f3eb632f43f83f738b17241f91dbd5a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 28 Oct 2016 03:38:00 +0000 Subject: ASoC: simple-scu-card: code sync: tidyup props/link naming simple sound card family are using very similar style, but because of its historical reason, there are small differences. For example pointer style, function name, caller postion etc... This patch synchronizes style to other simple card family so that be enable to easy reviewing. This patch uses dai_link/dai_props instead of links/props. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-scu-card.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-scu-card.c b/sound/soc/generic/simple-scu-card.c index 1704b187f6ee..348e9a7c4d10 100644 --- a/sound/soc/generic/simple-scu-card.c +++ b/sound/soc/generic/simple-scu-card.c @@ -254,8 +254,8 @@ static int asoc_simple_card_parse_of(struct device_node *node, static int asoc_simple_card_probe(struct platform_device *pdev) { struct simple_card_data *priv; - struct snd_soc_dai_link *links; - struct asoc_simple_dai *props; + struct snd_soc_dai_link *dai_link; + struct asoc_simple_dai *dai_props; struct device *dev = &pdev->dev; struct device_node *np = pdev->dev.of_node; int num, ret; @@ -267,13 +267,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) num = of_get_child_count(np); - props = devm_kzalloc(dev, sizeof(*props) * num, GFP_KERNEL); - links = devm_kzalloc(dev, sizeof(*links) * num, GFP_KERNEL); - if (!props || !links) + dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL); + dai_link = devm_kzalloc(dev, sizeof(*dai_link) * num, GFP_KERNEL); + if (!dai_props || !dai_link) return -ENOMEM; - priv->dai_props = props; - priv->dai_link = links; + priv->dai_props = dai_props; + priv->dai_link = dai_link; /* Init snd_soc_card */ priv->snd_card.owner = THIS_MODULE; -- cgit v1.2.3-59-g8ed1b From 6c1c06cb776cf9a34ceafc5be288aa3670aa3ef2 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 28 Oct 2016 03:38:28 +0000 Subject: ASoC: simple-card-utils: remove unnecessary cpu/codec pointer check Remove cpu/codec pointer check from asoc_simple_card_canonicalize_dailink() This is verbose check, and will be issue if CPU name was created by fmt_single_name() on simple-scu-card.c. see also asoc_simple_card_canonicalize_cpu() Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/generic/simple-card-utils.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 1cb39309f5d5..e5b80f53093a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -195,9 +195,6 @@ EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai); int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link) { - if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) - return -EINVAL; - /* Assumes platform == cpu */ if (!dai_link->platform_of_node) dai_link->platform_of_node = dai_link->cpu_of_node; -- cgit v1.2.3-59-g8ed1b From ca5f17c59b63c3e52f8fad887c27c6eaa5ced81f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 26 Oct 2016 09:40:44 +0800 Subject: ASoC: rt5640: add Mono ADC Capture Switch control Mono ADC Capture Switch control is missing in the driver. So, add it. Signed-off-by: Bard Liao Tested-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 2 ++ sound/soc/codecs/rt5640.h | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 0a7378f81acb..e29a6defefa0 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -423,6 +423,8 @@ static const struct snd_kcontrol_new rt5640_snd_controls[] = { SOC_DOUBLE_TLV("ADC Capture Volume", RT5640_ADC_DIG_VOL, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5640_DUMMY1, + RT5640_M_MONO_ADC_L_SFT, RT5640_M_MONO_ADC_R_SFT, 1, 1), SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5640_ADC_DATA, RT5640_L_VOL_SFT, RT5640_R_VOL_SFT, 127, 0, adc_vol_tlv), diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 22c017c58d5b..b8a811732a52 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h @@ -1971,6 +1971,10 @@ #define RT5640_ZCD_HP_EN (0x1 << 15) /* General Control 1 (0xfa) */ +#define RT5640_M_MONO_ADC_L (0x1 << 13) +#define RT5640_M_MONO_ADC_L_SFT 13 +#define RT5640_M_MONO_ADC_R (0x1 << 12) +#define RT5640_M_MONO_ADC_R_SFT 12 #define RT5640_MCLK_DET (0x1 << 11) /* Codec Private Register definition */ -- cgit v1.2.3-59-g8ed1b From 583958fa2e522139a5fe8b039069e31502c20d31 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Tue, 11 Oct 2016 14:36:42 +0800 Subject: ASoC: topology: Make manifest backward compatible from ABI v4 This patch adds support for old version 4 of manifest. Topology ABI v5 added new fields to manifest while user space may still uses v4. So kernel will check the ABI version by comparing the object size. If user space uses v4 of manifest, kernel will create a latest version of manifest from the old one, and use the new one internally and free it later. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 87 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 6b05047a4134..c832b24b0cde 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -53,6 +53,23 @@ #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST #define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI + +/* + * Old version of ABI structs, supported for backward compatibility. + */ + +/* Manifest v4 */ +struct snd_soc_tplg_manifest_v4 { + __le32 size; /* in bytes of this structure */ + __le32 control_elems; /* number of control elements */ + __le32 widget_elems; /* number of widget elements */ + __le32 graph_elems; /* number of graph elements */ + __le32 pcm_elems; /* number of PCM elements */ + __le32 dai_link_elems; /* number of DAI link elements */ + struct snd_soc_tplg_private priv; +} __packed; + +/* topology context */ struct soc_tplg { const struct firmware *fw; @@ -1798,27 +1815,81 @@ static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, return 0; } +/** + * manifest_new_ver - Create a new version of manifest from the old version + * of source. + * @toplogy: topology context + * @src: old version of manifest as a source + * @manifest: latest version of manifest created from the source + * + * Support from vesion 4. Users need free the returned manifest manually. + */ +static int manifest_new_ver(struct soc_tplg *tplg, + struct snd_soc_tplg_manifest *src, + struct snd_soc_tplg_manifest **manifest) +{ + struct snd_soc_tplg_manifest *dest; + struct snd_soc_tplg_manifest_v4 *src_v4; + + *manifest = NULL; + + if (src->size != sizeof(*src_v4)) { + dev_err(tplg->dev, "ASoC: invalid manifest size\n"); + return -EINVAL; + } + + dev_warn(tplg->dev, "ASoC: old version of manifest\n"); + + src_v4 = (struct snd_soc_tplg_manifest_v4 *)src; + dest = kzalloc(sizeof(*dest) + src_v4->priv.size, GFP_KERNEL); + if (!dest) + return -ENOMEM; + + dest->size = sizeof(*dest); /* size of latest abi version */ + dest->control_elems = src_v4->control_elems; + dest->widget_elems = src_v4->widget_elems; + dest->graph_elems = src_v4->graph_elems; + dest->pcm_elems = src_v4->pcm_elems; + dest->dai_link_elems = src_v4->dai_link_elems; + dest->priv.size = src_v4->priv.size; + if (dest->priv.size) + memcpy(dest->priv.data, src_v4->priv.data, + src_v4->priv.size); + + *manifest = dest; + return 0; +} static int soc_tplg_manifest_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_manifest *manifest; + struct snd_soc_tplg_manifest *manifest, *_manifest; + bool abi_match; + int err; if (tplg->pass != SOC_TPLG_PASS_MANIFEST) return 0; manifest = (struct snd_soc_tplg_manifest *)tplg->pos; - if (manifest->size != sizeof(*manifest)) { - dev_err(tplg->dev, "ASoC: invalid manifest size\n"); - return -EINVAL; - } - tplg->pos += sizeof(struct snd_soc_tplg_manifest); + /* check ABI version by size, create a new manifest if abi not match */ + if (manifest->size == sizeof(*manifest)) { + abi_match = true; + _manifest = manifest; + } else { + abi_match = false; + err = manifest_new_ver(tplg, manifest, &_manifest); + if (err < 0) + return err; + } + /* pass control to component driver for optional further init */ if (tplg->comp && tplg->ops && tplg->ops->manifest) - return tplg->ops->manifest(tplg->comp, manifest); + return tplg->ops->manifest(tplg->comp, _manifest); + + if (!abi_match) /* free the duplicated one */ + kfree(_manifest); - dev_err(tplg->dev, "ASoC: Firmware manifest not supported\n"); return 0; } -- cgit v1.2.3-59-g8ed1b From 2f3d1b659344ad28bd559dcb2176e9ae84a2b044 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 16:27:23 +0000 Subject: ASoC: wm8580: Fix non static symbol warnings Fixes the following sparse warnings: sound/soc/codecs/wm8580.c:988:33: warning: symbol 'wm8580_data' was not declared. Should it be static? sound/soc/codecs/wm8580.c:992:33: warning: symbol 'wm8581_data' was not declared. Should it be static? Signed-off-by: Wei Yongjun Signed-off-by: Mark Brown --- sound/soc/codecs/wm8580.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index aecd3c99e604..da93b703ed49 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -985,11 +985,11 @@ static const struct regmap_config wm8580_regmap = { .volatile_reg = wm8580_volatile, }; -const struct wm8580_driver_data wm8580_data = { +static const struct wm8580_driver_data wm8580_data = { .num_dacs = 3, }; -const struct wm8580_driver_data wm8581_data = { +static const struct wm8580_driver_data wm8581_data = { .num_dacs = 4, }; -- cgit v1.2.3-59-g8ed1b From 4774e27ab8206f4a959a8c9054f55545e2dff42c Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 31 Oct 2016 17:19:54 +0800 Subject: ASoC: rt286: remove unnecessary selection in Kconfig SND_SOC_RT5663 is not required for SND_SOC_RT286. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..22aaf63616a2 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -672,7 +672,6 @@ config SND_SOC_RL6347A config SND_SOC_RT286 tristate - select SND_SOC_RT5663 depends on I2C config SND_SOC_RT298 -- cgit v1.2.3-59-g8ed1b From 4314f928f79f816367a4f09539aeebf7c5b4f5fa Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Mon, 31 Oct 2016 11:25:44 +0000 Subject: ASoC: lpass-platform: use dma_ch instead of rdma_ch/wrdma_ch This patch cleans up usage of wrdma_ch and rdma_ch variables into a common variable dma_ch, As there is no real use of tracking the dma channel in two different variables based on stream direction. Signed-off-by: Srinivas Kandagatla Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 46 ++++++++--------------------------------- 1 file changed, 9 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 07000f53db44..ca5e19f55a28 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -25,8 +25,7 @@ #include "lpass.h" struct lpass_pcm_data { - int rdma_ch; - int wrdma_ch; + int dma_ch; int i2s_port; }; @@ -91,10 +90,7 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) return ret; } - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - data->rdma_ch = dma_ch; - else - data->wrdma_ch = dma_ch; + data->dma_ch = dma_ch; snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware); @@ -121,20 +117,12 @@ static int lpass_platform_pcmops_close(struct snd_pcm_substream *substream) snd_soc_platform_get_drvdata(soc_runtime->platform); struct lpass_variant *v = drvdata->variant; struct lpass_pcm_data *data; - int dma_ch, dir = substream->stream; data = runtime->private_data; v = drvdata->variant; - - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - dma_ch = data->rdma_ch; - else - dma_ch = data->wrdma_ch; - - drvdata->substream[dma_ch] = NULL; - + drvdata->substream[data->dma_ch] = NULL; if (v->free_dma_channel) - v->free_dma_channel(drvdata, dma_ch); + v->free_dma_channel(drvdata, data->dma_ch); return 0; } @@ -155,10 +143,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream, int bitwidth; int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; bitwidth = snd_pcm_format_width(format); if (bitwidth < 0) { @@ -245,11 +230,7 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream) unsigned int reg; int ret; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg = LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch); - else - reg = LPAIF_WRDMACTL_REG(v, pcm_data->wrdma_ch); - + reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream); ret = regmap_write(drvdata->lpaif_map, reg, 0); if (ret) dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n", @@ -269,10 +250,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream) struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; ret = regmap_write(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), @@ -324,10 +302,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream, struct lpass_variant *v = drvdata->variant; int ret, ch, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -402,10 +377,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer( unsigned int base_addr, curr_addr; int ret, ch, dir = substream->stream; - if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ch = pcm_data->rdma_ch; - else - ch = pcm_data->wrdma_ch; + ch = pcm_data->dma_ch; ret = regmap_read(drvdata->lpaif_map, LPAIF_DMABASE_REG(v, ch, dir), &base_addr); -- cgit v1.2.3-59-g8ed1b From d8dbb4b327a84a7d373c8c4bf173bcab22f102ff Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Nov 2016 12:28:17 +0100 Subject: ASoC: samsung: pcm: Conversion to use devm_ioremap_resource() This simplifies the code a bit and removes a hard coded IO memory region size. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/pcm.c | 60 +++++++++++++------------------------------------ 1 file changed, 16 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index c484985812ed..d50a6377c23d 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c @@ -499,13 +499,6 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) pcm_pdata = pdev->dev.platform_data; - /* Check for availability of necessary resource */ - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem_res) { - dev_err(&pdev->dev, "Unable to get register resource\n"); - return -ENXIO; - } - if (pcm_pdata && pcm_pdata->cfg_gpio && pcm_pdata->cfg_gpio(pdev)) { dev_err(&pdev->dev, "Unable to configure gpio\n"); return -EINVAL; @@ -519,36 +512,26 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) /* Default is 128fs */ pcm->sclk_per_fs = 128; + mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pcm->regs = devm_ioremap_resource(&pdev->dev, mem_res); + if (IS_ERR(pcm->regs)) + return PTR_ERR(pcm->regs); + pcm->cclk = devm_clk_get(&pdev->dev, "audio-bus"); if (IS_ERR(pcm->cclk)) { - dev_err(&pdev->dev, "failed to get audio-bus\n"); - ret = PTR_ERR(pcm->cclk); - goto err1; + dev_err(&pdev->dev, "failed to get audio-bus clock\n"); + return PTR_ERR(pcm->cclk); } clk_prepare_enable(pcm->cclk); /* record our pcm structure for later use in the callbacks */ dev_set_drvdata(&pdev->dev, pcm); - if (!request_mem_region(mem_res->start, - resource_size(mem_res), "samsung-pcm")) { - dev_err(&pdev->dev, "Unable to request register region\n"); - ret = -EBUSY; - goto err2; - } - - pcm->regs = ioremap(mem_res->start, 0x100); - if (pcm->regs == NULL) { - dev_err(&pdev->dev, "cannot ioremap registers\n"); - ret = -ENXIO; - goto err3; - } - pcm->pclk = devm_clk_get(&pdev->dev, "pcm"); if (IS_ERR(pcm->pclk)) { - dev_err(&pdev->dev, "failed to get pcm_clock\n"); - ret = -ENOENT; - goto err4; + dev_err(&pdev->dev, "failed to get pcm clock\n"); + ret = PTR_ERR(pcm->pclk); + goto err_dis_cclk; } clk_prepare_enable(pcm->pclk); @@ -569,7 +552,7 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) NULL, NULL); if (ret) { dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); - goto err5; + goto err_dis_pclk; } pm_runtime_enable(&pdev->dev); @@ -578,36 +561,25 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) &s3c_pcm_dai[pdev->id], 1); if (ret != 0) { dev_err(&pdev->dev, "failed to get register DAI: %d\n", ret); - goto err6; + goto err_dis_pm; } return 0; -err6: + +err_dis_pm: pm_runtime_disable(&pdev->dev); -err5: +err_dis_pclk: clk_disable_unprepare(pcm->pclk); -err4: - iounmap(pcm->regs); -err3: - release_mem_region(mem_res->start, resource_size(mem_res)); -err2: +err_dis_cclk: clk_disable_unprepare(pcm->cclk); -err1: return ret; } static int s3c_pcm_dev_remove(struct platform_device *pdev) { struct s3c_pcm_info *pcm = &s3c_pcm[pdev->id]; - struct resource *mem_res; pm_runtime_disable(&pdev->dev); - - iounmap(pcm->regs); - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mem_res->start, resource_size(mem_res)); - clk_disable_unprepare(pcm->cclk); clk_disable_unprepare(pcm->pclk); -- cgit v1.2.3-59-g8ed1b From 5d3c1f633ea2984602bbbfe84e3e858050cb36f3 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Nov 2016 12:11:47 +0100 Subject: ASoC: samsung: s2c24xx-i2s: remove redundant error message There is no need to report the resource request error in the driver as it is already handled within devm_ioremap_resource(). While at it also drop a redundant variable initialization. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx-i2s.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 3b4bef9025a7..c93169823c7c 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -426,13 +426,9 @@ static const struct snd_soc_component_driver s3c24xx_i2s_component = { static int s3c24xx_iis_dev_probe(struct platform_device *pdev) { struct resource *res; - int ret = 0; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Can't get IO resource.\n"); - return -ENOENT; - } s3c24xx_i2s.regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(s3c24xx_i2s.regs)) return PTR_ERR(s3c24xx_i2s.regs); -- cgit v1.2.3-59-g8ed1b From a076d418235fc94030733b43114a4f1a0a3b4489 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Nov 2016 12:06:55 +0100 Subject: ASoC: samsung: Drop AC97 drivers The AC97 drivers are broken and it seems these have not been used for a long time. This patch removes the unused code, i.e. Samsung SoC AC97 controller driver and related machine drivers: ln2440sbc_alc650, smdk2443_wm9710, smdk_wm9713. Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 32 --- sound/soc/samsung/Makefile | 2 - sound/soc/samsung/ac97.c | 437 ----------------------------------- sound/soc/samsung/ln2440sbc_alc650.c | 72 ------ sound/soc/samsung/regs-ac97.h | 66 ------ sound/soc/samsung/smdk2443_wm9710.c | 68 ------ sound/soc/samsung/smdk_wm9713.c | 108 --------- 7 files changed, 785 deletions(-) delete mode 100644 sound/soc/samsung/ac97.c delete mode 100644 sound/soc/samsung/ln2440sbc_alc650.c delete mode 100644 sound/soc/samsung/regs-ac97.h delete mode 100644 sound/soc/samsung/smdk2443_wm9710.c delete mode 100644 sound/soc/samsung/smdk_wm9713.c (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index f6023b46c107..1d2ef4c2afd0 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -22,10 +22,6 @@ config SND_S3C2412_SOC_I2S config SND_SAMSUNG_PCM tristate "Samsung PCM interface support" -config SND_SAMSUNG_AC97 - tristate - select SND_SOC_AC97_BUS - config SND_SAMSUNG_SPDIF tristate "Samsung SPDIF transmitter support" select SND_SOC_SPDIF @@ -69,26 +65,6 @@ config SND_SOC_SAMSUNG_SMDK_WM8994 help Say Y if you want to add support for SoC audio on the SMDKs. -config SND_SOC_SAMSUNG_SMDK2443_WM9710 - tristate "SoC AC97 Audio support for SMDK2443 - WM9710" - depends on MACH_SMDK2443 - select AC97_BUS - select SND_SOC_AC97_CODEC - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on smdk2443 - with the WM9710. - -config SND_SOC_SAMSUNG_LN2440SBC_ALC650 - tristate "SoC AC97 Audio support for LN2440SBC - ALC650" - depends on ARCH_S3C24XX - select AC97_BUS - select SND_SOC_AC97_CODEC - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on ln2440sbc - with the ALC650. - config SND_SOC_SAMSUNG_S3C24XX_UDA134X tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" depends on ARCH_S3C24XX @@ -131,14 +107,6 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 help This driver provides audio support for HP iPAQ RX1950 PDA. -config SND_SOC_SAMSUNG_SMDK_WM9713 - tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 - select SND_SOC_WM9713 - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on the SMDK. - config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" depends on MACH_SMARTQ && I2C diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 5d03f5ce6916..f3f4a32cd376 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -3,7 +3,6 @@ snd-soc-s3c-dma-objs := dmaengine.o snd-soc-idma-objs := idma.o snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o -snd-soc-ac97-objs := ac97.o snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o snd-soc-samsung-spdif-objs := spdif.o snd-soc-pcm-objs := pcm.o @@ -11,7 +10,6 @@ snd-soc-i2s-objs := i2s.o obj-$(CONFIG_SND_SOC_SAMSUNG) += snd-soc-s3c-dma.o obj-$(CONFIG_SND_S3C24XX_I2S) += snd-soc-s3c24xx-i2s.o -obj-$(CONFIG_SND_SAMSUNG_AC97) += snd-soc-ac97.o obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o obj-$(CONFIG_SND_SAMSUNG_SPDIF) += snd-soc-samsung-spdif.o diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c deleted file mode 100644 index cbc0023c2bc8..000000000000 --- a/sound/soc/samsung/ac97.c +++ /dev/null @@ -1,437 +0,0 @@ -/* sound/soc/samsung/ac97.c - * - * ALSA SoC Audio Layer - S3C AC97 Controller driver - * Evolved from s3c2443-ac97.c - * - * Copyright (c) 2010 Samsung Electronics Co. Ltd - * Author: Jaswinder Singh - * Credits: Graeme Gregory, Sean Choi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include - -#include "regs-ac97.h" -#include - -#include "dma.h" - -#define AC_CMD_ADDR(x) (x << 16) -#define AC_CMD_DATA(x) (x & 0xffff) - -#define S3C_AC97_DAI_PCM 0 -#define S3C_AC97_DAI_MIC 1 - -struct s3c_ac97_info { - struct clk *ac97_clk; - void __iomem *regs; - struct mutex lock; - struct completion done; -}; -static struct s3c_ac97_info s3c_ac97; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_out = { - .addr_width = 4, -}; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_pcm_in = { - .addr_width = 4, -}; - -static struct snd_dmaengine_dai_dma_data s3c_ac97_mic_in = { - .addr_width = 4, -}; - -static void s3c_ac97_activate(struct snd_ac97 *ac97) -{ - u32 ac_glbctrl, stat; - - stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; - if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) - return; /* Return if already active */ - - reinit_completion(&s3c_ac97.done); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl = S3C_AC97_GLBCTRL_ACLINKON; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl |= S3C_AC97_GLBCTRL_TRANSFERDATAENABLE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to activate!\n"); -} - -static unsigned short s3c_ac97_read(struct snd_ac97 *ac97, - unsigned short reg) -{ - u32 ac_glbctrl, ac_codec_cmd; - u32 stat, addr, data; - - mutex_lock(&s3c_ac97.lock); - - s3c_ac97_activate(ac97); - - reinit_completion(&s3c_ac97.done); - - ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd = S3C_AC97_CODEC_CMD_READ | AC_CMD_ADDR(reg); - writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - - udelay(50); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to read!\n"); - - stat = readl(s3c_ac97.regs + S3C_AC97_STAT); - addr = (stat >> 16) & 0x7f; - data = (stat & 0xffff); - - if (addr != reg) - pr_err("ac97: req addr = %02x, rep addr = %02x\n", - reg, addr); - - mutex_unlock(&s3c_ac97.lock); - - return (unsigned short)data; -} - -static void s3c_ac97_write(struct snd_ac97 *ac97, unsigned short reg, - unsigned short val) -{ - u32 ac_glbctrl, ac_codec_cmd; - - mutex_lock(&s3c_ac97.lock); - - s3c_ac97_activate(ac97); - - reinit_completion(&s3c_ac97.done); - - ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd = AC_CMD_ADDR(reg) | AC_CMD_DATA(val); - writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - - udelay(50); - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - if (!wait_for_completion_timeout(&s3c_ac97.done, HZ)) - pr_err("AC97: Unable to write!\n"); - - ac_codec_cmd = readl(s3c_ac97.regs + S3C_AC97_CODEC_CMD); - ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; - writel(ac_codec_cmd, s3c_ac97.regs + S3C_AC97_CODEC_CMD); - - mutex_unlock(&s3c_ac97.lock); -} - -static void s3c_ac97_cold_reset(struct snd_ac97 *ac97) -{ - pr_debug("AC97: Cold reset\n"); - writel(S3C_AC97_GLBCTRL_COLDRESET, - s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); -} - -static void s3c_ac97_warm_reset(struct snd_ac97 *ac97) -{ - u32 stat; - - stat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT) & 0x7; - if (stat == S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE) - return; /* Return if already active */ - - pr_debug("AC97: Warm reset\n"); - - writel(S3C_AC97_GLBCTRL_WARMRESET, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - writel(0, s3c_ac97.regs + S3C_AC97_GLBCTRL); - msleep(1); - - s3c_ac97_activate(ac97); -} - -static irqreturn_t s3c_ac97_irq(int irq, void *dev_id) -{ - u32 ac_glbctrl, ac_glbstat; - - ac_glbstat = readl(s3c_ac97.regs + S3C_AC97_GLBSTAT); - - if (ac_glbstat & S3C_AC97_GLBSTAT_CODECREADY) { - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl &= ~S3C_AC97_GLBCTRL_CODECREADYIE; - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - complete(&s3c_ac97.done); - } - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl |= (1<<30); /* Clear interrupt */ - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - return IRQ_HANDLED; -} - -static struct snd_ac97_bus_ops s3c_ac97_ops = { - .read = s3c_ac97_read, - .write = s3c_ac97_write, - .warm_reset = s3c_ac97_warm_reset, - .reset = s3c_ac97_cold_reset, -}; - -static int s3c_ac97_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - u32 ac_glbctrl; - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMINTM_MASK; - else - ac_glbctrl &= ~S3C_AC97_GLBCTRL_PCMOUTTM_MASK; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMINTM_DMA; - else - ac_glbctrl |= S3C_AC97_GLBCTRL_PCMOUTTM_DMA; - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - break; - } - - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - return 0; -} - -static int s3c_ac97_mic_trigger(struct snd_pcm_substream *substream, - int cmd, struct snd_soc_dai *dai) -{ - u32 ac_glbctrl; - - ac_glbctrl = readl(s3c_ac97.regs + S3C_AC97_GLBCTRL); - ac_glbctrl &= ~S3C_AC97_GLBCTRL_MICINTM_MASK; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ac_glbctrl |= S3C_AC97_GLBCTRL_MICINTM_DMA; - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - break; - } - - writel(ac_glbctrl, s3c_ac97.regs + S3C_AC97_GLBCTRL); - - return 0; -} - -static const struct snd_soc_dai_ops s3c_ac97_dai_ops = { - .trigger = s3c_ac97_trigger, -}; - -static const struct snd_soc_dai_ops s3c_ac97_mic_dai_ops = { - .trigger = s3c_ac97_mic_trigger, -}; - -static int s3c_ac97_dai_probe(struct snd_soc_dai *dai) -{ - snd_soc_dai_init_dma_data(dai, &s3c_ac97_pcm_out, &s3c_ac97_pcm_in); - - return 0; -} - -static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) -{ - snd_soc_dai_init_dma_data(dai, NULL, &s3c_ac97_mic_in); - - return 0; -} - -static struct snd_soc_dai_driver s3c_ac97_dai[] = { - [S3C_AC97_DAI_PCM] = { - .name = "samsung-ac97", - .bus_control = true, - .playback = { - .stream_name = "AC97 Playback", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .capture = { - .stream_name = "AC97 Capture", - .channels_min = 2, - .channels_max = 2, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .probe = s3c_ac97_dai_probe, - .ops = &s3c_ac97_dai_ops, - }, - [S3C_AC97_DAI_MIC] = { - .name = "samsung-ac97-mic", - .bus_control = true, - .capture = { - .stream_name = "AC97 Mic Capture", - .channels_min = 1, - .channels_max = 1, - .rates = SNDRV_PCM_RATE_8000_48000, - .formats = SNDRV_PCM_FMTBIT_S16_LE,}, - .probe = s3c_ac97_mic_dai_probe, - .ops = &s3c_ac97_mic_dai_ops, - }, -}; - -static const struct snd_soc_component_driver s3c_ac97_component = { - .name = "s3c-ac97", -}; - -static int s3c_ac97_probe(struct platform_device *pdev) -{ - struct resource *mem_res, *irq_res; - struct s3c_audio_pdata *ac97_pdata; - int ret; - - ac97_pdata = pdev->dev.platform_data; - if (!ac97_pdata || !ac97_pdata->cfg_gpio) { - dev_err(&pdev->dev, "cfg_gpio callback not provided!\n"); - return -EINVAL; - } - - /* Check for availability of necessary resource */ - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq_res) { - dev_err(&pdev->dev, "AC97 IRQ not provided!\n"); - return -ENXIO; - } - - mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - s3c_ac97.regs = devm_ioremap_resource(&pdev->dev, mem_res); - if (IS_ERR(s3c_ac97.regs)) - return PTR_ERR(s3c_ac97.regs); - - s3c_ac97_pcm_out.filter_data = ac97_pdata->dma_playback; - s3c_ac97_pcm_out.addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_pcm_in.filter_data = ac97_pdata->dma_capture; - s3c_ac97_pcm_in.addr = mem_res->start + S3C_AC97_PCM_DATA; - s3c_ac97_mic_in.filter_data = ac97_pdata->dma_capture_mic; - s3c_ac97_mic_in.addr = mem_res->start + S3C_AC97_MIC_DATA; - - init_completion(&s3c_ac97.done); - mutex_init(&s3c_ac97.lock); - - s3c_ac97.ac97_clk = devm_clk_get(&pdev->dev, "ac97"); - if (IS_ERR(s3c_ac97.ac97_clk)) { - dev_err(&pdev->dev, "ac97 failed to get ac97_clock\n"); - ret = -ENODEV; - goto err2; - } - clk_prepare_enable(s3c_ac97.ac97_clk); - - if (ac97_pdata->cfg_gpio(pdev)) { - dev_err(&pdev->dev, "Unable to configure gpio\n"); - ret = -EINVAL; - goto err3; - } - - ret = request_irq(irq_res->start, s3c_ac97_irq, - 0, "AC97", NULL); - if (ret < 0) { - dev_err(&pdev->dev, "ac97: interrupt request failed.\n"); - goto err4; - } - - ret = snd_soc_set_ac97_ops(&s3c_ac97_ops); - if (ret != 0) { - dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret); - goto err4; - } - - ret = samsung_asoc_dma_platform_register(&pdev->dev, - ac97_pdata->dma_filter, - NULL, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); - goto err5; - } - - ret = devm_snd_soc_register_component(&pdev->dev, &s3c_ac97_component, - s3c_ac97_dai, ARRAY_SIZE(s3c_ac97_dai)); - if (ret) - goto err5; - - return 0; -err5: - free_irq(irq_res->start, NULL); -err4: -err3: - clk_disable_unprepare(s3c_ac97.ac97_clk); -err2: - snd_soc_set_ac97_ops(NULL); - return ret; -} - -static int s3c_ac97_remove(struct platform_device *pdev) -{ - struct resource *irq_res; - - irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (irq_res) - free_irq(irq_res->start, NULL); - - clk_disable_unprepare(s3c_ac97.ac97_clk); - snd_soc_set_ac97_ops(NULL); - - return 0; -} - -static struct platform_driver s3c_ac97_driver = { - .probe = s3c_ac97_probe, - .remove = s3c_ac97_remove, - .driver = { - .name = "samsung-ac97", - }, -}; - -module_platform_driver(s3c_ac97_driver); - -MODULE_AUTHOR("Jaswinder Singh, "); -MODULE_DESCRIPTION("AC97 driver for the Samsung SoC"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:samsung-ac97"); diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c deleted file mode 100644 index 9342fc270c2b..000000000000 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * SoC audio for ln2440sbc - * - * Copyright 2007 KonekTel, a.s. - * Author: Ivan Kuten - * ivan.kuten@promwad.com - * - * Heavily based on smdk2443_wm9710.c - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ - -#include -#include - -static struct snd_soc_card ln2440sbc; - -static struct snd_soc_dai_link ln2440sbc_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai_name = "samsung-ac97", - .codec_dai_name = "ac97-hifi", - .codec_name = "ac97-codec", - .platform_name = "samsung-ac97", -}, -}; - -static struct snd_soc_card ln2440sbc = { - .name = "LN2440SBC", - .owner = THIS_MODULE, - .dai_link = ln2440sbc_dai, - .num_links = ARRAY_SIZE(ln2440sbc_dai), -}; - -static struct platform_device *ln2440sbc_snd_ac97_device; - -static int __init ln2440sbc_init(void) -{ - int ret; - - ln2440sbc_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!ln2440sbc_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(ln2440sbc_snd_ac97_device, &ln2440sbc); - ret = platform_device_add(ln2440sbc_snd_ac97_device); - - if (ret) - platform_device_put(ln2440sbc_snd_ac97_device); - - return ret; -} - -static void __exit ln2440sbc_exit(void) -{ - platform_device_unregister(ln2440sbc_snd_ac97_device); -} - -module_init(ln2440sbc_init); -module_exit(ln2440sbc_exit); - -/* Module information */ -MODULE_AUTHOR("Ivan Kuten"); -MODULE_DESCRIPTION("ALSA SoC ALC650 LN2440SBC"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/regs-ac97.h b/sound/soc/samsung/regs-ac97.h deleted file mode 100644 index a71be45bbffc..000000000000 --- a/sound/soc/samsung/regs-ac97.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2006 Simtec Electronics - * http://www.simtec.co.uk/products/SWLINUX/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * S3C2440 AC97 Controller -*/ - -#ifndef __SAMSUNG_REGS_AC97_H__ -#define __SAMSUNG_REGS_AC97_H__ - -#define S3C_AC97_GLBCTRL (0x00) - -#define S3C_AC97_GLBCTRL_CODECREADYIE (1<<22) -#define S3C_AC97_GLBCTRL_PCMOUTURIE (1<<21) -#define S3C_AC97_GLBCTRL_PCMINORIE (1<<20) -#define S3C_AC97_GLBCTRL_MICINORIE (1<<19) -#define S3C_AC97_GLBCTRL_PCMOUTTIE (1<<18) -#define S3C_AC97_GLBCTRL_PCMINTIE (1<<17) -#define S3C_AC97_GLBCTRL_MICINTIE (1<<16) -#define S3C_AC97_GLBCTRL_PCMOUTTM_OFF (0<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_PIO (1<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_DMA (2<<12) -#define S3C_AC97_GLBCTRL_PCMOUTTM_MASK (3<<12) -#define S3C_AC97_GLBCTRL_PCMINTM_OFF (0<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_PIO (1<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_DMA (2<<10) -#define S3C_AC97_GLBCTRL_PCMINTM_MASK (3<<10) -#define S3C_AC97_GLBCTRL_MICINTM_OFF (0<<8) -#define S3C_AC97_GLBCTRL_MICINTM_PIO (1<<8) -#define S3C_AC97_GLBCTRL_MICINTM_DMA (2<<8) -#define S3C_AC97_GLBCTRL_MICINTM_MASK (3<<8) -#define S3C_AC97_GLBCTRL_TRANSFERDATAENABLE (1<<3) -#define S3C_AC97_GLBCTRL_ACLINKON (1<<2) -#define S3C_AC97_GLBCTRL_WARMRESET (1<<1) -#define S3C_AC97_GLBCTRL_COLDRESET (1<<0) - -#define S3C_AC97_GLBSTAT (0x04) - -#define S3C_AC97_GLBSTAT_CODECREADY (1<<22) -#define S3C_AC97_GLBSTAT_PCMOUTUR (1<<21) -#define S3C_AC97_GLBSTAT_PCMINORI (1<<20) -#define S3C_AC97_GLBSTAT_MICINORI (1<<19) -#define S3C_AC97_GLBSTAT_PCMOUTTI (1<<18) -#define S3C_AC97_GLBSTAT_PCMINTI (1<<17) -#define S3C_AC97_GLBSTAT_MICINTI (1<<16) -#define S3C_AC97_GLBSTAT_MAINSTATE_IDLE (0<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_INIT (1<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_READY (2<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_ACTIVE (3<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_LP (4<<0) -#define S3C_AC97_GLBSTAT_MAINSTATE_WARM (5<<0) - -#define S3C_AC97_CODEC_CMD (0x08) - -#define S3C_AC97_CODEC_CMD_READ (1<<23) - -#define S3C_AC97_STAT (0x0c) -#define S3C_AC97_PCM_ADDR (0x10) -#define S3C_AC97_PCM_DATA (0x18) -#define S3C_AC97_MIC_DATA (0x1C) - -#endif /* __SAMSUNG_REGS_AC97_H__ */ diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c deleted file mode 100644 index c390aad68cfb..000000000000 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * smdk2443_wm9710.c -- SoC audio for smdk2443 - * - * Copyright 2007 Wolfson Microelectronics PLC. - * Author: Graeme Gregory - * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#include -#include - -static struct snd_soc_card smdk2443; - -static struct snd_soc_dai_link smdk2443_dai[] = { -{ - .name = "AC97", - .stream_name = "AC97 HiFi", - .cpu_dai_name = "samsung-ac97", - .codec_dai_name = "ac97-hifi", - .codec_name = "ac97-codec", - .platform_name = "samsung-ac97", -}, -}; - -static struct snd_soc_card smdk2443 = { - .name = "SMDK2443", - .owner = THIS_MODULE, - .dai_link = smdk2443_dai, - .num_links = ARRAY_SIZE(smdk2443_dai), -}; - -static struct platform_device *smdk2443_snd_ac97_device; - -static int __init smdk2443_init(void) -{ - int ret; - - smdk2443_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!smdk2443_snd_ac97_device) - return -ENOMEM; - - platform_set_drvdata(smdk2443_snd_ac97_device, &smdk2443); - ret = platform_device_add(smdk2443_snd_ac97_device); - - if (ret) - platform_device_put(smdk2443_snd_ac97_device); - - return ret; -} - -static void __exit smdk2443_exit(void) -{ - platform_device_unregister(smdk2443_snd_ac97_device); -} - -module_init(smdk2443_init); -module_exit(smdk2443_exit); - -/* Module information */ -MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com"); -MODULE_DESCRIPTION("ALSA SoC WM9710 SMDK2443"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c deleted file mode 100644 index 0d20e4ed27aa..000000000000 --- a/sound/soc/samsung/smdk_wm9713.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * smdk_wm9713.c -- SoC audio for SMDK - * - * Copyright 2010 Samsung Electronics Co. Ltd. - * Author: Jaswinder Singh Brar - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - */ - -#include -#include - -static struct snd_soc_card smdk; - -/* - * Default CFG switch settings to use this driver: - * - * SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off - * SMDKC100: Set CFG6 1-3 On, CFG7 1 On - * SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On - * SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On - * SMDKV310: Set CFG2 1-2 Off, CFG4 All On, CFG7 All Off, CFG8 1-On - */ - -/* - Playback (HeadPhone):- - $ amixer sset 'Headphone' unmute - $ amixer sset 'Right Headphone Out Mux' 'Headphone' - $ amixer sset 'Left Headphone Out Mux' 'Headphone' - $ amixer sset 'Right HP Mixer PCM' unmute - $ amixer sset 'Left HP Mixer PCM' unmute - - Capture (LineIn):- - $ amixer sset 'Right Capture Source' 'Line' - $ amixer sset 'Left Capture Source' 'Line' -*/ - -static struct snd_soc_dai_link smdk_dai = { - .name = "AC97", - .stream_name = "AC97 PCM", - .platform_name = "samsung-ac97", - .cpu_dai_name = "samsung-ac97", - .codec_dai_name = "wm9713-hifi", - .codec_name = "wm9713-codec", -}; - -static struct snd_soc_card smdk = { - .name = "SMDK WM9713", - .owner = THIS_MODULE, - .dai_link = &smdk_dai, - .num_links = 1, -}; - -static struct platform_device *smdk_snd_wm9713_device; -static struct platform_device *smdk_snd_ac97_device; - -static int __init smdk_init(void) -{ - int ret; - - smdk_snd_wm9713_device = platform_device_alloc("wm9713-codec", -1); - if (!smdk_snd_wm9713_device) - return -ENOMEM; - - ret = platform_device_add(smdk_snd_wm9713_device); - if (ret) - goto err1; - - smdk_snd_ac97_device = platform_device_alloc("soc-audio", -1); - if (!smdk_snd_ac97_device) { - ret = -ENOMEM; - goto err2; - } - - platform_set_drvdata(smdk_snd_ac97_device, &smdk); - - ret = platform_device_add(smdk_snd_ac97_device); - if (ret) - goto err3; - - return 0; - -err3: - platform_device_put(smdk_snd_ac97_device); -err2: - platform_device_del(smdk_snd_wm9713_device); -err1: - platform_device_put(smdk_snd_wm9713_device); - return ret; -} - -static void __exit smdk_exit(void) -{ - platform_device_unregister(smdk_snd_ac97_device); - platform_device_unregister(smdk_snd_wm9713_device); -} - -module_init(smdk_init); -module_exit(smdk_exit); - -/* Module information */ -MODULE_AUTHOR("Jaswinder Singh Brar, jassisinghbrar@gmail.com"); -MODULE_DESCRIPTION("ALSA SoC SMDK+WM9713"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 6c9473c55e7bb93dd4086f74e8e727dd3350855d Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Nov 2016 12:04:36 +0100 Subject: ASoC: samsung: s3c24xx-i2s.c merge fixup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a build error as below which appeared after merging branch fix/samsung and also proper error messages are restored. sound/soc/samsung/s3c24xx-i2s.c: In function ‘s3c24xx_iis_dev_probe’: sound/soc/samsung/s3c24xx-i2s.c:444:8: error: ‘pdata’ undeclared (first use in this function) sound/soc/samsung/s3c24xx-i2s.c:444:8: note: each undeclared identifier is reported only once for each function it appears in Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/s3c24xx-i2s.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index c93169823c7c..07f5091b33e8 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c @@ -436,18 +436,17 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) s3c24xx_i2s_pcm_stereo_out.addr = res->start + S3C2410_IISFIFO; s3c24xx_i2s_pcm_stereo_in.addr = res->start + S3C2410_IISFIFO; - ret = samsung_asoc_dma_platform_register(&pdev->dev, - pdata->dma_filter, + ret = samsung_asoc_dma_platform_register(&pdev->dev, NULL, NULL, NULL); if (ret) { - dev_err(&pdev->dev, "Failed to register the DAI\n"); + dev_err(&pdev->dev, "Failed to register the DMA: %d\n", ret); return ret; } ret = devm_snd_soc_register_component(&pdev->dev, &s3c24xx_i2s_component, &s3c24xx_i2s_dai, 1); if (ret) - pr_err("failed to register the dai\n"); + dev_err(&pdev->dev, "Failed to register the DAI\n"); return ret; } -- cgit v1.2.3-59-g8ed1b From e411b0b5eb9b65257a050eac333d181d6e00e2c6 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 2 Nov 2016 15:35:58 +0800 Subject: ASoC: dapm: Support second register for DAPM control updates To support double channel shared controls split across 2 registers, one for each channel, we must be able to update both registers together. Add a second set of register fields to struct snd_soc_dapm_update, and update the DAPM control writeback (put) callbacks to support this. For codecs that use custom events which call into DAPM to do updates, also clear struct snd_soc_dapm_update before using it, so the second set of fields remains clean. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 4 ++++ sound/soc/codecs/adau17x1.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/wm9712.c | 2 +- sound/soc/codecs/wm9713.c | 2 +- sound/soc/soc-dapm.c | 13 +++++++++++-- 6 files changed, 19 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index f60d755f7ac6..d5f4677776ce 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -615,6 +615,10 @@ struct snd_soc_dapm_update { int reg; int mask; int val; + int reg2; + int mask2; + int val2; + bool has_second_set; }; struct snd_soc_dapm_wcache { diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 439aa3ff1f99..b36511d965c8 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -160,7 +160,7 @@ static int adau17x1_dsp_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct adau *adau = snd_soc_codec_get_drvdata(codec); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; unsigned int stream = e->shift_l; unsigned int val, change; int reg; diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5a8d96ec058c..8877b74b0510 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -157,7 +157,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol, unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; unsigned short val; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; int connect, change; val = (ucontrol->value.integer.value[0] & mask); diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 557709eac698..85f7c5bb8b82 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -187,7 +187,7 @@ static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mixer, mask, shift, old; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; bool change; mixer = mc->shift >> 8; diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index e4301ddb1b84..7e4822185feb 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -231,7 +231,7 @@ static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; unsigned int mixer, mask, shift, old; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { 0 }; bool change; mixer = mc->shift >> 8; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 3bbe32ee4630..32e7af9b93d5 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -1626,6 +1626,15 @@ static void dapm_widget_update(struct snd_soc_card *card) dev_err(w->dapm->dev, "ASoC: %s DAPM update failed: %d\n", w->name, ret); + if (update->has_second_set) { + ret = soc_dapm_update_bits(w->dapm, update->reg2, + update->mask2, update->val2); + if (ret < 0) + dev_err(w->dapm->dev, + "ASoC: %s DAPM update failed: %d\n", + w->name, ret); + } + for (wi = 0; wi < wlist->num_widgets; wi++) { w = wlist->widgets[wi]; @@ -3084,7 +3093,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, unsigned int invert = mc->invert; unsigned int val; int connect, change, reg_change = 0; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { NULL }; int ret = 0; if (snd_soc_volsw_is_stereo(mc)) @@ -3192,7 +3201,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, unsigned int *item = ucontrol->value.enumerated.item; unsigned int val, change, reg_change = 0; unsigned int mask; - struct snd_soc_dapm_update update; + struct snd_soc_dapm_update update = { NULL }; int ret = 0; if (item[0] >= e->items) -- cgit v1.2.3-59-g8ed1b From e7aa450fe17890e59db7d3c2d8eff5b6b41fc531 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Wed, 2 Nov 2016 15:35:59 +0800 Subject: ASoC: dapm: Implement stereo mixer control support While DAPM is mono or single channel, its controls can be shared between widgets, such as sharing one stereo mixer control between the left and right channel widgets. An example such as the following routes [Line In Left]-----------------[Left Mixer] ^ ^ ^ | ^ (inputs) (paths) (outputs) v v | v v [Line In Right]----------------[Right Mixer] where we have separate widgets and paths for the left and right channels from "Line In" to "Mixer", but a shared stereo mixer control for the 2 paths. This patch introduces support for such shared mixer controls, allowing more than 1 path to be attached to a single stereo control, and being able to control left/right channels independently. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 141 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 112 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 32e7af9b93d5..27dd02e57b31 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -330,6 +330,11 @@ static int dapm_kcontrol_data_alloc(struct snd_soc_dapm_widget *widget, case snd_soc_dapm_mixer_named_ctl: mc = (struct soc_mixer_control *)kcontrol->private_value; + if (mc->autodisable && snd_soc_volsw_is_stereo(mc)) + dev_warn(widget->dapm->dev, + "ASoC: Unsupported stereo autodisable control '%s'\n", + ctrl_name); + if (mc->autodisable) { struct snd_soc_dapm_widget template; @@ -723,7 +728,8 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, } /* set up initial codec paths */ -static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) +static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i, + int nth_path) { struct soc_mixer_control *mc = (struct soc_mixer_control *) p->sink->kcontrol_news[i].private_value; @@ -736,7 +742,25 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) if (reg != SND_SOC_NOPM) { soc_dapm_read(p->sink->dapm, reg, &val); - val = (val >> shift) & mask; + /* + * The nth_path argument allows this function to know + * which path of a kcontrol it is setting the initial + * status for. Ideally this would support any number + * of paths and channels. But since kcontrols only come + * in mono and stereo variants, we are limited to 2 + * channels. + * + * The following code assumes for stereo controls the + * first path is the left channel, and all remaining + * paths are the right channel. + */ + if (snd_soc_volsw_is_stereo(mc) && nth_path > 0) { + if (reg != mc->rreg) + soc_dapm_read(p->sink->dapm, mc->rreg, &val); + val = (val >> mc->rshift) & mask; + } else { + val = (val >> shift) & mask; + } if (invert) val = max - val; p->connect = !!val; @@ -749,13 +773,13 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, struct snd_soc_dapm_path *path, const char *control_name) { - int i; + int i, nth_path = 0; /* search for mixer kcontrol */ for (i = 0; i < path->sink->num_kcontrols; i++) { if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { path->name = path->sink->kcontrol_news[i].name; - dapm_set_mixer_path_status(path, i); + dapm_set_mixer_path_status(path, i, nth_path++); return 0; } } @@ -2186,7 +2210,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, - struct snd_kcontrol *kcontrol, int connect) + struct snd_kcontrol *kcontrol, + int connect, int rconnect) { struct snd_soc_dapm_path *path; int found = 0; @@ -2195,8 +2220,33 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, /* find dapm widget path assoc with kcontrol */ dapm_kcontrol_for_each_path(path, kcontrol) { + /* + * Ideally this function should support any number of + * paths and channels. But since kcontrols only come + * in mono and stereo variants, we are limited to 2 + * channels. + * + * The following code assumes for stereo controls the + * first path (when 'found == 0') is the left channel, + * and all remaining paths (when 'found == 1') are the + * right channel. + * + * A stereo control is signified by a valid 'rconnect' + * value, either 0 for unconnected, or >= 0 for connected. + * This is chosen instead of using snd_soc_volsw_is_stereo, + * so that the behavior of snd_soc_dapm_mixer_update_power + * doesn't change even when the kcontrol passed in is + * stereo. + * + * It passes 'connect' as the path connect status for + * the left channel, and 'rconnect' for the right + * channel. + */ + if (found && rconnect >= 0) + soc_dapm_connect_path(path, rconnect, "mixer update"); + else + soc_dapm_connect_path(path, connect, "mixer update"); found = 1; - soc_dapm_connect_path(path, connect, "mixer update"); } if (found) @@ -2214,7 +2264,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); card->update = update; - ret = soc_dapm_mixer_update_power(card, kcontrol, connect); + ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1); card->update = NULL; mutex_unlock(&card->dapm_mutex); if (ret > 0) @@ -3039,22 +3089,28 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; + unsigned int width = fls(max); unsigned int mask = (1 << fls(max)) - 1; unsigned int invert = mc->invert; - unsigned int val; + unsigned int reg_val, val, rval = 0; int ret = 0; - if (snd_soc_volsw_is_stereo(mc)) - dev_warn(dapm->dev, - "ASoC: Control '%s' is stereo, which is not supported\n", - kcontrol->id.name); - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); if (dapm_kcontrol_is_powered(kcontrol) && reg != SND_SOC_NOPM) { - ret = soc_dapm_read(dapm, reg, &val); - val = (val >> shift) & mask; + ret = soc_dapm_read(dapm, reg, ®_val); + val = (reg_val >> shift) & mask; + + if (ret == 0 && reg != mc->rreg) + ret = soc_dapm_read(dapm, mc->rreg, ®_val); + + if (snd_soc_volsw_is_stereo(mc)) + rval = (reg_val >> mc->rshift) & mask; } else { - val = dapm_kcontrol_get_value(kcontrol); + reg_val = dapm_kcontrol_get_value(kcontrol); + val = reg_val & mask; + + if (snd_soc_volsw_is_stereo(mc)) + rval = (reg_val >> width) & mask; } mutex_unlock(&card->dapm_mutex); @@ -3066,6 +3122,13 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, else ucontrol->value.integer.value[0] = val; + if (snd_soc_volsw_is_stereo(mc)) { + if (invert) + ucontrol->value.integer.value[1] = max - rval; + else + ucontrol->value.integer.value[1] = rval; + } + return ret; } EXPORT_SYMBOL_GPL(snd_soc_dapm_get_volsw); @@ -3089,46 +3152,66 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, int reg = mc->reg; unsigned int shift = mc->shift; int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; + unsigned int width = fls(max); + unsigned int mask = (1 << width) - 1; unsigned int invert = mc->invert; - unsigned int val; - int connect, change, reg_change = 0; + unsigned int val, rval = 0; + int connect, rconnect = -1, change, reg_change = 0; struct snd_soc_dapm_update update = { NULL }; int ret = 0; - if (snd_soc_volsw_is_stereo(mc)) - dev_warn(dapm->dev, - "ASoC: Control '%s' is stereo, which is not supported\n", - kcontrol->id.name); - val = (ucontrol->value.integer.value[0] & mask); connect = !!val; if (invert) val = max - val; + if (snd_soc_volsw_is_stereo(mc)) { + rval = (ucontrol->value.integer.value[1] & mask); + rconnect = !!rval; + if (invert) + rval = max - rval; + } + mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - change = dapm_kcontrol_set_value(kcontrol, val); + /* This assumes field width < (bits in unsigned int / 2) */ + if (width > sizeof(unsigned int) * 8 / 2) + dev_warn(dapm->dev, + "ASoC: control %s field width limit exceeded\n", + kcontrol->id.name); + change = dapm_kcontrol_set_value(kcontrol, val | (rval << width)); if (reg != SND_SOC_NOPM) { - mask = mask << shift; val = val << shift; + rval = rval << mc->rshift; + + reg_change = soc_dapm_test_bits(dapm, reg, mask << shift, val); - reg_change = soc_dapm_test_bits(dapm, reg, mask, val); + if (snd_soc_volsw_is_stereo(mc)) + reg_change |= soc_dapm_test_bits(dapm, mc->rreg, + mask << mc->rshift, + rval); } if (change || reg_change) { if (reg_change) { + if (snd_soc_volsw_is_stereo(mc)) { + update.has_second_set = true; + update.reg2 = mc->rreg; + update.mask2 = mask << mc->rshift; + update.val2 = rval; + } update.kcontrol = kcontrol; update.reg = reg; - update.mask = mask; + update.mask = mask << shift; update.val = val; card->update = &update; } change |= reg_change; - ret = soc_dapm_mixer_update_power(card, kcontrol, connect); + ret = soc_dapm_mixer_update_power(card, kcontrol, connect, + rconnect); card->update = NULL; } -- cgit v1.2.3-59-g8ed1b From fe3683779e0b20edf91c549bbff0d81785e1c7a0 Mon Sep 17 00:00:00 2001 From: Scott Branden Date: Wed, 2 Nov 2016 13:43:24 -0700 Subject: ASoC: bcm: add depends on HAS_DMA add depends on HAS_DMA to Kconfig. This fixes error reported by kbuild test robot when building for ARCH=m32r: ERROR: "bad_dma_ops" [sound/soc/bcm/snd-soc-cygnus.ko] undefined! Signed-off-by: Scott Branden Signed-off-by: Mark Brown --- sound/soc/bcm/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index d528aaceaad9..edf367100ebd 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig @@ -11,6 +11,7 @@ config SND_BCM2835_SOC_I2S config SND_SOC_CYGNUS tristate "SoC platform audio for Broadcom Cygnus chips" depends on ARCH_BCM_CYGNUS || COMPILE_TEST + depends on HAS_DMA help Say Y if you want to add support for ASoC audio on Broadcom Cygnus chips (bcm958300, bcm958305, bcm911360) -- cgit v1.2.3-59-g8ed1b From 55726dc95b78da32454878ac2b8a76daa53db396 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:00:16 +0800 Subject: ASoC: topology: Make PCM backward compatible from ABI v4 This patch adds support for old version 4 of PCMs (FE DAI & DAI links). Topology ABI v5 added new fields to stream caps and thus changed PCMs. Since user space may still uses v4, kernel will check the ABI version by comparing the object size. If user space uses v4 of PCMs, kernel will create the latest version of PCMs from the old version, and use the new version internally to create FE DAI & DAI links. Because these new created PCM elements will be freed later, kernel need duplicate the name strings of DAI driver and DAI links when creating them. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 145 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 133 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index c832b24b0cde..03edde57bfea 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -53,7 +53,6 @@ #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST #define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI - /* * Old version of ABI structs, supported for backward compatibility. */ @@ -69,6 +68,39 @@ struct snd_soc_tplg_manifest_v4 { struct snd_soc_tplg_private priv; } __packed; +/* Stream Capabilities v4 */ +struct snd_soc_tplg_stream_caps_v4 { + __le32 size; /* in bytes of this structure */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le64 formats; /* supported formats SNDRV_PCM_FMTBIT_* */ + __le32 rates; /* supported rates SNDRV_PCM_RATE_* */ + __le32 rate_min; /* min rate */ + __le32 rate_max; /* max rate */ + __le32 channels_min; /* min channels */ + __le32 channels_max; /* max channels */ + __le32 periods_min; /* min number of periods */ + __le32 periods_max; /* max number of periods */ + __le32 period_size_min; /* min period size bytes */ + __le32 period_size_max; /* max period size bytes */ + __le32 buffer_size_min; /* min buffer size bytes */ + __le32 buffer_size_max; /* max buffer size bytes */ +} __packed; + +/* PCM v4 */ +struct snd_soc_tplg_pcm_v4 { + __le32 size; /* in bytes of this structure */ + char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + __le32 pcm_id; /* unique ID - used to match with DAI link */ + __le32 dai_id; /* unique ID - used to match */ + __le32 playback; /* supports playback mode */ + __le32 capture; /* supports capture mode */ + __le32 compress; /* 1 = compressed; 0 = PCM */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ + __le32 num_streams; /* number of streams */ + struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */ +} __packed; + /* topology context */ struct soc_tplg { const struct firmware *fw; @@ -1692,38 +1724,127 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg, return soc_tplg_link_create(tplg, pcm); } +/* copy stream caps from the old version 4 of source */ +static void stream_caps_new_ver(struct snd_soc_tplg_stream_caps *dest, + struct snd_soc_tplg_stream_caps_v4 *src) +{ + dest->size = sizeof(*dest); + memcpy(dest->name, src->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + dest->formats = src->formats; + dest->rates = src->rates; + dest->rate_min = src->rate_min; + dest->rate_max = src->rate_max; + dest->channels_min = src->channels_min; + dest->channels_max = src->channels_max; + dest->periods_min = src->periods_min; + dest->periods_max = src->periods_max; + dest->period_size_min = src->period_size_min; + dest->period_size_max = src->period_size_max; + dest->buffer_size_min = src->buffer_size_min; + dest->buffer_size_max = src->buffer_size_max; +} + +/** + * pcm_new_ver - Create the new version of PCM from the old version. + * @tplg: topology context + * @src: older version of pcm as a source + * @pcm: latest version of pcm created from the source + * + * Support from vesion 4. User should free the returned pcm manually. + */ +static int pcm_new_ver(struct soc_tplg *tplg, + struct snd_soc_tplg_pcm *src, + struct snd_soc_tplg_pcm **pcm) +{ + struct snd_soc_tplg_pcm *dest; + struct snd_soc_tplg_pcm_v4 *src_v4; + int i; + + *pcm = NULL; + + if (src->size != sizeof(*src_v4)) { + dev_err(tplg->dev, "ASoC: invalid PCM size\n"); + return -EINVAL; + } + + dev_warn(tplg->dev, "ASoC: old version of PCM\n"); + src_v4 = (struct snd_soc_tplg_pcm_v4 *)src; + dest = kzalloc(sizeof(*dest), GFP_KERNEL); + if (!dest) + return -ENOMEM; + + dest->size = sizeof(*dest); /* size of latest abi version */ + memcpy(dest->pcm_name, src_v4->pcm_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + memcpy(dest->dai_name, src_v4->dai_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + dest->pcm_id = src_v4->pcm_id; + dest->dai_id = src_v4->dai_id; + dest->playback = src_v4->playback; + dest->capture = src_v4->capture; + dest->compress = src_v4->compress; + dest->num_streams = src_v4->num_streams; + for (i = 0; i < dest->num_streams; i++) + memcpy(&dest->stream[i], &src_v4->stream[i], + sizeof(struct snd_soc_tplg_stream)); + + for (i = 0; i < 2; i++) + stream_caps_new_ver(&dest->caps[i], &src_v4->caps[i]); + + *pcm = dest; + return 0; +} + static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_pcm *pcm; + struct snd_soc_tplg_pcm *pcm, *_pcm; int count = hdr->count; - int i; + int i, err; + bool abi_match; if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) return 0; + /* check the element size and count */ + pcm = (struct snd_soc_tplg_pcm *)tplg->pos; + if (pcm->size > sizeof(struct snd_soc_tplg_pcm) + || pcm->size < sizeof(struct snd_soc_tplg_pcm_v4)) { + dev_err(tplg->dev, "ASoC: invalid size %d for PCM elems\n", + pcm->size); + return -EINVAL; + } + if (soc_tplg_check_elem_count(tplg, - sizeof(struct snd_soc_tplg_pcm), count, + pcm->size, count, hdr->payload_size, "PCM DAI")) { dev_err(tplg->dev, "ASoC: invalid count %d for PCM DAI elems\n", count); return -EINVAL; } - /* create the FE DAIs and DAI links */ - pcm = (struct snd_soc_tplg_pcm *)tplg->pos; for (i = 0; i < count; i++) { - if (pcm->size != sizeof(*pcm)) { - dev_err(tplg->dev, "ASoC: invalid pcm size\n"); - return -EINVAL; + pcm = (struct snd_soc_tplg_pcm *)tplg->pos; + + /* check ABI version by size, create a new version of pcm + * if abi not match. + */ + if (pcm->size == sizeof(*pcm)) { + abi_match = true; + _pcm = pcm; + } else { + abi_match = false; + err = pcm_new_ver(tplg, pcm, &_pcm); } - soc_tplg_pcm_create(tplg, pcm); - pcm++; + /* create the FE DAIs and DAI links */ + soc_tplg_pcm_create(tplg, _pcm); + + if (!abi_match) + kfree(_pcm); /* free the duplicated one */ + + tplg->pos += pcm->size; /* offset by version-specific size */ } dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); - tplg->pos += sizeof(struct snd_soc_tplg_pcm) * count; return 0; } -- cgit v1.2.3-59-g8ed1b From 8f27c4abc2cd7a31adb896a6b4861cdcb921d063 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:02:59 +0800 Subject: ASoC: topology: Only use valid names of PCM for the kernel DAI & DAI link User space may not always set a valid FE DAI driver's name, FE DAI link's name, stream name or cpu DAI name. In such cases, there are all ZERO in these name string buffers of a topology PCM object. This patch will only duplicate valid name strings for kernel FE DAI driver and DAI link when creating them from topology, and free the name strings when destroying them. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 03edde57bfea..0f1c8ebf8cda 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -523,6 +523,7 @@ static void remove_dai(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->dai_unload) dobj->ops->dai_unload(comp, dobj); + kfree(dai_drv->name); list_del(&dobj->list); kfree(dai_drv); } @@ -540,6 +541,10 @@ static void remove_link(struct snd_soc_component *comp, if (dobj->ops && dobj->ops->link_unload) dobj->ops->link_unload(comp, dobj); + kfree(link->name); + kfree(link->stream_name); + kfree(link->cpu_dai_name); + list_del(&dobj->list); snd_soc_remove_dai_link(comp->card, link); kfree(link); @@ -1638,7 +1643,8 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, if (dai_drv == NULL) return -ENOMEM; - dai_drv->name = pcm->dai_name; + if (strlen(pcm->dai_name)) + dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL); dai_drv->id = pcm->dai_id; if (pcm->playback) { @@ -1681,11 +1687,15 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, if (link == NULL) return -ENOMEM; - link->name = pcm->pcm_name; - link->stream_name = pcm->pcm_name; + if (strlen(pcm->pcm_name)) { + link->name = kstrdup(pcm->pcm_name, GFP_KERNEL); + link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL); + } link->id = pcm->pcm_id; - link->cpu_dai_name = pcm->dai_name; + if (strlen(pcm->dai_name)) + link->cpu_dai_name = kstrdup(pcm->dai_name, GFP_KERNEL); + link->codec_name = "snd-soc-dummy"; link->codec_dai_name = "snd-soc-dummy-dai"; -- cgit v1.2.3-59-g8ed1b From 288b8da7e992f0b86b283f98e92885781ffdcaee Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:03:17 +0800 Subject: ASoC: topology: Support topology file of ABI v4 Users start to use topology ABI from v4. ABI v5 updated existing manifest and PCM elements. Two previous patches can support these ABI updates in a backward compatible way. So if the topology file from user space is generated by ABI v4, kernel will no longer quit but continue parsing. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/uapi/sound/asoc.h | 3 ++- sound/soc/soc-topology.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 8d9814b17c46..69cae7198b18 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -83,7 +83,8 @@ #define SND_SOC_TPLG_NUM_TEXTS 16 /* ABI version */ -#define SND_SOC_TPLG_ABI_VERSION 0x5 +#define SND_SOC_TPLG_ABI_VERSION 0x5 /* current version */ +#define SND_SOC_TPLG_ABI_VERSION_MIN 0x4 /* oldest version supported */ /* Max size of TLV data */ #define SND_SOC_TPLG_TLV_SIZE 32 diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 0f1c8ebf8cda..2f9b64ec5904 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2056,7 +2056,9 @@ static int soc_valid_header(struct soc_tplg *tplg, return -EINVAL; } - if (hdr->abi != SND_SOC_TPLG_ABI_VERSION) { + /* Support ABI from version 4 */ + if (hdr->abi > SND_SOC_TPLG_ABI_VERSION + || hdr->abi < SND_SOC_TPLG_ABI_VERSION_MIN) { dev_err(tplg->dev, "ASoC: pass %d invalid ABI version got 0x%x need 0x%x at offset 0x%lx size 0x%zx.\n", tplg->pass, hdr->abi, -- cgit v1.2.3-59-g8ed1b From 717a8e7235377fa50f074c407cc5d0486aa15aa2 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:03:34 +0800 Subject: ASoC: topology: ABI - Add flags and private data to PCM This is the remaining update to PCM ABI object of version 5. The flags will be applied to FE (Front End) links and can also be used by physical links. The private data is reserved for future extension, so offset update will add the private data size. Now user space is using ABI v4, and the previous patch "ASoC: topology: make PCM backward compatible from ABI v4" can assure the backward compatibility. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/uapi/sound/asoc.h | 8 ++++++++ sound/soc/soc-topology.c | 28 ++++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 69cae7198b18..aeb408241bc3 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -146,6 +146,11 @@ #define SND_SOC_DAI_FORMAT_MSB SND_SOC_DAI_FORMAT_LEFT_J #define SND_SOC_DAI_FORMAT_LSB SND_SOC_DAI_FORMAT_RIGHT_J +/* DAI link flags */ +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES (1 << 0) +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) +#define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) + /* * Block Header. * This header precedes all object and object arrays below. @@ -456,6 +461,9 @@ struct snd_soc_tplg_pcm { struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* for DAI link */ __le32 num_streams; /* number of streams */ struct snd_soc_tplg_stream_caps caps[2]; /* playback and capture for DAI */ + __le32 flag_mask; /* bitmask of flags to configure */ + __le32 flags; /* SND_SOC_TPLG_LNK_FLGBIT_* flag value */ + struct snd_soc_tplg_private priv; } __attribute__((packed)); diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 2f9b64ec5904..8baa1761b874 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1676,6 +1676,24 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, return snd_soc_register_dai(tplg->comp, dai_drv); } +static void set_link_flags(struct snd_soc_dai_link *link, + unsigned int flag_mask, unsigned int flags) +{ + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES) + link->symmetric_rates = + flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES ? 1 : 0; + + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS) + link->symmetric_channels = + flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS ? + 1 : 0; + + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS) + link->symmetric_samplebits = + flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ? + 1 : 0; +} + /* create the FE DAI link */ static int soc_tplg_link_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) @@ -1703,6 +1721,8 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, link->dynamic = 1; link->dpcm_playback = pcm->playback; link->dpcm_capture = pcm->capture; + if (pcm->flag_mask) + set_link_flags(link, pcm->flag_mask, pcm->flags); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_link_load(tplg, link); @@ -1848,10 +1868,14 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, /* create the FE DAIs and DAI links */ soc_tplg_pcm_create(tplg, _pcm); + + /* offset by version-specific struct size and + * real priv data size + */ + tplg->pos += pcm->size + _pcm->priv.size; + if (!abi_match) kfree(_pcm); /* free the duplicated one */ - - tplg->pos += pcm->size; /* offset by version-specific size */ } dev_dbg(tplg->dev, "ASoC: adding %d PCM DAIs\n", count); -- cgit v1.2.3-59-g8ed1b From ae73b34f66f629ab1986673e8e069342c09e3168 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 3 Nov 2016 17:27:05 +0100 Subject: ASoC: sun4i-i2s: Implement capture support The i2s driver was only implementing playback for now. Implement capture to make sure that's not a limitation anymore. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 52 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index 687a8f83dbe5..a7653114e895 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,7 @@ struct sun4i_i2s { struct clk *mod_clk; struct regmap *regmap; + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -341,6 +342,27 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } +static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s) +{ + /* Flush RX FIFO */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, + SUN4I_I2S_FIFO_CTRL_FLUSH_RX, + SUN4I_I2S_FIFO_CTRL_FLUSH_RX); + + /* Clear RX counter */ + regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0); + + /* Enable RX Block */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_RX_EN, + SUN4I_I2S_CTRL_RX_EN); + + /* Enable RX DRQ */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, + SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, + SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN); +} + static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) { /* Flush TX FIFO */ @@ -362,6 +384,18 @@ static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); } +static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s) +{ + /* Disable RX Block */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, + SUN4I_I2S_CTRL_RX_EN, + 0); + + /* Disable RX DRQ */ + regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, + SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, + 0); +} static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) { @@ -388,7 +422,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) sun4i_i2s_start_playback(i2s); else - return -EINVAL; + sun4i_i2s_start_capture(i2s); break; case SNDRV_PCM_TRIGGER_STOP: @@ -397,7 +431,7 @@ static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) sun4i_i2s_stop_playback(i2s); else - return -EINVAL; + sun4i_i2s_stop_capture(i2s); break; default: @@ -459,7 +493,9 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) { struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); - snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL); + snd_soc_dai_init_dma_data(dai, + &i2s->playback_dma_data, + &i2s->capture_dma_data); snd_soc_dai_set_drvdata(dai, i2s); @@ -468,6 +504,13 @@ static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) static struct snd_soc_dai_driver sun4i_i2s_dai = { .probe = sun4i_i2s_dai_probe, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, .playback = { .stream_name = "Playback", .channels_min = 2, @@ -630,6 +673,9 @@ static int sun4i_i2s_probe(struct platform_device *pdev) i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; i2s->playback_dma_data.maxburst = 4; + i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG; + i2s->capture_dma_data.maxburst = 4; + pm_runtime_enable(&pdev->dev); if (!pm_runtime_enabled(&pdev->dev)) { ret = sun4i_i2s_runtime_resume(&pdev->dev); -- cgit v1.2.3-59-g8ed1b From 80a0df18191ab50eee7da3cd56cecdd55b7ab148 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:14 +0530 Subject: ASoC: Intel: Add sst_ipc_tx_message_nopm If the DSP is in low power mode, it needs to be woken up by a "wake" IPC to set it into the D0 state before we can send any other IPC command. The call flow is that the driver calls sst_ipc_tx_message_wait() to send any IPC and this call checks if the device is in low power mode and in that case we need to send the wake IPC. So add a new IPC nopm variant which can be called from driver and doesn't check for power state (as we already know that) and avoids circular dependency of again checking power state. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-ipc.c | 8 ++++++++ sound/soc/intel/common/sst-ipc.h | 3 +++ 2 files changed, 11 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 45a85190a081..2c1b3159ac1a 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -220,6 +220,14 @@ int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, } EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nowait); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) +{ + return ipc_tx_message(ipc, header, tx_data, tx_bytes, + rx_data, rx_bytes, 1); +} +EXPORT_SYMBOL_GPL(sst_ipc_tx_message_nopm); + struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header) { diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index 46871a5dff1d..f4aab1b3789a 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -82,6 +82,9 @@ int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, int sst_ipc_tx_message_nowait(struct sst_generic_ipc *ipc, u64 header, void *tx_data, size_t tx_bytes); +int sst_ipc_tx_message_nopm(struct sst_generic_ipc *ipc, u64 header, + void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes); + struct ipc_message *sst_ipc_reply_find_msg(struct sst_generic_ipc *ipc, u64 header); -- cgit v1.2.3-59-g8ed1b From 41b7523f192bdf3804e3e18a61f91244e4a0cb25 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Thu, 3 Nov 2016 17:07:15 +0530 Subject: ASoC: Intel: Skylake: Add D0iX IPCs The audio DSP supports intermediate power states between D0 and D3 states. These states are D0i0 and D0i3 states. Collectively we refer these two states as D0iX states. To set or wake up from these states, driver also needs to send an IPC "Set D0iX IPC" before doing anything else. Add support for this new IPC messages. Signed-off-by: Pardha Saradhi K Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.c | 43 ++++++++++++++++++++++++++++++++++- sound/soc/intel/skylake/skl-sst-ipc.h | 10 ++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 797cf4053235..087b8d6e7186 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -172,6 +172,17 @@ << IPC_INITIAL_BLOCK_SHIFT) #define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ << IPC_INITIAL_BLOCK_SHIFT) +/* Set D0ix IPC extension register */ +#define IPC_D0IX_WAKE_SHIFT 0 +#define IPC_D0IX_WAKE_MASK 0x1 +#define IPC_D0IX_WAKE(x) (((x) & IPC_D0IX_WAKE_MASK) \ + << IPC_D0IX_WAKE_SHIFT) + +#define IPC_D0IX_STREAMING_SHIFT 1 +#define IPC_D0IX_STREAMING_MASK 0x1 +#define IPC_D0IX_STREAMING(x) (((x) & IPC_D0IX_STREAMING_MASK) \ + << IPC_D0IX_STREAMING_SHIFT) + enum skl_ipc_msg_target { IPC_FW_GEN_MSG = 0, @@ -258,7 +269,8 @@ enum skl_ipc_module_msg { IPC_MOD_LARGE_CONFIG_SET = 4, IPC_MOD_BIND = 5, IPC_MOD_UNBIND = 6, - IPC_MOD_SET_DX = 7 + IPC_MOD_SET_DX = 7, + IPC_MOD_SET_D0IX = 8 }; static void skl_ipc_tx_data_copy(struct ipc_message *msg, char *tx_data, @@ -931,3 +943,32 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, return ret; } EXPORT_SYMBOL_GPL(skl_sst_ipc_load_library); + +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_D0IX); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_D0IX_WAKE(msg->wake); + header.extension |= IPC_D0IX_STREAMING(msg->streaming); + + dev_dbg(ipc->dev, "In %s primary=%x ext=%x\n", __func__, + header.primary, header.extension); + + /* + * Use the nopm IPC here as we dont want it checking for D0iX + */ + ret = sst_ipc_tx_message_nopm(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) + dev_err(ipc->dev, "ipc: set d0ix failed, err %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_d0ix); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 0334ed4af031..1ae265d8ee08 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -111,6 +111,13 @@ struct skl_ipc_large_config_msg { u32 param_data_size; }; +struct skl_ipc_d0ix_msg { + u32 module_id; + u32 instance_id; + u8 streaming; + u8 wake; +}; + #define SKL_IPC_BOOT_MSECS 3000 #define SKL_IPC_D3_MASK 0 @@ -155,6 +162,9 @@ int skl_ipc_get_large_config(struct sst_generic_ipc *ipc, int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, u8 dma_id, u8 table_id); +int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, + struct skl_ipc_d0ix_msg *msg); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); -- cgit v1.2.3-59-g8ed1b From a26a3f53e3d2bfeb666ca31b5f86c65a1816eb89 Mon Sep 17 00:00:00 2001 From: Pardha Saradhi K Date: Thu, 3 Nov 2016 17:07:16 +0530 Subject: ASoC: Intel: Skylake: Add support for programming D0i3C To set the controller in D0i3 mode, the driver needs to set D0i3C register after DSP is quiesced. Since the D0iX entry/exit is done by IPC, add this as callback so that it can be invoked from IPC module. Signed-off-by: Pardha Saradhi K Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 1 + sound/soc/intel/skylake/skl-sst-ipc.h | 3 +++ sound/soc/intel/skylake/skl.c | 47 +++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl.h | 5 ++++ 4 files changed, 56 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c966b40da180..b69e05ec6844 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -1211,6 +1211,7 @@ static int skl_platform_soc_probe(struct snd_soc_platform *platform) return ret; } skl_populate_modules(skl); + skl->skl_sst->update_d0i3c = skl_update_d0i3c; } pm_runtime_mark_last_busy(platform->dev); pm_runtime_put_autosuspend(platform->dev); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 1ae265d8ee08..ef2182d21934 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -83,6 +83,9 @@ struct skl_sst { /* tplg manifest */ struct skl_dfw_manifest manifest; + + /* Callback to update D0i3C register */ + void (*update_d0i3c)(struct device *dev, bool enable); }; struct skl_ipc_init_instance_msg { diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 2989c164dafe..b9209af89915 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include "../common/sst-acpi.h" #include @@ -109,6 +110,52 @@ static int skl_init_chip(struct hdac_bus *bus, bool full_reset) return ret; } +void skl_update_d0i3c(struct device *dev, bool enable) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + u8 reg; + int timeout = 50; + + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + /* Do not write to D0I3C until command in progress bit is cleared */ + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "Before D0I3C update: D0I3C CIP timeout\n"); + return; + } + + if (enable) + reg = reg | AZX_REG_VS_D0I3C_I3; + else + reg = reg & (~AZX_REG_VS_D0I3C_I3); + + snd_hdac_chip_writeb(bus, VS_D0I3C, reg); + + timeout = 50; + /* Wait for cmd in progress to be cleared before exiting the function */ + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + while ((reg & AZX_REG_VS_D0I3C_CIP) && --timeout) { + udelay(10); + reg = snd_hdac_chip_readb(bus, VS_D0I3C); + } + + /* Highly unlikely. But if it happens, flag error explicitly */ + if (!timeout) { + dev_err(bus->dev, "After D0I3C update: D0I3C CIP timeout\n"); + return; + } + + dev_dbg(bus->dev, "D0I3C register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); +} + /* called from IRQ */ static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) { diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 5d4fbb094c48..88ba54ba5f72 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -52,6 +52,9 @@ #define AZX_PGCTL_LSRMD_MASK (1 << 4) #define AZX_PCIREG_CGCTL 0x48 #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) +/* D0I3C Register fields */ +#define AZX_REG_VS_D0I3C_CIP 0x1 /* Command in progress */ +#define AZX_REG_VS_D0I3C_I3 0x4 /* D0i3 enable */ struct skl_dsp_resource { u32 max_mcps; @@ -125,4 +128,6 @@ int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); const struct skl_dsp_ops *skl_get_dsp_ops(int pci_id); +void skl_update_d0i3c(struct device *dev, bool enable); + #endif /* __SOUND_SOC_SKL_H */ -- cgit v1.2.3-59-g8ed1b From 5bb4cd46ace5f220fbc34370e7fe9ba515ead9f8 Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Thu, 3 Nov 2016 17:07:17 +0530 Subject: ASoC: Intel: Skylake: Add D0iX callbacks The driver needs two DSP callback, one to set D0i0 (active) and D0i3 (low-power) states. Add these callbacks in dsp ops and implement them for broxton platforms. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 140 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 12 +++ sound/soc/intel/skylake/skl-sst-ipc.h | 19 +++++ 3 files changed, 171 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 1d251d59bcb9..fed818fe2e69 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -43,6 +43,9 @@ #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 +/* Delay before scheduling D0i3 entry */ +#define BXT_D0I3_DELAY 5000 + static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) { return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); @@ -288,6 +291,141 @@ sst_load_base_firmware_failed: return ret; } +/* + * Decide the D0i3 state that can be targeted based on the usecase + * ref counts and DSP state + * + * Decision Matrix: (X= dont care; state = target state) + * + * DSP state != SKL_DSP_RUNNING ; state = no d0i3 + * + * DSP state == SKL_DSP_RUNNING , the following matrix applies + * non_d0i3 >0; streaming =X; non_streaming =X; state = no d0i3 + * non_d0i3 =X; streaming =0; non_streaming =0; state = no d0i3 + * non_d0i3 =0; streaming >0; non_streaming =X; state = streaming d0i3 + * non_d0i3 =0; streaming =0; non_streaming =X; state = non-streaming d0i3 + */ +static int bxt_d0i3_target_state(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + + if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING) + return SKL_DSP_D0I3_NONE; + + if (d0i3->non_d0i3) + return SKL_DSP_D0I3_NONE; + else if (d0i3->streaming) + return SKL_DSP_D0I3_STREAMING; + else if (d0i3->non_streaming) + return SKL_DSP_D0I3_NON_STREAMING; + else + return SKL_DSP_D0I3_NONE; +} + +static void bxt_set_dsp_D0i3(struct work_struct *work) +{ + int ret; + struct skl_ipc_d0ix_msg msg; + struct skl_sst *skl = container_of(work, + struct skl_sst, d0i3.work.work); + struct sst_dsp *ctx = skl->dsp; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + int target_state; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + + /* D0i3 entry allowed only if core 0 alone is running */ + if (skl_dsp_get_enabled_cores(ctx) != SKL_DSP_CORE0_MASK) { + dev_warn(ctx->dev, + "D0i3 allowed when only core0 running:Exit\n"); + return; + } + + target_state = bxt_d0i3_target_state(ctx); + if (target_state == SKL_DSP_D0I3_NONE) + return; + + msg.instance_id = 0; + msg.module_id = 0; + msg.wake = 1; + msg.streaming = 0; + if (target_state == SKL_DSP_D0I3_STREAMING) + msg.streaming = 1; + + ret = skl_ipc_set_d0ix(&skl->ipc, &msg); + + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D0i3 state\n"); + return; + } + + /* Set Vendor specific register D0I3C.I3 to enable D0i3*/ + if (skl->update_d0i3c) + skl->update_d0i3c(skl->dev, true); + + d0i3->state = target_state; + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING_D0I3; +} + +static int bxt_schedule_dsp_D0i3(struct sst_dsp *ctx) +{ + struct skl_sst *skl = ctx->thread_context; + struct skl_d0i3_data *d0i3 = &skl->d0i3; + + /* Schedule D0i3 only if the usecase ref counts are appropriate */ + if (bxt_d0i3_target_state(ctx) != SKL_DSP_D0I3_NONE) { + + dev_dbg(ctx->dev, "%s: Schedule D0i3\n", __func__); + + schedule_delayed_work(&d0i3->work, + msecs_to_jiffies(BXT_D0I3_DELAY)); + } + + return 0; +} + +static int bxt_set_dsp_D0i0(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_d0ix_msg msg; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + + /* First Cancel any pending attempt to put DSP to D0i3 */ + cancel_delayed_work_sync(&skl->d0i3.work); + + /* If DSP is currently in D0i3, bring it to D0i0 */ + if (skl->cores.state[SKL_DSP_CORE0_ID] != SKL_DSP_RUNNING_D0I3) + return 0; + + dev_dbg(ctx->dev, "Set DSP to D0i0\n"); + + msg.instance_id = 0; + msg.module_id = 0; + msg.streaming = 0; + msg.wake = 0; + + if (skl->d0i3.state == SKL_DSP_D0I3_STREAMING) + msg.streaming = 1; + + /* Clear Vendor specific register D0I3C.I3 to disable D0i3*/ + if (skl->update_d0i3c) + skl->update_d0i3c(skl->dev, false); + + ret = skl_ipc_set_d0ix(&skl->ipc, &msg); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D0i0\n"); + return ret; + } + + skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; + skl->d0i3.state = SKL_DSP_D0I3_NONE; + + return 0; +} + static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) { struct skl_sst *skl = ctx->thread_context; @@ -414,6 +552,8 @@ static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) static struct skl_dsp_fw_ops bxt_fw_ops = { .set_state_D0 = bxt_set_dsp_D0, .set_state_D3 = bxt_set_dsp_D3, + .set_state_D0i3 = bxt_schedule_dsp_D0i3, + .set_state_D0i0 = bxt_set_dsp_D0i0, .load_fw = bxt_load_base_firmware, .get_fw_errcode = bxt_get_errorcode, .load_library = bxt_load_library, diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index b9e71d051fb1..7c272ba0f4b5 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -126,11 +126,21 @@ struct sst_dsp_device; #define SKL_ADSPCS_CPA_SHIFT 24 #define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) +/* DSP Core state */ enum skl_dsp_states { SKL_DSP_RUNNING = 1, + /* Running in D0i3 state; can be in streaming or non-streaming D0i3 */ + SKL_DSP_RUNNING_D0I3, /* Running in D0i3 state*/ SKL_DSP_RESET, }; +/* D0i3 substates */ +enum skl_dsp_d0i3_states { + SKL_DSP_D0I3_NONE = -1, /* No D0i3 */ + SKL_DSP_D0I3_NON_STREAMING = 0, + SKL_DSP_D0I3_STREAMING = 1, +}; + struct skl_dsp_fw_ops { int (*load_fw)(struct sst_dsp *ctx); /* FW module parser/loader */ @@ -139,6 +149,8 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); + int (*set_state_D0i3)(struct sst_dsp *ctx); + int (*set_state_D0i0)(struct sst_dsp *ctx); unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index ef2182d21934..a45c42046b64 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -53,6 +53,23 @@ struct skl_dsp_cores { int usage_count[SKL_DSP_CORES_MAX]; }; +/** + * skl_d0i3_data: skl D0i3 counters data struct + * + * @streaming: Count of usecases that can attempt streaming D0i3 + * @non_streaming: Count of usecases that can attempt non-streaming D0i3 + * @non_d0i3: Count of usecases that cannot attempt D0i3 + * @state: current state + * @work: D0i3 worker thread + */ +struct skl_d0i3_data { + int streaming; + int non_streaming; + int non_d0i3; + enum skl_dsp_d0i3_states state; + struct delayed_work work; +}; + struct skl_sst { struct device *dev; struct sst_dsp *dsp; @@ -86,6 +103,8 @@ struct skl_sst { /* Callback to update D0i3C register */ void (*update_d0i3c)(struct device *dev, bool enable); + + struct skl_d0i3_data d0i3; }; struct skl_ipc_init_instance_msg { -- cgit v1.2.3-59-g8ed1b From 8a0cb2360ddb941e0a2fbe33d400d2985e4f2fff Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:18 +0530 Subject: ASoC: Intel: Skylake: Add support for LPMode For D0i3, we need to tell DSP to run the pipelines in LP mode. This information is kept in topology and passed to driver as an attribute for pipe. So add a new tuple for lpmode and program the pipe based on value set. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 5 ++++- sound/soc/intel/skylake/skl-messages.c | 3 ++- sound/soc/intel/skylake/skl-sst-ipc.c | 9 ++++++++- sound/soc/intel/skylake/skl-sst-ipc.h | 2 +- sound/soc/intel/skylake/skl-topology.c | 5 +++++ sound/soc/intel/skylake/skl-topology.h | 1 + 6 files changed, 21 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index 1ee2e943d66a..f4b8b34de519 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -157,6 +157,8 @@ * * %SKL_TKN_STR_LIB_NAME: Specifies the library name * + * %SKL_TKN_U32_PMODE: Specifies the power mode for pipe + * * module_id and loadable flags dont have tokens as these values will be * read from the DSP FW manifest */ @@ -208,7 +210,8 @@ enum SKL_TKNS { SKL_TKN_U32_PROC_DOMAIN, SKL_TKN_U32_LIB_COUNT, SKL_TKN_STR_LIB_NAME, - SKL_TKN_MAX = SKL_TKN_STR_LIB_NAME, + SKL_TKN_U32_PMODE, + SKL_TKN_MAX = SKL_TKN_U32_PMODE, }; #endif diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 805b7f2173f3..87fc647fa04c 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -1042,7 +1042,8 @@ int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe) dev_dbg(ctx->dev, "%s: pipe_id = %d\n", __func__, pipe->ppl_id); ret = skl_ipc_create_pipeline(&ctx->ipc, pipe->memory_pages, - pipe->pipe_priority, pipe->ppl_id); + pipe->pipe_priority, pipe->ppl_id, + pipe->lp_mode); if (ret < 0) { dev_err(ctx->dev, "Failed to create pipeline\n"); return ret; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 087b8d6e7186..734408a34a24 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -81,6 +81,11 @@ #define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ << IPC_INSTANCE_ID_SHIFT) +#define IPC_PPL_LP_MODE_SHIFT 0 +#define IPC_PPL_LP_MODE_MASK 0x1 +#define IPC_PPL_LP_MODE(x) (((x) & IPC_PPL_LP_MODE_MASK) \ + << IPC_PPL_LP_MODE_SHIFT) + /* Set pipeline state message */ #define IPC_PPL_STATE_SHIFT 0 #define IPC_PPL_STATE_MASK 0x1F @@ -559,7 +564,7 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) } int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id) + u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode) { struct skl_ipc_header header = {0}; u64 *ipc_header = (u64 *)(&header); @@ -572,6 +577,8 @@ int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, header.primary |= IPC_PPL_TYPE(ppl_type); header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); + header.extension = IPC_PPL_LP_MODE(lp_mode); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); if (ret < 0) { diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index a45c42046b64..83bf1689f62e 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -148,7 +148,7 @@ struct skl_ipc_d0ix_msg { irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, - u16 ppl_mem_size, u8 ppl_type, u8 instance_id); + u16 ppl_mem_size, u8 ppl_type, u8 instance_id, u8 lp_mode); int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index b5b1934d8550..9a7a008f6689 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1519,6 +1519,10 @@ static int skl_tplg_fill_pipe_tkn(struct device *dev, pipe->memory_pages = tkn_val; break; + case SKL_TKN_U32_PMODE: + pipe->lp_mode = tkn_val; + break; + default: dev_err(dev, "Token not handled %d\n", tkn); return -EINVAL; @@ -1841,6 +1845,7 @@ static int skl_tplg_get_token(struct device *dev, case SKL_TKN_U32_PIPE_CONN_TYPE: case SKL_TKN_U32_PIPE_PRIORITY: case SKL_TKN_U32_PIPE_MEM_PGS: + case SKL_TKN_U32_PMODE: if (is_pipe_exists) { ret = skl_tplg_fill_pipe_tkn(dev, mconfig->pipe, tkn_elem->token, tkn_elem->value); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index a519360f42a6..11fd0a4b6603 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -279,6 +279,7 @@ struct skl_pipe { u8 pipe_priority; u16 conn_type; u32 memory_pages; + u8 lp_mode; struct skl_pipe_params *p_params; enum skl_pipe_state state; struct list_head w_list; -- cgit v1.2.3-59-g8ed1b From 6bd9dcf339ebb292fa149ee0e52ea3c9d9822553 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:19 +0530 Subject: ASoC: Intel: Skylake: Add support for specifying D0i3 configuration Not all use cases can support Doi3. Only certain use cases like hot word detection, deep buffering can support D0i3 based on resource requirement. So, pass the D0i3 capability for the FE/BE copier using topology. This will be used to take a decision for D0i3 mode entry/exit. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/uapi/sound/snd_sst_tokens.h | 5 ++++- sound/soc/intel/skylake/skl-topology.c | 4 ++++ sound/soc/intel/skylake/skl-topology.h | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/uapi/sound/snd_sst_tokens.h b/include/uapi/sound/snd_sst_tokens.h index f4b8b34de519..93392bedcc58 100644 --- a/include/uapi/sound/snd_sst_tokens.h +++ b/include/uapi/sound/snd_sst_tokens.h @@ -159,6 +159,8 @@ * * %SKL_TKN_U32_PMODE: Specifies the power mode for pipe * + * %SKL_TKL_U32_D0I3_CAPS: Specifies the D0i3 capability for module + * * module_id and loadable flags dont have tokens as these values will be * read from the DSP FW manifest */ @@ -211,7 +213,8 @@ enum SKL_TKNS { SKL_TKN_U32_LIB_COUNT, SKL_TKN_STR_LIB_NAME, SKL_TKN_U32_PMODE, - SKL_TKN_MAX = SKL_TKN_U32_PMODE, + SKL_TKL_U32_D0I3_CAPS, + SKL_TKN_MAX = SKL_TKL_U32_D0I3_CAPS, }; #endif diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 9a7a008f6689..86597d491982 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -1830,6 +1830,10 @@ static int skl_tplg_get_token(struct device *dev, mconfig->converter = tkn_elem->value; break; + case SKL_TKL_U32_D0I3_CAPS: + mconfig->d0i3_caps = tkn_elem->value; + break; + case SKL_TKN_U32_PIPE_ID: ret = skl_tplg_add_pipe(dev, mconfig, skl, tkn_elem); diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 11fd0a4b6603..38809f6d20d6 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -294,6 +294,12 @@ enum skl_module_state { SKL_MODULE_UNLOADED = 4, }; +enum d0i3_capability { + SKL_D0I3_NONE = 0, + SKL_D0I3_STREAMING = 1, + SKL_D0I3_NON_STREAMING = 2, +}; + struct skl_module_cfg { u8 guid[16]; struct skl_module_inst_id id; @@ -320,6 +326,7 @@ struct skl_module_cfg { u32 converter; u32 vbus_id; u32 mem_pages; + enum d0i3_capability d0i3_caps; struct skl_module_pin *m_in_pin; struct skl_module_pin *m_out_pin; enum skl_module_type m_type; -- cgit v1.2.3-59-g8ed1b From a83e3b4c4454ecdc473cf09aa1c9d1705623c4cc Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 3 Nov 2016 17:07:20 +0530 Subject: ASoC: Intel: Skylake: Add D0i3 mode ref counting For device opened/closed, we check the D0i3 capability for the device and invoke skl_tplg_d0i3_get/put, which counts the use case based on the mode supported. These counters are then used to decide if the device can enter D0i3 mode of streaming or non-streaming or no D0i3. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/bxt-sst.c | 5 +++++ sound/soc/intel/skylake/skl-pcm.c | 9 ++++++++ sound/soc/intel/skylake/skl-sst-ipc.c | 17 +++++++++++++++ sound/soc/intel/skylake/skl-sst-ipc.h | 2 ++ sound/soc/intel/skylake/skl-topology.c | 38 ++++++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-topology.h | 3 +++ 6 files changed, 74 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index fed818fe2e69..1f9f33d34000 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c @@ -610,10 +610,15 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, if (ret) return ret; + /* set the D0i3 check */ + skl->ipc.ops.check_dsp_lp_on = skl_ipc_check_D0i0; + skl->cores.count = 2; skl->boot_complete = false; init_waitqueue_head(&skl->boot_wait); skl->is_first_boot = true; + INIT_DELAYED_WORK(&skl->d0i3.work, bxt_set_dsp_D0i3); + skl->d0i3.state = SKL_DSP_D0I3_NONE; if (dsp) *dsp = skl; diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index b69e05ec6844..84b5101e6ca6 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -144,6 +144,8 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, struct hdac_ext_stream *stream; struct snd_pcm_runtime *runtime = substream->runtime; struct skl_dma_params *dma_params; + struct skl *skl = get_skl_ctx(dai->dev); + struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -177,6 +179,9 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, skl_set_suspend_active(substream, dai, true); snd_pcm_set_sync(substream); + mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + skl_tplg_d0i3_get(skl, mconfig->d0i3_caps); + return 0; } @@ -302,6 +307,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; struct skl *skl = ebus_to_skl(ebus); + struct skl_module_cfg *mconfig; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); @@ -325,6 +331,9 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, skl->skl_sst->miscbdcg_disabled = false; } + mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); + skl_tplg_d0i3_put(skl, mconfig->d0i3_caps); + kfree(dma_params); } diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 734408a34a24..594623a4b4cd 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -306,6 +306,23 @@ static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) header->primary | SKL_ADSP_REG_HIPCI_BUSY); } +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state) +{ + int ret; + + /* check D0i3 support */ + if (!dsp->fw_ops.set_state_D0i0) + return 0; + + /* Attempt D0i0 or D0i3 based on state */ + if (state) + ret = dsp->fw_ops.set_state_D0i0(dsp); + else + ret = dsp->fw_ops.set_state_D0i3(dsp); + + return ret; +} + static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, u64 ipc_header) { diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 83bf1689f62e..0568f2e8fc57 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -187,6 +187,8 @@ int skl_sst_ipc_load_library(struct sst_generic_ipc *ipc, int skl_ipc_set_d0ix(struct sst_generic_ipc *ipc, struct skl_ipc_d0ix_msg *msg); +int skl_ipc_check_D0i0(struct sst_dsp *dsp, bool state); + void skl_ipc_int_enable(struct sst_dsp *dsp); void skl_ipc_op_int_enable(struct sst_dsp *ctx); void skl_ipc_op_int_disable(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 86597d491982..bd313c907b20 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c @@ -36,6 +36,44 @@ #define SKL_IN_DIR_BIT_MASK BIT(0) #define SKL_PIN_COUNT_MASK GENMASK(7, 4) +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps) +{ + struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + + switch (caps) { + case SKL_D0I3_NONE: + d0i3->non_d0i3++; + break; + + case SKL_D0I3_STREAMING: + d0i3->streaming++; + break; + + case SKL_D0I3_NON_STREAMING: + d0i3->non_streaming++; + break; + } +} + +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps) +{ + struct skl_d0i3_data *d0i3 = &skl->skl_sst->d0i3; + + switch (caps) { + case SKL_D0I3_NONE: + d0i3->non_d0i3--; + break; + + case SKL_D0I3_STREAMING: + d0i3->streaming--; + break; + + case SKL_D0I3_NON_STREAMING: + d0i3->non_streaming--; + break; + } +} + /* * SKL DSP driver modelling uses only few DAPM widgets so for rest we will * ignore. This helpers checks if the SKL driver handles this widget type diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 38809f6d20d6..3b962d84bcb8 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -369,6 +369,9 @@ struct skl_module_cfg *skl_tplg_fe_get_cpr_module( int skl_tplg_update_pipe_params(struct device *dev, struct skl_module_cfg *mconfig, struct skl_pipe_params *params); +void skl_tplg_d0i3_get(struct skl *skl, enum d0i3_capability caps); +void skl_tplg_d0i3_put(struct skl *skl, enum d0i3_capability caps); + int skl_create_pipeline(struct skl_sst *ctx, struct skl_pipe *pipe); int skl_run_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); -- cgit v1.2.3-59-g8ed1b From 2f2a3462bc15e9613412ca186bf8a6611afa66c7 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:43 +0800 Subject: ASoC: sun4i-codec: Move data structures to add create_card call to quirks The audio codec on later Allwinner SoCs have a different layout and audio path compared to the A10/A20. However the PCM parts are still the same. The different layout and audio paths mean we need a different create_card function for different families, so they can create DAPM endpoint widgets and routes. This patch moves the regmap configs, quirks and of_device_id structures to just before the probe function, so we can, among other things, include a pointer for the create_card function. None of the lines of code were changed. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 78 +++++++++++++++++++++---------------------- 1 file changed, 39 insertions(+), 39 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index a60707761abf..7b78f4045d38 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -678,45 +678,6 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { }, }; -static const struct regmap_config sun4i_codec_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = SUN4I_CODEC_ADC_RXCNT, -}; - -static const struct regmap_config sun7i_codec_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, -}; - -struct sun4i_codec_quirks { - const struct regmap_config *regmap_config; -}; - -static const struct sun4i_codec_quirks sun4i_codec_quirks = { - .regmap_config = &sun4i_codec_regmap_config, -}; - -static const struct sun4i_codec_quirks sun7i_codec_quirks = { - .regmap_config = &sun7i_codec_regmap_config, -}; - -static const struct of_device_id sun4i_codec_of_match[] = { - { - .compatible = "allwinner,sun4i-a10-codec", - .data = &sun4i_codec_quirks, - }, - { - .compatible = "allwinner,sun7i-a20-codec", - .data = &sun7i_codec_quirks, - }, - {} -}; -MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); - static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, int *num_links) { @@ -781,6 +742,45 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) return card; }; +static const struct regmap_config sun4i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN4I_CODEC_ADC_RXCNT, +}; + +static const struct regmap_config sun7i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, +}; + +struct sun4i_codec_quirks { + const struct regmap_config *regmap_config; +}; + +static const struct sun4i_codec_quirks sun4i_codec_quirks = { + .regmap_config = &sun4i_codec_regmap_config, +}; + +static const struct sun4i_codec_quirks sun7i_codec_quirks = { + .regmap_config = &sun7i_codec_regmap_config, +}; + +static const struct of_device_id sun4i_codec_of_match[] = { + { + .compatible = "allwinner,sun4i-a10-codec", + .data = &sun4i_codec_quirks, + }, + { + .compatible = "allwinner,sun7i-a20-codec", + .data = &sun7i_codec_quirks, + }, + {} +}; +MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); + static int sun4i_codec_probe(struct platform_device *pdev) { struct snd_soc_card *card; -- cgit v1.2.3-59-g8ed1b From bd720ecf4ec6923207b4059ff4b4a43ee25ac891 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:45 +0800 Subject: ASoC: sun4i-codec: Revise comments for register definition macros This revises existing comments in the register definition macros section, and adds a few more, so that readers can clearly identify the types of control registers. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 7b78f4045d38..969d86b4cd44 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -38,7 +38,7 @@ #include #include -/* Codec DAC register offsets and bit fields */ +/* Codec DAC digital controls and FIFO registers */ #define SUN4I_CODEC_DAC_DPC (0x00) #define SUN4I_CODEC_DAC_DPC_EN_DA (31) #define SUN4I_CODEC_DAC_DPC_DVOL (12) @@ -55,6 +55,8 @@ #define SUN4I_CODEC_DAC_FIFOC_FIFO_FLUSH (0) #define SUN4I_CODEC_DAC_FIFOS (0x08) #define SUN4I_CODEC_DAC_TXDATA (0x0c) + +/* Codec DAC side analog signal controls */ #define SUN4I_CODEC_DAC_ACTL (0x10) #define SUN4I_CODEC_DAC_ACTL_DACAENR (31) #define SUN4I_CODEC_DAC_ACTL_DACAENL (30) @@ -69,7 +71,7 @@ #define SUN4I_CODEC_DAC_TUNE (0x14) #define SUN4I_CODEC_DAC_DEBUG (0x18) -/* Codec ADC register offsets and bit fields */ +/* Codec ADC digital controls and FIFO registers */ #define SUN4I_CODEC_ADC_FIFOC (0x1c) #define SUN4I_CODEC_ADC_FIFOC_ADC_FS (29) #define SUN4I_CODEC_ADC_FIFOC_EN_AD (28) @@ -81,6 +83,8 @@ #define SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH (0) #define SUN4I_CODEC_ADC_FIFOS (0x20) #define SUN4I_CODEC_ADC_RXDATA (0x24) + +/* Codec ADC side analog signal controls */ #define SUN4I_CODEC_ADC_ACTL (0x28) #define SUN4I_CODEC_ADC_ACTL_ADC_R_EN (31) #define SUN4I_CODEC_ADC_ACTL_ADC_L_EN (30) @@ -93,10 +97,14 @@ #define SUN4I_CODEC_ADC_ACTL_DDE (3) #define SUN4I_CODEC_ADC_DEBUG (0x2c) -/* Other various ADC registers */ +/* FIFO counters */ #define SUN4I_CODEC_DAC_TXCNT (0x30) #define SUN4I_CODEC_ADC_RXCNT (0x34) + +/* Calibration register (sun7i only) */ #define SUN7I_CODEC_AC_DAC_CAL (0x38) + +/* Microphone controls (sun7i only) */ #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) struct sun4i_codec { -- cgit v1.2.3-59-g8ed1b From bc03f0d576000739694ed95e89c71cda78964224 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:44 +0800 Subject: ASoC: sun4i-codec: Expand quirks to handle register offsets and card creation The A31 has a similar codec to the A10/A20. The PCM parts are very similar, with just different register offsets. The analog paths are very different. There are more inputs and outputs. The A31s, A23, and H3 have a similar PCM interface, again with register offsets slightly rearranged. The analog path controls, while very similar between them and the A31, have been moved a separate bus which is accessed through a message box like interface in the PRCM address range. This would be handled by a separate auxiliary device tied in through the device tree in its supporting create_card function. The quirks structure is expanded to include different register offsets and separate callbacks for creating the ASoC card. The regmap_config, quirks, and of_device_match tables have been moved to facilitate this. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 87 +++++++++++++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 5ff071fd4996..61ae502a5061 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -3,6 +3,7 @@ * Copyright 2014 Jon Smirl * Copyright 2015 Maxime Ripard * Copyright 2015 Adam Sampson + * Copyright 2016 Chen-Yu Tsai * * Based on the Allwinner SDK driver, released under the GPL. * @@ -24,8 +25,9 @@ #include #include #include -#include #include +#include +#include #include #include #include @@ -114,6 +116,9 @@ struct sun4i_codec { struct clk *clk_module; struct gpio_desc *gpio_pa; + /* ADC_FIFOC register is at different offset on different SoCs */ + struct regmap_field *reg_adc_fifoc; + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -142,16 +147,16 @@ static void sun4i_codec_stop_playback(struct sun4i_codec *scodec) static void sun4i_codec_start_capture(struct sun4i_codec *scodec) { /* Enable ADC DRQ */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN)); } static void sun4i_codec_stop_capture(struct sun4i_codec *scodec) { /* Disable ADC DRQ */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_ADC_DRQ_EN), 0); } static int sun4i_codec_trigger(struct snd_pcm_substream *substream, int cmd, @@ -194,15 +199,15 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, /* Flush RX FIFO */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), - BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH), + BIT(SUN4I_CODEC_ADC_FIFOC_FIFO_FLUSH)); /* Set RX FIFO trigger level */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, - 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); + regmap_field_update_bits(scodec->reg_adc_fifoc, + 0xf << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL, + 0x7 << SUN4I_CODEC_ADC_FIFOC_RX_TRIG_LEVEL); /* * FIXME: Undocumented in the datasheet, but @@ -221,9 +226,9 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, 0x1 << 8); /* Fill most significant bits with valid data MSB */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), - BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE), + BIT(SUN4I_CODEC_ADC_FIFOC_RX_FIFO_MODE)); return 0; } @@ -350,18 +355,19 @@ static int sun4i_codec_hw_params_capture(struct sun4i_codec *scodec, unsigned int hwrate) { /* Set ADC sample rate */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, - hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); + regmap_field_update_bits(scodec->reg_adc_fifoc, + 7 << SUN4I_CODEC_ADC_FIFOC_ADC_FS, + hwrate << SUN4I_CODEC_ADC_FIFOC_ADC_FS); /* Set the number of channels we want to use */ if (params_channels(params) == 1) - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN)); else - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_FIFOC, - BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), 0); + regmap_field_update_bits(scodec->reg_adc_fifoc, + BIT(SUN4I_CODEC_ADC_FIFOC_MONO_EN), + 0); return 0; } @@ -766,14 +772,29 @@ static const struct regmap_config sun7i_codec_regmap_config = { struct sun4i_codec_quirks { const struct regmap_config *regmap_config; + const struct snd_soc_codec_driver *codec; + struct snd_soc_card * (*create_card)(struct device *dev); + struct reg_field reg_adc_fifoc; /* used for regmap_field */ + unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ + unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ }; static const struct sun4i_codec_quirks sun4i_codec_quirks = { .regmap_config = &sun4i_codec_regmap_config, + .codec = &sun4i_codec_codec, + .create_card = sun4i_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; static const struct sun4i_codec_quirks sun7i_codec_quirks = { .regmap_config = &sun7i_codec_regmap_config, + .codec = &sun4i_codec_codec, + .create_card = sun4i_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN4I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; static const struct of_device_id sun4i_codec_of_match[] = { @@ -846,6 +867,17 @@ static int sun4i_codec_probe(struct platform_device *pdev) return ret; } + /* reg_field setup */ + scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, + scodec->regmap, + quirks->reg_adc_fifoc); + if (IS_ERR(scodec->reg_adc_fifoc)) { + ret = PTR_ERR(scodec->reg_adc_fifoc); + dev_err(&pdev->dev, "Failed to create regmap fields: %d\n", + ret); + return ret; + } + /* Enable the bus clock */ if (clk_prepare_enable(scodec->clk_apb)) { dev_err(&pdev->dev, "Failed to enable the APB clock\n"); @@ -853,16 +885,16 @@ static int sun4i_codec_probe(struct platform_device *pdev) } /* DMA configuration for TX FIFO */ - scodec->playback_dma_data.addr = res->start + SUN4I_CODEC_DAC_TXDATA; + scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; scodec->playback_dma_data.maxburst = 4; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; /* DMA configuration for RX FIFO */ - scodec->capture_dma_data.addr = res->start + SUN4I_CODEC_ADC_RXDATA; + scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; scodec->capture_dma_data.maxburst = 4; scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; - ret = snd_soc_register_codec(&pdev->dev, &sun4i_codec_codec, + ret = snd_soc_register_codec(&pdev->dev, quirks->codec, &sun4i_codec_dai, 1); if (ret) { dev_err(&pdev->dev, "Failed to register our codec\n"); @@ -883,7 +915,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) goto err_unregister_codec; } - card = sun4i_codec_create_card(&pdev->dev); + card = quirks->create_card(&pdev->dev); if (IS_ERR(card)) { ret = PTR_ERR(card); dev_err(&pdev->dev, "Failed to create our card\n"); @@ -934,4 +966,5 @@ MODULE_DESCRIPTION("Allwinner A10 codec driver"); MODULE_AUTHOR("Emilio López "); MODULE_AUTHOR("Jon Smirl "); MODULE_AUTHOR("Maxime Ripard "); +MODULE_AUTHOR("Chen-Yu Tsai "); MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 730e2dd0cbc7a7ec10174d9d291cdd8e8082a948 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:46 +0800 Subject: ASoC: sun4i-codec: Increase DMA max burst to 8 According to the DMA engine API documentation, maxburst denotes the largest possible size of a single transfer, so as not to overflow destination FIFOs as explained in this excerpt from dmaengine.h * @src_maxburst: the maximum number of words (note: words, as in * units of the src_addr_width member, not bytes) that can be sent * in one burst to the device. Typically something like half the * FIFO depth on I/O peripherals so you don't overflow it. This * may or may not be applicable on memory sources. * @dst_maxburst: same as src_maxburst but for destination target * mutatis mutandis. The TX FIFO is 64 samples deep for stereo, and the RX FIFO is 16 samples deep. So maxburst could be 32 and 8 for TX and RX respectively. Unfortunately the sunxi DMA controller driver takes maxburst as the requested burst size, rather than a limit, and returns an error for unsupported values. The original value was 4, but some later SoCs do not officially support this burst size. This patch increases maxburst on the TX side to 8, which is supported by all variants of the sunxi DMA controller. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 61ae502a5061..d867b96d367b 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -886,12 +886,12 @@ static int sun4i_codec_probe(struct platform_device *pdev) /* DMA configuration for TX FIFO */ scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; - scodec->playback_dma_data.maxburst = 4; + scodec->playback_dma_data.maxburst = 8; scodec->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; /* DMA configuration for RX FIFO */ scodec->capture_dma_data.addr = res->start + quirks->reg_adc_rxdata; - scodec->capture_dma_data.maxburst = 4; + scodec->capture_dma_data.maxburst = 8; scodec->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; ret = snd_soc_register_codec(&pdev->dev, quirks->codec, -- cgit v1.2.3-59-g8ed1b From 8d9e4c9e993f34e7f74bf36f417920a01a42c4b0 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:48 +0800 Subject: ASoC: sun4i-codec: Add support for A31 playback through headphone output The A31 has a similar codec to the A10/A20. The PCM parts are very similar, with different register offsets. The analog paths are very different. There are more inputs and outputs. The ADC mux has been replaced with a proper mixer. This patch adds support for the basic playback path of the A31 codec, from the DAC to the headphones. Headphone detection, microphone, signaling, other inputs/outputs and capture will be added later. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-codec.txt | 22 +- sound/soc/sunxi/sun4i-codec.c | 271 ++++++++++++++++++++- 2 files changed, 287 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index 0dce690f78f5..bf480e9683a3 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -1,8 +1,10 @@ * Allwinner A10 Codec Required properties: -- compatible: must be either "allwinner,sun4i-a10-codec" or - "allwinner,sun7i-a20-codec" +- compatible: must be one of the following compatibles: + - "allwinner,sun4i-a10-codec" + - "allwinner,sun6i-a31-codec" + - "allwinner,sun7i-a20-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - dmas: DMA channels for tx and rx dma. See the DMA client binding, @@ -17,6 +19,10 @@ Required properties: Optional properties: - allwinner,pa-gpios: gpio to enable external amplifier +Required properties for the following compatibles: + - "allwinner,sun6i-a31-codec" +- resets: phandle to the reset control for this device + Example: codec: codec@01c22c00 { #sound-dai-cells = <0>; @@ -28,3 +34,15 @@ codec: codec@01c22c00 { dmas = <&dma 0 19>, <&dma 0 19>; dma-names = "rx", "tx"; }; + +codec: codec@01c22c00 { + #sound-dai-cells = <0>; + compatible = "allwinner,sun6i-a31-codec"; + reg = <0x01c22c00 0x98>; + interrupts = ; + clocks = <&ccu CLK_APB1_CODEC>, <&ccu CLK_CODEC>; + clock-names = "apb", "codec"; + resets = <&ccu RST_APB1_CODEC>; + dmas = <&dma 15>, <&dma 15>; + dma-names = "rx", "tx"; +}; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index d867b96d367b..d4b2186b5d84 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -109,6 +109,109 @@ /* Microphone controls (sun7i only) */ #define SUN7I_CODEC_AC_MIC_PHONE_CAL (0x3c) +/* + * sun6i specific registers + * + * sun6i shares the same digital control and FIFO registers as sun4i, + * but only the DAC digital controls are at the same offset. The others + * have been moved around to accommodate extra analog controls. + */ + +/* Codec DAC digital controls and FIFO registers */ +#define SUN6I_CODEC_ADC_FIFOC (0x10) +#define SUN6I_CODEC_ADC_FIFOC_EN_AD (28) +#define SUN6I_CODEC_ADC_FIFOS (0x14) +#define SUN6I_CODEC_ADC_RXDATA (0x18) + +/* Output mixer and gain controls */ +#define SUN6I_CODEC_OM_DACA_CTRL (0x20) +#define SUN6I_CODEC_OM_DACA_CTRL_DACAREN (31) +#define SUN6I_CODEC_OM_DACA_CTRL_DACALEN (30) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIXEN (29) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIXEN (28) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1 (23) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2 (22) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONE (21) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_PHONEP (20) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR (19) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR (18) +#define SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL (17) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1 (16) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2 (15) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONE (14) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_PHONEN (13) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL (12) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL (11) +#define SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR (10) +#define SUN6I_CODEC_OM_DACA_CTRL_RHPIS (9) +#define SUN6I_CODEC_OM_DACA_CTRL_LHPIS (8) +#define SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE (7) +#define SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE (6) +#define SUN6I_CODEC_OM_DACA_CTRL_HPVOL (0) +#define SUN6I_CODEC_OM_PA_CTRL (0x24) +#define SUN6I_CODEC_OM_PA_CTRL_HPPAEN (31) +#define SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL (29) +#define SUN6I_CODEC_OM_PA_CTRL_COMPTEN (28) +#define SUN6I_CODEC_OM_PA_CTRL_MIC1G (15) +#define SUN6I_CODEC_OM_PA_CTRL_MIC2G (12) +#define SUN6I_CODEC_OM_PA_CTRL_LINEING (9) +#define SUN6I_CODEC_OM_PA_CTRL_PHONEG (6) +#define SUN6I_CODEC_OM_PA_CTRL_PHONEPG (3) +#define SUN6I_CODEC_OM_PA_CTRL_PHONENG (0) + +/* Microphone, line out and phone out controls */ +#define SUN6I_CODEC_MIC_CTRL (0x28) +#define SUN6I_CODEC_MIC_CTRL_HBIASEN (31) +#define SUN6I_CODEC_MIC_CTRL_MBIASEN (30) +#define SUN6I_CODEC_MIC_CTRL_MIC1AMPEN (28) +#define SUN6I_CODEC_MIC_CTRL_MIC1BOOST (25) +#define SUN6I_CODEC_MIC_CTRL_MIC2AMPEN (24) +#define SUN6I_CODEC_MIC_CTRL_MIC2BOOST (21) +#define SUN6I_CODEC_MIC_CTRL_MIC2SLT (20) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTLEN (19) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTREN (18) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC (17) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC (16) +#define SUN6I_CODEC_MIC_CTRL_LINEOUTVC (11) +#define SUN6I_CODEC_MIC_CTRL_PHONEPREG (8) + +/* ADC mixer controls */ +#define SUN6I_CODEC_ADC_ACTL (0x2c) +#define SUN6I_CODEC_ADC_ACTL_ADCREN (31) +#define SUN6I_CODEC_ADC_ACTL_ADCLEN (30) +#define SUN6I_CODEC_ADC_ACTL_ADCRG (27) +#define SUN6I_CODEC_ADC_ACTL_ADCLG (24) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1 (13) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2 (12) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONE (11) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_PHONEP (10) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR (9) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR (8) +#define SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL (7) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1 (6) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2 (5) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONE (4) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_PHONEN (3) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL (2) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL (1) +#define SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR (0) + +/* Analog performance tuning controls */ +#define SUN6I_CODEC_ADDA_TUNE (0x30) + +/* Calibration controls */ +#define SUN6I_CODEC_CALIBRATION (0x34) + +/* FIFO counters */ +#define SUN6I_CODEC_DAC_TXCNT (0x40) +#define SUN6I_CODEC_ADC_RXCNT (0x44) + +/* headset jack detection and button support registers */ +#define SUN6I_CODEC_HMIC_CTL (0x50) +#define SUN6I_CODEC_HMIC_DATA (0x54) + +/* TODO sun6i DAP (Digital Audio Processing) bits */ + struct sun4i_codec { struct device *dev; struct regmap *regmap; @@ -214,9 +317,14 @@ static int sun4i_codec_prepare_capture(struct snd_pcm_substream *substream, * Allwinner's code mentions that it is related * related to microphone gain */ - regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, - 0x3 << 25, - 0x1 << 25); + if (of_device_is_compatible(scodec->dev->of_node, + "allwinner,sun4i-a10-codec") || + of_device_is_compatible(scodec->dev->of_node, + "allwinner,sun7i-a20-codec")) { + regmap_update_bits(scodec->regmap, SUN4I_CODEC_ADC_ACTL, + 0x3 << 25, + 0x1 << 25); + } if (of_device_is_compatible(scodec->dev->of_node, "allwinner,sun7i-a20-codec")) @@ -516,7 +624,7 @@ static struct snd_soc_dai_driver sun4i_codec_dai = { }, }; -/*** Codec ***/ +/*** sun4i Codec ***/ static const struct snd_kcontrol_new sun4i_codec_pa_mute = SOC_DAPM_SINGLE("Switch", SUN4I_CODEC_DAC_ACTL, SUN4I_CODEC_DAC_ACTL_PA_MUTE, 1, 0); @@ -652,6 +760,122 @@ static struct snd_soc_codec_driver sun4i_codec_codec = { }, }; +/*** sun6i Codec ***/ + +/* mixer controls */ +static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE("DAC Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACL, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACR, 1, 0), + SOC_DAPM_DOUBLE("DAC Reversed Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0), +}; + +/* headphone controls */ +static const char * const sun6i_codec_hp_src_enum_text[] = { + "DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_hp_src_enum, + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LHPIS, + SUN6I_CODEC_OM_DACA_CTRL_RHPIS, + sun6i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_hp_src[] = { + SOC_DAPM_ENUM("Headphone Source Playback Route", + sun6i_codec_hp_src_enum), +}; + +/* volume / mute controls */ +static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0); +static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1); + +static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0, + sun6i_codec_hp_vol_scale), + SOC_DOUBLE("Headphone Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE, + SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0), +}; + +static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, + NULL, 0), + + /* Analog parts of the DACs */ + SND_SOC_DAPM_DAC("Left DAC", "Codec Playback", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", "Codec Playback", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_DACAREN, 0), + + /* Mixers */ + SOC_MIXER_ARRAY("Left Mixer", SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIXEN, 0, + sun6i_codec_mixer_controls), + SOC_MIXER_ARRAY("Right Mixer", SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_RMIXEN, 0, + sun6i_codec_mixer_controls), + + /* Headphone output path */ + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun6i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN6I_CODEC_OM_PA_CTRL, + SUN6I_CODEC_OM_PA_CTRL_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN6I_CODEC_OM_PA_CTRL, + SUN6I_CODEC_OM_PA_CTRL_COMPTEN, 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL, + SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0), + SND_SOC_DAPM_OUTPUT("HP"), +}; + +static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + + /* Headphone Routes */ + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HP", NULL, "Headphone Amp" }, + { "HPCOM", NULL, "HPCOM Protection" }, +}; + +static struct snd_soc_codec_driver sun6i_codec_codec = { + .component_driver = { + .controls = sun6i_codec_codec_widgets, + .num_controls = ARRAY_SIZE(sun6i_codec_codec_widgets), + .dapm_widgets = sun6i_codec_codec_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun6i_codec_codec_dapm_widgets), + .dapm_routes = sun6i_codec_codec_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(sun6i_codec_codec_dapm_routes), + }, +}; + static const struct snd_soc_component_driver sun4i_codec_component = { .name = "sun4i-codec", }; @@ -756,6 +980,24 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) return card; }; +static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "A31 Audio Codec"; + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -763,6 +1005,13 @@ static const struct regmap_config sun4i_codec_regmap_config = { .max_register = SUN4I_CODEC_ADC_RXCNT, }; +static const struct regmap_config sun6i_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN6I_CODEC_HMIC_DATA, +}; + static const struct regmap_config sun7i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -788,6 +1037,16 @@ static const struct sun4i_codec_quirks sun4i_codec_quirks = { .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; +static const struct sun4i_codec_quirks sun6i_a31_codec_quirks = { + .regmap_config = &sun6i_codec_regmap_config, + .codec = &sun6i_codec_codec, + .create_card = sun6i_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + static const struct sun4i_codec_quirks sun7i_codec_quirks = { .regmap_config = &sun7i_codec_regmap_config, .codec = &sun4i_codec_codec, @@ -802,6 +1061,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun4i-a10-codec", .data = &sun4i_codec_quirks, }, + { + .compatible = "allwinner,sun6i-a31-codec", + .data = &sun6i_a31_codec_quirks, + }, { .compatible = "allwinner,sun7i-a20-codec", .data = &sun7i_codec_quirks, -- cgit v1.2.3-59-g8ed1b From dff5051250674fce575fa36c22b2f007363e42d0 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:49 +0800 Subject: ASoC: sun4i-codec: Add support for A31 Line In playback The A31 integrated codec has a stereo "Line In" input. Add support for it to the playback paths. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index d4b2186b5d84..72a84f76aa57 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -772,6 +772,10 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { SUN6I_CODEC_OM_DACA_CTRL, SUN6I_CODEC_OM_DACA_CTRL_LMIX_DACR, SUN6I_CODEC_OM_DACA_CTRL_RMIX_DACL, 1, 0), + SOC_DAPM_DOUBLE("Line In Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0), }; /* headphone controls */ @@ -793,6 +797,8 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = { /* volume / mute controls */ static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0); static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1); +static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale, + -450, 150, 0); static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, @@ -806,9 +812,16 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SUN6I_CODEC_OM_DACA_CTRL, SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE, SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0), + /* Mixer pre-gains */ + SOC_SINGLE_TLV("Line In Playback Volume", + SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING, + 0x7, 0, sun6i_codec_out_mixer_pregain_scale), }; static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { + /* Line In */ + SND_SOC_DAPM_INPUT("LINEIN"), + /* Digital parts of the DACs */ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, SUN4I_CODEC_DAC_DPC_EN_DA, 0, @@ -850,10 +863,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { /* Left Mixer Routes */ { "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, /* Right Mixer Routes */ { "Right Mixer", "DAC Playback Switch", "Right DAC" }, { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, /* Headphone Routes */ { "Headphone Source Playback Route", "DAC", "Left DAC" }, -- cgit v1.2.3-59-g8ed1b From 4323ec250cbc675c7fc40edf5f791a736210747b Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 4 Nov 2016 14:45:39 +0000 Subject: ASoC: codecs: msm8916-wcd-analog: clean parse_dt() Move the code which is not parsing dt from pm8916_wcd_analog_parse_dt() to make it clear to reader. No functional changes done. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index d9f999b14b28..50ad75ab10ea 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -802,7 +802,6 @@ static struct snd_soc_codec_driver pm8916_wcd_analog = { static int pm8916_wcd_analog_parse_dt(struct device *dev, struct pm8916_wcd_analog_priv *priv) { - int ret, i; if (of_property_read_bool(dev->of_node, "qcom,micbias1-ext-cap")) priv->micbias1_cap_mode = MICB_1_EN_EXT_BYP_CAP; @@ -814,21 +813,6 @@ static int pm8916_wcd_analog_parse_dt(struct device *dev, else priv->micbias2_cap_mode = MICB_1_EN_NO_EXT_BYP_CAP; - priv->mclk = devm_clk_get(dev, "mclk"); - if (IS_ERR(priv->mclk)) { - dev_err(dev, "failed to get mclk\n"); - return PTR_ERR(priv->mclk); - } - for (i = 0; i < ARRAY_SIZE(supply_names); i++) - priv->supplies[i].supply = supply_names[i]; - - ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), - priv->supplies); - if (ret) { - dev_err(dev, "Failed to get regulator supplies %d\n", ret); - return ret; - } - return 0; } @@ -836,7 +820,7 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) { struct pm8916_wcd_analog_priv *priv; struct device *dev = &pdev->dev; - int ret; + int ret, i; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -846,6 +830,22 @@ static int pm8916_wcd_analog_spmi_probe(struct platform_device *pdev) if (ret < 0) return ret; + priv->mclk = devm_clk_get(dev, "mclk"); + if (IS_ERR(priv->mclk)) { + dev_err(dev, "failed to get mclk\n"); + return PTR_ERR(priv->mclk); + } + + for (i = 0; i < ARRAY_SIZE(supply_names); i++) + priv->supplies[i].supply = supply_names[i]; + + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(priv->supplies), + priv->supplies); + if (ret) { + dev_err(dev, "Failed to get regulator supplies %d\n", ret); + return ret; + } + ret = clk_prepare_enable(priv->mclk); if (ret < 0) { dev_err(dev, "failed to enable mclk %d\n", ret); -- cgit v1.2.3-59-g8ed1b From ba9b8c42cff5aaf78229260c5622d6b699683e28 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Fri, 4 Nov 2016 14:45:40 +0000 Subject: ASoC: codecs: msm8916-wcd-digital: rename parse_dt to get_clks This patch renames msm8916_wcd_digital_parse_dt() to msm8916_wcd_digital_get_clks() as the function is not directly dealing with dt parsing. No functional changes done. Signed-off-by: Srinivas Kandagatla Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-digital.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/msm8916-wcd-digital.c b/sound/soc/codecs/msm8916-wcd-digital.c index e35501af91ab..f690442af8c9 100644 --- a/sound/soc/codecs/msm8916-wcd-digital.c +++ b/sound/soc/codecs/msm8916-wcd-digital.c @@ -539,7 +539,7 @@ static const struct snd_soc_dapm_widget msm8916_wcd_digital_dapm_widgets[] = { }; -static int msm8916_wcd_digital_parse_dt(struct platform_device *pdev, +static int msm8916_wcd_digital_get_clks(struct platform_device *pdev, struct msm8916_wcd_digital_priv *priv) { struct device *dev = &pdev->dev; @@ -866,7 +866,7 @@ static int msm8916_wcd_digital_probe(struct platform_device *pdev) if (IS_ERR(digital_map)) return PTR_ERR(digital_map); - ret = msm8916_wcd_digital_parse_dt(pdev, priv); + ret = msm8916_wcd_digital_get_clks(pdev, priv); if (ret < 0) return ret; -- cgit v1.2.3-59-g8ed1b From 17fb175520e5497d71351aa66a125324fcb625a7 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:04:12 +0800 Subject: ASoC: Define API to find a dai link Define the API to find an existing DAI link of the soc card by matching the ID, name and stream name. Some cards may use unique ID for each DAI link, so matching ID is enough, and name or stream name are not necessary. But user need to specify name or stream name as well if not sure whether link ID is unique since most cards use 0 as the default link ID. Topology can use this API to find an existing BE link and configure it. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc.h | 3 +++ sound/soc/soc-core.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 4f1c784e44f6..c3a38ee2b006 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1671,6 +1671,9 @@ int snd_soc_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); void snd_soc_remove_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link); +struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, + int id, const char *name, + const char *stream_name); int snd_soc_register_dai(struct snd_soc_component *component, struct snd_soc_dai_driver *dai_drv); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..a7a1ca40bcf5 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -972,6 +972,48 @@ struct snd_soc_dai *snd_soc_find_dai( } EXPORT_SYMBOL_GPL(snd_soc_find_dai); + +/** + * snd_soc_find_dai_link - Find a DAI link + * + * @card: soc card + * @id: DAI link ID to match + * @name: DAI link name to match, optional + * @stream name: DAI link stream name to match, optional + * + * This function will search all existing DAI links of the soc card to + * find the link of the same ID. Since DAI links may not have their + * unique ID, so name and stream name should also match if being + * specified. + * + * Return: pointer of DAI link, or NULL if not found. + */ +struct snd_soc_dai_link *snd_soc_find_dai_link(struct snd_soc_card *card, + int id, const char *name, + const char *stream_name) +{ + struct snd_soc_dai_link *link, *_link; + + lockdep_assert_held(&client_mutex); + + list_for_each_entry_safe(link, _link, &card->dai_link_list, list) { + if (link->id != id) + continue; + + if (name && (!link->name || strcmp(name, link->name))) + continue; + + if (stream_name && (!link->stream_name + || strcmp(stream_name, link->stream_name))) + continue; + + return link; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_find_dai_link); + static bool soc_is_dai_link_bound(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link) { -- cgit v1.2.3-59-g8ed1b From 593d9e52f9bb84bb4d8965278632e8ec7319f336 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:04:27 +0800 Subject: ASoC: topology: Add support to configure existing physical DAI links Topology will find an existing physical link (including BE link for DPCM) by checking its ID, name and stream name, and configure its physical audio format and flags. This support is backward compatible for old ABI v4. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8baa1761b874..b15a2049efcf 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -49,9 +49,10 @@ #define SOC_TPLG_PASS_GRAPH 5 #define SOC_TPLG_PASS_PINS 6 #define SOC_TPLG_PASS_BE_DAI 7 +#define SOC_TPLG_PASS_LINK 8 #define SOC_TPLG_PASS_START SOC_TPLG_PASS_MANIFEST -#define SOC_TPLG_PASS_END SOC_TPLG_PASS_BE_DAI +#define SOC_TPLG_PASS_END SOC_TPLG_PASS_LINK /* * Old version of ABI structs, supported for backward compatibility. @@ -101,6 +102,14 @@ struct snd_soc_tplg_pcm_v4 { struct snd_soc_tplg_stream_caps_v4 caps[2]; /* playback and capture for DAI */ } __packed; +/* Physical link config v4 */ +struct snd_soc_tplg_link_config_v4 { + __le32 size; /* in bytes of this structure */ + __le32 id; /* unique ID - used to match */ + struct snd_soc_tplg_stream stream[SND_SOC_TPLG_STREAM_CONFIG_MAX]; /* supported configs playback and captrure */ + __le32 num_streams; /* number of streams */ +} __packed; + /* topology context */ struct soc_tplg { const struct firmware *fw; @@ -1868,7 +1877,6 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, /* create the FE DAIs and DAI links */ soc_tplg_pcm_create(tplg, _pcm); - /* offset by version-specific struct size and * real priv data size */ @@ -1883,6 +1891,196 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, return 0; } +/** + * set_link_hw_format - Set the HW audio format of the physical DAI link. + * @tplg: topology context + * @cfg: physical link configs. + * + * Topology context contains a list of supported HW formats (configs) and + * a default format ID for the physical link. This function will use this + * default ID to choose the HW format to set the link's DAI format for init. + */ +static void set_link_hw_format(struct snd_soc_dai_link *link, + struct snd_soc_tplg_link_config *cfg) +{ + struct snd_soc_tplg_hw_config *hw_config; + unsigned char bclk_master, fsync_master; + unsigned char invert_bclk, invert_fsync; + int i; + + for (i = 0; i < cfg->num_hw_configs; i++) { + hw_config = &cfg->hw_config[i]; + if (hw_config->id != cfg->default_hw_config_id) + continue; + + link->dai_fmt = hw_config->fmt & SND_SOC_DAIFMT_FORMAT_MASK; + + /* clock signal polarity */ + invert_bclk = hw_config->invert_bclk; + invert_fsync = hw_config->invert_fsync; + if (!invert_bclk && !invert_fsync) + link->dai_fmt |= SND_SOC_DAIFMT_NB_NF; + else if (!invert_bclk && invert_fsync) + link->dai_fmt |= SND_SOC_DAIFMT_NB_IF; + else if (invert_bclk && !invert_fsync) + link->dai_fmt |= SND_SOC_DAIFMT_IB_NF; + else + link->dai_fmt |= SND_SOC_DAIFMT_IB_IF; + + /* clock masters */ + bclk_master = hw_config->bclk_master; + fsync_master = hw_config->fsync_master; + if (!bclk_master && !fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + else if (bclk_master && !fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFM; + else if (!bclk_master && fsync_master) + link->dai_fmt |= SND_SOC_DAIFMT_CBM_CFS; + else + link->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + } +} + +/** + * link_new_ver - Create a new physical link config from the old + * version of source. + * @toplogy: topology context + * @src: old version of phyical link config as a source + * @link: latest version of physical link config created from the source + * + * Support from vesion 4. User need free the returned link config manually. + */ +static int link_new_ver(struct soc_tplg *tplg, + struct snd_soc_tplg_link_config *src, + struct snd_soc_tplg_link_config **link) +{ + struct snd_soc_tplg_link_config *dest; + struct snd_soc_tplg_link_config_v4 *src_v4; + int i; + + *link = NULL; + + if (src->size != sizeof(struct snd_soc_tplg_link_config_v4)) { + dev_err(tplg->dev, "ASoC: invalid physical link config size\n"); + return -EINVAL; + } + + dev_warn(tplg->dev, "ASoC: old version of physical link config\n"); + + src_v4 = (struct snd_soc_tplg_link_config_v4 *)src; + dest = kzalloc(sizeof(*dest), GFP_KERNEL); + if (!dest) + return -ENOMEM; + + dest->size = sizeof(*dest); + dest->id = src_v4->id; + dest->num_streams = src_v4->num_streams; + for (i = 0; i < dest->num_streams; i++) + memcpy(&dest->stream[i], &src_v4->stream[i], + sizeof(struct snd_soc_tplg_stream)); + + *link = dest; + return 0; +} + +/* Find and configure an existing physical DAI link */ +static int soc_tplg_link_config(struct soc_tplg *tplg, + struct snd_soc_tplg_link_config *cfg) +{ + struct snd_soc_dai_link *link; + const char *name, *stream_name; + int ret; + + name = strlen(cfg->name) ? cfg->name : NULL; + stream_name = strlen(cfg->stream_name) ? cfg->stream_name : NULL; + + link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, + name, stream_name); + if (!link) { + dev_err(tplg->dev, "ASoC: physical link %s (id %d) not exist\n", + name, cfg->id); + return -EINVAL; + } + + /* hw format */ + if (cfg->num_hw_configs) + set_link_hw_format(link, cfg); + + /* flags */ + if (cfg->flag_mask) + set_link_flags(link, cfg->flag_mask, cfg->flags); + + /* pass control to component driver for optional further init */ + ret = soc_tplg_dai_link_load(tplg, link); + if (ret < 0) { + dev_err(tplg->dev, "ASoC: physical link loading failed\n"); + return ret; + } + + return 0; +} + + +/* Load physical link config elements from the topology context */ +static int soc_tplg_link_elems_load(struct soc_tplg *tplg, + struct snd_soc_tplg_hdr *hdr) +{ + struct snd_soc_tplg_link_config *link, *_link; + int count = hdr->count; + int i, ret; + bool abi_match; + + if (tplg->pass != SOC_TPLG_PASS_LINK) { + tplg->pos += hdr->size + hdr->payload_size; + return 0; + }; + + /* check the element size and count */ + link = (struct snd_soc_tplg_link_config *)tplg->pos; + if (link->size > sizeof(struct snd_soc_tplg_link_config) + || link->size < sizeof(struct snd_soc_tplg_link_config_v4)) { + dev_err(tplg->dev, "ASoC: invalid size %d for physical link elems\n", + link->size); + return -EINVAL; + } + + if (soc_tplg_check_elem_count(tplg, + link->size, count, + hdr->payload_size, "physical link config")) { + dev_err(tplg->dev, "ASoC: invalid count %d for physical link elems\n", + count); + return -EINVAL; + } + + /* config physical DAI links */ + for (i = 0; i < count; i++) { + link = (struct snd_soc_tplg_link_config *)tplg->pos; + if (link->size == sizeof(*link)) { + abi_match = true; + _link = link; + } else { + abi_match = false; + ret = link_new_ver(tplg, link, &_link); + if (ret < 0) + return ret; + } + + ret = soc_tplg_link_config(tplg, _link); + if (ret < 0) + return ret; + + /* offset by version-specific struct size and + * real priv data size + */ + tplg->pos += link->size + _link->priv.size; + + if (!abi_match) + kfree(_link); /* free the duplicated one */ + } + + return 0; +} + /* * * soc_tplg_be_dai_config - Find and configure an existing BE DAI. * @tplg: topology context @@ -2132,6 +2330,10 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, return soc_tplg_pcm_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_BE_DAI: return soc_tplg_be_dai_elems_load(tplg, hdr); + case SND_SOC_TPLG_TYPE_DAI_LINK: + case SND_SOC_TPLG_TYPE_BACKEND_LINK: + /* physical link configurations */ + return soc_tplg_link_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_MANIFEST: return soc_tplg_manifest_load(tplg, hdr); default: -- cgit v1.2.3-59-g8ed1b From ab4bc5eed8e9c9fa36d80d58c55300dd1eef29a3 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:04:42 +0800 Subject: ASoC: topology: Rename the function to create a FE link Just code refactoring. The function soc_tplg_link_create() will create a front end link, not a physical link. So rename it to soc_tplg_fe_link_create(). Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index b15a2049efcf..eea28ade5b32 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1704,7 +1704,7 @@ static void set_link_flags(struct snd_soc_dai_link *link, } /* create the FE DAI link */ -static int soc_tplg_link_create(struct soc_tplg *tplg, +static int soc_tplg_fe_link_create(struct soc_tplg *tplg, struct snd_soc_tplg_pcm *pcm) { struct snd_soc_dai_link *link; @@ -1760,7 +1760,7 @@ static int soc_tplg_pcm_create(struct soc_tplg *tplg, if (ret < 0) return ret; - return soc_tplg_link_create(tplg, pcm); + return soc_tplg_fe_link_create(tplg, pcm); } /* copy stream caps from the old version 4 of source */ -- cgit v1.2.3-59-g8ed1b From 3fbf793510c7628248a965972112fab958e6e3cf Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:05:01 +0800 Subject: ASoC: topology: ABI - Rename struct and type for physical DAIs Rename the ABI struct and type because they are for configuring physical DAIs, not only backend DAIs since users may not need DPCM: - Rename struct snd_soc_tplg_be_dai to snd_soc_tplg_dai. - Rename type SND_SOC_TPLG_TYPE_BE_DAI to SND_SOC_TPLG_TYPE_DAI. This code refactoring is backward compatible because: - Both layout of the struct and type value has no change. Kernel can find the same type value and map to same data layout. - This struct is not in ABI v4 at all. Now the user space uses ABI v4. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/uapi/sound/asoc.h | 15 ++++++++------- sound/soc/soc-topology.c | 8 ++++---- 2 files changed, 12 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index ed28ebc392d1..3c3fcc86b9f4 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -111,8 +111,8 @@ #define SND_SOC_TPLG_TYPE_CODEC_LINK 9 #define SND_SOC_TPLG_TYPE_BACKEND_LINK 10 #define SND_SOC_TPLG_TYPE_PDATA 11 -#define SND_SOC_TPLG_TYPE_BE_DAI 12 -#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_BE_DAI +#define SND_SOC_TPLG_TYPE_DAI 12 +#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_DAI /* vendor block IDs - please add new vendor types to end */ #define SND_SOC_TPLG_TYPE_VENDOR_FW 1000 @@ -131,7 +131,7 @@ #define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 #define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5 -/* BE DAI flags */ +/* DAI flags */ #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_RATES (1 << 0) #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) #define SND_SOC_TPLG_DAI_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) @@ -527,16 +527,17 @@ struct snd_soc_tplg_link_config { } __attribute__((packed)); /* - * Describes SW/FW specific features of BE DAI. + * Describes SW/FW specific features of physical DAI. + * It can be used to configure backend DAIs for DPCM. * - * File block representation for BE DAI :- + * File block representation for physical DAI :- * +-----------------------------------+-----+ * | struct snd_soc_tplg_hdr | 1 | * +-----------------------------------+-----+ - * | struct snd_soc_tplg_be_dai | N | + * | struct snd_soc_tplg_dai | N | * +-----------------------------------+-----+ */ -struct snd_soc_tplg_be_dai { +struct snd_soc_tplg_dai { __le32 size; /* in bytes of this structure */ char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* name - used to match */ __le32 dai_id; /* unique ID - used to match */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index eea28ade5b32..a839dc857e0d 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2090,7 +2090,7 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, * platform driver should specify the BE DAI name and ID for matching. */ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, - struct snd_soc_tplg_be_dai *be) + struct snd_soc_tplg_dai *be) { struct snd_soc_dai_link_component dai_component = {0}; struct snd_soc_dai *dai; @@ -2145,7 +2145,7 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_be_dai *be; + struct snd_soc_tplg_dai *be; int count = hdr->count; int i; @@ -2154,7 +2154,7 @@ static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, /* config the existing BE DAIs */ for (i = 0; i < count; i++) { - be = (struct snd_soc_tplg_be_dai *)tplg->pos; + be = (struct snd_soc_tplg_dai *)tplg->pos; if (be->size != sizeof(*be)) { dev_err(tplg->dev, "ASoC: invalid BE DAI size\n"); return -EINVAL; @@ -2328,7 +2328,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, return soc_tplg_dapm_widget_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_PCM: return soc_tplg_pcm_elems_load(tplg, hdr); - case SND_SOC_TPLG_TYPE_BE_DAI: + case SND_SOC_TPLG_TYPE_DAI: return soc_tplg_be_dai_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_DAI_LINK: case SND_SOC_TPLG_TYPE_BACKEND_LINK: -- cgit v1.2.3-59-g8ed1b From 9aa3f03473ce1187062bb0c68aeacf7b3ac52831 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:05:15 +0800 Subject: ASoC: topology: Rename functions & variables for physical DAIs Code refactoring. These functions and variables are for configuring physical DAIs, not only backend DAIs since users may not need DPCM. So remove 'be' from the function names, and rename variables 'be' to 'd' or 'dai'. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index a839dc857e0d..f44f12eb1798 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -2081,16 +2081,16 @@ static int soc_tplg_link_elems_load(struct soc_tplg *tplg, return 0; } -/* * - * soc_tplg_be_dai_config - Find and configure an existing BE DAI. +/** + * soc_tplg_dai_config - Find and configure an existing physical DAI. * @tplg: topology context - * @be: topology BE DAI configs. + * @d: physical DAI configs. * - * The BE dai should already be registered by the platform driver. The - * platform driver should specify the BE DAI name and ID for matching. + * The physical dai should already be registered by the platform driver. + * The platform driver should specify the DAI name and ID for matching. */ -static int soc_tplg_be_dai_config(struct soc_tplg *tplg, - struct snd_soc_tplg_dai *be) +static int soc_tplg_dai_config(struct soc_tplg *tplg, + struct snd_soc_tplg_dai *d) { struct snd_soc_dai_link_component dai_component = {0}; struct snd_soc_dai *dai; @@ -2099,17 +2099,17 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, struct snd_soc_tplg_stream_caps *caps; int ret; - dai_component.dai_name = be->dai_name; + dai_component.dai_name = d->dai_name; dai = snd_soc_find_dai(&dai_component); if (!dai) { - dev_err(tplg->dev, "ASoC: BE DAI %s not registered\n", - be->dai_name); + dev_err(tplg->dev, "ASoC: physical DAI %s not registered\n", + d->dai_name); return -EINVAL; } - if (be->dai_id != dai->id) { - dev_err(tplg->dev, "ASoC: BE DAI %s id mismatch\n", - be->dai_name); + if (d->dai_id != dai->id) { + dev_err(tplg->dev, "ASoC: physical DAI %s id mismatch\n", + d->dai_name); return -EINVAL; } @@ -2117,20 +2117,20 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, if (!dai_drv) return -EINVAL; - if (be->playback) { + if (d->playback) { stream = &dai_drv->playback; - caps = &be->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; + caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK]; set_stream_info(stream, caps); } - if (be->capture) { + if (d->capture) { stream = &dai_drv->capture; - caps = &be->caps[SND_SOC_TPLG_STREAM_CAPTURE]; + caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE]; set_stream_info(stream, caps); } - if (be->flag_mask) - set_dai_flags(dai_drv, be->flag_mask, be->flags); + if (d->flag_mask) + set_dai_flags(dai_drv, d->flag_mask, d->flags); /* pass control to component driver for optional further init */ ret = soc_tplg_dai_load(tplg, dai_drv); @@ -2142,10 +2142,11 @@ static int soc_tplg_be_dai_config(struct soc_tplg *tplg, return 0; } -static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, - struct snd_soc_tplg_hdr *hdr) +/* load physical DAI elements */ +static int soc_tplg_dai_elems_load(struct soc_tplg *tplg, + struct snd_soc_tplg_hdr *hdr) { - struct snd_soc_tplg_dai *be; + struct snd_soc_tplg_dai *dai; int count = hdr->count; int i; @@ -2154,14 +2155,14 @@ static int soc_tplg_be_dai_elems_load(struct soc_tplg *tplg, /* config the existing BE DAIs */ for (i = 0; i < count; i++) { - be = (struct snd_soc_tplg_dai *)tplg->pos; - if (be->size != sizeof(*be)) { - dev_err(tplg->dev, "ASoC: invalid BE DAI size\n"); + dai = (struct snd_soc_tplg_dai *)tplg->pos; + if (dai->size != sizeof(*dai)) { + dev_err(tplg->dev, "ASoC: invalid physical DAI size\n"); return -EINVAL; } - soc_tplg_be_dai_config(tplg, be); - tplg->pos += (sizeof(*be) + be->priv.size); + soc_tplg_dai_config(tplg, dai); + tplg->pos += (sizeof(*dai) + dai->priv.size); } dev_dbg(tplg->dev, "ASoC: Configure %d BE DAIs\n", count); @@ -2329,7 +2330,7 @@ static int soc_tplg_load_header(struct soc_tplg *tplg, case SND_SOC_TPLG_TYPE_PCM: return soc_tplg_pcm_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_DAI: - return soc_tplg_be_dai_elems_load(tplg, hdr); + return soc_tplg_dai_elems_load(tplg, hdr); case SND_SOC_TPLG_TYPE_DAI_LINK: case SND_SOC_TPLG_TYPE_BACKEND_LINK: /* physical link configurations */ -- cgit v1.2.3-59-g8ed1b From 6ff67ccafdf4c782489de1ccc47e1ec8d8480b63 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Thu, 3 Nov 2016 01:05:32 +0800 Subject: ASoC: topology: ABI - Add voice wake up flag for DAI links Add a new flag bit SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP to link flags. If a link is used for voice wake up, users can set this flag bit and topology will set the link's 'ignore_suspend' to true. This ABI update is backward compatible. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/uapi/sound/asoc.h | 1 + sound/soc/soc-topology.c | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'sound') diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index 3c3fcc86b9f4..6a4280c6e860 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h @@ -155,6 +155,7 @@ #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_RATES (1 << 0) #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_CHANNELS (1 << 1) #define SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS (1 << 2) +#define SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP (1 << 3) /* * Block Header. diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index f44f12eb1798..8772fd994e82 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1701,6 +1701,11 @@ static void set_link_flags(struct snd_soc_dai_link *link, link->symmetric_samplebits = flags & SND_SOC_TPLG_LNK_FLGBIT_SYMMETRIC_SAMPLEBITS ? 1 : 0; + + if (flag_mask & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP) + link->ignore_suspend = + flags & SND_SOC_TPLG_LNK_FLGBIT_VOICE_WAKEUP ? + 1 : 0; } /* create the FE DAI link */ -- cgit v1.2.3-59-g8ed1b From 355602eb5af91ff8ddda435f0f9e910f3b18c438 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 4 Nov 2016 18:26:53 +0100 Subject: ASoC: stac9766: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used instead and the defines are unused. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h index c726f907e2c0..cb0d5505d571 100644 --- a/sound/soc/codecs/stac9766.h +++ b/sound/soc/codecs/stac9766.h @@ -10,8 +10,4 @@ #define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E) #define AC97_STAC_STEREO_MIC 0x78 -/* STAC9766 DAI ID's */ -#define STAC9766_DAI_AC97_ANALOG 0 -#define STAC9766_DAI_AC97_DIGITAL 1 - #endif -- cgit v1.2.3-59-g8ed1b From 2bea8f97d4c3aded4c71d72e8702aa7dbe9894cf Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 4 Nov 2016 18:26:54 +0100 Subject: ASoC: stac9766: Remove register paging support The AC'97 standard defines paging support for the register range 0x60-0x6f. Meaning registers in this window are mapped to different physical registers depending on the setting of the page select register (0x24). The stac9766 implements support for switching between page 0 and page 1 depending on the addressed register. But the driver never accesses any registers from page 1, in addition page 0 is the page selected by default. Considering the development history it is unlikely that the driver will see any new features that require paging support. Removing the paging support makes transitioning the driver to regmap a bit more straight forward. The default register value table is update to contain the values from page 0, rather than page 1. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 16 ++-------------- sound/soc/codecs/stac9766.h | 5 ++--- 2 files changed, 4 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 27f30d352867..e54e4a4ce296 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -47,8 +47,8 @@ static const u16 stac9766_reg[] = { 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ - 0x1201, 0xFFFF, 0xFFFF, 0x0000, /* 66 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ + 0x1201, 0x0000, 0x0000, 0x0000, /* 66 */ + 0x0000, 0x0000, 0x0000, 0x1000, /* 6e */ 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ }; @@ -145,12 +145,6 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 *cache = codec->reg_cache; - if (reg > AC97_STAC_PAGE0) { - stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - soc_ac97_ops->write(ac97, reg, val); - stac9766_ac97_write(codec, AC97_INT_PAGING, 1); - return 0; - } if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) return -EIO; @@ -165,12 +159,6 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); u16 val = 0, *cache = codec->reg_cache; - if (reg > AC97_STAC_PAGE0) { - stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0); - stac9766_ac97_write(codec, AC97_INT_PAGING, 1); - return val; - } if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) return -EIO; diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h index cb0d5505d571..e35cee82f416 100644 --- a/sound/soc/codecs/stac9766.h +++ b/sound/soc/codecs/stac9766.h @@ -5,9 +5,8 @@ #ifndef _STAC9766_H #define _STAC9766_H -#define AC97_STAC_PAGE0 0x1000 -#define AC97_STAC_DA_CONTROL (AC97_STAC_PAGE0 | 0x6A) -#define AC97_STAC_ANALOG_SPECIAL (AC97_STAC_PAGE0 | 0x6E) +#define AC97_STAC_DA_CONTROL 0x6A +#define AC97_STAC_ANALOG_SPECIAL 0x6E #define AC97_STAC_STEREO_MIC 0x78 #endif -- cgit v1.2.3-59-g8ed1b From dccb395c268e9f96dfaf3f3bb9933aa9a0ded8cc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 4 Nov 2016 18:26:55 +0100 Subject: ASoC: stac9766: Move register defines to main source file The stac9766 driver has a header file that defines 3 register locations. Move these to the main source file since it is not really worth it having a separate file for them. The header file is now empty and can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 6 ++++-- sound/soc/codecs/stac9766.h | 12 ------------ sound/soc/fsl/efika-audio-fabric.c | 1 - 3 files changed, 4 insertions(+), 15 deletions(-) delete mode 100644 sound/soc/codecs/stac9766.h (limited to 'sound') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index e54e4a4ce296..f675d343b529 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -26,11 +26,13 @@ #include #include -#include "stac9766.h" - #define STAC9766_VENDOR_ID 0x83847666 #define STAC9766_VENDOR_ID_MASK 0xffffffff +#define AC97_STAC_DA_CONTROL 0x6A +#define AC97_STAC_ANALOG_SPECIAL 0x6E +#define AC97_STAC_STEREO_MIC 0x78 + /* * STAC9766 register cache */ diff --git a/sound/soc/codecs/stac9766.h b/sound/soc/codecs/stac9766.h deleted file mode 100644 index e35cee82f416..000000000000 --- a/sound/soc/codecs/stac9766.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * stac9766.h -- STAC9766 Soc Audio driver - */ - -#ifndef _STAC9766_H -#define _STAC9766_H - -#define AC97_STAC_DA_CONTROL 0x6A -#define AC97_STAC_ANALOG_SPECIAL 0x6E -#define AC97_STAC_STEREO_MIC 0x78 - -#endif diff --git a/sound/soc/fsl/efika-audio-fabric.c b/sound/soc/fsl/efika-audio-fabric.c index b2acd3293ea8..f200d1cfc4bd 100644 --- a/sound/soc/fsl/efika-audio-fabric.c +++ b/sound/soc/fsl/efika-audio-fabric.c @@ -27,7 +27,6 @@ #include "mpc5200_dma.h" #include "mpc5200_psc_ac97.h" -#include "../codecs/stac9766.h" #define DRV_NAME "efika-audio-fabric" -- cgit v1.2.3-59-g8ed1b From 6bbf787bb70c8a16509a2d51182423a6f6977742 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 4 Nov 2016 18:26:56 +0100 Subject: ASoC: stac9766: Convert to regmap Currently the stac9766 driver still uses custom snd_soc_codec_driver IO callbacks. This has been deprecated for a while, so convert the stac9766 driver to use regmap for its IO. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 108 ++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 49 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index f675d343b529..62cbeedf93b9 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -33,26 +34,49 @@ #define AC97_STAC_ANALOG_SPECIAL 0x6E #define AC97_STAC_STEREO_MIC 0x78 -/* - * STAC9766 register cache - */ -static const u16 stac9766_reg[] = { - 0x6A90, 0x8000, 0x8000, 0x8000, /* 6 */ - 0x0000, 0x0000, 0x8008, 0x8008, /* e */ - 0x8808, 0x8808, 0x8808, 0x8808, /* 16 */ - 0x8808, 0x0000, 0x8000, 0x0000, /* 1e */ - 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */ - 0x0a05, 0x0400, 0xbb80, 0x0000, /* 2e */ - 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */ - 0x0000, 0x2000, 0x0000, 0x0100, /* 3e */ - 0x0000, 0x0000, 0x0080, 0x0000, /* 46 */ - 0x0000, 0x0000, 0x0003, 0xffff, /* 4e */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 56 */ - 0x4000, 0x0000, 0x0000, 0x0000, /* 5e */ - 0x1201, 0x0000, 0x0000, 0x0000, /* 66 */ - 0x0000, 0x0000, 0x0000, 0x1000, /* 6e */ - 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ - 0x0000, 0x0000, 0x0000, 0x0000, /* 7e */ +static const struct reg_default stac9766_reg_defaults[] = { + { 0x02, 0x8000 }, + { 0x04, 0x8000 }, + { 0x06, 0x8000 }, + { 0x0a, 0x0000 }, + { 0x0c, 0x8008 }, + { 0x0e, 0x8008 }, + { 0x10, 0x8808 }, + { 0x12, 0x8808 }, + { 0x14, 0x8808 }, + { 0x16, 0x8808 }, + { 0x18, 0x8808 }, + { 0x1a, 0x0000 }, + { 0x1c, 0x8000 }, + { 0x20, 0x0000 }, + { 0x22, 0x0000 }, + { 0x28, 0x0a05 }, + { 0x2c, 0xbb80 }, + { 0x32, 0xbb80 }, + { 0x3a, 0x2000 }, + { 0x3e, 0x0100 }, + { 0x4c, 0x0300 }, + { 0x4e, 0xffff }, + { 0x50, 0x0000 }, + { 0x52, 0x0000 }, + { 0x54, 0x0000 }, + { 0x6a, 0x0000 }, + { 0x6e, 0x1000 }, + { 0x72, 0x0000 }, + { 0x78, 0x0000 }, +}; + +static const struct regmap_config stac9766_regmap_config = { + .reg_bits = 16, + .reg_stride = 2, + .val_bits = 16, + .max_register = 0x78, + .cache_type = REGCACHE_RBTREE, + + .volatile_reg = regmap_ac97_default_volatile, + + .reg_defaults = stac9766_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(stac9766_reg_defaults), }; static const char *stac9766_record_mux[] = {"Mic", "CD", "Video", "AUX", @@ -144,34 +168,13 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 *cache = codec->reg_cache; - - if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) - return -EIO; - - soc_ac97_ops->write(ac97, reg, val); - cache[reg / 2] = val; - return 0; + return snd_soc_write(codec, reg, val); } static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, unsigned int reg) { - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 val = 0, *cache = codec->reg_cache; - - if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) - return -EIO; - - if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || - reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || - reg == AC97_VENDOR_ID2) { - - val = soc_ac97_ops->read(ac97, reg); - return val; - } - return cache[reg / 2]; + return snd_soc_read(codec, reg); } static int ac97_analog_prepare(struct snd_pcm_substream *substream, @@ -290,21 +293,34 @@ static struct snd_soc_dai_driver stac9766_dai[] = { static int stac9766_codec_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; + struct regmap *regmap; + int ret; ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, STAC9766_VENDOR_ID_MASK); if (IS_ERR(ac97)) return PTR_ERR(ac97); + regmap = regmap_init_ac97(ac97, &stac9766_regmap_config); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + goto err_free_ac97; + } + + snd_soc_codec_init_regmap(codec, regmap); snd_soc_codec_set_drvdata(codec, ac97); return 0; +err_free_ac97: + snd_soc_free_ac97_codec(ac97); + return ret; } static int stac9766_codec_remove(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); + snd_soc_codec_exit_regmap(codec); snd_soc_free_ac97_codec(ac97); return 0; } @@ -314,17 +330,11 @@ static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { .controls = stac9766_snd_ac97_controls, .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), }, - .write = stac9766_ac97_write, - .read = stac9766_ac97_read, .set_bias_level = stac9766_set_bias_level, .suspend_bias_off = true, .probe = stac9766_codec_probe, .remove = stac9766_codec_remove, .resume = stac9766_codec_resume, - .reg_cache_size = ARRAY_SIZE(stac9766_reg), - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, - .reg_cache_default = stac9766_reg, }; static int stac9766_probe(struct platform_device *pdev) -- cgit v1.2.3-59-g8ed1b From 7aacbc7ff7f6da9ec6deb833154f0883497ab82f Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 4 Nov 2016 18:26:57 +0100 Subject: ASoC: stac9766: Remove ac97_read/ac97_write wrappers Since the regmap conversion ac97_read/ac97_write are just simple wrappers around snd_soc_read/snd_soc_write. Use those instead directly and remove the wrappers. Also use snd_soc_update_bits() where appropriate. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 40 +++++++++++----------------------------- 1 file changed, 11 insertions(+), 29 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 62cbeedf93b9..9de7fe8af255 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -165,38 +165,22 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { SOC_ENUM("Pop Bypass Mux", stac9766_popbypass_enum), }; -static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - return snd_soc_write(codec, reg, val); -} - -static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - return snd_soc_read(codec, reg); -} - static int ac97_analog_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned short reg, vra; - - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); + unsigned short reg; - vra |= 0x1; /* enable variable rate audio */ - vra &= ~0x4; /* disable SPDIF output */ - - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + /* enable variable rate audio, disable SPDIF output */ + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x1); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) reg = AC97_PCM_FRONT_DAC_RATE; else reg = AC97_PCM_LR_ADC_RATE; - return stac9766_ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int ac97_digital_prepare(struct snd_pcm_substream *substream, @@ -204,18 +188,16 @@ static int ac97_digital_prepare(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct snd_pcm_runtime *runtime = substream->runtime; - unsigned short reg, vra; - - stac9766_ac97_write(codec, AC97_SPDIF, 0x2002); + unsigned short reg; - vra = stac9766_ac97_read(codec, AC97_EXTENDED_STATUS); - vra |= 0x5; /* Enable VRA and SPDIF out */ + snd_soc_write(codec, AC97_SPDIF, 0x2002); - stac9766_ac97_write(codec, AC97_EXTENDED_STATUS, vra); + /* Enable VRA and SPDIF out */ + snd_soc_update_bits(codec, AC97_EXTENDED_STATUS, 0x5, 0x5); reg = AC97_PCM_FRONT_DAC_RATE; - return stac9766_ac97_write(codec, reg, runtime->rate); + return snd_soc_write(codec, reg, runtime->rate); } static int stac9766_set_bias_level(struct snd_soc_codec *codec, @@ -225,11 +207,11 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_ON: /* full On */ case SND_SOC_BIAS_PREPARE: /* partial On */ case SND_SOC_BIAS_STANDBY: /* Off, with power */ - stac9766_ac97_write(codec, AC97_POWERDOWN, 0x0000); + snd_soc_write(codec, AC97_POWERDOWN, 0x0000); break; case SND_SOC_BIAS_OFF: /* Off, without power */ /* disable everything including AC link */ - stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff); + snd_soc_write(codec, AC97_POWERDOWN, 0xffff); break; } return 0; -- cgit v1.2.3-59-g8ed1b From 0f909f98d7cbabc3641a45da9c6891444b929a92 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:50 +0800 Subject: ASoC: sun4i-codec: Add support for A31 Line Out playback The A31 integrated codec has a second "Line Out" output which does not include an integrated amplifier in its path. This path does have a separate volume control. This patch adds support for the playback path from the DAC to the Line Out pins. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 72a84f76aa57..a10251f4932e 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -794,11 +794,31 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = { sun6i_codec_hp_src_enum), }; +/* line out controls */ +static const char * const sun6i_codec_lineout_src_enum_text[] = { + "Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun6i_codec_lineout_src_enum, + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_LINEOUTLSRC, + SUN6I_CODEC_MIC_CTRL_LINEOUTRSRC, + sun6i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun6i_codec_lineout_src_enum), +}; + /* volume / mute controls */ static const DECLARE_TLV_DB_SCALE(sun6i_codec_dvol_scale, -7308, 116, 0); static const DECLARE_TLV_DB_SCALE(sun6i_codec_hp_vol_scale, -6300, 100, 1); static const DECLARE_TLV_DB_SCALE(sun6i_codec_out_mixer_pregain_scale, -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, @@ -808,10 +828,18 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SUN6I_CODEC_OM_DACA_CTRL, SUN6I_CODEC_OM_DACA_CTRL_HPVOL, 0x3f, 0, sun6i_codec_hp_vol_scale), + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_LINEOUTVC, 0x1f, 0, + sun6i_codec_lineout_vol_scale), SOC_DOUBLE("Headphone Playback Switch", SUN6I_CODEC_OM_DACA_CTRL, SUN6I_CODEC_OM_DACA_CTRL_LHPPAMUTE, SUN6I_CODEC_OM_DACA_CTRL_RHPPAMUTE, 1, 0), + SOC_DOUBLE("Line Out Playback Switch", + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_LINEOUTLEN, + SUN6I_CODEC_MIC_CTRL_LINEOUTREN, 1, 0), /* Mixer pre-gains */ SOC_SINGLE_TLV("Line In Playback Volume", SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING, @@ -853,6 +881,11 @@ static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_HPCOM_CTL, 0x3, 0x3, 0), SND_SOC_DAPM_OUTPUT("HP"), + + /* Line Out path */ + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun6i_codec_lineout_src), + SND_SOC_DAPM_OUTPUT("LINEOUT"), }; static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { @@ -878,6 +911,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { { "Headphone Amp", NULL, "Headphone Source Playback Route" }, { "HP", NULL, "Headphone Amp" }, { "HPCOM", NULL, "HPCOM Protection" }, + + /* Line Out Routes */ + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, }; static struct snd_soc_codec_driver sun6i_codec_codec = { -- cgit v1.2.3-59-g8ed1b From ecd5cdb4fd818b1cec55863d5de3683dad1c2f53 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:51 +0800 Subject: ASoC: sun4i-codec: Add support for A31 analog microphone inputs The A31 internal codec has 3 microphone outputs, of which MIC2 and MIC3 are muxed internally. The resulting two microphone inputs have separate gain controls and mixer inputs. The codec also has 2 microphone bias pins. HBIAS is specifically for the headphone jack, which also supports headphone detection and control buttons. These extra functions are not supported yet. The other, MBIAS, is for all other analog microphones. There is also mention of digital microphone support, but documentation is scarce, and no hardware with it is available. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 70 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index a10251f4932e..f55718fe7c5b 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -776,6 +776,14 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { SUN6I_CODEC_OM_DACA_CTRL, SUN6I_CODEC_OM_DACA_CTRL_LMIX_LINEINL, SUN6I_CODEC_OM_DACA_CTRL_RMIX_LINEINR, 1, 0), + SOC_DAPM_DOUBLE("Mic1 Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC1, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC1, 1, 0), + SOC_DAPM_DOUBLE("Mic2 Playback Switch", + SUN6I_CODEC_OM_DACA_CTRL, + SUN6I_CODEC_OM_DACA_CTRL_LMIX_MIC2, + SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0), }; /* headphone controls */ @@ -794,6 +802,21 @@ static const struct snd_kcontrol_new sun6i_codec_hp_src[] = { sun6i_codec_hp_src_enum), }; +/* microphone controls */ +static const char * const sun6i_codec_mic2_src_enum_text[] = { + "Mic2", "Mic3", +}; + +static SOC_ENUM_SINGLE_DECL(sun6i_codec_mic2_src_enum, + SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC2SLT, + sun6i_codec_mic2_src_enum_text); + +static const struct snd_kcontrol_new sun6i_codec_mic2_src[] = { + SOC_DAPM_ENUM("Mic2 Amplifier Source Route", + sun6i_codec_mic2_src_enum), +}; + /* line out controls */ static const char * const sun6i_codec_lineout_src_enum_text[] = { "Stereo", "Mono Differential", @@ -819,6 +842,10 @@ static const DECLARE_TLV_DB_RANGE(sun6i_codec_lineout_vol_scale, 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), ); +static const DECLARE_TLV_DB_RANGE(sun6i_codec_mic_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, @@ -844,9 +871,42 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SOC_SINGLE_TLV("Line In Playback Volume", SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_LINEING, 0x7, 0, sun6i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic1 Playback Volume", + SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC1G, + 0x7, 0, sun6i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN6I_CODEC_OM_PA_CTRL, SUN6I_CODEC_OM_PA_CTRL_MIC2G, + 0x7, 0, sun6i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gains */ + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC1BOOST, 0x7, 0, + sun6i_codec_mic_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0, + sun6i_codec_mic_gain_scale), }; static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("MIC3"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("HBIAS", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_HBIASEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MBIAS", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MBIASEN, 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_MUX("Mic2 Amplifier Source Route", + SND_SOC_NOPM, 0, 0, sun6i_codec_mic2_src), + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC1AMPEN, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN6I_CODEC_MIC_CTRL, + SUN6I_CODEC_MIC_CTRL_MIC2AMPEN, 0, NULL, 0), + /* Line In */ SND_SOC_DAPM_INPUT("LINEIN"), @@ -893,15 +953,25 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { { "Left DAC", NULL, "DAC Enable" }, { "Right DAC", NULL, "DAC Enable" }, + /* Microphone Routes */ + { "Mic1 Amplifier", NULL, "MIC1"}, + { "Mic2 Amplifier Source Route", "Mic2", "MIC2" }, + { "Mic2 Amplifier Source Route", "Mic3", "MIC3" }, + { "Mic2 Amplifier", NULL, "Mic2 Amplifier Source Route"}, + /* Left Mixer Routes */ { "Left Mixer", "DAC Playback Switch", "Left DAC" }, { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, /* Right Mixer Routes */ { "Right Mixer", "DAC Playback Switch", "Right DAC" }, { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, /* Headphone Routes */ { "Headphone Source Playback Route", "DAC", "Left DAC" }, -- cgit v1.2.3-59-g8ed1b From 300a18d13f7eaec789e79dc45bce026e098b45da Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Thu, 3 Nov 2016 15:55:53 +0800 Subject: ASoC: sun4i-codec: Add support for A31 board level audio routing The A31 SoC's codec has various inputs, outputs and microphone bias supplies. These can be routed on the board in different ways, such as: - HPCOM may be connected to have the headphone DC coupled. - Microphones all use the MBIAS main microphone supply or one mic may use the HBIAS supply, which supports headset detection and buttons. - Line Out may be routed to an audio jack, or an onboard speaker amp with power controls. Add support for specifying the audio routes in the device tree. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-codec.txt | 33 ++++++++++++++++++++++ sound/soc/sunxi/sun4i-codec.c | 21 ++++++++++++-- 2 files changed, 52 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index bf480e9683a3..d91a95377f49 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -22,6 +22,31 @@ Optional properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-codec" - resets: phandle to the reset control for this device +- allwinner,audio-routing: A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names include: + + Audio pins on the SoC: + "HP" + "HPCOM" + "LINEIN" + "LINEOUT" + "MIC1" + "MIC2" + "MIC3" + + Microphone biases from the SoC: + "HBIAS" + "MBIAS" + + Board connectors: + "Headphone" + "Headset Mic" + "Line In" + "Line Out" + "Mic" + "Speaker" Example: codec: codec@01c22c00 { @@ -45,4 +70,12 @@ codec: codec@01c22c00 { resets = <&ccu RST_APB1_CODEC>; dmas = <&dma 15>, <&dma 15>; dma-names = "rx", "tx"; + allwinner,audio-routing = + "Headphone", "HP", + "Speaker", "LINEOUT", + "LINEIN", "Line In", + "MIC1", "MBIAS", + "MIC1", "Mic", + "MIC2", "HBIAS", + "MIC2", "Headset Mic"; }; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index f55718fe7c5b..1934db29b2b5 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1104,9 +1104,19 @@ static struct snd_soc_card *sun4i_codec_create_card(struct device *dev) return card; }; +static const struct snd_soc_dapm_widget sun6i_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_LINE("Line In", NULL), + SND_SOC_DAPM_LINE("Line Out", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), +}; + static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) { struct snd_soc_card *card; + int ret; card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); if (!card) @@ -1116,8 +1126,15 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) if (!card->dai_link) return ERR_PTR(-ENOMEM); - card->dev = dev; - card->name = "A31 Audio Codec"; + card->dev = dev; + card->name = "A31 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); return card; }; -- cgit v1.2.3-59-g8ed1b From 4ce8e6a51abfc69bf222f676cfe938f7732385d7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 8 Nov 2016 15:48:06 +0100 Subject: ALSA: hda - Fix typo EPAD -> EAPD Signed-off-by: Lars-Peter Clausen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2f909dd8b7b8..47224c69cc06 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -420,7 +420,7 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) } /* generic shutup callback; - * just turning off EPAD and a little pause for avoiding pop-noise + * just turning off EAPD and a little pause for avoiding pop-noise */ static void alc_eapd_shutup(struct hda_codec *codec) { -- cgit v1.2.3-59-g8ed1b From 3b89e4b77ef9c2f985964fab17032db98f074ed0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Nov 2016 14:38:52 +0100 Subject: ASoC: lpass-platform: initialize dma channel number MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bugfix accidentally removed the implicit initialization of the dma channel number, causing undefined behavior when v->alloc_dma_channel is NULL: sound/soc/qcom/lpass-platform.c: In function ‘lpass_platform_pcmops_open’: sound/soc/qcom/lpass-platform.c:83:29: error: ‘dma_ch’ may be used uninitialized in this function [-Werror=maybe-uninitialized] This adds back an explicit initialization to zero, restoring the previous behavior for that case. Fixes: 022d00ee0b55 ("ASoC: lpass-platform: Fix broken pcm data usage") Signed-off-by: Arnd Bergmann Acked-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-platform.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index 07000f53db44..e223bc90b2ef 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -77,6 +77,9 @@ static int lpass_platform_pcmops_open(struct snd_pcm_substream *substream) if (v->alloc_dma_channel) dma_ch = v->alloc_dma_channel(drvdata, dir); + else + dma_ch = 0; + if (dma_ch < 0) return dma_ch; -- cgit v1.2.3-59-g8ed1b From 2c394ca79604b404fe60218670ab301ecb758b34 Mon Sep 17 00:00:00 2001 From: James Schulman Date: Mon, 7 Nov 2016 14:38:37 -0600 Subject: ASoC: Add support for CS42L42 codec Add support for Cirrus Logic CS42L42 codec. SoundWire support is not enabled. Features support for I2C control and I2S audio. Signed-off-by: James Schulman Signed-off-by: Mark Brown --- include/dt-bindings/sound/cs42l42.h | 73 ++ sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs42l42.c | 1987 +++++++++++++++++++++++++++++++++++ sound/soc/codecs/cs42l42.h | 776 ++++++++++++++ 5 files changed, 2843 insertions(+) create mode 100644 include/dt-bindings/sound/cs42l42.h create mode 100644 sound/soc/codecs/cs42l42.c create mode 100644 sound/soc/codecs/cs42l42.h (limited to 'sound') diff --git a/include/dt-bindings/sound/cs42l42.h b/include/dt-bindings/sound/cs42l42.h new file mode 100644 index 000000000000..399a123aed58 --- /dev/null +++ b/include/dt-bindings/sound/cs42l42.h @@ -0,0 +1,73 @@ +/* + * cs42l42.h -- CS42L42 ALSA SoC audio driver DT bindings header + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman + * Author: Brian Austin + * Author: Michael White + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __DT_CS42L42_H +#define __DT_CS42L42_H + +/* HPOUT Load Capacity */ +#define CS42L42_HPOUT_LOAD_1NF 0 +#define CS42L42_HPOUT_LOAD_10NF 1 + +/* HPOUT Clamp to GND Overide */ +#define CS42L42_HPOUT_CLAMP_EN 0 +#define CS42L42_HPOUT_CLAMP_DIS 1 + +/* Tip Sense Inversion */ +#define CS42L42_TS_INV_DIS 0 +#define CS42L42_TS_INV_EN 1 + +/* Tip Sense Debounce */ +#define CS42L42_TS_DBNCE_0 0 +#define CS42L42_TS_DBNCE_125 1 +#define CS42L42_TS_DBNCE_250 2 +#define CS42L42_TS_DBNCE_500 3 +#define CS42L42_TS_DBNCE_750 4 +#define CS42L42_TS_DBNCE_1000 5 +#define CS42L42_TS_DBNCE_1250 6 +#define CS42L42_TS_DBNCE_1500 7 + +/* Button Press Software Debounce Times */ +#define CS42L42_BTN_DET_INIT_DBNCE_MIN 0 +#define CS42L42_BTN_DET_INIT_DBNCE_DEFAULT 100 +#define CS42L42_BTN_DET_INIT_DBNCE_MAX 200 + +#define CS42L42_BTN_DET_EVENT_DBNCE_MIN 0 +#define CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT 10 +#define CS42L42_BTN_DET_EVENT_DBNCE_MAX 20 + +/* Button Detect Level Sensitivities */ +#define CS42L42_NUM_BIASES 4 + +#define CS42L42_HS_DET_LEVEL_15 0x0F +#define CS42L42_HS_DET_LEVEL_8 0x08 +#define CS42L42_HS_DET_LEVEL_4 0x04 +#define CS42L42_HS_DET_LEVEL_1 0x01 + +#define CS42L42_HS_DET_LEVEL_MIN 0 +#define CS42L42_HS_DET_LEVEL_MAX 0x3F + +/* HS Bias Ramp Rate */ + +#define CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL 0 +#define CS42L42_HSBIAS_RAMP_FAST 1 +#define CS42L42_HSBIAS_RAMP_SLOW 2 +#define CS42L42_HSBIAS_RAMP_SLOWEST 3 + +#define CS42L42_HSBIAS_RAMP_TIME0 10 +#define CS42L42_HSBIAS_RAMP_TIME1 40 +#define CS42L42_HSBIAS_RAMP_TIME2 90 +#define CS42L42_HSBIAS_RAMP_TIME3 170 + +#endif /* __DT_CS42L42_H */ diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index bf2f26dddfab..2aa709a0e87a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -49,6 +49,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS35L32 if I2C select SND_SOC_CS35L33 if I2C select SND_SOC_CS35L34 if I2C + select SND_SOC_CS42L42 if I2C select SND_SOC_CS42L51_I2C if I2C select SND_SOC_CS42L52 if I2C && INPUT select SND_SOC_CS42L56 if I2C && INPUT @@ -404,6 +405,10 @@ config SND_SOC_CS35L34 tristate "Cirrus Logic CS35L34 CODEC" depends on I2C +config SND_SOC_CS42L42 + tristate "Cirrus Logic CS42L42 CODEC" + depends on I2C + config SND_SOC_CS42L51 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 3f0cd9047f09..4bcafc345248 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -39,6 +39,7 @@ snd-soc-cq93vc-objs := cq93vc.o snd-soc-cs35l32-objs := cs35l32.o snd-soc-cs35l33-objs := cs35l33.o snd-soc-cs35l34-objs := cs35l34.o +snd-soc-cs42l42-objs := cs42l42.o snd-soc-cs42l51-objs := cs42l51.o snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o snd-soc-cs42l52-objs := cs42l52.o @@ -265,6 +266,7 @@ obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o +obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c new file mode 100644 index 000000000000..f3c10f5d68c8 --- /dev/null +++ b/sound/soc/codecs/cs42l42.c @@ -0,0 +1,1987 @@ +/* + * cs42l42.c -- CS42L42 ALSA SoC audio driver + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman + * Author: Brian Austin + * Author: Michael White + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cs42l42.h" + +static const struct reg_default cs42l42_reg_defaults[] = { + { CS42L42_FRZ_CTL, 0x00 }, + { CS42L42_SRC_CTL, 0x10 }, + { CS42L42_MCLK_STATUS, 0x02 }, + { CS42L42_MCLK_CTL, 0x02 }, + { CS42L42_SFTRAMP_RATE, 0xA4 }, + { CS42L42_I2C_DEBOUNCE, 0x88 }, + { CS42L42_I2C_STRETCH, 0x03 }, + { CS42L42_I2C_TIMEOUT, 0xB7 }, + { CS42L42_PWR_CTL1, 0xFF }, + { CS42L42_PWR_CTL2, 0x84 }, + { CS42L42_PWR_CTL3, 0x20 }, + { CS42L42_RSENSE_CTL1, 0x40 }, + { CS42L42_RSENSE_CTL2, 0x00 }, + { CS42L42_OSC_SWITCH, 0x00 }, + { CS42L42_OSC_SWITCH_STATUS, 0x05 }, + { CS42L42_RSENSE_CTL3, 0x1B }, + { CS42L42_TSENSE_CTL, 0x1B }, + { CS42L42_TSRS_INT_DISABLE, 0x00 }, + { CS42L42_TRSENSE_STATUS, 0x00 }, + { CS42L42_HSDET_CTL1, 0x77 }, + { CS42L42_HSDET_CTL2, 0x00 }, + { CS42L42_HS_SWITCH_CTL, 0xF3 }, + { CS42L42_HS_DET_STATUS, 0x00 }, + { CS42L42_HS_CLAMP_DISABLE, 0x00 }, + { CS42L42_MCLK_SRC_SEL, 0x00 }, + { CS42L42_SPDIF_CLK_CFG, 0x00 }, + { CS42L42_FSYNC_PW_LOWER, 0x00 }, + { CS42L42_FSYNC_PW_UPPER, 0x00 }, + { CS42L42_FSYNC_P_LOWER, 0xF9 }, + { CS42L42_FSYNC_P_UPPER, 0x00 }, + { CS42L42_ASP_CLK_CFG, 0x00 }, + { CS42L42_ASP_FRM_CFG, 0x10 }, + { CS42L42_FS_RATE_EN, 0x00 }, + { CS42L42_IN_ASRC_CLK, 0x00 }, + { CS42L42_OUT_ASRC_CLK, 0x00 }, + { CS42L42_PLL_DIV_CFG1, 0x00 }, + { CS42L42_ADC_OVFL_STATUS, 0x00 }, + { CS42L42_MIXER_STATUS, 0x00 }, + { CS42L42_SRC_STATUS, 0x00 }, + { CS42L42_ASP_RX_STATUS, 0x00 }, + { CS42L42_ASP_TX_STATUS, 0x00 }, + { CS42L42_CODEC_STATUS, 0x00 }, + { CS42L42_DET_INT_STATUS1, 0x00 }, + { CS42L42_DET_INT_STATUS2, 0x00 }, + { CS42L42_SRCPL_INT_STATUS, 0x00 }, + { CS42L42_VPMON_STATUS, 0x00 }, + { CS42L42_PLL_LOCK_STATUS, 0x00 }, + { CS42L42_TSRS_PLUG_STATUS, 0x00 }, + { CS42L42_ADC_OVFL_INT_MASK, 0x01 }, + { CS42L42_MIXER_INT_MASK, 0x0F }, + { CS42L42_SRC_INT_MASK, 0x0F }, + { CS42L42_ASP_RX_INT_MASK, 0x1F }, + { CS42L42_ASP_TX_INT_MASK, 0x0F }, + { CS42L42_CODEC_INT_MASK, 0x03 }, + { CS42L42_SRCPL_INT_MASK, 0xFF }, + { CS42L42_VPMON_INT_MASK, 0x01 }, + { CS42L42_PLL_LOCK_INT_MASK, 0x01 }, + { CS42L42_TSRS_PLUG_INT_MASK, 0x0F }, + { CS42L42_PLL_CTL1, 0x00 }, + { CS42L42_PLL_DIV_FRAC0, 0x00 }, + { CS42L42_PLL_DIV_FRAC1, 0x00 }, + { CS42L42_PLL_DIV_FRAC2, 0x00 }, + { CS42L42_PLL_DIV_INT, 0x40 }, + { CS42L42_PLL_CTL3, 0x10 }, + { CS42L42_PLL_CAL_RATIO, 0x80 }, + { CS42L42_PLL_CTL4, 0x03 }, + { CS42L42_LOAD_DET_RCSTAT, 0x00 }, + { CS42L42_LOAD_DET_DONE, 0x00 }, + { CS42L42_LOAD_DET_EN, 0x00 }, + { CS42L42_HSBIAS_SC_AUTOCTL, 0x03 }, + { CS42L42_WAKE_CTL, 0xC0 }, + { CS42L42_ADC_DISABLE_MUTE, 0x00 }, + { CS42L42_TIPSENSE_CTL, 0x02 }, + { CS42L42_MISC_DET_CTL, 0x03 }, + { CS42L42_MIC_DET_CTL1, 0x1F }, + { CS42L42_MIC_DET_CTL2, 0x2F }, + { CS42L42_DET_STATUS1, 0x00 }, + { CS42L42_DET_STATUS2, 0x00 }, + { CS42L42_DET_INT1_MASK, 0xE0 }, + { CS42L42_DET_INT2_MASK, 0xFF }, + { CS42L42_HS_BIAS_CTL, 0xC2 }, + { CS42L42_ADC_CTL, 0x00 }, + { CS42L42_ADC_VOLUME, 0x00 }, + { CS42L42_ADC_WNF_HPF_CTL, 0x71 }, + { CS42L42_DAC_CTL1, 0x00 }, + { CS42L42_DAC_CTL2, 0x02 }, + { CS42L42_HP_CTL, 0x0D }, + { CS42L42_CLASSH_CTL, 0x07 }, + { CS42L42_MIXER_CHA_VOL, 0x3F }, + { CS42L42_MIXER_ADC_VOL, 0x3F }, + { CS42L42_MIXER_CHB_VOL, 0x3F }, + { CS42L42_EQ_COEF_IN0, 0x22 }, + { CS42L42_EQ_COEF_IN1, 0x00 }, + { CS42L42_EQ_COEF_IN2, 0x00 }, + { CS42L42_EQ_COEF_IN3, 0x00 }, + { CS42L42_EQ_COEF_RW, 0x00 }, + { CS42L42_EQ_COEF_OUT0, 0x00 }, + { CS42L42_EQ_COEF_OUT1, 0x00 }, + { CS42L42_EQ_COEF_OUT2, 0x00 }, + { CS42L42_EQ_COEF_OUT3, 0x00 }, + { CS42L42_EQ_INIT_STAT, 0x00 }, + { CS42L42_EQ_START_FILT, 0x00 }, + { CS42L42_EQ_MUTE_CTL, 0x00 }, + { CS42L42_SP_RX_CH_SEL, 0x04 }, + { CS42L42_SP_RX_ISOC_CTL, 0x04 }, + { CS42L42_SP_RX_FS, 0x8C }, + { CS42l42_SPDIF_CH_SEL, 0x0E }, + { CS42L42_SP_TX_ISOC_CTL, 0x04 }, + { CS42L42_SP_TX_FS, 0xCC }, + { CS42L42_SPDIF_SW_CTL1, 0x3F }, + { CS42L42_SRC_SDIN_FS, 0x40 }, + { CS42L42_SRC_SDOUT_FS, 0x40 }, + { CS42L42_SPDIF_CTL1, 0x01 }, + { CS42L42_SPDIF_CTL2, 0x00 }, + { CS42L42_SPDIF_CTL3, 0x00 }, + { CS42L42_SPDIF_CTL4, 0x42 }, + { CS42L42_ASP_TX_SZ_EN, 0x00 }, + { CS42L42_ASP_TX_CH_EN, 0x00 }, + { CS42L42_ASP_TX_CH_AP_RES, 0x0F }, + { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_TX_HIZ_DLY_CFG, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_TX_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_EN, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH1_BIT_LSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_AP_RES, 0x03 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_MSB, 0x00 }, + { CS42L42_ASP_RX_DAI1_CH2_BIT_LSB, 0x00 }, + { CS42L42_SUB_REVID, 0x03 }, +}; + +static bool cs42l42_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L42_PAGE_REGISTER: + case CS42L42_DEVID_AB: + case CS42L42_DEVID_CD: + case CS42L42_DEVID_E: + case CS42L42_FABID: + case CS42L42_REVID: + case CS42L42_FRZ_CTL: + case CS42L42_SRC_CTL: + case CS42L42_MCLK_STATUS: + case CS42L42_MCLK_CTL: + case CS42L42_SFTRAMP_RATE: + case CS42L42_I2C_DEBOUNCE: + case CS42L42_I2C_STRETCH: + case CS42L42_I2C_TIMEOUT: + case CS42L42_PWR_CTL1: + case CS42L42_PWR_CTL2: + case CS42L42_PWR_CTL3: + case CS42L42_RSENSE_CTL1: + case CS42L42_RSENSE_CTL2: + case CS42L42_OSC_SWITCH: + case CS42L42_OSC_SWITCH_STATUS: + case CS42L42_RSENSE_CTL3: + case CS42L42_TSENSE_CTL: + case CS42L42_TSRS_INT_DISABLE: + case CS42L42_TRSENSE_STATUS: + case CS42L42_HSDET_CTL1: + case CS42L42_HSDET_CTL2: + case CS42L42_HS_SWITCH_CTL: + case CS42L42_HS_DET_STATUS: + case CS42L42_HS_CLAMP_DISABLE: + case CS42L42_MCLK_SRC_SEL: + case CS42L42_SPDIF_CLK_CFG: + case CS42L42_FSYNC_PW_LOWER: + case CS42L42_FSYNC_PW_UPPER: + case CS42L42_FSYNC_P_LOWER: + case CS42L42_FSYNC_P_UPPER: + case CS42L42_ASP_CLK_CFG: + case CS42L42_ASP_FRM_CFG: + case CS42L42_FS_RATE_EN: + case CS42L42_IN_ASRC_CLK: + case CS42L42_OUT_ASRC_CLK: + case CS42L42_PLL_DIV_CFG1: + case CS42L42_ADC_OVFL_STATUS: + case CS42L42_MIXER_STATUS: + case CS42L42_SRC_STATUS: + case CS42L42_ASP_RX_STATUS: + case CS42L42_ASP_TX_STATUS: + case CS42L42_CODEC_STATUS: + case CS42L42_DET_INT_STATUS1: + case CS42L42_DET_INT_STATUS2: + case CS42L42_SRCPL_INT_STATUS: + case CS42L42_VPMON_STATUS: + case CS42L42_PLL_LOCK_STATUS: + case CS42L42_TSRS_PLUG_STATUS: + case CS42L42_ADC_OVFL_INT_MASK: + case CS42L42_MIXER_INT_MASK: + case CS42L42_SRC_INT_MASK: + case CS42L42_ASP_RX_INT_MASK: + case CS42L42_ASP_TX_INT_MASK: + case CS42L42_CODEC_INT_MASK: + case CS42L42_SRCPL_INT_MASK: + case CS42L42_VPMON_INT_MASK: + case CS42L42_PLL_LOCK_INT_MASK: + case CS42L42_TSRS_PLUG_INT_MASK: + case CS42L42_PLL_CTL1: + case CS42L42_PLL_DIV_FRAC0: + case CS42L42_PLL_DIV_FRAC1: + case CS42L42_PLL_DIV_FRAC2: + case CS42L42_PLL_DIV_INT: + case CS42L42_PLL_CTL3: + case CS42L42_PLL_CAL_RATIO: + case CS42L42_PLL_CTL4: + case CS42L42_LOAD_DET_RCSTAT: + case CS42L42_LOAD_DET_DONE: + case CS42L42_LOAD_DET_EN: + case CS42L42_HSBIAS_SC_AUTOCTL: + case CS42L42_WAKE_CTL: + case CS42L42_ADC_DISABLE_MUTE: + case CS42L42_TIPSENSE_CTL: + case CS42L42_MISC_DET_CTL: + case CS42L42_MIC_DET_CTL1: + case CS42L42_MIC_DET_CTL2: + case CS42L42_DET_STATUS1: + case CS42L42_DET_STATUS2: + case CS42L42_DET_INT1_MASK: + case CS42L42_DET_INT2_MASK: + case CS42L42_HS_BIAS_CTL: + case CS42L42_ADC_CTL: + case CS42L42_ADC_VOLUME: + case CS42L42_ADC_WNF_HPF_CTL: + case CS42L42_DAC_CTL1: + case CS42L42_DAC_CTL2: + case CS42L42_HP_CTL: + case CS42L42_CLASSH_CTL: + case CS42L42_MIXER_CHA_VOL: + case CS42L42_MIXER_ADC_VOL: + case CS42L42_MIXER_CHB_VOL: + case CS42L42_EQ_COEF_IN0: + case CS42L42_EQ_COEF_IN1: + case CS42L42_EQ_COEF_IN2: + case CS42L42_EQ_COEF_IN3: + case CS42L42_EQ_COEF_RW: + case CS42L42_EQ_COEF_OUT0: + case CS42L42_EQ_COEF_OUT1: + case CS42L42_EQ_COEF_OUT2: + case CS42L42_EQ_COEF_OUT3: + case CS42L42_EQ_INIT_STAT: + case CS42L42_EQ_START_FILT: + case CS42L42_EQ_MUTE_CTL: + case CS42L42_SP_RX_CH_SEL: + case CS42L42_SP_RX_ISOC_CTL: + case CS42L42_SP_RX_FS: + case CS42l42_SPDIF_CH_SEL: + case CS42L42_SP_TX_ISOC_CTL: + case CS42L42_SP_TX_FS: + case CS42L42_SPDIF_SW_CTL1: + case CS42L42_SRC_SDIN_FS: + case CS42L42_SRC_SDOUT_FS: + case CS42L42_SPDIF_CTL1: + case CS42L42_SPDIF_CTL2: + case CS42L42_SPDIF_CTL3: + case CS42L42_SPDIF_CTL4: + case CS42L42_ASP_TX_SZ_EN: + case CS42L42_ASP_TX_CH_EN: + case CS42L42_ASP_TX_CH_AP_RES: + case CS42L42_ASP_TX_CH1_BIT_MSB: + case CS42L42_ASP_TX_CH1_BIT_LSB: + case CS42L42_ASP_TX_HIZ_DLY_CFG: + case CS42L42_ASP_TX_CH2_BIT_MSB: + case CS42L42_ASP_TX_CH2_BIT_LSB: + case CS42L42_ASP_RX_DAI0_EN: + case CS42L42_ASP_RX_DAI0_CH1_AP_RES: + case CS42L42_ASP_RX_DAI0_CH1_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH1_BIT_LSB: + case CS42L42_ASP_RX_DAI0_CH2_AP_RES: + case CS42L42_ASP_RX_DAI0_CH2_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH2_BIT_LSB: + case CS42L42_ASP_RX_DAI0_CH3_AP_RES: + case CS42L42_ASP_RX_DAI0_CH3_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH3_BIT_LSB: + case CS42L42_ASP_RX_DAI0_CH4_AP_RES: + case CS42L42_ASP_RX_DAI0_CH4_BIT_MSB: + case CS42L42_ASP_RX_DAI0_CH4_BIT_LSB: + case CS42L42_ASP_RX_DAI1_CH1_AP_RES: + case CS42L42_ASP_RX_DAI1_CH1_BIT_MSB: + case CS42L42_ASP_RX_DAI1_CH1_BIT_LSB: + case CS42L42_ASP_RX_DAI1_CH2_AP_RES: + case CS42L42_ASP_RX_DAI1_CH2_BIT_MSB: + case CS42L42_ASP_RX_DAI1_CH2_BIT_LSB: + case CS42L42_SUB_REVID: + return true; + default: + return false; + } +} + +static bool cs42l42_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS42L42_DEVID_AB: + case CS42L42_DEVID_CD: + case CS42L42_DEVID_E: + case CS42L42_MCLK_STATUS: + case CS42L42_TRSENSE_STATUS: + case CS42L42_HS_DET_STATUS: + case CS42L42_ADC_OVFL_STATUS: + case CS42L42_MIXER_STATUS: + case CS42L42_SRC_STATUS: + case CS42L42_ASP_RX_STATUS: + case CS42L42_ASP_TX_STATUS: + case CS42L42_CODEC_STATUS: + case CS42L42_DET_INT_STATUS1: + case CS42L42_DET_INT_STATUS2: + case CS42L42_SRCPL_INT_STATUS: + case CS42L42_VPMON_STATUS: + case CS42L42_PLL_LOCK_STATUS: + case CS42L42_TSRS_PLUG_STATUS: + case CS42L42_LOAD_DET_RCSTAT: + case CS42L42_LOAD_DET_DONE: + case CS42L42_DET_STATUS1: + case CS42L42_DET_STATUS2: + return true; + default: + return false; + } +} + +static const struct regmap_range_cfg cs42l42_page_range = { + .name = "Pages", + .range_min = 0, + .range_max = CS42L42_MAX_REGISTER, + .selector_reg = CS42L42_PAGE_REGISTER, + .selector_mask = 0xff, + .selector_shift = 0, + .window_start = 0, + .window_len = 256, +}; + +static const struct regmap_config cs42l42_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .readable_reg = cs42l42_readable_register, + .volatile_reg = cs42l42_volatile_register, + + .ranges = &cs42l42_page_range, + .num_ranges = 1, + + .max_register = CS42L42_MAX_REGISTER, + .reg_defaults = cs42l42_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs42l42_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + +static DECLARE_TLV_DB_SCALE(adc_tlv, -9600, 100, false); +static DECLARE_TLV_DB_SCALE(mixer_tlv, -6200, 100, false); + +static const char * const cs42l42_hpf_freq_text[] = { + "1.86Hz", "120Hz", "235Hz", "466Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_hpf_freq_enum, CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_HPF_CF_SHIFT, + cs42l42_hpf_freq_text); + +static const char * const cs42l42_wnf3_freq_text[] = { + "160Hz", "180Hz", "200Hz", "220Hz", + "240Hz", "260Hz", "280Hz", "300Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_wnf3_freq_enum, CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_WNF_CF_SHIFT, + cs42l42_wnf3_freq_text); + +static const char * const cs42l42_wnf05_freq_text[] = { + "280Hz", "315Hz", "350Hz", "385Hz", + "420Hz", "455Hz", "490Hz", "525Hz" +}; + +static SOC_ENUM_SINGLE_DECL(cs42l42_wnf05_freq_enum, CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_WNF_CF_SHIFT, + cs42l42_wnf05_freq_text); + +static const struct snd_kcontrol_new cs42l42_snd_controls[] = { + /* ADC Volume and Filter Controls */ + SOC_SINGLE("ADC Notch Switch", CS42L42_ADC_CTL, + CS42L42_ADC_NOTCH_DIS_SHIFT, true, false), + SOC_SINGLE("ADC Weak Force Switch", CS42L42_ADC_CTL, + CS42L42_ADC_FORCE_WEAK_VCM_SHIFT, true, false), + SOC_SINGLE("ADC Invert Switch", CS42L42_ADC_CTL, + CS42L42_ADC_INV_SHIFT, true, false), + SOC_SINGLE("ADC Boost Switch", CS42L42_ADC_CTL, + CS42L42_ADC_DIG_BOOST_SHIFT, true, false), + SOC_SINGLE_SX_TLV("ADC Volume", CS42L42_ADC_VOLUME, + CS42L42_ADC_VOL_SHIFT, 0xA0, 0x6C, adc_tlv), + SOC_SINGLE("ADC WNF Switch", CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_WNF_EN_SHIFT, true, false), + SOC_SINGLE("ADC HPF Switch", CS42L42_ADC_WNF_HPF_CTL, + CS42L42_ADC_HPF_EN_SHIFT, true, false), + SOC_ENUM("HPF Corner Freq", cs42l42_hpf_freq_enum), + SOC_ENUM("WNF 3dB Freq", cs42l42_wnf3_freq_enum), + SOC_ENUM("WNF 05dB Freq", cs42l42_wnf05_freq_enum), + + /* DAC Volume and Filter Controls */ + SOC_SINGLE("DACA Invert Switch", CS42L42_DAC_CTL1, + CS42L42_DACA_INV_SHIFT, true, false), + SOC_SINGLE("DACB Invert Switch", CS42L42_DAC_CTL1, + CS42L42_DACB_INV_SHIFT, true, false), + SOC_SINGLE("DAC HPF Switch", CS42L42_DAC_CTL2, + CS42L42_DAC_HPF_EN_SHIFT, true, false), + SOC_DOUBLE_R_TLV("Mixer Volume", CS42L42_MIXER_CHA_VOL, + CS42L42_MIXER_CHB_VOL, CS42L42_MIXER_CH_VOL_SHIFT, + 0x3e, 1, mixer_tlv) +}; + +static int cs42l42_hpdrv_evt(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + if (event & SND_SOC_DAPM_POST_PMU) { + /* Enable the channels */ + snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN, + CS42L42_ASP_RX0_CH_EN_MASK, + (CS42L42_ASP_RX0_CH1_EN | + CS42L42_ASP_RX0_CH2_EN) << + CS42L42_ASP_RX0_CH_EN_SHIFT); + + /* Power up */ + snd_soc_update_bits(codec, CS42L42_PWR_CTL1, + CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | + CS42L42_HP_PDN_MASK, 0); + } else if (event & SND_SOC_DAPM_PRE_PMD) { + /* Disable the channels */ + snd_soc_update_bits(codec, CS42L42_ASP_RX_DAI0_EN, + CS42L42_ASP_RX0_CH_EN_MASK, 0); + + /* Power down */ + snd_soc_update_bits(codec, CS42L42_PWR_CTL1, + CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | + CS42L42_HP_PDN_MASK, + CS42L42_ASP_DAI_PDN_MASK | CS42L42_MIXER_PDN_MASK | + CS42L42_HP_PDN_MASK); + } else { + dev_err(codec->dev, "Invalid event 0x%x\n", event); + } + return 0; +} + +static const struct snd_soc_dapm_widget cs42l42_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("HP"), + SND_SOC_DAPM_AIF_IN("SDIN", NULL, 0, CS42L42_ASP_CLK_CFG, + CS42L42_ASP_SCLK_EN_SHIFT, false), + SND_SOC_DAPM_OUT_DRV_E("HPDRV", SND_SOC_NOPM, 0, + 0, NULL, 0, cs42l42_hpdrv_evt, + SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD) +}; + +static const struct snd_soc_dapm_route cs42l42_audio_map[] = { + {"SDIN", NULL, "Playback"}, + {"HPDRV", NULL, "SDIN"}, + {"HP", NULL, "HPDRV"} +}; + +static int cs42l42_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + int ret; + + switch (level) { + case SND_SOC_BIAS_ON: + break; + case SND_SOC_BIAS_PREPARE: + break; + case SND_SOC_BIAS_STANDBY: + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { + regcache_cache_only(cs42l42->regmap, false); + regcache_sync(cs42l42->regmap); + ret = regulator_bulk_enable( + ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(codec->dev, + "Failed to enable regulators: %d\n", + ret); + return ret; + } + } + break; + case SND_SOC_BIAS_OFF: + + regcache_cache_only(cs42l42->regmap, true); + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + break; + } + + return 0; +} + +static int cs42l42_codec_probe(struct snd_soc_codec *codec) +{ + struct cs42l42_private *cs42l42 = + (struct cs42l42_private *)snd_soc_codec_get_drvdata(codec); + + cs42l42->codec = codec; + + return 0; +} + +static const struct snd_soc_codec_driver soc_codec_dev_cs42l42 = { + .probe = cs42l42_codec_probe, + .set_bias_level = cs42l42_set_bias_level, + .ignore_pmdown_time = true, + + .component_driver = { + .dapm_widgets = cs42l42_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs42l42_dapm_widgets), + .dapm_routes = cs42l42_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs42l42_audio_map), + + .controls = cs42l42_snd_controls, + .num_controls = ARRAY_SIZE(cs42l42_snd_controls), + }, +}; + +struct cs42l42_pll_params { + u32 sclk; + u8 mclk_div; + u8 mclk_src_sel; + u8 sclk_prediv; + u8 pll_div_int; + u32 pll_div_frac; + u8 pll_mode; + u8 pll_divout; + u32 mclk_int; + u8 pll_cal_ratio; +}; + +/* + * Common PLL Settings for given SCLK + * Table 4-5 from the Datasheet + */ +static const struct cs42l42_pll_params pll_ratio_table[] = { + { 1536000, 0, 1, 0x00, 0x7D, 0x000000, 0x03, 0x10, 12000000, 125 }, + { 2822400, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, + { 3000000, 0, 1, 0x00, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, + { 3072000, 0, 1, 0x00, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, + { 4000000, 0, 1, 0x00, 0x30, 0x800000, 0x03, 0x10, 12000000, 96 }, + { 4096000, 0, 1, 0x00, 0x2E, 0xE00000, 0x03, 0x10, 12000000, 94 }, + { 5644800, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 11289600, 128 }, + { 6000000, 0, 1, 0x01, 0x40, 0x000000, 0x03, 0x10, 12000000, 128 }, + { 6144000, 0, 1, 0x01, 0x3E, 0x800000, 0x03, 0x10, 12000000, 125 }, + { 11289600, 0, 0, 0, 0, 0, 0, 0, 11289600, 0 }, + { 12000000, 0, 0, 0, 0, 0, 0, 0, 12000000, 0 }, + { 12288000, 0, 0, 0, 0, 0, 0, 0, 12288000, 0 }, + { 22579200, 1, 0, 0, 0, 0, 0, 0, 22579200, 0 }, + { 24000000, 1, 0, 0, 0, 0, 0, 0, 24000000, 0 }, + { 24576000, 1, 0, 0, 0, 0, 0, 0, 24576000, 0 } +}; + +static int cs42l42_pll_config(struct snd_soc_codec *codec) +{ + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + int i; + u32 fsync; + + for (i = 0; i < ARRAY_SIZE(pll_ratio_table); i++) { + if (pll_ratio_table[i].sclk == cs42l42->sclk) { + /* Configure the internal sample rate */ + snd_soc_update_bits(codec, CS42L42_MCLK_CTL, + CS42L42_INTERNAL_FS_MASK, + ((pll_ratio_table[i].mclk_int != + 12000000) && + (pll_ratio_table[i].mclk_int != + 24000000)) << + CS42L42_INTERNAL_FS_SHIFT); + /* Set the MCLK src (PLL or SCLK) and the divide + * ratio + */ + snd_soc_update_bits(codec, CS42L42_MCLK_SRC_SEL, + CS42L42_MCLK_SRC_SEL_MASK | + CS42L42_MCLKDIV_MASK, + (pll_ratio_table[i].mclk_src_sel + << CS42L42_MCLK_SRC_SEL_SHIFT) | + (pll_ratio_table[i].mclk_div << + CS42L42_MCLKDIV_SHIFT)); + /* Set up the LRCLK */ + fsync = cs42l42->sclk / cs42l42->srate; + if (((fsync * cs42l42->srate) != cs42l42->sclk) + || ((fsync % 2) != 0)) { + dev_err(codec->dev, + "Unsupported sclk %d/sample rate %d\n", + cs42l42->sclk, + cs42l42->srate); + return -EINVAL; + } + /* Set the LRCLK period */ + snd_soc_update_bits(codec, + CS42L42_FSYNC_P_LOWER, + CS42L42_FSYNC_PERIOD_MASK, + CS42L42_FRAC0_VAL(fsync - 1) << + CS42L42_FSYNC_PERIOD_SHIFT); + snd_soc_update_bits(codec, + CS42L42_FSYNC_P_UPPER, + CS42L42_FSYNC_PERIOD_MASK, + CS42L42_FRAC1_VAL(fsync - 1) << + CS42L42_FSYNC_PERIOD_SHIFT); + /* Set the LRCLK to 50% duty cycle */ + fsync = fsync / 2; + snd_soc_update_bits(codec, + CS42L42_FSYNC_PW_LOWER, + CS42L42_FSYNC_PULSE_WIDTH_MASK, + CS42L42_FRAC0_VAL(fsync - 1) << + CS42L42_FSYNC_PULSE_WIDTH_SHIFT); + snd_soc_update_bits(codec, + CS42L42_FSYNC_PW_UPPER, + CS42L42_FSYNC_PULSE_WIDTH_MASK, + CS42L42_FRAC1_VAL(fsync - 1) << + CS42L42_FSYNC_PULSE_WIDTH_SHIFT); + snd_soc_update_bits(codec, + CS42L42_ASP_FRM_CFG, + CS42L42_ASP_5050_MASK, + CS42L42_ASP_5050_MASK); + /* Set the frame delay to 1.0 SCLK clocks */ + snd_soc_update_bits(codec, CS42L42_ASP_FRM_CFG, + CS42L42_ASP_FSD_MASK, + CS42L42_ASP_FSD_1_0 << + CS42L42_ASP_FSD_SHIFT); + /* Set the sample rates (96k or lower) */ + snd_soc_update_bits(codec, CS42L42_FS_RATE_EN, + CS42L42_FS_EN_MASK, + (CS42L42_FS_EN_IASRC_96K | + CS42L42_FS_EN_OASRC_96K) << + CS42L42_FS_EN_SHIFT); + /* Set the input/output internal MCLK clock ~12 MHz */ + snd_soc_update_bits(codec, CS42L42_IN_ASRC_CLK, + CS42L42_CLK_IASRC_SEL_MASK, + CS42L42_CLK_IASRC_SEL_12 << + CS42L42_CLK_IASRC_SEL_SHIFT); + snd_soc_update_bits(codec, + CS42L42_OUT_ASRC_CLK, + CS42L42_CLK_OASRC_SEL_MASK, + CS42L42_CLK_OASRC_SEL_12 << + CS42L42_CLK_OASRC_SEL_SHIFT); + /* channel 1 on low LRCLK, 32 bit */ + snd_soc_update_bits(codec, + CS42L42_ASP_RX_DAI0_CH1_AP_RES, + CS42L42_ASP_RX_CH_AP_MASK | + CS42L42_ASP_RX_CH_RES_MASK, + (CS42L42_ASP_RX_CH_AP_LOW << + CS42L42_ASP_RX_CH_AP_SHIFT) | + (CS42L42_ASP_RX_CH_RES_32 << + CS42L42_ASP_RX_CH_RES_SHIFT)); + /* Channel 2 on high LRCLK, 32 bit */ + snd_soc_update_bits(codec, + CS42L42_ASP_RX_DAI0_CH2_AP_RES, + CS42L42_ASP_RX_CH_AP_MASK | + CS42L42_ASP_RX_CH_RES_MASK, + (CS42L42_ASP_RX_CH_AP_HI << + CS42L42_ASP_RX_CH_AP_SHIFT) | + (CS42L42_ASP_RX_CH_RES_32 << + CS42L42_ASP_RX_CH_RES_SHIFT)); + if (pll_ratio_table[i].mclk_src_sel == 0) { + /* Pass the clock straight through */ + snd_soc_update_bits(codec, + CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, 0); + } else { + /* Configure PLL per table 4-5 */ + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_CFG1, + CS42L42_SCLK_PREDIV_MASK, + pll_ratio_table[i].sclk_prediv + << CS42L42_SCLK_PREDIV_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_INT, + CS42L42_PLL_DIV_INT_MASK, + pll_ratio_table[i].pll_div_int + << CS42L42_PLL_DIV_INT_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_FRAC0, + CS42L42_PLL_DIV_FRAC_MASK, + CS42L42_FRAC0_VAL( + pll_ratio_table[i].pll_div_frac) + << CS42L42_PLL_DIV_FRAC_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_FRAC1, + CS42L42_PLL_DIV_FRAC_MASK, + CS42L42_FRAC1_VAL( + pll_ratio_table[i].pll_div_frac) + << CS42L42_PLL_DIV_FRAC_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_DIV_FRAC2, + CS42L42_PLL_DIV_FRAC_MASK, + CS42L42_FRAC2_VAL( + pll_ratio_table[i].pll_div_frac) + << CS42L42_PLL_DIV_FRAC_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_CTL4, + CS42L42_PLL_MODE_MASK, + pll_ratio_table[i].pll_mode + << CS42L42_PLL_MODE_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_CTL3, + CS42L42_PLL_DIVOUT_MASK, + pll_ratio_table[i].pll_divout + << CS42L42_PLL_DIVOUT_SHIFT); + snd_soc_update_bits(codec, + CS42L42_PLL_CAL_RATIO, + CS42L42_PLL_CAL_RATIO_MASK, + pll_ratio_table[i].pll_cal_ratio + << CS42L42_PLL_CAL_RATIO_SHIFT); + } + return 0; + } + } + + return -EINVAL; +} + +static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 asp_cfg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFM: + asp_cfg_val |= CS42L42_ASP_MASTER_MODE << + CS42L42_ASP_MODE_SHIFT; + break; + case SND_SOC_DAIFMT_CBS_CFS: + asp_cfg_val |= CS42L42_ASP_SLAVE_MODE << + CS42L42_ASP_MODE_SHIFT; + break; + default: + return -EINVAL; + } + + /* interface format */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + break; + default: + return -EINVAL; + } + + /* Bitclock/frame inversion */ + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_NB_IF: + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_LCPOL_IN_SHIFT; + break; + case SND_SOC_DAIFMT_IB_NF: + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_SCPOL_IN_DAC_SHIFT; + break; + case SND_SOC_DAIFMT_IB_IF: + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_LCPOL_IN_SHIFT; + asp_cfg_val |= CS42L42_ASP_POL_INV << + CS42L42_ASP_SCPOL_IN_DAC_SHIFT; + break; + } + + snd_soc_update_bits(codec, CS42L42_ASP_CLK_CFG, + CS42L42_ASP_MODE_MASK | + CS42L42_ASP_SCPOL_IN_DAC_MASK | + CS42L42_ASP_LCPOL_IN_MASK, asp_cfg_val); + + return 0; +} + +static int cs42l42_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + int retval; + + cs42l42->srate = params_rate(params); + cs42l42->swidth = params_width(params); + + retval = cs42l42_pll_config(codec); + + return retval; +} + +static int cs42l42_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs42l42_private *cs42l42 = snd_soc_codec_get_drvdata(codec); + + cs42l42->sclk = freq; + + return 0; +} + +static int cs42l42_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int regval; + u8 fullScaleVol; + + if (mute) { + /* Mark SCLK as not present to turn on the internal + * oscillator. + */ + snd_soc_update_bits(codec, CS42L42_OSC_SWITCH, + CS42L42_SCLK_PRESENT_MASK, 0); + + snd_soc_update_bits(codec, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, + 0 << CS42L42_PLL_START_SHIFT); + + /* Mute the headphone */ + snd_soc_update_bits(codec, CS42L42_HP_CTL, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK); + } else { + snd_soc_update_bits(codec, CS42L42_PLL_CTL1, + CS42L42_PLL_START_MASK, + 1 << CS42L42_PLL_START_SHIFT); + /* Read the headphone load */ + regval = snd_soc_read(codec, CS42L42_LOAD_DET_RCSTAT); + if (((regval & CS42L42_RLA_STAT_MASK) >> + CS42L42_RLA_STAT_SHIFT) == CS42L42_RLA_STAT_15_OHM) { + fullScaleVol = CS42L42_HP_FULL_SCALE_VOL_MASK; + } else { + fullScaleVol = 0; + } + + /* Un-mute the headphone, set the full scale volume flag */ + snd_soc_update_bits(codec, CS42L42_HP_CTL, + CS42L42_HP_ANA_AMUTE_MASK | + CS42L42_HP_ANA_BMUTE_MASK | + CS42L42_HP_FULL_SCALE_VOL_MASK, fullScaleVol); + + /* Mark SCLK as present, turn off internal oscillator */ + snd_soc_update_bits(codec, CS42L42_OSC_SWITCH, + CS42L42_SCLK_PRESENT_MASK, + CS42L42_SCLK_PRESENT_MASK); + } + + return 0; +} + +#define CS42L42_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +static struct snd_soc_dai_ops cs42l42_ops = { + .hw_params = cs42l42_pcm_hw_params, + .set_fmt = cs42l42_set_dai_fmt, + .set_sysclk = cs42l42_set_sysclk, + .digital_mute = cs42l42_digital_mute +}; + +static struct snd_soc_dai_driver cs42l42_dai = { + .name = "cs42l42", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = CS42L42_FORMATS, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = CS42L42_FORMATS, + }, + .ops = &cs42l42_ops, +}; + +static void cs42l42_process_hs_type_detect(struct cs42l42_private *cs42l42) +{ + unsigned int hs_det_status; + unsigned int int_status; + + /* Mask the auto detect interrupt */ + regmap_update_bits(cs42l42->regmap, + CS42L42_CODEC_INT_MASK, + CS42L42_PDN_DONE_MASK | + CS42L42_HSDET_AUTO_DONE_MASK, + (1 << CS42L42_PDN_DONE_SHIFT) | + (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + /* Set hs detect to automatic, disabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (2 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + + /* Read and save the hs detection result */ + regmap_read(cs42l42->regmap, CS42L42_HS_DET_STATUS, &hs_det_status); + + cs42l42->hs_type = (hs_det_status & CS42L42_HSDET_TYPE_MASK) >> + CS42L42_HSDET_TYPE_SHIFT; + + /* Set up button detection */ + if ((cs42l42->hs_type == CS42L42_PLUG_CTIA) || + (cs42l42->hs_type == CS42L42_PLUG_OMTP)) { + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Set up hs detect level sensitivity */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[0] << + CS42L42_HS_DET_LEVEL_SHIFT)); + + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (1 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (1 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Turn on level detect circuitry */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (3 << CS42L42_HSBIAS_CTL_SHIFT) | + (0 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + msleep(cs42l42->btn_det_init_dbnce); + + /* Clear any button interrupts before unmasking them */ + regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, + &int_status); + + /* Unmask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (0 << CS42L42_M_DETECT_TF_SHIFT) | + (0 << CS42L42_M_DETECT_FT_SHIFT) | + (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + } else { + /* Make sure button detect and HS bias circuits are off */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (1 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + } + + regmap_update_bits(cs42l42->regmap, + CS42L42_DAC_CTL2, + CS42L42_HPOUT_PULLDOWN_MASK | + CS42L42_HPOUT_LOAD_MASK | + CS42L42_HPOUT_CLAMP_MASK | + CS42L42_DAC_HPF_EN_MASK | + CS42L42_DAC_MON_EN_MASK, + (0 << CS42L42_HPOUT_PULLDOWN_SHIFT) | + (0 << CS42L42_HPOUT_LOAD_SHIFT) | + (0 << CS42L42_HPOUT_CLAMP_SHIFT) | + (1 << CS42L42_DAC_HPF_EN_SHIFT) | + (0 << CS42L42_DAC_MON_EN_SHIFT)); + + /* Unmask tip sense interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | + CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | + CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | + (1 << CS42L42_RS_UNPLUG_SHIFT) | + (0 << CS42L42_TS_PLUG_SHIFT) | + (0 << CS42L42_TS_UNPLUG_SHIFT)); +} + +static void cs42l42_init_hs_type_detect(struct cs42l42_private *cs42l42) +{ + /* Mask tip sense interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | + CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | + CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | + (1 << CS42L42_RS_UNPLUG_SHIFT) | + (1 << CS42L42_TS_PLUG_SHIFT) | + (1 << CS42L42_TS_UNPLUG_SHIFT)); + + /* Make sure button detect and HS bias circuits are off */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (1 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Set hs detect to manual, disabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (0 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); + + regmap_update_bits(cs42l42->regmap, + CS42L42_DAC_CTL2, + CS42L42_HPOUT_PULLDOWN_MASK | + CS42L42_HPOUT_LOAD_MASK | + CS42L42_HPOUT_CLAMP_MASK | + CS42L42_DAC_HPF_EN_MASK | + CS42L42_DAC_MON_EN_MASK, + (8 << CS42L42_HPOUT_PULLDOWN_SHIFT) | + (0 << CS42L42_HPOUT_LOAD_SHIFT) | + (1 << CS42L42_HPOUT_CLAMP_SHIFT) | + (1 << CS42L42_DAC_HPF_EN_SHIFT) | + (1 << CS42L42_DAC_MON_EN_SHIFT)); + + /* Power up HS bias to 2.7V */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (3 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + /* Wait for HS bias to ramp up */ + msleep(cs42l42->hs_bias_ramp_time); + + /* Unmask auto detect interrupt */ + regmap_update_bits(cs42l42->regmap, + CS42L42_CODEC_INT_MASK, + CS42L42_PDN_DONE_MASK | + CS42L42_HSDET_AUTO_DONE_MASK, + (1 << CS42L42_PDN_DONE_SHIFT) | + (0 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + /* Set hs detect to automatic, enabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (3 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); +} + +static void cs42l42_cancel_hs_type_detect(struct cs42l42_private *cs42l42) +{ + /* Mask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (1 << CS42L42_M_DETECT_TF_SHIFT) | + (1 << CS42L42_M_DETECT_FT_SHIFT) | + (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + + /* Ground HS bias */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MISC_DET_CTL, + CS42L42_DETECT_MODE_MASK | + CS42L42_HSBIAS_CTL_MASK | + CS42L42_PDN_MIC_LVL_DET_MASK, + (0 << CS42L42_DETECT_MODE_SHIFT) | + (1 << CS42L42_HSBIAS_CTL_SHIFT) | + (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT)); + + /* Set auto HS bias settings to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSBIAS_SC_AUTOCTL, + CS42L42_HSBIAS_SENSE_EN_MASK | + CS42L42_AUTO_HSBIAS_HIZ_MASK | + CS42L42_TIP_SENSE_EN_MASK | + CS42L42_HSBIAS_SENSE_TRIP_MASK, + (0 << CS42L42_HSBIAS_SENSE_EN_SHIFT) | + (0 << CS42L42_AUTO_HSBIAS_HIZ_SHIFT) | + (0 << CS42L42_TIP_SENSE_EN_SHIFT) | + (3 << CS42L42_HSBIAS_SENSE_TRIP_SHIFT)); + + /* Set hs detect to manual, disabled mode */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HSDET_CTL2, + CS42L42_HSDET_CTRL_MASK | + CS42L42_HSDET_SET_MASK | + CS42L42_HSBIAS_REF_MASK | + CS42L42_HSDET_AUTO_TIME_MASK, + (0 << CS42L42_HSDET_CTRL_SHIFT) | + (2 << CS42L42_HSDET_SET_SHIFT) | + (0 << CS42L42_HSBIAS_REF_SHIFT) | + (3 << CS42L42_HSDET_AUTO_TIME_SHIFT)); +} + +static void cs42l42_handle_button_press(struct cs42l42_private *cs42l42) +{ + int bias_level; + unsigned int detect_status; + + /* Mask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (1 << CS42L42_M_DETECT_TF_SHIFT) | + (1 << CS42L42_M_DETECT_FT_SHIFT) | + (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + + usleep_range(cs42l42->btn_det_event_dbnce * 1000, + cs42l42->btn_det_event_dbnce * 2000); + + /* Test all 4 level detect biases */ + bias_level = 1; + do { + /* Adjust button detect level sensitivity */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[bias_level] << + CS42L42_HS_DET_LEVEL_SHIFT)); + + regmap_read(cs42l42->regmap, CS42L42_DET_STATUS2, + &detect_status); + } while ((detect_status & CS42L42_HS_TRUE_MASK) && + (++bias_level < CS42L42_NUM_BIASES)); + + switch (bias_level) { + case 1: /* Function C button press */ + dev_dbg(cs42l42->codec->dev, "Function C button press\n"); + break; + case 2: /* Function B button press */ + dev_dbg(cs42l42->codec->dev, "Function B button press\n"); + break; + case 3: /* Function D button press */ + dev_dbg(cs42l42->codec->dev, "Function D button press\n"); + break; + case 4: /* Function A button press */ + dev_dbg(cs42l42->codec->dev, "Function A button press\n"); + break; + } + + /* Set button detect level sensitivity back to default */ + regmap_update_bits(cs42l42->regmap, + CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[0] << CS42L42_HS_DET_LEVEL_SHIFT)); + + /* Clear any button interrupts before unmasking them */ + regmap_read(cs42l42->regmap, CS42L42_DET_INT_STATUS2, + &detect_status); + + /* Unmask button detect interrupts */ + regmap_update_bits(cs42l42->regmap, + CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (0 << CS42L42_M_DETECT_TF_SHIFT) | + (0 << CS42L42_M_DETECT_FT_SHIFT) | + (0 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); +} + +struct cs42l42_irq_params { + u16 status_addr; + u16 mask_addr; + u8 mask; +}; + +static const struct cs42l42_irq_params irq_params_table[] = { + {CS42L42_ADC_OVFL_STATUS, CS42L42_ADC_OVFL_INT_MASK, + CS42L42_ADC_OVFL_VAL_MASK}, + {CS42L42_MIXER_STATUS, CS42L42_MIXER_INT_MASK, + CS42L42_MIXER_VAL_MASK}, + {CS42L42_SRC_STATUS, CS42L42_SRC_INT_MASK, + CS42L42_SRC_VAL_MASK}, + {CS42L42_ASP_RX_STATUS, CS42L42_ASP_RX_INT_MASK, + CS42L42_ASP_RX_VAL_MASK}, + {CS42L42_ASP_TX_STATUS, CS42L42_ASP_TX_INT_MASK, + CS42L42_ASP_TX_VAL_MASK}, + {CS42L42_CODEC_STATUS, CS42L42_CODEC_INT_MASK, + CS42L42_CODEC_VAL_MASK}, + {CS42L42_DET_INT_STATUS1, CS42L42_DET_INT1_MASK, + CS42L42_DET_INT_VAL1_MASK}, + {CS42L42_DET_INT_STATUS2, CS42L42_DET_INT2_MASK, + CS42L42_DET_INT_VAL2_MASK}, + {CS42L42_SRCPL_INT_STATUS, CS42L42_SRCPL_INT_MASK, + CS42L42_SRCPL_VAL_MASK}, + {CS42L42_VPMON_STATUS, CS42L42_VPMON_INT_MASK, + CS42L42_VPMON_VAL_MASK}, + {CS42L42_PLL_LOCK_STATUS, CS42L42_PLL_LOCK_INT_MASK, + CS42L42_PLL_LOCK_VAL_MASK}, + {CS42L42_TSRS_PLUG_STATUS, CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_TSRS_PLUG_VAL_MASK} +}; + +static irqreturn_t cs42l42_irq_thread(int irq, void *data) +{ + struct cs42l42_private *cs42l42 = (struct cs42l42_private *)data; + struct snd_soc_codec *codec = cs42l42->codec; + unsigned int stickies[12]; + unsigned int masks[12]; + unsigned int current_plug_status; + unsigned int current_button_status; + unsigned int i; + + /* Read sticky registers to clear interurpt */ + for (i = 0; i < ARRAY_SIZE(stickies); i++) { + regmap_read(cs42l42->regmap, irq_params_table[i].status_addr, + &(stickies[i])); + regmap_read(cs42l42->regmap, irq_params_table[i].mask_addr, + &(masks[i])); + stickies[i] = stickies[i] & (~masks[i]) & + irq_params_table[i].mask; + } + + /* Read tip sense status before handling type detect */ + current_plug_status = (stickies[11] & + (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> + CS42L42_TS_PLUG_SHIFT; + + /* Read button sense status */ + current_button_status = stickies[7] & + (CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK); + + /* Check auto-detect status */ + if ((~masks[5]) & irq_params_table[5].mask) { + if (stickies[5] & CS42L42_HSDET_AUTO_DONE_MASK) { + cs42l42_process_hs_type_detect(cs42l42); + dev_dbg(codec->dev, + "Auto detect done (%d)\n", + cs42l42->hs_type); + } + } + + /* Check tip sense status */ + if ((~masks[11]) & irq_params_table[11].mask) { + switch (current_plug_status) { + case CS42L42_TS_PLUG: + if (cs42l42->plug_state != CS42L42_TS_PLUG) { + cs42l42->plug_state = CS42L42_TS_PLUG; + cs42l42_init_hs_type_detect(cs42l42); + } + break; + + case CS42L42_TS_UNPLUG: + if (cs42l42->plug_state != CS42L42_TS_UNPLUG) { + cs42l42->plug_state = CS42L42_TS_UNPLUG; + cs42l42_cancel_hs_type_detect(cs42l42); + dev_dbg(codec->dev, + "Unplug event\n"); + } + break; + + default: + if (cs42l42->plug_state != CS42L42_TS_TRANS) + cs42l42->plug_state = CS42L42_TS_TRANS; + } + } + + /* Check button detect status */ + if ((~masks[7]) & irq_params_table[7].mask) { + if (!(current_button_status & + CS42L42_M_HSBIAS_HIZ_MASK)) { + + if (current_button_status & + CS42L42_M_DETECT_TF_MASK) { + dev_dbg(codec->dev, + "Button released\n"); + } else if (current_button_status & + CS42L42_M_DETECT_FT_MASK) { + cs42l42_handle_button_press(cs42l42); + } + } + } + + return IRQ_HANDLED; +} + +static void cs42l42_set_interrupt_masks(struct cs42l42_private *cs42l42) +{ + regmap_update_bits(cs42l42->regmap, CS42L42_ADC_OVFL_INT_MASK, + CS42L42_ADC_OVFL_MASK, + (1 << CS42L42_ADC_OVFL_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_MIXER_INT_MASK, + CS42L42_MIX_CHB_OVFL_MASK | + CS42L42_MIX_CHA_OVFL_MASK | + CS42L42_EQ_OVFL_MASK | + CS42L42_EQ_BIQUAD_OVFL_MASK, + (1 << CS42L42_MIX_CHB_OVFL_SHIFT) | + (1 << CS42L42_MIX_CHA_OVFL_SHIFT) | + (1 << CS42L42_EQ_OVFL_SHIFT) | + (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_SRC_INT_MASK, + CS42L42_SRC_ILK_MASK | + CS42L42_SRC_OLK_MASK | + CS42L42_SRC_IUNLK_MASK | + CS42L42_SRC_OUNLK_MASK, + (1 << CS42L42_SRC_ILK_SHIFT) | + (1 << CS42L42_SRC_OLK_SHIFT) | + (1 << CS42L42_SRC_IUNLK_SHIFT) | + (1 << CS42L42_SRC_OUNLK_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_ASP_RX_INT_MASK, + CS42L42_ASPRX_NOLRCK_MASK | + CS42L42_ASPRX_EARLY_MASK | + CS42L42_ASPRX_LATE_MASK | + CS42L42_ASPRX_ERROR_MASK | + CS42L42_ASPRX_OVLD_MASK, + (1 << CS42L42_ASPRX_NOLRCK_SHIFT) | + (1 << CS42L42_ASPRX_EARLY_SHIFT) | + (1 << CS42L42_ASPRX_LATE_SHIFT) | + (1 << CS42L42_ASPRX_ERROR_SHIFT) | + (1 << CS42L42_ASPRX_OVLD_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_ASP_TX_INT_MASK, + CS42L42_ASPTX_NOLRCK_MASK | + CS42L42_ASPTX_EARLY_MASK | + CS42L42_ASPTX_LATE_MASK | + CS42L42_ASPTX_SMERROR_MASK, + (1 << CS42L42_ASPTX_NOLRCK_SHIFT) | + (1 << CS42L42_ASPTX_EARLY_SHIFT) | + (1 << CS42L42_ASPTX_LATE_SHIFT) | + (1 << CS42L42_ASPTX_SMERROR_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_CODEC_INT_MASK, + CS42L42_PDN_DONE_MASK | + CS42L42_HSDET_AUTO_DONE_MASK, + (1 << CS42L42_PDN_DONE_SHIFT) | + (1 << CS42L42_HSDET_AUTO_DONE_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_SRCPL_INT_MASK, + CS42L42_SRCPL_ADC_LK_MASK | + CS42L42_SRCPL_DAC_LK_MASK | + CS42L42_SRCPL_ADC_UNLK_MASK | + CS42L42_SRCPL_DAC_UNLK_MASK, + (1 << CS42L42_SRCPL_ADC_LK_SHIFT) | + (1 << CS42L42_SRCPL_DAC_LK_SHIFT) | + (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) | + (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT1_MASK, + CS42L42_TIP_SENSE_UNPLUG_MASK | + CS42L42_TIP_SENSE_PLUG_MASK | + CS42L42_HSBIAS_SENSE_MASK, + (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) | + (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) | + (1 << CS42L42_HSBIAS_SENSE_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_DET_INT2_MASK, + CS42L42_M_DETECT_TF_MASK | + CS42L42_M_DETECT_FT_MASK | + CS42L42_M_HSBIAS_HIZ_MASK | + CS42L42_M_SHORT_RLS_MASK | + CS42L42_M_SHORT_DET_MASK, + (1 << CS42L42_M_DETECT_TF_SHIFT) | + (1 << CS42L42_M_DETECT_FT_SHIFT) | + (1 << CS42L42_M_HSBIAS_HIZ_SHIFT) | + (1 << CS42L42_M_SHORT_RLS_SHIFT) | + (1 << CS42L42_M_SHORT_DET_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_VPMON_INT_MASK, + CS42L42_VPMON_MASK, + (1 << CS42L42_VPMON_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_PLL_LOCK_INT_MASK, + CS42L42_PLL_LOCK_MASK, + (1 << CS42L42_PLL_LOCK_SHIFT)); + + regmap_update_bits(cs42l42->regmap, CS42L42_TSRS_PLUG_INT_MASK, + CS42L42_RS_PLUG_MASK | + CS42L42_RS_UNPLUG_MASK | + CS42L42_TS_PLUG_MASK | + CS42L42_TS_UNPLUG_MASK, + (1 << CS42L42_RS_PLUG_SHIFT) | + (1 << CS42L42_RS_UNPLUG_SHIFT) | + (0 << CS42L42_TS_PLUG_SHIFT) | + (0 << CS42L42_TS_UNPLUG_SHIFT)); +} + +static void cs42l42_setup_hs_type_detect(struct cs42l42_private *cs42l42) +{ + unsigned int reg; + + cs42l42->hs_type = CS42L42_PLUG_INVALID; + + /* Latch analog controls to VP power domain */ + regmap_update_bits(cs42l42->regmap, CS42L42_MIC_DET_CTL1, + CS42L42_LATCH_TO_VP_MASK | + CS42L42_EVENT_STAT_SEL_MASK | + CS42L42_HS_DET_LEVEL_MASK, + (1 << CS42L42_LATCH_TO_VP_SHIFT) | + (0 << CS42L42_EVENT_STAT_SEL_SHIFT) | + (cs42l42->bias_thresholds[0] << + CS42L42_HS_DET_LEVEL_SHIFT)); + + /* Remove ground noise-suppression clamps */ + regmap_update_bits(cs42l42->regmap, + CS42L42_HS_CLAMP_DISABLE, + CS42L42_HS_CLAMP_DISABLE_MASK, + (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT)); + + /* Enable the tip sense circuit */ + regmap_update_bits(cs42l42->regmap, CS42L42_TIPSENSE_CTL, + CS42L42_TIP_SENSE_CTRL_MASK | + CS42L42_TIP_SENSE_INV_MASK | + CS42L42_TIP_SENSE_DEBOUNCE_MASK, + (3 << CS42L42_TIP_SENSE_CTRL_SHIFT) | + (0 << CS42L42_TIP_SENSE_INV_SHIFT) | + (2 << CS42L42_TIP_SENSE_DEBOUNCE_SHIFT)); + + /* Save the initial status of the tip sense */ + regmap_read(cs42l42->regmap, + CS42L42_TSRS_PLUG_STATUS, + ®); + cs42l42->plug_state = (((char) reg) & + (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK)) >> + CS42L42_TS_PLUG_SHIFT; +} + +static const unsigned int threshold_defaults[] = { + CS42L42_HS_DET_LEVEL_15, + CS42L42_HS_DET_LEVEL_8, + CS42L42_HS_DET_LEVEL_4, + CS42L42_HS_DET_LEVEL_1 +}; + +static int cs42l42_handle_device_data(struct i2c_client *i2c_client, + struct cs42l42_private *cs42l42) +{ + struct device_node *np = i2c_client->dev.of_node; + unsigned int val; + unsigned int thresholds[CS42L42_NUM_BIASES]; + int ret; + int i; + + ret = of_property_read_u32(np, "cirrus,ts-inv", &val); + + if (!ret) { + switch (val) { + case CS42L42_TS_INV_EN: + case CS42L42_TS_INV_DIS: + cs42l42->ts_inv = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,ts-inv DT value %d\n", + val); + cs42l42->ts_inv = CS42L42_TS_INV_DIS; + } + } else { + cs42l42->ts_inv = CS42L42_TS_INV_DIS; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, + CS42L42_TS_INV_MASK, + (cs42l42->ts_inv << CS42L42_TS_INV_SHIFT)); + + ret = of_property_read_u32(np, "cirrus,ts-dbnc-rise", &val); + + if (!ret) { + switch (val) { + case CS42L42_TS_DBNCE_0: + case CS42L42_TS_DBNCE_125: + case CS42L42_TS_DBNCE_250: + case CS42L42_TS_DBNCE_500: + case CS42L42_TS_DBNCE_750: + case CS42L42_TS_DBNCE_1000: + case CS42L42_TS_DBNCE_1250: + case CS42L42_TS_DBNCE_1500: + cs42l42->ts_dbnc_rise = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,ts-dbnc-rise DT value %d\n", + val); + cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; + } + } else { + cs42l42->ts_dbnc_rise = CS42L42_TS_DBNCE_1000; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, + CS42L42_TS_RISE_DBNCE_TIME_MASK, + (cs42l42->ts_dbnc_rise << + CS42L42_TS_RISE_DBNCE_TIME_SHIFT)); + + ret = of_property_read_u32(np, "cirrus,ts-dbnc-fall", &val); + + if (!ret) { + switch (val) { + case CS42L42_TS_DBNCE_0: + case CS42L42_TS_DBNCE_125: + case CS42L42_TS_DBNCE_250: + case CS42L42_TS_DBNCE_500: + case CS42L42_TS_DBNCE_750: + case CS42L42_TS_DBNCE_1000: + case CS42L42_TS_DBNCE_1250: + case CS42L42_TS_DBNCE_1500: + cs42l42->ts_dbnc_fall = val; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,ts-dbnc-fall DT value %d\n", + val); + cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; + } + } else { + cs42l42->ts_dbnc_fall = CS42L42_TS_DBNCE_0; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_TSENSE_CTL, + CS42L42_TS_FALL_DBNCE_TIME_MASK, + (cs42l42->ts_dbnc_fall << + CS42L42_TS_FALL_DBNCE_TIME_SHIFT)); + + ret = of_property_read_u32(np, "cirrus,btn-det-init-dbnce", &val); + + if (!ret) { + if ((val >= CS42L42_BTN_DET_INIT_DBNCE_MIN) && + (val <= CS42L42_BTN_DET_INIT_DBNCE_MAX)) + cs42l42->btn_det_init_dbnce = val; + else { + dev_err(&i2c_client->dev, + "Wrong cirrus,btn-det-init-dbnce DT value %d\n", + val); + cs42l42->btn_det_init_dbnce = + CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; + } + } else { + cs42l42->btn_det_init_dbnce = + CS42L42_BTN_DET_INIT_DBNCE_DEFAULT; + } + + ret = of_property_read_u32(np, "cirrus,btn-det-event-dbnce", &val); + + if (!ret) { + if ((val >= CS42L42_BTN_DET_EVENT_DBNCE_MIN) && + (val <= CS42L42_BTN_DET_EVENT_DBNCE_MAX)) + cs42l42->btn_det_event_dbnce = val; + else { + dev_err(&i2c_client->dev, + "Wrong cirrus,btn-det-event-dbnce DT value %d\n", val); + cs42l42->btn_det_event_dbnce = + CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; + } + } else { + cs42l42->btn_det_event_dbnce = + CS42L42_BTN_DET_EVENT_DBNCE_DEFAULT; + } + + ret = of_property_read_u32_array(np, "cirrus,bias-lvls", + (u32 *)thresholds, CS42L42_NUM_BIASES); + + if (!ret) { + for (i = 0; i < CS42L42_NUM_BIASES; i++) { + if ((thresholds[i] >= CS42L42_HS_DET_LEVEL_MIN) && + (thresholds[i] <= CS42L42_HS_DET_LEVEL_MAX)) + cs42l42->bias_thresholds[i] = thresholds[i]; + else { + dev_err(&i2c_client->dev, + "Wrong cirrus,bias-lvls[%d] DT value %d\n", i, + thresholds[i]); + cs42l42->bias_thresholds[i] = + threshold_defaults[i]; + } + } + } else { + for (i = 0; i < CS42L42_NUM_BIASES; i++) + cs42l42->bias_thresholds[i] = threshold_defaults[i]; + } + + ret = of_property_read_u32(np, "cirrus,hs-bias-ramp-rate", &val); + + if (!ret) { + switch (val) { + case CS42L42_HSBIAS_RAMP_FAST_RISE_SLOW_FALL: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME0; + break; + case CS42L42_HSBIAS_RAMP_FAST: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME1; + break; + case CS42L42_HSBIAS_RAMP_SLOW: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; + break; + case CS42L42_HSBIAS_RAMP_SLOWEST: + cs42l42->hs_bias_ramp_rate = val; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME3; + break; + default: + dev_err(&i2c_client->dev, + "Wrong cirrus,hs-bias-ramp-rate DT value %d\n", + val); + cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; + } + } else { + cs42l42->hs_bias_ramp_rate = CS42L42_HSBIAS_RAMP_SLOW; + cs42l42->hs_bias_ramp_time = CS42L42_HSBIAS_RAMP_TIME2; + } + + regmap_update_bits(cs42l42->regmap, CS42L42_HS_BIAS_CTL, + CS42L42_HSBIAS_RAMP_MASK, + (cs42l42->hs_bias_ramp_rate << + CS42L42_HSBIAS_RAMP_SHIFT)); + + return 0; +} + +static int cs42l42_i2c_probe(struct i2c_client *i2c_client, + const struct i2c_device_id *id) +{ + struct cs42l42_private *cs42l42; + int ret, i; + unsigned int devid = 0; + unsigned int reg; + + cs42l42 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l42_private), + GFP_KERNEL); + if (!cs42l42) + return -ENOMEM; + + i2c_set_clientdata(i2c_client, cs42l42); + + cs42l42->regmap = devm_regmap_init_i2c(i2c_client, &cs42l42_regmap); + if (IS_ERR(cs42l42->regmap)) { + ret = PTR_ERR(cs42l42->regmap); + dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(cs42l42->supplies); i++) + cs42l42->supplies[i].supply = cs42l42_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c_client->dev, + ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(&i2c_client->dev, + "Failed to enable supplies: %d\n", ret); + return ret; + } + + /* Reset the Device */ + cs42l42->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs42l42->reset_gpio)) + return PTR_ERR(cs42l42->reset_gpio); + + if (cs42l42->reset_gpio) { + dev_dbg(&i2c_client->dev, "Found reset GPIO\n"); + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + } + mdelay(3); + + /* Request IRQ */ + ret = devm_request_threaded_irq(&i2c_client->dev, + i2c_client->irq, + NULL, cs42l42_irq_thread, + IRQF_ONESHOT | IRQF_TRIGGER_LOW, + "cs42l42", cs42l42); + + if (ret != 0) + dev_err(&i2c_client->dev, + "Failed to request IRQ: %d\n", ret); + + /* initialize codec */ + ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_AB, ®); + devid = (reg & 0xFF) << 12; + + ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_CD, ®); + devid |= (reg & 0xFF) << 4; + + ret = regmap_read(cs42l42->regmap, CS42L42_DEVID_E, ®); + devid |= (reg & 0xF0) >> 4; + + if (devid != CS42L42_CHIP_ID) { + ret = -ENODEV; + dev_err(&i2c_client->dev, + "CS42L42 Device ID (%X). Expected %X\n", + devid, CS42L42_CHIP_ID); + return ret; + } + + ret = regmap_read(cs42l42->regmap, CS42L42_REVID, ®); + if (ret < 0) { + dev_err(&i2c_client->dev, "Get Revision ID failed\n"); + return ret; + } + + dev_info(&i2c_client->dev, + "Cirrus Logic CS42L42, Revision: %02X\n", reg & 0xFF); + + /* Power up the codec */ + regmap_update_bits(cs42l42->regmap, CS42L42_PWR_CTL1, + CS42L42_ASP_DAO_PDN_MASK | + CS42L42_ASP_DAI_PDN_MASK | + CS42L42_MIXER_PDN_MASK | + CS42L42_EQ_PDN_MASK | + CS42L42_HP_PDN_MASK | + CS42L42_ADC_PDN_MASK | + CS42L42_PDN_ALL_MASK, + (1 << CS42L42_ASP_DAO_PDN_SHIFT) | + (1 << CS42L42_ASP_DAI_PDN_SHIFT) | + (1 << CS42L42_MIXER_PDN_SHIFT) | + (1 << CS42L42_EQ_PDN_SHIFT) | + (1 << CS42L42_HP_PDN_SHIFT) | + (1 << CS42L42_ADC_PDN_SHIFT) | + (0 << CS42L42_PDN_ALL_SHIFT)); + + if (i2c_client->dev.of_node) { + ret = cs42l42_handle_device_data(i2c_client, cs42l42); + if (ret != 0) + return ret; + } + + /* Setup headset detection */ + cs42l42_setup_hs_type_detect(cs42l42); + + /* Mask/Unmask Interrupts */ + cs42l42_set_interrupt_masks(cs42l42); + + /* Register codec for machine driver */ + ret = snd_soc_register_codec(&i2c_client->dev, + &soc_codec_dev_cs42l42, &cs42l42_dai, 1); + if (ret < 0) + goto err_disable; + return 0; + +err_disable: + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + return ret; +} + +static int cs42l42_i2c_remove(struct i2c_client *i2c_client) +{ + struct cs42l42_private *cs42l42 = i2c_get_clientdata(i2c_client); + + snd_soc_unregister_codec(&i2c_client->dev); + + /* Hold down reset */ + if (cs42l42->reset_gpio) + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int cs42l42_runtime_suspend(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + + regcache_cache_only(cs42l42->regmap, true); + regcache_mark_dirty(cs42l42->regmap); + + /* Hold down reset */ + if (cs42l42->reset_gpio) + gpiod_set_value_cansleep(cs42l42->reset_gpio, 0); + + /* remove power */ + regulator_bulk_disable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + + return 0; +} + +static int cs42l42_runtime_resume(struct device *dev) +{ + struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); + int ret; + + /* Enable power */ + ret = regulator_bulk_enable(ARRAY_SIZE(cs42l42->supplies), + cs42l42->supplies); + if (ret != 0) { + dev_err(dev, "Failed to enable supplies: %d\n", + ret); + return ret; + } + + if (cs42l42->reset_gpio) + gpiod_set_value_cansleep(cs42l42->reset_gpio, 1); + + regcache_cache_only(cs42l42->regmap, false); + regcache_sync(cs42l42->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs42l42_runtime_pm = { + SET_RUNTIME_PM_OPS(cs42l42_runtime_suspend, cs42l42_runtime_resume, + NULL) +}; + +static const struct of_device_id cs42l42_of_match[] = { + { .compatible = "cirrus,cs42l42", }, + {}, +}; +MODULE_DEVICE_TABLE(of, cs42l42_of_match); + + +static const struct i2c_device_id cs42l42_id[] = { + {"cs42l42", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs42l42_id); + +static struct i2c_driver cs42l42_i2c_driver = { + .driver = { + .name = "cs42l42", + .owner = THIS_MODULE, + .pm = &cs42l42_runtime_pm, + .of_match_table = cs42l42_of_match, + }, + .id_table = cs42l42_id, + .probe = cs42l42_i2c_probe, + .remove = cs42l42_i2c_remove, +}; + +module_i2c_driver(cs42l42_i2c_driver); + +MODULE_DESCRIPTION("ASoC CS42L42 driver"); +MODULE_AUTHOR("James Schulman, Cirrus Logic Inc, "); +MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, "); +MODULE_AUTHOR("Michael White, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs42l42.h b/sound/soc/codecs/cs42l42.h new file mode 100644 index 000000000000..d87a0a5322d5 --- /dev/null +++ b/sound/soc/codecs/cs42l42.h @@ -0,0 +1,776 @@ +/* + * cs42l42.h -- CS42L42 ALSA SoC audio driver header + * + * Copyright 2016 Cirrus Logic, Inc. + * + * Author: James Schulman + * Author: Brian Austin + * Author: Michael White + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#ifndef __CS42L42_H__ +#define __CS42L42_H__ + +#define CS42L42_PAGE_REGISTER 0x00 /* Page Select Register */ +#define CS42L42_WIN_START 0x00 +#define CS42L42_WIN_LEN 0x100 +#define CS42L42_RANGE_MIN 0x00 +#define CS42L42_RANGE_MAX 0x7F + +#define CS42L42_PAGE_10 0x1000 +#define CS42L42_PAGE_11 0x1100 +#define CS42L42_PAGE_12 0x1200 +#define CS42L42_PAGE_13 0x1300 +#define CS42L42_PAGE_15 0x1500 +#define CS42L42_PAGE_19 0x1900 +#define CS42L42_PAGE_1B 0x1B00 +#define CS42L42_PAGE_1C 0x1C00 +#define CS42L42_PAGE_1D 0x1D00 +#define CS42L42_PAGE_1F 0x1F00 +#define CS42L42_PAGE_20 0x2000 +#define CS42L42_PAGE_21 0x2100 +#define CS42L42_PAGE_23 0x2300 +#define CS42L42_PAGE_24 0x2400 +#define CS42L42_PAGE_25 0x2500 +#define CS42L42_PAGE_26 0x2600 +#define CS42L42_PAGE_28 0x2800 +#define CS42L42_PAGE_29 0x2900 +#define CS42L42_PAGE_2A 0x2A00 +#define CS42L42_PAGE_30 0x3000 + +#define CS42L42_CHIP_ID 0x42A42 + +/* Page 0x10 Global Registers */ +#define CS42L42_DEVID_AB (CS42L42_PAGE_10 + 0x01) +#define CS42L42_DEVID_CD (CS42L42_PAGE_10 + 0x02) +#define CS42L42_DEVID_E (CS42L42_PAGE_10 + 0x03) +#define CS42L42_FABID (CS42L42_PAGE_10 + 0x04) +#define CS42L42_REVID (CS42L42_PAGE_10 + 0x05) +#define CS42L42_FRZ_CTL (CS42L42_PAGE_10 + 0x06) + +#define CS42L42_SRC_CTL (CS42L42_PAGE_10 + 0x07) +#define CS42L42_SRC_BYPASS_DAC_SHIFT 1 +#define CS42L42_SRC_BYPASS_DAC_MASK (1 << CS42L42_SRC_BYPASS_DAC_SHIFT) + +#define CS42L42_MCLK_STATUS (CS42L42_PAGE_10 + 0x08) + +#define CS42L42_MCLK_CTL (CS42L42_PAGE_10 + 0x09) +#define CS42L42_INTERNAL_FS_SHIFT 1 +#define CS42L42_INTERNAL_FS_MASK (1 << CS42L42_INTERNAL_FS_SHIFT) + +#define CS42L42_SFTRAMP_RATE (CS42L42_PAGE_10 + 0x0A) +#define CS42L42_I2C_DEBOUNCE (CS42L42_PAGE_10 + 0x0E) +#define CS42L42_I2C_STRETCH (CS42L42_PAGE_10 + 0x0F) +#define CS42L42_I2C_TIMEOUT (CS42L42_PAGE_10 + 0x10) + +/* Page 0x11 Power and Headset Detect Registers */ +#define CS42L42_PWR_CTL1 (CS42L42_PAGE_11 + 0x01) +#define CS42L42_ASP_DAO_PDN_SHIFT 7 +#define CS42L42_ASP_DAO_PDN_MASK (1 << CS42L42_ASP_DAO_PDN_SHIFT) +#define CS42L42_ASP_DAI_PDN_SHIFT 6 +#define CS42L42_ASP_DAI_PDN_MASK (1 << CS42L42_ASP_DAI_PDN_SHIFT) +#define CS42L42_MIXER_PDN_SHIFT 5 +#define CS42L42_MIXER_PDN_MASK (1 << CS42L42_MIXER_PDN_SHIFT) +#define CS42L42_EQ_PDN_SHIFT 4 +#define CS42L42_EQ_PDN_MASK (1 << CS42L42_EQ_PDN_SHIFT) +#define CS42L42_HP_PDN_SHIFT 3 +#define CS42L42_HP_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_ADC_PDN_SHIFT 2 +#define CS42L42_ADC_PDN_MASK (1 << CS42L42_HP_PDN_SHIFT) +#define CS42L42_PDN_ALL_SHIFT 0 +#define CS42L42_PDN_ALL_MASK (1 << CS42L42_PDN_ALL_SHIFT) + +#define CS42L42_PWR_CTL2 (CS42L42_PAGE_11 + 0x02) +#define CS42L42_ADC_SRC_PDNB_SHIFT 0 +#define CS42L42_ADC_SRC_PDNB_MASK (1 << CS42L42_ADC_SRC_PDNB_SHIFT) +#define CS42L42_DAC_SRC_PDNB_SHIFT 1 +#define CS42L42_DAC_SRC_PDNB_MASK (1 << CS42L42_DAC_SRC_PDNB_SHIFT) +#define CS42L42_ASP_DAI1_PDN_SHIFT 2 +#define CS42L42_ASP_DAI1_PDN_MASK (1 << CS42L42_ASP_DAI1_PDN_SHIFT) +#define CS42L42_SRC_PDN_OVERRIDE_SHIFT 3 +#define CS42L42_SRC_PDN_OVERRIDE_MASK (1 << CS42L42_SRC_PDN_OVERRIDE_SHIFT) +#define CS42L42_DISCHARGE_FILT_SHIFT 4 +#define CS42L42_DISCHARGE_FILT_MASK (1 << CS42L42_DISCHARGE_FILT_SHIFT) + +#define CS42L42_PWR_CTL3 (CS42L42_PAGE_11 + 0x03) +#define CS42L42_RING_SENSE_PDNB_SHIFT 1 +#define CS42L42_RING_SENSE_PDNB_MASK (1 << \ + CS42L42_RING_SENSE_PDNB_SHIFT) +#define CS42L42_VPMON_PDNB_SHIFT 2 +#define CS42L42_VPMON_PDNB_MASK (1 << \ + CS42L42_VPMON_PDNB_SHIFT) +#define CS42L42_SW_CLK_STP_STAT_SEL_SHIFT 5 +#define CS42L42_SW_CLK_STP_STAT_SEL_MASK (3 << \ + CS42L42_SW_CLK_STP_STAT_SEL_SHIFT) + +#define CS42L42_RSENSE_CTL1 (CS42L42_PAGE_11 + 0x04) +#define CS42L42_RS_TRIM_R_SHIFT 0 +#define CS42L42_RS_TRIM_R_MASK (1 << \ + CS42L42_RS_TRIM_R_SHIFT) +#define CS42L42_RS_TRIM_T_SHIFT 1 +#define CS42L42_RS_TRIM_T_MASK (1 << \ + CS42L42_RS_TRIM_T_SHIFT) +#define CS42L42_HPREF_RS_SHIFT 2 +#define CS42L42_HPREF_RS_MASK (1 << \ + CS42L42_HPREF_RS_SHIFT) +#define CS42L42_HSBIAS_FILT_REF_RS_SHIFT 3 +#define CS42L42_HSBIAS_FILT_REF_RS_MASK (1 << \ + CS42L42_HSBIAS_FILT_REF_RS_SHIFT) +#define CS42L42_RING_SENSE_PU_HIZ_SHIFT 6 +#define CS42L42_RING_SENSE_PU_HIZ_MASK (1 << \ + CS42L42_RING_SENSE_PU_HIZ_SHIFT) + +#define CS42L42_RSENSE_CTL2 (CS42L42_PAGE_11 + 0x05) +#define CS42L42_TS_RS_GATE_SHIFT 7 +#define CS42L42_TS_RS_GATE_MAS (1 << CS42L42_TS_RS_GATE_SHIFT) + +#define CS42L42_OSC_SWITCH (CS42L42_PAGE_11 + 0x07) +#define CS42L42_SCLK_PRESENT_SHIFT 0 +#define CS42L42_SCLK_PRESENT_MASK (1 << CS42L42_SCLK_PRESENT_SHIFT) + +#define CS42L42_OSC_SWITCH_STATUS (CS42L42_PAGE_11 + 0x09) +#define CS42L42_OSC_SW_SEL_STAT_SHIFT 0 +#define CS42L42_OSC_SW_SEL_STAT_MASK (3 << CS42L42_OSC_SW_SEL_STAT_SHIFT) +#define CS42L42_OSC_PDNB_STAT_SHIFT 2 +#define CS42L42_OSC_PDNB_STAT_MASK (1 << CS42L42_OSC_SW_SEL_STAT_SHIFT) + +#define CS42L42_RSENSE_CTL3 (CS42L42_PAGE_11 + 0x12) +#define CS42L42_RS_RISE_DBNCE_TIME_SHIFT 0 +#define CS42L42_RS_RISE_DBNCE_TIME_MASK (7 << \ + CS42L42_RS_RISE_DBNCE_TIME_SHIFT) +#define CS42L42_RS_FALL_DBNCE_TIME_SHIFT 3 +#define CS42L42_RS_FALL_DBNCE_TIME_MASK (7 << \ + CS42L42_RS_FALL_DBNCE_TIME_SHIFT) +#define CS42L42_RS_PU_EN_SHIFT 6 +#define CS42L42_RS_PU_EN_MASK (1 << \ + CS42L42_RS_PU_EN_SHIFT) +#define CS42L42_RS_INV_SHIFT 7 +#define CS42L42_RS_INV_MASK (1 << \ + CS42L42_RS_INV_SHIFT) + +#define CS42L42_TSENSE_CTL (CS42L42_PAGE_11 + 0x13) +#define CS42L42_TS_RISE_DBNCE_TIME_SHIFT 0 +#define CS42L42_TS_RISE_DBNCE_TIME_MASK (7 << \ + CS42L42_TS_RISE_DBNCE_TIME_SHIFT) +#define CS42L42_TS_FALL_DBNCE_TIME_SHIFT 3 +#define CS42L42_TS_FALL_DBNCE_TIME_MASK (7 << \ + CS42L42_TS_FALL_DBNCE_TIME_SHIFT) +#define CS42L42_TS_INV_SHIFT 7 +#define CS42L42_TS_INV_MASK (1 << \ + CS42L42_TS_INV_SHIFT) + +#define CS42L42_TSRS_INT_DISABLE (CS42L42_PAGE_11 + 0x14) +#define CS42L42_D_RS_PLUG_DBNC_SHIFT 0 +#define CS42L42_D_RS_PLUG_DBNC_MASK (1 << CS42L42_D_RS_PLUG_DBNC_SHIFT) +#define CS42L42_D_RS_UNPLUG_DBNC_SHIFT 1 +#define CS42L42_D_RS_UNPLUG_DBNC_MASK (1 << CS42L42_D_RS_UNPLUG_DBNC_SHIFT) +#define CS42L42_D_TS_PLUG_DBNC_SHIFT 2 +#define CS42L42_D_TS_PLUG_DBNC_MASK (1 << CS42L42_D_TS_PLUG_DBNC_SHIFT) +#define CS42L42_D_TS_UNPLUG_DBNC_SHIFT 3 +#define CS42L42_D_TS_UNPLUG_DBNC_MASK (1 << CS42L42_D_TS_UNPLUG_DBNC_SHIFT) + +#define CS42L42_TRSENSE_STATUS (CS42L42_PAGE_11 + 0x15) +#define CS42L42_RS_PLUG_DBNC_SHIFT 0 +#define CS42L42_RS_PLUG_DBNC_MASK (1 << CS42L42_RS_PLUG_DBNC_SHIFT) +#define CS42L42_RS_UNPLUG_DBNC_SHIFT 1 +#define CS42L42_RS_UNPLUG_DBNC_MASK (1 << CS42L42_RS_UNPLUG_DBNC_SHIFT) +#define CS42L42_TS_PLUG_DBNC_SHIFT 2 +#define CS42L42_TS_PLUG_DBNC_MASK (1 << CS42L42_TS_PLUG_DBNC_SHIFT) +#define CS42L42_TS_UNPLUG_DBNC_SHIFT 3 +#define CS42L42_TS_UNPLUG_DBNC_MASK (1 << CS42L42_TS_UNPLUG_DBNC_SHIFT) + +#define CS42L42_HSDET_CTL1 (CS42L42_PAGE_11 + 0x1F) +#define CS42L42_HSDET_COMP1_LVL_SHIFT 0 +#define CS42L42_HSDET_COMP1_LVL_MASK (15 << CS42L42_HSDET_COMP1_LVL_SHIFT) +#define CS42L42_HSDET_COMP2_LVL_SHIFT 4 +#define CS42L42_HSDET_COMP2_LVL_MASK (15 << CS42L42_HSDET_COMP2_LVL_SHIFT) + +#define CS42L42_HSDET_CTL2 (CS42L42_PAGE_11 + 0x20) +#define CS42L42_HSDET_AUTO_TIME_SHIFT 0 +#define CS42L42_HSDET_AUTO_TIME_MASK (3 << CS42L42_HSDET_AUTO_TIME_SHIFT) +#define CS42L42_HSBIAS_REF_SHIFT 3 +#define CS42L42_HSBIAS_REF_MASK (1 << CS42L42_HSBIAS_REF_SHIFT) +#define CS42L42_HSDET_SET_SHIFT 4 +#define CS42L42_HSDET_SET_MASK (3 << CS42L42_HSDET_SET_SHIFT) +#define CS42L42_HSDET_CTRL_SHIFT 6 +#define CS42L42_HSDET_CTRL_MASK (3 << CS42L42_HSDET_CTRL_SHIFT) + +#define CS42L42_HS_SWITCH_CTL (CS42L42_PAGE_11 + 0x21) +#define CS42L42_SW_GNDHS_HS4_SHIFT 0 +#define CS42L42_SW_GNDHS_HS4_MASK (1 << CS42L42_SW_GNDHS_HS4_SHIFT) +#define CS42L42_SW_GNDHS_HS3_SHIFT 1 +#define CS42L42_SW_GNDHS_HS3_MASK (1 << CS42L42_SW_GNDHS_HS3_SHIFT) +#define CS42L42_SW_HSB_HS4_SHIFT 2 +#define CS42L42_SW_HSB_HS4_MASK (1 << CS42L42_SW_HSB_HS4_SHIFT) +#define CS42L42_SW_HSB_HS3_SHIFT 3 +#define CS42L42_SW_HSB_HS3_MASK (1 << CS42L42_SW_HSB_HS3_SHIFT) +#define CS42L42_SW_HSB_FILT_HS4_SHIFT 4 +#define CS42L42_SW_HSB_FILT_HS4_MASK (1 << CS42L42_SW_HSB_FILT_HS4_SHIFT) +#define CS42L42_SW_HSB_FILT_HS3_SHIFT 5 +#define CS42L42_SW_HSB_FILT_HS3_MASK (1 << CS42L42_SW_HSB_FILT_HS3_SHIFT) +#define CS42L42_SW_REF_HS4_SHIFT 6 +#define CS42L42_SW_REF_HS4_MASK (1 << CS42L42_SW_REF_HS4_SHIFT) +#define CS42L42_SW_REF_HS3_SHIFT 7 +#define CS42L42_SW_REF_HS3_MASK (1 << CS42L42_SW_REF_HS3_SHIFT) + +#define CS42L42_HS_DET_STATUS (CS42L42_PAGE_11 + 0x24) +#define CS42L42_HSDET_TYPE_SHIFT 0 +#define CS42L42_HSDET_TYPE_MASK (3 << CS42L42_HSDET_TYPE_SHIFT) +#define CS42L42_HSDET_COMP1_OUT_SHIFT 6 +#define CS42L42_HSDET_COMP1_OUT_MASK (1 << CS42L42_HSDET_COMP1_OUT_SHIFT) +#define CS42L42_HSDET_COMP2_OUT_SHIFT 7 +#define CS42L42_HSDET_COMP2_OUT_MASK (1 << CS42L42_HSDET_COMP2_OUT_SHIFT) +#define CS42L42_PLUG_CTIA 0 +#define CS42L42_PLUG_OMTP 1 +#define CS42L42_PLUG_HEADPHONE 2 +#define CS42L42_PLUG_INVALID 3 + +#define CS42L42_HS_CLAMP_DISABLE (CS42L42_PAGE_11 + 0x29) +#define CS42L42_HS_CLAMP_DISABLE_SHIFT 0 +#define CS42L42_HS_CLAMP_DISABLE_MASK (1 << CS42L42_HS_CLAMP_DISABLE_SHIFT) + +/* Page 0x12 Clocking Registers */ +#define CS42L42_MCLK_SRC_SEL (CS42L42_PAGE_12 + 0x01) +#define CS42L42_MCLKDIV_SHIFT 1 +#define CS42L42_MCLKDIV_MASK (1 << CS42L42_MCLKDIV_SHIFT) +#define CS42L42_MCLK_SRC_SEL_SHIFT 0 +#define CS42L42_MCLK_SRC_SEL_MASK (1 << CS42L42_MCLK_SRC_SEL_SHIFT) + +#define CS42L42_SPDIF_CLK_CFG (CS42L42_PAGE_12 + 0x02) +#define CS42L42_FSYNC_PW_LOWER (CS42L42_PAGE_12 + 0x03) + +#define CS42L42_FSYNC_PW_UPPER (CS42L42_PAGE_12 + 0x04) +#define CS42L42_FSYNC_PULSE_WIDTH_SHIFT 0 +#define CS42L42_FSYNC_PULSE_WIDTH_MASK (0xff << \ + CS42L42_FSYNC_PULSE_WIDTH_SHIFT) + +#define CS42L42_FSYNC_P_LOWER (CS42L42_PAGE_12 + 0x05) + +#define CS42L42_FSYNC_P_UPPER (CS42L42_PAGE_12 + 0x06) +#define CS42L42_FSYNC_PERIOD_SHIFT 0 +#define CS42L42_FSYNC_PERIOD_MASK (0xff << CS42L42_FSYNC_PERIOD_SHIFT) + +#define CS42L42_ASP_CLK_CFG (CS42L42_PAGE_12 + 0x07) +#define CS42L42_ASP_SCLK_EN_SHIFT 5 +#define CS42L42_ASP_SCLK_EN_MASK (1 << CS42L42_ASP_SCLK_EN_SHIFT) +#define CS42L42_ASP_MASTER_MODE 0x01 +#define CS42L42_ASP_SLAVE_MODE 0x00 +#define CS42L42_ASP_MODE_SHIFT 4 +#define CS42L42_ASP_MODE_MASK (1 << CS42L42_ASP_MODE_SHIFT) +#define CS42L42_ASP_SCPOL_IN_DAC_SHIFT 2 +#define CS42L42_ASP_SCPOL_IN_DAC_MASK (1 << CS42L42_ASP_SCPOL_IN_DAC_SHIFT) +#define CS42L42_ASP_LCPOL_IN_SHIFT 0 +#define CS42L42_ASP_LCPOL_IN_MASK (1 << CS42L42_ASP_LCPOL_IN_SHIFT) +#define CS42L42_ASP_POL_INV 1 + +#define CS42L42_ASP_FRM_CFG (CS42L42_PAGE_12 + 0x08) +#define CS42L42_ASP_STP_SHIFT 4 +#define CS42L42_ASP_STP_MASK (1 << CS42L42_ASP_STP_SHIFT) +#define CS42L42_ASP_5050_SHIFT 3 +#define CS42L42_ASP_5050_MASK (1 << CS42L42_ASP_5050_SHIFT) +#define CS42L42_ASP_FSD_SHIFT 0 +#define CS42L42_ASP_FSD_MASK (7 << CS42L42_ASP_FSD_SHIFT) +#define CS42L42_ASP_FSD_0_5 1 +#define CS42L42_ASP_FSD_1_0 2 +#define CS42L42_ASP_FSD_1_5 3 +#define CS42L42_ASP_FSD_2_0 4 + +#define CS42L42_FS_RATE_EN (CS42L42_PAGE_12 + 0x09) +#define CS42L42_FS_EN_SHIFT 0 +#define CS42L42_FS_EN_MASK (0xf << CS42L42_FS_EN_SHIFT) +#define CS42L42_FS_EN_IASRC_96K 0x1 +#define CS42L42_FS_EN_OASRC_96K 0x2 + +#define CS42L42_IN_ASRC_CLK (CS42L42_PAGE_12 + 0x0A) +#define CS42L42_CLK_IASRC_SEL_SHIFT 0 +#define CS42L42_CLK_IASRC_SEL_MASK (1 << CS42L42_CLK_IASRC_SEL_SHIFT) +#define CS42L42_CLK_IASRC_SEL_12 1 + +#define CS42L42_OUT_ASRC_CLK (CS42L42_PAGE_12 + 0x0B) +#define CS42L42_CLK_OASRC_SEL_SHIFT 0 +#define CS42L42_CLK_OASRC_SEL_MASK (1 << CS42L42_CLK_OASRC_SEL_SHIFT) +#define CS42L42_CLK_OASRC_SEL_12 1 + +#define CS42L42_PLL_DIV_CFG1 (CS42L42_PAGE_12 + 0x0C) +#define CS42L42_SCLK_PREDIV_SHIFT 0 +#define CS42L42_SCLK_PREDIV_MASK (3 << CS42L42_SCLK_PREDIV_SHIFT) + +/* Page 0x13 Interrupt Registers */ +/* Interrupts */ +#define CS42L42_ADC_OVFL_STATUS (CS42L42_PAGE_13 + 0x01) +#define CS42L42_MIXER_STATUS (CS42L42_PAGE_13 + 0x02) +#define CS42L42_SRC_STATUS (CS42L42_PAGE_13 + 0x03) +#define CS42L42_ASP_RX_STATUS (CS42L42_PAGE_13 + 0x04) +#define CS42L42_ASP_TX_STATUS (CS42L42_PAGE_13 + 0x05) +#define CS42L42_CODEC_STATUS (CS42L42_PAGE_13 + 0x08) +#define CS42L42_DET_INT_STATUS1 (CS42L42_PAGE_13 + 0x09) +#define CS42L42_DET_INT_STATUS2 (CS42L42_PAGE_13 + 0x0A) +#define CS42L42_SRCPL_INT_STATUS (CS42L42_PAGE_13 + 0x0B) +#define CS42L42_VPMON_STATUS (CS42L42_PAGE_13 + 0x0D) +#define CS42L42_PLL_LOCK_STATUS (CS42L42_PAGE_13 + 0x0E) +#define CS42L42_TSRS_PLUG_STATUS (CS42L42_PAGE_13 + 0x0F) +/* Masks */ +#define CS42L42_ADC_OVFL_INT_MASK (CS42L42_PAGE_13 + 0x16) +#define CS42L42_ADC_OVFL_SHIFT 0 +#define CS42L42_ADC_OVFL_MASK (1 << CS42L42_ADC_OVFL_SHIFT) +#define CS42L42_ADC_OVFL_VAL_MASK CS42L42_ADC_OVFL_MASK + +#define CS42L42_MIXER_INT_MASK (CS42L42_PAGE_13 + 0x17) +#define CS42L42_MIX_CHB_OVFL_SHIFT 0 +#define CS42L42_MIX_CHB_OVFL_MASK (1 << CS42L42_MIX_CHB_OVFL_SHIFT) +#define CS42L42_MIX_CHA_OVFL_SHIFT 1 +#define CS42L42_MIX_CHA_OVFL_MASK (1 << CS42L42_MIX_CHA_OVFL_SHIFT) +#define CS42L42_EQ_OVFL_SHIFT 2 +#define CS42L42_EQ_OVFL_MASK (1 << CS42L42_EQ_OVFL_SHIFT) +#define CS42L42_EQ_BIQUAD_OVFL_SHIFT 3 +#define CS42L42_EQ_BIQUAD_OVFL_MASK (1 << CS42L42_EQ_BIQUAD_OVFL_SHIFT) +#define CS42L42_MIXER_VAL_MASK (CS42L42_MIX_CHB_OVFL_MASK | \ + CS42L42_MIX_CHA_OVFL_MASK | \ + CS42L42_EQ_OVFL_MASK | \ + CS42L42_EQ_BIQUAD_OVFL_MASK) + +#define CS42L42_SRC_INT_MASK (CS42L42_PAGE_13 + 0x18) +#define CS42L42_SRC_ILK_SHIFT 0 +#define CS42L42_SRC_ILK_MASK (1 << CS42L42_SRC_ILK_SHIFT) +#define CS42L42_SRC_OLK_SHIFT 1 +#define CS42L42_SRC_OLK_MASK (1 << CS42L42_SRC_OLK_SHIFT) +#define CS42L42_SRC_IUNLK_SHIFT 2 +#define CS42L42_SRC_IUNLK_MASK (1 << CS42L42_SRC_IUNLK_SHIFT) +#define CS42L42_SRC_OUNLK_SHIFT 3 +#define CS42L42_SRC_OUNLK_MASK (1 << CS42L42_SRC_OUNLK_SHIFT) +#define CS42L42_SRC_VAL_MASK (CS42L42_SRC_ILK_MASK | \ + CS42L42_SRC_OLK_MASK | \ + CS42L42_SRC_IUNLK_MASK | \ + CS42L42_SRC_OUNLK_MASK) + +#define CS42L42_ASP_RX_INT_MASK (CS42L42_PAGE_13 + 0x19) +#define CS42L42_ASPRX_NOLRCK_SHIFT 0 +#define CS42L42_ASPRX_NOLRCK_MASK (1 << CS42L42_ASPRX_NOLRCK_SHIFT) +#define CS42L42_ASPRX_EARLY_SHIFT 1 +#define CS42L42_ASPRX_EARLY_MASK (1 << CS42L42_ASPRX_EARLY_SHIFT) +#define CS42L42_ASPRX_LATE_SHIFT 2 +#define CS42L42_ASPRX_LATE_MASK (1 << CS42L42_ASPRX_LATE_SHIFT) +#define CS42L42_ASPRX_ERROR_SHIFT 3 +#define CS42L42_ASPRX_ERROR_MASK (1 << CS42L42_ASPRX_ERROR_SHIFT) +#define CS42L42_ASPRX_OVLD_SHIFT 4 +#define CS42L42_ASPRX_OVLD_MASK (1 << CS42L42_ASPRX_OVLD_SHIFT) +#define CS42L42_ASP_RX_VAL_MASK (CS42L42_ASPRX_NOLRCK_MASK | \ + CS42L42_ASPRX_EARLY_MASK | \ + CS42L42_ASPRX_LATE_MASK | \ + CS42L42_ASPRX_ERROR_MASK | \ + CS42L42_ASPRX_OVLD_MASK) + +#define CS42L42_ASP_TX_INT_MASK (CS42L42_PAGE_13 + 0x1A) +#define CS42L42_ASPTX_NOLRCK_SHIFT 0 +#define CS42L42_ASPTX_NOLRCK_MASK (1 << CS42L42_ASPTX_NOLRCK_SHIFT) +#define CS42L42_ASPTX_EARLY_SHIFT 1 +#define CS42L42_ASPTX_EARLY_MASK (1 << CS42L42_ASPTX_EARLY_SHIFT) +#define CS42L42_ASPTX_LATE_SHIFT 2 +#define CS42L42_ASPTX_LATE_MASK (1 << CS42L42_ASPTX_LATE_SHIFT) +#define CS42L42_ASPTX_SMERROR_SHIFT 3 +#define CS42L42_ASPTX_SMERROR_MASK (1 << CS42L42_ASPTX_SMERROR_SHIFT) +#define CS42L42_ASP_TX_VAL_MASK (CS42L42_ASPTX_NOLRCK_MASK | \ + CS42L42_ASPTX_EARLY_MASK | \ + CS42L42_ASPTX_LATE_MASK | \ + CS42L42_ASPTX_SMERROR_MASK) + +#define CS42L42_CODEC_INT_MASK (CS42L42_PAGE_13 + 0x1B) +#define CS42L42_PDN_DONE_SHIFT 0 +#define CS42L42_PDN_DONE_MASK (1 << CS42L42_PDN_DONE_SHIFT) +#define CS42L42_HSDET_AUTO_DONE_SHIFT 1 +#define CS42L42_HSDET_AUTO_DONE_MASK (1 << CS42L42_HSDET_AUTO_DONE_SHIFT) +#define CS42L42_CODEC_VAL_MASK (CS42L42_PDN_DONE_MASK | \ + CS42L42_HSDET_AUTO_DONE_MASK) + +#define CS42L42_SRCPL_INT_MASK (CS42L42_PAGE_13 + 0x1C) +#define CS42L42_SRCPL_ADC_LK_SHIFT 0 +#define CS42L42_SRCPL_ADC_LK_MASK (1 << CS42L42_SRCPL_ADC_LK_SHIFT) +#define CS42L42_SRCPL_DAC_LK_SHIFT 2 +#define CS42L42_SRCPL_DAC_LK_MASK (1 << CS42L42_SRCPL_DAC_LK_SHIFT) +#define CS42L42_SRCPL_ADC_UNLK_SHIFT 5 +#define CS42L42_SRCPL_ADC_UNLK_MASK (1 << CS42L42_SRCPL_ADC_UNLK_SHIFT) +#define CS42L42_SRCPL_DAC_UNLK_SHIFT 6 +#define CS42L42_SRCPL_DAC_UNLK_MASK (1 << CS42L42_SRCPL_DAC_UNLK_SHIFT) +#define CS42L42_SRCPL_VAL_MASK (CS42L42_SRCPL_ADC_LK_MASK | \ + CS42L42_SRCPL_DAC_LK_MASK | \ + CS42L42_SRCPL_ADC_UNLK_MASK | \ + CS42L42_SRCPL_DAC_UNLK_MASK) + +#define CS42L42_VPMON_INT_MASK (CS42L42_PAGE_13 + 0x1E) +#define CS42L42_VPMON_SHIFT 0 +#define CS42L42_VPMON_MASK (1 << CS42L42_VPMON_SHIFT) +#define CS42L42_VPMON_VAL_MASK CS42L42_VPMON_MASK + +#define CS42L42_PLL_LOCK_INT_MASK (CS42L42_PAGE_13 + 0x1F) +#define CS42L42_PLL_LOCK_SHIFT 0 +#define CS42L42_PLL_LOCK_MASK (1 << CS42L42_PLL_LOCK_SHIFT) +#define CS42L42_PLL_LOCK_VAL_MASK CS42L42_PLL_LOCK_MASK + +#define CS42L42_TSRS_PLUG_INT_MASK (CS42L42_PAGE_13 + 0x20) +#define CS42L42_RS_PLUG_SHIFT 0 +#define CS42L42_RS_PLUG_MASK (1 << CS42L42_RS_PLUG_SHIFT) +#define CS42L42_RS_UNPLUG_SHIFT 1 +#define CS42L42_RS_UNPLUG_MASK (1 << CS42L42_RS_UNPLUG_SHIFT) +#define CS42L42_TS_PLUG_SHIFT 2 +#define CS42L42_TS_PLUG_MASK (1 << CS42L42_TS_PLUG_SHIFT) +#define CS42L42_TS_UNPLUG_SHIFT 3 +#define CS42L42_TS_UNPLUG_MASK (1 << CS42L42_TS_UNPLUG_SHIFT) +#define CS42L42_TSRS_PLUG_VAL_MASK (CS42L42_RS_PLUG_MASK | \ + CS42L42_RS_UNPLUG_MASK | \ + CS42L42_TS_PLUG_MASK | \ + CS42L42_TS_UNPLUG_MASK) +#define CS42L42_TS_PLUG 3 +#define CS42L42_TS_UNPLUG 0 +#define CS42L42_TS_TRANS 1 + +/* Page 0x15 Fractional-N PLL Registers */ +#define CS42L42_PLL_CTL1 (CS42L42_PAGE_15 + 0x01) +#define CS42L42_PLL_START_SHIFT 0 +#define CS42L42_PLL_START_MASK (1 << CS42L42_PLL_START_SHIFT) + +#define CS42L42_PLL_DIV_FRAC0 (CS42L42_PAGE_15 + 0x02) +#define CS42L42_PLL_DIV_FRAC_SHIFT 0 +#define CS42L42_PLL_DIV_FRAC_MASK (0xff << CS42L42_PLL_DIV_FRAC_SHIFT) + +#define CS42L42_PLL_DIV_FRAC1 (CS42L42_PAGE_15 + 0x03) +#define CS42L42_PLL_DIV_FRAC2 (CS42L42_PAGE_15 + 0x04) + +#define CS42L42_PLL_DIV_INT (CS42L42_PAGE_15 + 0x05) +#define CS42L42_PLL_DIV_INT_SHIFT 0 +#define CS42L42_PLL_DIV_INT_MASK (0xff << CS42L42_PLL_DIV_INT_SHIFT) + +#define CS42L42_PLL_CTL3 (CS42L42_PAGE_15 + 0x08) +#define CS42L42_PLL_DIVOUT_SHIFT 0 +#define CS42L42_PLL_DIVOUT_MASK (0xff << CS42L42_PLL_DIVOUT_SHIFT) + +#define CS42L42_PLL_CAL_RATIO (CS42L42_PAGE_15 + 0x0A) +#define CS42L42_PLL_CAL_RATIO_SHIFT 0 +#define CS42L42_PLL_CAL_RATIO_MASK (0xff << CS42L42_PLL_CAL_RATIO_SHIFT) + +#define CS42L42_PLL_CTL4 (CS42L42_PAGE_15 + 0x1B) +#define CS42L42_PLL_MODE_SHIFT 0 +#define CS42L42_PLL_MODE_MASK (3 << CS42L42_PLL_MODE_SHIFT) + +/* Page 0x19 HP Load Detect Registers */ +#define CS42L42_LOAD_DET_RCSTAT (CS42L42_PAGE_19 + 0x25) +#define CS42L42_RLA_STAT_SHIFT 0 +#define CS42L42_RLA_STAT_MASK (3 << CS42L42_RLA_STAT_SHIFT) +#define CS42L42_RLA_STAT_15_OHM 0 + +#define CS42L42_LOAD_DET_DONE (CS42L42_PAGE_19 + 0x26) +#define CS42L42_HPLOAD_DET_DONE_SHIFT 0 +#define CS42L42_HPLOAD_DET_DONE_MASK (1 << CS42L42_HPLOAD_DET_DONE_SHIFT) + +#define CS42L42_LOAD_DET_EN (CS42L42_PAGE_19 + 0x27) +#define CS42L42_HP_LD_EN_SHIFT 0 +#define CS42L42_HP_LD_EN_MASK (1 << CS42L42_HP_LD_EN_SHIFT) + +/* Page 0x1B Headset Interface Registers */ +#define CS42L42_HSBIAS_SC_AUTOCTL (CS42L42_PAGE_1B + 0x70) +#define CS42L42_HSBIAS_SENSE_TRIP_SHIFT 0 +#define CS42L42_HSBIAS_SENSE_TRIP_MASK (7 << \ + CS42L42_HSBIAS_SENSE_TRIP_SHIFT) +#define CS42L42_TIP_SENSE_EN_SHIFT 5 +#define CS42L42_TIP_SENSE_EN_MASK (1 << \ + CS42L42_TIP_SENSE_EN_SHIFT) +#define CS42L42_AUTO_HSBIAS_HIZ_SHIFT 6 +#define CS42L42_AUTO_HSBIAS_HIZ_MASK (1 << \ + CS42L42_AUTO_HSBIAS_HIZ_SHIFT) +#define CS42L42_HSBIAS_SENSE_EN_SHIFT 7 +#define CS42L42_HSBIAS_SENSE_EN_MASK (1 << \ + CS42L42_HSBIAS_SENSE_EN_SHIFT) + +#define CS42L42_WAKE_CTL (CS42L42_PAGE_1B + 0x71) +#define CS42L42_WAKEB_CLEAR_SHIFT 0 +#define CS42L42_WAKEB_CLEAR_MASK (1 << CS42L42_WAKEB_CLEAR_SHIFT) +#define CS42L42_WAKEB_MODE_SHIFT 5 +#define CS42L42_WAKEB_MODE_MASK (1 << CS42L42_WAKEB_MODE_SHIFT) +#define CS42L42_M_HP_WAKE_SHIFT 6 +#define CS42L42_M_HP_WAKE_MASK (1 << CS42L42_M_HP_WAKE_SHIFT) +#define CS42L42_M_MIC_WAKE_SHIFT 7 +#define CS42L42_M_MIC_WAKE_MASK (1 << CS42L42_M_MIC_WAKE_SHIFT) + +#define CS42L42_ADC_DISABLE_MUTE (CS42L42_PAGE_1B + 0x72) +#define CS42L42_ADC_DISABLE_S0_MUTE_SHIFT 7 +#define CS42L42_ADC_DISABLE_S0_MUTE_MASK (1 << \ + CS42L42_ADC_DISABLE_S0_MUTE_SHIFT) + +#define CS42L42_TIPSENSE_CTL (CS42L42_PAGE_1B + 0x73) +#define CS42L42_TIP_SENSE_DEBOUNCE_SHIFT 0 +#define CS42L42_TIP_SENSE_DEBOUNCE_MASK (3 << \ + CS42L42_TIP_SENSE_DEBOUNCE_SHIFT) +#define CS42L42_TIP_SENSE_INV_SHIFT 5 +#define CS42L42_TIP_SENSE_INV_MASK (1 << \ + CS42L42_TIP_SENSE_INV_SHIFT) +#define CS42L42_TIP_SENSE_CTRL_SHIFT 6 +#define CS42L42_TIP_SENSE_CTRL_MASK (3 << \ + CS42L42_TIP_SENSE_CTRL_SHIFT) + +#define CS42L42_MISC_DET_CTL (CS42L42_PAGE_1B + 0x74) +#define CS42L42_PDN_MIC_LVL_DET_SHIFT 0 +#define CS42L42_PDN_MIC_LVL_DET_MASK (1 << CS42L42_PDN_MIC_LVL_DET_SHIFT) +#define CS42L42_HSBIAS_CTL_SHIFT 1 +#define CS42L42_HSBIAS_CTL_MASK (3 << CS42L42_HSBIAS_CTL_SHIFT) +#define CS42L42_DETECT_MODE_SHIFT 3 +#define CS42L42_DETECT_MODE_MASK (3 << CS42L42_DETECT_MODE_SHIFT) + +#define CS42L42_MIC_DET_CTL1 (CS42L42_PAGE_1B + 0x75) +#define CS42L42_HS_DET_LEVEL_SHIFT 0 +#define CS42L42_HS_DET_LEVEL_MASK (0x3F << CS42L42_HS_DET_LEVEL_SHIFT) +#define CS42L42_EVENT_STAT_SEL_SHIFT 6 +#define CS42L42_EVENT_STAT_SEL_MASK (1 << CS42L42_EVENT_STAT_SEL_SHIFT) +#define CS42L42_LATCH_TO_VP_SHIFT 7 +#define CS42L42_LATCH_TO_VP_MASK (1 << CS42L42_LATCH_TO_VP_SHIFT) + +#define CS42L42_MIC_DET_CTL2 (CS42L42_PAGE_1B + 0x76) +#define CS42L42_DEBOUNCE_TIME_SHIFT 5 +#define CS42L42_DEBOUNCE_TIME_MASK (0x07 << CS42L42_DEBOUNCE_TIME_SHIFT) + +#define CS42L42_DET_STATUS1 (CS42L42_PAGE_1B + 0x77) +#define CS42L42_HSBIAS_HIZ_MODE_SHIFT 6 +#define CS42L42_HSBIAS_HIZ_MODE_MASK (1 << CS42L42_HSBIAS_HIZ_MODE_SHIFT) +#define CS42L42_TIP_SENSE_SHIFT 7 +#define CS42L42_TIP_SENSE_MASK (1 << CS42L42_TIP_SENSE_SHIFT) + +#define CS42L42_DET_STATUS2 (CS42L42_PAGE_1B + 0x78) +#define CS42L42_SHORT_TRUE_SHIFT 0 +#define CS42L42_SHORT_TRUE_MASK (1 << CS42L42_SHORT_TRUE_SHIFT) +#define CS42L42_HS_TRUE_SHIFT 1 +#define CS42L42_HS_TRUE_MASK (1 << CS42L42_HS_TRUE_SHIFT) + +#define CS42L42_DET_INT1_MASK (CS42L42_PAGE_1B + 0x79) +#define CS42L42_TIP_SENSE_UNPLUG_SHIFT 5 +#define CS42L42_TIP_SENSE_UNPLUG_MASK (1 << CS42L42_TIP_SENSE_UNPLUG_SHIFT) +#define CS42L42_TIP_SENSE_PLUG_SHIFT 6 +#define CS42L42_TIP_SENSE_PLUG_MASK (1 << CS42L42_TIP_SENSE_PLUG_SHIFT) +#define CS42L42_HSBIAS_SENSE_SHIFT 7 +#define CS42L42_HSBIAS_SENSE_MASK (1 << CS42L42_HSBIAS_SENSE_SHIFT) +#define CS42L42_DET_INT_VAL1_MASK (CS42L42_TIP_SENSE_UNPLUG_MASK | \ + CS42L42_TIP_SENSE_PLUG_MASK | \ + CS42L42_HSBIAS_SENSE_MASK) + +#define CS42L42_DET_INT2_MASK (CS42L42_PAGE_1B + 0x7A) +#define CS42L42_M_SHORT_DET_SHIFT 0 +#define CS42L42_M_SHORT_DET_MASK (1 << \ + CS42L42_M_SHORT_DET_SHIFT) +#define CS42L42_M_SHORT_RLS_SHIFT 1 +#define CS42L42_M_SHORT_RLS_MASK (1 << \ + CS42L42_M_SHORT_RLS_SHIFT) +#define CS42L42_M_HSBIAS_HIZ_SHIFT 2 +#define CS42L42_M_HSBIAS_HIZ_MASK (1 << \ + CS42L42_M_HSBIAS_HIZ_SHIFT) +#define CS42L42_M_DETECT_FT_SHIFT 6 +#define CS42L42_M_DETECT_FT_MASK (1 << \ + CS42L42_M_DETECT_FT_SHIFT) +#define CS42L42_M_DETECT_TF_SHIFT 7 +#define CS42L42_M_DETECT_TF_MASK (1 << \ + CS42L42_M_DETECT_TF_SHIFT) +#define CS42L42_DET_INT_VAL2_MASK (CS42L42_M_SHORT_DET_MASK | \ + CS42L42_M_SHORT_RLS_MASK | \ + CS42L42_M_HSBIAS_HIZ_MASK | \ + CS42L42_M_DETECT_FT_MASK | \ + CS42L42_M_DETECT_TF_MASK) + +/* Page 0x1C Headset Bias Registers */ +#define CS42L42_HS_BIAS_CTL (CS42L42_PAGE_1C + 0x03) +#define CS42L42_HSBIAS_RAMP_SHIFT 0 +#define CS42L42_HSBIAS_RAMP_MASK (3 << CS42L42_HSBIAS_RAMP_SHIFT) +#define CS42L42_HSBIAS_PD_SHIFT 4 +#define CS42L42_HSBIAS_PD_MASK (1 << CS42L42_HSBIAS_PD_SHIFT) +#define CS42L42_HSBIAS_CAPLESS_SHIFT 7 +#define CS42L42_HSBIAS_CAPLESS_MASK (1 << CS42L42_HSBIAS_CAPLESS_SHIFT) + +/* Page 0x1D ADC Registers */ +#define CS42L42_ADC_CTL (CS42L42_PAGE_1D + 0x01) +#define CS42L42_ADC_NOTCH_DIS_SHIFT 5 +#define CS42L42_ADC_FORCE_WEAK_VCM_SHIFT 4 +#define CS42L42_ADC_INV_SHIFT 2 +#define CS42L42_ADC_DIG_BOOST_SHIFT 0 + +#define CS42L42_ADC_VOLUME (CS42L42_PAGE_1D + 0x03) +#define CS42L42_ADC_VOL_SHIFT 0 + +#define CS42L42_ADC_WNF_HPF_CTL (CS42L42_PAGE_1D + 0x04) +#define CS42L42_ADC_WNF_CF_SHIFT 4 +#define CS42L42_ADC_WNF_EN_SHIFT 3 +#define CS42L42_ADC_HPF_CF_SHIFT 1 +#define CS42L42_ADC_HPF_EN_SHIFT 0 + +/* Page 0x1F DAC Registers */ +#define CS42L42_DAC_CTL1 (CS42L42_PAGE_1F + 0x01) +#define CS42L42_DACB_INV_SHIFT 1 +#define CS42L42_DACA_INV_SHIFT 0 + +#define CS42L42_DAC_CTL2 (CS42L42_PAGE_1F + 0x06) +#define CS42L42_HPOUT_PULLDOWN_SHIFT 4 +#define CS42L42_HPOUT_PULLDOWN_MASK (15 << CS42L42_HPOUT_PULLDOWN_SHIFT) +#define CS42L42_HPOUT_LOAD_SHIFT 3 +#define CS42L42_HPOUT_LOAD_MASK (1 << CS42L42_HPOUT_LOAD_SHIFT) +#define CS42L42_HPOUT_CLAMP_SHIFT 2 +#define CS42L42_HPOUT_CLAMP_MASK (1 << CS42L42_HPOUT_CLAMP_SHIFT) +#define CS42L42_DAC_HPF_EN_SHIFT 1 +#define CS42L42_DAC_HPF_EN_MASK (1 << CS42L42_DAC_HPF_EN_SHIFT) +#define CS42L42_DAC_MON_EN_SHIFT 0 +#define CS42L42_DAC_MON_EN_MASK (1 << CS42L42_DAC_MON_EN_SHIFT) + +/* Page 0x20 HP CTL Registers */ +#define CS42L42_HP_CTL (CS42L42_PAGE_20 + 0x01) +#define CS42L42_HP_ANA_BMUTE_SHIFT 3 +#define CS42L42_HP_ANA_BMUTE_MASK (1 << CS42L42_HP_ANA_BMUTE_SHIFT) +#define CS42L42_HP_ANA_AMUTE_SHIFT 2 +#define CS42L42_HP_ANA_AMUTE_MASK (1 << CS42L42_HP_ANA_AMUTE_SHIFT) +#define CS42L42_HP_FULL_SCALE_VOL_SHIFT 1 +#define CS42L42_HP_FULL_SCALE_VOL_MASK (1 << CS42L42_HP_FULL_SCALE_VOL_SHIFT) + +/* Page 0x21 Class H Registers */ +#define CS42L42_CLASSH_CTL (CS42L42_PAGE_21 + 0x01) + +/* Page 0x23 Mixer Volume Registers */ +#define CS42L42_MIXER_CHA_VOL (CS42L42_PAGE_23 + 0x01) +#define CS42L42_MIXER_ADC_VOL (CS42L42_PAGE_23 + 0x02) + +#define CS42L42_MIXER_CHB_VOL (CS42L42_PAGE_23 + 0x03) +#define CS42L42_MIXER_CH_VOL_SHIFT 0 +#define CS42L42_MIXER_CH_VOL_MASK (0x3f << CS42L42_MIXER_CH_VOL_SHIFT) + +/* Page 0x24 EQ Registers */ +#define CS42L42_EQ_COEF_IN0 (CS42L42_PAGE_24 + 0x01) +#define CS42L42_EQ_COEF_IN1 (CS42L42_PAGE_24 + 0x02) +#define CS42L42_EQ_COEF_IN2 (CS42L42_PAGE_24 + 0x03) +#define CS42L42_EQ_COEF_IN3 (CS42L42_PAGE_24 + 0x04) +#define CS42L42_EQ_COEF_RW (CS42L42_PAGE_24 + 0x06) +#define CS42L42_EQ_COEF_OUT0 (CS42L42_PAGE_24 + 0x07) +#define CS42L42_EQ_COEF_OUT1 (CS42L42_PAGE_24 + 0x08) +#define CS42L42_EQ_COEF_OUT2 (CS42L42_PAGE_24 + 0x09) +#define CS42L42_EQ_COEF_OUT3 (CS42L42_PAGE_24 + 0x0A) +#define CS42L42_EQ_INIT_STAT (CS42L42_PAGE_24 + 0x0B) +#define CS42L42_EQ_START_FILT (CS42L42_PAGE_24 + 0x0C) +#define CS42L42_EQ_MUTE_CTL (CS42L42_PAGE_24 + 0x0E) + +/* Page 0x25 Audio Port Registers */ +#define CS42L42_SP_RX_CH_SEL (CS42L42_PAGE_25 + 0x01) + +#define CS42L42_SP_RX_ISOC_CTL (CS42L42_PAGE_25 + 0x02) +#define CS42L42_SP_RX_RSYNC_SHIFT 6 +#define CS42L42_SP_RX_RSYNC_MASK (1 << CS42L42_SP_RX_RSYNC_SHIFT) +#define CS42L42_SP_RX_NSB_POS_SHIFT 3 +#define CS42L42_SP_RX_NSB_POS_MASK (7 << CS42L42_SP_RX_NSB_POS_SHIFT) +#define CS42L42_SP_RX_NFS_NSBB_SHIFT 2 +#define CS42L42_SP_RX_NFS_NSBB_MASK (1 << CS42L42_SP_RX_NFS_NSBB_SHIFT) +#define CS42L42_SP_RX_ISOC_MODE_SHIFT 0 +#define CS42L42_SP_RX_ISOC_MODE_MASK (3 << CS42L42_SP_RX_ISOC_MODE_SHIFT) + +#define CS42L42_SP_RX_FS (CS42L42_PAGE_25 + 0x03) +#define CS42l42_SPDIF_CH_SEL (CS42L42_PAGE_25 + 0x04) +#define CS42L42_SP_TX_ISOC_CTL (CS42L42_PAGE_25 + 0x05) +#define CS42L42_SP_TX_FS (CS42L42_PAGE_25 + 0x06) +#define CS42L42_SPDIF_SW_CTL1 (CS42L42_PAGE_25 + 0x07) + +/* Page 0x26 SRC Registers */ +#define CS42L42_SRC_SDIN_FS (CS42L42_PAGE_26 + 0x01) +#define CS42L42_SRC_SDIN_FS_SHIFT 0 +#define CS42L42_SRC_SDIN_FS_MASK (0x1f << CS42L42_SRC_SDIN_FS_SHIFT) + +#define CS42L42_SRC_SDOUT_FS (CS42L42_PAGE_26 + 0x09) + +/* Page 0x28 S/PDIF Registers */ +#define CS42L42_SPDIF_CTL1 (CS42L42_PAGE_28 + 0x01) +#define CS42L42_SPDIF_CTL2 (CS42L42_PAGE_28 + 0x02) +#define CS42L42_SPDIF_CTL3 (CS42L42_PAGE_28 + 0x03) +#define CS42L42_SPDIF_CTL4 (CS42L42_PAGE_28 + 0x04) + +/* Page 0x29 Serial Port TX Registers */ +#define CS42L42_ASP_TX_SZ_EN (CS42L42_PAGE_29 + 0x01) +#define CS42L42_ASP_TX_CH_EN (CS42L42_PAGE_29 + 0x02) +#define CS42L42_ASP_TX_CH_AP_RES (CS42L42_PAGE_29 + 0x03) +#define CS42L42_ASP_TX_CH1_BIT_MSB (CS42L42_PAGE_29 + 0x04) +#define CS42L42_ASP_TX_CH1_BIT_LSB (CS42L42_PAGE_29 + 0x05) +#define CS42L42_ASP_TX_HIZ_DLY_CFG (CS42L42_PAGE_29 + 0x06) +#define CS42L42_ASP_TX_CH2_BIT_MSB (CS42L42_PAGE_29 + 0x0A) +#define CS42L42_ASP_TX_CH2_BIT_LSB (CS42L42_PAGE_29 + 0x0B) + +/* Page 0x2A Serial Port RX Registers */ +#define CS42L42_ASP_RX_DAI0_EN (CS42L42_PAGE_2A + 0x01) +#define CS42L42_ASP_RX0_CH_EN_SHIFT 2 +#define CS42L42_ASP_RX0_CH_EN_MASK (0xf << CS42L42_ASP_RX0_CH_EN_SHIFT) +#define CS42L42_ASP_RX0_CH1_EN 1 +#define CS42L42_ASP_RX0_CH2_EN 2 +#define CS42L42_ASP_RX0_CH3_EN 4 +#define CS42L42_ASP_RX0_CH4_EN 8 + +#define CS42L42_ASP_RX_DAI0_CH1_AP_RES (CS42L42_PAGE_2A + 0x02) +#define CS42L42_ASP_RX_DAI0_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x03) +#define CS42L42_ASP_RX_DAI0_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x04) +#define CS42L42_ASP_RX_DAI0_CH2_AP_RES (CS42L42_PAGE_2A + 0x05) +#define CS42L42_ASP_RX_DAI0_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x06) +#define CS42L42_ASP_RX_DAI0_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x07) +#define CS42L42_ASP_RX_DAI0_CH3_AP_RES (CS42L42_PAGE_2A + 0x08) +#define CS42L42_ASP_RX_DAI0_CH3_BIT_MSB (CS42L42_PAGE_2A + 0x09) +#define CS42L42_ASP_RX_DAI0_CH3_BIT_LSB (CS42L42_PAGE_2A + 0x0A) +#define CS42L42_ASP_RX_DAI0_CH4_AP_RES (CS42L42_PAGE_2A + 0x0B) +#define CS42L42_ASP_RX_DAI0_CH4_BIT_MSB (CS42L42_PAGE_2A + 0x0C) +#define CS42L42_ASP_RX_DAI0_CH4_BIT_LSB (CS42L42_PAGE_2A + 0x0D) +#define CS42L42_ASP_RX_DAI1_CH1_AP_RES (CS42L42_PAGE_2A + 0x0E) +#define CS42L42_ASP_RX_DAI1_CH1_BIT_MSB (CS42L42_PAGE_2A + 0x0F) +#define CS42L42_ASP_RX_DAI1_CH1_BIT_LSB (CS42L42_PAGE_2A + 0x10) +#define CS42L42_ASP_RX_DAI1_CH2_AP_RES (CS42L42_PAGE_2A + 0x11) +#define CS42L42_ASP_RX_DAI1_CH2_BIT_MSB (CS42L42_PAGE_2A + 0x12) +#define CS42L42_ASP_RX_DAI1_CH2_BIT_LSB (CS42L42_PAGE_2A + 0x13) + +#define CS42L42_ASP_RX_CH_AP_SHIFT 6 +#define CS42L42_ASP_RX_CH_AP_MASK (1 << CS42L42_ASP_RX_CH_AP_SHIFT) +#define CS42L42_ASP_RX_CH_AP_LOW 0 +#define CS42L42_ASP_RX_CH_AP_HI 1 +#define CS42L42_ASP_RX_CH_RES_SHIFT 0 +#define CS42L42_ASP_RX_CH_RES_MASK (3 << CS42L42_ASP_RX_CH_RES_SHIFT) +#define CS42L42_ASP_RX_CH_RES_32 3 +#define CS42L42_ASP_RX_CH_RES_16 1 +#define CS42L42_ASP_RX_CH_BIT_ST_SHIFT 0 +#define CS42L42_ASP_RX_CH_BIT_ST_MASK (0xff << CS42L42_ASP_RX_CH_BIT_ST_SHIFT) + +/* Page 0x30 ID Registers */ +#define CS42L42_SUB_REVID (CS42L42_PAGE_30 + 0x14) +#define CS42L42_MAX_REGISTER (CS42L42_PAGE_30 + 0x14) + +/* Defines for fracturing values spread across multiple registers */ +#define CS42L42_FRAC0_VAL(val) ((val) & 0x0000ff) +#define CS42L42_FRAC1_VAL(val) (((val) & 0x00ff00) >> 8) +#define CS42L42_FRAC2_VAL(val) (((val) & 0xff0000) >> 16) + +#define CS42L42_NUM_SUPPLIES 5 + +static const char *const cs42l42_supply_names[CS42L42_NUM_SUPPLIES] = { + "VA", + "VP", + "VCP", + "VD_FILT", + "VL", +}; + +struct cs42l42_private { + struct regmap *regmap; + struct snd_soc_codec *codec; + struct regulator_bulk_data supplies[CS42L42_NUM_SUPPLIES]; + struct gpio_desc *reset_gpio; + struct completion pdn_done; + u32 sclk; + u32 srate; + u32 swidth; + u8 plug_state; + u8 hs_type; + u8 ts_inv; + u8 ts_dbnc_rise; + u8 ts_dbnc_fall; + u8 btn_det_init_dbnce; + u8 btn_det_event_dbnce; + u8 bias_thresholds[CS42L42_NUM_BIASES]; + u8 hs_bias_ramp_rate; + u8 hs_bias_ramp_time; +}; + +#endif /* __CS42L42_H__ */ -- cgit v1.2.3-59-g8ed1b From b2b7b56f713ab833413548b119c53bbe2a9a9f8f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 7 Nov 2016 14:08:19 +0100 Subject: ASoC: sunxi: i2s: Implement set_sysclk In our i2s driver, we were previously trying to guess which oversample the user wanted to use by looking at the rate and trying to max it. However, the cards, and especially simple-card with its mclk-fs property will already provide the expected oversample ratio by using the set_sysclk callback. We can thus implement it and remove the logic to deal with the runtime guess. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-i2s.c | 53 ++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c index a7653114e895..f24d19526603 100644 --- a/sound/soc/sunxi/sun4i-i2s.c +++ b/sound/soc/sunxi/sun4i-i2s.c @@ -93,6 +93,8 @@ struct sun4i_i2s { struct clk *mod_clk; struct regmap *regmap; + unsigned int mclk_freq; + struct snd_dmaengine_dai_dma_data capture_dma_data; struct snd_dmaengine_dai_dma_data playback_dma_data; }; @@ -158,14 +160,24 @@ static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, } static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; +static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++) + if (sun4i_i2s_oversample_rates[i] == oversample) + return true; + + return false; +} static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, unsigned int rate, unsigned int word_size) { - unsigned int clk_rate; + unsigned int oversample_rate, clk_rate; int bclk_div, mclk_div; - int ret, i; + int ret; switch (rate) { case 176400: @@ -197,21 +209,18 @@ static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, if (ret) return ret; - /* Always favor the highest oversampling rate */ - for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) { - unsigned int oversample_rate = sun4i_i2s_oversample_rates[i]; - - bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, - word_size); - mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, - clk_rate, - rate); + oversample_rate = i2s->mclk_freq / rate; + if (!sun4i_i2s_oversample_is_valid(oversample_rate)) + return -EINVAL; - if ((bclk_div >= 0) && (mclk_div >= 0)) - break; - } + bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, + word_size); + if (bclk_div < 0) + return -EINVAL; - if ((bclk_div < 0) || (mclk_div < 0)) + mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, + clk_rate, rate); + if (mclk_div < 0) return -EINVAL; regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, @@ -481,9 +490,23 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream, regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); } +static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); + + if (clk_id != 0) + return -EINVAL; + + i2s->mclk_freq = freq; + + return 0; +} + static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { .hw_params = sun4i_i2s_hw_params, .set_fmt = sun4i_i2s_set_fmt, + .set_sysclk = sun4i_i2s_set_sysclk, .shutdown = sun4i_i2s_shutdown, .startup = sun4i_i2s_startup, .trigger = sun4i_i2s_trigger, -- cgit v1.2.3-59-g8ed1b From fbd972d7f4a60677f6fbe558dc23e4029dc2d45d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 7 Nov 2016 14:08:20 +0100 Subject: ASoC: wm8978: Adjust clock indices so that simple card works Using simple-card with the wm8978 doesn't work because simple card calls set_sysclk on the clock index 0, which is not the MCLK in the WM8978. Adjust the clock definition so that the clock 0 is the MCLK. Signed-off-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/codecs/wm8978.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8978.h b/sound/soc/codecs/wm8978.h index 6ae43495b7cf..0dcf6868dff6 100644 --- a/sound/soc/codecs/wm8978.h +++ b/sound/soc/codecs/wm8978.h @@ -78,8 +78,8 @@ enum wm8978_clk_id { }; enum wm8978_sysclk_src { + WM8978_MCLK = 0, WM8978_PLL, - WM8978_MCLK }; #endif /* __WM8978_H__ */ -- cgit v1.2.3-59-g8ed1b From 06859fca4368c407d4acccf3948b8b825db5e569 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 7 Nov 2016 13:03:17 +0000 Subject: ASoC: core: If a platform doesn't have an of_node use parent's node Support was added to allow location of both CPU and CODEC components of a DAI link from their parent's of_node if they did not have an of_node themselves in this commit: commit 3e0aa8d83bf8 ("ASoC: core: If component doesn't have of_node use parent's node instead") However this leaves platforms as something of a special case as the major DAI component that doesn't do this. Since this is useful for MFD devices which often utilise a single device tree entry for the whole device, add support for looking up platforms from the parent's of_node as well. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..26da0466126d 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -993,6 +993,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link_component cpu_dai_component; struct snd_soc_dai **codec_dais; struct snd_soc_platform *platform; + struct device_node *platform_of_node; const char *platform_name; int i; @@ -1042,9 +1043,12 @@ static int soc_bind_dai_link(struct snd_soc_card *card, /* find one from the set of registered platforms */ list_for_each_entry(platform, &platform_list, list) { + platform_of_node = platform->dev->of_node; + if (!platform_of_node && platform->dev->parent->of_node) + platform_of_node = platform->dev->parent->of_node; + if (dai_link->platform_of_node) { - if (platform->dev->of_node != - dai_link->platform_of_node) + if (platform_of_node != dai_link->platform_of_node) continue; } else { if (strcmp(platform->component.name, platform_name)) -- cgit v1.2.3-59-g8ed1b From 24c99f843208df70ec7d1e04aa405f7e4c36f228 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 7 Nov 2016 18:06:59 +0800 Subject: ASoC: sun4i-codec: Add support for A31 ADC capture path The A31's internal codec capture path has a mixer in front of the ADC for each channel, capable of selecting various inputs, including microphones, line in, phone in, and the main output mixer. This patch adds the various controls, widgets and routes needed for audio capture from the already supported inputs on the A31. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 65 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 1934db29b2b5..735115244b17 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -786,6 +786,30 @@ static const struct snd_kcontrol_new sun6i_codec_mixer_controls[] = { SUN6I_CODEC_OM_DACA_CTRL_RMIX_MIC2, 1, 0), }; +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun6i_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE("Mixer Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXL, + SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXR, 1, 0), + SOC_DAPM_DOUBLE("Mixer Reversed Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_OMIXR, + SUN6I_CODEC_ADC_ACTL_RADCMIX_OMIXL, 1, 0), + SOC_DAPM_DOUBLE("Line In Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_LINEINL, + SUN6I_CODEC_ADC_ACTL_RADCMIX_LINEINR, 1, 0), + SOC_DAPM_DOUBLE("Mic1 Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC1, + SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC1, 1, 0), + SOC_DAPM_DOUBLE("Mic2 Capture Switch", + SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_LADCMIX_MIC2, + SUN6I_CODEC_ADC_ACTL_RADCMIX_MIC2, 1, 0), +}; + /* headphone controls */ static const char * const sun6i_codec_hp_src_enum_text[] = { "DAC", "Mixer", @@ -885,6 +909,10 @@ static const struct snd_kcontrol_new sun6i_codec_codec_widgets[] = { SOC_SINGLE_TLV("Mic2 Boost Volume", SUN6I_CODEC_MIC_CTRL, SUN6I_CODEC_MIC_CTRL_MIC2BOOST, 0x7, 0, sun6i_codec_mic_gain_scale), + SOC_DOUBLE_TLV("ADC Capture Volume", + SUN6I_CODEC_ADC_ACTL, SUN6I_CODEC_ADC_ACTL_ADCLG, + SUN6I_CODEC_ADC_ACTL_ADCRG, 0x7, 0, + sun6i_codec_out_mixer_pregain_scale), }; static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { @@ -910,6 +938,23 @@ static const struct snd_soc_dapm_widget sun6i_codec_codec_dapm_widgets[] = { /* Line In */ SND_SOC_DAPM_INPUT("LINEIN"), + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, + SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, + NULL, 0), + + /* Analog parts of the ADCs */ + SND_SOC_DAPM_ADC("Left ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", "Codec Capture", SUN6I_CODEC_ADC_ACTL, + SUN6I_CODEC_ADC_ACTL_ADCREN, 0), + + /* ADC Mixers */ + SOC_MIXER_ARRAY("Left ADC Mixer", SND_SOC_NOPM, 0, 0, + sun6i_codec_adc_mixer_controls), + SOC_MIXER_ARRAY("Right ADC Mixer", SND_SOC_NOPM, 0, 0, + sun6i_codec_adc_mixer_controls), + /* Digital parts of the DACs */ SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, SUN4I_CODEC_DAC_DPC_EN_DA, 0, @@ -973,6 +1018,20 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + /* Headphone Routes */ { "Headphone Source Playback Route", "DAC", "Left DAC" }, { "Headphone Source Playback Route", "DAC", "Right DAC" }, @@ -987,6 +1046,12 @@ static const struct snd_soc_dapm_route sun6i_codec_codec_dapm_routes[] = { { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, { "LINEOUT", NULL, "Line Out Source Playback Route" }, + + /* ADC Routes */ + { "Left ADC", NULL, "ADC Enable" }, + { "Right ADC", NULL, "ADC Enable" }, + { "Left ADC", NULL, "Left ADC Mixer" }, + { "Right ADC", NULL, "Right ADC Mixer" }, }; static struct snd_soc_codec_driver sun6i_codec_codec = { -- cgit v1.2.3-59-g8ed1b From 9aead156c0665a362c8b007b51fe3396fea4d346 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 7 Nov 2016 18:06:58 +0800 Subject: ASoC: sun4i-codec: Add support for optional reset control to quirks The later Allwinner SoCs have a dedicated reset controller, and peripherals have dedicated reset controls which need to be deasserted before the associated peripheral can be used. Add support for this to the quirks structure and probe/remove functions. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 735115244b17..6379efd21f00 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -217,6 +218,7 @@ struct sun4i_codec { struct regmap *regmap; struct clk *clk_apb; struct clk *clk_module; + struct reset_control *rst; struct gpio_desc *gpio_pa; /* ADC_FIFOC register is at different offset on different SoCs */ @@ -1232,6 +1234,7 @@ struct sun4i_codec_quirks { struct reg_field reg_adc_fifoc; /* used for regmap_field */ unsigned int reg_dac_txdata; /* TX FIFO offset for DMA config */ unsigned int reg_adc_rxdata; /* RX FIFO offset for DMA config */ + bool has_reset; }; static const struct sun4i_codec_quirks sun4i_codec_quirks = { @@ -1327,6 +1330,14 @@ static int sun4i_codec_probe(struct platform_device *pdev) return PTR_ERR(scodec->clk_module); } + if (quirks->has_reset) { + scodec->rst = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(scodec->rst)) { + dev_err(&pdev->dev, "Failed to get reset control\n"); + return PTR_ERR(scodec->rst); + } + }; + scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", GPIOD_OUT_LOW); if (IS_ERR(scodec->gpio_pa)) { @@ -1353,6 +1364,16 @@ static int sun4i_codec_probe(struct platform_device *pdev) return -EINVAL; } + /* Deassert the reset control */ + if (scodec->rst) { + ret = reset_control_deassert(scodec->rst); + if (ret) { + dev_err(&pdev->dev, + "Failed to deassert the reset control\n"); + goto err_clk_disable; + } + } + /* DMA configuration for TX FIFO */ scodec->playback_dma_data.addr = res->start + quirks->reg_dac_txdata; scodec->playback_dma_data.maxburst = 8; @@ -1367,7 +1388,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) &sun4i_codec_dai, 1); if (ret) { dev_err(&pdev->dev, "Failed to register our codec\n"); - goto err_clk_disable; + goto err_assert_reset; } ret = devm_snd_soc_register_component(&pdev->dev, @@ -1404,6 +1425,9 @@ static int sun4i_codec_probe(struct platform_device *pdev) err_unregister_codec: snd_soc_unregister_codec(&pdev->dev); +err_assert_reset: + if (scodec->rst) + reset_control_assert(scodec->rst); err_clk_disable: clk_disable_unprepare(scodec->clk_apb); return ret; @@ -1416,6 +1440,8 @@ static int sun4i_codec_remove(struct platform_device *pdev) snd_soc_unregister_card(card); snd_soc_unregister_codec(&pdev->dev); + if (scodec->rst) + reset_control_assert(scodec->rst); clk_disable_unprepare(scodec->clk_apb); return 0; -- cgit v1.2.3-59-g8ed1b From b3af6d3f966a86cc556f5048fe6fff4e8cf567bc Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 5 Nov 2016 16:16:32 -0700 Subject: ASoC: fsl: fix fsl_spdif.c build errors Fix build errors in sound/soc/fsl/fsl_spdif.c by selecting BITREVERSE. Fixes these build errors: sound/built-in.o: In function `spdif_write_channel_status': fsl_spdif.c:(.text+0xbe39d): undefined reference to `byte_rev_table' fsl_spdif.c:(.text+0xbe3a8): undefined reference to `byte_rev_table' fsl_spdif.c:(.text+0xbe3be): undefined reference to `byte_rev_table' fsl_spdif.c:(.text+0xbe3d8): undefined reference to `byte_rev_table' Signed-off-by: Randy Dunlap Reported-by: kbuild test robot Reviewed-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/fsl/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 19bdcac71775..37f9b6201918 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -40,6 +40,7 @@ config SND_SOC_FSL_SPDIF select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) + select BITREVERSE help Say Y if you want to add Sony/Philips Digital Interface (SPDIF) support for the Freescale CPUs. -- cgit v1.2.3-59-g8ed1b From b4f89a0cce0d579fda6c1f6db72202c6bf2ae95f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 5 Nov 2016 15:28:55 +0800 Subject: ASoC: msm8916-wcd-analog: Update correct register setting for MIC BIAS Internal1 pm8916_wcd_analog_enable_micbias_int1() should set micbias1_cap_mode rather than micbias2_cap_mode. Also change the order of pm8916_wcd_analog_enable_micbias_int1/init2 functions for better readability. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/msm8916-wcd-analog.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 50ad75ab10ea..d8e8590746af 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -349,7 +349,7 @@ static int pm8916_wcd_analog_enable_micbias_ext2(struct } -static int pm8916_wcd_analog_enable_micbias_int2(struct +static int pm8916_wcd_analog_enable_micbias_int1(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -358,10 +358,10 @@ static int pm8916_wcd_analog_enable_micbias_int2(struct struct pm8916_wcd_analog_priv *wcd = snd_soc_codec_get_drvdata(codec); return pm8916_wcd_analog_enable_micbias_int(codec, event, w->reg, - wcd->micbias2_cap_mode); + wcd->micbias1_cap_mode); } -static int pm8916_wcd_analog_enable_micbias_int1(struct +static int pm8916_wcd_analog_enable_micbias_int2(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) -- cgit v1.2.3-59-g8ed1b From dbab1cb88e84813254091d0d02ab83d9929e6a27 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Sat, 5 Nov 2016 08:42:14 +0800 Subject: ASoC: topology: Check name strings of physical DAI links Check if the name strings are properly terminated, and only use valid name strings to find existing physical DAI links to configure. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 8772fd994e82..4dfdc656cce6 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1994,10 +1994,24 @@ static int soc_tplg_link_config(struct soc_tplg *tplg, { struct snd_soc_dai_link *link; const char *name, *stream_name; + size_t len; int ret; - name = strlen(cfg->name) ? cfg->name : NULL; - stream_name = strlen(cfg->stream_name) ? cfg->stream_name : NULL; + len = strnlen(cfg->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (len == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + else if (len) + name = cfg->name; + else + name = NULL; + + len = strnlen(cfg->stream_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN); + if (len == SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return -EINVAL; + else if (len) + stream_name = cfg->stream_name; + else + stream_name = NULL; link = snd_soc_find_dai_link(tplg->comp->card, cfg->id, name, stream_name); -- cgit v1.2.3-59-g8ed1b From 68d03a3aa2747e1a33231950d2c8369f1cef4244 Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Thu, 3 Nov 2016 17:07:22 +0530 Subject: ASoC: Intel: Skylake: remove pci device enabling calls on suspend We were invoking pci_disable_device() while going to suspend-to-idle and pci_enable_device() while coming back to active state. Turns out that we do not need these calls as we only need system to be wake capable when in suspend-to-idle state. The wake capability is already done by enable_irq_wake() calls, so remove these unwanted calls in driver. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index b9209af89915..ed59783e9846 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -290,7 +290,6 @@ static int skl_suspend(struct device *dev) enable_irq_wake(bus->irq); pci_save_state(pci); - pci_disable_device(pci); } else { ret = _skl_suspend(ebus); if (ret < 0) @@ -333,7 +332,6 @@ static int skl_resume(struct device *dev) */ if (skl->supend_active) { pci_restore_state(pci); - ret = pci_enable_device(pci); snd_hdac_ext_bus_link_power_up_all(ebus); disable_irq_wake(bus->irq); /* -- cgit v1.2.3-59-g8ed1b From 8b4a133c6145a34618c770117b65b33f1aa993aa Mon Sep 17 00:00:00 2001 From: Jayachandran B Date: Thu, 3 Nov 2016 17:07:21 +0530 Subject: ASoC: Intel: Skylake: Flush pending D0i3 request on suspend While going to suspend, if we have any pending D0i3 work scheduled, flush that and force the DSP to goto D0i3 mode before going to suspend. Signed-off-by: Jayachandran B Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 27 +++++++++++++++++++++++++++ sound/soc/intel/skylake/skl.c | 10 ++++++++++ sound/soc/intel/skylake/skl.h | 1 + 3 files changed, 38 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 87fc647fa04c..4ae021aabc3a 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -294,6 +294,33 @@ int skl_free_dsp(struct skl *skl) return 0; } +/* + * In the case of "suspend_active" i.e, the Audio IP being active + * during system suspend, immediately excecute any pending D0i3 work + * before suspending. This is needed for the IP to work in low power + * mode during system suspend. In the case of normal suspend, cancel + * any pending D0i3 work. + */ +int skl_suspend_late_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + struct delayed_work *dwork; + + if (!ctx) + return 0; + + dwork = &ctx->d0i3.work; + + if (dwork->work.func) { + if (skl->supend_active) + flush_delayed_work(dwork); + else + cancel_delayed_work_sync(dwork); + } + + return 0; +} + int skl_suspend_dsp(struct skl *skl) { struct skl_sst *ctx = skl->skl_sst; diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index ed59783e9846..61a484888cfa 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -228,6 +228,15 @@ static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) return 0; } +static int skl_suspend_late(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + + return skl_suspend_late_dsp(skl); +} + #ifdef CONFIG_PM static int _skl_suspend(struct hdac_ext_bus *ebus) { @@ -390,6 +399,7 @@ static int skl_runtime_resume(struct device *dev) static const struct dev_pm_ops skl_pm = { SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) + .suspend_late = skl_suspend_late, }; /* diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 88ba54ba5f72..4986e3929dd3 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -124,6 +124,7 @@ int skl_get_dmic_geo(struct skl *skl); int skl_nhlt_update_topology_bin(struct skl *skl); int skl_init_dsp(struct skl *skl); int skl_free_dsp(struct skl *skl); +int skl_suspend_late_dsp(struct skl *skl); int skl_suspend_dsp(struct skl *skl); int skl_resume_dsp(struct skl *skl); void skl_cleanup_resources(struct skl *skl); -- cgit v1.2.3-59-g8ed1b From 35db57622c31af687d5cb14104e91897d778a8fc Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 10 Nov 2016 00:35:18 +0800 Subject: ASoC: sun4i-codec: fix semicolon.cocci warnings sound/soc/sunxi/sun4i-codec.c:1339:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci Signed-off-by: Fengguang Wu Acked-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/sun4i-codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 6379efd21f00..092fdcf6de95 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -1336,7 +1336,7 @@ static int sun4i_codec_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Failed to get reset control\n"); return PTR_ERR(scodec->rst); } - }; + } scodec->gpio_pa = devm_gpiod_get_optional(&pdev->dev, "allwinner,pa", GPIOD_OUT_LOW); -- cgit v1.2.3-59-g8ed1b From 45ee1d855528ebd577d98d2f9481f8778af003a9 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Thu, 10 Nov 2016 00:58:40 +0800 Subject: ASoC: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/cs42l42.c:1972:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: James Schulman Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l42.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index f3c10f5d68c8..55e4520cdcaf 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -1969,7 +1969,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l42_id); static struct i2c_driver cs42l42_i2c_driver = { .driver = { .name = "cs42l42", - .owner = THIS_MODULE, .pm = &cs42l42_runtime_pm, .of_match_table = cs42l42_of_match, }, -- cgit v1.2.3-59-g8ed1b From 4090d63b49d7d440ff984db3715d5c780209e8e8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 10 Nov 2016 15:34:52 +0000 Subject: ASoC: wm2200: Correct types of mixer texts and values The core expects "const char * const" and "unsigned int" for enum controls, the mixer control definitions in wm2200 use "const char *" and "int". This patch corrects the type of these arrays. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 606bf88abfc4..d83dab57a1d1 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -999,7 +999,7 @@ static DECLARE_TLV_DB_SCALE(in_tlv, -6300, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); static DECLARE_TLV_DB_SCALE(out_tlv, -6400, 100, 0); -static const char *wm2200_mixer_texts[] = { +static const char * const wm2200_mixer_texts[] = { "None", "Tone Generator", "AEC Loopback", @@ -1033,7 +1033,7 @@ static const char *wm2200_mixer_texts[] = { "DSP2.6", }; -static int wm2200_mixer_values[] = { +static unsigned int wm2200_mixer_values[] = { 0x00, 0x04, /* Tone */ 0x08, /* AEC */ -- cgit v1.2.3-59-g8ed1b From d3d5c90556301dc1f3afe5a4e1133ddd1f43858b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 10 Nov 2016 15:24:14 +0000 Subject: ASoC: arizona: Move notifier functions to header and make inline These functions are very thin wrappers around core functions, so they make sense as inline functions. Also making them inline avoids build issues in the case where the machine driver is built in but the CODEC is built as a module. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 24 ------------------------ sound/soc/codecs/arizona.h | 32 ++++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 99ce6a0e73de..ca5ca9eac272 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2691,30 +2691,6 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); -int arizona_register_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb, - int (*notify)(struct notifier_block *nb, - unsigned long action, void *data)) -{ - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - - nb->notifier_call = notify; - - return blocking_notifier_chain_register(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_register_notifier); - -int arizona_unregister_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb) -{ - struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); - struct arizona *arizona = priv->arizona; - - return blocking_notifier_chain_unregister(&arizona->notifier, nb); -} -EXPORT_SYMBOL_GPL(arizona_unregister_notifier); - MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 34d65d1eafba..813f1cdb565d 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -14,6 +14,8 @@ #define _ASOC_ARIZONA_H #include +#include +#include #include @@ -66,7 +68,6 @@ /* Notifier events */ #define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1 -struct arizona; struct wm_adsp; struct arizona_dai_priv { @@ -329,12 +330,27 @@ extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); -extern int arizona_register_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb, - int (*notify)(struct notifier_block *nb, - unsigned long action, - void *data)); -extern int arizona_unregister_notifier(struct snd_soc_codec *codec, - struct notifier_block *nb); +static inline int arizona_register_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb, + int (*notify) + (struct notifier_block *nb, + unsigned long action, void *data)) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + + nb->notifier_call = notify; + + return blocking_notifier_chain_register(&arizona->notifier, nb); +} + +static inline int arizona_unregister_notifier(struct snd_soc_codec *codec, + struct notifier_block *nb) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + + return blocking_notifier_chain_unregister(&arizona->notifier, nb); +} #endif -- cgit v1.2.3-59-g8ed1b From 88c1886075e069f699c20fbc04ef6f10b8eb8c43 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 10 Nov 2016 15:24:15 +0000 Subject: ASoC: arizona: Call arizona_init_notifiers for all CODECs The call to arizona_init_notifiers was only added for CODECs that are generating voice trigger events, however, this is somewhat annoying for machine drivers that might be used with multiple CODECs as they need to conditionally register for the notifier, depending on the CODEC being attached. As the cost of initialising the notifier is so minimal, and we may well add other events in the future that apply to more CODECs, simply do this for all Arizona CODECs. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 1 + sound/soc/codecs/wm8997.c | 1 + sound/soc/codecs/wm8998.c | 1 + 3 files changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 0136234e6e66..72ff291a85be 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1945,6 +1945,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) arizona_init_spk(codec); arizona_init_gpio(codec); + arizona_init_notifiers(codec); snd_soc_dapm_disable_pin(dapm, "HAPTICS"); diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 600595c54fe7..ea8b1bfdf5a0 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1063,6 +1063,7 @@ static int wm8997_codec_probe(struct snd_soc_codec *codec) struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); arizona_init_spk(codec); + arizona_init_notifiers(codec); snd_soc_dapm_disable_pin(dapm, "HAPTICS"); diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 4cccaae6dcfa..1e1d9c1f0371 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1325,6 +1325,7 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec) arizona_init_spk(codec); arizona_init_gpio(codec); + arizona_init_notifiers(codec); snd_soc_dapm_disable_pin(dapm, "HAPTICS"); -- cgit v1.2.3-59-g8ed1b From a4a1d79ea75eec48e086648678b62a8220fe3723 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 10 Nov 2016 09:55:54 +0200 Subject: ASoC: tlv320aic31xx: Add missing of_device_id for dac3100 The compatible table was not updated when the support for DAC3100 was added. Signed-off-by: Peter Ujfalusi Reviewed-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/codecs/tlv320aic31xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index be1a64bfd320..8880f6be3336 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1253,6 +1253,7 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { { .compatible = "ti,tlv320aic3110" }, { .compatible = "ti,tlv320aic3120" }, { .compatible = "ti,tlv320aic3111" }, + { .compatible = "ti,tlv320dac3100" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); -- cgit v1.2.3-59-g8ed1b From 7364c8dc255232db33bcd1c5b19eb8f34cf6108a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Nov 2016 01:18:35 +0000 Subject: ASoC: soc-core: adjust for graph on snd_soc_of_parse_audio_routing It is assuming that the card related information is located on "card" node, but graph case doesn't have it. This patch adds node parameter to adjust for graph support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 9 +++++++-- sound/soc/soc-core.c | 9 ++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 4f1c784e44f6..148bf553d598 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1655,8 +1655,13 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); -int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, - const char *propname); + +#define snd_soc_of_parse_audio_routing(card, propname) \ + snd_soc_of_parse_audio_routing_from_node(card, NULL, propname) +int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, + struct device_node *np, + const char *propname); + unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, struct device_node **bitclkmaster, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..ec881b8825b6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3615,14 +3615,17 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); -int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, +int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, + struct device_node *np, const char *propname) { - struct device_node *np = card->dev->of_node; int num_routes; struct snd_soc_dapm_route *routes; int i, ret; + if (!np) + np = card->dev->of_node; + num_routes = of_property_count_strings(np, propname); if (num_routes < 0 || num_routes & 1) { dev_err(card->dev, @@ -3669,7 +3672,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_routing_from_node); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, -- cgit v1.2.3-59-g8ed1b From 1ad8ec535b997ed36c0f32c2616206725258dd30 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Nov 2016 01:19:28 +0000 Subject: ASoC: soc-core: snd_soc_get_dai_name() become non static snd_soc_get_dai_name() is used from snd_soc_of_get_dai_name(), and it is assuming that DT is using "sound-dai" / "#sound-dai-cells". But graph base DT is using "remote-endpoint". This patch makes snd_soc_get_dai_name() non static for graph support. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 2 ++ sound/soc/soc-core.c | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 148bf553d598..6dffa9540a30 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1666,6 +1666,8 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, const char *prefix, struct device_node **bitclkmaster, struct device_node **framemaster); +int snd_soc_get_dai_name(struct of_phandle_args *args, + const char **dai_name); int snd_soc_of_get_dai_name(struct device_node *of_node, const char **dai_name); int snd_soc_of_get_dai_link_codecs(struct device *dev, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ec881b8825b6..81b604151f26 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3787,7 +3787,7 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); -static int snd_soc_get_dai_name(struct of_phandle_args *args, +int snd_soc_get_dai_name(struct of_phandle_args *args, const char **dai_name) { struct snd_soc_component *pos; @@ -3839,6 +3839,7 @@ static int snd_soc_get_dai_name(struct of_phandle_args *args, mutex_unlock(&client_mutex); return ret; } +EXPORT_SYMBOL_GPL(snd_soc_get_dai_name); int snd_soc_of_get_dai_name(struct device_node *of_node, const char **dai_name) -- cgit v1.2.3-59-g8ed1b From b6defcca0a604129155ae472b116a2e1688d8995 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Nov 2016 01:19:03 +0000 Subject: ASoC: soc-core: adjust for graph on snd_soc_of_parse_audio_prefix It is assuming that the card related information is located on "card" node, but graph case doesn't have it. This patch adds node parameter to adjust for graph support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 6 +++++- sound/soc/soc-core.c | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 6dffa9540a30..346223b38e0d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1651,7 +1651,11 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *rx_mask, unsigned int *slots, unsigned int *slot_width); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, +#define snd_soc_of_parse_audio_prefix(card, codec_conf, of_node, propname) \ + snd_soc_of_parse_audio_prefix_from_node(card, NULL, codec_conf, \ + of_node, propname) +void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, + struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname); diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 81b604151f26..e4c90806fa10 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3595,15 +3595,18 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); -void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, +void snd_soc_of_parse_audio_prefix_from_node(struct snd_soc_card *card, + struct device_node *np, struct snd_soc_codec_conf *codec_conf, struct device_node *of_node, const char *propname) { - struct device_node *np = card->dev->of_node; const char *str; int ret; + if (!np) + np = card->dev->of_node; + ret = of_property_read_string(np, propname, &str); if (ret < 0) { /* no prefix is not error */ @@ -3613,7 +3616,7 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, codec_conf->of_node = of_node; codec_conf->name_prefix = str; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix_from_node); int snd_soc_of_parse_audio_routing_from_node(struct snd_soc_card *card, struct device_node *np, -- cgit v1.2.3-59-g8ed1b From 8f5ebb1bee15b5720741a98414767bb86f6c2b23 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Nov 2016 01:17:27 +0000 Subject: ASoC: soc-core: adjust for graph on snd_soc_of_parse_card_name It is assuming that the card related information is located on "card" node, but graph case doesn't have it. This patch adds node parameter to adjust for graph support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 7 +++++-- sound/soc/soc-core.c | 11 ++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 346223b38e0d..8457aab9eab0 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1642,8 +1642,11 @@ static inline struct snd_soc_platform *snd_soc_kcontrol_platform( int snd_soc_util_init(void); void snd_soc_util_exit(void); -int snd_soc_of_parse_card_name(struct snd_soc_card *card, - const char *propname); +#define snd_soc_of_parse_card_name(card, propname) \ + snd_soc_of_parse_card_name_from_node(card, NULL, propname) +int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, + struct device_node *np, + const char *propname); int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_tdm_slot(struct device_node *np, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e4c90806fa10..17132fb57930 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3424,10 +3424,10 @@ found: EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); /* Retrieve a card's name from device tree */ -int snd_soc_of_parse_card_name(struct snd_soc_card *card, - const char *propname) +int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, + struct device_node *np, + const char *propname) { - struct device_node *np; int ret; if (!card->dev) { @@ -3435,7 +3435,8 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, return -EINVAL; } - np = card->dev->of_node; + if (!np) + np = card->dev->of_node; ret = of_property_read_string_index(np, propname, 0, &card->name); /* @@ -3452,7 +3453,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name_from_node); static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_MIC("Microphone", NULL), -- cgit v1.2.3-59-g8ed1b From 1ef5bcd57be5c8b31286b7b47828064be25f266b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 11 Nov 2016 01:18:08 +0000 Subject: ASoC: soc-core: adjust for graph on snd_soc_of_parse_audio_simple_widgets It is assuming that the card related information is located on "card" node, but graph case doesn't have it. This patch adds node parameter to adjust for graph support Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 8 ++++++-- sound/soc/soc-core.c | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 8457aab9eab0..77b01c45ee8d 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1647,8 +1647,12 @@ void snd_soc_util_exit(void); int snd_soc_of_parse_card_name_from_node(struct snd_soc_card *card, struct device_node *np, const char *propname); -int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, - const char *propname); +#define snd_soc_of_parse_audio_simple_widgets(card, propname)\ + snd_soc_of_parse_audio_simple_widgets_from_node(card, NULL, propname) +int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, + struct device_node *np, + const char *propname); + int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *tx_mask, unsigned int *rx_mask, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 17132fb57930..6f911f4d413a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3462,14 +3462,17 @@ static const struct snd_soc_dapm_widget simple_widgets[] = { SND_SOC_DAPM_SPK("Speaker", NULL), }; -int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, +int snd_soc_of_parse_audio_simple_widgets_from_node(struct snd_soc_card *card, + struct device_node *np, const char *propname) { - struct device_node *np = card->dev->of_node; struct snd_soc_dapm_widget *widgets; const char *template, *wname; int i, j, num_widgets, ret; + if (!np) + np = card->dev->of_node; + num_widgets = of_property_count_strings(np, propname); if (num_widgets < 0) { dev_err(card->dev, @@ -3540,7 +3543,7 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, return 0; } -EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets_from_node); static int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, -- cgit v1.2.3-59-g8ed1b From 93dfec758ff2d0292be35cafd239e929a8973b73 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 11 Nov 2016 12:34:12 +0800 Subject: ASoC: nau8825: Disable short Frame Sync detection logic If the short Frame Sync detection logic enabled, the logic will check the short frame sync threshold. If frame sync is less than the setting; for example, frame sync less than 252 MCLK, the short frame sync signal is flagged, digital filter temporary mute and skip that data. If the system was intended for sampling rate change which could create temporary short frame sync and not enough MIPS to run the digital filter. But the situation doesn't happen in ALSA architecure. Thus the Frame Sync is always stable, then no require to do the detection. Therefore, the dirver disables the function for better performance. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 3 +++ sound/soc/codecs/nau8825.h | 5 +++++ 2 files changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index e643be91d762..0db618b2f2b8 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1811,6 +1811,9 @@ static void nau8825_init_regs(struct nau8825 *nau8825) NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L); regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL, NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R); + /* Disable short Frame Sync detection logic */ + regmap_update_bits(regmap, NAU8825_REG_LEFT_TIME_SLOT, + NAU8825_DIS_FS_SHORT_DET, NAU8825_DIS_FS_SHORT_DET); } static const struct regmap_config nau8825_regmap_config = { diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 1c63e2abafa9..6365c9c3f8d9 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -246,6 +246,11 @@ #define NAU8825_I2S_MS_SLAVE (0 << NAU8825_I2S_MS_SFT) #define NAU8825_I2S_BLK_DIV_MASK 0x7 +/* LEFT_TIME_SLOT (0x1e) */ +#define NAU8825_FS_ERR_CMP_SEL_SFT 14 +#define NAU8825_FS_ERR_CMP_SEL_MASK (0x3 << NAU8825_FS_ERR_CMP_SEL_SFT) +#define NAU8825_DIS_FS_SHORT_DET (1 << 13) + /* BIQ_CTRL (0x20) */ #define NAU8825_BIQ_WRT_SFT 4 #define NAU8825_BIQ_WRT_EN (1 << NAU8825_BIQ_WRT_SFT) -- cgit v1.2.3-59-g8ed1b From d6d197458b5fc801b2274f5287a4df6ce74b230f Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 11 Nov 2016 11:34:42 +0800 Subject: ASoC: nau8825: AD/DA over sampling rate configuration Over Sampling Rate (OSR) is defined as CLK_ADC frequency divided by the audio sample rate (Fs). OSR = CLK_ADC / FS The available OSRs are 32, 64, 128 or 256. Note that the OSR and Fs values must be selected such that the maximum frequency of CLK_ADC is less than 6.144 MHz. It is recommended to match the relationship between OSR and clock SRC according to following Table. ADC_RATE: 00(OSR=32) | CLK_ADC_SRC: 11(CODEC 1/8) ADC_RATE: 01(OSR=64) | CLK_ADC_SRC: 10(CODEC1/4) ADC_RATE: 10(OSR=128) | CLK_ADC_SRC: 01(CODEC 1/2) ADC_RATE: 11(OSR=256) | CLK_ADC_SRC: 00(CODEC CLK) The over sampling rate about DAC follows the same rule with ADCs. The driver changes the OSR to 64 value when initiation for better FLL performance and applies the dynamic SRC change by different OSR. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 78 ++++++++++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/nau8825.h | 4 +++ 2 files changed, 79 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 0db618b2f2b8..50cdb30297b4 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -43,6 +43,8 @@ #define GAIN_AUGMENT 22500 #define SIDETONE_BASE 207000 +/* the maximum frequency of CLK_ADC and CLK_DAC */ +#define CLK_DA_AD_MAX 6144000 static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, unsigned int freq); @@ -95,6 +97,27 @@ static const struct nau8825_fll_attr fll_pre_scalar[] = { { 8, 0x3 }, }; +/* over sampling rate */ +struct nau8825_osr_attr { + unsigned int osr; + unsigned int clk_src; +}; + +static const struct nau8825_osr_attr osr_dac_sel[] = { + { 64, 2 }, /* OSR 64, SRC 1/4 */ + { 256, 0 }, /* OSR 256, SRC 1 */ + { 128, 1 }, /* OSR 128, SRC 1/2 */ + { 0, 0 }, + { 32, 3 }, /* OSR 32, SRC 1/8 */ +}; + +static const struct nau8825_osr_attr osr_adc_sel[] = { + { 32, 3 }, /* OSR 32, SRC 1/8 */ + { 64, 2 }, /* OSR 64, SRC 1/4 */ + { 128, 1 }, /* OSR 128, SRC 1/2 */ + { 256, 0 }, /* OSR 256, SRC 1 */ +}; + static const struct reg_default nau8825_reg_defaults[] = { { NAU8825_REG_ENA_CTRL, 0x00ff }, { NAU8825_REG_IIC_ADDR_SET, 0x0 }, @@ -1179,16 +1202,65 @@ static const struct snd_soc_dapm_route nau8825_dapm_routes[] = { {"HPOR", NULL, "Class G"}, }; +static int nau8825_clock_check(struct nau8825 *nau8825, + int stream, int rate, int osr) +{ + int osrate; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (osr >= ARRAY_SIZE(osr_dac_sel)) + return -EINVAL; + osrate = osr_dac_sel[osr].osr; + } else { + if (osr >= ARRAY_SIZE(osr_adc_sel)) + return -EINVAL; + osrate = osr_adc_sel[osr].osr; + } + + if (!osrate || rate * osr > CLK_DA_AD_MAX) { + dev_err(nau8825->dev, "exceed the maximum frequency of CLK_ADC or CLK_DAC\n"); + return -EINVAL; + } + + return 0; +} + static int nau8825_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); - unsigned int val_len = 0; + unsigned int val_len = 0, osr; nau8825_sema_acquire(nau8825, 2 * HZ); + /* CLK_DAC or CLK_ADC = OSR * FS + * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR) + * multiplied by the audio sample rate (Fs). Note that the OSR and Fs + * values must be selected such that the maximum frequency is less + * than 6.144 MHz. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_read(nau8825->regmap, NAU8825_REG_DAC_CTRL1, &osr); + osr &= NAU8825_DAC_OVERSAMPLE_MASK; + if (nau8825_clock_check(nau8825, substream->stream, + params_rate(params), osr)) + return -EINVAL; + regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_DAC_SRC_MASK, + osr_dac_sel[osr].clk_src << NAU8825_CLK_DAC_SRC_SFT); + } else { + regmap_read(nau8825->regmap, NAU8825_REG_ADC_RATE, &osr); + osr &= NAU8825_ADC_SYNC_DOWN_MASK; + if (nau8825_clock_check(nau8825, substream->stream, + params_rate(params), osr)) + return -EINVAL; + regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, + NAU8825_CLK_ADC_SRC_MASK, + osr_adc_sel[osr].clk_src << NAU8825_CLK_ADC_SRC_SFT); + } + switch (params_width(params)) { case 16: val_len |= NAU8825_I2S_DL_16; @@ -1774,9 +1846,9 @@ static void nau8825_init_regs(struct nau8825 *nau8825) * (audible hiss). Set it to something better. */ regmap_update_bits(regmap, NAU8825_REG_ADC_RATE, - NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_128); + NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, - NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_128); + NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64); /* Disable DACR/L power */ regmap_update_bits(regmap, NAU8825_REG_CHARGE_PUMP, NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 6365c9c3f8d9..167a2aaad256 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -115,6 +115,10 @@ #define NAU8825_CLK_SRC_MASK (1 << NAU8825_CLK_SRC_SFT) #define NAU8825_CLK_SRC_VCO (1 << NAU8825_CLK_SRC_SFT) #define NAU8825_CLK_SRC_MCLK (0 << NAU8825_CLK_SRC_SFT) +#define NAU8825_CLK_ADC_SRC_SFT 6 +#define NAU8825_CLK_ADC_SRC_MASK (0x3 << NAU8825_CLK_ADC_SRC_SFT) +#define NAU8825_CLK_DAC_SRC_SFT 4 +#define NAU8825_CLK_DAC_SRC_MASK (0x3 << NAU8825_CLK_DAC_SRC_SFT) #define NAU8825_CLK_MCLK_SRC_MASK (0xf << 0) /* FLL1 (0x04) */ -- cgit v1.2.3-59-g8ed1b From aee02c75a5fb3b3583780bb7b298cb0d0d6647e2 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 11 Nov 2016 12:16:29 +0800 Subject: ASoC: nau8825: FLL parameters finetune The driver fine-tune some parameters to improve FLL performance. Those items have description as follow. (1)ICTRL_LATCH: FLL DSP speed capability control When FLL running at high frequency with long decimal number, DSP needs to operate at high speed. FLL DSP can optimize between performance and power consumption by ICTRL_LATCH.(111 has highest power consumption.) The default setting can be used to reduce power. (2)CUTOFF500: loop filter cutoff frequency at 500Khz It will give the best FLL performance but highest power consumption to enable the cutoff frequency. FLL Loop Filter enable to reduce FLL output noise, especially,(DCO frequency)/(FLL input reference frequency) is not a integer. (3)GAIN_ERR: FLL gain error correction threshold setting The threshold is comparison between DCO and target frequency. The value 1111 has the most sensitive threshold, that is, 1111 can have the most accurate DCO to target frequency. However, the gain error setting conditionally and inversely depends on FLL input reference clock rate. Higher FLL reference input frequency can only set lower gain error, such as 0000 for input reference from MCLK=12.288Mhz. On the other side, if FLL reference input is from Frame Sync, 48KHz, higher error gain can apply such as 1111. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 48 ++++++++++++++++++++++++++++++++++++++-------- sound/soc/codecs/nau8825.h | 5 +++++ 2 files changed, 45 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 50cdb30297b4..3f9137f60c0d 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1994,8 +1994,10 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK, NAU8825_CLK_SRC_MCLK | fll_param->mclk_src); + /* Make DSP operate at high speed for better performance. */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, - NAU8825_FLL_RATIO_MASK, fll_param->ratio); + NAU8825_FLL_RATIO_MASK | NAU8825_ICTRL_LATCH_MASK, + fll_param->ratio | (0x6 << NAU8825_ICTRL_LATCH_SFT)); /* FLL 16-bit fractional input */ regmap_write(nau8825->regmap, NAU8825_REG_FLL2, fll_param->fll_frac); /* FLL 10-bit integer input */ @@ -2011,19 +2013,22 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, 0); if (fll_param->fll_frac) { + /* set FLL loop filter enable and cutoff frequency at 500Khz */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | NAU8825_FLL_FTR_SW_FILTER); regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, - NAU8825_SDM_EN, NAU8825_SDM_EN); + NAU8825_SDM_EN | NAU8825_CUTOFF500, + NAU8825_SDM_EN | NAU8825_CUTOFF500); } else { + /* disable FLL loop filter and cutoff frequency */ regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU); - regmap_update_bits(nau8825->regmap, - NAU8825_REG_FLL6, NAU8825_SDM_EN, 0); + regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, + NAU8825_SDM_EN | NAU8825_CUTOFF500, 0); } } @@ -2089,6 +2094,9 @@ static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap) NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK); regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, 0); + /* Make DSP operate as default setting for power saving. */ + regmap_update_bits(regmap, NAU8825_REG_FLL1, + NAU8825_ICTRL_LATCH_MASK, 0); } static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, @@ -2132,10 +2140,13 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, NAU8825_DCO_EN, NAU8825_DCO_EN); regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); - /* Decrease the VCO frequency for power saving */ + /* Decrease the VCO frequency and make DSP operate + * as default setting for power saving. + */ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, NAU8825_CLK_MCLK_SRC_MASK, 0xf); regmap_update_bits(regmap, NAU8825_REG_FLL1, + NAU8825_ICTRL_LATCH_MASK | NAU8825_FLL_RATIO_MASK, 0x10); regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_SDM_EN, NAU8825_SDM_EN); @@ -2159,8 +2170,13 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * preparation halted until cross talk process finish. */ nau8825_sema_acquire(nau8825, 2 * HZ); + /* Higher FLL reference input frequency can only set lower + * gain error, such as 0000 for input reference from MCLK + * 12.288Mhz. + */ regmap_update_bits(regmap, NAU8825_REG_FLL3, - NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_MCLK); + NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, + NAU8825_FLL_CLK_SRC_MCLK | 0); /* Release the semaphone. */ nau8825_sema_release(nau8825); @@ -2176,8 +2192,16 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * preparation halted until cross talk process finish. */ nau8825_sema_acquire(nau8825, 2 * HZ); + /* If FLL reference input is from low frequency source, + * higher error gain can apply such as 0xf which has + * the most sensitive gain error correction threshold, + * Therefore, FLL has the most accurate DCO to + * target frequency. + */ regmap_update_bits(regmap, NAU8825_REG_FLL3, - NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_BLK); + NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, + NAU8825_FLL_CLK_SRC_BLK | + (0xf << NAU8825_GAIN_ERR_SFT)); /* Release the semaphone. */ nau8825_sema_release(nau8825); @@ -2194,8 +2218,16 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * preparation halted until cross talk process finish. */ nau8825_sema_acquire(nau8825, 2 * HZ); + /* If FLL reference input is from low frequency source, + * higher error gain can apply such as 0xf which has + * the most sensitive gain error correction threshold, + * Therefore, FLL has the most accurate DCO to + * target frequency. + */ regmap_update_bits(regmap, NAU8825_REG_FLL3, - NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_FS); + NAU8825_FLL_CLK_SRC_MASK | NAU8825_GAIN_ERR_MASK, + NAU8825_FLL_CLK_SRC_FS | + (0xf << NAU8825_GAIN_ERR_SFT)); /* Release the semaphone. */ nau8825_sema_release(nau8825); diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 167a2aaad256..0672a25617b9 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -122,9 +122,13 @@ #define NAU8825_CLK_MCLK_SRC_MASK (0xf << 0) /* FLL1 (0x04) */ +#define NAU8825_ICTRL_LATCH_SFT 10 +#define NAU8825_ICTRL_LATCH_MASK (0x7 << NAU8825_ICTRL_LATCH_SFT) #define NAU8825_FLL_RATIO_MASK (0x7f << 0) /* FLL3 (0x06) */ +#define NAU8825_GAIN_ERR_SFT 12 +#define NAU8825_GAIN_ERR_MASK (0xf << NAU8825_GAIN_ERR_SFT) #define NAU8825_FLL_INTEGER_MASK (0x3ff << 0) #define NAU8825_FLL_CLK_SRC_SFT 10 #define NAU8825_FLL_CLK_SRC_MASK (0x3 << NAU8825_FLL_CLK_SRC_SFT) @@ -148,6 +152,7 @@ /* FLL6 (0x9) */ #define NAU8825_DCO_EN (0x1 << 15) #define NAU8825_SDM_EN (0x1 << 14) +#define NAU8825_CUTOFF500 (0x1 << 13) /* HSD_CTRL (0xc) */ #define NAU8825_HSD_AUTO_MODE (1 << 6) -- cgit v1.2.3-59-g8ed1b From 5acbd343980b034b6ea9b01824cc28d0b01cf4d8 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 10 Nov 2016 08:11:55 +0100 Subject: ASoC: samsung: Makefile cleanup Commit a076d418235f ("ASoC: samsung: Drop AC97 drivers") removed some unused code and the associated Kconfig options, but left those options referenced in the Makefile. Remove the leftover references in the Makefile. Signed-off-by: Valentin Rothberg Reviewed-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/Makefile | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index f3f4a32cd376..27956621c849 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -45,8 +45,6 @@ snd-soc-arndale-rt5631-objs := arndale_rt5631.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o -obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o -obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC) += snd-soc-s3c24xx-simtec.o obj-$(CONFIG_SND_SOC_SAMSUNG_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o @@ -56,7 +54,6 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_RX1950_UDA1380) += snd-soc-rx1950-uda1380.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8580) += snd-soc-smdk-wm8580.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o -obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM9713) += snd-soc-smdk-wm9713.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o -- cgit v1.2.3-59-g8ed1b From f174c1db904fe49713571a3ea2547b79da025fa9 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 9 Nov 2016 19:45:10 +0100 Subject: ASoC: samsung: Remove unselectable smdk_wm8580pcm The SND_SOC_SMDK_WM8580_PCM Kconfig entry depends on either MACH_SMDKV210 or MACH_SMDKC110. Both of which were removed in commit 28c8331d386a ("ARM: S5PV210: Remove support for board files") over two years ago. The driver has been unselectable ever since. Considering the lack of complaints about this it can be concluded that the driver is unused and can be removed. Signed-off-by: Lars-Peter Clausen Reviewed-by: Krzysztof Kozlowski Reviewed-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 9 -- sound/soc/samsung/Makefile | 2 - sound/soc/samsung/smdk_wm8580pcm.c | 175 ------------------------------------- 3 files changed, 186 deletions(-) delete mode 100644 sound/soc/samsung/smdk_wm8580pcm.c (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 1d2ef4c2afd0..79ae6a7c93ff 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -119,15 +119,6 @@ config SND_SOC_SAMSUNG_SMDK_SPDIF help Say Y if you want to add support for SoC S/PDIF audio on the SMDK. -config SND_SOC_SMDK_WM8580_PCM - tristate "SoC PCM Audio support for WM8580 on SMDK" - depends on MACH_SMDKV210 || MACH_SMDKC110 - depends on I2C - select SND_SOC_WM8580 - select SND_SAMSUNG_PCM - help - Say Y if you want to add support for SoC audio on the SMDK. - config SND_SOC_SMDK_WM8994_PCM tristate "SoC PCM Audio support for WM8994 on SMDK" depends on I2C=y diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 27956621c849..c95b6835361f 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -34,7 +34,6 @@ snd-soc-snow-objs := snow.o snd-soc-smdk-wm9713-objs := smdk_wm9713.o snd-soc-s3c64xx-smartq-wm8987-objs := smartq_wm8987.o snd-soc-smdk-spdif-objs := smdk_spdif.o -snd-soc-smdk-wm8580pcm-objs := smdk_wm8580pcm.o snd-soc-smdk-wm8994pcm-objs := smdk_wm8994pcm.o snd-soc-speyside-objs := speyside.o snd-soc-tobermory-objs := tobermory.o @@ -56,7 +55,6 @@ obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_WM8994) += snd-soc-smdk-wm8994.o obj-$(CONFIG_SND_SOC_SNOW) += snd-soc-snow.o obj-$(CONFIG_SND_SOC_SMARTQ) += snd-soc-s3c64xx-smartq-wm8987.o obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK_SPDIF) += snd-soc-smdk-spdif.o -obj-$(CONFIG_SND_SOC_SMDK_WM8580_PCM) += snd-soc-smdk-wm8580pcm.o obj-$(CONFIG_SND_SOC_SMDK_WM8994_PCM) += snd-soc-smdk-wm8994pcm.o obj-$(CONFIG_SND_SOC_SPEYSIDE) += snd-soc-speyside.o obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o diff --git a/sound/soc/samsung/smdk_wm8580pcm.c b/sound/soc/samsung/smdk_wm8580pcm.c deleted file mode 100644 index a6d223310c67..000000000000 --- a/sound/soc/samsung/smdk_wm8580pcm.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * sound/soc/samsung/smdk_wm8580pcm.c - * - * Copyright (c) 2011 Samsung Electronics Co. Ltd - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ -#include -#include -#include -#include - -#include - -#include "../codecs/wm8580.h" -#include "pcm.h" - -/* - * Board Settings: - * o '1' means 'ON' - * o '0' means 'OFF' - * o 'X' means 'Don't care' - * - * SMDK6410 Base B/D: CFG1-0000, CFG2-1111 - * SMDKC110, SMDKV210: CFGB11-100100, CFGB12-0000 - */ - -#define SMDK_WM8580_EXT_OSC 12000000 -#define SMDK_WM8580_EXT_MCLK 4096000 -#define SMDK_WM8580_EXT_VOICE 2048000 - -static unsigned long mclk_freq; -static unsigned long xtal_freq; - -/* - * If MCLK clock directly gets from XTAL, we don't have to use PLL - * to make MCLK, but if XTAL clock source connects with other codec - * pin (like XTI), we should have to set codec's PLL to make MCLK. - * Because Samsung SoC does not support pcmcdclk output like I2S. - */ - -static int smdk_wm8580_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - struct snd_soc_dai *cpu_dai = rtd->cpu_dai; - int rfs, ret; - - switch (params_rate(params)) { - case 8000: - break; - default: - printk(KERN_ERR "%s:%d Sampling Rate %u not supported!\n", - __func__, __LINE__, params_rate(params)); - return -EINVAL; - } - - rfs = mclk_freq / params_rate(params) / 2; - - if (mclk_freq == xtal_freq) { - ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_MCLK, - mclk_freq, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, - WM8580_CLKSRC_MCLK); - if (ret < 0) - return ret; - } else { - ret = snd_soc_dai_set_sysclk(codec_dai, WM8580_CLKSRC_PLLA, - mclk_freq, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, - WM8580_CLKSRC_PLLA); - if (ret < 0) - return ret; - - ret = snd_soc_dai_set_pll(codec_dai, WM8580_PLLA, 0, - xtal_freq, mclk_freq); - if (ret < 0) - return ret; - } - - /* Set PCM source clock on CPU */ - ret = snd_soc_dai_set_sysclk(cpu_dai, S3C_PCM_CLKSRC_MUX, - mclk_freq, SND_SOC_CLOCK_IN); - if (ret < 0) - return ret; - - /* Set SCLK_DIV for making bclk */ - ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_PCM_SCLK_PER_FS, rfs); - if (ret < 0) - return ret; - - return 0; -} - -static struct snd_soc_ops smdk_wm8580_pcm_ops = { - .hw_params = smdk_wm8580_pcm_hw_params, -}; - -#define SMDK_DAI_FMT (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | \ - SND_SOC_DAIFMT_CBS_CFS) - -static struct snd_soc_dai_link smdk_dai[] = { - { - .name = "WM8580 PAIF PCM RX", - .stream_name = "Playback", - .cpu_dai_name = "samsung-pcm.0", - .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-audio", - .codec_name = "wm8580.0-001b", - .dai_fmt = SMDK_DAI_FMT, - .ops = &smdk_wm8580_pcm_ops, - }, { - .name = "WM8580 PAIF PCM TX", - .stream_name = "Capture", - .cpu_dai_name = "samsung-pcm.0", - .codec_dai_name = "wm8580-hifi-capture", - .platform_name = "samsung-pcm.0", - .codec_name = "wm8580.0-001b", - .dai_fmt = SMDK_DAI_FMT, - .ops = &smdk_wm8580_pcm_ops, - }, -}; - -static struct snd_soc_card smdk_pcm = { - .name = "SMDK-PCM", - .owner = THIS_MODULE, - .dai_link = smdk_dai, - .num_links = 2, -}; - -/* - * After SMDKC110 Base Board's Rev is '0.1', 12MHz External OSC(X1) - * is absent (or not connected), so we connect EXT_VOICE_CLK(OSC4), - * 2.0484Mhz, directly with MCLK both Codec and SoC. - */ -static int snd_smdk_probe(struct platform_device *pdev) -{ - int ret = 0; - - xtal_freq = SMDK_WM8580_EXT_OSC; - mclk_freq = SMDK_WM8580_EXT_MCLK; - - if (machine_is_smdkc110() || machine_is_smdkv210()) - xtal_freq = mclk_freq = SMDK_WM8580_EXT_VOICE; - - smdk_pcm.dev = &pdev->dev; - ret = devm_snd_soc_register_card(&pdev->dev, &smdk_pcm); - if (ret) - dev_err(&pdev->dev, "snd_soc_register_card failed %d\n", ret); - - return ret; -} - -static struct platform_driver snd_smdk_driver = { - .driver = { - .name = "samsung-smdk-pcm", - }, - .probe = snd_smdk_probe, -}; - -module_platform_driver(snd_smdk_driver); - -MODULE_AUTHOR("Sangbeom Kim, "); -MODULE_DESCRIPTION("ALSA SoC SMDK WM8580 for PCM"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From f4f0c4c60c3959a8f3650850b799049161732e91 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 9 Nov 2016 17:14:17 +0000 Subject: ASoC: wm_adsp: Signal firmware shutdown through event control If the firmware has any system event signalling controls, signal them during DSP PRE_PMD to tell the firmware it is about to be stopped. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 114 +++++++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/wmfw.h | 3 ++ 2 files changed, 117 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 7320fcacd86a..07cf7cb93301 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -162,6 +162,14 @@ #define ADSP_MAX_STD_CTRL_SIZE 512 +#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 +#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS 10 + +/* + * Event control messages + */ +#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001 + struct wm_adsp_buf { struct list_head list; void *buf; @@ -739,6 +747,66 @@ static int wm_coeff_info(struct snd_kcontrol *kctl, return 0; } +static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, + unsigned int event_id) +{ + struct wm_adsp *dsp = ctl->dsp; + u32 val = cpu_to_be32(event_id); + unsigned int reg; + int i, ret; + + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; + + adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", + event_id, ctl->alg_region.alg, + wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset); + + ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); + if (ret) { + adsp_err(dsp, "Failed to write %x: %d\n", reg, ret); + return ret; + } + + /* + * Poll for ack, we initially poll at ~1ms intervals for firmwares + * that respond quickly, then go to ~10ms polls. A firmware is unlikely + * to ack instantly so we do the first 1ms delay before reading the + * control to avoid a pointless bus transaction + */ + for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) { + switch (i) { + case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1: + usleep_range(1000, 2000); + i++; + break; + default: + usleep_range(10000, 20000); + i += 10; + break; + } + + ret = regmap_raw_read(dsp->regmap, reg, &val, sizeof(val)); + if (ret) { + adsp_err(dsp, "Failed to read %x: %d\n", reg, ret); + return ret; + } + + if (val == 0) { + adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); + return 0; + } + } + + adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", + reg, ctl->alg_region.alg, + wm_adsp_mem_region_name(ctl->alg_region.type), + ctl->offset); + + return -ETIMEDOUT; +} + static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, const void *buf, size_t len) { @@ -1034,6 +1102,24 @@ static int wm_coeff_sync_controls(struct wm_adsp *dsp) return 0; } +static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, + unsigned int event) +{ + struct wm_coeff_ctl *ctl; + int ret; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) + continue; + + ret = wm_coeff_write_acked_control(ctl, event); + if (ret) + adsp_warn(dsp, + "Failed to send 0x%x event to alg 0x%x (%d)\n", + event, ctl->alg_region.alg, ret); + } +} + static void wm_adsp_ctl_work(struct work_struct *work) { struct wmfw_ctl_work *ctl_work = container_of(work, @@ -1307,6 +1393,21 @@ static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); } +static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp, + const struct wm_coeff_parsed_coeff *coeff_blk, + unsigned int f_required, + unsigned int f_illegal) +{ + if ((coeff_blk->flags & f_illegal) || + ((coeff_blk->flags & f_required) != f_required)) { + adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", + coeff_blk->flags, coeff_blk->ctl_type); + return -EINVAL; + } + + return 0; +} + static int wm_adsp_parse_coeff(struct wm_adsp *dsp, const struct wmfw_region *region) { @@ -1323,6 +1424,16 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp, switch (coeff_blk.ctl_type) { case SNDRV_CTL_ELEM_TYPE_BYTES: break; + case WMFW_CTL_TYPE_HOSTEVENT: + ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_SYS | + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); + if (ret) + return -EINVAL; + break; default: adsp_err(dsp, "Unknown control type: %d\n", coeff_blk.ctl_type); @@ -2400,6 +2511,9 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_PRE_PMD: + /* Tell the firmware to cleanup */ + wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); + /* Log firmware state, it can be useful for analysis */ wm_adsp2_show_fw_status(dsp); diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h index 7613d60d62ea..892fc7490f3b 100644 --- a/sound/soc/codecs/wmfw.h +++ b/sound/soc/codecs/wmfw.h @@ -26,6 +26,9 @@ #define WMFW_CTL_FLAG_WRITEABLE 0x0002 #define WMFW_CTL_FLAG_READABLE 0x0001 +/* Non-ALSA coefficient types start at 0x1000 */ +#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */ + struct wmfw_header { char magic[4]; __le32 len; -- cgit v1.2.3-59-g8ed1b From 9ce5e6e61122cdd6556d4e61657aa47b207042a1 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 9 Nov 2016 17:14:15 +0000 Subject: ASoC: wm_adsp: factor out getting region name from type This patch factors out converting a memory region type into a name string, mainly so that it can be used in log commands. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 53 +++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 07cf7cb93301..ef33de651028 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -454,6 +454,24 @@ struct wm_coeff_ctl { unsigned int flags; }; +static const char *wm_adsp_mem_region_name(unsigned int type) +{ + switch (type) { + case WMFW_ADSP1_PM: + return "PM"; + case WMFW_ADSP1_DM: + return "DM"; + case WMFW_ADSP2_XM: + return "XM"; + case WMFW_ADSP2_YM: + return "YM"; + case WMFW_ADSP1_ZM: + return "ZM"; + default: + return NULL; + } +} + #ifdef CONFIG_DEBUG_FS static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) { @@ -1146,29 +1164,14 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl; struct wmfw_ctl_work *ctl_work; char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; - char *region_name; + const char *region_name; int ret; if (flags & WMFW_CTL_FLAG_SYS) return 0; - switch (alg_region->type) { - case WMFW_ADSP1_PM: - region_name = "PM"; - break; - case WMFW_ADSP1_DM: - region_name = "DM"; - break; - case WMFW_ADSP2_XM: - region_name = "XM"; - break; - case WMFW_ADSP2_YM: - region_name = "YM"; - break; - case WMFW_ADSP1_ZM: - region_name = "ZM"; - break; - default: + region_name = wm_adsp_mem_region_name(alg_region->type); + if (!region_name) { adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); return -EINVAL; } @@ -1601,23 +1604,11 @@ static int wm_adsp_load(struct wm_adsp *dsp) reg = offset; break; case WMFW_ADSP1_PM: - region_name = "PM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP1_DM: - region_name = "DM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP2_XM: - region_name = "XM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP2_YM: - region_name = "YM"; - reg = wm_adsp_region_to_reg(mem, offset); - break; case WMFW_ADSP1_ZM: - region_name = "ZM"; + region_name = wm_adsp_mem_region_name(type); reg = wm_adsp_region_to_reg(mem, offset); break; default: -- cgit v1.2.3-59-g8ed1b From 8eb084d066baeca2b2911632bb4edddbc2b762c1 Mon Sep 17 00:00:00 2001 From: Stuart Henderson Date: Wed, 9 Nov 2016 17:14:16 +0000 Subject: ASoC: wm_adsp: Add support for SYSTEM firmware controls Add support for firmware controls marked SYSTEM. These are internal to the driver-firmware interface and do not have a user-accessible ALSA control. Signed-off-by: Stuart Henderson Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ef33de651028..d13dd9a9c817 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -452,6 +452,7 @@ struct wm_coeff_ctl { struct snd_kcontrol *kcontrol; struct soc_bytes_ext bytes_ext; unsigned int flags; + unsigned int type; }; static const char *wm_adsp_mem_region_name(unsigned int type) @@ -1159,7 +1160,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, const struct wm_adsp_alg_region *alg_region, unsigned int offset, unsigned int len, const char *subname, unsigned int subname_len, - unsigned int flags) + unsigned int flags, unsigned int type) { struct wm_coeff_ctl *ctl; struct wmfw_ctl_work *ctl_work; @@ -1167,9 +1168,6 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, const char *region_name; int ret; - if (flags & WMFW_CTL_FLAG_SYS) - return 0; - region_name = wm_adsp_mem_region_name(alg_region->type); if (!region_name) { adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); @@ -1227,6 +1225,7 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, ctl->dsp = dsp; ctl->flags = flags; + ctl->type = type; ctl->offset = offset; ctl->len = len; ctl->cache = kzalloc(ctl->len, GFP_KERNEL); @@ -1237,6 +1236,9 @@ static int wm_adsp_create_control(struct wm_adsp *dsp, list_add(&ctl->list, &dsp->ctl_list); + if (flags & WMFW_CTL_FLAG_SYS) + return 0; + ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); if (!ctl_work) { ret = -ENOMEM; @@ -1451,7 +1453,8 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp, coeff_blk.len, coeff_blk.name, coeff_blk.name_len, - coeff_blk.flags); + coeff_blk.flags, + coeff_blk.ctl_type); if (ret < 0) adsp_err(dsp, "Failed to create control: %.*s, %d\n", coeff_blk.name_len, coeff_blk.name, ret); @@ -1851,7 +1854,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp1_alg[i].dm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region DM with ID %x\n", be32_to_cpu(adsp1_alg[i].alg.id)); @@ -1871,7 +1875,8 @@ static int wm_adsp1_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp1_alg[i].zm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", be32_to_cpu(adsp1_alg[i].alg.id)); @@ -1962,7 +1967,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp2_alg[i].xm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region XM with ID %x\n", be32_to_cpu(adsp2_alg[i].alg.id)); @@ -1982,7 +1988,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp2_alg[i].ym); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region YM with ID %x\n", be32_to_cpu(adsp2_alg[i].alg.id)); @@ -2002,7 +2009,8 @@ static int wm_adsp2_setup_algs(struct wm_adsp *dsp) len -= be32_to_cpu(adsp2_alg[i].zm); len *= 4; wm_adsp_create_control(dsp, alg_region, 0, - len, NULL, 0, 0); + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); } else { adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", be32_to_cpu(adsp2_alg[i].alg.id)); -- cgit v1.2.3-59-g8ed1b From a23ebba845fee07cce00659c06844845b24da290 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 9 Nov 2016 17:14:18 +0000 Subject: ASoC: wm_adsp: Support acknowledged controls This patch handles publishing acknowledged controls through ALSA. These controls allow user-side to send events to the firmware and wait for the firmware to acknowledge it. Note that although acked controls only operate in the direction host->firmware, and therefore they are write-only as seen from user- side code, we have to make them readable to account for all the code out there that assumes that ALSA controls are always readable (amixer for example.) Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 89 +++++++++++++++++++++++++++++++++++++++++----- sound/soc/codecs/wmfw.h | 1 + 2 files changed, 82 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index d13dd9a9c817..0f705bfd76b4 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -164,6 +164,8 @@ #define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 #define WM_ADSP_ACKED_CTL_N_QUICKPOLLS 10 +#define WM_ADSP_ACKED_CTL_MIN_VALUE 0 +#define WM_ADSP_ACKED_CTL_MAX_VALUE 0xFFFFFF /* * Event control messages @@ -761,8 +763,20 @@ static int wm_coeff_info(struct snd_kcontrol *kctl, (struct soc_bytes_ext *)kctl->private_value; struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); - uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; - uinfo->count = ctl->len; + switch (ctl->type) { + case WMFW_CTL_TYPE_ACKED: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE; + uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE; + uinfo->value.integer.step = 1; + uinfo->count = 1; + break; + default: + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = ctl->len; + break; + } + return 0; } @@ -910,6 +924,30 @@ static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, return ret; } +static int wm_coeff_put_acked(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + unsigned int val = ucontrol->value.integer.value[0]; + int ret; + + if (val == 0) + return 0; /* 0 means no event */ + + mutex_lock(&ctl->dsp->pwr_lock); + + if (ctl->enabled) + ret = wm_coeff_write_acked_control(ctl, val); + else + ret = -EPERM; + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, void *buf, size_t len) { @@ -1005,6 +1043,21 @@ static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, return ret; } +static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Although it's not useful to read an acked control, we must satisfy + * user-side assumptions that all controls are readable and that a + * write of the same value should be filtered out (it's valid to send + * the same event number again to the firmware). We therefore return 0, + * meaning "no event" so valid event numbers will always be a change + */ + ucontrol->value.integer.value[0] = 0; + + return 0; +} + struct wmfw_ctl_work { struct wm_adsp *dsp; struct wm_coeff_ctl *ctl; @@ -1057,17 +1110,25 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kcontrol->name = ctl->name; kcontrol->info = wm_coeff_info; - kcontrol->get = wm_coeff_get; - kcontrol->put = wm_coeff_put; kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; kcontrol->tlv.c = snd_soc_bytes_tlv_callback; kcontrol->private_value = (unsigned long)&ctl->bytes_ext; + kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); - ctl->bytes_ext.max = ctl->len; - ctl->bytes_ext.get = wm_coeff_tlv_get; - ctl->bytes_ext.put = wm_coeff_tlv_put; + switch (ctl->type) { + case WMFW_CTL_TYPE_ACKED: + kcontrol->get = wm_coeff_get_acked; + kcontrol->put = wm_coeff_put_acked; + break; + default: + kcontrol->get = wm_coeff_get; + kcontrol->put = wm_coeff_put; - kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); + ctl->bytes_ext.max = ctl->len; + ctl->bytes_ext.get = wm_coeff_tlv_get; + ctl->bytes_ext.put = wm_coeff_tlv_put; + break; + } ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); if (ret < 0) @@ -1429,6 +1490,18 @@ static int wm_adsp_parse_coeff(struct wm_adsp *dsp, switch (coeff_blk.ctl_type) { case SNDRV_CTL_ELEM_TYPE_BYTES: break; + case WMFW_CTL_TYPE_ACKED: + if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) + continue; /* ignore */ + + ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); + if (ret) + return -EINVAL; + break; case WMFW_CTL_TYPE_HOSTEVENT: ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, WMFW_CTL_FLAG_SYS | diff --git a/sound/soc/codecs/wmfw.h b/sound/soc/codecs/wmfw.h index 892fc7490f3b..ec78b9da020f 100644 --- a/sound/soc/codecs/wmfw.h +++ b/sound/soc/codecs/wmfw.h @@ -27,6 +27,7 @@ #define WMFW_CTL_FLAG_READABLE 0x0001 /* Non-ALSA coefficient types start at 0x1000 */ +#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */ #define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */ struct wmfw_header { -- cgit v1.2.3-59-g8ed1b From db0717da2a74faf7694cdfe1e591425e84ae7504 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Nov 2016 09:28:33 +0100 Subject: ALSA: opl3: don't opencode IS_REACHABLE() Signed-off-by: Fabian Frederick Signed-off-by: Takashi Iwai --- sound/drivers/opl3/opl3_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c index 369cef212ea9..cd9e9f31720f 100644 --- a/sound/drivers/opl3/opl3_lib.c +++ b/sound/drivers/opl3/opl3_lib.c @@ -528,7 +528,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, opl3->hwdep = hw; opl3->seq_dev_num = seq_device; -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) if (snd_seq_device_new(card, seq_device, SNDRV_SEQ_DEV_ID_OPL3, sizeof(struct snd_opl3 *), &opl3->seq_dev) >= 0) { strcpy(opl3->seq_dev->name, hw->name); -- cgit v1.2.3-59-g8ed1b From 7e1b23b07825dd46c56b249370eec809fcc9d877 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Nov 2016 09:34:49 +0100 Subject: ALSA: rawmidi: don't opencode IS_REACHABLE() Signed-off-by: Fabian Frederick Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index b450a27588c8..2096bb0835c8 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1610,7 +1610,7 @@ static int snd_rawmidi_dev_free(struct snd_device *device) return snd_rawmidi_free(rmidi); } -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) static void snd_rawmidi_dev_seq_free(struct snd_seq_device *device) { struct snd_rawmidi *rmidi = device->private_data; @@ -1691,7 +1691,7 @@ static int snd_rawmidi_dev_register(struct snd_device *device) } } rmidi->proc_entry = entry; -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) if (!rmidi->ops || !rmidi->ops->dev_register) { /* own registration mechanism */ if (snd_seq_device_new(rmidi->card, rmidi->device, SNDRV_SEQ_DEV_ID_MIDISYNTH, 0, &rmidi->seq_dev) >= 0) { rmidi->seq_dev->private_data = rmidi; -- cgit v1.2.3-59-g8ed1b From 658355b599c700c9826f581d087cbd9c26c2cb56 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Nov 2016 09:36:01 +0100 Subject: ALSA: oss: don't opencode IS_REACHABLE() Signed-off-by: Fabian Frederick Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index ebc9fdfe64df..698a01419515 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -2501,7 +2501,7 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long return put_user(SNDRV_OSS_VERSION, p); if (cmd == OSS_ALSAEMULVER) return put_user(1, p); -#if defined(CONFIG_SND_MIXER_OSS) || (defined(MODULE) && defined(CONFIG_SND_MIXER_OSS_MODULE)) +#if IS_REACHABLE(CONFIG_SND_MIXER_OSS) if (((cmd >> 8) & 0xff) == 'M') { /* mixer ioctl - for OSS compatibility */ struct snd_pcm_substream *substream; int idx; -- cgit v1.2.3-59-g8ed1b From 4e2cc814eb2755df286ea890078fb636e1aa0f69 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 10 Nov 2016 09:55:55 +0200 Subject: ASoC: tlv320aic31xx: Add support for tlv320dac3101 The DAC3101 is mostly identical to DAC3100 with the exception that it has stereo speaker AMP instead of mono used in DAC3100. Signed-off-by: Peter Ujfalusi Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/tlv320aic31xx.txt | 1 + sound/soc/codecs/tlv320aic31xx.c | 2 ++ sound/soc/codecs/tlv320aic31xx.h | 1 + 3 files changed, 4 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt index 9340d2ddcc54..6fbba562eaa7 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt @@ -12,6 +12,7 @@ Required properties: "ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP) "ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP) "ti,tlv320dac3100" - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP) + "ti,tlv320dac3101" - TLV320DAC3101 (no ADC, stereo speaker amp, no MiniDSP) - reg - - I2C slave address - HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 8880f6be3336..f8a90ba8cd71 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1254,6 +1254,7 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { { .compatible = "ti,tlv320aic3120" }, { .compatible = "ti,tlv320aic3111" }, { .compatible = "ti,tlv320dac3100" }, + { .compatible = "ti,tlv320dac3101" }, {}, }; MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); @@ -1380,6 +1381,7 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { { "tlv320aic3120", AIC3120 }, { "tlv320aic3111", AIC3111 }, { "tlv320dac3100", DAC3100 }, + { "tlv320dac3101", DAC3101 }, { } }; MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 5acd5b69fb83..730fb2058869 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -32,6 +32,7 @@ enum aic31xx_type { AIC3120 = AIC31XX_MINIDSP_BIT, AIC3111 = (AIC31XX_STEREO_CLASS_D_BIT | AIC31XX_MINIDSP_BIT), DAC3100 = DAC31XX_BIT, + DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT, }; struct aic31xx_pdata { -- cgit v1.2.3-59-g8ed1b From 3421894765a345c6919b22cdda606c2ba1aab2eb Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Nov 2016 18:07:44 -0600 Subject: ASoC: Intel: common: add ACPI package extraction utility Add a new common routine to extract a package exposed by a device indexed with the HID value. The functionality is implemented without assumptions on the package type or structure to allow for reuse. The caller is responsible for defining the name and allocating structures to store the results, ACPICA will complain in case of type mismatches or buffer size issues. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-acpi.h | 17 +++++++++- sound/soc/intel/common/sst-match-acpi.c | 57 +++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 012742299dd5..214e000667ae 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h @@ -15,14 +15,29 @@ #include #include -/* translation fron HID to I2C name, needed for DAI codec_name */ +struct sst_acpi_package_context { + char *name; /* package name */ + int length; /* number of elements */ + struct acpi_buffer *format; + struct acpi_buffer *state; + bool data_valid; +}; + #if IS_ENABLED(CONFIG_ACPI) +/* translation fron HID to I2C name, needed for DAI codec_name */ const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx); #else static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) { return NULL; } +static inline bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx) +{ + return false; +} #endif /* acpi match */ diff --git a/sound/soc/intel/common/sst-match-acpi.c b/sound/soc/intel/common/sst-match-acpi.c index 789843307a49..1070f3ad23e5 100644 --- a/sound/soc/intel/common/sst-match-acpi.c +++ b/sound/soc/intel/common/sst-match-acpi.c @@ -77,5 +77,62 @@ struct sst_acpi_mach *sst_acpi_find_machine(struct sst_acpi_mach *machines) } EXPORT_SYMBOL_GPL(sst_acpi_find_machine); +static acpi_status sst_acpi_find_package(acpi_handle handle, u32 level, + void *context, void **ret) +{ + struct acpi_device *adev; + acpi_status status = AE_OK; + struct sst_acpi_package_context *pkg_ctx = context; + + pkg_ctx->data_valid = false; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (adev->status.present && adev->status.functional) { + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object *myobj = NULL; + + status = acpi_evaluate_object_typed(handle, pkg_ctx->name, + NULL, &buffer, + ACPI_TYPE_PACKAGE); + if (ACPI_FAILURE(status)) + return AE_OK; + + myobj = buffer.pointer; + if (!myobj || myobj->package.count != pkg_ctx->length) { + kfree(buffer.pointer); + return AE_OK; + } + + status = acpi_extract_package(myobj, + pkg_ctx->format, pkg_ctx->state); + if (ACPI_FAILURE(status)) { + kfree(buffer.pointer); + return AE_OK; + } + + kfree(buffer.pointer); + pkg_ctx->data_valid = true; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +bool sst_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], + struct sst_acpi_package_context *ctx) +{ + acpi_status status; + + status = acpi_get_devices(hid, sst_acpi_find_package, ctx, NULL); + + if (ACPI_FAILURE(status) || !ctx->data_valid) + return false; + + return true; +} +EXPORT_SYMBOL_GPL(sst_acpi_find_package_from_hid); + MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("Intel Common ACPI Match module"); -- cgit v1.2.3-59-g8ed1b From 64e84305cb936024a9862c48f61539fdad649a22 Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Nov 2016 18:07:45 -0600 Subject: ASoC: Intel: detect audio routing with CHAN package Baytrail-CR devices usually expose information in the DSDT which can be used to auto-detect AIF1/AIF2 connections. The CHAN package contains two integers, the first one describes the AIF number (1: AIF1, 2: AIF2) and the second the MCLK value (ignored in this patch) For example the following information is found in Lenovo 100s: Device (RTEK) { [...] Name (CHAN, Package (0x02) { One, 0x017D7840 }) While on Asus T100TAF the package values are: Name (CHAN, Package (0x02) { 0x02, 0x017D7840 }) This patch relies on the new common routine to extract a package exposed by a device indexed with the HID value. The CHAN package contents are queried from the machine driver and stored in a structure. If this auto-detection fails (missing or bad package in the BIOS), the routing falls back to SSP0-AIF2. Note that quirks may still be needed to support mono speakers or microphone, but this should reduce the number of issues with Baytrail significantly. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 53 +++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index bff77a1f27fc..32aeffc352ee 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -689,6 +689,10 @@ static bool is_valleyview(void) return true; } +struct acpi_chan_package { /* ACPICA seems to require 64 bit integers */ + u64 aif_value; /* 1: AIF1, 2: AIF2 */ + u64 mclock_value; /* usually 25MHz (0x17d7940), ignored */ +}; static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) { @@ -698,6 +702,7 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) int i; int dai_index; struct byt_rt5640_private *priv; + bool is_bytcr = false; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_ATOMIC); if (!priv) @@ -734,8 +739,52 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) struct sst_platform_info *p_info = mach->pdata; const struct sst_res_info *res_info = p_info->res_info; - /* TODO: use CHAN package info from BIOS to detect AIF1/AIF2 */ - if (res_info->acpi_ipc_irq_index == 0) { + if (res_info->acpi_ipc_irq_index == 0) + is_bytcr = true; + } + + if (is_bytcr) { + /* + * Baytrail CR platforms may have CHAN package in BIOS, try + * to find relevant routing quirk based as done on Windows + * platforms. We have to read the information directly from the + * BIOS, at this stage the card is not created and the links + * with the codec driver/pdata are non-existent + */ + + struct acpi_chan_package chan_package; + + /* format specified: 2 64-bit integers */ + struct acpi_buffer format = {sizeof("NN"), "NN"}; + struct acpi_buffer state = {0, NULL}; + struct sst_acpi_package_context pkg_ctx; + bool pkg_found = false; + + state.length = sizeof(chan_package); + state.pointer = &chan_package; + + pkg_ctx.name = "CHAN"; + pkg_ctx.length = 2; + pkg_ctx.format = &format; + pkg_ctx.state = &state; + pkg_ctx.data_valid = false; + + pkg_found = sst_acpi_find_package_from_hid(mach->id, &pkg_ctx); + if (pkg_found) { + if (chan_package.aif_value == 1) { + dev_info(&pdev->dev, "BIOS Routing: AIF1 connected\n"); + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF1; + } else if (chan_package.aif_value == 2) { + dev_info(&pdev->dev, "BIOS Routing: AIF2 connected\n"); + byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; + } else { + dev_info(&pdev->dev, "BIOS Routing isn't valid, ignored\n"); + pkg_found = false; + } + } + + if (!pkg_found) { + /* no BIOS indications, assume SSP0-AIF2 connection */ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } } -- cgit v1.2.3-59-g8ed1b From bf46241bee7bc3ec28703796f4fbd56085055fca Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bossart Date: Sat, 12 Nov 2016 18:07:46 -0600 Subject: ASoC: Intel: bytct_rt5640: change default capture settings Most Baytrail-CR devices use analog differential microphones, modify capture default to avoid DMI quirks. Keep digital mics for all other configurations. Signed-off-by: Pierre-Louis Bossart Signed-off-by: Mark Brown --- sound/soc/intel/boards/bytcr_rt5640.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bytcr_rt5640.c b/sound/soc/intel/boards/bytcr_rt5640.c index 32aeffc352ee..f9d73b55d2f7 100644 --- a/sound/soc/intel/boards/bytcr_rt5640.c +++ b/sound/soc/intel/boards/bytcr_rt5640.c @@ -57,9 +57,7 @@ struct byt_rt5640_private { struct clk *mclk; }; -static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | - BYT_RT5640_DMIC_EN | - BYT_RT5640_MCLK_EN; +static unsigned long byt_rt5640_quirk = BYT_RT5640_MCLK_EN; static void log_quirks(struct device *dev) { @@ -787,6 +785,13 @@ static int snd_byt_rt5640_mc_probe(struct platform_device *pdev) /* no BIOS indications, assume SSP0-AIF2 connection */ byt_rt5640_quirk |= BYT_RT5640_SSP0_AIF2; } + + /* change defaults for Baytrail-CR capture */ + byt_rt5640_quirk |= BYT_RT5640_IN1_MAP; + byt_rt5640_quirk |= BYT_RT5640_DIFF_MIC; + } else { + byt_rt5640_quirk |= (BYT_RT5640_DMIC1_MAP | + BYT_RT5640_DMIC_EN); } /* check quirks before creating card */ -- cgit v1.2.3-59-g8ed1b From 2e622ae41e653cd71a6d3bc5a4685b01eacbee8d Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 13 Nov 2016 12:10:02 +0530 Subject: ASoC: compress: Add support for compress dai ops ASoC Compress ops have only platform ops and no DAI ops unlike PCM device where we have both platform ops as well as DAI ops. So add compress dai ops and add this new structure to the ASoC core to make compressed devices a first class ASoC citizen Again like PCM ops, drivers are free to implement either or both of these ops based on device needs. Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- include/sound/soc-dai.h | 25 ++++++++++++ sound/soc/soc-compress.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 121 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 964b7de1a1cc..756ee1b78ffc 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h @@ -207,6 +207,30 @@ struct snd_soc_dai_ops { struct snd_soc_dai *); }; +struct snd_soc_cdai_ops { + /* + * for compress ops + */ + int (*startup)(struct snd_compr_stream *, + struct snd_soc_dai *); + int (*shutdown)(struct snd_compr_stream *, + struct snd_soc_dai *); + int (*set_params)(struct snd_compr_stream *, + struct snd_compr_params *, struct snd_soc_dai *); + int (*get_params)(struct snd_compr_stream *, + struct snd_codec *, struct snd_soc_dai *); + int (*set_metadata)(struct snd_compr_stream *, + struct snd_compr_metadata *, struct snd_soc_dai *); + int (*get_metadata)(struct snd_compr_stream *, + struct snd_compr_metadata *, struct snd_soc_dai *); + int (*trigger)(struct snd_compr_stream *, int, + struct snd_soc_dai *); + int (*pointer)(struct snd_compr_stream *, + struct snd_compr_tstamp *, struct snd_soc_dai *); + int (*ack)(struct snd_compr_stream *, size_t, + struct snd_soc_dai *); +}; + /* * Digital Audio Interface Driver. * @@ -236,6 +260,7 @@ struct snd_soc_dai_driver { /* ops */ const struct snd_soc_dai_ops *ops; + const struct snd_soc_cdai_ops *cops; /* DAI capabilities */ struct snd_soc_pcm_stream capture; diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index bf7b52fce597..bfd71b873ca2 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -30,16 +30,26 @@ static int soc_compr_open(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { + ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n", + cpu_dai->name, ret); + goto out; + } + } + if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { pr_err("compress asoc: can't open platform %s\n", platform->component.name); - goto out; + goto plat_err; } } @@ -60,6 +70,9 @@ static int soc_compr_open(struct snd_compr_stream *cstream) machine_err: if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); +plat_err: + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); out: mutex_unlock(&rtd->pcm_mutex); return ret; @@ -70,6 +83,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; struct snd_soc_dpcm *dpcm; struct snd_soc_dapm_widget_list *list; int stream; @@ -82,12 +96,22 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->startup) { + ret = cpu_dai->driver->cops->startup(cstream, cpu_dai); + if (ret < 0) { + dev_err(cpu_dai->dev, "Compress ASoC: can't open interface %s: %d\n", + cpu_dai->name, ret); + goto out; + } + } + + if (platform->driver->compr_ops && platform->driver->compr_ops->open) { ret = platform->driver->compr_ops->open(cstream); if (ret < 0) { pr_err("compress asoc: can't open platform %s\n", platform->component.name); - goto out; + goto plat_err; } } @@ -144,6 +168,9 @@ fe_err: machine_err: if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); +plat_err: + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); out: fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; mutex_unlock(&fe->card->mutex); @@ -210,6 +237,9 @@ static int soc_compr_free(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); + if (cstream->direction == SND_COMPRESS_PLAYBACK) { if (snd_soc_runtime_ignore_pmdown_time(rtd)) { snd_soc_dapm_stream_event(rtd, @@ -236,6 +266,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; struct snd_soc_dpcm *dpcm; int stream, ret; @@ -275,6 +306,9 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) if (platform->driver->compr_ops && platform->driver->compr_ops->free) platform->driver->compr_ops->free(cstream); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->shutdown) + cpu_dai->driver->cops->shutdown(cstream, cpu_dai); + mutex_unlock(&fe->card->mutex); return 0; } @@ -285,6 +319,7 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -295,6 +330,10 @@ static int soc_compr_trigger(struct snd_compr_stream *cstream, int cmd) goto out; } + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) + cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); + + switch (cmd) { case SNDRV_PCM_TRIGGER_START: snd_soc_dai_digital_mute(codec_dai, 0, cstream->direction); @@ -313,6 +352,7 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) { struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret = 0, stream; if (cmd == SND_COMPR_TRIGGER_PARTIAL_DRAIN || @@ -332,6 +372,12 @@ static int soc_compr_trigger_fe(struct snd_compr_stream *cstream, int cmd) mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->trigger) { + ret = cpu_dai->driver->cops->trigger(cstream, cmd, cpu_dai); + if (ret < 0) + goto out; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->trigger) { ret = platform->driver->compr_ops->trigger(cstream, cmd); if (ret < 0) @@ -368,6 +414,7 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); @@ -378,6 +425,12 @@ static int soc_compr_set_params(struct snd_compr_stream *cstream, * expectation is that platform and machine will configure everything * for this compress path, like configuring pcm port for codec */ + if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { + ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); + if (ret < 0) + goto err; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) @@ -416,6 +469,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *fe = cstream->private_data; struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; struct snd_soc_platform *platform = fe->platform; + struct snd_soc_dai *cpu_dai = fe->cpu_dai; int ret = 0, stream; if (cstream->direction == SND_COMPRESS_PLAYBACK) @@ -425,6 +479,12 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_params) { + ret = cpu_dai->driver->cops->set_params(cstream, params, cpu_dai); + if (ret < 0) + goto out; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->set_params) { ret = platform->driver->compr_ops->set_params(cstream, params); if (ret < 0) @@ -469,13 +529,21 @@ static int soc_compr_get_params(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_params) { + ret = cpu_dai->driver->cops->get_params(cstream, params, cpu_dai); + if (ret < 0) + goto err; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->get_params) ret = platform->driver->compr_ops->get_params(cstream, params); +err: mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -516,13 +584,21 @@ static int soc_compr_ack(struct snd_compr_stream *cstream, size_t bytes) { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->ack) { + ret = cpu_dai->driver->cops->ack(cstream, bytes, cpu_dai); + if (ret < 0) + goto err; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->ack) ret = platform->driver->compr_ops->ack(cstream, bytes); +err: mutex_unlock(&rtd->pcm_mutex); return ret; } @@ -533,9 +609,13 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; int ret = 0; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); + if (cpu_dai->driver->cops && cpu_dai->driver->cops->pointer) + cpu_dai->driver->cops->pointer(cstream, tstamp, cpu_dai); + if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) ret = platform->driver->compr_ops->pointer(cstream, tstamp); @@ -564,8 +644,15 @@ static int soc_compr_set_metadata(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->set_metadata) { + ret = cpu_dai->driver->cops->set_metadata(cstream, metadata, cpu_dai); + if (ret < 0) + return ret; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->set_metadata) ret = platform->driver->compr_ops->set_metadata(cstream, metadata); @@ -577,8 +664,15 @@ static int soc_compr_get_metadata(struct snd_compr_stream *cstream, { struct snd_soc_pcm_runtime *rtd = cstream->private_data; struct snd_soc_platform *platform = rtd->platform; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; int ret = 0; + if (cpu_dai->driver->cops && cpu_dai->driver->cops->get_metadata) { + ret = cpu_dai->driver->cops->get_metadata(cstream, metadata, cpu_dai); + if (ret < 0) + return ret; + } + if (platform->driver->compr_ops && platform->driver->compr_ops->get_metadata) ret = platform->driver->compr_ops->get_metadata(cstream, metadata); -- cgit v1.2.3-59-g8ed1b From 28ab49bf9bd9185d8221392a5195bb6c989ed7c7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 12 Nov 2016 16:30:25 +0000 Subject: ASoC: mioa701_wm9713: add missing white space in dev_err message There is a missing whitespace in the dev_err message between "will" and "lead". Add the whitespace. Signed-off-by: Colin Ian King Signed-off-by: Mark Brown --- sound/soc/pxa/mioa701_wm9713.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index d1661fa6ee08..0fe0abec8fc4 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c @@ -187,7 +187,7 @@ static int mioa701_wm9713_probe(struct platform_device *pdev) mioa701.dev = &pdev->dev; rc = devm_snd_soc_register_card(&pdev->dev, &mioa701); if (!rc) - dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will" + dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will " "lead to overheating and possible destruction of your device." " Do not use without a good knowledge of mio's board design!\n"); return rc; -- cgit v1.2.3-59-g8ed1b From 92be58106e5d750b97567bea7171f5aee74a678a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 12 Nov 2016 14:23:13 +0100 Subject: ASoC: pxa: Make static string arrays 'const 'char * const []' const char * const [] is the preferred type for static string arrays since this states explicitly that the individual entries are not going to be changed. Due to limitations in the ASoC API it was not possible to use it for enum text arrays. Commit 87023ff74 ('ASoC: Declare const properly for enum texts') changed this, but most drivers still use 'const char * []' as the type for their enum text arrays. Change these occurrences of 'static * const char * []' to 'static const char * const []'. The conversion was done automatically using the following coccinelle semantic patch: // @disable optional_qualifier@ identifier s; @@ static -const char * +const char * const s[] = ...; // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/pxa/corgi.c | 6 +++--- sound/soc/pxa/magician.c | 2 +- sound/soc/pxa/poodle.c | 4 ++-- sound/soc/pxa/spitz.c | 6 +++--- sound/soc/pxa/tosa.c | 6 +++--- 5 files changed, 12 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index dcbb7aa9830c..311774e9ca46 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c @@ -244,9 +244,9 @@ static const struct snd_soc_dapm_route corgi_audio_map[] = { {"MICIN", NULL, "Line Jack"}, }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", - "Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", + "Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"}; static const struct soc_enum corgi_enum[] = { SOC_ENUM_SINGLE_EXT(5, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 62b8377a9d2b..2d4d4455fe87 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c @@ -376,7 +376,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"VINM", NULL, "Call Mic"}, }; -static const char *input_select[] = {"Call Mic", "Headset Mic"}; +static const char * const input_select[] = {"Call Mic", "Headset Mic"}; static const struct soc_enum magician_in_sel_enum = SOC_ENUM_SINGLE_EXT(2, input_select); diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index 4b3b714f5ee7..a879aba0691f 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c @@ -209,8 +209,8 @@ static const struct snd_soc_dapm_route poodle_audio_map[] = { {"MICIN", NULL, "Microphone"}, }; -static const char *jack_function[] = {"Off", "Headphone"}; -static const char *spk_function[] = {"Off", "On"}; +static const char * const jack_function[] = {"Off", "Headphone"}; +static const char * const spk_function[] = {"Off", "On"}; static const struct soc_enum poodle_enum[] = { SOC_ENUM_SINGLE_EXT(2, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 0e02634c8b7f..07d77cddac60 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -241,9 +241,9 @@ static const struct snd_soc_dapm_route spitz_audio_map[] = { {"LINPUT1", NULL, "Line Jack"}, }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", - "Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", + "Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"}; static const struct soc_enum spitz_enum[] = { SOC_ENUM_SINGLE_EXT(5, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index c508f024ecfb..08b0cf50e91a 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c @@ -170,9 +170,9 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Mic Bias", NULL, "Headset Jack"}, }; -static const char *jack_function[] = {"Headphone", "Mic", "Line", "Headset", - "Off"}; -static const char *spk_function[] = {"On", "Off"}; +static const char * const jack_function[] = {"Headphone", "Mic", "Line", + "Headset", "Off"}; +static const char * const spk_function[] = {"On", "Off"}; static const struct soc_enum tosa_enum[] = { SOC_ENUM_SINGLE_EXT(5, jack_function), SOC_ENUM_SINGLE_EXT(2, spk_function), -- cgit v1.2.3-59-g8ed1b From b2fac0730347d591b528d8f0e4a9438c1bb6f558 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sat, 12 Nov 2016 23:26:41 +0100 Subject: ALSA: pci: don't opencode IS_REACHABLE() Signed-off-by: Fabian Frederick Signed-off-by: Takashi Iwai --- sound/pci/als4000.c | 2 +- sound/pci/au88x0/au88x0_game.c | 2 +- sound/pci/azt3328.c | 2 +- sound/pci/cmipci.c | 2 +- sound/pci/cs4281.c | 2 +- sound/pci/cs46xx/cs46xx_lib.c | 2 +- sound/pci/emu10k1/emu10k1.c | 2 +- sound/pci/ens1370.c | 2 +- sound/pci/es1938.c | 2 +- sound/pci/es1968.c | 2 +- sound/pci/riptide/riptide.c | 2 +- sound/pci/sonicvibes.c | 2 +- sound/pci/trident/trident_main.c | 2 +- sound/pci/via82xx.c | 2 +- sound/pci/ymfpci/ymfpci.h | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index edabe1371660..92bc06d01288 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -84,7 +84,7 @@ MODULE_DESCRIPTION("Avance Logic ALS4000"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index 151815b857a0..53abcd3eccbd 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c @@ -36,7 +36,7 @@ #include #include -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define VORTEX_GAME_DWAIT 20 /* 20 ms */ diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 80c4a4456197..79b2e6b7d88b 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -212,7 +212,7 @@ MODULE_DESCRIPTION("Aztech AZF3328 (PCI168)"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_GAMEPORT 1 #endif diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 73f593526b2d..aeedc270ed9b 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -48,7 +48,7 @@ MODULE_SUPPORTED_DEVICE("{{C-Media,CMI8738}," "{C-Media,CMI8338A}," "{C-Media,CMI8338B}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 615d8a99d8c8..8f0f5f24e40e 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -1194,7 +1194,7 @@ static void snd_cs4281_proc_init(struct cs4281 *chip) * joystick support */ -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) static void snd_cs4281_gameport_trigger(struct gameport *gameport) { diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 528102cc2d5d..fde3cd48258c 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -2718,7 +2718,7 @@ int snd_cs46xx_midi(struct snd_cs46xx *chip, int device) * gameport interface */ -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) static void snd_cs46xx_gameport_trigger(struct gameport *gameport) { diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index db7a2e5e4a14..4733b68c9eb0 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -37,7 +37,7 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Creative Labs,SB Live!/PCI512/E-mu APS}," "{Creative Labs,SB Audigy}}"); -#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE)) +#if IS_REACHABLE(CONFIG_SND_SEQUENCER) #define ENABLE_SYNTH #include #endif diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 7e760fed0728..51736c2b5a00 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -79,7 +79,7 @@ MODULE_SUPPORTED_DEVICE("{{Ensoniq,AudioPCI ES1371/73}," "{Ectiva,EV1938}}"); #endif -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK #endif diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 681355829484..e8d943071a8c 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -72,7 +72,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,ES1938}," "{ESS,ES1969}," "{TerraTec,128i PCI}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 8146fb76a4ad..2ec2b1ce0af6 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -126,7 +126,7 @@ MODULE_SUPPORTED_DEVICE("{{ESS,Maestro 2e}," "{ESS,Maestro 1}," "{TerraTec,DMX}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index ada5f01d479c..19c9df6b0f3d 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -110,7 +110,7 @@ #include #include -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index e1a13870bb80..a6aa48c5b969 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -45,7 +45,7 @@ MODULE_DESCRIPTION("S3 SonicVibes PCI"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{S3,SonicVibes PCI}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 27f0ed840979..92ad2d7a6bf8 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -3120,7 +3120,7 @@ static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) * gameport interface */ -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) static unsigned char snd_trident_gameport_read(struct gameport *gameport) { diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 38a17b4342a6..2d8c14e3f8d2 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -72,7 +72,7 @@ MODULE_DESCRIPTION("VIA VT82xx audio"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{VIA,VT82C686A/B/C,pci},{VIA,VT8233A/C,8235}}"); -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK 1 #endif diff --git a/sound/pci/ymfpci/ymfpci.h b/sound/pci/ymfpci/ymfpci.h index 149d4cb46998..aa9bb065f385 100644 --- a/sound/pci/ymfpci/ymfpci.h +++ b/sound/pci/ymfpci/ymfpci.h @@ -176,7 +176,7 @@ #define YMFPCI_LEGACY2_IMOD (1 << 15) /* legacy IRQ mode */ /* SIEN:IMOD 0:0 = legacy irq, 0:1 = INTA, 1:0 = serialized IRQ */ -#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE)) +#if IS_REACHABLE(CONFIG_GAMEPORT) #define SUPPORT_JOYSTICK #endif -- cgit v1.2.3-59-g8ed1b From 134340b33f2ddf4869519d728ad0ca4bc67154f3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 13 Nov 2016 21:06:16 +0100 Subject: ASoC: rt5616: Don't use rtd->codec rtd->codec does not necessarily point to the CODEC instance for which the callback was called (e.g. for CODEC<->CODEC or multi-CODEC links). Use dai->codec instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5616.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index d1f273b24991..7d6e0823f98f 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -960,8 +960,7 @@ static int rt5616_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct rt5616_priv *rt5616 = snd_soc_codec_get_drvdata(codec); unsigned int val_len = 0, val_clk, mask_clk; int pre_div, bclk_ms, frame_size; -- cgit v1.2.3-59-g8ed1b From b396ebca736f94a1a18bdc9a518ad0ca58fbd842 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 9 Nov 2016 17:14:14 +0000 Subject: ASoC: wm_adsp: factor out getting base register for a control The lookup of the base register corresponding to a control is duplicated in read and write so factor it out into a separate function. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 0f705bfd76b4..4fb6e2f035e0 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -756,6 +756,24 @@ static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) return container_of(ext, struct wm_coeff_ctl, bytes_ext); } +static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg) +{ + const struct wm_adsp_alg_region *alg_region = &ctl->alg_region; + struct wm_adsp *dsp = ctl->dsp; + const struct wm_adsp_region *mem; + + mem = wm_adsp_find_region(dsp, alg_region->type); + if (!mem) { + adsp_err(dsp, "No base for region %x\n", + alg_region->type); + return -EINVAL; + } + + *reg = wm_adsp_region_to_reg(mem, ctl->alg_region.base + ctl->offset); + + return 0; +} + static int wm_coeff_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) { @@ -843,22 +861,14 @@ static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, const void *buf, size_t len) { - struct wm_adsp_alg_region *alg_region = &ctl->alg_region; - const struct wm_adsp_region *mem; struct wm_adsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - mem = wm_adsp_find_region(dsp, alg_region->type); - if (!mem) { - adsp_err(dsp, "No base for region %x\n", - alg_region->type); - return -EINVAL; - } - - reg = ctl->alg_region.base + ctl->offset; - reg = wm_adsp_region_to_reg(mem, reg); + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA); if (!scratch) @@ -951,22 +961,14 @@ static int wm_coeff_put_acked(struct snd_kcontrol *kctl, static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, void *buf, size_t len) { - struct wm_adsp_alg_region *alg_region = &ctl->alg_region; - const struct wm_adsp_region *mem; struct wm_adsp *dsp = ctl->dsp; void *scratch; int ret; unsigned int reg; - mem = wm_adsp_find_region(dsp, alg_region->type); - if (!mem) { - adsp_err(dsp, "No base for region %x\n", - alg_region->type); - return -EINVAL; - } - - reg = ctl->alg_region.base + ctl->offset; - reg = wm_adsp_region_to_reg(mem, reg); + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; scratch = kmalloc(len, GFP_KERNEL | GFP_DMA); if (!scratch) -- cgit v1.2.3-59-g8ed1b From 33ada14a26c8f174dac8765f4236ca66c64ae5be Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 14 Nov 2016 11:00:10 +0800 Subject: ASoC: add rt5665 codec driver This is the initial codec driver for rt5665. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/rt5665.txt | 68 + include/sound/rt5665.h | 47 + sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt5665.c | 4875 ++++++++++++++++++++ sound/soc/codecs/rt5665.h | 1990 ++++++++ 6 files changed, 6988 insertions(+) create mode 100755 Documentation/devicetree/bindings/sound/rt5665.txt create mode 100755 include/sound/rt5665.h create mode 100644 sound/soc/codecs/rt5665.c create mode 100644 sound/soc/codecs/rt5665.h (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/rt5665.txt b/Documentation/devicetree/bindings/sound/rt5665.txt new file mode 100755 index 000000000000..419c89219681 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5665.txt @@ -0,0 +1,68 @@ +RT5665/RT5666/RT5668 audio CODEC + +This device supports I2C only. + +Required properties: + +- compatible : One of "realtek,rt5665", "realtek,rt5666" or "realtek,rt5668". + +- reg : The I2C address of the device. + +- interrupts : The CODEC's interrupt output. + +Optional properties: + +- realtek,in1-differential +- realtek,in2-differential +- realtek,in3-differential +- realtek,in4-differential + Boolean. Indicate MIC1/2/3/4 input are differential, rather than single-ended. + +- realtek,dmic1-data-pin + 0: dmic1 is not used + 1: using GPIO4 pin as dmic1 data pin + 2: using IN2N pin as dmic2 data pin + +- realtek,dmic2-data-pin + 0: dmic2 is not used + 1: using GPIO5 pin as dmic2 data pin + 2: using IN2P pin as dmic2 data pin + +- realtek,jd-src + 0: No JD is used + 1: using JD1 as JD source + +- realtek,ldo1-en-gpios : The GPIO that controls the CODEC's LDO1_EN pin. + +Pins on the device (for linking into audio routes) for RT5659/RT5658: + + * DMIC L1 + * DMIC R1 + * DMIC L2 + * DMIC R2 + * IN1P + * IN1N + * IN2P + * IN2N + * IN3P + * IN3N + * IN4P + * IN4N + * HPOL + * HPOR + * LOUTL + * LOUTR + * MONOOUT + * PDML + * PDMR + +Example: + +rt5659 { + compatible = "realtek,rt5665"; + reg = <0x1b>; + interrupt-parent = <&gpio>; + interrupts = ; + realtek,ldo1-en-gpios = + <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; +}; diff --git a/include/sound/rt5665.h b/include/sound/rt5665.h new file mode 100755 index 000000000000..963229e71dc7 --- /dev/null +++ b/include/sound/rt5665.h @@ -0,0 +1,47 @@ +/* + * linux/sound/rt5665.h -- Platform data for RT5665 + * + * Copyright 2016 Realtek Microelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_RT5665_H +#define __LINUX_SND_RT5665_H + +enum rt5665_dmic1_data_pin { + RT5665_DMIC1_NULL, + RT5665_DMIC1_DATA_GPIO4, + RT5665_DMIC1_DATA_IN2N, +}; + +enum rt5665_dmic2_data_pin { + RT5665_DMIC2_NULL, + RT5665_DMIC2_DATA_GPIO5, + RT5665_DMIC2_DATA_IN2P, +}; + +enum rt5665_jd_src { + RT5665_JD_NULL, + RT5665_JD1, +}; + +struct rt5665_platform_data { + bool in1_diff; + bool in2_diff; + bool in3_diff; + bool in4_diff; + + int ldo1_en; /* GPIO for LDO1_EN */ + + enum rt5665_dmic1_data_pin dmic1_data_pin; + enum rt5665_dmic2_data_pin dmic2_data_pin; + enum rt5665_jd_src jd_src; + + unsigned int sar_hs_type; +}; + +#endif + diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..f1de9720d9d3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -114,6 +114,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_RT5651 if I2C select SND_SOC_RT5659 if I2C select SND_SOC_RT5660 if I2C + select SND_SOC_RT5665 if I2C select SND_SOC_RT5663 if I2C select SND_SOC_RT5670 if I2C select SND_SOC_RT5677 if I2C && SPI_MASTER @@ -649,6 +650,7 @@ config SND_SOC_RL6231 default y if SND_SOC_RT5651=y default y if SND_SOC_RT5659=y default y if SND_SOC_RT5660=y + default y if SND_SOC_RT5665=y default y if SND_SOC_RT5663=y default y if SND_SOC_RT5670=y default y if SND_SOC_RT5677=y @@ -659,6 +661,7 @@ config SND_SOC_RL6231 default m if SND_SOC_RT5651=m default m if SND_SOC_RT5659=m default m if SND_SOC_RT5660=m + default m if SND_SOC_RT5665=m default m if SND_SOC_RT5663=m default m if SND_SOC_RT5670=m default m if SND_SOC_RT5677=m @@ -708,6 +711,9 @@ config SND_SOC_RT5659 config SND_SOC_RT5660 tristate +config SND_SOC_RT5665 + tristate + config SND_SOC_RT5663 tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 958cd4912fbc..e1704e09806c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -114,6 +114,7 @@ snd-soc-rt5645-objs := rt5645.o snd-soc-rt5651-objs := rt5651.o snd-soc-rt5659-objs := rt5659.o snd-soc-rt5660-objs := rt5660.o +snd-soc-rt5665-objs := rt5665.o snd-soc-rt5663-objs := rt5663.o snd-soc-rt5670-objs := rt5670.o snd-soc-rt5677-objs := rt5677.o @@ -338,6 +339,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o obj-$(CONFIG_SND_SOC_RT5660) += snd-soc-rt5660.o +obj-$(CONFIG_SND_SOC_RT5665) += snd-soc-rt5665.o obj-$(CONFIG_SND_SOC_RT5663) += snd-soc-rt5663.o obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c new file mode 100644 index 000000000000..34254fd47efe --- /dev/null +++ b/sound/soc/codecs/rt5665.c @@ -0,0 +1,4875 @@ +/* + * rt5665.c -- RT5665/RT5658 ALSA SoC audio codec driver + * + * Copyright 2016 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6231.h" +#include "rt5665.h" + +#define RT5665_NUM_SUPPLIES 3 + +static const char *rt5665_supply_names[RT5665_NUM_SUPPLIES] = { + "AVDD", + "MICVDD", + "VBAT", +}; + +struct rt5665_priv { + struct snd_soc_codec *codec; + struct rt5665_platform_data pdata; + struct regmap *regmap; + struct gpio_desc *gpiod_ldo1_en; + struct gpio_desc *gpiod_reset; + struct snd_soc_jack *hs_jack; + struct regulator_bulk_data supplies[RT5665_NUM_SUPPLIES]; + struct delayed_work jack_detect_work; + struct delayed_work calibrate_work; + struct delayed_work jd_check_work; + struct mutex calibrate_mutex; + + int sysclk; + int sysclk_src; + int lrck[RT5665_AIFS]; + int bclk[RT5665_AIFS]; + int master[RT5665_AIFS]; + int id; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; + int irq_work_delay_time; + unsigned int sar_adc_value; +}; + +static const struct reg_default rt5665_reg[] = { + {0x0000, 0x0000}, + {0x0001, 0xc8c8}, + {0x0002, 0x8080}, + {0x0003, 0x8000}, + {0x0004, 0xc80a}, + {0x0005, 0x0000}, + {0x0006, 0x0000}, + {0x0007, 0x0000}, + {0x000a, 0x0000}, + {0x000b, 0x0000}, + {0x000c, 0x0000}, + {0x000d, 0x0000}, + {0x000f, 0x0808}, + {0x0010, 0x4040}, + {0x0011, 0x0000}, + {0x0012, 0x1404}, + {0x0013, 0x1000}, + {0x0014, 0xa00a}, + {0x0015, 0x0404}, + {0x0016, 0x0404}, + {0x0017, 0x0011}, + {0x0018, 0xafaf}, + {0x0019, 0xafaf}, + {0x001a, 0xafaf}, + {0x001b, 0x0011}, + {0x001c, 0x2f2f}, + {0x001d, 0x2f2f}, + {0x001e, 0x2f2f}, + {0x001f, 0x0000}, + {0x0020, 0x0000}, + {0x0021, 0x0000}, + {0x0022, 0x5757}, + {0x0023, 0x0039}, + {0x0026, 0xc0c0}, + {0x0027, 0xc0c0}, + {0x0028, 0xc0c0}, + {0x0029, 0x8080}, + {0x002a, 0xaaaa}, + {0x002b, 0xaaaa}, + {0x002c, 0xaba8}, + {0x002d, 0x0000}, + {0x002e, 0x0000}, + {0x002f, 0x0000}, + {0x0030, 0x0000}, + {0x0031, 0x5000}, + {0x0032, 0x0000}, + {0x0033, 0x0000}, + {0x0034, 0x0000}, + {0x0035, 0x0000}, + {0x003a, 0x0000}, + {0x003b, 0x0000}, + {0x003c, 0x00ff}, + {0x003d, 0x0000}, + {0x003e, 0x00ff}, + {0x003f, 0x0000}, + {0x0040, 0x0000}, + {0x0041, 0x00ff}, + {0x0042, 0x0000}, + {0x0043, 0x00ff}, + {0x0044, 0x0c0c}, + {0x0049, 0xc00b}, + {0x004a, 0x0000}, + {0x004b, 0x031f}, + {0x004d, 0x0000}, + {0x004e, 0x001f}, + {0x004f, 0x0000}, + {0x0050, 0x001f}, + {0x0052, 0xf000}, + {0x0061, 0x0000}, + {0x0062, 0x0000}, + {0x0063, 0x003e}, + {0x0064, 0x0000}, + {0x0065, 0x0000}, + {0x0066, 0x003f}, + {0x0067, 0x0000}, + {0x006b, 0x0000}, + {0x006d, 0xff00}, + {0x006e, 0x2808}, + {0x006f, 0x000a}, + {0x0070, 0x8000}, + {0x0071, 0x8000}, + {0x0072, 0x8000}, + {0x0073, 0x7000}, + {0x0074, 0x7770}, + {0x0075, 0x0002}, + {0x0076, 0x0001}, + {0x0078, 0x00f0}, + {0x0079, 0x0000}, + {0x007a, 0x0000}, + {0x007b, 0x0000}, + {0x007c, 0x0000}, + {0x007d, 0x0123}, + {0x007e, 0x4500}, + {0x007f, 0x8003}, + {0x0080, 0x0000}, + {0x0081, 0x0000}, + {0x0082, 0x0000}, + {0x0083, 0x0000}, + {0x0084, 0x0000}, + {0x0085, 0x0000}, + {0x0086, 0x0008}, + {0x0087, 0x0000}, + {0x0088, 0x0000}, + {0x0089, 0x0000}, + {0x008a, 0x0000}, + {0x008b, 0x0000}, + {0x008c, 0x0003}, + {0x008e, 0x0060}, + {0x008f, 0x1000}, + {0x0091, 0x0c26}, + {0x0092, 0x0073}, + {0x0093, 0x0000}, + {0x0094, 0x0080}, + {0x0098, 0x0000}, + {0x0099, 0x0000}, + {0x009a, 0x0007}, + {0x009f, 0x0000}, + {0x00a0, 0x0000}, + {0x00a1, 0x0002}, + {0x00a2, 0x0001}, + {0x00a3, 0x0002}, + {0x00a4, 0x0001}, + {0x00ae, 0x2040}, + {0x00af, 0x0000}, + {0x00b6, 0x0000}, + {0x00b7, 0x0000}, + {0x00b8, 0x0000}, + {0x00b9, 0x0000}, + {0x00ba, 0x0002}, + {0x00bb, 0x0000}, + {0x00be, 0x0000}, + {0x00c0, 0x0000}, + {0x00c1, 0x0aaa}, + {0x00c2, 0xaa80}, + {0x00c3, 0x0003}, + {0x00c4, 0x0000}, + {0x00d0, 0x0000}, + {0x00d1, 0x2244}, + {0x00d3, 0x3300}, + {0x00d4, 0x2200}, + {0x00d9, 0x0809}, + {0x00da, 0x0000}, + {0x00db, 0x0008}, + {0x00dc, 0x00c0}, + {0x00dd, 0x6724}, + {0x00de, 0x3131}, + {0x00df, 0x0008}, + {0x00e0, 0x4000}, + {0x00e1, 0x3131}, + {0x00e2, 0x600c}, + {0x00ea, 0xb320}, + {0x00eb, 0x0000}, + {0x00ec, 0xb300}, + {0x00ed, 0x0000}, + {0x00ee, 0xb320}, + {0x00ef, 0x0000}, + {0x00f0, 0x0201}, + {0x00f1, 0x0ddd}, + {0x00f2, 0x0ddd}, + {0x00f6, 0x0000}, + {0x00f7, 0x0000}, + {0x00f8, 0x0000}, + {0x00fa, 0x0000}, + {0x00fb, 0x0000}, + {0x00fc, 0x0000}, + {0x00fd, 0x0000}, + {0x00fe, 0x10ec}, + {0x00ff, 0x6451}, + {0x0100, 0xaaaa}, + {0x0101, 0x000a}, + {0x010a, 0xaaaa}, + {0x010b, 0xa0a0}, + {0x010c, 0xaeae}, + {0x010d, 0xaaaa}, + {0x010e, 0xaaaa}, + {0x010f, 0xaaaa}, + {0x0110, 0xe002}, + {0x0111, 0xa402}, + {0x0112, 0xaaaa}, + {0x0113, 0x2000}, + {0x0117, 0x0f00}, + {0x0125, 0x0410}, + {0x0132, 0x0000}, + {0x0133, 0x0000}, + {0x0137, 0x5540}, + {0x0138, 0x3700}, + {0x0139, 0x79a1}, + {0x013a, 0x2020}, + {0x013b, 0x2020}, + {0x013c, 0x2005}, + {0x013f, 0x0000}, + {0x0145, 0x0002}, + {0x0146, 0x0000}, + {0x0147, 0x0000}, + {0x0148, 0x0000}, + {0x0150, 0x0000}, + {0x0160, 0x4eff}, + {0x0161, 0x0080}, + {0x0162, 0x0200}, + {0x0163, 0x0800}, + {0x0164, 0x0000}, + {0x0165, 0x0000}, + {0x0166, 0x0000}, + {0x0167, 0x000f}, + {0x0170, 0x4e87}, + {0x0171, 0x0080}, + {0x0172, 0x0200}, + {0x0173, 0x0800}, + {0x0174, 0x00ff}, + {0x0175, 0x0000}, + {0x0190, 0x413d}, + {0x0191, 0x4139}, + {0x0192, 0x4135}, + {0x0193, 0x413d}, + {0x0194, 0x0000}, + {0x0195, 0x0000}, + {0x0196, 0x0000}, + {0x0197, 0x0000}, + {0x0198, 0x0000}, + {0x0199, 0x0000}, + {0x01a0, 0x1e64}, + {0x01a1, 0x06a3}, + {0x01a2, 0x0000}, + {0x01a3, 0x0000}, + {0x01a4, 0x0000}, + {0x01a5, 0x0000}, + {0x01a6, 0x0000}, + {0x01a7, 0x8000}, + {0x01a8, 0x0000}, + {0x01a9, 0x0000}, + {0x01aa, 0x0000}, + {0x01ab, 0x0000}, + {0x01b5, 0x0000}, + {0x01b6, 0x01c3}, + {0x01b7, 0x02a0}, + {0x01b8, 0x03e9}, + {0x01b9, 0x1389}, + {0x01ba, 0xc351}, + {0x01bb, 0x0009}, + {0x01bc, 0x0018}, + {0x01bd, 0x002a}, + {0x01be, 0x004c}, + {0x01bf, 0x0097}, + {0x01c0, 0x433d}, + {0x01c1, 0x0000}, + {0x01c2, 0x0000}, + {0x01c3, 0x0000}, + {0x01c4, 0x0000}, + {0x01c5, 0x0000}, + {0x01c6, 0x0000}, + {0x01c7, 0x0000}, + {0x01c8, 0x40af}, + {0x01c9, 0x0702}, + {0x01ca, 0x0000}, + {0x01cb, 0x0000}, + {0x01cc, 0x5757}, + {0x01cd, 0x5757}, + {0x01ce, 0x5757}, + {0x01cf, 0x5757}, + {0x01d0, 0x5757}, + {0x01d1, 0x5757}, + {0x01d2, 0x5757}, + {0x01d3, 0x5757}, + {0x01d4, 0x5757}, + {0x01d5, 0x5757}, + {0x01d6, 0x003c}, + {0x01da, 0x0000}, + {0x01db, 0x0000}, + {0x01dc, 0x0000}, + {0x01de, 0x7c00}, + {0x01df, 0x0320}, + {0x01e0, 0x06a1}, + {0x01e1, 0x0000}, + {0x01e2, 0x0000}, + {0x01e3, 0x0000}, + {0x01e4, 0x0000}, + {0x01e6, 0x0001}, + {0x01e7, 0x0000}, + {0x01e8, 0x0000}, + {0x01ea, 0xbf3f}, + {0x01eb, 0x0000}, + {0x01ec, 0x0000}, + {0x01ed, 0x0000}, + {0x01ee, 0x0000}, + {0x01ef, 0x0000}, + {0x01f0, 0x0000}, + {0x01f1, 0x0000}, + {0x01f2, 0x0000}, + {0x01f3, 0x0000}, + {0x01f4, 0x0000}, + {0x0200, 0x0000}, + {0x0201, 0x0000}, + {0x0202, 0x0000}, + {0x0203, 0x0000}, + {0x0204, 0x0000}, + {0x0205, 0x0000}, + {0x0206, 0x0000}, + {0x0207, 0x0000}, + {0x0208, 0x0000}, + {0x0210, 0x60b1}, + {0x0211, 0xa005}, + {0x0212, 0x024c}, + {0x0213, 0xf7ff}, + {0x0214, 0x024c}, + {0x0215, 0x0102}, + {0x0216, 0x00a3}, + {0x0217, 0x0048}, + {0x0218, 0xa2c0}, + {0x0219, 0x0400}, + {0x021a, 0x00c8}, + {0x021b, 0x00c0}, + {0x02ff, 0x0110}, + {0x0300, 0x001f}, + {0x0301, 0x032c}, + {0x0302, 0x5f21}, + {0x0303, 0x4000}, + {0x0304, 0x4000}, + {0x0305, 0x06d5}, + {0x0306, 0x8000}, + {0x0307, 0x0700}, + {0x0310, 0x4560}, + {0x0311, 0xa4a8}, + {0x0312, 0x7418}, + {0x0313, 0x0000}, + {0x0314, 0x0006}, + {0x0315, 0xffff}, + {0x0316, 0xc400}, + {0x0317, 0x0000}, + {0x0330, 0x00a6}, + {0x0331, 0x04c3}, + {0x0332, 0x27c8}, + {0x0333, 0xbf50}, + {0x0334, 0x0045}, + {0x0335, 0x0007}, + {0x0336, 0x7418}, + {0x0337, 0x0501}, + {0x0338, 0x0000}, + {0x0339, 0x0010}, + {0x033a, 0x1010}, + {0x03c0, 0x7e00}, + {0x03c1, 0x8000}, + {0x03c2, 0x8000}, + {0x03c3, 0x8000}, + {0x03c4, 0x8000}, + {0x03c5, 0x8000}, + {0x03c6, 0x8000}, + {0x03c7, 0x8000}, + {0x03c8, 0x8000}, + {0x03c9, 0x8000}, + {0x03ca, 0x8000}, + {0x03cb, 0x8000}, + {0x03cc, 0x8000}, + {0x03d0, 0x0000}, + {0x03d1, 0x0000}, + {0x03d2, 0x0000}, + {0x03d3, 0x0000}, + {0x03d4, 0x2000}, + {0x03d5, 0x2000}, + {0x03d6, 0x0000}, + {0x03d7, 0x0000}, + {0x03d8, 0x2000}, + {0x03d9, 0x2000}, + {0x03da, 0x2000}, + {0x03db, 0x2000}, + {0x03dc, 0x0000}, + {0x03dd, 0x0000}, + {0x03de, 0x0000}, + {0x03df, 0x2000}, + {0x03e0, 0x0000}, + {0x03e1, 0x0000}, + {0x03e2, 0x0000}, + {0x03e3, 0x0000}, + {0x03e4, 0x0000}, + {0x03e5, 0x0000}, + {0x03e6, 0x0000}, + {0x03e7, 0x0000}, + {0x03e8, 0x0000}, + {0x03e9, 0x0000}, + {0x03ea, 0x0000}, + {0x03eb, 0x0000}, + {0x03ec, 0x0000}, + {0x03ed, 0x0000}, + {0x03ee, 0x0000}, + {0x03ef, 0x0000}, + {0x03f0, 0x0800}, + {0x03f1, 0x0800}, + {0x03f2, 0x0800}, + {0x03f3, 0x0800}, +}; + +static bool rt5665_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5665_RESET: + case RT5665_EJD_CTRL_2: + case RT5665_GPIO_STA: + case RT5665_INT_ST_1: + case RT5665_IL_CMD_1: + case RT5665_4BTN_IL_CMD_1: + case RT5665_PSV_IL_CMD_1: + case RT5665_AJD1_CTRL: + case RT5665_JD_CTRL_3: + case RT5665_STO_NG2_CTRL_1: + case RT5665_SAR_IL_CMD_4: + case RT5665_DEVICE_ID: + case RT5665_STO1_DAC_SIL_DET ... RT5665_STO2_DAC_SIL_DET: + case RT5665_MONO_AMP_CALIB_STA1 ... RT5665_MONO_AMP_CALIB_STA6: + case RT5665_HP_IMP_SENS_CTRL_12 ... RT5665_HP_IMP_SENS_CTRL_15: + case RT5665_HP_CALIB_STA_1 ... RT5665_HP_CALIB_STA_11: + return true; + default: + return false; + } +} + +static bool rt5665_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case RT5665_RESET: + case RT5665_VENDOR_ID: + case RT5665_VENDOR_ID_1: + case RT5665_DEVICE_ID: + case RT5665_LOUT: + case RT5665_HP_CTRL_1: + case RT5665_HP_CTRL_2: + case RT5665_MONO_OUT: + case RT5665_HPL_GAIN: + case RT5665_HPR_GAIN: + case RT5665_MONO_GAIN: + case RT5665_CAL_BST_CTRL: + case RT5665_CBJ_BST_CTRL: + case RT5665_IN1_IN2: + case RT5665_IN3_IN4: + case RT5665_INL1_INR1_VOL: + case RT5665_EJD_CTRL_1: + case RT5665_EJD_CTRL_2: + case RT5665_EJD_CTRL_3: + case RT5665_EJD_CTRL_4: + case RT5665_EJD_CTRL_5: + case RT5665_EJD_CTRL_6: + case RT5665_EJD_CTRL_7: + case RT5665_DAC2_CTRL: + case RT5665_DAC2_DIG_VOL: + case RT5665_DAC1_DIG_VOL: + case RT5665_DAC3_DIG_VOL: + case RT5665_DAC3_CTRL: + case RT5665_STO1_ADC_DIG_VOL: + case RT5665_MONO_ADC_DIG_VOL: + case RT5665_STO2_ADC_DIG_VOL: + case RT5665_STO1_ADC_BOOST: + case RT5665_MONO_ADC_BOOST: + case RT5665_STO2_ADC_BOOST: + case RT5665_HP_IMP_GAIN_1: + case RT5665_HP_IMP_GAIN_2: + case RT5665_STO1_ADC_MIXER: + case RT5665_MONO_ADC_MIXER: + case RT5665_STO2_ADC_MIXER: + case RT5665_AD_DA_MIXER: + case RT5665_STO1_DAC_MIXER: + case RT5665_MONO_DAC_MIXER: + case RT5665_STO2_DAC_MIXER: + case RT5665_A_DAC1_MUX: + case RT5665_A_DAC2_MUX: + case RT5665_DIG_INF2_DATA: + case RT5665_DIG_INF3_DATA: + case RT5665_PDM_OUT_CTRL: + case RT5665_PDM_DATA_CTRL_1: + case RT5665_PDM_DATA_CTRL_2: + case RT5665_PDM_DATA_CTRL_3: + case RT5665_PDM_DATA_CTRL_4: + case RT5665_REC1_GAIN: + case RT5665_REC1_L1_MIXER: + case RT5665_REC1_L2_MIXER: + case RT5665_REC1_R1_MIXER: + case RT5665_REC1_R2_MIXER: + case RT5665_REC2_GAIN: + case RT5665_REC2_L1_MIXER: + case RT5665_REC2_L2_MIXER: + case RT5665_REC2_R1_MIXER: + case RT5665_REC2_R2_MIXER: + case RT5665_CAL_REC: + case RT5665_ALC_BACK_GAIN: + case RT5665_MONOMIX_GAIN: + case RT5665_MONOMIX_IN_GAIN: + case RT5665_OUT_L_GAIN: + case RT5665_OUT_L_MIXER: + case RT5665_OUT_R_GAIN: + case RT5665_OUT_R_MIXER: + case RT5665_LOUT_MIXER: + case RT5665_PWR_DIG_1: + case RT5665_PWR_DIG_2: + case RT5665_PWR_ANLG_1: + case RT5665_PWR_ANLG_2: + case RT5665_PWR_ANLG_3: + case RT5665_PWR_MIXER: + case RT5665_PWR_VOL: + case RT5665_CLK_DET: + case RT5665_HPF_CTRL1: + case RT5665_DMIC_CTRL_1: + case RT5665_DMIC_CTRL_2: + case RT5665_I2S1_SDP: + case RT5665_I2S2_SDP: + case RT5665_I2S3_SDP: + case RT5665_ADDA_CLK_1: + case RT5665_ADDA_CLK_2: + case RT5665_I2S1_F_DIV_CTRL_1: + case RT5665_I2S1_F_DIV_CTRL_2: + case RT5665_TDM_CTRL_1: + case RT5665_TDM_CTRL_2: + case RT5665_TDM_CTRL_3: + case RT5665_TDM_CTRL_4: + case RT5665_TDM_CTRL_5: + case RT5665_TDM_CTRL_6: + case RT5665_TDM_CTRL_7: + case RT5665_TDM_CTRL_8: + case RT5665_GLB_CLK: + case RT5665_PLL_CTRL_1: + case RT5665_PLL_CTRL_2: + case RT5665_ASRC_1: + case RT5665_ASRC_2: + case RT5665_ASRC_3: + case RT5665_ASRC_4: + case RT5665_ASRC_5: + case RT5665_ASRC_6: + case RT5665_ASRC_7: + case RT5665_ASRC_8: + case RT5665_ASRC_9: + case RT5665_ASRC_10: + case RT5665_DEPOP_1: + case RT5665_DEPOP_2: + case RT5665_HP_CHARGE_PUMP_1: + case RT5665_HP_CHARGE_PUMP_2: + case RT5665_MICBIAS_1: + case RT5665_MICBIAS_2: + case RT5665_ASRC_12: + case RT5665_ASRC_13: + case RT5665_ASRC_14: + case RT5665_RC_CLK_CTRL: + case RT5665_I2S_M_CLK_CTRL_1: + case RT5665_I2S2_F_DIV_CTRL_1: + case RT5665_I2S2_F_DIV_CTRL_2: + case RT5665_I2S3_F_DIV_CTRL_1: + case RT5665_I2S3_F_DIV_CTRL_2: + case RT5665_EQ_CTRL_1: + case RT5665_EQ_CTRL_2: + case RT5665_IRQ_CTRL_1: + case RT5665_IRQ_CTRL_2: + case RT5665_IRQ_CTRL_3: + case RT5665_IRQ_CTRL_4: + case RT5665_IRQ_CTRL_5: + case RT5665_IRQ_CTRL_6: + case RT5665_INT_ST_1: + case RT5665_GPIO_CTRL_1: + case RT5665_GPIO_CTRL_2: + case RT5665_GPIO_CTRL_3: + case RT5665_GPIO_CTRL_4: + case RT5665_GPIO_STA: + case RT5665_HP_AMP_DET_CTRL_1: + case RT5665_HP_AMP_DET_CTRL_2: + case RT5665_MID_HP_AMP_DET: + case RT5665_LOW_HP_AMP_DET: + case RT5665_SV_ZCD_1: + case RT5665_SV_ZCD_2: + case RT5665_IL_CMD_1: + case RT5665_IL_CMD_2: + case RT5665_IL_CMD_3: + case RT5665_IL_CMD_4: + case RT5665_4BTN_IL_CMD_1: + case RT5665_4BTN_IL_CMD_2: + case RT5665_4BTN_IL_CMD_3: + case RT5665_PSV_IL_CMD_1: + case RT5665_ADC_STO1_HP_CTRL_1: + case RT5665_ADC_STO1_HP_CTRL_2: + case RT5665_ADC_MONO_HP_CTRL_1: + case RT5665_ADC_MONO_HP_CTRL_2: + case RT5665_ADC_STO2_HP_CTRL_1: + case RT5665_ADC_STO2_HP_CTRL_2: + case RT5665_AJD1_CTRL: + case RT5665_JD1_THD: + case RT5665_JD2_THD: + case RT5665_JD_CTRL_1: + case RT5665_JD_CTRL_2: + case RT5665_JD_CTRL_3: + case RT5665_DIG_MISC: + case RT5665_DUMMY_2: + case RT5665_DUMMY_3: + case RT5665_DAC_ADC_DIG_VOL1: + case RT5665_DAC_ADC_DIG_VOL2: + case RT5665_BIAS_CUR_CTRL_1: + case RT5665_BIAS_CUR_CTRL_2: + case RT5665_BIAS_CUR_CTRL_3: + case RT5665_BIAS_CUR_CTRL_4: + case RT5665_BIAS_CUR_CTRL_5: + case RT5665_BIAS_CUR_CTRL_6: + case RT5665_BIAS_CUR_CTRL_7: + case RT5665_BIAS_CUR_CTRL_8: + case RT5665_BIAS_CUR_CTRL_9: + case RT5665_BIAS_CUR_CTRL_10: + case RT5665_VREF_REC_OP_FB_CAP_CTRL: + case RT5665_CHARGE_PUMP_1: + case RT5665_DIG_IN_CTRL_1: + case RT5665_DIG_IN_CTRL_2: + case RT5665_PAD_DRIVING_CTRL: + case RT5665_SOFT_RAMP_DEPOP: + case RT5665_PLL: + case RT5665_CHOP_DAC: + case RT5665_CHOP_ADC: + case RT5665_CALIB_ADC_CTRL: + case RT5665_VOL_TEST: + case RT5665_TEST_MODE_CTRL_1: + case RT5665_TEST_MODE_CTRL_2: + case RT5665_TEST_MODE_CTRL_3: + case RT5665_TEST_MODE_CTRL_4: + case RT5665_BASSBACK_CTRL: + case RT5665_STO_NG2_CTRL_1: + case RT5665_STO_NG2_CTRL_2: + case RT5665_STO_NG2_CTRL_3: + case RT5665_STO_NG2_CTRL_4: + case RT5665_STO_NG2_CTRL_5: + case RT5665_STO_NG2_CTRL_6: + case RT5665_STO_NG2_CTRL_7: + case RT5665_STO_NG2_CTRL_8: + case RT5665_MONO_NG2_CTRL_1: + case RT5665_MONO_NG2_CTRL_2: + case RT5665_MONO_NG2_CTRL_3: + case RT5665_MONO_NG2_CTRL_4: + case RT5665_MONO_NG2_CTRL_5: + case RT5665_MONO_NG2_CTRL_6: + case RT5665_STO1_DAC_SIL_DET: + case RT5665_MONOL_DAC_SIL_DET: + case RT5665_MONOR_DAC_SIL_DET: + case RT5665_STO2_DAC_SIL_DET: + case RT5665_SIL_PSV_CTRL1: + case RT5665_SIL_PSV_CTRL2: + case RT5665_SIL_PSV_CTRL3: + case RT5665_SIL_PSV_CTRL4: + case RT5665_SIL_PSV_CTRL5: + case RT5665_SIL_PSV_CTRL6: + case RT5665_MONO_AMP_CALIB_CTRL_1: + case RT5665_MONO_AMP_CALIB_CTRL_2: + case RT5665_MONO_AMP_CALIB_CTRL_3: + case RT5665_MONO_AMP_CALIB_CTRL_4: + case RT5665_MONO_AMP_CALIB_CTRL_5: + case RT5665_MONO_AMP_CALIB_CTRL_6: + case RT5665_MONO_AMP_CALIB_CTRL_7: + case RT5665_MONO_AMP_CALIB_STA1: + case RT5665_MONO_AMP_CALIB_STA2: + case RT5665_MONO_AMP_CALIB_STA3: + case RT5665_MONO_AMP_CALIB_STA4: + case RT5665_MONO_AMP_CALIB_STA6: + case RT5665_HP_IMP_SENS_CTRL_01: + case RT5665_HP_IMP_SENS_CTRL_02: + case RT5665_HP_IMP_SENS_CTRL_03: + case RT5665_HP_IMP_SENS_CTRL_04: + case RT5665_HP_IMP_SENS_CTRL_05: + case RT5665_HP_IMP_SENS_CTRL_06: + case RT5665_HP_IMP_SENS_CTRL_07: + case RT5665_HP_IMP_SENS_CTRL_08: + case RT5665_HP_IMP_SENS_CTRL_09: + case RT5665_HP_IMP_SENS_CTRL_10: + case RT5665_HP_IMP_SENS_CTRL_11: + case RT5665_HP_IMP_SENS_CTRL_12: + case RT5665_HP_IMP_SENS_CTRL_13: + case RT5665_HP_IMP_SENS_CTRL_14: + case RT5665_HP_IMP_SENS_CTRL_15: + case RT5665_HP_IMP_SENS_CTRL_16: + case RT5665_HP_IMP_SENS_CTRL_17: + case RT5665_HP_IMP_SENS_CTRL_18: + case RT5665_HP_IMP_SENS_CTRL_19: + case RT5665_HP_IMP_SENS_CTRL_20: + case RT5665_HP_IMP_SENS_CTRL_21: + case RT5665_HP_IMP_SENS_CTRL_22: + case RT5665_HP_IMP_SENS_CTRL_23: + case RT5665_HP_IMP_SENS_CTRL_24: + case RT5665_HP_IMP_SENS_CTRL_25: + case RT5665_HP_IMP_SENS_CTRL_26: + case RT5665_HP_IMP_SENS_CTRL_27: + case RT5665_HP_IMP_SENS_CTRL_28: + case RT5665_HP_IMP_SENS_CTRL_29: + case RT5665_HP_IMP_SENS_CTRL_30: + case RT5665_HP_IMP_SENS_CTRL_31: + case RT5665_HP_IMP_SENS_CTRL_32: + case RT5665_HP_IMP_SENS_CTRL_33: + case RT5665_HP_IMP_SENS_CTRL_34: + case RT5665_HP_LOGIC_CTRL_1: + case RT5665_HP_LOGIC_CTRL_2: + case RT5665_HP_LOGIC_CTRL_3: + case RT5665_HP_CALIB_CTRL_1: + case RT5665_HP_CALIB_CTRL_2: + case RT5665_HP_CALIB_CTRL_3: + case RT5665_HP_CALIB_CTRL_4: + case RT5665_HP_CALIB_CTRL_5: + case RT5665_HP_CALIB_CTRL_6: + case RT5665_HP_CALIB_CTRL_7: + case RT5665_HP_CALIB_CTRL_9: + case RT5665_HP_CALIB_CTRL_10: + case RT5665_HP_CALIB_CTRL_11: + case RT5665_HP_CALIB_STA_1: + case RT5665_HP_CALIB_STA_2: + case RT5665_HP_CALIB_STA_3: + case RT5665_HP_CALIB_STA_4: + case RT5665_HP_CALIB_STA_5: + case RT5665_HP_CALIB_STA_6: + case RT5665_HP_CALIB_STA_7: + case RT5665_HP_CALIB_STA_8: + case RT5665_HP_CALIB_STA_9: + case RT5665_HP_CALIB_STA_10: + case RT5665_HP_CALIB_STA_11: + case RT5665_PGM_TAB_CTRL1: + case RT5665_PGM_TAB_CTRL2: + case RT5665_PGM_TAB_CTRL3: + case RT5665_PGM_TAB_CTRL4: + case RT5665_PGM_TAB_CTRL5: + case RT5665_PGM_TAB_CTRL6: + case RT5665_PGM_TAB_CTRL7: + case RT5665_PGM_TAB_CTRL8: + case RT5665_PGM_TAB_CTRL9: + case RT5665_SAR_IL_CMD_1: + case RT5665_SAR_IL_CMD_2: + case RT5665_SAR_IL_CMD_3: + case RT5665_SAR_IL_CMD_4: + case RT5665_SAR_IL_CMD_5: + case RT5665_SAR_IL_CMD_6: + case RT5665_SAR_IL_CMD_7: + case RT5665_SAR_IL_CMD_8: + case RT5665_SAR_IL_CMD_9: + case RT5665_SAR_IL_CMD_10: + case RT5665_SAR_IL_CMD_11: + case RT5665_SAR_IL_CMD_12: + case RT5665_DRC1_CTRL_0: + case RT5665_DRC1_CTRL_1: + case RT5665_DRC1_CTRL_2: + case RT5665_DRC1_CTRL_3: + case RT5665_DRC1_CTRL_4: + case RT5665_DRC1_CTRL_5: + case RT5665_DRC1_CTRL_6: + case RT5665_DRC1_HARD_LMT_CTRL_1: + case RT5665_DRC1_HARD_LMT_CTRL_2: + case RT5665_DRC1_PRIV_1: + case RT5665_DRC1_PRIV_2: + case RT5665_DRC1_PRIV_3: + case RT5665_DRC1_PRIV_4: + case RT5665_DRC1_PRIV_5: + case RT5665_DRC1_PRIV_6: + case RT5665_DRC1_PRIV_7: + case RT5665_DRC1_PRIV_8: + case RT5665_ALC_PGA_CTRL_1: + case RT5665_ALC_PGA_CTRL_2: + case RT5665_ALC_PGA_CTRL_3: + case RT5665_ALC_PGA_CTRL_4: + case RT5665_ALC_PGA_CTRL_5: + case RT5665_ALC_PGA_CTRL_6: + case RT5665_ALC_PGA_CTRL_7: + case RT5665_ALC_PGA_CTRL_8: + case RT5665_ALC_PGA_STA_1: + case RT5665_ALC_PGA_STA_2: + case RT5665_ALC_PGA_STA_3: + case RT5665_EQ_AUTO_RCV_CTRL1: + case RT5665_EQ_AUTO_RCV_CTRL2: + case RT5665_EQ_AUTO_RCV_CTRL3: + case RT5665_EQ_AUTO_RCV_CTRL4: + case RT5665_EQ_AUTO_RCV_CTRL5: + case RT5665_EQ_AUTO_RCV_CTRL6: + case RT5665_EQ_AUTO_RCV_CTRL7: + case RT5665_EQ_AUTO_RCV_CTRL8: + case RT5665_EQ_AUTO_RCV_CTRL9: + case RT5665_EQ_AUTO_RCV_CTRL10: + case RT5665_EQ_AUTO_RCV_CTRL11: + case RT5665_EQ_AUTO_RCV_CTRL12: + case RT5665_EQ_AUTO_RCV_CTRL13: + case RT5665_ADC_L_EQ_LPF1_A1: + case RT5665_R_EQ_LPF1_A1: + case RT5665_L_EQ_LPF1_H0: + case RT5665_R_EQ_LPF1_H0: + case RT5665_L_EQ_BPF1_A1: + case RT5665_R_EQ_BPF1_A1: + case RT5665_L_EQ_BPF1_A2: + case RT5665_R_EQ_BPF1_A2: + case RT5665_L_EQ_BPF1_H0: + case RT5665_R_EQ_BPF1_H0: + case RT5665_L_EQ_BPF2_A1: + case RT5665_R_EQ_BPF2_A1: + case RT5665_L_EQ_BPF2_A2: + case RT5665_R_EQ_BPF2_A2: + case RT5665_L_EQ_BPF2_H0: + case RT5665_R_EQ_BPF2_H0: + case RT5665_L_EQ_BPF3_A1: + case RT5665_R_EQ_BPF3_A1: + case RT5665_L_EQ_BPF3_A2: + case RT5665_R_EQ_BPF3_A2: + case RT5665_L_EQ_BPF3_H0: + case RT5665_R_EQ_BPF3_H0: + case RT5665_L_EQ_BPF4_A1: + case RT5665_R_EQ_BPF4_A1: + case RT5665_L_EQ_BPF4_A2: + case RT5665_R_EQ_BPF4_A2: + case RT5665_L_EQ_BPF4_H0: + case RT5665_R_EQ_BPF4_H0: + case RT5665_L_EQ_HPF1_A1: + case RT5665_R_EQ_HPF1_A1: + case RT5665_L_EQ_HPF1_H0: + case RT5665_R_EQ_HPF1_H0: + case RT5665_L_EQ_PRE_VOL: + case RT5665_R_EQ_PRE_VOL: + case RT5665_L_EQ_POST_VOL: + case RT5665_R_EQ_POST_VOL: + case RT5665_SCAN_MODE_CTRL: + case RT5665_I2C_MODE: + return true; + default: + return false; + } +} + +static const DECLARE_TLV_DB_SCALE(hp_vol_tlv, -2250, 150, 0); +static const DECLARE_TLV_DB_SCALE(mono_vol_tlv, -1400, 150, 0); +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); +static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); +static const DECLARE_TLV_DB_SCALE(in_bst_tlv, -1200, 75, 0); + +/* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ +static const DECLARE_TLV_DB_RANGE(bst_tlv, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0) +); + +/* Interface data select */ +static const char * const rt5665_data_select[] = { + "L/R", "R/L", "L/L", "R/R" +}; + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_01_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT01_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_23_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT23_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_45_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT45_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_1_67_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_1_DS_ADC_SLOT67_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_01_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT01_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_23_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT23_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_45_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT45_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if1_2_67_adc_enum, + RT5665_TDM_CTRL_2, RT5665_I2S1_2_DS_ADC_SLOT67_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_dac_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_1_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_1_adc_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_1_ADC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_dac_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_2_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if2_2_adc_enum, + RT5665_DIG_INF2_DATA, RT5665_IF2_2_ADC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if3_dac_enum, + RT5665_DIG_INF3_DATA, RT5665_IF3_DAC_SEL_SFT, rt5665_data_select); + +static const SOC_ENUM_SINGLE_DECL(rt5665_if3_adc_enum, + RT5665_DIG_INF3_DATA, RT5665_IF3_ADC_SEL_SFT, rt5665_data_select); + +static const struct snd_kcontrol_new rt5665_if1_1_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 01 ADC Swap Mux", rt5665_if1_1_01_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 23 ADC Swap Mux", rt5665_if1_1_23_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 45 ADC Swap Mux", rt5665_if1_1_45_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_1_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1_1 67 ADC Swap Mux", rt5665_if1_1_67_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_01_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 01 ADC Swap Mux", rt5665_if1_2_01_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_23_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 23 ADC1 Swap Mux", rt5665_if1_2_23_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_45_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 45 ADC1 Swap Mux", rt5665_if1_2_45_adc_enum); + +static const struct snd_kcontrol_new rt5665_if1_2_67_adc_swap_mux = + SOC_DAPM_ENUM("IF1_2 67 ADC1 Swap Mux", rt5665_if1_2_67_adc_enum); + +static const struct snd_kcontrol_new rt5665_if2_1_dac_swap_mux = + SOC_DAPM_ENUM("IF2_1 DAC Swap Source", rt5665_if2_1_dac_enum); + +static const struct snd_kcontrol_new rt5665_if2_1_adc_swap_mux = + SOC_DAPM_ENUM("IF2_1 ADC Swap Source", rt5665_if2_1_adc_enum); + +static const struct snd_kcontrol_new rt5665_if2_2_dac_swap_mux = + SOC_DAPM_ENUM("IF2_2 DAC Swap Source", rt5665_if2_2_dac_enum); + +static const struct snd_kcontrol_new rt5665_if2_2_adc_swap_mux = + SOC_DAPM_ENUM("IF2_2 ADC Swap Source", rt5665_if2_2_adc_enum); + +static const struct snd_kcontrol_new rt5665_if3_dac_swap_mux = + SOC_DAPM_ENUM("IF3 DAC Swap Source", rt5665_if3_dac_enum); + +static const struct snd_kcontrol_new rt5665_if3_adc_swap_mux = + SOC_DAPM_ENUM("IF3 ADC Swap Source", rt5665_if3_adc_enum); + +static int rt5665_hp_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (snd_soc_read(codec, RT5665_STO_NG2_CTRL_1) & RT5665_NG2_EN) { + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + } + + return ret; +} + +static int rt5665_mono_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + int ret = snd_soc_put_volsw(kcontrol, ucontrol); + + if (snd_soc_read(codec, RT5665_MONO_NG2_CTRL_1) & RT5665_NG2_EN) { + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + } + + return ret; +} + +/** + * rt5665_sel_asrc_clk_src - select ASRC clock source for a set of filters + * @codec: SoC audio codec device. + * @filter_mask: mask of filters. + * @clk_src: clock source + * + * The ASRC function is for asynchronous MCLK and LRCK. Also, since RT5665 can + * only support standard 32fs or 64fs i2s format, ASRC should be enabled to + * support special i2s clock format such as Intel's 100fs(100 * sampling rate). + * ASRC function will track i2s clock and generate a corresponding system clock + * for codec. This function provides an API to select the clock source for a + * set of filters specified by the mask. And the codec driver will turn on ASRC + * for these filters if ASRC is selected as their clock source. + */ +int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src) +{ + unsigned int asrc2_mask = 0; + unsigned int asrc2_value = 0; + unsigned int asrc3_mask = 0; + unsigned int asrc3_value = 0; + + switch (clk_src) { + case RT5665_CLK_SEL_SYS: + case RT5665_CLK_SEL_I2S1_ASRC: + case RT5665_CLK_SEL_I2S2_ASRC: + case RT5665_CLK_SEL_I2S3_ASRC: + case RT5665_CLK_SEL_SYS2: + case RT5665_CLK_SEL_SYS3: + case RT5665_CLK_SEL_SYS4: + break; + + default: + return -EINVAL; + } + + if (filter_mask & RT5665_DA_STEREO1_FILTER) { + asrc2_mask |= RT5665_DA_STO1_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_STO1_CLK_SEL_MASK) + | (clk_src << RT5665_DA_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_DA_STEREO2_FILTER) { + asrc2_mask |= RT5665_DA_STO2_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_STO2_CLK_SEL_MASK) + | (clk_src << RT5665_DA_STO2_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_DA_MONO_L_FILTER) { + asrc2_mask |= RT5665_DA_MONOL_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_MONOL_CLK_SEL_MASK) + | (clk_src << RT5665_DA_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_DA_MONO_R_FILTER) { + asrc2_mask |= RT5665_DA_MONOR_CLK_SEL_MASK; + asrc2_value = (asrc2_value & ~RT5665_DA_MONOR_CLK_SEL_MASK) + | (clk_src << RT5665_DA_MONOR_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_STEREO1_FILTER) { + asrc3_mask |= RT5665_AD_STO1_CLK_SEL_MASK; + asrc3_value = (asrc2_value & ~RT5665_AD_STO1_CLK_SEL_MASK) + | (clk_src << RT5665_AD_STO1_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_STEREO2_FILTER) { + asrc3_mask |= RT5665_AD_STO2_CLK_SEL_MASK; + asrc3_value = (asrc2_value & ~RT5665_AD_STO2_CLK_SEL_MASK) + | (clk_src << RT5665_AD_STO2_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_MONO_L_FILTER) { + asrc3_mask |= RT5665_AD_MONOL_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5665_AD_MONOL_CLK_SEL_MASK) + | (clk_src << RT5665_AD_MONOL_CLK_SEL_SFT); + } + + if (filter_mask & RT5665_AD_MONO_R_FILTER) { + asrc3_mask |= RT5665_AD_MONOR_CLK_SEL_MASK; + asrc3_value = (asrc3_value & ~RT5665_AD_MONOR_CLK_SEL_MASK) + | (clk_src << RT5665_AD_MONOR_CLK_SEL_SFT); + } + + if (asrc2_mask) + snd_soc_update_bits(codec, RT5665_ASRC_2, + asrc2_mask, asrc2_value); + + if (asrc3_mask) + snd_soc_update_bits(codec, RT5665_ASRC_3, + asrc3_mask, asrc3_value); + + return 0; +} +EXPORT_SYMBOL_GPL(rt5665_sel_asrc_clk_src); + +static int rt5665_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5665_4BTN_IL_CMD_1); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, val); + + return btn_type; +} + +static void rt5665_enable_push_button_irq(struct snd_soc_codec *codec, + bool enable) +{ + if (enable) { + snd_soc_write(codec, RT5665_4BTN_IL_CMD_1, 0x000b); + snd_soc_write(codec, RT5665_IL_CMD_1, 0x0048); + snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, + RT5665_4BTN_IL_MASK | RT5665_4BTN_IL_RST_MASK, + RT5665_4BTN_IL_EN | RT5665_4BTN_IL_NOR); + snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3, + RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_EN); + } else { + snd_soc_update_bits(codec, RT5665_IRQ_CTRL_3, + RT5665_IL_IRQ_MASK, RT5665_IL_IRQ_DIS); + snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, + RT5665_4BTN_IL_MASK, RT5665_4BTN_IL_DIS); + snd_soc_update_bits(codec, RT5665_4BTN_IL_CMD_2, + RT5665_4BTN_IL_RST_MASK, RT5665_4BTN_IL_RST); + } +} + +/** + * rt5665_headset_detect - Detect headset. + * @codec: SoC audio codec device. + * @jack_insert: Jack insert or not. + * + * Detect whether is headset or not when jack inserted. + * + * Returns detect status. + */ +static int rt5665_headset_detect(struct snd_soc_codec *codec, int jack_insert) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + unsigned int sar_hs_type, val; + + if (jack_insert) { + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_sync(dapm); + + regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, + 0x100); + + regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val); + if (val & 0x4) { + regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, + 0x100, 0); + + regmap_read(rt5665->regmap, RT5665_GPIO_STA, &val); + while (val & 0x4) { + usleep_range(10000, 15000); + regmap_read(rt5665->regmap, RT5665_GPIO_STA, + &val); + } + } + + regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, + 0x180, 0x180); + regmap_write(rt5665->regmap, RT5665_EJD_CTRL_3, 0x3424); + regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0xa291); + + rt5665->sar_adc_value = snd_soc_read(rt5665->codec, + RT5665_SAR_IL_CMD_4) & 0x7ff; + + sar_hs_type = rt5665->pdata.sar_hs_type ? + rt5665->pdata.sar_hs_type : 729; + + if (rt5665->sar_adc_value > sar_hs_type) { + rt5665->jack_type = SND_JACK_HEADSET; + rt5665_enable_push_button_irq(codec, true); + } else { + rt5665->jack_type = SND_JACK_HEADPHONE; + regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, + 0x2291); + regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, + 0x100, 0); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_sync(dapm); + } + } else { + regmap_write(rt5665->regmap, RT5665_SAR_IL_CMD_1, 0x2291); + regmap_update_bits(rt5665->regmap, RT5665_MICBIAS_2, 0x100, 0); + snd_soc_dapm_disable_pin(dapm, "MICBIAS1"); + snd_soc_dapm_sync(dapm); + if (rt5665->jack_type == SND_JACK_HEADSET) + rt5665_enable_push_button_irq(codec, false); + rt5665->jack_type = 0; + } + + dev_dbg(codec->dev, "jack_type = %d\n", rt5665->jack_type); + return rt5665->jack_type; +} + +static irqreturn_t rt5665_irq(int irq, void *data) +{ + struct rt5665_priv *rt5665 = data; + + mod_delayed_work(system_power_efficient_wq, + &rt5665->jack_detect_work, msecs_to_jiffies(250)); + + return IRQ_HANDLED; +} + +static void rt5665_jd_check_handler(struct work_struct *work) +{ + struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv, + calibrate_work.work); + + if (snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010) { + /* jack out */ + rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0); + + snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + } else { + schedule_delayed_work(&rt5665->jd_check_work, 500); + } +} + +int rt5665_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + switch (rt5665->pdata.jd_src) { + case RT5665_JD1: + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP1_PIN_MASK, RT5665_GP1_PIN_IRQ); + regmap_update_bits(rt5665->regmap, RT5665_RC_CLK_CTRL, + 0xc000, 0xc000); + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_2, + RT5665_PWR_JD1, RT5665_PWR_JD1); + regmap_update_bits(rt5665->regmap, RT5665_IRQ_CTRL_1, 0x8, 0x8); + break; + + case RT5665_JD_NULL: + break; + + default: + dev_warn(codec->dev, "Wrong JD source\n"); + break; + } + + rt5665->hs_jack = hs_jack; + + return 0; +} +EXPORT_SYMBOL_GPL(rt5665_set_jack_detect); + +static void rt5665_jack_detect_handler(struct work_struct *work) +{ + struct rt5665_priv *rt5665 = + container_of(work, struct rt5665_priv, jack_detect_work.work); + int val, btn_type; + + while (!rt5665->codec) { + pr_debug("%s codec = null\n", __func__); + usleep_range(10000, 15000); + } + + while (!rt5665->codec->component.card->instantiated) { + pr_debug("%s\n", __func__); + usleep_range(10000, 15000); + } + + mutex_lock(&rt5665->calibrate_mutex); + + val = snd_soc_read(rt5665->codec, RT5665_AJD1_CTRL) & 0x0010; + if (!val) { + /* jack in */ + if (rt5665->jack_type == 0) { + /* jack was out, report jack type */ + rt5665->jack_type = + rt5665_headset_detect(rt5665->codec, 1); + } else { + /* jack is already in, report button event */ + rt5665->jack_type = SND_JACK_HEADSET; + btn_type = rt5665_button_detect(rt5665->codec); + /** + * rt5665 can report three kinds of button behavior, + * one click, double click and hold. However, + * currently we will report button pressed/released + * event. So all the three button behaviors are + * treated as button pressed. + */ + switch (btn_type) { + case 0x8000: + case 0x4000: + case 0x2000: + rt5665->jack_type |= SND_JACK_BTN_0; + break; + case 0x1000: + case 0x0800: + case 0x0400: + rt5665->jack_type |= SND_JACK_BTN_1; + break; + case 0x0200: + case 0x0100: + case 0x0080: + rt5665->jack_type |= SND_JACK_BTN_2; + break; + case 0x0040: + case 0x0020: + case 0x0010: + rt5665->jack_type |= SND_JACK_BTN_3; + break; + case 0x0000: /* unpressed */ + break; + default: + btn_type = 0; + dev_err(rt5665->codec->dev, + "Unexpected button code 0x%04x\n", + btn_type); + break; + } + } + } else { + /* jack out */ + rt5665->jack_type = rt5665_headset_detect(rt5665->codec, 0); + } + + snd_soc_jack_report(rt5665->hs_jack, rt5665->jack_type, + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3); + + if (rt5665->jack_type & (SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3)) + schedule_delayed_work(&rt5665->jd_check_work, 0); + else + cancel_delayed_work_sync(&rt5665->jd_check_work); + + mutex_unlock(&rt5665->calibrate_mutex); +} + +static const struct snd_kcontrol_new rt5665_snd_controls[] = { + /* Headphone Output Volume */ + SOC_DOUBLE_R_EXT_TLV("Headphone Playback Volume", RT5665_HPL_GAIN, + RT5665_HPR_GAIN, RT5665_G_HP_SFT, 15, 1, snd_soc_get_volsw, + rt5665_hp_vol_put, hp_vol_tlv), + + /* Mono Output Volume */ + SOC_SINGLE_EXT_TLV("Mono Playback Volume", RT5665_MONO_GAIN, + RT5665_L_VOL_SFT, 15, 1, snd_soc_get_volsw, + rt5665_mono_vol_put, mono_vol_tlv), + + /* Output Volume */ + SOC_DOUBLE_TLV("OUT Playback Volume", RT5665_LOUT, RT5665_L_VOL_SFT, + RT5665_R_VOL_SFT, 39, 1, out_vol_tlv), + + /* DAC Digital Volume */ + SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5665_DAC1_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5665_DAC2_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 175, 0, dac_vol_tlv), + SOC_DOUBLE("DAC2 Playback Switch", RT5665_DAC2_CTRL, + RT5665_M_DAC2_L_VOL_SFT, RT5665_M_DAC2_R_VOL_SFT, 1, 1), + + /* IN1/IN2/IN3/IN4 Volume */ + SOC_SINGLE_TLV("IN1 Boost Volume", RT5665_IN1_IN2, + RT5665_BST1_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN2 Boost Volume", RT5665_IN1_IN2, + RT5665_BST2_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN3 Boost Volume", RT5665_IN3_IN4, + RT5665_BST3_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("IN4 Boost Volume", RT5665_IN3_IN4, + RT5665_BST4_SFT, 69, 0, in_bst_tlv), + SOC_SINGLE_TLV("CBJ Boost Volume", RT5665_CBJ_BST_CTRL, + RT5665_BST_CBJ_SFT, 8, 0, bst_tlv), + + /* INL/INR Volume Control */ + SOC_DOUBLE_TLV("IN Capture Volume", RT5665_INL1_INR1_VOL, + RT5665_INL_VOL_SFT, RT5665_INR_VOL_SFT, 31, 1, in_vol_tlv), + + /* ADC Digital Volume Control */ + SOC_DOUBLE("STO1 ADC Capture Switch", RT5665_STO1_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO1 ADC Capture Volume", RT5665_STO1_ADC_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("Mono ADC Capture Switch", RT5665_MONO_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5665_MONO_ADC_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + SOC_DOUBLE("STO2 ADC Capture Switch", RT5665_STO2_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, RT5665_R_MUTE_SFT, 1, 1), + SOC_DOUBLE_TLV("STO2 ADC Capture Volume", RT5665_STO2_ADC_DIG_VOL, + RT5665_L_VOL_SFT, RT5665_R_VOL_SFT, 127, 0, adc_vol_tlv), + + /* ADC Boost Volume Control */ + SOC_DOUBLE_TLV("STO1 ADC Boost Gain Volume", RT5665_STO1_ADC_BOOST, + RT5665_STO1_ADC_L_BST_SFT, RT5665_STO1_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("Mono ADC Boost Gain Volume", RT5665_MONO_ADC_BOOST, + RT5665_MONO_ADC_L_BST_SFT, RT5665_MONO_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), + + SOC_DOUBLE_TLV("STO2 ADC Boost Gain Volume", RT5665_STO2_ADC_BOOST, + RT5665_STO2_ADC_L_BST_SFT, RT5665_STO2_ADC_R_BST_SFT, + 3, 0, adc_bst_tlv), +}; + +/** + * set_dmic_clk - Set parameter of dmic. + * + * @w: DAPM widget. + * @kcontrol: The kcontrol of this widget. + * @event: Event id. + * + * Choose dmic clock between 1MHz and 3MHz. + * It is better for clock to approximate 3MHz. + */ +static int set_dmic_clk(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + int pd, idx = -EINVAL; + + pd = rl6231_get_pre_div(rt5665->regmap, + RT5665_ADDA_CLK_1, RT5665_I2S_PD1_SFT); + idx = rl6231_calc_dmic_clk(rt5665->sysclk / pd); + + if (idx < 0) + dev_err(codec->dev, "Failed to set DMIC clock\n"); + else { + snd_soc_update_bits(codec, RT5665_DMIC_CTRL_1, + RT5665_DMIC_CLK_MASK, idx << RT5665_DMIC_CLK_SFT); + } + return idx; +} + +static int rt5665_charge_pump_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1, + RT5665_PM_HP_MASK | RT5665_OSW_L_MASK, + RT5665_PM_HP_HV | RT5665_OSW_L_EN); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5665_HP_CHARGE_PUMP_1, + RT5665_PM_HP_MASK | RT5665_OSW_L_MASK, + RT5665_PM_HP_LV | RT5665_OSW_L_DIS); + break; + default: + return 0; + } + + return 0; +} + +static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + val = snd_soc_read(codec, RT5665_GLB_CLK); + val &= RT5665_SCLK_SRC_MASK; + if (val == RT5665_SCLK_SRC_PLL1) + return 1; + else + return 0; +} + +static int is_using_asrc(struct snd_soc_dapm_widget *w, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, shift, val; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (w->shift) { + case RT5665_ADC_MONO_R_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_MONOR_CLK_SEL_SFT; + break; + case RT5665_ADC_MONO_L_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_MONOL_CLK_SEL_SFT; + break; + case RT5665_ADC_STO1_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_STO1_CLK_SEL_SFT; + break; + case RT5665_ADC_STO2_ASRC_SFT: + reg = RT5665_ASRC_3; + shift = RT5665_AD_STO2_CLK_SEL_SFT; + break; + case RT5665_DAC_MONO_R_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_MONOR_CLK_SEL_SFT; + break; + case RT5665_DAC_MONO_L_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_MONOL_CLK_SEL_SFT; + break; + case RT5665_DAC_STO1_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_STO1_CLK_SEL_SFT; + break; + case RT5665_DAC_STO2_ASRC_SFT: + reg = RT5665_ASRC_2; + shift = RT5665_DA_STO2_CLK_SEL_SFT; + break; + default: + return 0; + } + + val = (snd_soc_read(codec, reg) >> shift) & 0xf; + switch (val) { + case RT5665_CLK_SEL_I2S1_ASRC: + case RT5665_CLK_SEL_I2S2_ASRC: + case RT5665_CLK_SEL_I2S3_ASRC: + /* I2S_Pre_Div1 should be 1 in asrc mode */ + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_I2S_PD1_MASK, RT5665_I2S_PD1_2); + return 1; + default: + return 0; + } + +} + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt5665_sto1_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO1_ADC_MIXER, + RT5665_M_STO1_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_STO2_ADC_MIXER, + RT5665_M_STO2_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_adc_l_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_L1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_L2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_adc_r_mix[] = { + SOC_DAPM_SINGLE("ADC1 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_R1_SFT, 1, 1), + SOC_DAPM_SINGLE("ADC2 Switch", RT5665_MONO_ADC_MIXER, + RT5665_M_MONO_ADC_R2_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_dac_l_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER, + RT5665_M_ADCMIX_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER, + RT5665_M_DAC1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_dac_r_mix[] = { + SOC_DAPM_SINGLE("Stereo ADC Switch", RT5665_AD_DA_MIXER, + RT5665_M_ADCMIX_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC1 Switch", RT5665_AD_DA_MIXER, + RT5665_M_DAC1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R1_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L2_STO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R2_STO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto1_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R1_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_L2_STO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO1_DAC_MIXER, + RT5665_M_DAC_R2_STO_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_L1_STO2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_L2_STO2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L3 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_L3_STO2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_sto2_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_R1_STO2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_R2_STO2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R3 Switch", RT5665_STO2_DAC_MIXER, + RT5665_M_DAC_R3_STO2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_dac_l_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R1_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L2_MONO_L_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R2_MONO_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_dac_r_mix[] = { + SOC_DAPM_SINGLE("DAC L1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R1 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R1_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_L2_MONO_R_SFT, 1, 1), + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_MONO_DAC_MIXER, + RT5665_M_DAC_R2_MONO_R_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt5665_rec1_l_mix[] = { + SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC1_L2_MIXER, + RT5665_M_CBJ_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5665_REC1_L2_MIXER, + RT5665_M_INL_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_L2_MIXER, + RT5665_M_INR_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST4_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST3_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST2_RM1_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_L2_MIXER, + RT5665_M_BST1_RM1_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec1_r_mix[] = { + SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC1_R2_MIXER, + RT5665_M_AEC_REF_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC1_R2_MIXER, + RT5665_M_INR_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST4_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST3_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST2_RM1_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC1_R2_MIXER, + RT5665_M_BST1_RM1_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec2_l_mix[] = { + SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_L2_MIXER, + RT5665_M_INL_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_L2_MIXER, + RT5665_M_INR_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("CBJ Switch", RT5665_REC2_L2_MIXER, + RT5665_M_CBJ_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST4_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST3_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST2_RM2_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_L2_MIXER, + RT5665_M_BST1_RM2_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_rec2_r_mix[] = { + SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_REC2_R2_MIXER, + RT5665_M_MONOVOL_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5665_REC2_R2_MIXER, + RT5665_M_INL_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_REC2_R2_MIXER, + RT5665_M_INR_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST4_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST3_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST2_RM2_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_REC2_R2_MIXER, + RT5665_M_BST1_RM2_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_monovol_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_DAC_L2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIX2L Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_RECMIC2L_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_BST1_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_BST2_MM_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_BST3_MM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_out_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_OUT_L_MIXER, + RT5665_M_DAC_L2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("INL Switch", RT5665_OUT_L_MIXER, + RT5665_M_IN_L_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST1 Switch", RT5665_OUT_L_MIXER, + RT5665_M_BST1_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_L_MIXER, + RT5665_M_BST2_OM_L_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_L_MIXER, + RT5665_M_BST3_OM_L_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_out_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_OUT_R_MIXER, + RT5665_M_DAC_R2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("INR Switch", RT5665_OUT_R_MIXER, + RT5665_M_IN_R_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST2 Switch", RT5665_OUT_R_MIXER, + RT5665_M_BST2_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST3 Switch", RT5665_OUT_R_MIXER, + RT5665_M_BST3_OM_R_SFT, 1, 1), + SOC_DAPM_SINGLE("BST4 Switch", RT5665_OUT_R_MIXER, + RT5665_M_BST4_OM_R_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_mono_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_DAC_L2_MA_SFT, 1, 1), + SOC_DAPM_SINGLE("MONOVOL Switch", RT5665_MONOMIX_IN_GAIN, + RT5665_M_MONOVOL_MA_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_lout_l_mix[] = { + SOC_DAPM_SINGLE("DAC L2 Switch", RT5665_LOUT_MIXER, + RT5665_M_DAC_L2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL L Switch", RT5665_LOUT_MIXER, + RT5665_M_OV_L_LM_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5665_lout_r_mix[] = { + SOC_DAPM_SINGLE("DAC R2 Switch", RT5665_LOUT_MIXER, + RT5665_M_DAC_R2_LM_SFT, 1, 1), + SOC_DAPM_SINGLE("OUTVOL R Switch", RT5665_LOUT_MIXER, + RT5665_M_OV_R_LM_SFT, 1, 1), +}; + +/*DAC L2, DAC R2*/ +/*MX-17 [6:4], MX-17 [2:0]*/ +static const char * const rt5665_dac2_src[] = { + "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "Mono ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_l2_enum, RT5665_DAC2_CTRL, + RT5665_DAC_L2_SEL_SFT, rt5665_dac2_src); + +static const struct snd_kcontrol_new rt5665_dac_l2_mux = + SOC_DAPM_ENUM("Digital DAC L2 Source", rt5665_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_r2_enum, RT5665_DAC2_CTRL, + RT5665_DAC_R2_SEL_SFT, rt5665_dac2_src); + +static const struct snd_kcontrol_new rt5665_dac_r2_mux = + SOC_DAPM_ENUM("Digital DAC R2 Source", rt5665_dac_r2_enum); + +/*DAC L3, DAC R3*/ +/*MX-1B [6:4], MX-1B [2:0]*/ +static const char * const rt5665_dac3_src[] = { + "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC", "STO2 ADC MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_l3_enum, RT5665_DAC3_CTRL, + RT5665_DAC_L3_SEL_SFT, rt5665_dac3_src); + +static const struct snd_kcontrol_new rt5665_dac_l3_mux = + SOC_DAPM_ENUM("Digital DAC L3 Source", rt5665_dac_l3_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_r3_enum, RT5665_DAC3_CTRL, + RT5665_DAC_R3_SEL_SFT, rt5665_dac3_src); + +static const struct snd_kcontrol_new rt5665_dac_r3_mux = + SOC_DAPM_ENUM("Digital DAC R3 Source", rt5665_dac_r3_enum); + +/* STO1 ADC1 Source */ +/* MX-26 [13] [5] */ +static const char * const rt5665_sto1_adc1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc1l_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC1L_SRC_SFT, rt5665_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc1l_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc1r_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC1R_SRC_SFT, rt5665_sto1_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc1r_mux = + SOC_DAPM_ENUM("Stereo1 ADC1L Source", rt5665_sto1_adc1r_enum); + +/* STO1 ADC Source */ +/* MX-26 [11:10] [3:2] */ +static const char * const rt5665_sto1_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adcl_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADCL_SRC_SFT, rt5665_sto1_adc_src); + +static const struct snd_kcontrol_new rt5665_sto1_adcl_mux = + SOC_DAPM_ENUM("Stereo1 ADCL Source", rt5665_sto1_adcl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adcr_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADCR_SRC_SFT, rt5665_sto1_adc_src); + +static const struct snd_kcontrol_new rt5665_sto1_adcr_mux = + SOC_DAPM_ENUM("Stereo1 ADCR Source", rt5665_sto1_adcr_enum); + +/* STO1 ADC2 Source */ +/* MX-26 [12] [4] */ +static const char * const rt5665_sto1_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc2l_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC2L_SRC_SFT, rt5665_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc2l_mux = + SOC_DAPM_ENUM("Stereo1 ADC2L Source", rt5665_sto1_adc2l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_adc2r_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_ADC2R_SRC_SFT, rt5665_sto1_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto1_adc2r_mux = + SOC_DAPM_ENUM("Stereo1 ADC2R Source", rt5665_sto1_adc2r_enum); + +/* STO1 DMIC Source */ +/* MX-26 [8] */ +static const char * const rt5665_sto1_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_dmic_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_DMIC_SRC_SFT, rt5665_sto1_dmic_src); + +static const struct snd_kcontrol_new rt5665_sto1_dmic_mux = + SOC_DAPM_ENUM("Stereo1 DMIC Mux", rt5665_sto1_dmic_enum); + +/* MX-26 [9] */ +static const char * const rt5665_sto1_dd_l_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_dd_l_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_DD_L_SRC_SFT, rt5665_sto1_dd_l_src); + +static const struct snd_kcontrol_new rt5665_sto1_dd_l_mux = + SOC_DAPM_ENUM("Stereo1 DD L Source", rt5665_sto1_dd_l_enum); + +/* MX-26 [1:0] */ +static const char * const rt5665_sto1_dd_r_src[] = { + "STO2 DAC", "MONO DAC", "AEC REF" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto1_dd_r_enum, RT5665_STO1_ADC_MIXER, + RT5665_STO1_DD_R_SRC_SFT, rt5665_sto1_dd_r_src); + +static const struct snd_kcontrol_new rt5665_sto1_dd_r_mux = + SOC_DAPM_ENUM("Stereo1 DD R Source", rt5665_sto1_dd_r_enum); + +/* MONO ADC L2 Source */ +/* MX-27 [12] */ +static const char * const rt5665_mono_adc_l2_src[] = { + "DAC MIXL", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_l2_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_L2_SRC_SFT, rt5665_mono_adc_l2_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l2_mux = + SOC_DAPM_ENUM("Mono ADC L2 Source", rt5665_mono_adc_l2_enum); + + +/* MONO ADC L1 Source */ +/* MX-27 [13] */ +static const char * const rt5665_mono_adc_l1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_l1_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_L1_SRC_SFT, rt5665_mono_adc_l1_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l1_mux = + SOC_DAPM_ENUM("Mono ADC L1 Source", rt5665_mono_adc_l1_enum); + +/* MX-27 [9][1]*/ +static const char * const rt5665_mono_dd_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dd_l_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DD_L_SRC_SFT, rt5665_mono_dd_src); + +static const struct snd_kcontrol_new rt5665_mono_dd_l_mux = + SOC_DAPM_ENUM("Mono DD L Source", rt5665_mono_dd_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dd_r_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DD_R_SRC_SFT, rt5665_mono_dd_src); + +static const struct snd_kcontrol_new rt5665_mono_dd_r_mux = + SOC_DAPM_ENUM("Mono DD R Source", rt5665_mono_dd_r_enum); + +/* MONO ADC L Source, MONO ADC R Source*/ +/* MX-27 [11:10], MX-27 [3:2] */ +static const char * const rt5665_mono_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L", "ADC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_l_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_L_SRC_SFT, rt5665_mono_adc_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_l_mux = + SOC_DAPM_ENUM("Mono ADC L Source", rt5665_mono_adc_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adcr_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_R_SRC_SFT, rt5665_mono_adc_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r_mux = + SOC_DAPM_ENUM("Mono ADC R Source", rt5665_mono_adcr_enum); + +/* MONO DMIC L Source */ +/* MX-27 [8] */ +static const char * const rt5665_mono_dmic_l_src[] = { + "DMIC1 L", "DMIC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dmic_l_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DMIC_L_SRC_SFT, rt5665_mono_dmic_l_src); + +static const struct snd_kcontrol_new rt5665_mono_dmic_l_mux = + SOC_DAPM_ENUM("Mono DMIC L Source", rt5665_mono_dmic_l_enum); + +/* MONO ADC R2 Source */ +/* MX-27 [4] */ +static const char * const rt5665_mono_adc_r2_src[] = { + "DAC MIXR", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_r2_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_R2_SRC_SFT, rt5665_mono_adc_r2_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r2_mux = + SOC_DAPM_ENUM("Mono ADC R2 Source", rt5665_mono_adc_r2_enum); + +/* MONO ADC R1 Source */ +/* MX-27 [5] */ +static const char * const rt5665_mono_adc_r1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_adc_r1_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_ADC_R1_SRC_SFT, rt5665_mono_adc_r1_src); + +static const struct snd_kcontrol_new rt5665_mono_adc_r1_mux = + SOC_DAPM_ENUM("Mono ADC R1 Source", rt5665_mono_adc_r1_enum); + +/* MONO DMIC R Source */ +/* MX-27 [0] */ +static const char * const rt5665_mono_dmic_r_src[] = { + "DMIC1 R", "DMIC2 R" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_mono_dmic_r_enum, RT5665_MONO_ADC_MIXER, + RT5665_MONO_DMIC_R_SRC_SFT, rt5665_mono_dmic_r_src); + +static const struct snd_kcontrol_new rt5665_mono_dmic_r_mux = + SOC_DAPM_ENUM("Mono DMIC R Source", rt5665_mono_dmic_r_enum); + + +/* STO2 ADC1 Source */ +/* MX-28 [13] [5] */ +static const char * const rt5665_sto2_adc1_src[] = { + "DD Mux", "ADC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc1l_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC1L_SRC_SFT, rt5665_sto2_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc1l_mux = + SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc1r_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC1R_SRC_SFT, rt5665_sto2_adc1_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc1r_mux = + SOC_DAPM_ENUM("Stereo2 ADC1L Source", rt5665_sto2_adc1r_enum); + +/* STO2 ADC Source */ +/* MX-28 [11:10] [3:2] */ +static const char * const rt5665_sto2_adc_src[] = { + "ADC1 L", "ADC1 R", "ADC2 L" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adcl_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADCL_SRC_SFT, rt5665_sto2_adc_src); + +static const struct snd_kcontrol_new rt5665_sto2_adcl_mux = + SOC_DAPM_ENUM("Stereo2 ADCL Source", rt5665_sto2_adcl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adcr_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADCR_SRC_SFT, rt5665_sto2_adc_src); + +static const struct snd_kcontrol_new rt5665_sto2_adcr_mux = + SOC_DAPM_ENUM("Stereo2 ADCR Source", rt5665_sto2_adcr_enum); + +/* STO2 ADC2 Source */ +/* MX-28 [12] [4] */ +static const char * const rt5665_sto2_adc2_src[] = { + "DAC MIX", "DMIC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc2l_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC2L_SRC_SFT, rt5665_sto2_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc2l_mux = + SOC_DAPM_ENUM("Stereo2 ADC2L Source", rt5665_sto2_adc2l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_adc2r_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_ADC2R_SRC_SFT, rt5665_sto2_adc2_src); + +static const struct snd_kcontrol_new rt5665_sto2_adc2r_mux = + SOC_DAPM_ENUM("Stereo2 ADC2R Source", rt5665_sto2_adc2r_enum); + +/* STO2 DMIC Source */ +/* MX-28 [8] */ +static const char * const rt5665_sto2_dmic_src[] = { + "DMIC1", "DMIC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_dmic_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_DMIC_SRC_SFT, rt5665_sto2_dmic_src); + +static const struct snd_kcontrol_new rt5665_sto2_dmic_mux = + SOC_DAPM_ENUM("Stereo2 DMIC Source", rt5665_sto2_dmic_enum); + +/* MX-28 [9] */ +static const char * const rt5665_sto2_dd_l_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_dd_l_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_DD_L_SRC_SFT, rt5665_sto2_dd_l_src); + +static const struct snd_kcontrol_new rt5665_sto2_dd_l_mux = + SOC_DAPM_ENUM("Stereo2 DD L Source", rt5665_sto2_dd_l_enum); + +/* MX-28 [1] */ +static const char * const rt5665_sto2_dd_r_src[] = { + "STO2 DAC", "MONO DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_sto2_dd_r_enum, RT5665_STO2_ADC_MIXER, + RT5665_STO2_DD_R_SRC_SFT, rt5665_sto2_dd_r_src); + +static const struct snd_kcontrol_new rt5665_sto2_dd_r_mux = + SOC_DAPM_ENUM("Stereo2 DD R Source", rt5665_sto2_dd_r_enum); + +/* DAC R1 Source, DAC L1 Source*/ +/* MX-29 [11:10], MX-29 [9:8]*/ +static const char * const rt5665_dac1_src[] = { + "IF1 DAC1", "IF2_1 DAC", "IF2_2 DAC", "IF3 DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_r1_enum, RT5665_AD_DA_MIXER, + RT5665_DAC1_R_SEL_SFT, rt5665_dac1_src); + +static const struct snd_kcontrol_new rt5665_dac_r1_mux = + SOC_DAPM_ENUM("DAC R1 Source", rt5665_dac_r1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dac_l1_enum, RT5665_AD_DA_MIXER, + RT5665_DAC1_L_SEL_SFT, rt5665_dac1_src); + +static const struct snd_kcontrol_new rt5665_dac_l1_mux = + SOC_DAPM_ENUM("DAC L1 Source", rt5665_dac_l1_enum); + +/* DAC Digital Mixer L Source, DAC Digital Mixer R Source*/ +/* MX-2D [13:12], MX-2D [9:8]*/ +static const char * const rt5665_dig_dac_mix_src[] = { + "Stereo1 DAC Mixer", "Stereo2 DAC Mixer", "Mono DAC Mixer" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dig_dac_mixl_enum, RT5665_A_DAC1_MUX, + RT5665_DAC_MIX_L_SFT, rt5665_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5665_dig_dac_mixl_mux = + SOC_DAPM_ENUM("DAC Digital Mixer L Source", rt5665_dig_dac_mixl_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_dig_dac_mixr_enum, RT5665_A_DAC1_MUX, + RT5665_DAC_MIX_R_SFT, rt5665_dig_dac_mix_src); + +static const struct snd_kcontrol_new rt5665_dig_dac_mixr_mux = + SOC_DAPM_ENUM("DAC Digital Mixer R Source", rt5665_dig_dac_mixr_enum); + +/* Analog DAC L1 Source, Analog DAC R1 Source*/ +/* MX-2D [5:4], MX-2D [1:0]*/ +static const char * const rt5665_alg_dac1_src[] = { + "Stereo1 DAC Mixer", "DAC1", "DMIC1" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_l1_enum, RT5665_A_DAC1_MUX, + RT5665_A_DACL1_SFT, rt5665_alg_dac1_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_l1_mux = + SOC_DAPM_ENUM("Analog DAC L1 Source", rt5665_alg_dac_l1_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_r1_enum, RT5665_A_DAC1_MUX, + RT5665_A_DACR1_SFT, rt5665_alg_dac1_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_r1_mux = + SOC_DAPM_ENUM("Analog DAC R1 Source", rt5665_alg_dac_r1_enum); + +/* Analog DAC LR Source, Analog DAC R2 Source*/ +/* MX-2E [5:4], MX-2E [0]*/ +static const char * const rt5665_alg_dac2_src[] = { + "Mono DAC Mixer", "DAC2" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_l2_enum, RT5665_A_DAC2_MUX, + RT5665_A_DACL2_SFT, rt5665_alg_dac2_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_l2_mux = + SOC_DAPM_ENUM("Analog DAC L2 Source", rt5665_alg_dac_l2_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_alg_dac_r2_enum, RT5665_A_DAC2_MUX, + RT5665_A_DACR2_SFT, rt5665_alg_dac2_src); + +static const struct snd_kcontrol_new rt5665_alg_dac_r2_mux = + SOC_DAPM_ENUM("Analog DAC R2 Source", rt5665_alg_dac_r2_enum); + +/* Interface2 ADC Data Input*/ +/* MX-2F [14:12] */ +static const char * const rt5665_if2_1_adc_in_src[] = { + "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", + "IF1 DAC2", "IF2_2 DAC", "IF3 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if2_1_adc_in_enum, RT5665_DIG_INF2_DATA, + RT5665_IF3_ADC_IN_SFT, rt5665_if2_1_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if2_1_adc_in_mux = + SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_1_adc_in_enum); + +/* MX-2F [6:4] */ +static const char * const rt5665_if2_2_adc_in_src[] = { + "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", + "IF1 DAC2", "IF2_1 DAC", "IF3 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if2_2_adc_in_enum, RT5665_DIG_INF2_DATA, + RT5665_IF2_2_ADC_IN_SFT, rt5665_if2_2_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if2_2_adc_in_mux = + SOC_DAPM_ENUM("IF2_1 ADC IN Source", rt5665_if2_2_adc_in_enum); + +/* Interface3 ADC Data Input*/ +/* MX-30 [6:4] */ +static const char * const rt5665_if3_adc_in_src[] = { + "STO1 ADC", "STO2 ADC", "MONO ADC", "IF1 DAC1", + "IF1 DAC2", "IF2_1 DAC", "IF2_2 DAC", "DAC1 MIX" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if3_adc_in_enum, RT5665_DIG_INF3_DATA, + RT5665_IF3_ADC_IN_SFT, rt5665_if3_adc_in_src); + +static const struct snd_kcontrol_new rt5665_if3_adc_in_mux = + SOC_DAPM_ENUM("IF3 ADC IN Source", rt5665_if3_adc_in_enum); + +/* PDM 1 L/R*/ +/* MX-31 [11:10] [9:8] */ +static const char * const rt5665_pdm_src[] = { + "Stereo1 DAC", "Stereo2 DAC", "Mono DAC" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_pdm_l_enum, RT5665_PDM_OUT_CTRL, + RT5665_PDM1_L_SFT, rt5665_pdm_src); + +static const struct snd_kcontrol_new rt5665_pdm_l_mux = + SOC_DAPM_ENUM("PDM L Source", rt5665_pdm_l_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_pdm_r_enum, RT5665_PDM_OUT_CTRL, + RT5665_PDM1_R_SFT, rt5665_pdm_src); + +static const struct snd_kcontrol_new rt5665_pdm_r_mux = + SOC_DAPM_ENUM("PDM R Source", rt5665_pdm_r_enum); + + +/* I2S1 TDM ADCDAT Source */ +/* MX-7a[10] */ +static const char * const rt5665_if1_1_adc1_data_src[] = { + "STO1 ADC", "IF2_1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_1_adc1_data_enum, RT5665_TDM_CTRL_3, + RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_1_adc1_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc1_mux = + SOC_DAPM_ENUM("IF1_1 ADC1 Source", rt5665_if1_1_adc1_data_enum); + +/* MX-7a[9] */ +static const char * const rt5665_if1_1_adc2_data_src[] = { + "STO2 ADC", "IF2_2 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_1_adc2_data_enum, RT5665_TDM_CTRL_3, + RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_1_adc2_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc2_mux = + SOC_DAPM_ENUM("IF1_1 ADC2 Source", rt5665_if1_1_adc2_data_enum); + +/* MX-7a[8] */ +static const char * const rt5665_if1_1_adc3_data_src[] = { + "MONO ADC", "IF3 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_1_adc3_data_enum, RT5665_TDM_CTRL_3, + RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_1_adc3_data_src); + +static const struct snd_kcontrol_new rt5665_if1_1_adc3_mux = + SOC_DAPM_ENUM("IF1_1 ADC3 Source", rt5665_if1_1_adc3_data_enum); + +/* MX-7b[10] */ +static const char * const rt5665_if1_2_adc1_data_src[] = { + "STO1 ADC", "IF1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc1_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC1_SEL_SFT, rt5665_if1_2_adc1_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc1_mux = + SOC_DAPM_ENUM("IF1_2 ADC1 Source", rt5665_if1_2_adc1_data_enum); + +/* MX-7b[9] */ +static const char * const rt5665_if1_2_adc2_data_src[] = { + "STO2 ADC", "IF2_1 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc2_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC2_SEL_SFT, rt5665_if1_2_adc2_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc2_mux = + SOC_DAPM_ENUM("IF1_2 ADC2 Source", rt5665_if1_2_adc2_data_enum); + +/* MX-7b[8] */ +static const char * const rt5665_if1_2_adc3_data_src[] = { + "MONO ADC", "IF2_2 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc3_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC3_SEL_SFT, rt5665_if1_2_adc3_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc3_mux = + SOC_DAPM_ENUM("IF1_2 ADC3 Source", rt5665_if1_2_adc3_data_enum); + +/* MX-7b[7] */ +static const char * const rt5665_if1_2_adc4_data_src[] = { + "DAC1", "IF3 DAC", +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_if1_2_adc4_data_enum, RT5665_TDM_CTRL_4, + RT5665_IF1_ADC4_SEL_SFT, rt5665_if1_2_adc4_data_src); + +static const struct snd_kcontrol_new rt5665_if1_2_adc4_mux = + SOC_DAPM_ENUM("IF1_2 ADC4 Source", rt5665_if1_2_adc4_data_enum); + +/* MX-7a[4:0] MX-7b[4:0] */ +static const char * const rt5665_tdm_adc_data_src[] = { + "1234", "1243", "1324", "1342", "1432", "1423", + "2134", "2143", "2314", "2341", "2431", "2413", + "3124", "3142", "3214", "3241", "3412", "3421", + "4123", "4132", "4213", "4231", "4312", "4321" +}; + +static const SOC_ENUM_SINGLE_DECL( + rt5665_tdm1_adc_data_enum, RT5665_TDM_CTRL_3, + RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); + +static const struct snd_kcontrol_new rt5665_tdm1_adc_mux = + SOC_DAPM_ENUM("TDM1 ADC Mux", rt5665_tdm1_adc_data_enum); + +static const SOC_ENUM_SINGLE_DECL( + rt5665_tdm2_adc_data_enum, RT5665_TDM_CTRL_4, + RT5665_TDM_ADC_SEL_SFT, rt5665_tdm_adc_data_src); + +static const struct snd_kcontrol_new rt5665_tdm2_adc_mux = + SOC_DAPM_ENUM("TDM2 ADCDAT Source", rt5665_tdm2_adc_data_enum); + +/* Out Volume Switch */ +static const struct snd_kcontrol_new monovol_switch = + SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_l_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_L_SFT, 1, 1); + +static const struct snd_kcontrol_new outvol_r_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_VOL_R_SFT, 1, 1); + +/* Out Switch */ +static const struct snd_kcontrol_new mono_switch = + SOC_DAPM_SINGLE("Switch", RT5665_MONO_OUT, RT5665_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpo_switch = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT5665_HP_CTRL_2, + RT5665_VOL_L_SFT, 1, 0); + +static const struct snd_kcontrol_new lout_l_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_L_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new lout_r_switch = + SOC_DAPM_SINGLE("Switch", RT5665_LOUT, RT5665_R_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_l_switch = + SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL, + RT5665_M_PDM1_L_SFT, 1, 1); + +static const struct snd_kcontrol_new pdm_r_switch = + SOC_DAPM_SINGLE("Switch", RT5665_PDM_OUT_CTRL, + RT5665_M_PDM1_R_SFT, 1, 1); + +static int rt5665_mono_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40, + 0x0); + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0x10); + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0x20); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x20, 0); + snd_soc_update_bits(codec, RT5665_MONO_OUT, 0x10, 0); + snd_soc_update_bits(codec, RT5665_MONO_AMP_CALIB_CTRL_1, 0x40, + 0x40); + snd_soc_update_bits(codec, RT5665_MONO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5665_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_EN); + snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0003); + break; + + case SND_SOC_DAPM_POST_PMD: + snd_soc_write(codec, RT5665_HP_LOGIC_CTRL_2, 0x0002); + snd_soc_update_bits(codec, RT5665_STO_NG2_CTRL_1, + RT5665_NG2_EN_MASK, RT5665_NG2_DIS); + break; + + default: + return 0; + } + + return 0; + +} + +static int rt5665_lout_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, RT5665_DEPOP_1, + RT5665_PUMP_EN, RT5665_PUMP_EN); + break; + + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, RT5665_DEPOP_1, + RT5665_PUMP_EN, 0); + break; + + default: + return 0; + } + + return 0; + +} + +static int set_dmic_power(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + switch (event) { + case SND_SOC_DAPM_POST_PMU: + /*Add delay to avoid pop noise*/ + msleep(150); + break; + + default: + return 0; + } + + return 0; +} + +static int rt5655_set_verf(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + switch (w->shift) { + case RT5665_PWR_VREF1_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV1, 0); + break; + + case RT5665_PWR_VREF2_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV2, 0); + break; + + case RT5665_PWR_VREF3_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV3, 0); + break; + + default: + break; + } + break; + + case SND_SOC_DAPM_POST_PMU: + usleep_range(15000, 20000); + switch (w->shift) { + case RT5665_PWR_VREF1_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV1, RT5665_PWR_FV1); + break; + + case RT5665_PWR_VREF2_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV2, RT5665_PWR_FV2); + break; + + case RT5665_PWR_VREF3_BIT: + snd_soc_update_bits(codec, RT5665_PWR_ANLG_1, + RT5665_PWR_FV3, RT5665_PWR_FV3); + break; + + default: + break; + } + break; + + default: + return 0; + } + + return 0; +} + + +static const struct snd_soc_dapm_widget rt5665_dapm_widgets[] = { + SND_SOC_DAPM_SUPPLY("LDO2", RT5665_PWR_ANLG_3, RT5665_PWR_LDO2_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("PLL", RT5665_PWR_ANLG_3, RT5665_PWR_PLL_BIT, 0, + NULL, 0), + SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5665_PWR_VOL, + RT5665_PWR_MIC_DET_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Vref1", RT5665_PWR_ANLG_1, RT5665_PWR_VREF1_BIT, 0, + rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("Vref2", RT5665_PWR_ANLG_1, RT5665_PWR_VREF2_BIT, 0, + rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("Vref3", RT5665_PWR_ANLG_1, RT5665_PWR_VREF3_BIT, 0, + rt5655_set_verf, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), + + /* ASRC */ + SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5665_ASRC_1, + RT5665_I2S1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5665_ASRC_1, + RT5665_I2S2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("I2S3 ASRC", 1, RT5665_ASRC_1, + RT5665_I2S3_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO1 ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC STO2 ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_STO2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono L ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC Mono R ASRC", 1, RT5665_ASRC_1, + RT5665_DAC_MONO_R_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono L ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("ADC Mono R ASRC", 1, RT5665_ASRC_1, + RT5665_ADC_MONO_R_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_STO1_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_STO2_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_MONO_L_ASRC_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5665_ASRC_1, + RT5665_DMIC_MONO_R_ASRC_SFT, 0, NULL, 0), + + /* Input Side */ + SND_SOC_DAPM_SUPPLY("MICBIAS1", RT5665_PWR_ANLG_2, RT5665_PWR_MB1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS2", RT5665_PWR_ANLG_2, RT5665_PWR_MB2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MICBIAS3", RT5665_PWR_ANLG_2, RT5665_PWR_MB3_BIT, + 0, NULL, 0), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC L1"), + SND_SOC_DAPM_INPUT("DMIC R1"), + SND_SOC_DAPM_INPUT("DMIC L2"), + SND_SOC_DAPM_INPUT("DMIC R2"), + + SND_SOC_DAPM_INPUT("IN1P"), + SND_SOC_DAPM_INPUT("IN1N"), + SND_SOC_DAPM_INPUT("IN2P"), + SND_SOC_DAPM_INPUT("IN2N"), + SND_SOC_DAPM_INPUT("IN3P"), + SND_SOC_DAPM_INPUT("IN3N"), + SND_SOC_DAPM_INPUT("IN4P"), + SND_SOC_DAPM_INPUT("IN4N"), + + SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, + set_dmic_clk, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY("DMIC1 Power", RT5665_DMIC_CTRL_1, + RT5665_DMIC_1_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SUPPLY("DMIC2 Power", RT5665_DMIC_CTRL_1, + RT5665_DMIC_2_EN_SFT, 0, set_dmic_power, SND_SOC_DAPM_POST_PMU), + + /* Boost */ + SND_SOC_DAPM_PGA("BST1", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST2", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST3", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST4", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("BST1 CBJ", SND_SOC_NOPM, + 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST1 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST3 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST3_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST4 Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST4_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST1P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST1_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST2P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST2_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST3P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST3_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("BST4P Power", RT5665_PWR_ANLG_2, + RT5665_PWR_BST4_P_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CBJ Power", RT5665_PWR_ANLG_3, + RT5665_PWR_CBJ_BIT, 0, NULL, 0), + + + /* Input Volume */ + SND_SOC_DAPM_PGA("INL VOL", RT5665_PWR_VOL, RT5665_PWR_IN_L_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("INR VOL", RT5665_PWR_VOL, RT5665_PWR_IN_R_BIT, + 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX1L", SND_SOC_NOPM, 0, 0, rt5665_rec1_l_mix, + ARRAY_SIZE(rt5665_rec1_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX1R", SND_SOC_NOPM, 0, 0, rt5665_rec1_r_mix, + ARRAY_SIZE(rt5665_rec1_r_mix)), + SND_SOC_DAPM_MIXER("RECMIX2L", SND_SOC_NOPM, 0, 0, rt5665_rec2_l_mix, + ARRAY_SIZE(rt5665_rec2_l_mix)), + SND_SOC_DAPM_MIXER("RECMIX2R", SND_SOC_NOPM, 0, 0, rt5665_rec2_r_mix, + ARRAY_SIZE(rt5665_rec2_r_mix)), + SND_SOC_DAPM_SUPPLY("RECMIX1L Power", RT5665_PWR_ANLG_2, + RT5665_PWR_RM1_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX1R Power", RT5665_PWR_ANLG_2, + RT5665_PWR_RM1_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX2L Power", RT5665_PWR_MIXER, + RT5665_PWR_RM2_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("RECMIX2R Power", RT5665_PWR_MIXER, + RT5665_PWR_RM2_R_BIT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC1 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC1 R", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 L", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC2 R", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("ADC1 L Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_L1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 R Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_R1_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 L Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 R Power", RT5665_PWR_DIG_1, + RT5665_PWR_ADC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC1 clock", RT5665_CHOP_ADC, + RT5665_CKGEN_ADC1_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC2 clock", RT5665_CHOP_ADC, + RT5665_CKGEN_ADC2_SFT, 0, NULL, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX("Stereo1 DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dmic_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc1l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc1r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc2l_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adc2r_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adcl_mux), + SND_SOC_DAPM_MUX("Stereo1 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_adcr_mux), + SND_SOC_DAPM_MUX("Stereo1 DD L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dd_l_mux), + SND_SOC_DAPM_MUX("Stereo1 DD R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto1_dd_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_l2_mux), + SND_SOC_DAPM_MUX("Mono ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_r2_mux), + SND_SOC_DAPM_MUX("Mono ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_l1_mux), + SND_SOC_DAPM_MUX("Mono ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_r1_mux), + SND_SOC_DAPM_MUX("Mono DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dmic_l_mux), + SND_SOC_DAPM_MUX("Mono DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dmic_r_mux), + SND_SOC_DAPM_MUX("Mono ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_l_mux), + SND_SOC_DAPM_MUX("Mono ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_adc_r_mux), + SND_SOC_DAPM_MUX("Mono DD L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dd_l_mux), + SND_SOC_DAPM_MUX("Mono DD R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_mono_dd_r_mux), + SND_SOC_DAPM_MUX("Stereo2 DMIC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dmic_mux), + SND_SOC_DAPM_MUX("Stereo2 DMIC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dmic_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc1l_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc1r_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc2l_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adc2r_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adcl_mux), + SND_SOC_DAPM_MUX("Stereo2 ADC R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_adcr_mux), + SND_SOC_DAPM_MUX("Stereo2 DD L Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dd_l_mux), + SND_SOC_DAPM_MUX("Stereo2 DD R Mux", SND_SOC_NOPM, 0, 0, + &rt5665_sto2_dd_r_mux), + /* ADC Mixer */ + SND_SOC_DAPM_SUPPLY("ADC Stereo1 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("ADC Stereo2 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXL", RT5665_STO1_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, 1, rt5665_sto1_adc_l_mix, + ARRAY_SIZE(rt5665_sto1_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 ADC MIXR", RT5665_STO1_ADC_DIG_VOL, + RT5665_R_MUTE_SFT, 1, rt5665_sto1_adc_r_mix, + ARRAY_SIZE(rt5665_sto1_adc_r_mix)), + SND_SOC_DAPM_MIXER("Stereo2 ADC MIXL", RT5665_STO2_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, 1, rt5665_sto2_adc_l_mix, + ARRAY_SIZE(rt5665_sto2_adc_l_mix)), + SND_SOC_DAPM_MIXER("Stereo2 ADC MIXR", RT5665_STO2_ADC_DIG_VOL, + RT5665_R_MUTE_SFT, 1, rt5665_sto2_adc_r_mix, + ARRAY_SIZE(rt5665_sto2_adc_r_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Left Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXL", RT5665_MONO_ADC_DIG_VOL, + RT5665_L_MUTE_SFT, 1, rt5665_mono_adc_l_mix, + ARRAY_SIZE(rt5665_mono_adc_l_mix)), + SND_SOC_DAPM_SUPPLY("ADC Mono Right Filter", RT5665_PWR_DIG_2, + RT5665_PWR_ADC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Mono ADC MIXR", RT5665_MONO_ADC_DIG_VOL, + RT5665_R_MUTE_SFT, 1, rt5665_mono_adc_r_mix, + ARRAY_SIZE(rt5665_mono_adc_r_mix)), + + /* ADC PGA */ + SND_SOC_DAPM_PGA("Stereo1 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Stereo2 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface */ + SND_SOC_DAPM_SUPPLY("I2S1_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S1_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S1_2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2_1", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_1_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S2_2", RT5665_PWR_DIG_1, RT5665_PWR_I2S2_2_BIT, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("I2S3", RT5665_PWR_DIG_1, RT5665_PWR_I2S3_BIT, + 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC1 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC2 R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC3 L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF1 DAC3 R", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("IF2_1 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_1 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_1 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF2_2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_PGA("IF3 DAC", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC L", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 DAC R", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA("IF3 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* Digital Interface Select */ + SND_SOC_DAPM_MUX("IF1_1_ADC1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_adc1_mux), + SND_SOC_DAPM_MUX("IF1_1_ADC2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_adc2_mux), + SND_SOC_DAPM_MUX("IF1_1_ADC3 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_adc3_mux), + SND_SOC_DAPM_PGA("IF1_1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MUX("IF1_2_ADC1 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc1_mux), + SND_SOC_DAPM_MUX("IF1_2_ADC2 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc2_mux), + SND_SOC_DAPM_MUX("IF1_2_ADC3 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc3_mux), + SND_SOC_DAPM_MUX("IF1_2_ADC4 Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_adc4_mux), + SND_SOC_DAPM_MUX("TDM1 slot 01 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM1 slot 23 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM1 slot 45 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM1 slot 67 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm1_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 01 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 23 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 45 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("TDM2 slot 67 Data Mux", SND_SOC_NOPM, 0, 0, + &rt5665_tdm2_adc_mux), + SND_SOC_DAPM_MUX("IF2_1 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_1_adc_in_mux), + SND_SOC_DAPM_MUX("IF2_2 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_2_adc_in_mux), + SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if3_adc_in_mux), + SND_SOC_DAPM_MUX("IF1_1 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_1 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_1_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 0 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_01_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_23_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 4 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 5 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_45_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 6 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF1_2 7 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if1_2_67_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2_1 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_1_dac_swap_mux), + SND_SOC_DAPM_MUX("IF2_1 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_1_adc_swap_mux), + SND_SOC_DAPM_MUX("IF2_2 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_2_dac_swap_mux), + SND_SOC_DAPM_MUX("IF2_2 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if2_2_adc_swap_mux), + SND_SOC_DAPM_MUX("IF3 DAC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if3_dac_swap_mux), + SND_SOC_DAPM_MUX("IF3 ADC Swap Mux", SND_SOC_NOPM, 0, 0, + &rt5665_if3_adc_swap_mux), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 0", "AIF1_1 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 1", "AIF1_1 Capture", + 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 2", "AIF1_1 Capture", + 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 3", "AIF1_1 Capture", + 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 4", "AIF1_1 Capture", + 4, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 5", "AIF1_1 Capture", + 5, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 6", "AIF1_1 Capture", + 6, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_1TX slot 7", "AIF1_1 Capture", + 7, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 0", "AIF1_2 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 1", "AIF1_2 Capture", + 1, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 2", "AIF1_2 Capture", + 2, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 3", "AIF1_2 Capture", + 3, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 4", "AIF1_2 Capture", + 4, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 5", "AIF1_2 Capture", + 5, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 6", "AIF1_2 Capture", + 6, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1_2TX slot 7", "AIF1_2 Capture", + 7, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2_1TX", "AIF2_1 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2_2TX", "AIF2_2 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF3TX", "AIF3 Capture", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2_1RX", "AIF2_1 Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2_2RX", "AIF2_2 Playback", + 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF3RX", "AIF3 Playback", + 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DAC mixer before sound effect */ + SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, + rt5665_dac_l_mix, ARRAY_SIZE(rt5665_dac_l_mix)), + SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, + rt5665_dac_r_mix, ARRAY_SIZE(rt5665_dac_r_mix)), + + /* DAC channel Mux */ + SND_SOC_DAPM_MUX("DAC L1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r2_mux), + SND_SOC_DAPM_MUX("DAC L3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_l3_mux), + SND_SOC_DAPM_MUX("DAC R3 Mux", SND_SOC_NOPM, 0, 0, &rt5665_dac_r3_mux), + + SND_SOC_DAPM_MUX("DAC L1 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_l1_mux), + SND_SOC_DAPM_MUX("DAC R1 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_r1_mux), + SND_SOC_DAPM_MUX("DAC L2 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_l2_mux), + SND_SOC_DAPM_MUX("DAC R2 Source", SND_SOC_NOPM, 0, 0, + &rt5665_alg_dac_r2_mux), + + /* DAC Mixer */ + SND_SOC_DAPM_SUPPLY("DAC Stereo1 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_S1F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Stereo2 Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_S2F_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Left Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_MF_L_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC Mono Right Filter", RT5665_PWR_DIG_2, + RT5665_PWR_DAC_MF_R_BIT, 0, NULL, 0), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5665_sto1_dac_l_mix, ARRAY_SIZE(rt5665_sto1_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo1 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5665_sto1_dac_r_mix, ARRAY_SIZE(rt5665_sto1_dac_r_mix)), + SND_SOC_DAPM_MIXER("Stereo2 DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5665_sto2_dac_l_mix, ARRAY_SIZE(rt5665_sto2_dac_l_mix)), + SND_SOC_DAPM_MIXER("Stereo2 DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5665_sto2_dac_r_mix, ARRAY_SIZE(rt5665_sto2_dac_r_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXL", SND_SOC_NOPM, 0, 0, + rt5665_mono_dac_l_mix, ARRAY_SIZE(rt5665_mono_dac_l_mix)), + SND_SOC_DAPM_MIXER("Mono DAC MIXR", SND_SOC_NOPM, 0, 0, + rt5665_mono_dac_r_mix, ARRAY_SIZE(rt5665_mono_dac_r_mix)), + SND_SOC_DAPM_MUX("DAC MIXL", SND_SOC_NOPM, 0, 0, + &rt5665_dig_dac_mixl_mux), + SND_SOC_DAPM_MUX("DAC MIXR", SND_SOC_NOPM, 0, 0, + &rt5665_dig_dac_mixr_mux), + + /* DACs */ + SND_SOC_DAPM_DAC("DAC L1", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R1", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_SUPPLY("DAC L2 Power", RT5665_PWR_DIG_1, + RT5665_PWR_DAC_L2_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC R2 Power", RT5665_PWR_DIG_1, + RT5665_PWR_DAC_R2_BIT, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC L2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC R2", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("DAC1 MIX", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("DAC 1 Clock", 1, RT5665_CHOP_DAC, + RT5665_CKGEN_DAC1_SFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("DAC 2 Clock", 1, RT5665_CHOP_DAC, + RT5665_CKGEN_DAC2_SFT, 0, NULL, 0), + + /* OUT Mixer */ + SND_SOC_DAPM_MIXER("MONOVOL MIX", RT5665_PWR_MIXER, RT5665_PWR_MM_BIT, + 0, rt5665_monovol_mix, ARRAY_SIZE(rt5665_monovol_mix)), + SND_SOC_DAPM_MIXER("OUT MIXL", RT5665_PWR_MIXER, RT5665_PWR_OM_L_BIT, + 0, rt5665_out_l_mix, ARRAY_SIZE(rt5665_out_l_mix)), + SND_SOC_DAPM_MIXER("OUT MIXR", RT5665_PWR_MIXER, RT5665_PWR_OM_R_BIT, + 0, rt5665_out_r_mix, ARRAY_SIZE(rt5665_out_r_mix)), + + /* Output Volume */ + SND_SOC_DAPM_SWITCH("MONOVOL", RT5665_PWR_VOL, RT5665_PWR_MV_BIT, 0, + &monovol_switch), + SND_SOC_DAPM_SWITCH("OUTVOL L", RT5665_PWR_VOL, RT5665_PWR_OV_L_BIT, 0, + &outvol_l_switch), + SND_SOC_DAPM_SWITCH("OUTVOL R", RT5665_PWR_VOL, RT5665_PWR_OV_R_BIT, 0, + &outvol_r_switch), + + /* MONO/HPO/LOUT */ + SND_SOC_DAPM_MIXER("Mono MIX", SND_SOC_NOPM, 0, 0, rt5665_mono_mix, + ARRAY_SIZE(rt5665_mono_mix)), + SND_SOC_DAPM_MIXER("LOUT L MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_l_mix, + ARRAY_SIZE(rt5665_lout_l_mix)), + SND_SOC_DAPM_MIXER("LOUT R MIX", SND_SOC_NOPM, 0, 0, rt5665_lout_r_mix, + ARRAY_SIZE(rt5665_lout_r_mix)), + SND_SOC_DAPM_PGA_S("Mono Amp", 1, RT5665_PWR_ANLG_1, RT5665_PWR_MA_BIT, + 0, rt5665_mono_event, SND_SOC_DAPM_POST_PMD | + SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("HP Amp", 1, SND_SOC_NOPM, 0, 0, rt5665_hp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_PGA_S("LOUT Amp", 1, RT5665_PWR_ANLG_1, + RT5665_PWR_LM_BIT, 0, rt5665_lout_event, + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU), + + SND_SOC_DAPM_SUPPLY("Charge Pump", SND_SOC_NOPM, 0, 0, + rt5665_charge_pump_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + SND_SOC_DAPM_SWITCH("Mono Playback", SND_SOC_NOPM, 0, 0, + &mono_switch), + SND_SOC_DAPM_SWITCH("HPO Playback", SND_SOC_NOPM, 0, 0, + &hpo_switch), + SND_SOC_DAPM_SWITCH("LOUT L Playback", SND_SOC_NOPM, 0, 0, + &lout_l_switch), + SND_SOC_DAPM_SWITCH("LOUT R Playback", SND_SOC_NOPM, 0, 0, + &lout_r_switch), + SND_SOC_DAPM_SWITCH("PDM L Playback", SND_SOC_NOPM, 0, 0, + &pdm_l_switch), + SND_SOC_DAPM_SWITCH("PDM R Playback", SND_SOC_NOPM, 0, 0, + &pdm_r_switch), + + /* PDM */ + SND_SOC_DAPM_SUPPLY("PDM Power", RT5665_PWR_DIG_2, + RT5665_PWR_PDM1_BIT, 0, NULL, 0), + SND_SOC_DAPM_MUX("PDM L Mux", SND_SOC_NOPM, + 0, 1, &rt5665_pdm_l_mux), + SND_SOC_DAPM_MUX("PDM R Mux", SND_SOC_NOPM, + 0, 1, &rt5665_pdm_r_mux), + + /* CLK DET */ + SND_SOC_DAPM_SUPPLY("CLKDET SYS", RT5665_CLK_DET, RT5665_SYS_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET HP", RT5665_CLK_DET, RT5665_HP_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET MONO", RT5665_CLK_DET, RT5665_MONO_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET LOUT", RT5665_CLK_DET, RT5665_LOUT_CLK_DET, + 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("CLKDET", RT5665_CLK_DET, RT5665_POW_CLK_DET, + 0, NULL, 0), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("HPOL"), + SND_SOC_DAPM_OUTPUT("HPOR"), + SND_SOC_DAPM_OUTPUT("LOUTL"), + SND_SOC_DAPM_OUTPUT("LOUTR"), + SND_SOC_DAPM_OUTPUT("MONOOUT"), + SND_SOC_DAPM_OUTPUT("PDML"), + SND_SOC_DAPM_OUTPUT("PDMR"), +}; + +static const struct snd_soc_dapm_route rt5665_dapm_routes[] = { + /*PLL*/ + {"ADC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"ADC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"ADC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"ADC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Stereo1 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Stereo2 Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Mono Left Filter", NULL, "PLL", is_sys_clk_from_pll}, + {"DAC Mono Right Filter", NULL, "PLL", is_sys_clk_from_pll}, + + /*ASRC*/ + {"ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc}, + {"ADC Mono Left Filter", NULL, "ADC Mono L ASRC", is_using_asrc}, + {"ADC Mono Right Filter", NULL, "ADC Mono R ASRC", is_using_asrc}, + {"DAC Mono Left Filter", NULL, "DAC Mono L ASRC", is_using_asrc}, + {"DAC Mono Right Filter", NULL, "DAC Mono R ASRC", is_using_asrc}, + {"DAC Stereo1 Filter", NULL, "DAC STO1 ASRC", is_using_asrc}, + {"DAC Stereo2 Filter", NULL, "DAC STO2 ASRC", is_using_asrc}, + + /*Vref*/ + {"Mic Det Power", NULL, "Vref2"}, + {"MICBIAS1", NULL, "Vref1"}, + {"MICBIAS1", NULL, "Vref2"}, + {"MICBIAS2", NULL, "Vref1"}, + {"MICBIAS2", NULL, "Vref2"}, + {"MICBIAS3", NULL, "Vref1"}, + {"MICBIAS3", NULL, "Vref2"}, + + {"Stereo1 DMIC L Mux", NULL, "DMIC STO1 ASRC"}, + {"Stereo1 DMIC R Mux", NULL, "DMIC STO1 ASRC"}, + {"Stereo2 DMIC L Mux", NULL, "DMIC STO2 ASRC"}, + {"Stereo2 DMIC R Mux", NULL, "DMIC STO2 ASRC"}, + {"Mono DMIC L Mux", NULL, "DMIC MONO L ASRC"}, + {"Mono DMIC R Mux", NULL, "DMIC MONO R ASRC"}, + + {"I2S1_1", NULL, "I2S1 ASRC"}, + {"I2S1_2", NULL, "I2S1 ASRC"}, + {"I2S2_1", NULL, "I2S2 ASRC"}, + {"I2S2_2", NULL, "I2S2 ASRC"}, + {"I2S3", NULL, "I2S3 ASRC"}, + + {"CLKDET SYS", NULL, "CLKDET"}, + {"CLKDET HP", NULL, "CLKDET"}, + {"CLKDET MONO", NULL, "CLKDET"}, + {"CLKDET LOUT", NULL, "CLKDET"}, + + {"IN1P", NULL, "LDO2"}, + {"IN2P", NULL, "LDO2"}, + {"IN3P", NULL, "LDO2"}, + {"IN4P", NULL, "LDO2"}, + + {"DMIC1", NULL, "DMIC L1"}, + {"DMIC1", NULL, "DMIC R1"}, + {"DMIC2", NULL, "DMIC L2"}, + {"DMIC2", NULL, "DMIC R2"}, + + {"BST1", NULL, "IN1P"}, + {"BST1", NULL, "IN1N"}, + {"BST1", NULL, "BST1 Power"}, + {"BST1", NULL, "BST1P Power"}, + {"BST2", NULL, "IN2P"}, + {"BST2", NULL, "IN2N"}, + {"BST2", NULL, "BST2 Power"}, + {"BST2", NULL, "BST2P Power"}, + {"BST3", NULL, "IN3P"}, + {"BST3", NULL, "IN3N"}, + {"BST3", NULL, "BST3 Power"}, + {"BST3", NULL, "BST3P Power"}, + {"BST4", NULL, "IN4P"}, + {"BST4", NULL, "IN4N"}, + {"BST4", NULL, "BST4 Power"}, + {"BST4", NULL, "BST4P Power"}, + {"BST1 CBJ", NULL, "IN1P"}, + {"BST1 CBJ", NULL, "IN1N"}, + {"BST1 CBJ", NULL, "CBJ Power"}, + {"CBJ Power", NULL, "Vref2"}, + + {"INL VOL", NULL, "IN3P"}, + {"INR VOL", NULL, "IN3N"}, + + {"RECMIX1L", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX1L", "INL Switch", "INL VOL"}, + {"RECMIX1L", "INR Switch", "INR VOL"}, + {"RECMIX1L", "BST4 Switch", "BST4"}, + {"RECMIX1L", "BST3 Switch", "BST3"}, + {"RECMIX1L", "BST2 Switch", "BST2"}, + {"RECMIX1L", "BST1 Switch", "BST1"}, + {"RECMIX1L", NULL, "RECMIX1L Power"}, + + {"RECMIX1R", "MONOVOL Switch", "MONOVOL"}, + {"RECMIX1R", "INR Switch", "INR VOL"}, + {"RECMIX1R", "BST4 Switch", "BST4"}, + {"RECMIX1R", "BST3 Switch", "BST3"}, + {"RECMIX1R", "BST2 Switch", "BST2"}, + {"RECMIX1R", "BST1 Switch", "BST1"}, + {"RECMIX1R", NULL, "RECMIX1R Power"}, + + {"RECMIX2L", "CBJ Switch", "BST1 CBJ"}, + {"RECMIX2L", "INL Switch", "INL VOL"}, + {"RECMIX2L", "INR Switch", "INR VOL"}, + {"RECMIX2L", "BST4 Switch", "BST4"}, + {"RECMIX2L", "BST3 Switch", "BST3"}, + {"RECMIX2L", "BST2 Switch", "BST2"}, + {"RECMIX2L", "BST1 Switch", "BST1"}, + {"RECMIX2L", NULL, "RECMIX2L Power"}, + + {"RECMIX2R", "MONOVOL Switch", "MONOVOL"}, + {"RECMIX2R", "INL Switch", "INL VOL"}, + {"RECMIX2R", "INR Switch", "INR VOL"}, + {"RECMIX2R", "BST4 Switch", "BST4"}, + {"RECMIX2R", "BST3 Switch", "BST3"}, + {"RECMIX2R", "BST2 Switch", "BST2"}, + {"RECMIX2R", "BST1 Switch", "BST1"}, + {"RECMIX2R", NULL, "RECMIX2R Power"}, + + {"ADC1 L", NULL, "RECMIX1L"}, + {"ADC1 L", NULL, "ADC1 L Power"}, + {"ADC1 L", NULL, "ADC1 clock"}, + {"ADC1 R", NULL, "RECMIX1R"}, + {"ADC1 R", NULL, "ADC1 R Power"}, + {"ADC1 R", NULL, "ADC1 clock"}, + + {"ADC2 L", NULL, "RECMIX2L"}, + {"ADC2 L", NULL, "ADC2 L Power"}, + {"ADC2 L", NULL, "ADC2 clock"}, + {"ADC2 R", NULL, "RECMIX2R"}, + {"ADC2 R", NULL, "ADC2 R Power"}, + {"ADC2 R", NULL, "ADC2 clock"}, + + {"DMIC L1", NULL, "DMIC CLK"}, + {"DMIC L1", NULL, "DMIC1 Power"}, + {"DMIC R1", NULL, "DMIC CLK"}, + {"DMIC R1", NULL, "DMIC1 Power"}, + {"DMIC L2", NULL, "DMIC CLK"}, + {"DMIC L2", NULL, "DMIC2 Power"}, + {"DMIC R2", NULL, "DMIC CLK"}, + {"DMIC R2", NULL, "DMIC2 Power"}, + + {"Stereo1 DMIC L Mux", "DMIC1", "DMIC L1"}, + {"Stereo1 DMIC L Mux", "DMIC2", "DMIC L2"}, + + {"Stereo1 DMIC R Mux", "DMIC1", "DMIC R1"}, + {"Stereo1 DMIC R Mux", "DMIC2", "DMIC R2"}, + + {"Mono DMIC L Mux", "DMIC1 L", "DMIC L1"}, + {"Mono DMIC L Mux", "DMIC2 L", "DMIC L2"}, + + {"Mono DMIC R Mux", "DMIC1 R", "DMIC R1"}, + {"Mono DMIC R Mux", "DMIC2 R", "DMIC R2"}, + + {"Stereo2 DMIC L Mux", "DMIC1", "DMIC L1"}, + {"Stereo2 DMIC L Mux", "DMIC2", "DMIC L2"}, + + {"Stereo2 DMIC R Mux", "DMIC1", "DMIC R1"}, + {"Stereo2 DMIC R Mux", "DMIC2", "DMIC R2"}, + + {"Stereo1 ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Stereo1 ADC L Mux", "ADC2 L", "ADC2 L"}, + {"Stereo1 ADC L Mux", "ADC2 R", "ADC2 R"}, + {"Stereo1 ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Stereo1 ADC R Mux", "ADC1 R", "ADC1 R"}, + {"Stereo1 ADC R Mux", "ADC2 L", "ADC2 L"}, + {"Stereo1 ADC R Mux", "ADC2 R", "ADC2 R"}, + + {"Stereo1 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, + {"Stereo1 DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + + {"Stereo1 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, + {"Stereo1 DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + + {"Stereo1 ADC L1 Mux", "ADC", "Stereo1 ADC L Mux"}, + {"Stereo1 ADC L1 Mux", "DD Mux", "Stereo1 DD L Mux"}, + {"Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC L Mux"}, + {"Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL"}, + + {"Stereo1 ADC R1 Mux", "ADC", "Stereo1 ADC R Mux"}, + {"Stereo1 ADC R1 Mux", "DD Mux", "Stereo1 DD R Mux"}, + {"Stereo1 ADC R2 Mux", "DMIC", "Stereo1 DMIC R Mux"}, + {"Stereo1 ADC R2 Mux", "DAC MIX", "DAC MIXR"}, + + {"Mono ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Mono ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Mono ADC L Mux", "ADC2 L", "ADC2 L"}, + {"Mono ADC L Mux", "ADC2 R", "ADC2 R"}, + + {"Mono ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Mono ADC R Mux", "ADC1 R", "ADC1 R"}, + {"Mono ADC R Mux", "ADC2 L", "ADC2 L"}, + {"Mono ADC R Mux", "ADC2 R", "ADC2 R"}, + + {"Mono DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, + {"Mono DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + + {"Mono DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, + {"Mono DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + + {"Mono ADC L2 Mux", "DMIC", "Mono DMIC L Mux"}, + {"Mono ADC L2 Mux", "DAC MIXL", "DAC MIXL"}, + {"Mono ADC L1 Mux", "DD Mux", "Mono DD L Mux"}, + {"Mono ADC L1 Mux", "ADC", "Mono ADC L Mux"}, + + {"Mono ADC R1 Mux", "DD Mux", "Mono DD R Mux"}, + {"Mono ADC R1 Mux", "ADC", "Mono ADC R Mux"}, + {"Mono ADC R2 Mux", "DMIC", "Mono DMIC R Mux"}, + {"Mono ADC R2 Mux", "DAC MIXR", "DAC MIXR"}, + + {"Stereo2 ADC L Mux", "ADC1 L", "ADC1 L"}, + {"Stereo2 ADC L Mux", "ADC2 L", "ADC2 L"}, + {"Stereo2 ADC L Mux", "ADC1 R", "ADC1 R"}, + {"Stereo2 ADC R Mux", "ADC1 L", "ADC1 L"}, + {"Stereo2 ADC R Mux", "ADC2 L", "ADC2 L"}, + {"Stereo2 ADC R Mux", "ADC1 R", "ADC1 R"}, + + {"Stereo2 DD L Mux", "STO2 DAC", "Stereo2 DAC MIXL"}, + {"Stereo2 DD L Mux", "MONO DAC", "Mono DAC MIXL"}, + + {"Stereo2 DD R Mux", "STO2 DAC", "Stereo2 DAC MIXR"}, + {"Stereo2 DD R Mux", "MONO DAC", "Mono DAC MIXR"}, + + {"Stereo2 ADC L1 Mux", "ADC", "Stereo2 ADC L Mux"}, + {"Stereo2 ADC L1 Mux", "DD Mux", "Stereo2 DD L Mux"}, + {"Stereo2 ADC L2 Mux", "DMIC", "Stereo2 DMIC L Mux"}, + {"Stereo2 ADC L2 Mux", "DAC MIX", "DAC MIXL"}, + + {"Stereo2 ADC R1 Mux", "ADC", "Stereo2 ADC R Mux"}, + {"Stereo2 ADC R1 Mux", "DD Mux", "Stereo2 DD R Mux"}, + {"Stereo2 ADC R2 Mux", "DMIC", "Stereo2 DMIC R Mux"}, + {"Stereo2 ADC R2 Mux", "DAC MIX", "DAC MIXR"}, + + {"Stereo1 ADC MIXL", "ADC1 Switch", "Stereo1 ADC L1 Mux"}, + {"Stereo1 ADC MIXL", "ADC2 Switch", "Stereo1 ADC L2 Mux"}, + {"Stereo1 ADC MIXL", NULL, "ADC Stereo1 Filter"}, + + {"Stereo1 ADC MIXR", "ADC1 Switch", "Stereo1 ADC R1 Mux"}, + {"Stereo1 ADC MIXR", "ADC2 Switch", "Stereo1 ADC R2 Mux"}, + {"Stereo1 ADC MIXR", NULL, "ADC Stereo1 Filter"}, + + {"Mono ADC MIXL", "ADC1 Switch", "Mono ADC L1 Mux"}, + {"Mono ADC MIXL", "ADC2 Switch", "Mono ADC L2 Mux"}, + {"Mono ADC MIXL", NULL, "ADC Mono Left Filter"}, + + {"Mono ADC MIXR", "ADC1 Switch", "Mono ADC R1 Mux"}, + {"Mono ADC MIXR", "ADC2 Switch", "Mono ADC R2 Mux"}, + {"Mono ADC MIXR", NULL, "ADC Mono Right Filter"}, + + {"Stereo2 ADC MIXL", "ADC1 Switch", "Stereo2 ADC L1 Mux"}, + {"Stereo2 ADC MIXL", "ADC2 Switch", "Stereo2 ADC L2 Mux"}, + {"Stereo2 ADC MIXL", NULL, "ADC Stereo2 Filter"}, + + {"Stereo2 ADC MIXR", "ADC1 Switch", "Stereo2 ADC R1 Mux"}, + {"Stereo2 ADC MIXR", "ADC2 Switch", "Stereo2 ADC R2 Mux"}, + {"Stereo2 ADC MIXR", NULL, "ADC Stereo2 Filter"}, + + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXL"}, + {"Stereo1 ADC MIX", NULL, "Stereo1 ADC MIXR"}, + {"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXL"}, + {"Stereo2 ADC MIX", NULL, "Stereo2 ADC MIXR"}, + {"Mono ADC MIX", NULL, "Mono ADC MIXL"}, + {"Mono ADC MIX", NULL, "Mono ADC MIXR"}, + + {"IF1_1_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF1_1_ADC1 Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF1_1_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF1_1_ADC2 Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF1_1_ADC3 Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF1_1_ADC3 Mux", "IF3 DAC", "IF3 DAC"}, + {"IF1_1_ADC4", NULL, "DAC1 MIX"}, + + {"IF1_2_ADC1 Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF1_2_ADC1 Mux", "IF1 DAC", "IF1 DAC1"}, + {"IF1_2_ADC2 Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF1_2_ADC2 Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF1_2_ADC3 Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF1_2_ADC3 Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF1_2_ADC4 Mux", "DAC1", "DAC1 MIX"}, + {"IF1_2_ADC4 Mux", "IF3 DAC", "IF3 DAC"}, + + {"TDM1 slot 01 Data Mux", "1234", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1243", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1324", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1342", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1432", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "1423", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 01 Data Mux", "2134", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2143", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2314", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2341", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2431", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "2413", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 01 Data Mux", "3124", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3142", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3214", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3241", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3412", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "3421", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 01 Data Mux", "4123", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4132", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4213", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4231", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4312", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", "4321", "IF1_1_ADC4"}, + {"TDM1 slot 01 Data Mux", NULL, "I2S1_1"}, + + {"TDM1 slot 23 Data Mux", "1234", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "1243", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "1324", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "1342", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "1432", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "1423", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "2134", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "2143", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "2314", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "2341", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "2431", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "2413", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "3124", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "3142", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "3214", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "3241", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "3412", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "3421", "IF1_1_ADC4"}, + {"TDM1 slot 23 Data Mux", "4123", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "4132", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 23 Data Mux", "4213", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "4231", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 23 Data Mux", "4312", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", "4321", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 23 Data Mux", NULL, "I2S1_1"}, + + {"TDM1 slot 45 Data Mux", "1234", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "1243", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "1324", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "1342", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "1432", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "1423", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "2134", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "2143", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "2314", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "2341", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "2431", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "2413", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "3124", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "3142", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "3214", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "3241", "IF1_1_ADC4"}, + {"TDM1 slot 45 Data Mux", "3412", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "3421", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "4123", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", "4132", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "4213", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "4231", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 45 Data Mux", "4312", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 45 Data Mux", "4321", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 45 Data Mux", NULL, "I2S1_1"}, + + {"TDM1 slot 67 Data Mux", "1234", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "1243", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "1324", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "1342", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "1432", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "1423", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "2134", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "2143", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "2314", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "2341", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "2431", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "2413", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "3124", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "3142", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "3214", "IF1_1_ADC4"}, + {"TDM1 slot 67 Data Mux", "3241", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "3412", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "3421", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "4123", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "4132", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "4213", "IF1_1_ADC3 Mux"}, + {"TDM1 slot 67 Data Mux", "4231", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", "4312", "IF1_1_ADC2 Mux"}, + {"TDM1 slot 67 Data Mux", "4321", "IF1_1_ADC1 Mux"}, + {"TDM1 slot 67 Data Mux", NULL, "I2S1_1"}, + + + {"TDM2 slot 01 Data Mux", "1234", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1243", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1324", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1342", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1432", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "1423", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 01 Data Mux", "2134", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2143", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2314", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2341", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2431", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "2413", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 01 Data Mux", "3124", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3142", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3214", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3241", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3412", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "3421", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 01 Data Mux", "4123", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4132", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4213", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4231", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4312", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", "4321", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 01 Data Mux", NULL, "I2S1_2"}, + + {"TDM2 slot 23 Data Mux", "1234", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "1243", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "1324", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "1342", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "1432", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "1423", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "2134", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "2143", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "2314", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "2341", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "2431", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "2413", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "3124", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "3142", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "3214", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "3241", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "3412", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "3421", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 23 Data Mux", "4123", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "4132", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 23 Data Mux", "4213", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "4231", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 23 Data Mux", "4312", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", "4321", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 23 Data Mux", NULL, "I2S1_2"}, + + {"TDM2 slot 45 Data Mux", "1234", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "1243", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "1324", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "1342", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "1432", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "1423", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "2134", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "2143", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "2314", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "2341", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "2431", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "2413", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "3124", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "3142", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "3214", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "3241", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 45 Data Mux", "3412", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "3421", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "4123", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", "4132", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "4213", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "4231", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 45 Data Mux", "4312", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 45 Data Mux", "4321", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 45 Data Mux", NULL, "I2S1_2"}, + + {"TDM2 slot 67 Data Mux", "1234", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "1243", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "1324", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "1342", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "1432", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "1423", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "2134", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "2143", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "2314", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "2341", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "2431", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "2413", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "3124", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "3142", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "3214", "IF1_2_ADC4 Mux"}, + {"TDM2 slot 67 Data Mux", "3241", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "3412", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "3421", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "4123", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "4132", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "4213", "IF1_2_ADC3 Mux"}, + {"TDM2 slot 67 Data Mux", "4231", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", "4312", "IF1_2_ADC2 Mux"}, + {"TDM2 slot 67 Data Mux", "4321", "IF1_2_ADC1 Mux"}, + {"TDM2 slot 67 Data Mux", NULL, "I2S1_2"}, + + {"IF1_1 0 ADC Swap Mux", "L/R", "TDM1 slot 01 Data Mux"}, + {"IF1_1 0 ADC Swap Mux", "L/L", "TDM1 slot 01 Data Mux"}, + {"IF1_1 1 ADC Swap Mux", "R/L", "TDM1 slot 01 Data Mux"}, + {"IF1_1 1 ADC Swap Mux", "R/R", "TDM1 slot 01 Data Mux"}, + {"IF1_1 2 ADC Swap Mux", "L/R", "TDM1 slot 23 Data Mux"}, + {"IF1_1 2 ADC Swap Mux", "R/L", "TDM1 slot 23 Data Mux"}, + {"IF1_1 3 ADC Swap Mux", "L/L", "TDM1 slot 23 Data Mux"}, + {"IF1_1 3 ADC Swap Mux", "R/R", "TDM1 slot 23 Data Mux"}, + {"IF1_1 4 ADC Swap Mux", "L/R", "TDM1 slot 45 Data Mux"}, + {"IF1_1 4 ADC Swap Mux", "R/L", "TDM1 slot 45 Data Mux"}, + {"IF1_1 5 ADC Swap Mux", "L/L", "TDM1 slot 45 Data Mux"}, + {"IF1_1 5 ADC Swap Mux", "R/R", "TDM1 slot 45 Data Mux"}, + {"IF1_1 6 ADC Swap Mux", "L/R", "TDM1 slot 67 Data Mux"}, + {"IF1_1 6 ADC Swap Mux", "R/L", "TDM1 slot 67 Data Mux"}, + {"IF1_1 7 ADC Swap Mux", "L/L", "TDM1 slot 67 Data Mux"}, + {"IF1_1 7 ADC Swap Mux", "R/R", "TDM1 slot 67 Data Mux"}, + {"IF1_2 0 ADC Swap Mux", "L/R", "TDM2 slot 01 Data Mux"}, + {"IF1_2 0 ADC Swap Mux", "R/L", "TDM2 slot 01 Data Mux"}, + {"IF1_2 1 ADC Swap Mux", "L/L", "TDM2 slot 01 Data Mux"}, + {"IF1_2 1 ADC Swap Mux", "R/R", "TDM2 slot 01 Data Mux"}, + {"IF1_2 2 ADC Swap Mux", "L/R", "TDM2 slot 23 Data Mux"}, + {"IF1_2 2 ADC Swap Mux", "R/L", "TDM2 slot 23 Data Mux"}, + {"IF1_2 3 ADC Swap Mux", "L/L", "TDM2 slot 23 Data Mux"}, + {"IF1_2 3 ADC Swap Mux", "R/R", "TDM2 slot 23 Data Mux"}, + {"IF1_2 4 ADC Swap Mux", "L/R", "TDM2 slot 45 Data Mux"}, + {"IF1_2 4 ADC Swap Mux", "R/L", "TDM2 slot 45 Data Mux"}, + {"IF1_2 5 ADC Swap Mux", "L/L", "TDM2 slot 45 Data Mux"}, + {"IF1_2 5 ADC Swap Mux", "R/R", "TDM2 slot 45 Data Mux"}, + {"IF1_2 6 ADC Swap Mux", "L/R", "TDM2 slot 67 Data Mux"}, + {"IF1_2 6 ADC Swap Mux", "R/L", "TDM2 slot 67 Data Mux"}, + {"IF1_2 7 ADC Swap Mux", "L/L", "TDM2 slot 67 Data Mux"}, + {"IF1_2 7 ADC Swap Mux", "R/R", "TDM2 slot 67 Data Mux"}, + + {"IF2_1 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF2_1 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF2_1 ADC Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF2_1 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, + {"IF2_1 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, + {"IF2_1 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF2_1 ADC Mux", "IF3 DAC", "IF3 DAC"}, + {"IF2_1 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, + {"IF2_1 ADC", NULL, "IF2_1 ADC Mux"}, + {"IF2_1 ADC", NULL, "I2S2_1"}, + + {"IF2_2 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF2_2 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF2_2 ADC Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF2_2 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, + {"IF2_2 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, + {"IF2_2 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF2_2 ADC Mux", "IF3 DAC", "IF3 DAC"}, + {"IF2_2 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, + {"IF2_2 ADC", NULL, "IF2_2 ADC Mux"}, + {"IF2_2 ADC", NULL, "I2S2_2"}, + + {"IF3 ADC Mux", "STO1 ADC", "Stereo1 ADC MIX"}, + {"IF3 ADC Mux", "STO2 ADC", "Stereo2 ADC MIX"}, + {"IF3 ADC Mux", "MONO ADC", "Mono ADC MIX"}, + {"IF3 ADC Mux", "IF1 DAC1", "IF1 DAC1"}, + {"IF3 ADC Mux", "IF1 DAC2", "IF1 DAC2"}, + {"IF3 ADC Mux", "IF2_1 DAC", "IF2_1 DAC"}, + {"IF3 ADC Mux", "IF2_2 DAC", "IF2_2 DAC"}, + {"IF3 ADC Mux", "DAC1 MIX", "DAC1 MIX"}, + {"IF3 ADC", NULL, "IF3 ADC Mux"}, + {"IF3 ADC", NULL, "I2S3"}, + + {"AIF1_1TX slot 0", NULL, "IF1_1 0 ADC Swap Mux"}, + {"AIF1_1TX slot 1", NULL, "IF1_1 1 ADC Swap Mux"}, + {"AIF1_1TX slot 2", NULL, "IF1_1 2 ADC Swap Mux"}, + {"AIF1_1TX slot 3", NULL, "IF1_1 3 ADC Swap Mux"}, + {"AIF1_1TX slot 4", NULL, "IF1_1 4 ADC Swap Mux"}, + {"AIF1_1TX slot 5", NULL, "IF1_1 5 ADC Swap Mux"}, + {"AIF1_1TX slot 6", NULL, "IF1_1 6 ADC Swap Mux"}, + {"AIF1_1TX slot 7", NULL, "IF1_1 7 ADC Swap Mux"}, + {"AIF1_2TX slot 0", NULL, "IF1_2 0 ADC Swap Mux"}, + {"AIF1_2TX slot 1", NULL, "IF1_2 1 ADC Swap Mux"}, + {"AIF1_2TX slot 2", NULL, "IF1_2 2 ADC Swap Mux"}, + {"AIF1_2TX slot 3", NULL, "IF1_2 3 ADC Swap Mux"}, + {"AIF1_2TX slot 4", NULL, "IF1_2 4 ADC Swap Mux"}, + {"AIF1_2TX slot 5", NULL, "IF1_2 5 ADC Swap Mux"}, + {"AIF1_2TX slot 6", NULL, "IF1_2 6 ADC Swap Mux"}, + {"AIF1_2TX slot 7", NULL, "IF1_2 7 ADC Swap Mux"}, + {"IF2_1 ADC Swap Mux", "L/R", "IF2_1 ADC"}, + {"IF2_1 ADC Swap Mux", "R/L", "IF2_1 ADC"}, + {"IF2_1 ADC Swap Mux", "L/L", "IF2_1 ADC"}, + {"IF2_1 ADC Swap Mux", "R/R", "IF2_1 ADC"}, + {"AIF2_1TX", NULL, "IF2_1 ADC Swap Mux"}, + {"IF2_2 ADC Swap Mux", "L/R", "IF2_2 ADC"}, + {"IF2_2 ADC Swap Mux", "R/L", "IF2_2 ADC"}, + {"IF2_2 ADC Swap Mux", "L/L", "IF2_2 ADC"}, + {"IF2_2 ADC Swap Mux", "R/R", "IF2_2 ADC"}, + {"AIF2_2TX", NULL, "IF2_2 ADC Swap Mux"}, + {"IF3 ADC Swap Mux", "L/R", "IF3 ADC"}, + {"IF3 ADC Swap Mux", "R/L", "IF3 ADC"}, + {"IF3 ADC Swap Mux", "L/L", "IF3 ADC"}, + {"IF3 ADC Swap Mux", "R/R", "IF3 ADC"}, + {"AIF3TX", NULL, "IF3 ADC Swap Mux"}, + + {"IF1 DAC1", NULL, "AIF1RX"}, + {"IF1 DAC2", NULL, "AIF1RX"}, + {"IF1 DAC3", NULL, "AIF1RX"}, + {"IF2_1 DAC Swap Mux", "L/R", "AIF2_1RX"}, + {"IF2_1 DAC Swap Mux", "R/L", "AIF2_1RX"}, + {"IF2_1 DAC Swap Mux", "L/L", "AIF2_1RX"}, + {"IF2_1 DAC Swap Mux", "R/R", "AIF2_1RX"}, + {"IF2_2 DAC Swap Mux", "L/R", "AIF2_2RX"}, + {"IF2_2 DAC Swap Mux", "R/L", "AIF2_2RX"}, + {"IF2_2 DAC Swap Mux", "L/L", "AIF2_2RX"}, + {"IF2_2 DAC Swap Mux", "R/R", "AIF2_2RX"}, + {"IF2_1 DAC", NULL, "IF2_1 DAC Swap Mux"}, + {"IF2_2 DAC", NULL, "IF2_2 DAC Swap Mux"}, + {"IF3 DAC Swap Mux", "L/R", "AIF3RX"}, + {"IF3 DAC Swap Mux", "R/L", "AIF3RX"}, + {"IF3 DAC Swap Mux", "L/L", "AIF3RX"}, + {"IF3 DAC Swap Mux", "R/R", "AIF3RX"}, + {"IF3 DAC", NULL, "IF3 DAC Swap Mux"}, + + {"IF1 DAC1", NULL, "I2S1_1"}, + {"IF1 DAC2", NULL, "I2S1_1"}, + {"IF1 DAC3", NULL, "I2S1_1"}, + {"IF2_1 DAC", NULL, "I2S2_1"}, + {"IF2_2 DAC", NULL, "I2S2_2"}, + {"IF3 DAC", NULL, "I2S3"}, + + {"IF1 DAC1 L", NULL, "IF1 DAC1"}, + {"IF1 DAC1 R", NULL, "IF1 DAC1"}, + {"IF1 DAC2 L", NULL, "IF1 DAC2"}, + {"IF1 DAC2 R", NULL, "IF1 DAC2"}, + {"IF1 DAC3 L", NULL, "IF1 DAC3"}, + {"IF1 DAC3 R", NULL, "IF1 DAC3"}, + {"IF2_1 DAC L", NULL, "IF2_1 DAC"}, + {"IF2_1 DAC R", NULL, "IF2_1 DAC"}, + {"IF2_2 DAC L", NULL, "IF2_2 DAC"}, + {"IF2_2 DAC R", NULL, "IF2_2 DAC"}, + {"IF3 DAC L", NULL, "IF3 DAC"}, + {"IF3 DAC R", NULL, "IF3 DAC"}, + + {"DAC L1 Mux", "IF1 DAC1", "IF1 DAC1 L"}, + {"DAC L1 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, + {"DAC L1 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, + {"DAC L1 Mux", "IF3 DAC", "IF3 DAC L"}, + {"DAC L1 Mux", NULL, "DAC Stereo1 Filter"}, + + {"DAC R1 Mux", "IF1 DAC1", "IF1 DAC1 R"}, + {"DAC R1 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, + {"DAC R1 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, + {"DAC R1 Mux", "IF3 DAC", "IF3 DAC R"}, + {"DAC R1 Mux", NULL, "DAC Stereo1 Filter"}, + + {"DAC1 MIXL", "Stereo ADC Switch", "Stereo1 ADC MIXL"}, + {"DAC1 MIXL", "DAC1 Switch", "DAC L1 Mux"}, + {"DAC1 MIXR", "Stereo ADC Switch", "Stereo1 ADC MIXR"}, + {"DAC1 MIXR", "DAC1 Switch", "DAC R1 Mux"}, + + {"DAC1 MIX", NULL, "DAC1 MIXL"}, + {"DAC1 MIX", NULL, "DAC1 MIXR"}, + + {"DAC L2 Mux", "IF1 DAC2", "IF1 DAC2 L"}, + {"DAC L2 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, + {"DAC L2 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, + {"DAC L2 Mux", "IF3 DAC", "IF3 DAC L"}, + {"DAC L2 Mux", "Mono ADC MIX", "Mono ADC MIXL"}, + {"DAC L2 Mux", NULL, "DAC Mono Left Filter"}, + + {"DAC R2 Mux", "IF1 DAC2", "IF1 DAC2 R"}, + {"DAC R2 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, + {"DAC R2 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, + {"DAC R2 Mux", "IF3 DAC", "IF3 DAC R"}, + {"DAC R2 Mux", "Mono ADC MIX", "Mono ADC MIXR"}, + {"DAC R2 Mux", NULL, "DAC Mono Right Filter"}, + + {"DAC L3 Mux", "IF1 DAC2", "IF1 DAC2 L"}, + {"DAC L3 Mux", "IF2_1 DAC", "IF2_1 DAC L"}, + {"DAC L3 Mux", "IF2_2 DAC", "IF2_2 DAC L"}, + {"DAC L3 Mux", "IF3 DAC", "IF3 DAC L"}, + {"DAC L3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXL"}, + {"DAC L3 Mux", NULL, "DAC Stereo2 Filter"}, + + {"DAC R3 Mux", "IF1 DAC2", "IF1 DAC2 R"}, + {"DAC R3 Mux", "IF2_1 DAC", "IF2_1 DAC R"}, + {"DAC R3 Mux", "IF2_2 DAC", "IF2_2 DAC R"}, + {"DAC R3 Mux", "IF3 DAC", "IF3 DAC R"}, + {"DAC R3 Mux", "STO2 ADC MIX", "Stereo2 ADC MIXR"}, + {"DAC R3 Mux", NULL, "DAC Stereo2 Filter"}, + + {"Stereo1 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo1 DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo1 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo1 DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + + {"Stereo1 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo1 DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo1 DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo1 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + + {"Stereo2 DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Stereo2 DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Stereo2 DAC MIXL", "DAC L3 Switch", "DAC L3 Mux"}, + + {"Stereo2 DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Stereo2 DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + {"Stereo2 DAC MIXR", "DAC R3 Switch", "DAC R3 Mux"}, + + {"Mono DAC MIXL", "DAC L1 Switch", "DAC1 MIXL"}, + {"Mono DAC MIXL", "DAC R1 Switch", "DAC1 MIXR"}, + {"Mono DAC MIXL", "DAC L2 Switch", "DAC L2 Mux"}, + {"Mono DAC MIXL", "DAC R2 Switch", "DAC R2 Mux"}, + {"Mono DAC MIXR", "DAC L1 Switch", "DAC1 MIXL"}, + {"Mono DAC MIXR", "DAC R1 Switch", "DAC1 MIXR"}, + {"Mono DAC MIXR", "DAC L2 Switch", "DAC L2 Mux"}, + {"Mono DAC MIXR", "DAC R2 Switch", "DAC R2 Mux"}, + + {"DAC MIXL", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, + {"DAC MIXL", "Stereo2 DAC Mixer", "Stereo2 DAC MIXL"}, + {"DAC MIXL", "Mono DAC Mixer", "Mono DAC MIXL"}, + {"DAC MIXR", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, + {"DAC MIXR", "Stereo2 DAC Mixer", "Stereo2 DAC MIXR"}, + {"DAC MIXR", "Mono DAC Mixer", "Mono DAC MIXR"}, + + {"DAC L1 Source", "DAC1", "DAC1 MIXL"}, + {"DAC L1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXL"}, + {"DAC L1 Source", "DMIC1", "DMIC L1"}, + {"DAC R1 Source", "DAC1", "DAC1 MIXR"}, + {"DAC R1 Source", "Stereo1 DAC Mixer", "Stereo1 DAC MIXR"}, + {"DAC R1 Source", "DMIC1", "DMIC R1"}, + + {"DAC L2 Source", "DAC2", "DAC L2 Mux"}, + {"DAC L2 Source", "Mono DAC Mixer", "Mono DAC MIXL"}, + {"DAC L2 Source", NULL, "DAC L2 Power"}, + {"DAC R2 Source", "DAC2", "DAC R2 Mux"}, + {"DAC R2 Source", "Mono DAC Mixer", "Mono DAC MIXR"}, + {"DAC R2 Source", NULL, "DAC R2 Power"}, + + {"DAC L1", NULL, "DAC L1 Source"}, + {"DAC R1", NULL, "DAC R1 Source"}, + {"DAC L2", NULL, "DAC L2 Source"}, + {"DAC R2", NULL, "DAC R2 Source"}, + + {"DAC L1", NULL, "DAC 1 Clock"}, + {"DAC R1", NULL, "DAC 1 Clock"}, + {"DAC L2", NULL, "DAC 2 Clock"}, + {"DAC R2", NULL, "DAC 2 Clock"}, + + {"MONOVOL MIX", "DAC L2 Switch", "DAC L2"}, + {"MONOVOL MIX", "RECMIX2L Switch", "RECMIX2L"}, + {"MONOVOL MIX", "BST1 Switch", "BST1"}, + {"MONOVOL MIX", "BST2 Switch", "BST2"}, + {"MONOVOL MIX", "BST3 Switch", "BST3"}, + + {"OUT MIXL", "DAC L2 Switch", "DAC L2"}, + {"OUT MIXL", "INL Switch", "INL VOL"}, + {"OUT MIXL", "BST1 Switch", "BST1"}, + {"OUT MIXL", "BST2 Switch", "BST2"}, + {"OUT MIXL", "BST3 Switch", "BST3"}, + {"OUT MIXR", "DAC R2 Switch", "DAC R2"}, + {"OUT MIXR", "INR Switch", "INR VOL"}, + {"OUT MIXR", "BST2 Switch", "BST2"}, + {"OUT MIXR", "BST3 Switch", "BST3"}, + {"OUT MIXR", "BST4 Switch", "BST4"}, + + {"MONOVOL", "Switch", "MONOVOL MIX"}, + {"Mono MIX", "DAC L2 Switch", "DAC L2"}, + {"Mono MIX", "MONOVOL Switch", "MONOVOL"}, + {"Mono Amp", NULL, "Mono MIX"}, + {"Mono Amp", NULL, "Vref2"}, + {"Mono Amp", NULL, "CLKDET SYS"}, + {"Mono Amp", NULL, "CLKDET MONO"}, + {"Mono Playback", "Switch", "Mono Amp"}, + {"MONOOUT", NULL, "Mono Playback"}, + + {"HP Amp", NULL, "DAC L1"}, + {"HP Amp", NULL, "DAC R1"}, + {"HP Amp", NULL, "Charge Pump"}, + {"HP Amp", NULL, "CLKDET SYS"}, + {"HP Amp", NULL, "CLKDET HP"}, + {"HP Amp", NULL, "CBJ Power"}, + {"HP Amp", NULL, "Vref2"}, + {"HPO Playback", "Switch", "HP Amp"}, + {"HPOL", NULL, "HPO Playback"}, + {"HPOR", NULL, "HPO Playback"}, + + {"OUTVOL L", "Switch", "OUT MIXL"}, + {"OUTVOL R", "Switch", "OUT MIXR"}, + {"LOUT L MIX", "DAC L2 Switch", "DAC L2"}, + {"LOUT L MIX", "OUTVOL L Switch", "OUTVOL L"}, + {"LOUT R MIX", "DAC R2 Switch", "DAC R2"}, + {"LOUT R MIX", "OUTVOL R Switch", "OUTVOL R"}, + {"LOUT Amp", NULL, "LOUT L MIX"}, + {"LOUT Amp", NULL, "LOUT R MIX"}, + {"LOUT Amp", NULL, "Vref1"}, + {"LOUT Amp", NULL, "Vref2"}, + {"LOUT Amp", NULL, "CLKDET SYS"}, + {"LOUT Amp", NULL, "CLKDET LOUT"}, + {"LOUT L Playback", "Switch", "LOUT Amp"}, + {"LOUT R Playback", "Switch", "LOUT Amp"}, + {"LOUTL", NULL, "LOUT L Playback"}, + {"LOUTR", NULL, "LOUT R Playback"}, + + {"PDM L Mux", "Mono DAC", "Mono DAC MIXL"}, + {"PDM L Mux", "Stereo1 DAC", "Stereo1 DAC MIXL"}, + {"PDM L Mux", "Stereo2 DAC", "Stereo2 DAC MIXL"}, + {"PDM L Mux", NULL, "PDM Power"}, + {"PDM R Mux", "Mono DAC", "Mono DAC MIXR"}, + {"PDM R Mux", "Stereo1 DAC", "Stereo1 DAC MIXR"}, + {"PDM R Mux", "Stereo2 DAC", "Stereo2 DAC MIXR"}, + {"PDM R Mux", NULL, "PDM Power"}, + {"PDM L Playback", "Switch", "PDM L Mux"}, + {"PDM R Playback", "Switch", "PDM R Mux"}, + {"PDML", NULL, "PDM L Playback"}, + {"PDMR", NULL, "PDM R Playback"}, +}; + +static int rt5665_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + unsigned int val_len = 0, val_clk, mask_clk, val_bits = 0x0100; + int pre_div, frame_size; + + rt5665->lrck[dai->id] = params_rate(params); + pre_div = rl6231_get_clk_info(rt5665->sysclk, rt5665->lrck[dai->id]); + if (pre_div < 0) { + dev_err(codec->dev, "Unsupported clock setting %d for DAI %d\n", + rt5665->lrck[dai->id], dai->id); + return -EINVAL; + } + frame_size = snd_soc_params_to_frame_size(params); + if (frame_size < 0) { + dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size); + return -EINVAL; + } + + dev_dbg(dai->dev, "lrck is %dHz and pre_div is %d for iis %d\n", + rt5665->lrck[dai->id], pre_div, dai->id); + + switch (params_width(params)) { + case 16: + val_bits = 0x0100; + break; + case 20: + val_len |= RT5665_I2S_DL_20; + val_bits = 0x1300; + break; + case 24: + val_len |= RT5665_I2S_DL_24; + val_bits = 0x2500; + break; + case 8: + val_len |= RT5665_I2S_DL_8; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5665_AIF1_1: + case RT5665_AIF1_2: + mask_clk = RT5665_I2S_PD1_MASK; + val_clk = pre_div << RT5665_I2S_PD1_SFT; + snd_soc_update_bits(codec, RT5665_I2S1_SDP, + RT5665_I2S_DL_MASK, val_len); + break; + case RT5665_AIF2_1: + case RT5665_AIF2_2: + mask_clk = RT5665_I2S_PD2_MASK; + val_clk = pre_div << RT5665_I2S_PD2_SFT; + snd_soc_update_bits(codec, RT5665_I2S2_SDP, + RT5665_I2S_DL_MASK, val_len); + break; + case RT5665_AIF3: + mask_clk = RT5665_I2S_PD3_MASK; + val_clk = pre_div << RT5665_I2S_PD3_SFT; + snd_soc_update_bits(codec, RT5665_I2S3_SDP, + RT5665_I2S_DL_MASK, val_len); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, mask_clk, val_clk); + snd_soc_update_bits(codec, RT5665_STO1_DAC_SIL_DET, 0x3700, val_bits); + + switch (rt5665->lrck[dai->id]) { + case 192000: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, + RT5665_DAC_OSR_32 | RT5665_ADC_OSR_32); + break; + case 96000: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, + RT5665_DAC_OSR_64 | RT5665_ADC_OSR_64); + break; + default: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_DAC_OSR_MASK | RT5665_ADC_OSR_MASK, + RT5665_DAC_OSR_128 | RT5665_ADC_OSR_128); + break; + } + + return 0; +} + +static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + rt5665->master[dai->id] = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + reg_val |= RT5665_I2S_MS_S; + rt5665->master[dai->id] = 0; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + break; + case SND_SOC_DAIFMT_IB_NF: + reg_val |= RT5665_I2S_BP_INV; + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + break; + case SND_SOC_DAIFMT_LEFT_J: + reg_val |= RT5665_I2S_DF_LEFT; + break; + case SND_SOC_DAIFMT_DSP_A: + reg_val |= RT5665_I2S_DF_PCM_A; + break; + case SND_SOC_DAIFMT_DSP_B: + reg_val |= RT5665_I2S_DF_PCM_B; + break; + default: + return -EINVAL; + } + + switch (dai->id) { + case RT5665_AIF1_1: + case RT5665_AIF1_2: + snd_soc_update_bits(codec, RT5665_I2S1_SDP, + RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | + RT5665_I2S_DF_MASK, reg_val); + break; + case RT5665_AIF2_1: + case RT5665_AIF2_2: + snd_soc_update_bits(codec, RT5665_I2S2_SDP, + RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | + RT5665_I2S_DF_MASK, reg_val); + break; + case RT5665_AIF3: + snd_soc_update_bits(codec, RT5665_I2S3_SDP, + RT5665_I2S_MS_MASK | RT5665_I2S_BP_MASK | + RT5665_I2S_DF_MASK, reg_val); + break; + default: + dev_err(codec->dev, "Invalid dai->id: %d\n", dai->id); + return -EINVAL; + } + return 0; +} + +static int rt5665_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + unsigned int reg_val = 0; + + if (freq == rt5665->sysclk && clk_id == rt5665->sysclk_src) + return 0; + + switch (clk_id) { + case RT5665_SCLK_S_MCLK: + reg_val |= RT5665_SCLK_SRC_MCLK; + break; + case RT5665_SCLK_S_PLL1: + reg_val |= RT5665_SCLK_SRC_PLL1; + break; + case RT5665_SCLK_S_RCCLK: + reg_val |= RT5665_SCLK_SRC_RCCLK; + break; + default: + dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id); + return -EINVAL; + } + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_SCLK_SRC_MASK, reg_val); + rt5665->sysclk = freq; + rt5665->sysclk_src = clk_id; + + dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id); + + return 0; +} + +static int rt5665_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int Source, + unsigned int freq_in, unsigned int freq_out) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + struct rl6231_pll_code pll_code; + int ret; + + if (Source == rt5665->pll_src && freq_in == rt5665->pll_in && + freq_out == rt5665->pll_out) + return 0; + + if (!freq_in || !freq_out) { + dev_dbg(codec->dev, "PLL disabled\n"); + + rt5665->pll_in = 0; + rt5665->pll_out = 0; + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_SCLK_SRC_MASK, RT5665_SCLK_SRC_MCLK); + return 0; + } + + switch (Source) { + case RT5665_PLL1_S_MCLK: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_MCLK); + break; + case RT5665_PLL1_S_BCLK1: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK1); + break; + case RT5665_PLL1_S_BCLK2: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK2); + break; + case RT5665_PLL1_S_BCLK3: + snd_soc_update_bits(codec, RT5665_GLB_CLK, + RT5665_PLL1_SRC_MASK, RT5665_PLL1_SRC_BCLK3); + break; + default: + dev_err(codec->dev, "Unknown PLL Source %d\n", Source); + return -EINVAL; + } + + ret = rl6231_pll_calc(freq_in, freq_out, &pll_code); + if (ret < 0) { + dev_err(codec->dev, "Unsupport input clock %d\n", freq_in); + return ret; + } + + dev_dbg(codec->dev, "bypass=%d m=%d n=%d k=%d\n", + pll_code.m_bp, (pll_code.m_bp ? 0 : pll_code.m_code), + pll_code.n_code, pll_code.k_code); + + snd_soc_write(codec, RT5665_PLL_CTRL_1, + pll_code.n_code << RT5665_PLL_N_SFT | pll_code.k_code); + snd_soc_write(codec, RT5665_PLL_CTRL_2, + (pll_code.m_bp ? 0 : pll_code.m_code) << RT5665_PLL_M_SFT | + pll_code.m_bp << RT5665_PLL_M_BP_SFT); + + rt5665->pll_in = freq_in; + rt5665->pll_out = freq_out; + rt5665->pll_src = Source; + + return 0; +} + +static int rt5665_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + unsigned int val = 0; + + if (rx_mask || tx_mask) + val |= RT5665_I2S1_MODE_TDM; + + switch (slots) { + case 4: + val |= RT5665_TDM_IN_CH_4; + val |= RT5665_TDM_OUT_CH_4; + break; + case 6: + val |= RT5665_TDM_IN_CH_6; + val |= RT5665_TDM_OUT_CH_6; + break; + case 8: + val |= RT5665_TDM_IN_CH_8; + val |= RT5665_TDM_OUT_CH_8; + break; + case 2: + break; + default: + return -EINVAL; + } + + switch (slot_width) { + case 20: + val |= RT5665_TDM_IN_LEN_20; + val |= RT5665_TDM_OUT_LEN_20; + break; + case 24: + val |= RT5665_TDM_IN_LEN_24; + val |= RT5665_TDM_OUT_LEN_24; + break; + case 32: + val |= RT5665_TDM_IN_LEN_32; + val |= RT5665_TDM_OUT_LEN_32; + break; + case 16: + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, RT5665_TDM_CTRL_1, + RT5665_I2S1_MODE_MASK | RT5665_TDM_IN_CH_MASK | + RT5665_TDM_OUT_CH_MASK | RT5665_TDM_IN_LEN_MASK | + RT5665_TDM_OUT_LEN_MASK, val); + + return 0; +} + +static int rt5665_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + + rt5665->bclk[dai->id] = ratio; + + if (ratio == 64) { + switch (dai->id) { + case RT5665_AIF2_1: + case RT5665_AIF2_2: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_I2S_BCLK_MS2_MASK, + RT5665_I2S_BCLK_MS2_64); + break; + case RT5665_AIF3: + snd_soc_update_bits(codec, RT5665_ADDA_CLK_1, + RT5665_I2S_BCLK_MS3_MASK, + RT5665_I2S_BCLK_MS3_64); + break; + } + } + + return 0; +} + +static int rt5665_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + switch (level) { + case SND_SOC_BIAS_PREPARE: + regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC, + RT5665_DIG_GATE_CTRL, RT5665_DIG_GATE_CTRL); + break; + + case SND_SOC_BIAS_STANDBY: + regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1, + RT5665_PWR_LDO, RT5665_PWR_LDO); + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, + RT5665_PWR_MB, RT5665_PWR_MB); + regmap_update_bits(rt5665->regmap, RT5665_DIG_MISC, + RT5665_DIG_GATE_CTRL, 0); + break; + case SND_SOC_BIAS_OFF: + regmap_update_bits(rt5665->regmap, RT5665_PWR_DIG_1, + RT5665_PWR_LDO, 0); + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, + RT5665_PWR_MB, 0); + break; + + default: + break; + } + + return 0; +} + +static int rt5665_probe(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + rt5665->codec = codec; + + schedule_delayed_work(&rt5665->calibrate_work, msecs_to_jiffies(100)); + + return 0; +} + +static int rt5665_remove(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int rt5665_suspend(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5665->regmap, true); + regcache_mark_dirty(rt5665->regmap); + return 0; +} + +static int rt5665_resume(struct snd_soc_codec *codec) +{ + struct rt5665_priv *rt5665 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt5665->regmap, false); + regcache_sync(rt5665->regmap); + + return 0; +} +#else +#define rt5665_suspend NULL +#define rt5665_resume NULL +#endif + +#define RT5665_STEREO_RATES SNDRV_PCM_RATE_8000_192000 +#define RT5665_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt5665_aif_dai_ops = { + .hw_params = rt5665_hw_params, + .set_fmt = rt5665_set_dai_fmt, + .set_sysclk = rt5665_set_dai_sysclk, + .set_tdm_slot = rt5665_set_tdm_slot, + .set_pll = rt5665_set_dai_pll, + .set_bclk_ratio = rt5665_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt5665_dai[] = { + { + .name = "rt5665-aif1_1", + .id = RT5665_AIF1_1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 8, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF1_1 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif1_2", + .id = RT5665_AIF1_2, + .capture = { + .stream_name = "AIF1_2 Capture", + .channels_min = 1, + .channels_max = 8, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif2_1", + .id = RT5665_AIF2_1, + .playback = { + .stream_name = "AIF2_1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF2_1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif2_2", + .id = RT5665_AIF2_2, + .playback = { + .stream_name = "AIF2_2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF2_2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, + { + .name = "rt5665-aif3", + .id = RT5665_AIF3, + .playback = { + .stream_name = "AIF3 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .capture = { + .stream_name = "AIF3 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT5665_STEREO_RATES, + .formats = RT5665_FORMATS, + }, + .ops = &rt5665_aif_dai_ops, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt5665 = { + .probe = rt5665_probe, + .remove = rt5665_remove, + .suspend = rt5665_suspend, + .resume = rt5665_resume, + .set_bias_level = rt5665_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = rt5665_snd_controls, + .num_controls = ARRAY_SIZE(rt5665_snd_controls), + .dapm_widgets = rt5665_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt5665_dapm_widgets), + .dapm_routes = rt5665_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt5665_dapm_routes), + } +}; + + +static const struct regmap_config rt5665_regmap = { + .reg_bits = 16, + .val_bits = 16, + .max_register = 0x0400, + .volatile_reg = rt5665_volatile_register, + .readable_reg = rt5665_readable_register, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt5665_reg, + .num_reg_defaults = ARRAY_SIZE(rt5665_reg), + .use_single_rw = true, +}; + +static const struct i2c_device_id rt5665_i2c_id[] = { + {"rt5665", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt5665_i2c_id); + +static int rt5665_parse_dt(struct rt5665_priv *rt5665, struct device *dev) +{ + rt5665->pdata.in1_diff = of_property_read_bool(dev->of_node, + "realtek,in1-differential"); + rt5665->pdata.in2_diff = of_property_read_bool(dev->of_node, + "realtek,in2-differential"); + rt5665->pdata.in3_diff = of_property_read_bool(dev->of_node, + "realtek,in3-differential"); + rt5665->pdata.in4_diff = of_property_read_bool(dev->of_node, + "realtek,in4-differential"); + + of_property_read_u32(dev->of_node, "realtek,dmic1-data-pin", + &rt5665->pdata.dmic1_data_pin); + of_property_read_u32(dev->of_node, "realtek,dmic2-data-pin", + &rt5665->pdata.dmic2_data_pin); + of_property_read_u32(dev->of_node, "realtek,jd-src", + &rt5665->pdata.jd_src); + + rt5665->pdata.ldo1_en = of_get_named_gpio(dev->of_node, + "realtek,ldo1-en-gpios", 0); + + return 0; +} + +static void rt5665_calibrate(struct rt5665_priv *rt5665) +{ + int value, count; + + mutex_lock(&rt5665->calibrate_mutex); + + regcache_cache_bypass(rt5665->regmap, true); + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); + regmap_write(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, 0x0c26); + regmap_write(rt5665->regmap, RT5665_MONOMIX_IN_GAIN, 0x021f); + regmap_write(rt5665->regmap, RT5665_MONO_OUT, 0x480a); + regmap_write(rt5665->regmap, RT5665_PWR_MIXER, 0x083f); + regmap_write(rt5665->regmap, RT5665_PWR_DIG_1, 0x0180); + regmap_write(rt5665->regmap, RT5665_EJD_CTRL_1, 0x4040); + regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0000); + regmap_write(rt5665->regmap, RT5665_DIG_MISC, 0x0001); + regmap_write(rt5665->regmap, RT5665_MICBIAS_2, 0x0380); + regmap_write(rt5665->regmap, RT5665_GLB_CLK, 0x8000); + regmap_write(rt5665->regmap, RT5665_ADDA_CLK_1, 0x1000); + regmap_write(rt5665->regmap, RT5665_CHOP_DAC, 0x3030); + regmap_write(rt5665->regmap, RT5665_CALIB_ADC_CTRL, 0x3c05); + regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xaa3e); + usleep_range(15000, 20000); + regmap_write(rt5665->regmap, RT5665_PWR_ANLG_1, 0xfe7e); + regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_2, 0x0321); + + regmap_write(rt5665->regmap, RT5665_HP_CALIB_CTRL_1, 0xfc00); + count = 0; + while (true) { + regmap_read(rt5665->regmap, RT5665_HP_CALIB_STA_1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 60) { + pr_err("HP Calibration Failure\n"); + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regcache_cache_bypass(rt5665->regmap, false); + return; + } + + count++; + } + + regmap_write(rt5665->regmap, RT5665_MONO_AMP_CALIB_CTRL_1, 0x9e24); + count = 0; + while (true) { + regmap_read(rt5665->regmap, RT5665_MONO_AMP_CALIB_STA1, &value); + if (value & 0x8000) + usleep_range(10000, 10005); + else + break; + + if (count > 60) { + pr_err("MONO Calibration Failure\n"); + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regcache_cache_bypass(rt5665->regmap, false); + return; + } + + count++; + } + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + regcache_cache_bypass(rt5665->regmap, false); + + regcache_mark_dirty(rt5665->regmap); + regcache_sync(rt5665->regmap); + + regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); + regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); + + mutex_unlock(&rt5665->calibrate_mutex); +} + +static void rt5665_calibrate_handler(struct work_struct *work) +{ + struct rt5665_priv *rt5665 = container_of(work, struct rt5665_priv, + calibrate_work.work); + + while (!rt5665->codec->component.card->instantiated) { + pr_debug("%s\n", __func__); + usleep_range(10000, 15000); + } + + rt5665_calibrate(rt5665); +} + +static int rt5665_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt5665_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt5665_priv *rt5665; + int i, ret; + unsigned int val; + + rt5665 = devm_kzalloc(&i2c->dev, sizeof(struct rt5665_priv), + GFP_KERNEL); + + if (rt5665 == NULL) + return -ENOMEM; + + i2c_set_clientdata(i2c, rt5665); + + if (pdata) + rt5665->pdata = *pdata; + else + rt5665_parse_dt(rt5665, &i2c->dev); + + for (i = 0; i < ARRAY_SIZE(rt5665->supplies); i++) + rt5665->supplies[i].supply = rt5665_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(rt5665->supplies), + rt5665->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5665->supplies), + rt5665->supplies); + if (ret != 0) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + + if (gpio_is_valid(rt5665->pdata.ldo1_en)) { + if (devm_gpio_request(&i2c->dev, rt5665->pdata.ldo1_en, + "rt5665")) + dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); + else if (gpio_direction_output(rt5665->pdata.ldo1_en, 1)) + dev_err(&i2c->dev, "Fail gpio_direction gpio_ldo\n"); + } + + /* Sleep for 300 ms miniumum */ + usleep_range(300000, 350000); + + rt5665->regmap = devm_regmap_init_i2c(i2c, &rt5665_regmap); + if (IS_ERR(rt5665->regmap)) { + ret = PTR_ERR(rt5665->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt5665->regmap, RT5665_DEVICE_ID, &val); + if (val != DEVICE_ID) { + dev_err(&i2c->dev, + "Device with ID register %x is not rt5665\n", val); + return -ENODEV; + } + + regmap_read(rt5665->regmap, RT5665_RESET, &val); + switch (val) { + case 0x0: + rt5665->id = CODEC_5666; + break; + case 0x6: + rt5665->id = CODEC_5668; + break; + case 0x3: + default: + rt5665->id = CODEC_5665; + break; + } + + regmap_write(rt5665->regmap, RT5665_RESET, 0); + + /* line in diff mode*/ + if (rt5665->pdata.in1_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2, + RT5665_IN1_DF_MASK, RT5665_IN1_DF_MASK); + if (rt5665->pdata.in2_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN1_IN2, + RT5665_IN2_DF_MASK, RT5665_IN2_DF_MASK); + if (rt5665->pdata.in3_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4, + RT5665_IN3_DF_MASK, RT5665_IN3_DF_MASK); + if (rt5665->pdata.in4_diff) + regmap_update_bits(rt5665->regmap, RT5665_IN3_IN4, + RT5665_IN4_DF_MASK, RT5665_IN4_DF_MASK); + + /* DMIC pin*/ + if (rt5665->pdata.dmic1_data_pin != RT5665_DMIC1_NULL || + rt5665->pdata.dmic2_data_pin != RT5665_DMIC2_NULL) { + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2, + RT5665_GP9_PIN_MASK, RT5665_GP9_PIN_DMIC1_SCL); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP8_PIN_MASK, RT5665_GP8_PIN_DMIC2_SCL); + switch (rt5665->pdata.dmic1_data_pin) { + case RT5665_DMIC1_DATA_IN2N: + regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, + RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_IN2N); + break; + + case RT5665_DMIC1_DATA_GPIO4: + regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, + RT5665_DMIC_1_DP_MASK, RT5665_DMIC_1_DP_GPIO4); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP4_PIN_MASK, RT5665_GP4_PIN_DMIC1_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC1\n"); + break; + } + + switch (rt5665->pdata.dmic2_data_pin) { + case RT5665_DMIC2_DATA_IN2P: + regmap_update_bits(rt5665->regmap, RT5665_DMIC_CTRL_1, + RT5665_DMIC_2_DP_MASK, RT5665_DMIC_2_DP_IN2P); + break; + + case RT5665_DMIC2_DATA_GPIO5: + regmap_update_bits(rt5665->regmap, + RT5665_DMIC_CTRL_1, + RT5665_DMIC_2_DP_MASK, + RT5665_DMIC_2_DP_GPIO5); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_1, + RT5665_GP5_PIN_MASK, RT5665_GP5_PIN_DMIC2_SDA); + break; + + default: + dev_dbg(&i2c->dev, "no DMIC2\n"); + break; + + } + } + + regmap_write(rt5665->regmap, RT5665_HP_LOGIC_CTRL_2, 0x0002); + regmap_update_bits(rt5665->regmap, RT5665_EJD_CTRL_1, + 0xf000 | RT5665_VREF_POW_MASK, 0xd000 | RT5665_VREF_POW_REG); + /* Work around for pow_pump */ + regmap_update_bits(rt5665->regmap, RT5665_STO1_DAC_SIL_DET, + RT5665_DEB_STO_DAC_MASK, RT5665_DEB_80_MS); + + regmap_update_bits(rt5665->regmap, RT5665_HP_CHARGE_PUMP_1, + RT5665_PM_HP_MASK, RT5665_PM_HP_HV); + + /* Set GPIO4,8 as input for combo jack */ + if (rt5665->id == CODEC_5666) { + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_2, + RT5665_GP4_PF_MASK, RT5665_GP4_PF_IN); + regmap_update_bits(rt5665->regmap, RT5665_GPIO_CTRL_3, + RT5665_GP8_PF_MASK, RT5665_GP8_PF_IN); + } + + /* Enhance performance*/ + regmap_update_bits(rt5665->regmap, RT5665_PWR_ANLG_1, + RT5665_HP_DRIVER_MASK | RT5665_LDO1_DVO_MASK, + RT5665_HP_DRIVER_5X | RT5665_LDO1_DVO_09); + + INIT_DELAYED_WORK(&rt5665->jack_detect_work, + rt5665_jack_detect_handler); + INIT_DELAYED_WORK(&rt5665->calibrate_work, + rt5665_calibrate_handler); + INIT_DELAYED_WORK(&rt5665->jd_check_work, + rt5665_jd_check_handler); + + mutex_init(&rt5665->calibrate_mutex); + + if (i2c->irq) { + ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, + rt5665_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING + | IRQF_ONESHOT, "rt5665", rt5665); + if (ret) + dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + + } + + return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5665, + rt5665_dai, ARRAY_SIZE(rt5665_dai)); +} + +static int rt5665_i2c_remove(struct i2c_client *i2c) +{ + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + +static void rt5665_i2c_shutdown(struct i2c_client *client) +{ + struct rt5665_priv *rt5665 = i2c_get_clientdata(client); + + regmap_write(rt5665->regmap, RT5665_RESET, 0); +} + +#ifdef CONFIG_OF +static const struct of_device_id rt5665_of_match[] = { + {.compatible = "realtek,rt5665"}, + {.compatible = "realtek,rt5666"}, + {.compatible = "realtek,rt5668"}, + {}, +}; +MODULE_DEVICE_TABLE(of, rt5665_of_match); +#endif + +#ifdef CONFIG_ACPI +static struct acpi_device_id rt5665_acpi_match[] = { + {"10EC5665", 0,}, + {"10EC5666", 0,}, + {"10EC5668", 0,}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match); +#endif + +struct i2c_driver rt5665_i2c_driver = { + .driver = { + .name = "rt5665", + .of_match_table = of_match_ptr(rt5665_of_match), + .acpi_match_table = ACPI_PTR(rt5665_acpi_match), + }, + .probe = rt5665_i2c_probe, + .remove = rt5665_i2c_remove, + .shutdown = rt5665_i2c_shutdown, + .id_table = rt5665_i2c_id, +}; +module_i2c_driver(rt5665_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT5665 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/rt5665.h b/sound/soc/codecs/rt5665.h new file mode 100644 index 000000000000..12f7080a0d3c --- /dev/null +++ b/sound/soc/codecs/rt5665.h @@ -0,0 +1,1990 @@ +/* + * rt5665.h -- RT5665/RT5658 ALSA SoC audio driver + * + * Copyright 2016 Realtek Microelectronics + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT5665_H__ +#define __RT5665_H__ + +#include + +#define DEVICE_ID 0x6451 + +/* Info */ +#define RT5665_RESET 0x0000 +#define RT5665_VENDOR_ID 0x00fd +#define RT5665_VENDOR_ID_1 0x00fe +#define RT5665_DEVICE_ID 0x00ff +/* I/O - Output */ +#define RT5665_LOUT 0x0001 +#define RT5665_HP_CTRL_1 0x0002 +#define RT5665_HP_CTRL_2 0x0003 +#define RT5665_MONO_OUT 0x0004 +#define RT5665_HPL_GAIN 0x0005 +#define RT5665_HPR_GAIN 0x0006 +#define RT5665_MONO_GAIN 0x0007 + +/* I/O - Input */ +#define RT5665_CAL_BST_CTRL 0x000a +#define RT5665_CBJ_BST_CTRL 0x000b +#define RT5665_IN1_IN2 0x000c +#define RT5665_IN3_IN4 0x000d +#define RT5665_INL1_INR1_VOL 0x000f +/* I/O - Speaker */ +#define RT5665_EJD_CTRL_1 0x0010 +#define RT5665_EJD_CTRL_2 0x0011 +#define RT5665_EJD_CTRL_3 0x0012 +#define RT5665_EJD_CTRL_4 0x0013 +#define RT5665_EJD_CTRL_5 0x0014 +#define RT5665_EJD_CTRL_6 0x0015 +#define RT5665_EJD_CTRL_7 0x0016 +/* I/O - ADC/DAC/DMIC */ +#define RT5665_DAC2_CTRL 0x0017 +#define RT5665_DAC2_DIG_VOL 0x0018 +#define RT5665_DAC1_DIG_VOL 0x0019 +#define RT5665_DAC3_DIG_VOL 0x001a +#define RT5665_DAC3_CTRL 0x001b +#define RT5665_STO1_ADC_DIG_VOL 0x001c +#define RT5665_MONO_ADC_DIG_VOL 0x001d +#define RT5665_STO2_ADC_DIG_VOL 0x001e +#define RT5665_STO1_ADC_BOOST 0x001f +#define RT5665_MONO_ADC_BOOST 0x0020 +#define RT5665_STO2_ADC_BOOST 0x0021 +#define RT5665_HP_IMP_GAIN_1 0x0022 +#define RT5665_HP_IMP_GAIN_2 0x0023 +/* Mixer - D-D */ +#define RT5665_STO1_ADC_MIXER 0x0026 +#define RT5665_MONO_ADC_MIXER 0x0027 +#define RT5665_STO2_ADC_MIXER 0x0028 +#define RT5665_AD_DA_MIXER 0x0029 +#define RT5665_STO1_DAC_MIXER 0x002a +#define RT5665_MONO_DAC_MIXER 0x002b +#define RT5665_STO2_DAC_MIXER 0x002c +#define RT5665_A_DAC1_MUX 0x002d +#define RT5665_A_DAC2_MUX 0x002e +#define RT5665_DIG_INF2_DATA 0x002f +#define RT5665_DIG_INF3_DATA 0x0030 +/* Mixer - PDM */ +#define RT5665_PDM_OUT_CTRL 0x0031 +#define RT5665_PDM_DATA_CTRL_1 0x0032 +#define RT5665_PDM_DATA_CTRL_2 0x0033 +#define RT5665_PDM_DATA_CTRL_3 0x0034 +#define RT5665_PDM_DATA_CTRL_4 0x0035 +/* Mixer - ADC */ +#define RT5665_REC1_GAIN 0x003a +#define RT5665_REC1_L1_MIXER 0x003b +#define RT5665_REC1_L2_MIXER 0x003c +#define RT5665_REC1_R1_MIXER 0x003d +#define RT5665_REC1_R2_MIXER 0x003e +#define RT5665_REC2_GAIN 0x003f +#define RT5665_REC2_L1_MIXER 0x0040 +#define RT5665_REC2_L2_MIXER 0x0041 +#define RT5665_REC2_R1_MIXER 0x0042 +#define RT5665_REC2_R2_MIXER 0x0043 +#define RT5665_CAL_REC 0x0044 +/* Mixer - DAC */ +#define RT5665_ALC_BACK_GAIN 0x0049 +#define RT5665_MONOMIX_GAIN 0x004a +#define RT5665_MONOMIX_IN_GAIN 0x004b +#define RT5665_OUT_L_GAIN 0x004d +#define RT5665_OUT_L_MIXER 0x004e +#define RT5665_OUT_R_GAIN 0x004f +#define RT5665_OUT_R_MIXER 0x0050 +#define RT5665_LOUT_MIXER 0x0052 +/* Power */ +#define RT5665_PWR_DIG_1 0x0061 +#define RT5665_PWR_DIG_2 0x0062 +#define RT5665_PWR_ANLG_1 0x0063 +#define RT5665_PWR_ANLG_2 0x0064 +#define RT5665_PWR_ANLG_3 0x0065 +#define RT5665_PWR_MIXER 0x0066 +#define RT5665_PWR_VOL 0x0067 +/* Clock Detect */ +#define RT5665_CLK_DET 0x006b +/* Filter */ +#define RT5665_HPF_CTRL1 0x006d +/* DMIC */ +#define RT5665_DMIC_CTRL_1 0x006e +#define RT5665_DMIC_CTRL_2 0x006f +/* Format - ADC/DAC */ +#define RT5665_I2S1_SDP 0x0070 +#define RT5665_I2S2_SDP 0x0071 +#define RT5665_I2S3_SDP 0x0072 +#define RT5665_ADDA_CLK_1 0x0073 +#define RT5665_ADDA_CLK_2 0x0074 +#define RT5665_I2S1_F_DIV_CTRL_1 0x0075 +#define RT5665_I2S1_F_DIV_CTRL_2 0x0076 +/* Format - TDM Control */ +#define RT5665_TDM_CTRL_1 0x0078 +#define RT5665_TDM_CTRL_2 0x0079 +#define RT5665_TDM_CTRL_3 0x007a +#define RT5665_TDM_CTRL_4 0x007b +#define RT5665_TDM_CTRL_5 0x007c +#define RT5665_TDM_CTRL_6 0x007d +#define RT5665_TDM_CTRL_7 0x007e +#define RT5665_TDM_CTRL_8 0x007f +/* Function - Analog */ +#define RT5665_GLB_CLK 0x0080 +#define RT5665_PLL_CTRL_1 0x0081 +#define RT5665_PLL_CTRL_2 0x0082 +#define RT5665_ASRC_1 0x0083 +#define RT5665_ASRC_2 0x0084 +#define RT5665_ASRC_3 0x0085 +#define RT5665_ASRC_4 0x0086 +#define RT5665_ASRC_5 0x0087 +#define RT5665_ASRC_6 0x0088 +#define RT5665_ASRC_7 0x0089 +#define RT5665_ASRC_8 0x008a +#define RT5665_ASRC_9 0x008b +#define RT5665_ASRC_10 0x008c +#define RT5665_DEPOP_1 0x008e +#define RT5665_DEPOP_2 0x008f +#define RT5665_HP_CHARGE_PUMP_1 0x0091 +#define RT5665_HP_CHARGE_PUMP_2 0x0092 +#define RT5665_MICBIAS_1 0x0093 +#define RT5665_MICBIAS_2 0x0094 +#define RT5665_ASRC_12 0x0098 +#define RT5665_ASRC_13 0x0099 +#define RT5665_ASRC_14 0x009a +#define RT5665_RC_CLK_CTRL 0x009f +#define RT5665_I2S_M_CLK_CTRL_1 0x00a0 +#define RT5665_I2S2_F_DIV_CTRL_1 0x00a1 +#define RT5665_I2S2_F_DIV_CTRL_2 0x00a2 +#define RT5665_I2S3_F_DIV_CTRL_1 0x00a3 +#define RT5665_I2S3_F_DIV_CTRL_2 0x00a4 +/* Function - Digital */ +#define RT5665_EQ_CTRL_1 0x00ae +#define RT5665_EQ_CTRL_2 0x00af +#define RT5665_IRQ_CTRL_1 0x00b6 +#define RT5665_IRQ_CTRL_2 0x00b7 +#define RT5665_IRQ_CTRL_3 0x00b8 +#define RT5665_IRQ_CTRL_4 0x00b9 +#define RT5665_IRQ_CTRL_5 0x00ba +#define RT5665_IRQ_CTRL_6 0x00bb +#define RT5665_INT_ST_1 0x00be +#define RT5665_GPIO_CTRL_1 0x00c0 +#define RT5665_GPIO_CTRL_2 0x00c1 +#define RT5665_GPIO_CTRL_3 0x00c2 +#define RT5665_GPIO_CTRL_4 0x00c3 +#define RT5665_GPIO_STA 0x00c4 +#define RT5665_HP_AMP_DET_CTRL_1 0x00d0 +#define RT5665_HP_AMP_DET_CTRL_2 0x00d1 +#define RT5665_MID_HP_AMP_DET 0x00d3 +#define RT5665_LOW_HP_AMP_DET 0x00d4 +#define RT5665_SV_ZCD_1 0x00d9 +#define RT5665_SV_ZCD_2 0x00da +#define RT5665_IL_CMD_1 0x00db +#define RT5665_IL_CMD_2 0x00dc +#define RT5665_IL_CMD_3 0x00dd +#define RT5665_IL_CMD_4 0x00de +#define RT5665_4BTN_IL_CMD_1 0x00df +#define RT5665_4BTN_IL_CMD_2 0x00e0 +#define RT5665_4BTN_IL_CMD_3 0x00e1 +#define RT5665_PSV_IL_CMD_1 0x00e2 + +#define RT5665_ADC_STO1_HP_CTRL_1 0x00ea +#define RT5665_ADC_STO1_HP_CTRL_2 0x00eb +#define RT5665_ADC_MONO_HP_CTRL_1 0x00ec +#define RT5665_ADC_MONO_HP_CTRL_2 0x00ed +#define RT5665_ADC_STO2_HP_CTRL_1 0x00ee +#define RT5665_ADC_STO2_HP_CTRL_2 0x00ef +#define RT5665_AJD1_CTRL 0x00f0 +#define RT5665_JD1_THD 0x00f1 +#define RT5665_JD2_THD 0x00f2 +#define RT5665_JD_CTRL_1 0x00f6 +#define RT5665_JD_CTRL_2 0x00f7 +#define RT5665_JD_CTRL_3 0x00f8 +/* General Control */ +#define RT5665_DIG_MISC 0x00fa +#define RT5665_DUMMY_2 0x00fb +#define RT5665_DUMMY_3 0x00fc + +#define RT5665_DAC_ADC_DIG_VOL1 0x0100 +#define RT5665_DAC_ADC_DIG_VOL2 0x0101 +#define RT5665_BIAS_CUR_CTRL_1 0x010a +#define RT5665_BIAS_CUR_CTRL_2 0x010b +#define RT5665_BIAS_CUR_CTRL_3 0x010c +#define RT5665_BIAS_CUR_CTRL_4 0x010d +#define RT5665_BIAS_CUR_CTRL_5 0x010e +#define RT5665_BIAS_CUR_CTRL_6 0x010f +#define RT5665_BIAS_CUR_CTRL_7 0x0110 +#define RT5665_BIAS_CUR_CTRL_8 0x0111 +#define RT5665_BIAS_CUR_CTRL_9 0x0112 +#define RT5665_BIAS_CUR_CTRL_10 0x0113 +#define RT5665_VREF_REC_OP_FB_CAP_CTRL 0x0117 +#define RT5665_CHARGE_PUMP_1 0x0125 +#define RT5665_DIG_IN_CTRL_1 0x0132 +#define RT5665_DIG_IN_CTRL_2 0x0133 +#define RT5665_PAD_DRIVING_CTRL 0x0137 +#define RT5665_SOFT_RAMP_DEPOP 0x0138 +#define RT5665_PLL 0x0139 +#define RT5665_CHOP_DAC 0x013a +#define RT5665_CHOP_ADC 0x013b +#define RT5665_CALIB_ADC_CTRL 0x013c +#define RT5665_VOL_TEST 0x013f +#define RT5665_TEST_MODE_CTRL_1 0x0145 +#define RT5665_TEST_MODE_CTRL_2 0x0146 +#define RT5665_TEST_MODE_CTRL_3 0x0147 +#define RT5665_TEST_MODE_CTRL_4 0x0148 +#define RT5665_BASSBACK_CTRL 0x0150 +#define RT5665_STO_NG2_CTRL_1 0x0160 +#define RT5665_STO_NG2_CTRL_2 0x0161 +#define RT5665_STO_NG2_CTRL_3 0x0162 +#define RT5665_STO_NG2_CTRL_4 0x0163 +#define RT5665_STO_NG2_CTRL_5 0x0164 +#define RT5665_STO_NG2_CTRL_6 0x0165 +#define RT5665_STO_NG2_CTRL_7 0x0166 +#define RT5665_STO_NG2_CTRL_8 0x0167 +#define RT5665_MONO_NG2_CTRL_1 0x0170 +#define RT5665_MONO_NG2_CTRL_2 0x0171 +#define RT5665_MONO_NG2_CTRL_3 0x0172 +#define RT5665_MONO_NG2_CTRL_4 0x0173 +#define RT5665_MONO_NG2_CTRL_5 0x0174 +#define RT5665_MONO_NG2_CTRL_6 0x0175 +#define RT5665_STO1_DAC_SIL_DET 0x0190 +#define RT5665_MONOL_DAC_SIL_DET 0x0191 +#define RT5665_MONOR_DAC_SIL_DET 0x0192 +#define RT5665_STO2_DAC_SIL_DET 0x0193 +#define RT5665_SIL_PSV_CTRL1 0x0194 +#define RT5665_SIL_PSV_CTRL2 0x0195 +#define RT5665_SIL_PSV_CTRL3 0x0196 +#define RT5665_SIL_PSV_CTRL4 0x0197 +#define RT5665_SIL_PSV_CTRL5 0x0198 +#define RT5665_SIL_PSV_CTRL6 0x0199 +#define RT5665_MONO_AMP_CALIB_CTRL_1 0x01a0 +#define RT5665_MONO_AMP_CALIB_CTRL_2 0x01a1 +#define RT5665_MONO_AMP_CALIB_CTRL_3 0x01a2 +#define RT5665_MONO_AMP_CALIB_CTRL_4 0x01a3 +#define RT5665_MONO_AMP_CALIB_CTRL_5 0x01a4 +#define RT5665_MONO_AMP_CALIB_CTRL_6 0x01a5 +#define RT5665_MONO_AMP_CALIB_CTRL_7 0x01a6 +#define RT5665_MONO_AMP_CALIB_STA1 0x01a7 +#define RT5665_MONO_AMP_CALIB_STA2 0x01a8 +#define RT5665_MONO_AMP_CALIB_STA3 0x01a9 +#define RT5665_MONO_AMP_CALIB_STA4 0x01aa +#define RT5665_MONO_AMP_CALIB_STA6 0x01ab +#define RT5665_HP_IMP_SENS_CTRL_01 0x01b5 +#define RT5665_HP_IMP_SENS_CTRL_02 0x01b6 +#define RT5665_HP_IMP_SENS_CTRL_03 0x01b7 +#define RT5665_HP_IMP_SENS_CTRL_04 0x01b8 +#define RT5665_HP_IMP_SENS_CTRL_05 0x01b9 +#define RT5665_HP_IMP_SENS_CTRL_06 0x01ba +#define RT5665_HP_IMP_SENS_CTRL_07 0x01bb +#define RT5665_HP_IMP_SENS_CTRL_08 0x01bc +#define RT5665_HP_IMP_SENS_CTRL_09 0x01bd +#define RT5665_HP_IMP_SENS_CTRL_10 0x01be +#define RT5665_HP_IMP_SENS_CTRL_11 0x01bf +#define RT5665_HP_IMP_SENS_CTRL_12 0x01c0 +#define RT5665_HP_IMP_SENS_CTRL_13 0x01c1 +#define RT5665_HP_IMP_SENS_CTRL_14 0x01c2 +#define RT5665_HP_IMP_SENS_CTRL_15 0x01c3 +#define RT5665_HP_IMP_SENS_CTRL_16 0x01c4 +#define RT5665_HP_IMP_SENS_CTRL_17 0x01c5 +#define RT5665_HP_IMP_SENS_CTRL_18 0x01c6 +#define RT5665_HP_IMP_SENS_CTRL_19 0x01c7 +#define RT5665_HP_IMP_SENS_CTRL_20 0x01c8 +#define RT5665_HP_IMP_SENS_CTRL_21 0x01c9 +#define RT5665_HP_IMP_SENS_CTRL_22 0x01ca +#define RT5665_HP_IMP_SENS_CTRL_23 0x01cb +#define RT5665_HP_IMP_SENS_CTRL_24 0x01cc +#define RT5665_HP_IMP_SENS_CTRL_25 0x01cd +#define RT5665_HP_IMP_SENS_CTRL_26 0x01ce +#define RT5665_HP_IMP_SENS_CTRL_27 0x01cf +#define RT5665_HP_IMP_SENS_CTRL_28 0x01d0 +#define RT5665_HP_IMP_SENS_CTRL_29 0x01d1 +#define RT5665_HP_IMP_SENS_CTRL_30 0x01d2 +#define RT5665_HP_IMP_SENS_CTRL_31 0x01d3 +#define RT5665_HP_IMP_SENS_CTRL_32 0x01d4 +#define RT5665_HP_IMP_SENS_CTRL_33 0x01d5 +#define RT5665_HP_IMP_SENS_CTRL_34 0x01d6 +#define RT5665_HP_LOGIC_CTRL_1 0x01da +#define RT5665_HP_LOGIC_CTRL_2 0x01db +#define RT5665_HP_LOGIC_CTRL_3 0x01dc +#define RT5665_HP_CALIB_CTRL_1 0x01de +#define RT5665_HP_CALIB_CTRL_2 0x01df +#define RT5665_HP_CALIB_CTRL_3 0x01e0 +#define RT5665_HP_CALIB_CTRL_4 0x01e1 +#define RT5665_HP_CALIB_CTRL_5 0x01e2 +#define RT5665_HP_CALIB_CTRL_6 0x01e3 +#define RT5665_HP_CALIB_CTRL_7 0x01e4 +#define RT5665_HP_CALIB_CTRL_9 0x01e6 +#define RT5665_HP_CALIB_CTRL_10 0x01e7 +#define RT5665_HP_CALIB_CTRL_11 0x01e8 +#define RT5665_HP_CALIB_STA_1 0x01ea +#define RT5665_HP_CALIB_STA_2 0x01eb +#define RT5665_HP_CALIB_STA_3 0x01ec +#define RT5665_HP_CALIB_STA_4 0x01ed +#define RT5665_HP_CALIB_STA_5 0x01ee +#define RT5665_HP_CALIB_STA_6 0x01ef +#define RT5665_HP_CALIB_STA_7 0x01f0 +#define RT5665_HP_CALIB_STA_8 0x01f1 +#define RT5665_HP_CALIB_STA_9 0x01f2 +#define RT5665_HP_CALIB_STA_10 0x01f3 +#define RT5665_HP_CALIB_STA_11 0x01f4 +#define RT5665_PGM_TAB_CTRL1 0x0200 +#define RT5665_PGM_TAB_CTRL2 0x0201 +#define RT5665_PGM_TAB_CTRL3 0x0202 +#define RT5665_PGM_TAB_CTRL4 0x0203 +#define RT5665_PGM_TAB_CTRL5 0x0204 +#define RT5665_PGM_TAB_CTRL6 0x0205 +#define RT5665_PGM_TAB_CTRL7 0x0206 +#define RT5665_PGM_TAB_CTRL8 0x0207 +#define RT5665_PGM_TAB_CTRL9 0x0208 +#define RT5665_SAR_IL_CMD_1 0x0210 +#define RT5665_SAR_IL_CMD_2 0x0211 +#define RT5665_SAR_IL_CMD_3 0x0212 +#define RT5665_SAR_IL_CMD_4 0x0213 +#define RT5665_SAR_IL_CMD_5 0x0214 +#define RT5665_SAR_IL_CMD_6 0x0215 +#define RT5665_SAR_IL_CMD_7 0x0216 +#define RT5665_SAR_IL_CMD_8 0x0217 +#define RT5665_SAR_IL_CMD_9 0x0218 +#define RT5665_SAR_IL_CMD_10 0x0219 +#define RT5665_SAR_IL_CMD_11 0x021a +#define RT5665_SAR_IL_CMD_12 0x021b +#define RT5665_DRC1_CTRL_0 0x02ff +#define RT5665_DRC1_CTRL_1 0x0300 +#define RT5665_DRC1_CTRL_2 0x0301 +#define RT5665_DRC1_CTRL_3 0x0302 +#define RT5665_DRC1_CTRL_4 0x0303 +#define RT5665_DRC1_CTRL_5 0x0304 +#define RT5665_DRC1_CTRL_6 0x0305 +#define RT5665_DRC1_HARD_LMT_CTRL_1 0x0306 +#define RT5665_DRC1_HARD_LMT_CTRL_2 0x0307 +#define RT5665_DRC1_PRIV_1 0x0310 +#define RT5665_DRC1_PRIV_2 0x0311 +#define RT5665_DRC1_PRIV_3 0x0312 +#define RT5665_DRC1_PRIV_4 0x0313 +#define RT5665_DRC1_PRIV_5 0x0314 +#define RT5665_DRC1_PRIV_6 0x0315 +#define RT5665_DRC1_PRIV_7 0x0316 +#define RT5665_DRC1_PRIV_8 0x0317 +#define RT5665_ALC_PGA_CTRL_1 0x0330 +#define RT5665_ALC_PGA_CTRL_2 0x0331 +#define RT5665_ALC_PGA_CTRL_3 0x0332 +#define RT5665_ALC_PGA_CTRL_4 0x0333 +#define RT5665_ALC_PGA_CTRL_5 0x0334 +#define RT5665_ALC_PGA_CTRL_6 0x0335 +#define RT5665_ALC_PGA_CTRL_7 0x0336 +#define RT5665_ALC_PGA_CTRL_8 0x0337 +#define RT5665_ALC_PGA_STA_1 0x0338 +#define RT5665_ALC_PGA_STA_2 0x0339 +#define RT5665_ALC_PGA_STA_3 0x033a +#define RT5665_EQ_AUTO_RCV_CTRL1 0x03c0 +#define RT5665_EQ_AUTO_RCV_CTRL2 0x03c1 +#define RT5665_EQ_AUTO_RCV_CTRL3 0x03c2 +#define RT5665_EQ_AUTO_RCV_CTRL4 0x03c3 +#define RT5665_EQ_AUTO_RCV_CTRL5 0x03c4 +#define RT5665_EQ_AUTO_RCV_CTRL6 0x03c5 +#define RT5665_EQ_AUTO_RCV_CTRL7 0x03c6 +#define RT5665_EQ_AUTO_RCV_CTRL8 0x03c7 +#define RT5665_EQ_AUTO_RCV_CTRL9 0x03c8 +#define RT5665_EQ_AUTO_RCV_CTRL10 0x03c9 +#define RT5665_EQ_AUTO_RCV_CTRL11 0x03ca +#define RT5665_EQ_AUTO_RCV_CTRL12 0x03cb +#define RT5665_EQ_AUTO_RCV_CTRL13 0x03cc +#define RT5665_ADC_L_EQ_LPF1_A1 0x03d0 +#define RT5665_R_EQ_LPF1_A1 0x03d1 +#define RT5665_L_EQ_LPF1_H0 0x03d2 +#define RT5665_R_EQ_LPF1_H0 0x03d3 +#define RT5665_L_EQ_BPF1_A1 0x03d4 +#define RT5665_R_EQ_BPF1_A1 0x03d5 +#define RT5665_L_EQ_BPF1_A2 0x03d6 +#define RT5665_R_EQ_BPF1_A2 0x03d7 +#define RT5665_L_EQ_BPF1_H0 0x03d8 +#define RT5665_R_EQ_BPF1_H0 0x03d9 +#define RT5665_L_EQ_BPF2_A1 0x03da +#define RT5665_R_EQ_BPF2_A1 0x03db +#define RT5665_L_EQ_BPF2_A2 0x03dc +#define RT5665_R_EQ_BPF2_A2 0x03dd +#define RT5665_L_EQ_BPF2_H0 0x03de +#define RT5665_R_EQ_BPF2_H0 0x03df +#define RT5665_L_EQ_BPF3_A1 0x03e0 +#define RT5665_R_EQ_BPF3_A1 0x03e1 +#define RT5665_L_EQ_BPF3_A2 0x03e2 +#define RT5665_R_EQ_BPF3_A2 0x03e3 +#define RT5665_L_EQ_BPF3_H0 0x03e4 +#define RT5665_R_EQ_BPF3_H0 0x03e5 +#define RT5665_L_EQ_BPF4_A1 0x03e6 +#define RT5665_R_EQ_BPF4_A1 0x03e7 +#define RT5665_L_EQ_BPF4_A2 0x03e8 +#define RT5665_R_EQ_BPF4_A2 0x03e9 +#define RT5665_L_EQ_BPF4_H0 0x03ea +#define RT5665_R_EQ_BPF4_H0 0x03eb +#define RT5665_L_EQ_HPF1_A1 0x03ec +#define RT5665_R_EQ_HPF1_A1 0x03ed +#define RT5665_L_EQ_HPF1_H0 0x03ee +#define RT5665_R_EQ_HPF1_H0 0x03ef +#define RT5665_L_EQ_PRE_VOL 0x03f0 +#define RT5665_R_EQ_PRE_VOL 0x03f1 +#define RT5665_L_EQ_POST_VOL 0x03f2 +#define RT5665_R_EQ_POST_VOL 0x03f3 +#define RT5665_SCAN_MODE_CTRL 0x07f0 +#define RT5665_I2C_MODE 0x07fa + + + +/* global definition */ +#define RT5665_L_MUTE (0x1 << 15) +#define RT5665_L_MUTE_SFT 15 +#define RT5665_VOL_L_MUTE (0x1 << 14) +#define RT5665_VOL_L_SFT 14 +#define RT5665_R_MUTE (0x1 << 7) +#define RT5665_R_MUTE_SFT 7 +#define RT5665_VOL_R_MUTE (0x1 << 6) +#define RT5665_VOL_R_SFT 6 +#define RT5665_L_VOL_MASK (0x3f << 8) +#define RT5665_L_VOL_SFT 8 +#define RT5665_R_VOL_MASK (0x3f) +#define RT5665_R_VOL_SFT 0 + +/*Headphone Amp L/R Analog Gain and Digital NG2 Gain Control (0x0005 0x0006)*/ +#define RT5665_G_HP (0xf << 8) +#define RT5665_G_HP_SFT 8 +#define RT5665_G_STO_DA_DMIX (0xf) +#define RT5665_G_STO_DA_SFT 0 + +/* CBJ Control (0x000b) */ +#define RT5665_BST_CBJ_MASK (0xf << 8) +#define RT5665_BST_CBJ_SFT 8 + +/* IN1/IN2 Control (0x000c) */ +#define RT5665_IN1_DF_MASK (0x1 << 15) +#define RT5665_IN1_DF 15 +#define RT5665_BST1_MASK (0x7f << 8) +#define RT5665_BST1_SFT 8 +#define RT5665_IN2_DF_MASK (0x1 << 7) +#define RT5665_IN2_DF 7 +#define RT5665_BST2_MASK (0x7f) +#define RT5665_BST2_SFT 0 + +/* IN3/IN4 Control (0x000d) */ +#define RT5665_IN3_DF_MASK (0x1 << 15) +#define RT5665_IN3_DF 15 +#define RT5665_BST3_MASK (0x7f << 8) +#define RT5665_BST3_SFT 8 +#define RT5665_IN4_DF_MASK (0x1 << 7) +#define RT5665_IN4_DF 7 +#define RT5665_BST4_MASK (0x7f) +#define RT5665_BST4_SFT 0 + +/* INL and INR Volume Control (0x000f) */ +#define RT5665_INL_VOL_MASK (0x1f << 8) +#define RT5665_INL_VOL_SFT 8 +#define RT5665_INR_VOL_MASK (0x1f) +#define RT5665_INR_VOL_SFT 0 + +/* Embeeded Jack and Type Detection Control 1 (0x0010) */ +#define RT5665_EMB_JD_EN (0x1 << 15) +#define RT5665_EMB_JD_EN_SFT 15 +#define RT5665_JD_MODE (0x1 << 13) +#define RT5665_JD_MODE_SFT 13 +#define RT5665_POLA_EXT_JD_MASK (0x1 << 11) +#define RT5665_POLA_EXT_JD_LOW (0x1 << 11) +#define RT5665_POLA_EXT_JD_HIGH (0x0 << 11) +#define RT5665_EXT_JD_DIG (0x1 << 9) +#define RT5665_POL_FAST_OFF_MASK (0x1 << 8) +#define RT5665_POL_FAST_OFF_HIGH (0x1 << 8) +#define RT5665_POL_FAST_OFF_LOW (0x0 << 8) +#define RT5665_VREF_POW_MASK (0x1 << 6) +#define RT5665_VREF_POW_FSM (0x0 << 6) +#define RT5665_VREF_POW_REG (0x1 << 6) +#define RT5665_MB1_PATH_MASK (0x1 << 5) +#define RT5665_CTRL_MB1_REG (0x1 << 5) +#define RT5665_CTRL_MB1_FSM (0x0 << 5) +#define RT5665_MB2_PATH_MASK (0x1 << 4) +#define RT5665_CTRL_MB2_REG (0x1 << 4) +#define RT5665_CTRL_MB2_FSM (0x0 << 4) +#define RT5665_TRIG_JD_MASK (0x1 << 3) +#define RT5665_TRIG_JD_HIGH (0x1 << 3) +#define RT5665_TRIG_JD_LOW (0x0 << 3) + +/* Embeeded Jack and Type Detection Control 2 (0x0011) */ +#define RT5665_EXT_JD_SRC (0x7 << 4) +#define RT5665_EXT_JD_SRC_SFT 4 +#define RT5665_EXT_JD_SRC_GPIO_JD1 (0x0 << 4) +#define RT5665_EXT_JD_SRC_GPIO_JD2 (0x1 << 4) +#define RT5665_EXT_JD_SRC_JD1_1 (0x2 << 4) +#define RT5665_EXT_JD_SRC_JD1_2 (0x3 << 4) +#define RT5665_EXT_JD_SRC_JD2 (0x4 << 4) +#define RT5665_EXT_JD_SRC_JD3 (0x5 << 4) +#define RT5665_EXT_JD_SRC_MANUAL (0x6 << 4) + +/* Combo Jack and Type Detection Control 4 (0x0013) */ +#define RT5665_SEL_SHT_MID_TON_MASK (0x3 << 12) +#define RT5665_SEL_SHT_MID_TON_2 (0x0 << 12) +#define RT5665_SEL_SHT_MID_TON_3 (0x1 << 12) +#define RT5665_CBJ_JD_TEST_MASK (0x1 << 6) +#define RT5665_CBJ_JD_TEST_NORM (0x0 << 6) +#define RT5665_CBJ_JD_TEST_MODE (0x1 << 6) + +/* Slience Detection Control (0x0015) */ +#define RT5665_SIL_DET_MASK (0x1 << 15) +#define RT5665_SIL_DET_DIS (0x0 << 15) +#define RT5665_SIL_DET_EN (0x1 << 15) + +/* DAC2 Control (0x0017) */ +#define RT5665_M_DAC2_L_VOL (0x1 << 13) +#define RT5665_M_DAC2_L_VOL_SFT 13 +#define RT5665_M_DAC2_R_VOL (0x1 << 12) +#define RT5665_M_DAC2_R_VOL_SFT 12 +#define RT5665_DAC_L2_SEL_MASK (0x7 << 4) +#define RT5665_DAC_L2_SEL_SFT 4 +#define RT5665_DAC_R2_SEL_MASK (0x7 << 0) +#define RT5665_DAC_R2_SEL_SFT 0 + +/* Sidetone Control (0x0018) */ +#define RT5665_ST_SEL_MASK (0x7 << 9) +#define RT5665_ST_SEL_SFT 9 +#define RT5665_ST_EN (0x1 << 6) +#define RT5665_ST_EN_SFT 6 + +/* DAC1 Digital Volume (0x0019) */ +#define RT5665_DAC_L1_VOL_MASK (0xff << 8) +#define RT5665_DAC_L1_VOL_SFT 8 +#define RT5665_DAC_R1_VOL_MASK (0xff) +#define RT5665_DAC_R1_VOL_SFT 0 + +/* DAC2 Digital Volume (0x001a) */ +#define RT5665_DAC_L2_VOL_MASK (0xff << 8) +#define RT5665_DAC_L2_VOL_SFT 8 +#define RT5665_DAC_R2_VOL_MASK (0xff) +#define RT5665_DAC_R2_VOL_SFT 0 + +/* DAC3 Control (0x001b) */ +#define RT5665_M_DAC3_L_VOL (0x1 << 13) +#define RT5665_M_DAC3_L_VOL_SFT 13 +#define RT5665_M_DAC3_R_VOL (0x1 << 12) +#define RT5665_M_DAC3_R_VOL_SFT 12 +#define RT5665_DAC_L3_SEL_MASK (0x7 << 4) +#define RT5665_DAC_L3_SEL_SFT 4 +#define RT5665_DAC_R3_SEL_MASK (0x7 << 0) +#define RT5665_DAC_R3_SEL_SFT 0 + +/* ADC Digital Volume Control (0x001c) */ +#define RT5665_ADC_L_VOL_MASK (0x7f << 8) +#define RT5665_ADC_L_VOL_SFT 8 +#define RT5665_ADC_R_VOL_MASK (0x7f) +#define RT5665_ADC_R_VOL_SFT 0 + +/* Mono ADC Digital Volume Control (0x001d) */ +#define RT5665_MONO_ADC_L_VOL_MASK (0x7f << 8) +#define RT5665_MONO_ADC_L_VOL_SFT 8 +#define RT5665_MONO_ADC_R_VOL_MASK (0x7f) +#define RT5665_MONO_ADC_R_VOL_SFT 0 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5665_STO1_ADC_L_BST_MASK (0x3 << 14) +#define RT5665_STO1_ADC_L_BST_SFT 14 +#define RT5665_STO1_ADC_R_BST_MASK (0x3 << 12) +#define RT5665_STO1_ADC_R_BST_SFT 12 + +/* Mono ADC Boost Gain Control (0x0020) */ +#define RT5665_MONO_ADC_L_BST_MASK (0x3 << 14) +#define RT5665_MONO_ADC_L_BST_SFT 14 +#define RT5665_MONO_ADC_R_BST_MASK (0x3 << 12) +#define RT5665_MONO_ADC_R_BST_SFT 12 + +/* Stereo1 ADC Boost Gain Control (0x001f) */ +#define RT5665_STO2_ADC_L_BST_MASK (0x3 << 14) +#define RT5665_STO2_ADC_L_BST_SFT 14 +#define RT5665_STO2_ADC_R_BST_MASK (0x3 << 12) +#define RT5665_STO2_ADC_R_BST_SFT 12 + +/* Stereo1 ADC Mixer Control (0x0026) */ +#define RT5665_M_STO1_ADC_L1 (0x1 << 15) +#define RT5665_M_STO1_ADC_L1_SFT 15 +#define RT5665_M_STO1_ADC_L2 (0x1 << 14) +#define RT5665_M_STO1_ADC_L2_SFT 14 +#define RT5665_STO1_ADC1L_SRC_MASK (0x1 << 13) +#define RT5665_STO1_ADC1L_SRC_SFT 13 +#define RT5665_STO1_ADC1_SRC_ADC (0x1 << 13) +#define RT5665_STO1_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5665_STO1_ADC2L_SRC_MASK (0x1 << 12) +#define RT5665_STO1_ADC2L_SRC_SFT 12 +#define RT5665_STO1_ADCL_SRC_MASK (0x3 << 10) +#define RT5665_STO1_ADCL_SRC_SFT 10 +#define RT5665_STO1_DD_L_SRC_MASK (0x1 << 9) +#define RT5665_STO1_DD_L_SRC_SFT 9 +#define RT5665_STO1_DMIC_SRC_MASK (0x1 << 8) +#define RT5665_STO1_DMIC_SRC_SFT 8 +#define RT5665_STO1_DMIC_SRC_DMIC2 (0x1 << 8) +#define RT5665_STO1_DMIC_SRC_DMIC1 (0x0 << 8) +#define RT5665_M_STO1_ADC_R1 (0x1 << 7) +#define RT5665_M_STO1_ADC_R1_SFT 7 +#define RT5665_M_STO1_ADC_R2 (0x1 << 6) +#define RT5665_M_STO1_ADC_R2_SFT 6 +#define RT5665_STO1_ADC1R_SRC_MASK (0x1 << 5) +#define RT5665_STO1_ADC1R_SRC_SFT 5 +#define RT5665_STO1_ADC2R_SRC_MASK (0x1 << 4) +#define RT5665_STO1_ADC2R_SRC_SFT 4 +#define RT5665_STO1_ADCR_SRC_MASK (0x3 << 2) +#define RT5665_STO1_ADCR_SRC_SFT 2 +#define RT5665_STO1_DD_R_SRC_MASK (0x3) +#define RT5665_STO1_DD_R_SRC_SFT 0 + + +/* Mono1 ADC Mixer control (0x0027) */ +#define RT5665_M_MONO_ADC_L1 (0x1 << 15) +#define RT5665_M_MONO_ADC_L1_SFT 15 +#define RT5665_M_MONO_ADC_L2 (0x1 << 14) +#define RT5665_M_MONO_ADC_L2_SFT 14 +#define RT5665_MONO_ADC_L1_SRC_MASK (0x1 << 13) +#define RT5665_MONO_ADC_L1_SRC_SFT 13 +#define RT5665_MONO_ADC_L2_SRC_MASK (0x1 << 12) +#define RT5665_MONO_ADC_L2_SRC_SFT 12 +#define RT5665_MONO_ADC_L_SRC_MASK (0x3 << 10) +#define RT5665_MONO_ADC_L_SRC_SFT 10 +#define RT5665_MONO_DD_L_SRC_MASK (0x1 << 9) +#define RT5665_MONO_DD_L_SRC_SFT 9 +#define RT5665_MONO_DMIC_L_SRC_MASK (0x1 << 8) +#define RT5665_MONO_DMIC_L_SRC_SFT 8 +#define RT5665_M_MONO_ADC_R1 (0x1 << 7) +#define RT5665_M_MONO_ADC_R1_SFT 7 +#define RT5665_M_MONO_ADC_R2 (0x1 << 6) +#define RT5665_M_MONO_ADC_R2_SFT 6 +#define RT5665_MONO_ADC_R1_SRC_MASK (0x1 << 5) +#define RT5665_MONO_ADC_R1_SRC_SFT 5 +#define RT5665_MONO_ADC_R2_SRC_MASK (0x1 << 4) +#define RT5665_MONO_ADC_R2_SRC_SFT 4 +#define RT5665_MONO_ADC_R_SRC_MASK (0x3 << 2) +#define RT5665_MONO_ADC_R_SRC_SFT 2 +#define RT5665_MONO_DD_R_SRC_MASK (0x1 << 1) +#define RT5665_MONO_DD_R_SRC_SFT 1 +#define RT5665_MONO_DMIC_R_SRC_MASK 0x1 +#define RT5665_MONO_DMIC_R_SRC_SFT 0 + +/* Stereo2 ADC Mixer Control (0x0028) */ +#define RT5665_M_STO2_ADC_L1 (0x1 << 15) +#define RT5665_M_STO2_ADC_L1_UN (0x0 << 15) +#define RT5665_M_STO2_ADC_L1_SFT 15 +#define RT5665_M_STO2_ADC_L2 (0x1 << 14) +#define RT5665_M_STO2_ADC_L2_SFT 14 +#define RT5665_STO2_ADC1L_SRC_MASK (0x1 << 13) +#define RT5665_STO2_ADC1L_SRC_SFT 13 +#define RT5665_STO2_ADC1_SRC_ADC (0x1 << 13) +#define RT5665_STO2_ADC1_SRC_DACMIX (0x0 << 13) +#define RT5665_STO2_ADC2L_SRC_MASK (0x1 << 12) +#define RT5665_STO2_ADC2L_SRC_SFT 12 +#define RT5665_STO2_ADCL_SRC_MASK (0x3 << 10) +#define RT5665_STO2_ADCL_SRC_SFT 10 +#define RT5665_STO2_DD_L_SRC_MASK (0x1 << 9) +#define RT5665_STO2_DD_L_SRC_SFT 9 +#define RT5665_STO2_DMIC_SRC_MASK (0x1 << 8) +#define RT5665_STO2_DMIC_SRC_SFT 8 +#define RT5665_STO2_DMIC_SRC_DMIC2 (0x1 << 8) +#define RT5665_STO2_DMIC_SRC_DMIC1 (0x0 << 8) +#define RT5665_M_STO2_ADC_R1 (0x1 << 7) +#define RT5665_M_STO2_ADC_R1_UN (0x0 << 7) +#define RT5665_M_STO2_ADC_R1_SFT 7 +#define RT5665_M_STO2_ADC_R2 (0x1 << 6) +#define RT5665_M_STO2_ADC_R2_SFT 6 +#define RT5665_STO2_ADC1R_SRC_MASK (0x1 << 5) +#define RT5665_STO2_ADC1R_SRC_SFT 5 +#define RT5665_STO2_ADC2R_SRC_MASK (0x1 << 4) +#define RT5665_STO2_ADC2R_SRC_SFT 4 +#define RT5665_STO2_ADCR_SRC_MASK (0x3 << 2) +#define RT5665_STO2_ADCR_SRC_SFT 2 +#define RT5665_STO2_DD_R_SRC_MASK (0x1 << 1) +#define RT5665_STO2_DD_R_SRC_SFT 1 + +/* ADC Mixer to DAC Mixer Control (0x0029) */ +#define RT5665_M_ADCMIX_L (0x1 << 15) +#define RT5665_M_ADCMIX_L_SFT 15 +#define RT5665_M_DAC1_L (0x1 << 14) +#define RT5665_M_DAC1_L_SFT 14 +#define RT5665_DAC1_R_SEL_MASK (0x3 << 10) +#define RT5665_DAC1_R_SEL_SFT 10 +#define RT5665_DAC1_L_SEL_MASK (0x3 << 8) +#define RT5665_DAC1_L_SEL_SFT 8 +#define RT5665_M_ADCMIX_R (0x1 << 7) +#define RT5665_M_ADCMIX_R_SFT 7 +#define RT5665_M_DAC1_R (0x1 << 6) +#define RT5665_M_DAC1_R_SFT 6 + +/* Stereo1 DAC Mixer Control (0x002a) */ +#define RT5665_M_DAC_L1_STO_L (0x1 << 15) +#define RT5665_M_DAC_L1_STO_L_SFT 15 +#define RT5665_G_DAC_L1_STO_L_MASK (0x1 << 14) +#define RT5665_G_DAC_L1_STO_L_SFT 14 +#define RT5665_M_DAC_R1_STO_L (0x1 << 13) +#define RT5665_M_DAC_R1_STO_L_SFT 13 +#define RT5665_G_DAC_R1_STO_L_MASK (0x1 << 12) +#define RT5665_G_DAC_R1_STO_L_SFT 12 +#define RT5665_M_DAC_L2_STO_L (0x1 << 11) +#define RT5665_M_DAC_L2_STO_L_SFT 11 +#define RT5665_G_DAC_L2_STO_L_MASK (0x1 << 10) +#define RT5665_G_DAC_L2_STO_L_SFT 10 +#define RT5665_M_DAC_R2_STO_L (0x1 << 9) +#define RT5665_M_DAC_R2_STO_L_SFT 9 +#define RT5665_G_DAC_R2_STO_L_MASK (0x1 << 8) +#define RT5665_G_DAC_R2_STO_L_SFT 8 +#define RT5665_M_DAC_L1_STO_R (0x1 << 7) +#define RT5665_M_DAC_L1_STO_R_SFT 7 +#define RT5665_G_DAC_L1_STO_R_MASK (0x1 << 6) +#define RT5665_G_DAC_L1_STO_R_SFT 6 +#define RT5665_M_DAC_R1_STO_R (0x1 << 5) +#define RT5665_M_DAC_R1_STO_R_SFT 5 +#define RT5665_G_DAC_R1_STO_R_MASK (0x1 << 4) +#define RT5665_G_DAC_R1_STO_R_SFT 4 +#define RT5665_M_DAC_L2_STO_R (0x1 << 3) +#define RT5665_M_DAC_L2_STO_R_SFT 3 +#define RT5665_G_DAC_L2_STO_R_MASK (0x1 << 2) +#define RT5665_G_DAC_L2_STO_R_SFT 2 +#define RT5665_M_DAC_R2_STO_R (0x1 << 1) +#define RT5665_M_DAC_R2_STO_R_SFT 1 +#define RT5665_G_DAC_R2_STO_R_MASK (0x1) +#define RT5665_G_DAC_R2_STO_R_SFT 0 + +/* Mono DAC Mixer Control (0x002b) */ +#define RT5665_M_DAC_L1_MONO_L (0x1 << 15) +#define RT5665_M_DAC_L1_MONO_L_SFT 15 +#define RT5665_G_DAC_L1_MONO_L_MASK (0x1 << 14) +#define RT5665_G_DAC_L1_MONO_L_SFT 14 +#define RT5665_M_DAC_R1_MONO_L (0x1 << 13) +#define RT5665_M_DAC_R1_MONO_L_SFT 13 +#define RT5665_G_DAC_R1_MONO_L_MASK (0x1 << 12) +#define RT5665_G_DAC_R1_MONO_L_SFT 12 +#define RT5665_M_DAC_L2_MONO_L (0x1 << 11) +#define RT5665_M_DAC_L2_MONO_L_SFT 11 +#define RT5665_G_DAC_L2_MONO_L_MASK (0x1 << 10) +#define RT5665_G_DAC_L2_MONO_L_SFT 10 +#define RT5665_M_DAC_R2_MONO_L (0x1 << 9) +#define RT5665_M_DAC_R2_MONO_L_SFT 9 +#define RT5665_G_DAC_R2_MONO_L_MASK (0x1 << 8) +#define RT5665_G_DAC_R2_MONO_L_SFT 8 +#define RT5665_M_DAC_L1_MONO_R (0x1 << 7) +#define RT5665_M_DAC_L1_MONO_R_SFT 7 +#define RT5665_G_DAC_L1_MONO_R_MASK (0x1 << 6) +#define RT5665_G_DAC_L1_MONO_R_SFT 6 +#define RT5665_M_DAC_R1_MONO_R (0x1 << 5) +#define RT5665_M_DAC_R1_MONO_R_SFT 5 +#define RT5665_G_DAC_R1_MONO_R_MASK (0x1 << 4) +#define RT5665_G_DAC_R1_MONO_R_SFT 4 +#define RT5665_M_DAC_L2_MONO_R (0x1 << 3) +#define RT5665_M_DAC_L2_MONO_R_SFT 3 +#define RT5665_G_DAC_L2_MONO_R_MASK (0x1 << 2) +#define RT5665_G_DAC_L2_MONO_R_SFT 2 +#define RT5665_M_DAC_R2_MONO_R (0x1 << 1) +#define RT5665_M_DAC_R2_MONO_R_SFT 1 +#define RT5665_G_DAC_R2_MONO_R_MASK (0x1) +#define RT5665_G_DAC_R2_MONO_R_SFT 0 + +/* Stereo2 DAC Mixer Control (0x002c) */ +#define RT5665_M_DAC_L1_STO2_L (0x1 << 15) +#define RT5665_M_DAC_L1_STO2_L_SFT 15 +#define RT5665_G_DAC_L1_STO2_L_MASK (0x1 << 14) +#define RT5665_G_DAC_L1_STO2_L_SFT 14 +#define RT5665_M_DAC_L2_STO2_L (0x1 << 13) +#define RT5665_M_DAC_L2_STO2_L_SFT 13 +#define RT5665_G_DAC_L2_STO2_L_MASK (0x1 << 12) +#define RT5665_G_DAC_L2_STO2_L_SFT 12 +#define RT5665_M_DAC_L3_STO2_L (0x1 << 11) +#define RT5665_M_DAC_L3_STO2_L_SFT 11 +#define RT5665_G_DAC_L3_STO2_L_MASK (0x1 << 10) +#define RT5665_G_DAC_L3_STO2_L_SFT 10 +#define RT5665_M_ST_DAC_L1 (0x1 << 9) +#define RT5665_M_ST_DAC_L1_SFT 9 +#define RT5665_M_ST_DAC_R1 (0x1 << 8) +#define RT5665_M_ST_DAC_R1_SFT 8 +#define RT5665_M_DAC_R1_STO2_R (0x1 << 7) +#define RT5665_M_DAC_R1_STO2_R_SFT 7 +#define RT5665_G_DAC_R1_STO2_R_MASK (0x1 << 6) +#define RT5665_G_DAC_R1_STO2_R_SFT 6 +#define RT5665_M_DAC_R2_STO2_R (0x1 << 5) +#define RT5665_M_DAC_R2_STO2_R_SFT 5 +#define RT5665_G_DAC_R2_STO2_R_MASK (0x1 << 4) +#define RT5665_G_DAC_R2_STO2_R_SFT 4 +#define RT5665_M_DAC_R3_STO2_R (0x1 << 3) +#define RT5665_M_DAC_R3_STO2_R_SFT 3 +#define RT5665_G_DAC_R3_STO2_R_MASK (0x1 << 2) +#define RT5665_G_DAC_R3_STO2_R_SFT 2 + +/* Analog DAC1 Input Source Control (0x002d) */ +#define RT5665_DAC_MIX_L_MASK (0x3 << 12) +#define RT5665_DAC_MIX_L_SFT 12 +#define RT5665_DAC_MIX_R_MASK (0x3 << 8) +#define RT5665_DAC_MIX_R_SFT 8 +#define RT5665_DAC_L1_SRC_MASK (0x3 << 4) +#define RT5665_A_DACL1_SFT 4 +#define RT5665_DAC_R1_SRC_MASK (0x3) +#define RT5665_A_DACR1_SFT 0 + +/* Analog DAC Input Source Control (0x002e) */ +#define RT5665_A_DACL2_SEL (0x1 << 4) +#define RT5665_A_DACL2_SFT 4 +#define RT5665_A_DACR2_SEL (0x1 << 0) +#define RT5665_A_DACR2_SFT 0 + +/* Digital Interface Data Control (0x002f) */ +#define RT5665_IF2_1_ADC_IN_MASK (0x7 << 12) +#define RT5665_IF2_1_ADC_IN_SFT 12 +#define RT5665_IF2_1_DAC_SEL_MASK (0x3 << 10) +#define RT5665_IF2_1_DAC_SEL_SFT 10 +#define RT5665_IF2_1_ADC_SEL_MASK (0x3 << 8) +#define RT5665_IF2_1_ADC_SEL_SFT 8 +#define RT5665_IF2_2_ADC_IN_MASK (0x7 << 4) +#define RT5665_IF2_2_ADC_IN_SFT 4 +#define RT5665_IF2_2_DAC_SEL_MASK (0x3 << 2) +#define RT5665_IF2_2_DAC_SEL_SFT 2 +#define RT5665_IF2_2_ADC_SEL_MASK (0x3 << 0) +#define RT5665_IF2_2_ADC_SEL_SFT 0 + +/* Digital Interface Data Control (0x0030) */ +#define RT5665_IF3_ADC_IN_MASK (0x7 << 4) +#define RT5665_IF3_ADC_IN_SFT 4 +#define RT5665_IF3_DAC_SEL_MASK (0x3 << 2) +#define RT5665_IF3_DAC_SEL_SFT 2 +#define RT5665_IF3_ADC_SEL_MASK (0x3 << 0) +#define RT5665_IF3_ADC_SEL_SFT 0 + +/* PDM Output Control (0x0031) */ +#define RT5665_M_PDM1_L (0x1 << 14) +#define RT5665_M_PDM1_L_SFT 14 +#define RT5665_M_PDM1_R (0x1 << 12) +#define RT5665_M_PDM1_R_SFT 12 +#define RT5665_PDM1_L_MASK (0x3 << 10) +#define RT5665_PDM1_L_SFT 10 +#define RT5665_PDM1_R_MASK (0x3 << 8) +#define RT5665_PDM1_R_SFT 8 +#define RT5665_PDM1_BUSY (0x1 << 6) +#define RT5665_PDM_PATTERN (0x1 << 5) +#define RT5665_PDM_GAIN (0x1 << 4) +#define RT5665_LRCK_PDM_PI2C (0x1 << 3) +#define RT5665_PDM_DIV_MASK (0x3) + +/*S/PDIF Output Control (0x0036) */ +#define RT5665_SPDIF_SEL_MASK (0x3 << 0) +#define RT5665_SPDIF_SEL_SFT 0 + +/* REC Left Mixer Control 2 (0x003c) */ +#define RT5665_M_CBJ_RM1_L (0x1 << 7) +#define RT5665_M_CBJ_RM1_L_SFT 7 +#define RT5665_M_BST1_RM1_L (0x1 << 5) +#define RT5665_M_BST1_RM1_L_SFT 5 +#define RT5665_M_BST2_RM1_L (0x1 << 4) +#define RT5665_M_BST2_RM1_L_SFT 4 +#define RT5665_M_BST3_RM1_L (0x1 << 3) +#define RT5665_M_BST3_RM1_L_SFT 3 +#define RT5665_M_BST4_RM1_L (0x1 << 2) +#define RT5665_M_BST4_RM1_L_SFT 2 +#define RT5665_M_INL_RM1_L (0x1 << 1) +#define RT5665_M_INL_RM1_L_SFT 1 +#define RT5665_M_INR_RM1_L (0x1) +#define RT5665_M_INR_RM1_L_SFT 0 + +/* REC Right Mixer Control 2 (0x003e) */ +#define RT5665_M_AEC_REF_RM1_R (0x1 << 7) +#define RT5665_M_AEC_REF_RM1_R_SFT 7 +#define RT5665_M_BST1_RM1_R (0x1 << 5) +#define RT5665_M_BST1_RM1_R_SFT 5 +#define RT5665_M_BST2_RM1_R (0x1 << 4) +#define RT5665_M_BST2_RM1_R_SFT 4 +#define RT5665_M_BST3_RM1_R (0x1 << 3) +#define RT5665_M_BST3_RM1_R_SFT 3 +#define RT5665_M_BST4_RM1_R (0x1 << 2) +#define RT5665_M_BST4_RM1_R_SFT 2 +#define RT5665_M_INR_RM1_R (0x1 << 1) +#define RT5665_M_INR_RM1_R_SFT 1 +#define RT5665_M_MONOVOL_RM1_R (0x1) +#define RT5665_M_MONOVOL_RM1_R_SFT 0 + +/* REC Mixer 2 Left Control 2 (0x0041) */ +#define RT5665_M_CBJ_RM2_L (0x1 << 7) +#define RT5665_M_CBJ_RM2_L_SFT 7 +#define RT5665_M_BST1_RM2_L (0x1 << 5) +#define RT5665_M_BST1_RM2_L_SFT 5 +#define RT5665_M_BST2_RM2_L (0x1 << 4) +#define RT5665_M_BST2_RM2_L_SFT 4 +#define RT5665_M_BST3_RM2_L (0x1 << 3) +#define RT5665_M_BST3_RM2_L_SFT 3 +#define RT5665_M_BST4_RM2_L (0x1 << 2) +#define RT5665_M_BST4_RM2_L_SFT 2 +#define RT5665_M_INL_RM2_L (0x1 << 1) +#define RT5665_M_INL_RM2_L_SFT 1 +#define RT5665_M_INR_RM2_L (0x1) +#define RT5665_M_INR_RM2_L_SFT 0 + +/* REC Mixer 2 Right Control 2 (0x0043) */ +#define RT5665_M_MONOVOL_RM2_R (0x1 << 7) +#define RT5665_M_MONOVOL_RM2_R_SFT 7 +#define RT5665_M_BST1_RM2_R (0x1 << 5) +#define RT5665_M_BST1_RM2_R_SFT 5 +#define RT5665_M_BST2_RM2_R (0x1 << 4) +#define RT5665_M_BST2_RM2_R_SFT 4 +#define RT5665_M_BST3_RM2_R (0x1 << 3) +#define RT5665_M_BST3_RM2_R_SFT 3 +#define RT5665_M_BST4_RM2_R (0x1 << 2) +#define RT5665_M_BST4_RM2_R_SFT 2 +#define RT5665_M_INL_RM2_R (0x1 << 1) +#define RT5665_M_INL_RM2_R_SFT 1 +#define RT5665_M_INR_RM2_R (0x1) +#define RT5665_M_INR_RM2_R_SFT 0 + +/* SPK Left Mixer Control (0x0046) */ +#define RT5665_M_BST3_SM_L (0x1 << 4) +#define RT5665_M_BST3_SM_L_SFT 4 +#define RT5665_M_IN_R_SM_L (0x1 << 3) +#define RT5665_M_IN_R_SM_L_SFT 3 +#define RT5665_M_IN_L_SM_L (0x1 << 2) +#define RT5665_M_IN_L_SM_L_SFT 2 +#define RT5665_M_BST1_SM_L (0x1 << 1) +#define RT5665_M_BST1_SM_L_SFT 1 +#define RT5665_M_DAC_L2_SM_L (0x1) +#define RT5665_M_DAC_L2_SM_L_SFT 0 + +/* SPK Right Mixer Control (0x0047) */ +#define RT5665_M_BST3_SM_R (0x1 << 4) +#define RT5665_M_BST3_SM_R_SFT 4 +#define RT5665_M_IN_R_SM_R (0x1 << 3) +#define RT5665_M_IN_R_SM_R_SFT 3 +#define RT5665_M_IN_L_SM_R (0x1 << 2) +#define RT5665_M_IN_L_SM_R_SFT 2 +#define RT5665_M_BST4_SM_R (0x1 << 1) +#define RT5665_M_BST4_SM_R_SFT 1 +#define RT5665_M_DAC_R2_SM_R (0x1) +#define RT5665_M_DAC_R2_SM_R_SFT 0 + +/* SPO Amp Input and Gain Control (0x0048) */ +#define RT5665_M_DAC_L2_SPKOMIX (0x1 << 13) +#define RT5665_M_DAC_L2_SPKOMIX_SFT 13 +#define RT5665_M_SPKVOLL_SPKOMIX (0x1 << 12) +#define RT5665_M_SPKVOLL_SPKOMIX_SFT 12 +#define RT5665_M_DAC_R2_SPKOMIX (0x1 << 9) +#define RT5665_M_DAC_R2_SPKOMIX_SFT 9 +#define RT5665_M_SPKVOLR_SPKOMIX (0x1 << 8) +#define RT5665_M_SPKVOLR_SPKOMIX_SFT 8 + +/* MONOMIX Input and Gain Control (0x004b) */ +#define RT5665_G_MONOVOL_MA (0x1 << 10) +#define RT5665_G_MONOVOL_MA_SFT 10 +#define RT5665_M_MONOVOL_MA (0x1 << 9) +#define RT5665_M_MONOVOL_MA_SFT 9 +#define RT5665_M_DAC_L2_MA (0x1 << 8) +#define RT5665_M_DAC_L2_MA_SFT 8 +#define RT5665_M_BST3_MM (0x1 << 4) +#define RT5665_M_BST3_MM_SFT 4 +#define RT5665_M_BST2_MM (0x1 << 3) +#define RT5665_M_BST2_MM_SFT 3 +#define RT5665_M_BST1_MM (0x1 << 2) +#define RT5665_M_BST1_MM_SFT 2 +#define RT5665_M_RECMIC2L_MM (0x1 << 1) +#define RT5665_M_RECMIC2L_MM_SFT 1 +#define RT5665_M_DAC_L2_MM (0x1) +#define RT5665_M_DAC_L2_MM_SFT 0 + +/* Output Left Mixer Control 1 (0x004d) */ +#define RT5665_G_BST3_OM_L_MASK (0x7 << 12) +#define RT5665_G_BST3_OM_L_SFT 12 +#define RT5665_G_BST2_OM_L_MASK (0x7 << 9) +#define RT5665_G_BST2_OM_L_SFT 9 +#define RT5665_G_BST1_OM_L_MASK (0x7 << 6) +#define RT5665_G_BST1_OM_L_SFT 6 +#define RT5665_G_IN_L_OM_L_MASK (0x7 << 3) +#define RT5665_G_IN_L_OM_L_SFT 3 +#define RT5665_G_DAC_L2_OM_L_MASK (0x7 << 0) +#define RT5665_G_DAC_L2_OM_L_SFT 0 + +/* Output Left Mixer Input Control (0x004e) */ +#define RT5665_M_BST3_OM_L (0x1 << 4) +#define RT5665_M_BST3_OM_L_SFT 4 +#define RT5665_M_BST2_OM_L (0x1 << 3) +#define RT5665_M_BST2_OM_L_SFT 3 +#define RT5665_M_BST1_OM_L (0x1 << 2) +#define RT5665_M_BST1_OM_L_SFT 2 +#define RT5665_M_IN_L_OM_L (0x1 << 1) +#define RT5665_M_IN_L_OM_L_SFT 1 +#define RT5665_M_DAC_L2_OM_L (0x1) +#define RT5665_M_DAC_L2_OM_L_SFT 0 + +/* Output Right Mixer Input Control (0x0050) */ +#define RT5665_M_BST4_OM_R (0x1 << 4) +#define RT5665_M_BST4_OM_R_SFT 4 +#define RT5665_M_BST3_OM_R (0x1 << 3) +#define RT5665_M_BST3_OM_R_SFT 3 +#define RT5665_M_BST2_OM_R (0x1 << 2) +#define RT5665_M_BST2_OM_R_SFT 2 +#define RT5665_M_IN_R_OM_R (0x1 << 1) +#define RT5665_M_IN_R_OM_R_SFT 1 +#define RT5665_M_DAC_R2_OM_R (0x1) +#define RT5665_M_DAC_R2_OM_R_SFT 0 + +/* LOUT Mixer Control (0x0052) */ +#define RT5665_M_DAC_L2_LM (0x1 << 15) +#define RT5665_M_DAC_L2_LM_SFT 15 +#define RT5665_M_DAC_R2_LM (0x1 << 14) +#define RT5665_M_DAC_R2_LM_SFT 14 +#define RT5665_M_OV_L_LM (0x1 << 13) +#define RT5665_M_OV_L_LM_SFT 13 +#define RT5665_M_OV_R_LM (0x1 << 12) +#define RT5665_M_OV_R_LM_SFT 12 +#define RT5665_LOUT_BST_SFT 11 +#define RT5665_LOUT_DF (0x1 << 11) +#define RT5665_LOUT_DF_SFT 11 + +/* Power Management for Digital 1 (0x0061) */ +#define RT5665_PWR_I2S1_1 (0x1 << 15) +#define RT5665_PWR_I2S1_1_BIT 15 +#define RT5665_PWR_I2S1_2 (0x1 << 14) +#define RT5665_PWR_I2S1_2_BIT 14 +#define RT5665_PWR_I2S2_1 (0x1 << 13) +#define RT5665_PWR_I2S2_1_BIT 13 +#define RT5665_PWR_I2S2_2 (0x1 << 12) +#define RT5665_PWR_I2S2_2_BIT 12 +#define RT5665_PWR_DAC_L1 (0x1 << 11) +#define RT5665_PWR_DAC_L1_BIT 11 +#define RT5665_PWR_DAC_R1 (0x1 << 10) +#define RT5665_PWR_DAC_R1_BIT 10 +#define RT5665_PWR_I2S3 (0x1 << 9) +#define RT5665_PWR_I2S3_BIT 9 +#define RT5665_PWR_LDO (0x1 << 8) +#define RT5665_PWR_LDO_BIT 8 +#define RT5665_PWR_DAC_L2 (0x1 << 7) +#define RT5665_PWR_DAC_L2_BIT 7 +#define RT5665_PWR_DAC_R2 (0x1 << 6) +#define RT5665_PWR_DAC_R2_BIT 6 +#define RT5665_PWR_ADC_L1 (0x1 << 4) +#define RT5665_PWR_ADC_L1_BIT 4 +#define RT5665_PWR_ADC_R1 (0x1 << 3) +#define RT5665_PWR_ADC_R1_BIT 3 +#define RT5665_PWR_ADC_L2 (0x1 << 2) +#define RT5665_PWR_ADC_L2_BIT 2 +#define RT5665_PWR_ADC_R2 (0x1 << 1) +#define RT5665_PWR_ADC_R2_BIT 1 + +/* Power Management for Digital 2 (0x0062) */ +#define RT5665_PWR_ADC_S1F (0x1 << 15) +#define RT5665_PWR_ADC_S1F_BIT 15 +#define RT5665_PWR_ADC_S2F (0x1 << 14) +#define RT5665_PWR_ADC_S2F_BIT 14 +#define RT5665_PWR_ADC_MF_L (0x1 << 13) +#define RT5665_PWR_ADC_MF_L_BIT 13 +#define RT5665_PWR_ADC_MF_R (0x1 << 12) +#define RT5665_PWR_ADC_MF_R_BIT 12 +#define RT5665_PWR_DAC_S2F (0x1 << 11) +#define RT5665_PWR_DAC_S2F_BIT 11 +#define RT5665_PWR_DAC_S1F (0x1 << 10) +#define RT5665_PWR_DAC_S1F_BIT 10 +#define RT5665_PWR_DAC_MF_L (0x1 << 9) +#define RT5665_PWR_DAC_MF_L_BIT 9 +#define RT5665_PWR_DAC_MF_R (0x1 << 8) +#define RT5665_PWR_DAC_MF_R_BIT 8 +#define RT5665_PWR_PDM1 (0x1 << 7) +#define RT5665_PWR_PDM1_BIT 7 + +/* Power Management for Analog 1 (0x0063) */ +#define RT5665_PWR_VREF1 (0x1 << 15) +#define RT5665_PWR_VREF1_BIT 15 +#define RT5665_PWR_FV1 (0x1 << 14) +#define RT5665_PWR_FV1_BIT 14 +#define RT5665_PWR_VREF2 (0x1 << 13) +#define RT5665_PWR_VREF2_BIT 13 +#define RT5665_PWR_FV2 (0x1 << 12) +#define RT5665_PWR_FV2_BIT 12 +#define RT5665_PWR_VREF3 (0x1 << 11) +#define RT5665_PWR_VREF3_BIT 11 +#define RT5665_PWR_FV3 (0x1 << 10) +#define RT5665_PWR_FV3_BIT 10 +#define RT5665_PWR_MB (0x1 << 9) +#define RT5665_PWR_MB_BIT 9 +#define RT5665_PWR_LM (0x1 << 8) +#define RT5665_PWR_LM_BIT 8 +#define RT5665_PWR_BG (0x1 << 7) +#define RT5665_PWR_BG_BIT 7 +#define RT5665_PWR_MA (0x1 << 6) +#define RT5665_PWR_MA_BIT 6 +#define RT5665_PWR_HA_L (0x1 << 5) +#define RT5665_PWR_HA_L_BIT 5 +#define RT5665_PWR_HA_R (0x1 << 4) +#define RT5665_PWR_HA_R_BIT 4 +#define RT5665_HP_DRIVER_MASK (0x3 << 2) +#define RT5665_HP_DRIVER_1X (0x0 << 2) +#define RT5665_HP_DRIVER_3X (0x1 << 2) +#define RT5665_HP_DRIVER_5X (0x2 << 2) +#define RT5665_LDO1_DVO_MASK (0x3) +#define RT5665_LDO1_DVO_09 (0x0) +#define RT5665_LDO1_DVO_10 (0x1) +#define RT5665_LDO1_DVO_12 (0x2) +#define RT5665_LDO1_DVO_14 (0x3) + +/* Power Management for Analog 2 (0x0064) */ +#define RT5665_PWR_BST1 (0x1 << 15) +#define RT5665_PWR_BST1_BIT 15 +#define RT5665_PWR_BST2 (0x1 << 14) +#define RT5665_PWR_BST2_BIT 14 +#define RT5665_PWR_BST3 (0x1 << 13) +#define RT5665_PWR_BST3_BIT 13 +#define RT5665_PWR_BST4 (0x1 << 12) +#define RT5665_PWR_BST4_BIT 12 +#define RT5665_PWR_MB1 (0x1 << 11) +#define RT5665_PWR_MB1_PWR_DOWN (0x0 << 11) +#define RT5665_PWR_MB1_BIT 11 +#define RT5665_PWR_MB2 (0x1 << 10) +#define RT5665_PWR_MB2_PWR_DOWN (0x0 << 10) +#define RT5665_PWR_MB2_BIT 10 +#define RT5665_PWR_MB3 (0x1 << 9) +#define RT5665_PWR_MB3_BIT 9 +#define RT5665_PWR_BST1_P (0x1 << 7) +#define RT5665_PWR_BST1_P_BIT 7 +#define RT5665_PWR_BST2_P (0x1 << 6) +#define RT5665_PWR_BST2_P_BIT 6 +#define RT5665_PWR_BST3_P (0x1 << 5) +#define RT5665_PWR_BST3_P_BIT 5 +#define RT5665_PWR_BST4_P (0x1 << 4) +#define RT5665_PWR_BST4_P_BIT 4 +#define RT5665_PWR_JD1 (0x1 << 3) +#define RT5665_PWR_JD1_BIT 3 +#define RT5665_PWR_JD2 (0x1 << 2) +#define RT5665_PWR_JD2_BIT 2 +#define RT5665_PWR_RM1_L (0x1 << 1) +#define RT5665_PWR_RM1_L_BIT 1 +#define RT5665_PWR_RM1_R (0x1) +#define RT5665_PWR_RM1_R_BIT 0 + +/* Power Management for Analog 3 (0x0065) */ +#define RT5665_PWR_CBJ (0x1 << 9) +#define RT5665_PWR_CBJ_BIT 9 +#define RT5665_PWR_BST_L (0x1 << 8) +#define RT5665_PWR_BST_L_BIT 8 +#define RT5665_PWR_BST_R (0x1 << 7) +#define RT5665_PWR_BST_R_BIT 7 +#define RT5665_PWR_PLL (0x1 << 6) +#define RT5665_PWR_PLL_BIT 6 +#define RT5665_PWR_LDO2 (0x1 << 2) +#define RT5665_PWR_LDO2_BIT 2 +#define RT5665_PWR_SVD (0x1 << 1) +#define RT5665_PWR_SVD_BIT 1 + +/* Power Management for Mixer (0x0066) */ +#define RT5665_PWR_RM2_L (0x1 << 15) +#define RT5665_PWR_RM2_L_BIT 15 +#define RT5665_PWR_RM2_R (0x1 << 14) +#define RT5665_PWR_RM2_R_BIT 14 +#define RT5665_PWR_OM_L (0x1 << 13) +#define RT5665_PWR_OM_L_BIT 13 +#define RT5665_PWR_OM_R (0x1 << 12) +#define RT5665_PWR_OM_R_BIT 12 +#define RT5665_PWR_MM (0x1 << 11) +#define RT5665_PWR_MM_BIT 11 +#define RT5665_PWR_AEC_REF (0x1 << 6) +#define RT5665_PWR_AEC_REF_BIT 6 +#define RT5665_PWR_STO1_DAC_L (0x1 << 5) +#define RT5665_PWR_STO1_DAC_L_BIT 5 +#define RT5665_PWR_STO1_DAC_R (0x1 << 4) +#define RT5665_PWR_STO1_DAC_R_BIT 4 +#define RT5665_PWR_MONO_DAC_L (0x1 << 3) +#define RT5665_PWR_MONO_DAC_L_BIT 3 +#define RT5665_PWR_MONO_DAC_R (0x1 << 2) +#define RT5665_PWR_MONO_DAC_R_BIT 2 +#define RT5665_PWR_STO2_DAC_L (0x1 << 1) +#define RT5665_PWR_STO2_DAC_L_BIT 1 +#define RT5665_PWR_STO2_DAC_R (0x1) +#define RT5665_PWR_STO2_DAC_R_BIT 0 + +/* Power Management for Volume (0x0067) */ +#define RT5665_PWR_OV_L (0x1 << 13) +#define RT5665_PWR_OV_L_BIT 13 +#define RT5665_PWR_OV_R (0x1 << 12) +#define RT5665_PWR_OV_R_BIT 12 +#define RT5665_PWR_IN_L (0x1 << 9) +#define RT5665_PWR_IN_L_BIT 9 +#define RT5665_PWR_IN_R (0x1 << 8) +#define RT5665_PWR_IN_R_BIT 8 +#define RT5665_PWR_MV (0x1 << 7) +#define RT5665_PWR_MV_BIT 7 +#define RT5665_PWR_MIC_DET (0x1 << 5) +#define RT5665_PWR_MIC_DET_BIT 5 + +/* (0x006b) */ +#define RT5665_SYS_CLK_DET 15 +#define RT5665_HP_CLK_DET 14 +#define RT5665_MONO_CLK_DET 13 +#define RT5665_LOUT_CLK_DET 12 +#define RT5665_POW_CLK_DET 0 + +/* Digital Microphone Control 1 (0x006e) */ +#define RT5665_DMIC_1_EN_MASK (0x1 << 15) +#define RT5665_DMIC_1_EN_SFT 15 +#define RT5665_DMIC_1_DIS (0x0 << 15) +#define RT5665_DMIC_1_EN (0x1 << 15) +#define RT5665_DMIC_2_EN_MASK (0x1 << 14) +#define RT5665_DMIC_2_EN_SFT 14 +#define RT5665_DMIC_2_DIS (0x0 << 14) +#define RT5665_DMIC_2_EN (0x1 << 14) +#define RT5665_DMIC_2_DP_MASK (0x1 << 9) +#define RT5665_DMIC_2_DP_SFT 9 +#define RT5665_DMIC_2_DP_GPIO5 (0x0 << 9) +#define RT5665_DMIC_2_DP_IN2P (0x1 << 9) +#define RT5665_DMIC_CLK_MASK (0x7 << 5) +#define RT5665_DMIC_CLK_SFT 5 +#define RT5665_DMIC_1_DP_MASK (0x1 << 1) +#define RT5665_DMIC_1_DP_SFT 1 +#define RT5665_DMIC_1_DP_GPIO4 (0x0 << 1) +#define RT5665_DMIC_1_DP_IN2N (0x1 << 1) + + +/* Digital Microphone Control 1 (0x006f) */ +#define RT5665_DMIC_2L_LH_MASK (0x1 << 3) +#define RT5665_DMIC_2L_LH_SFT 3 +#define RT5665_DMIC_2L_LH_RISING (0x0 << 3) +#define RT5665_DMIC_2L_LH_FALLING (0x1 << 3) +#define RT5665_DMIC_2R_LH_MASK (0x1 << 2) +#define RT5665_DMIC_2R_LH_SFT 2 +#define RT5665_DMIC_2R_LH_RISING (0x0 << 2) +#define RT5665_DMIC_2R_LH_FALLING (0x1 << 2) +#define RT5665_DMIC_1L_LH_MASK (0x1 << 1) +#define RT5665_DMIC_1L_LH_SFT 1 +#define RT5665_DMIC_1L_LH_RISING (0x0 << 1) +#define RT5665_DMIC_1L_LH_FALLING (0x1 << 1) +#define RT5665_DMIC_1R_LH_MASK (0x1 << 0) +#define RT5665_DMIC_1R_LH_SFT 0 +#define RT5665_DMIC_1R_LH_RISING (0x0) +#define RT5665_DMIC_1R_LH_FALLING (0x1) + +/* I2S1/2/3 Audio Serial Data Port Control (0x0070 0x0071 0x0072) */ +#define RT5665_I2S_MS_MASK (0x1 << 15) +#define RT5665_I2S_MS_SFT 15 +#define RT5665_I2S_MS_M (0x0 << 15) +#define RT5665_I2S_MS_S (0x1 << 15) +#define RT5665_I2S_PIN_CFG_MASK (0x1 << 14) +#define RT5665_I2S_PIN_CFG_SFT 14 +#define RT5665_I2S_CLK_SEL_MASK (0x1 << 11) +#define RT5665_I2S_CLK_SEL_SFT 11 +#define RT5665_I2S_BP_MASK (0x1 << 8) +#define RT5665_I2S_BP_SFT 8 +#define RT5665_I2S_BP_NOR (0x0 << 8) +#define RT5665_I2S_BP_INV (0x1 << 8) +#define RT5665_I2S_DL_MASK (0x3 << 4) +#define RT5665_I2S_DL_SFT 4 +#define RT5665_I2S_DL_16 (0x0 << 4) +#define RT5665_I2S_DL_20 (0x1 << 4) +#define RT5665_I2S_DL_24 (0x2 << 4) +#define RT5665_I2S_DL_8 (0x3 << 4) +#define RT5665_I2S_DF_MASK (0x7) +#define RT5665_I2S_DF_SFT 0 +#define RT5665_I2S_DF_I2S (0x0) +#define RT5665_I2S_DF_LEFT (0x1) +#define RT5665_I2S_DF_PCM_A (0x2) +#define RT5665_I2S_DF_PCM_B (0x3) +#define RT5665_I2S_DF_PCM_A_N (0x6) +#define RT5665_I2S_DF_PCM_B_N (0x7) + +/* ADC/DAC Clock Control 1 (0x0073) */ +#define RT5665_I2S_PD1_MASK (0x7 << 12) +#define RT5665_I2S_PD1_SFT 12 +#define RT5665_I2S_PD1_1 (0x0 << 12) +#define RT5665_I2S_PD1_2 (0x1 << 12) +#define RT5665_I2S_PD1_3 (0x2 << 12) +#define RT5665_I2S_PD1_4 (0x3 << 12) +#define RT5665_I2S_PD1_6 (0x4 << 12) +#define RT5665_I2S_PD1_8 (0x5 << 12) +#define RT5665_I2S_PD1_12 (0x6 << 12) +#define RT5665_I2S_PD1_16 (0x7 << 12) +#define RT5665_I2S_M_PD2_MASK (0x7 << 8) +#define RT5665_I2S_M_PD2_SFT 8 +#define RT5665_I2S_M_PD2_1 (0x0 << 8) +#define RT5665_I2S_M_PD2_2 (0x1 << 8) +#define RT5665_I2S_M_PD2_3 (0x2 << 8) +#define RT5665_I2S_M_PD2_4 (0x3 << 8) +#define RT5665_I2S_M_PD2_6 (0x4 << 8) +#define RT5665_I2S_M_PD2_8 (0x5 << 8) +#define RT5665_I2S_M_PD2_12 (0x6 << 8) +#define RT5665_I2S_M_PD2_16 (0x7 << 8) +#define RT5665_I2S_CLK_SRC_MASK (0x3 << 4) +#define RT5665_I2S_CLK_SRC_SFT 4 +#define RT5665_I2S_CLK_SRC_MCLK (0x0 << 4) +#define RT5665_I2S_CLK_SRC_PLL1 (0x1 << 4) +#define RT5665_I2S_CLK_SRC_RCCLK (0x2 << 4) +#define RT5665_DAC_OSR_MASK (0x3 << 2) +#define RT5665_DAC_OSR_SFT 2 +#define RT5665_DAC_OSR_128 (0x0 << 2) +#define RT5665_DAC_OSR_64 (0x1 << 2) +#define RT5665_DAC_OSR_32 (0x2 << 2) +#define RT5665_ADC_OSR_MASK (0x3) +#define RT5665_ADC_OSR_SFT 0 +#define RT5665_ADC_OSR_128 (0x0) +#define RT5665_ADC_OSR_64 (0x1) +#define RT5665_ADC_OSR_32 (0x2) + +/* ADC/DAC Clock Control 2 (0x0074) */ +#define RT5665_I2S_BCLK_MS2_MASK (0x1 << 15) +#define RT5665_I2S_BCLK_MS2_SFT 15 +#define RT5665_I2S_BCLK_MS2_32 (0x0 << 15) +#define RT5665_I2S_BCLK_MS2_64 (0x1 << 15) +#define RT5665_I2S_PD2_MASK (0x7 << 12) +#define RT5665_I2S_PD2_SFT 12 +#define RT5665_I2S_PD2_1 (0x0 << 12) +#define RT5665_I2S_PD2_2 (0x1 << 12) +#define RT5665_I2S_PD2_3 (0x2 << 12) +#define RT5665_I2S_PD2_4 (0x3 << 12) +#define RT5665_I2S_PD2_6 (0x4 << 12) +#define RT5665_I2S_PD2_8 (0x5 << 12) +#define RT5665_I2S_PD2_12 (0x6 << 12) +#define RT5665_I2S_PD2_16 (0x7 << 12) +#define RT5665_I2S_BCLK_MS3_MASK (0x1 << 11) +#define RT5665_I2S_BCLK_MS3_SFT 11 +#define RT5665_I2S_BCLK_MS3_32 (0x0 << 11) +#define RT5665_I2S_BCLK_MS3_64 (0x1 << 11) +#define RT5665_I2S_PD3_MASK (0x7 << 8) +#define RT5665_I2S_PD3_SFT 8 +#define RT5665_I2S_PD3_1 (0x0 << 8) +#define RT5665_I2S_PD3_2 (0x1 << 8) +#define RT5665_I2S_PD3_3 (0x2 << 8) +#define RT5665_I2S_PD3_4 (0x3 << 8) +#define RT5665_I2S_PD3_6 (0x4 << 8) +#define RT5665_I2S_PD3_8 (0x5 << 8) +#define RT5665_I2S_PD3_12 (0x6 << 8) +#define RT5665_I2S_PD3_16 (0x7 << 8) +#define RT5665_I2S_PD4_MASK (0x7 << 4) +#define RT5665_I2S_PD4_SFT 4 +#define RT5665_I2S_PD4_1 (0x0 << 4) +#define RT5665_I2S_PD4_2 (0x1 << 4) +#define RT5665_I2S_PD4_3 (0x2 << 4) +#define RT5665_I2S_PD4_4 (0x3 << 4) +#define RT5665_I2S_PD4_6 (0x4 << 4) +#define RT5665_I2S_PD4_8 (0x5 << 4) +#define RT5665_I2S_PD4_12 (0x6 << 4) +#define RT5665_I2S_PD4_16 (0x7 << 4) + +/* TDM control 1 (0x0078) */ +#define RT5665_I2S1_MODE_MASK (0x1 << 15) +#define RT5665_I2S1_MODE_I2S (0x0 << 15) +#define RT5665_I2S1_MODE_TDM (0x1 << 15) +#define RT5665_TDM_IN_CH_MASK (0x3 << 10) +#define RT5665_TDM_IN_CH_2 (0x0 << 10) +#define RT5665_TDM_IN_CH_4 (0x1 << 10) +#define RT5665_TDM_IN_CH_6 (0x2 << 10) +#define RT5665_TDM_IN_CH_8 (0x3 << 10) +#define RT5665_TDM_OUT_CH_MASK (0x3 << 8) +#define RT5665_TDM_OUT_CH_2 (0x0 << 8) +#define RT5665_TDM_OUT_CH_4 (0x1 << 8) +#define RT5665_TDM_OUT_CH_6 (0x2 << 8) +#define RT5665_TDM_OUT_CH_8 (0x3 << 8) +#define RT5665_TDM_IN_LEN_MASK (0x3 << 6) +#define RT5665_TDM_IN_LEN_16 (0x0 << 6) +#define RT5665_TDM_IN_LEN_20 (0x1 << 6) +#define RT5665_TDM_IN_LEN_24 (0x2 << 6) +#define RT5665_TDM_IN_LEN_32 (0x3 << 6) +#define RT5665_TDM_OUT_LEN_MASK (0x3 << 4) +#define RT5665_TDM_OUT_LEN_16 (0x0 << 4) +#define RT5665_TDM_OUT_LEN_20 (0x1 << 4) +#define RT5665_TDM_OUT_LEN_24 (0x2 << 4) +#define RT5665_TDM_OUT_LEN_32 (0x3 << 4) + + +/* TDM control 2 (0x0079) */ +#define RT5665_I2S1_1_DS_ADC_SLOT01_SFT 14 +#define RT5665_I2S1_1_DS_ADC_SLOT23_SFT 12 +#define RT5665_I2S1_1_DS_ADC_SLOT45_SFT 10 +#define RT5665_I2S1_1_DS_ADC_SLOT67_SFT 8 +#define RT5665_I2S1_2_DS_ADC_SLOT01_SFT 6 +#define RT5665_I2S1_2_DS_ADC_SLOT23_SFT 4 +#define RT5665_I2S1_2_DS_ADC_SLOT45_SFT 2 +#define RT5665_I2S1_2_DS_ADC_SLOT67_SFT 0 + +/* TDM control 3/4 (0x007a) (0x007b) */ +#define RT5665_IF1_ADC1_SEL_SFT 10 +#define RT5665_IF1_ADC2_SEL_SFT 9 +#define RT5665_IF1_ADC3_SEL_SFT 8 +#define RT5665_IF1_ADC4_SEL_SFT 7 +#define RT5665_TDM_ADC_SEL_SFT 0 +#define RT5665_TDM_ADC_CTRL_MASK (0x1f << 0) +#define RT5665_TDM_ADC_DATA_06 (0x6 << 0) + +/* Global Clock Control (0x0080) */ +#define RT5665_SCLK_SRC_MASK (0x3 << 14) +#define RT5665_SCLK_SRC_SFT 14 +#define RT5665_SCLK_SRC_MCLK (0x0 << 14) +#define RT5665_SCLK_SRC_PLL1 (0x1 << 14) +#define RT5665_SCLK_SRC_RCCLK (0x2 << 14) +#define RT5665_PLL1_SRC_MASK (0x7 << 8) +#define RT5665_PLL1_SRC_SFT 8 +#define RT5665_PLL1_SRC_MCLK (0x0 << 8) +#define RT5665_PLL1_SRC_BCLK1 (0x1 << 8) +#define RT5665_PLL1_SRC_BCLK2 (0x2 << 8) +#define RT5665_PLL1_SRC_BCLK3 (0x3 << 8) +#define RT5665_PLL1_PD_MASK (0x7 << 4) +#define RT5665_PLL1_PD_SFT 4 + + +#define RT5665_PLL_INP_MAX 40000000 +#define RT5665_PLL_INP_MIN 256000 +/* PLL M/N/K Code Control 1 (0x0081) */ +#define RT5665_PLL_N_MAX 0x001ff +#define RT5665_PLL_N_MASK (RT5665_PLL_N_MAX << 7) +#define RT5665_PLL_N_SFT 7 +#define RT5665_PLL_K_MAX 0x001f +#define RT5665_PLL_K_MASK (RT5665_PLL_K_MAX) +#define RT5665_PLL_K_SFT 0 + +/* PLL M/N/K Code Control 2 (0x0082) */ +#define RT5665_PLL_M_MAX 0x00f +#define RT5665_PLL_M_MASK (RT5665_PLL_M_MAX << 12) +#define RT5665_PLL_M_SFT 12 +#define RT5665_PLL_M_BP (0x1 << 11) +#define RT5665_PLL_M_BP_SFT 11 +#define RT5665_PLL_K_BP (0x1 << 10) +#define RT5665_PLL_K_BP_SFT 10 + +/* PLL tracking mode 1 (0x0083) */ +#define RT5665_I2S3_ASRC_MASK (0x1 << 15) +#define RT5665_I2S3_ASRC_SFT 15 +#define RT5665_I2S2_ASRC_MASK (0x1 << 14) +#define RT5665_I2S2_ASRC_SFT 14 +#define RT5665_I2S1_ASRC_MASK (0x1 << 13) +#define RT5665_I2S1_ASRC_SFT 13 +#define RT5665_DAC_STO1_ASRC_MASK (0x1 << 12) +#define RT5665_DAC_STO1_ASRC_SFT 12 +#define RT5665_DAC_STO2_ASRC_MASK (0x1 << 11) +#define RT5665_DAC_STO2_ASRC_SFT 11 +#define RT5665_DAC_MONO_L_ASRC_MASK (0x1 << 10) +#define RT5665_DAC_MONO_L_ASRC_SFT 10 +#define RT5665_DAC_MONO_R_ASRC_MASK (0x1 << 9) +#define RT5665_DAC_MONO_R_ASRC_SFT 9 +#define RT5665_DMIC_STO1_ASRC_MASK (0x1 << 8) +#define RT5665_DMIC_STO1_ASRC_SFT 8 +#define RT5665_DMIC_STO2_ASRC_MASK (0x1 << 7) +#define RT5665_DMIC_STO2_ASRC_SFT 7 +#define RT5665_DMIC_MONO_L_ASRC_MASK (0x1 << 6) +#define RT5665_DMIC_MONO_L_ASRC_SFT 6 +#define RT5665_DMIC_MONO_R_ASRC_MASK (0x1 << 5) +#define RT5665_DMIC_MONO_R_ASRC_SFT 5 +#define RT5665_ADC_STO1_ASRC_MASK (0x1 << 4) +#define RT5665_ADC_STO1_ASRC_SFT 4 +#define RT5665_ADC_STO2_ASRC_MASK (0x1 << 3) +#define RT5665_ADC_STO2_ASRC_SFT 3 +#define RT5665_ADC_MONO_L_ASRC_MASK (0x1 << 2) +#define RT5665_ADC_MONO_L_ASRC_SFT 2 +#define RT5665_ADC_MONO_R_ASRC_MASK (0x1 << 1) +#define RT5665_ADC_MONO_R_ASRC_SFT 1 + +/* PLL tracking mode 2 (0x0084)*/ +#define RT5665_DA_STO1_CLK_SEL_MASK (0x7 << 12) +#define RT5665_DA_STO1_CLK_SEL_SFT 12 +#define RT5665_DA_STO2_CLK_SEL_MASK (0x7 << 8) +#define RT5665_DA_STO2_CLK_SEL_SFT 8 +#define RT5665_DA_MONOL_CLK_SEL_MASK (0x7 << 4) +#define RT5665_DA_MONOL_CLK_SEL_SFT 4 +#define RT5665_DA_MONOR_CLK_SEL_MASK (0x7) +#define RT5665_DA_MONOR_CLK_SEL_SFT 0 + +/* PLL tracking mode 3 (0x0085)*/ +#define RT5665_AD_STO1_CLK_SEL_MASK (0x7 << 12) +#define RT5665_AD_STO1_CLK_SEL_SFT 12 +#define RT5665_AD_STO2_CLK_SEL_MASK (0x7 << 8) +#define RT5665_AD_STO2_CLK_SEL_SFT 8 +#define RT5665_AD_MONOL_CLK_SEL_MASK (0x7 << 4) +#define RT5665_AD_MONOL_CLK_SEL_SFT 4 +#define RT5665_AD_MONOR_CLK_SEL_MASK (0x7) +#define RT5665_AD_MONOR_CLK_SEL_SFT 0 + +/* ASRC Control 4 (0x0086) */ +#define RT5665_I2S1_RATE_MASK (0xf << 12) +#define RT5665_I2S1_RATE_SFT 12 +#define RT5665_I2S2_RATE_MASK (0xf << 8) +#define RT5665_I2S2_RATE_SFT 8 +#define RT5665_I2S3_RATE_MASK (0xf << 4) +#define RT5665_I2S3_RATE_SFT 4 + +/* Depop Mode Control 1 (0x008e) */ +#define RT5665_PUMP_EN (0x1 << 3) + +/* Depop Mode Control 2 (0x8f) */ +#define RT5665_DEPOP_MASK (0x1 << 13) +#define RT5665_DEPOP_SFT 13 +#define RT5665_DEPOP_AUTO (0x0 << 13) +#define RT5665_DEPOP_MAN (0x1 << 13) +#define RT5665_RAMP_MASK (0x1 << 12) +#define RT5665_RAMP_SFT 12 +#define RT5665_RAMP_DIS (0x0 << 12) +#define RT5665_RAMP_EN (0x1 << 12) +#define RT5665_BPS_MASK (0x1 << 11) +#define RT5665_BPS_SFT 11 +#define RT5665_BPS_DIS (0x0 << 11) +#define RT5665_BPS_EN (0x1 << 11) +#define RT5665_FAST_UPDN_MASK (0x1 << 10) +#define RT5665_FAST_UPDN_SFT 10 +#define RT5665_FAST_UPDN_DIS (0x0 << 10) +#define RT5665_FAST_UPDN_EN (0x1 << 10) +#define RT5665_MRES_MASK (0x3 << 8) +#define RT5665_MRES_SFT 8 +#define RT5665_MRES_15MO (0x0 << 8) +#define RT5665_MRES_25MO (0x1 << 8) +#define RT5665_MRES_35MO (0x2 << 8) +#define RT5665_MRES_45MO (0x3 << 8) +#define RT5665_VLO_MASK (0x1 << 7) +#define RT5665_VLO_SFT 7 +#define RT5665_VLO_3V (0x0 << 7) +#define RT5665_VLO_32V (0x1 << 7) +#define RT5665_DIG_DP_MASK (0x1 << 6) +#define RT5665_DIG_DP_SFT 6 +#define RT5665_DIG_DP_DIS (0x0 << 6) +#define RT5665_DIG_DP_EN (0x1 << 6) +#define RT5665_DP_TH_MASK (0x3 << 4) +#define RT5665_DP_TH_SFT 4 + +/* Depop Mode Control 3 (0x90) */ +#define RT5665_CP_SYS_MASK (0x7 << 12) +#define RT5665_CP_SYS_SFT 12 +#define RT5665_CP_FQ1_MASK (0x7 << 8) +#define RT5665_CP_FQ1_SFT 8 +#define RT5665_CP_FQ2_MASK (0x7 << 4) +#define RT5665_CP_FQ2_SFT 4 +#define RT5665_CP_FQ3_MASK (0x7) +#define RT5665_CP_FQ3_SFT 0 +#define RT5665_CP_FQ_1_5_KHZ 0 +#define RT5665_CP_FQ_3_KHZ 1 +#define RT5665_CP_FQ_6_KHZ 2 +#define RT5665_CP_FQ_12_KHZ 3 +#define RT5665_CP_FQ_24_KHZ 4 +#define RT5665_CP_FQ_48_KHZ 5 +#define RT5665_CP_FQ_96_KHZ 6 +#define RT5665_CP_FQ_192_KHZ 7 + +/* HPOUT charge pump 1 (0x0091) */ +#define RT5665_OSW_L_MASK (0x1 << 11) +#define RT5665_OSW_L_SFT 11 +#define RT5665_OSW_L_DIS (0x0 << 11) +#define RT5665_OSW_L_EN (0x1 << 11) +#define RT5665_OSW_R_MASK (0x1 << 10) +#define RT5665_OSW_R_SFT 10 +#define RT5665_OSW_R_DIS (0x0 << 10) +#define RT5665_OSW_R_EN (0x1 << 10) +#define RT5665_PM_HP_MASK (0x3 << 8) +#define RT5665_PM_HP_SFT 8 +#define RT5665_PM_HP_LV (0x0 << 8) +#define RT5665_PM_HP_MV (0x1 << 8) +#define RT5665_PM_HP_HV (0x2 << 8) +#define RT5665_IB_HP_MASK (0x3 << 6) +#define RT5665_IB_HP_SFT 6 +#define RT5665_IB_HP_125IL (0x0 << 6) +#define RT5665_IB_HP_25IL (0x1 << 6) +#define RT5665_IB_HP_5IL (0x2 << 6) +#define RT5665_IB_HP_1IL (0x3 << 6) + +/* PV detection and SPK gain control (0x92) */ +#define RT5665_PVDD_DET_MASK (0x1 << 15) +#define RT5665_PVDD_DET_SFT 15 +#define RT5665_PVDD_DET_DIS (0x0 << 15) +#define RT5665_PVDD_DET_EN (0x1 << 15) +#define RT5665_SPK_AG_MASK (0x1 << 14) +#define RT5665_SPK_AG_SFT 14 +#define RT5665_SPK_AG_DIS (0x0 << 14) +#define RT5665_SPK_AG_EN (0x1 << 14) + +/* Micbias Control1 (0x93) */ +#define RT5665_MIC1_BS_MASK (0x1 << 15) +#define RT5665_MIC1_BS_SFT 15 +#define RT5665_MIC1_BS_9AV (0x0 << 15) +#define RT5665_MIC1_BS_75AV (0x1 << 15) +#define RT5665_MIC2_BS_MASK (0x1 << 14) +#define RT5665_MIC2_BS_SFT 14 +#define RT5665_MIC2_BS_9AV (0x0 << 14) +#define RT5665_MIC2_BS_75AV (0x1 << 14) +#define RT5665_MIC1_CLK_MASK (0x1 << 13) +#define RT5665_MIC1_CLK_SFT 13 +#define RT5665_MIC1_CLK_DIS (0x0 << 13) +#define RT5665_MIC1_CLK_EN (0x1 << 13) +#define RT5665_MIC2_CLK_MASK (0x1 << 12) +#define RT5665_MIC2_CLK_SFT 12 +#define RT5665_MIC2_CLK_DIS (0x0 << 12) +#define RT5665_MIC2_CLK_EN (0x1 << 12) +#define RT5665_MIC1_OVCD_MASK (0x1 << 11) +#define RT5665_MIC1_OVCD_SFT 11 +#define RT5665_MIC1_OVCD_DIS (0x0 << 11) +#define RT5665_MIC1_OVCD_EN (0x1 << 11) +#define RT5665_MIC1_OVTH_MASK (0x3 << 9) +#define RT5665_MIC1_OVTH_SFT 9 +#define RT5665_MIC1_OVTH_600UA (0x0 << 9) +#define RT5665_MIC1_OVTH_1500UA (0x1 << 9) +#define RT5665_MIC1_OVTH_2000UA (0x2 << 9) +#define RT5665_MIC2_OVCD_MASK (0x1 << 8) +#define RT5665_MIC2_OVCD_SFT 8 +#define RT5665_MIC2_OVCD_DIS (0x0 << 8) +#define RT5665_MIC2_OVCD_EN (0x1 << 8) +#define RT5665_MIC2_OVTH_MASK (0x3 << 6) +#define RT5665_MIC2_OVTH_SFT 6 +#define RT5665_MIC2_OVTH_600UA (0x0 << 6) +#define RT5665_MIC2_OVTH_1500UA (0x1 << 6) +#define RT5665_MIC2_OVTH_2000UA (0x2 << 6) +#define RT5665_PWR_MB_MASK (0x1 << 5) +#define RT5665_PWR_MB_SFT 5 +#define RT5665_PWR_MB_PD (0x0 << 5) +#define RT5665_PWR_MB_PU (0x1 << 5) + +/* Micbias Control2 (0x94) */ +#define RT5665_PWR_CLK25M_MASK (0x1 << 9) +#define RT5665_PWR_CLK25M_SFT 9 +#define RT5665_PWR_CLK25M_PD (0x0 << 9) +#define RT5665_PWR_CLK25M_PU (0x1 << 9) +#define RT5665_PWR_CLK1M_MASK (0x1 << 8) +#define RT5665_PWR_CLK1M_SFT 8 +#define RT5665_PWR_CLK1M_PD (0x0 << 8) +#define RT5665_PWR_CLK1M_PU (0x1 << 8) + + +/* EQ Control 1 (0x00b0) */ +#define RT5665_EQ_SRC_DAC (0x0 << 15) +#define RT5665_EQ_SRC_ADC (0x1 << 15) +#define RT5665_EQ_UPD (0x1 << 14) +#define RT5665_EQ_UPD_BIT 14 +#define RT5665_EQ_CD_MASK (0x1 << 13) +#define RT5665_EQ_CD_SFT 13 +#define RT5665_EQ_CD_DIS (0x0 << 13) +#define RT5665_EQ_CD_EN (0x1 << 13) +#define RT5665_EQ_DITH_MASK (0x3 << 8) +#define RT5665_EQ_DITH_SFT 8 +#define RT5665_EQ_DITH_NOR (0x0 << 8) +#define RT5665_EQ_DITH_LSB (0x1 << 8) +#define RT5665_EQ_DITH_LSB_1 (0x2 << 8) +#define RT5665_EQ_DITH_LSB_2 (0x3 << 8) + +/* IRQ Control 1 (0x00b7) */ +#define RT5665_JD1_1_EN_MASK (0x1 << 15) +#define RT5665_JD1_1_EN_SFT 15 +#define RT5665_JD1_1_DIS (0x0 << 15) +#define RT5665_JD1_1_EN (0x1 << 15) +#define RT5665_JD1_2_EN_MASK (0x1 << 12) +#define RT5665_JD1_2_EN_SFT 12 +#define RT5665_JD1_2_DIS (0x0 << 12) +#define RT5665_JD1_2_EN (0x1 << 12) + +/* IRQ Control 2 (0x00b8) */ +#define RT5665_IL_IRQ_MASK (0x1 << 6) +#define RT5665_IL_IRQ_DIS (0x0 << 6) +#define RT5665_IL_IRQ_EN (0x1 << 6) + +/* IRQ Control 5 (0x00ba) */ +#define RT5665_IRQ_JD_EN (0x1 << 3) +#define RT5665_IRQ_JD_EN_SFT 3 + +/* GPIO Control 1 (0x00c0) */ +#define RT5665_GP1_PIN_MASK (0x1 << 15) +#define RT5665_GP1_PIN_SFT 15 +#define RT5665_GP1_PIN_GPIO1 (0x0 << 15) +#define RT5665_GP1_PIN_IRQ (0x1 << 15) +#define RT5665_GP2_PIN_MASK (0x3 << 13) +#define RT5665_GP2_PIN_SFT 13 +#define RT5665_GP2_PIN_GPIO2 (0x0 << 13) +#define RT5665_GP2_PIN_BCLK2 (0x1 << 13) +#define RT5665_GP2_PIN_PDM_SCL (0x2 << 13) +#define RT5665_GP3_PIN_MASK (0x3 << 11) +#define RT5665_GP3_PIN_SFT 11 +#define RT5665_GP3_PIN_GPIO3 (0x0 << 11) +#define RT5665_GP3_PIN_LRCK2 (0x1 << 11) +#define RT5665_GP3_PIN_PDM_SDA (0x2 << 11) +#define RT5665_GP4_PIN_MASK (0x3 << 9) +#define RT5665_GP4_PIN_SFT 9 +#define RT5665_GP4_PIN_GPIO4 (0x0 << 9) +#define RT5665_GP4_PIN_DACDAT2_1 (0x1 << 9) +#define RT5665_GP4_PIN_DMIC1_SDA (0x2 << 9) +#define RT5665_GP5_PIN_MASK (0x3 << 7) +#define RT5665_GP5_PIN_SFT 7 +#define RT5665_GP5_PIN_GPIO5 (0x0 << 7) +#define RT5665_GP5_PIN_ADCDAT2_1 (0x1 << 7) +#define RT5665_GP5_PIN_DMIC2_SDA (0x2 << 7) +#define RT5665_GP6_PIN_MASK (0x3 << 5) +#define RT5665_GP6_PIN_SFT 5 +#define RT5665_GP6_PIN_GPIO6 (0x0 << 5) +#define RT5665_GP6_PIN_BCLK3 (0x0 << 5) +#define RT5665_GP6_PIN_PDM_SCL (0x1 << 5) +#define RT5665_GP7_PIN_MASK (0x3 << 3) +#define RT5665_GP7_PIN_SFT 3 +#define RT5665_GP7_PIN_GPIO7 (0x0 << 3) +#define RT5665_GP7_PIN_LRCK3 (0x1 << 3) +#define RT5665_GP7_PIN_PDM_SDA (0x2 << 3) +#define RT5665_GP8_PIN_MASK (0x3 << 1) +#define RT5665_GP8_PIN_SFT 1 +#define RT5665_GP8_PIN_GPIO8 (0x0 << 1) +#define RT5665_GP8_PIN_DACDAT3 (0x1 << 1) +#define RT5665_GP8_PIN_DMIC2_SCL (0x2 << 1) +#define RT5665_GP8_PIN_DACDAT2_2 (0x3 << 1) + + +/* GPIO Control 2 (0x00c1)*/ +#define RT5665_GP9_PIN_MASK (0x3 << 14) +#define RT5665_GP9_PIN_SFT 14 +#define RT5665_GP9_PIN_GPIO9 (0x0 << 14) +#define RT5665_GP9_PIN_ADCDAT3 (0x1 << 14) +#define RT5665_GP9_PIN_DMIC1_SCL (0x2 << 14) +#define RT5665_GP9_PIN_ADCDAT2_2 (0x3 << 14) +#define RT5665_GP10_PIN_MASK (0x3 << 12) +#define RT5665_GP10_PIN_SFT 12 +#define RT5665_GP10_PIN_GPIO10 (0x0 << 12) +#define RT5665_GP10_PIN_ADCDAT1_2 (0x1 << 12) +#define RT5665_GP10_PIN_LPD (0x2 << 12) +#define RT5665_GP1_PF_MASK (0x1 << 11) +#define RT5665_GP1_PF_IN (0x0 << 11) +#define RT5665_GP1_PF_OUT (0x1 << 11) +#define RT5665_GP1_OUT_MASK (0x1 << 10) +#define RT5665_GP1_OUT_H (0x0 << 10) +#define RT5665_GP1_OUT_L (0x1 << 10) +#define RT5665_GP2_PF_MASK (0x1 << 9) +#define RT5665_GP2_PF_IN (0x0 << 9) +#define RT5665_GP2_PF_OUT (0x1 << 9) +#define RT5665_GP2_OUT_MASK (0x1 << 8) +#define RT5665_GP2_OUT_H (0x0 << 8) +#define RT5665_GP2_OUT_L (0x1 << 8) +#define RT5665_GP3_PF_MASK (0x1 << 7) +#define RT5665_GP3_PF_IN (0x0 << 7) +#define RT5665_GP3_PF_OUT (0x1 << 7) +#define RT5665_GP3_OUT_MASK (0x1 << 6) +#define RT5665_GP3_OUT_H (0x0 << 6) +#define RT5665_GP3_OUT_L (0x1 << 6) +#define RT5665_GP4_PF_MASK (0x1 << 5) +#define RT5665_GP4_PF_IN (0x0 << 5) +#define RT5665_GP4_PF_OUT (0x1 << 5) +#define RT5665_GP4_OUT_MASK (0x1 << 4) +#define RT5665_GP4_OUT_H (0x0 << 4) +#define RT5665_GP4_OUT_L (0x1 << 4) +#define RT5665_GP5_PF_MASK (0x1 << 3) +#define RT5665_GP5_PF_IN (0x0 << 3) +#define RT5665_GP5_PF_OUT (0x1 << 3) +#define RT5665_GP5_OUT_MASK (0x1 << 2) +#define RT5665_GP5_OUT_H (0x0 << 2) +#define RT5665_GP5_OUT_L (0x1 << 2) +#define RT5665_GP6_PF_MASK (0x1 << 1) +#define RT5665_GP6_PF_IN (0x0 << 1) +#define RT5665_GP6_PF_OUT (0x1 << 1) +#define RT5665_GP6_OUT_MASK (0x1) +#define RT5665_GP6_OUT_H (0x0) +#define RT5665_GP6_OUT_L (0x1) + + +/* GPIO Control 3 (0x00c2) */ +#define RT5665_GP7_PF_MASK (0x1 << 15) +#define RT5665_GP7_PF_IN (0x0 << 15) +#define RT5665_GP7_PF_OUT (0x1 << 15) +#define RT5665_GP7_OUT_MASK (0x1 << 14) +#define RT5665_GP7_OUT_H (0x0 << 14) +#define RT5665_GP7_OUT_L (0x1 << 14) +#define RT5665_GP8_PF_MASK (0x1 << 13) +#define RT5665_GP8_PF_IN (0x0 << 13) +#define RT5665_GP8_PF_OUT (0x1 << 13) +#define RT5665_GP8_OUT_MASK (0x1 << 12) +#define RT5665_GP8_OUT_H (0x0 << 12) +#define RT5665_GP8_OUT_L (0x1 << 12) +#define RT5665_GP9_PF_MASK (0x1 << 11) +#define RT5665_GP9_PF_IN (0x0 << 11) +#define RT5665_GP9_PF_OUT (0x1 << 11) +#define RT5665_GP9_OUT_MASK (0x1 << 10) +#define RT5665_GP9_OUT_H (0x0 << 10) +#define RT5665_GP9_OUT_L (0x1 << 10) +#define RT5665_GP10_PF_MASK (0x1 << 9) +#define RT5665_GP10_PF_IN (0x0 << 9) +#define RT5665_GP10_PF_OUT (0x1 << 9) +#define RT5665_GP10_OUT_MASK (0x1 << 8) +#define RT5665_GP10_OUT_H (0x0 << 8) +#define RT5665_GP10_OUT_L (0x1 << 8) +#define RT5665_GP11_PF_MASK (0x1 << 7) +#define RT5665_GP11_PF_IN (0x0 << 7) +#define RT5665_GP11_PF_OUT (0x1 << 7) +#define RT5665_GP11_OUT_MASK (0x1 << 6) +#define RT5665_GP11_OUT_H (0x0 << 6) +#define RT5665_GP11_OUT_L (0x1 << 6) + +/* Soft volume and zero cross control 1 (0x00d9) */ +#define RT5665_SV_MASK (0x1 << 15) +#define RT5665_SV_SFT 15 +#define RT5665_SV_DIS (0x0 << 15) +#define RT5665_SV_EN (0x1 << 15) +#define RT5665_OUT_SV_MASK (0x1 << 13) +#define RT5665_OUT_SV_SFT 13 +#define RT5665_OUT_SV_DIS (0x0 << 13) +#define RT5665_OUT_SV_EN (0x1 << 13) +#define RT5665_HP_SV_MASK (0x1 << 12) +#define RT5665_HP_SV_SFT 12 +#define RT5665_HP_SV_DIS (0x0 << 12) +#define RT5665_HP_SV_EN (0x1 << 12) +#define RT5665_ZCD_DIG_MASK (0x1 << 11) +#define RT5665_ZCD_DIG_SFT 11 +#define RT5665_ZCD_DIG_DIS (0x0 << 11) +#define RT5665_ZCD_DIG_EN (0x1 << 11) +#define RT5665_ZCD_MASK (0x1 << 10) +#define RT5665_ZCD_SFT 10 +#define RT5665_ZCD_PD (0x0 << 10) +#define RT5665_ZCD_PU (0x1 << 10) +#define RT5665_SV_DLY_MASK (0xf) +#define RT5665_SV_DLY_SFT 0 + +/* Soft volume and zero cross control 2 (0x00da) */ +#define RT5665_ZCD_HP_MASK (0x1 << 15) +#define RT5665_ZCD_HP_SFT 15 +#define RT5665_ZCD_HP_DIS (0x0 << 15) +#define RT5665_ZCD_HP_EN (0x1 << 15) + +/* 4 Button Inline Command Control 2 (0x00e0) */ +#define RT5665_4BTN_IL_MASK (0x1 << 15) +#define RT5665_4BTN_IL_EN (0x1 << 15) +#define RT5665_4BTN_IL_DIS (0x0 << 15) +#define RT5665_4BTN_IL_RST_MASK (0x1 << 14) +#define RT5665_4BTN_IL_NOR (0x1 << 14) +#define RT5665_4BTN_IL_RST (0x0 << 14) + +/* Analog JD Control 1 (0x00f0) */ +#define RT5665_JD1_MODE_MASK (0x3 << 0) +#define RT5665_JD1_MODE_0 (0x0 << 0) +#define RT5665_JD1_MODE_1 (0x1 << 0) +#define RT5665_JD1_MODE_2 (0x2 << 0) + +/* Jack Detect Control 3 (0x00f8) */ +#define RT5665_JD_TRI_HPO_SEL_MASK (0x7) +#define RT5665_JD_TRI_HPO_SEL_SFT (0) +#define RT5665_JD_HPO_GPIO_JD1 (0x0) +#define RT5665_JD_HPO_JD1_1 (0x1) +#define RT5665_JD_HPO_JD1_2 (0x2) +#define RT5665_JD_HPO_JD2 (0x3) +#define RT5665_JD_HPO_GPIO_JD2 (0x4) +#define RT5665_JD_HPO_JD3 (0x5) +#define RT5665_JD_HPO_JD_D (0x6) + +/* Digital Misc Control (0x00fa) */ +#define RT5665_AM_MASK (0x1 << 7) +#define RT5665_AM_EN (0x1 << 7) +#define RT5665_AM_DIS (0x1 << 7) +#define RT5665_DIG_GATE_CTRL 0x1 +#define RT5665_DIG_GATE_CTRL_SFT (0) + +/* Chopper and Clock control for ADC (0x011c)*/ +#define RT5665_M_RF_DIG_MASK (0x1 << 12) +#define RT5665_M_RF_DIG_SFT 12 +#define RT5665_M_RI_DIG (0x1 << 11) + +/* Chopper and Clock control for DAC (0x013a)*/ +#define RT5665_CKXEN_DAC1_MASK (0x1 << 13) +#define RT5665_CKXEN_DAC1_SFT 13 +#define RT5665_CKGEN_DAC1_MASK (0x1 << 12) +#define RT5665_CKGEN_DAC1_SFT 12 +#define RT5665_CKXEN_DAC2_MASK (0x1 << 5) +#define RT5665_CKXEN_DAC2_SFT 5 +#define RT5665_CKGEN_DAC2_MASK (0x1 << 4) +#define RT5665_CKGEN_DAC2_SFT 4 + +/* Chopper and Clock control for ADC (0x013b)*/ +#define RT5665_CKXEN_ADC1_MASK (0x1 << 13) +#define RT5665_CKXEN_ADC1_SFT 13 +#define RT5665_CKGEN_ADC1_MASK (0x1 << 12) +#define RT5665_CKGEN_ADC1_SFT 12 +#define RT5665_CKXEN_ADC2_MASK (0x1 << 5) +#define RT5665_CKXEN_ADC2_SFT 5 +#define RT5665_CKGEN_ADC2_MASK (0x1 << 4) +#define RT5665_CKGEN_ADC2_SFT 4 + +/* Volume test (0x013f)*/ +#define RT5665_SEL_CLK_VOL_MASK (0x1 << 15) +#define RT5665_SEL_CLK_VOL_EN (0x1 << 15) +#define RT5665_SEL_CLK_VOL_DIS (0x0 << 15) + +/* Test Mode Control 1 (0x0145) */ +#define RT5665_AD2DA_LB_MASK (0x1 << 9) +#define RT5665_AD2DA_LB_SFT 9 + +/* Stereo Noise Gate Control 1 (0x0160) */ +#define RT5665_NG2_EN_MASK (0x1 << 15) +#define RT5665_NG2_EN (0x1 << 15) +#define RT5665_NG2_DIS (0x0 << 15) + +/* Stereo1 DAC Silence Detection Control (0x0190) */ +#define RT5665_DEB_STO_DAC_MASK (0x7 << 4) +#define RT5665_DEB_80_MS (0x0 << 4) + +/* SAR ADC Inline Command Control 1 (0x0210) */ +#define RT5665_SAR_BUTT_DET_MASK (0x1 << 15) +#define RT5665_SAR_BUTT_DET_EN (0x1 << 15) +#define RT5665_SAR_BUTT_DET_DIS (0x0 << 15) +#define RT5665_SAR_BUTDET_MODE_MASK (0x1 << 14) +#define RT5665_SAR_BUTDET_POW_SAV (0x1 << 14) +#define RT5665_SAR_BUTDET_POW_NORM (0x0 << 14) +#define RT5665_SAR_BUTDET_RST_MASK (0x1 << 13) +#define RT5665_SAR_BUTDET_RST_NORMAL (0x1 << 13) +#define RT5665_SAR_BUTDET_RST (0x0 << 13) +#define RT5665_SAR_POW_MASK (0x1 << 12) +#define RT5665_SAR_POW_EN (0x1 << 12) +#define RT5665_SAR_POW_DIS (0x0 << 12) +#define RT5665_SAR_RST_MASK (0x1 << 11) +#define RT5665_SAR_RST_NORMAL (0x1 << 11) +#define RT5665_SAR_RST (0x0 << 11) +#define RT5665_SAR_BYPASS_MASK (0x1 << 10) +#define RT5665_SAR_BYPASS_EN (0x1 << 10) +#define RT5665_SAR_BYPASS_DIS (0x0 << 10) +#define RT5665_SAR_SEL_MB1_MASK (0x1 << 9) +#define RT5665_SAR_SEL_MB1_SEL (0x1 << 9) +#define RT5665_SAR_SEL_MB1_NOSEL (0x0 << 9) +#define RT5665_SAR_SEL_MB2_MASK (0x1 << 8) +#define RT5665_SAR_SEL_MB2_SEL (0x1 << 8) +#define RT5665_SAR_SEL_MB2_NOSEL (0x0 << 8) +#define RT5665_SAR_SEL_MODE_MASK (0x1 << 7) +#define RT5665_SAR_SEL_MODE_CMP (0x1 << 7) +#define RT5665_SAR_SEL_MODE_ADC (0x0 << 7) +#define RT5665_SAR_SEL_MB1_MB2_MASK (0x1 << 5) +#define RT5665_SAR_SEL_MB1_MB2_AUTO (0x1 << 5) +#define RT5665_SAR_SEL_MB1_MB2_MANU (0x0 << 5) +#define RT5665_SAR_SEL_SIGNAL_MASK (0x1 << 4) +#define RT5665_SAR_SEL_SIGNAL_AUTO (0x1 << 4) +#define RT5665_SAR_SEL_SIGNAL_MANU (0x0 << 4) + +/* System Clock Source */ +enum { + RT5665_SCLK_S_MCLK, + RT5665_SCLK_S_PLL1, + RT5665_SCLK_S_RCCLK, +}; + +/* PLL1 Source */ +enum { + RT5665_PLL1_S_MCLK, + RT5665_PLL1_S_BCLK1, + RT5665_PLL1_S_BCLK2, + RT5665_PLL1_S_BCLK3, + RT5665_PLL1_S_BCLK4, +}; + +enum { + RT5665_AIF1_1, + RT5665_AIF1_2, + RT5665_AIF2_1, + RT5665_AIF2_2, + RT5665_AIF3, + RT5665_AIFS +}; + +enum { + CODEC_5665, + CODEC_5666, + CODEC_5668, +}; + +/* filter mask */ +enum { + RT5665_DA_STEREO1_FILTER = 0x1, + RT5665_DA_STEREO2_FILTER = (0x1 << 1), + RT5665_DA_MONO_L_FILTER = (0x1 << 2), + RT5665_DA_MONO_R_FILTER = (0x1 << 3), + RT5665_AD_STEREO1_FILTER = (0x1 << 4), + RT5665_AD_STEREO2_FILTER = (0x1 << 5), + RT5665_AD_MONO_L_FILTER = (0x1 << 6), + RT5665_AD_MONO_R_FILTER = (0x1 << 7), +}; + +enum { + RT5665_CLK_SEL_SYS, + RT5665_CLK_SEL_I2S1_ASRC, + RT5665_CLK_SEL_I2S2_ASRC, + RT5665_CLK_SEL_I2S3_ASRC, + RT5665_CLK_SEL_SYS2, + RT5665_CLK_SEL_SYS3, + RT5665_CLK_SEL_SYS4, +}; + +int rt5665_sel_asrc_clk_src(struct snd_soc_codec *codec, + unsigned int filter_mask, unsigned int clk_src); +int rt5665_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hs_jack); + +#endif /* __RT5665_H__ */ -- cgit v1.2.3-59-g8ed1b From 1936f00424d142c596e7d4af06a78b830a9ed62b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 14 Nov 2016 22:19:41 +0100 Subject: ALSA: ac97: Fix kernel-doc error with sphinx formatter Sphinx takes a word like (*foo)->bar in the kernel-doc comments as a part of the emphasized marker, and complains like ./sound/pci/ac97/ac97_codec.c:1908: WARNING: Inline emphasis start-string without end-string. For avoiding this, wrap it with the quotes (``) in the comment. Signed-off-by: Takashi Iwai --- sound/pci/ac97/ac97_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 82259ca61e64..1ef7cdf1d3e8 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -1907,7 +1907,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem) * write). The other callbacks, wait and reset, are not mandatory. * * The clock is set to 48000. If another clock is needed, set - * (*rbus)->clock manually. + * ``(*rbus)->clock`` manually. * * The AC97 bus instance is registered as a low-level device, so you don't * have to release it manually. -- cgit v1.2.3-59-g8ed1b From e8c44abeab76cc3b1d79242612b9a2d82ab11b6b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Nov 2016 16:38:21 +0100 Subject: ALSA: emu10k1: Fix emu1010 dock attach check The emu1010_firmware_thread() checks the previous dock status, but a wrong register is recorded as the last status when the dock is plugged in. Usually this isn't a big issue since this value gets overwritten by the next loop after one second. But when a dock is unplugged immediately after plugging, it means essentially missing undock handling. This patch addresses it by remembering the correct register value. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 891453451543..c1b603a8922c 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -762,19 +762,19 @@ static int emu1010_firmware_thread(void *data) } snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); dev_info(emu->card->dev, "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", - reg); + tmp); /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); + snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); dev_info(emu->card->dev, - "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg); - if ((reg & 0x1f) != 0x15) { + "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); + if ((tmp & 0x1f) != 0x15) { /* FPGA failed to be programmed */ dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", - reg); + tmp); continue; } dev_info(emu->card->dev, -- cgit v1.2.3-59-g8ed1b From 4e4dfe4c3fb2888bd96eed629220bd2e7f105f60 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Nov 2016 18:13:06 +0100 Subject: ALSA: emu10k1: Simplify firmware loader code The EMU1010 support in emu10k1 driver has two request_firmware() calls, one for the main board and one for the dock. Both call patterns are fairly similar, and we can simplify it by introducing a helper function and a table instead of the open switch/case. Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emu10k1_main.c | 102 +++++++++++++++------------------------ 1 file changed, 40 insertions(+), 62 deletions(-) (limited to 'sound') diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c1b603a8922c..03d793f3b058 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -662,7 +662,7 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, +static int snd_emu1010_load_firmware_entry(struct snd_emu10k1 *emu, const struct firmware *fw_entry) { int n, i; @@ -708,6 +708,40 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, return 0; } +/* firmware file names, per model, init-fw and dock-fw (optional) */ +static const char * const firmware_names[5][2] = { + [EMU_MODEL_EMU1010] = { + HANA_FILENAME, DOCK_FILENAME + }, + [EMU_MODEL_EMU1010B] = { + EMU1010B_FILENAME, MICRO_DOCK_FILENAME + }, + [EMU_MODEL_EMU1616] = { + EMU1010_NOTEBOOK_FILENAME, MICRO_DOCK_FILENAME + }, + [EMU_MODEL_EMU0404] = { + EMU0404_FILENAME, NULL + }, +}; + +static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock, + const struct firmware **fw) +{ + const char *filename; + int err; + + if (!*fw) { + filename = firmware_names[emu->card_capabilities->emu_model][dock]; + if (!filename) + return 0; + err = request_firmware(fw, filename, &emu->pci->dev); + if (err) + return err; + } + + return snd_emu1010_load_firmware_entry(emu, *fw); +} + static int emu1010_firmware_thread(void *data) { struct snd_emu10k1 *emu = data; @@ -732,34 +766,9 @@ static int emu1010_firmware_thread(void *data) dev_info(emu->card->dev, "emu1010: Loading Audio Dock Firmware\n"); snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); - - if (!emu->dock_fw) { - const char *filename = NULL; - switch (emu->card_capabilities->emu_model) { - case EMU_MODEL_EMU1010: - filename = DOCK_FILENAME; - break; - case EMU_MODEL_EMU1010B: - filename = MICRO_DOCK_FILENAME; - break; - case EMU_MODEL_EMU1616: - filename = MICRO_DOCK_FILENAME; - break; - } - if (filename) { - err = request_firmware(&emu->dock_fw, - filename, - &emu->pci->dev); - if (err) - continue; - } - } - - if (emu->dock_fw) { - err = snd_emu1010_load_firmware(emu, emu->dock_fw); - if (err) - continue; - } + err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); + if (err < 0) + continue; snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); @@ -881,39 +890,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) } dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg); - if (!emu->firmware) { - const char *filename; - switch (emu->card_capabilities->emu_model) { - case EMU_MODEL_EMU1010: - filename = HANA_FILENAME; - break; - case EMU_MODEL_EMU1010B: - filename = EMU1010B_FILENAME; - break; - case EMU_MODEL_EMU1616: - filename = EMU1010_NOTEBOOK_FILENAME; - break; - case EMU_MODEL_EMU0404: - filename = EMU0404_FILENAME; - break; - default: - return -ENODEV; - } - - err = request_firmware(&emu->firmware, filename, &emu->pci->dev); - if (err != 0) { - dev_info(emu->card->dev, - "emu1010: firmware: %s not found. Err = %d\n", - filename, err); - return err; - } - dev_info(emu->card->dev, - "emu1010: firmware file = %s, size = 0x%zx\n", - filename, emu->firmware->size); - } - - err = snd_emu1010_load_firmware(emu, emu->firmware); - if (err != 0) { + err = snd_emu1010_load_firmware(emu, 0, &emu->firmware); + if (err < 0) { dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n"); return err; } -- cgit v1.2.3-59-g8ed1b From aeaa6203b6c41d9add8932dbd95bc741839054d0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Nov 2016 18:38:39 +0100 Subject: ALSA: emu10k1: Use workqueue instead of kthread for emu1010 fw polling This patch is a cleanup of EMU1010 dock probing code in emu10k1 driver to use work instead of kthread in a loop. The work is lighter and easier to control than kthread, in general. Instead of a loop with the explicit sleep, we do simply delayed-schedule the work. At suspend/resume callbacks, the work is canceled and restarted, respectively. Signed-off-by: Takashi Iwai --- include/sound/emu10k1.h | 3 +- sound/pci/emu10k1/emu10k1.c | 9 +++ sound/pci/emu10k1/emu10k1_main.c | 132 +++++++++++++++++---------------------- 3 files changed, 67 insertions(+), 77 deletions(-) (limited to 'sound') diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 5bd134651f5e..4f42affe777c 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h @@ -1688,7 +1688,8 @@ struct snd_emu1010 { unsigned int internal_clock; /* 44100 or 48000 */ unsigned int optical_in; /* 0:SPDIF, 1:ADAT */ unsigned int optical_out; /* 0:SPDIF, 1:ADAT */ - struct task_struct *firmware_thread; + struct delayed_work firmware_work; + u32 last_reg; }; struct snd_emu10k1 { diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 4733b68c9eb0..6a0e49ac5273 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -194,6 +194,9 @@ static int snd_card_emu10k1_probe(struct pci_dev *pci, if ((err = snd_card_register(card)) < 0) goto error; + if (emu->card_capabilities->emu_model) + schedule_delayed_work(&emu->emu1010.firmware_work, 0); + pci_set_drvdata(pci, card); dev++; return 0; @@ -219,6 +222,8 @@ static int snd_emu10k1_suspend(struct device *dev) emu->suspend = 1; + cancel_delayed_work_sync(&emu->emu1010.firmware_work); + snd_pcm_suspend_all(emu->pcm); snd_pcm_suspend_all(emu->pcm_mic); snd_pcm_suspend_all(emu->pcm_efx); @@ -252,6 +257,10 @@ static int snd_emu10k1_resume(struct device *dev) emu->suspend = 0; snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + if (emu->card_capabilities->emu_model) + schedule_delayed_work(&emu->emu1010.firmware_work, 0); + return 0; } diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 03d793f3b058..ccf4415a1c7b 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -32,7 +32,6 @@ */ #include -#include #include #include #include @@ -742,73 +741,70 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, int dock, return snd_emu1010_load_firmware_entry(emu, *fw); } -static int emu1010_firmware_thread(void *data) +static void emu1010_firmware_work(struct work_struct *work) { - struct snd_emu10k1 *emu = data; + struct snd_emu10k1 *emu; u32 tmp, tmp2, reg; - u32 last_reg = 0; int err; - for (;;) { - /* Delay to allow Audio Dock to settle */ - msleep_interruptible(1000); - if (kthread_should_stop()) - break; + emu = container_of(work, struct snd_emu10k1, + emu1010.firmware_work.work); + if (emu->card->shutdown) + return; #ifdef CONFIG_PM_SLEEP - if (emu->suspend) - continue; + if (emu->suspend) + return; #endif - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ - snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ - if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { - /* Audio Dock attached */ - /* Return to Audio Dock programming mode */ - dev_info(emu->card->dev, - "emu1010: Loading Audio Dock Firmware\n"); - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); - err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); - if (err < 0) - continue; - - snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); - snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ + snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ + if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { + /* Audio Dock attached */ + /* Return to Audio Dock programming mode */ + dev_info(emu->card->dev, + "emu1010: Loading Audio Dock Firmware\n"); + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, + EMU_HANA_FPGA_CONFIG_AUDIODOCK); + err = snd_emu1010_load_firmware(emu, 1, &emu->dock_fw); + if (err < 0) + goto next; + + snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); + snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); + dev_info(emu->card->dev, + "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", tmp); + /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ + snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); + dev_info(emu->card->dev, + "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); + if ((tmp & 0x1f) != 0x15) { + /* FPGA failed to be programmed */ dev_info(emu->card->dev, - "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", + "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", tmp); - /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ - snd_emu1010_fpga_read(emu, EMU_HANA_ID, &tmp); - dev_info(emu->card->dev, - "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", tmp); - if ((tmp & 0x1f) != 0x15) { - /* FPGA failed to be programmed */ - dev_info(emu->card->dev, - "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", - tmp); - continue; - } - dev_info(emu->card->dev, - "emu1010: Audio Dock Firmware loaded\n"); - snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); - snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); - dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", - tmp, tmp2); - /* Sync clocking between 1010 and Dock */ - /* Allow DLL to settle */ - msleep(10); - /* Unmute all. Default is muted after a firmware load */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); - } else if (!reg && last_reg) { - /* Audio Dock removed */ - dev_info(emu->card->dev, - "emu1010: Audio Dock detached\n"); - /* Unmute all */ - snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + goto next; } - - last_reg = reg; + dev_info(emu->card->dev, + "emu1010: Audio Dock Firmware loaded\n"); + snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); + snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); + dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2); + /* Sync clocking between 1010 and Dock */ + /* Allow DLL to settle */ + msleep(10); + /* Unmute all. Default is muted after a firmware load */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); + } else if (!reg && emu->emu1010.last_reg) { + /* Audio Dock removed */ + dev_info(emu->card->dev, "emu1010: Audio Dock detached\n"); + /* Unmute all */ + snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); } - dev_info(emu->card->dev, "emu1010: firmware thread stopping\n"); - return 0; + + next: + emu->emu1010.last_reg = reg; + if (!emu->card->shutdown) + schedule_delayed_work(&emu->emu1010.firmware_work, + msecs_to_jiffies(1000)); } /* @@ -1114,22 +1110,6 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_SPDIF_MODE, &tmp); snd_emu1010_fpga_write(emu, EMU_HANA_SPDIF_MODE, 0x10); /* SPDIF Format spdif (or 0x11 for aes/ebu) */ - /* Start Micro/Audio Dock firmware loader thread */ - if (!emu->emu1010.firmware_thread) { - emu->emu1010.firmware_thread = - kthread_create(emu1010_firmware_thread, emu, - "emu1010_firmware"); - if (IS_ERR(emu->emu1010.firmware_thread)) { - err = PTR_ERR(emu->emu1010.firmware_thread); - emu->emu1010.firmware_thread = NULL; - dev_info(emu->card->dev, - "emu1010: Creating thread failed\n"); - return err; - } - - wake_up_process(emu->emu1010.firmware_thread); - } - #if 0 snd_emu1010_fpga_link_dst_src_write(emu, EMU_DST_HAMOA_DAC_LEFT1, EMU_SRC_ALICE_EMU32B + 2); /* ALICE2 bus 0xa2 */ @@ -1287,8 +1267,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) /* Disable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, 0); } - if (emu->emu1010.firmware_thread) - kthread_stop(emu->emu1010.firmware_thread); + cancel_delayed_work_sync(&emu->emu1010.firmware_work); release_firmware(emu->firmware); release_firmware(emu->dock_fw); if (emu->irq >= 0) @@ -1830,6 +1809,7 @@ int snd_emu10k1_create(struct snd_card *card, emu->irq = -1; emu->synth = NULL; emu->get_synth_voice = NULL; + INIT_DELAYED_WORK(&emu->emu1010.firmware_work, emu1010_firmware_work); /* read revision & serial */ emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); -- cgit v1.2.3-59-g8ed1b From 59b01131407780764f5286c1085a27675ee4898f Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 15 Nov 2016 15:25:50 +0800 Subject: ASoC: rl6231: add 19.2M to 4.096M pll preset table Add a pll mapping table for 19.2M in and 4.096M out. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rl6231.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 1dc68ab08a17..7b447d0b173a 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -102,6 +102,7 @@ struct pll_calc_map { }; static const struct pll_calc_map pll_preset_table[] = { + {19200000, 4096000, 23, 14, 1, false}, {19200000, 24576000, 3, 30, 3, false}, }; -- cgit v1.2.3-59-g8ed1b From 266c618d67dd4a42f798baaab47634018cb1db4b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 15 Nov 2016 21:40:45 +0100 Subject: ASoC: intel: mfld: Make static string arrays 'const 'char * const []' const char * const [] is the preferred type for static string arrays since this states explicitly that the individual entries are not going to be changed. Due to limitations in the ASoC API it was not possible to use it for enum text arrays. Commit 87023ff74b23 ("ASoC: Declare const properly for enum texts") changed this, but most drivers still use 'const char * []' as the type for their enum text arrays. Change these occurrences of 'static * const char * []' to 'static const char * const []'. The conversion was done automatically using the following coccinelle semantic patch: // @disable optional_qualifier@ identifier s; @@ static -const char * +const char * const s[] = ...; // Signed-off-by: Lars-Peter Clausen Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/mfld_machine.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/mfld_machine.c b/sound/soc/intel/boards/mfld_machine.c index 34f46c72a0e2..4e08885f37aa 100644 --- a/sound/soc/intel/boards/mfld_machine.c +++ b/sound/soc/intel/boards/mfld_machine.c @@ -81,9 +81,9 @@ static struct snd_soc_jack_zone mfld_zones[] = { }; /* sound card controls */ -static const char *headset_switch_text[] = {"Earpiece", "Headset"}; +static const char * const headset_switch_text[] = {"Earpiece", "Headset"}; -static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; +static const char * const lo_text[] = {"Vibra", "Headset", "IHF", "None"}; static const struct soc_enum headset_enum = SOC_ENUM_SINGLE_EXT(2, headset_switch_text); -- cgit v1.2.3-59-g8ed1b From a85787edaaf7bc77ed011c89e23d52b3ff352c51 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 15 Nov 2016 19:38:13 +0100 Subject: ASoC: atmel_ssc_dai: if not provided, default to sensible dividers When this driver masters BCLK and/or LRCLK, and noone has stated differently, assume that all the bits of a frame are used. This relieves the cpu dai users from the duty to fill in the dividers for the common case. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- sound/soc/atmel/atmel_ssc_dai.c | 83 +++++++++++++++++++++++++++++++++++++---- sound/soc/atmel/atmel_ssc_dai.h | 1 + 2 files changed, 77 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 16e459aedffe..a1e2c5682dcd 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c @@ -380,6 +380,7 @@ static void atmel_ssc_shutdown(struct snd_pcm_substream *substream, ssc_writel(ssc_p->ssc->regs, CR, SSC_BIT(CR_SWRST)); /* Clear the SSC dividers */ ssc_p->cmr_div = ssc_p->tcmr_period = ssc_p->rcmr_period = 0; + ssc_p->forced_divider = 0; } spin_unlock_irq(&ssc_p->lock); @@ -426,14 +427,17 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, else if (div != ssc_p->cmr_div) return -EBUSY; + ssc_p->forced_divider |= BIT(ATMEL_SSC_CMR_DIV); break; case ATMEL_SSC_TCMR_PERIOD: ssc_p->tcmr_period = div; + ssc_p->forced_divider |= BIT(ATMEL_SSC_TCMR_PERIOD); break; case ATMEL_SSC_RCMR_PERIOD: ssc_p->rcmr_period = div; + ssc_p->forced_divider |= BIT(ATMEL_SSC_RCMR_PERIOD); break; default: @@ -443,6 +447,28 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, return 0; } +/* Is the cpu-dai master of the frame clock? */ +static int atmel_ssc_cfs(struct atmel_ssc_info *ssc_p) +{ + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBS_CFS: + return 1; + } + return 0; +} + +/* Is the cpu-dai master of the bit clock? */ +static int atmel_ssc_cbs(struct atmel_ssc_info *ssc_p) +{ + switch (ssc_p->daifmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBS_CFS: + return 1; + } + return 0; +} + /* * Configure the SSC. */ @@ -459,6 +485,9 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, u32 tfmr, rfmr, tcmr, rcmr; int ret; int fslen, fslen_ext; + u32 cmr_div; + u32 tcmr_period; + u32 rcmr_period; /* * Currently, there is only one set of dma params for @@ -470,6 +499,46 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, else dir = 1; + /* + * If the cpu dai should provide BCLK, but noone has provided the + * divider needed for that to work, fall back to something sensible. + */ + cmr_div = ssc_p->cmr_div; + if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_CMR_DIV)) && + atmel_ssc_cbs(ssc_p)) { + int bclk_rate = snd_soc_params_to_bclk(params); + + if (bclk_rate < 0) { + dev_err(dai->dev, "unable to calculate cmr_div: %d\n", + bclk_rate); + return bclk_rate; + } + + cmr_div = DIV_ROUND_CLOSEST(ssc_p->mck_rate, 2 * bclk_rate); + } + + /* + * If the cpu dai should provide LRCLK, but noone has provided the + * dividers needed for that to work, fall back to something sensible. + */ + tcmr_period = ssc_p->tcmr_period; + rcmr_period = ssc_p->rcmr_period; + if (atmel_ssc_cfs(ssc_p)) { + int frame_size = snd_soc_params_to_frame_size(params); + + if (frame_size < 0) { + dev_err(dai->dev, + "unable to calculate tx/rx cmr_period: %d\n", + frame_size); + return frame_size; + } + + if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_TCMR_PERIOD))) + tcmr_period = frame_size / 2 - 1; + if (!(ssc_p->forced_divider & BIT(ATMEL_SSC_RCMR_PERIOD))) + rcmr_period = frame_size / 2 - 1; + } + dma_params = ssc_p->dma_params[dir]; channels = params_channels(params); @@ -524,7 +593,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, fslen_ext = (bits - 1) / 16; fslen = (bits - 1) % 16; - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -540,7 +609,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -606,7 +675,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, fslen_ext = (bits - 1) / 16; fslen = (bits - 1) % 16; - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) | SSC_BF(RCMR_STTDLY, START_DELAY) | SSC_BF(RCMR_START, SSC_START_FALLING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -623,7 +692,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) | SSC_BF(TCMR_STTDLY, START_DELAY) | SSC_BF(TCMR_START, SSC_START_FALLING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -650,7 +719,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, * MCK divider, and the BCLK signal is output * on the SSC TK line. */ - rcmr = SSC_BF(RCMR_PERIOD, ssc_p->rcmr_period) + rcmr = SSC_BF(RCMR_PERIOD, rcmr_period) | SSC_BF(RCMR_STTDLY, 1) | SSC_BF(RCMR_START, SSC_START_RISING_RF) | SSC_BF(RCMR_CKI, SSC_CKI_RISING) @@ -665,7 +734,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | SSC_BF(RFMR_LOOP, 0) | SSC_BF(RFMR_DATLEN, (bits - 1)); - tcmr = SSC_BF(TCMR_PERIOD, ssc_p->tcmr_period) + tcmr = SSC_BF(TCMR_PERIOD, tcmr_period) | SSC_BF(TCMR_STTDLY, 1) | SSC_BF(TCMR_START, SSC_START_RISING_RF) | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) @@ -760,7 +829,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, } /* set SSC clock mode register */ - ssc_writel(ssc_p->ssc->regs, CMR, ssc_p->cmr_div); + ssc_writel(ssc_p->ssc->regs, CMR, cmr_div); /* set receive clock mode and format */ ssc_writel(ssc_p->ssc->regs, RCMR, rcmr); diff --git a/sound/soc/atmel/atmel_ssc_dai.h b/sound/soc/atmel/atmel_ssc_dai.h index 80b153857a88..75194f582131 100644 --- a/sound/soc/atmel/atmel_ssc_dai.h +++ b/sound/soc/atmel/atmel_ssc_dai.h @@ -113,6 +113,7 @@ struct atmel_ssc_info { unsigned short cmr_div; unsigned short tcmr_period; unsigned short rcmr_period; + unsigned int forced_divider; struct atmel_pcm_dma_params *dma_params[2]; struct atmel_ssc_state ssc_state; unsigned long mck_rate; -- cgit v1.2.3-59-g8ed1b From aa43112445f0f3b7b30ea2189218fcbd437c28ec Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 15 Nov 2016 19:38:15 +0100 Subject: ASoC: atmel: tse850: add ASoC driver for the Axentia TSE-850 The TSE-850 is an FM Transmitter Station Equipment, designed to generate baseband signals for FM, mainly the DARC subcarrier, but other signals are also possible. Signed-off-by: Peter Rosin Signed-off-by: Mark Brown --- MAINTAINERS | 1 + sound/soc/atmel/Kconfig | 10 + sound/soc/atmel/Makefile | 2 + sound/soc/atmel/tse850-pcm5142.c | 472 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 485 insertions(+) create mode 100644 sound/soc/atmel/tse850-pcm5142.c (limited to 'sound') diff --git a/MAINTAINERS b/MAINTAINERS index 35485fd86e73..0dc36a9c61cd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2322,6 +2322,7 @@ M: Peter Rosin L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Maintained F: Documentation/devicetree/bindings/sound/axentia,* +F: sound/soc/atmel/tse850-pcm5142.c AZ6007 DVB DRIVER M: Mauro Carvalho Chehab diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 22aec9a1e9a4..4a56f3dfba51 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -78,4 +78,14 @@ config SND_ATMEL_SOC_PDMIC help Say Y if you want to add support for Atmel ASoC driver for boards using PDMIC. + +config SND_ATMEL_SOC_TSE850_PCM5142 + tristate "ASoC driver for the Axentia TSE-850" + depends on ARCH_AT91 && OF + depends on ATMEL_SSC && I2C + select SND_ATMEL_SOC_SSC_DMA + select SND_SOC_PCM512x_I2C + help + Say Y if you want to add support for the ASoC driver for the + Axentia TSE-850 with a PCM5142 codec. endif diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index a2b127bd9c87..67e10cbd4ed7 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -13,9 +13,11 @@ snd-atmel-soc-wm8904-objs := atmel_wm8904.o snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o snd-atmel-soc-classd-objs := atmel-classd.o snd-atmel-soc-pdmic-objs := atmel-pdmic.o +snd-atmel-soc-tse850-pcm5142-objs := tse850-pcm5142.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o obj-$(CONFIG_SND_ATMEL_SOC_PDMIC) += snd-atmel-soc-pdmic.o +obj-$(CONFIG_SND_ATMEL_SOC_TSE850_PCM5142) += snd-atmel-soc-tse850-pcm5142.o diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c new file mode 100644 index 000000000000..ac6a814c8ecf --- /dev/null +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -0,0 +1,472 @@ +/* + * TSE-850 audio - ASoC driver for the Axentia TSE-850 with a PCM5142 codec + * + * Copyright (C) 2016 Axentia Technologies AB + * + * Author: Peter Rosin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * loop1 relays + * IN1 +---o +------------+ o---+ OUT1 + * \ / + * + + + * | / | + * +--o +--. | + * | add | | + * | V | + * | .---. | + * DAC +----------->|Sum|---+ + * | '---' | + * | | + * + + + * + * IN2 +---o--+------------+--o---+ OUT2 + * loop2 relays + * + * The 'loop1' gpio pin controlls two relays, which are either in loop + * position, meaning that input and output are directly connected, or + * they are in mixer position, meaning that the signal is passed through + * the 'Sum' mixer. Similarly for 'loop2'. + * + * In the above, the 'loop1' relays are inactive, thus feeding IN1 to the + * mixer (if 'add' is active) and feeding the mixer output to OUT1. The + * 'loop2' relays are active, short-cutting the TSE-850 from channel 2. + * IN1, IN2, OUT1 and OUT2 are TSE-850 connectors and DAC is the PCB name + * of the (filtered) output from the PCM5142 codec. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "atmel_ssc_dai.h" + +struct tse850_priv { + int ssc_id; + + struct gpio_desc *add; + struct gpio_desc *loop1; + struct gpio_desc *loop2; + + struct regulator *ana; + + int add_cache; + int loop1_cache; + int loop2_cache; +}; + +static int tse850_get_mux1(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + ucontrol->value.enumerated.item[0] = tse850->loop1_cache; + + return 0; +} + +static int tse850_put_mux1(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + struct soc_enum *e = (struct soc_enum *)kctrl->private_value; + unsigned int val = ucontrol->value.enumerated.item[0]; + + if (val >= e->items) + return -EINVAL; + + gpiod_set_value_cansleep(tse850->loop1, val); + tse850->loop1_cache = val; + + return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +static int tse850_get_mux2(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + ucontrol->value.enumerated.item[0] = tse850->loop2_cache; + + return 0; +} + +static int tse850_put_mux2(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + struct soc_enum *e = (struct soc_enum *)kctrl->private_value; + unsigned int val = ucontrol->value.enumerated.item[0]; + + if (val >= e->items) + return -EINVAL; + + gpiod_set_value_cansleep(tse850->loop2, val); + tse850->loop2_cache = val; + + return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +int tse850_get_mix(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + ucontrol->value.enumerated.item[0] = tse850->add_cache; + + return 0; +} + +int tse850_put_mix(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + int connect = !!ucontrol->value.integer.value[0]; + + if (tse850->add_cache == connect) + return 0; + + /* + * Hmmm, this gpiod_set_value_cansleep call should probably happen + * inside snd_soc_dapm_mixer_update_power in the loop. + */ + gpiod_set_value_cansleep(tse850->add, connect); + tse850->add_cache = connect; + + snd_soc_dapm_mixer_update_power(dapm, kctrl, connect, NULL); + return 1; +} + +int tse850_get_ana(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + int ret; + + ret = regulator_get_voltage(tse850->ana); + if (ret < 0) + return ret; + + /* + * Map regulator output values like so: + * -11.5V to "Low" (enum 0) + * 11.5V-12.5V to "12V" (enum 1) + * 12.5V-13.5V to "13V" (enum 2) + * ... + * 18.5V-19.5V to "19V" (enum 8) + * 19.5V- to "20V" (enum 9) + */ + if (ret < 11000000) + ret = 11000000; + else if (ret > 20000000) + ret = 20000000; + ret -= 11000000; + ret = (ret + 500000) / 1000000; + + ucontrol->value.enumerated.item[0] = ret; + + return 0; +} + +int tse850_put_ana(struct snd_kcontrol *kctrl, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kctrl); + struct snd_soc_card *card = dapm->card; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + struct soc_enum *e = (struct soc_enum *)kctrl->private_value; + unsigned int uV = ucontrol->value.enumerated.item[0]; + int ret; + + if (uV >= e->items) + return -EINVAL; + + /* + * Map enum zero (Low) to 2 volts on the regulator, do this since + * the ana regulator is supplied by the system 12V voltage and + * requesting anything below the system voltage causes the system + * voltage to be passed through the regulator. Also, the ana + * regulator induces noise when requesting voltages near the + * system voltage. So, by mapping Low to 2V, that noise is + * eliminated when all that is needed is 12V (the system voltage). + */ + if (uV) + uV = 11000000 + (1000000 * uV); + else + uV = 2000000; + + ret = regulator_set_voltage(tse850->ana, uV, uV); + if (ret < 0) + return ret; + + return snd_soc_dapm_put_enum_double(kctrl, ucontrol); +} + +static const char * const mux_text[] = { "Mixer", "Loop" }; + +static const struct soc_enum mux_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, mux_text); + +static const struct snd_kcontrol_new mux1 = + SOC_DAPM_ENUM_EXT("MUX1", mux_enum, tse850_get_mux1, tse850_put_mux1); + +static const struct snd_kcontrol_new mux2 = + SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2); + +#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_info_volsw, \ + .get = xget, \ + .put = xput, \ + .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + +static const struct snd_kcontrol_new mix[] = { + TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0, + tse850_get_mix, tse850_put_mix), +}; + +static const char * const ana_text[] = { + "Low", "12V", "13V", "14V", "15V", "16V", "17V", "18V", "19V", "20V" +}; + +static const struct soc_enum ana_enum = + SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 9, ana_text); + +static const struct snd_kcontrol_new out = + SOC_DAPM_ENUM_EXT("ANA", ana_enum, tse850_get_ana, tse850_put_ana); + +static const struct snd_soc_dapm_widget tse850_dapm_widgets[] = { + SND_SOC_DAPM_LINE("OUT1", NULL), + SND_SOC_DAPM_LINE("OUT2", NULL), + SND_SOC_DAPM_LINE("IN1", NULL), + SND_SOC_DAPM_LINE("IN2", NULL), + SND_SOC_DAPM_INPUT("DAC"), + SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), + SOC_MIXER_ARRAY("MIX", SND_SOC_NOPM, 0, 0, mix), + SND_SOC_DAPM_MUX("MUX1", SND_SOC_NOPM, 0, 0, &mux1), + SND_SOC_DAPM_MUX("MUX2", SND_SOC_NOPM, 0, 0, &mux2), + SND_SOC_DAPM_OUT_DRV("OUT", SND_SOC_NOPM, 0, 0, &out, 1), +}; + +/* + * These connections are not entirely correct, since both IN1 and IN2 + * are always fed to MIX (if the "IN switch" is set so), i.e. without + * regard to the loop1 and loop2 relays that according to this only + * control MUX1 and MUX2 but in fact also control how the input signals + * are routed. + * But, 1) I don't know how to do it right, and 2) it doesn't seem to + * matter in practice since nothing is powered in those sections anyway. + */ +static const struct snd_soc_dapm_route tse850_intercon[] = { + { "OUT1", NULL, "MUX1" }, + { "OUT2", NULL, "MUX2" }, + + { "MUX1", "Loop", "IN1" }, + { "MUX1", "Mixer", "OUT" }, + + { "MUX2", "Loop", "IN2" }, + { "MUX2", "Mixer", "OUT" }, + + { "OUT", NULL, "MIX" }, + + { "MIX", NULL, "DAC" }, + { "MIX", "IN Switch", "IN1" }, + { "MIX", "IN Switch", "IN2" }, + + /* connect board input to the codec left channel output pin */ + { "DAC", NULL, "OUTL" }, +}; + +static struct snd_soc_dai_link tse850_dailink = { + .name = "TSE-850", + .stream_name = "TSE-850-PCM", + .codec_dai_name = "pcm512x-hifi", + .dai_fmt = SND_SOC_DAIFMT_I2S + | SND_SOC_DAIFMT_NB_NF + | SND_SOC_DAIFMT_CBM_CFS, +}; + +static struct snd_soc_card tse850_card = { + .name = "TSE-850-ASoC", + .owner = THIS_MODULE, + .dai_link = &tse850_dailink, + .num_links = 1, + .dapm_widgets = tse850_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tse850_dapm_widgets), + .dapm_routes = tse850_intercon, + .num_dapm_routes = ARRAY_SIZE(tse850_intercon), + .fully_routed = true, +}; + +static int tse850_dt_init(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *codec_np, *cpu_np; + struct snd_soc_card *card = &tse850_card; + struct snd_soc_dai_link *dailink = &tse850_dailink; + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + if (!np) { + dev_err(&pdev->dev, "only device tree supported\n"); + return -EINVAL; + } + + cpu_np = of_parse_phandle(np, "axentia,ssc-controller", 0); + if (!cpu_np) { + dev_err(&pdev->dev, "failed to get dai and pcm info\n"); + return -EINVAL; + } + dailink->cpu_of_node = cpu_np; + dailink->platform_of_node = cpu_np; + tse850->ssc_id = of_alias_get_id(cpu_np, "ssc"); + of_node_put(cpu_np); + + codec_np = of_parse_phandle(np, "axentia,audio-codec", 0); + if (!codec_np) { + dev_err(&pdev->dev, "failed to get codec info\n"); + return -EINVAL; + } + dailink->codec_of_node = codec_np; + of_node_put(codec_np); + + return 0; +} + +static int tse850_probe(struct platform_device *pdev) +{ + struct snd_soc_card *card = &tse850_card; + struct device *dev = card->dev = &pdev->dev; + struct tse850_priv *tse850; + int ret; + + tse850 = devm_kzalloc(dev, sizeof(*tse850), GFP_KERNEL); + if (!tse850) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, tse850); + + ret = tse850_dt_init(pdev); + if (ret) { + dev_err(dev, "failed to init dt info\n"); + return ret; + } + + tse850->add = devm_gpiod_get(dev, "axentia,add", GPIOD_OUT_HIGH); + if (IS_ERR(tse850->add)) { + if (PTR_ERR(tse850->add) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'add' gpio\n"); + return PTR_ERR(tse850->add); + } + tse850->add_cache = 1; + + tse850->loop1 = devm_gpiod_get(dev, "axentia,loop1", GPIOD_OUT_HIGH); + if (IS_ERR(tse850->loop1)) { + if (PTR_ERR(tse850->loop1) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'loop1' gpio\n"); + return PTR_ERR(tse850->loop1); + } + tse850->loop1_cache = 1; + + tse850->loop2 = devm_gpiod_get(dev, "axentia,loop2", GPIOD_OUT_HIGH); + if (IS_ERR(tse850->loop2)) { + if (PTR_ERR(tse850->loop2) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'loop2' gpio\n"); + return PTR_ERR(tse850->loop2); + } + tse850->loop2_cache = 1; + + tse850->ana = devm_regulator_get(dev, "axentia,ana"); + if (IS_ERR(tse850->ana)) { + if (PTR_ERR(tse850->ana) != -EPROBE_DEFER) + dev_err(dev, "failed to get 'ana' regulator\n"); + return PTR_ERR(tse850->ana); + } + + ret = regulator_enable(tse850->ana); + if (ret < 0) { + dev_err(dev, "failed to enable the 'ana' regulator\n"); + return ret; + } + + ret = atmel_ssc_set_audio(tse850->ssc_id); + if (ret != 0) { + dev_err(dev, + "failed to set SSC %d for audio\n", tse850->ssc_id); + goto err_disable_ana; + } + + ret = snd_soc_register_card(card); + if (ret) { + dev_err(dev, "snd_soc_register_card failed\n"); + goto err_put_audio; + } + + return 0; + +err_put_audio: + atmel_ssc_put_audio(tse850->ssc_id); +err_disable_ana: + regulator_disable(tse850->ana); + return ret; +} + +static int tse850_remove(struct platform_device *pdev) +{ + struct snd_soc_card *card = platform_get_drvdata(pdev); + struct tse850_priv *tse850 = snd_soc_card_get_drvdata(card); + + snd_soc_unregister_card(card); + atmel_ssc_put_audio(tse850->ssc_id); + regulator_disable(tse850->ana); + + return 0; +} + +static const struct of_device_id tse850_dt_ids[] = { + { .compatible = "axentia,tse850-pcm5142", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, tse850_dt_ids); + +static struct platform_driver tse850_driver = { + .driver = { + .name = "axentia-tse850-pcm5142", + .of_match_table = of_match_ptr(tse850_dt_ids), + }, + .probe = tse850_probe, + .remove = tse850_remove, +}; + +module_platform_driver(tse850_driver); + +/* Module information */ +MODULE_AUTHOR("Peter Rosin "); +MODULE_DESCRIPTION("ALSA SoC driver for TSE-850 with PCM5142 codec"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 0c95666f0d7364e364ab53e068f7891c98e90012 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 16 Nov 2016 21:08:41 +0800 Subject: ASoC: rt5665: Fix missing mutex_unlock in rt5665_calibrate Reported-by: Julia Lawall Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 34254fd47efe..7dfaaf1c2d14 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4587,7 +4587,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) pr_err("HP Calibration Failure\n"); regmap_write(rt5665->regmap, RT5665_RESET, 0); regcache_cache_bypass(rt5665->regmap, false); - return; + goto out_unlock; } count++; @@ -4606,7 +4606,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) pr_err("MONO Calibration Failure\n"); regmap_write(rt5665->regmap, RT5665_RESET, 0); regcache_cache_bypass(rt5665->regmap, false); - return; + goto out_unlock; } count++; @@ -4621,6 +4621,7 @@ static void rt5665_calibrate(struct rt5665_priv *rt5665) regmap_write(rt5665->regmap, RT5665_BIAS_CUR_CTRL_8, 0xa602); regmap_write(rt5665->regmap, RT5665_ASRC_8, 0x0120); +out_unlock: mutex_unlock(&rt5665->calibrate_mutex); } -- cgit v1.2.3-59-g8ed1b From f2826c1fe5d071fa437d337c41df979b60f0fc32 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 16 Nov 2016 21:08:42 +0800 Subject: ASoC: rt5665: Use devm_gpio_request_one() Simplify the code a bit. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5665.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 7dfaaf1c2d14..324461e985b3 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4677,11 +4677,9 @@ static int rt5665_i2c_probe(struct i2c_client *i2c, } if (gpio_is_valid(rt5665->pdata.ldo1_en)) { - if (devm_gpio_request(&i2c->dev, rt5665->pdata.ldo1_en, - "rt5665")) + if (devm_gpio_request_one(&i2c->dev, rt5665->pdata.ldo1_en, + GPIOF_OUT_INIT_HIGH, "rt5665")) dev_err(&i2c->dev, "Fail gpio_request gpio_ldo\n"); - else if (gpio_direction_output(rt5665->pdata.ldo1_en, 1)) - dev_err(&i2c->dev, "Fail gpio_direction gpio_ldo\n"); } /* Sleep for 300 ms miniumum */ -- cgit v1.2.3-59-g8ed1b From 6342ad66d117cfdaa3ad02043e9b3a753788a971 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 14 Nov 2016 22:17:44 +0100 Subject: ASoC: rt5514: Remove superfluous linux/kthread.h inclusion It's nowhere used in this driver code. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5514-spi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index 09103aab0cb2..0901e25d6db6 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From a40db07fbf6c47dd40aa6b5e0408e48cbae1338a Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 14 Nov 2016 22:17:45 +0100 Subject: ASoC: rt5677: Remove superfluous linux/kthread.h inclusion It's nowhere used in this driver code. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index 91879ea95415..ebd0f7c5ad3b 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 2e57069c869f3009ae70a429d6719a545de43522 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Fri, 18 Nov 2016 06:11:24 +0900 Subject: ALSA: bebob: compare whole string for model name so that readers are not confused A modalias of 'ieee1394:ven00000D6Cmo00010060sp' hits units for M-Audio FireWire Audiophile only. However the unit has two states relevant to loaded firmware. Initial firmware returns 'FW Audiophile Bootloader', while functional firmware returns 'FW Audiophile'. ALSA bebob driver compares the units' model name to strings of 24 characters by the first 15 characters. This is shorter way to differentiate these two states but confusing to readers. This commit improves the code for this point. Kernel stack is consumed more in call of check_audiophile_booted() by a bit. With initial firmware: $ ./linux-firewire-utils/src/crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 04276da6 bus_info_length 4, crc_length 39, crc 28070 404 31333934 bus_name "1394" 408 006481f2 irmc 0, cmc 0, isc 0, bmc 0, pmc 0, cyc_clk_acc 100, max_rec 8 (512), max_rom 1, gen 15, spd 2 (S400) 40c 000d6c03 company_id 000d6c | 410 102b7e2e device_id 03102b7e2e | EUI-64 000d6c03102b7e2e root directory ----------------------------------------------------------------- 414 00067414 directory_length 6, crc 29716 418 0c0083c0 node capabilities per IEEE 1394 41c 03000d6c vendor 420 81000009 --> descriptor leaf at 444 424 17010060 model 428 8100000c --> descriptor leaf at 458 42c d1000001 --> unit directory at 430 unit directory at 430 ----------------------------------------------------------------- 430 00049da1 directory_length 4, crc 40353 (should be 48611) 434 1200a02d specifier id: 1394 TA 438 13014001 version: Vender Unique and AV/C 43c 17010060 model 440 8100000f --> descriptor leaf at 47c descriptor leaf at 444 ----------------------------------------------------------------- 444 0004073e leaf_length 4, crc 1854 448 00000000 textual descriptor 44c 00000000 minimal ASCII 450 4d2d4155 "M-AU" 454 44494f00 "DIO" descriptor leaf at 458 ----------------------------------------------------------------- 458 00086f21 leaf_length 8, crc 28449 45c 00000000 textual descriptor 460 00000000 minimal ASCII 464 46572041 "FW A" 468 7564696f "udio" 46c 7068696c "phil" 470 6520426f "e Bo" 474 6f746c6f "otlo" 478 61646572 "ader" descriptor leaf at 47c ----------------------------------------------------------------- 47c 00086f21 leaf_length 8, crc 28449 480 00000000 textual descriptor 484 00000000 minimal ASCII 488 46572041 "FW A" 48c 7564696f "udio" 490 7068696c "phil" 494 6520426f "e Bo" 498 6f746c6f "otlo" 49c 61646572 "ader" With functional firmware: $ ./linux-firewire-utils/src/crpp < /sys/bus/firewire/devices/fw1/config_rom ROM header and bus information block ----------------------------------------------------------------- 400 042de16f bus_info_length 4, crc_length 45, crc 57711 404 31333934 bus_name "1394" 408 f0648122 irmc 1, cmc 1, isc 1, bmc 1, pmc 0, cyc_clk_acc 100, max_rec 8 (512), max_rom 1, gen 2, spd 2 (S400) 40c 000d6c03 company_id 000d6c | 410 002b7e2e device_id 03002b7e2e | EUI-64 000d6c03002b7e2e root directory ----------------------------------------------------------------- 414 0009dac4 directory_length 9, crc 56004 418 0400000d hardware version 41c 0c0083c0 node capabilities per IEEE 1394 420 03000d6c vendor 424 81000012 --> descriptor leaf at 46c 428 17010060 model 42c 81000015 --> descriptor leaf at 480 430 13ffffff version 434 d1000002 --> unit directory at 43c 438 d4000006 --> dependent info directory at 450 unit directory at 43c ----------------------------------------------------------------- 43c 00041eb9 directory_length 4, crc 7865 440 1200a02d specifier id: 1394 TA 444 13014001 version: Vender Unique and AV/C 448 17010060 model 44c 81000014 --> descriptor leaf at 49c dependent info directory at 450 ----------------------------------------------------------------- 450 000637c7 directory_length 6, crc 14279 454 120007f5 specifier id 458 13000001 version 45c 3affffc7 (immediate value) 460 3b100000 (immediate value) 464 3cffffc7 (immediate value) 468 3d600000 (immediate value) descriptor leaf at 46c ----------------------------------------------------------------- 46c 0004b8e4 leaf_length 4, crc 47332 470 00000000 textual descriptor 474 00000000 minimal ASCII 478 4d2d4175 "M-Au" 47c 64696f00 "dio" descriptor leaf at 480 ----------------------------------------------------------------- 480 0006194b leaf_length 6, crc 6475 484 00000000 textual descriptor 488 00000000 minimal ASCII 48c 46572041 "FW A" 490 7564696f "udio" 494 7068696c "phil" 498 65000000 "e" descriptor leaf at 49c ----------------------------------------------------------------- 49c 0006194b leaf_length 6, crc 6475 4a0 00000000 textual descriptor 4a4 00000000 minimal ASCII 4a8 46572041 "FW A" 4ac 7564696f "udio" 4b0 7068696c "phil" 4b4 65000000 "e" Reported-by: Nicolas Iooss Reported-by: Joe Perches Signed-off-by: Takashi Sakamoto Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c index 3469ac14c89c..730ea91d9be8 100644 --- a/sound/firewire/bebob/bebob.c +++ b/sound/firewire/bebob/bebob.c @@ -172,12 +172,12 @@ get_saffire_spec(struct fw_unit *unit) static bool check_audiophile_booted(struct fw_unit *unit) { - char name[24] = {0}; + char name[28] = {0}; if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0) return false; - return strncmp(name, "FW Audiophile Bootloader", 15) != 0; + return strncmp(name, "FW Audiophile Bootloader", 24) != 0; } static void -- cgit v1.2.3-59-g8ed1b From 4a5cf1320a9501261919cf96af300b1df3ad0210 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Nov 2016 01:12:30 +0000 Subject: ASoC: uda1380: Remove #if IS_ENABLED(CONFIG_I2C) uda1380 driver doesn't work without CONFIG_I2C anyway. Let's remove #if IS_ENABLED(CONFIG_I2C), and use module_i2c_driver(). And, this patch adds "depends on I2C" to Kconfig Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/uda1380.c | 22 +--------------------- 2 files changed, 2 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..98b9a0c35d6b 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -874,6 +874,7 @@ config SND_SOC_UDA134X config SND_SOC_UDA1380 tristate + depends on I2C config SND_SOC_WL1273 tristate diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 533e3bb444e4..8e52439a58fd 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -775,7 +775,6 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { }, }; -#if IS_ENABLED(CONFIG_I2C) static int uda1380_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -815,27 +814,8 @@ static struct i2c_driver uda1380_i2c_driver = { .remove = uda1380_i2c_remove, .id_table = uda1380_i2c_id, }; -#endif -static int __init uda1380_modinit(void) -{ - int ret = 0; -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&uda1380_i2c_driver); - if (ret != 0) - pr_err("Failed to register UDA1380 I2C driver: %d\n", ret); -#endif - return ret; -} -module_init(uda1380_modinit); - -static void __exit uda1380_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&uda1380_i2c_driver); -#endif -} -module_exit(uda1380_exit); +module_i2c_driver(uda1380_i2c_driver); MODULE_AUTHOR("Giorgio Padrin"); MODULE_DESCRIPTION("Audio support for codec Philips UDA1380"); -- cgit v1.2.3-59-g8ed1b From e2d575918bf38d16cacaac789ba05d5e5a649b6f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Nov 2016 01:13:00 +0000 Subject: ASoC: wm9081: Remove #if IS_ENABLED(CONFIG_I2C) wm9081 driver doesn't work without CONFIG_I2C anyway. Let's remove #if IS_ENABLED(CONFIG_I2C) And, this patch adds "depends on I2C" to Kconfig Signed-off-by: Kuninori Morimoto Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 + sound/soc/codecs/wm9081.c | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c67667bb970f..5efcd9b2152f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1048,6 +1048,7 @@ config SND_SOC_WM8998 config SND_SOC_WM9081 tristate + depends on I2C config SND_SOC_WM9090 tristate diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 856867ec2813..6febef337dd2 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1304,7 +1304,6 @@ static const struct regmap_config wm9081_regmap = { .cache_type = REGCACHE_RBTREE, }; -#if IS_ENABLED(CONFIG_I2C) static int wm9081_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1384,7 +1383,6 @@ static struct i2c_driver wm9081_i2c_driver = { .remove = wm9081_i2c_remove, .id_table = wm9081_i2c_id, }; -#endif module_i2c_driver(wm9081_i2c_driver); -- cgit v1.2.3-59-g8ed1b From 87aa63746260e3e9db2fe6b6d8e97b55bdb63a2b Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 21 Nov 2016 18:00:02 +0000 Subject: ASoC: wm_adsp: Only write shutdown controls for active firmwares The control list may contain shutdown controls for firmwares that are not currently active, attempting to write this will at best fail. To avoid this issue we skip any control that is not active. Fixes: commit f4f0c4c60c39 ("ASoC: wm_adsp: Signal firmware shutdown through event control") Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 4fb6e2f035e0..6ccb7313a0f6 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1194,6 +1194,9 @@ static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) continue; + if (!ctl->enabled) + continue; + ret = wm_coeff_write_acked_control(ctl, event); if (ret) adsp_warn(dsp, -- cgit v1.2.3-59-g8ed1b From f196e9ac07ed1212ce7d106c07a25019c9c1ee18 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Nov 2016 01:13:35 +0000 Subject: ASoC: wm8523: Remove #if IS_ENABLED(CONFIG_I2C) wm8523 driver doesn't work without CONFIG_I2C anyway. Let's remove #if IS_ENABLED(CONFIG_I2C), and use module_i2c_driver(). Signed-off-by: Kuninori Morimoto Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8523.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index deb2e075428e..6d0a2723bfde 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -446,7 +446,6 @@ static const struct regmap_config wm8523_regmap = { .volatile_reg = wm8523_volatile_register, }; -#if IS_ENABLED(CONFIG_I2C) static int wm8523_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -543,29 +542,8 @@ static struct i2c_driver wm8523_i2c_driver = { .remove = wm8523_i2c_remove, .id_table = wm8523_i2c_id, }; -#endif -static int __init wm8523_modinit(void) -{ - int ret; -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&wm8523_i2c_driver); - if (ret != 0) { - printk(KERN_ERR "Failed to register WM8523 I2C driver: %d\n", - ret); - } -#endif - return 0; -} -module_init(wm8523_modinit); - -static void __exit wm8523_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&wm8523_i2c_driver); -#endif -} -module_exit(wm8523_exit); +module_i2c_driver(wm8523_i2c_driver); MODULE_DESCRIPTION("ASoC WM8523 driver"); MODULE_AUTHOR("Mark Brown "); -- cgit v1.2.3-59-g8ed1b From 60bc6173e049ef0f2dd5e7341659afada62f6b1d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 17 Nov 2016 01:13:18 +0000 Subject: ASoC: wm8580: Remove #if IS_ENABLED(CONFIG_I2C) wm8580 driver doesn't work without CONFIG_I2C anyway. Let's remove #if IS_ENABLED(CONFIG_I2C), and use module_i2c_driver(). Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/wm8580.c | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index da93b703ed49..910801dddd64 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -1000,7 +1000,6 @@ static const struct of_device_id wm8580_of_match[] = { }; MODULE_DEVICE_TABLE(of, wm8580_of_match); -#if IS_ENABLED(CONFIG_I2C) static int wm8580_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1066,30 +1065,8 @@ static struct i2c_driver wm8580_i2c_driver = { .remove = wm8580_i2c_remove, .id_table = wm8580_i2c_id, }; -#endif -static int __init wm8580_modinit(void) -{ - int ret = 0; - -#if IS_ENABLED(CONFIG_I2C) - ret = i2c_add_driver(&wm8580_i2c_driver); - if (ret != 0) { - pr_err("Failed to register WM8580 I2C driver: %d\n", ret); - } -#endif - - return ret; -} -module_init(wm8580_modinit); - -static void __exit wm8580_exit(void) -{ -#if IS_ENABLED(CONFIG_I2C) - i2c_del_driver(&wm8580_i2c_driver); -#endif -} -module_exit(wm8580_exit); +module_i2c_driver(wm8580_i2c_driver); MODULE_DESCRIPTION("ASoC WM8580 driver"); MODULE_AUTHOR("Mark Brown "); -- cgit v1.2.3-59-g8ed1b From 852801417a89375c0df4285e60d90c7821a1d730 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 22 Nov 2016 11:29:14 +0100 Subject: ASoC: Make return type of dpcm_state_string() const char * dpcm_state_string() returns a pointer to a string literal. Modifying a string literal causes undefined behaviour. So make the return type of the function const char * to make it explicit that the returned value should not be modified. This patch is purely cosmetic, none of the users of dpcm_state_string() attempt to modify the returned content. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d56a16a0f6fa..e7a1eaa2772f 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -2882,7 +2882,7 @@ int snd_soc_platform_trigger(struct snd_pcm_substream *substream, EXPORT_SYMBOL_GPL(snd_soc_platform_trigger); #ifdef CONFIG_DEBUG_FS -static char *dpcm_state_string(enum snd_soc_dpcm_state state) +static const char *dpcm_state_string(enum snd_soc_dpcm_state state) { switch (state) { case SND_SOC_DPCM_STATE_NEW: -- cgit v1.2.3-59-g8ed1b From f8cbab42d98298ab9c4878dc9105d350b0b902ff Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 20 Nov 2016 21:24:51 +0200 Subject: ASoC: samsung: Remove non-existing MACH dependencies MACH_SMDKC100 was removed in commit b8529ec1c1b0 ("ARM: S5PC100: no more support S5PC100 SoC"). MACH_SMDKV210 and MACH_SMDKC110 in commit 28c8331d386 ("ARM: S5PV210: Remove support for board files"). Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 79ae6a7c93ff..ea0fa9971a0c 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -49,7 +49,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 + depends on MACH_SMDK6410 depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_I2S -- cgit v1.2.3-59-g8ed1b From cd9e2b62768c21c051c585f9d4935b4fa6e9603e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 20 Nov 2016 21:24:52 +0200 Subject: ASoC: samsung: smdk_wm8580: Remove old platforms and drop mach-types usage MACH_SMDKC100, MACH_SMDKV210 and MACH_SMDKC110 are no longer supported so we can drop the dead code. After this the driver no longer differentiates between machines (S3C24xx machines are not supported by it) so there is no need to override I2S device id in cpu_dai_name and SEC_PLAYBACK dai_link can be removed as well. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/smdk_wm8580.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index 548bfd993788..de724ce7b955 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c @@ -14,8 +14,6 @@ #include #include -#include - #include "../codecs/wm8580.h" #include "i2s.h" @@ -147,7 +145,6 @@ static int smdk_wm8580_init_paiftx(struct snd_soc_pcm_runtime *rtd) enum { PRI_PLAYBACK = 0, PRI_CAPTURE, - SEC_PLAYBACK, }; #define SMDK_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ @@ -157,7 +154,7 @@ static struct snd_soc_dai_link smdk_dai[] = { [PRI_PLAYBACK] = { /* Primary Playback i/f */ .name = "WM8580 PAIF RX", .stream_name = "Playback", - .cpu_dai_name = "samsung-i2s.0", + .cpu_dai_name = "samsung-i2s.2", .codec_dai_name = "wm8580-hifi-playback", .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", @@ -167,7 +164,7 @@ static struct snd_soc_dai_link smdk_dai[] = { [PRI_CAPTURE] = { /* Primary Capture i/f */ .name = "WM8580 PAIF TX", .stream_name = "Capture", - .cpu_dai_name = "samsung-i2s.0", + .cpu_dai_name = "samsung-i2s.2", .codec_dai_name = "wm8580-hifi-capture", .platform_name = "samsung-i2s.0", .codec_name = "wm8580.0-001b", @@ -175,23 +172,13 @@ static struct snd_soc_dai_link smdk_dai[] = { .init = smdk_wm8580_init_paiftx, .ops = &smdk_ops, }, - [SEC_PLAYBACK] = { /* Sec_Fifo Playback i/f */ - .name = "Sec_FIFO TX", - .stream_name = "Playback", - .cpu_dai_name = "samsung-i2s-sec", - .codec_dai_name = "wm8580-hifi-playback", - .platform_name = "samsung-i2s-sec", - .codec_name = "wm8580.0-001b", - .dai_fmt = SMDK_DAI_FMT, - .ops = &smdk_ops, - }, }; static struct snd_soc_card smdk = { .name = "SMDK-I2S", .owner = THIS_MODULE, .dai_link = smdk_dai, - .num_links = 2, + .num_links = ARRAY_SIZE(smdk_dai), .dapm_widgets = smdk_wm8580_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(smdk_wm8580_dapm_widgets), @@ -204,17 +191,6 @@ static struct platform_device *smdk_snd_device; static int __init smdk_audio_init(void) { int ret; - char *str; - - if (machine_is_smdkc100() - || machine_is_smdkv210() || machine_is_smdkc110()) { - smdk.num_links = 3; - } else if (machine_is_smdk6410()) { - str = (char *)smdk_dai[PRI_PLAYBACK].cpu_dai_name; - str[strlen(str) - 1] = '2'; - str = (char *)smdk_dai[PRI_CAPTURE].cpu_dai_name; - str[strlen(str) - 1] = '2'; - } smdk_snd_device = platform_device_alloc("soc-audio", -1); if (!smdk_snd_device) -- cgit v1.2.3-59-g8ed1b From a41dcdeee5d87cf3852b857cc3a8507832ec8b42 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 20 Nov 2016 21:24:54 +0200 Subject: ASoC: samsung: Enable COMPILE_TEST for entire Samsung ASoc Instead of build time, Samsung ASoC drivers have rather runtime dependency on Exynos or other Samsung platforms. For building they require Common Clock Framework. If it is provided they could be compile tested to increase build coverage. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index ea0fa9971a0c..48dcd3dd9ec7 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -1,6 +1,7 @@ menuconfig SND_SOC_SAMSUNG tristate "ASoC support for Samsung" - depends on (PLAT_SAMSUNG || ARCH_EXYNOS) + depends on PLAT_SAMSUNG || ARCH_EXYNOS || COMPILE_TEST + depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM ---help--- Say Y or M if you want to add support for codecs attached to -- cgit v1.2.3-59-g8ed1b From 95f5609d223d661419061bd6231da01a317c30d9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 20 Nov 2016 21:24:53 +0200 Subject: ASoC: samsung: Enable COMPILE_TEST for SmartQ and WM8580 The I2S sound drivers for SmartQ board and WM8580 codec can be compile tested to increase build coverage. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 48dcd3dd9ec7..a6cc6ca93fa7 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -50,7 +50,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 config SND_SOC_SAMSUNG_SMDK_WM8580 tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on MACH_SMDK6410 + depends on MACH_SMDK6410 || COMPILE_TEST depends on I2C select SND_SOC_WM8580 select SND_SAMSUNG_I2S @@ -110,7 +110,8 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 config SND_SOC_SMARTQ tristate "SoC I2S Audio support for SmartQ board" - depends on MACH_SMARTQ && I2C + depends on MACH_SMARTQ || COMPILE_TEST + depends on I2C select SND_SAMSUNG_I2S select SND_SOC_WM8750 -- cgit v1.2.3-59-g8ed1b From a823a17981a73faa115bc0f7eda0190763075e2c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Nov 2016 18:11:08 +0100 Subject: ASoC: cht_bsw_rt5645: Fix leftover kmalloc cht_bsw_rt5645 driver allocates the own codec_id string but doesn't release it. For simplicity, put the string in cht_mc_private; then the string is allocated in a shot and released altogether. Fixes: c8560b7c917f ("ASoC: cht_bsw_rt5645: Fix writing to string literal") Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5645.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index 56056ed7fcfd..16c94c45ce50 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c @@ -44,6 +44,7 @@ struct cht_acpi_card { struct cht_mc_private { struct snd_soc_jack jack; struct cht_acpi_card *acpi_card; + char codec_name[16]; }; static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) @@ -354,7 +355,6 @@ static int snd_cht_mc_probe(struct platform_device *pdev) int i; struct cht_mc_private *drv; struct snd_soc_card *card = snd_soc_cards[0].soc_card; - char codec_name[16]; struct sst_acpi_mach *mach; const char *i2c_name = NULL; int dai_index = 0; @@ -374,12 +374,12 @@ static int snd_cht_mc_probe(struct platform_device *pdev) } card->dev = &pdev->dev; mach = card->dev->platform_data; - sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); + sprintf(drv->codec_name, "i2c-%s:00", drv->acpi_card->codec_id); /* set correct codec name */ for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) { - card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL); + card->dai_link[i].codec_name = drv->codec_name; dai_index = i; } -- cgit v1.2.3-59-g8ed1b From 685f51a5eb98779147abb39f584b115ccdd87a4a Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 22 Nov 2016 16:58:57 +0000 Subject: ASoC: wm_adsp: Firmware controls should be added as codec controls We were adding firmware controls as card controls (using snd_soc_add_codec_controls). The DSP is part of a specific codec so we should be adding them as codec controls. Adding as codec controls also means that if the codec has a name_prefix it will be added to the control name, which won't happen when adding as a card control. As that was the only use of the card pointer in struct wm_adsp it can be removed. For ADSP2 codecs a wm_adsp2_codec_probe() was added since the original control handling was written, and that's the logical place to store a pointer to the codec rather than delaying it until the codec is powered-up. For ADSP1 we don't use a codec_probe() stage so the codec pointer initialization replaces the original card pointer initialization in wm_adsp1_event(). Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 8 ++++---- sound/soc/codecs/wm_adsp.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 6ccb7313a0f6..404466d2ae51 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -1132,7 +1132,7 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) break; } - ret = snd_soc_add_card_controls(dsp->card, kcontrol, 1); + ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1); if (ret < 0) goto err_kcontrol; @@ -2301,7 +2301,7 @@ int wm_adsp1_event(struct snd_soc_dapm_widget *w, int ret; unsigned int val; - dsp->card = codec->component.card; + dsp->codec = codec; mutex_lock(&dsp->pwr_lock); @@ -2512,8 +2512,6 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, struct wm_adsp *dsp = &dsps[w->shift]; struct wm_coeff_ctl *ctl; - dsp->card = codec->component.card; - switch (event) { case SND_SOC_DAPM_PRE_PMU: wm_adsp2_set_dspclk(dsp, freq); @@ -2631,6 +2629,8 @@ EXPORT_SYMBOL_GPL(wm_adsp2_event); int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) { + dsp->codec = codec; + wm_adsp2_init_debugfs(dsp, codec); return snd_soc_add_codec_controls(codec, diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 362dd7ce60d8..3f7c8ee42243 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -44,7 +44,7 @@ struct wm_adsp { int type; struct device *dev; struct regmap *regmap; - struct snd_soc_card *card; + struct snd_soc_codec *codec; int base; int sysclk_reg; -- cgit v1.2.3-59-g8ed1b From 1db51e6fb0f5596518975fd1b2f7ef050e9d58ef Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 22 Nov 2016 16:58:56 +0000 Subject: ASoC: wm_adsp: Remove unused wm_coeff_ctl.kcontrol The kcontrol pointer in wm_coeff_ctl is not used now. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 404466d2ae51..6e6b9d838332 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -451,7 +451,6 @@ struct wm_coeff_ctl { unsigned int offset; size_t len; unsigned int set:1; - struct snd_kcontrol *kcontrol; struct soc_bytes_ext bytes_ext; unsigned int flags; unsigned int type; @@ -1138,8 +1137,6 @@ static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) kfree(kcontrol); - ctl->kcontrol = snd_soc_card_get_kcontrol(dsp->card, ctl->name); - return 0; err_kcontrol: -- cgit v1.2.3-59-g8ed1b From edce5c496c6af3e5ca6e1bb18f7cf4f6ef6226fa Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 14 Nov 2016 04:20:40 +0000 Subject: ASoC: rsnd: Request/Release DMA channel each time Current Renesas Sound driver requests DMA channel when .probe timing, and release it when .remove timing. And use DMA on .start/.stop But, Audio DMAC power ON was handled when request timing (= .probe), and power OFF was when release timing (= .remove). This means Audio DMAC power is always ON during driver was enabled. The best choice to solve this issue is that DMAEngine side handle this. But current DMAEngine API design can't solve atmic/non-atmic context issue for power ON/OFF. So next better choice is sound driver request/release DMA channel each time. This patch do it Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 184 ++++++++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 77 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 2f0327714625..3c663a5cfe8b 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -34,6 +34,8 @@ struct rsnd_dmapp { struct rsnd_dma { struct rsnd_mod mod; + struct rsnd_mod *mod_from; + struct rsnd_mod *mod_to; dma_addr_t src_addr; dma_addr_t dst_addr; union { @@ -92,6 +94,20 @@ static void rsnd_dmaen_complete(void *data) rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); } +static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, + struct rsnd_mod *mod_from, + struct rsnd_mod *mod_to) +{ + if ((!mod_from && !mod_to) || + (mod_from && mod_to)) + return NULL; + + if (mod_from) + return rsnd_mod_dma_req(io, mod_from); + else + return rsnd_mod_dma_req(io, mod_to); +} + static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) @@ -99,7 +115,61 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dma *dma = rsnd_mod_to_dma(mod); struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - dmaengine_terminate_all(dmaen->chan); + if (dmaen->chan) { + dmaengine_terminate_all(dmaen->chan); + } + + return 0; +} + +static int rsnd_dmaen_nolock_stop(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + + /* + * DMAEngine release uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under nolock_start + */ + if (dmaen->chan) + dma_release_channel(dmaen->chan); + + dmaen->chan = NULL; + + return 0; +} + +static int rsnd_dmaen_nolock_start(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); + struct device *dev = rsnd_priv_to_dev(priv); + + if (dmaen->chan) { + dev_err(dev, "it already has dma channel\n"); + return -EIO; + } + + /* + * DMAEngine request uses mutex lock. + * Thus, it shouldn't be called under spinlock. + * Let's call it under nolock_start + */ + dmaen->chan = rsnd_dmaen_request_channel(io, + dma->mod_from, + dma->mod_to); + if (IS_ERR_OR_NULL(dmaen->chan)) { + int ret = PTR_ERR(dmaen->chan); + + dmaen->chan = NULL; + dev_err(dev, "can't get dma channel\n"); + return ret; + } return 0; } @@ -113,7 +183,23 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct snd_pcm_substream *substream = io->substream; struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; + struct dma_slave_config cfg = {}; int is_play = rsnd_io_is_play(io); + int ret; + + cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; + cfg.src_addr = dma->src_addr; + cfg.dst_addr = dma->dst_addr; + cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + dev_dbg(dev, "%s[%d] %pad -> %pad\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + &cfg.src_addr, &cfg.dst_addr); + + ret = dmaengine_slave_config(dmaen->chan, &cfg); + if (ret < 0) + return ret; desc = dmaengine_prep_dma_cyclic(dmaen->chan, substream->runtime->dma_addr, @@ -159,97 +245,39 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, return chan; } -static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, - struct rsnd_mod *mod_from, - struct rsnd_mod *mod_to) -{ - if ((!mod_from && !mod_to) || - (mod_from && mod_to)) - return NULL; - - if (mod_from) - return rsnd_mod_dma_req(io, mod_from); - else - return rsnd_mod_dma_req(io, mod_to); -} - -static int rsnd_dmaen_remove(struct rsnd_mod *mod, - struct rsnd_dai_stream *io, - struct rsnd_priv *priv) -{ - struct rsnd_dma *dma = rsnd_mod_to_dma(mod); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); - - if (dmaen->chan) - dma_release_channel(dmaen->chan); - - dmaen->chan = NULL; - - return 0; -} - static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, struct rsnd_dma *dma, struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) { - struct rsnd_mod *mod = rsnd_mod_get(dma); - struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); - struct device *dev = rsnd_priv_to_dev(priv); - struct dma_slave_config cfg = {}; - int is_play = rsnd_io_is_play(io); - int ret; - - if (dmaen->chan) { - dev_err(dev, "it already has dma channel\n"); - return -EIO; - } - - dmaen->chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); - - if (IS_ERR_OR_NULL(dmaen->chan)) { - dmaen->chan = NULL; - dev_err(dev, "can't get dma channel\n"); - goto rsnd_dma_channel_err; + struct dma_chan *chan; + + /* try to get DMAEngine channel */ + chan = rsnd_dmaen_request_channel(io, mod_from, mod_to); + if (IS_ERR_OR_NULL(chan)) { + /* + * DMA failed. try to PIO mode + * see + * rsnd_ssi_fallback() + * rsnd_rdai_continuance_probe() + */ + return -EAGAIN; } - cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; - cfg.src_addr = dma->src_addr; - cfg.dst_addr = dma->dst_addr; - cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - - dev_dbg(dev, "%s[%d] %pad -> %pad\n", - rsnd_mod_name(mod), rsnd_mod_id(mod), - &cfg.src_addr, &cfg.dst_addr); - - ret = dmaengine_slave_config(dmaen->chan, &cfg); - if (ret < 0) - goto rsnd_dma_attach_err; + dma_release_channel(chan); dmac->dmaen_num++; return 0; - -rsnd_dma_attach_err: - rsnd_dmaen_remove(mod, io, priv); -rsnd_dma_channel_err: - - /* - * DMA failed. try to PIO mode - * see - * rsnd_ssi_fallback() - * rsnd_rdai_continuance_probe() - */ - return -EAGAIN; } static struct rsnd_mod_ops rsnd_dmaen_ops = { .name = "audmac", + .nolock_start = rsnd_dmaen_nolock_start, + .nolock_stop = rsnd_dmaen_nolock_stop, .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, - .remove = rsnd_dmaen_remove, }; /* @@ -671,9 +699,6 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, *dma_mod = rsnd_mod_get(dma); - dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); - dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); - ret = rsnd_mod_init(priv, *dma_mod, ops, NULL, rsnd_mod_get_status, type, dma_id); if (ret < 0) @@ -687,6 +712,11 @@ int rsnd_dma_attach(struct rsnd_dai_stream *io, struct rsnd_mod *mod, ret = attach(io, dma, mod_from, mod_to); if (ret < 0) return ret; + + dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); + dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); + dma->mod_from = mod_from; + dma->mod_to = mod_to; } ret = rsnd_dai_connect(*dma_mod, io, type); -- cgit v1.2.3-59-g8ed1b From 4821d914fe747a91453021675a74069776f0b819 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 14 Nov 2016 04:20:56 +0000 Subject: ASoC: rsnd: use dma_sync_single_for_xxx() for IOMMU IOMMU needs DMA mapping function to use it. One solution is that we can use DMA mapped dev on snd_pcm_lib_preallocate_pages_for_all() for SNDRV_DMA_TYPE_DEV. But pcm_new and dma map timing are mismatched. Thus, this patch uses SNDRV_DMA_TYPE_CONTINUOUS for pcm_new, and use dma_sync_single_for_xxx() for each transfer. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 4 +-- sound/soc/sh/rcar/dma.c | 84 +++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 82 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 9ffa29941ceb..912dc62ff9c7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1126,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 3c663a5cfe8b..1f405c833867 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -25,6 +25,10 @@ struct rsnd_dmaen { struct dma_chan *chan; + dma_addr_t dma_buf; + unsigned int dma_len; + unsigned int dma_period; + unsigned int dma_cnt; }; struct rsnd_dmapp { @@ -58,10 +62,38 @@ struct rsnd_dma_ctrl { /* * Audio DMAC */ +#define rsnd_dmaen_sync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 1) +#define rsnd_dmaen_unsync(dmaen, io, i) __rsnd_dmaen_sync(dmaen, io, i, 0) +static void __rsnd_dmaen_sync(struct rsnd_dmaen *dmaen, struct rsnd_dai_stream *io, + int i, int sync) +{ + struct device *dev = dmaen->chan->device->dev; + enum dma_data_direction dir; + int is_play = rsnd_io_is_play(io); + dma_addr_t buf; + int len, max; + size_t period; + + len = dmaen->dma_len; + period = dmaen->dma_period; + max = len / period; + i = i % max; + buf = dmaen->dma_buf + (period * i); + + dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; + + if (sync) + dma_sync_single_for_device(dev, buf, period, dir); + else + dma_sync_single_for_cpu(dev, buf, period, dir); +} + static void __rsnd_dmaen_complete(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct rsnd_dma *dma = rsnd_mod_to_dma(mod); + struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); bool elapsed = false; unsigned long flags; @@ -78,9 +110,22 @@ static void __rsnd_dmaen_complete(struct rsnd_mod *mod, */ spin_lock_irqsave(&priv->lock, flags); - if (rsnd_io_is_working(io)) + if (rsnd_io_is_working(io)) { + rsnd_dmaen_unsync(dmaen, io, dmaen->dma_cnt); + + /* + * Next period is already started. + * Let's sync Next Next period + * see + * rsnd_dmaen_start() + */ + rsnd_dmaen_sync(dmaen, io, dmaen->dma_cnt + 2); + elapsed = rsnd_dai_pointer_update(io, io->byte_per_period); + dmaen->dma_cnt++; + } + spin_unlock_irqrestore(&priv->lock, flags); if (elapsed) @@ -116,7 +161,12 @@ static int rsnd_dmaen_stop(struct rsnd_mod *mod, struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); if (dmaen->chan) { + int is_play = rsnd_io_is_play(io); + dmaengine_terminate_all(dmaen->chan); + dma_unmap_single(dmaen->chan->device->dev, + dmaen->dma_buf, dmaen->dma_len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); } return 0; @@ -184,7 +234,11 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, struct device *dev = rsnd_priv_to_dev(priv); struct dma_async_tx_descriptor *desc; struct dma_slave_config cfg = {}; + dma_addr_t buf; + size_t len; + size_t period; int is_play = rsnd_io_is_play(io); + int i; int ret; cfg.direction = is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM; @@ -201,10 +255,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, if (ret < 0) return ret; + len = snd_pcm_lib_buffer_bytes(substream); + period = snd_pcm_lib_period_bytes(substream); + buf = dma_map_single(dmaen->chan->device->dev, + substream->runtime->dma_area, + len, + is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (dma_mapping_error(dmaen->chan->device->dev, buf)) { + dev_err(dev, "dma map failed\n"); + return -EIO; + } + desc = dmaengine_prep_dma_cyclic(dmaen->chan, - substream->runtime->dma_addr, - snd_pcm_lib_buffer_bytes(substream), - snd_pcm_lib_period_bytes(substream), + buf, len, period, is_play ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -216,6 +279,19 @@ static int rsnd_dmaen_start(struct rsnd_mod *mod, desc->callback = rsnd_dmaen_complete; desc->callback_param = rsnd_mod_get(dma); + dmaen->dma_buf = buf; + dmaen->dma_len = len; + dmaen->dma_period = period; + dmaen->dma_cnt = 0; + + /* + * synchronize this and next period + * see + * __rsnd_dmaen_complete() + */ + for (i = 0; i < 2; i++) + rsnd_dmaen_sync(dmaen, io, i); + if (dmaengine_submit(desc) < 0) { dev_err(dev, "dmaengine_submit() fail\n"); return -EIO; -- cgit v1.2.3-59-g8ed1b From ba2ff3027b5ab4a96b9d2832822311c3ccbf3011 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Sat, 12 Nov 2016 14:46:40 +0800 Subject: ASoC: sunxi: Add support for A23/A33/H3 codec's analog path controls The internal codec on A23/A33/H3 is split into 2 parts. The analog path controls are routed through an embedded custom register bus accessed through the PRCM block. The SoCs share a common set of inputs, outputs, and audio paths. The following table lists the differences. ---------------------------------------- | Feature \ SoC | A23 | A33 | H3 | ---------------------------------------- | Headphone | v | v | | ---------------------------------------- | Line Out | | | v | ---------------------------------------- | Phone In/Out | v | v | | ---------------------------------------- Add an ASoC component driver for it. This should be tied to the codec audio card as an auxiliary device. This patch adds the commont paths and controls, and variant specific headphone out and line out. Signed-off-by: Chen-Yu Tsai Signed-off-by: Mark Brown --- sound/soc/sunxi/Kconfig | 8 + sound/soc/sunxi/Makefile | 1 + sound/soc/sunxi/sun8i-codec-analog.c | 665 +++++++++++++++++++++++++++++++++++ 3 files changed, 674 insertions(+) create mode 100644 sound/soc/sunxi/sun8i-codec-analog.c (limited to 'sound') diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index dd2368297fd3..6c344e16aca4 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig @@ -9,6 +9,14 @@ config SND_SUN4I_CODEC Select Y or M to add support for the Codec embedded in the Allwinner A10 and affiliated SoCs. +config SND_SUN8I_CODEC_ANALOG + tristate "Allwinner sun8i Codec Analog Controls Support" + depends on MACH_SUN8I || COMPILE_TEST + select REGMAP + help + Say Y or M if you want to add support for the analog controls for + the codec embedded in newer Allwinner SoCs. + config SND_SUN4I_I2S tristate "Allwinner A10 I2S Support" select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 604c7b842837..241c0df9ca0c 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o +obj-$(CONFIG_SND_SUN8I_CODEC_ANALOG) += sun8i-codec-analog.o diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c new file mode 100644 index 000000000000..222bbd440b1e --- /dev/null +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -0,0 +1,665 @@ +/* + * This driver supports the analog controls for the internal codec + * found in Allwinner's A31s, A23, A33 and H3 SoCs. + * + * Copyright 2016 Chen-Yu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Codec analog control register offsets and bit fields */ +#define SUN8I_ADDA_HP_VOLC 0x00 +#define SUN8I_ADDA_HP_VOLC_PA_CLK_GATE 7 +#define SUN8I_ADDA_HP_VOLC_HP_VOL 0 +#define SUN8I_ADDA_LOMIXSC 0x01 +#define SUN8I_ADDA_LOMIXSC_MIC1 6 +#define SUN8I_ADDA_LOMIXSC_MIC2 5 +#define SUN8I_ADDA_LOMIXSC_PHONE 4 +#define SUN8I_ADDA_LOMIXSC_PHONEN 3 +#define SUN8I_ADDA_LOMIXSC_LINEINL 2 +#define SUN8I_ADDA_LOMIXSC_DACL 1 +#define SUN8I_ADDA_LOMIXSC_DACR 0 +#define SUN8I_ADDA_ROMIXSC 0x02 +#define SUN8I_ADDA_ROMIXSC_MIC1 6 +#define SUN8I_ADDA_ROMIXSC_MIC2 5 +#define SUN8I_ADDA_ROMIXSC_PHONE 4 +#define SUN8I_ADDA_ROMIXSC_PHONEP 3 +#define SUN8I_ADDA_ROMIXSC_LINEINR 2 +#define SUN8I_ADDA_ROMIXSC_DACR 1 +#define SUN8I_ADDA_ROMIXSC_DACL 0 +#define SUN8I_ADDA_DAC_PA_SRC 0x03 +#define SUN8I_ADDA_DAC_PA_SRC_DACAREN 7 +#define SUN8I_ADDA_DAC_PA_SRC_DACALEN 6 +#define SUN8I_ADDA_DAC_PA_SRC_RMIXEN 5 +#define SUN8I_ADDA_DAC_PA_SRC_LMIXEN 4 +#define SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE 3 +#define SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE 2 +#define SUN8I_ADDA_DAC_PA_SRC_RHPIS 1 +#define SUN8I_ADDA_DAC_PA_SRC_LHPIS 0 +#define SUN8I_ADDA_PHONEIN_GCTRL 0x04 +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONEPG 4 +#define SUN8I_ADDA_PHONEIN_GCTRL_PHONENG 0 +#define SUN8I_ADDA_LINEIN_GCTRL 0x05 +#define SUN8I_ADDA_LINEIN_GCTRL_LINEING 4 +#define SUN8I_ADDA_LINEIN_GCTRL_PHONEG 0 +#define SUN8I_ADDA_MICIN_GCTRL 0x06 +#define SUN8I_ADDA_MICIN_GCTRL_MIC1G 4 +#define SUN8I_ADDA_MICIN_GCTRL_MIC2G 0 +#define SUN8I_ADDA_PAEN_HP_CTRL 0x07 +#define SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN 7 +#define SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN 7 /* H3 specific */ +#define SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC 5 +#define SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN 4 +#define SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL 2 +#define SUN8I_ADDA_PAEN_HP_CTRL_LTRNMUTE 1 +#define SUN8I_ADDA_PAEN_HP_CTRL_RTLNMUTE 0 +#define SUN8I_ADDA_PHONEOUT_CTRL 0x08 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTG 5 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUTEN 4 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC1 3 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_MIC2 2 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_RMIX 1 +#define SUN8I_ADDA_PHONEOUT_CTRL_PHONEOUT_LMIX 0 +#define SUN8I_ADDA_PHONE_GAIN_CTRL 0x09 +#define SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL 3 +#define SUN8I_ADDA_PHONE_GAIN_CTRL_PHONEPREG 0 +#define SUN8I_ADDA_MIC2G_CTRL 0x0a +#define SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN 7 +#define SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST 4 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN 3 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN 2 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC 1 +#define SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC 0 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL 0x0b +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN 7 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN 6 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE 5 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN 3 +#define SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST 0 +#define SUN8I_ADDA_LADCMIXSC 0x0c +#define SUN8I_ADDA_LADCMIXSC_MIC1 6 +#define SUN8I_ADDA_LADCMIXSC_MIC2 5 +#define SUN8I_ADDA_LADCMIXSC_PHONE 4 +#define SUN8I_ADDA_LADCMIXSC_PHONEN 3 +#define SUN8I_ADDA_LADCMIXSC_LINEINL 2 +#define SUN8I_ADDA_LADCMIXSC_OMIXRL 1 +#define SUN8I_ADDA_LADCMIXSC_OMIXRR 0 +#define SUN8I_ADDA_RADCMIXSC 0x0d +#define SUN8I_ADDA_RADCMIXSC_MIC1 6 +#define SUN8I_ADDA_RADCMIXSC_MIC2 5 +#define SUN8I_ADDA_RADCMIXSC_PHONE 4 +#define SUN8I_ADDA_RADCMIXSC_PHONEP 3 +#define SUN8I_ADDA_RADCMIXSC_LINEINR 2 +#define SUN8I_ADDA_RADCMIXSC_OMIXR 1 +#define SUN8I_ADDA_RADCMIXSC_OMIXL 0 +#define SUN8I_ADDA_RES 0x0e +#define SUN8I_ADDA_RES_MMICBIAS_SEL 4 +#define SUN8I_ADDA_RES_PA_ANTI_POP_CTRL 0 +#define SUN8I_ADDA_ADC_AP_EN 0x0f +#define SUN8I_ADDA_ADC_AP_EN_ADCREN 7 +#define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6 +#define SUN8I_ADDA_ADC_AP_EN_ADCG 0 + +/* Analog control register access bits */ +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */ +#define ADDA_PR_RESET BIT(28) +#define ADDA_PR_WRITE BIT(24) +#define ADDA_PR_ADDR_SHIFT 16 +#define ADDA_PR_ADDR_MASK GENMASK(4, 0) +#define ADDA_PR_DATA_IN_SHIFT 8 +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0) +#define ADDA_PR_DATA_OUT_SHIFT 0 +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0) + +/* regmap access bits */ +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Read back value */ + *val = readl(base) & ADDA_PR_DATA_OUT_MASK; + + return 0; +} + +static int adda_reg_write(void *context, unsigned int reg, unsigned int val) +{ + void __iomem *base = (void __iomem *)context; + u32 tmp; + + /* De-assert reset */ + writel(readl(base) | ADDA_PR_RESET, base); + + /* Set register address */ + tmp = readl(base); + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT); + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT; + writel(tmp, base); + + /* Set data to write */ + tmp = readl(base); + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT); + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT; + writel(tmp, base); + + /* Set write bit to signal a write */ + writel(readl(base) | ADDA_PR_WRITE, base); + + /* Clear write bit */ + writel(readl(base) & ~ADDA_PR_WRITE, base); + + return 0; +} + +static const struct regmap_config adda_pr_regmap_cfg = { + .name = "adda-pr", + .reg_bits = 5, + .reg_stride = 1, + .val_bits = 8, + .reg_read = adda_reg_read, + .reg_write = adda_reg_write, + .fast_io = true, + .max_register = 24, +}; + +/* mixer controls */ +static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("DAC Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_DACL, 1, 0), + SOC_DAPM_DOUBLE_R("DAC Reversed Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_DACR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Playback Switch", + SUN8I_ADDA_LOMIXSC, + SUN8I_ADDA_ROMIXSC, + SUN8I_ADDA_LOMIXSC_MIC2, 1, 0), +}; + +/* ADC mixer controls */ +static const struct snd_kcontrol_new sun8i_codec_adc_mixer_controls[] = { + SOC_DAPM_DOUBLE_R("Mixer Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_OMIXRL, 1, 0), + SOC_DAPM_DOUBLE_R("Mixer Reversed Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_OMIXRR, 1, 0), + SOC_DAPM_DOUBLE_R("Line In Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_LINEINL, 1, 0), + SOC_DAPM_DOUBLE_R("Mic1 Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_MIC1, 1, 0), + SOC_DAPM_DOUBLE_R("Mic2 Capture Switch", + SUN8I_ADDA_LADCMIXSC, + SUN8I_ADDA_RADCMIXSC, + SUN8I_ADDA_LADCMIXSC_MIC2, 1, 0), +}; + +/* volume / mute controls */ +static const DECLARE_TLV_DB_SCALE(sun8i_codec_out_mixer_pregain_scale, + -450, 150, 0); +static const DECLARE_TLV_DB_RANGE(sun8i_codec_mic_gain_scale, + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 7, TLV_DB_SCALE_ITEM(2400, 300, 0), +); + +static const struct snd_kcontrol_new sun8i_codec_common_controls[] = { + /* Mixer pre-gains */ + SOC_SINGLE_TLV("Line In Playback Volume", SUN8I_ADDA_LINEIN_GCTRL, + SUN8I_ADDA_LINEIN_GCTRL_LINEING, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic1 Playback Volume", SUN8I_ADDA_MICIN_GCTRL, + SUN8I_ADDA_MICIN_GCTRL_MIC1G, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + SOC_SINGLE_TLV("Mic2 Playback Volume", + SUN8I_ADDA_MICIN_GCTRL, SUN8I_ADDA_MICIN_GCTRL_MIC2G, + 0x7, 0, sun8i_codec_out_mixer_pregain_scale), + + /* Microphone Amp boost gains */ + SOC_SINGLE_TLV("Mic1 Boost Volume", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1BOOST, 0x7, 0, + sun8i_codec_mic_gain_scale), + SOC_SINGLE_TLV("Mic2 Boost Volume", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2BOOST, 0x7, 0, + sun8i_codec_mic_gain_scale), + + /* ADC */ + SOC_SINGLE_TLV("ADC Gain Capture Volume", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCG, 0x7, 0, + sun8i_codec_out_mixer_pregain_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_common_widgets[] = { + /* ADC */ + SND_SOC_DAPM_ADC("Left ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0), + SND_SOC_DAPM_ADC("Right ADC", NULL, SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0), + + /* DAC */ + SND_SOC_DAPM_DAC("Left DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACALEN, 0), + SND_SOC_DAPM_DAC("Right DAC", NULL, SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_DACAREN, 0), + /* + * Due to this component and the codec belonging to separate DAPM + * contexts, we need to manually link the above widgets to their + * stream widgets at the card level. + */ + + /* Line In */ + SND_SOC_DAPM_INPUT("LINEIN"), + + /* Microphone inputs */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + + /* Microphone Bias */ + SND_SOC_DAPM_SUPPLY("MBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MMICBIASEN, + 0, NULL, 0), + + /* Mic input path */ + SND_SOC_DAPM_PGA("Mic1 Amplifier", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_MIC1AMPEN, 0, NULL, 0), + SND_SOC_DAPM_PGA("Mic2 Amplifier", SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_MIC2AMPEN, 0, NULL, 0), + + /* Mixers */ + SND_SOC_DAPM_MIXER("Left Mixer", SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Right Mixer", SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_RMIXEN, 0, + sun8i_codec_mixer_controls, + ARRAY_SIZE(sun8i_codec_mixer_controls)), + SND_SOC_DAPM_MIXER("Left ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCLEN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), + SND_SOC_DAPM_MIXER("Right ADC Mixer", SUN8I_ADDA_ADC_AP_EN, + SUN8I_ADDA_ADC_AP_EN_ADCREN, 0, + sun8i_codec_adc_mixer_controls, + ARRAY_SIZE(sun8i_codec_adc_mixer_controls)), +}; + +static const struct snd_soc_dapm_route sun8i_codec_common_routes[] = { + /* Microphone Routes */ + { "Mic1 Amplifier", NULL, "MIC1"}, + { "Mic2 Amplifier", NULL, "MIC2"}, + + /* Left Mixer Routes */ + { "Left Mixer", "DAC Playback Switch", "Left DAC" }, + { "Left Mixer", "DAC Reversed Playback Switch", "Right DAC" }, + { "Left Mixer", "Line In Playback Switch", "LINEIN" }, + { "Left Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Left Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + /* Right Mixer Routes */ + { "Right Mixer", "DAC Playback Switch", "Right DAC" }, + { "Right Mixer", "DAC Reversed Playback Switch", "Left DAC" }, + { "Right Mixer", "Line In Playback Switch", "LINEIN" }, + { "Right Mixer", "Mic1 Playback Switch", "Mic1 Amplifier" }, + { "Right Mixer", "Mic2 Playback Switch", "Mic2 Amplifier" }, + + /* Left ADC Mixer Routes */ + { "Left ADC Mixer", "Mixer Capture Switch", "Left Mixer" }, + { "Left ADC Mixer", "Mixer Reversed Capture Switch", "Right Mixer" }, + { "Left ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Left ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Left ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* Right ADC Mixer Routes */ + { "Right ADC Mixer", "Mixer Capture Switch", "Right Mixer" }, + { "Right ADC Mixer", "Mixer Reversed Capture Switch", "Left Mixer" }, + { "Right ADC Mixer", "Line In Capture Switch", "LINEIN" }, + { "Right ADC Mixer", "Mic1 Capture Switch", "Mic1 Amplifier" }, + { "Right ADC Mixer", "Mic2 Capture Switch", "Mic2 Amplifier" }, + + /* ADC Routes */ + { "Left ADC", NULL, "Left ADC Mixer" }, + { "Right ADC", NULL, "Right ADC Mixer" }, +}; + +/* headphone specific controls, widgets, and routes */ +static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1); +static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = { + SOC_SINGLE_TLV("Headphone Playback Volume", + SUN8I_ADDA_HP_VOLC, + SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0, + sun8i_codec_hp_vol_scale), + SOC_DOUBLE("Headphone Playback Switch", + SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LHPPAMUTE, + SUN8I_ADDA_DAC_PA_SRC_RHPPAMUTE, 1, 0), +}; + +static const char * const sun8i_codec_hp_src_enum_text[] = { + "DAC", "Mixer", +}; + +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_hp_src_enum, + SUN8I_ADDA_DAC_PA_SRC, + SUN8I_ADDA_DAC_PA_SRC_LHPIS, + SUN8I_ADDA_DAC_PA_SRC_RHPIS, + sun8i_codec_hp_src_enum_text); + +static const struct snd_kcontrol_new sun8i_codec_hp_src[] = { + SOC_DAPM_ENUM("Headphone Source Playback Route", + sun8i_codec_hp_src_enum), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_headphone_widgets[] = { + SND_SOC_DAPM_MUX("Headphone Source Playback Route", + SND_SOC_NOPM, 0, 0, sun8i_codec_hp_src), + SND_SOC_DAPM_OUT_DRV("Headphone Amp", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("HPCOM Protection", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_COMPTEN, 0, NULL, 0), + SND_SOC_DAPM_REG(snd_soc_dapm_supply, "HPCOM", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_HPCOM_FC, 0x3, 0x3, 0), + SND_SOC_DAPM_OUTPUT("HP"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_headphone_routes[] = { + { "Headphone Source Playback Route", "DAC", "Left DAC" }, + { "Headphone Source Playback Route", "DAC", "Right DAC" }, + { "Headphone Source Playback Route", "Mixer", "Left Mixer" }, + { "Headphone Source Playback Route", "Mixer", "Right Mixer" }, + { "Headphone Amp", NULL, "Headphone Source Playback Route" }, + { "HPCOM", NULL, "HPCOM Protection" }, + { "HP", NULL, "Headphone Amp" }, +}; + +static int sun8i_codec_add_headphone(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun8i_codec_headphone_controls, + ARRAY_SIZE(sun8i_codec_headphone_controls)); + if (ret) { + dev_err(dev, "Failed to add Headphone controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_headphone_widgets, + ARRAY_SIZE(sun8i_codec_headphone_widgets)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_headphone_routes, + ARRAY_SIZE(sun8i_codec_headphone_routes)); + if (ret) { + dev_err(dev, "Failed to add Headphone DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + +/* hmic specific widget */ +static const struct snd_soc_dapm_widget sun8i_codec_hmic_widgets[] = { + SND_SOC_DAPM_SUPPLY("HBIAS", SUN8I_ADDA_MIC1G_MICBIAS_CTRL, + SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN, + 0, NULL, 0), +}; + +static int sun8i_codec_add_hmic(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_hmic_widgets, + ARRAY_SIZE(sun8i_codec_hmic_widgets)); + if (ret) + dev_err(dev, "Failed to add Mic3 DAPM widgets: %d\n", ret); + + return ret; +} + +/* line out specific controls, widgets and routes */ +static const DECLARE_TLV_DB_RANGE(sun8i_codec_lineout_vol_scale, + 0, 1, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 2, 31, TLV_DB_SCALE_ITEM(-4350, 150, 0), +); +static const struct snd_kcontrol_new sun8i_codec_lineout_controls[] = { + SOC_SINGLE_TLV("Line Out Playback Volume", + SUN8I_ADDA_PHONE_GAIN_CTRL, + SUN8I_ADDA_PHONE_GAIN_CTRL_LINEOUT_VOL, 0x1f, 0, + sun8i_codec_lineout_vol_scale), + SOC_DOUBLE("Line Out Playback Switch", + SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLEN, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTREN, 1, 0), +}; + +static const char * const sun8i_codec_lineout_src_enum_text[] = { + "Stereo", "Mono Differential", +}; + +static SOC_ENUM_DOUBLE_DECL(sun8i_codec_lineout_src_enum, + SUN8I_ADDA_MIC2G_CTRL, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTLSRC, + SUN8I_ADDA_MIC2G_CTRL_LINEOUTRSRC, + sun8i_codec_lineout_src_enum_text); + +static const struct snd_kcontrol_new sun8i_codec_lineout_src[] = { + SOC_DAPM_ENUM("Line Out Source Playback Route", + sun8i_codec_lineout_src_enum), +}; + +static const struct snd_soc_dapm_widget sun8i_codec_lineout_widgets[] = { + SND_SOC_DAPM_MUX("Line Out Source Playback Route", + SND_SOC_NOPM, 0, 0, sun8i_codec_lineout_src), + /* It is unclear if this is a buffer or gate, model it as a supply */ + SND_SOC_DAPM_SUPPLY("Line Out Enable", SUN8I_ADDA_PAEN_HP_CTRL, + SUN8I_ADDA_PAEN_HP_CTRL_LINEOUTEN, 0, NULL, 0), + SND_SOC_DAPM_OUTPUT("LINEOUT"), +}; + +static const struct snd_soc_dapm_route sun8i_codec_lineout_routes[] = { + { "Line Out Source Playback Route", "Stereo", "Left Mixer" }, + { "Line Out Source Playback Route", "Stereo", "Right Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Left Mixer" }, + { "Line Out Source Playback Route", "Mono Differential", "Right Mixer" }, + { "LINEOUT", NULL, "Line Out Source Playback Route" }, + { "LINEOUT", NULL, "Line Out Enable", }, +}; + +static int sun8i_codec_add_lineout(struct snd_soc_component *cmpnt) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); + struct device *dev = cmpnt->dev; + int ret; + + ret = snd_soc_add_component_controls(cmpnt, + sun8i_codec_lineout_controls, + ARRAY_SIZE(sun8i_codec_lineout_controls)); + if (ret) { + dev_err(dev, "Failed to add Line Out controls: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_new_controls(dapm, sun8i_codec_lineout_widgets, + ARRAY_SIZE(sun8i_codec_lineout_widgets)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM widgets: %d\n", ret); + return ret; + } + + ret = snd_soc_dapm_add_routes(dapm, sun8i_codec_lineout_routes, + ARRAY_SIZE(sun8i_codec_lineout_routes)); + if (ret) { + dev_err(dev, "Failed to add Line Out DAPM routes: %d\n", ret); + return ret; + } + + return 0; +} + +struct sun8i_codec_analog_quirks { + bool has_headphone; + bool has_hmic; + bool has_lineout; +}; + +static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = { + .has_headphone = true, + .has_hmic = true, +}; + +static const struct sun8i_codec_analog_quirks sun8i_h3_quirks = { + .has_lineout = true, +}; + +static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) +{ + struct device *dev = cmpnt->dev; + const struct sun8i_codec_analog_quirks *quirks; + int ret; + + /* + * This would never return NULL unless someone directly registers a + * platform device matching this driver's name, without specifying a + * device tree node. + */ + quirks = of_device_get_match_data(dev); + + /* Add controls, widgets, and routes for individual features */ + + if (quirks->has_headphone) { + ret = sun8i_codec_add_headphone(cmpnt); + if (ret) + return ret; + } + + if (quirks->has_hmic) { + sun8i_codec_add_hmic(cmpnt); + if (ret) + return ret; + } + + if (quirks->has_lineout) { + ret = sun8i_codec_add_lineout(cmpnt); + if (ret) + return ret; + } + + return 0; +} + +static const struct snd_soc_component_driver sun8i_codec_analog_cmpnt_drv = { + .controls = sun8i_codec_common_controls, + .num_controls = ARRAY_SIZE(sun8i_codec_common_controls), + .dapm_widgets = sun8i_codec_common_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun8i_codec_common_widgets), + .dapm_routes = sun8i_codec_common_routes, + .num_dapm_routes = ARRAY_SIZE(sun8i_codec_common_routes), + .probe = sun8i_codec_analog_cmpnt_probe, +}; + +static const struct of_device_id sun8i_codec_analog_of_match[] = { + { + .compatible = "allwinner,sun8i-a23-codec-analog", + .data = &sun8i_a23_quirks, + }, + { + .compatible = "allwinner,sun8i-h3-codec-analog", + .data = &sun8i_h3_quirks, + }, + {} +}; +MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match); + +static int sun8i_codec_analog_probe(struct platform_device *pdev) +{ + struct resource *res; + struct regmap *regmap; + void __iomem *base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + dev_err(&pdev->dev, "Failed to map the registers\n"); + return PTR_ERR(base); + } + + regmap = devm_regmap_init(&pdev->dev, NULL, base, &adda_pr_regmap_cfg); + if (IS_ERR(regmap)) { + dev_err(&pdev->dev, "Failed to create regmap\n"); + return PTR_ERR(regmap); + } + + return devm_snd_soc_register_component(&pdev->dev, + &sun8i_codec_analog_cmpnt_drv, + NULL, 0); +} + +static struct platform_driver sun8i_codec_analog_driver = { + .driver = { + .name = "sun8i-codec-analog", + .of_match_table = sun8i_codec_analog_of_match, + }, + .probe = sun8i_codec_analog_probe, +}; +module_platform_driver(sun8i_codec_analog_driver); + +MODULE_DESCRIPTION("Allwinner internal codec analog controls driver"); +MODULE_AUTHOR("Chen-Yu Tsai "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:sun8i-codec-analog"); -- cgit v1.2.3-59-g8ed1b From 48c2c99359044763b0cf21e59405638f9630fe06 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 22 Nov 2016 15:38:34 +0000 Subject: ASoC: wm_adsp: Check return value from wm_adsp_buffer_init We are not checking the return value from a call to wm_adsp_buffer_init it looks like this used to be returned at the bottom of the function but probably got missed when more error paths were added. This patch adds the appropriate error check. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 6e6b9d838332..ff111a82fa3f 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -2575,8 +2575,13 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, mutex_lock(&dsp->pwr_lock); - if (wm_adsp_fw[dsp->fw].num_caps != 0) + if (wm_adsp_fw[dsp->fw].num_caps != 0) { ret = wm_adsp_buffer_init(dsp); + if (ret < 0) { + mutex_unlock(&dsp->pwr_lock); + goto err; + } + } mutex_unlock(&dsp->pwr_lock); -- cgit v1.2.3-59-g8ed1b From 4185d4be22a3fbf8e065437883ced195e692642b Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 23 Nov 2016 10:30:10 +0100 Subject: ASoC: uda1380: Remove unused DAI ID defines The DAI ID defines are back from the time when DAIs were referenced by a numerical ID. These days a string is used for matching instead and the defines are unused. The last user of these defines was removed in commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support"). So remove the defines as well. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.h | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/uda1380.h b/sound/soc/codecs/uda1380.h index 942e3927c72b..69a326ac3c1a 100644 --- a/sound/soc/codecs/uda1380.h +++ b/sound/soc/codecs/uda1380.h @@ -72,8 +72,4 @@ #define R22_SKIP_DCFIL 0x0002 #define R23_AGC_EN 0x0001 -#define UDA1380_DAI_DUPLEX 0 /* playback and capture on single DAI */ -#define UDA1380_DAI_PLAYBACK 1 /* playback DAI */ -#define UDA1380_DAI_CAPTURE 2 /* capture DAI */ - #endif /* _UDA1380_H */ -- cgit v1.2.3-59-g8ed1b From 222e728ca29b5976accd1fc520a716d168ee2ca5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 23 Nov 2016 10:30:11 +0100 Subject: ASoC: uda1380: Request GPIOs at bus probe time Resources should be requested when the device is probed on the control bus rather then when the CODEC is bound to the sound card. This allows things like probe deferring and device managed allocations to work. So move the GPIO request calls from the CODEC probe to the bus probe and also make them managed along the way. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda1380.c | 55 +++++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 35 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 8e52439a58fd..2918fdb95e58 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -698,25 +698,10 @@ static int uda1380_probe(struct snd_soc_codec *codec) codec->hw_write = (hw_write_t)i2c_master_send; codec->control_data = uda1380->control_data; - if (!pdata) - return -EINVAL; - - if (gpio_is_valid(pdata->gpio_reset)) { - ret = gpio_request_one(pdata->gpio_reset, GPIOF_OUT_INIT_LOW, - "uda1380 reset"); - if (ret) - goto err_out; - } - - if (gpio_is_valid(pdata->gpio_power)) { - ret = gpio_request_one(pdata->gpio_power, GPIOF_OUT_INIT_LOW, - "uda1380 power"); - if (ret) - goto err_free_gpio; - } else { + if (!gpio_is_valid(pdata->gpio_power)) { ret = uda1380_reset(codec); if (ret) - goto err_free_gpio; + return ret; } INIT_WORK(&uda1380->work, uda1380_flush_work); @@ -732,29 +717,11 @@ static int uda1380_probe(struct snd_soc_codec *codec) break; } - return 0; - -err_free_gpio: - if (gpio_is_valid(pdata->gpio_reset)) - gpio_free(pdata->gpio_reset); -err_out: - return ret; -} - -/* power down chip */ -static int uda1380_remove(struct snd_soc_codec *codec) -{ - struct uda1380_platform_data *pdata =codec->dev->platform_data; - - gpio_free(pdata->gpio_reset); - gpio_free(pdata->gpio_power); - return 0; } static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { .probe = uda1380_probe, - .remove = uda1380_remove, .read = uda1380_read_reg_cache, .write = uda1380_write, .set_bias_level = uda1380_set_bias_level, @@ -778,14 +745,32 @@ static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { static int uda1380_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { + struct uda1380_platform_data *pdata = i2c->dev.platform_data; struct uda1380_priv *uda1380; int ret; + if (!pdata) + return -EINVAL; + uda1380 = devm_kzalloc(&i2c->dev, sizeof(struct uda1380_priv), GFP_KERNEL); if (uda1380 == NULL) return -ENOMEM; + if (gpio_is_valid(pdata->gpio_reset)) { + ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_reset, + GPIOF_OUT_INIT_LOW, "uda1380 reset"); + if (ret) + return ret; + } + + if (gpio_is_valid(pdata->gpio_power)) { + ret = devm_gpio_request_one(&i2c->dev, pdata->gpio_power, + GPIOF_OUT_INIT_LOW, "uda1380 power"); + if (ret) + return ret; + } + i2c_set_clientdata(i2c, uda1380); uda1380->control_data = i2c; -- cgit v1.2.3-59-g8ed1b From 0a69516cd8b9878c4040c35294443ac18338febd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 22 Nov 2016 22:49:48 +0100 Subject: ASoC: ab8500: Remove explicit initialization of driver callbacks to NULL Fields of structs with global storage are implicitly initialized to 0/NULL, there is usually no need to do this explicitly. Removing the initialization of the legacy suspend/resume callback fields also gets the driver ready for the day when they are eventually removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ab8500-codec.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 935ff7cb71c5..312b2a11abb6 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c @@ -2587,8 +2587,6 @@ static struct platform_driver ab8500_codec_platform_driver = { }, .probe = ab8500_codec_driver_probe, .remove = ab8500_codec_driver_remove, - .suspend = NULL, - .resume = NULL, }; module_platform_driver(ab8500_codec_platform_driver); -- cgit v1.2.3-59-g8ed1b From 64047d7f4912de1769d1bf0d34c6322494b13779 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 23 Nov 2016 16:05:37 +0800 Subject: ALSA: hda - ignore the assoc and seq when comparing pin configurations More and more pin configurations have been adding to the pin quirk table, lots of them are only different from assoc and seq, but they all apply to the same QUIRK_FIXUP, if we don't compare assoc and seq when matching pin configurations, it will greatly reduce the pin quirk table size. We have tested this change on a couple of Dell laptops, it worked well. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 7f57a145a47e..4ad29f8d7a4a 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -901,7 +901,7 @@ static bool pin_config_match(struct hda_codec *codec, for (; t_pins->nid; t_pins++) { if (t_pins->nid == nid) { found = 1; - if (t_pins->val == cfg) + if ((t_pins->val & 0xfffffff0) == (cfg & 0xfffffff0)) break; else if ((cfg & 0xf0000000) == 0x40000000 && (t_pins->val & 0xf0000000) == 0x40000000) break; -- cgit v1.2.3-59-g8ed1b From 989dbe4a30728c047316ab87e5fa8b609951ce7c Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Wed, 23 Nov 2016 16:05:38 +0800 Subject: ALSA: hda - fix headset-mic problem on a Dell laptop This group of new pins is not in the pin quirk table yet, adding them to the pin quirk table to fix the headset-mic problem. Cc: Signed-off-by: Hui Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ea81c08ddc7a..3f75d1b83bf2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5917,6 +5917,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { {0x12, 0x90a60180}, {0x14, 0x90170120}, {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x1b, 0x01011020}, + {0x21, 0x02211010}), SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, {0x12, 0x90a60160}, {0x14, 0x90170120}, -- cgit v1.2.3-59-g8ed1b From 999982ef7c7f8aa131d32ef551897804443a40a1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Nov 2016 01:29:06 +0300 Subject: ASoC: sunxi: Uninitialized variable in probe() Oddly enough, my version of GCC misses this uninitialized variable. Fixes: ba2ff3027b5a ("ASoC: sunxi: Add support for A23/A33/H3 codec's analog path controls") Signed-off-by: Dan Carpenter Acked-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- sound/soc/sunxi/sun8i-codec-analog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c index 222bbd440b1e..af02290ebe49 100644 --- a/sound/soc/sunxi/sun8i-codec-analog.c +++ b/sound/soc/sunxi/sun8i-codec-analog.c @@ -589,7 +589,7 @@ static int sun8i_codec_analog_cmpnt_probe(struct snd_soc_component *cmpnt) } if (quirks->has_hmic) { - sun8i_codec_add_hmic(cmpnt); + ret = sun8i_codec_add_hmic(cmpnt); if (ret) return ret; } -- cgit v1.2.3-59-g8ed1b From c186fe7401e4234aee6796eda3ad38bd57507899 Mon Sep 17 00:00:00 2001 From: GuruprasadX Pawse Date: Wed, 23 Nov 2016 22:46:26 +0530 Subject: ASoC: Intel: Skylake: Don't use dma I2S config structure in kernel I2S blob config structure can change between DSP copier module versions. We are not modifying these structures anyway and NHLT blobs specify them properly, so use the blob directly to send the dma_control ipc instead of using the predefined I2S blob config structure. Signed-off-by: GuruprasadX Pawse Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-messages.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 4ae021aabc3a..e79cbcf6e462 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c @@ -527,16 +527,14 @@ static void skl_setup_cpr_gateway_cfg(struct skl_sst *ctx, int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) { struct skl_dma_control *dma_ctrl; - struct skl_i2s_config_blob config_blob; struct skl_ipc_large_config_msg msg = {0}; int err = 0; /* - * if blob size is same as capablity size, then no dma control - * present so return + * if blob size zero, then return */ - if (mconfig->formats_config.caps_size == sizeof(config_blob)) + if (mconfig->formats_config.caps_size == 0) return 0; msg.large_param_id = DMA_CONTROL_ID; @@ -550,7 +548,7 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) dma_ctrl->node_id = skl_get_node_id(ctx, mconfig); /* size in dwords */ - dma_ctrl->config_length = sizeof(config_blob) / 4; + dma_ctrl->config_length = mconfig->formats_config.caps_size / 4; memcpy(dma_ctrl->config_data, mconfig->formats_config.caps, mconfig->formats_config.caps_size); @@ -558,7 +556,6 @@ int skl_dsp_set_dma_control(struct skl_sst *ctx, struct skl_module_cfg *mconfig) err = skl_ipc_set_large_config(&ctx->ipc, &msg, (u32 *)dma_ctrl); kfree(dma_ctrl); - return err; } -- cgit v1.2.3-59-g8ed1b From 48458cc891232ba6cb0270ba03520f54536d590a Mon Sep 17 00:00:00 2001 From: GuruprasadX Pawse Date: Wed, 23 Nov 2016 22:46:27 +0530 Subject: ASoC: Intel: Skylake: Removed the unused I2S blob structure Now that I2S conflig blob structure is no longer in use, remove it. Signed-off-by: GuruprasadX Pawse Signed-off-by: Jeeja KP Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-topology.h | 17 ----------------- 1 file changed, 17 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index 3b962d84bcb8..08d39280b07b 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h @@ -113,23 +113,6 @@ struct skl_cpr_gtw_cfg { u32 config_data[1]; } __packed; -struct skl_i2s_config_blob { - u32 gateway_attrib; - u32 tdm_ts_group[8]; - u32 ssc0; - u32 ssc1; - u32 sscto; - u32 sspsp; - u32 sstsa; - u32 ssrsa; - u32 ssc2; - u32 sspsp2; - u32 ssc3; - u32 ssioc; - u32 mdivc; - u32 mdivr; -} __packed; - struct skl_dma_control { u32 node_id; u32 config_length; -- cgit v1.2.3-59-g8ed1b From b5337cfe067e96b8a98699da90c7dcd2bec21133 Mon Sep 17 00:00:00 2001 From: Sven Hahne Date: Fri, 25 Nov 2016 14:16:43 +0100 Subject: ALSA: hda/ca0132 - Add quirk for Alienware 15 R2 2016 I'm using an Alienware 15 R2 and had to use the alienware quirks to get my headphone output working. I fixed it by adding, SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE) to the patch. Signed-off-by: Sven Hahne Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_ca0132.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index ad06866d7c69..11b9b2f17a2e 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -780,6 +780,7 @@ static const struct hda_pintbl alienware_pincfgs[] = { static const struct snd_pci_quirk ca0132_quirks[] = { SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), + SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE), {} }; -- cgit v1.2.3-59-g8ed1b From c6790c8e770c6a7a5414e42438705ec92b03a790 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Fri, 25 Nov 2016 16:15:17 +0800 Subject: ALSA: hda/realtek - Add support for headset MIC for ALC622 Add headset MIC support for ALC622 of USI platform. It only support headset of iphone type. Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 64c22ccf239b..9448daff9d8b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6564,6 +6564,30 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec, } } +static void alc662_usi_automute_hook(struct hda_codec *codec, + struct hda_jack_callback *jack) +{ + struct alc_spec *spec = codec->spec; + int vref; + msleep(200); + snd_hda_gen_hp_automute(codec, jack); + + vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; + msleep(100); + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + vref); +} + +static void alc662_fixup_usi_headset_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + spec->gen.hp_automute_hook = alc662_usi_automute_hook; + } +} + static struct coef_fw alc668_coefs[] = { WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03, 0x0), WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06, 0x0), WRITE_COEF(0x07, 0x0f80), @@ -6629,6 +6653,8 @@ enum { ALC891_FIXUP_DELL_MIC_NO_PRESENCE, ALC662_FIXUP_ACER_VERITON, ALC892_FIXUP_ASROCK_MOBO, + ALC662_FIXUP_USI_FUNC, + ALC662_FIXUP_USI_HEADSET_MODE, }; static const struct hda_fixup alc662_fixups[] = { @@ -6913,6 +6939,20 @@ static const struct hda_fixup alc662_fixups[] = { { } } }, + [ALC662_FIXUP_USI_FUNC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_usi_headset_mic, + }, + [ALC662_FIXUP_USI_HEADSET_MODE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */ + { 0x18, 0x01a1903d }, + { } + }, + .chained = true, + .chain_id = ALC662_FIXUP_USI_FUNC + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { @@ -6948,6 +6988,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), + SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD), SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO), -- cgit v1.2.3-59-g8ed1b From 739507159e4e135a0a21df5a947753f44b0789b8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 29 Nov 2016 10:46:22 +0000 Subject: ASoC: arizona: Remove redundant extern declarations Functions are given external linkage by default making the extern's unnecessary, as such remove them. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.h | 80 ++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 42 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 813f1cdb565d..56707860657c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -256,28 +256,24 @@ extern const struct soc_enum arizona_output_anc_src[]; extern const struct snd_kcontrol_new arizona_voice_trigger_switch[]; -extern int arizona_in_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); -extern int arizona_out_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); -extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); -extern int arizona_anc_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, - int event); - -extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -extern int arizona_clk_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); -extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, - int source, unsigned int freq, int dir); +int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_out_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_anc_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); + +int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int arizona_clk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event); +int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, + unsigned int freq, int dir); extern const struct snd_soc_dai_ops arizona_dai_ops; extern const struct snd_soc_dai_ops arizona_simple_dai_ops; @@ -300,35 +296,35 @@ struct arizona_fll { char clock_ok_name[ARIZONA_FLL_NAME_LEN]; }; -extern int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); -extern int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); -extern int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event); -extern void arizona_init_dvfs(struct arizona_priv *priv); - -extern int arizona_init_fll(struct arizona *arizona, int id, int base, - int lock_irq, int ok_irq, struct arizona_fll *fll); -extern int arizona_set_fll_refclk(struct arizona_fll *fll, int source, - unsigned int Fref, unsigned int Fout); -extern int arizona_set_fll(struct arizona_fll *fll, int source, +int arizona_dvfs_up(struct snd_soc_codec *codec, unsigned int flags); +int arizona_dvfs_down(struct snd_soc_codec *codec, unsigned int flags); +int arizona_dvfs_sysclk_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +void arizona_init_dvfs(struct arizona_priv *priv); + +int arizona_init_fll(struct arizona *arizona, int id, int base, + int lock_irq, int ok_irq, struct arizona_fll *fll); +int arizona_set_fll_refclk(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout); +int arizona_set_fll(struct arizona_fll *fll, int source, + unsigned int Fref, unsigned int Fout); -extern int arizona_init_spk(struct snd_soc_codec *codec); -extern int arizona_init_gpio(struct snd_soc_codec *codec); -extern int arizona_init_mono(struct snd_soc_codec *codec); -extern int arizona_init_notifiers(struct snd_soc_codec *codec); +int arizona_init_spk(struct snd_soc_codec *codec); +int arizona_init_gpio(struct snd_soc_codec *codec); +int arizona_init_mono(struct snd_soc_codec *codec); +int arizona_init_notifiers(struct snd_soc_codec *codec); -extern int arizona_init_spk_irqs(struct arizona *arizona); -extern int arizona_free_spk_irqs(struct arizona *arizona); +int arizona_init_spk_irqs(struct arizona *arizona); +int arizona_free_spk_irqs(struct arizona *arizona); -extern int arizona_init_dai(struct arizona_priv *priv, int dai); +int arizona_init_dai(struct arizona_priv *priv, int dai); int arizona_set_output_mode(struct snd_soc_codec *codec, int output, bool diff); -extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); +bool arizona_input_analog(struct snd_soc_codec *codec, int shift); -extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); +const char *arizona_sample_rate_val_to_name(unsigned int rate_val); static inline int arizona_register_notifier(struct snd_soc_codec *codec, struct notifier_block *nb, -- cgit v1.2.3-59-g8ed1b From 63079b6e43a813341fc5b44bc899796d5a857fd8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 29 Nov 2016 10:46:21 +0000 Subject: ASoC: wm_adsp: Remove redundant extern declarations Functions are given external linkage by default making the extern's unnecessary, as such remove them. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.h | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index 3f7c8ee42243..411d062c13f2 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h @@ -110,18 +110,17 @@ int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, int wm_adsp2_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); -extern int wm_adsp_compr_open(struct wm_adsp *dsp, - struct snd_compr_stream *stream); -extern int wm_adsp_compr_free(struct snd_compr_stream *stream); -extern int wm_adsp_compr_set_params(struct snd_compr_stream *stream, - struct snd_compr_params *params); -extern int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, - struct snd_compr_caps *caps); -extern int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); -extern int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); -extern int wm_adsp_compr_pointer(struct snd_compr_stream *stream, - struct snd_compr_tstamp *tstamp); -extern int wm_adsp_compr_copy(struct snd_compr_stream *stream, - char __user *buf, size_t count); +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, + struct snd_compr_params *params); +int wm_adsp_compr_get_caps(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_handle_irq(struct wm_adsp *dsp); +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp); +int wm_adsp_compr_copy(struct snd_compr_stream *stream, + char __user *buf, size_t count); #endif -- cgit v1.2.3-59-g8ed1b From 91197a9230e852eeefdb79b1bddc3cd9505d4248 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Nov 2016 16:26:40 +0100 Subject: ASoC: Intel: atom: Make some messages to debug level Intel sst driver spews lots of kernel messages in INFO level; typically, it gives a kernel message at each time it allocates or frees a stream, or at each time when a stream is started or stopped. This will piles up quickly, and it's almost useless for normal users, so let's hide them to KERN_DEBUG level. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- sound/soc/intel/atom/sst/sst_stream.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 0838478c4c3f..c7b3cbf92faf 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -937,7 +937,7 @@ int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) struct sst_data *drv = snd_soc_dai_get_drvdata(dai); int ssp_id; - dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); + dev_dbg(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); if (strcmp(id, "ssp0-port") == 0) ssp_id = SSP_MODEM; diff --git a/sound/soc/intel/atom/sst/sst_stream.c b/sound/soc/intel/atom/sst/sst_stream.c index 4ccc80e5e8cc..51bdeeecb7c8 100644 --- a/sound/soc/intel/atom/sst/sst_stream.c +++ b/sound/soc/intel/atom/sst/sst_stream.c @@ -104,7 +104,7 @@ int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, str_id, alloc_param.operation, 0); - dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", + dev_dbg(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", str_id, pipe_id); ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), @@ -415,7 +415,7 @@ int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) str_info->status = STREAM_UN_INIT; mutex_unlock(&str_info->lock); - dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", + dev_dbg(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", str_id, str_info->pipe_id); retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, -- cgit v1.2.3-59-g8ed1b From e3d62cb8c70ff5ff946051484b1cdb38523d8b95 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 28 Nov 2016 13:24:06 +0800 Subject: ASoC: rt298: disable IRQ when jack is NULL Disable IRQ when jack is NULL in rt298_mic_detect. So machine driver can use it in suspend/resume. Signed-off-by: Bard Liao Reviewed-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 55558643166f..6c4ac5b04665 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -321,11 +321,31 @@ static void rt298_jack_detect_work(struct work_struct *work) int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) { struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm; + bool hp = false; + bool mic = false; + int status = 0; + + /* If jack in NULL, disable HS jack */ + if (!jack) { + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x0); + dapm = snd_soc_codec_get_dapm(codec); + snd_soc_dapm_disable_pin(dapm, "LDO1"); + snd_soc_dapm_sync(dapm); + return 0; + } rt298->jack = jack; + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); - /* Send an initial empty report */ - snd_soc_jack_report(rt298->jack, 0, + rt298_jack_detect(rt298, &hp, &mic); + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt298->jack, status, SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); return 0; -- cgit v1.2.3-59-g8ed1b From e59d8bb574f6d8097e7e14981440dc37425fddc6 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Tue, 29 Nov 2016 07:33:07 +0800 Subject: ALSA: echoaudio: Fix improper return value in function load_asic When the second call to load_asic_generic() fails in function load_asic(), "false" is returned. The real value of "false" is 0, which indicates success in the context. As a result, the execution status and the return value may be inconsistent. This patch fixes the bug. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=188761 Signed-off-by: Pan Bian Signed-off-by: Takashi Iwai --- sound/pci/echoaudio/layla24_dsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index df28e5117359..c02bc1dcc170 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c @@ -135,7 +135,7 @@ static int load_asic(struct echoaudio *chip) err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, FW_LAYLA24_2S_ASIC); if (err < 0) - return false; + return err; /* Now give the external ASIC a little time to set up */ mdelay(10); -- cgit v1.2.3-59-g8ed1b From fc90172ba283b598b5497e968de47e3bc2800ed5 Mon Sep 17 00:00:00 2001 From: Andrej Krutak Date: Tue, 29 Nov 2016 22:12:51 +0100 Subject: ALSA: line6: Claim pod x3 usb data interface Userspace apps have to claim USB interfaces before using endpoints in them (drivers/usb/core/devio.c:checkintf()). It's a lock mechanism so that two "drivers" don't steal data from each other. Kernel drivers don't have to claim interfaces to work - but they should, to lock out userspace. While there, fix line6_properties struct to match checkpatch.pl. Signed-off-by: Andrej Krutak Signed-off-by: Takashi Iwai --- sound/usb/line6/driver.h | 9 +++++---- sound/usb/line6/podhd.c | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h index 7e3a3aada222..a5c2e9ae5f17 100644 --- a/sound/usb/line6/driver.h +++ b/sound/usb/line6/driver.h @@ -98,10 +98,11 @@ struct line6_properties { int altsetting; - unsigned ep_ctrl_r; - unsigned ep_ctrl_w; - unsigned ep_audio_r; - unsigned ep_audio_w; + unsigned int ctrl_if; + unsigned int ep_ctrl_r; + unsigned int ep_ctrl_w; + unsigned int ep_audio_r; + unsigned int ep_audio_w; }; /* Capability bits */ diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c index 49cd4a65e390..6ab23e5aee71 100644 --- a/sound/usb/line6/podhd.c +++ b/sound/usb/line6/podhd.c @@ -153,6 +153,7 @@ static struct line6_pcm_properties podx3_pcm_properties = { .rats = &podhd_ratden}, .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */ }; +static struct usb_driver podhd_driver; static void podhd_startup_start_workqueue(unsigned long data); static void podhd_startup_workqueue(struct work_struct *work); @@ -291,8 +292,14 @@ static void podhd_disconnect(struct usb_line6 *line6) struct usb_line6_podhd *pod = (struct usb_line6_podhd *)line6; if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { + struct usb_interface *intf; + del_timer_sync(&pod->startup_timer); cancel_work_sync(&pod->startup_work); + + intf = usb_ifnum_to_if(line6->usbdev, + pod->line6.properties->ctrl_if); + usb_driver_release_interface(&podhd_driver, intf); } } @@ -304,10 +311,27 @@ static int podhd_init(struct usb_line6 *line6, { int err; struct usb_line6_podhd *pod = (struct usb_line6_podhd *) line6; + struct usb_interface *intf; line6->disconnect = podhd_disconnect; if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { + /* claim the data interface */ + intf = usb_ifnum_to_if(line6->usbdev, + pod->line6.properties->ctrl_if); + if (!intf) { + dev_err(pod->line6.ifcdev, "interface %d not found\n", + pod->line6.properties->ctrl_if); + return -ENODEV; + } + + err = usb_driver_claim_interface(&podhd_driver, intf, NULL); + if (err != 0) { + dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n", + pod->line6.properties->ctrl_if, err); + return err; + } + /* create sysfs entries: */ err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group); if (err < 0) @@ -406,6 +430,7 @@ static const struct line6_properties podhd_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x81, .ep_ctrl_w = 0x01, + .ctrl_if = 1, .ep_audio_r = 0x86, .ep_audio_w = 0x02, }, @@ -417,6 +442,7 @@ static const struct line6_properties podhd_properties_table[] = { .altsetting = 1, .ep_ctrl_r = 0x81, .ep_ctrl_w = 0x01, + .ctrl_if = 1, .ep_audio_r = 0x86, .ep_audio_w = 0x02, }, -- cgit v1.2.3-59-g8ed1b From 4763601a56f155ddf94ef35fc2c41504a2de15f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 29 Nov 2016 22:28:40 +0100 Subject: ALSA: usb-audio: Fix bogus error return in snd_usb_create_stream() The function returns -EINVAL even if it builds the stream properly. The bogus error code sneaked in during the code refactoring, but it wasn't noticed until now since the returned error code itself is ignored in anyway. Kill it here, but there is no behavior change by this patch, obviously. Fixes: e5779998bf8b ('ALSA: usb-audio: refactor code') Signed-off-by: Takashi Iwai --- sound/usb/card.c | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/card.c b/sound/usb/card.c index 2ddc034673a8..f36cb068dad3 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -206,7 +206,6 @@ static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int int if (! snd_usb_parse_audio_interface(chip, interface)) { usb_set_interface(dev, interface, 0); /* reset the current interface */ usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); - return -EINVAL; } return 0; -- cgit v1.2.3-59-g8ed1b From 6648eb8666af7681e6ff3830ca715e8255f17078 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Nov 2016 14:56:26 +0100 Subject: ASoC: Intel: Add missing 10EC5672 ACPI ID matching for Cherry Trail Add the missing ACPI ID 10EC5672 for Cherry Trail, which bounds with cht-bsw-rt5672 driver. This combination was found on Dell Wyse 3040. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index ba5c0d71720a..4461b6521740 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c @@ -451,6 +451,8 @@ static struct sst_acpi_mach sst_acpi_bytcr[] = { static struct sst_acpi_mach sst_acpi_chv[] = { {"10EC5670", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, + {"10EC5672", "cht-bsw-rt5672", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, + &chv_platform_data }, {"10EC5645", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, &chv_platform_data }, {"10EC5650", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, -- cgit v1.2.3-59-g8ed1b From b4ff47d2843f7df61b956c8ee4a576bf83b11fab Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Nov 2016 17:19:20 +0100 Subject: ASoC: rt5670: Enable Braswell platform workaround for Dell Wyse 3040 Dell Wyse 3040 requires the platform workaround for enabling dmic and jack detection as defined for Braswell CRB. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 12d3bc14a558..d32ebe73c2c9 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2826,6 +2826,13 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_BOARD_NAME, "Braswell CRB"), }, }, + { + .ident = "Dell Wyse 3040", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Wyse 3040"), + }, + }, {} }; -- cgit v1.2.3-59-g8ed1b From d25280060835e1b2b84c242905da8334ab15c5b4 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 30 Nov 2016 14:55:29 +0100 Subject: ASoC: rt5670: Add missing 10EC5072 ACPI ID rt5670 driver supports also RT5672 codec, but its ACPI ID is missing. This was found on Dell Wyse 3040 box. Signed-off-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index d32ebe73c2c9..97bafac3bc15 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2813,6 +2813,7 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5670_acpi_match[] = { { "10EC5670", 0}, + { "10EC5672", 0}, { }, }; MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); -- cgit v1.2.3-59-g8ed1b From 1b4d9c22191583ef1fb7433417b2ceb2a608d887 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 29 Nov 2016 15:44:38 +0000 Subject: ASoC: core: Add component pin control functions It's often the case that a codec driver will need to control its own pins. However, if a name_prefix has been applied to this codec it must be included in the name passed to any of the snd_soc_dapm_x_pin() functions. The behaviour of the existing pin control functions is reasonable, since you may want to search for a fully-specified name within the scope of an entire card. This means that we can't apply the prefix in these functions because it will break card-scope searches. Constructing a prefixed string "manually" in codec drivers leads to a lot of repetition of the same code. To make this tidier in codec drivers this patch adds a new set of equivalent functions that take a struct snd_soc_component instead of a dapm context and automatically add the component's name_prefix to the given name. This makes it a simple change in codec drivers to be prefix-safe. The new functions are not quite trivial enough to be inlines and the compiler won't be able to compile-away any part of them. Although it looks somewhat inefficient to have to allocate a temporary buffer and combine strings, the current design of the widget list doesn't lend itself to a more optimized implementation - it's a single list of all widgets on a card and is searched linearly for a matching string. As pin state changes are generally low-frequency events it's unlikely to be a significant issue - at least not enough to rewrite the widget list handling just for this. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- include/sound/soc.h | 20 +++++ sound/soc/soc-utils.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 4f1c784e44f6..a26c651cb1ee 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1697,4 +1697,24 @@ static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm) mutex_unlock(&dapm->card->dapm_mutex); } +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin); +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin); + #endif diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 393e8f0fe2cc..644d9a9ebfbc 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -58,6 +58,205 @@ int snd_soc_params_to_bclk(struct snd_pcm_hw_params *params) } EXPORT_SYMBOL_GPL(snd_soc_params_to_bclk); +int snd_soc_component_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin); + +int snd_soc_component_enable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_enable_pin_unlocked); + +int snd_soc_component_disable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin); + +int snd_soc_component_disable_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_disable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_disable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_disable_pin_unlocked); + +int snd_soc_component_nc_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin); + +int snd_soc_component_nc_pin_unlocked(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_nc_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_nc_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_nc_pin_unlocked); + +int snd_soc_component_get_pin_status(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_get_pin_status(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_get_pin_status(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_get_pin_status); + +int snd_soc_component_force_enable_pin(struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin); + +int snd_soc_component_force_enable_pin_unlocked( + struct snd_soc_component *component, + const char *pin) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_component_get_dapm(component); + char *full_name; + int ret; + + if (!component->name_prefix) + return snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); + + full_name = kasprintf(GFP_KERNEL, "%s %s", component->name_prefix, pin); + if (!full_name) + return -ENOMEM; + + ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, full_name); + kfree(full_name); + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_component_force_enable_pin_unlocked); + static const struct snd_pcm_hardware dummy_dma_hardware = { /* Random values to keep userspace happy when checking constraints */ .info = SNDRV_PCM_INFO_INTERLEAVED | -- cgit v1.2.3-59-g8ed1b From 35f4403edb21d8b162beb3ab82b2087f4063f19d Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 29 Nov 2016 15:44:39 +0000 Subject: ASoC: arizona: Use component pin control functions We need to modify the state of some of our own pins and are currently not taking account that the pin name may have a name_prefix applied to it. Replace the snd_soc_dapm_x_pin functions with the equivalent snd_soc_component_x_pin functions so that any name_prefix will be handled automatically. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 12 ++++++++---- sound/soc/codecs/cs47l24.c | 3 ++- sound/soc/codecs/wm5102.c | 3 ++- sound/soc/codecs/wm5110.c | 3 ++- sound/soc/codecs/wm8997.c | 3 ++- sound/soc/codecs/wm8998.c | 3 ++- 6 files changed, 18 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index ca5ca9eac272..0a734d910850 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -257,6 +257,7 @@ EXPORT_SYMBOL_GPL(arizona_init_mono); int arizona_init_gpio(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; int i; @@ -264,21 +265,24 @@ int arizona_init_gpio(struct snd_soc_codec *codec) switch (arizona->type) { case WM5110: case WM8280: - snd_soc_dapm_disable_pin(dapm, "DRC2 Signal Activity"); + snd_soc_component_disable_pin(component, + "DRC2 Signal Activity"); break; default: break; } - snd_soc_dapm_disable_pin(dapm, "DRC1 Signal Activity"); + snd_soc_component_disable_pin(component, "DRC1 Signal Activity"); for (i = 0; i < ARRAY_SIZE(arizona->pdata.gpio_defaults); i++) { switch (arizona->pdata.gpio_defaults[i] & ARIZONA_GPN_FN_MASK) { case ARIZONA_GP_FN_DRC1_SIGNAL_DETECT: - snd_soc_dapm_enable_pin(dapm, "DRC1 Signal Activity"); + snd_soc_component_enable_pin(component, + "DRC1 Signal Activity"); break; case ARIZONA_GP_FN_DRC2_SIGNAL_DETECT: - snd_soc_dapm_enable_pin(dapm, "DRC2 Signal Activity"); + snd_soc_component_enable_pin(component, + "DRC2 Signal Activity"); break; default: break; diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 1ed1329c31cc..73559ae864b6 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c @@ -1115,6 +1115,7 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) static int cs47l24_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct cs47l24_priv *priv = snd_soc_codec_get_drvdata(codec); int ret; @@ -1138,7 +1139,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) if (ret) goto err_adsp2_codec_probe; - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); return 0; diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 72ff291a85be..e7ab37d0dd32 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1931,6 +1931,7 @@ static irqreturn_t wm5102_adsp2_irq(int irq, void *data) static int wm5102_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); int ret; @@ -1947,7 +1948,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_notifiers(codec); - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); priv->core.arizona->dapm = dapm; diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index a9a8bc98fb29..585fc706c1b0 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -2273,6 +2273,7 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data) static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); int i, ret; @@ -2295,7 +2296,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) if (ret) goto err_adsp2_codec_probe; - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); return 0; diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index ea8b1bfdf5a0..ee0c8639c743 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -1060,12 +1060,13 @@ static struct snd_soc_dai_driver wm8997_dai[] = { static int wm8997_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); struct wm8997_priv *priv = snd_soc_codec_get_drvdata(codec); arizona_init_spk(codec); arizona_init_notifiers(codec); - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); priv->core.arizona->dapm = dapm; diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 1e1d9c1f0371..3694f5958d86 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c @@ -1320,6 +1320,7 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec) { struct wm8998_priv *priv = snd_soc_codec_get_drvdata(codec); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); priv->core.arizona->dapm = dapm; @@ -1327,7 +1328,7 @@ static int wm8998_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_notifiers(codec); - snd_soc_dapm_disable_pin(dapm, "HAPTICS"); + snd_soc_component_disable_pin(component, "HAPTICS"); return 0; } -- cgit v1.2.3-59-g8ed1b From 786e1c37194e8e822eb72a0aed5fa850e07071a0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Nov 2016 16:32:19 +0100 Subject: ASoC: intel: Replace kthread with work The usage pattern of kthread worker in Intel SST drivers can be replaced gracefully with the normal workqueue, which is more light- weight and easier to manage in general. Let's do it. While in the replacement, move the schedule_work() call inside the spinlock for excluding the race, too. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Tested-by: Subhransu S. Prusty Signed-off-by: Mark Brown --- sound/soc/intel/baytrail/sst-baytrail-ipc.c | 3 +- sound/soc/intel/common/sst-ipc.c | 58 ++++++++++------------------- sound/soc/intel/common/sst-ipc.h | 4 +- sound/soc/intel/haswell/sst-haswell-ipc.c | 3 +- sound/soc/intel/skylake/skl-sst-cldma.c | 1 - sound/soc/intel/skylake/skl-sst-ipc.c | 2 +- sound/soc/intel/skylake/skl-sst-ipc.h | 1 - 7 files changed, 24 insertions(+), 48 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/baytrail/sst-baytrail-ipc.c b/sound/soc/intel/baytrail/sst-baytrail-ipc.c index 7ab14ce65a73..260447da32b8 100644 --- a/sound/soc/intel/baytrail/sst-baytrail-ipc.c +++ b/sound/soc/intel/baytrail/sst-baytrail-ipc.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -338,7 +337,7 @@ static irqreturn_t sst_byt_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/common/sst-ipc.c b/sound/soc/intel/common/sst-ipc.c index 2c1b3159ac1a..62f3a8e0ec87 100644 --- a/sound/soc/intel/common/sst-ipc.c +++ b/sound/soc/intel/common/sst-ipc.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include "sst-dsp.h" @@ -109,10 +108,9 @@ static int ipc_tx_message(struct sst_generic_ipc *ipc, u64 header, ipc->ops.tx_data_copy(msg, tx_data, tx_bytes); list_add_tail(&msg->list, &ipc->tx_list); + schedule_work(&ipc->kwork); spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - kthread_queue_work(&ipc->kworker, &ipc->kwork); - if (wait) return tx_wait_done(ipc, msg, rx_data); else @@ -156,35 +154,32 @@ free_mem: return -ENOMEM; } -static void ipc_tx_msgs(struct kthread_work *work) +static void ipc_tx_msgs(struct work_struct *work) { struct sst_generic_ipc *ipc = container_of(work, struct sst_generic_ipc, kwork); struct ipc_message *msg; - unsigned long flags; - spin_lock_irqsave(&ipc->dsp->spinlock, flags); + spin_lock_irq(&ipc->dsp->spinlock); - if (list_empty(&ipc->tx_list) || ipc->pending) { - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return; - } - - /* if the DSP is busy, we will TX messages after IRQ. - * also postpone if we are in the middle of procesing completion irq*/ - if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { - dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); - return; - } + while (!list_empty(&ipc->tx_list) && !ipc->pending) { + /* if the DSP is busy, we will TX messages after IRQ. + * also postpone if we are in the middle of processing + * completion irq + */ + if (ipc->ops.is_dsp_busy && ipc->ops.is_dsp_busy(ipc->dsp)) { + dev_dbg(ipc->dev, "ipc_tx_msgs dsp busy\n"); + break; + } - msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); - list_move(&msg->list, &ipc->rx_list); + msg = list_first_entry(&ipc->tx_list, struct ipc_message, list); + list_move(&msg->list, &ipc->rx_list); - if (ipc->ops.tx_msg != NULL) - ipc->ops.tx_msg(ipc, msg); + if (ipc->ops.tx_msg != NULL) + ipc->ops.tx_msg(ipc, msg); + } - spin_unlock_irqrestore(&ipc->dsp->spinlock, flags); + spin_unlock_irq(&ipc->dsp->spinlock); } int sst_ipc_tx_message_wait(struct sst_generic_ipc *ipc, u64 header, @@ -305,19 +300,7 @@ int sst_ipc_init(struct sst_generic_ipc *ipc) if (ret < 0) return -ENOMEM; - /* start the IPC message thread */ - kthread_init_worker(&ipc->kworker); - ipc->tx_thread = kthread_run(kthread_worker_fn, - &ipc->kworker, "%s", - dev_name(ipc->dev)); - if (IS_ERR(ipc->tx_thread)) { - dev_err(ipc->dev, "error: failed to create message TX task\n"); - ret = PTR_ERR(ipc->tx_thread); - kfree(ipc->msg); - return ret; - } - - kthread_init_work(&ipc->kwork, ipc_tx_msgs); + INIT_WORK(&ipc->kwork, ipc_tx_msgs); return 0; } EXPORT_SYMBOL_GPL(sst_ipc_init); @@ -326,8 +309,7 @@ void sst_ipc_fini(struct sst_generic_ipc *ipc) { int i; - if (ipc->tx_thread) - kthread_stop(ipc->tx_thread); + cancel_work_sync(&ipc->kwork); if (ipc->msg) { for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { diff --git a/sound/soc/intel/common/sst-ipc.h b/sound/soc/intel/common/sst-ipc.h index f4aab1b3789a..7ed42a640ad6 100644 --- a/sound/soc/intel/common/sst-ipc.h +++ b/sound/soc/intel/common/sst-ipc.h @@ -23,7 +23,6 @@ #include #include #include -#include #define IPC_MAX_MAILBOX_BYTES 256 @@ -66,8 +65,7 @@ struct sst_generic_ipc { struct list_head empty_list; wait_queue_head_t wait_txq; struct task_struct *tx_thread; - struct kthread_worker kworker; - struct kthread_work kwork; + struct work_struct kwork; bool pending; struct ipc_message *msg; int tx_data_max_size; diff --git a/sound/soc/intel/haswell/sst-haswell-ipc.c b/sound/soc/intel/haswell/sst-haswell-ipc.c index e432a31fd9f2..a3459d1682a6 100644 --- a/sound/soc/intel/haswell/sst-haswell-ipc.c +++ b/sound/soc/intel/haswell/sst-haswell-ipc.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -818,7 +817,7 @@ static irqreturn_t hsw_irq_thread(int irq, void *context) spin_unlock_irqrestore(&sst->spinlock, flags); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index efa2532114ba..c9f6d87381db 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -17,7 +17,6 @@ #include #include -#include #include #include "../common/sst-dsp.h" #include "../common/sst-dsp-priv.h" diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 594623a4b4cd..e1391dfbc9e9 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -498,7 +498,7 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) skl_ipc_int_enable(dsp); /* continue to send any remaining messages... */ - kthread_queue_work(&ipc->kworker, &ipc->kwork); + schedule_work(&ipc->kwork); return IRQ_HANDLED; } diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index 0568f2e8fc57..cc40341233fa 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -16,7 +16,6 @@ #ifndef __SKL_IPC_H #define __SKL_IPC_H -#include #include #include "../common/sst-ipc.h" -- cgit v1.2.3-59-g8ed1b From 2263fddcd0ba9d8e75a90b1359f92d3b9d0b78b3 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Tue, 29 Nov 2016 10:05:16 +0800 Subject: ASoC: nau8825: lock longer to avoid playback pop upon resume There is an issue about pop noise in NAU88L25 as follows. Issue 54078: Chell_headphone pop back from S3 (1)Play directly to hw, bypassing CRAS: sox -b 16 -n -t alsa hw:0,0 synth sine 200 sine 200 (2)Close lid or powerd_dbus_suspend, then press a key to resume. (3)no audio after resume (4)Audio will be back after close then reopen the pcm device. After verification, we find one defect is that semaphone lock is not long enough and expired. In this situation, the playback comes back early but pauses a while to wait for the crosstalk detection done. But the detection spends too much time and lock time is up. Therefore, the playback and jack detection sequence interfere to each other. That breaks sequence and makes noise. The driver extends the lock time for the issue. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 3f9137f60c0d..2b89569333a1 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1233,7 +1233,7 @@ static int nau8825_hw_params(struct snd_pcm_substream *substream, struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int val_len = 0, osr; - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); /* CLK_DAC or CLK_ADC = OSR * FS * DAC or ADC clock frequency is defined as Over Sampling Rate (OSR) @@ -1293,7 +1293,7 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); unsigned int ctrl1_val = 0, ctrl2_val = 0; - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: @@ -2121,7 +2121,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); nau8825_configure_mclk_as_sysclk(regmap); /* MCLK not changed by clock tree */ regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, @@ -2169,7 +2169,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); /* Higher FLL reference input frequency can only set lower * gain error, such as 0000 for input reference from MCLK * 12.288Mhz. @@ -2191,7 +2191,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); /* If FLL reference input is from low frequency source, * higher error gain can apply such as 0xf which has * the most sensitive gain error correction threshold, @@ -2217,7 +2217,7 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, * fered by cross talk process, the driver make the playback * preparation halted until cross talk process finish. */ - nau8825_sema_acquire(nau8825, 2 * HZ); + nau8825_sema_acquire(nau8825, 3 * HZ); /* If FLL reference input is from low frequency source, * higher error gain can apply such as 0xf which has * the most sensitive gain error correction threshold, -- cgit v1.2.3-59-g8ed1b From 2fc995a87f2efcd803438f07bfecd35cc3d90d32 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Nov 2016 16:54:06 +0100 Subject: ASoC: intel: Fix crash at suspend/resume without card registration When ASoC Intel SST Medfield driver is probed but without codec / card assigned, it causes an Oops and freezes the kernel at suspend/resume, PM: Suspending system (freeze) Suspending console(s) (use no_console_suspend to debug) BUG: unable to handle kernel NULL pointer dereference at 0000000000000018 IP: [] sst_soc_prepare+0x19/0xa0 [snd_soc_sst_mfld_platform] Oops: 0000 [#1] PREEMPT SMP CPU: 0 PID: 1552 Comm: systemd-sleep Tainted: G W 4.9.0-rc6-1.g5f5c2ad-default #1 Call Trace: [] dpm_prepare+0x209/0x460 [] dpm_suspend_start+0x11/0x60 [] suspend_devices_and_enter+0xb2/0x710 [] pm_suspend+0x30e/0x390 [] state_store+0x8a/0x90 [] kobj_attr_store+0xf/0x20 [] sysfs_kf_write+0x37/0x40 [] kernfs_fop_write+0x11c/0x1b0 [] __vfs_write+0x28/0x140 [] ? apparmor_file_permission+0x18/0x20 [] ? security_file_permission+0x3b/0xc0 [] vfs_write+0xb5/0x1a0 [] SyS_write+0x46/0xa0 [] entry_SYSCALL_64_fastpath+0x1e/0xad Add proper NULL checks in the PM code of mdfld driver. Signed-off-by: Takashi Iwai Acked-by: Vinod Koul Signed-off-by: Mark Brown Cc: --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 25c6d87c818e..f5a8050351b5 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -771,6 +771,9 @@ static int sst_soc_prepare(struct device *dev) struct sst_data *drv = dev_get_drvdata(dev); struct snd_soc_pcm_runtime *rtd; + if (!drv->soc_card) + return 0; + /* suspend all pcms first */ snd_soc_suspend(drv->soc_card->dev); snd_soc_poweroff(drv->soc_card->dev); @@ -793,6 +796,9 @@ static void sst_soc_complete(struct device *dev) struct sst_data *drv = dev_get_drvdata(dev); struct snd_soc_pcm_runtime *rtd; + if (!drv->soc_card) + return; + /* restart SSPs */ list_for_each_entry(rtd, &drv->soc_card->rtd_list, list) { struct snd_soc_dai *dai = rtd->cpu_dai; -- cgit v1.2.3-59-g8ed1b From fee3244cd1f5af813a24537950e211eee4f33297 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 25 Nov 2016 15:40:18 +0100 Subject: ASoC: cht_bsw_rt5672: Use HID translation unit Instead of hard-coded "i2c-10EC5670:00", use the translation helper to avoid the mismatch between i2c-codec and ACPI strings just like what we've done for bytcr_rt5640. This gives more robust binding on funky devices like Dell Wyse 3040. Signed-off-by: Takashi Iwai Reviewed-by: Pierre-Louis Bossart Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_rt5672.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index df9d254baa18..fe607d8701a0 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -25,12 +25,14 @@ #include #include "../../codecs/rt5670.h" #include "../atom/sst-atom-controls.h" +#include "../common/sst-acpi.h" /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ #define CHT_PLAT_CLK_3_HZ 19200000 #define CHT_CODEC_DAI "rt5670-aif1" static struct snd_soc_jack cht_bsw_headset; +static char cht_bsw_codec_name[16]; /* Headset jack detection DAPM pins */ static struct snd_soc_jack_pin cht_bsw_headset_pins[] = { @@ -295,7 +297,7 @@ static int cht_suspend_pre(struct snd_soc_card *card) struct snd_soc_codec *codec; list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { + if (!strcmp(codec->component.name, cht_bsw_codec_name)) { dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); rt5670_jack_suspend(codec); break; @@ -309,7 +311,7 @@ static int cht_resume_post(struct snd_soc_card *card) struct snd_soc_codec *codec; list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { + if (!strcmp(codec->component.name, cht_bsw_codec_name)) { dev_dbg(codec->dev, "enabling jack detect for resume.\n"); rt5670_jack_resume(codec); break; @@ -335,9 +337,33 @@ static struct snd_soc_card snd_soc_card_cht = { .resume_post = cht_resume_post, }; +#define RT5672_I2C_DEFAULT "i2c-10EC5670:00" + static int snd_cht_mc_probe(struct platform_device *pdev) { int ret_val = 0; + struct sst_acpi_mach *mach = pdev->dev.platform_data; + const char *i2c_name; + int i; + + strcpy(cht_bsw_codec_name, RT5672_I2C_DEFAULT); + + /* fixup codec name based on HID */ + if (mach) { + i2c_name = sst_acpi_find_name_from_hid(mach->id); + if (i2c_name) { + snprintf(cht_bsw_codec_name, sizeof(cht_bsw_codec_name), + "i2c-%s", i2c_name); + for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) { + if (!strcmp(cht_dailink[i].codec_name, + RT5672_I2C_DEFAULT)) { + cht_dailink[i].codec_name = + cht_bsw_codec_name; + break; + } + } + } + } /* register the soc card */ snd_soc_card_cht.dev = &pdev->dev; -- cgit v1.2.3-59-g8ed1b From dac5f86bc9e60eae87a28512f025362d1e2574e3 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 25 Nov 2016 20:34:36 +0800 Subject: ASoC: sun4i-codec: Add support for A23 codec The codec in the A23 is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev. In addition, the A23 does not have LINEOUT, and it does not support headset jack detection or buttons. Signed-off-by: Chen-Yu Tsai Acked-by: Rob Herring Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-codec.txt | 11 ++- sound/soc/sunxi/sun4i-codec.c | 108 +++++++++++++++++++++ 2 files changed, 117 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index d91a95377f49..f7a548b604fc 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -5,6 +5,7 @@ Required properties: - "allwinner,sun4i-a10-codec" - "allwinner,sun6i-a31-codec" - "allwinner,sun7i-a20-codec" + - "allwinner,sun8i-a23-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - dmas: DMA channels for tx and rx dma. See the DMA client binding, @@ -21,6 +22,7 @@ Optional properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-codec" + - "allwinner,sun8i-a23-codec" - resets: phandle to the reset control for this device - allwinner,audio-routing: A list of the connections between audio components. Each entry is a pair of strings, the first being the @@ -31,10 +33,10 @@ Required properties for the following compatibles: "HP" "HPCOM" "LINEIN" - "LINEOUT" + "LINEOUT" (not on sun8i-a23) "MIC1" "MIC2" - "MIC3" + "MIC3" (sun6i-a31 only) Microphone biases from the SoC: "HBIAS" @@ -48,6 +50,11 @@ Required properties for the following compatibles: "Mic" "Speaker" +Required properties for the following compatibles: + - "allwinner,sun8i-a23-codec" +- allwinner,codec-analog-controls: A phandle to the codec analog controls + block in the PRCM. + Example: codec: codec@01c22c00 { #sound-dai-cells = <0>; diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 092fdcf6de95..ada5fa055950 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -213,6 +213,10 @@ /* TODO sun6i DAP (Digital Audio Processing) bits */ +/* FIFO counters moved on A23 */ +#define SUN8I_A23_CODEC_DAC_TXCNT (0x1c) +#define SUN8I_A23_CODEC_ADC_RXCNT (0x20) + struct sun4i_codec { struct device *dev; struct regmap *regmap; @@ -1067,6 +1071,32 @@ static struct snd_soc_codec_driver sun6i_codec_codec = { }, }; +/* sun8i A23 codec */ +static const struct snd_kcontrol_new sun8i_a23_codec_codec_controls[] = { + SOC_SINGLE_TLV("DAC Playback Volume", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_DVOL, 0x3f, 1, + sun6i_codec_dvol_scale), +}; + +static const struct snd_soc_dapm_widget sun8i_a23_codec_codec_widgets[] = { + /* Digital parts of the ADCs */ + SND_SOC_DAPM_SUPPLY("ADC Enable", SUN6I_CODEC_ADC_FIFOC, + SUN6I_CODEC_ADC_FIFOC_EN_AD, 0, NULL, 0), + /* Digital parts of the DACs */ + SND_SOC_DAPM_SUPPLY("DAC Enable", SUN4I_CODEC_DAC_DPC, + SUN4I_CODEC_DAC_DPC_EN_DA, 0, NULL, 0), + +}; + +static struct snd_soc_codec_driver sun8i_a23_codec_codec = { + .component_driver = { + .controls = sun8i_a23_codec_codec_controls, + .num_controls = ARRAY_SIZE(sun8i_a23_codec_codec_controls), + .dapm_widgets = sun8i_a23_codec_codec_widgets, + .num_dapm_widgets = ARRAY_SIZE(sun8i_a23_codec_codec_widgets), + }, +}; + static const struct snd_soc_component_driver sun4i_codec_component = { .name = "sun4i-codec", }; @@ -1206,6 +1236,63 @@ static struct snd_soc_card *sun6i_codec_create_card(struct device *dev) return card; }; +/* Connect digital side enables to analog side widgets */ +static const struct snd_soc_dapm_route sun8i_codec_card_routes[] = { + /* ADC Routes */ + { "Left ADC", NULL, "ADC Enable" }, + { "Right ADC", NULL, "ADC Enable" }, + { "Codec Capture", NULL, "Left ADC" }, + { "Codec Capture", NULL, "Right ADC" }, + + /* DAC Routes */ + { "Left DAC", NULL, "DAC Enable" }, + { "Right DAC", NULL, "DAC Enable" }, + { "Left DAC", NULL, "Codec Playback" }, + { "Right DAC", NULL, "Codec Playback" }, +}; + +static struct snd_soc_aux_dev aux_dev = { + .name = "Codec Analog Controls", +}; + +static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "A23 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1227,6 +1314,13 @@ static const struct regmap_config sun7i_codec_regmap_config = { .max_register = SUN7I_CODEC_AC_MIC_PHONE_CAL, }; +static const struct regmap_config sun8i_a23_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_A23_CODEC_ADC_RXCNT, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_codec_driver *codec; @@ -1265,6 +1359,16 @@ static const struct sun4i_codec_quirks sun7i_codec_quirks = { .reg_adc_rxdata = SUN4I_CODEC_ADC_RXDATA, }; +static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { + .regmap_config = &sun8i_a23_codec_regmap_config, + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_a23_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN4I_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1278,6 +1382,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun7i-a20-codec", .data = &sun7i_codec_quirks, }, + { + .compatible = "allwinner,sun8i-a23-codec", + .data = &sun8i_a23_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); -- cgit v1.2.3-59-g8ed1b From 4a15b24a65f13778f7616ad0a65be78d8ec0b45a Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 25 Nov 2016 20:34:40 +0800 Subject: ASoC: sun4i-codec: Add support for H3 codec The codec on the H3 is similar to the one found on the A31. One key difference is the analog path controls are routed through the PRCM block. This is supported by the sun8i-codec-analog driver, and tied into this codec driver with the audio card's aux_dev. In addition, the H3 has no HP (headphone) and HBIAS support, and no MIC3 input. The FIFO related registers are slightly rearranged. Signed-off-by: Chen-Yu Tsai Acked-by: Rob Herring Acked-by: Maxime Ripard Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/sun4i-codec.txt | 3 + sound/soc/sunxi/sun4i-codec.c | 71 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) (limited to 'sound') diff --git a/Documentation/devicetree/bindings/sound/sun4i-codec.txt b/Documentation/devicetree/bindings/sound/sun4i-codec.txt index f7a548b604fc..3033bd8aab0f 100644 --- a/Documentation/devicetree/bindings/sound/sun4i-codec.txt +++ b/Documentation/devicetree/bindings/sound/sun4i-codec.txt @@ -6,6 +6,7 @@ Required properties: - "allwinner,sun6i-a31-codec" - "allwinner,sun7i-a20-codec" - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" - reg: must contain the registers location and length - interrupts: must contain the codec interrupt - dmas: DMA channels for tx and rx dma. See the DMA client binding, @@ -23,6 +24,7 @@ Optional properties: Required properties for the following compatibles: - "allwinner,sun6i-a31-codec" - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" - resets: phandle to the reset control for this device - allwinner,audio-routing: A list of the connections between audio components. Each entry is a pair of strings, the first being the @@ -52,6 +54,7 @@ Required properties for the following compatibles: Required properties for the following compatibles: - "allwinner,sun8i-a23-codec" + - "allwinner,sun8i-h3-codec" - allwinner,codec-analog-controls: A phandle to the codec analog controls block in the PRCM. diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index ada5fa055950..848af01692a0 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -217,6 +217,13 @@ #define SUN8I_A23_CODEC_DAC_TXCNT (0x1c) #define SUN8I_A23_CODEC_ADC_RXCNT (0x20) +/* TX FIFO moved on H3 */ +#define SUN8I_H3_CODEC_DAC_TXDATA (0x20) +#define SUN8I_H3_CODEC_DAC_DBG (0x48) +#define SUN8I_H3_CODEC_ADC_DBG (0x4c) + +/* TODO H3 DAP (Digital Audio Processing) bits */ + struct sun4i_codec { struct device *dev; struct regmap *regmap; @@ -1293,6 +1300,44 @@ static struct snd_soc_card *sun8i_a23_codec_create_card(struct device *dev) return card; }; +static struct snd_soc_card *sun8i_h3_codec_create_card(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return ERR_PTR(-ENOMEM); + + aux_dev.codec_of_node = of_parse_phandle(dev->of_node, + "allwinner,codec-analog-controls", + 0); + if (!aux_dev.codec_of_node) { + dev_err(dev, "Can't find analog controls for codec.\n"); + return ERR_PTR(-EINVAL); + }; + + card->dai_link = sun4i_codec_create_link(dev, &card->num_links); + if (!card->dai_link) + return ERR_PTR(-ENOMEM); + + card->dev = dev; + card->name = "H3 Audio Codec"; + card->dapm_widgets = sun6i_codec_card_dapm_widgets; + card->num_dapm_widgets = ARRAY_SIZE(sun6i_codec_card_dapm_widgets); + card->dapm_routes = sun8i_codec_card_routes; + card->num_dapm_routes = ARRAY_SIZE(sun8i_codec_card_routes); + card->aux_dev = &aux_dev; + card->num_aux_devs = 1; + card->fully_routed = true; + + ret = snd_soc_of_parse_audio_routing(card, "allwinner,audio-routing"); + if (ret) + dev_warn(dev, "failed to parse audio-routing: %d\n", ret); + + return card; +}; + static const struct regmap_config sun4i_codec_regmap_config = { .reg_bits = 32, .reg_stride = 4, @@ -1321,6 +1366,13 @@ static const struct regmap_config sun8i_a23_codec_regmap_config = { .max_register = SUN8I_A23_CODEC_ADC_RXCNT, }; +static const struct regmap_config sun8i_h3_codec_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = SUN8I_H3_CODEC_ADC_DBG, +}; + struct sun4i_codec_quirks { const struct regmap_config *regmap_config; const struct snd_soc_codec_driver *codec; @@ -1369,6 +1421,21 @@ static const struct sun4i_codec_quirks sun8i_a23_codec_quirks = { .has_reset = true, }; +static const struct sun4i_codec_quirks sun8i_h3_codec_quirks = { + .regmap_config = &sun8i_h3_codec_regmap_config, + /* + * TODO Share the codec structure with A23 for now. + * This should be split out when adding digital audio + * processing support for the H3. + */ + .codec = &sun8i_a23_codec_codec, + .create_card = sun8i_h3_codec_create_card, + .reg_adc_fifoc = REG_FIELD(SUN6I_CODEC_ADC_FIFOC, 0, 31), + .reg_dac_txdata = SUN8I_H3_CODEC_DAC_TXDATA, + .reg_adc_rxdata = SUN6I_CODEC_ADC_RXDATA, + .has_reset = true, +}; + static const struct of_device_id sun4i_codec_of_match[] = { { .compatible = "allwinner,sun4i-a10-codec", @@ -1386,6 +1453,10 @@ static const struct of_device_id sun4i_codec_of_match[] = { .compatible = "allwinner,sun8i-a23-codec", .data = &sun8i_a23_codec_quirks, }, + { + .compatible = "allwinner,sun8i-h3-codec", + .data = &sun8i_h3_codec_quirks, + }, {} }; MODULE_DEVICE_TABLE(of, sun4i_codec_of_match); -- cgit v1.2.3-59-g8ed1b From d9fc40639dc1b87915426d2ef489a591b0fd650b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Nov 2016 06:22:36 +0000 Subject: ASoC: core: replace codec_dev_list to component_dev_list on Card Current Card has Codec list (= codec_dev_list), but Codec will be removed in the future. Because of this reason, this patch adds new Component list in Card, and replace Codec list. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 6 +++--- sound/soc/intel/boards/broadwell.c | 16 ++++++++++------ sound/soc/intel/boards/cht_bsw_rt5672.c | 16 ++++++++++------ sound/soc/soc-core.c | 28 ++++++++++++++++------------ 4 files changed, 39 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 1ed9371ece0d..b5544e2287b8 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -810,6 +810,7 @@ struct snd_soc_component { struct list_head list; struct list_head list_aux; /* for auxiliary component of the card */ + struct list_head card_list; struct snd_soc_dai_driver *dai_drv; int num_dai; @@ -868,7 +869,6 @@ struct snd_soc_codec { const struct snd_soc_codec_driver *driver; struct list_head list; - struct list_head card_list; /* runtime */ unsigned int cache_bypass:1; /* Suppress access to the cache */ @@ -1170,7 +1170,7 @@ struct snd_soc_card { struct work_struct deferred_resume_work; /* lists of probed devices belonging to this card */ - struct list_head codec_dev_list; + struct list_head component_dev_list; struct list_head widgets; struct list_head paths; @@ -1540,11 +1540,11 @@ static inline void *snd_soc_platform_get_drvdata(struct snd_soc_platform *platfo static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) { - INIT_LIST_HEAD(&card->codec_dev_list); INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->dapm_list); INIT_LIST_HEAD(&card->aux_comp_list); + INIT_LIST_HEAD(&card->component_dev_list); } static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) diff --git a/sound/soc/intel/boards/broadwell.c b/sound/soc/intel/boards/broadwell.c index 7486a0022fde..80f3a2d95737 100644 --- a/sound/soc/intel/boards/broadwell.c +++ b/sound/soc/intel/boards/broadwell.c @@ -220,10 +220,12 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { }; static int broadwell_suspend(struct snd_soc_card *card){ - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-INT343A:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-INT343A:00")) { dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); rt286_mic_detect(codec, NULL); break; @@ -233,10 +235,12 @@ static int broadwell_suspend(struct snd_soc_card *card){ } static int broadwell_resume(struct snd_soc_card *card){ - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-INT343A:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-INT343A:00")) { dev_dbg(codec->dev, "enabling jack detect for resume.\n"); rt286_mic_detect(codec, &broadwell_headset); break; diff --git a/sound/soc/intel/boards/cht_bsw_rt5672.c b/sound/soc/intel/boards/cht_bsw_rt5672.c index df9d254baa18..dfae9cfa0ac6 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5672.c +++ b/sound/soc/intel/boards/cht_bsw_rt5672.c @@ -292,10 +292,12 @@ static struct snd_soc_dai_link cht_dailink[] = { static int cht_suspend_pre(struct snd_soc_card *card) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-10EC5670:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { dev_dbg(codec->dev, "disabling jack detect before going to suspend.\n"); rt5670_jack_suspend(codec); break; @@ -306,10 +308,12 @@ static int cht_suspend_pre(struct snd_soc_card *card) static int cht_resume_post(struct snd_soc_card *card) { - struct snd_soc_codec *codec; + struct snd_soc_component *component; + + list_for_each_entry(component, &card->component_dev_list, card_list) { + if (!strcmp(component->name, "i2c-10EC5670:00")) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - if (!strcmp(codec->component.name, "i2c-10EC5670:00")) { dev_dbg(codec->dev, "enabling jack detect for resume.\n"); rt5670_jack_resume(codec); break; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c0bbcd903261..d204bb772f00 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -626,7 +626,7 @@ static void codec2codec_close_delayed_work(struct work_struct *work) int snd_soc_suspend(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - struct snd_soc_codec *codec; + struct snd_soc_component *component; struct snd_soc_pcm_runtime *rtd; int i; @@ -703,8 +703,12 @@ int snd_soc_suspend(struct device *dev) snd_soc_dapm_sync(&card->dapm); /* suspend all CODECs */ - list_for_each_entry(codec, &card->codec_dev_list, card_list) { - struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + list_for_each_entry(component, &card->component_dev_list, card_list) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + if (!codec) + continue; /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ @@ -768,7 +772,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_card *card = container_of(work, struct snd_soc_card, deferred_resume_work); struct snd_soc_pcm_runtime *rtd; - struct snd_soc_codec *codec; + struct snd_soc_component *component; int i; /* our power state is still SNDRV_CTL_POWER_D3hot from suspend time, @@ -794,7 +798,12 @@ static void soc_resume_deferred(struct work_struct *work) cpu_dai->driver->resume(cpu_dai); } - list_for_each_entry(codec, &card->codec_dev_list, card_list) { + list_for_each_entry(component, &card->component_dev_list, card_list) { + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + if (!codec) + continue; + if (codec->suspended) { if (codec->driver->resume) codec->driver->resume(codec); @@ -1072,9 +1081,7 @@ static void soc_remove_component(struct snd_soc_component *component) if (!component->card) return; - /* This is a HACK and will be removed soon */ - if (component->codec) - list_del(&component->codec->card_list); + list_del(&component->card_list); if (component->remove) component->remove(component); @@ -1443,10 +1450,7 @@ static int soc_probe_component(struct snd_soc_card *card, component->num_dapm_routes); list_add(&dapm->list, &card->dapm_list); - - /* This is a HACK and will be removed soon */ - if (component->codec) - list_add(&component->codec->card_list, &card->codec_dev_list); + list_add(&component->card_list, &card->component_dev_list); return 0; -- cgit v1.2.3-59-g8ed1b From 1a653aa44725668590b36bbe2d7fe4736a69f055 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Nov 2016 06:22:55 +0000 Subject: ASoC: core: replace aux_comp_list to component_dev_list Now, Card has component_dev_list, we can replace aux_comp_list to component_dev_list with new auxiliary flags Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 4 +--- sound/soc/soc-core.c | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index b5544e2287b8..0bd57b77d010 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -807,9 +807,9 @@ struct snd_soc_component { unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ unsigned int registered_as_component:1; + unsigned int auxiliary:1; /* for auxiliary component of the card */ struct list_head list; - struct list_head list_aux; /* for auxiliary component of the card */ struct list_head card_list; struct snd_soc_dai_driver *dai_drv; @@ -1148,7 +1148,6 @@ struct snd_soc_card { */ struct snd_soc_aux_dev *aux_dev; int num_aux_devs; - struct list_head aux_comp_list; const struct snd_kcontrol_new *controls; int num_controls; @@ -1543,7 +1542,6 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card) INIT_LIST_HEAD(&card->widgets); INIT_LIST_HEAD(&card->paths); INIT_LIST_HEAD(&card->dapm_list); - INIT_LIST_HEAD(&card->aux_comp_list); INIT_LIST_HEAD(&card->component_dev_list); } diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d204bb772f00..ba8e000faaf1 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1710,7 +1710,8 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) } component->init = aux_dev->init; - list_add(&component->list_aux, &card->aux_comp_list); + component->auxiliary = 1; + return 0; err_defer: @@ -1726,7 +1727,10 @@ static int soc_probe_aux_devices(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { - list_for_each_entry(comp, &card->aux_comp_list, list_aux) { + list_for_each_entry(comp, &card->component_dev_list, card_list) { + if (!comp->auxiliary) + continue; + if (comp->driver->probe_order == order) { ret = soc_probe_component(card, comp); if (ret < 0) { @@ -1750,11 +1754,14 @@ static void soc_remove_aux_devices(struct snd_soc_card *card) for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; order++) { list_for_each_entry_safe(comp, _comp, - &card->aux_comp_list, list_aux) { + &card->component_dev_list, card_list) { + + if (!comp->auxiliary) + continue; + if (comp->driver->remove_order == order) { soc_remove_component(comp); - /* remove it from the card's aux_comp_list */ - list_del(&comp->list_aux); + comp->auxiliary = 0; } } } -- cgit v1.2.3-59-g8ed1b From 9178feb4538e055bf22be44c38b90cc31d2baf99 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 30 Nov 2016 06:23:13 +0000 Subject: ASoC: add Component level suspend/resume In current ALSA SoC, Codec only has suspend/resume feature, but it should be supported on Component level. This patch adds it. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/soc.h | 6 ++++- sound/soc/soc-core.c | 63 ++++++++++++++++++++++++++++++---------------------- 2 files changed, 42 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/include/sound/soc.h b/include/sound/soc.h index 0bd57b77d010..13cc64e5bb77 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -782,6 +782,8 @@ struct snd_soc_component_driver { int (*probe)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *); + int (*suspend)(struct snd_soc_component *); + int (*resume)(struct snd_soc_component *); /* DT */ int (*of_xlate_dai_name)(struct snd_soc_component *component, @@ -808,6 +810,7 @@ struct snd_soc_component { unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ unsigned int registered_as_component:1; unsigned int auxiliary:1; /* for auxiliary component of the card */ + unsigned int suspended:1; /* is in suspend PM state */ struct list_head list; struct list_head card_list; @@ -853,6 +856,8 @@ struct snd_soc_component { int (*probe)(struct snd_soc_component *); void (*remove)(struct snd_soc_component *); + int (*suspend)(struct snd_soc_component *); + int (*resume)(struct snd_soc_component *); /* machine specific init */ int (*init)(struct snd_soc_component *component); @@ -872,7 +877,6 @@ struct snd_soc_codec { /* runtime */ unsigned int cache_bypass:1; /* Suppress access to the cache */ - unsigned int suspended:1; /* Codec is in suspend PM state */ unsigned int cache_init:1; /* codec cache has been initialized */ /* codec IO */ diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ba8e000faaf1..f35ec5bf3b78 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -702,43 +702,39 @@ int snd_soc_suspend(struct device *dev) dapm_mark_endpoints_dirty(card); snd_soc_dapm_sync(&card->dapm); - /* suspend all CODECs */ + /* suspend all COMPONENTs */ list_for_each_entry(component, &card->component_dev_list, card_list) { struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); - struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - if (!codec) - continue; - - /* If there are paths active then the CODEC will be held with + /* If there are paths active then the COMPONENT will be held with * bias _ON and should not be suspended. */ - if (!codec->suspended) { + if (!component->suspended) { switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* - * If the CODEC is capable of idle + * If the COMPONENT is capable of idle * bias off then being in STANDBY * means it's doing something, * otherwise fall through. */ if (dapm->idle_bias_off) { - dev_dbg(codec->dev, + dev_dbg(component->dev, "ASoC: idle_bias_off CODEC on over suspend\n"); break; } case SND_SOC_BIAS_OFF: - if (codec->driver->suspend) - codec->driver->suspend(codec); - codec->suspended = 1; - if (codec->component.regmap) - regcache_mark_dirty(codec->component.regmap); + if (component->suspend) + component->suspend(component); + component->suspended = 1; + if (component->regmap) + regcache_mark_dirty(component->regmap); /* deactivate pins to sleep state */ - pinctrl_pm_select_sleep_state(codec->dev); + pinctrl_pm_select_sleep_state(component->dev); break; default: - dev_dbg(codec->dev, - "ASoC: CODEC is on over suspend\n"); + dev_dbg(component->dev, + "ASoC: COMPONENT is on over suspend\n"); break; } } @@ -799,15 +795,10 @@ static void soc_resume_deferred(struct work_struct *work) } list_for_each_entry(component, &card->component_dev_list, card_list) { - struct snd_soc_codec *codec = snd_soc_component_to_codec(component); - - if (!codec) - continue; - - if (codec->suspended) { - if (codec->driver->resume) - codec->driver->resume(codec); - codec->suspended = 0; + if (component->suspended) { + if (component->resume) + component->resume(component); + component->suspended = 0; } } @@ -2937,6 +2928,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->driver = driver; component->probe = component->driver->probe; component->remove = component->driver->remove; + component->suspend = component->driver->suspend; + component->resume = component->driver->resume; dapm = &component->dapm; dapm->dev = dev; @@ -3286,6 +3279,20 @@ static void snd_soc_codec_drv_remove(struct snd_soc_component *component) codec->driver->remove(codec); } +static int snd_soc_codec_drv_suspend(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->suspend(codec); +} + +static int snd_soc_codec_drv_resume(struct snd_soc_component *component) +{ + struct snd_soc_codec *codec = snd_soc_component_to_codec(component); + + return codec->driver->resume(codec); +} + static int snd_soc_codec_drv_write(struct snd_soc_component *component, unsigned int reg, unsigned int val) { @@ -3347,6 +3354,10 @@ int snd_soc_register_codec(struct device *dev, codec->component.probe = snd_soc_codec_drv_probe; if (codec_drv->remove) codec->component.remove = snd_soc_codec_drv_remove; + if (codec_drv->suspend) + codec->component.suspend = snd_soc_codec_drv_suspend; + if (codec_drv->resume) + codec->component.resume = snd_soc_codec_drv_resume; if (codec_drv->write) codec->component.write = snd_soc_codec_drv_write; if (codec_drv->read) -- cgit v1.2.3-59-g8ed1b From 1bfbc260a5b474f1376bdfdfbc590f75645d62af Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 2 Nov 2016 17:05:45 +0100 Subject: ASoC: samsung: Add machine driver for Exynos5433 based TM2 board This patch adds the sound machine driver for the TM2 and TM2E boards. Speaker and headphone playback, Main Mic capture, Bluetooth, Voice call and external accessory are supported. Signed-off-by: Inha Song [k.kozlowski: rebased on 4.1] Signed-off-by: Krzysztof Kozlowski [s.nawrocki: rebased to 4.7, adjustment to the ASoC core changes, removed unused ops and direct calls to the max98504 function, added parsing of "audio-amplifier" and "audio-codec" properties, added TDM API calls, switched to gpiod API] Signed-off-by: Sylwester Nawrocki Reviewed-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/samsung/Kconfig | 9 + sound/soc/samsung/Makefile | 2 + sound/soc/samsung/tm2_wm5110.c | 552 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 563 insertions(+) create mode 100644 sound/soc/samsung/tm2_wm5110.c (limited to 'sound') diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index a6cc6ca93fa7..7c423151ef7d 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig @@ -190,4 +190,13 @@ config SND_SOC_ARNDALE_RT5631_ALC5631 select SND_SAMSUNG_I2S select SND_SOC_RT5631 +config SND_SOC_SAMSUNG_TM2_WM5110 + tristate "SoC I2S Audio support for WM5110 on TM2 board" + depends on SND_SOC_SAMSUNG && MFD_ARIZONA && I2C && SPI_MASTER + select SND_SOC_MAX98504 + select SND_SOC_WM5110 + select SND_SAMSUNG_I2S + help + Say Y if you want to add support for SoC audio on the TM2 board. + endif #SND_SOC_SAMSUNG diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index c95b6835361f..b5df5e2e3d94 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile @@ -41,6 +41,7 @@ snd-soc-lowland-objs := lowland.o snd-soc-littlemill-objs := littlemill.o snd-soc-bells-objs := bells.o snd-soc-arndale-rt5631-objs := arndale_rt5631.o +snd-soc-tm2-wm5110-objs := tm2_wm5110.o obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o @@ -62,3 +63,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o +obj-$(CONFIG_SND_SOC_SAMSUNG_TM2_WM5110) += snd-soc-tm2-wm5110.o diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c new file mode 100644 index 000000000000..5cdf7d19b87f --- /dev/null +++ b/sound/soc/samsung/tm2_wm5110.c @@ -0,0 +1,552 @@ +/* + * Copyright (C) 2015 - 2016 Samsung Electronics Co., Ltd. + * + * Authors: Inha Song + * Sylwester Nawrocki + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include + +#include "i2s.h" +#include "../codecs/wm5110.h" + +/* + * The source clock is XCLKOUT with its mux set to the external fixed rate + * oscillator (XXTI). + */ +#define MCLK_RATE 24000000U + +#define TM2_DAI_AIF1 0 +#define TM2_DAI_AIF2 1 + +struct tm2_machine_priv { + struct snd_soc_codec *codec; + unsigned int sysclk_rate; + struct gpio_desc *gpio_mic_bias; +}; + +static int tm2_start_sysclk(struct snd_soc_card *card) +{ + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_codec *codec = priv->codec; + int ret; + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL1_REFCLK, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + priv->sysclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to set FLL1 source: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + priv->sysclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to start FLL1: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, + priv->sysclk_rate, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec->dev, "Failed to set SYSCLK source: %d\n", ret); + return ret; + } + + return 0; +} + +static int tm2_stop_sysclk(struct snd_soc_card *card) +{ + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_codec *codec = priv->codec; + int ret; + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL1, 0, 0, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to stop FLL1: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_SYSCLK, + ARIZONA_CLK_SRC_FLL1, 0, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to stop SYSCLK: %d\n", ret); + return ret; + } + + return 0; +} + +static int tm2_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(rtd->card); + + switch (params_rate(params)) { + case 4000: + case 8000: + case 12000: + case 16000: + case 24000: + case 32000: + case 48000: + case 96000: + case 192000: + /* Highest possible SYSCLK frequency: 147.456MHz */ + priv->sysclk_rate = 147456000U; + break; + case 11025: + case 22050: + case 44100: + case 88200: + case 176400: + /* Highest possible SYSCLK frequency: 135.4752 MHz */ + priv->sysclk_rate = 135475200U; + break; + default: + dev_err(codec->dev, "Not supported sample rate: %d\n", + params_rate(params)); + return -EINVAL; + } + + return tm2_start_sysclk(rtd->card); +} + +static struct snd_soc_ops tm2_aif1_ops = { + .hw_params = tm2_aif1_hw_params, +}; + +static int tm2_aif2_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + unsigned int asyncclk_rate; + int ret; + + switch (params_rate(params)) { + case 8000: + case 12000: + case 16000: + /* Highest possible ASYNCCLK frequency: 49.152MHz */ + asyncclk_rate = 49152000U; + break; + case 11025: + /* Highest possible ASYNCCLK frequency: 45.1584 MHz */ + asyncclk_rate = 45158400U; + break; + default: + dev_err(codec->dev, "Not supported sample rate: %d\n", + params_rate(params)); + return -EINVAL; + } + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL2_REFCLK, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + asyncclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to set FLL2 source: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, + ARIZONA_FLL_SRC_MCLK1, + MCLK_RATE, + asyncclk_rate); + if (ret < 0) { + dev_err(codec->dev, "Failed to start FLL2: %d\n", ret); + return ret; + } + + ret = snd_soc_codec_set_sysclk(codec, ARIZONA_CLK_ASYNCCLK, + ARIZONA_CLK_SRC_FLL2, + asyncclk_rate, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec->dev, "Failed to set ASYNCCLK source: %d\n", ret); + return ret; + } + + return 0; +} + +static int tm2_aif2_hw_free(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + int ret; + + /* disable FLL2 */ + ret = snd_soc_codec_set_pll(codec, WM5110_FLL2, ARIZONA_FLL_SRC_MCLK1, + 0, 0); + if (ret < 0) + dev_err(codec->dev, "Failed to stop FLL2: %d\n", ret); + + return ret; +} + +static struct snd_soc_ops tm2_aif2_ops = { + .hw_params = tm2_aif2_hw_params, + .hw_free = tm2_aif2_hw_free, +}; + +static int tm2_mic_bias(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_card *card = w->dapm->card; + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + gpiod_set_value_cansleep(priv->gpio_mic_bias, 1); + break; + case SND_SOC_DAPM_POST_PMD: + gpiod_set_value_cansleep(priv->gpio_mic_bias, 0); + break; + } + + return 0; +} + +static int tm2_set_bias_level(struct snd_soc_card *card, + struct snd_soc_dapm_context *dapm, + enum snd_soc_bias_level level) +{ + struct snd_soc_pcm_runtime *rtd; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); + + if (dapm->dev != rtd->codec_dai->dev) + return 0; + + switch (level) { + case SND_SOC_BIAS_STANDBY: + if (card->dapm.bias_level == SND_SOC_BIAS_OFF) + tm2_start_sysclk(card); + break; + case SND_SOC_BIAS_OFF: + tm2_stop_sysclk(card); + break; + default: + break; + } + + return 0; +} + +static struct snd_soc_aux_dev tm2_speaker_amp_dev; + +static int tm2_late_probe(struct snd_soc_card *card) +{ + struct tm2_machine_priv *priv = snd_soc_card_get_drvdata(card); + struct snd_soc_dai_link_component dlc = { 0 }; + unsigned int ch_map[] = { 0, 1 }; + struct snd_soc_dai *amp_pdm_dai; + struct snd_soc_pcm_runtime *rtd; + struct snd_soc_dai *aif1_dai; + struct snd_soc_dai *aif2_dai; + int ret; + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF1].name); + aif1_dai = rtd->codec_dai; + priv->codec = rtd->codec; + + ret = snd_soc_dai_set_sysclk(aif1_dai, ARIZONA_CLK_SYSCLK, 0, 0); + if (ret < 0) { + dev_err(aif1_dai->dev, "Failed to set SYSCLK: %d\n", ret); + return ret; + } + + rtd = snd_soc_get_pcm_runtime(card, card->dai_link[TM2_DAI_AIF2].name); + aif2_dai = rtd->codec_dai; + + ret = snd_soc_dai_set_sysclk(aif2_dai, ARIZONA_CLK_ASYNCCLK, 0, 0); + if (ret < 0) { + dev_err(aif2_dai->dev, "Failed to set ASYNCCLK: %d\n", ret); + return ret; + } + + dlc.of_node = tm2_speaker_amp_dev.codec_of_node; + amp_pdm_dai = snd_soc_find_dai(&dlc); + if (!amp_pdm_dai) + return -ENODEV; + + /* Set the MAX98504 V/I sense PDM Tx DAI channel mapping */ + ret = snd_soc_dai_set_channel_map(amp_pdm_dai, ARRAY_SIZE(ch_map), + ch_map, 0, NULL); + if (ret < 0) + return ret; + + ret = snd_soc_dai_set_tdm_slot(amp_pdm_dai, 0x3, 0x0, 2, 16); + if (ret < 0) + return ret; + + return 0; +} + +static const struct snd_kcontrol_new tm2_controls[] = { + SOC_DAPM_PIN_SWITCH("HP"), + SOC_DAPM_PIN_SWITCH("SPK"), + SOC_DAPM_PIN_SWITCH("RCV"), + SOC_DAPM_PIN_SWITCH("VPS"), + SOC_DAPM_PIN_SWITCH("HDMI"), + + SOC_DAPM_PIN_SWITCH("Main Mic"), + SOC_DAPM_PIN_SWITCH("Sub Mic"), + SOC_DAPM_PIN_SWITCH("Third Mic"), + + SOC_DAPM_PIN_SWITCH("Headset Mic"), +}; + +const struct snd_soc_dapm_widget tm2_dapm_widgets[] = { + SND_SOC_DAPM_HP("HP", NULL), + SND_SOC_DAPM_SPK("SPK", NULL), + SND_SOC_DAPM_SPK("RCV", NULL), + SND_SOC_DAPM_LINE("VPS", NULL), + SND_SOC_DAPM_LINE("HDMI", NULL), + + SND_SOC_DAPM_MIC("Main Mic", tm2_mic_bias), + SND_SOC_DAPM_MIC("Sub Mic", NULL), + SND_SOC_DAPM_MIC("Third Mic", NULL), + + SND_SOC_DAPM_MIC("Headset Mic", NULL), +}; + +static const struct snd_soc_component_driver tm2_component = { + .name = "tm2-audio", +}; + +static struct snd_soc_dai_driver tm2_ext_dai[] = { + { + .name = "Voice call", + .playback = { + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 48000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, + { + .name = "Bluetooth", + .playback = { + .channels_min = 1, + .channels_max = 4, + .rate_min = 8000, + .rate_max = 16000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 16000, + .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + }, +}; + +static struct snd_soc_dai_link tm2_dai_links[] = { + { + .name = "WM5110 AIF1", + .stream_name = "HiFi Primary", + .codec_dai_name = "wm5110-aif1", + .ops = &tm2_aif1_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + }, { + .name = "WM5110 Voice", + .stream_name = "Voice call", + .codec_dai_name = "wm5110-aif2", + .ops = &tm2_aif2_ops, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + }, { + .name = "WM5110 BT", + .stream_name = "Bluetooth", + .codec_dai_name = "wm5110-aif3", + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM, + .ignore_suspend = 1, + } +}; + +static struct snd_soc_card tm2_card = { + .owner = THIS_MODULE, + + .dai_link = tm2_dai_links, + .num_links = ARRAY_SIZE(tm2_dai_links), + .controls = tm2_controls, + .num_controls = ARRAY_SIZE(tm2_controls), + .dapm_widgets = tm2_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tm2_dapm_widgets), + .aux_dev = &tm2_speaker_amp_dev, + .num_aux_devs = 1, + + .late_probe = tm2_late_probe, + .set_bias_level = tm2_set_bias_level, +}; + +static int tm2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct snd_soc_card *card = &tm2_card; + struct tm2_machine_priv *priv; + struct device_node *cpu_dai_node, *codec_dai_node; + int ret, i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, priv); + card->dev = dev; + + priv->gpio_mic_bias = devm_gpiod_get(dev, "mic-bias", + GPIOF_OUT_INIT_LOW); + if (IS_ERR(priv->gpio_mic_bias)) { + dev_err(dev, "Failed to get mic bias gpio\n"); + return PTR_ERR(priv->gpio_mic_bias); + } + + ret = snd_soc_of_parse_card_name(card, "model"); + if (ret < 0) { + dev_err(dev, "Card name is not specified\n"); + return ret; + } + + ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); + if (ret < 0) { + dev_err(dev, "Audio routing is not specified or invalid\n"); + return ret; + } + + card->aux_dev[0].codec_of_node = of_parse_phandle(dev->of_node, + "audio-amplifier", 0); + if (!card->aux_dev[0].codec_of_node) { + dev_err(dev, "audio-amplifier property invalid or missing\n"); + return -EINVAL; + } + + cpu_dai_node = of_parse_phandle(dev->of_node, "i2s-controller", 0); + if (!cpu_dai_node) { + dev_err(dev, "i2s-controllers property invalid or missing\n"); + ret = -EINVAL; + goto amp_node_put; + } + + codec_dai_node = of_parse_phandle(dev->of_node, "audio-codec", 0); + if (!codec_dai_node) { + dev_err(dev, "audio-codec property invalid or missing\n"); + ret = -EINVAL; + goto cpu_dai_node_put; + } + + for (i = 0; i < card->num_links; i++) { + card->dai_link[i].cpu_dai_name = NULL; + card->dai_link[i].cpu_name = NULL; + card->dai_link[i].platform_name = NULL; + card->dai_link[i].codec_of_node = codec_dai_node; + card->dai_link[i].cpu_of_node = cpu_dai_node; + card->dai_link[i].platform_of_node = cpu_dai_node; + } + + ret = devm_snd_soc_register_component(dev, &tm2_component, + tm2_ext_dai, ARRAY_SIZE(tm2_ext_dai)); + if (ret < 0) { + dev_err(dev, "Failed to register component: %d\n", ret); + goto codec_dai_node_put; + } + + ret = devm_snd_soc_register_card(dev, card); + if (ret < 0) { + dev_err(dev, "Failed to register card: %d\n", ret); + goto codec_dai_node_put; + } + +codec_dai_node_put: + of_node_put(codec_dai_node); +cpu_dai_node_put: + of_node_put(cpu_dai_node); +amp_node_put: + of_node_put(card->aux_dev[0].codec_of_node); + return ret; +} + +static int tm2_pm_prepare(struct device *dev) +{ + struct snd_soc_card *card = dev_get_drvdata(dev); + + return tm2_stop_sysclk(card); +} + +static void tm2_pm_complete(struct device *dev) +{ + struct snd_soc_card *card = dev_get_drvdata(dev); + + tm2_start_sysclk(card); +} + +const struct dev_pm_ops tm2_pm_ops = { + .prepare = tm2_pm_prepare, + .suspend = snd_soc_suspend, + .resume = snd_soc_resume, + .complete = tm2_pm_complete, + .freeze = snd_soc_suspend, + .thaw = snd_soc_resume, + .poweroff = snd_soc_poweroff, + .restore = snd_soc_resume, +}; + +static const struct of_device_id tm2_of_match[] = { + { .compatible = "samsung,tm2-audio" }, + { }, +}; +MODULE_DEVICE_TABLE(of, tm2_of_match); + +static struct platform_driver tm2_driver = { + .driver = { + .name = "tm2-audio", + .pm = &tm2_pm_ops, + .of_match_table = tm2_of_match, + }, + .probe = tm2_probe, +}; +module_platform_driver(tm2_driver); + +MODULE_AUTHOR("Inha Song "); +MODULE_DESCRIPTION("ALSA SoC Exynos TM2 Audio Support"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 16200948d8353fe29a473a394d7d26790deae0e7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Dec 2016 11:19:38 +0100 Subject: ALSA: usb-audio: Fix race at stopping the stream We've got a kernel crash report showing like: Unable to handle kernel NULL pointer dereference at virtual address 00000008 pgd = a1d7c000 [00000008] *pgd=31c93831, *pte=00000000, *ppte=00000000 Internal error: Oops: 17 [#1] PREEMPT SMP ARM CPU: 0 PID: 250 Comm: dbus-daemon Not tainted 3.14.51-03479-gf50bdf4 #1 task: a3ae61c0 ti: a08c8000 task.ti: a08c8000 PC is at retire_capture_urb+0x10/0x1f4 [snd_usb_audio] LR is at snd_complete_urb+0x140/0x1f0 [snd_usb_audio] pc : [<7f0eb22c>] lr : [<7f0e57fc>] psr: 200e0193 sp : a08c9c98 ip : a08c9ce8 fp : a08c9ce4 r10: 0000000a r9 : 00000102 r8 : 94cb3000 r7 : 94cb3000 r6 : 94d0f000 r5 : 94d0e8e8 r4 : 94d0e000 r3 : 7f0eb21c r2 : 00000000 r1 : 94cb3000 r0 : 00000000 Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user Control: 10c5387d Table: 31d7c04a DAC: 00000015 Process dbus-daemon (pid: 250, stack limit = 0xa08c8238) Stack: (0xa08c9c98 to 0xa08ca000) ... Backtrace: [<7f0eb21c>] (retire_capture_urb [snd_usb_audio]) from [<7f0e57fc>] (snd_complete_urb+0x140/0x1f0 [snd_usb_audio]) [<7f0e56bc>] (snd_complete_urb [snd_usb_audio]) from [<80371118>] (__usb_hcd_giveback_urb+0x78/0xf4) [<803710a0>] (__usb_hcd_giveback_urb) from [<80371514>] (usb_giveback_urb_bh+0x8c/0xc0) [<80371488>] (usb_giveback_urb_bh) from [<80028e3c>] (tasklet_hi_action+0xc4/0x148) [<80028d78>] (tasklet_hi_action) from [<80028358>] (__do_softirq+0x190/0x380) [<800281c8>] (__do_softirq) from [<80028858>] (irq_exit+0x8c/0xfc) [<800287cc>] (irq_exit) from [<8000ea88>] (handle_IRQ+0x8c/0xc8) [<8000e9fc>] (handle_IRQ) from [<800085e8>] (gic_handle_irq+0xbc/0xf8) [<8000852c>] (gic_handle_irq) from [<80509044>] (__irq_svc+0x44/0x78) [<80508820>] (_raw_spin_unlock_irq) from [<8004b880>] (finish_task_switch+0x5c/0x100) [<8004b824>] (finish_task_switch) from [<805052f0>] (__schedule+0x48c/0x6d8) [<80504e64>] (__schedule) from [<805055d4>] (schedule+0x98/0x9c) [<8050553c>] (schedule) from [<800116c8>] (do_work_pending+0x30/0xd0) [<80011698>] (do_work_pending) from [<8000e160>] (work_pending+0xc/0x20) Code: e1a0c00d e92ddff0 e24cb004 e24dd024 (e5902008) Kernel panic - not syncing: Fatal exception in interrupt There is a race between retire_capture_urb() and stop_endpoints(). The latter is called at stopping the stream and it sets some endpoint fields to NULL. But its call is asynchronous, thus the pending complete callback might get called after these NULL clears, and it leads the NULL dereference like the above. The fix is to move the NULL clearance after the synchronization, i.e. wait_clear_urbs(). This is called at prepare and hw_free callbacks, so it's assured to be called before the restart of the stream or the release of the stream. Also, while we're at it, put the EP_FLAG_RUNNING flag check at the beginning of snd_complete_urb() to skip the pending complete after the stream is stopped. Fixes: b2eb950de2f0 ("ALSA: usb-audio: stop both data and sync...") Reported-by: Jiada Wang Reported-by: Mark Craske Cc: Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index c470251cea4b..f3fce9abece9 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -384,6 +384,9 @@ static void snd_complete_urb(struct urb *urb) if (unlikely(atomic_read(&ep->chip->shutdown))) goto exit_clear; + if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags))) + goto exit_clear; + if (usb_pipeout(ep->pipe)) { retire_outbound_urb(ep, ctx); /* can be stopped during retire callback */ @@ -534,6 +537,11 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) alive, ep->ep_num); clear_bit(EP_FLAG_STOPPING, &ep->flags); + ep->data_subs = NULL; + ep->sync_slave = NULL; + ep->retire_data_urb = NULL; + ep->prepare_data_urb = NULL; + return 0; } @@ -1006,10 +1014,6 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep) if (--ep->use_count == 0) { deactivate_urbs(ep, false); - ep->data_subs = NULL; - ep->sync_slave = NULL; - ep->retire_data_urb = NULL; - ep->prepare_data_urb = NULL; set_bit(EP_FLAG_STOPPING, &ep->flags); } } -- cgit v1.2.3-59-g8ed1b From 3ce2959d162a8f2d69a83582df619a20ff3f6645 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 2 Dec 2016 02:44:23 +0000 Subject: ASoC: rsnd: rsnd_get_dalign() needs to care SSIU, not SSI SSIU was controlled by SSI before, but commit c7f69ab53("ASoC: rsnd: use mod base common method on SSIU") separated it into ssiu.c But, it didn't care about rsnd_get_dalign() for judging SSI_BUSIF_DALIGN register value which changes the stream data order. This function will be called from cmd/src/ssiu now, but current code still cares ssi, not ssiu. This patch fix it up Signed-off-by: Kuninori Morimoto Tested-by: Hiroyuki Yokoyama Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 6 +++--- sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 912dc62ff9c7..825635aaf30e 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) */ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; @@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (rsnd_io_is_play(io)) { struct rsnd_mod *src = rsnd_io_to_mod_src(io); - target = src ? src : ssi; + target = src ? src : ssiu; } else { struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); - target = cmd ? cmd : ssi; + target = cmd ? cmd : ssiu; } mask <<= runtime->channels * 4; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d9e550211c09..71158c8bc254 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -428,6 +428,7 @@ struct rsnd_dai_stream { }; #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_ssiu(io) rsnd_io_to_mod((io), RSND_MOD_SSIU) #define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) -- cgit v1.2.3-59-g8ed1b From 29a43aa9b4b609eba73e76c5fd92d435fc6e35ce Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 2 Dec 2016 05:27:30 +0000 Subject: ASoC: simple_card_utils: tidyup file comment/define simple_card_utils was created as simple_card_core in 1st prototype, and current code still have it. Let's tidyup Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- include/sound/simple_card_utils.h | 8 ++++---- sound/soc/generic/simple-card-utils.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h index fd6412551145..64e90ca9ad32 100644 --- a/include/sound/simple_card_utils.h +++ b/include/sound/simple_card_utils.h @@ -1,5 +1,5 @@ /* - * simple_card_core.h + * simple_card_utils.h * * Copyright (c) 2016 Kuninori Morimoto * @@ -7,8 +7,8 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ -#ifndef __SIMPLE_CARD_CORE_H -#define __SIMPLE_CARD_CORE_H +#ifndef __SIMPLE_CARD_UTILS_H +#define __SIMPLE_CARD_UTILS_H #include @@ -68,4 +68,4 @@ void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link, int asoc_simple_card_clean_reference(struct snd_soc_card *card); -#endif /* __SIMPLE_CARD_CORE_H */ +#endif /* __SIMPLE_CARD_UTILS_H */ diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index e5b80f53093a..cf026252cd4a 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -1,5 +1,5 @@ /* - * simple-card-core.c + * simple-card-utils.c * * Copyright (c) 2016 Kuninori Morimoto * -- cgit v1.2.3-59-g8ed1b From 1a7dd6e2f192960229dd3113a35c74690e503ea2 Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Fri, 25 Nov 2016 16:09:10 +0800 Subject: ASoC: topology: Allow a widget to have multiple enum controls This patch can create multiple enumerated mixer controls for a widget. Previously topology kernel driver assumes a widget can have only one emumerated mixer control. We need to remove this restriction for Broxton. Its firmware modules (widgets) may need multiple enum controls based on the channel and MIC combination. No ABI change is needed. The ABI allows a widget to embed multiple controls. Reported-by: G Kranthi Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 163 +++++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 76 deletions(-) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 4dfdc656cce6..63e1a50f2161 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -486,21 +486,24 @@ static void remove_widget(struct snd_soc_component *comp, dobj->ops->widget_unload(comp, dobj); /* - * Dynamic Widgets either have 1 enum kcontrol or 1..N mixers. + * Dynamic Widgets either have 1..N enum kcontrols or mixers. * The enum may either have an array of values or strings. */ if (dobj->widget.kcontrol_enum) { /* enumerated widget mixer */ - struct soc_enum *se = - (struct soc_enum *)w->kcontrols[0]->private_value; + for (i = 0; i < w->num_kcontrols; i++) { + struct snd_kcontrol *kcontrol = w->kcontrols[i]; + struct soc_enum *se = + (struct soc_enum *)kcontrol->private_value; - snd_ctl_remove(card, w->kcontrols[0]); + snd_ctl_remove(card, kcontrol); - kfree(se->dobj.control.dvalues); - for (i = 0; i < se->items; i++) - kfree(se->dobj.control.dtexts[i]); + kfree(se->dobj.control.dvalues); + for (i = 0; i < se->items; i++) + kfree(se->dobj.control.dtexts[i]); - kfree(se); + kfree(se); + } kfree(w->kcontrol_news); } else { /* non enumerated widget mixer */ @@ -1256,98 +1259,105 @@ err: } static struct snd_kcontrol_new *soc_tplg_dapm_widget_denum_create( - struct soc_tplg *tplg) + struct soc_tplg *tplg, int num_kcontrols) { struct snd_kcontrol_new *kc; struct snd_soc_tplg_enum_control *ec; struct soc_enum *se; - int i, err; - - ec = (struct snd_soc_tplg_enum_control *)tplg->pos; - tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + - ec->priv.size); - - /* validate kcontrol */ - if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == - SNDRV_CTL_ELEM_ID_NAME_MAXLEN) - return NULL; + int i, j, err; - kc = kzalloc(sizeof(*kc), GFP_KERNEL); + kc = kcalloc(num_kcontrols, sizeof(*kc), GFP_KERNEL); if (kc == NULL) return NULL; - se = kzalloc(sizeof(*se), GFP_KERNEL); - if (se == NULL) - goto err; + for (i = 0; i < num_kcontrols; i++) { + ec = (struct snd_soc_tplg_enum_control *)tplg->pos; + /* validate kcontrol */ + if (strnlen(ec->hdr.name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == + SNDRV_CTL_ELEM_ID_NAME_MAXLEN) + return NULL; + + se = kzalloc(sizeof(*se), GFP_KERNEL); + if (se == NULL) + goto err; - dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", - ec->hdr.name); + dev_dbg(tplg->dev, " adding DAPM widget enum control %s\n", + ec->hdr.name); - kc->name = ec->hdr.name; - kc->private_value = (long)se; - kc->iface = SNDRV_CTL_ELEM_IFACE_MIXER; - kc->access = ec->hdr.access; + kc[i].name = ec->hdr.name; + kc[i].private_value = (long)se; + kc[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kc[i].access = ec->hdr.access; - /* we only support FL/FR channel mapping atm */ - se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_l = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FL); - se->shift_r = tplc_chan_get_shift(tplg, ec->channel, SNDRV_CHMAP_FR); + /* we only support FL/FR channel mapping atm */ + se->reg = tplc_chan_get_reg(tplg, ec->channel, SNDRV_CHMAP_FL); + se->shift_l = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FL); + se->shift_r = tplc_chan_get_shift(tplg, ec->channel, + SNDRV_CHMAP_FR); - se->items = ec->items; - se->mask = ec->mask; - se->dobj.index = tplg->index; + se->items = ec->items; + se->mask = ec->mask; + se->dobj.index = tplg->index; - switch (ec->hdr.ops.info) { - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - err = soc_tplg_denum_create_values(se, ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create values for %s\n", - ec->hdr.name); + switch (ec->hdr.ops.info) { + case SND_SOC_TPLG_CTL_ENUM_VALUE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + err = soc_tplg_denum_create_values(se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create values for %s\n", + ec->hdr.name); + goto err_se; + } + /* fall through to create texts */ + case SND_SOC_TPLG_CTL_ENUM: + case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: + case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: + err = soc_tplg_denum_create_texts(se, ec); + if (err < 0) { + dev_err(tplg->dev, "ASoC: could not create texts for %s\n", + ec->hdr.name); + goto err_se; + } + break; + default: + dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", + ec->hdr.ops.info, ec->hdr.name); goto err_se; } - /* fall through to create texts */ - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - err = soc_tplg_denum_create_texts(se, ec); + + /* map io handlers */ + err = soc_tplg_kcontrol_bind_io(&ec->hdr, &kc[i], tplg); + if (err) { + soc_control_err(tplg, &ec->hdr, ec->hdr.name); + goto err_se; + } + + /* pass control to driver for optional further init */ + err = soc_tplg_init_kcontrol(tplg, &kc[i], + (struct snd_soc_tplg_ctl_hdr *)ec); if (err < 0) { - dev_err(tplg->dev, "ASoC: could not create texts for %s\n", + dev_err(tplg->dev, "ASoC: failed to init %s\n", ec->hdr.name); goto err_se; } - break; - default: - dev_err(tplg->dev, "ASoC: invalid enum control type %d for %s\n", - ec->hdr.ops.info, ec->hdr.name); - goto err_se; - } - /* map io handlers */ - err = soc_tplg_kcontrol_bind_io(&ec->hdr, kc, tplg); - if (err) { - soc_control_err(tplg, &ec->hdr, ec->hdr.name); - goto err_se; - } - - /* pass control to driver for optional further init */ - err = soc_tplg_init_kcontrol(tplg, kc, - (struct snd_soc_tplg_ctl_hdr *)ec); - if (err < 0) { - dev_err(tplg->dev, "ASoC: failed to init %s\n", - ec->hdr.name); - goto err_se; + tplg->pos += (sizeof(struct snd_soc_tplg_enum_control) + + ec->priv.size); } return kc; err_se: - /* free values and texts */ - kfree(se->dobj.control.dvalues); - for (i = 0; i < ec->items; i++) - kfree(se->dobj.control.dtexts[i]); + for (; i >= 0; i--) { + /* free values and texts */ + se = (struct soc_enum *)kc[i].private_value; + kfree(se->dobj.control.dvalues); + for (j = 0; j < ec->items; j++) + kfree(se->dobj.control.dtexts[j]); - kfree(se); + kfree(se); + } err: kfree(kc); @@ -1499,9 +1509,10 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: template.dobj.widget.kcontrol_enum = 1; - template.num_kcontrols = 1; + template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = - soc_tplg_dapm_widget_denum_create(tplg); + soc_tplg_dapm_widget_denum_create(tplg, + template.num_kcontrols); if (!template.kcontrol_news) { ret = -ENOMEM; goto hdr_err; -- cgit v1.2.3-59-g8ed1b From eea3dd4f1247aa8654194fb19ade22c94c42e41a Mon Sep 17 00:00:00 2001 From: Mengdong Lin Date: Fri, 25 Nov 2016 16:09:17 +0800 Subject: ASoC: topology: Only free TLV for volume mixers of a widget This patch will check the type of embedded controls for a widget, and only free the TLV of volume mixers. Bytes controls don't have TLV. Just free the private value which is used as struct soc_mixer_control for volume mixers or soc_bytes_ext for bytes controls. No need to cast to these types before freeing it. Signed-off-by: Mengdong Lin Signed-off-by: Mark Brown --- include/sound/soc-topology.h | 2 +- sound/soc/soc-topology.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/include/sound/soc-topology.h b/include/sound/soc-topology.h index b897b9d63161..f9cc7b9271ac 100644 --- a/include/sound/soc-topology.h +++ b/include/sound/soc-topology.h @@ -53,7 +53,7 @@ struct snd_soc_dobj_control { /* dynamic widget object */ struct snd_soc_dobj_widget { - unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */ + unsigned int kcontrol_type; /* kcontrol type: mixer, enum, bytes */ }; /* generic dynamic object - all dynamic objects belong to this struct */ diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 63e1a50f2161..11feb19e9730 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -489,7 +489,7 @@ static void remove_widget(struct snd_soc_component *comp, * Dynamic Widgets either have 1..N enum kcontrols or mixers. * The enum may either have an array of values or strings. */ - if (dobj->widget.kcontrol_enum) { + if (dobj->widget.kcontrol_type == SND_SOC_TPLG_TYPE_ENUM) { /* enumerated widget mixer */ for (i = 0; i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; @@ -506,16 +506,21 @@ static void remove_widget(struct snd_soc_component *comp, } kfree(w->kcontrol_news); } else { - /* non enumerated widget mixer */ + /* volume mixer or bytes controls */ for (i = 0; i < w->num_kcontrols; i++) { struct snd_kcontrol *kcontrol = w->kcontrols[i]; - struct soc_mixer_control *sm = - (struct soc_mixer_control *) kcontrol->private_value; - kfree(w->kcontrols[i]->tlv.p); + if (dobj->widget.kcontrol_type + == SND_SOC_TPLG_TYPE_MIXER) + kfree(kcontrol->tlv.p); - snd_ctl_remove(card, w->kcontrols[i]); - kfree(sm); + snd_ctl_remove(card, kcontrol); + + /* Private value is used as struct soc_mixer_control + * for volume mixers or soc_bytes_ext for bytes + * controls. + */ + kfree((void *)kcontrol->private_value); } kfree(w->kcontrol_news); } @@ -1439,6 +1444,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, struct snd_soc_dapm_widget template, *widget; struct snd_soc_tplg_ctl_hdr *control_hdr; struct snd_soc_card *card = tplg->comp->card; + unsigned int kcontrol_type; int ret = 0; if (strnlen(w->name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == @@ -1494,6 +1500,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_CTL_VOLSW_XR_SX: case SND_SOC_TPLG_CTL_RANGE: case SND_SOC_TPLG_DAPM_CTL_VOLSW: + kcontrol_type = SND_SOC_TPLG_TYPE_MIXER; /* volume mixer */ template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = soc_tplg_dapm_widget_dmixer_create(tplg, @@ -1508,7 +1515,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: - template.dobj.widget.kcontrol_enum = 1; + kcontrol_type = SND_SOC_TPLG_TYPE_ENUM; /* enumerated mixer */ template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = soc_tplg_dapm_widget_denum_create(tplg, @@ -1519,6 +1526,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, } break; case SND_SOC_TPLG_CTL_BYTES: + kcontrol_type = SND_SOC_TPLG_TYPE_BYTES; /* bytes control */ template.num_kcontrols = w->num_kcontrols; template.kcontrol_news = soc_tplg_dapm_widget_dbytes_create(tplg, @@ -1555,6 +1563,7 @@ widget: } widget->dobj.type = SND_SOC_DOBJ_WIDGET; + widget->dobj.widget.kcontrol_type = kcontrol_type; widget->dobj.ops = tplg->ops; widget->dobj.index = tplg->index; kfree(template.sname); -- cgit v1.2.3-59-g8ed1b From 8c317fafdd4e3b988c44d986022c66cebf71fc41 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 29 Nov 2016 18:10:49 +0100 Subject: ASoC: cs42l56: Fix misuse of regmap_update_bits Using regmap_update_bits(..., mask, 1) with 'mask' following (1 << k) and k greater than 0 is wrong. Indeed, _regmap_update_bits will perform (mask & 1), which results in 0 if LSB of mask is 0. Thus the call regmap_update_bits(..., mask, 1) is in reality equivalent to regmap_update_bits(..., mask, 0). In such a case, the correct use is regmap_update_bits(..., mask, mask). This driver is performing such a mistake with the CS42L56_AIN*_REF_MASK masks, which equal 0x10, 0x20, 0x40 and 0x80. Fix the driver to make it consistent with the API. Please note that this change is untested, as I do not have this piece of hardware. Testers are welcome! Signed-off-by: Florian Vaussard Reviewed-by: Charles Keepax Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l56.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 3e2c04642f1e..cb6ca85f1536 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1277,19 +1277,23 @@ static int cs42l56_i2c_probe(struct i2c_client *i2c_client, if (cs42l56->pdata.ain1a_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN1A_REF_MASK, 1); + CS42L56_AIN1A_REF_MASK, + CS42L56_AIN1A_REF_MASK); if (cs42l56->pdata.ain1b_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN1B_REF_MASK, 1); + CS42L56_AIN1B_REF_MASK, + CS42L56_AIN1B_REF_MASK); if (cs42l56->pdata.ain2a_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN2A_REF_MASK, 1); + CS42L56_AIN2A_REF_MASK, + CS42L56_AIN2A_REF_MASK); if (cs42l56->pdata.ain2b_ref_cfg) regmap_update_bits(cs42l56->regmap, CS42L56_AIN_REFCFG_ADC_MUX, - CS42L56_AIN2B_REF_MASK, 1); + CS42L56_AIN2B_REF_MASK, + CS42L56_AIN2B_REF_MASK); if (cs42l56->pdata.micbias_lvl) regmap_update_bits(cs42l56->regmap, CS42L56_GAIN_BIAS_CTL, -- cgit v1.2.3-59-g8ed1b From fade74dfab7cdba55a197db08f3d15cf2319bf4c Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Mon, 5 Dec 2016 17:45:02 +0100 Subject: ASoC: Intel: atom: Add sysfs entry in order to store FW version This patch is adding a sysfs entry in order to be able to get access to SST FW version. Signed-off-by: Sebastien Guiriec Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst.c b/sound/soc/intel/atom/sst/sst.c index 9b6e27385dc9..f9ba71315e33 100644 --- a/sound/soc/intel/atom/sst/sst.c +++ b/sound/soc/intel/atom/sst/sst.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -242,6 +243,32 @@ int sst_alloc_drv_context(struct intel_sst_drv **ctx, } EXPORT_SYMBOL_GPL(sst_alloc_drv_context); +static ssize_t firmware_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct intel_sst_drv *ctx = dev_get_drvdata(dev); + + if (ctx->fw_version.type == 0 && ctx->fw_version.major == 0 && + ctx->fw_version.minor == 0 && ctx->fw_version.build == 0) + return sprintf(buf, "FW not yet loaded\n"); + else + return sprintf(buf, "v%02x.%02x.%02x.%02x\n", + ctx->fw_version.type, ctx->fw_version.major, + ctx->fw_version.minor, ctx->fw_version.build); + +} + +DEVICE_ATTR_RO(firmware_version); + +static const struct attribute *sst_fw_version_attrs[] = { + &dev_attr_firmware_version.attr, + NULL, +}; + +static const struct attribute_group sst_fw_version_attr_group = { + .attrs = (struct attribute **)sst_fw_version_attrs, +}; + int sst_context_init(struct intel_sst_drv *ctx) { int ret = 0, i; @@ -315,8 +342,19 @@ int sst_context_init(struct intel_sst_drv *ctx) dev_err(ctx->dev, "Firmware download failed:%d\n", ret); goto do_free_mem; } + + ret = sysfs_create_group(&ctx->dev->kobj, + &sst_fw_version_attr_group); + if (ret) { + dev_err(ctx->dev, + "Unable to create sysfs\n"); + goto err_sysfs; + } + sst_register(ctx->dev); return 0; +err_sysfs: + sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); do_free_mem: destroy_workqueue(ctx->post_msg_wq); @@ -330,6 +368,7 @@ void sst_context_cleanup(struct intel_sst_drv *ctx) pm_runtime_disable(ctx->dev); sst_unregister(ctx->dev); sst_set_fw_state_locked(ctx, SST_SHUTDOWN); + sysfs_remove_group(&ctx->dev->kobj, &sst_fw_version_attr_group); flush_scheduled_work(); destroy_workqueue(ctx->post_msg_wq); pm_qos_remove_request(ctx->qos); -- cgit v1.2.3-59-g8ed1b From c7da1e9d2641f67e8b20703118ac02fe79604f10 Mon Sep 17 00:00:00 2001 From: Sebastien Guiriec Date: Mon, 5 Dec 2016 17:45:01 +0100 Subject: ASoC: Intel: atom: save FW version After the boot of the SST FW the firmware version is send back to the driver. This patch is saving the FW version inside the driver. Signed-off-by: Sebastien Guiriec Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst/sst.h | 1 + sound/soc/intel/atom/sst/sst_ipc.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'sound') diff --git a/sound/soc/intel/atom/sst/sst.h b/sound/soc/intel/atom/sst/sst.h index 3f493862e98d..5c9a51cc77aa 100644 --- a/sound/soc/intel/atom/sst/sst.h +++ b/sound/soc/intel/atom/sst/sst.h @@ -436,6 +436,7 @@ struct intel_sst_drv { */ char firmware_name[FW_NAME_SIZE]; + struct snd_sst_fw_version fw_version; struct sst_fw_save *fw_save; }; diff --git a/sound/soc/intel/atom/sst/sst_ipc.c b/sound/soc/intel/atom/sst/sst_ipc.c index 7934a0047384..374bb61c596d 100644 --- a/sound/soc/intel/atom/sst/sst_ipc.c +++ b/sound/soc/intel/atom/sst/sst_ipc.c @@ -242,6 +242,12 @@ static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, dev_dbg(sst_drv_ctx->dev, "Build date %s Time %s\n", init->build_info.date, init->build_info.time); + /* Save FW version */ + sst_drv_ctx->fw_version.type = init->fw_version.type; + sst_drv_ctx->fw_version.major = init->fw_version.major; + sst_drv_ctx->fw_version.minor = init->fw_version.minor; + sst_drv_ctx->fw_version.build = init->fw_version.build; + ret: sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); } -- cgit v1.2.3-59-g8ed1b From 5e0ad0d8747f3e4803a9c3d96d64dd7332506d3c Mon Sep 17 00:00:00 2001 From: Kai-Heng Feng Date: Tue, 6 Dec 2016 16:56:27 +0800 Subject: ALSA: hda: when comparing pin configurations, ignore assoc in addition to seq Commit [64047d7f4912 ALSA: hda - ignore the assoc and seq when comparing pin configurations] intented to ignore both seq and assoc at pin comparing, but it only ignored seq. So that commit may still fail to match pins on some machines. Change the bitmask to also ignore assoc. v2: Use macro to do bit masking. Thanks to Hui Wang for the analysis. Fixes: 64047d7f4912 ("ALSA: hda - ignore the assoc and seq when comparing...") Signed-off-by: Kai-Heng Feng Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_auto_parser.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4ad29f8d7a4a..a03cf68d0bcd 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -884,6 +884,8 @@ void snd_hda_apply_fixup(struct hda_codec *codec, int action) } EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); +#define IGNORE_SEQ_ASSOC (~(AC_DEFCFG_SEQUENCE | AC_DEFCFG_DEF_ASSOC)) + static bool pin_config_match(struct hda_codec *codec, const struct hda_pintbl *pins) { @@ -901,7 +903,7 @@ static bool pin_config_match(struct hda_codec *codec, for (; t_pins->nid; t_pins++) { if (t_pins->nid == nid) { found = 1; - if ((t_pins->val & 0xfffffff0) == (cfg & 0xfffffff0)) + if ((t_pins->val & IGNORE_SEQ_ASSOC) == (cfg & IGNORE_SEQ_ASSOC)) break; else if ((cfg & 0xf0000000) == 0x40000000 && (t_pins->val & 0xf0000000) == 0x40000000) break; -- cgit v1.2.3-59-g8ed1b From f73cd43ac3b41c0f09a126387f302bbc0d9c726d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 6 Dec 2016 11:55:17 +0100 Subject: ALSA: hda - Gate the mic jack on HP Z1 Gen3 AiO HP Z1 Gen3 AiO with Conexant codec doesn't give an unsolicited event to the headset mic pin upon the jack plugging, it reports only to the headphone pin. It results in the missing mic switching. Let's fix up by simply gating the jack event. Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ed62748a6d55..c15c51bea26d 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -262,6 +262,7 @@ enum { CXT_FIXUP_CAP_MIX_AMP_5047, CXT_FIXUP_MUTE_LED_EAPD, CXT_FIXUP_HP_SPECTRE, + CXT_FIXUP_HP_GATE_MIC, }; /* for hda_fixup_thinkpad_acpi() */ @@ -633,6 +634,17 @@ static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec, (1 << AC_AMPCAP_MUTE_SHIFT)); } +static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + /* the mic pin (0x19) doesn't give an unsolicited event; + * probe the mic pin together with the headphone pin (0x16) + */ + if (action == HDA_FIXUP_ACT_PROBE) + snd_hda_jack_set_gating_jack(codec, 0x19, 0x16); +} + /* ThinkPad X200 & co with cxt5051 */ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ @@ -774,6 +786,10 @@ static const struct hda_fixup cxt_fixups[] = { { } } }, + [CXT_FIXUP_HP_GATE_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_hp_gate_mic_jack, + }, }; static const struct snd_pci_quirk cxt5045_fixups[] = { @@ -824,6 +840,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC), SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE), + SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC), SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), -- cgit v1.2.3-59-g8ed1b From 914657c2be09fb89a50c7841e98186301c93767e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 3 Dec 2016 15:10:50 +0800 Subject: ASoC: cs35l34: Simplify the logic to set CS35L34_MCLK_CTL setting The logic of "value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_XXXXXX;" is unnecessary complex. By setting CS35L34_MCLK_DIV | CS35L34_MCLK_RATE_MASK as the mask for regmap_update_bits() call, what the code does is exactly the same as setting value = CS35L34_MCLK_RATE_XXXXXX. Signed-off-by: Axel Lin Acked-by: Paul Handrigan Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l34.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index e0f672af1d84..7c5d1510cf2c 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -610,15 +610,15 @@ static int cs35l34_dai_set_sysclk(struct snd_soc_dai *dai, switch (freq) { case CS35L34_MCLK_5644: - value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_5P6448; + value = CS35L34_MCLK_RATE_5P6448; cs35l34->mclk_int = freq; break; case CS35L34_MCLK_6: - value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_6P0000; + value = CS35L34_MCLK_RATE_6P0000; cs35l34->mclk_int = freq; break; case CS35L34_MCLK_6144: - value = ~CS35L34_MCLK_DIV & CS35L34_MCLK_RATE_6P1440; + value = CS35L34_MCLK_RATE_6P1440; cs35l34->mclk_int = freq; break; case CS35L34_MCLK_11289: -- cgit v1.2.3-59-g8ed1b From 1e2e3fe480064ca33186e5a923beaa160efed35d Mon Sep 17 00:00:00 2001 From: Daniel Girnus Date: Tue, 6 Dec 2016 14:46:15 +0900 Subject: ALSA: usb-audio: avoid setting of sample rate multiple times on bus Some of userland applications call 'snd_pcm_hw_params()' and 'snd_pcm_hw_prepare()' sequentially, which means 'snd_pcm_hw_prepare()' is called twice and the second 'snd_pcm_hw_prepare()' is called in 'SNDRV_PCM_STATE_PREPARED' state. Some devices are not able to manage this and they will stop playback if the sample rate will be configured several times over USB protocol. V2: updated Changelog Signed-off-by: Daniel Girnus Signed-off-by: Jens Lorenz Signed-off-by: Jiada Wang Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 44d178ee9177..a522c9af1f34 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -806,17 +806,18 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) if (ret < 0) goto unlock; - iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); - alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; - ret = snd_usb_init_sample_rate(subs->stream->chip, - subs->cur_audiofmt->iface, - alts, - subs->cur_audiofmt, - subs->cur_rate); - if (ret < 0) - goto unlock; - if (subs->need_setup_ep) { + + iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); + alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; + ret = snd_usb_init_sample_rate(subs->stream->chip, + subs->cur_audiofmt->iface, + alts, + subs->cur_audiofmt, + subs->cur_rate); + if (ret < 0) + goto unlock; + ret = configure_endpoint(subs); if (ret < 0) goto unlock; -- cgit v1.2.3-59-g8ed1b From fd1a5059610cd3887f1050171a840ca864108730 Mon Sep 17 00:00:00 2001 From: Andreas Pape Date: Tue, 6 Dec 2016 14:46:14 +0900 Subject: ALSA: usb-audio: more tolerant packetsize since commit 57e6dae1087b ("ALSA: usb-audio: do not trust too-big wMaxPacketSize values"), the expected packetsize is always limited to nominal + 25%. It was discovered, that some devices (Android audio accessory) have a much higher jitter in used packetsizes than 25% which would result in BABBLE condition and dropping of packets. A better solution is so assume the jitter to be the nominal packetsize: -one nearly empty packet followed by a almost 150% sized one. V2: changed to assume max frequency is +50 of nominal packetsize. Signed-off-by: Andreas Pape Signed-off-by: Jiada Wang Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index c470251cea4b..a2931f49a1fc 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -632,8 +632,8 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, ep->stride = frame_bits >> 3; ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; - /* assume max. frequency is 25% higher than nominal */ - ep->freqmax = ep->freqn + (ep->freqn >> 2); + /* assume max. frequency is 50% higher than nominal */ + ep->freqmax = ep->freqn + (ep->freqn >> 1); /* Round up freqmax to nearest integer in order to calculate maximum * packet size, which must represent a whole number of frames. * This is accomplished by adding 0x0.ffff before converting the -- cgit v1.2.3-59-g8ed1b From 5f1516d52f9287a94dc3b9d57c370ed01802a911 Mon Sep 17 00:00:00 2001 From: John Hsu Date: Fri, 2 Dec 2016 09:48:58 +0800 Subject: ASoC: nau8825: disable sinc filter for high THD of ADC This bit will enable 4th order SINC filter. =1, filter will enable; but it consumes higher power. =0, the sinc filter is disable, and it should always keep 0 value to get high THD. Therefor, disable the filter when codec initiation for better performance when recording. Signed-off-by: John Hsu Signed-off-by: Mark Brown --- sound/soc/codecs/nau8825.c | 3 ++- sound/soc/codecs/nau8825.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 2b89569333a1..efe3a44658d5 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1846,7 +1846,8 @@ static void nau8825_init_regs(struct nau8825 *nau8825) * (audible hiss). Set it to something better. */ regmap_update_bits(regmap, NAU8825_REG_ADC_RATE, - NAU8825_ADC_SYNC_DOWN_MASK, NAU8825_ADC_SYNC_DOWN_64); + NAU8825_ADC_SYNC_DOWN_MASK | NAU8825_ADC_SINC4_EN, + NAU8825_ADC_SYNC_DOWN_64); regmap_update_bits(regmap, NAU8825_REG_DAC_CTRL1, NAU8825_DAC_OVERSAMPLE_MASK, NAU8825_DAC_OVERSAMPLE_64); /* Disable DACR/L power */ diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 0672a25617b9..5d1704e73241 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h @@ -269,6 +269,8 @@ #define NAU8825_BIQ_PATH_DAC (1 << NAU8825_BIQ_PATH_SFT) /* ADC_RATE (0x2b) */ +#define NAU8825_ADC_SINC4_SFT 4 +#define NAU8825_ADC_SINC4_EN (1 << NAU8825_ADC_SINC4_SFT) #define NAU8825_ADC_SYNC_DOWN_SFT 0 #define NAU8825_ADC_SYNC_DOWN_MASK 0x3 #define NAU8825_ADC_SYNC_DOWN_32 0 -- cgit v1.2.3-59-g8ed1b From c1aee1d828caa86a663c57a56eead7fd5f22d80f Mon Sep 17 00:00:00 2001 From: Sathyanarayana Nujella Date: Tue, 6 Dec 2016 07:08:36 -0800 Subject: ASoC: Intel: update bxt_da7219_max98357a to support quad ch dmic capture This patch updates FE channel constraints & BE fixup to support quad channel DMIC capture. DMIC pin's BE fixup is configured based on channel input, i.e. either stereo or quad. Signed-off-by: Sathyanarayana Nujella Signed-off-by: Harsha Priya Acked-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/boards/bxt_da7219_max98357a.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c index bff80b467262..3a8c24a59020 100644 --- a/sound/soc/intel/boards/bxt_da7219_max98357a.c +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c @@ -30,6 +30,7 @@ #define BXT_DIALOG_CODEC_DAI "da7219-hifi" #define BXT_MAXIM_CODEC_DAI "HiFi" #define DUAL_CHANNEL 2 +#define QUAD_CHANNEL 4 static struct snd_soc_jack broxton_headset; @@ -182,6 +183,16 @@ static struct snd_pcm_hw_constraint_list constraints_channels = { .mask = 0, }; +static unsigned int channels_quad[] = { + QUAD_CHANNEL, +}; + +static struct snd_pcm_hw_constraint_list constraints_channels_quad = { + .count = ARRAY_SIZE(channels_quad), + .list = channels_quad, + .mask = 0, +}; + static int bxt_fe_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; @@ -258,7 +269,10 @@ static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, { struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); - channels->min = channels->max = DUAL_CHANNEL; + if (params_channels(params) == 2) + channels->min = channels->max = 2; + else + channels->min = channels->max = 4; return 0; } @@ -267,9 +281,9 @@ static int broxton_dmic_startup(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - runtime->hw.channels_max = DUAL_CHANNEL; + runtime->hw.channels_min = runtime->hw.channels_max = QUAD_CHANNEL; snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, - &constraints_channels); + &constraints_channels_quad); return snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); -- cgit v1.2.3-59-g8ed1b From 048ea6dfbe94f00afe52a2403324449efb356cd6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 7 Dec 2016 14:22:50 +0300 Subject: ALSA: cs46xx: add a new line We accidentally deleted a newline so now the "nreallocated++;" statement is hanging out way off to the right of the screen. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/pci/cs46xx/dsp_spos.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 4a0cbd2241d8..aa61615288ff 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -107,7 +107,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 dev_dbg(chip->card->dev, "handle_wideop:[2] %05x:%05x addr %04x\n", - hival, loval, address); nreallocated++; + hival, loval, address); + nreallocated++; } /* wide_opcodes[j] == wide_op */ } /* for */ } /* mod_type == 0 ... */ -- cgit v1.2.3-59-g8ed1b From 6bf66b1c35870e08359cb03c49a94e7fef529ef5 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Dec 2016 02:05:22 +0000 Subject: ASoC: rsnd: tidyup ssi->usrcnt counter check in hw_params ssi->usrcnt will be updated on snd_soc_dai_ops::trigger, but snd_pcm_ops::hw_params will be called *before* it. Thus, ssi->usrcnt is still 0 when 1st call. rsnd_ssi_hw_params() needs to check its called count, this means trigger should be if (ssi->usrcnt) instead of if (ssi->usrcnt > 1). Reported-by: Nguyen Viet Dung Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index e23e07b54d8c..411bda2387ad 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -417,11 +417,14 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, int chan = params_channels(params); /* - * Already working. - * It will happen if SSI has parent/child connection. + * snd_pcm_ops::hw_params will be called *before* + * snd_soc_dai_ops::trigger. Thus, ssi->usrcnt is 0 + * in 1st call. */ - if (ssi->usrcnt > 1) { + if (ssi->usrcnt) { /* + * Already working. + * It will happen if SSI has parent/child connection. * it is error if child <-> parent SSI uses * different channels. */ -- cgit v1.2.3-59-g8ed1b From c2d3171847611e8a33d3e10a9942f6c065d05c1f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Dec 2016 00:29:02 +0000 Subject: ASoC: rsnd: enable/disable ADG when suspend/resume timing Current rsnd driver enables ADG clock when .probe timing, but it breaks sound after Suspend/Resume. These should be setups every suspend/resume timing too. This patch is tested on R-Car Gen3 Salvator-X board Signed-off-by: Kuninori Morimoto Tested-by: Gaku Inami Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 38 ++++++++++++++++++++++++-------------- sound/soc/sh/rcar/core.c | 24 ++++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 3 +++ 3 files changed, 51 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 545377dc15ed..54b28fd502ef 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -376,6 +376,25 @@ found_clock: return 0; } +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable) +{ + struct rsnd_adg *adg = rsnd_priv_to_adg(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct clk *clk; + int i, ret; + + for_each_rsnd_clk(clk, adg, i) { + ret = 0; + if (enable) + ret = clk_prepare_enable(clk); + else + clk_disable_unprepare(clk); + + if (ret < 0) + dev_warn(dev, "can't use clk %d\n", i); + } +} + static void rsnd_adg_get_clkin(struct rsnd_priv *priv, struct rsnd_adg *adg) { @@ -387,20 +406,15 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, [CLKC] = "clk_c", [CLKI] = "clk_i", }; - int i, ret; + int i; for (i = 0; i < CLKMAX; i++) { clk = devm_clk_get(dev, clk_name[i]); adg->clk[i] = IS_ERR(clk) ? NULL : clk; } - for_each_rsnd_clk(clk, adg, i) { - ret = clk_prepare_enable(clk); - if (ret < 0) - dev_warn(dev, "can't use clk %d\n", i); - + for_each_rsnd_clk(clk, adg, i) dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); - } } static void rsnd_adg_get_clkout(struct rsnd_priv *priv, @@ -565,16 +579,12 @@ int rsnd_adg_probe(struct rsnd_priv *priv) priv->adg = adg; + rsnd_adg_clk_enable(priv); + return 0; } void rsnd_adg_remove(struct rsnd_priv *priv) { - struct rsnd_adg *adg = rsnd_priv_to_adg(priv); - struct clk *clk; - int i; - - for_each_rsnd_clk(clk, adg, i) { - clk_disable_unprepare(clk); - } + rsnd_adg_clk_disable(priv); } diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 825635aaf30e..4bd68de76130 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -1308,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev) return ret; } +static int rsnd_suspend(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_disable(priv); + + return 0; +} + +static int rsnd_resume(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_enable(priv); + + return 0; +} + +static struct dev_pm_ops rsnd_pm_ops = { + .suspend = rsnd_suspend, + .resume = rsnd_resume, +}; + static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", + .pm = &rsnd_pm_ops, .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 71158c8bc254..b90df77662df 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -499,6 +499,9 @@ int rsnd_adg_set_src_timesel_gen2(struct rsnd_mod *src_mod, unsigned int out_rate); int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +#define rsnd_adg_clk_enable(priv) rsnd_adg_clk_control(priv, 1) +#define rsnd_adg_clk_disable(priv) rsnd_adg_clk_control(priv, 0) +void rsnd_adg_clk_control(struct rsnd_priv *priv, int enable); /* * R-Car sound priv -- cgit v1.2.3-59-g8ed1b From b99258a3151a70da9b4125f940c4dcc091df84c1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 7 Dec 2016 00:28:11 +0000 Subject: ASoC: rsnd: setup BRGCKR/BRRA/BRRB when starting Current rsnd driver setups BRGCKR/BRRA/BRRB when .probe timing. But it breaks sound after Suspend/Resume. These should be setups every start timing. This patch is tested on R-Car Gen3 Salvator-X board Signed-off-by: Kuninori Morimoto Tested-by: Gaku Inami Signed-off-by: Mark Brown --- sound/soc/sh/rcar/adg.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 54b28fd502ef..85a33ac0a5c4 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c @@ -34,6 +34,9 @@ struct rsnd_adg { struct clk_onecell_data onecell; struct rsnd_mod mod; u32 flags; + u32 ckr; + u32 rbga; + u32 rbgb; int rbga_rate_for_441khz; /* RBGA */ int rbgb_rate_for_48khz; /* RBGB */ @@ -316,9 +319,11 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); struct rsnd_adg *adg = rsnd_priv_to_adg(priv); struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct clk *clk; int i; u32 data; + u32 ckr = 0; int sel_table[] = { [CLKA] = 0x1, [CLKB] = 0x2, @@ -360,15 +365,14 @@ found_clock: rsnd_adg_set_ssi_clk(ssi_mod, data); if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); - u32 ckr = 0; - if (0 == (rate % 8000)) ckr = 0x80000000; - - rsnd_mod_bset(adg_mod, BRGCKR, 0x80000000, ckr); } + rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, adg->ckr | ckr); + rsnd_mod_write(adg_mod, BRRA, adg->rbga); + rsnd_mod_write(adg_mod, BRRB, adg->rbgb); + dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), data, rate); @@ -421,7 +425,6 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, struct rsnd_adg *adg) { struct clk *clk; - struct rsnd_mod *adg_mod = rsnd_mod_get(adg); struct device *dev = rsnd_priv_to_dev(priv); struct device_node *np = dev->of_node; u32 ckr, rbgx, rbga, rbgb; @@ -546,9 +549,9 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, } } - rsnd_mod_bset(adg_mod, BRGCKR, 0x80FF0000, ckr); - rsnd_mod_write(adg_mod, BRRA, rbga); - rsnd_mod_write(adg_mod, BRRB, rbgb); + adg->ckr = ckr; + adg->rbga = rbga; + adg->rbgb = rbgb; for_each_rsnd_clkout(clk, adg, i) dev_dbg(dev, "clkout %d : %p : %ld\n", i, clk, clk_get_rate(clk)); -- cgit v1.2.3-59-g8ed1b From de7975c2a42de889e2b3fd2f7d46f899ad8ccd45 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 8 Dec 2016 16:44:14 +0800 Subject: ASoC: zte: spdif and i2s drivers are not zx296702 specific ZTE ZX SPDIF and I2S drivers can work on not only ZX296702 but also other ZTE ZX family SoCs like ZX296718, which is an arm64 platform. Let's make a few renaming and tweak the Kconfig a bit to get the drivers available for other ZTE ZX platforms. Signed-off-by: Shawn Guo Reviewed-by: Jun Nie Signed-off-by: Mark Brown --- sound/soc/zte/Kconfig | 16 +- sound/soc/zte/Makefile | 4 +- sound/soc/zte/zx-i2s.c | 436 +++++++++++++++++++++++++++++++++++++++++ sound/soc/zte/zx-spdif.c | 365 ++++++++++++++++++++++++++++++++++ sound/soc/zte/zx296702-i2s.c | 436 ----------------------------------------- sound/soc/zte/zx296702-spdif.c | 365 ---------------------------------- 6 files changed, 811 insertions(+), 811 deletions(-) create mode 100644 sound/soc/zte/zx-i2s.c create mode 100644 sound/soc/zte/zx-spdif.c delete mode 100644 sound/soc/zte/zx296702-i2s.c delete mode 100644 sound/soc/zte/zx296702-spdif.c (limited to 'sound') diff --git a/sound/soc/zte/Kconfig b/sound/soc/zte/Kconfig index c47eb25e441f..6d8a90d36315 100644 --- a/sound/soc/zte/Kconfig +++ b/sound/soc/zte/Kconfig @@ -1,17 +1,17 @@ -config ZX296702_SPDIF - tristate "ZX296702 spdif" - depends on SOC_ZX296702 || COMPILE_TEST +config ZX_SPDIF + tristate "ZTE ZX SPDIF Driver Support" + depends on ARCH_ZX || COMPILE_TEST depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to the - zx296702 spdif interface + ZTE ZX SPDIF interface -config ZX296702_I2S - tristate "ZX296702 i2s" - depends on SOC_ZX296702 || COMPILE_TEST +config ZX_I2S + tristate "ZTE ZX I2S Driver Support" + depends on ARCH_ZX || COMPILE_TEST depends on COMMON_CLK select SND_SOC_GENERIC_DMAENGINE_PCM help Say Y or M if you want to add support for codecs attached to the - zx296702 i2s interface + ZTE ZX I2S interface diff --git a/sound/soc/zte/Makefile b/sound/soc/zte/Makefile index 254ed2c8c1a0..77768f5fd10c 100644 --- a/sound/soc/zte/Makefile +++ b/sound/soc/zte/Makefile @@ -1,2 +1,2 @@ -obj-$(CONFIG_ZX296702_SPDIF) += zx296702-spdif.o -obj-$(CONFIG_ZX296702_I2S) += zx296702-i2s.o +obj-$(CONFIG_ZX_SPDIF) += zx-spdif.o +obj-$(CONFIG_ZX_I2S) += zx-i2s.o diff --git a/sound/soc/zte/zx-i2s.c b/sound/soc/zte/zx-i2s.c new file mode 100644 index 000000000000..1cad93dc1fcf --- /dev/null +++ b/sound/soc/zte/zx-i2s.c @@ -0,0 +1,436 @@ +/* + * Copyright (C) 2015 Linaro + * + * Author: Jun Nie + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ZX_I2S_PROCESS_CTRL 0x04 +#define ZX_I2S_TIMING_CTRL 0x08 +#define ZX_I2S_FIFO_CTRL 0x0C +#define ZX_I2S_FIFO_STATUS 0x10 +#define ZX_I2S_INT_EN 0x14 +#define ZX_I2S_INT_STATUS 0x18 +#define ZX_I2S_DATA 0x1C +#define ZX_I2S_FRAME_CNTR 0x20 + +#define I2S_DEAGULT_FIFO_THRES (0x10) +#define I2S_MAX_FIFO_THRES (0x20) + +#define ZX_I2S_PROCESS_TX_EN (1 << 0) +#define ZX_I2S_PROCESS_TX_DIS (0 << 0) +#define ZX_I2S_PROCESS_RX_EN (1 << 1) +#define ZX_I2S_PROCESS_RX_DIS (0 << 1) +#define ZX_I2S_PROCESS_I2S_EN (1 << 2) +#define ZX_I2S_PROCESS_I2S_DIS (0 << 2) + +#define ZX_I2S_TIMING_MAST (1 << 0) +#define ZX_I2S_TIMING_SLAVE (0 << 0) +#define ZX_I2S_TIMING_MS_MASK (1 << 0) +#define ZX_I2S_TIMING_LOOP (1 << 1) +#define ZX_I2S_TIMING_NOR (0 << 1) +#define ZX_I2S_TIMING_LOOP_MASK (1 << 1) +#define ZX_I2S_TIMING_PTNR (1 << 2) +#define ZX_I2S_TIMING_NTPR (0 << 2) +#define ZX_I2S_TIMING_PHASE_MASK (1 << 2) +#define ZX_I2S_TIMING_TDM (1 << 3) +#define ZX_I2S_TIMING_I2S (0 << 3) +#define ZX_I2S_TIMING_TIMING_MASK (1 << 3) +#define ZX_I2S_TIMING_LONG_SYNC (1 << 4) +#define ZX_I2S_TIMING_SHORT_SYNC (0 << 4) +#define ZX_I2S_TIMING_SYNC_MASK (1 << 4) +#define ZX_I2S_TIMING_TEAK_EN (1 << 5) +#define ZX_I2S_TIMING_TEAK_DIS (0 << 5) +#define ZX_I2S_TIMING_TEAK_MASK (1 << 5) +#define ZX_I2S_TIMING_STD_I2S (0 << 6) +#define ZX_I2S_TIMING_MSB_JUSTIF (1 << 6) +#define ZX_I2S_TIMING_LSB_JUSTIF (2 << 6) +#define ZX_I2S_TIMING_ALIGN_MASK (3 << 6) +#define ZX_I2S_TIMING_CHN_MASK (7 << 8) +#define ZX_I2S_TIMING_CHN(x) ((x - 1) << 8) +#define ZX_I2S_TIMING_LANE_MASK (3 << 11) +#define ZX_I2S_TIMING_LANE(x) ((x - 1) << 11) +#define ZX_I2S_TIMING_TSCFG_MASK (7 << 13) +#define ZX_I2S_TIMING_TSCFG(x) (x << 13) +#define ZX_I2S_TIMING_TS_WIDTH_MASK (0x1f << 16) +#define ZX_I2S_TIMING_TS_WIDTH(x) ((x - 1) << 16) +#define ZX_I2S_TIMING_DATA_SIZE_MASK (0x1f << 21) +#define ZX_I2S_TIMING_DATA_SIZE(x) ((x - 1) << 21) +#define ZX_I2S_TIMING_CFG_ERR_MASK (1 << 31) + +#define ZX_I2S_FIFO_CTRL_TX_RST (1 << 0) +#define ZX_I2S_FIFO_CTRL_TX_RST_MASK (1 << 0) +#define ZX_I2S_FIFO_CTRL_RX_RST (1 << 1) +#define ZX_I2S_FIFO_CTRL_RX_RST_MASK (1 << 1) +#define ZX_I2S_FIFO_CTRL_TX_DMA_EN (1 << 4) +#define ZX_I2S_FIFO_CTRL_TX_DMA_DIS (0 << 4) +#define ZX_I2S_FIFO_CTRL_TX_DMA_MASK (1 << 4) +#define ZX_I2S_FIFO_CTRL_RX_DMA_EN (1 << 5) +#define ZX_I2S_FIFO_CTRL_RX_DMA_DIS (0 << 5) +#define ZX_I2S_FIFO_CTRL_RX_DMA_MASK (1 << 5) +#define ZX_I2S_FIFO_CTRL_TX_THRES_MASK (0x1F << 8) +#define ZX_I2S_FIFO_CTRL_RX_THRES_MASK (0x1F << 16) + +#define CLK_RAT (32 * 4) + +struct zx_i2s_info { + struct snd_dmaengine_dai_dma_data dma_playback; + struct snd_dmaengine_dai_dma_data dma_capture; + struct clk *dai_clk; + void __iomem *reg_base; + int master; + resource_size_t mapbase; +}; + +static void zx_i2s_tx_en(void __iomem *base, bool on) +{ + unsigned long val; + + val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); + if (on) + val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN; + else + val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN); + writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); +} + +static void zx_i2s_rx_en(void __iomem *base, bool on) +{ + unsigned long val; + + val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); + if (on) + val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN; + else + val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN); + writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); +} + +static void zx_i2s_tx_dma_en(void __iomem *base, bool on) +{ + unsigned long val; + + val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); + val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8); + if (on) + val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN; + else + val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN; + writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); +} + +static void zx_i2s_rx_dma_en(void __iomem *base, bool on) +{ + unsigned long val; + + val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); + val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16); + if (on) + val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN; + else + val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN; + writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); +} + +#define ZX_I2S_RATES \ + (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define ZX_I2S_FMTBIT \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +static int zx_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); + + snd_soc_dai_set_drvdata(dai, zx_i2s); + zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA; + zx_i2s->dma_playback.maxburst = 16; + zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA; + zx_i2s->dma_capture.maxburst = 16; + snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback, + &zx_i2s->dma_capture); + return 0; +} + +static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) +{ + struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai); + unsigned long val; + + val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); + val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK | + ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK | + ZX_I2S_TIMING_MS_MASK); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S); + break; + case SND_SOC_DAIFMT_LEFT_J: + val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF); + break; + case SND_SOC_DAIFMT_RIGHT_J: + val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF); + break; + default: + dev_err(cpu_dai->dev, "Unknown i2s timeing\n"); + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + i2s->master = 1; + val |= ZX_I2S_TIMING_MAST; + break; + case SND_SOC_DAIFMT_CBS_CFS: + i2s->master = 0; + val |= ZX_I2S_TIMING_SLAVE; + break; + default: + dev_err(cpu_dai->dev, "Unknown master/slave format\n"); + return -EINVAL; + } + + writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); + return 0; +} + +static int zx_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *socdai) +{ + struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); + struct snd_dmaengine_dai_dma_data *dma_data; + unsigned int lane, ch_num, len, ret = 0; + unsigned long val, format; + unsigned long chn_cfg; + + dma_data = snd_soc_dai_get_dma_data(socdai, substream); + dma_data->addr_width = params_width(params) >> 3; + + val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); + val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | + ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK | + ZX_I2S_TIMING_TSCFG_MASK); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + format = 0; + len = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + format = 1; + len = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + format = 2; + len = 32; + break; + default: + dev_err(socdai->dev, "Unknown data format\n"); + return -EINVAL; + } + val |= ZX_I2S_TIMING_TS_WIDTH(len) | ZX_I2S_TIMING_DATA_SIZE(len); + + ch_num = params_channels(params); + switch (ch_num) { + case 1: + lane = 1; + chn_cfg = 2; + break; + case 2: + case 4: + case 6: + case 8: + lane = ch_num / 2; + chn_cfg = 3; + break; + default: + dev_err(socdai->dev, "Not support channel num %d\n", ch_num); + return -EINVAL; + } + val |= ZX_I2S_TIMING_LANE(lane); + val |= ZX_I2S_TIMING_TSCFG(chn_cfg); + val |= ZX_I2S_TIMING_CHN(ch_num); + writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); + + if (i2s->master) + ret = clk_set_rate(i2s->dai_clk, + params_rate(params) * ch_num * CLK_RAT); + return ret; +} + +static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); + int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (capture) + zx_i2s_rx_dma_en(zx_i2s->reg_base, true); + else + zx_i2s_tx_dma_en(zx_i2s->reg_base, true); + /* fall thru */ + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if (capture) + zx_i2s_rx_en(zx_i2s->reg_base, true); + else + zx_i2s_tx_en(zx_i2s->reg_base, true); + break; + + case SNDRV_PCM_TRIGGER_STOP: + if (capture) + zx_i2s_rx_dma_en(zx_i2s->reg_base, false); + else + zx_i2s_tx_dma_en(zx_i2s->reg_base, false); + /* fall thru */ + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if (capture) + zx_i2s_rx_en(zx_i2s->reg_base, false); + else + zx_i2s_tx_en(zx_i2s->reg_base, false); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int zx_i2s_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); + + return clk_prepare_enable(zx_i2s->dai_clk); +} + +static void zx_i2s_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); + + clk_disable_unprepare(zx_i2s->dai_clk); +} + +static struct snd_soc_dai_ops zx_i2s_dai_ops = { + .trigger = zx_i2s_trigger, + .hw_params = zx_i2s_hw_params, + .set_fmt = zx_i2s_set_fmt, + .startup = zx_i2s_startup, + .shutdown = zx_i2s_shutdown, +}; + +static const struct snd_soc_component_driver zx_i2s_component = { + .name = "zx-i2s", +}; + +static struct snd_soc_dai_driver zx_i2s_dai = { + .name = "zx-i2s-dai", + .id = 0, + .probe = zx_i2s_dai_probe, + .playback = { + .channels_min = 1, + .channels_max = 8, + .rates = ZX_I2S_RATES, + .formats = ZX_I2S_FMTBIT, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = ZX_I2S_RATES, + .formats = ZX_I2S_FMTBIT, + }, + .ops = &zx_i2s_dai_ops, +}; + +static int zx_i2s_probe(struct platform_device *pdev) +{ + struct resource *res; + struct zx_i2s_info *zx_i2s; + int ret; + + zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL); + if (!zx_i2s) + return -ENOMEM; + + zx_i2s->dai_clk = devm_clk_get(&pdev->dev, "tx"); + if (IS_ERR(zx_i2s->dai_clk)) { + dev_err(&pdev->dev, "Fail to get clk\n"); + return PTR_ERR(zx_i2s->dai_clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + zx_i2s->mapbase = res->start; + zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(zx_i2s->reg_base)) { + dev_err(&pdev->dev, "ioremap failed!\n"); + return PTR_ERR(zx_i2s->reg_base); + } + + writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); + platform_set_drvdata(pdev, zx_i2s); + + ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component, + &zx_i2s_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); + + return ret; +} + +static const struct of_device_id zx_i2s_dt_ids[] = { + { .compatible = "zte,zx296702-i2s", }, + {} +}; +MODULE_DEVICE_TABLE(of, zx_i2s_dt_ids); + +static struct platform_driver i2s_driver = { + .probe = zx_i2s_probe, + .driver = { + .name = "zx-i2s", + .of_match_table = zx_i2s_dt_ids, + }, +}; + +module_platform_driver(i2s_driver); + +MODULE_AUTHOR("Jun Nie "); +MODULE_DESCRIPTION("ZTE I2S SoC DAI"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/zte/zx-spdif.c b/sound/soc/zte/zx-spdif.c new file mode 100644 index 000000000000..26265ce4caca --- /dev/null +++ b/sound/soc/zte/zx-spdif.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2015 Linaro + * + * Author: Jun Nie + * + * License terms: GNU General Public License (GPL) version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZX_CTRL 0x04 +#define ZX_FIFOCTRL 0x08 +#define ZX_INT_STATUS 0x10 +#define ZX_INT_MASK 0x14 +#define ZX_DATA 0x18 +#define ZX_VALID_BIT 0x1c +#define ZX_CH_STA_1 0x20 +#define ZX_CH_STA_2 0x24 +#define ZX_CH_STA_3 0x28 +#define ZX_CH_STA_4 0x2c +#define ZX_CH_STA_5 0x30 +#define ZX_CH_STA_6 0x34 + +#define ZX_CTRL_MODA_16 (0 << 6) +#define ZX_CTRL_MODA_18 BIT(6) +#define ZX_CTRL_MODA_20 (2 << 6) +#define ZX_CTRL_MODA_24 (3 << 6) +#define ZX_CTRL_MODA_MASK (3 << 6) + +#define ZX_CTRL_ENB BIT(4) +#define ZX_CTRL_DNB (0 << 4) +#define ZX_CTRL_ENB_MASK BIT(4) + +#define ZX_CTRL_TX_OPEN BIT(0) +#define ZX_CTRL_TX_CLOSE (0 << 0) +#define ZX_CTRL_TX_MASK BIT(0) + +#define ZX_CTRL_OPEN (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB) +#define ZX_CTRL_CLOSE (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB) + +#define ZX_CTRL_DOUBLE_TRACK (0 << 8) +#define ZX_CTRL_LEFT_TRACK BIT(8) +#define ZX_CTRL_RIGHT_TRACK (2 << 8) +#define ZX_CTRL_TRACK_MASK (3 << 8) + +#define ZX_FIFOCTRL_TXTH_MASK (0x1f << 8) +#define ZX_FIFOCTRL_TXTH(x) (x << 8) +#define ZX_FIFOCTRL_TX_DMA_EN BIT(2) +#define ZX_FIFOCTRL_TX_DMA_DIS (0 << 2) +#define ZX_FIFOCTRL_TX_DMA_EN_MASK BIT(2) +#define ZX_FIFOCTRL_TX_FIFO_RST BIT(0) +#define ZX_FIFOCTRL_TX_FIFO_RST_MASK BIT(0) + +#define ZX_VALID_DOUBLE_TRACK (0 << 0) +#define ZX_VALID_LEFT_TRACK BIT(1) +#define ZX_VALID_RIGHT_TRACK (2 << 0) +#define ZX_VALID_TRACK_MASK (3 << 0) + +#define ZX_SPDIF_CLK_RAT (4 * 32) + +struct zx_spdif_info { + struct snd_dmaengine_dai_dma_data dma_data; + struct clk *dai_clk; + void __iomem *reg_base; + resource_size_t mapbase; +}; + +static int zx_spdif_dai_probe(struct snd_soc_dai *dai) +{ + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); + + snd_soc_dai_set_drvdata(dai, zx_spdif); + zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA; + zx_spdif->dma_data.maxburst = 8; + snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL); + return 0; +} + +static int zx_spdif_chanstats(void __iomem *base, unsigned int rate) +{ + u32 cstas1; + + switch (rate) { + case 22050: + cstas1 = IEC958_AES3_CON_FS_22050; + break; + case 24000: + cstas1 = IEC958_AES3_CON_FS_24000; + break; + case 32000: + cstas1 = IEC958_AES3_CON_FS_32000; + break; + case 44100: + cstas1 = IEC958_AES3_CON_FS_44100; + break; + case 48000: + cstas1 = IEC958_AES3_CON_FS_48000; + break; + case 88200: + cstas1 = IEC958_AES3_CON_FS_88200; + break; + case 96000: + cstas1 = IEC958_AES3_CON_FS_96000; + break; + case 176400: + cstas1 = IEC958_AES3_CON_FS_176400; + break; + case 192000: + cstas1 = IEC958_AES3_CON_FS_192000; + break; + default: + return -EINVAL; + } + cstas1 = cstas1 << 24; + cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT; + + writel_relaxed(cstas1, base + ZX_CH_STA_1); + return 0; +} + +static int zx_spdif_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *socdai) +{ + struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev); + struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai); + struct snd_dmaengine_dai_dma_data *dma_data = &zx_spdif->dma_data; + u32 val, ch_num, rate; + int ret; + + dma_data = snd_soc_dai_get_dma_data(socdai, substream); + dma_data->addr_width = params_width(params) >> 3; + + val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL); + val &= ~ZX_CTRL_MODA_MASK; + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + val |= ZX_CTRL_MODA_16; + break; + + case SNDRV_PCM_FORMAT_S18_3LE: + val |= ZX_CTRL_MODA_18; + break; + + case SNDRV_PCM_FORMAT_S20_3LE: + val |= ZX_CTRL_MODA_20; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + val |= ZX_CTRL_MODA_24; + break; + default: + dev_err(socdai->dev, "Format not support!\n"); + return -EINVAL; + } + + ch_num = params_channels(params); + if (ch_num == 2) + val |= ZX_CTRL_DOUBLE_TRACK; + else + val |= ZX_CTRL_LEFT_TRACK; + writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL); + + val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT); + val &= ~ZX_VALID_TRACK_MASK; + if (ch_num == 2) + val |= ZX_VALID_DOUBLE_TRACK; + else + val |= ZX_VALID_RIGHT_TRACK; + writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT); + + rate = params_rate(params); + ret = zx_spdif_chanstats(zx_spdif->reg_base, rate); + if (ret) + return ret; + return clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT); +} + +static void zx_spdif_cfg_tx(void __iomem *base, int on) +{ + u32 val; + + val = readl_relaxed(base + ZX_CTRL); + val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK); + val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE; + writel_relaxed(val, base + ZX_CTRL); + + val = readl_relaxed(base + ZX_FIFOCTRL); + val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK; + if (on) + val |= ZX_FIFOCTRL_TX_DMA_EN; + writel_relaxed(val, base + ZX_FIFOCTRL); +} + +static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + u32 val; + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); + int ret = 0; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL); + val |= ZX_FIFOCTRL_TX_FIFO_RST; + writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL); + /* fall thru */ + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + zx_spdif_cfg_tx(zx_spdif->reg_base, true); + break; + + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + zx_spdif_cfg_tx(zx_spdif->reg_base, false); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int zx_spdif_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); + + return clk_prepare_enable(zx_spdif->dai_clk); +} + +static void zx_spdif_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); + + clk_disable_unprepare(zx_spdif->dai_clk); +} + +#define ZX_RATES \ + (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) + +#define ZX_FORMAT \ + (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \ + | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) + +static struct snd_soc_dai_ops zx_spdif_dai_ops = { + .trigger = zx_spdif_trigger, + .startup = zx_spdif_startup, + .shutdown = zx_spdif_shutdown, + .hw_params = zx_spdif_hw_params, +}; + +static struct snd_soc_dai_driver zx_spdif_dai = { + .name = "spdif", + .id = 0, + .probe = zx_spdif_dai_probe, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = ZX_RATES, + .formats = ZX_FORMAT, + }, + .ops = &zx_spdif_dai_ops, +}; + +static const struct snd_soc_component_driver zx_spdif_component = { + .name = "spdif", +}; + +static void zx_spdif_dev_init(void __iomem *base) +{ + u32 val; + + writel_relaxed(0, base + ZX_CTRL); + writel_relaxed(0, base + ZX_INT_MASK); + writel_relaxed(0xf, base + ZX_INT_STATUS); + writel_relaxed(0x1, base + ZX_FIFOCTRL); + + val = readl_relaxed(base + ZX_FIFOCTRL); + val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK); + val |= ZX_FIFOCTRL_TXTH(8); + writel_relaxed(val, base + ZX_FIFOCTRL); +} + +static int zx_spdif_probe(struct platform_device *pdev) +{ + struct resource *res; + struct zx_spdif_info *zx_spdif; + int ret; + + zx_spdif = devm_kzalloc(&pdev->dev, sizeof(*zx_spdif), GFP_KERNEL); + if (!zx_spdif) + return -ENOMEM; + + zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx"); + if (IS_ERR(zx_spdif->dai_clk)) { + dev_err(&pdev->dev, "Fail to get clk\n"); + return PTR_ERR(zx_spdif->dai_clk); + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + zx_spdif->mapbase = res->start; + zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(zx_spdif->reg_base)) { + dev_err(&pdev->dev, "ioremap failed!\n"); + return PTR_ERR(zx_spdif->reg_base); + } + + zx_spdif_dev_init(zx_spdif->reg_base); + platform_set_drvdata(pdev, zx_spdif); + + ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component, + &zx_spdif_dai, 1); + if (ret) { + dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + if (ret) + dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); + + return ret; +} + +static const struct of_device_id zx_spdif_dt_ids[] = { + { .compatible = "zte,zx296702-spdif", }, + {} +}; +MODULE_DEVICE_TABLE(of, zx_spdif_dt_ids); + +static struct platform_driver spdif_driver = { + .probe = zx_spdif_probe, + .driver = { + .name = "zx-spdif", + .of_match_table = zx_spdif_dt_ids, + }, +}; + +module_platform_driver(spdif_driver); + +MODULE_AUTHOR("Jun Nie "); +MODULE_DESCRIPTION("ZTE SPDIF SoC DAI"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx296702-i2s.c deleted file mode 100644 index 1cad93dc1fcf..000000000000 --- a/sound/soc/zte/zx296702-i2s.c +++ /dev/null @@ -1,436 +0,0 @@ -/* - * Copyright (C) 2015 Linaro - * - * Author: Jun Nie - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define ZX_I2S_PROCESS_CTRL 0x04 -#define ZX_I2S_TIMING_CTRL 0x08 -#define ZX_I2S_FIFO_CTRL 0x0C -#define ZX_I2S_FIFO_STATUS 0x10 -#define ZX_I2S_INT_EN 0x14 -#define ZX_I2S_INT_STATUS 0x18 -#define ZX_I2S_DATA 0x1C -#define ZX_I2S_FRAME_CNTR 0x20 - -#define I2S_DEAGULT_FIFO_THRES (0x10) -#define I2S_MAX_FIFO_THRES (0x20) - -#define ZX_I2S_PROCESS_TX_EN (1 << 0) -#define ZX_I2S_PROCESS_TX_DIS (0 << 0) -#define ZX_I2S_PROCESS_RX_EN (1 << 1) -#define ZX_I2S_PROCESS_RX_DIS (0 << 1) -#define ZX_I2S_PROCESS_I2S_EN (1 << 2) -#define ZX_I2S_PROCESS_I2S_DIS (0 << 2) - -#define ZX_I2S_TIMING_MAST (1 << 0) -#define ZX_I2S_TIMING_SLAVE (0 << 0) -#define ZX_I2S_TIMING_MS_MASK (1 << 0) -#define ZX_I2S_TIMING_LOOP (1 << 1) -#define ZX_I2S_TIMING_NOR (0 << 1) -#define ZX_I2S_TIMING_LOOP_MASK (1 << 1) -#define ZX_I2S_TIMING_PTNR (1 << 2) -#define ZX_I2S_TIMING_NTPR (0 << 2) -#define ZX_I2S_TIMING_PHASE_MASK (1 << 2) -#define ZX_I2S_TIMING_TDM (1 << 3) -#define ZX_I2S_TIMING_I2S (0 << 3) -#define ZX_I2S_TIMING_TIMING_MASK (1 << 3) -#define ZX_I2S_TIMING_LONG_SYNC (1 << 4) -#define ZX_I2S_TIMING_SHORT_SYNC (0 << 4) -#define ZX_I2S_TIMING_SYNC_MASK (1 << 4) -#define ZX_I2S_TIMING_TEAK_EN (1 << 5) -#define ZX_I2S_TIMING_TEAK_DIS (0 << 5) -#define ZX_I2S_TIMING_TEAK_MASK (1 << 5) -#define ZX_I2S_TIMING_STD_I2S (0 << 6) -#define ZX_I2S_TIMING_MSB_JUSTIF (1 << 6) -#define ZX_I2S_TIMING_LSB_JUSTIF (2 << 6) -#define ZX_I2S_TIMING_ALIGN_MASK (3 << 6) -#define ZX_I2S_TIMING_CHN_MASK (7 << 8) -#define ZX_I2S_TIMING_CHN(x) ((x - 1) << 8) -#define ZX_I2S_TIMING_LANE_MASK (3 << 11) -#define ZX_I2S_TIMING_LANE(x) ((x - 1) << 11) -#define ZX_I2S_TIMING_TSCFG_MASK (7 << 13) -#define ZX_I2S_TIMING_TSCFG(x) (x << 13) -#define ZX_I2S_TIMING_TS_WIDTH_MASK (0x1f << 16) -#define ZX_I2S_TIMING_TS_WIDTH(x) ((x - 1) << 16) -#define ZX_I2S_TIMING_DATA_SIZE_MASK (0x1f << 21) -#define ZX_I2S_TIMING_DATA_SIZE(x) ((x - 1) << 21) -#define ZX_I2S_TIMING_CFG_ERR_MASK (1 << 31) - -#define ZX_I2S_FIFO_CTRL_TX_RST (1 << 0) -#define ZX_I2S_FIFO_CTRL_TX_RST_MASK (1 << 0) -#define ZX_I2S_FIFO_CTRL_RX_RST (1 << 1) -#define ZX_I2S_FIFO_CTRL_RX_RST_MASK (1 << 1) -#define ZX_I2S_FIFO_CTRL_TX_DMA_EN (1 << 4) -#define ZX_I2S_FIFO_CTRL_TX_DMA_DIS (0 << 4) -#define ZX_I2S_FIFO_CTRL_TX_DMA_MASK (1 << 4) -#define ZX_I2S_FIFO_CTRL_RX_DMA_EN (1 << 5) -#define ZX_I2S_FIFO_CTRL_RX_DMA_DIS (0 << 5) -#define ZX_I2S_FIFO_CTRL_RX_DMA_MASK (1 << 5) -#define ZX_I2S_FIFO_CTRL_TX_THRES_MASK (0x1F << 8) -#define ZX_I2S_FIFO_CTRL_RX_THRES_MASK (0x1F << 16) - -#define CLK_RAT (32 * 4) - -struct zx_i2s_info { - struct snd_dmaengine_dai_dma_data dma_playback; - struct snd_dmaengine_dai_dma_data dma_capture; - struct clk *dai_clk; - void __iomem *reg_base; - int master; - resource_size_t mapbase; -}; - -static void zx_i2s_tx_en(void __iomem *base, bool on) -{ - unsigned long val; - - val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); - if (on) - val |= ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN; - else - val &= ~(ZX_I2S_PROCESS_TX_EN | ZX_I2S_PROCESS_I2S_EN); - writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); -} - -static void zx_i2s_rx_en(void __iomem *base, bool on) -{ - unsigned long val; - - val = readl_relaxed(base + ZX_I2S_PROCESS_CTRL); - if (on) - val |= ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN; - else - val &= ~(ZX_I2S_PROCESS_RX_EN | ZX_I2S_PROCESS_I2S_EN); - writel_relaxed(val, base + ZX_I2S_PROCESS_CTRL); -} - -static void zx_i2s_tx_dma_en(void __iomem *base, bool on) -{ - unsigned long val; - - val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); - val |= ZX_I2S_FIFO_CTRL_TX_RST | (I2S_DEAGULT_FIFO_THRES << 8); - if (on) - val |= ZX_I2S_FIFO_CTRL_TX_DMA_EN; - else - val &= ~ZX_I2S_FIFO_CTRL_TX_DMA_EN; - writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); -} - -static void zx_i2s_rx_dma_en(void __iomem *base, bool on) -{ - unsigned long val; - - val = readl_relaxed(base + ZX_I2S_FIFO_CTRL); - val |= ZX_I2S_FIFO_CTRL_RX_RST | (I2S_DEAGULT_FIFO_THRES << 16); - if (on) - val |= ZX_I2S_FIFO_CTRL_RX_DMA_EN; - else - val &= ~ZX_I2S_FIFO_CTRL_RX_DMA_EN; - writel_relaxed(val, base + ZX_I2S_FIFO_CTRL); -} - -#define ZX_I2S_RATES \ - (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \ - SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000| \ - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) - -#define ZX_I2S_FMTBIT \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \ - SNDRV_PCM_FMTBIT_S32_LE) - -static int zx_i2s_dai_probe(struct snd_soc_dai *dai) -{ - struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); - - snd_soc_dai_set_drvdata(dai, zx_i2s); - zx_i2s->dma_playback.addr = zx_i2s->mapbase + ZX_I2S_DATA; - zx_i2s->dma_playback.maxburst = 16; - zx_i2s->dma_capture.addr = zx_i2s->mapbase + ZX_I2S_DATA; - zx_i2s->dma_capture.maxburst = 16; - snd_soc_dai_init_dma_data(dai, &zx_i2s->dma_playback, - &zx_i2s->dma_capture); - return 0; -} - -static int zx_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(cpu_dai); - unsigned long val; - - val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); - val &= ~(ZX_I2S_TIMING_TIMING_MASK | ZX_I2S_TIMING_ALIGN_MASK | - ZX_I2S_TIMING_TEAK_MASK | ZX_I2S_TIMING_SYNC_MASK | - ZX_I2S_TIMING_MS_MASK); - - switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { - case SND_SOC_DAIFMT_I2S: - val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_STD_I2S); - break; - case SND_SOC_DAIFMT_LEFT_J: - val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_MSB_JUSTIF); - break; - case SND_SOC_DAIFMT_RIGHT_J: - val |= (ZX_I2S_TIMING_I2S | ZX_I2S_TIMING_LSB_JUSTIF); - break; - default: - dev_err(cpu_dai->dev, "Unknown i2s timeing\n"); - return -EINVAL; - } - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - i2s->master = 1; - val |= ZX_I2S_TIMING_MAST; - break; - case SND_SOC_DAIFMT_CBS_CFS: - i2s->master = 0; - val |= ZX_I2S_TIMING_SLAVE; - break; - default: - dev_err(cpu_dai->dev, "Unknown master/slave format\n"); - return -EINVAL; - } - - writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); - return 0; -} - -static int zx_i2s_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *socdai) -{ - struct zx_i2s_info *i2s = snd_soc_dai_get_drvdata(socdai); - struct snd_dmaengine_dai_dma_data *dma_data; - unsigned int lane, ch_num, len, ret = 0; - unsigned long val, format; - unsigned long chn_cfg; - - dma_data = snd_soc_dai_get_dma_data(socdai, substream); - dma_data->addr_width = params_width(params) >> 3; - - val = readl_relaxed(i2s->reg_base + ZX_I2S_TIMING_CTRL); - val &= ~(ZX_I2S_TIMING_TS_WIDTH_MASK | ZX_I2S_TIMING_DATA_SIZE_MASK | - ZX_I2S_TIMING_LANE_MASK | ZX_I2S_TIMING_CHN_MASK | - ZX_I2S_TIMING_TSCFG_MASK); - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - format = 0; - len = 16; - break; - case SNDRV_PCM_FORMAT_S24_LE: - format = 1; - len = 24; - break; - case SNDRV_PCM_FORMAT_S32_LE: - format = 2; - len = 32; - break; - default: - dev_err(socdai->dev, "Unknown data format\n"); - return -EINVAL; - } - val |= ZX_I2S_TIMING_TS_WIDTH(len) | ZX_I2S_TIMING_DATA_SIZE(len); - - ch_num = params_channels(params); - switch (ch_num) { - case 1: - lane = 1; - chn_cfg = 2; - break; - case 2: - case 4: - case 6: - case 8: - lane = ch_num / 2; - chn_cfg = 3; - break; - default: - dev_err(socdai->dev, "Not support channel num %d\n", ch_num); - return -EINVAL; - } - val |= ZX_I2S_TIMING_LANE(lane); - val |= ZX_I2S_TIMING_TSCFG(chn_cfg); - val |= ZX_I2S_TIMING_CHN(ch_num); - writel_relaxed(val, i2s->reg_base + ZX_I2S_TIMING_CTRL); - - if (i2s->master) - ret = clk_set_rate(i2s->dai_clk, - params_rate(params) * ch_num * CLK_RAT); - return ret; -} - -static int zx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); - int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (capture) - zx_i2s_rx_dma_en(zx_i2s->reg_base, true); - else - zx_i2s_tx_dma_en(zx_i2s->reg_base, true); - /* fall thru */ - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (capture) - zx_i2s_rx_en(zx_i2s->reg_base, true); - else - zx_i2s_tx_en(zx_i2s->reg_base, true); - break; - - case SNDRV_PCM_TRIGGER_STOP: - if (capture) - zx_i2s_rx_dma_en(zx_i2s->reg_base, false); - else - zx_i2s_tx_dma_en(zx_i2s->reg_base, false); - /* fall thru */ - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (capture) - zx_i2s_rx_en(zx_i2s->reg_base, false); - else - zx_i2s_tx_en(zx_i2s->reg_base, false); - break; - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int zx_i2s_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); - - return clk_prepare_enable(zx_i2s->dai_clk); -} - -static void zx_i2s_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct zx_i2s_info *zx_i2s = dev_get_drvdata(dai->dev); - - clk_disable_unprepare(zx_i2s->dai_clk); -} - -static struct snd_soc_dai_ops zx_i2s_dai_ops = { - .trigger = zx_i2s_trigger, - .hw_params = zx_i2s_hw_params, - .set_fmt = zx_i2s_set_fmt, - .startup = zx_i2s_startup, - .shutdown = zx_i2s_shutdown, -}; - -static const struct snd_soc_component_driver zx_i2s_component = { - .name = "zx-i2s", -}; - -static struct snd_soc_dai_driver zx_i2s_dai = { - .name = "zx-i2s-dai", - .id = 0, - .probe = zx_i2s_dai_probe, - .playback = { - .channels_min = 1, - .channels_max = 8, - .rates = ZX_I2S_RATES, - .formats = ZX_I2S_FMTBIT, - }, - .capture = { - .channels_min = 1, - .channels_max = 2, - .rates = ZX_I2S_RATES, - .formats = ZX_I2S_FMTBIT, - }, - .ops = &zx_i2s_dai_ops, -}; - -static int zx_i2s_probe(struct platform_device *pdev) -{ - struct resource *res; - struct zx_i2s_info *zx_i2s; - int ret; - - zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL); - if (!zx_i2s) - return -ENOMEM; - - zx_i2s->dai_clk = devm_clk_get(&pdev->dev, "tx"); - if (IS_ERR(zx_i2s->dai_clk)) { - dev_err(&pdev->dev, "Fail to get clk\n"); - return PTR_ERR(zx_i2s->dai_clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - zx_i2s->mapbase = res->start; - zx_i2s->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(zx_i2s->reg_base)) { - dev_err(&pdev->dev, "ioremap failed!\n"); - return PTR_ERR(zx_i2s->reg_base); - } - - writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); - platform_set_drvdata(pdev, zx_i2s); - - ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component, - &zx_i2s_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); - return ret; - } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); - if (ret) - dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); - - return ret; -} - -static const struct of_device_id zx_i2s_dt_ids[] = { - { .compatible = "zte,zx296702-i2s", }, - {} -}; -MODULE_DEVICE_TABLE(of, zx_i2s_dt_ids); - -static struct platform_driver i2s_driver = { - .probe = zx_i2s_probe, - .driver = { - .name = "zx-i2s", - .of_match_table = zx_i2s_dt_ids, - }, -}; - -module_platform_driver(i2s_driver); - -MODULE_AUTHOR("Jun Nie "); -MODULE_DESCRIPTION("ZTE I2S SoC DAI"); -MODULE_LICENSE("GPL"); diff --git a/sound/soc/zte/zx296702-spdif.c b/sound/soc/zte/zx296702-spdif.c deleted file mode 100644 index 26265ce4caca..000000000000 --- a/sound/soc/zte/zx296702-spdif.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright (C) 2015 Linaro - * - * Author: Jun Nie - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ZX_CTRL 0x04 -#define ZX_FIFOCTRL 0x08 -#define ZX_INT_STATUS 0x10 -#define ZX_INT_MASK 0x14 -#define ZX_DATA 0x18 -#define ZX_VALID_BIT 0x1c -#define ZX_CH_STA_1 0x20 -#define ZX_CH_STA_2 0x24 -#define ZX_CH_STA_3 0x28 -#define ZX_CH_STA_4 0x2c -#define ZX_CH_STA_5 0x30 -#define ZX_CH_STA_6 0x34 - -#define ZX_CTRL_MODA_16 (0 << 6) -#define ZX_CTRL_MODA_18 BIT(6) -#define ZX_CTRL_MODA_20 (2 << 6) -#define ZX_CTRL_MODA_24 (3 << 6) -#define ZX_CTRL_MODA_MASK (3 << 6) - -#define ZX_CTRL_ENB BIT(4) -#define ZX_CTRL_DNB (0 << 4) -#define ZX_CTRL_ENB_MASK BIT(4) - -#define ZX_CTRL_TX_OPEN BIT(0) -#define ZX_CTRL_TX_CLOSE (0 << 0) -#define ZX_CTRL_TX_MASK BIT(0) - -#define ZX_CTRL_OPEN (ZX_CTRL_TX_OPEN | ZX_CTRL_ENB) -#define ZX_CTRL_CLOSE (ZX_CTRL_TX_CLOSE | ZX_CTRL_DNB) - -#define ZX_CTRL_DOUBLE_TRACK (0 << 8) -#define ZX_CTRL_LEFT_TRACK BIT(8) -#define ZX_CTRL_RIGHT_TRACK (2 << 8) -#define ZX_CTRL_TRACK_MASK (3 << 8) - -#define ZX_FIFOCTRL_TXTH_MASK (0x1f << 8) -#define ZX_FIFOCTRL_TXTH(x) (x << 8) -#define ZX_FIFOCTRL_TX_DMA_EN BIT(2) -#define ZX_FIFOCTRL_TX_DMA_DIS (0 << 2) -#define ZX_FIFOCTRL_TX_DMA_EN_MASK BIT(2) -#define ZX_FIFOCTRL_TX_FIFO_RST BIT(0) -#define ZX_FIFOCTRL_TX_FIFO_RST_MASK BIT(0) - -#define ZX_VALID_DOUBLE_TRACK (0 << 0) -#define ZX_VALID_LEFT_TRACK BIT(1) -#define ZX_VALID_RIGHT_TRACK (2 << 0) -#define ZX_VALID_TRACK_MASK (3 << 0) - -#define ZX_SPDIF_CLK_RAT (4 * 32) - -struct zx_spdif_info { - struct snd_dmaengine_dai_dma_data dma_data; - struct clk *dai_clk; - void __iomem *reg_base; - resource_size_t mapbase; -}; - -static int zx_spdif_dai_probe(struct snd_soc_dai *dai) -{ - struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); - - snd_soc_dai_set_drvdata(dai, zx_spdif); - zx_spdif->dma_data.addr = zx_spdif->mapbase + ZX_DATA; - zx_spdif->dma_data.maxburst = 8; - snd_soc_dai_init_dma_data(dai, &zx_spdif->dma_data, NULL); - return 0; -} - -static int zx_spdif_chanstats(void __iomem *base, unsigned int rate) -{ - u32 cstas1; - - switch (rate) { - case 22050: - cstas1 = IEC958_AES3_CON_FS_22050; - break; - case 24000: - cstas1 = IEC958_AES3_CON_FS_24000; - break; - case 32000: - cstas1 = IEC958_AES3_CON_FS_32000; - break; - case 44100: - cstas1 = IEC958_AES3_CON_FS_44100; - break; - case 48000: - cstas1 = IEC958_AES3_CON_FS_48000; - break; - case 88200: - cstas1 = IEC958_AES3_CON_FS_88200; - break; - case 96000: - cstas1 = IEC958_AES3_CON_FS_96000; - break; - case 176400: - cstas1 = IEC958_AES3_CON_FS_176400; - break; - case 192000: - cstas1 = IEC958_AES3_CON_FS_192000; - break; - default: - return -EINVAL; - } - cstas1 = cstas1 << 24; - cstas1 |= IEC958_AES0_CON_NOT_COPYRIGHT; - - writel_relaxed(cstas1, base + ZX_CH_STA_1); - return 0; -} - -static int zx_spdif_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *socdai) -{ - struct zx_spdif_info *zx_spdif = dev_get_drvdata(socdai->dev); - struct zx_spdif_info *spdif = snd_soc_dai_get_drvdata(socdai); - struct snd_dmaengine_dai_dma_data *dma_data = &zx_spdif->dma_data; - u32 val, ch_num, rate; - int ret; - - dma_data = snd_soc_dai_get_dma_data(socdai, substream); - dma_data->addr_width = params_width(params) >> 3; - - val = readl_relaxed(zx_spdif->reg_base + ZX_CTRL); - val &= ~ZX_CTRL_MODA_MASK; - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_S16_LE: - val |= ZX_CTRL_MODA_16; - break; - - case SNDRV_PCM_FORMAT_S18_3LE: - val |= ZX_CTRL_MODA_18; - break; - - case SNDRV_PCM_FORMAT_S20_3LE: - val |= ZX_CTRL_MODA_20; - break; - - case SNDRV_PCM_FORMAT_S24_LE: - val |= ZX_CTRL_MODA_24; - break; - default: - dev_err(socdai->dev, "Format not support!\n"); - return -EINVAL; - } - - ch_num = params_channels(params); - if (ch_num == 2) - val |= ZX_CTRL_DOUBLE_TRACK; - else - val |= ZX_CTRL_LEFT_TRACK; - writel_relaxed(val, zx_spdif->reg_base + ZX_CTRL); - - val = readl_relaxed(zx_spdif->reg_base + ZX_VALID_BIT); - val &= ~ZX_VALID_TRACK_MASK; - if (ch_num == 2) - val |= ZX_VALID_DOUBLE_TRACK; - else - val |= ZX_VALID_RIGHT_TRACK; - writel_relaxed(val, zx_spdif->reg_base + ZX_VALID_BIT); - - rate = params_rate(params); - ret = zx_spdif_chanstats(zx_spdif->reg_base, rate); - if (ret) - return ret; - return clk_set_rate(spdif->dai_clk, rate * ch_num * ZX_SPDIF_CLK_RAT); -} - -static void zx_spdif_cfg_tx(void __iomem *base, int on) -{ - u32 val; - - val = readl_relaxed(base + ZX_CTRL); - val &= ~(ZX_CTRL_ENB_MASK | ZX_CTRL_TX_MASK); - val |= on ? ZX_CTRL_OPEN : ZX_CTRL_CLOSE; - writel_relaxed(val, base + ZX_CTRL); - - val = readl_relaxed(base + ZX_FIFOCTRL); - val &= ~ZX_FIFOCTRL_TX_DMA_EN_MASK; - if (on) - val |= ZX_FIFOCTRL_TX_DMA_EN; - writel_relaxed(val, base + ZX_FIFOCTRL); -} - -static int zx_spdif_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - u32 val; - struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - val = readl_relaxed(zx_spdif->reg_base + ZX_FIFOCTRL); - val |= ZX_FIFOCTRL_TX_FIFO_RST; - writel_relaxed(val, zx_spdif->reg_base + ZX_FIFOCTRL); - /* fall thru */ - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - zx_spdif_cfg_tx(zx_spdif->reg_base, true); - break; - - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - zx_spdif_cfg_tx(zx_spdif->reg_base, false); - break; - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int zx_spdif_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); - - return clk_prepare_enable(zx_spdif->dai_clk); -} - -static void zx_spdif_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct zx_spdif_info *zx_spdif = dev_get_drvdata(dai->dev); - - clk_disable_unprepare(zx_spdif->dai_clk); -} - -#define ZX_RATES \ - (SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ - SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |\ - SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000) - -#define ZX_FORMAT \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE \ - | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) - -static struct snd_soc_dai_ops zx_spdif_dai_ops = { - .trigger = zx_spdif_trigger, - .startup = zx_spdif_startup, - .shutdown = zx_spdif_shutdown, - .hw_params = zx_spdif_hw_params, -}; - -static struct snd_soc_dai_driver zx_spdif_dai = { - .name = "spdif", - .id = 0, - .probe = zx_spdif_dai_probe, - .playback = { - .channels_min = 1, - .channels_max = 2, - .rates = ZX_RATES, - .formats = ZX_FORMAT, - }, - .ops = &zx_spdif_dai_ops, -}; - -static const struct snd_soc_component_driver zx_spdif_component = { - .name = "spdif", -}; - -static void zx_spdif_dev_init(void __iomem *base) -{ - u32 val; - - writel_relaxed(0, base + ZX_CTRL); - writel_relaxed(0, base + ZX_INT_MASK); - writel_relaxed(0xf, base + ZX_INT_STATUS); - writel_relaxed(0x1, base + ZX_FIFOCTRL); - - val = readl_relaxed(base + ZX_FIFOCTRL); - val &= ~(ZX_FIFOCTRL_TXTH_MASK | ZX_FIFOCTRL_TX_FIFO_RST_MASK); - val |= ZX_FIFOCTRL_TXTH(8); - writel_relaxed(val, base + ZX_FIFOCTRL); -} - -static int zx_spdif_probe(struct platform_device *pdev) -{ - struct resource *res; - struct zx_spdif_info *zx_spdif; - int ret; - - zx_spdif = devm_kzalloc(&pdev->dev, sizeof(*zx_spdif), GFP_KERNEL); - if (!zx_spdif) - return -ENOMEM; - - zx_spdif->dai_clk = devm_clk_get(&pdev->dev, "tx"); - if (IS_ERR(zx_spdif->dai_clk)) { - dev_err(&pdev->dev, "Fail to get clk\n"); - return PTR_ERR(zx_spdif->dai_clk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - zx_spdif->mapbase = res->start; - zx_spdif->reg_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(zx_spdif->reg_base)) { - dev_err(&pdev->dev, "ioremap failed!\n"); - return PTR_ERR(zx_spdif->reg_base); - } - - zx_spdif_dev_init(zx_spdif->reg_base); - platform_set_drvdata(pdev, zx_spdif); - - ret = devm_snd_soc_register_component(&pdev->dev, &zx_spdif_component, - &zx_spdif_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); - return ret; - } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); - if (ret) - dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); - - return ret; -} - -static const struct of_device_id zx_spdif_dt_ids[] = { - { .compatible = "zte,zx296702-spdif", }, - {} -}; -MODULE_DEVICE_TABLE(of, zx_spdif_dt_ids); - -static struct platform_driver spdif_driver = { - .probe = zx_spdif_probe, - .driver = { - .name = "zx-spdif", - .of_match_table = zx_spdif_dt_ids, - }, -}; - -module_platform_driver(spdif_driver); - -MODULE_AUTHOR("Jun Nie "); -MODULE_DESCRIPTION("ZTE SPDIF SoC DAI"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 44b1c9a6e7a2692e761e35ada2ffe84b20c2a377 Mon Sep 17 00:00:00 2001 From: Shawn Guo Date: Thu, 8 Dec 2016 16:44:15 +0800 Subject: ASoC: zte: spdif: correct ZX_SPDIF_CLK_RAT define The macro ZX_SPDIF_CLK_RAT should be 2 instead of 4. With this fix, we can get correct audio output on HDMI through SPDIF interface. Signed-off-by: Shawn Guo Acked-by: Jun Nie Signed-off-by: Mark Brown --- sound/soc/zte/zx-spdif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/zte/zx-spdif.c b/sound/soc/zte/zx-spdif.c index 26265ce4caca..9fa6463ce5d7 100644 --- a/sound/soc/zte/zx-spdif.c +++ b/sound/soc/zte/zx-spdif.c @@ -71,7 +71,7 @@ #define ZX_VALID_RIGHT_TRACK (2 << 0) #define ZX_VALID_TRACK_MASK (3 << 0) -#define ZX_SPDIF_CLK_RAT (4 * 32) +#define ZX_SPDIF_CLK_RAT (2 * 32) struct zx_spdif_info { struct snd_dmaengine_dai_dma_data dma_data; -- cgit v1.2.3-59-g8ed1b From 17f08b0d9aafccdb10038ab6dbd9ddb6433c13e2 Mon Sep 17 00:00:00 2001 From: Alberto Aguirre Date: Thu, 8 Dec 2016 00:36:48 -0600 Subject: ALSA: usb-audio: add implicit fb quirk for Axe-Fx II The Axe-Fx II implicit feedback end point and the data sync endpoint are in different interface descriptors. Add quirk to ensure a sync endpoint is properly configured. Signed-off-by: Alberto Aguirre Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index a522c9af1f34..34c6d4f2c0b6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -348,6 +348,16 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, alts = &iface->altsetting[1]; goto add_sync_ep; + case USB_ID(0x2466, 0x8003): + ep = 0x86; + iface = usb_ifnum_to_if(dev, 2); + + if (!iface || iface->num_altsetting == 0) + return -EINVAL; + + alts = &iface->altsetting[1]; + goto add_sync_ep; + } if (attr == USB_ENDPOINT_SYNC_ASYNC && altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && -- cgit v1.2.3-59-g8ed1b From 82ffb6fc637150b279f49e174166d2aa3853eaf4 Mon Sep 17 00:00:00 2001 From: Con Kolivas Date: Fri, 9 Dec 2016 15:15:57 +1100 Subject: ALSA: usb-audio: Add QuickCam Communicate Deluxe/S7500 to volume_control_quirks The Logitech QuickCam Communicate Deluxe/S7500 microphone fails with the following warning. [ 6.778995] usb 2-1.2.2.2: Warning! Unlikely big volume range (=3072), cval->res is probably wrong. [ 6.778996] usb 2-1.2.2.2: [5] FU [Mic Capture Volume] ch = 1, val = 4608/7680/1 Adding it to the list of devices in volume_control_quirks makes it work properly, fixing related typo. Signed-off-by: Con Kolivas Cc: Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 2f8c388ef84f..4703caea56b2 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -932,9 +932,10 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, case USB_ID(0x046d, 0x0826): /* HD Webcam c525 */ case USB_ID(0x046d, 0x08ca): /* Logitech Quickcam Fusion */ case USB_ID(0x046d, 0x0991): + case USB_ID(0x046d, 0x09a2): /* QuickCam Communicate Deluxe/S7500 */ /* Most audio usb devices lie about volume resolution. * Most Logitech webcams have res = 384. - * Proboly there is some logitech magic behind this number --fishor + * Probably there is some logitech magic behind this number --fishor */ if (!strcmp(kctl->id.name, "Mic Capture Volume")) { usb_audio_info(chip, -- cgit v1.2.3-59-g8ed1b From dd5abb742071a962be4403f171063ed1e9d4202d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Dec 2016 12:51:46 +0100 Subject: ASoC: topology: avoid uninitialized kcontrol_type When num_kcontrols is zero, widget->dobj.widget.kcontrol_type gets set to an uninitialized local variable: sound/soc/soc-topology.c: In function 'soc_tplg_dapm_widget_create': sound/soc/soc-topology.c:1566:36: error: 'kcontrol_type' may be used uninitialized in this function [-Werror=maybe-uninitialized] I could not figure out which of the valid types would be appropriate here, so this sets it to '0', which is invalid but at least well-defined here. There is probably a better way to address the issue. Fixes: eea3dd4f1247 ("ASoC: topology: Only free TLV for volume mixers of a widget") Signed-off-by: Arnd Bergmann Reported-by: Dan Carpenter Reviewed-by: Takashi Sakamoto Signed-off-by: Mark Brown --- sound/soc/soc-topology.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 11feb19e9730..65670b2b408c 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1485,6 +1485,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, tplg->pos += (sizeof(struct snd_soc_tplg_dapm_widget) + w->priv.size); if (w->num_kcontrols == 0) { + kcontrol_type = 0; template.num_kcontrols = 0; goto widget; } -- cgit v1.2.3-59-g8ed1b From 4d41c74dcb6778ae92d985e4d32055345c3a1fed Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Fri, 9 Dec 2016 09:57:41 +0000 Subject: ASoC: wm_adsp: wm_adsp_buf_alloc should use kfree in error path buf was allocated by kzalloc() so it should be passed to kfree() Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/wm_adsp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index ff111a82fa3f..593b7d1aed46 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c @@ -187,7 +187,7 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, buf->buf = vmalloc(len); if (!buf->buf) { - vfree(buf); + kfree(buf); return NULL; } memcpy(buf->buf, src, len); -- cgit v1.2.3-59-g8ed1b From 7f38ca047b0cb54df7f6d9e4110e292e45dba6ad Mon Sep 17 00:00:00 2001 From: Nobutaka Okabe Date: Tue, 13 Dec 2016 01:24:08 +0900 Subject: ALSA: usb-audio: Add native DSD support for TEAC 501/503 DAC This patch adds native DSD support for the following devices. - TEAC NT-503 - TEAC UD-503 - TEAC UD-501 (1) Add quirks for native DSD support for TEAC devices. (2) A specific vendor command is needed to switch between PCM/DOP and DSD mode, same as Denon/Marantz devices. Signed-off-by: Nobutaka Okabe Signed-off-by: Takashi Iwai --- sound/usb/quirks.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'sound') diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 2782155ae3ce..b3fd2382fdd9 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1165,6 +1165,18 @@ static bool is_marantz_denon_dac(unsigned int id) return false; } +/* TEAC UD-501/UD-503/NT-503 USB DACs need a vendor cmd to switch + * between PCM/DOP and native DSD mode + */ +static bool is_teac_50X_dac(unsigned int id) +{ + switch (id) { + case USB_ID(0x0644, 0x8043): /* TEAC UD-501/UD-503/NT-503 */ + return true; + } + return false; +} + int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, struct audioformat *fmt) { @@ -1192,6 +1204,26 @@ int snd_usb_select_mode_quirk(struct snd_usb_substream *subs, break; } mdelay(20); + } else if (is_teac_50X_dac(subs->stream->chip->usb_id)) { + /* Vendor mode switch cmd is required. */ + switch (fmt->altsetting) { + case 3: /* DSD mode (DSD_U32) requested */ + err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 1, 1, NULL, 0); + if (err < 0) + return err; + break; + + case 2: /* PCM or DOP mode (S32) requested */ + case 1: /* PCM mode (S16) requested */ + err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0, + USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE, + 0, 1, NULL, 0); + if (err < 0) + return err; + break; + } } return 0; } @@ -1337,5 +1369,11 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, return SNDRV_PCM_FMTBIT_DSD_U32_BE; } + /* TEAC devices with USB DAC functionality */ + if (is_teac_50X_dac(chip->usb_id)) { + if (fp->altsetting == 3) + return SNDRV_PCM_FMTBIT_DSD_U32_BE; + } + return 0; } -- cgit v1.2.3-59-g8ed1b From 012007309133d21a5a7eae3f552c03ac061a2b51 Mon Sep 17 00:00:00 2001 From: Nobutaka Okabe Date: Tue, 13 Dec 2016 02:52:58 +0900 Subject: ALSA: usb-audio: Eliminate noise at the start of DSD playback. [Problem] In some USB DACs, a terrible pop noise comes to be heard at the start of DSD playback (in the following situations). - play first DSD track - change from PCM track to DSD track - change from DSD64 track to DSD128 track (and etc...) - seek DSD track - Fast-Forward/Rewind DSD track [Cause] At the start of playback, there is a little silence. The silence bit pattern "0x69" is required on DSD mode, but it is not like that. [Solution] This patch adds DSD silence pattern to the endpoint settings. Signed-off-by: Nobutaka Okabe Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 57b0d9968ec2..a2cdf3370afe 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -638,7 +638,21 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, ep->datainterval = fmt->datainterval; ep->stride = frame_bits >> 3; - ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; + + switch (pcm_format) { + case SNDRV_PCM_FORMAT_U8: + ep->silence_value = 0x80; + break; + case SNDRV_PCM_FORMAT_DSD_U8: + case SNDRV_PCM_FORMAT_DSD_U16_LE: + case SNDRV_PCM_FORMAT_DSD_U32_LE: + case SNDRV_PCM_FORMAT_DSD_U16_BE: + case SNDRV_PCM_FORMAT_DSD_U32_BE: + ep->silence_value = 0x69; + break; + default: + ep->silence_value = 0; + } /* assume max. frequency is 50% higher than nominal */ ep->freqmax = ep->freqn + (ep->freqn >> 1); -- cgit v1.2.3-59-g8ed1b From 995c6a7fd9b9212abdf01160f6ce3193176be503 Mon Sep 17 00:00:00 2001 From: Jussi Laako Date: Mon, 28 Nov 2016 11:27:45 +0200 Subject: ALSA: hiface: Fix M2Tech hiFace driver sampling rate change Sampling rate changes after first set one are not reflected to the hardware, while driver and ALSA think the rate has been changed. Fix the problem by properly stopping the interface at the beginning of prepare call, allowing new rate to be set to the hardware. This keeps the hardware in sync with the driver. Signed-off-by: Jussi Laako Cc: Signed-off-by: Takashi Iwai --- sound/usb/hiface/pcm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/usb/hiface/pcm.c b/sound/usb/hiface/pcm.c index 2c44139b4041..33db205dd12b 100644 --- a/sound/usb/hiface/pcm.c +++ b/sound/usb/hiface/pcm.c @@ -445,6 +445,8 @@ static int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) mutex_lock(&rt->stream_mutex); + hiface_pcm_stream_stop(rt); + sub->dma_off = 0; sub->period_off = 0; -- cgit v1.2.3-59-g8ed1b