diff options
Diffstat (limited to 'sound/soc/codecs/wm8741.c')
-rw-r--r-- | sound/soc/codecs/wm8741.c | 204 |
1 files changed, 57 insertions, 147 deletions
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index b9ea8904ad4b..0c6d59e4d226 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c | |||
@@ -30,9 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8741.h" | 31 | #include "wm8741.h" |
32 | 32 | ||
33 | static struct snd_soc_codec *wm8741_codec; | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
35 | |||
36 | #define WM8741_NUM_SUPPLIES 2 | 33 | #define WM8741_NUM_SUPPLIES 2 |
37 | static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { | 34 | static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { |
38 | "AVDD", | 35 | "AVDD", |
@@ -43,7 +40,8 @@ static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { | |||
43 | 40 | ||
44 | /* codec private data */ | 41 | /* codec private data */ |
45 | struct wm8741_priv { | 42 | struct wm8741_priv { |
46 | struct snd_soc_codec codec; | 43 | enum snd_soc_control_type control_type; |
44 | void *control_data; | ||
47 | u16 reg_cache[WM8741_REGISTER_COUNT]; | 45 | u16 reg_cache[WM8741_REGISTER_COUNT]; |
48 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; | 46 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; |
49 | unsigned int sysclk; | 47 | unsigned int sysclk; |
@@ -145,8 +143,7 @@ static int wm8741_hw_params(struct snd_pcm_substream *substream, | |||
145 | struct snd_soc_dai *dai) | 143 | struct snd_soc_dai *dai) |
146 | { | 144 | { |
147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
148 | struct snd_soc_device *socdev = rtd->socdev; | 146 | struct snd_soc_codec *codec = rtd->codec; |
149 | struct snd_soc_codec *codec = socdev->card->codec; | ||
150 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | 147 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); |
151 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; | 148 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; |
152 | int i; | 149 | int i; |
@@ -314,7 +311,7 @@ static struct snd_soc_dai_ops wm8741_dai_ops = { | |||
314 | .set_fmt = wm8741_set_dai_fmt, | 311 | .set_fmt = wm8741_set_dai_fmt, |
315 | }; | 312 | }; |
316 | 313 | ||
317 | struct snd_soc_dai wm8741_dai = { | 314 | static struct snd_soc_dai_driver wm8741_dai = { |
318 | .name = "WM8741", | 315 | .name = "WM8741", |
319 | .playback = { | 316 | .playback = { |
320 | .stream_name = "Playback", | 317 | .stream_name = "Playback", |
@@ -325,13 +322,10 @@ struct snd_soc_dai wm8741_dai = { | |||
325 | }, | 322 | }, |
326 | .ops = &wm8741_dai_ops, | 323 | .ops = &wm8741_dai_ops, |
327 | }; | 324 | }; |
328 | EXPORT_SYMBOL_GPL(wm8741_dai); | ||
329 | 325 | ||
330 | #ifdef CONFIG_PM | 326 | #ifdef CONFIG_PM |
331 | static int wm8741_resume(struct platform_device *pdev) | 327 | static int wm8741_resume(struct snd_soc_codec *codec) |
332 | { | 328 | { |
333 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
334 | struct snd_soc_codec *codec = socdev->card->codec; | ||
335 | u16 *cache = codec->reg_cache; | 329 | u16 *cache = codec->reg_cache; |
336 | int i; | 330 | int i; |
337 | 331 | ||
@@ -348,189 +342,105 @@ static int wm8741_resume(struct platform_device *pdev) | |||
348 | #define wm8741_resume NULL | 342 | #define wm8741_resume NULL |
349 | #endif | 343 | #endif |
350 | 344 | ||
351 | static int wm8741_probe(struct platform_device *pdev) | 345 | static int wm8741_probe(struct snd_soc_codec *codec) |
352 | { | 346 | { |
353 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 347 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); |
354 | struct snd_soc_codec *codec; | ||
355 | int ret = 0; | 348 | int ret = 0; |
356 | 349 | ||
357 | if (wm8741_codec == NULL) { | 350 | codec->control_data = wm8741->control_data; |
358 | dev_err(&pdev->dev, "Codec device not registered\n"); | 351 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type); |
359 | return -ENODEV; | 352 | if (ret != 0) { |
353 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
354 | return ret; | ||
360 | } | 355 | } |
361 | 356 | ||
362 | socdev->card->codec = wm8741_codec; | 357 | ret = wm8741_reset(codec); |
363 | codec = wm8741_codec; | ||
364 | |||
365 | /* register pcms */ | ||
366 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
367 | if (ret < 0) { | 358 | if (ret < 0) { |
368 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | 359 | dev_err(codec->dev, "Failed to issue reset\n"); |
369 | goto pcm_err; | 360 | return ret; |
370 | } | 361 | } |
371 | 362 | ||
363 | /* Change some default settings - latch VU */ | ||
364 | wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; | ||
365 | wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; | ||
366 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; | ||
367 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; | ||
368 | |||
372 | snd_soc_add_controls(codec, wm8741_snd_controls, | 369 | snd_soc_add_controls(codec, wm8741_snd_controls, |
373 | ARRAY_SIZE(wm8741_snd_controls)); | 370 | ARRAY_SIZE(wm8741_snd_controls)); |
374 | wm8741_add_widgets(codec); | 371 | wm8741_add_widgets(codec); |
375 | 372 | ||
373 | dev_dbg(codec->dev, "Successful registration\n"); | ||
376 | return ret; | 374 | return ret; |
377 | |||
378 | pcm_err: | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int wm8741_remove(struct platform_device *pdev) | ||
383 | { | ||
384 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
385 | |||
386 | snd_soc_free_pcms(socdev); | ||
387 | snd_soc_dapm_free(socdev); | ||
388 | |||
389 | return 0; | ||
390 | } | 375 | } |
391 | 376 | ||
392 | struct snd_soc_codec_device soc_codec_dev_wm8741 = { | 377 | static struct snd_soc_codec_driver soc_codec_dev_wm8741 = { |
393 | .probe = wm8741_probe, | 378 | .probe = wm8741_probe, |
394 | .remove = wm8741_remove, | ||
395 | .resume = wm8741_resume, | 379 | .resume = wm8741_resume, |
380 | .reg_cache_size = sizeof(wm8741_reg_defaults), | ||
381 | .reg_word_size = sizeof(u16), | ||
382 | .reg_cache_default = &wm8741_reg_defaults, | ||
396 | }; | 383 | }; |
397 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741); | ||
398 | 384 | ||
399 | static int wm8741_register(struct wm8741_priv *wm8741, | 385 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
400 | enum snd_soc_control_type control) | 386 | static int wm8741_i2c_probe(struct i2c_client *i2c, |
387 | const struct i2c_device_id *id) | ||
401 | { | 388 | { |
402 | int ret; | 389 | struct wm8741_priv *wm8741; |
403 | struct snd_soc_codec *codec = &wm8741->codec; | 390 | int ret, i; |
404 | int i; | ||
405 | |||
406 | if (wm8741_codec) { | ||
407 | dev_err(codec->dev, "Another WM8741 is registered\n"); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | mutex_init(&codec->mutex); | ||
412 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
413 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
414 | 391 | ||
415 | snd_soc_codec_set_drvdata(codec, wm8741); | 392 | wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL); |
416 | codec->name = "WM8741"; | 393 | if (wm8741 == NULL) |
417 | codec->owner = THIS_MODULE; | 394 | return -ENOMEM; |
418 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
419 | codec->set_bias_level = NULL; | ||
420 | codec->dai = &wm8741_dai; | ||
421 | codec->num_dai = 1; | ||
422 | codec->reg_cache_size = WM8741_REGISTER_COUNT; | ||
423 | codec->reg_cache = &wm8741->reg_cache; | ||
424 | 395 | ||
425 | wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; | 396 | wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; |
426 | wm8741->rate_constraint.count = | 397 | wm8741->rate_constraint.count = |
427 | ARRAY_SIZE(wm8741->rate_constraint_list); | 398 | ARRAY_SIZE(wm8741->rate_constraint_list); |
428 | 399 | ||
429 | memcpy(codec->reg_cache, wm8741_reg_defaults, | ||
430 | sizeof(wm8741->reg_cache)); | ||
431 | |||
432 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
433 | if (ret != 0) { | ||
434 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
435 | goto err; | ||
436 | } | ||
437 | |||
438 | for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) | 400 | for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) |
439 | wm8741->supplies[i].supply = wm8741_supply_names[i]; | 401 | wm8741->supplies[i].supply = wm8741_supply_names[i]; |
440 | 402 | ||
441 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), | 403 | ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies), |
442 | wm8741->supplies); | 404 | wm8741->supplies); |
443 | if (ret != 0) { | 405 | if (ret != 0) { |
444 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | 406 | dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); |
445 | goto err; | 407 | goto err; |
446 | } | 408 | } |
447 | 409 | ||
448 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), | 410 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), |
449 | wm8741->supplies); | 411 | wm8741->supplies); |
450 | if (ret != 0) { | 412 | if (ret != 0) { |
451 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | 413 | dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); |
452 | goto err_get; | 414 | goto err_get; |
453 | } | 415 | } |
454 | 416 | ||
455 | ret = wm8741_reset(codec); | 417 | i2c_set_clientdata(i2c, wm8741); |
456 | if (ret < 0) { | 418 | wm8741->control_data = i2c; |
457 | dev_err(codec->dev, "Failed to issue reset\n"); | 419 | wm8741->control_type = SND_SOC_I2C; |
458 | goto err_enable; | ||
459 | } | ||
460 | |||
461 | wm8741_dai.dev = codec->dev; | ||
462 | |||
463 | /* Change some default settings - latch VU */ | ||
464 | wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; | ||
465 | wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; | ||
466 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; | ||
467 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; | ||
468 | |||
469 | wm8741_codec = codec; | ||
470 | |||
471 | ret = snd_soc_register_codec(codec); | ||
472 | if (ret != 0) { | ||
473 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | ret = snd_soc_register_dai(&wm8741_dai); | ||
478 | if (ret != 0) { | ||
479 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
480 | snd_soc_unregister_codec(codec); | ||
481 | return ret; | ||
482 | } | ||
483 | 420 | ||
484 | dev_dbg(codec->dev, "Successful registration\n"); | 421 | ret = snd_soc_register_codec(&i2c->dev, |
485 | return 0; | 422 | &soc_codec_dev_wm8741, &wm8741_dai, 1); |
423 | if (ret < 0) | ||
424 | goto err_enable; | ||
425 | return ret; | ||
486 | 426 | ||
487 | err_enable: | 427 | err_enable: |
488 | regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | 428 | regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); |
489 | 429 | ||
490 | err_get: | 430 | err_get: |
491 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | 431 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); |
492 | |||
493 | err: | 432 | err: |
494 | kfree(wm8741); | 433 | kfree(wm8741); |
495 | return ret; | 434 | return ret; |
496 | } | 435 | } |
497 | 436 | ||
498 | static void wm8741_unregister(struct wm8741_priv *wm8741) | 437 | static int wm8741_i2c_remove(struct i2c_client *client) |
499 | { | ||
500 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
501 | |||
502 | snd_soc_unregister_dai(&wm8741_dai); | ||
503 | snd_soc_unregister_codec(&wm8741->codec); | ||
504 | kfree(wm8741); | ||
505 | wm8741_codec = NULL; | ||
506 | } | ||
507 | |||
508 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
509 | static __devinit int wm8741_i2c_probe(struct i2c_client *i2c, | ||
510 | const struct i2c_device_id *id) | ||
511 | { | ||
512 | struct wm8741_priv *wm8741; | ||
513 | struct snd_soc_codec *codec; | ||
514 | |||
515 | wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL); | ||
516 | if (wm8741 == NULL) | ||
517 | return -ENOMEM; | ||
518 | |||
519 | codec = &wm8741->codec; | ||
520 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
521 | |||
522 | i2c_set_clientdata(i2c, wm8741); | ||
523 | codec->control_data = i2c; | ||
524 | |||
525 | codec->dev = &i2c->dev; | ||
526 | |||
527 | return wm8741_register(wm8741, SND_SOC_I2C); | ||
528 | } | ||
529 | |||
530 | static __devexit int wm8741_i2c_remove(struct i2c_client *client) | ||
531 | { | 438 | { |
532 | struct wm8741_priv *wm8741 = i2c_get_clientdata(client); | 439 | struct wm8741_priv *wm8741 = i2c_get_clientdata(client); |
533 | wm8741_unregister(wm8741); | 440 | |
441 | snd_soc_unregister_codec(&client->dev); | ||
442 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
443 | kfree(i2c_get_clientdata(client)); | ||
534 | return 0; | 444 | return 0; |
535 | } | 445 | } |
536 | 446 | ||
@@ -540,29 +450,29 @@ static const struct i2c_device_id wm8741_i2c_id[] = { | |||
540 | }; | 450 | }; |
541 | MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); | 451 | MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); |
542 | 452 | ||
543 | |||
544 | static struct i2c_driver wm8741_i2c_driver = { | 453 | static struct i2c_driver wm8741_i2c_driver = { |
545 | .driver = { | 454 | .driver = { |
546 | .name = "WM8741", | 455 | .name = "wm8741-codec", |
547 | .owner = THIS_MODULE, | 456 | .owner = THIS_MODULE, |
548 | }, | 457 | }, |
549 | .probe = wm8741_i2c_probe, | 458 | .probe = wm8741_i2c_probe, |
550 | .remove = __devexit_p(wm8741_i2c_remove), | 459 | .remove = wm8741_i2c_remove, |
551 | .id_table = wm8741_i2c_id, | 460 | .id_table = wm8741_i2c_id, |
552 | }; | 461 | }; |
553 | #endif | 462 | #endif |
554 | 463 | ||
555 | static int __init wm8741_modinit(void) | 464 | static int __init wm8741_modinit(void) |
556 | { | 465 | { |
557 | int ret; | 466 | int ret = 0; |
467 | |||
558 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 468 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
559 | ret = i2c_add_driver(&wm8741_i2c_driver); | 469 | ret = i2c_add_driver(&wm8741_i2c_driver); |
560 | if (ret != 0) { | 470 | if (ret != 0) { |
561 | printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n", | 471 | pr_err("Failed to register WM8741 I2C driver: %d\n", ret); |
562 | ret); | ||
563 | } | 472 | } |
564 | #endif | 473 | #endif |
565 | return 0; | 474 | |
475 | return ret; | ||
566 | } | 476 | } |
567 | module_init(wm8741_modinit); | 477 | module_init(wm8741_modinit); |
568 | 478 | ||