| OLD | NEW |
| 1 /* | 1 /* |
| 2 * wm8580.c -- WM8580 ALSA Soc Audio driver | 2 * wm8580.c -- WM8580 ALSA Soc Audio driver |
| 3 * | 3 * |
| 4 * Copyright 2008, 2009 Wolfson Microelectronics PLC. | 4 * Copyright 2008, 2009 Wolfson Microelectronics PLC. |
| 5 * | 5 * |
| 6 * This program is free software; you can redistribute it and/or modify it | 6 * This program is free software; you can redistribute it and/or modify it |
| 7 * under the terms of the GNU General Public License as published by the | 7 * under the terms of the GNU General Public License as published by the |
| 8 * Free Software Foundation; either version 2 of the License, or (at your | 8 * Free Software Foundation; either version 2 of the License, or (at your |
| 9 * option) any later version. | 9 * option) any later version. |
| 10 * | 10 * |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include <linux/pm.h> | 24 #include <linux/pm.h> |
| 25 #include <linux/i2c.h> | 25 #include <linux/i2c.h> |
| 26 #include <linux/platform_device.h> | 26 #include <linux/platform_device.h> |
| 27 #include <linux/regulator/consumer.h> | 27 #include <linux/regulator/consumer.h> |
| 28 #include <linux/slab.h> | 28 #include <linux/slab.h> |
| 29 | 29 |
| 30 #include <sound/core.h> | 30 #include <sound/core.h> |
| 31 #include <sound/pcm.h> | 31 #include <sound/pcm.h> |
| 32 #include <sound/pcm_params.h> | 32 #include <sound/pcm_params.h> |
| 33 #include <sound/soc.h> | 33 #include <sound/soc.h> |
| 34 #include <sound/soc-dapm.h> | |
| 35 #include <sound/tlv.h> | 34 #include <sound/tlv.h> |
| 36 #include <sound/initval.h> | 35 #include <sound/initval.h> |
| 37 #include <asm/div64.h> | 36 #include <asm/div64.h> |
| 38 | 37 |
| 39 #include "wm8580.h" | 38 #include "wm8580.h" |
| 40 | 39 |
| 41 /* WM8580 register space */ | 40 /* WM8580 register space */ |
| 42 #define WM8580_PLLA1 0x00 | 41 #define WM8580_PLLA1 0x00 |
| 43 #define WM8580_PLLA2 0x01 | 42 #define WM8580_PLLA2 0x01 |
| 44 #define WM8580_PLLA3 0x02 | 43 #define WM8580_PLLA3 0x02 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { | 183 static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = { |
| 185 "AVDD", | 184 "AVDD", |
| 186 "DVDD", | 185 "DVDD", |
| 187 "PVDD", | 186 "PVDD", |
| 188 }; | 187 }; |
| 189 | 188 |
| 190 /* codec private data */ | 189 /* codec private data */ |
| 191 struct wm8580_priv { | 190 struct wm8580_priv { |
| 192 enum snd_soc_control_type control_type; | 191 enum snd_soc_control_type control_type; |
| 193 struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; | 192 struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES]; |
| 194 u16 reg_cache[WM8580_MAX_REGISTER + 1]; | |
| 195 struct pll_state a; | 193 struct pll_state a; |
| 196 struct pll_state b; | 194 struct pll_state b; |
| 197 int sysclk[2]; | 195 int sysclk[2]; |
| 198 }; | 196 }; |
| 199 | 197 |
| 200 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); | 198 static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); |
| 201 | 199 |
| 202 static int wm8580_out_vu(struct snd_kcontrol *kcontrol, | 200 static int wm8580_out_vu(struct snd_kcontrol *kcontrol, |
| 203 struct snd_ctl_elem_value *ucontrol) | 201 struct snd_ctl_elem_value *ucontrol) |
| 204 { | 202 { |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 | 293 |
| 296 { "VOUT3L", NULL, "DAC3" }, | 294 { "VOUT3L", NULL, "DAC3" }, |
| 297 { "VOUT3R", NULL, "DAC3" }, | 295 { "VOUT3R", NULL, "DAC3" }, |
| 298 | 296 |
| 299 { "ADC", NULL, "AINL" }, | 297 { "ADC", NULL, "AINL" }, |
| 300 { "ADC", NULL, "AINR" }, | 298 { "ADC", NULL, "AINR" }, |
| 301 }; | 299 }; |
| 302 | 300 |
| 303 static int wm8580_add_widgets(struct snd_soc_codec *codec) | 301 static int wm8580_add_widgets(struct snd_soc_codec *codec) |
| 304 { | 302 { |
| 305 » snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets, | 303 » struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 304 |
| 305 » snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets, |
| 306 ARRAY_SIZE(wm8580_dapm_widgets)); | 306 ARRAY_SIZE(wm8580_dapm_widgets)); |
| 307 | 307 » snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
| 308 » snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | |
| 309 | 308 |
| 310 return 0; | 309 return 0; |
| 311 } | 310 } |
| 312 | 311 |
| 313 /* PLL divisors */ | 312 /* PLL divisors */ |
| 314 struct _pll_div { | 313 struct _pll_div { |
| 315 u32 prescale:1; | 314 u32 prescale:1; |
| 316 u32 postscale:1; | 315 u32 postscale:1; |
| 317 u32 freqmode:2; | 316 u32 freqmode:2; |
| 318 u32 n:4; | 317 u32 n:4; |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 500 break; | 499 break; |
| 501 case SNDRV_PCM_FORMAT_S32_LE: | 500 case SNDRV_PCM_FORMAT_S32_LE: |
| 502 paifa |= 0x0; | 501 paifa |= 0x0; |
| 503 paifb |= WM8580_AIF_LENGTH_32; | 502 paifb |= WM8580_AIF_LENGTH_32; |
| 504 break; | 503 break; |
| 505 default: | 504 default: |
| 506 return -EINVAL; | 505 return -EINVAL; |
| 507 } | 506 } |
| 508 | 507 |
| 509 /* Look up the SYSCLK ratio; accept only exact matches */ | 508 /* Look up the SYSCLK ratio; accept only exact matches */ |
| 510 » ratio = wm8580->sysclk[dai->id] / params_rate(params); | 509 » ratio = wm8580->sysclk[dai->driver->id] / params_rate(params); |
| 511 for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++) | 510 for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++) |
| 512 if (ratio == wm8580_sysclk_ratios[i]) | 511 if (ratio == wm8580_sysclk_ratios[i]) |
| 513 break; | 512 break; |
| 514 if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) { | 513 if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) { |
| 515 dev_err(codec->dev, "Invalid clock ratio %d/%d\n", | 514 dev_err(codec->dev, "Invalid clock ratio %d/%d\n", |
| 516 » » » wm8580->sysclk[dai->id], params_rate(params)); | 515 » » » wm8580->sysclk[dai->driver->id], params_rate(params)); |
| 517 return -EINVAL; | 516 return -EINVAL; |
| 518 } | 517 } |
| 519 paifa |= i; | 518 paifa |= i; |
| 520 dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n", | 519 dev_dbg(codec->dev, "Running at %dfs with %dHz clock\n", |
| 521 wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]); | 520 wm8580_sysclk_ratios[i], wm8580->sysclk[dai->driver->id]); |
| 522 | 521 |
| 523 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 522 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 524 switch (ratio) { | 523 switch (ratio) { |
| 525 case 128: | 524 case 128: |
| 526 case 192: | 525 case 192: |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 sel_shift = 2; | 708 sel_shift = 2; |
| 710 break; | 709 break; |
| 711 | 710 |
| 712 default: | 711 default: |
| 713 BUG_ON("Unknown DAI driver ID\n"); | 712 BUG_ON("Unknown DAI driver ID\n"); |
| 714 return -EINVAL; | 713 return -EINVAL; |
| 715 } | 714 } |
| 716 | 715 |
| 717 switch (clk_id) { | 716 switch (clk_id) { |
| 718 case WM8580_CLKSRC_ADCMCLK: | 717 case WM8580_CLKSRC_ADCMCLK: |
| 719 » » if (dai->id != WM8580_DAI_PAIFTX) | 718 » » if (dai->driver->id != WM8580_DAI_PAIFTX) |
| 720 return -EINVAL; | 719 return -EINVAL; |
| 721 sel = 0 << sel_shift; | 720 sel = 0 << sel_shift; |
| 722 break; | 721 break; |
| 723 case WM8580_CLKSRC_PLLA: | 722 case WM8580_CLKSRC_PLLA: |
| 724 sel = 1 << sel_shift; | 723 sel = 1 << sel_shift; |
| 725 break; | 724 break; |
| 726 case WM8580_CLKSRC_PLLB: | 725 case WM8580_CLKSRC_PLLB: |
| 727 sel = 2 << sel_shift; | 726 sel = 2 << sel_shift; |
| 728 break; | 727 break; |
| 729 case WM8580_CLKSRC_MCLK: | 728 case WM8580_CLKSRC_MCLK: |
| 730 sel = 3 << sel_shift; | 729 sel = 3 << sel_shift; |
| 731 break; | 730 break; |
| 732 default: | 731 default: |
| 733 dev_err(codec->dev, "Unknown clock %d\n", clk_id); | 732 dev_err(codec->dev, "Unknown clock %d\n", clk_id); |
| 734 return -EINVAL; | 733 return -EINVAL; |
| 735 } | 734 } |
| 736 | 735 |
| 737 /* We really should validate PLL settings but not yet */ | 736 /* We really should validate PLL settings but not yet */ |
| 738 » wm8580->sysclk[dai->id] = freq; | 737 » wm8580->sysclk[dai->driver->id] = freq; |
| 739 | 738 |
| 740 return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel); | 739 return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel); |
| 741 } | 740 } |
| 742 | 741 |
| 743 static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) | 742 static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) |
| 744 { | 743 { |
| 745 struct snd_soc_codec *codec = codec_dai->codec; | 744 struct snd_soc_codec *codec = codec_dai->codec; |
| 746 unsigned int reg; | 745 unsigned int reg; |
| 747 | 746 |
| 748 reg = snd_soc_read(codec, WM8580_DAC_CONTROL5); | 747 reg = snd_soc_read(codec, WM8580_DAC_CONTROL5); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 760 static int wm8580_set_bias_level(struct snd_soc_codec *codec, | 759 static int wm8580_set_bias_level(struct snd_soc_codec *codec, |
| 761 enum snd_soc_bias_level level) | 760 enum snd_soc_bias_level level) |
| 762 { | 761 { |
| 763 u16 reg; | 762 u16 reg; |
| 764 switch (level) { | 763 switch (level) { |
| 765 case SND_SOC_BIAS_ON: | 764 case SND_SOC_BIAS_ON: |
| 766 case SND_SOC_BIAS_PREPARE: | 765 case SND_SOC_BIAS_PREPARE: |
| 767 break; | 766 break; |
| 768 | 767 |
| 769 case SND_SOC_BIAS_STANDBY: | 768 case SND_SOC_BIAS_STANDBY: |
| 770 » » if (codec->bias_level == SND_SOC_BIAS_OFF) { | 769 » » if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
| 771 /* Power up and get individual control of the DACs */ | 770 /* Power up and get individual control of the DACs */ |
| 772 reg = snd_soc_read(codec, WM8580_PWRDN1); | 771 reg = snd_soc_read(codec, WM8580_PWRDN1); |
| 773 reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); | 772 reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); |
| 774 snd_soc_write(codec, WM8580_PWRDN1, reg); | 773 snd_soc_write(codec, WM8580_PWRDN1, reg); |
| 775 | 774 |
| 776 /* Make VMID high impedence */ | 775 /* Make VMID high impedence */ |
| 777 reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); | 776 reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); |
| 778 reg &= ~0x100; | 777 reg &= ~0x100; |
| 779 snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); | 778 snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); |
| 780 } | 779 } |
| 781 break; | 780 break; |
| 782 | 781 |
| 783 case SND_SOC_BIAS_OFF: | 782 case SND_SOC_BIAS_OFF: |
| 784 reg = snd_soc_read(codec, WM8580_PWRDN1); | 783 reg = snd_soc_read(codec, WM8580_PWRDN1); |
| 785 snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); | 784 snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); |
| 786 break; | 785 break; |
| 787 } | 786 } |
| 788 » codec->bias_level = level; | 787 » codec->dapm.bias_level = level; |
| 789 return 0; | 788 return 0; |
| 790 } | 789 } |
| 791 | 790 |
| 792 #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 791 #define WM8580_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 793 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | 792 SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
| 794 | 793 |
| 795 static struct snd_soc_dai_ops wm8580_dai_ops_playback = { | 794 static struct snd_soc_dai_ops wm8580_dai_ops_playback = { |
| 796 .set_sysclk = wm8580_set_sysclk, | 795 .set_sysclk = wm8580_set_sysclk, |
| 797 .hw_params = wm8580_paif_hw_params, | 796 .hw_params = wm8580_paif_hw_params, |
| 798 .set_fmt = wm8580_set_paif_dai_fmt, | 797 .set_fmt = wm8580_set_paif_dai_fmt, |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 898 | 897 |
| 899 return 0; | 898 return 0; |
| 900 } | 899 } |
| 901 | 900 |
| 902 static struct snd_soc_codec_driver soc_codec_dev_wm8580 = { | 901 static struct snd_soc_codec_driver soc_codec_dev_wm8580 = { |
| 903 .probe = wm8580_probe, | 902 .probe = wm8580_probe, |
| 904 .remove = wm8580_remove, | 903 .remove = wm8580_remove, |
| 905 .set_bias_level = wm8580_set_bias_level, | 904 .set_bias_level = wm8580_set_bias_level, |
| 906 .reg_cache_size = ARRAY_SIZE(wm8580_reg), | 905 .reg_cache_size = ARRAY_SIZE(wm8580_reg), |
| 907 .reg_word_size = sizeof(u16), | 906 .reg_word_size = sizeof(u16), |
| 908 » .reg_cache_default = &wm8580_reg, | 907 » .reg_cache_default = wm8580_reg, |
| 909 }; | 908 }; |
| 910 | 909 |
| 911 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 910 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 912 static int wm8580_i2c_probe(struct i2c_client *i2c, | 911 static int wm8580_i2c_probe(struct i2c_client *i2c, |
| 913 const struct i2c_device_id *id) | 912 const struct i2c_device_id *id) |
| 914 { | 913 { |
| 915 struct wm8580_priv *wm8580; | 914 struct wm8580_priv *wm8580; |
| 916 int ret; | 915 int ret; |
| 917 | 916 |
| 918 wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); | 917 wm8580 = kzalloc(sizeof(struct wm8580_priv), GFP_KERNEL); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 972 { | 971 { |
| 973 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 972 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 974 i2c_del_driver(&wm8580_i2c_driver); | 973 i2c_del_driver(&wm8580_i2c_driver); |
| 975 #endif | 974 #endif |
| 976 } | 975 } |
| 977 module_exit(wm8580_exit); | 976 module_exit(wm8580_exit); |
| 978 | 977 |
| 979 MODULE_DESCRIPTION("ASoC WM8580 driver"); | 978 MODULE_DESCRIPTION("ASoC WM8580 driver"); |
| 980 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 979 MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
| 981 MODULE_LICENSE("GPL"); | 980 MODULE_LICENSE("GPL"); |
| OLD | NEW |