[alsa-devel] [PATCH 00/11] ASoC/MFD: twl4030 codec local register cache removal
Hi,
After the twl6040 codec, now it is time for the twl4030 codec driver to loose it's local reg cache and let the MFD core's regmap to take care of the caching.
We have different functions behind of the 0x49 i2c address in twl (where the audio registers can be found between 0x01 - 0x49). I mark all non audio registers as volatile for now to avoid any side effect of the caching. Gradually other functionalities can also move their caching to regmap to simplify the code.
I have included couple of clean up patches after the local regcache removal to the series to freshen up the code a bit.
Regards, Peter --- Peter Ujfalusi (11): MFD: twl-core: Simplify IO wrapper functions by moving common code out MFD: twl-core: API to set the regcache bypass for a given regmap in twl MFD: twl-core: Enable regcache for audio registers ASoC: twl4030: Separate write condition checking from I/O function ASoC: twl4030: Remove check defaults functionality ASoC: twl4030: Remove reset registers functionality ASoC: twl4030: Introduce local ctl register cache ASoC: twl4030: Remove local reg cache ASoC: twl4030: Parameter alignment fixes (for code consistency) ASoC: twl4030: Move the ctl cache update local to twl4030_write() function ASoC: twl4030: Pass the twl4030_priv directly to twl4030_can_write_to_chip()
drivers/mfd/twl-core.c | 190 +++++++++++++++++++---- include/linux/i2c/twl.h | 5 +- sound/soc/codecs/twl4030.c | 376 ++++++++++++++++----------------------------- 3 files changed, 300 insertions(+), 271 deletions(-)
The new twl_get_regmap() function will return a pointer to the regmap needed for the given module. Since both read and write function were using the same code to do the lookup we can reuse this in both places to simplify the code.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/mfd/twl-core.c | 58 +++++++++++++++++++++++++++----------------------- 1 file changed, 31 insertions(+), 27 deletions(-)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index 29473c2c95ae..c91cb4367b9b 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -302,35 +302,50 @@ unsigned int twl_rev(void) EXPORT_SYMBOL(twl_rev);
/** - * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 + * twl_get_regmap - Get the regmap associated with the given module * @mod_no: module number - * @value: an array of num_bytes+1 containing data to write - * @reg: register address (just offset will do) - * @num_bytes: number of bytes to transfer * - * Returns the result of operation - 0 is success + * Returns the regmap pointer or NULL in case of failure. */ -int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) +static struct regmap *twl_get_regmap(u8 mod_no) { - int ret; int sid; struct twl_client *twl;
if (unlikely(!twl_priv || !twl_priv->ready)) { pr_err("%s: not initialized\n", DRIVER_NAME); - return -EPERM; + return NULL; } if (unlikely(mod_no >= twl_get_last_module())) { pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); - return -EPERM; + return NULL; }
sid = twl_priv->twl_map[mod_no].sid; twl = &twl_priv->twl_modules[sid];
- ret = regmap_bulk_write(twl->regmap, - twl_priv->twl_map[mod_no].base + reg, value, - num_bytes); + return twl->regmap; +} + +/** + * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0 + * @mod_no: module number + * @value: an array of num_bytes+1 containing data to write + * @reg: register address (just offset will do) + * @num_bytes: number of bytes to transfer + * + * Returns the result of operation - 0 is success + */ +int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) +{ + struct regmap *regmap = twl_get_regmap(mod_no); + int ret; + + if (!regmap) + return -EPERM; + + ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg, + value, num_bytes);
if (ret) pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)\n", @@ -351,25 +366,14 @@ EXPORT_SYMBOL(twl_i2c_write); */ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) { + struct regmap *regmap = twl_get_regmap(mod_no); int ret; - int sid; - struct twl_client *twl;
- if (unlikely(!twl_priv || !twl_priv->ready)) { - pr_err("%s: not initialized\n", DRIVER_NAME); - return -EPERM; - } - if (unlikely(mod_no >= twl_get_last_module())) { - pr_err("%s: invalid module number %d\n", DRIVER_NAME, mod_no); + if (!regmap) return -EPERM; - } - - sid = twl_priv->twl_map[mod_no].sid; - twl = &twl_priv->twl_modules[sid];
- ret = regmap_bulk_read(twl->regmap, - twl_priv->twl_map[mod_no].base + reg, value, - num_bytes); + ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg, + value, num_bytes);
if (ret) pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)\n",
If the regcache is enabled on the regmap module drivers might need to access to HW register(s) in certain cases in cache bypass mode. As an example of this is the audio block's ANAMICL register. In normal operation the content can be cached but during initialization one bit from the register need to be monitored. With the twl_set_regcache_bypass() the client driver can switch regcache bypass on and off when it is needed so we can utilize the regcache for more registers.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/mfd/twl-core.c | 21 +++++++++++++++++++++ include/linux/i2c/twl.h | 3 +++ 2 files changed, 24 insertions(+)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index c91cb4367b9b..f0abca79ff34 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -383,6 +383,27 @@ int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes) } EXPORT_SYMBOL(twl_i2c_read);
+/** + * twl_regcache_bypass - Configure the regcache bypass for the regmap associated + * with the module + * @mod_no: module number + * @enable: Regcache bypass state + * + * Returns 0 else failure. + */ +int twl_set_regcache_bypass(u8 mod_no, bool enable) +{ + struct regmap *regmap = twl_get_regmap(mod_no); + + if (!regmap) + return -EPERM; + + regcache_cache_bypass(regmap, enable); + + return 0; +} +EXPORT_SYMBOL(twl_set_regcache_bypass); + /*----------------------------------------------------------------------*/
/** diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 673a3ce67f31..a09da0910339 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -175,6 +175,9 @@ static inline int twl_class_is_ ##class(void) \ TWL_CLASS_IS(4030, TWL4030_CLASS_ID) TWL_CLASS_IS(6030, TWL6030_CLASS_ID)
+/* Set the regcache bypass for the regmap associated with the nodule */ +int twl_set_regcache_bypass(u8 mod_no, bool enable); + /* * Read and write several 8-bit registers at once. */
Enable regmap's regcache for the audio registers: i2c address 0x49, register range 0x01 - 0x49 Mark all other registers as volatile to avoid any side effect for the non audio functions behind 0x49 i2c address.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- drivers/mfd/twl-core.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+)
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c index f0abca79ff34..6ef7685a4cf8 100644 --- a/drivers/mfd/twl-core.c +++ b/drivers/mfd/twl-core.c @@ -47,6 +47,9 @@ #include <linux/i2c.h> #include <linux/i2c/twl.h>
+/* Register descriptions for audio */ +#include <linux/mfd/twl4030-audio.h> + #include "twl-core.h"
/* @@ -200,6 +203,105 @@ static struct twl_mapping twl4030_map[] = { { 2, TWL5031_BASEADD_INTERRUPTS }, };
+static struct reg_default twl4030_49_defaults[] = { + /* Audio Registers */ + { 0x01, 0x00}, /* CODEC_MODE */ + { 0x02, 0x00}, /* OPTION */ + /* 0x03 Unused */ + { 0x04, 0x00}, /* MICBIAS_CTL */ + { 0x05, 0x00}, /* ANAMICL */ + { 0x06, 0x00}, /* ANAMICR */ + { 0x07, 0x00}, /* AVADC_CTL */ + { 0x08, 0x00}, /* ADCMICSEL */ + { 0x09, 0x00}, /* DIGMIXING */ + { 0x0a, 0x0f}, /* ATXL1PGA */ + { 0x0b, 0x0f}, /* ATXR1PGA */ + { 0x0c, 0x0f}, /* AVTXL2PGA */ + { 0x0d, 0x0f}, /* AVTXR2PGA */ + { 0x0e, 0x00}, /* AUDIO_IF */ + { 0x0f, 0x00}, /* VOICE_IF */ + { 0x10, 0x3f}, /* ARXR1PGA */ + { 0x11, 0x3f}, /* ARXL1PGA */ + { 0x12, 0x3f}, /* ARXR2PGA */ + { 0x13, 0x3f}, /* ARXL2PGA */ + { 0x14, 0x25}, /* VRXPGA */ + { 0x15, 0x00}, /* VSTPGA */ + { 0x16, 0x00}, /* VRX2ARXPGA */ + { 0x17, 0x00}, /* AVDAC_CTL */ + { 0x18, 0x00}, /* ARX2VTXPGA */ + { 0x19, 0x32}, /* ARXL1_APGA_CTL*/ + { 0x1a, 0x32}, /* ARXR1_APGA_CTL*/ + { 0x1b, 0x32}, /* ARXL2_APGA_CTL*/ + { 0x1c, 0x32}, /* ARXR2_APGA_CTL*/ + { 0x1d, 0x00}, /* ATX2ARXPGA */ + { 0x1e, 0x00}, /* BT_IF */ + { 0x1f, 0x55}, /* BTPGA */ + { 0x20, 0x00}, /* BTSTPGA */ + { 0x21, 0x00}, /* EAR_CTL */ + { 0x22, 0x00}, /* HS_SEL */ + { 0x23, 0x00}, /* HS_GAIN_SET */ + { 0x24, 0x00}, /* HS_POPN_SET */ + { 0x25, 0x00}, /* PREDL_CTL */ + { 0x26, 0x00}, /* PREDR_CTL */ + { 0x27, 0x00}, /* PRECKL_CTL */ + { 0x28, 0x00}, /* PRECKR_CTL */ + { 0x29, 0x00}, /* HFL_CTL */ + { 0x2a, 0x00}, /* HFR_CTL */ + { 0x2b, 0x05}, /* ALC_CTL */ + { 0x2c, 0x00}, /* ALC_SET1 */ + { 0x2d, 0x00}, /* ALC_SET2 */ + { 0x2e, 0x00}, /* BOOST_CTL */ + { 0x2f, 0x00}, /* SOFTVOL_CTL */ + { 0x30, 0x13}, /* DTMF_FREQSEL */ + { 0x31, 0x00}, /* DTMF_TONEXT1H */ + { 0x32, 0x00}, /* DTMF_TONEXT1L */ + { 0x33, 0x00}, /* DTMF_TONEXT2H */ + { 0x34, 0x00}, /* DTMF_TONEXT2L */ + { 0x35, 0x79}, /* DTMF_TONOFF */ + { 0x36, 0x11}, /* DTMF_WANONOFF */ + { 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */ + { 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */ + { 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */ + { 0x3a, 0x06}, /* APLL_CTL */ + { 0x3b, 0x00}, /* DTMF_CTL */ + { 0x3c, 0x44}, /* DTMF_PGA_CTL2 (0x3C) */ + { 0x3d, 0x69}, /* DTMF_PGA_CTL1 (0x3D) */ + { 0x3e, 0x00}, /* MISC_SET_1 */ + { 0x3f, 0x00}, /* PCMBTMUX */ + /* 0x40 - 0x42 Unused */ + { 0x43, 0x00}, /* RX_PATH_SEL */ + { 0x44, 0x32}, /* VDL_APGA_CTL */ + { 0x45, 0x00}, /* VIBRA_CTL */ + { 0x46, 0x00}, /* VIBRA_SET */ + { 0x47, 0x00}, /* VIBRA_PWM_SET */ + { 0x48, 0x00}, /* ANAMIC_GAIN */ + { 0x49, 0x00}, /* MISC_SET_2 */ + /* End of Audio Registers */ +}; + +static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0: + case 3: + case 40: + case 41: + case 42: + return false; + default: + return true; + } +} + +static const struct regmap_range twl4030_49_volatile_ranges[] = { + regmap_reg_range(TWL4030_BASEADD_TEST, 0xff), +}; + +static const struct regmap_access_table twl4030_49_volatile_table = { + .yes_ranges = twl4030_49_volatile_ranges, + .n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges), +}; + static struct regmap_config twl4030_regmap_config[4] = { { /* Address 0x48 */ @@ -212,6 +314,15 @@ static struct regmap_config twl4030_regmap_config[4] = { .reg_bits = 8, .val_bits = 8, .max_register = 0xff, + + .readable_reg = twl4030_49_nop_reg, + .writeable_reg = twl4030_49_nop_reg, + + .volatile_table = &twl4030_49_volatile_table, + + .reg_defaults = twl4030_49_defaults, + .num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults), + .cache_type = REGCACHE_RBTREE, }, { /* Address 0x4a */
Simplifies the code a bit and prepares it to the removal of local caching.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/codecs/twl4030.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index dfc51bb425da..419108ae31de 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -181,50 +181,56 @@ static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec, cache[reg] = 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 snd_soc_codec *codec, + 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; +} + +/* + * write to the twl4030 register space + */ +static int twl4030_write(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + twl4030_write_reg_cache(codec, reg, value); + if (twl4030_can_write_to_chip(codec, reg)) + return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
return 0; }
No need to keep the check defaults functionality anymore.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- include/linux/i2c/twl.h | 1 - sound/soc/codecs/twl4030.c | 23 ----------------------- 2 files changed, 24 deletions(-)
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index a09da0910339..2937a9472b94 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -670,7 +670,6 @@ struct twl4030_codec_data { unsigned int digimic_delay; /* in ms */ unsigned int ramp_delay_value; unsigned int offset_cncl_path; - unsigned int check_defaults:1; unsigned int reset_registers:1; unsigned int hs_extmute:1; int hs_extmute_gpio; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 419108ae31de..7b732ab70d2c 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -268,25 +268,6 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) 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; @@ -378,10 +359,6 @@ 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);
The register states now tracked by the regmap implementation in the core which makes the reset registers functionality 'redundant' since we know the state of the registers now all the time.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- include/linux/i2c/twl.h | 1 - sound/soc/codecs/twl4030.c | 17 ----------------- 2 files changed, 18 deletions(-)
diff --git a/include/linux/i2c/twl.h b/include/linux/i2c/twl.h index 2937a9472b94..ade1c06d4ceb 100644 --- a/include/linux/i2c/twl.h +++ b/include/linux/i2c/twl.h @@ -670,7 +670,6 @@ struct twl4030_codec_data { unsigned int digimic_delay; /* in ms */ unsigned int ramp_delay_value; unsigned int offset_cncl_path; - unsigned int reset_registers:1; unsigned int hs_extmute:1; int hs_extmute_gpio; }; diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 7b732ab70d2c..ab2f22299db2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -268,17 +268,6 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) udelay(10); }
-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) { @@ -359,10 +348,6 @@ static void twl4030_init_chip(struct snd_soc_codec *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); @@ -2293,8 +2278,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))
Few registers need to be cached in the codec driver level. These registers should only be written when the path is active to avoid pop noise on the given path. This patch adds an array which covers the range where the sensitive registers are located and uppon loadinf the driver the ctl cache will be initialized.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/codecs/twl4030.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index ab2f22299db2..f88207712d3d 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -150,10 +150,22 @@ 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; };
+static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) +{ + int i; + u8 byte; + + 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; + } +} + /* * read twl4030 register cache */ @@ -348,6 +360,9 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) } }
+ /* Initialize the local ctl register cache */ + tw4030_init_ctl_cache(twl4030); + /* Refresh APLL_CTL register from HW */ twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, TWL4030_REG_APLL_CTL);
Depend on the regmap reg cache implementation for register caching done in the twl-core driver. The local register cache can be removed and we can keep only shadow copies of certain ctl registers for pop noise reduction.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/codecs/twl4030.c | 207 ++++++++++++++------------------------------- 1 file changed, 63 insertions(+), 144 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index f88207712d3d..dda53e8c51e5 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; @@ -166,31 +86,48 @@ static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) } }
-/* - * read twl4030 register cache - */ -static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) +static void twl4030_update_ctl_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) { - u8 *cache = codec->reg_cache; - - if (reg >= TWL4030_CACHEREGNUM) - return -EIO; + struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- return cache[reg]; + 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; + } }
-/* - * 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; }
static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, @@ -234,13 +171,10 @@ static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, return write_to_reg; }
-/* - * write to the twl4030 register space - */ static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - twl4030_write_reg_cache(codec, reg, value); + twl4030_update_ctl_cache(codec, reg, value); if (twl4030_can_write_to_chip(codec, reg)) return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
@@ -270,10 +204,8 @@ 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 */ @@ -363,13 +295,8 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* Initialize the local ctl register cache */ tw4030_init_ctl_cache(twl4030);
- /* 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); - /* 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);
@@ -386,15 +313,15 @@ 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, @@ -408,15 +335,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); + 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); }
@@ -436,9 +362,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 */ @@ -661,8 +584,7 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ 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; \ @@ -683,7 +605,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 */ @@ -763,7 +685,7 @@ static int aif_event(struct snd_soc_dapm_widget *w, { 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 */ @@ -793,8 +715,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;
@@ -1738,7 +1660,7 @@ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, { 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; @@ -1767,7 +1689,7 @@ 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 @@ -1815,8 +1737,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? */ @@ -1832,8 +1754,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)) { @@ -1874,7 +1796,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)) { @@ -1957,7 +1879,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, 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 */ @@ -2007,7 +1929,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; @@ -2024,7 +1946,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, { 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; @@ -2059,7 +1981,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) { @@ -2091,7 +2013,7 @@ 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) + old_mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE) & ~(TWL4030_CODECPDZ); mode = old_mode;
@@ -2154,7 +2076,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, 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 */ @@ -2201,7 +2123,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; @@ -2304,13 +2226,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),
Depend on the regmap reg cache implementation for register caching done in the twl-core driver. The local register cache can be removed and we can keep only shadow copies of certain ctl registers for pop noise reduction.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com
sound/soc/codecs/twl4030.c | 207 ++++++++++++++------------------------------- 1 file changed, 63 insertions(+), 144 deletions(-)
Which commit is the patch-set based on? This patch doesn't apply.
At a guess I'd say it's becuase this commit is applied on my tree:
mfd: twl6040: reg_defaults support for regmap
Would you mind rebasing on my ASoC branch please?
git://git.linaro.org/people/lee.jones/mfd.git ib-asoc
NB: Mark also has this commit on his tree, so it would likely aid us both.
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index f88207712d3d..dda53e8c51e5 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; @@ -166,31 +86,48 @@ static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) } }
-/*
- read twl4030 register cache
- */
-static inline unsigned int twl4030_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
+static void twl4030_update_ctl_cache(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value)
{
- u8 *cache = codec->reg_cache;
- if (reg >= TWL4030_CACHEREGNUM)
return -EIO;
- struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
- return cache[reg];
- 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;
- }
}
-/*
- 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;
}
static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, @@ -234,13 +171,10 @@ static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, return write_to_reg; }
-/*
- write to the twl4030 register space
- */
static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) {
- twl4030_write_reg_cache(codec, reg, value);
- twl4030_update_ctl_cache(codec, reg, value); if (twl4030_can_write_to_chip(codec, reg)) return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
@@ -270,10 +204,8 @@ 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 */
@@ -363,13 +295,8 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* Initialize the local ctl register cache */ tw4030_init_ctl_cache(twl4030);
- /* 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);
- /* 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);
@@ -386,15 +313,15 @@ 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,
@@ -408,15 +335,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) msleep(20); do { usleep_range(1000, 2000);
twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, TWL4030_REG_ANAMICL);twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, true);
} while ((i++ < 100) && ((byte & TWL4030_CNCL_OFFSET_START) == TWL4030_CNCL_OFFSET_START));twl_set_regcache_bypass(TWL4030_MODULE_AUDIO_VOICE, false);
- /* 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);
}
@@ -436,9 +362,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 */ @@ -661,8 +584,7 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ 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)); \
break; \ case SND_SOC_DAPM_POST_PMD: \ twl4030->pin_name##_enabled = 0; \twl4030_write(w->codec, reg, twl4030_read(w->codec, reg)); \
@@ -683,7 +605,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 */
@@ -763,7 +685,7 @@ static int aif_event(struct snd_soc_dapm_widget *w, { 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 */
@@ -793,8 +715,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;
@@ -1738,7 +1660,7 @@ static void twl4030_tdm_enable(struct snd_soc_codec *codec, int direction, { 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;
@@ -1767,7 +1689,7 @@ 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
@@ -1815,8 +1737,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? */
@@ -1832,8 +1754,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)) {
@@ -1874,7 +1796,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)) {
@@ -1957,7 +1879,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, 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 */
@@ -2007,7 +1929,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;
@@ -2024,7 +1946,7 @@ static void twl4030_voice_enable(struct snd_soc_codec *codec, int direction, { 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;
@@ -2059,7 +1981,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) {
@@ -2091,7 +2013,7 @@ 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)
- old_mode = twl4030_read(codec, TWL4030_REG_CODEC_MODE) & ~(TWL4030_CODECPDZ); mode = old_mode;
@@ -2154,7 +2076,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, 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 */
@@ -2201,7 +2123,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;
@@ -2304,13 +2226,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),
Hi Lee,
On 01/08/2014 10:05 AM, Lee Jones wrote:
Depend on the regmap reg cache implementation for register caching done in the twl-core driver. The local register cache can be removed and we can keep only shadow copies of certain ctl registers for pop noise reduction.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com
sound/soc/codecs/twl4030.c | 207 ++++++++++++++------------------------------- 1 file changed, 63 insertions(+), 144 deletions(-)
Which commit is the patch-set based on? This patch doesn't apply.
When I have sent it it was mainline 3.13-rc6, Now I rebased my series on 3.13-rc7 locally.
At a guess I'd say it's becuase this commit is applied on my tree:
mfd: twl6040: reg_defaults support for regmap
I also have the twl6040 series underneath the twl4030 patches in my working branch and the two series does not touch the same files.
Would you mind rebasing on my ASoC branch please?
git://git.linaro.org/people/lee.jones/mfd.git ib-asoc
I have applied this twl4030 series on this branch and all patches (from 01 to 11) applied w/o issue, not even offset difference.
Not sure what is going on since the sound/soc/codecs/twl4030.c file is identical in 3.13-rc7 and in your ib-asoc branch so the series should apply cleanly for you.
Depend on the regmap reg cache implementation for register caching done in the twl-core driver. The local register cache can be removed and we can keep only shadow copies of certain ctl registers for pop noise reduction.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com
sound/soc/codecs/twl4030.c | 207 ++++++++++++++------------------------------- 1 file changed, 63 insertions(+), 144 deletions(-)
Which commit is the patch-set based on? This patch doesn't apply.
When I have sent it it was mainline 3.13-rc6, Now I rebased my series on 3.13-rc7 locally.
At a guess I'd say it's becuase this commit is applied on my tree:
mfd: twl6040: reg_defaults support for regmap
I also have the twl6040 series underneath the twl4030 patches in my working branch and the two series does not touch the same files.
Would you mind rebasing on my ASoC branch please?
git://git.linaro.org/people/lee.jones/mfd.git ib-asoc
I have applied this twl4030 series on this branch and all patches (from 01 to 11) applied w/o issue, not even offset difference.
Not sure what is going on since the sound/soc/codecs/twl4030.c file is identical in 3.13-rc7 and in your ib-asoc branch so the series should apply cleanly for you.
Now that is strange. I just attempted to apply them again and they did so cleanly. I'm not sure what happened, but they're find now.
Applied, thanks.
Over time the multi line alignment got messed up. Correct them in one go so the code will look consistent.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/codecs/twl4030.c | 93 ++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 48 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index dda53e8c51e5..7a5b91e70f98 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -171,8 +171,8 @@ static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, return write_to_reg; }
-static int twl4030_write(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) +static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) { twl4030_update_ctl_cache(codec, reg, value); if (twl4030_can_write_to_chip(codec, reg)) @@ -298,11 +298,11 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) /* anti-pop when changing analog gain */ 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); @@ -325,7 +325,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) 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. @@ -337,7 +337,7 @@ static void twl4030_init_chip(struct snd_soc_codec *codec) 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) == @@ -577,7 +577,7 @@ 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); \ \ @@ -588,8 +588,7 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ 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; \ @@ -632,7 +631,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: @@ -646,7 +645,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: @@ -660,14 +659,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: @@ -681,7 +680,7 @@ 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;
@@ -693,12 +692,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; } @@ -736,9 +735,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 */ @@ -751,9 +749,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); @@ -771,7 +768,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);
@@ -795,7 +792,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);
@@ -819,7 +816,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; @@ -840,7 +837,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; @@ -869,7 +866,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; @@ -898,7 +895,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; @@ -925,7 +922,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; @@ -1656,7 +1653,7 @@ 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;
@@ -1695,8 +1692,8 @@ static int twl4030_startup(struct snd_pcm_substream *substream, * 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; } @@ -1728,8 +1725,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); @@ -1845,8 +1842,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); @@ -1871,8 +1868,7 @@ 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); @@ -1942,7 +1938,7 @@ 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;
@@ -1962,7 +1958,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); @@ -1994,7 +1990,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;
@@ -2003,7 +1999,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); @@ -2013,8 +2010,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(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)) { @@ -2048,7 +2045,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); @@ -2069,7 +2066,7 @@ 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); @@ -2242,7 +2239,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)
There's no other users of this functionality, the code can be moved inside of twl4030_write.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/codecs/twl4030.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 7a5b91e70f98..c3c15f891270 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -86,25 +86,6 @@ static void tw4030_init_ctl_cache(struct twl4030_priv *twl4030) } }
-static void twl4030_update_ctl_cache(struct snd_soc_codec *codec, - unsigned int reg, unsigned int value) -{ - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); - - 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; - } -} - static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg) { struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); @@ -174,7 +155,22 @@ static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value) { - twl4030_update_ctl_cache(codec, reg, 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(codec, reg)) return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
To avoid another lookup for the twl4030_priv in there.
Signed-off-by: Peter Ujfalusi peter.ujfalusi@ti.com --- sound/soc/codecs/twl4030.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c3c15f891270..00665ada23e2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -111,10 +111,9 @@ static unsigned int twl4030_read(struct snd_soc_codec *codec, unsigned int reg) return value; }
-static bool twl4030_can_write_to_chip(struct snd_soc_codec *codec, +static bool twl4030_can_write_to_chip(struct twl4030_priv *twl4030, unsigned int reg) { - struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); bool write_to_reg = false;
/* Decide if the given register can be written */ @@ -171,7 +170,7 @@ static int twl4030_write(struct snd_soc_codec *codec, unsigned int reg, break; }
- if (twl4030_can_write_to_chip(codec, reg)) + if (twl4030_can_write_to_chip(twl4030, reg)) return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg);
return 0;
On Fri, Jan 03, 2014 at 03:27:45PM +0200, Peter Ujfalusi wrote:
Hi,
After the twl6040 codec, now it is time for the twl4030 codec driver to loose it's local reg cache and let the MFD core's regmap to take care of the caching.
This all looks good to me - Lee/Samuel how do you want to handle this, are you OK with merging the MFD bits via ASoC or something else?
On Mon, 06 Jan 2014, Mark Brown wrote:
On Fri, Jan 03, 2014 at 03:27:45PM +0200, Peter Ujfalusi wrote:
Hi,
After the twl6040 codec, now it is time for the twl4030 codec driver to loose it's local reg cache and let the MFD core's regmap to take care of the caching.
This all looks good to me - Lee/Samuel how do you want to handle this, are you OK with merging the MFD bits via ASoC or something else?
Are you planning on taking this in for v3.14? Only we're on -rc7 already.
It also depends how closely knit the MFD changes are to the ASoC ones.
Are they completely dependant?
On Mon, Jan 06, 2014 at 04:10:01PM +0000, Lee Jones wrote:
Are you planning on taking this in for v3.14? Only we're on -rc7 already.
Yes. It's a driver change and if it's buggy we've got a couple of months of integration to fix any issues.
It also depends how closely knit the MFD changes are to the ASoC ones.
Are they completely dependant?
Yes, they're tied to each other.
Mark,
Enjoy!
The following changes since commit 6ce4eac1f600b34f2f7f58f9cd8f0503d79e42ae:
Linux 3.13-rc1 (2013-11-22 11:30:55 -0800)
are available in the git repository at:
git://git.linaro.org/people/ljones/mfd.git tags/ib-asoc-3.14.2
for you to fetch changes up to 9146070089cca0fa5c396f1a4d0b96d675004c04:
mfd: twl-core: Enable regcache for audio registers (2014-01-08 11:37:52 +0000)
---------------------------------------------------------------- Immutable branch between MFD and ASoC due for the v3.14 merge window
---------------------------------------------------------------- Peter Ujfalusi (4): mfd: twl6040: reg_defaults support for regmap mfd: twl-core: Simplify IO wrapper functions by moving common code out mfd: twl-core: API to set the regcache bypass for a given regmap in twl mfd: twl-core: Enable regcache for audio registers
drivers/mfd/twl-core.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ drivers/mfd/twl6040.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- include/linux/i2c/twl.h | 3 ++ 3 files changed, 255 insertions(+), 30 deletions(-)
On Wed, Jan 08, 2014 at 11:42:32AM +0000, Lee Jones wrote:
are available in the git repository at:
git://git.linaro.org/people/ljones/mfd.git tags/ib-asoc-3.14.2
for you to fetch changes up to 9146070089cca0fa5c396f1a4d0b96d675004c04:
Pulled, thanks.
drivers/mfd/twl-core.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ drivers/mfd/twl6040.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Wrapping seems broken here...
are available in the git repository at:
git://git.linaro.org/people/ljones/mfd.git tags/ib-asoc-3.14.2
for you to fetch changes up to 9146070089cca0fa5c396f1a4d0b96d675004c04:
Pulled, thanks.
drivers/mfd/twl-core.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ drivers/mfd/twl6040.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Wrapping seems broken here...
Odd. Looks broken in Mutt, but now I'm replying (in Emacs) it looks fine again!
On Fri, Jan 03, 2014 at 03:27:45PM +0200, Peter Ujfalusi wrote:
Hi,
After the twl6040 codec, now it is time for the twl4030 codec driver to loose it's local reg cache and let the MFD core's regmap to take care of the caching.
Applied all, thanks.
participants (3)
-
Lee Jones
-
Mark Brown
-
Peter Ujfalusi