diff options
| author | Mark Brown <broonie@linaro.org> | 2013-10-24 06:24:14 -0400 |
|---|---|---|
| committer | Mark Brown <broonie@linaro.org> | 2013-10-24 06:24:14 -0400 |
| commit | 7524be376db6f0ffa13447a35b095f8829b42303 (patch) | |
| tree | bb60307851132d5e5ebc490556628ea7a9bf76f7 | |
| parent | abdd182e935a18ed7e075e2d267c371b9878a453 (diff) | |
| parent | 285d00c11b0a8d0ef63c176f88caab5071c9e80d (diff) | |
Merge remote-tracking branch 'asoc/topic/tas5086' into asoc-next
| -rw-r--r-- | sound/soc/codecs/tas5086.c | 171 |
1 files changed, 109 insertions, 62 deletions
diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 6d31d88f7204..fe4d29d88564 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c | |||
| @@ -37,6 +37,7 @@ | |||
| 37 | #include <linux/i2c.h> | 37 | #include <linux/i2c.h> |
| 38 | #include <linux/regmap.h> | 38 | #include <linux/regmap.h> |
| 39 | #include <linux/spi/spi.h> | 39 | #include <linux/spi/spi.h> |
| 40 | #include <linux/of.h> | ||
| 40 | #include <linux/of_device.h> | 41 | #include <linux/of_device.h> |
| 41 | #include <linux/of_gpio.h> | 42 | #include <linux/of_gpio.h> |
| 42 | #include <sound/pcm.h> | 43 | #include <sound/pcm.h> |
| @@ -244,6 +245,8 @@ struct tas5086_private { | |||
| 244 | unsigned int mclk, sclk; | 245 | unsigned int mclk, sclk; |
| 245 | unsigned int format; | 246 | unsigned int format; |
| 246 | bool deemph; | 247 | bool deemph; |
| 248 | unsigned int charge_period; | ||
| 249 | unsigned int pwm_start_mid_z; | ||
| 247 | /* Current sample rate for de-emphasis control */ | 250 | /* Current sample rate for de-emphasis control */ |
| 248 | int rate; | 251 | int rate; |
| 249 | /* GPIO driving Reset pin, if any */ | 252 | /* GPIO driving Reset pin, if any */ |
| @@ -456,6 +459,75 @@ static int tas5086_mute_stream(struct snd_soc_dai *dai, int mute, int stream) | |||
| 456 | return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); | 459 | return regmap_write(priv->regmap, TAS5086_SOFT_MUTE, val); |
| 457 | } | 460 | } |
| 458 | 461 | ||
| 462 | static void tas5086_reset(struct tas5086_private *priv) | ||
| 463 | { | ||
| 464 | if (gpio_is_valid(priv->gpio_nreset)) { | ||
| 465 | /* Reset codec - minimum assertion time is 400ns */ | ||
| 466 | gpio_direction_output(priv->gpio_nreset, 0); | ||
| 467 | udelay(1); | ||
| 468 | gpio_set_value(priv->gpio_nreset, 1); | ||
| 469 | |||
| 470 | /* Codec needs ~15ms to wake up */ | ||
| 471 | msleep(15); | ||
| 472 | } | ||
| 473 | } | ||
| 474 | |||
| 475 | /* charge period values in microseconds */ | ||
| 476 | static const int tas5086_charge_period[] = { | ||
| 477 | 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, | ||
| 478 | 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, | ||
| 479 | 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, | ||
| 480 | }; | ||
| 481 | |||
| 482 | static int tas5086_init(struct device *dev, struct tas5086_private *priv) | ||
| 483 | { | ||
| 484 | int ret, i; | ||
| 485 | |||
| 486 | /* | ||
| 487 | * If any of the channels is configured to start in Mid-Z mode, | ||
| 488 | * configure 'part 1' of the PWM starts to use Mid-Z, and tell | ||
| 489 | * all configured mid-z channels to start start under 'part 1'. | ||
| 490 | */ | ||
| 491 | if (priv->pwm_start_mid_z) | ||
| 492 | regmap_write(priv->regmap, TAS5086_PWM_START, | ||
| 493 | TAS5086_PWM_START_MIDZ_FOR_START_1 | | ||
| 494 | priv->pwm_start_mid_z); | ||
| 495 | |||
| 496 | /* lookup and set split-capacitor charge period */ | ||
| 497 | if (priv->charge_period == 0) { | ||
| 498 | regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); | ||
| 499 | } else { | ||
| 500 | i = index_in_array(tas5086_charge_period, | ||
| 501 | ARRAY_SIZE(tas5086_charge_period), | ||
| 502 | priv->charge_period); | ||
| 503 | if (i >= 0) | ||
| 504 | regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, | ||
| 505 | i + 0x08); | ||
| 506 | else | ||
| 507 | dev_warn(dev, | ||
| 508 | "Invalid split-cap charge period of %d ns.\n", | ||
| 509 | priv->charge_period); | ||
| 510 | } | ||
| 511 | |||
| 512 | /* enable factory trim */ | ||
| 513 | ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); | ||
| 514 | if (ret < 0) | ||
| 515 | return ret; | ||
| 516 | |||
| 517 | /* start all channels */ | ||
| 518 | ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); | ||
| 519 | if (ret < 0) | ||
| 520 | return ret; | ||
| 521 | |||
| 522 | /* mute all channels for now */ | ||
| 523 | ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, | ||
| 524 | TAS5086_SOFT_MUTE_ALL); | ||
| 525 | if (ret < 0) | ||
| 526 | return ret; | ||
| 527 | |||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | |||
| 459 | /* TAS5086 controls */ | 531 | /* TAS5086 controls */ |
| 460 | static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); | 532 | static const DECLARE_TLV_DB_SCALE(tas5086_dac_tlv, -10350, 50, 1); |
| 461 | 533 | ||
| @@ -691,14 +763,39 @@ static struct snd_soc_dai_driver tas5086_dai = { | |||
| 691 | }; | 763 | }; |
| 692 | 764 | ||
| 693 | #ifdef CONFIG_PM | 765 | #ifdef CONFIG_PM |
| 766 | static int tas5086_soc_suspend(struct snd_soc_codec *codec) | ||
| 767 | { | ||
| 768 | struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); | ||
| 769 | int ret; | ||
| 770 | |||
| 771 | /* Shut down all channels */ | ||
| 772 | ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x60); | ||
| 773 | if (ret < 0) | ||
| 774 | return ret; | ||
| 775 | |||
| 776 | return 0; | ||
| 777 | } | ||
| 778 | |||
| 694 | static int tas5086_soc_resume(struct snd_soc_codec *codec) | 779 | static int tas5086_soc_resume(struct snd_soc_codec *codec) |
| 695 | { | 780 | { |
| 696 | struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); | 781 | struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); |
| 782 | int ret; | ||
| 783 | |||
| 784 | tas5086_reset(priv); | ||
| 785 | regcache_mark_dirty(priv->regmap); | ||
| 786 | |||
| 787 | ret = tas5086_init(codec->dev, priv); | ||
| 788 | if (ret < 0) | ||
| 789 | return ret; | ||
| 790 | |||
| 791 | ret = regcache_sync(priv->regmap); | ||
| 792 | if (ret < 0) | ||
| 793 | return ret; | ||
| 697 | 794 | ||
| 698 | /* Restore codec state */ | 795 | return 0; |
| 699 | return regcache_sync(priv->regmap); | ||
| 700 | } | 796 | } |
| 701 | #else | 797 | #else |
| 798 | #define tas5086_soc_suspend NULL | ||
| 702 | #define tas5086_soc_resume NULL | 799 | #define tas5086_soc_resume NULL |
| 703 | #endif /* CONFIG_PM */ | 800 | #endif /* CONFIG_PM */ |
| 704 | 801 | ||
| @@ -710,23 +807,19 @@ static const struct of_device_id tas5086_dt_ids[] = { | |||
| 710 | MODULE_DEVICE_TABLE(of, tas5086_dt_ids); | 807 | MODULE_DEVICE_TABLE(of, tas5086_dt_ids); |
| 711 | #endif | 808 | #endif |
| 712 | 809 | ||
| 713 | /* charge period values in microseconds */ | ||
| 714 | static const int tas5086_charge_period[] = { | ||
| 715 | 13000, 16900, 23400, 31200, 41600, 54600, 72800, 96200, | ||
| 716 | 130000, 156000, 234000, 312000, 416000, 546000, 728000, 962000, | ||
| 717 | 1300000, 169000, 2340000, 3120000, 4160000, 5460000, 7280000, 9620000, | ||
| 718 | }; | ||
| 719 | |||
| 720 | static int tas5086_probe(struct snd_soc_codec *codec) | 810 | static int tas5086_probe(struct snd_soc_codec *codec) |
| 721 | { | 811 | { |
| 722 | struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); | 812 | struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); |
| 723 | int charge_period = 1300000; /* hardware default is 1300 ms */ | ||
| 724 | u8 pwm_start_mid_z = 0; | ||
| 725 | int i, ret; | 813 | int i, ret; |
| 726 | 814 | ||
| 815 | priv->pwm_start_mid_z = 0; | ||
| 816 | priv->charge_period = 1300000; /* hardware default is 1300 ms */ | ||
| 817 | |||
| 727 | if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { | 818 | if (of_match_device(of_match_ptr(tas5086_dt_ids), codec->dev)) { |
| 728 | struct device_node *of_node = codec->dev->of_node; | 819 | struct device_node *of_node = codec->dev->of_node; |
| 729 | of_property_read_u32(of_node, "ti,charge-period", &charge_period); | 820 | |
| 821 | of_property_read_u32(of_node, "ti,charge-period", | ||
| 822 | &priv->charge_period); | ||
| 730 | 823 | ||
| 731 | for (i = 0; i < 6; i++) { | 824 | for (i = 0; i < 6; i++) { |
| 732 | char name[25]; | 825 | char name[25]; |
| @@ -735,43 +828,11 @@ static int tas5086_probe(struct snd_soc_codec *codec) | |||
| 735 | "ti,mid-z-channel-%d", i + 1); | 828 | "ti,mid-z-channel-%d", i + 1); |
| 736 | 829 | ||
| 737 | if (of_get_property(of_node, name, NULL) != NULL) | 830 | if (of_get_property(of_node, name, NULL) != NULL) |
| 738 | pwm_start_mid_z |= 1 << i; | 831 | priv->pwm_start_mid_z |= 1 << i; |
| 739 | } | 832 | } |
| 740 | } | 833 | } |
| 741 | 834 | ||
| 742 | /* | 835 | ret = tas5086_init(codec->dev, priv); |
| 743 | * If any of the channels is configured to start in Mid-Z mode, | ||
| 744 | * configure 'part 1' of the PWM starts to use Mid-Z, and tell | ||
| 745 | * all configured mid-z channels to start start under 'part 1'. | ||
| 746 | */ | ||
| 747 | if (pwm_start_mid_z) | ||
| 748 | regmap_write(priv->regmap, TAS5086_PWM_START, | ||
| 749 | TAS5086_PWM_START_MIDZ_FOR_START_1 | | ||
| 750 | pwm_start_mid_z); | ||
| 751 | |||
| 752 | /* lookup and set split-capacitor charge period */ | ||
| 753 | if (charge_period == 0) { | ||
| 754 | regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, 0); | ||
| 755 | } else { | ||
| 756 | i = index_in_array(tas5086_charge_period, | ||
| 757 | ARRAY_SIZE(tas5086_charge_period), | ||
| 758 | charge_period); | ||
| 759 | if (i >= 0) | ||
| 760 | regmap_write(priv->regmap, TAS5086_SPLIT_CAP_CHARGE, | ||
| 761 | i + 0x08); | ||
| 762 | else | ||
| 763 | dev_warn(codec->dev, | ||
| 764 | "Invalid split-cap charge period of %d ns.\n", | ||
| 765 | charge_period); | ||
| 766 | } | ||
| 767 | |||
| 768 | /* enable factory trim */ | ||
| 769 | ret = regmap_write(priv->regmap, TAS5086_OSC_TRIM, 0x00); | ||
| 770 | if (ret < 0) | ||
| 771 | return ret; | ||
| 772 | |||
| 773 | /* start all channels */ | ||
| 774 | ret = regmap_write(priv->regmap, TAS5086_SYS_CONTROL_2, 0x20); | ||
| 775 | if (ret < 0) | 836 | if (ret < 0) |
| 776 | return ret; | 837 | return ret; |
| 777 | 838 | ||
| @@ -780,12 +841,6 @@ static int tas5086_probe(struct snd_soc_codec *codec) | |||
| 780 | if (ret < 0) | 841 | if (ret < 0) |
| 781 | return ret; | 842 | return ret; |
| 782 | 843 | ||
| 783 | /* mute all channels for now */ | ||
| 784 | ret = regmap_write(priv->regmap, TAS5086_SOFT_MUTE, | ||
| 785 | TAS5086_SOFT_MUTE_ALL); | ||
| 786 | if (ret < 0) | ||
| 787 | return ret; | ||
| 788 | |||
| 789 | return 0; | 844 | return 0; |
| 790 | } | 845 | } |
| 791 | 846 | ||
| @@ -803,6 +858,7 @@ static int tas5086_remove(struct snd_soc_codec *codec) | |||
| 803 | static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { | 858 | static struct snd_soc_codec_driver soc_codec_dev_tas5086 = { |
| 804 | .probe = tas5086_probe, | 859 | .probe = tas5086_probe, |
| 805 | .remove = tas5086_remove, | 860 | .remove = tas5086_remove, |
| 861 | .suspend = tas5086_soc_suspend, | ||
| 806 | .resume = tas5086_soc_resume, | 862 | .resume = tas5086_soc_resume, |
| 807 | .controls = tas5086_controls, | 863 | .controls = tas5086_controls, |
| 808 | .num_controls = ARRAY_SIZE(tas5086_controls), | 864 | .num_controls = ARRAY_SIZE(tas5086_controls), |
| @@ -862,17 +918,8 @@ static int tas5086_i2c_probe(struct i2c_client *i2c, | |||
| 862 | if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) | 918 | if (devm_gpio_request(dev, gpio_nreset, "TAS5086 Reset")) |
| 863 | gpio_nreset = -EINVAL; | 919 | gpio_nreset = -EINVAL; |
| 864 | 920 | ||
| 865 | if (gpio_is_valid(gpio_nreset)) { | ||
| 866 | /* Reset codec - minimum assertion time is 400ns */ | ||
| 867 | gpio_direction_output(gpio_nreset, 0); | ||
| 868 | udelay(1); | ||
| 869 | gpio_set_value(gpio_nreset, 1); | ||
| 870 | |||
| 871 | /* Codec needs ~15ms to wake up */ | ||
| 872 | msleep(15); | ||
| 873 | } | ||
| 874 | |||
| 875 | priv->gpio_nreset = gpio_nreset; | 921 | priv->gpio_nreset = gpio_nreset; |
| 922 | tas5086_reset(priv); | ||
| 876 | 923 | ||
| 877 | /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ | 924 | /* The TAS5086 always returns 0x03 in its TAS5086_DEV_ID register */ |
| 878 | ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); | 925 | ret = regmap_read(priv->regmap, TAS5086_DEV_ID, &i); |
