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