1
2
3
4
5
6
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
28struct sirf_audio_codec {
29 struct clk *clk;
30 struct regmap *regmap;
31 u32 reg_ctrl0, reg_ctrl1;
32};
33
34static const char * const input_mode_mux[] = {"Single-ended",
35 "Differential"};
36
37static const struct soc_enum input_mode_mux_enum =
38 SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux);
39
40static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control =
41 SOC_DAPM_ENUM("Route", input_mode_mux_enum);
42
43static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0);
44static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0);
45static 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
50static 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
57static 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
64static 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
69static 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
74static 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
77static 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
80static 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
83static 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
86static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control =
87 SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0);
88
89static 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
93static 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
107static 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
118static 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
141static 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
164static 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
173static 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
182static 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
187static 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
192static 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
242static 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
282static 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
296static 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
303static 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
325static 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
332static 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
342
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
373static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = {
374 .trigger = sirf_audio_codec_trigger,
375};
376
377static 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
396static 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
426static int sirf_audio_codec_remove(struct snd_soc_codec *codec)
427{
428 pm_runtime_disable(codec->dev);
429 return 0;
430}
431
432static 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
442static const struct of_device_id sirf_audio_codec_of_match[] = {
443 { .compatible = "sirf,prima2-audio-codec" },
444 { .compatible = "sirf,atlas6-audio-codec" },
445 {}
446};
447MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match);
448
449static 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
457static 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
506
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
516err_clk_put:
517 clk_disable_unprepare(sirf_audio_codec->clk);
518 return ret;
519}
520
521static 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
532static 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
545static 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
563static 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
567static 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
577module_platform_driver(sirf_audio_codec_driver);
578
579MODULE_DESCRIPTION("SiRF audio codec driver");
580MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>");
581MODULE_LICENSE("GPL v2");
582