| OLD | NEW |
| 1 /* | 1 /* |
| 2 * wm9081.c -- WM9081 ALSA SoC Audio driver | 2 * wm9081.c -- WM9081 ALSA SoC Audio driver |
| 3 * | 3 * |
| 4 * Author: Mark Brown | 4 * Author: Mark Brown |
| 5 * | 5 * |
| 6 * Copyright 2009 Wolfson Microelectronics plc | 6 * Copyright 2009 Wolfson Microelectronics plc |
| 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 | 13 |
| 14 #include <linux/module.h> | 14 #include <linux/module.h> |
| 15 #include <linux/moduleparam.h> | 15 #include <linux/moduleparam.h> |
| 16 #include <linux/init.h> | 16 #include <linux/init.h> |
| 17 #include <linux/delay.h> | 17 #include <linux/delay.h> |
| 18 #include <linux/pm.h> | 18 #include <linux/pm.h> |
| 19 #include <linux/i2c.h> | 19 #include <linux/i2c.h> |
| 20 #include <linux/platform_device.h> | 20 #include <linux/platform_device.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/soc.h> | 25 #include <sound/soc.h> |
| 26 #include <sound/soc-dapm.h> | |
| 27 #include <sound/initval.h> | 26 #include <sound/initval.h> |
| 28 #include <sound/tlv.h> | 27 #include <sound/tlv.h> |
| 29 | 28 |
| 30 #include <sound/wm9081.h> | 29 #include <sound/wm9081.h> |
| 31 #include "wm9081.h" | 30 #include "wm9081.h" |
| 32 | 31 |
| 33 static u16 wm9081_reg_defaults[] = { | 32 static u16 wm9081_reg_defaults[] = { |
| 34 0x0000, /* R0 - Software Reset */ | 33 0x0000, /* R0 - Software Reset */ |
| 35 0x0000, /* R1 */ | 34 0x0000, /* R1 */ |
| 36 0x00B9, /* R2 - Analogue Lineout */ | 35 0x00B9, /* R2 - Analogue Lineout */ |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 151 { 250, 16 }, | 150 { 250, 16 }, |
| 152 { 300, 17 }, | 151 { 300, 17 }, |
| 153 { 320, 18 }, | 152 { 320, 18 }, |
| 154 { 440, 19 }, | 153 { 440, 19 }, |
| 155 { 480, 20 }, | 154 { 480, 20 }, |
| 156 }; | 155 }; |
| 157 | 156 |
| 158 struct wm9081_priv { | 157 struct wm9081_priv { |
| 159 enum snd_soc_control_type control_type; | 158 enum snd_soc_control_type control_type; |
| 160 void *control_data; | 159 void *control_data; |
| 161 u16 reg_cache[WM9081_MAX_REGISTER + 1]; | |
| 162 int sysclk_source; | 160 int sysclk_source; |
| 163 int mclk_rate; | 161 int mclk_rate; |
| 164 int sysclk_rate; | 162 int sysclk_rate; |
| 165 int fs; | 163 int fs; |
| 166 int bclk; | 164 int bclk; |
| 167 int master; | 165 int master; |
| 168 int fll_fref; | 166 int fll_fref; |
| 169 int fll_fout; | 167 int fll_fout; |
| 170 int tdm_width; | 168 int tdm_width; |
| 171 struct wm9081_retune_mobile_config *retune; | 169 struct wm9081_retune_mobile_config *retune; |
| 172 }; | 170 }; |
| 173 | 171 |
| 174 static int wm9081_volatile_register(unsigned int reg) | 172 static int wm9081_volatile_register(struct snd_soc_codec *codec, unsigned int re
g) |
| 175 { | 173 { |
| 176 switch (reg) { | 174 switch (reg) { |
| 177 case WM9081_SOFTWARE_RESET: | 175 case WM9081_SOFTWARE_RESET: |
| 178 return 1; | 176 return 1; |
| 179 default: | 177 default: |
| 180 return 0; | 178 return 0; |
| 181 } | 179 } |
| 182 } | 180 } |
| 183 | 181 |
| 184 static int wm9081_reset(struct snd_soc_codec *codec) | 182 static int wm9081_reset(struct snd_soc_codec *codec) |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 | 582 |
| 585 reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4); | 583 reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4); |
| 586 reg4 &= ~WM9081_FLL_N_MASK; | 584 reg4 &= ~WM9081_FLL_N_MASK; |
| 587 reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; | 585 reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; |
| 588 snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4); | 586 snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4); |
| 589 | 587 |
| 590 reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; | 588 reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; |
| 591 reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; | 589 reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; |
| 592 snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5); | 590 snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5); |
| 593 | 591 |
| 592 /* Set gain to the recommended value */ |
| 593 snd_soc_update_bits(codec, WM9081_FLL_CONTROL_4, |
| 594 WM9081_FLL_GAIN_MASK, 0); |
| 595 |
| 594 /* Enable the FLL */ | 596 /* Enable the FLL */ |
| 595 snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); | 597 snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); |
| 596 | 598 |
| 597 /* Then bring CLK_SYS up again if it was disabled */ | 599 /* Then bring CLK_SYS up again if it was disabled */ |
| 598 if (clk_sys_reg & WM9081_CLK_SYS_ENA) | 600 if (clk_sys_reg & WM9081_CLK_SYS_ENA) |
| 599 snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); | 601 snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); |
| 600 | 602 |
| 601 dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); | 603 dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); |
| 602 | 604 |
| 603 wm9081->fll_fref = Fref; | 605 wm9081->fll_fref = Fref; |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 798 snd_soc_write(codec, WM9081_VMID_CONTROL, reg); | 800 snd_soc_write(codec, WM9081_VMID_CONTROL, reg); |
| 799 | 801 |
| 800 /* Normal bias current */ | 802 /* Normal bias current */ |
| 801 reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); | 803 reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); |
| 802 reg &= ~WM9081_STBY_BIAS_ENA; | 804 reg &= ~WM9081_STBY_BIAS_ENA; |
| 803 snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); | 805 snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); |
| 804 break; | 806 break; |
| 805 | 807 |
| 806 case SND_SOC_BIAS_STANDBY: | 808 case SND_SOC_BIAS_STANDBY: |
| 807 /* Initial cold start */ | 809 /* Initial cold start */ |
| 808 » » if (codec->bias_level == SND_SOC_BIAS_OFF) { | 810 » » if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
| 809 /* Disable LINEOUT discharge */ | 811 /* Disable LINEOUT discharge */ |
| 810 reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); | 812 reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); |
| 811 reg &= ~WM9081_LINEOUT_DISCH; | 813 reg &= ~WM9081_LINEOUT_DISCH; |
| 812 snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); | 814 snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); |
| 813 | 815 |
| 814 /* Select startup bias source */ | 816 /* Select startup bias source */ |
| 815 reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); | 817 reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); |
| 816 reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; | 818 reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; |
| 817 snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); | 819 snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); |
| 818 | 820 |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 reg |= WM9081_VMID_RAMP; | 860 reg |= WM9081_VMID_RAMP; |
| 859 snd_soc_write(codec, WM9081_VMID_CONTROL, reg); | 861 snd_soc_write(codec, WM9081_VMID_CONTROL, reg); |
| 860 | 862 |
| 861 /* Actively discharge LINEOUT */ | 863 /* Actively discharge LINEOUT */ |
| 862 reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); | 864 reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); |
| 863 reg |= WM9081_LINEOUT_DISCH; | 865 reg |= WM9081_LINEOUT_DISCH; |
| 864 snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); | 866 snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); |
| 865 break; | 867 break; |
| 866 } | 868 } |
| 867 | 869 |
| 868 » codec->bias_level = level; | 870 » codec->dapm.bias_level = level; |
| 869 | 871 |
| 870 return 0; | 872 return 0; |
| 871 } | 873 } |
| 872 | 874 |
| 873 static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, | 875 static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, |
| 874 unsigned int fmt) | 876 unsigned int fmt) |
| 875 { | 877 { |
| 876 struct snd_soc_codec *codec = dai->codec; | 878 struct snd_soc_codec *codec = dai->codec; |
| 877 struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); | 879 struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); |
| 878 unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2); | 880 unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2); |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 .channels_max = 2, | 1223 .channels_max = 2, |
| 1222 .rates = WM9081_RATES, | 1224 .rates = WM9081_RATES, |
| 1223 .formats = WM9081_FORMATS, | 1225 .formats = WM9081_FORMATS, |
| 1224 }, | 1226 }, |
| 1225 .ops = &wm9081_dai_ops, | 1227 .ops = &wm9081_dai_ops, |
| 1226 }; | 1228 }; |
| 1227 | 1229 |
| 1228 static int wm9081_probe(struct snd_soc_codec *codec) | 1230 static int wm9081_probe(struct snd_soc_codec *codec) |
| 1229 { | 1231 { |
| 1230 struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); | 1232 struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); |
| 1233 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 1231 int ret; | 1234 int ret; |
| 1232 u16 reg; | 1235 u16 reg; |
| 1233 | 1236 |
| 1234 codec->control_data = wm9081->control_data; | 1237 codec->control_data = wm9081->control_data; |
| 1235 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type); | 1238 ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm9081->control_type); |
| 1236 if (ret != 0) { | 1239 if (ret != 0) { |
| 1237 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1240 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 1238 return ret; | 1241 return ret; |
| 1239 } | 1242 } |
| 1240 | 1243 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 1262 | 1265 |
| 1263 snd_soc_add_controls(codec, wm9081_snd_controls, | 1266 snd_soc_add_controls(codec, wm9081_snd_controls, |
| 1264 ARRAY_SIZE(wm9081_snd_controls)); | 1267 ARRAY_SIZE(wm9081_snd_controls)); |
| 1265 if (!wm9081->retune) { | 1268 if (!wm9081->retune) { |
| 1266 dev_dbg(codec->dev, | 1269 dev_dbg(codec->dev, |
| 1267 "No ReTune Mobile data, using normal EQ\n"); | 1270 "No ReTune Mobile data, using normal EQ\n"); |
| 1268 snd_soc_add_controls(codec, wm9081_eq_controls, | 1271 snd_soc_add_controls(codec, wm9081_eq_controls, |
| 1269 ARRAY_SIZE(wm9081_eq_controls)); | 1272 ARRAY_SIZE(wm9081_eq_controls)); |
| 1270 } | 1273 } |
| 1271 | 1274 |
| 1272 » snd_soc_dapm_new_controls(codec, wm9081_dapm_widgets, | 1275 » snd_soc_dapm_new_controls(dapm, wm9081_dapm_widgets, |
| 1273 ARRAY_SIZE(wm9081_dapm_widgets)); | 1276 ARRAY_SIZE(wm9081_dapm_widgets)); |
| 1274 » snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | 1277 » snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); |
| 1275 | 1278 |
| 1276 return ret; | 1279 return ret; |
| 1277 } | 1280 } |
| 1278 | 1281 |
| 1279 static int wm9081_remove(struct snd_soc_codec *codec) | 1282 static int wm9081_remove(struct snd_soc_codec *codec) |
| 1280 { | 1283 { |
| 1281 wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1284 wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1282 return 0; | 1285 return 0; |
| 1283 } | 1286 } |
| 1284 | 1287 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1388 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1391 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 1389 i2c_del_driver(&wm9081_i2c_driver); | 1392 i2c_del_driver(&wm9081_i2c_driver); |
| 1390 #endif | 1393 #endif |
| 1391 } | 1394 } |
| 1392 module_exit(wm9081_exit); | 1395 module_exit(wm9081_exit); |
| 1393 | 1396 |
| 1394 | 1397 |
| 1395 MODULE_DESCRIPTION("ASoC WM9081 driver"); | 1398 MODULE_DESCRIPTION("ASoC WM9081 driver"); |
| 1396 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 1399 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
| 1397 MODULE_LICENSE("GPL"); | 1400 MODULE_LICENSE("GPL"); |
| OLD | NEW |