~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/codecs/sirf-audio-codec.c

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * SiRF audio codec driver
  3  *
  4  * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
  5  *
  6  * Licensed under GPLv2 or later.
  7  */
  8 
  9 #include <linux/module.h>
 10 #include <linux/platform_device.h>
 11 #include <linux/pm_runtime.h>
 12 #include <linux/of.h>
 13 #include <linux/of_device.h>
 14 #include <linux/clk.h>
 15 #include <linux/delay.h>
 16 #include <linux/io.h>
 17 #include <linux/regmap.h>
 18 #include <sound/core.h>
 19 #include <sound/pcm.h>
 20 #include <sound/pcm_params.h>
 21 #include <sound/initval.h>
 22 #include <sound/tlv.h>
 23 #include <sound/soc.h>
 24 #include <sound/dmaengine_pcm.h>
 25 
 26 #include "sirf-audio-codec.h"
 27 
 28 struct sirf_audio_codec {
 29         struct clk *clk;
 30         struct regmap *regmap;
 31         u32 reg_ctrl0, reg_ctrl1;
 32 };
 33 
 34 static const char * const input_mode_mux[] = {"Single-ended",
 35         "Differential"};
 36 
 37 static const struct soc_enum input_mode_mux_enum =
 38         SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
 39 
 40 static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
 41         SOC_DAPM_ENUM("Route", input_mode_mux_enum);
 42 
 43 static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
 44 static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
 45 static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6,
 46         0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0),
 47         0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0),
 48 );
 49 
 50 static struct snd_kcontrol_new volume_controls_atlas6[] = {
 51         SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
 52                         0x7F, 0, playback_vol_tlv),
 53         SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10,
 54                         0x3F, 0, capture_vol_tlv_atlas6),
 55 };
 56 
 57 static struct snd_kcontrol_new volume_controls_prima2[] = {
 58         SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14,
 59                         0x7F, 0, playback_vol_tlv),
 60         SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10,
 61                         0x1F, 0, capture_vol_tlv_prima2),
 62 };
 63 
 64 static struct snd_kcontrol_new left_input_path_controls[] = {
 65         SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0),
 66         SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0),
 67 };
 68 
 69 static struct snd_kcontrol_new right_input_path_controls[] = {
 70         SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0),
 71         SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0),
 72 };
 73 
 74 static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control =
 75         SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0);
 76 
 77 static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control =
 78         SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0);
 79 
 80 static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control =
 81         SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0);
 82 
 83 static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control =
 84         SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0);
 85 
 86 static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
 87         SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
 88 
 89 static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control =
 90         SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0);
 91 
 92 /* After enable adc, Delay 200ms to avoid pop noise */
 93 static int adc_enable_delay_event(struct snd_soc_dapm_widget *w,
 94                 struct snd_kcontrol *kcontrol, int event)
 95 {
 96         switch (event) {
 97         case SND_SOC_DAPM_POST_PMU:
 98                 msleep(200);
 99                 break;
100         default:
101                 break;
102         }
103 
104         return 0;
105 }
106 
107 static void enable_and_reset_codec(struct regmap *regmap,
108                 u32 codec_enable_bits, u32 codec_reset_bits)
109 {
110         regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
111                         codec_enable_bits | codec_reset_bits,
112                         codec_enable_bits);
113         msleep(20);
114         regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1,
115                         codec_reset_bits, codec_reset_bits);
116 }
117 
118 static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
119                 struct snd_kcontrol *kcontrol, int event)
120 {
121 #define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
122 #define ATLAS6_CODEC_RESET_BITS (1 << 28)
123         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
124         struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
125         switch (event) {
126         case SND_SOC_DAPM_PRE_PMU:
127                 enable_and_reset_codec(sirf_audio_codec->regmap,
128                         ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS);
129                 break;
130         case SND_SOC_DAPM_POST_PMD:
131                 regmap_update_bits(sirf_audio_codec->regmap,
132                         AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, 0);
133                 break;
134         default:
135                 break;
136         }
137 
138         return 0;
139 }
140 
141 static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
142                 struct snd_kcontrol *kcontrol, int event)
143 {
144 #define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
145 #define PRIMA2_CODEC_RESET_BITS (1 << 26)
146         struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
147         struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
148         switch (event) {
149         case SND_SOC_DAPM_POST_PMU:
150                 enable_and_reset_codec(sirf_audio_codec->regmap,
151                         PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS);
152                 break;
153         case SND_SOC_DAPM_POST_PMD:
154                 regmap_update_bits(sirf_audio_codec->regmap,
155                         AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, 0);
156                 break;
157         default:
158                 break;
159         }
160 
161         return 0;
162 }
163 
164 static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = {
165         SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
166                         25, 0, NULL, 0),
167         SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
168                         26, 0, NULL, 0),
169         SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
170                         27, 0, NULL, 0),
171 };
172 
173 static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = {
174         SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1,
175                         23, 0, NULL, 0),
176         SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1,
177                         24, 0, NULL, 0),
178         SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1,
179                         25, 0, NULL, 0),
180 };
181 
182 static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget =
183         SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
184                         atlas6_codec_enable_and_reset_event,
185                         SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
186 
187 static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget =
188         SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0,
189                         prima2_codec_enable_and_reset_event,
190                         SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD);
191 
192 static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = {
193         SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0),
194         SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0),
195         SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0,
196                         &left_dac_to_hp_left_amp_switch_control),
197         SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0,
198                         &left_dac_to_hp_right_amp_switch_control),
199         SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0,
200                         &right_dac_to_hp_left_amp_switch_control),
201         SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0,
202                         &right_dac_to_hp_right_amp_switch_control),
203         SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
204                         NULL, 0),
205         SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0,
206                         NULL, 0),
207 
208         SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0,
209                         &left_dac_to_speaker_lineout_switch_control),
210         SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0,
211                         &right_dac_to_speaker_lineout_switch_control),
212         SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0,
213                         NULL, 0),
214 
215         SND_SOC_DAPM_OUTPUT("HPOUTL"),
216         SND_SOC_DAPM_OUTPUT("HPOUTR"),
217         SND_SOC_DAPM_OUTPUT("SPKOUT"),
218 
219         SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0,
220                         adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
221         SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0,
222                         adc_enable_delay_event, SND_SOC_DAPM_POST_PMU),
223         SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0,
224                 &left_input_path_controls[0],
225                 ARRAY_SIZE(left_input_path_controls)),
226         SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0,
227                 &right_input_path_controls[0],
228                 ARRAY_SIZE(right_input_path_controls)),
229 
230         SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0,
231                         &sirf_audio_codec_input_mode_control),
232         SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0),
233         SND_SOC_DAPM_INPUT("MICIN1"),
234         SND_SOC_DAPM_INPUT("MICIN2"),
235         SND_SOC_DAPM_INPUT("LINEIN1"),
236         SND_SOC_DAPM_INPUT("LINEIN2"),
237 
238         SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0,
239                         30, 0, NULL, 0),
240 };
241 
242 static const struct snd_soc_dapm_route sirf_audio_codec_map[] = {
243         {"SPKOUT", NULL, "Speaker Driver"},
244         {"Speaker Driver", NULL, "Speaker amp driver"},
245         {"Speaker amp driver", NULL, "Left dac to speaker lineout"},
246         {"Speaker amp driver", NULL, "Right dac to speaker lineout"},
247         {"Left dac to speaker lineout", "Switch", "DAC left"},
248         {"Right dac to speaker lineout", "Switch", "DAC right"},
249         {"HPOUTL", NULL, "HP Left Driver"},
250         {"HPOUTR", NULL, "HP Right Driver"},
251         {"HP Left Driver", NULL, "HP amp left driver"},
252         {"HP Right Driver", NULL, "HP amp right driver"},
253         {"HP amp left driver", NULL, "Right dac to hp left amp"},
254         {"HP amp right driver", NULL , "Right dac to hp right amp"},
255         {"HP amp left driver", NULL, "Left dac to hp left amp"},
256         {"HP amp right driver", NULL , "Right dac to hp right amp"},
257         {"Right dac to hp left amp", "Switch", "DAC left"},
258         {"Right dac to hp right amp", "Switch", "DAC right"},
259         {"Left dac to hp left amp", "Switch", "DAC left"},
260         {"Left dac to hp right amp", "Switch", "DAC right"},
261         {"DAC left", NULL, "codecclk"},
262         {"DAC right", NULL, "codecclk"},
263         {"DAC left", NULL, "Playback"},
264         {"DAC right", NULL, "Playback"},
265         {"DAC left", NULL, "HSL Phase Opposite"},
266         {"DAC right", NULL, "HSL Phase Opposite"},
267 
268         {"Capture", NULL, "ADC left"},
269         {"Capture", NULL, "ADC right"},
270         {"ADC left", NULL, "codecclk"},
271         {"ADC right", NULL, "codecclk"},
272         {"ADC left", NULL, "Left PGA mixer"},
273         {"ADC right", NULL, "Right PGA mixer"},
274         {"Left PGA mixer", "Line Left Switch", "LINEIN2"},
275         {"Right PGA mixer", "Line Right Switch", "LINEIN1"},
276         {"Left PGA mixer", "Mic Left Switch", "MICIN2"},
277         {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"},
278         {"Mic input mode mux", "Single-ended", "MICIN1"},
279         {"Mic input mode mux", "Differential", "MICIN1"},
280 };
281 
282 static void sirf_audio_codec_tx_enable(struct sirf_audio_codec *sirf_audio_codec)
283 {
284         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
285                 AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
286         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
287                 AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
288         regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0);
289         regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
290         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP,
291                 AUDIO_FIFO_START, AUDIO_FIFO_START);
292         regmap_update_bits(sirf_audio_codec->regmap,
293                 AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, IC_TX_ENABLE);
294 }
295 
296 static void sirf_audio_codec_tx_disable(struct sirf_audio_codec *sirf_audio_codec)
297 {
298         regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0);
299         regmap_update_bits(sirf_audio_codec->regmap,
300                 AUDIO_PORT_IC_CODEC_TX_CTRL, IC_TX_ENABLE, ~IC_TX_ENABLE);
301 }
302 
303 static void sirf_audio_codec_rx_enable(struct sirf_audio_codec *sirf_audio_codec,
304         int channels)
305 {
306         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
307                 AUDIO_FIFO_RESET, AUDIO_FIFO_RESET);
308         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
309                 AUDIO_FIFO_RESET, ~AUDIO_FIFO_RESET);
310         regmap_write(sirf_audio_codec->regmap,
311                 AUDIO_PORT_IC_RXFIFO_INT_MSK, 0);
312         regmap_write(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0);
313         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_PORT_IC_RXFIFO_OP,
314                 AUDIO_FIFO_START, AUDIO_FIFO_START);
315         if (channels == 1)
316                 regmap_update_bits(sirf_audio_codec->regmap,
317                         AUDIO_PORT_IC_CODEC_RX_CTRL,
318                         IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO);
319         else
320                 regmap_update_bits(sirf_audio_codec->regmap,
321                         AUDIO_PORT_IC_CODEC_RX_CTRL,
322                         IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO);
323 }
324 
325 static void sirf_audio_codec_rx_disable(struct sirf_audio_codec *sirf_audio_codec)
326 {
327         regmap_update_bits(sirf_audio_codec->regmap,
328                         AUDIO_PORT_IC_CODEC_RX_CTRL,
329                         IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO);
330 }
331 
332 static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream,
333                 int cmd,
334                 struct snd_soc_dai *dai)
335 {
336         struct snd_soc_codec *codec = dai->codec;
337         struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
338         int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
339 
340         /*
341          * This is a workaround, When stop playback,
342          * need disable HP amp, avoid the current noise.
343          */
344         switch (cmd) {
345         case SNDRV_PCM_TRIGGER_STOP:
346         case SNDRV_PCM_TRIGGER_SUSPEND:
347         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
348                 if (playback) {
349                         snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
350                                 IC_HSLEN | IC_HSREN, 0);
351                         sirf_audio_codec_tx_disable(sirf_audio_codec);
352                 } else
353                         sirf_audio_codec_rx_disable(sirf_audio_codec);
354                 break;
355         case SNDRV_PCM_TRIGGER_START:
356         case SNDRV_PCM_TRIGGER_RESUME:
357         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
358                 if (playback) {
359                         sirf_audio_codec_tx_enable(sirf_audio_codec);
360                         snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0,
361                                 IC_HSLEN | IC_HSREN, IC_HSLEN | IC_HSREN);
362                 } else
363                         sirf_audio_codec_rx_enable(sirf_audio_codec,
364                                 substream->runtime->channels);
365                 break;
366         default:
367                 return -EINVAL;
368         }
369 
370         return 0;
371 }
372 
373 static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
374         .trigger = sirf_audio_codec_trigger,
375 };
376 
377 static struct snd_soc_dai_driver sirf_audio_codec_dai = {
378         .name = "sirf-audio-codec",
379         .playback = {
380                 .stream_name = "Playback",
381                 .channels_min = 2,
382                 .channels_max = 2,
383                 .rates = SNDRV_PCM_RATE_48000,
384                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
385         },
386         .capture = {
387                 .stream_name = "Capture",
388                 .channels_min = 1,
389                 .channels_max = 2,
390                 .rates = SNDRV_PCM_RATE_48000,
391                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
392         },
393         .ops = &sirf_audio_codec_dai_ops,
394 };
395 
396 static int sirf_audio_codec_probe(struct snd_soc_codec *codec)
397 {
398         struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
399 
400         pm_runtime_enable(codec->dev);
401 
402         if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) {
403                 snd_soc_dapm_new_controls(dapm,
404                         prima2_output_driver_dapm_widgets,
405                         ARRAY_SIZE(prima2_output_driver_dapm_widgets));
406                 snd_soc_dapm_new_controls(dapm,
407                         &prima2_codec_clock_dapm_widget, 1);
408                 return snd_soc_add_codec_controls(codec,
409                         volume_controls_prima2,
410                         ARRAY_SIZE(volume_controls_prima2));
411         }
412         if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) {
413                 snd_soc_dapm_new_controls(dapm,
414                         atlas6_output_driver_dapm_widgets,
415                         ARRAY_SIZE(atlas6_output_driver_dapm_widgets));
416                 snd_soc_dapm_new_controls(dapm,
417                         &atlas6_codec_clock_dapm_widget, 1);
418                 return snd_soc_add_codec_controls(codec,
419                         volume_controls_atlas6,
420                         ARRAY_SIZE(volume_controls_atlas6));
421         }
422 
423         return -EINVAL;
424 }
425 
426 static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
427 {
428         pm_runtime_disable(codec->dev);
429         return 0;
430 }
431 
432 static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = {
433         .probe = sirf_audio_codec_probe,
434         .remove = sirf_audio_codec_remove,
435         .dapm_widgets = sirf_audio_codec_dapm_widgets,
436         .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets),
437         .dapm_routes = sirf_audio_codec_map,
438         .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map),
439         .idle_bias_off = true,
440 };
441 
442 static const struct of_device_id sirf_audio_codec_of_match[] = {
443         { .compatible = "sirf,prima2-audio-codec" },
444         { .compatible = "sirf,atlas6-audio-codec" },
445         {}
446 };
447 MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
448 
449 static const struct regmap_config sirf_audio_codec_regmap_config = {
450         .reg_bits = 32,
451         .reg_stride = 4,
452         .val_bits = 32,
453         .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK,
454         .cache_type = REGCACHE_NONE,
455 };
456 
457 static int sirf_audio_codec_driver_probe(struct platform_device *pdev)
458 {
459         int ret;
460         struct sirf_audio_codec *sirf_audio_codec;
461         void __iomem *base;
462         struct resource *mem_res;
463         const struct of_device_id *match;
464 
465         match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node);
466 
467         sirf_audio_codec = devm_kzalloc(&pdev->dev,
468                 sizeof(struct sirf_audio_codec), GFP_KERNEL);
469         if (!sirf_audio_codec)
470                 return -ENOMEM;
471 
472         platform_set_drvdata(pdev, sirf_audio_codec);
473 
474         mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
475         base = devm_ioremap_resource(&pdev->dev, mem_res);
476         if (IS_ERR(base))
477                 return PTR_ERR(base);
478 
479         sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base,
480                                             &sirf_audio_codec_regmap_config);
481         if (IS_ERR(sirf_audio_codec->regmap))
482                 return PTR_ERR(sirf_audio_codec->regmap);
483 
484         sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL);
485         if (IS_ERR(sirf_audio_codec->clk)) {
486                 dev_err(&pdev->dev, "Get clock failed.\n");
487                 return PTR_ERR(sirf_audio_codec->clk);
488         }
489 
490         ret = clk_prepare_enable(sirf_audio_codec->clk);
491         if (ret) {
492                 dev_err(&pdev->dev, "Enable clock failed.\n");
493                 return ret;
494         }
495 
496         ret = snd_soc_register_codec(&(pdev->dev),
497                         &soc_codec_device_sirf_audio_codec,
498                         &sirf_audio_codec_dai, 1);
499         if (ret) {
500                 dev_err(&pdev->dev, "Register Audio Codec dai failed.\n");
501                 goto err_clk_put;
502         }
503 
504         /*
505          * Always open charge pump, if not, when the charge pump closed the
506          * adc will not stable
507          */
508         regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
509                 IC_CPFREQ, IC_CPFREQ);
510 
511         if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec"))
512                 regmap_update_bits(sirf_audio_codec->regmap,
513                                 AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN);
514         return 0;
515 
516 err_clk_put:
517         clk_disable_unprepare(sirf_audio_codec->clk);
518         return ret;
519 }
520 
521 static int sirf_audio_codec_driver_remove(struct platform_device *pdev)
522 {
523         struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev);
524 
525         clk_disable_unprepare(sirf_audio_codec->clk);
526         snd_soc_unregister_codec(&(pdev->dev));
527 
528         return 0;
529 }
530 
531 #ifdef CONFIG_PM_SLEEP
532 static int sirf_audio_codec_suspend(struct device *dev)
533 {
534         struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
535 
536         regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
537                 &sirf_audio_codec->reg_ctrl0);
538         regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
539                 &sirf_audio_codec->reg_ctrl1);
540         clk_disable_unprepare(sirf_audio_codec->clk);
541 
542         return 0;
543 }
544 
545 static int sirf_audio_codec_resume(struct device *dev)
546 {
547         struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev);
548         int ret;
549 
550         ret = clk_prepare_enable(sirf_audio_codec->clk);
551         if (ret)
552                 return ret;
553 
554         regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0,
555                 sirf_audio_codec->reg_ctrl0);
556         regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1,
557                 sirf_audio_codec->reg_ctrl1);
558 
559         return 0;
560 }
561 #endif
562 
563 static const struct dev_pm_ops sirf_audio_codec_pm_ops = {
564         SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume)
565 };
566 
567 static struct platform_driver sirf_audio_codec_driver = {
568         .driver = {
569                 .name = "sirf-audio-codec",
570                 .of_match_table = sirf_audio_codec_of_match,
571                 .pm = &sirf_audio_codec_pm_ops,
572         },
573         .probe = sirf_audio_codec_driver_probe,
574         .remove = sirf_audio_codec_driver_remove,
575 };
576 
577 module_platform_driver(sirf_audio_codec_driver);
578 
579 MODULE_DESCRIPTION("SiRF audio codec driver");
580 MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
581 MODULE_LICENSE("GPL v2");
582 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp