diff options
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
-rw-r--r-- | sound/soc/codecs/wm8753.c | 407 |
1 files changed, 147 insertions, 260 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index b59f349c5218..976e408b3616 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -57,7 +57,7 @@ module_param(caps_charge, int, 0); | |||
57 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 57 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
58 | 58 | ||
59 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | 59 | static 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 */ |
87 | struct wm8753_priv { | 87 | struct 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 | ||
909 | static 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 | ||
1149 | static 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 | */ |
1305 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | 1319 | static 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 | ||
1314 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | 1329 | static 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 | ||
1323 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | 1339 | static 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 | ||
1332 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { | 1349 | static 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 | ||
1341 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { | 1359 | static 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 | ||
1350 | static const struct snd_soc_dai wm8753_all_dai[] = { | 1369 | static 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 | ||
1450 | struct snd_soc_dai wm8753_dai[] = { | 1461 | static 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 | }; |
1458 | EXPORT_SYMBOL_GPL(wm8753_dai); | ||
1459 | 1469 | ||
1460 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | 1470 | static 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 | ||
1499 | static void wm8753_work(struct work_struct *work) | 1484 | static 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 | ||
1506 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1491 | static 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 | ||
1515 | static int wm8753_resume(struct platform_device *pdev) | 1497 | static 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 | ||
1550 | static struct snd_soc_codec *wm8753_codec; | ||
1551 | |||
1552 | static 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 | |||
1581 | pcm_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 */ | 1549 | static int wm8753_probe(struct snd_soc_codec *codec) |
1605 | static 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 | |||
1615 | struct 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 | }; | ||
1621 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); | ||
1622 | 1553 | ||
1623 | static 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 | ||
1706 | err_codec: | ||
1707 | run_delayed_work(&codec->delayed_work); | 1606 | run_delayed_work(&codec->delayed_work); |
1708 | snd_soc_unregister_codec(codec); | ||
1709 | err: | ||
1710 | kfree(wm8753); | ||
1711 | return ret; | 1607 | return ret; |
1712 | } | 1608 | } |
1713 | 1609 | ||
1714 | static void wm8753_unregister(struct wm8753_priv *wm8753) | 1610 | /* power down chip */ |
1611 | static 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) | 1619 | static 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 | ||
1726 | static int wm8753_i2c_probe(struct i2c_client *i2c, | 1630 | #if defined(CONFIG_SPI_MASTER) |
1727 | const struct i2c_device_id *id) | 1631 | static 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 | ||
1746 | static int wm8753_i2c_remove(struct i2c_client *client) | 1651 | static 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 | ||
1753 | static const struct i2c_device_id wm8753_i2c_id[] = { | 1658 | static struct spi_driver wm8753_spi_driver = { |
1754 | { "wm8753", 0 }, | ||
1755 | { } | ||
1756 | }; | ||
1757 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1758 | |||
1759 | static 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) | ||
1771 | static 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)); | 1670 | static __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 | |||
1795 | static 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 | ||
1814 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | 1691 | static __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 | ||
1821 | static struct spi_driver wm8753_spi_driver = { | 1698 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1699 | { "wm8753", 0 }, | ||
1700 | { } | ||
1701 | }; | ||
1702 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1703 | |||
1704 | static 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 | ||
1832 | static int __init wm8753_modinit(void) | 1715 | static 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 | } |
1847 | module_init(wm8753_modinit); | 1734 | module_init(wm8753_modinit); |
1848 | 1735 | ||