diff options
Diffstat (limited to 'sound/soc/codecs/twl4030.c')
-rw-r--r-- | sound/soc/codecs/twl4030.c | 477 |
1 files changed, 171 insertions, 306 deletions
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index dfc51bb425da..975e0f760ac1 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -48,86 +48,6 @@ #define TWL4030_CACHEREGNUM (TWL4030_REG_MISC_SET_2 + 1) -/* - * twl4030 register cache & default register settings - */ -static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { - 0x00, /* this register not used */ - 0x00, /* REG_CODEC_MODE (0x1) */ - 0x00, /* REG_OPTION (0x2) */ - 0x00, /* REG_UNKNOWN (0x3) */ - 0x00, /* REG_MICBIAS_CTL (0x4) */ - 0x00, /* REG_ANAMICL (0x5) */ - 0x00, /* REG_ANAMICR (0x6) */ - 0x00, /* REG_AVADC_CTL (0x7) */ - 0x00, /* REG_ADCMICSEL (0x8) */ - 0x00, /* REG_DIGMIXING (0x9) */ - 0x0f, /* REG_ATXL1PGA (0xA) */ - 0x0f, /* REG_ATXR1PGA (0xB) */ - 0x0f, /* REG_AVTXL2PGA (0xC) */ - 0x0f, /* REG_AVTXR2PGA (0xD) */ - 0x00, /* REG_AUDIO_IF (0xE) */ - 0x00, /* REG_VOICE_IF (0xF) */ - 0x3f, /* REG_ARXR1PGA (0x10) */ - 0x3f, /* REG_ARXL1PGA (0x11) */ - 0x3f, /* REG_ARXR2PGA (0x12) */ - 0x3f, /* REG_ARXL2PGA (0x13) */ - 0x25, /* REG_VRXPGA (0x14) */ - 0x00, /* REG_VSTPGA (0x15) */ - 0x00, /* REG_VRX2ARXPGA (0x16) */ - 0x00, /* REG_AVDAC_CTL (0x17) */ - 0x00, /* REG_ARX2VTXPGA (0x18) */ - 0x32, /* REG_ARXL1_APGA_CTL (0x19) */ - 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */ - 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */ - 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */ - 0x00, /* REG_ATX2ARXPGA (0x1D) */ - 0x00, /* REG_BT_IF (0x1E) */ - 0x55, /* REG_BTPGA (0x1F) */ - 0x00, /* REG_BTSTPGA (0x20) */ - 0x00, /* REG_EAR_CTL (0x21) */ - 0x00, /* REG_HS_SEL (0x22) */ - 0x00, /* REG_HS_GAIN_SET (0x23) */ - 0x00, /* REG_HS_POPN_SET (0x24) */ - 0x00, /* REG_PREDL_CTL (0x25) */ - 0x00, /* REG_PREDR_CTL (0x26) */ - 0x00, /* REG_PRECKL_CTL (0x27) */ - 0x00, /* REG_PRECKR_CTL (0x28) */ - 0x00, /* REG_HFL_CTL (0x29) */ - 0x00, /* REG_HFR_CTL (0x2A) */ - 0x05, /* REG_ALC_CTL (0x2B) */ - 0x00, /* REG_ALC_SET1 (0x2C) */ - 0x00, /* REG_ALC_SET2 (0x2D) */ - 0x00, /* REG_BOOST_CTL (0x2E) */ - 0x00, /* REG_SOFTVOL_CTL (0x2F) */ - 0x13, /* REG_DTMF_FREQSEL (0x30) */ - 0x00, /* REG_DTMF_TONEXT1H (0x31) */ - 0x00, /* REG_DTMF_TONEXT1L (0x32) */ - 0x00, /* REG_DTMF_TONEXT2H (0x33) */ - 0x00, /* REG_DTMF_TONEXT2L (0x34) */ - 0x79, /* REG_DTMF_TONOFF (0x35) */ - 0x11, /* REG_DTMF_WANONOFF (0x36) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ - 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ - 0x06, /* REG_APLL_CTL (0x3A) */ - 0x00, /* REG_DTMF_CTL (0x3B) */ - 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */ - 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */ - 0x00, /* REG_MISC_SET_1 (0x3E) */ - 0x00, /* REG_PCMBTMUX (0x3F) */ - 0x00, /* not used (0x40) */ - 0x00, /* not used (0x41) */ - 0x00, /* not used (0x42) */ - 0x00, /* REG_RX_PATH_SEL (0x43) */ - 0x32, /* REG_VDL_APGA_CTL (0x44) */ - 0x00, /* REG_VIBRA_CTL (0x45) */ - 0x00, /* REG_VIBRA_SET (0x46) */ - 0x00, /* REG_VIBRA_PWM_SET (0x47) */ - 0x00, /* REG_ANAMIC_GAIN (0x48) */ - 0x00, /* REG_MISC_SET_2 (0x49) */ -}; - /* codec private data */ struct twl4030_priv { unsigned int codec_powered; @@ -150,81 +70,108 @@ struct twl4030_priv { u8 earpiece_enabled; u8 predrivel_enabled, predriver_enabled; u8 carkitl_enabled, carkitr_enabled; + u8 ctl_cache[TWL4030_REG_PRECKR_CTL - TWL4030_REG_EAR_CTL + 1]; struct twl4030_codec_data *pdata; }; -/* - * read twl4030 register cache - */ -static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) +static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) { - u8 *cache = codec->reg_cache; - - if (reg >= TWL4030_CACHEREGNUM) - return -EIO; + int i; + u8 byte; - return cache[reg]; + for (i = TWL4030_REG_EAR_CTL; i <= TWL4030_REG_PRECKR_CTL; i++) { + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, i); + twl4030->ctl_cache[i - TWL4030_REG_EAR_CTL] = byte; + } } -/* - * write twl4030 register cache - */ -static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, u8 value) +static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg) { - u8 *cache = codec->reg_cache; + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); + u8 value = 0; if (reg >= TWL4030_CACHEREGNUM) - return; - cache[reg] = value; + return -EIO; + + switch (reg) { + case TWL4030_REG_EAR_CTL: + case TWL4030_REG_PREDL_CTL: + case TWL4030_REG_PREDR_CTL: + case TWL4030_REG_PRECKL_CTL: + case TWL4030_REG_PRECKR_CTL: + case TWL4030_REG_HS_GAIN_SET: + value = twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL]; + break; + default: + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &value, reg); + break; + } + + return value; } -/* - * write to the twl4030 register space - */ -static int twl4030_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030, + unsigned int reg) { - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); - int write_to_reg = 0; + bool write_to_reg = false; - twl4030_write_reg_cache(codec, reg, value); /* Decide if the given register can be written */ switch (reg) { case TWL4030_REG_EAR_CTL: if (twl4030->earpiece_enabled) - write_to_reg = 1; + write_to_reg = true; break; case TWL4030_REG_PREDL_CTL: if (twl4030->predrivel_enabled) - write_to_reg = 1; + write_to_reg = true; break; case TWL4030_REG_PREDR_CTL: if (twl4030->predriver_enabled) - write_to_reg = 1; + write_to_reg = true; break; case TWL4030_REG_PRECKL_CTL: if (twl4030->carkitl_enabled) - write_to_reg = 1; + write_to_reg = true; break; case TWL4030_REG_PRECKR_CTL: if (twl4030->carkitr_enabled) - write_to_reg = 1; + write_to_reg = true; break; case TWL4030_REG_HS_GAIN_SET: if (twl4030->hsl_enabled || twl4030->hsr_enabled) - write_to_reg = 1; + write_to_reg = true; break; default: /* All other register can be written */ - write_to_reg = 1; + write_to_reg = true; break; } - if (write_to_reg) - return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - value, reg); + + return write_to_reg; +} + +static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); + + /* Update the ctl cache */ + switch (reg) { + case TWL4030_REG_EAR_CTL: + case TWL4030_REG_PREDL_CTL: + case TWL4030_REG_PREDR_CTL: + case TWL4030_REG_PRECKL_CTL: + case TWL4030_REG_PRECKR_CTL: + case TWL4030_REG_HS_GAIN_SET: + twl4030->ctl_cache[reg - TWL4030_REG_EAR_CTL] = value; + break; + default: + break; + } + + if (twl4030_can_write_to_chip(twl4030, reg)) + return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); return 0; } @@ -252,46 +199,14 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) else mode = twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER); - if (mode >= 0) { - twl4030_write_reg_cache(codec, TWL4030_REG_CODEC_MODE, mode); + if (mode >= 0) twl4030->codec_powered = enable; - } /* REVISIT: this delay is present in TI sample drivers */ /* but there seems to be no TRM requirement for it */ udelay(10); } -static inline void twl4030_check_defaults(struct snd_soc_codec *codec) -{ - int i, difference = 0; - u8 val; - - dev_dbg(codec->dev, "Checking TWL audio default configuration\n"); - for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) { - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i); - if (val != twl4030_reg[i]) { - difference++; - dev_dbg(codec->dev, - "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n", - i, val, twl4030_reg[i]); - } - } - dev_dbg(codec->dev, "Found %d non-matching registers. %s\n", - difference, difference ? "Not OK" : "OK"); -} - -static inline void twl4030_reset_registers(struct snd_soc_codec *codec) -{ - int i; - - /* set all audio section registers to reasonable defaults */ - for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) - if (i != TWL4030_REG_APLL_CTL) - twl4030_write(codec, i, twl4030_reg[i]); - -} - static void twl4030_setup_pdata_of(struct twl4030_codec_data *pdata, struct device_node *node) { @@ -372,27 +287,17 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } } - /* Check defaults, if instructed before anything else */ - if (pdata && pdata->check_defaults) - twl4030_check_defaults(codec); - - /* Reset registers, if no setup data or if instructed to do so */ - if (!pdata || (pdata && pdata->reset_registers)) - twl4030_reset_registers(codec); - - /* Refresh APLL_CTL register from HW */ - twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, - TWL4030_REG_APLL_CTL); - twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte); + /* Initialize the local ctl register cache */ + tw4030_init_ctl_cache(twl4030); /* anti-pop when changing analog gain */ - reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); + reg = twl4030_read(codec, TWL4030_REG_MISC_SET_1); twl4030_write(codec, TWL4030_REG_MISC_SET_1, - reg | TWL4030_SMOOTH_ANAVOL_EN); + reg | TWL4030_SMOOTH_ANAVOL_EN); twl4030_write(codec, TWL4030_REG_OPTION, - TWL4030_ATXL1_EN | TWL4030_ATXR1_EN | - TWL4030_ARXL2_EN | TWL4030_ARXR2_EN); + TWL4030_ATXL1_EN | TWL4030_ATXR1_EN | + TWL4030_ARXL2_EN | TWL4030_ARXR2_EN); /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */ twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32); @@ -403,19 +308,19 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) twl4030->pdata = pdata; - reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + reg = twl4030_read(codec, TWL4030_REG_HS_POPN_SET); reg &= ~TWL4030_RAMP_DELAY; reg |= (pdata->ramp_delay_value << 2); - twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg); + twl4030_write(codec, TWL4030_REG_HS_POPN_SET, reg); /* initiate offset cancellation */ twl4030_codec_enable(codec, 1); - reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); + reg = twl4030_read(codec, TWL4030_REG_ANAMICL); reg &= ~TWL4030_OFFSET_CNCL_SEL; reg |= pdata->offset_cncl_path; twl4030_write(codec, TWL4030_REG_ANAMICL, - reg | TWL4030_CNCL_OFFSET_START); + reg | TWL4030_CNCL_OFFSET_START); /* * Wait for offset cancellation to complete. @@ -425,15 +330,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) msleep(20); do { usleep_range(1000, 2000); + twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, true); twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, - TWL4030_REG_ANAMICL); + TWL4030_REG_ANAMICL); + twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, false); } while ((i++ < 100) && ((byte & TWL4030_CNCL_OFFSET_START) == TWL4030_CNCL_OFFSET_START)); - /* Make sure that the reg_cache has the same value as the HW */ - twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); - twl4030_codec_enable(codec, 0); } @@ -453,9 +357,6 @@ static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) status = twl4030_audio_disable_resource( TWL4030_AUDIO_RES_APLL); } - - if (status >= 0) - twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); } /* Earpiece */ @@ -514,10 +415,9 @@ static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = { static const char *twl4030_handsfreel_texts[] = {"Voice", "AudioL1", "AudioL2", "AudioR2"}; -static const struct soc_enum twl4030_handsfreel_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, - ARRAY_SIZE(twl4030_handsfreel_texts), - twl4030_handsfreel_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_handsfreel_enum, + TWL4030_REG_HFL_CTL, 0, + twl4030_handsfreel_texts); static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); @@ -530,10 +430,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = static const char *twl4030_handsfreer_texts[] = {"Voice", "AudioR1", "AudioR2", "AudioL2"}; -static const struct soc_enum twl4030_handsfreer_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, - ARRAY_SIZE(twl4030_handsfreer_texts), - twl4030_handsfreer_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_handsfreer_enum, + TWL4030_REG_HFR_CTL, 0, + twl4030_handsfreer_texts); static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); @@ -547,10 +446,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = static const char *twl4030_vibra_texts[] = {"AudioL1", "AudioR1", "AudioL2", "AudioR2"}; -static const struct soc_enum twl4030_vibra_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2, - ARRAY_SIZE(twl4030_vibra_texts), - twl4030_vibra_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibra_enum, + TWL4030_REG_VIBRA_CTL, 2, + twl4030_vibra_texts); static const struct snd_kcontrol_new twl4030_dapm_vibra_control = SOC_DAPM_ENUM("Route", twl4030_vibra_enum); @@ -559,10 +457,9 @@ SOC_DAPM_ENUM("Route", twl4030_vibra_enum); static const char *twl4030_vibrapath_texts[] = {"Local vibrator", "Audio"}; -static const struct soc_enum twl4030_vibrapath_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4, - ARRAY_SIZE(twl4030_vibrapath_texts), - twl4030_vibrapath_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibrapath_enum, + TWL4030_REG_VIBRA_CTL, 4, + twl4030_vibrapath_texts); static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control = SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); @@ -589,10 +486,9 @@ static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { static const char *twl4030_micpathtx1_texts[] = {"Analog", "Digimic0"}; -static const struct soc_enum twl4030_micpathtx1_enum = - SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 0, - ARRAY_SIZE(twl4030_micpathtx1_texts), - twl4030_micpathtx1_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx1_enum, + TWL4030_REG_ADCMICSEL, 0, + twl4030_micpathtx1_texts); static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control = SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); @@ -601,10 +497,9 @@ SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); static const char *twl4030_micpathtx2_texts[] = {"Analog", "Digimic1"}; -static const struct soc_enum twl4030_micpathtx2_enum = - SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 2, - ARRAY_SIZE(twl4030_micpathtx2_texts), - twl4030_micpathtx2_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx2_enum, + TWL4030_REG_ADCMICSEL, 2, + twl4030_micpathtx2_texts); static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); @@ -671,20 +566,18 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = */ #define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ - struct snd_kcontrol *kcontrol, int event) \ + struct snd_kcontrol *kcontrol, int event) \ { \ struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \ \ switch (event) { \ case SND_SOC_DAPM_POST_PMU: \ twl4030->pin_name##_enabled = 1; \ - twl4030_write(w->codec, reg, \ - twl4030_read_reg_cache(w->codec, reg)); \ + twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \ break; \ case SND_SOC_DAPM_POST_PMD: \ twl4030->pin_name##_enabled = 0; \ - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \ - 0, reg); \ + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, 0, reg); \ break; \ } \ return 0; \ @@ -700,7 +593,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) { unsigned char hs_ctl; - hs_ctl = twl4030_read_reg_cache(codec, reg); + hs_ctl = twl4030_read(codec, reg); if (ramp) { /* HF ramp-up */ @@ -727,7 +620,7 @@ static void handsfree_ramp(struct snd_soc_codec *codec, int reg, int ramp) } static int handsfreelpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -741,7 +634,7 @@ static int handsfreelpga_event(struct snd_soc_dapm_widget *w, } static int handsfreerpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -755,14 +648,14 @@ static int handsfreerpga_event(struct snd_soc_dapm_widget *w, } static int vibramux_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { twl4030_write(w->codec, TWL4030_REG_VIBRA_SET, 0xff); return 0; } static int apll_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { switch (event) { case SND_SOC_DAPM_PRE_PMU: @@ -776,11 +669,11 @@ static int apll_event(struct snd_soc_dapm_widget *w, } static int aif_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { u8 audio_if; - audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF); + audio_if = twl4030_read(w->codec, TWL4030_REG_AUDIO_IF); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Enable AIF */ @@ -788,12 +681,12 @@ static int aif_event(struct snd_soc_dapm_widget *w, twl4030_apll_enable(w->codec, 1); twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, - audio_if | TWL4030_AIF_EN); + audio_if | TWL4030_AIF_EN); break; case SND_SOC_DAPM_POST_PMD: /* disable the DAI before we stop it's source PLL */ twl4030_write(w->codec, TWL4030_REG_AUDIO_IF, - audio_if & ~TWL4030_AIF_EN); + audio_if & ~TWL4030_AIF_EN); twl4030_apll_enable(w->codec, 0); break; } @@ -810,8 +703,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) 8388608, 16777216, 33554432, 67108864}; unsigned int delay; - hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET); - hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); + hs_gain = twl4030_read(codec, TWL4030_REG_HS_GAIN_SET); + hs_pop = twl4030_read(codec, TWL4030_REG_HS_POPN_SET); delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / twl4030->sysclk) + 1; @@ -831,9 +724,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) hs_pop |= TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); /* Actually write to the register */ - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - hs_gain, - TWL4030_REG_HS_GAIN_SET); + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain, + TWL4030_REG_HS_GAIN_SET); hs_pop |= TWL4030_RAMP_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); /* Wait ramp delay time + 1, so the VMID can settle */ @@ -846,9 +738,8 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) /* Wait ramp delay time + 1, so the VMID can settle */ twl4030_wait_ms(delay); /* Bypass the reg_cache to mute the headset */ - twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, - hs_gain & (~0x0f), - TWL4030_REG_HS_GAIN_SET); + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f), + TWL4030_REG_HS_GAIN_SET); hs_pop &= ~TWL4030_VMID_EN; twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop); @@ -866,7 +757,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) } static int headsetlpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); @@ -890,7 +781,7 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w, } static int headsetrpga_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); @@ -914,7 +805,7 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w, } static int digimic_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) + struct snd_kcontrol *kcontrol, int event) { struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); struct twl4030_codec_data *pdata = twl4030->pdata; @@ -935,7 +826,7 @@ static int digimic_event(struct snd_soc_dapm_widget *w, * Custom volsw and volsw_2r get/put functions to handle these gain bits. */ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -964,7 +855,7 @@ static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, } static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -993,7 +884,7 @@ static int snd_soc_put_volsw_twl4030(struct snd_kcontrol *kcontrol, } static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -1020,7 +911,7 @@ static int snd_soc_get_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, } static int snd_soc_put_volsw_r2_twl4030(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; @@ -1058,19 +949,15 @@ static const char *twl4030_op_modes_texts[] = { "Option 2 (voice/audio)", "Option 1 (audio)" }; -static const struct soc_enum twl4030_op_modes_enum = - SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0, - ARRAY_SIZE(twl4030_op_modes_texts), - twl4030_op_modes_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum, + TWL4030_REG_CODEC_MODE, 0, + twl4030_op_modes_texts); static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned short val; - unsigned short mask; if (twl4030->configured) { dev_err(codec->dev, @@ -1078,19 +965,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, return -EBUSY; } - if (ucontrol->value.enumerated.item[0] > e->max - 1) - return -EINVAL; - - val = ucontrol->value.enumerated.item[0] << e->shift_l; - mask = e->mask << e->shift_l; - if (e->shift_l != e->shift_r) { - if (ucontrol->value.enumerated.item[1] > e->max - 1) - return -EINVAL; - val |= ucontrol->value.enumerated.item[1] << e->shift_r; - mask |= e->mask << e->shift_r; - } - - return snd_soc_update_bits(codec, e->reg, mask, val); + return snd_soc_put_enum_double(kcontrol, ucontrol); } /* @@ -1147,10 +1022,9 @@ static const char *twl4030_avadc_clk_priority_texts[] = { "Voice high priority", "HiFi high priority" }; -static const struct soc_enum twl4030_avadc_clk_priority_enum = - SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2, - ARRAY_SIZE(twl4030_avadc_clk_priority_texts), - twl4030_avadc_clk_priority_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_avadc_clk_priority_enum, + TWL4030_REG_AVADC_CTL, 2, + twl4030_avadc_clk_priority_texts); static const char *twl4030_rampdelay_texts[] = { "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", @@ -1158,40 +1032,36 @@ static const char *twl4030_rampdelay_texts[] = { "3495/2581/1748 ms" }; -static const struct soc_enum twl4030_rampdelay_enum = - SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2, - ARRAY_SIZE(twl4030_rampdelay_texts), - twl4030_rampdelay_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_rampdelay_enum, + TWL4030_REG_HS_POPN_SET, 2, + twl4030_rampdelay_texts); /* Vibra H-bridge direction mode */ static const char *twl4030_vibradirmode_texts[] = { "Vibra H-bridge direction", "Audio data MSB", }; -static const struct soc_enum twl4030_vibradirmode_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5, - ARRAY_SIZE(twl4030_vibradirmode_texts), - twl4030_vibradirmode_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibradirmode_enum, + TWL4030_REG_VIBRA_CTL, 5, + twl4030_vibradirmode_texts); /* Vibra H-bridge direction */ static const char *twl4030_vibradir_texts[] = { "Positive polarity", "Negative polarity", }; -static const struct soc_enum twl4030_vibradir_enum = - SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1, - ARRAY_SIZE(twl4030_vibradir_texts), - twl4030_vibradir_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_vibradir_enum, + TWL4030_REG_VIBRA_CTL, 1, + twl4030_vibradir_texts); /* Digimic Left and right swapping */ static const char *twl4030_digimicswap_texts[] = { "Not swapped", "Swapped", }; -static const struct soc_enum twl4030_digimicswap_enum = - SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0, - ARRAY_SIZE(twl4030_digimicswap_texts), - twl4030_digimicswap_texts); +static SOC_ENUM_SINGLE_DECL(twl4030_digimicswap_enum, + TWL4030_REG_MISC_SET_1, 0, + twl4030_digimicswap_texts); static const struct snd_kcontrol_new twl4030_snd_controls[] = { /* Codec operation mode control */ @@ -1751,11 +1621,11 @@ static void twl4030_constraints(struct twl4030_priv *twl4030, /* In case of 4 channel mode, the RX1 L/R for playback and the TX2 L/R for * capture has to be enabled/disabled. */ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, - int enable) + int enable) { u8 reg, mask; - reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); + reg = twl4030_read(codec, TWL4030_REG_OPTION); if (direction == SNDRV_PCM_STREAM_PLAYBACK) mask = TWL4030_ARXL1_VRX_EN | TWL4030_ARXR1_EN; @@ -1784,14 +1654,14 @@ static int twl4030_startup(struct snd_pcm_substream *substream, if (twl4030->configured) twl4030_constraints(twl4030, twl4030->master_substream); } else { - if (!(twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) & + if (!(twl4030_read(codec, TWL4030_REG_CODEC_MODE) & TWL4030_OPTION_1)) { /* In option2 4 channel is not supported, set the * constraint for the first stream for channels, the * second stream will 'inherit' this cosntraint */ snd_pcm_hw_constraint_minmax(substream->runtime, - SNDRV_PCM_HW_PARAM_CHANNELS, - 2, 2); + SNDRV_PCM_HW_PARAM_CHANNELS, + 2, 2); } twl4030->master_substream = substream; } @@ -1823,8 +1693,8 @@ static void twl4030_shutdown(struct snd_pcm_substream *substream, } static int twl4030_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -1832,8 +1702,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, /* If the substream has 4 channel, do the necessary setup */ if (params_channels(params) == 4) { - format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE); + format = twl4030_read(codec, TWL4030_REG_AUDIO_IF); + mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE); /* Safety check: are we in the correct operating mode and * the interface is in TDM mode? */ @@ -1849,8 +1719,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, return 0; /* bit rate */ - old_mode = twl4030_read_reg_cache(codec, - TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; + old_mode = twl4030_read(codec, + TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; mode = old_mode & ~TWL4030_APLL_RATE; switch (params_rate(params)) { @@ -1891,7 +1761,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, } /* sample size */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF); format = old_format; format &= ~TWL4030_DATA_WIDTH; switch (params_format(params)) { @@ -1940,8 +1810,8 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, return 0; } -static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) +static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, int clk_id, + unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -1966,15 +1836,14 @@ static int twl4030_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0; } -static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) +static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); u8 old_format, format; /* get format */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + old_format = twl4030_read(codec, TWL4030_REG_AUDIO_IF); format = old_format; /* set master/slave audio interface */ @@ -2024,7 +1893,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate) { struct snd_soc_codec *codec = dai->codec; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); + u8 reg = twl4030_read(codec, TWL4030_REG_AUDIO_IF); if (tristate) reg |= TWL4030_AIF_TRI_EN; @@ -2037,11 +1906,11 @@ static int twl4030_set_tristate(struct snd_soc_dai *dai, int tristate) /* In case of voice mode, the RX1 L(VRX) for downlink and the TX2 L/R * (VTXL, VTXR) for uplink has to be enabled/disabled. */ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, - int enable) + int enable) { u8 reg, mask; - reg = twl4030_read_reg_cache(codec, TWL4030_REG_OPTION); + reg = twl4030_read(codec, TWL4030_REG_OPTION); if (direction == SNDRV_PCM_STREAM_PLAYBACK) mask = TWL4030_ARXL1_VRX_EN; @@ -2057,7 +1926,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, } static int twl4030_voice_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -2076,7 +1945,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, /* If the codec mode is not option2, the voice PCM interface is not * available. */ - mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) + mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE) & TWL4030_OPT_MODE; if (mode != TWL4030_OPTION_2) { @@ -2089,7 +1958,7 @@ static int twl4030_voice_startup(struct snd_pcm_substream *substream, } static void twl4030_voice_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) + struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; @@ -2098,7 +1967,8 @@ static void twl4030_voice_shutdown(struct snd_pcm_substream *substream, } static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -2108,8 +1978,8 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, twl4030_voice_enable(codec, substream->stream, 1); /* bit rate */ - old_mode = twl4030_read_reg_cache(codec, TWL4030_REG_CODEC_MODE) - & ~(TWL4030_CODECPDZ); + old_mode = twl4030_read(codec, + TWL4030_REG_CODEC_MODE) & ~TWL4030_CODECPDZ; mode = old_mode; switch (params_rate(params)) { @@ -2143,7 +2013,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, } static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, - int clk_id, unsigned int freq, int dir) + int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -2164,14 +2034,14 @@ static int twl4030_voice_set_dai_sysclk(struct snd_soc_dai *codec_dai, } static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, - unsigned int fmt) + unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); u8 old_format, format; /* get format */ - old_format = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); + old_format = twl4030_read(codec, TWL4030_REG_VOICE_IF); format = old_format; /* set master/slave audio interface */ @@ -2218,7 +2088,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate) { struct snd_soc_codec *codec = dai->codec; - u8 reg = twl4030_read_reg_cache(codec, TWL4030_REG_VOICE_IF); + u8 reg = twl4030_read(codec, TWL4030_REG_VOICE_IF); if (tristate) reg |= TWL4030_VIF_TRI_EN; @@ -2310,8 +2180,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); struct twl4030_codec_data *pdata = twl4030->pdata; - /* Reset registers to their chip default before leaving */ - twl4030_reset_registers(codec); twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) @@ -2323,13 +2191,10 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { .probe = twl4030_soc_probe, .remove = twl4030_soc_remove, - .read = twl4030_read_reg_cache, + .read = twl4030_read, .write = twl4030_write, .set_bias_level = twl4030_set_bias_level, .idle_bias_off = true, - .reg_cache_size = sizeof(twl4030_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = twl4030_reg, .controls = twl4030_snd_controls, .num_controls = ARRAY_SIZE(twl4030_snd_controls), @@ -2342,7 +2207,7 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = { static int twl4030_codec_probe(struct platform_device *pdev) { return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_twl4030, - twl4030_dai, ARRAY_SIZE(twl4030_dai)); + twl4030_dai, ARRAY_SIZE(twl4030_dai)); } static int twl4030_codec_remove(struct platform_device *pdev) |