diff options
Diffstat (limited to 'sound/soc/codecs/wm8523.c')
-rw-r--r-- | sound/soc/codecs/wm8523.c | 177 |
1 files changed, 44 insertions, 133 deletions
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 0ad039b4adf5..712ef7c76f90 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -30,9 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8523.h" | 31 | #include "wm8523.h" |
32 | 32 | ||
33 | static struct snd_soc_codec *wm8523_codec; | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8523; | ||
35 | |||
36 | #define WM8523_NUM_SUPPLIES 2 | 33 | #define WM8523_NUM_SUPPLIES 2 |
37 | static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { | 34 | static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { |
38 | "AVDD", | 35 | "AVDD", |
@@ -43,7 +40,7 @@ static const char *wm8523_supply_names[WM8523_NUM_SUPPLIES] = { | |||
43 | 40 | ||
44 | /* codec private data */ | 41 | /* codec private data */ |
45 | struct wm8523_priv { | 42 | struct wm8523_priv { |
46 | struct snd_soc_codec codec; | 43 | enum snd_soc_control_type control_type; |
47 | u16 reg_cache[WM8523_REGISTER_COUNT]; | 44 | u16 reg_cache[WM8523_REGISTER_COUNT]; |
48 | struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES]; | 45 | struct regulator_bulk_data supplies[WM8523_NUM_SUPPLIES]; |
49 | unsigned int sysclk; | 46 | unsigned int sysclk; |
@@ -162,8 +159,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream, | |||
162 | struct snd_soc_dai *dai) | 159 | struct snd_soc_dai *dai) |
163 | { | 160 | { |
164 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 161 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
165 | struct snd_soc_device *socdev = rtd->socdev; | 162 | struct snd_soc_codec *codec = rtd->codec; |
166 | struct snd_soc_codec *codec = socdev->card->codec; | ||
167 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); | 163 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); |
168 | int i; | 164 | int i; |
169 | u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); | 165 | u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); |
@@ -387,8 +383,8 @@ static struct snd_soc_dai_ops wm8523_dai_ops = { | |||
387 | .set_fmt = wm8523_set_dai_fmt, | 383 | .set_fmt = wm8523_set_dai_fmt, |
388 | }; | 384 | }; |
389 | 385 | ||
390 | struct snd_soc_dai wm8523_dai = { | 386 | static struct snd_soc_dai_driver wm8523_dai = { |
391 | .name = "WM8523", | 387 | .name = "wm8523-hifi", |
392 | .playback = { | 388 | .playback = { |
393 | .stream_name = "Playback", | 389 | .stream_name = "Playback", |
394 | .channels_min = 2, /* Mono modes not yet supported */ | 390 | .channels_min = 2, /* Mono modes not yet supported */ |
@@ -398,25 +394,17 @@ struct snd_soc_dai wm8523_dai = { | |||
398 | }, | 394 | }, |
399 | .ops = &wm8523_dai_ops, | 395 | .ops = &wm8523_dai_ops, |
400 | }; | 396 | }; |
401 | EXPORT_SYMBOL_GPL(wm8523_dai); | ||
402 | 397 | ||
403 | #ifdef CONFIG_PM | 398 | #ifdef CONFIG_PM |
404 | static int wm8523_suspend(struct platform_device *pdev, pm_message_t state) | 399 | static int wm8523_suspend(struct snd_soc_codec *codec, pm_message_t state) |
405 | { | 400 | { |
406 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
407 | struct snd_soc_codec *codec = socdev->card->codec; | ||
408 | |||
409 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | 401 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); |
410 | return 0; | 402 | return 0; |
411 | } | 403 | } |
412 | 404 | ||
413 | static int wm8523_resume(struct platform_device *pdev) | 405 | static int wm8523_resume(struct snd_soc_codec *codec) |
414 | { | 406 | { |
415 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
416 | struct snd_soc_codec *codec = socdev->card->codec; | ||
417 | |||
418 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 407 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
419 | |||
420 | return 0; | 408 | return 0; |
421 | } | 409 | } |
422 | #else | 410 | #else |
@@ -424,93 +412,20 @@ static int wm8523_resume(struct platform_device *pdev) | |||
424 | #define wm8523_resume NULL | 412 | #define wm8523_resume NULL |
425 | #endif | 413 | #endif |
426 | 414 | ||
427 | static int wm8523_probe(struct platform_device *pdev) | 415 | static int wm8523_probe(struct snd_soc_codec *codec) |
428 | { | ||
429 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
430 | struct snd_soc_codec *codec; | ||
431 | int ret = 0; | ||
432 | |||
433 | if (wm8523_codec == NULL) { | ||
434 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
435 | return -ENODEV; | ||
436 | } | ||
437 | |||
438 | socdev->card->codec = wm8523_codec; | ||
439 | codec = wm8523_codec; | ||
440 | |||
441 | /* register pcms */ | ||
442 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
443 | if (ret < 0) { | ||
444 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
445 | goto pcm_err; | ||
446 | } | ||
447 | |||
448 | snd_soc_add_controls(codec, wm8523_snd_controls, | ||
449 | ARRAY_SIZE(wm8523_snd_controls)); | ||
450 | wm8523_add_widgets(codec); | ||
451 | |||
452 | return ret; | ||
453 | |||
454 | pcm_err: | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | static int wm8523_remove(struct platform_device *pdev) | ||
459 | { | ||
460 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
461 | |||
462 | snd_soc_free_pcms(socdev); | ||
463 | snd_soc_dapm_free(socdev); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | struct snd_soc_codec_device soc_codec_dev_wm8523 = { | ||
469 | .probe = wm8523_probe, | ||
470 | .remove = wm8523_remove, | ||
471 | .suspend = wm8523_suspend, | ||
472 | .resume = wm8523_resume, | ||
473 | }; | ||
474 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); | ||
475 | |||
476 | static int wm8523_register(struct wm8523_priv *wm8523, | ||
477 | enum snd_soc_control_type control) | ||
478 | { | 416 | { |
479 | int ret; | 417 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); |
480 | struct snd_soc_codec *codec = &wm8523->codec; | 418 | int ret, i; |
481 | int i; | ||
482 | |||
483 | if (wm8523_codec) { | ||
484 | dev_err(codec->dev, "Another WM8523 is registered\n"); | ||
485 | ret = -EINVAL; | ||
486 | goto err; | ||
487 | } | ||
488 | |||
489 | mutex_init(&codec->mutex); | ||
490 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
491 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
492 | |||
493 | snd_soc_codec_set_drvdata(codec, wm8523); | ||
494 | codec->name = "WM8523"; | ||
495 | codec->owner = THIS_MODULE; | ||
496 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
497 | codec->set_bias_level = wm8523_set_bias_level; | ||
498 | codec->dai = &wm8523_dai; | ||
499 | codec->num_dai = 1; | ||
500 | codec->reg_cache_size = WM8523_REGISTER_COUNT; | ||
501 | codec->reg_cache = &wm8523->reg_cache; | ||
502 | codec->volatile_register = wm8523_volatile_register; | ||
503 | 419 | ||
420 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
504 | wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; | 421 | wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; |
505 | wm8523->rate_constraint.count = | 422 | wm8523->rate_constraint.count = |
506 | ARRAY_SIZE(wm8523->rate_constraint_list); | 423 | ARRAY_SIZE(wm8523->rate_constraint_list); |
507 | 424 | ||
508 | memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); | 425 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8523->control_type); |
509 | |||
510 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); | ||
511 | if (ret != 0) { | 426 | if (ret != 0) { |
512 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 427 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
513 | goto err; | 428 | return ret; |
514 | } | 429 | } |
515 | 430 | ||
516 | for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) | 431 | for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) |
@@ -520,7 +435,7 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
520 | wm8523->supplies); | 435 | wm8523->supplies); |
521 | if (ret != 0) { | 436 | if (ret != 0) { |
522 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | 437 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); |
523 | goto err; | 438 | return ret; |
524 | } | 439 | } |
525 | 440 | ||
526 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), | 441 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies), |
@@ -555,8 +470,6 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
555 | goto err_enable; | 470 | goto err_enable; |
556 | } | 471 | } |
557 | 472 | ||
558 | wm8523_dai.dev = codec->dev; | ||
559 | |||
560 | /* Change some default settings - latch VU and enable ZC */ | 473 | /* Change some default settings - latch VU and enable ZC */ |
561 | wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; | 474 | wm8523->reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; |
562 | wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; | 475 | wm8523->reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; |
@@ -566,69 +479,67 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
566 | /* Bias level configuration will have done an extra enable */ | 479 | /* Bias level configuration will have done an extra enable */ |
567 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | 480 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); |
568 | 481 | ||
569 | wm8523_codec = codec; | 482 | snd_soc_add_controls(codec, wm8523_snd_controls, |
570 | 483 | ARRAY_SIZE(wm8523_snd_controls)); | |
571 | ret = snd_soc_register_codec(codec); | 484 | wm8523_add_widgets(codec); |
572 | if (ret != 0) { | ||
573 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
574 | goto err_enable; | ||
575 | } | ||
576 | |||
577 | ret = snd_soc_register_dai(&wm8523_dai); | ||
578 | if (ret != 0) { | ||
579 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
580 | goto err_codec; | ||
581 | } | ||
582 | 485 | ||
583 | return 0; | 486 | return 0; |
584 | 487 | ||
585 | err_codec: | ||
586 | snd_soc_unregister_codec(codec); | ||
587 | err_enable: | 488 | err_enable: |
588 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | 489 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); |
589 | err_get: | 490 | err_get: |
590 | regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | 491 | regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); |
591 | err: | 492 | |
592 | kfree(wm8523); | ||
593 | return ret; | 493 | return ret; |
594 | } | 494 | } |
595 | 495 | ||
596 | static void wm8523_unregister(struct wm8523_priv *wm8523) | 496 | static int wm8523_remove(struct snd_soc_codec *codec) |
597 | { | 497 | { |
598 | wm8523_set_bias_level(&wm8523->codec, SND_SOC_BIAS_OFF); | 498 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); |
499 | |||
500 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
599 | regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | 501 | regulator_bulk_free(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); |
600 | snd_soc_unregister_dai(&wm8523_dai); | 502 | return 0; |
601 | snd_soc_unregister_codec(&wm8523->codec); | ||
602 | kfree(wm8523); | ||
603 | wm8523_codec = NULL; | ||
604 | } | 503 | } |
605 | 504 | ||
505 | static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { | ||
506 | .probe = wm8523_probe, | ||
507 | .remove = wm8523_remove, | ||
508 | .suspend = wm8523_suspend, | ||
509 | .resume = wm8523_resume, | ||
510 | .set_bias_level = wm8523_set_bias_level, | ||
511 | .reg_cache_size = WM8523_REGISTER_COUNT, | ||
512 | .reg_word_size = sizeof(u16), | ||
513 | .reg_cache_default = wm8523_reg, | ||
514 | .volatile_register = wm8523_volatile_register, | ||
515 | }; | ||
516 | |||
606 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 517 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
607 | static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, | 518 | static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, |
608 | const struct i2c_device_id *id) | 519 | const struct i2c_device_id *id) |
609 | { | 520 | { |
610 | struct wm8523_priv *wm8523; | 521 | struct wm8523_priv *wm8523; |
611 | struct snd_soc_codec *codec; | 522 | int ret; |
612 | 523 | ||
613 | wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); | 524 | wm8523 = kzalloc(sizeof(struct wm8523_priv), GFP_KERNEL); |
614 | if (wm8523 == NULL) | 525 | if (wm8523 == NULL) |
615 | return -ENOMEM; | 526 | return -ENOMEM; |
616 | 527 | ||
617 | codec = &wm8523->codec; | ||
618 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
619 | |||
620 | i2c_set_clientdata(i2c, wm8523); | 528 | i2c_set_clientdata(i2c, wm8523); |
621 | codec->control_data = i2c; | 529 | wm8523->control_type = SND_SOC_I2C; |
622 | 530 | ||
623 | codec->dev = &i2c->dev; | 531 | ret = snd_soc_register_codec(&i2c->dev, |
532 | &soc_codec_dev_wm8523, &wm8523_dai, 1); | ||
533 | if (ret < 0) | ||
534 | kfree(wm8523); | ||
535 | return ret; | ||
624 | 536 | ||
625 | return wm8523_register(wm8523, SND_SOC_I2C); | ||
626 | } | 537 | } |
627 | 538 | ||
628 | static __devexit int wm8523_i2c_remove(struct i2c_client *client) | 539 | static __devexit int wm8523_i2c_remove(struct i2c_client *client) |
629 | { | 540 | { |
630 | struct wm8523_priv *wm8523 = i2c_get_clientdata(client); | 541 | snd_soc_unregister_codec(&client->dev); |
631 | wm8523_unregister(wm8523); | 542 | kfree(i2c_get_clientdata(client)); |
632 | return 0; | 543 | return 0; |
633 | } | 544 | } |
634 | 545 | ||
@@ -640,7 +551,7 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); | |||
640 | 551 | ||
641 | static struct i2c_driver wm8523_i2c_driver = { | 552 | static struct i2c_driver wm8523_i2c_driver = { |
642 | .driver = { | 553 | .driver = { |
643 | .name = "WM8523", | 554 | .name = "wm8523-codec", |
644 | .owner = THIS_MODULE, | 555 | .owner = THIS_MODULE, |
645 | }, | 556 | }, |
646 | .probe = wm8523_i2c_probe, | 557 | .probe = wm8523_i2c_probe, |