diff options
Diffstat (limited to 'sound/soc/codecs/wm8711.c')
-rw-r--r-- | sound/soc/codecs/wm8711.c | 206 |
1 files changed, 59 insertions, 147 deletions
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index e2dba07f0260..8d942b3b111f 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -31,11 +31,10 @@ | |||
31 | 31 | ||
32 | #include "wm8711.h" | 32 | #include "wm8711.h" |
33 | 33 | ||
34 | static struct snd_soc_codec *wm8711_codec; | ||
35 | |||
36 | /* codec private data */ | 34 | /* codec private data */ |
37 | struct wm8711_priv { | 35 | struct wm8711_priv { |
38 | struct snd_soc_codec codec; | 36 | enum snd_soc_control_type bus_type; |
37 | void *control_data; | ||
39 | u16 reg_cache[WM8711_CACHEREGNUM]; | 38 | u16 reg_cache[WM8711_CACHEREGNUM]; |
40 | unsigned int sysclk; | 39 | unsigned int sysclk; |
41 | }; | 40 | }; |
@@ -163,7 +162,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream, | |||
163 | struct snd_soc_dai *dai) | 162 | struct snd_soc_dai *dai) |
164 | { | 163 | { |
165 | struct snd_soc_codec *codec = dai->codec; | 164 | struct snd_soc_codec *codec = dai->codec; |
166 | struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); | 165 | struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); |
167 | u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; | 166 | u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc; |
168 | int i = get_coeff(wm8711->sysclk, params_rate(params)); | 167 | int i = get_coeff(wm8711->sysclk, params_rate(params)); |
169 | u16 srate = (coeff_div[i].sr << 2) | | 168 | u16 srate = (coeff_div[i].sr << 2) | |
@@ -227,7 +226,7 @@ static int wm8711_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
227 | int clk_id, unsigned int freq, int dir) | 226 | int clk_id, unsigned int freq, int dir) |
228 | { | 227 | { |
229 | struct snd_soc_codec *codec = codec_dai->codec; | 228 | struct snd_soc_codec *codec = codec_dai->codec; |
230 | struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); | 229 | struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); |
231 | 230 | ||
232 | switch (freq) { | 231 | switch (freq) { |
233 | case 11289600: | 232 | case 11289600: |
@@ -338,8 +337,8 @@ static struct snd_soc_dai_ops wm8711_ops = { | |||
338 | .set_fmt = wm8711_set_dai_fmt, | 337 | .set_fmt = wm8711_set_dai_fmt, |
339 | }; | 338 | }; |
340 | 339 | ||
341 | struct snd_soc_dai wm8711_dai = { | 340 | static struct snd_soc_dai_driver wm8711_dai = { |
342 | .name = "WM8711", | 341 | .name = "wm8711-hifi", |
343 | .playback = { | 342 | .playback = { |
344 | .stream_name = "Playback", | 343 | .stream_name = "Playback", |
345 | .channels_min = 1, | 344 | .channels_min = 1, |
@@ -349,22 +348,16 @@ struct snd_soc_dai wm8711_dai = { | |||
349 | }, | 348 | }, |
350 | .ops = &wm8711_ops, | 349 | .ops = &wm8711_ops, |
351 | }; | 350 | }; |
352 | EXPORT_SYMBOL_GPL(wm8711_dai); | ||
353 | 351 | ||
354 | static int wm8711_suspend(struct platform_device *pdev, pm_message_t state) | 352 | static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state) |
355 | { | 353 | { |
356 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
357 | struct snd_soc_codec *codec = socdev->card->codec; | ||
358 | |||
359 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | 354 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); |
360 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | 355 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); |
361 | return 0; | 356 | return 0; |
362 | } | 357 | } |
363 | 358 | ||
364 | static int wm8711_resume(struct platform_device *pdev) | 359 | static int wm8711_resume(struct snd_soc_codec *codec) |
365 | { | 360 | { |
366 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
367 | struct snd_soc_codec *codec = socdev->card->codec; | ||
368 | int i; | 361 | int i; |
369 | u8 data[2]; | 362 | u8 data[2]; |
370 | u16 *cache = codec->reg_cache; | 363 | u16 *cache = codec->reg_cache; |
@@ -380,99 +373,24 @@ static int wm8711_resume(struct platform_device *pdev) | |||
380 | return 0; | 373 | return 0; |
381 | } | 374 | } |
382 | 375 | ||
383 | static int wm8711_probe(struct platform_device *pdev) | 376 | static int wm8711_probe(struct snd_soc_codec *codec) |
384 | { | 377 | { |
385 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 378 | struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); |
386 | struct snd_soc_codec *codec; | 379 | int ret, reg; |
387 | int ret = 0; | ||
388 | |||
389 | if (wm8711_codec == NULL) { | ||
390 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
391 | return -ENODEV; | ||
392 | } | ||
393 | |||
394 | socdev->card->codec = wm8711_codec; | ||
395 | codec = wm8711_codec; | ||
396 | |||
397 | /* register pcms */ | ||
398 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
399 | if (ret < 0) { | ||
400 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
401 | goto pcm_err; | ||
402 | } | ||
403 | |||
404 | snd_soc_add_controls(codec, wm8711_snd_controls, | ||
405 | ARRAY_SIZE(wm8711_snd_controls)); | ||
406 | wm8711_add_widgets(codec); | ||
407 | |||
408 | return ret; | ||
409 | |||
410 | pcm_err: | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | /* power down chip */ | ||
415 | static int wm8711_remove(struct platform_device *pdev) | ||
416 | { | ||
417 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
418 | |||
419 | snd_soc_free_pcms(socdev); | ||
420 | snd_soc_dapm_free(socdev); | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | struct snd_soc_codec_device soc_codec_dev_wm8711 = { | ||
426 | .probe = wm8711_probe, | ||
427 | .remove = wm8711_remove, | ||
428 | .suspend = wm8711_suspend, | ||
429 | .resume = wm8711_resume, | ||
430 | }; | ||
431 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8711); | ||
432 | |||
433 | static int wm8711_register(struct wm8711_priv *wm8711, | ||
434 | enum snd_soc_control_type control) | ||
435 | { | ||
436 | int ret; | ||
437 | struct snd_soc_codec *codec = &wm8711->codec; | ||
438 | u16 reg; | ||
439 | |||
440 | if (wm8711_codec) { | ||
441 | dev_err(codec->dev, "Another WM8711 is registered\n"); | ||
442 | ret = -EINVAL; | ||
443 | goto err; | ||
444 | } | ||
445 | |||
446 | mutex_init(&codec->mutex); | ||
447 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
448 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
449 | |||
450 | snd_soc_codec_set_drvdata(codec, wm8711); | ||
451 | codec->name = "WM8711"; | ||
452 | codec->owner = THIS_MODULE; | ||
453 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
454 | codec->set_bias_level = wm8711_set_bias_level; | ||
455 | codec->dai = &wm8711_dai; | ||
456 | codec->num_dai = 1; | ||
457 | codec->reg_cache_size = WM8711_CACHEREGNUM; | ||
458 | codec->reg_cache = &wm8711->reg_cache; | ||
459 | |||
460 | memcpy(codec->reg_cache, wm8711_reg, sizeof(wm8711_reg)); | ||
461 | 380 | ||
462 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | 381 | codec->control_data = wm8711->control_data; |
382 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type); | ||
463 | if (ret < 0) { | 383 | if (ret < 0) { |
464 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 384 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
465 | goto err; | 385 | return ret; |
466 | } | 386 | } |
467 | 387 | ||
468 | ret = wm8711_reset(codec); | 388 | ret = wm8711_reset(codec); |
469 | if (ret < 0) { | 389 | if (ret < 0) { |
470 | dev_err(codec->dev, "Failed to issue reset\n"); | 390 | dev_err(codec->dev, "Failed to issue reset\n"); |
471 | goto err; | 391 | return ret; |
472 | } | 392 | } |
473 | 393 | ||
474 | wm8711_dai.dev = codec->dev; | ||
475 | |||
476 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 394 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
477 | 395 | ||
478 | /* Latch the update bits */ | 396 | /* Latch the update bits */ |
@@ -481,69 +399,63 @@ static int wm8711_register(struct wm8711_priv *wm8711, | |||
481 | reg = snd_soc_read(codec, WM8711_ROUT1V); | 399 | reg = snd_soc_read(codec, WM8711_ROUT1V); |
482 | snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100); | 400 | snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100); |
483 | 401 | ||
484 | wm8711_codec = codec; | 402 | snd_soc_add_controls(codec, wm8711_snd_controls, |
485 | 403 | ARRAY_SIZE(wm8711_snd_controls)); | |
486 | ret = snd_soc_register_codec(codec); | 404 | wm8711_add_widgets(codec); |
487 | if (ret != 0) { | ||
488 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
489 | goto err; | ||
490 | } | ||
491 | |||
492 | ret = snd_soc_register_dai(&wm8711_dai); | ||
493 | if (ret != 0) { | ||
494 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
495 | goto err_codec; | ||
496 | } | ||
497 | |||
498 | return 0; | ||
499 | 405 | ||
500 | err_codec: | ||
501 | snd_soc_unregister_codec(codec); | ||
502 | err: | ||
503 | kfree(wm8711); | ||
504 | return ret; | 406 | return ret; |
407 | |||
505 | } | 408 | } |
506 | 409 | ||
507 | static void wm8711_unregister(struct wm8711_priv *wm8711) | 410 | /* power down chip */ |
411 | static int wm8711_remove(struct snd_soc_codec *codec) | ||
508 | { | 412 | { |
509 | wm8711_set_bias_level(&wm8711->codec, SND_SOC_BIAS_OFF); | 413 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); |
510 | snd_soc_unregister_dai(&wm8711_dai); | 414 | return 0; |
511 | snd_soc_unregister_codec(&wm8711->codec); | ||
512 | kfree(wm8711); | ||
513 | wm8711_codec = NULL; | ||
514 | } | 415 | } |
515 | 416 | ||
417 | static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { | ||
418 | .probe = wm8711_probe, | ||
419 | .remove = wm8711_remove, | ||
420 | .suspend = wm8711_suspend, | ||
421 | .resume = wm8711_resume, | ||
422 | .set_bias_level = wm8711_set_bias_level, | ||
423 | .reg_cache_size = sizeof(wm8711_reg), | ||
424 | .reg_word_size = sizeof(u16), | ||
425 | .reg_cache_default = wm8711_reg, | ||
426 | }; | ||
427 | |||
516 | #if defined(CONFIG_SPI_MASTER) | 428 | #if defined(CONFIG_SPI_MASTER) |
517 | static int __devinit wm8711_spi_probe(struct spi_device *spi) | 429 | static int __devinit wm8711_spi_probe(struct spi_device *spi) |
518 | { | 430 | { |
519 | struct snd_soc_codec *codec; | ||
520 | struct wm8711_priv *wm8711; | 431 | struct wm8711_priv *wm8711; |
432 | int ret; | ||
521 | 433 | ||
522 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); | 434 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); |
523 | if (wm8711 == NULL) | 435 | if (wm8711 == NULL) |
524 | return -ENOMEM; | 436 | return -ENOMEM; |
525 | 437 | ||
526 | codec = &wm8711->codec; | 438 | spi_set_drvdata(spi, wm8711); |
527 | codec->control_data = spi; | 439 | wm8711->control_data = spi; |
528 | codec->dev = &spi->dev; | 440 | wm8711->bus_type = SND_SOC_SPI; |
529 | 441 | ||
530 | dev_set_drvdata(&spi->dev, wm8711); | 442 | ret = snd_soc_register_codec(&spi->dev, |
531 | 443 | &soc_codec_dev_wm8711, &wm8711_dai, 1); | |
532 | return wm8711_register(wm8711, SND_SOC_SPI); | 444 | if (ret < 0) |
445 | kfree(wm8711); | ||
446 | return ret; | ||
533 | } | 447 | } |
534 | 448 | ||
535 | static int __devexit wm8711_spi_remove(struct spi_device *spi) | 449 | static int __devexit wm8711_spi_remove(struct spi_device *spi) |
536 | { | 450 | { |
537 | struct wm8711_priv *wm8711 = dev_get_drvdata(&spi->dev); | 451 | snd_soc_unregister_codec(&spi->dev); |
538 | 452 | kfree(spi_get_drvdata(spi)); | |
539 | wm8711_unregister(wm8711); | ||
540 | |||
541 | return 0; | 453 | return 0; |
542 | } | 454 | } |
543 | 455 | ||
544 | static struct spi_driver wm8711_spi_driver = { | 456 | static struct spi_driver wm8711_spi_driver = { |
545 | .driver = { | 457 | .driver = { |
546 | .name = "wm8711", | 458 | .name = "wm8711-codec", |
547 | .bus = &spi_bus_type, | 459 | .bus = &spi_bus_type, |
548 | .owner = THIS_MODULE, | 460 | .owner = THIS_MODULE, |
549 | }, | 461 | }, |
@@ -553,31 +465,31 @@ static struct spi_driver wm8711_spi_driver = { | |||
553 | #endif /* CONFIG_SPI_MASTER */ | 465 | #endif /* CONFIG_SPI_MASTER */ |
554 | 466 | ||
555 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 467 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
556 | static __devinit int wm8711_i2c_probe(struct i2c_client *i2c, | 468 | static __devinit int wm8711_i2c_probe(struct i2c_client *client, |
557 | const struct i2c_device_id *id) | 469 | const struct i2c_device_id *id) |
558 | { | 470 | { |
559 | struct wm8711_priv *wm8711; | 471 | struct wm8711_priv *wm8711; |
560 | struct snd_soc_codec *codec; | 472 | int ret; |
561 | 473 | ||
562 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); | 474 | wm8711 = kzalloc(sizeof(struct wm8711_priv), GFP_KERNEL); |
563 | if (wm8711 == NULL) | 475 | if (wm8711 == NULL) |
564 | return -ENOMEM; | 476 | return -ENOMEM; |
565 | 477 | ||
566 | codec = &wm8711->codec; | 478 | i2c_set_clientdata(client, wm8711); |
567 | codec->hw_write = (hw_write_t)i2c_master_send; | 479 | wm8711->control_data = client; |
568 | 480 | wm8711->bus_type = SND_SOC_I2C; | |
569 | i2c_set_clientdata(i2c, wm8711); | ||
570 | codec->control_data = i2c; | ||
571 | 481 | ||
572 | codec->dev = &i2c->dev; | 482 | ret = snd_soc_register_codec(&client->dev, |
573 | 483 | &soc_codec_dev_wm8711, &wm8711_dai, 1); | |
574 | return wm8711_register(wm8711, SND_SOC_I2C); | 484 | if (ret < 0) |
485 | kfree(wm8711); | ||
486 | return ret; | ||
575 | } | 487 | } |
576 | 488 | ||
577 | static __devexit int wm8711_i2c_remove(struct i2c_client *client) | 489 | static __devexit int wm8711_i2c_remove(struct i2c_client *client) |
578 | { | 490 | { |
579 | struct wm8711_priv *wm8711 = i2c_get_clientdata(client); | 491 | snd_soc_unregister_codec(&client->dev); |
580 | wm8711_unregister(wm8711); | 492 | kfree(i2c_get_clientdata(client)); |
581 | return 0; | 493 | return 0; |
582 | } | 494 | } |
583 | 495 | ||
@@ -589,7 +501,7 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id); | |||
589 | 501 | ||
590 | static struct i2c_driver wm8711_i2c_driver = { | 502 | static struct i2c_driver wm8711_i2c_driver = { |
591 | .driver = { | 503 | .driver = { |
592 | .name = "WM8711 I2C Codec", | 504 | .name = "wm8711-codec", |
593 | .owner = THIS_MODULE, | 505 | .owner = THIS_MODULE, |
594 | }, | 506 | }, |
595 | .probe = wm8711_i2c_probe, | 507 | .probe = wm8711_i2c_probe, |