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.c103
1 files changed, 24 insertions, 79 deletions
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index ee4fb201de60..1f1ac8110bef 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -29,7 +29,6 @@
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <sound/tpa6130a2-plat.h> 30#include <sound/tpa6130a2-plat.h>
31#include <sound/soc.h> 31#include <sound/soc.h>
32#include <sound/soc-dapm.h>
33#include <sound/tlv.h> 32#include <sound/tlv.h>
34 33
35#include "tpa6130a2.h" 34#include "tpa6130a2.h"
@@ -42,7 +41,7 @@ struct tpa6130a2_data {
42 unsigned char regs[TPA6130A2_CACHEREGNUM]; 41 unsigned char regs[TPA6130A2_CACHEREGNUM];
43 struct regulator *supply; 42 struct regulator *supply;
44 int power_gpio; 43 int power_gpio;
45 unsigned char power_state; 44 u8 power_state:1;
46 enum tpa_model id; 45 enum tpa_model id;
47}; 46};
48 47
@@ -78,8 +77,10 @@ static int tpa6130a2_i2c_write(int reg, u8 value)
78 77
79 if (data->power_state) { 78 if (data->power_state) {
80 val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value); 79 val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value);
81 if (val < 0) 80 if (val < 0) {
82 dev_err(&tpa6130a2_client->dev, "Write failed\n"); 81 dev_err(&tpa6130a2_client->dev, "Write failed\n");
82 return val;
83 }
83 } 84 }
84 85
85 /* Either powered on or off, we save the context */ 86 /* Either powered on or off, we save the context */
@@ -115,7 +116,7 @@ static int tpa6130a2_initialize(void)
115 return ret; 116 return ret;
116} 117}
117 118
118static int tpa6130a2_power(int power) 119static int tpa6130a2_power(u8 power)
119{ 120{
120 struct tpa6130a2_data *data; 121 struct tpa6130a2_data *data;
121 u8 val; 122 u8 val;
@@ -125,17 +126,19 @@ static int tpa6130a2_power(int power)
125 data = i2c_get_clientdata(tpa6130a2_client); 126 data = i2c_get_clientdata(tpa6130a2_client);
126 127
127 mutex_lock(&data->mutex); 128 mutex_lock(&data->mutex);
128 if (power && !data->power_state) { 129 if (power == data->power_state)
129 /* Power on */ 130 goto exit;
130 if (data->power_gpio >= 0)
131 gpio_set_value(data->power_gpio, 1);
132 131
132 if (power) {
133 ret = regulator_enable(data->supply); 133 ret = regulator_enable(data->supply);
134 if (ret != 0) { 134 if (ret != 0) {
135 dev_err(&tpa6130a2_client->dev, 135 dev_err(&tpa6130a2_client->dev,
136 "Failed to enable supply: %d\n", ret); 136 "Failed to enable supply: %d\n", ret);
137 goto exit; 137 goto exit;
138 } 138 }
139 /* Power on */
140 if (data->power_gpio >= 0)
141 gpio_set_value(data->power_gpio, 1);
139 142
140 data->power_state = 1; 143 data->power_state = 1;
141 ret = tpa6130a2_initialize(); 144 ret = tpa6130a2_initialize();
@@ -148,12 +151,7 @@ static int tpa6130a2_power(int power)
148 data->power_state = 0; 151 data->power_state = 0;
149 goto exit; 152 goto exit;
150 } 153 }
151 154 } else {
152 /* Clear SWS */
153 val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
154 val &= ~TPA6130A2_SWS;
155 tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
156 } else if (!power && data->power_state) {
157 /* set SWS */ 155 /* set SWS */
158 val = tpa6130a2_read(TPA6130A2_REG_CONTROL); 156 val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
159 val |= TPA6130A2_SWS; 157 val |= TPA6130A2_SWS;
@@ -298,6 +296,7 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
298 /* Enable amplifier */ 296 /* Enable amplifier */
299 val = tpa6130a2_read(TPA6130A2_REG_CONTROL); 297 val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
300 val |= channel; 298 val |= channel;
299 val &= ~TPA6130A2_SWS;
301 tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); 300 tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
302 301
303 /* Unmute channel */ 302 /* Unmute channel */
@@ -318,72 +317,24 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
318 } 317 }
319} 318}
320 319
321static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w, 320int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable)
322 struct snd_kcontrol *kcontrol, int event)
323{
324 switch (event) {
325 case SND_SOC_DAPM_POST_PMU:
326 tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1);
327 break;
328 case SND_SOC_DAPM_POST_PMD:
329 tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0);
330 break;
331 }
332 return 0;
333}
334
335static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
336 struct snd_kcontrol *kcontrol, int event)
337{
338 switch (event) {
339 case SND_SOC_DAPM_POST_PMU:
340 tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1);
341 break;
342 case SND_SOC_DAPM_POST_PMD:
343 tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0);
344 break;
345 }
346 return 0;
347}
348
349static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
350 struct snd_kcontrol *kcontrol, int event)
351{ 321{
352 int ret = 0; 322 int ret = 0;
353 323 if (enable) {
354 switch (event) {
355 case SND_SOC_DAPM_POST_PMU:
356 ret = tpa6130a2_power(1); 324 ret = tpa6130a2_power(1);
357 break; 325 if (ret < 0)
358 case SND_SOC_DAPM_POST_PMD: 326 return ret;
327 tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
328 1);
329 } else {
330 tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
331 0);
359 ret = tpa6130a2_power(0); 332 ret = tpa6130a2_power(0);
360 break;
361 } 333 }
334
362 return ret; 335 return ret;
363} 336}
364 337EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable);
365static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
366 SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM,
367 0, 0, NULL, 0, tpa6130a2_left_event,
368 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
369 SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM,
370 0, 0, NULL, 0, tpa6130a2_right_event,
371 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
372 SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM,
373 0, 0, tpa6130a2_supply_event,
374 SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
375 /* Outputs */
376 SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Left"),
377 SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Right"),
378};
379
380static const struct snd_soc_dapm_route audio_map[] = {
381 {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"},
382 {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"},
383
384 {"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"},
385 {"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"},
386};
387 338
388int tpa6130a2_add_controls(struct snd_soc_codec *codec) 339int tpa6130a2_add_controls(struct snd_soc_codec *codec)
389{ 340{
@@ -394,18 +345,12 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
394 345
395 data = i2c_get_clientdata(tpa6130a2_client); 346 data = i2c_get_clientdata(tpa6130a2_client);
396 347
397 snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
398 ARRAY_SIZE(tpa6130a2_dapm_widgets));
399
400 snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
401
402 if (data->id == TPA6140A2) 348 if (data->id == TPA6140A2)
403 return snd_soc_add_controls(codec, tpa6140a2_controls, 349 return snd_soc_add_controls(codec, tpa6140a2_controls,
404 ARRAY_SIZE(tpa6140a2_controls)); 350 ARRAY_SIZE(tpa6140a2_controls));
405 else 351 else
406 return snd_soc_add_controls(codec, tpa6130a2_controls, 352 return snd_soc_add_controls(codec, tpa6130a2_controls,
407 ARRAY_SIZE(tpa6130a2_controls)); 353 ARRAY_SIZE(tpa6130a2_controls));
408
409} 354}
410EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); 355EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);
411 356