diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 148 |
1 files changed, 123 insertions, 25 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1d70829464ef..7ff04ad2a97e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/bitops.h> | 28 | #include <linux/bitops.h> |
29 | #include <linux/debugfs.h> | 29 | #include <linux/debugfs.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <sound/ac97_codec.h> | ||
31 | #include <sound/core.h> | 32 | #include <sound/core.h> |
32 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
33 | #include <sound/pcm_params.h> | 34 | #include <sound/pcm_params.h> |
@@ -619,8 +620,9 @@ static struct snd_pcm_ops soc_pcm_ops = { | |||
619 | 620 | ||
620 | #ifdef CONFIG_PM | 621 | #ifdef CONFIG_PM |
621 | /* powers down audio subsystem for suspend */ | 622 | /* powers down audio subsystem for suspend */ |
622 | static int soc_suspend(struct platform_device *pdev, pm_message_t state) | 623 | static int soc_suspend(struct device *dev) |
623 | { | 624 | { |
625 | struct platform_device *pdev = to_platform_device(dev); | ||
624 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 626 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
625 | struct snd_soc_card *card = socdev->card; | 627 | struct snd_soc_card *card = socdev->card; |
626 | struct snd_soc_platform *platform = card->platform; | 628 | struct snd_soc_platform *platform = card->platform; |
@@ -656,7 +658,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
656 | snd_pcm_suspend_all(card->dai_link[i].pcm); | 658 | snd_pcm_suspend_all(card->dai_link[i].pcm); |
657 | 659 | ||
658 | if (card->suspend_pre) | 660 | if (card->suspend_pre) |
659 | card->suspend_pre(pdev, state); | 661 | card->suspend_pre(pdev, PMSG_SUSPEND); |
660 | 662 | ||
661 | for (i = 0; i < card->num_links; i++) { | 663 | for (i = 0; i < card->num_links; i++) { |
662 | struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; | 664 | struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; |
@@ -682,7 +684,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
682 | } | 684 | } |
683 | 685 | ||
684 | if (codec_dev->suspend) | 686 | if (codec_dev->suspend) |
685 | codec_dev->suspend(pdev, state); | 687 | codec_dev->suspend(pdev, PMSG_SUSPEND); |
686 | 688 | ||
687 | for (i = 0; i < card->num_links; i++) { | 689 | for (i = 0; i < card->num_links; i++) { |
688 | struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; | 690 | struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai; |
@@ -691,7 +693,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) | |||
691 | } | 693 | } |
692 | 694 | ||
693 | if (card->suspend_post) | 695 | if (card->suspend_post) |
694 | card->suspend_post(pdev, state); | 696 | card->suspend_post(pdev, PMSG_SUSPEND); |
695 | 697 | ||
696 | return 0; | 698 | return 0; |
697 | } | 699 | } |
@@ -765,8 +767,9 @@ static void soc_resume_deferred(struct work_struct *work) | |||
765 | } | 767 | } |
766 | 768 | ||
767 | /* powers up audio subsystem after a suspend */ | 769 | /* powers up audio subsystem after a suspend */ |
768 | static int soc_resume(struct platform_device *pdev) | 770 | static int soc_resume(struct device *dev) |
769 | { | 771 | { |
772 | struct platform_device *pdev = to_platform_device(dev); | ||
770 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 773 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
771 | struct snd_soc_card *card = socdev->card; | 774 | struct snd_soc_card *card = socdev->card; |
772 | struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai; | 775 | struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai; |
@@ -788,6 +791,44 @@ static int soc_resume(struct platform_device *pdev) | |||
788 | return 0; | 791 | return 0; |
789 | } | 792 | } |
790 | 793 | ||
794 | /** | ||
795 | * snd_soc_suspend_device: Notify core of device suspend | ||
796 | * | ||
797 | * @dev: Device being suspended. | ||
798 | * | ||
799 | * In order to ensure that the entire audio subsystem is suspended in a | ||
800 | * coordinated fashion ASoC devices should suspend themselves when | ||
801 | * called by ASoC. When the standard kernel suspend process asks the | ||
802 | * device to suspend it should call this function to initiate a suspend | ||
803 | * of the entire ASoC card. | ||
804 | * | ||
805 | * \note Currently this function is stubbed out. | ||
806 | */ | ||
807 | int snd_soc_suspend_device(struct device *dev) | ||
808 | { | ||
809 | return 0; | ||
810 | } | ||
811 | EXPORT_SYMBOL_GPL(snd_soc_suspend_device); | ||
812 | |||
813 | /** | ||
814 | * snd_soc_resume_device: Notify core of device resume | ||
815 | * | ||
816 | * @dev: Device being resumed. | ||
817 | * | ||
818 | * In order to ensure that the entire audio subsystem is resumed in a | ||
819 | * coordinated fashion ASoC devices should resume themselves when called | ||
820 | * by ASoC. When the standard kernel resume process asks the device | ||
821 | * to resume it should call this function. Once all the components of | ||
822 | * the card have notified that they are ready to be resumed the card | ||
823 | * will be resumed. | ||
824 | * | ||
825 | * \note Currently this function is stubbed out. | ||
826 | */ | ||
827 | int snd_soc_resume_device(struct device *dev) | ||
828 | { | ||
829 | return 0; | ||
830 | } | ||
831 | EXPORT_SYMBOL_GPL(snd_soc_resume_device); | ||
791 | #else | 832 | #else |
792 | #define soc_suspend NULL | 833 | #define soc_suspend NULL |
793 | #define soc_resume NULL | 834 | #define soc_resume NULL |
@@ -981,16 +1022,39 @@ static int soc_remove(struct platform_device *pdev) | |||
981 | return 0; | 1022 | return 0; |
982 | } | 1023 | } |
983 | 1024 | ||
1025 | static int soc_poweroff(struct device *dev) | ||
1026 | { | ||
1027 | struct platform_device *pdev = to_platform_device(dev); | ||
1028 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
1029 | struct snd_soc_card *card = socdev->card; | ||
1030 | |||
1031 | if (!card->instantiated) | ||
1032 | return 0; | ||
1033 | |||
1034 | /* Flush out pmdown_time work - we actually do want to run it | ||
1035 | * now, we're shutting down so no imminent restart. */ | ||
1036 | run_delayed_work(&card->delayed_work); | ||
1037 | |||
1038 | snd_soc_dapm_shutdown(socdev); | ||
1039 | |||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static struct dev_pm_ops soc_pm_ops = { | ||
1044 | .suspend = soc_suspend, | ||
1045 | .resume = soc_resume, | ||
1046 | .poweroff = soc_poweroff, | ||
1047 | }; | ||
1048 | |||
984 | /* ASoC platform driver */ | 1049 | /* ASoC platform driver */ |
985 | static struct platform_driver soc_driver = { | 1050 | static struct platform_driver soc_driver = { |
986 | .driver = { | 1051 | .driver = { |
987 | .name = "soc-audio", | 1052 | .name = "soc-audio", |
988 | .owner = THIS_MODULE, | 1053 | .owner = THIS_MODULE, |
1054 | .pm = &soc_pm_ops, | ||
989 | }, | 1055 | }, |
990 | .probe = soc_probe, | 1056 | .probe = soc_probe, |
991 | .remove = soc_remove, | 1057 | .remove = soc_remove, |
992 | .suspend = soc_suspend, | ||
993 | .resume = soc_resume, | ||
994 | }; | 1058 | }; |
995 | 1059 | ||
996 | /* create a new pcm */ | 1060 | /* create a new pcm */ |
@@ -1062,6 +1126,23 @@ static int soc_new_pcm(struct snd_soc_device *socdev, | |||
1062 | return ret; | 1126 | return ret; |
1063 | } | 1127 | } |
1064 | 1128 | ||
1129 | /** | ||
1130 | * snd_soc_codec_volatile_register: Report if a register is volatile. | ||
1131 | * | ||
1132 | * @codec: CODEC to query. | ||
1133 | * @reg: Register to query. | ||
1134 | * | ||
1135 | * Boolean function indiciating if a CODEC register is volatile. | ||
1136 | */ | ||
1137 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg) | ||
1138 | { | ||
1139 | if (codec->volatile_register) | ||
1140 | return codec->volatile_register(reg); | ||
1141 | else | ||
1142 | return 0; | ||
1143 | } | ||
1144 | EXPORT_SYMBOL_GPL(snd_soc_codec_volatile_register); | ||
1145 | |||
1065 | /* codec register dump */ | 1146 | /* codec register dump */ |
1066 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | 1147 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) |
1067 | { | 1148 | { |
@@ -1075,6 +1156,9 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | |||
1075 | 1156 | ||
1076 | count += sprintf(buf, "%s registers\n", codec->name); | 1157 | count += sprintf(buf, "%s registers\n", codec->name); |
1077 | for (i = 0; i < codec->reg_cache_size; i += step) { | 1158 | for (i = 0; i < codec->reg_cache_size; i += step) { |
1159 | if (codec->readable_register && !codec->readable_register(i)) | ||
1160 | continue; | ||
1161 | |||
1078 | count += sprintf(buf + count, "%2x: ", i); | 1162 | count += sprintf(buf + count, "%2x: ", i); |
1079 | if (count >= PAGE_SIZE - 1) | 1163 | if (count >= PAGE_SIZE - 1) |
1080 | break; | 1164 | break; |
@@ -1183,10 +1267,18 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | |||
1183 | if (!codec->debugfs_pop_time) | 1267 | if (!codec->debugfs_pop_time) |
1184 | printk(KERN_WARNING | 1268 | printk(KERN_WARNING |
1185 | "Failed to create pop time debugfs file\n"); | 1269 | "Failed to create pop time debugfs file\n"); |
1270 | |||
1271 | codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root); | ||
1272 | if (!codec->debugfs_dapm) | ||
1273 | printk(KERN_WARNING | ||
1274 | "Failed to create DAPM debugfs directory\n"); | ||
1275 | |||
1276 | snd_soc_dapm_debugfs_init(codec); | ||
1186 | } | 1277 | } |
1187 | 1278 | ||
1188 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | 1279 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) |
1189 | { | 1280 | { |
1281 | debugfs_remove_recursive(codec->debugfs_dapm); | ||
1190 | debugfs_remove(codec->debugfs_pop_time); | 1282 | debugfs_remove(codec->debugfs_pop_time); |
1191 | debugfs_remove(codec->debugfs_reg); | 1283 | debugfs_remove(codec->debugfs_reg); |
1192 | } | 1284 | } |
@@ -1264,10 +1356,10 @@ EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | |||
1264 | * Returns 1 for change else 0. | 1356 | * Returns 1 for change else 0. |
1265 | */ | 1357 | */ |
1266 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 1358 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
1267 | unsigned short mask, unsigned short value) | 1359 | unsigned int mask, unsigned int value) |
1268 | { | 1360 | { |
1269 | int change; | 1361 | int change; |
1270 | unsigned short old, new; | 1362 | unsigned int old, new; |
1271 | 1363 | ||
1272 | mutex_lock(&io_mutex); | 1364 | mutex_lock(&io_mutex); |
1273 | old = snd_soc_read(codec, reg); | 1365 | old = snd_soc_read(codec, reg); |
@@ -1294,10 +1386,10 @@ EXPORT_SYMBOL_GPL(snd_soc_update_bits); | |||
1294 | * Returns 1 for change else 0. | 1386 | * Returns 1 for change else 0. |
1295 | */ | 1387 | */ |
1296 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, | 1388 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned short reg, |
1297 | unsigned short mask, unsigned short value) | 1389 | unsigned int mask, unsigned int value) |
1298 | { | 1390 | { |
1299 | int change; | 1391 | int change; |
1300 | unsigned short old, new; | 1392 | unsigned int old, new; |
1301 | 1393 | ||
1302 | mutex_lock(&io_mutex); | 1394 | mutex_lock(&io_mutex); |
1303 | old = snd_soc_read(codec, reg); | 1395 | old = snd_soc_read(codec, reg); |
@@ -1381,8 +1473,11 @@ int snd_soc_init_card(struct snd_soc_device *socdev) | |||
1381 | continue; | 1473 | continue; |
1382 | } | 1474 | } |
1383 | } | 1475 | } |
1384 | if (card->dai_link[i].codec_dai->ac97_control) | 1476 | if (card->dai_link[i].codec_dai->ac97_control) { |
1385 | ac97 = 1; | 1477 | ac97 = 1; |
1478 | snd_ac97_dev_add_pdata(codec->ac97, | ||
1479 | card->dai_link[i].cpu_dai->ac97_pdata); | ||
1480 | } | ||
1386 | } | 1481 | } |
1387 | snprintf(codec->card->shortname, sizeof(codec->card->shortname), | 1482 | snprintf(codec->card->shortname, sizeof(codec->card->shortname), |
1388 | "%s", card->name); | 1483 | "%s", card->name); |
@@ -1586,7 +1681,7 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
1586 | { | 1681 | { |
1587 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1682 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1588 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1683 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1589 | unsigned short val, bitmask; | 1684 | unsigned int val, bitmask; |
1590 | 1685 | ||
1591 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 1686 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1592 | ; | 1687 | ; |
@@ -1615,8 +1710,8 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
1615 | { | 1710 | { |
1616 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1711 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1617 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1712 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1618 | unsigned short val; | 1713 | unsigned int val; |
1619 | unsigned short mask, bitmask; | 1714 | unsigned int mask, bitmask; |
1620 | 1715 | ||
1621 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) | 1716 | for (bitmask = 1; bitmask < e->max; bitmask <<= 1) |
1622 | ; | 1717 | ; |
@@ -1652,7 +1747,7 @@ int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1652 | { | 1747 | { |
1653 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1748 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1654 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1749 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1655 | unsigned short reg_val, val, mux; | 1750 | unsigned int reg_val, val, mux; |
1656 | 1751 | ||
1657 | reg_val = snd_soc_read(codec, e->reg); | 1752 | reg_val = snd_soc_read(codec, e->reg); |
1658 | val = (reg_val >> e->shift_l) & e->mask; | 1753 | val = (reg_val >> e->shift_l) & e->mask; |
@@ -1691,8 +1786,8 @@ int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
1691 | { | 1786 | { |
1692 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 1787 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
1693 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 1788 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
1694 | unsigned short val; | 1789 | unsigned int val; |
1695 | unsigned short mask; | 1790 | unsigned int mask; |
1696 | 1791 | ||
1697 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 1792 | if (ucontrol->value.enumerated.item[0] > e->max - 1) |
1698 | return -EINVAL; | 1793 | return -EINVAL; |
@@ -1852,7 +1947,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
1852 | int max = mc->max; | 1947 | int max = mc->max; |
1853 | unsigned int mask = (1 << fls(max)) - 1; | 1948 | unsigned int mask = (1 << fls(max)) - 1; |
1854 | unsigned int invert = mc->invert; | 1949 | unsigned int invert = mc->invert; |
1855 | unsigned short val, val2, val_mask; | 1950 | unsigned int val, val2, val_mask; |
1856 | 1951 | ||
1857 | val = (ucontrol->value.integer.value[0] & mask); | 1952 | val = (ucontrol->value.integer.value[0] & mask); |
1858 | if (invert) | 1953 | if (invert) |
@@ -1918,7 +2013,7 @@ int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1918 | unsigned int reg2 = mc->rreg; | 2013 | unsigned int reg2 = mc->rreg; |
1919 | unsigned int shift = mc->shift; | 2014 | unsigned int shift = mc->shift; |
1920 | int max = mc->max; | 2015 | int max = mc->max; |
1921 | unsigned int mask = (1<<fls(max))-1; | 2016 | unsigned int mask = (1 << fls(max)) - 1; |
1922 | unsigned int invert = mc->invert; | 2017 | unsigned int invert = mc->invert; |
1923 | 2018 | ||
1924 | ucontrol->value.integer.value[0] = | 2019 | ucontrol->value.integer.value[0] = |
@@ -1958,7 +2053,7 @@ int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol, | |||
1958 | unsigned int mask = (1 << fls(max)) - 1; | 2053 | unsigned int mask = (1 << fls(max)) - 1; |
1959 | unsigned int invert = mc->invert; | 2054 | unsigned int invert = mc->invert; |
1960 | int err; | 2055 | int err; |
1961 | unsigned short val, val2, val_mask; | 2056 | unsigned int val, val2, val_mask; |
1962 | 2057 | ||
1963 | val_mask = mask << shift; | 2058 | val_mask = mask << shift; |
1964 | val = (ucontrol->value.integer.value[0] & mask); | 2059 | val = (ucontrol->value.integer.value[0] & mask); |
@@ -2050,7 +2145,7 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | |||
2050 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2145 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2051 | unsigned int reg = mc->reg; | 2146 | unsigned int reg = mc->reg; |
2052 | int min = mc->min; | 2147 | int min = mc->min; |
2053 | unsigned short val; | 2148 | unsigned int val; |
2054 | 2149 | ||
2055 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | 2150 | val = (ucontrol->value.integer.value[0]+min) & 0xff; |
2056 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | 2151 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; |
@@ -2136,17 +2231,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | |||
2136 | /** | 2231 | /** |
2137 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. | 2232 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. |
2138 | * @dai: DAI | 2233 | * @dai: DAI |
2139 | * @mask: DAI specific mask representing used slots. | 2234 | * @tx_mask: bitmask representing active TX slots. |
2235 | * @rx_mask: bitmask representing active RX slots. | ||
2140 | * @slots: Number of slots in use. | 2236 | * @slots: Number of slots in use. |
2237 | * @slot_width: Width in bits for each slot. | ||
2141 | * | 2238 | * |
2142 | * Configures a DAI for TDM operation. Both mask and slots are codec and DAI | 2239 | * Configures a DAI for TDM operation. Both mask and slots are codec and DAI |
2143 | * specific. | 2240 | * specific. |
2144 | */ | 2241 | */ |
2145 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | 2242 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, |
2146 | unsigned int mask, int slots) | 2243 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) |
2147 | { | 2244 | { |
2148 | if (dai->ops && dai->ops->set_tdm_slot) | 2245 | if (dai->ops && dai->ops->set_tdm_slot) |
2149 | return dai->ops->set_tdm_slot(dai, mask, slots); | 2246 | return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
2247 | slots, slot_width); | ||
2150 | else | 2248 | else |
2151 | return -EINVAL; | 2249 | return -EINVAL; |
2152 | } | 2250 | } |