Commit 36633237be60c0ec88b11e00d5fa22a305563d03
Committed by
Mark Brown
1 parent
42aee9b43e
Exists in
master
and in
7 other branches
ASoC: sn95031: Add support for reading mic bias
This patch adds support to read the mic bias voltage when a jack is inserted. It uses ADC to measure. Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Harsha Priya <priya.harsha@intel.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Showing 2 changed files with 147 additions and 4 deletions Side-by-side Diff
sound/soc/codecs/sn95031.c
... | ... | @@ -40,13 +40,130 @@ |
40 | 40 | #define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100) |
41 | 41 | #define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
42 | 42 | |
43 | +/* adc helper functions */ | |
44 | + | |
45 | +/* enables mic bias voltage */ | |
46 | +static void sn95031_enable_mic_bias(struct snd_soc_codec *codec) | |
47 | +{ | |
48 | + snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0)); | |
49 | + snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2)); | |
50 | +} | |
51 | + | |
52 | +/* Enable/Disable the ADC depending on the argument */ | |
53 | +static void configure_adc(struct snd_soc_codec *sn95031_codec, int val) | |
54 | +{ | |
55 | + int value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1); | |
56 | + | |
57 | + if (val) { | |
58 | + /* Enable and start the ADC */ | |
59 | + value |= (SN95031_ADC_ENBL | SN95031_ADC_START); | |
60 | + value &= (~SN95031_ADC_NO_LOOP); | |
61 | + } else { | |
62 | + /* Just stop the ADC */ | |
63 | + value &= (~SN95031_ADC_START); | |
64 | + } | |
65 | + snd_soc_write(sn95031_codec, SN95031_ADC1CNTL1, value); | |
66 | +} | |
67 | + | |
43 | 68 | /* |
44 | - * todo: | |
45 | - * capture paths | |
46 | - * jack detection | |
47 | - * PM functions | |
69 | + * finds an empty channel for conversion | |
70 | + * If the ADC is not enabled then start using 0th channel | |
71 | + * itself. Otherwise find an empty channel by looking for a | |
72 | + * channel in which the stopbit is set to 1. returns the index | |
73 | + * of the first free channel if succeeds or an error code. | |
74 | + * | |
75 | + * Context: can sleep | |
76 | + * | |
48 | 77 | */ |
78 | +static int find_free_channel(struct snd_soc_codec *sn95031_codec) | |
79 | +{ | |
80 | + int ret = 0, i, value; | |
49 | 81 | |
82 | + /* check whether ADC is enabled */ | |
83 | + value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1); | |
84 | + | |
85 | + if ((value & SN95031_ADC_ENBL) == 0) | |
86 | + return 0; | |
87 | + | |
88 | + /* ADC is already enabled; Looking for an empty channel */ | |
89 | + for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) { | |
90 | + value = snd_soc_read(sn95031_codec, | |
91 | + SN95031_ADC_CHNL_START_ADDR + i); | |
92 | + if (value & SN95031_STOPBIT_MASK) { | |
93 | + ret = i; | |
94 | + break; | |
95 | + } | |
96 | + } | |
97 | + return (ret > SN95031_ADC_LOOP_MAX) ? (-EINVAL) : ret; | |
98 | +} | |
99 | + | |
100 | +/* Initialize the ADC for reading micbias values. Can sleep. */ | |
101 | +static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec) | |
102 | +{ | |
103 | + int base_addr, chnl_addr; | |
104 | + int value; | |
105 | + static int channel_index; | |
106 | + | |
107 | + /* Index of the first channel in which the stop bit is set */ | |
108 | + channel_index = find_free_channel(sn95031_codec); | |
109 | + if (channel_index < 0) { | |
110 | + pr_err("No free ADC channels"); | |
111 | + return channel_index; | |
112 | + } | |
113 | + | |
114 | + base_addr = SN95031_ADC_CHNL_START_ADDR + channel_index; | |
115 | + | |
116 | + if (!(channel_index == 0 || channel_index == SN95031_ADC_LOOP_MAX)) { | |
117 | + /* Reset stop bit for channels other than 0 and 12 */ | |
118 | + value = snd_soc_read(sn95031_codec, base_addr); | |
119 | + /* Set the stop bit to zero */ | |
120 | + snd_soc_write(sn95031_codec, base_addr, value & 0xEF); | |
121 | + /* Index of the first free channel */ | |
122 | + base_addr++; | |
123 | + channel_index++; | |
124 | + } | |
125 | + | |
126 | + /* Since this is the last channel, set the stop bit | |
127 | + to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ | |
128 | + snd_soc_write(sn95031_codec, base_addr, | |
129 | + SN95031_AUDIO_DETECT_CODE | 0x10); | |
130 | + | |
131 | + chnl_addr = SN95031_ADC_DATA_START_ADDR + 2 * channel_index; | |
132 | + pr_debug("mid_initialize : %x", chnl_addr); | |
133 | + configure_adc(sn95031_codec, 1); | |
134 | + return chnl_addr; | |
135 | +} | |
136 | + | |
137 | + | |
138 | +/* reads the ADC registers and gets the mic bias value in mV. */ | |
139 | +static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec) | |
140 | +{ | |
141 | + u16 adc_adr = sn95031_initialize_adc(codec); | |
142 | + u16 adc_val1, adc_val2; | |
143 | + unsigned int mic_bias; | |
144 | + | |
145 | + sn95031_enable_mic_bias(codec); | |
146 | + | |
147 | + /* Enable the sound card for conversion before reading */ | |
148 | + snd_soc_write(codec, SN95031_ADC1CNTL3, 0x05); | |
149 | + /* Re-toggle the RRDATARD bit */ | |
150 | + snd_soc_write(codec, SN95031_ADC1CNTL3, 0x04); | |
151 | + | |
152 | + /* Read the higher bits of data */ | |
153 | + msleep(1000); | |
154 | + adc_val1 = snd_soc_read(codec, adc_adr); | |
155 | + adc_adr++; | |
156 | + adc_val2 = snd_soc_read(codec, adc_adr); | |
157 | + | |
158 | + /* Adding lower two bits to the higher bits */ | |
159 | + mic_bias = (adc_val1 << 2) + (adc_val2 & 3); | |
160 | + mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000; | |
161 | + pr_debug("mic bias = %dmV\n", mic_bias); | |
162 | + return mic_bias; | |
163 | +} | |
164 | +EXPORT_SYMBOL_GPL(sn95031_get_mic_bias); | |
165 | +/*end - adc helper functions */ | |
166 | + | |
50 | 167 | static inline unsigned int sn95031_read(struct snd_soc_codec *codec, |
51 | 168 | unsigned int reg) |
52 | 169 | { |
... | ... | @@ -663,6 +780,8 @@ |
663 | 780 | |
664 | 781 | static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack) |
665 | 782 | { |
783 | + int micbias = sn95031_get_mic_bias(mfld_jack->codec); | |
784 | + | |
666 | 785 | /* Defaulting to HEADSET for now. |
667 | 786 | * will change after adding soc-jack detection apis */ |
668 | 787 | int jack_type = SND_JACK_HEADSET; |
sound/soc/codecs/sn95031.h
... | ... | @@ -96,7 +96,31 @@ |
96 | 96 | #define SN95031_SSR5 0x384 |
97 | 97 | #define SN95031_SSR6 0x385 |
98 | 98 | |
99 | +/* ADC registers */ | |
100 | + | |
101 | +#define SN95031_ADC1CNTL1 0x1C0 | |
102 | +#define SN95031_ADC_ENBL 0x10 | |
103 | +#define SN95031_ADC_START 0x08 | |
104 | +#define SN95031_ADC1CNTL3 0x1C2 | |
105 | +#define SN95031_ADCTHERM_ENBL 0x04 | |
106 | +#define SN95031_ADCRRDATA_ENBL 0x05 | |
107 | +#define SN95031_STOPBIT_MASK 16 | |
108 | +#define SN95031_ADCTHERM_MASK 4 | |
109 | +#define SN95031_ADC_CHANLS_MAX 15 /* Number of ADC channels */ | |
110 | +#define SN95031_ADC_LOOP_MAX (SN95031_ADC_CHANLS_MAX - 1) | |
111 | +#define SN95031_ADC_NO_LOOP 0x07 | |
99 | 112 | #define SN95031_AUDIO_GPIO_CTRL 0x070 |
113 | + | |
114 | +/* ADC channel code values */ | |
115 | +#define SN95031_AUDIO_DETECT_CODE 0x06 | |
116 | + | |
117 | +/* ADC base addresses */ | |
118 | +#define SN95031_ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ | |
119 | +#define SN95031_ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ | |
120 | +/* multipier to convert to mV */ | |
121 | +#define SN95031_ADC_ONE_LSB_MULTIPLIER 2346 | |
122 | + | |
123 | + | |
100 | 124 | struct mfld_jack_data { |
101 | 125 | int intr_id; |
102 | 126 | int micbias_vol; |