From dfd72a68aa0f6cf87575f3181319bde8a2d4c01b Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 30 Jan 2014 18:14:05 +0100 Subject: [PATCH 01/10] ASoC: cs42l51: add Device Tree binding to cs42l51 This commit adds a trivial Device Tree binding to the I2C-based cs42l51 sound codec, so that it can be used from Device Tree based platforms. Signed-off-by: Thomas Petazzoni Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/i2c/trivial-devices.txt | 1 + sound/soc/codecs/cs42l51.c | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 1a1ac2e560e9..f47e56bcf78d 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt @@ -18,6 +18,7 @@ atmel,24c02 i2c serial eeprom (24cxx) atmel,at97sc3204t i2c trusted platform module (TPM) capella,cm32181 CM32181: Ambient Light Sensor catalyst,24c32 i2c serial eeprom +cirrus,cs42l51 Cirrus Logic CS42L51 audio codec dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock dallas,ds1338 I2C RTC with 56-Byte NV RAM dallas,ds1339 I2C Serial Real-Time Clock diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 6e9ea8379a91..824cdf4d4974 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -600,10 +600,17 @@ static const struct i2c_device_id cs42l51_id[] = { }; MODULE_DEVICE_TABLE(i2c, cs42l51_id); +static const struct of_device_id cs42l51_of_match[] = { + { .compatible = "cirrus,cs42l51", }, + { } +}; +MODULE_DEVICE_TABLE(of, cs42l51_of_match); + static struct i2c_driver cs42l51_i2c_driver = { .driver = { .name = "cs42l51-codec", .owner = THIS_MODULE, + .of_match_table = cs42l51_of_match, }, .id_table = cs42l51_id, .probe = cs42l51_i2c_probe, From 5be736442ed94217c6521ae0c948abab995f281f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Feb 2014 19:21:16 +0000 Subject: [PATCH 02/10] ASoC: cs42l51: Don't log if we fail to allocate memory The VM subsystem already logs quite loudly if we run out of memory so don't bother here. Signed-off-by: Mark Brown Acked-by: Brian Austin --- sound/soc/codecs/cs42l51.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 824cdf4d4974..b11079b38f15 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -574,10 +574,8 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c_client, cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), GFP_KERNEL); - if (!cs42l51) { - dev_err(&i2c_client->dev, "could not allocate codec\n"); + if (!cs42l51) return -ENOMEM; - } i2c_set_clientdata(i2c_client, cs42l51); cs42l51->control_type = SND_SOC_I2C; From da071489762499a3635cb3563d32792cea20c087 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Feb 2014 19:24:31 +0000 Subject: [PATCH 03/10] ASoC: cs42l51: Convert to direct regmap API usage As part of phasing out the ASoC level register I/O code (which is now just a thin wrapper around regmap anyway) convert the cs42l51 driver to use the regmap API directly. We now no longer initialise the cache from hardware at startup, the regmap caches are smart enough to understand which registers are actually cached and read on demand. This should have no visible effect on the system. Signed-off-by: Mark Brown Acked-by: Brian Austin --- sound/soc/codecs/cs42l51.c | 59 ++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 34 deletions(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index b11079b38f15..e53c8714591f 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "cs42l51.h" @@ -40,7 +41,6 @@ enum master_slave_mode { }; struct cs42l51_private { - enum snd_soc_control_type control_type; unsigned int mclk; unsigned int audio_mode; /* The mode (I2S or left-justified) */ enum master_slave_mode func; @@ -52,24 +52,6 @@ struct cs42l51_private { SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) -static int cs42l51_fill_cache(struct snd_soc_codec *codec) -{ - u8 *cache = codec->reg_cache + 1; - struct i2c_client *i2c_client = to_i2c_client(codec->dev); - s32 length; - - length = i2c_smbus_read_i2c_block_data(i2c_client, - CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); - if (length != CS42L51_NUMREGS) { - dev_err(&i2c_client->dev, - "I2C read failure, addr=0x%x (ret=%d vs %d)\n", - i2c_client->addr, length, CS42L51_NUMREGS); - return -EIO; - } - - return 0; -} - static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -508,13 +490,7 @@ static int cs42l51_probe(struct snd_soc_codec *codec) struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); int ret, reg; - ret = cs42l51_fill_cache(codec); - if (ret < 0) { - dev_err(codec->dev, "failed to fill register cache\n"); - return ret; - } - - ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -538,8 +514,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .probe = cs42l51_probe, - .reg_cache_size = CS42L51_NUMREGS + 1, - .reg_word_size = sizeof(u8), .controls = cs42l51_snd_controls, .num_controls = ARRAY_SIZE(cs42l51_snd_controls), @@ -549,28 +523,46 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), }; +static const struct regmap_config cs42l51_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS42L51_CHARGE_FREQ, + .cache_type = REGCACHE_RBTREE, +}; + static int cs42l51_i2c_probe(struct i2c_client *i2c_client, const struct i2c_device_id *id) { struct cs42l51_private *cs42l51; + struct regmap *regmap; + unsigned int val; int ret; + regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&i2c_client->dev, "Failed to create regmap: %d\n", + ret); + return ret; + } + /* Verify that we have a CS42L51 */ - ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); + ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); if (ret < 0) { dev_err(&i2c_client->dev, "failed to read I2C\n"); goto error; } - if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && - (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { - dev_err(&i2c_client->dev, "Invalid chip id\n"); + if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && + (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { + dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val); ret = -ENODEV; goto error; } dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", - ret & 7); + val & 7); cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), GFP_KERNEL); @@ -578,7 +570,6 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c_client, return -ENOMEM; i2c_set_clientdata(i2c_client, cs42l51); - cs42l51->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&i2c_client->dev, &soc_codec_device_cs42l51, &cs42l51_dai, 1); From 78c51bc6475982a843947a556853affd2c360b19 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Feb 2014 19:51:58 +0000 Subject: [PATCH 04/10] ASoC: ak4671: Convert to table based control init Saves code and adds error handling. Signed-off-by: Mark Brown --- sound/soc/codecs/ak4671.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 25bdf6ad4a54..456bd0a065b1 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -628,9 +628,6 @@ static int ak4671_probe(struct snd_soc_codec *codec) return ret; } - snd_soc_add_codec_controls(codec, ak4671_snd_controls, - ARRAY_SIZE(ak4671_snd_controls)); - ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); return ret; @@ -646,6 +643,8 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .probe = ak4671_probe, .remove = ak4671_remove, .set_bias_level = ak4671_set_bias_level, + .controls = ak4671_snd_controls, + .num_controls = ARRAY_SIZE(ak4671_snd_controls), .reg_cache_size = AK4671_CACHEREGNUM, .reg_word_size = sizeof(u8), .reg_cache_default = ak4671_reg, From 7ac5a47886ae4b211f08657d0d06027285eda2d0 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 11 Feb 2014 19:53:25 +0000 Subject: [PATCH 05/10] ASoC: ak4671: Convert to direct regmap API usage This helps us remove the ASoC level I/O functionality which is now just a thin wrapper around regmap. Signed-off-by: Mark Brown --- sound/soc/codecs/ak4671.c | 221 +++++++++++++++++++------------------- sound/soc/codecs/ak4671.h | 2 - 2 files changed, 111 insertions(+), 112 deletions(-) diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 456bd0a065b1..743bbe31bc08 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,104 +24,99 @@ #include "ak4671.h" -/* codec private data */ -struct ak4671_priv { - enum snd_soc_control_type control_type; -}; - /* ak4671 register cache & default register settings */ -static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { - 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ - 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ - 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ - 0x02, /* AK4671_FORMAT_SELECT (0x03) */ - 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ - 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ - 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ - 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ - 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ - 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ - 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ - 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ - 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ - 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ - 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ - 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ - 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ - 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ - 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ - 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ - 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ - 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ - 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ - 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ - 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ - 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ - 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ - 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ - 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ - 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ - 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ - 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ - 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ - 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ - 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ - 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ - 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ - 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ - 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ - 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ - 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ - 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ - 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ - 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ - 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ - 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ - 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ - 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ - 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ - 0x00, /* this register not used */ - 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ - 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ - 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ - 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ - 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ - 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ - 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ - 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ - 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ - 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ - 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ - 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ - 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ - 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ - 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ - 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ - 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ - 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ - 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ - 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ - 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ - 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ - 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ - 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ - 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ - 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ - 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ - 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ - 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ - 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ - 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ - 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ - 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ - 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ - 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ - 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ - 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ - 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ - 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ - 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ - 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ +static const struct reg_default ak4671_reg_defaults[] = { + { 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ + { 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0 (0x01) */ + { 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1 (0x02) */ + { 0x03, 0x02 }, /* AK4671_FORMAT_SELECT (0x03) */ + { 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ + { 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN (0x05) */ + { 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ + { 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ + { 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ + { 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ + { 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ + { 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ + { 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ + { 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ + { 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ + { 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ + { 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ + { 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ + { 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ + { 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ + { 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ + { 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ + { 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT (0x16) */ + { 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL (0x17) */ + { 0x18, 0x02 }, /* AK4671_MODE_CONTROL1 (0x18) */ + { 0x19, 0x01 }, /* AK4671_MODE_CONTROL2 (0x19) */ + { 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ + { 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ + { 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ + { 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ + { 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ + { 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ + { 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ + { 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ + { 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0 (0x22) */ + { 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1 (0x23) */ + { 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2 (0x24) */ + { 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3 (0x25) */ + { 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4 (0x26) */ + { 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5 (0x27) */ + { 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ + { 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ + { 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ + { 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ + { 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ + { 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ + { 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ + { 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ + { 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ + + { 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0 (0x32) */ + { 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1 (0x33) */ + { 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2 (0x34) */ + { 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3 (0x35) */ + { 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4 (0x36) */ + { 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5 (0x37) */ + { 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0 (0x38) */ + { 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1 (0x39) */ + { 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2 (0x3a) */ + { 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3 (0x3b) */ + { 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4 (0x3c) */ + { 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5 (0x3d) */ + { 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0 (0x3e) */ + { 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1 (0x3f) */ + { 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2 (0x40) */ + { 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3 (0x41) */ + { 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4 (0x42) */ + { 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5 (0x43) */ + { 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0 (0x44) */ + { 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1 (0x45) */ + { 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2 (0x46) */ + { 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3 (0x47) */ + { 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4 (0x48) */ + { 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5 (0x49) */ + { 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0 (0x4a) */ + { 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1 (0x4b) */ + { 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2 (0x4c) */ + { 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3 (0x4d) */ + { 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4 (0x4e) */ + { 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5 (0x4f) */ + { 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ + { 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ + { 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ + { 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0 (0x53) */ + { 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1 (0x54) */ + { 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2 (0x55) */ + { 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ + { 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ + { 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ + { 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ + { 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL (0x5a) */ }; /* @@ -619,10 +615,9 @@ static struct snd_soc_dai_driver ak4671_dai = { static int ak4671_probe(struct snd_soc_codec *codec) { - struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec); int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type); + ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; @@ -645,28 +640,34 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { .set_bias_level = ak4671_set_bias_level, .controls = ak4671_snd_controls, .num_controls = ARRAY_SIZE(ak4671_snd_controls), - .reg_cache_size = AK4671_CACHEREGNUM, - .reg_word_size = sizeof(u8), - .reg_cache_default = ak4671_reg, .dapm_widgets = ak4671_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), .dapm_routes = ak4671_intercon, .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), }; +static const struct regmap_config ak4671_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = AK4671_SAR_ADC_CONTROL, + .reg_defaults = ak4671_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults), + .cache_type = REGCACHE_RBTREE, +}; + static int ak4671_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct ak4671_priv *ak4671; + struct regmap *regmap; int ret; - ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv), - GFP_KERNEL); - if (ak4671 == NULL) - return -ENOMEM; - - i2c_set_clientdata(client, ak4671); - ak4671->control_type = SND_SOC_I2C; + regmap = devm_regmap_init_i2c(client, &ak4671_regmap); + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(&client->dev, "Failed to create regmap: %d\n", ret); + return ret; + } ret = snd_soc_register_codec(&client->dev, &soc_codec_dev_ak4671, &ak4671_dai, 1); diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h index 61cb7ab7552c..394a34d3f50a 100644 --- a/sound/soc/codecs/ak4671.h +++ b/sound/soc/codecs/ak4671.h @@ -105,8 +105,6 @@ #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 #define AK4671_SAR_ADC_CONTROL 0x5a -#define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) - /* Bitfield Definitions */ /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ From 423f0c4a3d32cc83dff204324f59aecb4516f3cf Mon Sep 17 00:00:00 2001 From: Sachin Kamat Date: Tue, 18 Feb 2014 14:32:48 +0530 Subject: [PATCH 06/10] ASoC: cs42l51: Remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ‘cs42l51’ is not used. Remove it. Signed-off-by: Sachin Kamat Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l51.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index e53c8714591f..3eab46020a30 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -487,7 +487,6 @@ static struct snd_soc_dai_driver cs42l51_dai = { static int cs42l51_probe(struct snd_soc_codec *codec) { - struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); int ret, reg; ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); From 98bf1b5e788e63536705dcc418cc97b36481067e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Feb 2014 10:00:29 +0100 Subject: [PATCH 07/10] ASoC: alc5623: Use SOC_ENUM_SINGLE_DECL() Just replace with the helper macro. No functional change at all. Signed-off-by: Takashi Iwai Acked-by: Liam Girdwood Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/alc5623.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index d3036283482a..ba61c07ebbb2 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -228,32 +228,37 @@ static const char *alc5623_aux_out_input_sel[] = { "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; /* auxout output mux */ -static const struct soc_enum alc5623_aux_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 6, + alc5623_aux_out_input_sel); static const struct snd_kcontrol_new alc5623_auxout_mux_controls = SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); /* speaker output mux */ -static const struct soc_enum alc5623_spkout_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 10, + alc5623_spkout_input_sel); static const struct snd_kcontrol_new alc5623_spkout_mux_controls = SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); /* headphone left output mux */ -static const struct soc_enum alc5623_hpl_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 9, + alc5623_hpl_out_input_sel); static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); /* headphone right output mux */ -static const struct soc_enum alc5623_hpr_out_input_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum, + ALC5623_OUTPUT_MIXER_CTRL, 8, + alc5623_hpr_out_input_sel); static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); /* speaker output N select */ -static const struct soc_enum alc5623_spk_n_sour_enum = -SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel); +static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum, + ALC5623_OUTPUT_MIXER_CTRL, 14, + alc5623_spk_n_sour_sel); static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); @@ -338,8 +343,9 @@ SND_SOC_DAPM_VMID("Vmid"), }; static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; -static const struct soc_enum alc5623_amp_enum = - SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names); +static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum, + ALC5623_OUTPUT_MIXER_CTRL, 13, + alc5623_amp_names); static const struct snd_kcontrol_new alc5623_amp_mux_controls = SOC_DAPM_ENUM("Route", alc5623_amp_enum); From 64e6b58db9c3ee550092c73e18e36ad9dc168334 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Feb 2014 10:43:58 +0100 Subject: [PATCH 08/10] ASoC: ak4671: Use SOC_ENUM_SINGLE_DECL() Just replace with the helper macro. No functional change at all. Signed-off-by: Takashi Iwai Acked-by: Liam Girdwood Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ak4671.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 743bbe31bc08..deb2b44669de 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -237,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { /* Input MUXs */ static const char *ak4671_lin_mux_texts[] = {"LIN1", "LIN2", "LIN3", "LIN4"}; -static const struct soc_enum ak4671_lin_mux_enum = - SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, - ARRAY_SIZE(ak4671_lin_mux_texts), - ak4671_lin_mux_texts); +static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum, + AK4671_MIC_SIGNAL_SELECT, 0, + ak4671_lin_mux_texts); static const struct snd_kcontrol_new ak4671_lin_mux_control = SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); static const char *ak4671_rin_mux_texts[] = {"RIN1", "RIN2", "RIN3", "RIN4"}; -static const struct soc_enum ak4671_rin_mux_enum = - SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, - ARRAY_SIZE(ak4671_rin_mux_texts), - ak4671_rin_mux_texts); +static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum, + AK4671_MIC_SIGNAL_SELECT, 2, + ak4671_rin_mux_texts); static const struct snd_kcontrol_new ak4671_rin_mux_control = SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); From e84f2463765ff34a322511be815ad235dcc1f218 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Feb 2014 10:44:32 +0100 Subject: [PATCH 09/10] ASoC: alc5632: Use SOC_ENUM_SINGLE_DECL() Just replace with the helper macro. No functional change at all. Signed-off-by: Takashi Iwai Acked-by: Liam Girdwood Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/alc5632.c | 40 +++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index fb001c56cf8d..d885056ad8f2 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = { "ADC LR", "Voice Stereo Digital"}; /* auxout output mux */ -static const struct soc_enum alc5632_aux_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 6, + alc5632_aux_out_input_sel); static const struct snd_kcontrol_new alc5632_auxout_mux_controls = SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum); /* speaker output mux */ -static const struct soc_enum alc5632_spkout_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 10, + alc5632_spkout_input_sel); static const struct snd_kcontrol_new alc5632_spkout_mux_controls = SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum); /* headphone left output mux */ -static const struct soc_enum alc5632_hpl_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 9, + alc5632_hpl_out_input_sel); static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls = SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum); /* headphone right output mux */ -static const struct soc_enum alc5632_hpr_out_input_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum, + ALC5632_OUTPUT_MIXER_CTRL, 8, + alc5632_hpr_out_input_sel); static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls = SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum); /* speaker output N select */ -static const struct soc_enum alc5632_spk_n_sour_enum = -SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum, + ALC5632_OUTPUT_MIXER_CTRL, 14, + alc5632_spk_n_sour_sel); static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls = SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum); /* speaker amplifier */ static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; -static const struct soc_enum alc5632_amp_enum = - SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names); +static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum, + ALC5632_OUTPUT_MIXER_CTRL, 13, + alc5632_amp_names); static const struct snd_kcontrol_new alc5632_amp_mux_controls = SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); /* ADC output select */ -static const struct soc_enum alc5632_adcr_func_enum = - SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum, + ALC5632_DAC_FUNC_SELECT, 5, + alc5632_adcr_func_sel); static const struct snd_kcontrol_new alc5632_adcr_func_controls = SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); /* I2S out select */ -static const struct soc_enum alc5632_i2s_out_enum = - SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel); +static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum, + ALC5632_I2S_OUT_CTL, 5, + alc5632_i2s_out_sel); static const struct snd_kcontrol_new alc5632_i2s_out_controls = SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); From 0cd257bf9b9b0cbb4fa1a5c988a232506997867c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 20 Feb 2014 09:04:06 +0900 Subject: [PATCH 10/10] ASoC: alc5623: Convert to direct regmap API usage Convert to directly use the regmap API, allowing us to eliminate the last user of the ASoC level I/O implementations (there are still open coded I/O implementations in drivers), avoiding duplicating code in regmap. We no longer cache the entire CODEC register map on probe since the more advanced cache infrastructure in regmap is able to fill the cache on demand. Signed-off-by: Mark Brown --- sound/soc/codecs/alc5623.c | 87 +++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index ba61c07ebbb2..ed506253a914 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,26 +39,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)"); /* codec private data */ struct alc5623_priv { - enum snd_soc_control_type control_type; + struct regmap *regmap; u8 id; unsigned int sysclk; - u16 reg_cache[ALC5623_VENDOR_ID2+2]; unsigned int add_ctrl; unsigned int jack_det_ctrl; }; -static void alc5623_fill_cache(struct snd_soc_codec *codec) -{ - int i, step = codec->driver->reg_cache_step; - u16 *cache = codec->reg_cache; - - /* not really efficient ... */ - codec->cache_bypass = 1; - for (i = 0 ; i < codec->driver->reg_cache_size ; i += step) - cache[i] = snd_soc_read(codec, i); - codec->cache_bypass = 0; -} - static inline int alc5623_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, ALC5623_RESET, 0); @@ -875,18 +863,28 @@ static struct snd_soc_dai_driver alc5623_dai = { static int alc5623_suspend(struct snd_soc_codec *codec) { + struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); + alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); + regcache_cache_only(alc5623->regmap, true); + return 0; } static int alc5623_resume(struct snd_soc_codec *codec) { - int i, step = codec->driver->reg_cache_step; - u16 *cache = codec->reg_cache; + struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); + int ret; /* Sync reg_cache with the hardware */ - for (i = 2 ; i < codec->driver->reg_cache_size ; i += step) - snd_soc_write(codec, i, cache[i]); + regcache_cache_only(alc5623->regmap, false); + ret = regcache_sync(alc5623->regmap); + if (ret != 0) { + dev_err(codec->dev, "Failed to sync register cache: %d\n", + ret); + regcache_cache_only(alc5623->regmap, true); + return ret; + } alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -906,14 +904,14 @@ static int alc5623_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = &codec->dapm; int ret; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type); + codec->control_data = alc5623->regmap; + ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); if (ret < 0) { dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); return ret; } alc5623_reset(codec); - alc5623_fill_cache(codec); /* power on device */ alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -986,9 +984,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = { .suspend = alc5623_suspend, .resume = alc5623_resume, .set_bias_level = alc5623_set_bias_level, - .reg_cache_size = ALC5623_VENDOR_ID2+2, - .reg_word_size = sizeof(u16), - .reg_cache_step = 2, +}; + +static const struct regmap_config alc5623_regmap = { + .reg_bits = 8, + .val_bits = 16, + .reg_stride = 2, + + .max_register = ALC5623_VENDOR_ID2, + .cache_type = REGCACHE_RBTREE, }; /* @@ -1002,19 +1006,32 @@ static int alc5623_i2c_probe(struct i2c_client *client, { struct alc5623_platform_data *pdata; struct alc5623_priv *alc5623; - int ret, vid1, vid2; + unsigned int vid1, vid2; + int ret; - vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1); - if (vid1 < 0) { - dev_err(&client->dev, "failed to read I2C\n"); - return -EIO; + alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), + GFP_KERNEL); + if (alc5623 == NULL) + return -ENOMEM; + + alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap); + if (IS_ERR(alc5623->regmap)) { + ret = PTR_ERR(alc5623->regmap); + dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret); + return ret; + } + + ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1); + if (ret < 0) { + dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); + return ret; } vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); - vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2); - if (vid2 < 0) { - dev_err(&client->dev, "failed to read I2C\n"); - return -EIO; + ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2); + if (ret < 0) { + dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret); + return ret; } if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { @@ -1027,11 +1044,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); - alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), - GFP_KERNEL); - if (alc5623 == NULL) - return -ENOMEM; - pdata = client->dev.platform_data; if (pdata) { alc5623->add_ctrl = pdata->add_ctrl; @@ -1054,7 +1066,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, } i2c_set_clientdata(client, alc5623); - alc5623->control_type = SND_SOC_I2C; ret = snd_soc_register_codec(&client->dev, &soc_codec_device_alc5623, &alc5623_dai, 1);