diff options
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
-rw-r--r-- | sound/soc/codecs/wm8753.c | 404 |
1 files changed, 141 insertions, 263 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index b59f349c5218..8f679a13f2bc 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,11 @@ 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; | ||
88 | unsigned int sysclk; | 89 | unsigned int sysclk; |
89 | unsigned int pcmclk; | 90 | unsigned int pcmclk; |
90 | struct snd_soc_codec codec; | ||
91 | u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; | 91 | u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; |
92 | int dai_func; | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | /* | 95 | /* |
@@ -228,6 +229,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
228 | { | 229 | { |
229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 230 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
230 | int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); | 231 | int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL); |
232 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
231 | 233 | ||
232 | if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) | 234 | if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) |
233 | return 0; | 235 | return 0; |
@@ -235,8 +237,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
235 | mode &= 0xfff3; | 237 | mode &= 0xfff3; |
236 | mode |= (ucontrol->value.integer.value[0] << 2); | 238 | mode |= (ucontrol->value.integer.value[0] << 2); |
237 | 239 | ||
238 | wm8753_write(codec, WM8753_IOCTL, mode); | 240 | wm8753->dai_func = ucontrol->value.integer.value[0]; |
239 | wm8753_set_dai_mode(codec, ucontrol->value.integer.value[0]); | ||
240 | return 1; | 241 | return 1; |
241 | } | 242 | } |
242 | 243 | ||
@@ -904,6 +905,13 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
904 | return 0; | 905 | return 0; |
905 | } | 906 | } |
906 | 907 | ||
908 | static int wm8753_pcm_startup(struct snd_pcm_substream *substream, | ||
909 | struct snd_soc_dai *dai) | ||
910 | { | ||
911 | wm8753_set_dai_mode(dai->codec, dai, 0); | ||
912 | return 0; | ||
913 | } | ||
914 | |||
907 | /* | 915 | /* |
908 | * Set PCM DAI bit size and sample rate. | 916 | * Set PCM DAI bit size and sample rate. |
909 | */ | 917 | */ |
@@ -912,8 +920,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
912 | struct snd_soc_dai *dai) | 920 | struct snd_soc_dai *dai) |
913 | { | 921 | { |
914 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 922 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
915 | struct snd_soc_device *socdev = rtd->socdev; | 923 | 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); | 924 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
918 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; | 925 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; |
919 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; | 926 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; |
@@ -1138,6 +1145,13 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1138 | return 0; | 1145 | return 0; |
1139 | } | 1146 | } |
1140 | 1147 | ||
1148 | static int wm8753_i2s_startup(struct snd_pcm_substream *substream, | ||
1149 | struct snd_soc_dai *dai) | ||
1150 | { | ||
1151 | wm8753_set_dai_mode(dai->codec, dai, 1); | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1141 | /* | 1155 | /* |
1142 | * Set PCM DAI bit size and sample rate. | 1156 | * Set PCM DAI bit size and sample rate. |
1143 | */ | 1157 | */ |
@@ -1146,8 +1160,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
1146 | struct snd_soc_dai *dai) | 1160 | struct snd_soc_dai *dai) |
1147 | { | 1161 | { |
1148 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1162 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1149 | struct snd_soc_device *socdev = rtd->socdev; | 1163 | 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); | 1164 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
1152 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; | 1165 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; |
1153 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; | 1166 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; |
@@ -1240,12 +1253,12 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) | |||
1240 | { | 1253 | { |
1241 | struct snd_soc_codec *codec = dai->codec; | 1254 | struct snd_soc_codec *codec = dai->codec; |
1242 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; | 1255 | u16 mute_reg = wm8753_read_reg_cache(codec, WM8753_DAC) & 0xfff7; |
1256 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
1243 | 1257 | ||
1244 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. | 1258 | /* 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 */ | 1259 | * make sure we check if they are not both active when we mute */ |
1246 | if (mute && dai->id == 1) { | 1260 | if (mute && wm8753->dai_func == 1) { |
1247 | if (!wm8753_dai[WM8753_DAI_VOICE].playback.active || | 1261 | if (!codec->active) |
1248 | !wm8753_dai[WM8753_DAI_HIFI].playback.active) | ||
1249 | wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); | 1262 | wm8753_write(codec, WM8753_DAC, mute_reg | 0x8); |
1250 | } else { | 1263 | } else { |
1251 | if (mute) | 1264 | if (mute) |
@@ -1303,6 +1316,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 | 1316 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1304 | */ | 1317 | */ |
1305 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | 1318 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { |
1319 | .startup = wm8753_i2s_startup, | ||
1306 | .hw_params = wm8753_i2s_hw_params, | 1320 | .hw_params = wm8753_i2s_hw_params, |
1307 | .digital_mute = wm8753_mute, | 1321 | .digital_mute = wm8753_mute, |
1308 | .set_fmt = wm8753_mode1h_set_dai_fmt, | 1322 | .set_fmt = wm8753_mode1h_set_dai_fmt, |
@@ -1312,6 +1326,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | |||
1312 | }; | 1326 | }; |
1313 | 1327 | ||
1314 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | 1328 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { |
1329 | .startup = wm8753_pcm_startup, | ||
1315 | .hw_params = wm8753_pcm_hw_params, | 1330 | .hw_params = wm8753_pcm_hw_params, |
1316 | .digital_mute = wm8753_mute, | 1331 | .digital_mute = wm8753_mute, |
1317 | .set_fmt = wm8753_mode1v_set_dai_fmt, | 1332 | .set_fmt = wm8753_mode1v_set_dai_fmt, |
@@ -1321,6 +1336,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | |||
1321 | }; | 1336 | }; |
1322 | 1337 | ||
1323 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | 1338 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { |
1339 | .startup = wm8753_pcm_startup, | ||
1324 | .hw_params = wm8753_pcm_hw_params, | 1340 | .hw_params = wm8753_pcm_hw_params, |
1325 | .digital_mute = wm8753_mute, | 1341 | .digital_mute = wm8753_mute, |
1326 | .set_fmt = wm8753_mode2_set_dai_fmt, | 1342 | .set_fmt = wm8753_mode2_set_dai_fmt, |
@@ -1330,6 +1346,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | |||
1330 | }; | 1346 | }; |
1331 | 1347 | ||
1332 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { | 1348 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { |
1349 | .startup = wm8753_i2s_startup, | ||
1333 | .hw_params = wm8753_i2s_hw_params, | 1350 | .hw_params = wm8753_i2s_hw_params, |
1334 | .digital_mute = wm8753_mute, | 1351 | .digital_mute = wm8753_mute, |
1335 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | 1352 | .set_fmt = wm8753_mode3_4_set_dai_fmt, |
@@ -1339,6 +1356,7 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { | |||
1339 | }; | 1356 | }; |
1340 | 1357 | ||
1341 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { | 1358 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { |
1359 | .startup = wm8753_i2s_startup, | ||
1342 | .hw_params = wm8753_i2s_hw_params, | 1360 | .hw_params = wm8753_i2s_hw_params, |
1343 | .digital_mute = wm8753_mute, | 1361 | .digital_mute = wm8753_mute, |
1344 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | 1362 | .set_fmt = wm8753_mode3_4_set_dai_fmt, |
@@ -1347,10 +1365,9 @@ static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { | |||
1347 | .set_sysclk = wm8753_set_dai_sysclk, | 1365 | .set_sysclk = wm8753_set_dai_sysclk, |
1348 | }; | 1366 | }; |
1349 | 1367 | ||
1350 | static const struct snd_soc_dai wm8753_all_dai[] = { | 1368 | static struct snd_soc_dai_driver wm8753_all_dai[] = { |
1351 | /* DAI HiFi mode 1 */ | 1369 | /* DAI HiFi mode 1 */ |
1352 | { .name = "WM8753 HiFi", | 1370 | { .name = "wm8753-hifi", |
1353 | .id = 1, | ||
1354 | .playback = { | 1371 | .playback = { |
1355 | .stream_name = "HiFi Playback", | 1372 | .stream_name = "HiFi Playback", |
1356 | .channels_min = 1, | 1373 | .channels_min = 1, |
@@ -1366,8 +1383,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1366 | .ops = &wm8753_dai_ops_hifi_mode1, | 1383 | .ops = &wm8753_dai_ops_hifi_mode1, |
1367 | }, | 1384 | }, |
1368 | /* DAI Voice mode 1 */ | 1385 | /* DAI Voice mode 1 */ |
1369 | { .name = "WM8753 Voice", | 1386 | { .name = "wm8753-voice", |
1370 | .id = 1, | ||
1371 | .playback = { | 1387 | .playback = { |
1372 | .stream_name = "Voice Playback", | 1388 | .stream_name = "Voice Playback", |
1373 | .channels_min = 1, | 1389 | .channels_min = 1, |
@@ -1383,12 +1399,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1383 | .ops = &wm8753_dai_ops_voice_mode1, | 1399 | .ops = &wm8753_dai_ops_voice_mode1, |
1384 | }, | 1400 | }, |
1385 | /* DAI HiFi mode 2 - dummy */ | 1401 | /* DAI HiFi mode 2 - dummy */ |
1386 | { .name = "WM8753 HiFi", | 1402 | { .name = "wm8753-hifi", |
1387 | .id = 2, | ||
1388 | }, | 1403 | }, |
1389 | /* DAI Voice mode 2 */ | 1404 | /* DAI Voice mode 2 */ |
1390 | { .name = "WM8753 Voice", | 1405 | { .name = "wm8753-voice", |
1391 | .id = 2, | ||
1392 | .playback = { | 1406 | .playback = { |
1393 | .stream_name = "Voice Playback", | 1407 | .stream_name = "Voice Playback", |
1394 | .channels_min = 1, | 1408 | .channels_min = 1, |
@@ -1404,8 +1418,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1404 | .ops = &wm8753_dai_ops_voice_mode2, | 1418 | .ops = &wm8753_dai_ops_voice_mode2, |
1405 | }, | 1419 | }, |
1406 | /* DAI HiFi mode 3 */ | 1420 | /* DAI HiFi mode 3 */ |
1407 | { .name = "WM8753 HiFi", | 1421 | { .name = "wm8753-hifi", |
1408 | .id = 3, | ||
1409 | .playback = { | 1422 | .playback = { |
1410 | .stream_name = "HiFi Playback", | 1423 | .stream_name = "HiFi Playback", |
1411 | .channels_min = 1, | 1424 | .channels_min = 1, |
@@ -1421,12 +1434,10 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1421 | .ops = &wm8753_dai_ops_hifi_mode3, | 1434 | .ops = &wm8753_dai_ops_hifi_mode3, |
1422 | }, | 1435 | }, |
1423 | /* DAI Voice mode 3 - dummy */ | 1436 | /* DAI Voice mode 3 - dummy */ |
1424 | { .name = "WM8753 Voice", | 1437 | { .name = "wm8753-voice", |
1425 | .id = 3, | ||
1426 | }, | 1438 | }, |
1427 | /* DAI HiFi mode 4 */ | 1439 | /* DAI HiFi mode 4 */ |
1428 | { .name = "WM8753 HiFi", | 1440 | { .name = "wm8753-hifi", |
1429 | .id = 4, | ||
1430 | .playback = { | 1441 | .playback = { |
1431 | .stream_name = "HiFi Playback", | 1442 | .stream_name = "HiFi Playback", |
1432 | .channels_min = 1, | 1443 | .channels_min = 1, |
@@ -1442,58 +1453,31 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1442 | .ops = &wm8753_dai_ops_hifi_mode4, | 1453 | .ops = &wm8753_dai_ops_hifi_mode4, |
1443 | }, | 1454 | }, |
1444 | /* DAI Voice mode 4 - dummy */ | 1455 | /* DAI Voice mode 4 - dummy */ |
1445 | { .name = "WM8753 Voice", | 1456 | { .name = "wm8753-voice", |
1446 | .id = 4, | ||
1447 | }, | 1457 | }, |
1448 | }; | 1458 | }; |
1449 | 1459 | ||
1450 | struct snd_soc_dai wm8753_dai[] = { | 1460 | static struct snd_soc_dai_driver wm8753_dai[] = { |
1451 | { | 1461 | { |
1452 | .name = "WM8753 DAI 0", | 1462 | .name = "wm8753-aif0", |
1453 | }, | 1463 | }, |
1454 | { | 1464 | { |
1455 | .name = "WM8753 DAI 1", | 1465 | .name = "wm8753-aif1", |
1456 | }, | 1466 | }, |
1457 | }; | 1467 | }; |
1458 | EXPORT_SYMBOL_GPL(wm8753_dai); | ||
1459 | 1468 | ||
1460 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | 1469 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, |
1470 | struct snd_soc_dai *dai, unsigned int hifi) | ||
1461 | { | 1471 | { |
1462 | if (mode < 4) { | 1472 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
1463 | int playback_active, capture_active, codec_active, pop_wait; | 1473 | |
1464 | void *private_data; | 1474 | if (wm8753->dai_func < 4) { |
1465 | struct list_head list; | 1475 | if (hifi) |
1466 | 1476 | dai->driver = &wm8753_all_dai[wm8753->dai_func << 1]; | |
1467 | playback_active = wm8753_dai[0].playback.active; | 1477 | else |
1468 | capture_active = wm8753_dai[0].capture.active; | 1478 | 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 | } | 1479 | } |
1495 | wm8753_dai[0].codec = codec; | 1480 | wm8753_write(codec, WM8753_IOCTL, wm8753->dai_func); |
1496 | wm8753_dai[1].codec = codec; | ||
1497 | } | 1481 | } |
1498 | 1482 | ||
1499 | static void wm8753_work(struct work_struct *work) | 1483 | static void wm8753_work(struct work_struct *work) |
@@ -1503,19 +1487,14 @@ static void wm8753_work(struct work_struct *work) | |||
1503 | wm8753_set_bias_level(codec, codec->bias_level); | 1487 | wm8753_set_bias_level(codec, codec->bias_level); |
1504 | } | 1488 | } |
1505 | 1489 | ||
1506 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1490 | static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state) |
1507 | { | 1491 | { |
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); | 1492 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1512 | return 0; | 1493 | return 0; |
1513 | } | 1494 | } |
1514 | 1495 | ||
1515 | static int wm8753_resume(struct platform_device *pdev) | 1496 | static int wm8753_resume(struct snd_soc_codec *codec) |
1516 | { | 1497 | { |
1517 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1518 | struct snd_soc_codec *codec = socdev->card->codec; | ||
1519 | int i; | 1498 | int i; |
1520 | u8 data[2]; | 1499 | u8 data[2]; |
1521 | u16 *cache = codec->reg_cache; | 1500 | u16 *cache = codec->reg_cache; |
@@ -1547,41 +1526,6 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1547 | return 0; | 1526 | return 0; |
1548 | } | 1527 | } |
1549 | 1528 | ||
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 | /* | 1529 | /* |
1586 | * This function forces any delayed work to be queued and run. | 1530 | * This function forces any delayed work to be queued and run. |
1587 | */ | 1531 | */ |
@@ -1601,62 +1545,28 @@ static int run_delayed_work(struct delayed_work *dwork) | |||
1601 | return ret; | 1545 | return ret; |
1602 | } | 1546 | } |
1603 | 1547 | ||
1604 | /* power down chip */ | 1548 | static int wm8753_probe(struct snd_soc_codec *codec) |
1605 | static int wm8753_remove(struct platform_device *pdev) | ||
1606 | { | 1549 | { |
1607 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1550 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
1608 | 1551 | 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 | 1552 | ||
1623 | static int wm8753_register(struct wm8753_priv *wm8753) | 1553 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); |
1624 | { | ||
1625 | int ret, i; | ||
1626 | struct snd_soc_codec *codec = &wm8753->codec; | ||
1627 | u16 reg; | ||
1628 | 1554 | ||
1629 | if (wm8753_codec) { | 1555 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type); |
1630 | dev_err(codec->dev, "Multiple WM8753 devices not supported\n"); | 1556 | if (ret < 0) { |
1631 | ret = -EINVAL; | 1557 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
1632 | goto err; | 1558 | return ret; |
1633 | } | 1559 | } |
1634 | 1560 | ||
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); | 1561 | ret = wm8753_reset(codec); |
1655 | if (ret < 0) { | 1562 | if (ret < 0) { |
1656 | dev_err(codec->dev, "Failed to issue reset\n"); | 1563 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); |
1657 | goto err; | 1564 | return ret; |
1658 | } | 1565 | } |
1659 | 1566 | ||
1567 | wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1568 | wm8753->dai_func = 0; | ||
1569 | |||
1660 | /* charge output caps */ | 1570 | /* charge output caps */ |
1661 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1571 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1662 | schedule_delayed_work(&codec->delayed_work, | 1572 | schedule_delayed_work(&codec->delayed_work, |
@@ -1684,165 +1594,133 @@ static int wm8753_register(struct wm8753_priv *wm8753) | |||
1684 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); | 1594 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); |
1685 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); | 1595 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); |
1686 | 1596 | ||
1687 | wm8753_codec = codec; | 1597 | snd_soc_add_controls(codec, wm8753_snd_controls, |
1688 | 1598 | ARRAY_SIZE(wm8753_snd_controls)); | |
1689 | for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++) | 1599 | 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 | 1600 | ||
1704 | return 0; | 1601 | return 0; |
1705 | |||
1706 | err_codec: | ||
1707 | run_delayed_work(&codec->delayed_work); | ||
1708 | snd_soc_unregister_codec(codec); | ||
1709 | err: | ||
1710 | kfree(wm8753); | ||
1711 | return ret; | ||
1712 | } | 1602 | } |
1713 | 1603 | ||
1714 | static void wm8753_unregister(struct wm8753_priv *wm8753) | 1604 | /* power down chip */ |
1605 | static int wm8753_remove(struct snd_soc_codec *codec) | ||
1715 | { | 1606 | { |
1716 | wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF); | 1607 | run_delayed_work(&codec->delayed_work); |
1717 | run_delayed_work(&wm8753->codec.delayed_work); | 1608 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1718 | snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); | 1609 | |
1719 | snd_soc_unregister_codec(&wm8753->codec); | 1610 | return 0; |
1720 | kfree(wm8753); | ||
1721 | wm8753_codec = NULL; | ||
1722 | } | 1611 | } |
1723 | 1612 | ||
1724 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1613 | static struct snd_soc_codec_driver soc_codec_dev_wm8753 = { |
1614 | .probe = wm8753_probe, | ||
1615 | .remove = wm8753_remove, | ||
1616 | .suspend = wm8753_suspend, | ||
1617 | .resume = wm8753_resume, | ||
1618 | .set_bias_level = wm8753_set_bias_level, | ||
1619 | .reg_cache_size = ARRAY_SIZE(wm8753_reg), | ||
1620 | .reg_word_size = sizeof(u16), | ||
1621 | .reg_cache_default = wm8753_reg, | ||
1622 | }; | ||
1725 | 1623 | ||
1726 | static int wm8753_i2c_probe(struct i2c_client *i2c, | 1624 | #if defined(CONFIG_SPI_MASTER) |
1727 | const struct i2c_device_id *id) | 1625 | static int __devinit wm8753_spi_probe(struct spi_device *spi) |
1728 | { | 1626 | { |
1729 | struct snd_soc_codec *codec; | ||
1730 | struct wm8753_priv *wm8753; | 1627 | struct wm8753_priv *wm8753; |
1628 | int ret; | ||
1731 | 1629 | ||
1732 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1630 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1733 | if (wm8753 == NULL) | 1631 | if (wm8753 == NULL) |
1734 | return -ENOMEM; | 1632 | return -ENOMEM; |
1735 | 1633 | ||
1736 | codec = &wm8753->codec; | 1634 | wm8753->control_type = SND_SOC_SPI; |
1737 | codec->hw_write = (hw_write_t)i2c_master_send; | 1635 | spi_set_drvdata(spi, wm8753); |
1738 | codec->control_data = i2c; | ||
1739 | i2c_set_clientdata(i2c, wm8753); | ||
1740 | |||
1741 | codec->dev = &i2c->dev; | ||
1742 | 1636 | ||
1743 | return wm8753_register(wm8753); | 1637 | ret = snd_soc_register_codec(&spi->dev, |
1638 | &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); | ||
1639 | if (ret < 0) | ||
1640 | kfree(wm8753); | ||
1641 | return ret; | ||
1744 | } | 1642 | } |
1745 | 1643 | ||
1746 | static int wm8753_i2c_remove(struct i2c_client *client) | 1644 | static int __devexit wm8753_spi_remove(struct spi_device *spi) |
1747 | { | 1645 | { |
1748 | struct wm8753_priv *wm8753 = i2c_get_clientdata(client); | 1646 | snd_soc_unregister_codec(&spi->dev); |
1749 | wm8753_unregister(wm8753); | 1647 | kfree(spi_get_drvdata(spi)); |
1750 | return 0; | 1648 | return 0; |
1751 | } | 1649 | } |
1752 | 1650 | ||
1753 | static const struct i2c_device_id wm8753_i2c_id[] = { | 1651 | 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 = { | 1652 | .driver = { |
1761 | .name = "wm8753", | 1653 | .name = "wm8753-codec", |
1762 | .owner = THIS_MODULE, | 1654 | .owner = THIS_MODULE, |
1763 | }, | 1655 | }, |
1764 | .probe = wm8753_i2c_probe, | 1656 | .probe = wm8753_spi_probe, |
1765 | .remove = wm8753_i2c_remove, | 1657 | .remove = __devexit_p(wm8753_spi_remove), |
1766 | .id_table = wm8753_i2c_id, | ||
1767 | }; | 1658 | }; |
1768 | #endif | 1659 | #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 | 1660 | ||
1780 | msg[0] = data[0]; | 1661 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1781 | msg[1] = data[1]; | 1662 | static __devinit int wm8753_i2c_probe(struct i2c_client *i2c, |
1782 | 1663 | const struct i2c_device_id *id) | |
1783 | spi_message_init(&m); | ||
1784 | memset(&t, 0, (sizeof t)); | ||
1785 | |||
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 | { | 1664 | { |
1797 | struct snd_soc_codec *codec; | ||
1798 | struct wm8753_priv *wm8753; | 1665 | struct wm8753_priv *wm8753; |
1666 | int ret; | ||
1799 | 1667 | ||
1800 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1668 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1801 | if (wm8753 == NULL) | 1669 | if (wm8753 == NULL) |
1802 | return -ENOMEM; | 1670 | return -ENOMEM; |
1803 | 1671 | ||
1804 | codec = &wm8753->codec; | 1672 | i2c_set_clientdata(i2c, wm8753); |
1805 | codec->control_data = spi; | 1673 | wm8753->control_type = SND_SOC_I2C; |
1806 | codec->hw_write = (hw_write_t)wm8753_spi_write; | ||
1807 | codec->dev = &spi->dev; | ||
1808 | 1674 | ||
1809 | dev_set_drvdata(&spi->dev, wm8753); | 1675 | ret = snd_soc_register_codec(&i2c->dev, |
1810 | 1676 | &soc_codec_dev_wm8753, wm8753_dai, ARRAY_SIZE(wm8753_dai)); | |
1811 | return wm8753_register(wm8753); | 1677 | if (ret < 0) |
1678 | kfree(wm8753); | ||
1679 | return ret; | ||
1812 | } | 1680 | } |
1813 | 1681 | ||
1814 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | 1682 | static __devexit int wm8753_i2c_remove(struct i2c_client *client) |
1815 | { | 1683 | { |
1816 | struct wm8753_priv *wm8753 = dev_get_drvdata(&spi->dev); | 1684 | snd_soc_unregister_codec(&client->dev); |
1817 | wm8753_unregister(wm8753); | 1685 | kfree(i2c_get_clientdata(client)); |
1818 | return 0; | 1686 | return 0; |
1819 | } | 1687 | } |
1820 | 1688 | ||
1821 | static struct spi_driver wm8753_spi_driver = { | 1689 | static const struct i2c_device_id wm8753_i2c_id[] = { |
1690 | { "wm8753", 0 }, | ||
1691 | { } | ||
1692 | }; | ||
1693 | MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | ||
1694 | |||
1695 | static struct i2c_driver wm8753_i2c_driver = { | ||
1822 | .driver = { | 1696 | .driver = { |
1823 | .name = "wm8753", | 1697 | .name = "wm8753-codec", |
1824 | .bus = &spi_bus_type, | 1698 | .owner = THIS_MODULE, |
1825 | .owner = THIS_MODULE, | ||
1826 | }, | 1699 | }, |
1827 | .probe = wm8753_spi_probe, | 1700 | .probe = wm8753_i2c_probe, |
1828 | .remove = __devexit_p(wm8753_spi_remove), | 1701 | .remove = __devexit_p(wm8753_i2c_remove), |
1702 | .id_table = wm8753_i2c_id, | ||
1829 | }; | 1703 | }; |
1830 | #endif | 1704 | #endif |
1831 | 1705 | ||
1832 | static int __init wm8753_modinit(void) | 1706 | static int __init wm8753_modinit(void) |
1833 | { | 1707 | { |
1834 | int ret; | 1708 | int ret = 0; |
1835 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1709 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1836 | ret = i2c_add_driver(&wm8753_i2c_driver); | 1710 | ret = i2c_add_driver(&wm8753_i2c_driver); |
1837 | if (ret != 0) | 1711 | if (ret != 0) { |
1838 | pr_err("Failed to register WM8753 I2C driver: %d\n", ret); | 1712 | printk(KERN_ERR "Failed to register wm8753 I2C driver: %d\n", |
1713 | ret); | ||
1714 | } | ||
1839 | #endif | 1715 | #endif |
1840 | #if defined(CONFIG_SPI_MASTER) | 1716 | #if defined(CONFIG_SPI_MASTER) |
1841 | ret = spi_register_driver(&wm8753_spi_driver); | 1717 | ret = spi_register_driver(&wm8753_spi_driver); |
1842 | if (ret != 0) | 1718 | if (ret != 0) { |
1843 | pr_err("Failed to register WM8753 SPI driver: %d\n", ret); | 1719 | printk(KERN_ERR "Failed to register wm8753 SPI driver: %d\n", |
1720 | ret); | ||
1721 | } | ||
1844 | #endif | 1722 | #endif |
1845 | return 0; | 1723 | return ret; |
1846 | } | 1724 | } |
1847 | module_init(wm8753_modinit); | 1725 | module_init(wm8753_modinit); |
1848 | 1726 | ||