From 997288e3824e4c6a7ab4ca4f580fe35e138d62e8 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 13 Aug 2013 13:10:19 +0100 Subject: [PATCH 1/3] ASoC: max9877: Convert to use regmap API Signed-off-by: Mark Brown --- sound/soc/codecs/max9877.c | 179 +++++++++++++++++++++++-------------- 1 file changed, 114 insertions(+), 65 deletions(-) diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 6b6c74cd83e2..7e2fe5023fb2 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -14,27 +14,21 @@ #include #include #include +#include #include #include #include "max9877.h" -static struct i2c_client *i2c; +static struct regmap *regmap; -static u8 max9877_regs[5] = { 0x40, 0x00, 0x00, 0x00, 0x49 }; - -static void max9877_write_regs(void) -{ - unsigned int i; - u8 data[6]; - - data[0] = MAX9877_INPUT_MODE; - for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) - data[i + 1] = max9877_regs[i]; - - if (i2c_master_send(i2c, data, 6) != 6) - dev_err(&i2c->dev, "i2c write failed\n"); -} +static struct reg_default max9877_regs[] = { + { 0, 0x40 }, + { 1, 0x00 }, + { 2, 0x00 }, + { 3, 0x00 }, + { 4, 0x49 }, +}; static int max9877_get_reg(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -45,8 +39,14 @@ static int max9877_get_reg(struct snd_kcontrol *kcontrol, unsigned int shift = mc->shift; unsigned int mask = mc->max; unsigned int invert = mc->invert; + unsigned int val; + int ret; - ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; + ret = regmap_read(regmap, reg, &val); + if (ret != 0) + return ret; + + ucontrol->value.integer.value[0] = (val >> shift) & mask; if (invert) ucontrol->value.integer.value[0] = @@ -65,18 +65,21 @@ static int max9877_set_reg(struct snd_kcontrol *kcontrol, unsigned int mask = mc->max; unsigned int invert = mc->invert; unsigned int val = (ucontrol->value.integer.value[0] & mask); + bool change; + int ret; if (invert) val = mask - val; - if (((max9877_regs[reg] >> shift) & mask) == val) + ret = regmap_update_bits_check(regmap, reg, mask << shift, + val << shift, &change); + if (ret != 0) + return ret; + + if (change) + return 1; + else return 0; - - max9877_regs[reg] &= ~(mask << shift); - max9877_regs[reg] |= val << shift; - max9877_write_regs(); - - return 1; } static int max9877_get_2reg(struct snd_kcontrol *kcontrol, @@ -88,9 +91,18 @@ static int max9877_get_2reg(struct snd_kcontrol *kcontrol, unsigned int reg2 = mc->rreg; unsigned int shift = mc->shift; unsigned int mask = mc->max; + unsigned int val; + int ret; - ucontrol->value.integer.value[0] = (max9877_regs[reg] >> shift) & mask; - ucontrol->value.integer.value[1] = (max9877_regs[reg2] >> shift) & mask; + ret = regmap_read(regmap, reg, &val); + if (ret != 0) + return ret; + ucontrol->value.integer.value[0] = (val >> shift) & mask; + + ret = regmap_read(regmap, reg2, &val); + if (ret != 0) + return ret; + ucontrol->value.integer.value[1] = (val >> shift) & mask; return 0; } @@ -106,77 +118,99 @@ static int max9877_set_2reg(struct snd_kcontrol *kcontrol, unsigned int mask = mc->max; unsigned int val = (ucontrol->value.integer.value[0] & mask); unsigned int val2 = (ucontrol->value.integer.value[1] & mask); - unsigned int change = 0; + bool change1, change2; + int ret; - if (((max9877_regs[reg] >> shift) & mask) != val) - change = 1; + ret = regmap_update_bits_check(regmap, reg, mask << shift, + val << shift, &change1); + if (ret != 0) + return ret; - if (((max9877_regs[reg2] >> shift) & mask) != val2) - change = 1; + ret = regmap_update_bits_check(regmap, reg2, mask << shift, + val2 << shift, &change2); + if (ret != 0) + return ret; - if (change) { - max9877_regs[reg] &= ~(mask << shift); - max9877_regs[reg] |= val << shift; - max9877_regs[reg2] &= ~(mask << shift); - max9877_regs[reg2] |= val2 << shift; - max9877_write_regs(); - } - - return change; + if (change1 || change2) + return 1; + else + return 0; } static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - u8 value = max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK; + unsigned int val; + int ret; - if (value) - value -= 1; + ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val); + if (ret != 0) + return ret; + + val &= MAX9877_OUTMODE_MASK; + if (val) + val--; + + ucontrol->value.integer.value[0] = val; - ucontrol->value.integer.value[0] = value; return 0; } static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - u8 value = ucontrol->value.integer.value[0]; + unsigned int val; + bool change; + int ret; - value += 1; + val = ucontrol->value.integer.value[0] + 1; - if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OUTMODE_MASK) == value) + ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE, + MAX9877_OUTMODE_MASK, val, &change); + if (ret != 0) + return ret; + + if (change) + return 1; + else return 0; - - max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OUTMODE_MASK; - max9877_regs[MAX9877_OUTPUT_MODE] |= value; - max9877_write_regs(); - return 1; } static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - u8 value = (max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK); + unsigned int val; + int ret; - value = value >> MAX9877_OSC_OFFSET; + ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val); + if (ret != 0) + return ret; + + val &= MAX9877_OSC_MASK; + val >>= MAX9877_OSC_OFFSET; + + ucontrol->value.integer.value[0] = val; - ucontrol->value.integer.value[0] = value; return 0; } static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - u8 value = ucontrol->value.integer.value[0]; + unsigned int val; + bool change; + int ret; - value = value << MAX9877_OSC_OFFSET; - if ((max9877_regs[MAX9877_OUTPUT_MODE] & MAX9877_OSC_MASK) == value) + val = ucontrol->value.integer.value[0] << MAX9877_OSC_OFFSET; + ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE, + MAX9877_OSC_MASK, val, &change); + if (ret != 0) + return ret; + + if (change) + return 1; + else return 0; - - max9877_regs[MAX9877_OUTPUT_MODE] &= ~MAX9877_OSC_MASK; - max9877_regs[MAX9877_OUTPUT_MODE] |= value; - max9877_write_regs(); - return 1; } static const unsigned int max9877_pgain_tlv[] = { @@ -258,19 +292,34 @@ int max9877_add_controls(struct snd_soc_codec *codec) } EXPORT_SYMBOL_GPL(max9877_add_controls); +static const struct regmap_config max9877_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .reg_defaults = max9877_regs, + .num_reg_defaults = ARRAY_SIZE(max9877_regs), + .cache_type = REGCACHE_RBTREE, +}; + static int max9877_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { - i2c = client; + int i; - max9877_write_regs(); + regmap = devm_regmap_init_i2c(client, &max9877_regmap); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Ensure the device is in reset state */ + for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) + regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); return 0; } static int max9877_i2c_remove(struct i2c_client *client) { - i2c = NULL; + regmap = NULL; return 0; } From d76a96174b31bd916c1dfaa81a3db82fc8c54b91 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 13 Aug 2013 13:20:15 +0100 Subject: [PATCH 2/3] ASoC: max9877: Convert to standard CODEC driver Signed-off-by: Mark Brown --- sound/soc/codecs/max9877.c | 256 +++++-------------------------------- 1 file changed, 31 insertions(+), 225 deletions(-) diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 7e2fe5023fb2..8505b401d3c4 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -30,189 +30,6 @@ static struct reg_default max9877_regs[] = { { 4, 0x49 }, }; -static int max9877_get_reg(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int mask = mc->max; - unsigned int invert = mc->invert; - unsigned int val; - int ret; - - ret = regmap_read(regmap, reg, &val); - if (ret != 0) - return ret; - - ucontrol->value.integer.value[0] = (val >> shift) & mask; - - if (invert) - ucontrol->value.integer.value[0] = - mask - ucontrol->value.integer.value[0]; - - return 0; -} - -static int max9877_set_reg(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int mask = mc->max; - unsigned int invert = mc->invert; - unsigned int val = (ucontrol->value.integer.value[0] & mask); - bool change; - int ret; - - if (invert) - val = mask - val; - - ret = regmap_update_bits_check(regmap, reg, mask << shift, - val << shift, &change); - if (ret != 0) - return ret; - - if (change) - return 1; - else - return 0; -} - -static int max9877_get_2reg(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - unsigned int mask = mc->max; - unsigned int val; - int ret; - - ret = regmap_read(regmap, reg, &val); - if (ret != 0) - return ret; - ucontrol->value.integer.value[0] = (val >> shift) & mask; - - ret = regmap_read(regmap, reg2, &val); - if (ret != 0) - return ret; - ucontrol->value.integer.value[1] = (val >> shift) & mask; - - return 0; -} - -static int max9877_set_2reg(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - unsigned int mask = mc->max; - unsigned int val = (ucontrol->value.integer.value[0] & mask); - unsigned int val2 = (ucontrol->value.integer.value[1] & mask); - bool change1, change2; - int ret; - - ret = regmap_update_bits_check(regmap, reg, mask << shift, - val << shift, &change1); - if (ret != 0) - return ret; - - ret = regmap_update_bits_check(regmap, reg2, mask << shift, - val2 << shift, &change2); - if (ret != 0) - return ret; - - if (change1 || change2) - return 1; - else - return 0; -} - -static int max9877_get_out_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int val; - int ret; - - ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val); - if (ret != 0) - return ret; - - val &= MAX9877_OUTMODE_MASK; - if (val) - val--; - - ucontrol->value.integer.value[0] = val; - - return 0; -} - -static int max9877_set_out_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int val; - bool change; - int ret; - - val = ucontrol->value.integer.value[0] + 1; - - ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE, - MAX9877_OUTMODE_MASK, val, &change); - if (ret != 0) - return ret; - - if (change) - return 1; - else - return 0; -} - -static int max9877_get_osc_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int val; - int ret; - - ret = regmap_read(regmap, MAX9877_OUTPUT_MODE, &val); - if (ret != 0) - return ret; - - val &= MAX9877_OSC_MASK; - val >>= MAX9877_OSC_OFFSET; - - ucontrol->value.integer.value[0] = val; - - return 0; -} - -static int max9877_set_osc_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - unsigned int val; - bool change; - int ret; - - val = ucontrol->value.integer.value[0] << MAX9877_OSC_OFFSET; - ret = regmap_update_bits_check(regmap, MAX9877_OUTPUT_MODE, - MAX9877_OSC_MASK, val, &change); - if (ret != 0) - return ret; - - if (change) - return 1; - else - return 0; -} - static const unsigned int max9877_pgain_tlv[] = { TLV_DB_RANGE_HEAD(2), 0, 1, TLV_DB_SCALE_ITEM(0, 900, 0), @@ -246,51 +63,40 @@ static const char *max9877_osc_mode[] = { }; static const struct soc_enum max9877_enum[] = { - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_out_mode), max9877_out_mode), - SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), + SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, 0, ARRAY_SIZE(max9877_out_mode), + max9877_out_mode), + SOC_ENUM_SINGLE(MAX9877_OUTPUT_MODE, MAX9877_OSC_OFFSET, + ARRAY_SIZE(max9877_osc_mode), max9877_osc_mode), }; static const struct snd_kcontrol_new max9877_controls[] = { - SOC_SINGLE_EXT_TLV("MAX9877 PGAINA Playback Volume", - MAX9877_INPUT_MODE, 0, 2, 0, - max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), - SOC_SINGLE_EXT_TLV("MAX9877 PGAINB Playback Volume", - MAX9877_INPUT_MODE, 2, 2, 0, - max9877_get_reg, max9877_set_reg, max9877_pgain_tlv), - SOC_SINGLE_EXT_TLV("MAX9877 Amp Speaker Playback Volume", - MAX9877_SPK_VOLUME, 0, 31, 0, - max9877_get_reg, max9877_set_reg, max9877_output_tlv), - SOC_DOUBLE_R_EXT_TLV("MAX9877 Amp HP Playback Volume", - MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, - max9877_get_2reg, max9877_set_2reg, max9877_output_tlv), - SOC_SINGLE_EXT("MAX9877 INB Stereo Switch", - MAX9877_INPUT_MODE, 4, 1, 1, - max9877_get_reg, max9877_set_reg), - SOC_SINGLE_EXT("MAX9877 INA Stereo Switch", - MAX9877_INPUT_MODE, 5, 1, 1, - max9877_get_reg, max9877_set_reg), - SOC_SINGLE_EXT("MAX9877 Zero-crossing detection Switch", - MAX9877_INPUT_MODE, 6, 1, 0, - max9877_get_reg, max9877_set_reg), - SOC_SINGLE_EXT("MAX9877 Bypass Mode Switch", - MAX9877_OUTPUT_MODE, 6, 1, 0, - max9877_get_reg, max9877_set_reg), - SOC_SINGLE_EXT("MAX9877 Shutdown Mode Switch", - MAX9877_OUTPUT_MODE, 7, 1, 1, - max9877_get_reg, max9877_set_reg), - SOC_ENUM_EXT("MAX9877 Output Mode", max9877_enum[0], - max9877_get_out_mode, max9877_set_out_mode), - SOC_ENUM_EXT("MAX9877 Oscillator Mode", max9877_enum[1], - max9877_get_osc_mode, max9877_set_osc_mode), + SOC_SINGLE_TLV("MAX9877 PGAINA Playback Volume", + MAX9877_INPUT_MODE, 0, 2, 0, max9877_pgain_tlv), + SOC_SINGLE_TLV("MAX9877 PGAINB Playback Volume", + MAX9877_INPUT_MODE, 2, 2, 0, max9877_pgain_tlv), + SOC_SINGLE_TLV("MAX9877 Amp Speaker Playback Volume", + MAX9877_SPK_VOLUME, 0, 31, 0, max9877_output_tlv), + SOC_DOUBLE_R_TLV("MAX9877 Amp HP Playback Volume", + MAX9877_HPL_VOLUME, MAX9877_HPR_VOLUME, 0, 31, 0, + max9877_output_tlv), + SOC_SINGLE("MAX9877 INB Stereo Switch", + MAX9877_INPUT_MODE, 4, 1, 1), + SOC_SINGLE("MAX9877 INA Stereo Switch", + MAX9877_INPUT_MODE, 5, 1, 1), + SOC_SINGLE("MAX9877 Zero-crossing detection Switch", + MAX9877_INPUT_MODE, 6, 1, 0), + SOC_SINGLE("MAX9877 Bypass Mode Switch", + MAX9877_OUTPUT_MODE, 6, 1, 0), + SOC_SINGLE("MAX9877 Shutdown Mode Switch", + MAX9877_OUTPUT_MODE, 7, 1, 1), + SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]), + SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]), }; -/* This function is called from ASoC machine driver */ -int max9877_add_controls(struct snd_soc_codec *codec) -{ - return snd_soc_add_codec_controls(codec, max9877_controls, - ARRAY_SIZE(max9877_controls)); -} -EXPORT_SYMBOL_GPL(max9877_add_controls); +static const struct snd_soc_codec_driver max9877_codec = { + .controls = max9877_controls, + .num_controls = ARRAY_SIZE(max9877_controls), +}; static const struct regmap_config max9877_regmap = { .reg_bits = 8, @@ -314,12 +120,12 @@ static int max9877_i2c_probe(struct i2c_client *client, for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); - return 0; + return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0); } static int max9877_i2c_remove(struct i2c_client *client) { - regmap = NULL; + snd_soc_unregister_codec(&client->dev); return 0; } From 5cf9da8aacbfaed72ada8c195859f49d5d7f5f6c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 13 Aug 2013 13:32:03 +0100 Subject: [PATCH 3/3] ASoC: max9877: Add basic DAPM support This does not fully map the power control available within the device but it provides the hooks for routing signals through the device and allows automatic management of the device low power mode. Signed-off-by: Mark Brown --- sound/soc/codecs/max9877.c | 39 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 8505b401d3c4..29549cdbf4c1 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -87,15 +87,50 @@ static const struct snd_kcontrol_new max9877_controls[] = { MAX9877_INPUT_MODE, 6, 1, 0), SOC_SINGLE("MAX9877 Bypass Mode Switch", MAX9877_OUTPUT_MODE, 6, 1, 0), - SOC_SINGLE("MAX9877 Shutdown Mode Switch", - MAX9877_OUTPUT_MODE, 7, 1, 1), SOC_ENUM("MAX9877 Output Mode", max9877_enum[0]), SOC_ENUM("MAX9877 Oscillator Mode", max9877_enum[1]), }; +static const struct snd_soc_dapm_widget max9877_dapm_widgets[] = { +SND_SOC_DAPM_INPUT("INA1"), +SND_SOC_DAPM_INPUT("INA2"), +SND_SOC_DAPM_INPUT("INB1"), +SND_SOC_DAPM_INPUT("INB2"), +SND_SOC_DAPM_INPUT("RXIN+"), +SND_SOC_DAPM_INPUT("RXIN-"), + +SND_SOC_DAPM_PGA("SHDN", MAX9877_OUTPUT_MODE, 7, 1, NULL, 0), + +SND_SOC_DAPM_OUTPUT("OUT+"), +SND_SOC_DAPM_OUTPUT("OUT-"), +SND_SOC_DAPM_OUTPUT("HPL"), +SND_SOC_DAPM_OUTPUT("HPR"), +}; + +static const struct snd_soc_dapm_route max9877_dapm_routes[] = { + { "SHDN", NULL, "INA1" }, + { "SHDN", NULL, "INA2" }, + { "SHDN", NULL, "INB1" }, + { "SHDN", NULL, "INB2" }, + + { "OUT+", NULL, "RXIN+" }, + { "OUT+", NULL, "SHDN" }, + + { "OUT-", NULL, "SHDN" }, + { "OUT-", NULL, "RXIN-" }, + + { "HPL", NULL, "SHDN" }, + { "HPR", NULL, "SHDN" }, +}; + static const struct snd_soc_codec_driver max9877_codec = { .controls = max9877_controls, .num_controls = ARRAY_SIZE(max9877_controls), + + .dapm_widgets = max9877_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(max9877_dapm_widgets), + .dapm_routes = max9877_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(max9877_dapm_routes), }; static const struct regmap_config max9877_regmap = {