| OLD | NEW |
| 1 /* | 1 /* |
| 2 * wm8993.c -- WM8993 ALSA SoC audio driver | 2 * wm8993.c -- WM8993 ALSA SoC audio driver |
| 3 * | 3 * |
| 4 * Copyright 2009, 2010 Wolfson Microelectronics plc | 4 * Copyright 2009, 2010 Wolfson Microelectronics plc |
| 5 * | 5 * |
| 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
| 7 * | 7 * |
| 8 * This program is free software; you can redistribute it and/or modify | 8 * This program is free software; you can redistribute it and/or modify |
| 9 * it under the terms of the GNU General Public License version 2 as | 9 * it under the terms of the GNU General Public License version 2 as |
| 10 * published by the Free Software Foundation. | 10 * published by the Free Software Foundation. |
| 11 */ | 11 */ |
| 12 | 12 |
| 13 #include <linux/module.h> | 13 #include <linux/module.h> |
| 14 #include <linux/moduleparam.h> | 14 #include <linux/moduleparam.h> |
| 15 #include <linux/init.h> | 15 #include <linux/init.h> |
| 16 #include <linux/delay.h> | 16 #include <linux/delay.h> |
| 17 #include <linux/pm.h> | 17 #include <linux/pm.h> |
| 18 #include <linux/i2c.h> | 18 #include <linux/i2c.h> |
| 19 #include <linux/regulator/consumer.h> | 19 #include <linux/regulator/consumer.h> |
| 20 #include <linux/spi/spi.h> | 20 #include <linux/spi/spi.h> |
| 21 #include <linux/slab.h> | 21 #include <linux/slab.h> |
| 22 #include <sound/core.h> | 22 #include <sound/core.h> |
| 23 #include <sound/pcm.h> | 23 #include <sound/pcm.h> |
| 24 #include <sound/pcm_params.h> | 24 #include <sound/pcm_params.h> |
| 25 #include <sound/tlv.h> | 25 #include <sound/tlv.h> |
| 26 #include <sound/soc.h> | 26 #include <sound/soc.h> |
| 27 #include <sound/soc-dapm.h> | |
| 28 #include <sound/initval.h> | 27 #include <sound/initval.h> |
| 29 #include <sound/wm8993.h> | 28 #include <sound/wm8993.h> |
| 30 | 29 |
| 31 #include "wm8993.h" | 30 #include "wm8993.h" |
| 32 #include "wm_hubs.h" | 31 #include "wm_hubs.h" |
| 33 | 32 |
| 34 #define WM8993_NUM_SUPPLIES 6 | 33 #define WM8993_NUM_SUPPLIES 6 |
| 35 static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { | 34 static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { |
| 36 "DCVDD", | 35 "DCVDD", |
| 37 "DBVDD", | 36 "DBVDD", |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 { 160, 10 }, | 218 { 160, 10 }, |
| 220 { 220, 11 }, | 219 { 220, 11 }, |
| 221 { 240, 12 }, | 220 { 240, 12 }, |
| 222 { 320, 13 }, | 221 { 320, 13 }, |
| 223 { 440, 14 }, | 222 { 440, 14 }, |
| 224 { 480, 15 }, | 223 { 480, 15 }, |
| 225 }; | 224 }; |
| 226 | 225 |
| 227 struct wm8993_priv { | 226 struct wm8993_priv { |
| 228 struct wm_hubs_data hubs_data; | 227 struct wm_hubs_data hubs_data; |
| 229 u16 reg_cache[WM8993_REGISTER_COUNT]; | |
| 230 struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES]; | 228 struct regulator_bulk_data supplies[WM8993_NUM_SUPPLIES]; |
| 231 struct wm8993_platform_data pdata; | 229 struct wm8993_platform_data pdata; |
| 232 enum snd_soc_control_type control_type; | 230 enum snd_soc_control_type control_type; |
| 233 int master; | 231 int master; |
| 234 int sysclk_source; | 232 int sysclk_source; |
| 235 int tdm_slots; | 233 int tdm_slots; |
| 236 int tdm_width; | 234 int tdm_width; |
| 237 unsigned int mclk_rate; | 235 unsigned int mclk_rate; |
| 238 unsigned int sysclk_rate; | 236 unsigned int sysclk_rate; |
| 239 unsigned int fs; | 237 unsigned int fs; |
| 240 unsigned int bclk; | 238 unsigned int bclk; |
| 241 int class_w_users; | 239 int class_w_users; |
| 242 unsigned int fll_fref; | 240 unsigned int fll_fref; |
| 243 unsigned int fll_fout; | 241 unsigned int fll_fout; |
| 244 int fll_src; | 242 int fll_src; |
| 245 }; | 243 }; |
| 246 | 244 |
| 247 static int wm8993_volatile(unsigned int reg) | 245 static int wm8993_volatile(struct snd_soc_codec *codec, unsigned int reg) |
| 248 { | 246 { |
| 249 switch (reg) { | 247 switch (reg) { |
| 250 case WM8993_SOFTWARE_RESET: | 248 case WM8993_SOFTWARE_RESET: |
| 251 case WM8993_DC_SERVO_0: | 249 case WM8993_DC_SERVO_0: |
| 252 case WM8993_DC_SERVO_READBACK_0: | 250 case WM8993_DC_SERVO_READBACK_0: |
| 253 case WM8993_DC_SERVO_READBACK_1: | 251 case WM8993_DC_SERVO_READBACK_1: |
| 254 case WM8993_DC_SERVO_READBACK_2: | 252 case WM8993_DC_SERVO_READBACK_2: |
| 255 return 1; | 253 return 1; |
| 256 default: | 254 default: |
| 257 return 0; | 255 return 0; |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 /* Turn it off if we're using the main output mixer */ | 726 /* Turn it off if we're using the main output mixer */ |
| 729 if (ucontrol->value.integer.value[0] == 0) { | 727 if (ucontrol->value.integer.value[0] == 0) { |
| 730 if (wm8993->class_w_users == 0) { | 728 if (wm8993->class_w_users == 0) { |
| 731 dev_dbg(codec->dev, "Disabling Class W\n"); | 729 dev_dbg(codec->dev, "Disabling Class W\n"); |
| 732 snd_soc_update_bits(codec, WM8993_CLASS_W_0, | 730 snd_soc_update_bits(codec, WM8993_CLASS_W_0, |
| 733 WM8993_CP_DYN_FREQ | | 731 WM8993_CP_DYN_FREQ | |
| 734 WM8993_CP_DYN_V, | 732 WM8993_CP_DYN_V, |
| 735 0); | 733 0); |
| 736 } | 734 } |
| 737 wm8993->class_w_users++; | 735 wm8993->class_w_users++; |
| 736 wm8993->hubs_data.class_w = true; |
| 738 } | 737 } |
| 739 | 738 |
| 740 /* Implement the change */ | 739 /* Implement the change */ |
| 741 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); | 740 ret = snd_soc_dapm_put_enum_double(kcontrol, ucontrol); |
| 742 | 741 |
| 743 /* Enable it if we're using the direct DAC path */ | 742 /* Enable it if we're using the direct DAC path */ |
| 744 if (ucontrol->value.integer.value[0] == 1) { | 743 if (ucontrol->value.integer.value[0] == 1) { |
| 745 if (wm8993->class_w_users == 1) { | 744 if (wm8993->class_w_users == 1) { |
| 746 dev_dbg(codec->dev, "Enabling Class W\n"); | 745 dev_dbg(codec->dev, "Enabling Class W\n"); |
| 747 snd_soc_update_bits(codec, WM8993_CLASS_W_0, | 746 snd_soc_update_bits(codec, WM8993_CLASS_W_0, |
| 748 WM8993_CP_DYN_FREQ | | 747 WM8993_CP_DYN_FREQ | |
| 749 WM8993_CP_DYN_V, | 748 WM8993_CP_DYN_V, |
| 750 WM8993_CP_DYN_FREQ | | 749 WM8993_CP_DYN_FREQ | |
| 751 WM8993_CP_DYN_V); | 750 WM8993_CP_DYN_V); |
| 752 } | 751 } |
| 753 wm8993->class_w_users--; | 752 wm8993->class_w_users--; |
| 753 wm8993->hubs_data.class_w = false; |
| 754 } | 754 } |
| 755 | 755 |
| 756 dev_dbg(codec->dev, "Indirect DAC use count now %d\n", | 756 dev_dbg(codec->dev, "Indirect DAC use count now %d\n", |
| 757 wm8993->class_w_users); | 757 wm8993->class_w_users); |
| 758 | 758 |
| 759 return ret; | 759 return ret; |
| 760 } | 760 } |
| 761 | 761 |
| 762 #define SOC_DAPM_ENUM_W(xname, xenum) \ | 762 #define SOC_DAPM_ENUM_W(xname, xenum) \ |
| 763 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 763 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 961 case SND_SOC_BIAS_ON: | 961 case SND_SOC_BIAS_ON: |
| 962 case SND_SOC_BIAS_PREPARE: | 962 case SND_SOC_BIAS_PREPARE: |
| 963 /* VMID=2*40k */ | 963 /* VMID=2*40k */ |
| 964 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 964 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
| 965 WM8993_VMID_SEL_MASK, 0x2); | 965 WM8993_VMID_SEL_MASK, 0x2); |
| 966 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2, | 966 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_2, |
| 967 WM8993_TSHUT_ENA, WM8993_TSHUT_ENA); | 967 WM8993_TSHUT_ENA, WM8993_TSHUT_ENA); |
| 968 break; | 968 break; |
| 969 | 969 |
| 970 case SND_SOC_BIAS_STANDBY: | 970 case SND_SOC_BIAS_STANDBY: |
| 971 » » if (codec->bias_level == SND_SOC_BIAS_OFF) { | 971 » » if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
| 972 ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies)
, | 972 ret = regulator_bulk_enable(ARRAY_SIZE(wm8993->supplies)
, |
| 973 wm8993->supplies); | 973 wm8993->supplies); |
| 974 if (ret != 0) | 974 if (ret != 0) |
| 975 return ret; | 975 return ret; |
| 976 | 976 |
| 977 wm8993_cache_restore(codec); | 977 wm8993_cache_restore(codec); |
| 978 | 978 |
| 979 /* Tune DC servo configuration */ | 979 /* Tune DC servo configuration */ |
| 980 snd_soc_write(codec, 0x44, 3); | 980 snd_soc_write(codec, 0x44, 3); |
| 981 snd_soc_write(codec, 0x56, 3); | 981 snd_soc_write(codec, 0x56, 3); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 break; | 1022 break; |
| 1023 | 1023 |
| 1024 case SND_SOC_BIAS_OFF: | 1024 case SND_SOC_BIAS_OFF: |
| 1025 snd_soc_update_bits(codec, WM8993_ANTIPOP1, | 1025 snd_soc_update_bits(codec, WM8993_ANTIPOP1, |
| 1026 WM8993_LINEOUT_VMID_BUF_ENA, 0); | 1026 WM8993_LINEOUT_VMID_BUF_ENA, 0); |
| 1027 | 1027 |
| 1028 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 1028 snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
| 1029 WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, | 1029 WM8993_VMID_SEL_MASK | WM8993_BIAS_ENA, |
| 1030 0); | 1030 0); |
| 1031 | 1031 |
| 1032 snd_soc_update_bits(codec, WM8993_ANTIPOP2, |
| 1033 WM8993_STARTUP_BIAS_ENA | |
| 1034 WM8993_VMID_BUF_ENA | |
| 1035 WM8993_VMID_RAMP_MASK | |
| 1036 WM8993_BIAS_SRC, 0); |
| 1037 |
| 1032 #ifdef CONFIG_REGULATOR | 1038 #ifdef CONFIG_REGULATOR |
| 1033 /* Post 2.6.34 we will be able to get a callback when | 1039 /* Post 2.6.34 we will be able to get a callback when |
| 1034 * the regulators are disabled which we can use but | 1040 * the regulators are disabled which we can use but |
| 1035 * for now just assume that the power will be cut if | 1041 * for now just assume that the power will be cut if |
| 1036 * the regulator API is in use. | 1042 * the regulator API is in use. |
| 1037 */ | 1043 */ |
| 1038 codec->cache_sync = 1; | 1044 codec->cache_sync = 1; |
| 1039 #endif | 1045 #endif |
| 1040 | 1046 |
| 1041 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), | 1047 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), |
| 1042 wm8993->supplies); | 1048 wm8993->supplies); |
| 1043 break; | 1049 break; |
| 1044 } | 1050 } |
| 1045 | 1051 |
| 1046 » codec->bias_level = level; | 1052 » codec->dapm.bias_level = level; |
| 1047 | 1053 |
| 1048 return 0; | 1054 return 0; |
| 1049 } | 1055 } |
| 1050 | 1056 |
| 1051 static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai, | 1057 static int wm8993_set_sysclk(struct snd_soc_dai *codec_dai, |
| 1052 int clk_id, unsigned int freq, int dir) | 1058 int clk_id, unsigned int freq, int dir) |
| 1053 { | 1059 { |
| 1054 struct snd_soc_codec *codec = codec_dai->codec; | 1060 struct snd_soc_codec *codec = codec_dai->codec; |
| 1055 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | 1061 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); |
| 1056 | 1062 |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1218 ret = configure_clock(codec); | 1224 ret = configure_clock(codec); |
| 1219 if (ret != 0) | 1225 if (ret != 0) |
| 1220 return ret; | 1226 return ret; |
| 1221 | 1227 |
| 1222 /* Select nearest CLK_SYS_RATE */ | 1228 /* Select nearest CLK_SYS_RATE */ |
| 1223 best = 0; | 1229 best = 0; |
| 1224 best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio) | 1230 best_val = abs((wm8993->sysclk_rate / clk_sys_rates[0].ratio) |
| 1225 - wm8993->fs); | 1231 - wm8993->fs); |
| 1226 for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { | 1232 for (i = 1; i < ARRAY_SIZE(clk_sys_rates); i++) { |
| 1227 cur_val = abs((wm8993->sysclk_rate / | 1233 cur_val = abs((wm8993->sysclk_rate / |
| 1228 » » » clk_sys_rates[i].ratio) - wm8993->fs);; | 1234 » » » clk_sys_rates[i].ratio) - wm8993->fs); |
| 1229 if (cur_val < best_val) { | 1235 if (cur_val < best_val) { |
| 1230 best = i; | 1236 best = i; |
| 1231 best_val = cur_val; | 1237 best_val = cur_val; |
| 1232 } | 1238 } |
| 1233 } | 1239 } |
| 1234 dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", | 1240 dev_dbg(codec->dev, "Selected CLK_SYS_RATIO of %d\n", |
| 1235 clk_sys_rates[best].ratio); | 1241 clk_sys_rates[best].ratio); |
| 1236 clocking3 |= (clk_sys_rates[best].clk_sys_rate | 1242 clocking3 |= (clk_sys_rates[best].clk_sys_rate |
| 1237 << WM8993_CLK_SYS_RATE_SHIFT); | 1243 << WM8993_CLK_SYS_RATE_SHIFT); |
| 1238 | 1244 |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1415 .rates = WM8993_RATES, | 1421 .rates = WM8993_RATES, |
| 1416 .formats = WM8993_FORMATS, | 1422 .formats = WM8993_FORMATS, |
| 1417 }, | 1423 }, |
| 1418 .ops = &wm8993_ops, | 1424 .ops = &wm8993_ops, |
| 1419 .symmetric_rates = 1, | 1425 .symmetric_rates = 1, |
| 1420 }; | 1426 }; |
| 1421 | 1427 |
| 1422 static int wm8993_probe(struct snd_soc_codec *codec) | 1428 static int wm8993_probe(struct snd_soc_codec *codec) |
| 1423 { | 1429 { |
| 1424 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | 1430 struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); |
| 1431 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 1425 int ret, i, val; | 1432 int ret, i, val; |
| 1426 | 1433 |
| 1427 wm8993->hubs_data.hp_startup_mode = 1; | 1434 wm8993->hubs_data.hp_startup_mode = 1; |
| 1428 wm8993->hubs_data.dcs_codes = -2; | 1435 wm8993->hubs_data.dcs_codes = -2; |
| 1429 | 1436 |
| 1430 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | 1437 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); |
| 1431 if (ret != 0) { | 1438 if (ret != 0) { |
| 1432 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1439 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 1433 return ret; | 1440 return ret; |
| 1434 } | 1441 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1496 snd_soc_add_controls(codec, wm8993_snd_controls, | 1503 snd_soc_add_controls(codec, wm8993_snd_controls, |
| 1497 ARRAY_SIZE(wm8993_snd_controls)); | 1504 ARRAY_SIZE(wm8993_snd_controls)); |
| 1498 if (wm8993->pdata.num_retune_configs != 0) { | 1505 if (wm8993->pdata.num_retune_configs != 0) { |
| 1499 dev_dbg(codec->dev, "Using ReTune Mobile\n"); | 1506 dev_dbg(codec->dev, "Using ReTune Mobile\n"); |
| 1500 } else { | 1507 } else { |
| 1501 dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n"); | 1508 dev_dbg(codec->dev, "No ReTune Mobile, using normal EQ\n"); |
| 1502 snd_soc_add_controls(codec, wm8993_eq_controls, | 1509 snd_soc_add_controls(codec, wm8993_eq_controls, |
| 1503 ARRAY_SIZE(wm8993_eq_controls)); | 1510 ARRAY_SIZE(wm8993_eq_controls)); |
| 1504 } | 1511 } |
| 1505 | 1512 |
| 1506 » snd_soc_dapm_new_controls(codec, wm8993_dapm_widgets, | 1513 » snd_soc_dapm_new_controls(dapm, wm8993_dapm_widgets, |
| 1507 ARRAY_SIZE(wm8993_dapm_widgets)); | 1514 ARRAY_SIZE(wm8993_dapm_widgets)); |
| 1508 wm_hubs_add_analogue_controls(codec); | 1515 wm_hubs_add_analogue_controls(codec); |
| 1509 | 1516 |
| 1510 » snd_soc_dapm_add_routes(codec, routes, ARRAY_SIZE(routes)); | 1517 » snd_soc_dapm_add_routes(dapm, routes, ARRAY_SIZE(routes)); |
| 1511 wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff, | 1518 wm_hubs_add_analogue_routes(codec, wm8993->pdata.lineout1_diff, |
| 1512 wm8993->pdata.lineout2_diff); | 1519 wm8993->pdata.lineout2_diff); |
| 1513 | 1520 |
| 1514 return 0; | 1521 return 0; |
| 1515 | 1522 |
| 1516 err_enable: | 1523 err_enable: |
| 1517 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); | 1524 regulator_bulk_disable(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); |
| 1518 err_get: | 1525 err_get: |
| 1519 regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); | 1526 regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); |
| 1520 return ret; | 1527 return ret; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1655 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1662 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 1656 i2c_del_driver(&wm8993_i2c_driver); | 1663 i2c_del_driver(&wm8993_i2c_driver); |
| 1657 #endif | 1664 #endif |
| 1658 } | 1665 } |
| 1659 module_exit(wm8993_exit); | 1666 module_exit(wm8993_exit); |
| 1660 | 1667 |
| 1661 | 1668 |
| 1662 MODULE_DESCRIPTION("ASoC WM8993 driver"); | 1669 MODULE_DESCRIPTION("ASoC WM8993 driver"); |
| 1663 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 1670 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
| 1664 MODULE_LICENSE("GPL"); | 1671 MODULE_LICENSE("GPL"); |
| OLD | NEW |