diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-08 18:07:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-08 18:07:14 -0400 |
commit | f5a246eab9a268f51ba8189ea5b098a1bfff200e (patch) | |
tree | a6ff7169e0bcaca498d9aec8b0624de1b74eaecb /sound/soc/codecs/cs4270.c | |
parent | d5bbd43d5f450c3fca058f5b85f3dfb4e8cc88c9 (diff) | |
parent | 7ff34ad80b7080fafaac8efa9ef0061708eddd51 (diff) |
Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"This contains pretty many small commits covering fairly large range of
files in sound/ directory. Partly because of additional API support
and partly because of constantly developed ASoC and ARM stuff.
Some highlights:
- Introduced the helper function and documentation for exposing the
channel map via control API, as discussed in Plumbers; most of PCI
drivers are covered, will follow more drivers later
- Most of drivers have been replaced with the new PM callbacks (if
the bus is supported)
- HD-audio controller got the support of runtime PM and the support
of D3 clock-stop. Also changing the power_save option in sysfs
kicks off immediately to enable / disable the power-save mode.
- Another significant code change in HD-audio is the rewrite of
firmware loading code. Other than that, most of changes in
HD-audio are continued cleanups and standardization for the generic
auto parser and bug fixes (HBR, device-specific fixups), in
addition to the support of channel-map API.
- Addition of ASoC bindings for the compressed API, used by the
mid-x86 drivers.
- Lots of cleanups and API refreshes for ASoC codec drivers and
DaVinci.
- Conversion of OMAP to dmaengine.
- New machine driver for Wolfson Microelectronics Bells.
- New CODEC driver for Wolfson Microelectronics WM0010.
- Enhancements to the ux500 and wm2000 drivers
- A new driver for DA9055 and the support for regulator bypass mode."
Fix up various arm soc header file reorg conflicts.
* tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (339 commits)
ALSA: hda - Add new codec ALC283 ALC290 support
ALSA: hda - avoid unneccesary indices on "Headphone Jack" controls
ALSA: hda - fix indices on boost volume on Conexant
ALSA: aloop - add locking to timer access
ALSA: hda - Fix hang caused by race during suspend.
sound: Remove unnecessary semicolon
ALSA: hda/realtek - Fix detection of ALC271X codec
ALSA: hda - Add inverted internal mic quirk for Lenovo IdeaPad U310
ALSA: hda - make Realtek/Sigmatel/Conexant use the generic unsol event
ALSA: hda - make a generic unsol event handler
ASoC: codecs: Add DA9055 codec driver
ASoC: eukrea-tlv320: Convert it to platform driver
ALSA: ASoC: add DT bindings for CS4271
ASoC: wm_hubs: Ensure volume updates are handled during class W startup
ASoC: wm5110: Adding missing volume update bits
ASoC: wm5110: Add OUT3R support
ASoC: wm5110: Add AEC loopback support
ASoC: wm5110: Rename EPOUT to HPOUT3
ASoC: arizona: Add more clock rates
ASoC: arizona: Add more DSP options for mixer input muxes
...
Diffstat (limited to 'sound/soc/codecs/cs4270.c')
-rw-r--r-- | sound/soc/codecs/cs4270.c | 156 |
1 files changed, 86 insertions, 70 deletions
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 047917f0b8ae..8e4779812b96 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/delay.h> | 30 | #include <linux/delay.h> |
31 | #include <linux/regulator/consumer.h> | 31 | #include <linux/regulator/consumer.h> |
32 | #include <linux/of_device.h> | ||
33 | #include <linux/of_gpio.h> | ||
32 | 34 | ||
33 | /* | 35 | /* |
34 | * The codec isn't really big-endian or little-endian, since the I2S | 36 | * The codec isn't really big-endian or little-endian, since the I2S |
@@ -110,14 +112,15 @@ | |||
110 | * This array contains the power-on default values of the registers, with the | 112 | * This array contains the power-on default values of the registers, with the |
111 | * exception of the "CHIPID" register (01h). The lower four bits of that | 113 | * exception of the "CHIPID" register (01h). The lower four bits of that |
112 | * register contain the hardware revision, so it is treated as volatile. | 114 | * register contain the hardware revision, so it is treated as volatile. |
113 | * | ||
114 | * Also note that on the CS4270, the first readable register is 1, but ASoC | ||
115 | * assumes the first register is 0. Therfore, the array must have an entry for | ||
116 | * register 0, but we use cs4270_reg_is_readable() to tell ASoC that it can't | ||
117 | * be read. | ||
118 | */ | 115 | */ |
119 | static const u8 cs4270_default_reg_cache[CS4270_LASTREG + 1] = { | 116 | static const struct reg_default cs4270_reg_defaults[] = { |
120 | 0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x20, 0x00, 0x00 | 117 | { 2, 0x00 }, |
118 | { 3, 0x30 }, | ||
119 | { 4, 0x00 }, | ||
120 | { 5, 0x60 }, | ||
121 | { 6, 0x20 }, | ||
122 | { 7, 0x00 }, | ||
123 | { 8, 0x00 }, | ||
121 | }; | 124 | }; |
122 | 125 | ||
123 | static const char *supply_names[] = { | 126 | static const char *supply_names[] = { |
@@ -126,7 +129,7 @@ static const char *supply_names[] = { | |||
126 | 129 | ||
127 | /* Private data for the CS4270 */ | 130 | /* Private data for the CS4270 */ |
128 | struct cs4270_private { | 131 | struct cs4270_private { |
129 | enum snd_soc_control_type control_type; | 132 | struct regmap *regmap; |
130 | unsigned int mclk; /* Input frequency of the MCLK pin */ | 133 | unsigned int mclk; /* Input frequency of the MCLK pin */ |
131 | unsigned int mode; /* The mode (I2S or left-justified) */ | 134 | unsigned int mode; /* The mode (I2S or left-justified) */ |
132 | unsigned int slave_mode; | 135 | unsigned int slave_mode; |
@@ -191,12 +194,12 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { | |||
191 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ | 194 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ |
192 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) | 195 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) |
193 | 196 | ||
194 | static int cs4270_reg_is_readable(struct snd_soc_codec *codec, unsigned int reg) | 197 | static bool cs4270_reg_is_readable(struct device *dev, unsigned int reg) |
195 | { | 198 | { |
196 | return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG); | 199 | return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG); |
197 | } | 200 | } |
198 | 201 | ||
199 | static int cs4270_reg_is_volatile(struct snd_soc_codec *codec, unsigned int reg) | 202 | static bool cs4270_reg_is_volatile(struct device *dev, unsigned int reg) |
200 | { | 203 | { |
201 | /* Unreadable registers are considered volatile */ | 204 | /* Unreadable registers are considered volatile */ |
202 | if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) | 205 | if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) |
@@ -456,7 +459,7 @@ static struct snd_soc_dai_driver cs4270_dai = { | |||
456 | .name = "cs4270-hifi", | 459 | .name = "cs4270-hifi", |
457 | .playback = { | 460 | .playback = { |
458 | .stream_name = "Playback", | 461 | .stream_name = "Playback", |
459 | .channels_min = 1, | 462 | .channels_min = 2, |
460 | .channels_max = 2, | 463 | .channels_max = 2, |
461 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | 464 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
462 | .rate_min = 4000, | 465 | .rate_min = 4000, |
@@ -465,7 +468,7 @@ static struct snd_soc_dai_driver cs4270_dai = { | |||
465 | }, | 468 | }, |
466 | .capture = { | 469 | .capture = { |
467 | .stream_name = "Capture", | 470 | .stream_name = "Capture", |
468 | .channels_min = 1, | 471 | .channels_min = 2, |
469 | .channels_max = 2, | 472 | .channels_max = 2, |
470 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | 473 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
471 | .rate_min = 4000, | 474 | .rate_min = 4000, |
@@ -485,12 +488,12 @@ static struct snd_soc_dai_driver cs4270_dai = { | |||
485 | static int cs4270_probe(struct snd_soc_codec *codec) | 488 | static int cs4270_probe(struct snd_soc_codec *codec) |
486 | { | 489 | { |
487 | struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); | 490 | struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); |
488 | int i, ret; | 491 | int ret; |
489 | 492 | ||
490 | /* Tell ASoC what kind of I/O to use to read the registers. ASoC will | 493 | /* Tell ASoC what kind of I/O to use to read the registers. ASoC will |
491 | * then do the I2C transactions itself. | 494 | * then do the I2C transactions itself. |
492 | */ | 495 | */ |
493 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs4270->control_type); | 496 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
494 | if (ret < 0) { | 497 | if (ret < 0) { |
495 | dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); | 498 | dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret); |
496 | return ret; | 499 | return ret; |
@@ -519,33 +522,8 @@ static int cs4270_probe(struct snd_soc_codec *codec) | |||
519 | return ret; | 522 | return ret; |
520 | } | 523 | } |
521 | 524 | ||
522 | /* Add the non-DAPM controls */ | ||
523 | ret = snd_soc_add_codec_controls(codec, cs4270_snd_controls, | ||
524 | ARRAY_SIZE(cs4270_snd_controls)); | ||
525 | if (ret < 0) { | ||
526 | dev_err(codec->dev, "failed to add controls\n"); | ||
527 | return ret; | ||
528 | } | ||
529 | |||
530 | /* get the power supply regulators */ | ||
531 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) | ||
532 | cs4270->supplies[i].supply = supply_names[i]; | ||
533 | |||
534 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(cs4270->supplies), | ||
535 | cs4270->supplies); | ||
536 | if (ret < 0) | ||
537 | return ret; | ||
538 | |||
539 | ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), | 525 | ret = regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), |
540 | cs4270->supplies); | 526 | cs4270->supplies); |
541 | if (ret < 0) | ||
542 | goto error_free_regulators; | ||
543 | |||
544 | return 0; | ||
545 | |||
546 | error_free_regulators: | ||
547 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), | ||
548 | cs4270->supplies); | ||
549 | 527 | ||
550 | return ret; | 528 | return ret; |
551 | } | 529 | } |
@@ -561,7 +539,6 @@ static int cs4270_remove(struct snd_soc_codec *codec) | |||
561 | struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); | 539 | struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); |
562 | 540 | ||
563 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | 541 | regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); |
564 | regulator_bulk_free(ARRAY_SIZE(cs4270->supplies), cs4270->supplies); | ||
565 | 542 | ||
566 | return 0; | 543 | return 0; |
567 | }; | 544 | }; |
@@ -611,7 +588,7 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec) | |||
611 | ndelay(500); | 588 | ndelay(500); |
612 | 589 | ||
613 | /* first restore the entire register cache ... */ | 590 | /* first restore the entire register cache ... */ |
614 | snd_soc_cache_sync(codec); | 591 | regcache_sync(cs4270->regmap); |
615 | 592 | ||
616 | /* ... then disable the power-down bits */ | 593 | /* ... then disable the power-down bits */ |
617 | reg = snd_soc_read(codec, CS4270_PWRCTL); | 594 | reg = snd_soc_read(codec, CS4270_PWRCTL); |
@@ -632,11 +609,30 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { | |||
632 | .remove = cs4270_remove, | 609 | .remove = cs4270_remove, |
633 | .suspend = cs4270_soc_suspend, | 610 | .suspend = cs4270_soc_suspend, |
634 | .resume = cs4270_soc_resume, | 611 | .resume = cs4270_soc_resume, |
635 | .volatile_register = cs4270_reg_is_volatile, | 612 | |
636 | .readable_register = cs4270_reg_is_readable, | 613 | .controls = cs4270_snd_controls, |
637 | .reg_cache_size = CS4270_LASTREG + 1, | 614 | .num_controls = ARRAY_SIZE(cs4270_snd_controls), |
638 | .reg_word_size = sizeof(u8), | 615 | }; |
639 | .reg_cache_default = cs4270_default_reg_cache, | 616 | |
617 | /* | ||
618 | * cs4270_of_match - the device tree bindings | ||
619 | */ | ||
620 | static const struct of_device_id cs4270_of_match[] = { | ||
621 | { .compatible = "cirrus,cs4270", }, | ||
622 | { } | ||
623 | }; | ||
624 | MODULE_DEVICE_TABLE(of, cs4270_of_match); | ||
625 | |||
626 | static const struct regmap_config cs4270_regmap = { | ||
627 | .reg_bits = 8, | ||
628 | .val_bits = 8, | ||
629 | .max_register = CS4270_LASTREG, | ||
630 | .reg_defaults = cs4270_reg_defaults, | ||
631 | .num_reg_defaults = ARRAY_SIZE(cs4270_reg_defaults), | ||
632 | .cache_type = REGCACHE_RBTREE, | ||
633 | |||
634 | .readable_reg = cs4270_reg_is_readable, | ||
635 | .volatile_reg = cs4270_reg_is_volatile, | ||
640 | }; | 636 | }; |
641 | 637 | ||
642 | /** | 638 | /** |
@@ -650,19 +646,56 @@ static const struct snd_soc_codec_driver soc_codec_device_cs4270 = { | |||
650 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, | 646 | static int cs4270_i2c_probe(struct i2c_client *i2c_client, |
651 | const struct i2c_device_id *id) | 647 | const struct i2c_device_id *id) |
652 | { | 648 | { |
649 | struct device_node *np = i2c_client->dev.of_node; | ||
653 | struct cs4270_private *cs4270; | 650 | struct cs4270_private *cs4270; |
654 | int ret; | 651 | unsigned int val; |
652 | int ret, i; | ||
655 | 653 | ||
656 | /* Verify that we have a CS4270 */ | 654 | cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private), |
655 | GFP_KERNEL); | ||
656 | if (!cs4270) { | ||
657 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
658 | return -ENOMEM; | ||
659 | } | ||
660 | |||
661 | /* get the power supply regulators */ | ||
662 | for (i = 0; i < ARRAY_SIZE(supply_names); i++) | ||
663 | cs4270->supplies[i].supply = supply_names[i]; | ||
664 | |||
665 | ret = devm_regulator_bulk_get(&i2c_client->dev, | ||
666 | ARRAY_SIZE(cs4270->supplies), | ||
667 | cs4270->supplies); | ||
668 | if (ret < 0) | ||
669 | return ret; | ||
670 | |||
671 | /* See if we have a way to bring the codec out of reset */ | ||
672 | if (np) { | ||
673 | enum of_gpio_flags flags; | ||
674 | int gpio = of_get_named_gpio_flags(np, "reset-gpio", 0, &flags); | ||
675 | |||
676 | if (gpio_is_valid(gpio)) { | ||
677 | ret = devm_gpio_request_one(&i2c_client->dev, gpio, | ||
678 | flags & OF_GPIO_ACTIVE_LOW ? | ||
679 | GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH, | ||
680 | "cs4270 reset"); | ||
681 | if (ret < 0) | ||
682 | return ret; | ||
683 | } | ||
684 | } | ||
685 | |||
686 | cs4270->regmap = devm_regmap_init_i2c(i2c_client, &cs4270_regmap); | ||
687 | if (IS_ERR(cs4270->regmap)) | ||
688 | return PTR_ERR(cs4270->regmap); | ||
657 | 689 | ||
658 | ret = i2c_smbus_read_byte_data(i2c_client, CS4270_CHIPID); | 690 | /* Verify that we have a CS4270 */ |
691 | ret = regmap_read(cs4270->regmap, CS4270_CHIPID, &val); | ||
659 | if (ret < 0) { | 692 | if (ret < 0) { |
660 | dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n", | 693 | dev_err(&i2c_client->dev, "failed to read i2c at addr %X\n", |
661 | i2c_client->addr); | 694 | i2c_client->addr); |
662 | return ret; | 695 | return ret; |
663 | } | 696 | } |
664 | /* The top four bits of the chip ID should be 1100. */ | 697 | /* The top four bits of the chip ID should be 1100. */ |
665 | if ((ret & 0xF0) != 0xC0) { | 698 | if ((val & 0xF0) != 0xC0) { |
666 | dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n", | 699 | dev_err(&i2c_client->dev, "device at addr %X is not a CS4270\n", |
667 | i2c_client->addr); | 700 | i2c_client->addr); |
668 | return -ENODEV; | 701 | return -ENODEV; |
@@ -670,17 +703,9 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client, | |||
670 | 703 | ||
671 | dev_info(&i2c_client->dev, "found device at i2c address %X\n", | 704 | dev_info(&i2c_client->dev, "found device at i2c address %X\n", |
672 | i2c_client->addr); | 705 | i2c_client->addr); |
673 | dev_info(&i2c_client->dev, "hardware revision %X\n", ret & 0xF); | 706 | dev_info(&i2c_client->dev, "hardware revision %X\n", val & 0xF); |
674 | |||
675 | cs4270 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs4270_private), | ||
676 | GFP_KERNEL); | ||
677 | if (!cs4270) { | ||
678 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
679 | return -ENOMEM; | ||
680 | } | ||
681 | 707 | ||
682 | i2c_set_clientdata(i2c_client, cs4270); | 708 | i2c_set_clientdata(i2c_client, cs4270); |
683 | cs4270->control_type = SND_SOC_I2C; | ||
684 | 709 | ||
685 | ret = snd_soc_register_codec(&i2c_client->dev, | 710 | ret = snd_soc_register_codec(&i2c_client->dev, |
686 | &soc_codec_device_cs4270, &cs4270_dai, 1); | 711 | &soc_codec_device_cs4270, &cs4270_dai, 1); |
@@ -718,23 +743,14 @@ static struct i2c_driver cs4270_i2c_driver = { | |||
718 | .driver = { | 743 | .driver = { |
719 | .name = "cs4270", | 744 | .name = "cs4270", |
720 | .owner = THIS_MODULE, | 745 | .owner = THIS_MODULE, |
746 | .of_match_table = cs4270_of_match, | ||
721 | }, | 747 | }, |
722 | .id_table = cs4270_id, | 748 | .id_table = cs4270_id, |
723 | .probe = cs4270_i2c_probe, | 749 | .probe = cs4270_i2c_probe, |
724 | .remove = cs4270_i2c_remove, | 750 | .remove = cs4270_i2c_remove, |
725 | }; | 751 | }; |
726 | 752 | ||
727 | static int __init cs4270_init(void) | 753 | module_i2c_driver(cs4270_i2c_driver); |
728 | { | ||
729 | return i2c_add_driver(&cs4270_i2c_driver); | ||
730 | } | ||
731 | module_init(cs4270_init); | ||
732 | |||
733 | static void __exit cs4270_exit(void) | ||
734 | { | ||
735 | i2c_del_driver(&cs4270_i2c_driver); | ||
736 | } | ||
737 | module_exit(cs4270_exit); | ||
738 | 754 | ||
739 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); | 755 | MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); |
740 | MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); | 756 | MODULE_DESCRIPTION("Cirrus Logic CS4270 ALSA SoC Codec Driver"); |