aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/tpa6130a2.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/tpa6130a2.c')
-rw-r--r--sound/soc/codecs/tpa6130a2.c99
1 files changed, 92 insertions, 7 deletions
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 958d49c969ac..31f67b527ca1 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -46,6 +46,9 @@ static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
46 "AVdd", 46 "AVdd",
47}; 47};
48 48
49#define TPA6130A2_GAIN_MAX 0x3f
50#define TPA6140A2_GAIN_MAX 0x1f
51
49/* This struct is used to save the context */ 52/* This struct is used to save the context */
50struct tpa6130a2_data { 53struct tpa6130a2_data {
51 struct mutex mutex; 54 struct mutex mutex;
@@ -53,6 +56,8 @@ struct tpa6130a2_data {
53 struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES]; 56 struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES];
54 int power_gpio; 57 int power_gpio;
55 unsigned char power_state; 58 unsigned char power_state;
59 enum tpa_model id;
60 int gain_limit;
56}; 61};
57 62
58static int tpa6130a2_i2c_read(int reg) 63static int tpa6130a2_i2c_read(int reg)
@@ -175,6 +180,40 @@ exit:
175 return ret; 180 return ret;
176} 181}
177 182
183static 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;
212out:
213 mutex_unlock(&data->mutex);
214 return 0;
215}
216
178static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol, 217static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
179 struct snd_ctl_elem_value *ucontrol) 218 struct snd_ctl_elem_value *ucontrol)
180{ 219{
@@ -238,6 +277,15 @@ static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
238 return 1; 277 return 1;
239} 278}
240 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
241/* 289/*
242 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going 290 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
243 * down in gain. 291 * down in gain.
@@ -257,10 +305,22 @@ static const unsigned int tpa6130_tlv[] = {
257}; 305};
258 306
259static const struct snd_kcontrol_new tpa6130a2_controls[] = { 307static const struct snd_kcontrol_new tpa6130a2_controls[] = {
260 SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume", 308 SOC_SINGLE_EXT_TLV_TPA("TPA6130A2 Headphone Playback Volume",
261 TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, 309 TPA6130A2_REG_VOL_MUTE, 0, TPA6130A2_GAIN_MAX, 0,
262 tpa6130a2_get_reg, tpa6130a2_set_reg, 310 tpa6130_tlv),
263 tpa6130_tlv), 311};
312
313static const unsigned int tpa6140_tlv[] = {
314 TLV_DB_RANGE_HEAD(3),
315 0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0),
316 9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0),
317 17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0),
318};
319
320static const struct snd_kcontrol_new tpa6140a2_controls[] = {
321 SOC_SINGLE_EXT_TLV_TPA("TPA6140A2 Headphone Playback Volume",
322 TPA6130A2_REG_VOL_MUTE, 1, TPA6140A2_GAIN_MAX, 0,
323 tpa6140_tlv),
264}; 324};
265 325
266/* 326/*
@@ -368,13 +428,22 @@ static const struct snd_soc_dapm_route audio_map[] = {
368 428
369int tpa6130a2_add_controls(struct snd_soc_codec *codec) 429int tpa6130a2_add_controls(struct snd_soc_codec *codec)
370{ 430{
431 struct tpa6130a2_data *data;
432
433 BUG_ON(tpa6130a2_client == NULL);
434 data = i2c_get_clientdata(tpa6130a2_client);
435
371 snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets, 436 snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
372 ARRAY_SIZE(tpa6130a2_dapm_widgets)); 437 ARRAY_SIZE(tpa6130a2_dapm_widgets));
373 438
374 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); 439 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
375 440
376 return snd_soc_add_controls(codec, tpa6130a2_controls, 441 if (data->id == TPA6140A2)
377 ARRAY_SIZE(tpa6130a2_controls)); 442 return snd_soc_add_controls(codec, tpa6140a2_controls,
443 ARRAY_SIZE(tpa6140a2_controls));
444 else
445 return snd_soc_add_controls(codec, tpa6130a2_controls,
446 ARRAY_SIZE(tpa6130a2_controls));
378 447
379} 448}
380EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); 449EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
@@ -407,6 +476,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
407 476
408 pdata = client->dev.platform_data; 477 pdata = client->dev.platform_data;
409 data->power_gpio = pdata->power_gpio; 478 data->power_gpio = pdata->power_gpio;
479 data->id = pdata->id;
410 480
411 mutex_init(&data->mutex); 481 mutex_init(&data->mutex);
412 482
@@ -425,20 +495,35 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
425 gpio_direction_output(data->power_gpio, 0); 495 gpio_direction_output(data->power_gpio, 0);
426 } 496 }
427 497
428 switch (pdata->id) { 498 switch (data->id) {
429 case TPA6130A2: 499 case TPA6130A2:
430 for (i = 0; i < ARRAY_SIZE(data->supplies); i++) 500 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
431 data->supplies[i].supply = tpa6130a2_supply_names[i]; 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;
432 break; 507 break;
433 case TPA6140A2: 508 case TPA6140A2:
434 for (i = 0; i < ARRAY_SIZE(data->supplies); i++) 509 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
435 data->supplies[i].supply = tpa6140a2_supply_names[i];; 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;
436 break; 516 break;
437 default: 517 default:
438 dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n", 518 dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
439 pdata->id); 519 pdata->id);
440 for (i = 0; i < ARRAY_SIZE(data->supplies); i++) 520 for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
441 data->supplies[i].supply = tpa6130a2_supply_names[i]; 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;
442 } 527 }
443 528
444 ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), 529 ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),