diff options
Diffstat (limited to 'sound/soc/codecs/tlv320aic23.c')
| -rw-r--r-- | sound/soc/codecs/tlv320aic23.c | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 31762ebdd774..5d430cc56f51 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
| 26 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
| 27 | #include <linux/regmap.h> | ||
| 27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
| 28 | #include <sound/core.h> | 29 | #include <sound/core.h> |
| 29 | #include <sound/pcm.h> | 30 | #include <sound/pcm.h> |
| @@ -37,11 +38,27 @@ | |||
| 37 | /* | 38 | /* |
| 38 | * AIC23 register cache | 39 | * AIC23 register cache |
| 39 | */ | 40 | */ |
| 40 | static const u16 tlv320aic23_reg[] = { | 41 | static const struct reg_default tlv320aic23_reg[] = { |
| 41 | 0x0097, 0x0097, 0x00F9, 0x00F9, /* 0 */ | 42 | { 0, 0x0097 }, |
| 42 | 0x001A, 0x0004, 0x0007, 0x0001, /* 4 */ | 43 | { 1, 0x0097 }, |
| 43 | 0x0020, 0x0000, 0x0000, 0x0000, /* 8 */ | 44 | { 2, 0x00F9 }, |
| 44 | 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */ | 45 | { 3, 0x00F9 }, |
| 46 | { 4, 0x001A }, | ||
| 47 | { 5, 0x0004 }, | ||
| 48 | { 6, 0x0007 }, | ||
| 49 | { 7, 0x0001 }, | ||
| 50 | { 8, 0x0020 }, | ||
| 51 | { 9, 0x0000 }, | ||
| 52 | }; | ||
| 53 | |||
| 54 | static const struct regmap_config tlv320aic23_regmap = { | ||
| 55 | .reg_bits = 7, | ||
| 56 | .val_bits = 9, | ||
| 57 | |||
| 58 | .max_register = TLV320AIC23_RESET, | ||
| 59 | .reg_defaults = tlv320aic23_reg, | ||
| 60 | .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg), | ||
| 61 | .cache_type = REGCACHE_RBTREE, | ||
| 45 | }; | 62 | }; |
| 46 | 63 | ||
| 47 | static const char *rec_src_text[] = { "Line", "Mic" }; | 64 | static const char *rec_src_text[] = { "Line", "Mic" }; |
| @@ -171,7 +188,7 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = { | |||
| 171 | 188 | ||
| 172 | /* AIC23 driver data */ | 189 | /* AIC23 driver data */ |
| 173 | struct aic23 { | 190 | struct aic23 { |
| 174 | enum snd_soc_control_type control_type; | 191 | struct regmap *regmap; |
| 175 | int mclk; | 192 | int mclk; |
| 176 | int requested_adc; | 193 | int requested_adc; |
| 177 | int requested_dac; | 194 | int requested_dac; |
| @@ -532,7 +549,9 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec) | |||
| 532 | 549 | ||
| 533 | static int tlv320aic23_resume(struct snd_soc_codec *codec) | 550 | static int tlv320aic23_resume(struct snd_soc_codec *codec) |
| 534 | { | 551 | { |
| 535 | snd_soc_cache_sync(codec); | 552 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
| 553 | regcache_mark_dirty(aic23->regmap); | ||
| 554 | regcache_sync(aic23->regmap); | ||
| 536 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 555 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 537 | 556 | ||
| 538 | return 0; | 557 | return 0; |
| @@ -540,10 +559,9 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec) | |||
| 540 | 559 | ||
| 541 | static int tlv320aic23_probe(struct snd_soc_codec *codec) | 560 | static int tlv320aic23_probe(struct snd_soc_codec *codec) |
| 542 | { | 561 | { |
| 543 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); | ||
| 544 | int ret; | 562 | int ret; |
| 545 | 563 | ||
| 546 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type); | 564 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_REGMAP); |
| 547 | if (ret < 0) { | 565 | if (ret < 0) { |
| 548 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 566 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 549 | return ret; | 567 | return ret; |
| @@ -552,16 +570,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec) | |||
| 552 | /* Reset codec */ | 570 | /* Reset codec */ |
| 553 | snd_soc_write(codec, TLV320AIC23_RESET, 0); | 571 | snd_soc_write(codec, TLV320AIC23_RESET, 0); |
| 554 | 572 | ||
| 555 | /* Write the register default value to cache for reserved registers, | ||
| 556 | * so the write to the these registers are suppressed by the cache | ||
| 557 | * restore code when it skips writes of default registers. | ||
| 558 | */ | ||
| 559 | snd_soc_cache_write(codec, 0x0A, 0); | ||
| 560 | snd_soc_cache_write(codec, 0x0B, 0); | ||
| 561 | snd_soc_cache_write(codec, 0x0C, 0); | ||
| 562 | snd_soc_cache_write(codec, 0x0D, 0); | ||
| 563 | snd_soc_cache_write(codec, 0x0E, 0); | ||
| 564 | |||
| 565 | /* power on device */ | 573 | /* power on device */ |
| 566 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 574 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 567 | 575 | ||
| @@ -586,9 +594,6 @@ static int tlv320aic23_probe(struct snd_soc_codec *codec) | |||
| 586 | 594 | ||
| 587 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1); | 595 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1); |
| 588 | 596 | ||
| 589 | snd_soc_add_codec_controls(codec, tlv320aic23_snd_controls, | ||
| 590 | ARRAY_SIZE(tlv320aic23_snd_controls)); | ||
| 591 | |||
| 592 | return 0; | 597 | return 0; |
| 593 | } | 598 | } |
| 594 | 599 | ||
| @@ -599,21 +604,19 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec) | |||
| 599 | } | 604 | } |
| 600 | 605 | ||
| 601 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | 606 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { |
| 602 | .reg_cache_size = ARRAY_SIZE(tlv320aic23_reg), | ||
| 603 | .reg_word_size = sizeof(u16), | ||
| 604 | .reg_cache_default = tlv320aic23_reg, | ||
| 605 | .probe = tlv320aic23_probe, | 607 | .probe = tlv320aic23_probe, |
| 606 | .remove = tlv320aic23_remove, | 608 | .remove = tlv320aic23_remove, |
| 607 | .suspend = tlv320aic23_suspend, | 609 | .suspend = tlv320aic23_suspend, |
| 608 | .resume = tlv320aic23_resume, | 610 | .resume = tlv320aic23_resume, |
| 609 | .set_bias_level = tlv320aic23_set_bias_level, | 611 | .set_bias_level = tlv320aic23_set_bias_level, |
| 612 | .controls = tlv320aic23_snd_controls, | ||
| 613 | .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), | ||
| 610 | .dapm_widgets = tlv320aic23_dapm_widgets, | 614 | .dapm_widgets = tlv320aic23_dapm_widgets, |
| 611 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), | 615 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), |
| 612 | .dapm_routes = tlv320aic23_intercon, | 616 | .dapm_routes = tlv320aic23_intercon, |
| 613 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), | 617 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), |
| 614 | }; | 618 | }; |
| 615 | 619 | ||
| 616 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 617 | /* | 620 | /* |
| 618 | * If the i2c layer weren't so broken, we could pass this kind of data | 621 | * If the i2c layer weren't so broken, we could pass this kind of data |
| 619 | * around | 622 | * around |
| @@ -631,8 +634,11 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c, | |||
| 631 | if (aic23 == NULL) | 634 | if (aic23 == NULL) |
| 632 | return -ENOMEM; | 635 | return -ENOMEM; |
| 633 | 636 | ||
| 637 | aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); | ||
| 638 | if (IS_ERR(aic23->regmap)) | ||
| 639 | return PTR_ERR(aic23->regmap); | ||
| 640 | |||
| 634 | i2c_set_clientdata(i2c, aic23); | 641 | i2c_set_clientdata(i2c, aic23); |
| 635 | aic23->control_type = SND_SOC_I2C; | ||
| 636 | 642 | ||
| 637 | ret = snd_soc_register_codec(&i2c->dev, | 643 | ret = snd_soc_register_codec(&i2c->dev, |
| 638 | &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); | 644 | &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); |
| @@ -660,29 +666,7 @@ static struct i2c_driver tlv320aic23_i2c_driver = { | |||
| 660 | .id_table = tlv320aic23_id, | 666 | .id_table = tlv320aic23_id, |
| 661 | }; | 667 | }; |
| 662 | 668 | ||
| 663 | #endif | 669 | module_i2c_driver(tlv320aic23_i2c_driver); |
| 664 | |||
| 665 | static int __init tlv320aic23_modinit(void) | ||
| 666 | { | ||
| 667 | int ret; | ||
| 668 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 669 | ret = i2c_add_driver(&tlv320aic23_i2c_driver); | ||
| 670 | if (ret != 0) { | ||
| 671 | printk(KERN_ERR "Failed to register TLV320AIC23 I2C driver: %d\n", | ||
| 672 | ret); | ||
| 673 | } | ||
| 674 | #endif | ||
| 675 | return ret; | ||
| 676 | } | ||
| 677 | module_init(tlv320aic23_modinit); | ||
| 678 | |||
| 679 | static void __exit tlv320aic23_exit(void) | ||
| 680 | { | ||
| 681 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
| 682 | i2c_del_driver(&tlv320aic23_i2c_driver); | ||
| 683 | #endif | ||
| 684 | } | ||
| 685 | module_exit(tlv320aic23_exit); | ||
| 686 | 670 | ||
| 687 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); | 671 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); |
| 688 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | 672 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); |
