diff options
Diffstat (limited to 'sound/soc/codecs/wm8753.c')
-rw-r--r-- | sound/soc/codecs/wm8753.c | 542 |
1 files changed, 261 insertions, 281 deletions
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 77620ab98756..a6e8f3f7f052 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -51,8 +51,6 @@ | |||
51 | 51 | ||
52 | #include "wm8753.h" | 52 | #include "wm8753.h" |
53 | 53 | ||
54 | #define WM8753_VERSION "0.16" | ||
55 | |||
56 | static int caps_charge = 2000; | 54 | static int caps_charge = 2000; |
57 | module_param(caps_charge, int, 0); | 55 | module_param(caps_charge, int, 0); |
58 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 56 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
@@ -60,12 +58,6 @@ MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | |||
60 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | 58 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, |
61 | unsigned int mode); | 59 | unsigned int mode); |
62 | 60 | ||
63 | /* codec private data */ | ||
64 | struct wm8753_priv { | ||
65 | unsigned int sysclk; | ||
66 | unsigned int pcmclk; | ||
67 | }; | ||
68 | |||
69 | /* | 61 | /* |
70 | * wm8753 register cache | 62 | * wm8753 register cache |
71 | * We can't read the WM8753 register space when we | 63 | * We can't read the WM8753 register space when we |
@@ -90,6 +82,14 @@ static const u16 wm8753_reg[] = { | |||
90 | 0x0000, 0x0000 | 82 | 0x0000, 0x0000 |
91 | }; | 83 | }; |
92 | 84 | ||
85 | /* codec private data */ | ||
86 | struct wm8753_priv { | ||
87 | unsigned int sysclk; | ||
88 | unsigned int pcmclk; | ||
89 | struct snd_soc_codec codec; | ||
90 | u16 reg_cache[ARRAY_SIZE(wm8753_reg)]; | ||
91 | }; | ||
92 | |||
93 | /* | 93 | /* |
94 | * read wm8753 register cache | 94 | * read wm8753 register cache |
95 | */ | 95 | */ |
@@ -97,7 +97,7 @@ static inline unsigned int wm8753_read_reg_cache(struct snd_soc_codec *codec, | |||
97 | unsigned int reg) | 97 | unsigned int reg) |
98 | { | 98 | { |
99 | u16 *cache = codec->reg_cache; | 99 | u16 *cache = codec->reg_cache; |
100 | if (reg < 1 || reg > (ARRAY_SIZE(wm8753_reg) + 1)) | 100 | if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) |
101 | return -1; | 101 | return -1; |
102 | return cache[reg - 1]; | 102 | return cache[reg - 1]; |
103 | } | 103 | } |
@@ -109,7 +109,7 @@ static inline void wm8753_write_reg_cache(struct snd_soc_codec *codec, | |||
109 | unsigned int reg, unsigned int value) | 109 | unsigned int reg, unsigned int value) |
110 | { | 110 | { |
111 | u16 *cache = codec->reg_cache; | 111 | u16 *cache = codec->reg_cache; |
112 | if (reg < 1 || reg > 0x3f) | 112 | if (reg < 1 || reg >= (ARRAY_SIZE(wm8753_reg) + 1)) |
113 | return; | 113 | return; |
114 | cache[reg - 1] = value; | 114 | cache[reg - 1] = value; |
115 | } | 115 | } |
@@ -339,21 +339,6 @@ SOC_ENUM("ADC Data Select", wm8753_enum[27]), | |||
339 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), | 339 | SOC_ENUM("ROUT2 Phase", wm8753_enum[28]), |
340 | }; | 340 | }; |
341 | 341 | ||
342 | /* add non dapm controls */ | ||
343 | static int wm8753_add_controls(struct snd_soc_codec *codec) | ||
344 | { | ||
345 | int err, i; | ||
346 | |||
347 | for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) { | ||
348 | err = snd_ctl_add(codec->card, | ||
349 | snd_soc_cnew(&wm8753_snd_controls[i], | ||
350 | codec, NULL)); | ||
351 | if (err < 0) | ||
352 | return err; | ||
353 | } | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* | 342 | /* |
358 | * _DAPM_ Controls | 343 | * _DAPM_ Controls |
359 | */ | 344 | */ |
@@ -927,7 +912,7 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
927 | { | 912 | { |
928 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 913 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
929 | struct snd_soc_device *socdev = rtd->socdev; | 914 | struct snd_soc_device *socdev = rtd->socdev; |
930 | struct snd_soc_codec *codec = socdev->codec; | 915 | struct snd_soc_codec *codec = socdev->card->codec; |
931 | struct wm8753_priv *wm8753 = codec->private_data; | 916 | struct wm8753_priv *wm8753 = codec->private_data; |
932 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; | 917 | u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3; |
933 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; | 918 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f; |
@@ -1161,7 +1146,7 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
1161 | { | 1146 | { |
1162 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 1147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
1163 | struct snd_soc_device *socdev = rtd->socdev; | 1148 | struct snd_soc_device *socdev = rtd->socdev; |
1164 | struct snd_soc_codec *codec = socdev->codec; | 1149 | struct snd_soc_codec *codec = socdev->card->codec; |
1165 | struct wm8753_priv *wm8753 = codec->private_data; | 1150 | struct wm8753_priv *wm8753 = codec->private_data; |
1166 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; | 1151 | u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0; |
1167 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; | 1152 | u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3; |
@@ -1316,6 +1301,51 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, | |||
1316 | * 3. Voice disabled - HIFI over HIFI | 1301 | * 3. Voice disabled - HIFI over HIFI |
1317 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1302 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1318 | */ | 1303 | */ |
1304 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | ||
1305 | .hw_params = wm8753_i2s_hw_params, | ||
1306 | .digital_mute = wm8753_mute, | ||
1307 | .set_fmt = wm8753_mode1h_set_dai_fmt, | ||
1308 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1309 | .set_pll = wm8753_set_dai_pll, | ||
1310 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1311 | }; | ||
1312 | |||
1313 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | ||
1314 | .hw_params = wm8753_pcm_hw_params, | ||
1315 | .digital_mute = wm8753_mute, | ||
1316 | .set_fmt = wm8753_mode1v_set_dai_fmt, | ||
1317 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1318 | .set_pll = wm8753_set_dai_pll, | ||
1319 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1320 | }; | ||
1321 | |||
1322 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | ||
1323 | .hw_params = wm8753_pcm_hw_params, | ||
1324 | .digital_mute = wm8753_mute, | ||
1325 | .set_fmt = wm8753_mode2_set_dai_fmt, | ||
1326 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1327 | .set_pll = wm8753_set_dai_pll, | ||
1328 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1329 | }; | ||
1330 | |||
1331 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { | ||
1332 | .hw_params = wm8753_i2s_hw_params, | ||
1333 | .digital_mute = wm8753_mute, | ||
1334 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1335 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1336 | .set_pll = wm8753_set_dai_pll, | ||
1337 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1338 | }; | ||
1339 | |||
1340 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { | ||
1341 | .hw_params = wm8753_i2s_hw_params, | ||
1342 | .digital_mute = wm8753_mute, | ||
1343 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1344 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1345 | .set_pll = wm8753_set_dai_pll, | ||
1346 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1347 | }; | ||
1348 | |||
1319 | static const struct snd_soc_dai wm8753_all_dai[] = { | 1349 | static const struct snd_soc_dai wm8753_all_dai[] = { |
1320 | /* DAI HiFi mode 1 */ | 1350 | /* DAI HiFi mode 1 */ |
1321 | { .name = "WM8753 HiFi", | 1351 | { .name = "WM8753 HiFi", |
@@ -1332,14 +1362,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1332 | .channels_max = 2, | 1362 | .channels_max = 2, |
1333 | .rates = WM8753_RATES, | 1363 | .rates = WM8753_RATES, |
1334 | .formats = WM8753_FORMATS}, | 1364 | .formats = WM8753_FORMATS}, |
1335 | .ops = { | 1365 | .ops = &wm8753_dai_ops_hifi_mode1, |
1336 | .hw_params = wm8753_i2s_hw_params, | ||
1337 | .digital_mute = wm8753_mute, | ||
1338 | .set_fmt = wm8753_mode1h_set_dai_fmt, | ||
1339 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1340 | .set_pll = wm8753_set_dai_pll, | ||
1341 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1342 | }, | ||
1343 | }, | 1366 | }, |
1344 | /* DAI Voice mode 1 */ | 1367 | /* DAI Voice mode 1 */ |
1345 | { .name = "WM8753 Voice", | 1368 | { .name = "WM8753 Voice", |
@@ -1356,14 +1379,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1356 | .channels_max = 2, | 1379 | .channels_max = 2, |
1357 | .rates = WM8753_RATES, | 1380 | .rates = WM8753_RATES, |
1358 | .formats = WM8753_FORMATS,}, | 1381 | .formats = WM8753_FORMATS,}, |
1359 | .ops = { | 1382 | .ops = &wm8753_dai_ops_voice_mode1, |
1360 | .hw_params = wm8753_pcm_hw_params, | ||
1361 | .digital_mute = wm8753_mute, | ||
1362 | .set_fmt = wm8753_mode1v_set_dai_fmt, | ||
1363 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1364 | .set_pll = wm8753_set_dai_pll, | ||
1365 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1366 | }, | ||
1367 | }, | 1383 | }, |
1368 | /* DAI HiFi mode 2 - dummy */ | 1384 | /* DAI HiFi mode 2 - dummy */ |
1369 | { .name = "WM8753 HiFi", | 1385 | { .name = "WM8753 HiFi", |
@@ -1384,14 +1400,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1384 | .channels_max = 2, | 1400 | .channels_max = 2, |
1385 | .rates = WM8753_RATES, | 1401 | .rates = WM8753_RATES, |
1386 | .formats = WM8753_FORMATS,}, | 1402 | .formats = WM8753_FORMATS,}, |
1387 | .ops = { | 1403 | .ops = &wm8753_dai_ops_voice_mode2, |
1388 | .hw_params = wm8753_pcm_hw_params, | ||
1389 | .digital_mute = wm8753_mute, | ||
1390 | .set_fmt = wm8753_mode2_set_dai_fmt, | ||
1391 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1392 | .set_pll = wm8753_set_dai_pll, | ||
1393 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1394 | }, | ||
1395 | }, | 1404 | }, |
1396 | /* DAI HiFi mode 3 */ | 1405 | /* DAI HiFi mode 3 */ |
1397 | { .name = "WM8753 HiFi", | 1406 | { .name = "WM8753 HiFi", |
@@ -1408,14 +1417,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1408 | .channels_max = 2, | 1417 | .channels_max = 2, |
1409 | .rates = WM8753_RATES, | 1418 | .rates = WM8753_RATES, |
1410 | .formats = WM8753_FORMATS,}, | 1419 | .formats = WM8753_FORMATS,}, |
1411 | .ops = { | 1420 | .ops = &wm8753_dai_ops_hifi_mode3, |
1412 | .hw_params = wm8753_i2s_hw_params, | ||
1413 | .digital_mute = wm8753_mute, | ||
1414 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1415 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1416 | .set_pll = wm8753_set_dai_pll, | ||
1417 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1418 | }, | ||
1419 | }, | 1421 | }, |
1420 | /* DAI Voice mode 3 - dummy */ | 1422 | /* DAI Voice mode 3 - dummy */ |
1421 | { .name = "WM8753 Voice", | 1423 | { .name = "WM8753 Voice", |
@@ -1436,14 +1438,7 @@ static const struct snd_soc_dai wm8753_all_dai[] = { | |||
1436 | .channels_max = 2, | 1438 | .channels_max = 2, |
1437 | .rates = WM8753_RATES, | 1439 | .rates = WM8753_RATES, |
1438 | .formats = WM8753_FORMATS,}, | 1440 | .formats = WM8753_FORMATS,}, |
1439 | .ops = { | 1441 | .ops = &wm8753_dai_ops_hifi_mode4, |
1440 | .hw_params = wm8753_i2s_hw_params, | ||
1441 | .digital_mute = wm8753_mute, | ||
1442 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1443 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1444 | .set_pll = wm8753_set_dai_pll, | ||
1445 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1446 | }, | ||
1447 | }, | 1442 | }, |
1448 | /* DAI Voice mode 4 - dummy */ | 1443 | /* DAI Voice mode 4 - dummy */ |
1449 | { .name = "WM8753 Voice", | 1444 | { .name = "WM8753 Voice", |
@@ -1466,30 +1461,35 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec, unsigned int mode) | |||
1466 | if (mode < 4) { | 1461 | if (mode < 4) { |
1467 | int playback_active, capture_active, codec_active, pop_wait; | 1462 | int playback_active, capture_active, codec_active, pop_wait; |
1468 | void *private_data; | 1463 | void *private_data; |
1464 | struct list_head list; | ||
1469 | 1465 | ||
1470 | playback_active = wm8753_dai[0].playback.active; | 1466 | playback_active = wm8753_dai[0].playback.active; |
1471 | capture_active = wm8753_dai[0].capture.active; | 1467 | capture_active = wm8753_dai[0].capture.active; |
1472 | codec_active = wm8753_dai[0].active; | 1468 | codec_active = wm8753_dai[0].active; |
1473 | private_data = wm8753_dai[0].private_data; | 1469 | private_data = wm8753_dai[0].private_data; |
1474 | pop_wait = wm8753_dai[0].pop_wait; | 1470 | pop_wait = wm8753_dai[0].pop_wait; |
1471 | list = wm8753_dai[0].list; | ||
1475 | wm8753_dai[0] = wm8753_all_dai[mode << 1]; | 1472 | wm8753_dai[0] = wm8753_all_dai[mode << 1]; |
1476 | wm8753_dai[0].playback.active = playback_active; | 1473 | wm8753_dai[0].playback.active = playback_active; |
1477 | wm8753_dai[0].capture.active = capture_active; | 1474 | wm8753_dai[0].capture.active = capture_active; |
1478 | wm8753_dai[0].active = codec_active; | 1475 | wm8753_dai[0].active = codec_active; |
1479 | wm8753_dai[0].private_data = private_data; | 1476 | wm8753_dai[0].private_data = private_data; |
1480 | wm8753_dai[0].pop_wait = pop_wait; | 1477 | wm8753_dai[0].pop_wait = pop_wait; |
1478 | wm8753_dai[0].list = list; | ||
1481 | 1479 | ||
1482 | playback_active = wm8753_dai[1].playback.active; | 1480 | playback_active = wm8753_dai[1].playback.active; |
1483 | capture_active = wm8753_dai[1].capture.active; | 1481 | capture_active = wm8753_dai[1].capture.active; |
1484 | codec_active = wm8753_dai[1].active; | 1482 | codec_active = wm8753_dai[1].active; |
1485 | private_data = wm8753_dai[1].private_data; | 1483 | private_data = wm8753_dai[1].private_data; |
1486 | pop_wait = wm8753_dai[1].pop_wait; | 1484 | pop_wait = wm8753_dai[1].pop_wait; |
1485 | list = wm8753_dai[1].list; | ||
1487 | wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1]; | 1486 | wm8753_dai[1] = wm8753_all_dai[(mode << 1) + 1]; |
1488 | wm8753_dai[1].playback.active = playback_active; | 1487 | wm8753_dai[1].playback.active = playback_active; |
1489 | wm8753_dai[1].capture.active = capture_active; | 1488 | wm8753_dai[1].capture.active = capture_active; |
1490 | wm8753_dai[1].active = codec_active; | 1489 | wm8753_dai[1].active = codec_active; |
1491 | wm8753_dai[1].private_data = private_data; | 1490 | wm8753_dai[1].private_data = private_data; |
1492 | wm8753_dai[1].pop_wait = pop_wait; | 1491 | wm8753_dai[1].pop_wait = pop_wait; |
1492 | wm8753_dai[1].list = list; | ||
1493 | } | 1493 | } |
1494 | wm8753_dai[0].codec = codec; | 1494 | wm8753_dai[0].codec = codec; |
1495 | wm8753_dai[1].codec = codec; | 1495 | wm8753_dai[1].codec = codec; |
@@ -1505,7 +1505,7 @@ static void wm8753_work(struct work_struct *work) | |||
1505 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | 1505 | static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) |
1506 | { | 1506 | { |
1507 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1507 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1508 | struct snd_soc_codec *codec = socdev->codec; | 1508 | struct snd_soc_codec *codec = socdev->card->codec; |
1509 | 1509 | ||
1510 | /* we only need to suspend if we are a valid card */ | 1510 | /* we only need to suspend if we are a valid card */ |
1511 | if (!codec->card) | 1511 | if (!codec->card) |
@@ -1518,7 +1518,7 @@ static int wm8753_suspend(struct platform_device *pdev, pm_message_t state) | |||
1518 | static int wm8753_resume(struct platform_device *pdev) | 1518 | static int wm8753_resume(struct platform_device *pdev) |
1519 | { | 1519 | { |
1520 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1520 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1521 | struct snd_soc_codec *codec = socdev->codec; | 1521 | struct snd_soc_codec *codec = socdev->card->codec; |
1522 | int i; | 1522 | int i; |
1523 | u8 data[2]; | 1523 | u8 data[2]; |
1524 | u16 *cache = codec->reg_cache; | 1524 | u16 *cache = codec->reg_cache; |
@@ -1531,6 +1531,11 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1531 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { | 1531 | for (i = 0; i < ARRAY_SIZE(wm8753_reg); i++) { |
1532 | if (i + 1 == WM8753_RESET) | 1532 | if (i + 1 == WM8753_RESET) |
1533 | continue; | 1533 | continue; |
1534 | |||
1535 | /* No point in writing hardware default values back */ | ||
1536 | if (cache[i] == wm8753_reg[i]) | ||
1537 | continue; | ||
1538 | |||
1534 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); | 1539 | data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001); |
1535 | data[1] = cache[i] & 0x00ff; | 1540 | data[1] = cache[i] & 0x00ff; |
1536 | codec->hw_write(codec->control_data, data, 2); | 1541 | codec->hw_write(codec->control_data, data, 2); |
@@ -1549,44 +1554,129 @@ static int wm8753_resume(struct platform_device *pdev) | |||
1549 | return 0; | 1554 | return 0; |
1550 | } | 1555 | } |
1551 | 1556 | ||
1557 | static struct snd_soc_codec *wm8753_codec; | ||
1558 | |||
1559 | static int wm8753_probe(struct platform_device *pdev) | ||
1560 | { | ||
1561 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1562 | struct snd_soc_codec *codec; | ||
1563 | int ret = 0; | ||
1564 | |||
1565 | if (!wm8753_codec) { | ||
1566 | dev_err(&pdev->dev, "WM8753 codec not yet registered\n"); | ||
1567 | return -EINVAL; | ||
1568 | } | ||
1569 | |||
1570 | socdev->card->codec = wm8753_codec; | ||
1571 | codec = wm8753_codec; | ||
1572 | |||
1573 | wm8753_set_dai_mode(codec, 0); | ||
1574 | |||
1575 | /* register pcms */ | ||
1576 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1577 | if (ret < 0) { | ||
1578 | printk(KERN_ERR "wm8753: failed to create pcms\n"); | ||
1579 | goto pcm_err; | ||
1580 | } | ||
1581 | |||
1582 | snd_soc_add_controls(codec, wm8753_snd_controls, | ||
1583 | ARRAY_SIZE(wm8753_snd_controls)); | ||
1584 | wm8753_add_widgets(codec); | ||
1585 | ret = snd_soc_init_card(socdev); | ||
1586 | if (ret < 0) { | ||
1587 | printk(KERN_ERR "wm8753: failed to register card\n"); | ||
1588 | goto card_err; | ||
1589 | } | ||
1590 | |||
1591 | return 0; | ||
1592 | |||
1593 | card_err: | ||
1594 | snd_soc_free_pcms(socdev); | ||
1595 | snd_soc_dapm_free(socdev); | ||
1596 | |||
1597 | pcm_err: | ||
1598 | return ret; | ||
1599 | } | ||
1600 | |||
1552 | /* | 1601 | /* |
1553 | * initialise the WM8753 driver | 1602 | * This function forces any delayed work to be queued and run. |
1554 | * register the mixer and dsp interfaces with the kernel | ||
1555 | */ | 1603 | */ |
1556 | static int wm8753_init(struct snd_soc_device *socdev) | 1604 | static int run_delayed_work(struct delayed_work *dwork) |
1605 | { | ||
1606 | int ret; | ||
1607 | |||
1608 | /* cancel any work waiting to be queued. */ | ||
1609 | ret = cancel_delayed_work(dwork); | ||
1610 | |||
1611 | /* if there was any work waiting then we run it now and | ||
1612 | * wait for it's completion */ | ||
1613 | if (ret) { | ||
1614 | schedule_delayed_work(dwork, 0); | ||
1615 | flush_scheduled_work(); | ||
1616 | } | ||
1617 | return ret; | ||
1618 | } | ||
1619 | |||
1620 | /* power down chip */ | ||
1621 | static int wm8753_remove(struct platform_device *pdev) | ||
1557 | { | 1622 | { |
1558 | struct snd_soc_codec *codec = socdev->codec; | 1623 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1559 | int reg, ret = 0; | 1624 | |
1625 | snd_soc_free_pcms(socdev); | ||
1626 | snd_soc_dapm_free(socdev); | ||
1627 | |||
1628 | return 0; | ||
1629 | } | ||
1630 | |||
1631 | struct snd_soc_codec_device soc_codec_dev_wm8753 = { | ||
1632 | .probe = wm8753_probe, | ||
1633 | .remove = wm8753_remove, | ||
1634 | .suspend = wm8753_suspend, | ||
1635 | .resume = wm8753_resume, | ||
1636 | }; | ||
1637 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); | ||
1638 | |||
1639 | static int wm8753_register(struct wm8753_priv *wm8753) | ||
1640 | { | ||
1641 | int ret, i; | ||
1642 | struct snd_soc_codec *codec = &wm8753->codec; | ||
1643 | u16 reg; | ||
1644 | |||
1645 | if (wm8753_codec) { | ||
1646 | dev_err(codec->dev, "Multiple WM8753 devices not supported\n"); | ||
1647 | ret = -EINVAL; | ||
1648 | goto err; | ||
1649 | } | ||
1650 | |||
1651 | mutex_init(&codec->mutex); | ||
1652 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1653 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1560 | 1654 | ||
1561 | codec->name = "WM8753"; | 1655 | codec->name = "WM8753"; |
1562 | codec->owner = THIS_MODULE; | 1656 | codec->owner = THIS_MODULE; |
1563 | codec->read = wm8753_read_reg_cache; | 1657 | codec->read = wm8753_read_reg_cache; |
1564 | codec->write = wm8753_write; | 1658 | codec->write = wm8753_write; |
1659 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
1565 | codec->set_bias_level = wm8753_set_bias_level; | 1660 | codec->set_bias_level = wm8753_set_bias_level; |
1566 | codec->dai = wm8753_dai; | 1661 | codec->dai = wm8753_dai; |
1567 | codec->num_dai = 2; | 1662 | codec->num_dai = 2; |
1568 | codec->reg_cache_size = ARRAY_SIZE(wm8753_reg); | 1663 | codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache); |
1569 | codec->reg_cache = kmemdup(wm8753_reg, sizeof(wm8753_reg), GFP_KERNEL); | 1664 | codec->reg_cache = &wm8753->reg_cache; |
1570 | 1665 | codec->private_data = wm8753; | |
1571 | if (codec->reg_cache == NULL) | ||
1572 | return -ENOMEM; | ||
1573 | |||
1574 | wm8753_set_dai_mode(codec, 0); | ||
1575 | 1666 | ||
1576 | wm8753_reset(codec); | 1667 | memcpy(codec->reg_cache, wm8753_reg, sizeof(codec->reg_cache)); |
1668 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); | ||
1577 | 1669 | ||
1578 | /* register pcms */ | 1670 | ret = wm8753_reset(codec); |
1579 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1580 | if (ret < 0) { | 1671 | if (ret < 0) { |
1581 | printk(KERN_ERR "wm8753: failed to create pcms\n"); | 1672 | dev_err(codec->dev, "Failed to issue reset\n"); |
1582 | goto pcm_err; | 1673 | goto err; |
1583 | } | 1674 | } |
1584 | 1675 | ||
1585 | /* charge output caps */ | 1676 | /* charge output caps */ |
1586 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | 1677 | wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE); |
1587 | codec->bias_level = SND_SOC_BIAS_STANDBY; | ||
1588 | schedule_delayed_work(&codec->delayed_work, | 1678 | schedule_delayed_work(&codec->delayed_work, |
1589 | msecs_to_jiffies(caps_charge)); | 1679 | msecs_to_jiffies(caps_charge)); |
1590 | 1680 | ||
1591 | /* set the update bits */ | 1681 | /* set the update bits */ |
1592 | reg = wm8753_read_reg_cache(codec, WM8753_LDAC); | 1682 | reg = wm8753_read_reg_cache(codec, WM8753_LDAC); |
@@ -1610,59 +1700,70 @@ static int wm8753_init(struct snd_soc_device *socdev) | |||
1610 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); | 1700 | reg = wm8753_read_reg_cache(codec, WM8753_RINVOL); |
1611 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); | 1701 | wm8753_write(codec, WM8753_RINVOL, reg | 0x0100); |
1612 | 1702 | ||
1613 | wm8753_add_controls(codec); | 1703 | wm8753_codec = codec; |
1614 | wm8753_add_widgets(codec); | 1704 | |
1615 | ret = snd_soc_init_card(socdev); | 1705 | for (i = 0; i < ARRAY_SIZE(wm8753_dai); i++) |
1616 | if (ret < 0) { | 1706 | wm8753_dai[i].dev = codec->dev; |
1617 | printk(KERN_ERR "wm8753: failed to register card\n"); | 1707 | |
1618 | goto card_err; | 1708 | ret = snd_soc_register_codec(codec); |
1709 | if (ret != 0) { | ||
1710 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
1711 | goto err; | ||
1619 | } | 1712 | } |
1620 | 1713 | ||
1621 | return ret; | 1714 | ret = snd_soc_register_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); |
1715 | if (ret != 0) { | ||
1716 | dev_err(codec->dev, "Failed to register DAIs: %d\n", ret); | ||
1717 | goto err_codec; | ||
1718 | } | ||
1622 | 1719 | ||
1623 | card_err: | 1720 | return 0; |
1624 | snd_soc_free_pcms(socdev); | 1721 | |
1625 | snd_soc_dapm_free(socdev); | 1722 | err_codec: |
1626 | pcm_err: | 1723 | run_delayed_work(&codec->delayed_work); |
1627 | kfree(codec->reg_cache); | 1724 | snd_soc_unregister_codec(codec); |
1725 | err: | ||
1726 | kfree(wm8753); | ||
1628 | return ret; | 1727 | return ret; |
1629 | } | 1728 | } |
1630 | 1729 | ||
1631 | /* If the i2c layer weren't so broken, we could pass this kind of data | 1730 | static void wm8753_unregister(struct wm8753_priv *wm8753) |
1632 | around */ | 1731 | { |
1633 | static struct snd_soc_device *wm8753_socdev; | 1732 | wm8753_set_bias_level(&wm8753->codec, SND_SOC_BIAS_OFF); |
1733 | run_delayed_work(&wm8753->codec.delayed_work); | ||
1734 | snd_soc_unregister_dais(&wm8753_dai[0], ARRAY_SIZE(wm8753_dai)); | ||
1735 | snd_soc_unregister_codec(&wm8753->codec); | ||
1736 | kfree(wm8753); | ||
1737 | wm8753_codec = NULL; | ||
1738 | } | ||
1634 | 1739 | ||
1635 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1740 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1636 | 1741 | ||
1637 | /* | ||
1638 | * WM8753 2 wire address is determined by GPIO5 | ||
1639 | * state during powerup. | ||
1640 | * low = 0x1a | ||
1641 | * high = 0x1b | ||
1642 | */ | ||
1643 | |||
1644 | static int wm8753_i2c_probe(struct i2c_client *i2c, | 1742 | static int wm8753_i2c_probe(struct i2c_client *i2c, |
1645 | const struct i2c_device_id *id) | 1743 | const struct i2c_device_id *id) |
1646 | { | 1744 | { |
1647 | struct snd_soc_device *socdev = wm8753_socdev; | 1745 | struct snd_soc_codec *codec; |
1648 | struct snd_soc_codec *codec = socdev->codec; | 1746 | struct wm8753_priv *wm8753; |
1649 | int ret; | ||
1650 | 1747 | ||
1651 | i2c_set_clientdata(i2c, codec); | 1748 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1652 | codec->control_data = i2c; | 1749 | if (wm8753 == NULL) |
1750 | return -ENOMEM; | ||
1653 | 1751 | ||
1654 | ret = wm8753_init(socdev); | 1752 | codec = &wm8753->codec; |
1655 | if (ret < 0) | 1753 | codec->hw_write = (hw_write_t)i2c_master_send; |
1656 | pr_err("failed to initialise WM8753\n"); | 1754 | codec->control_data = i2c; |
1755 | i2c_set_clientdata(i2c, wm8753); | ||
1657 | 1756 | ||
1658 | return ret; | 1757 | codec->dev = &i2c->dev; |
1758 | |||
1759 | return wm8753_register(wm8753); | ||
1659 | } | 1760 | } |
1660 | 1761 | ||
1661 | static int wm8753_i2c_remove(struct i2c_client *client) | 1762 | static int wm8753_i2c_remove(struct i2c_client *client) |
1662 | { | 1763 | { |
1663 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1764 | struct wm8753_priv *wm8753 = i2c_get_clientdata(client); |
1664 | kfree(codec->reg_cache); | 1765 | wm8753_unregister(wm8753); |
1665 | return 0; | 1766 | return 0; |
1666 | } | 1767 | } |
1667 | 1768 | ||
1668 | static const struct i2c_device_id wm8753_i2c_id[] = { | 1769 | static const struct i2c_device_id wm8753_i2c_id[] = { |
@@ -1673,86 +1774,16 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); | |||
1673 | 1774 | ||
1674 | static struct i2c_driver wm8753_i2c_driver = { | 1775 | static struct i2c_driver wm8753_i2c_driver = { |
1675 | .driver = { | 1776 | .driver = { |
1676 | .name = "WM8753 I2C Codec", | 1777 | .name = "wm8753", |
1677 | .owner = THIS_MODULE, | 1778 | .owner = THIS_MODULE, |
1678 | }, | 1779 | }, |
1679 | .probe = wm8753_i2c_probe, | 1780 | .probe = wm8753_i2c_probe, |
1680 | .remove = wm8753_i2c_remove, | 1781 | .remove = wm8753_i2c_remove, |
1681 | .id_table = wm8753_i2c_id, | 1782 | .id_table = wm8753_i2c_id, |
1682 | }; | 1783 | }; |
1683 | |||
1684 | static int wm8753_add_i2c_device(struct platform_device *pdev, | ||
1685 | const struct wm8753_setup_data *setup) | ||
1686 | { | ||
1687 | struct i2c_board_info info; | ||
1688 | struct i2c_adapter *adapter; | ||
1689 | struct i2c_client *client; | ||
1690 | int ret; | ||
1691 | |||
1692 | ret = i2c_add_driver(&wm8753_i2c_driver); | ||
1693 | if (ret != 0) { | ||
1694 | dev_err(&pdev->dev, "can't add i2c driver\n"); | ||
1695 | return ret; | ||
1696 | } | ||
1697 | |||
1698 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1699 | info.addr = setup->i2c_address; | ||
1700 | strlcpy(info.type, "wm8753", I2C_NAME_SIZE); | ||
1701 | |||
1702 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1703 | if (!adapter) { | ||
1704 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1705 | setup->i2c_bus); | ||
1706 | goto err_driver; | ||
1707 | } | ||
1708 | |||
1709 | client = i2c_new_device(adapter, &info); | ||
1710 | i2c_put_adapter(adapter); | ||
1711 | if (!client) { | ||
1712 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1713 | (unsigned int)info.addr); | ||
1714 | goto err_driver; | ||
1715 | } | ||
1716 | |||
1717 | return 0; | ||
1718 | |||
1719 | err_driver: | ||
1720 | i2c_del_driver(&wm8753_i2c_driver); | ||
1721 | return -ENODEV; | ||
1722 | } | ||
1723 | #endif | 1784 | #endif |
1724 | 1785 | ||
1725 | #if defined(CONFIG_SPI_MASTER) | 1786 | #if defined(CONFIG_SPI_MASTER) |
1726 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | ||
1727 | { | ||
1728 | struct snd_soc_device *socdev = wm8753_socdev; | ||
1729 | struct snd_soc_codec *codec = socdev->codec; | ||
1730 | int ret; | ||
1731 | |||
1732 | codec->control_data = spi; | ||
1733 | |||
1734 | ret = wm8753_init(socdev); | ||
1735 | if (ret < 0) | ||
1736 | dev_err(&spi->dev, "failed to initialise WM8753\n"); | ||
1737 | |||
1738 | return ret; | ||
1739 | } | ||
1740 | |||
1741 | static int __devexit wm8753_spi_remove(struct spi_device *spi) | ||
1742 | { | ||
1743 | return 0; | ||
1744 | } | ||
1745 | |||
1746 | static struct spi_driver wm8753_spi_driver = { | ||
1747 | .driver = { | ||
1748 | .name = "wm8753", | ||
1749 | .bus = &spi_bus_type, | ||
1750 | .owner = THIS_MODULE, | ||
1751 | }, | ||
1752 | .probe = wm8753_spi_probe, | ||
1753 | .remove = __devexit_p(wm8753_spi_remove), | ||
1754 | }; | ||
1755 | |||
1756 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | 1787 | static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) |
1757 | { | 1788 | { |
1758 | struct spi_transfer t; | 1789 | struct spi_transfer t; |
@@ -1776,120 +1807,69 @@ static int wm8753_spi_write(struct spi_device *spi, const char *data, int len) | |||
1776 | 1807 | ||
1777 | return len; | 1808 | return len; |
1778 | } | 1809 | } |
1779 | #endif | ||
1780 | 1810 | ||
1781 | 1811 | static int __devinit wm8753_spi_probe(struct spi_device *spi) | |
1782 | static int wm8753_probe(struct platform_device *pdev) | ||
1783 | { | 1812 | { |
1784 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1785 | struct wm8753_setup_data *setup; | ||
1786 | struct snd_soc_codec *codec; | 1813 | struct snd_soc_codec *codec; |
1787 | struct wm8753_priv *wm8753; | 1814 | struct wm8753_priv *wm8753; |
1788 | int ret = 0; | ||
1789 | |||
1790 | pr_info("WM8753 Audio Codec %s", WM8753_VERSION); | ||
1791 | |||
1792 | setup = socdev->codec_data; | ||
1793 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1794 | if (codec == NULL) | ||
1795 | return -ENOMEM; | ||
1796 | 1815 | ||
1797 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); | 1816 | wm8753 = kzalloc(sizeof(struct wm8753_priv), GFP_KERNEL); |
1798 | if (wm8753 == NULL) { | 1817 | if (wm8753 == NULL) |
1799 | kfree(codec); | ||
1800 | return -ENOMEM; | 1818 | return -ENOMEM; |
1801 | } | ||
1802 | 1819 | ||
1803 | codec->private_data = wm8753; | 1820 | codec = &wm8753->codec; |
1804 | socdev->codec = codec; | 1821 | codec->control_data = spi; |
1805 | mutex_init(&codec->mutex); | 1822 | codec->hw_write = (hw_write_t)wm8753_spi_write; |
1806 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1823 | codec->dev = &spi->dev; |
1807 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1808 | wm8753_socdev = socdev; | ||
1809 | INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work); | ||
1810 | 1824 | ||
1811 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1825 | spi->dev.driver_data = wm8753; |
1812 | if (setup->i2c_address) { | ||
1813 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
1814 | ret = wm8753_add_i2c_device(pdev, setup); | ||
1815 | } | ||
1816 | #endif | ||
1817 | #if defined(CONFIG_SPI_MASTER) | ||
1818 | if (setup->spi) { | ||
1819 | codec->hw_write = (hw_write_t)wm8753_spi_write; | ||
1820 | ret = spi_register_driver(&wm8753_spi_driver); | ||
1821 | if (ret != 0) | ||
1822 | printk(KERN_ERR "can't add spi driver"); | ||
1823 | } | ||
1824 | #endif | ||
1825 | 1826 | ||
1826 | if (ret != 0) { | 1827 | return wm8753_register(wm8753); |
1827 | kfree(codec->private_data); | ||
1828 | kfree(codec); | ||
1829 | } | ||
1830 | return ret; | ||
1831 | } | 1828 | } |
1832 | 1829 | ||
1833 | /* | 1830 | static int __devexit wm8753_spi_remove(struct spi_device *spi) |
1834 | * This function forces any delayed work to be queued and run. | ||
1835 | */ | ||
1836 | static int run_delayed_work(struct delayed_work *dwork) | ||
1837 | { | 1831 | { |
1838 | int ret; | 1832 | struct wm8753_priv *wm8753 = spi->dev.driver_data; |
1839 | 1833 | wm8753_unregister(wm8753); | |
1840 | /* cancel any work waiting to be queued. */ | 1834 | return 0; |
1841 | ret = cancel_delayed_work(dwork); | ||
1842 | |||
1843 | /* if there was any work waiting then we run it now and | ||
1844 | * wait for it's completion */ | ||
1845 | if (ret) { | ||
1846 | schedule_delayed_work(dwork, 0); | ||
1847 | flush_scheduled_work(); | ||
1848 | } | ||
1849 | return ret; | ||
1850 | } | 1835 | } |
1851 | 1836 | ||
1852 | /* power down chip */ | 1837 | static struct spi_driver wm8753_spi_driver = { |
1853 | static int wm8753_remove(struct platform_device *pdev) | 1838 | .driver = { |
1854 | { | 1839 | .name = "wm8753", |
1855 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1840 | .bus = &spi_bus_type, |
1856 | struct snd_soc_codec *codec = socdev->codec; | 1841 | .owner = THIS_MODULE, |
1842 | }, | ||
1843 | .probe = wm8753_spi_probe, | ||
1844 | .remove = __devexit_p(wm8753_spi_remove), | ||
1845 | }; | ||
1846 | #endif | ||
1857 | 1847 | ||
1858 | if (codec->control_data) | 1848 | static int __init wm8753_modinit(void) |
1859 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1849 | { |
1860 | run_delayed_work(&codec->delayed_work); | 1850 | int ret; |
1861 | snd_soc_free_pcms(socdev); | ||
1862 | snd_soc_dapm_free(socdev); | ||
1863 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1851 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1864 | i2c_unregister_device(codec->control_data); | 1852 | ret = i2c_add_driver(&wm8753_i2c_driver); |
1865 | i2c_del_driver(&wm8753_i2c_driver); | 1853 | if (ret != 0) |
1854 | pr_err("Failed to register WM8753 I2C driver: %d\n", ret); | ||
1866 | #endif | 1855 | #endif |
1867 | #if defined(CONFIG_SPI_MASTER) | 1856 | #if defined(CONFIG_SPI_MASTER) |
1868 | spi_unregister_driver(&wm8753_spi_driver); | 1857 | ret = spi_register_driver(&wm8753_spi_driver); |
1858 | if (ret != 0) | ||
1859 | pr_err("Failed to register WM8753 SPI driver: %d\n", ret); | ||
1869 | #endif | 1860 | #endif |
1870 | kfree(codec->private_data); | ||
1871 | kfree(codec); | ||
1872 | |||
1873 | return 0; | 1861 | return 0; |
1874 | } | 1862 | } |
1875 | |||
1876 | struct snd_soc_codec_device soc_codec_dev_wm8753 = { | ||
1877 | .probe = wm8753_probe, | ||
1878 | .remove = wm8753_remove, | ||
1879 | .suspend = wm8753_suspend, | ||
1880 | .resume = wm8753_resume, | ||
1881 | }; | ||
1882 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753); | ||
1883 | |||
1884 | static int __init wm8753_modinit(void) | ||
1885 | { | ||
1886 | return snd_soc_register_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); | ||
1887 | } | ||
1888 | module_init(wm8753_modinit); | 1863 | module_init(wm8753_modinit); |
1889 | 1864 | ||
1890 | static void __exit wm8753_exit(void) | 1865 | static void __exit wm8753_exit(void) |
1891 | { | 1866 | { |
1892 | snd_soc_unregister_dais(wm8753_dai, ARRAY_SIZE(wm8753_dai)); | 1867 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1868 | i2c_del_driver(&wm8753_i2c_driver); | ||
1869 | #endif | ||
1870 | #if defined(CONFIG_SPI_MASTER) | ||
1871 | spi_unregister_driver(&wm8753_spi_driver); | ||
1872 | #endif | ||
1893 | } | 1873 | } |
1894 | module_exit(wm8753_exit); | 1874 | module_exit(wm8753_exit); |
1895 | 1875 | ||