summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorHelen Koike <helen.koike@collabora.co.uk>2016-06-23 15:23:13 -0400
committerMark Brown <broonie@kernel.org>2016-06-26 07:28:13 -0400
commit6d2de5ab4328718302c54b20222c6b1a574c3fce (patch)
tree9d399249d7f5ae34104f54d12a1bb5220e510de5 /sound
parente01d700c399d8d899850a1e5fad5227a9d976304 (diff)
ASoC: tpa6130a2: Add DAPM support
Add DAPM support and updated rx51 accordingly. As a consequence: - the exported function tpa6130a2_stereo_enable is not needed anymore - the mutex is dealt in the DAPM - the power state is tracked by the DAPM Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> [koike: port for upstream] Signed-off-by: Helen Koike <helen.koike@collabora.co.uk> Tested-by: Sebastian Reichel <sre@kernel.org> Reviewed-by: Sebastian Reichel <sre@kernel.org> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/tpa6130a2.c185
-rw-r--r--sound/soc/codecs/tpa6130a2.h11
-rw-r--r--sound/soc/omap/rx51.c23
3 files changed, 89 insertions, 130 deletions
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c
index 81bf5848b743..9da1dd12f839 100644
--- a/sound/soc/codecs/tpa6130a2.c
+++ b/sound/soc/codecs/tpa6130a2.c
@@ -41,79 +41,74 @@ enum tpa_model {
41 TPA6140A2, 41 TPA6140A2,
42}; 42};
43 43
44static struct i2c_client *tpa6130a2_client;
45
46/* This struct is used to save the context */ 44/* This struct is used to save the context */
47struct tpa6130a2_data { 45struct tpa6130a2_data {
48 struct mutex mutex; 46 struct device *dev;
49 struct regmap *regmap; 47 struct regmap *regmap;
50 struct regulator *supply; 48 struct regulator *supply;
51 int power_gpio; 49 int power_gpio;
52 u8 power_state:1;
53 enum tpa_model id; 50 enum tpa_model id;
54}; 51};
55 52
56static int tpa6130a2_power(u8 power) 53static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable)
57{ 54{
58 struct tpa6130a2_data *data; 55 int ret;
59 int ret = 0;
60
61 if (WARN_ON(!tpa6130a2_client))
62 return -EINVAL;
63 data = i2c_get_clientdata(tpa6130a2_client);
64
65 mutex_lock(&data->mutex);
66 if (power == data->power_state)
67 goto exit;
68 56
69 if (power) { 57 if (enable) {
70 ret = regulator_enable(data->supply); 58 ret = regulator_enable(data->supply);
71 if (ret != 0) { 59 if (ret != 0) {
72 dev_err(&tpa6130a2_client->dev, 60 dev_err(data->dev,
73 "Failed to enable supply: %d\n", ret); 61 "Failed to enable supply: %d\n", ret);
74 goto exit; 62 return ret;
75 } 63 }
76 /* Power on */ 64 /* Power on */
77 if (data->power_gpio >= 0) 65 if (data->power_gpio >= 0)
78 gpio_set_value(data->power_gpio, 1); 66 gpio_set_value(data->power_gpio, 1);
79
80 data->power_state = 1;
81 ret = regcache_sync(data->regmap);
82 if (ret < 0) {
83 dev_err(&tpa6130a2_client->dev,
84 "Failed to initialize chip\n");
85 if (data->power_gpio >= 0)
86 gpio_set_value(data->power_gpio, 0);
87 regulator_disable(data->supply);
88 data->power_state = 0;
89 goto exit;
90 }
91 } else { 67 } else {
92 /* set SWS */
93 regmap_update_bits(data->regmap, TPA6130A2_REG_CONTROL,
94 TPA6130A2_SWS, TPA6130A2_SWS);
95
96 /* Power off */ 68 /* Power off */
97 if (data->power_gpio >= 0) 69 if (data->power_gpio >= 0)
98 gpio_set_value(data->power_gpio, 0); 70 gpio_set_value(data->power_gpio, 0);
99 71
100 ret = regulator_disable(data->supply); 72 ret = regulator_disable(data->supply);
101 if (ret != 0) { 73 if (ret != 0) {
102 dev_err(&tpa6130a2_client->dev, 74 dev_err(data->dev,
103 "Failed to disable supply: %d\n", ret); 75 "Failed to disable supply: %d\n", ret);
104 goto exit; 76 return ret;
105 } 77 }
106 78
107 data->power_state = 0;
108 /* device regs does not match the cache state anymore */ 79 /* device regs does not match the cache state anymore */
109 regcache_mark_dirty(data->regmap); 80 regcache_mark_dirty(data->regmap);
110 } 81 }
111 82
112exit:
113 mutex_unlock(&data->mutex);
114 return ret; 83 return ret;
115} 84}
116 85
86static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w,
87 struct snd_kcontrol *kctrl, int event)
88{
89 struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
90 struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c);
91 int ret;
92
93 /* before widget power up */
94 if (SND_SOC_DAPM_EVENT_ON(event)) {
95 /* Turn on the chip */
96 tpa6130a2_power(data, true);
97 /* Sync the registers */
98 ret = regcache_sync(data->regmap);
99 if (ret < 0) {
100 dev_err(c->dev, "Failed to initialize chip\n");
101 tpa6130a2_power(data, false);
102 return ret;
103 }
104 /* after widget power down */
105 } else {
106 tpa6130a2_power(data, false);
107 }
108
109 return 0;
110}
111
117/* 112/*
118 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going 113 * TPA6130 volume. From -59.5 to 4 dB with increasing step size when going
119 * down in gain. 114 * down in gain.
@@ -149,57 +144,6 @@ static const struct snd_kcontrol_new tpa6140a2_controls[] = {
149 tpa6140_tlv), 144 tpa6140_tlv),
150}; 145};
151 146
152/*
153 * Enable or disable channel (left or right)
154 * The bit number for mute and amplifier are the same per channel:
155 * bit 6: Right channel
156 * bit 7: Left channel
157 * in both registers.
158 */
159static void tpa6130a2_channel_enable(u8 channel, int enable)
160{
161 struct tpa6130a2_data *data = i2c_get_clientdata(tpa6130a2_client);
162
163 if (enable) {
164 /* Enable channel */
165 /* Enable amplifier */
166 regmap_update_bits(data->regmap, TPA6130A2_REG_CONTROL,
167 channel | TPA6130A2_SWS, channel & ~TPA6130A2_SWS);
168
169 /* Unmute channel */
170 regmap_update_bits(data->regmap, TPA6130A2_REG_VOL_MUTE,
171 channel, 0);
172 } else {
173 /* Disable channel */
174 /* Mute channel */
175 regmap_update_bits(data->regmap, TPA6130A2_REG_VOL_MUTE,
176 channel, channel);
177
178 /* Disable amplifier */
179 regmap_update_bits(data->regmap, TPA6130A2_REG_CONTROL,
180 channel, 0);
181 }
182}
183
184int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable)
185{
186 int ret = 0;
187 if (enable) {
188 ret = tpa6130a2_power(1);
189 if (ret < 0)
190 return ret;
191 tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
192 1);
193 } else {
194 tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
195 0);
196 ret = tpa6130a2_power(0);
197 }
198
199 return ret;
200}
201EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable);
202
203static int tpa6130a2_component_probe(struct snd_soc_component *component) 147static int tpa6130a2_component_probe(struct snd_soc_component *component)
204{ 148{
205 struct tpa6130a2_data *data = snd_soc_component_get_drvdata(component); 149 struct tpa6130a2_data *data = snd_soc_component_get_drvdata(component);
@@ -212,9 +156,47 @@ static int tpa6130a2_component_probe(struct snd_soc_component *component)
212 tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls)); 156 tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls));
213} 157}
214 158
159static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
160 SND_SOC_DAPM_INPUT("LEFTIN"),
161 SND_SOC_DAPM_INPUT("RIGHTIN"),
162 SND_SOC_DAPM_OUTPUT("HPLEFT"),
163 SND_SOC_DAPM_OUTPUT("HPRIGHT"),
164
165 SND_SOC_DAPM_PGA("Left Mute", TPA6130A2_REG_VOL_MUTE,
166 TPA6130A2_HP_EN_L_SHIFT, 1, NULL, 0),
167 SND_SOC_DAPM_PGA("Right Mute", TPA6130A2_REG_VOL_MUTE,
168 TPA6130A2_HP_EN_R_SHIFT, 1, NULL, 0),
169 SND_SOC_DAPM_PGA("Left PGA", TPA6130A2_REG_CONTROL,
170 TPA6130A2_HP_EN_L_SHIFT, 0, NULL, 0),
171 SND_SOC_DAPM_PGA("Right PGA", TPA6130A2_REG_CONTROL,
172 TPA6130A2_HP_EN_R_SHIFT, 0, NULL, 0),
173
174 SND_SOC_DAPM_SUPPLY("Power", TPA6130A2_REG_CONTROL,
175 TPA6130A2_SWS_SHIFT, 1, tpa6130a2_power_event,
176 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
177};
178
179static const struct snd_soc_dapm_route tpa6130a2_dapm_routes[] = {
180 { "Left PGA", NULL, "LEFTIN" },
181 { "Right PGA", NULL, "RIGHTIN" },
182
183 { "Left Mute", NULL, "Left PGA" },
184 { "Right Mute", NULL, "Right PGA" },
185
186 { "HPLEFT", NULL, "Left Mute" },
187 { "HPRIGHT", NULL, "Right Mute" },
188
189 { "Left PGA", NULL, "Power" },
190 { "Right PGA", NULL, "Power" },
191};
192
215struct snd_soc_component_driver tpa6130a2_component_driver = { 193struct snd_soc_component_driver tpa6130a2_component_driver = {
216 .name = "tpa6130a2", 194 .name = "tpa6130a2",
217 .probe = tpa6130a2_component_probe, 195 .probe = tpa6130a2_component_probe,
196 .dapm_widgets = tpa6130a2_dapm_widgets,
197 .num_dapm_widgets = ARRAY_SIZE(tpa6130a2_dapm_widgets),
198 .dapm_routes = tpa6130a2_dapm_routes,
199 .num_dapm_routes = ARRAY_SIZE(tpa6130a2_dapm_routes),
218}; 200};
219 201
220static const struct reg_default tpa6130a2_reg_defaults[] = { 202static const struct reg_default tpa6130a2_reg_defaults[] = {
@@ -248,6 +230,8 @@ static int tpa6130a2_probe(struct i2c_client *client,
248 if (!data) 230 if (!data)
249 return -ENOMEM; 231 return -ENOMEM;
250 232
233 data->dev = dev;
234
251 data->regmap = devm_regmap_init_i2c(client, &tpa6130a2_regmap_config); 235 data->regmap = devm_regmap_init_i2c(client, &tpa6130a2_regmap_config);
252 if (IS_ERR(data->regmap)) 236 if (IS_ERR(data->regmap))
253 return PTR_ERR(data->regmap); 237 return PTR_ERR(data->regmap);
@@ -262,14 +246,10 @@ static int tpa6130a2_probe(struct i2c_client *client,
262 return -ENODEV; 246 return -ENODEV;
263 } 247 }
264 248
265 tpa6130a2_client = client; 249 i2c_set_clientdata(client, data);
266
267 i2c_set_clientdata(tpa6130a2_client, data);
268 250
269 data->id = id->driver_data; 251 data->id = id->driver_data;
270 252
271 mutex_init(&data->mutex);
272
273 if (data->power_gpio >= 0) { 253 if (data->power_gpio >= 0) {
274 ret = devm_gpio_request(dev, data->power_gpio, 254 ret = devm_gpio_request(dev, data->power_gpio,
275 "tpa6130a2 enable"); 255 "tpa6130a2 enable");
@@ -300,7 +280,7 @@ static int tpa6130a2_probe(struct i2c_client *client,
300 goto err_gpio; 280 goto err_gpio;
301 } 281 }
302 282
303 ret = tpa6130a2_power(1); 283 ret = tpa6130a2_power(data, true);
304 if (ret != 0) 284 if (ret != 0)
305 goto err_gpio; 285 goto err_gpio;
306 286
@@ -312,7 +292,7 @@ static int tpa6130a2_probe(struct i2c_client *client,
312 dev_warn(dev, "UNTESTED version detected (%d)\n", version); 292 dev_warn(dev, "UNTESTED version detected (%d)\n", version);
313 293
314 /* Disable the chip */ 294 /* Disable the chip */
315 ret = tpa6130a2_power(0); 295 ret = tpa6130a2_power(data, false);
316 if (ret != 0) 296 if (ret != 0)
317 goto err_gpio; 297 goto err_gpio;
318 298
@@ -320,19 +300,9 @@ static int tpa6130a2_probe(struct i2c_client *client,
320 &tpa6130a2_component_driver, NULL, 0); 300 &tpa6130a2_component_driver, NULL, 0);
321 301
322err_gpio: 302err_gpio:
323 tpa6130a2_client = NULL;
324
325 return ret; 303 return ret;
326} 304}
327 305
328static int tpa6130a2_remove(struct i2c_client *client)
329{
330 tpa6130a2_power(0);
331 tpa6130a2_client = NULL;
332
333 return 0;
334}
335
336static const struct i2c_device_id tpa6130a2_id[] = { 306static const struct i2c_device_id tpa6130a2_id[] = {
337 { "tpa6130a2", TPA6130A2 }, 307 { "tpa6130a2", TPA6130A2 },
338 { "tpa6140a2", TPA6140A2 }, 308 { "tpa6140a2", TPA6140A2 },
@@ -355,7 +325,6 @@ static struct i2c_driver tpa6130a2_i2c_driver = {
355 .of_match_table = of_match_ptr(tpa6130a2_of_match), 325 .of_match_table = of_match_ptr(tpa6130a2_of_match),
356 }, 326 },
357 .probe = tpa6130a2_probe, 327 .probe = tpa6130a2_probe,
358 .remove = tpa6130a2_remove,
359 .id_table = tpa6130a2_id, 328 .id_table = tpa6130a2_id,
360}; 329};
361 330
diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h
index ef05a3ff189b..f19cad5d4172 100644
--- a/sound/soc/codecs/tpa6130a2.h
+++ b/sound/soc/codecs/tpa6130a2.h
@@ -32,15 +32,18 @@
32 32
33/* Register bits */ 33/* Register bits */
34/* TPA6130A2_REG_CONTROL (0x01) */ 34/* TPA6130A2_REG_CONTROL (0x01) */
35#define TPA6130A2_SWS (0x01 << 0) 35#define TPA6130A2_SWS_SHIFT 0
36#define TPA6130A2_SWS (0x01 << TPA6130A2_SWS_SHIFT)
36#define TPA6130A2_TERMAL (0x01 << 1) 37#define TPA6130A2_TERMAL (0x01 << 1)
37#define TPA6130A2_MODE(x) (x << 4) 38#define TPA6130A2_MODE(x) (x << 4)
38#define TPA6130A2_MODE_STEREO (0x00) 39#define TPA6130A2_MODE_STEREO (0x00)
39#define TPA6130A2_MODE_DUAL_MONO (0x01) 40#define TPA6130A2_MODE_DUAL_MONO (0x01)
40#define TPA6130A2_MODE_BRIDGE (0x02) 41#define TPA6130A2_MODE_BRIDGE (0x02)
41#define TPA6130A2_MODE_MASK (0x03) 42#define TPA6130A2_MODE_MASK (0x03)
42#define TPA6130A2_HP_EN_R (0x01 << 6) 43#define TPA6130A2_HP_EN_R_SHIFT 6
43#define TPA6130A2_HP_EN_L (0x01 << 7) 44#define TPA6130A2_HP_EN_R (0x01 << TPA6130A2_HP_EN_R_SHIFT)
45#define TPA6130A2_HP_EN_L_SHIFT 7
46#define TPA6130A2_HP_EN_L (0x01 << TPA6130A2_HP_EN_L_SHIFT)
44 47
45/* TPA6130A2_REG_VOL_MUTE (0x02) */ 48/* TPA6130A2_REG_VOL_MUTE (0x02) */
46#define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0) 49#define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0)
@@ -54,6 +57,4 @@
54/* TPA6130A2_REG_VERSION (0x04) */ 57/* TPA6130A2_REG_VERSION (0x04) */
55#define TPA6130A2_VERSION_MASK (0x0f) 58#define TPA6130A2_VERSION_MASK (0x0f)
56 59
57extern int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable);
58
59#endif /* __TPA6130A2_H__ */ 60#endif /* __TPA6130A2_H__ */
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index b59cf89c5cab..a76845748a10 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -33,7 +33,6 @@
33#include <sound/pcm.h> 33#include <sound/pcm.h>
34#include <sound/soc.h> 34#include <sound/soc.h>
35#include <linux/platform_data/asoc-ti-mcbsp.h> 35#include <linux/platform_data/asoc-ti-mcbsp.h>
36#include "../codecs/tpa6130a2.h"
37 36
38#include <asm/mach-types.h> 37#include <asm/mach-types.h>
39 38
@@ -164,19 +163,6 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w,
164 return 0; 163 return 0;
165} 164}
166 165
167static int rx51_hp_event(struct snd_soc_dapm_widget *w,
168 struct snd_kcontrol *k, int event)
169{
170 struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
171
172 if (SND_SOC_DAPM_EVENT_ON(event))
173 tpa6130a2_stereo_enable(codec, 1);
174 else
175 tpa6130a2_stereo_enable(codec, 0);
176
177 return 0;
178}
179
180static int rx51_get_input(struct snd_kcontrol *kcontrol, 166static int rx51_get_input(struct snd_kcontrol *kcontrol,
181 struct snd_ctl_elem_value *ucontrol) 167 struct snd_ctl_elem_value *ucontrol)
182{ 168{
@@ -235,7 +221,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = {
235static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { 221static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = {
236 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), 222 SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event),
237 SND_SOC_DAPM_MIC("DMic", NULL), 223 SND_SOC_DAPM_MIC("DMic", NULL),
238 SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), 224 SND_SOC_DAPM_HP("Headphone Jack", NULL),
239 SND_SOC_DAPM_MIC("HS Mic", NULL), 225 SND_SOC_DAPM_MIC("HS Mic", NULL),
240 SND_SOC_DAPM_LINE("FM Transmitter", NULL), 226 SND_SOC_DAPM_LINE("FM Transmitter", NULL),
241 SND_SOC_DAPM_SPK("Earphone", NULL), 227 SND_SOC_DAPM_SPK("Earphone", NULL),
@@ -246,11 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = {
246 {"Ext Spk", NULL, "HPROUT"}, 232 {"Ext Spk", NULL, "HPROUT"},
247 {"Ext Spk", NULL, "HPLCOM"}, 233 {"Ext Spk", NULL, "HPLCOM"},
248 {"Ext Spk", NULL, "HPRCOM"}, 234 {"Ext Spk", NULL, "HPRCOM"},
249 {"Headphone Jack", NULL, "LLOUT"},
250 {"Headphone Jack", NULL, "RLOUT"},
251 {"FM Transmitter", NULL, "LLOUT"}, 235 {"FM Transmitter", NULL, "LLOUT"},
252 {"FM Transmitter", NULL, "RLOUT"}, 236 {"FM Transmitter", NULL, "RLOUT"},
253 237
238 {"Headphone Jack", NULL, "TPA6130A2 HPLEFT"},
239 {"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"},
240 {"TPA6130A2 LEFTIN", NULL, "LLOUT"},
241 {"TPA6130A2 RIGHTIN", NULL, "RLOUT"},
242
254 {"DMic Rate 64", NULL, "DMic"}, 243 {"DMic Rate 64", NULL, "DMic"},
255 {"DMic", NULL, "Mic Bias"}, 244 {"DMic", NULL, "Mic Bias"},
256 245