Commit 6f3991152f20933b77eff30413e893bf1a15e578

Authored by Peter Ujfalusi
Committed by Liam Girdwood
1 parent 5193d62f18

ASoC: tpa6130a2: Support for limiting gain

Add support for platform dependent gain limiting on the
tpa6130a2 (and tpa6140a2) Headset amplifier.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com>
Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>

Showing 2 changed files with 69 additions and 8 deletions Side-by-side Diff

include/sound/tpa6130a2-plat.h
... ... @@ -31,6 +31,7 @@
31 31 struct tpa6130a2_platform_data {
32 32 enum tpa_model id;
33 33 int power_gpio;
  34 + int limit_gain;
34 35 };
35 36  
36 37 #endif
sound/soc/codecs/tpa6130a2.c
... ... @@ -46,6 +46,9 @@
46 46 "AVdd",
47 47 };
48 48  
  49 +#define TPA6130A2_GAIN_MAX 0x3f
  50 +#define TPA6140A2_GAIN_MAX 0x1f
  51 +
49 52 /* This struct is used to save the context */
50 53 struct tpa6130a2_data {
51 54 struct mutex mutex;
... ... @@ -54,6 +57,7 @@
54 57 int power_gpio;
55 58 unsigned char power_state;
56 59 enum tpa_model id;
  60 + int gain_limit;
57 61 };
58 62  
59 63 static int tpa6130a2_i2c_read(int reg)
... ... @@ -176,6 +180,40 @@
176 180 return ret;
177 181 }
178 182  
  183 +static int tpa6130a2_info_volsw(struct snd_kcontrol *kcontrol,
  184 + struct snd_ctl_elem_info *uinfo)
  185 +{
  186 + struct soc_mixer_control *mc =
  187 + (struct soc_mixer_control *)kcontrol->private_value;
  188 + struct tpa6130a2_data *data;
  189 +
  190 + BUG_ON(tpa6130a2_client == NULL);
  191 + data = i2c_get_clientdata(tpa6130a2_client);
  192 +
  193 + mutex_lock(&data->mutex);
  194 + switch (mc->reg) {
  195 + case TPA6130A2_REG_VOL_MUTE:
  196 + if (data->gain_limit != mc->max)
  197 + mc->max = data->gain_limit;
  198 + break;
  199 + default:
  200 + dev_err(&tpa6130a2_client->dev,
  201 + "Invalid register: 0x02%x\n", mc->reg);
  202 + goto out;
  203 + }
  204 + if (unlikely(mc->max == 1))
  205 + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
  206 + else
  207 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  208 +
  209 + uinfo->count = 1;
  210 + uinfo->value.integer.min = 0;
  211 + uinfo->value.integer.max = mc->max;
  212 +out:
  213 + mutex_unlock(&data->mutex);
  214 + return 0;
  215 +}
  216 +
179 217 static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
180 218 struct snd_ctl_elem_value *ucontrol)
181 219 {
... ... @@ -239,6 +277,15 @@
239 277 return 1;
240 278 }
241 279  
  280 +#define SOC_SINGLE_EXT_TLV_TPA(xname, xreg, xshift, xmax, xinvert, tlv_array) \
  281 +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
  282 + .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
  283 + SNDRV_CTL_ELEM_ACCESS_READWRITE,\
  284 + .tlv.p = (tlv_array), \
  285 + .info = tpa6130a2_info_volsw, \
  286 + .get = tpa6130a2_get_reg, .put = tpa6130a2_set_reg, \
  287 + .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
  288 +
242 289 /*
243 290 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
244 291 * down in gain.
... ... @@ -258,10 +305,9 @@
258 305 };
259 306  
260 307 static const struct snd_kcontrol_new tpa6130a2_controls[] = {
261   - SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
262   - TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
263   - tpa6130a2_get_reg, tpa6130a2_set_reg,
264   - tpa6130_tlv),
  308 + SOC_SINGLE_EXT_TLV_TPA("TPA6130A2 Headphone Playback Volume",
  309 + TPA6130A2_REG_VOL_MUTE, 0, TPA6130A2_GAIN_MAX, 0,
  310 + tpa6130_tlv),
265 311 };
266 312  
267 313 static const unsigned int tpa6140_tlv[] = {
... ... @@ -272,10 +318,9 @@
272 318 };
273 319  
274 320 static const struct snd_kcontrol_new tpa6140a2_controls[] = {
275   - SOC_SINGLE_EXT_TLV("TPA6140A2 Headphone Playback Volume",
276   - TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
277   - tpa6130a2_get_reg, tpa6130a2_set_reg,
278   - tpa6140_tlv),
  321 + SOC_SINGLE_EXT_TLV_TPA("TPA6140A2 Headphone Playback Volume",
  322 + TPA6130A2_REG_VOL_MUTE, 1, TPA6140A2_GAIN_MAX, 0,
  323 + tpa6140_tlv),
279 324 };
280 325  
281 326 /*
282 327  
283 328  
... ... @@ -454,16 +499,31 @@
454 499 case TPA6130A2:
455 500 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
456 501 data->supplies[i].supply = tpa6130a2_supply_names[i];
  502 + if (pdata->limit_gain > 0 &&
  503 + pdata->limit_gain < TPA6130A2_GAIN_MAX)
  504 + data->gain_limit = pdata->limit_gain;
  505 + else
  506 + data->gain_limit = TPA6130A2_GAIN_MAX;
457 507 break;
458 508 case TPA6140A2:
459 509 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
460 510 data->supplies[i].supply = tpa6140a2_supply_names[i];;
  511 + if (pdata->limit_gain > 0 &&
  512 + pdata->limit_gain < TPA6140A2_GAIN_MAX)
  513 + data->gain_limit = pdata->limit_gain;
  514 + else
  515 + data->gain_limit = TPA6140A2_GAIN_MAX;
461 516 break;
462 517 default:
463 518 dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
464 519 pdata->id);
465 520 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
466 521 data->supplies[i].supply = tpa6130a2_supply_names[i];
  522 + if (pdata->limit_gain > 0 &&
  523 + pdata->limit_gain < TPA6130A2_GAIN_MAX)
  524 + data->gain_limit = pdata->limit_gain;
  525 + else
  526 + data->gain_limit = TPA6130A2_GAIN_MAX;
467 527 }
468 528  
469 529 ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),