| OLD | NEW |
| 1 /* | 1 /* |
| 2 * wm8961.c -- WM8961 ALSA SoC Audio driver | 2 * wm8961.c -- WM8961 ALSA SoC Audio driver |
| 3 * | 3 * |
| 4 * Author: Mark Brown | 4 * Author: Mark Brown |
| 5 * | 5 * |
| 6 * This program is free software; you can redistribute it and/or modify | 6 * This program is free software; you can redistribute it and/or modify |
| 7 * it under the terms of the GNU General Public License version 2 as | 7 * it under the terms of the GNU General Public License version 2 as |
| 8 * published by the Free Software Foundation. | 8 * published by the Free Software Foundation. |
| 9 * | 9 * |
| 10 * Currently unimplemented features: | 10 * Currently unimplemented features: |
| 11 * - ALC | 11 * - ALC |
| 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 "wm8961.h" | 29 #include "wm8961.h" |
| 31 | 30 |
| 32 #define WM8961_MAX_REGISTER 0xFC | 31 #define WM8961_MAX_REGISTER 0xFC |
| 33 | 32 |
| 34 static u16 wm8961_reg_defaults[] = { | 33 static u16 wm8961_reg_defaults[] = { |
| 35 0x009F, /* R0 - Left Input volume */ | 34 0x009F, /* R0 - Left Input volume */ |
| 36 0x009F, /* R1 - Right Input volume */ | 35 0x009F, /* R1 - Right Input volume */ |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 283 0x0000, /* R248 */ | 282 0x0000, /* R248 */ |
| 284 0x0030, /* R249 */ | 283 0x0030, /* R249 */ |
| 285 0x0000, /* R250 */ | 284 0x0000, /* R250 */ |
| 286 0x0000, /* R251 */ | 285 0x0000, /* R251 */ |
| 287 0x0001, /* R252 - General test 1 */ | 286 0x0001, /* R252 - General test 1 */ |
| 288 }; | 287 }; |
| 289 | 288 |
| 290 struct wm8961_priv { | 289 struct wm8961_priv { |
| 291 enum snd_soc_control_type control_type; | 290 enum snd_soc_control_type control_type; |
| 292 int sysclk; | 291 int sysclk; |
| 293 u16 reg_cache[WM8961_MAX_REGISTER]; | |
| 294 }; | 292 }; |
| 295 | 293 |
| 296 static int wm8961_volatile_register(unsigned int reg) | 294 static int wm8961_volatile_register(struct snd_soc_codec *codec, unsigned int re
g) |
| 297 { | 295 { |
| 298 switch (reg) { | 296 switch (reg) { |
| 299 case WM8961_SOFTWARE_RESET: | 297 case WM8961_SOFTWARE_RESET: |
| 300 case WM8961_WRITE_SEQUENCER_7: | 298 case WM8961_WRITE_SEQUENCER_7: |
| 301 case WM8961_DC_SERVO_1: | 299 case WM8961_DC_SERVO_1: |
| 302 return 1; | 300 return 1; |
| 303 | 301 |
| 304 default: | 302 default: |
| 305 return 0; | 303 return 0; |
| 306 } | 304 } |
| (...skipping 568 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 875 /* This is all slightly unusual since we have no bypass paths | 873 /* This is all slightly unusual since we have no bypass paths |
| 876 * and the output amplifier structure means we can just slam | 874 * and the output amplifier structure means we can just slam |
| 877 * the biases straight up rather than having to ramp them | 875 * the biases straight up rather than having to ramp them |
| 878 * slowly. | 876 * slowly. |
| 879 */ | 877 */ |
| 880 switch (level) { | 878 switch (level) { |
| 881 case SND_SOC_BIAS_ON: | 879 case SND_SOC_BIAS_ON: |
| 882 break; | 880 break; |
| 883 | 881 |
| 884 case SND_SOC_BIAS_PREPARE: | 882 case SND_SOC_BIAS_PREPARE: |
| 885 » » if (codec->bias_level == SND_SOC_BIAS_STANDBY) { | 883 » » if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { |
| 886 /* Enable bias generation */ | 884 /* Enable bias generation */ |
| 887 reg = snd_soc_read(codec, WM8961_ANTI_POP); | 885 reg = snd_soc_read(codec, WM8961_ANTI_POP); |
| 888 reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; | 886 reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; |
| 889 snd_soc_write(codec, WM8961_ANTI_POP, reg); | 887 snd_soc_write(codec, WM8961_ANTI_POP, reg); |
| 890 | 888 |
| 891 /* VMID=2*50k, VREF */ | 889 /* VMID=2*50k, VREF */ |
| 892 reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); | 890 reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); |
| 893 reg &= ~WM8961_VMIDSEL_MASK; | 891 reg &= ~WM8961_VMIDSEL_MASK; |
| 894 reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; | 892 reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; |
| 895 snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); | 893 snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); |
| 896 } | 894 } |
| 897 break; | 895 break; |
| 898 | 896 |
| 899 case SND_SOC_BIAS_STANDBY: | 897 case SND_SOC_BIAS_STANDBY: |
| 900 » » if (codec->bias_level == SND_SOC_BIAS_PREPARE) { | 898 » » if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { |
| 901 /* VREF off */ | 899 /* VREF off */ |
| 902 reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); | 900 reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); |
| 903 reg &= ~WM8961_VREF; | 901 reg &= ~WM8961_VREF; |
| 904 snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); | 902 snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); |
| 905 | 903 |
| 906 /* Bias generation off */ | 904 /* Bias generation off */ |
| 907 reg = snd_soc_read(codec, WM8961_ANTI_POP); | 905 reg = snd_soc_read(codec, WM8961_ANTI_POP); |
| 908 reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); | 906 reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); |
| 909 snd_soc_write(codec, WM8961_ANTI_POP, reg); | 907 snd_soc_write(codec, WM8961_ANTI_POP, reg); |
| 910 | 908 |
| 911 /* VMID off */ | 909 /* VMID off */ |
| 912 reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); | 910 reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); |
| 913 reg &= ~WM8961_VMIDSEL_MASK; | 911 reg &= ~WM8961_VMIDSEL_MASK; |
| 914 snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); | 912 snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); |
| 915 } | 913 } |
| 916 break; | 914 break; |
| 917 | 915 |
| 918 case SND_SOC_BIAS_OFF: | 916 case SND_SOC_BIAS_OFF: |
| 919 break; | 917 break; |
| 920 } | 918 } |
| 921 | 919 |
| 922 » codec->bias_level = level; | 920 » codec->dapm.bias_level = level; |
| 923 | 921 |
| 924 return 0; | 922 return 0; |
| 925 } | 923 } |
| 926 | 924 |
| 927 | 925 |
| 928 #define WM8961_RATES SNDRV_PCM_RATE_8000_48000 | 926 #define WM8961_RATES SNDRV_PCM_RATE_8000_48000 |
| 929 | 927 |
| 930 #define WM8961_FORMATS \ | 928 #define WM8961_FORMATS \ |
| 931 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 929 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
| 932 SNDRV_PCM_FMTBIT_S24_LE) | 930 SNDRV_PCM_FMTBIT_S24_LE) |
| (...skipping 19 matching lines...) Expand all Loading... |
| 952 .stream_name = "HiFi Capture", | 950 .stream_name = "HiFi Capture", |
| 953 .channels_min = 1, | 951 .channels_min = 1, |
| 954 .channels_max = 2, | 952 .channels_max = 2, |
| 955 .rates = WM8961_RATES, | 953 .rates = WM8961_RATES, |
| 956 .formats = WM8961_FORMATS,}, | 954 .formats = WM8961_FORMATS,}, |
| 957 .ops = &wm8961_dai_ops, | 955 .ops = &wm8961_dai_ops, |
| 958 }; | 956 }; |
| 959 | 957 |
| 960 static int wm8961_probe(struct snd_soc_codec *codec) | 958 static int wm8961_probe(struct snd_soc_codec *codec) |
| 961 { | 959 { |
| 960 struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 962 int ret = 0; | 961 int ret = 0; |
| 963 u16 reg; | 962 u16 reg; |
| 964 | 963 |
| 965 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | 964 ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); |
| 966 if (ret != 0) { | 965 if (ret != 0) { |
| 967 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 966 dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 968 return ret; | 967 return ret; |
| 969 } | 968 } |
| 970 | 969 |
| 971 reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET); | 970 reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1017 * we support. | 1016 * we support. |
| 1018 */ | 1017 */ |
| 1019 reg = snd_soc_read(codec, WM8961_CLOCKING_3); | 1018 reg = snd_soc_read(codec, WM8961_CLOCKING_3); |
| 1020 reg &= ~WM8961_MANUAL_MODE; | 1019 reg &= ~WM8961_MANUAL_MODE; |
| 1021 snd_soc_write(codec, WM8961_CLOCKING_3, reg); | 1020 snd_soc_write(codec, WM8961_CLOCKING_3, reg); |
| 1022 | 1021 |
| 1023 wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1022 wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 1024 | 1023 |
| 1025 snd_soc_add_controls(codec, wm8961_snd_controls, | 1024 snd_soc_add_controls(codec, wm8961_snd_controls, |
| 1026 ARRAY_SIZE(wm8961_snd_controls)); | 1025 ARRAY_SIZE(wm8961_snd_controls)); |
| 1027 » snd_soc_dapm_new_controls(codec, wm8961_dapm_widgets, | 1026 » snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets, |
| 1028 ARRAY_SIZE(wm8961_dapm_widgets)); | 1027 ARRAY_SIZE(wm8961_dapm_widgets)); |
| 1029 » snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | 1028 » snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); |
| 1030 | 1029 |
| 1031 return 0; | 1030 return 0; |
| 1032 } | 1031 } |
| 1033 | 1032 |
| 1034 static int wm8961_remove(struct snd_soc_codec *codec) | 1033 static int wm8961_remove(struct snd_soc_codec *codec) |
| 1035 { | 1034 { |
| 1036 wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1035 wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1037 return 0; | 1036 return 0; |
| 1038 } | 1037 } |
| 1039 | 1038 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1143 { | 1142 { |
| 1144 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1143 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 1145 i2c_del_driver(&wm8961_i2c_driver); | 1144 i2c_del_driver(&wm8961_i2c_driver); |
| 1146 #endif | 1145 #endif |
| 1147 } | 1146 } |
| 1148 module_exit(wm8961_exit); | 1147 module_exit(wm8961_exit); |
| 1149 | 1148 |
| 1150 MODULE_DESCRIPTION("ASoC WM8961 driver"); | 1149 MODULE_DESCRIPTION("ASoC WM8961 driver"); |
| 1151 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 1150 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
| 1152 MODULE_LICENSE("GPL"); | 1151 MODULE_LICENSE("GPL"); |
| OLD | NEW |