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, |
