aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/codecs/wm8753.c
diff options
context:
space:
mode:
authorLiam Girdwood <lrg@slimlogic.co.uk>2010-03-17 16:15:21 -0400
committerLiam Girdwood <lrg@slimlogic.co.uk>2010-08-12 09:00:00 -0400
commitf0fba2ad1b6b53d5360125c41953b7afcd6deff0 (patch)
treef6ad50905f8daa616593c978d7ae992e73241180 /sound/soc/codecs/wm8753.c
parentbda7d2a862e6b788bca2d02d38a07966a9c92e48 (diff)
ASoC: multi-component - ASoC Multi-Component Support
This patch extends the ASoC API to allow sound cards to have more than one CODEC and more than one platform DMA controller. This is achieved by dividing some current ASoC structures that contain both driver data and device data into structures that only either contain device data or driver data. i.e. struct snd_soc_codec ---> struct snd_soc_codec (device data) +-> struct snd_soc_codec_driver (driver data) struct snd_soc_platform ---> struct snd_soc_platform (device data) +-> struct snd_soc_platform_driver (driver data) struct snd_soc_dai ---> struct snd_soc_dai (device data) +-> struct snd_soc_dai_driver (driver data) struct snd_soc_device ---> deleted This now allows ASoC to be more tightly aligned with the Linux driver model and also means that every ASoC codec, platform and (platform) DAI is a kernel device. ASoC component private data is now stored as device private data. The ASoC sound card struct snd_soc_card has also been updated to store lists of it's components rather than a pointer to a codec and platform. The PCM runtime struct soc_pcm_runtime now has pointers to all its components. This patch adds DAPM support for ASoC multi-component and removes struct snd_soc_socdev from DAPM core. All DAPM calls are now made on a card, codec or runtime PCM level basis rather than using snd_soc_socdev. Other notable multi-component changes:- * Stream operations now de-reference less structures. * close_delayed work() now runs on a DAI basis rather than looping all DAIs in a card. * PM suspend()/resume() operations can now handle N CODECs and Platforms per sound card. * Added soc_bind_dai_link() to bind the component devices to the sound card. * Added soc_dai_link_probe() and soc_dai_link_remove() to probe and remove DAI link components. * sysfs entries can now be registered per component per card. * snd_soc_new_pcms() functionailty rolled into dai_link_probe(). * snd_soc_register_codec() now does all the codec list and mutex init. This patch changes the probe() and remove() of the CODEC drivers as follows:- o Make CODEC driver a platform driver o Moved all struct snd_soc_codec list, mutex, etc initialiasation to core. o Removed all static codec pointers (drivers now support > 1 codec dev) o snd_soc_register_pcms() now done by core. o snd_soc_register_dai() folded into snd_soc_register_codec(). CS4270 portions: Acked-by: Timur Tabi <timur@freescale.com> Some TLV320aic23 and Cirrus platform fixes. Signed-off-by: Ryan Mallon <ryan@bluewatersys.com> TI CODEC and OMAP fixes Signed-off-by: Peter Ujfalusi <peter.ujfalusi@nokia.com> Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> Signed-off-by: Jarkko Nikula <jhnikula@gmail.com> Samsung platform and misc fixes :- Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Jassi Brar <jassi.brar@samsung.com> Signed-off-by: Seungwhan Youn <sw.youn@samsung.com> MPC8610 and PPC fixes. Signed-off-by: Timur Tabi <timur@freescale.com> i.MX fixes and some core fixes. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> J4740 platform fixes:- Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> CC: Tony Lindgren <tony@atomide.com> CC: Nicolas Ferre <nicolas.ferre@atmel.com> CC: Kevin Hilman <khilman@deeprootsystems.com> CC: Sascha Hauer <s.hauer@pengutronix.de> CC: Atsushi Nemoto <anemo@mba.ocn.ne.jp> CC: Kuninori Morimoto <morimoto.kuninori@renesas.com> CC: Daniel Gloeckner <dg@emlix.com> CC: Manuel Lauss <mano@roarinelk.homelinux.net> CC: Mike Frysinger <vapier.adi@gmail.com> CC: Arnaud Patard <apatard@mandriva.com> CC: Wan ZongShun <mcuos.com@gmail.com> Acked-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Signed-off-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
-rw-r--r--sound/soc/codecs/wm8753.c407
1 files changed, 147 insertions, 260 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index b59f349c521..976e408b361 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -57,7 +57,7 @@ module_param(caps_charge, int, 0);
57MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); 57MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)");
58 58
59static void wm8753_set_dai_mode(struct snd_soc_codec *codec, 59static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
60 unsigned int mode); 60 struct snd_soc_dai *dai, unsigned int hifi);
61 61
62/* 62/*
63 * wm8753 register cache 63 * wm8753 register cache
@@ -85,10 +85,12 @@ static const u16 wm8753_reg[] = {
85 85
86/* codec private data */ 86/* codec private data */
87struct wm8753_priv { 87struct wm8753_priv {
88 enum snd_soc_control_type control_type;
89 void *control_data;
88 unsigned int sysclk; 90 unsigned int sysclk;
89 unsigned int pcmclk; 91 unsigned int pcmclk;
90 struct snd_soc_codec codec;
91 u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; 92 u16 reg_cache[ARRAY_SIZE(wm8753_reg)];
93 int dai_func;
92}; 94};
93 95
94/* 96/*
@@ -228,6 +230,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
228{ 230{
229 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); 231 struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
230 int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); 232 int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
233 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
231 234
232 if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) 235 if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
233 return 0; 236 return 0;
@@ -235,8 +238,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol,
235 mode &= 0xfff3; 238 mode &= 0xfff3;
236 mode |= (ucontrol->value.integer.value[0] << 2); 239 mode |= (ucontrol->value.integer.value[0] << 2);
237 240
238 wm8753_write(codec, WM8753_IOCTL, mode); 241 wm8753->dai_func = ucontrol->value.integer.value[0];
239 wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]);
240 return 1; 242 return 1;
241} 243}
242 244
@@ -904,6 +906,13 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai,
904 return 0; 906 return 0;
905} 907}
906 908
909static int wm8753_pcm_startup(struct snd_pcm_substream *substream,
910 struct snd_soc_dai *dai)
911{
912 wm8753_set_dai_mode(dai->codec, dai, 0);
913 return 0;
914}
915
907/* 916/*
908 * Set PCM DAI bit size and sample rate. 917 * Set PCM DAI bit size and sample rate.
909 */ 918 */
@@ -912,8 +921,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream,
912 struct snd_soc_dai *dai) 921 struct snd_soc_dai *dai)
913{ 922{
914 struct snd_soc_pcm_runtime *rtd = substream->private_data; 923 struct snd_soc_pcm_runtime *rtd = substream->private_data;
915 struct snd_soc_device *socdev = rtd->socdev; 924 struct snd_soc_codec *codec = rtd->codec;
916 struct snd_soc_codec *codec = socdev->card->codec;
917 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); 925 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
918 u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; 926 u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
919 u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; 927 u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
@@ -1138,6 +1146,13 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai,
1138 return 0; 1146 return 0;
1139} 1147}
1140 1148
1149static int wm8753_i2s_startup(struct snd_pcm_substream *substream,
1150 struct snd_soc_dai *dai)
1151{
1152 wm8753_set_dai_mode(dai->codec, dai, 1);
1153 return 0;
1154}
1155
1141/* 1156/*
1142 * Set PCM DAI bit size and sample rate. 1157 * Set PCM DAI bit size and sample rate.
1143 */ 1158 */
@@ -1146,8 +1161,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream,
1146 struct snd_soc_dai *dai) 1161 struct snd_soc_dai *dai)
1147{ 1162{
1148 struct snd_soc_pcm_runtime *rtd = substream->private_data; 1163 struct snd_soc_pcm_runtime *rtd = substream->private_data;
1149 struct snd_soc_device *socdev = rtd->socdev; 1164 struct snd_soc_codec *codec = rtd->codec;
1150 struct snd_soc_codec *codec = socdev->card->codec;
1151 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); 1165 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
1152 u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; 1166 u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
1153 u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; 1167 u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
@@ -1240,12 +1254,12 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute)
1240{ 1254{
1241 struct snd_soc_codec *codec = dai->codec; 1255 struct snd_soc_codec *codec = dai->codec;
1242 u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; 1256 u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7;
1257 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
1243 1258
1244 /* the digital mute covers the HiFi and Voice DAC's on the WM8753. 1259 /* the digital mute covers the HiFi and Voice DAC's on the WM8753.
1245 * make sure we check if they are not both active when we mute */ 1260 * make sure we check if they are not both active when we mute */
1246 if (mute && dai->id == 1) { 1261 if (mute && wm8753->dai_func == 1) {
1247 if (!wm8753_dai[WM8753_DAI_VOICE].playback.active || 1262 if (!codec->active)
1248 !wm8753_dai[WM8753_DAI_HIFI].playback.active)
1249 wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); 1263 wm8753_write(codec, WM8753_DAC, mute_reg | 0x8);
1250 } else { 1264 } else {
1251 if (mute) 1265 if (mute)
@@ -1303,6 +1317,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
1303 * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture 1317 * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture
1304 */ 1318 */
1305static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { 1319static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
1320 .startup = wm8753_i2s_startup,
1306 .hw_params = wm8753_i2s_hw_params, 1321 .hw_params = wm8753_i2s_hw_params,
1307 .digital_mute = wm8753_mute, 1322 .digital_mute = wm8753_mute,
1308 .set_fmt = wm8753_mode1h_set_dai_fmt, 1323 .set_fmt = wm8753_mode1h_set_dai_fmt,
@@ -1312,6 +1327,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = {
1312}; 1327};
1313 1328
1314static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { 1329static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
1330 .startup = wm8753_pcm_startup,
1315 .hw_params = wm8753_pcm_hw_params, 1331 .hw_params = wm8753_pcm_hw_params,
1316 .digital_mute = wm8753_mute, 1332 .digital_mute = wm8753_mute,
1317 .set_fmt = wm8753_mode1v_set_dai_fmt, 1333 .set_fmt = wm8753_mode1v_set_dai_fmt,
@@ -1321,6 +1337,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = {
1321}; 1337};
1322 1338
1323static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { 1339static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
1340 .startup = wm8753_pcm_startup,
1324 .hw_params = wm8753_pcm_hw_params, 1341 .hw_params = wm8753_pcm_hw_params,
1325 .digital_mute = wm8753_mute, 1342 .digital_mute = wm8753_mute,
1326 .set_fmt = wm8753_mode2_set_dai_fmt, 1343 .set_fmt = wm8753_mode2_set_dai_fmt,
@@ -1330,6 +1347,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = {
1330}; 1347};
1331 1348
1332static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { 1349static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
1350 .startup = wm8753_i2s_startup,
1333 .hw_params = wm8753_i2s_hw_params, 1351 .hw_params = wm8753_i2s_hw_params,
1334 .digital_mute = wm8753_mute, 1352 .digital_mute = wm8753_mute,
1335 .set_fmt = wm8753_mode3_4_set_dai_fmt, 1353 .set_fmt = wm8753_mode3_4_set_dai_fmt,
@@ -1339,6 +1357,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = {
1339}; 1357};
1340 1358
1341static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { 1359static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
1360 .startup = wm8753_i2s_startup,
1342 .hw_params = wm8753_i2s_hw_params, 1361 .hw_params = wm8753_i2s_hw_params,
1343 .digital_mute = wm8753_mute, 1362 .digital_mute = wm8753_mute,
1344 .set_fmt = wm8753_mode3_4_set_dai_fmt, 1363 .set_fmt = wm8753_mode3_4_set_dai_fmt,
@@ -1347,10 +1366,9 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = {
1347 .set_sysclk = wm8753_set_dai_sysclk, 1366 .set_sysclk = wm8753_set_dai_sysclk,
1348}; 1367};
1349 1368
1350static const struct snd_soc_dai wm8753_all_dai[] = { 1369static struct snd_soc_dai_driver wm8753_all_dai[] = {
1351/* DAI HiFi mode 1 */ 1370/* DAI HiFi mode 1 */
1352{ .name = "WM8753 HiFi", 1371{ .name = "wm8753-hifi",
1353 .id = 1,
1354 .playback = { 1372 .playback = {
1355 .stream_name = "HiFi Playback", 1373 .stream_name = "HiFi Playback",
1356 .channels_min = 1, 1374 .channels_min = 1,
@@ -1366,8 +1384,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
1366 .ops = &wm8753_dai_ops_hifi_mode1, 1384 .ops = &wm8753_dai_ops_hifi_mode1,
1367}, 1385},
1368/* DAI Voice mode 1 */ 1386/* DAI Voice mode 1 */
1369{ .name = "WM8753 Voice", 1387{ .name = "wm8753-voice",
1370 .id = 1,
1371 .playback = { 1388 .playback = {
1372 .stream_name = "Voice Playback", 1389 .stream_name = "Voice Playback",
1373 .channels_min = 1, 1390 .channels_min = 1,
@@ -1383,12 +1400,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
1383 .ops = &wm8753_dai_ops_voice_mode1, 1400 .ops = &wm8753_dai_ops_voice_mode1,
1384}, 1401},
1385/* DAI HiFi mode 2 - dummy */ 1402/* DAI HiFi mode 2 - dummy */
1386{ .name = "WM8753 HiFi", 1403{ .name = "wm8753-hifi",
1387 .id = 2,
1388}, 1404},
1389/* DAI Voice mode 2 */ 1405/* DAI Voice mode 2 */
1390{ .name = "WM8753 Voice", 1406{ .name = "wm8753-voice",
1391 .id = 2,
1392 .playback = { 1407 .playback = {
1393 .stream_name = "Voice Playback", 1408 .stream_name = "Voice Playback",
1394 .channels_min = 1, 1409 .channels_min = 1,
@@ -1404,8 +1419,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
1404 .ops = &wm8753_dai_ops_voice_mode2, 1419 .ops = &wm8753_dai_ops_voice_mode2,
1405}, 1420},
1406/* DAI HiFi mode 3 */ 1421/* DAI HiFi mode 3 */
1407{ .name = "WM8753 HiFi", 1422{ .name = "wm8753-hifi",
1408 .id = 3,
1409 .playback = { 1423 .playback = {
1410 .stream_name = "HiFi Playback", 1424 .stream_name = "HiFi Playback",
1411 .channels_min = 1, 1425 .channels_min = 1,
@@ -1421,12 +1435,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
1421 .ops = &wm8753_dai_ops_hifi_mode3, 1435 .ops = &wm8753_dai_ops_hifi_mode3,
1422}, 1436},
1423/* DAI Voice mode 3 - dummy */ 1437/* DAI Voice mode 3 - dummy */
1424{ .name = "WM8753 Voice", 1438{ .name = "wm8753-voice",
1425 .id = 3,
1426}, 1439},
1427/* DAI HiFi mode 4 */ 1440/* DAI HiFi mode 4 */
1428{ .name = "WM8753 HiFi", 1441{ .name = "wm8753-hifi",
1429 .id = 4,
1430 .playback = { 1442 .playback = {
1431 .stream_name = "HiFi Playback", 1443 .stream_name = "HiFi Playback",
1432 .channels_min = 1, 1444 .channels_min = 1,
@@ -1442,58 +1454,31 @@ static const struct snd_soc_dai wm8753_all_dai[] = {
1442 .ops = &wm8753_dai_ops_hifi_mode4, 1454 .ops = &wm8753_dai_ops_hifi_mode4,
1443}, 1455},
1444/* DAI Voice mode 4 - dummy */ 1456/* DAI Voice mode 4 - dummy */
1445{ .name = "WM8753 Voice", 1457{ .name = "wm8753-voice",
1446 .id = 4,
1447}, 1458},
1448}; 1459};
1449 1460
1450struct snd_soc_dai wm8753_dai[] = { 1461static struct snd_soc_dai_driver wm8753_dai[] = {
1451 { 1462 {
1452 .name = "WM8753 DAI 0", 1463 .name = "wm8753-aif0",
1453 }, 1464 },
1454 { 1465 {
1455 .name = "WM8753 DAI 1", 1466 .name = "wm8753-aif1",
1456 }, 1467 },
1457}; 1468};
1458EXPORT_SYMBOL_GPL(wm8753_dai);
1459 1469
1460static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) 1470static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
1471 struct snd_soc_dai *dai, unsigned int hifi)
1461{ 1472{
1462 if (mode < 4) { 1473 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
1463 int playback_active, capture_active, codec_active, pop_wait; 1474
1464 void *private_data; 1475 if (wm8753->dai_func < 4) {
1465 struct list_head list; 1476 if (hifi)
1466 1477 dai->driver = &wm8753_all_dai[wm8753->dai_func << 1];
1467 playback_active = wm8753_dai[0].playback.active; 1478 else
1468 capture_active = wm8753_dai[0].capture.active; 1479 dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1];
1469 codec_active = wm8753_dai[0].active;
1470 private_data = wm8753_dai[0].private_data;
1471 pop_wait = wm8753_dai[0].pop_wait;
1472 list = wm8753_dai[0].list;
1473 wm8753_dai[0] = wm8753_all_dai[mode << 1];
1474 wm8753_dai[0].playback.active = playback_active;
1475 wm8753_dai[0].capture.active = capture_active;
1476 wm8753_dai[0].active = codec_active;
1477 wm8753_dai[0].private_data = private_data;
1478 wm8753_dai[0].pop_wait = pop_wait;
1479 wm8753_dai[0].list = list;
1480
1481 playback_active = wm8753_dai[1].playback.active;
1482 capture_active = wm8753_dai[1].capture.active;
1483 codec_active = wm8753_dai[1].active;
1484 private_data = wm8753_dai[1].private_data;
1485 pop_wait = wm8753_dai[1].pop_wait;
1486 list = wm8753_dai[1].list;
1487 wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1];
1488 wm8753_dai[1].playback.active = playback_active;
1489 wm8753_dai[1].capture.active = capture_active;
1490 wm8753_dai[1].active = codec_active;
1491 wm8753_dai[1].private_data = private_data;
1492 wm8753_dai[1].pop_wait = pop_wait;
1493 wm8753_dai[1].list = list;
1494 } 1480 }
1495 wm8753_dai[0].codec = codec; 1481 wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func);
1496 wm8753_dai[1].codec = codec;
1497} 1482}
1498 1483
1499static void wm8753_work(struct work_struct *work) 1484static void wm8753_work(struct work_struct *work)
@@ -1503,19 +1488,14 @@ static void wm8753_work(struct work_struct *work)
1503 wm8753_set_bias_level(codec, codec->bias_level); 1488 wm8753_set_bias_level(codec, codec->bias_level);
1504} 1489}
1505 1490
1506static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) 1491static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
1507{ 1492{
1508 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1509 struct snd_soc_codec *codec = socdev->card->codec;
1510
1511 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); 1493 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
1512 return 0; 1494 return 0;
1513} 1495}
1514 1496
1515static int wm8753_resume(struct platform_device *pdev) 1497static int wm8753_resume(struct snd_soc_codec *codec)
1516{ 1498{
1517 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1518 struct snd_soc_codec *codec = socdev->card->codec;
1519 int i; 1499 int i;
1520 u8 data[2]; 1500 u8 data[2];
1521 u16 *cache = codec->reg_cache; 1501 u16 *cache = codec->reg_cache;
@@ -1547,41 +1527,6 @@ static int wm8753_resume(struct platform_device *pdev)
1547 return 0; 1527 return 0;
1548} 1528}
1549 1529
1550static struct snd_soc_codec *wm8753_codec;
1551
1552static int wm8753_probe(struct platform_device *pdev)
1553{
1554 struct snd_soc_device *socdev = platform_get_drvdata(pdev);
1555 struct snd_soc_codec *codec;
1556 int ret = 0;
1557
1558 if (!wm8753_codec) {
1559 dev_err(&pdev->dev, "WM8753 codec not yet registered\n");
1560 return -EINVAL;
1561 }
1562
1563 socdev->card->codec = wm8753_codec;
1564 codec = wm8753_codec;
1565
1566 wm8753_set_dai_mode(codec, 0);
1567
1568 /* register pcms */
1569 ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
1570 if (ret < 0) {
1571 printk(KERN_ERR "wm8753: failed to create pcms\n");
1572 goto pcm_err;
1573 }
1574
1575 snd_soc_add_controls(codec, wm8753_snd_controls,
1576 ARRAY_SIZE(wm8753_snd_controls));
1577 wm8753_add_widgets(codec);
1578
1579 return 0;
1580
1581pcm_err:
1582 return ret;
1583}
1584
1585/* 1530/*
1586 * This function forces any delayed work to be queued and run. 1531 * This function forces any delayed work to be queued and run.
1587 */ 1532 */
@@ -1601,62 +1546,30 @@ static int run_delayed_work(struct delayed_work *dwork)
1601 return ret; 1546 return ret;
1602} 1547}
1603 1548
1604/* power down chip */ 1549static int wm8753_probe(struct snd_soc_codec *codec)
1605static int wm8753_remove(struct platform_device *pdev)
1606{ 1550{
1607 struct snd_soc_device *socdev = platform_get_drvdata(pdev); 1551 struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
1608 1552 int ret = 0, reg;
1609 snd_soc_free_pcms(socdev);
1610 snd_soc_dapm_free(socdev);
1611
1612 return 0;
1613}
1614
1615struct snd_soc_codec_device soc_codec_dev_wm8753 = {
1616 .probe = wm8753_probe,
1617 .remove = wm8753_remove,
1618 .suspend = wm8753_suspend,
1619 .resume = wm8753_resume,
1620};
1621EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
1622 1553
1623static int wm8753_register(struct wm8753_priv *wm8753) 1554 codec->bias_level = SND_SOC_BIAS_OFF,
1624{ 1555 codec->control_data = wm8753->control_data;
1625 int ret, i; 1556 INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
1626 struct snd_soc_codec *codec = &wm8753->codec;
1627 u16 reg;
1628 1557
1629 if (wm8753_codec) { 1558 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
1630 dev_err(codec->dev, "Multiple WM8753 devices not supported\n"); 1559 if (ret < 0) {
1631 ret = -EINVAL; 1560 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
1632 goto err; 1561 return ret;
1633 } 1562 }
1634 1563
1635 mutex_init(&codec->mutex);
1636 INIT_LIST_HEAD(&codec->dapm_widgets);
1637 INIT_LIST_HEAD(&codec->dapm_paths);
1638
1639 codec->name = "WM8753";
1640 codec->owner = THIS_MODULE;
1641 codec->read = wm8753_read_reg_cache;
1642 codec->write = wm8753_write;
1643 codec->bias_level = SND_SOC_BIAS_STANDBY;
1644 codec->set_bias_level = wm8753_set_bias_level;
1645 codec->dai = wm8753_dai;
1646 codec->num_dai = 2;
1647 codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
1648 codec->reg_cache = &wm8753->reg_cache;
1649 snd_soc_codec_set_drvdata(codec, wm8753);
1650
1651 memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
1652 INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
1653
1654 ret = wm8753_reset(codec); 1564 ret = wm8753_reset(codec);
1655 if (ret < 0) { 1565 if (ret < 0) {
1656 dev_err(codec->dev, "Failed to issue reset\n"); 1566 dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
1657 goto err; 1567 return ret;
1658 } 1568 }
1659 1569
1570 wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
1571 wm8753->dai_func = 0;
1572
1660 /* charge output caps */ 1573 /* charge output caps */
1661 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); 1574 wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
1662 schedule_delayed_work(&codec->delayed_work, 1575 schedule_delayed_work(&codec->delayed_work,
@@ -1684,165 +1597,139 @@ static int wm8753_register(struct wm8753_priv *wm8753)
1684 reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); 1597 reg = wm8753_read_reg_cache(codec, WM8753_RINVOL);
1685 wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); 1598 wm8753_write(codec, WM8753_RINVOL, reg | 0x0100);
1686 1599
1687 wm8753_codec = codec; 1600 snd_soc_add_controls(codec, wm8753_snd_controls,
1688 1601 ARRAY_SIZE(wm8753_snd_controls));
1689 for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++) 1602 wm8753_add_widgets(codec);
1690 wm8753_dai[i].dev = codec->dev;
1691
1692 ret = snd_soc_register_codec(codec);
1693 if (ret != 0) {
1694 dev_err(codec->dev, "Failed to register codec: %d\n", ret);
1695 goto err;
1696 }
1697
1698 ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai));
1699 if (ret != 0) {
1700 dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
1701 goto err_codec;
1702 }
1703 1603
1704 return 0; 1604 return 0;
1705 1605
1706err_codec:
1707 run_delayed_work(&codec->delayed_work); 1606 run_delayed_work(&codec->delayed_work);
1708 snd_soc_unregister_codec(codec);
1709err:
1710 kfree(wm8753);
1711 return ret; 1607 return ret;
1712} 1608}
1713 1609
1714static void wm8753_unregister(struct wm8753_priv *wm8753) 1610/* power down chip */
1611static int wm8753_remove(struct snd_soc_codec *codec)
1715{ 1612{
1716 wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF); 1613 run_delayed_work(&codec->delayed_work);
1717 run_delayed_work(&wm8753->codec.delayed_work); 1614 wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
1718 snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); 1615
1719 snd_soc_unregister_codec(&wm8753->codec); 1616 return 0;
1720 kfree(wm8753);
1721 wm8753_codec = NULL;
1722} 1617}
1723 1618
1724#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 1619static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
1620 .probe = wm8753_probe,
1621 .remove = wm8753_remove,
1622 .suspend = wm8753_suspend,
1623 .resume = wm8753_resume,
1624 .set_bias_level = wm8753_set_bias_level,
1625 .reg_cache_size = sizeof(wm8753_reg),
1626 .reg_word_size = sizeof(u16),
1627 .reg_cache_default = wm8753_reg,
1628};
1725 1629
1726static int wm8753_i2c_probe(struct i2c_client *i2c, 1630#if defined(CONFIG_SPI_MASTER)
1727 const struct i2c_device_id *id) 1631static int __devinit wm8753_spi_probe(struct spi_device *spi)
1728{ 1632{
1729 struct snd_soc_codec *codec;
1730 struct wm8753_priv *wm8753; 1633 struct wm8753_priv *wm8753;
1634 int ret;
1731 1635
1732 wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); 1636 wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
1733 if (wm8753 == NULL) 1637 if (wm8753 == NULL)
1734 return -ENOMEM; 1638 return -ENOMEM;
1735 1639
1736 codec = &wm8753->codec; 1640 wm8753->control_data = spi;
1737 codec->hw_write = (hw_write_t)i2c_master_send; 1641 wm8753->control_type = SND_SOC_SPI;
1738 codec->control_data = i2c; 1642 spi_set_drvdata(spi, wm8753);
1739 i2c_set_clientdata(i2c, wm8753);
1740
1741 codec->dev = &i2c->dev;
1742 1643
1743 return wm8753_register(wm8753); 1644 ret = snd_soc_register_codec(&spi->dev,
1645 &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
1646 if (ret < 0)
1647 kfree(wm8753);
1648 return ret;
1744} 1649}
1745 1650
1746static int wm8753_i2c_remove(struct i2c_client *client) 1651static int __devexit wm8753_spi_remove(struct spi_device *spi)
1747{ 1652{
1748 struct wm8753_priv *wm8753 = i2c_get_clientdata(client); 1653 snd_soc_unregister_codec(&spi->dev);
1749 wm8753_unregister(wm8753); 1654 kfree(spi_get_drvdata(spi));
1750 return 0; 1655 return 0;
1751} 1656}
1752 1657
1753static const struct i2c_device_id wm8753_i2c_id[] = { 1658static struct spi_driver wm8753_spi_driver = {
1754 { "wm8753", 0 },
1755 { }
1756};
1757MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
1758
1759static struct i2c_driver wm8753_i2c_driver = {
1760 .driver = { 1659 .driver = {
1761 .name = "wm8753", 1660 .name = "wm8753-codec",
1762 .owner = THIS_MODULE, 1661 .bus = &spi_bus_type,
1662 .owner = THIS_MODULE,
1763 }, 1663 },
1764 .probe = wm8753_i2c_probe, 1664 .probe = wm8753_spi_probe,
1765 .remove = wm8753_i2c_remove, 1665 .remove = __devexit_p(wm8753_spi_remove),
1766 .id_table = wm8753_i2c_id,
1767}; 1666};
1768#endif 1667#endif /* CONFIG_SPI_MASTER */
1769
1770#if defined(CONFIG_SPI_MASTER)
1771static int wm8753_spi_write(struct spi_device *spi, const char *data, int len)
1772{
1773 struct spi_transfer t;
1774 struct spi_message m;
1775 u8 msg[2];
1776
1777 if (len <= 0)
1778 return 0;
1779
1780 msg[0] = data[0];
1781 msg[1] = data[1];
1782 1668
1783 spi_message_init(&m); 1669#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1784 memset(&t, 0, (sizeof t)); 1670static __devinit int wm8753_i2c_probe(struct i2c_client *i2c,
1785 1671 const struct i2c_device_id *id)
1786 t.tx_buf = &msg[0];
1787 t.len = len;
1788
1789 spi_message_add_tail(&t, &m);
1790 spi_sync(spi, &m);
1791
1792 return len;
1793}
1794
1795static int __devinit wm8753_spi_probe(struct spi_device *spi)
1796{ 1672{
1797 struct snd_soc_codec *codec;
1798 struct wm8753_priv *wm8753; 1673 struct wm8753_priv *wm8753;
1674 int ret;
1799 1675
1800 wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); 1676 wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL);
1801 if (wm8753 == NULL) 1677 if (wm8753 == NULL)
1802 return -ENOMEM; 1678 return -ENOMEM;
1803 1679
1804 codec = &wm8753->codec; 1680 i2c_set_clientdata(i2c, wm8753);
1805 codec->control_data = spi; 1681 wm8753->control_data = i2c;
1806 codec->hw_write = (hw_write_t)wm8753_spi_write; 1682 wm8753->control_type = SND_SOC_I2C;
1807 codec->dev = &spi->dev;
1808
1809 dev_set_drvdata(&spi->dev, wm8753);
1810 1683
1811 return wm8753_register(wm8753); 1684 ret = snd_soc_register_codec(&i2c->dev,
1685 &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai));
1686 if (ret < 0)
1687 kfree(wm8753);
1688 return ret;
1812} 1689}
1813 1690
1814static int __devexit wm8753_spi_remove(struct spi_device *spi) 1691static __devexit int wm8753_i2c_remove(struct i2c_client *client)
1815{ 1692{
1816 struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev); 1693 snd_soc_unregister_codec(&client->dev);
1817 wm8753_unregister(wm8753); 1694 kfree(i2c_get_clientdata(client));
1818 return 0; 1695 return 0;
1819} 1696}
1820 1697
1821static struct spi_driver wm8753_spi_driver = { 1698static const struct i2c_device_id wm8753_i2c_id[] = {
1699 { "wm8753", 0 },
1700 { }
1701};
1702MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
1703
1704static struct i2c_driver wm8753_i2c_driver = {
1822 .driver = { 1705 .driver = {
1823 .name = "wm8753", 1706 .name = "wm8753-codec",
1824 .bus = &spi_bus_type, 1707 .owner = THIS_MODULE,
1825 .owner = THIS_MODULE,
1826 }, 1708 },
1827 .probe = wm8753_spi_probe, 1709 .probe = wm8753_i2c_probe,
1828 .remove = __devexit_p(wm8753_spi_remove), 1710 .remove = __devexit_p(wm8753_i2c_remove),
1711 .id_table = wm8753_i2c_id,
1829}; 1712};
1830#endif 1713#endif
1831 1714
1832static int __init wm8753_modinit(void) 1715static int __init wm8753_modinit(void)
1833{ 1716{
1834 int ret; 1717 int ret = 0;
1835#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) 1718#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
1836 ret = i2c_add_driver(&wm8753_i2c_driver); 1719 ret = i2c_add_driver(&wm8753_i2c_driver);
1837 if (ret != 0) 1720 if (ret != 0) {
1838 pr_err("Failed to register WM8753 I2C driver: %d\n", ret); 1721 printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n",
1722 ret);
1723 }
1839#endif 1724#endif
1840#if defined(CONFIG_SPI_MASTER) 1725#if defined(CONFIG_SPI_MASTER)
1841 ret = spi_register_driver(&wm8753_spi_driver); 1726 ret = spi_register_driver(&wm8753_spi_driver);
1842 if (ret != 0) 1727 if (ret != 0) {
1843 pr_err("Failed to register WM8753 SPI driver: %d\n", ret); 1728 printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n",
1729 ret);
1730 }
1844#endif 1731#endif
1845 return 0; 1732 return ret;
1846} 1733}
1847module_init(wm8753_modinit); 1734module_init(wm8753_modinit);
1848 1735