]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - sound/soc/sunxi/sun4i-i2s.c
ASoC: sun4i-codec: Add support for A31 board level audio routing
[mirror_ubuntu-bionic-kernel.git] / sound / soc / sunxi / sun4i-i2s.c
CommitLineData
fa7c0d13
MR
1/*
2 * Copyright (C) 2015 Andrea Venturi
3 * Andrea Venturi <be17068@iperbole.bo.it>
4 *
5 * Copyright (C) 2016 Maxime Ripard
6 * Maxime Ripard <maxime.ripard@free-electrons.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/dmaengine.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18#include <linux/pm_runtime.h>
19#include <linux/regmap.h>
20
21#include <sound/dmaengine_pcm.h>
22#include <sound/pcm_params.h>
23#include <sound/soc.h>
24#include <sound/soc-dai.h>
25
26#define SUN4I_I2S_CTRL_REG 0x00
27#define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8)
28#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo))
29#define SUN4I_I2S_CTRL_MODE_MASK BIT(5)
30#define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5)
31#define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5)
32#define SUN4I_I2S_CTRL_TX_EN BIT(2)
33#define SUN4I_I2S_CTRL_RX_EN BIT(1)
34#define SUN4I_I2S_CTRL_GL_EN BIT(0)
35
36#define SUN4I_I2S_FMT0_REG 0x04
37#define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(7)
38#define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 7)
39#define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 7)
40#define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK BIT(6)
41#define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 6)
42#define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 6)
43#define SUN4I_I2S_FMT0_SR_MASK GENMASK(5, 4)
44#define SUN4I_I2S_FMT0_SR(sr) ((sr) << 4)
45#define SUN4I_I2S_FMT0_WSS_MASK GENMASK(3, 2)
46#define SUN4I_I2S_FMT0_WSS(wss) ((wss) << 2)
47#define SUN4I_I2S_FMT0_FMT_MASK GENMASK(1, 0)
48#define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0)
49#define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0)
50#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0)
51
52#define SUN4I_I2S_FMT1_REG 0x08
53#define SUN4I_I2S_FIFO_TX_REG 0x0c
54#define SUN4I_I2S_FIFO_RX_REG 0x10
55
56#define SUN4I_I2S_FIFO_CTRL_REG 0x14
57#define SUN4I_I2S_FIFO_CTRL_FLUSH_TX BIT(25)
58#define SUN4I_I2S_FIFO_CTRL_FLUSH_RX BIT(24)
59#define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK BIT(2)
60#define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode) ((mode) << 2)
61#define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK GENMASK(1, 0)
62#define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode) (mode)
63
64#define SUN4I_I2S_FIFO_STA_REG 0x18
65
66#define SUN4I_I2S_DMA_INT_CTRL_REG 0x1c
67#define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN BIT(7)
68#define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN BIT(3)
69
70#define SUN4I_I2S_INT_STA_REG 0x20
71
72#define SUN4I_I2S_CLK_DIV_REG 0x24
73#define SUN4I_I2S_CLK_DIV_MCLK_EN BIT(7)
74#define SUN4I_I2S_CLK_DIV_BCLK_MASK GENMASK(6, 4)
75#define SUN4I_I2S_CLK_DIV_BCLK(bclk) ((bclk) << 4)
76#define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0)
77#define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0)
78
79#define SUN4I_I2S_RX_CNT_REG 0x28
80#define SUN4I_I2S_TX_CNT_REG 0x2c
81
82#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30
83#define SUN4I_I2S_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0)
84
85#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34
86#define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2))
87
88#define SUN4I_I2S_RX_CHAN_SEL_REG 0x38
89#define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c
90
91struct sun4i_i2s {
92 struct clk *bus_clk;
93 struct clk *mod_clk;
94 struct regmap *regmap;
95
ae73b34f 96 struct snd_dmaengine_dai_dma_data capture_dma_data;
fa7c0d13
MR
97 struct snd_dmaengine_dai_dma_data playback_dma_data;
98};
99
100struct sun4i_i2s_clk_div {
101 u8 div;
102 u8 val;
103};
104
105static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = {
106 { .div = 2, .val = 0 },
107 { .div = 4, .val = 1 },
108 { .div = 6, .val = 2 },
109 { .div = 8, .val = 3 },
110 { .div = 12, .val = 4 },
111 { .div = 16, .val = 5 },
112};
113
114static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = {
115 { .div = 1, .val = 0 },
116 { .div = 2, .val = 1 },
117 { .div = 4, .val = 2 },
118 { .div = 6, .val = 3 },
119 { .div = 8, .val = 4 },
120 { .div = 12, .val = 5 },
121 { .div = 16, .val = 6 },
122 { .div = 24, .val = 7 },
123};
124
125static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s,
126 unsigned int oversample_rate,
127 unsigned int word_size)
128{
129 int div = oversample_rate / word_size / 2;
130 int i;
131
132 for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) {
133 const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i];
134
135 if (bdiv->div == div)
136 return bdiv->val;
137 }
138
139 return -EINVAL;
140}
141
142static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s,
143 unsigned int oversample_rate,
144 unsigned int module_rate,
145 unsigned int sampling_rate)
146{
147 int div = module_rate / sampling_rate / oversample_rate;
148 int i;
149
150 for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) {
151 const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i];
152
153 if (mdiv->div == div)
154 return mdiv->val;
155 }
156
157 return -EINVAL;
158}
159
160static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 };
161
162static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s,
163 unsigned int rate,
164 unsigned int word_size)
165{
166 unsigned int clk_rate;
167 int bclk_div, mclk_div;
168 int ret, i;
169
170 switch (rate) {
171 case 176400:
172 case 88200:
173 case 44100:
174 case 22050:
175 case 11025:
176 clk_rate = 22579200;
177 break;
178
179 case 192000:
180 case 128000:
181 case 96000:
182 case 64000:
183 case 48000:
184 case 32000:
185 case 24000:
186 case 16000:
187 case 12000:
188 case 8000:
189 clk_rate = 24576000;
190 break;
191
192 default:
193 return -EINVAL;
194 }
195
196 ret = clk_set_rate(i2s->mod_clk, clk_rate);
197 if (ret)
198 return ret;
199
200 /* Always favor the highest oversampling rate */
201 for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) {
202 unsigned int oversample_rate = sun4i_i2s_oversample_rates[i];
203
204 bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate,
205 word_size);
206 mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate,
207 clk_rate,
208 rate);
209
210 if ((bclk_div >= 0) && (mclk_div >= 0))
211 break;
212 }
213
214 if ((bclk_div < 0) || (mclk_div < 0))
215 return -EINVAL;
216
217 regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG,
218 SUN4I_I2S_CLK_DIV_BCLK(bclk_div) |
219 SUN4I_I2S_CLK_DIV_MCLK(mclk_div) |
220 SUN4I_I2S_CLK_DIV_MCLK_EN);
221
222 return 0;
223}
224
225static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream,
226 struct snd_pcm_hw_params *params,
227 struct snd_soc_dai *dai)
228{
229 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
230 int sr, wss;
231 u32 width;
232
233 if (params_channels(params) != 2)
234 return -EINVAL;
235
236 switch (params_physical_width(params)) {
237 case 16:
238 width = DMA_SLAVE_BUSWIDTH_2_BYTES;
239 break;
240 default:
241 return -EINVAL;
242 }
243 i2s->playback_dma_data.addr_width = width;
244
245 switch (params_width(params)) {
246 case 16:
247 sr = 0;
248 wss = 0;
249 break;
250
251 default:
252 return -EINVAL;
253 }
254
255 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
256 SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK,
257 SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr));
258
259 return sun4i_i2s_set_clk_rate(i2s, params_rate(params),
260 params_width(params));
261}
262
263static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
264{
265 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
266 u32 val;
267
268 /* DAI Mode */
269 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
270 case SND_SOC_DAIFMT_I2S:
271 val = SUN4I_I2S_FMT0_FMT_I2S;
272 break;
273 case SND_SOC_DAIFMT_LEFT_J:
274 val = SUN4I_I2S_FMT0_FMT_LEFT_J;
275 break;
276 case SND_SOC_DAIFMT_RIGHT_J:
277 val = SUN4I_I2S_FMT0_FMT_RIGHT_J;
278 break;
279 default:
280 return -EINVAL;
281 }
282
283 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
284 SUN4I_I2S_FMT0_FMT_MASK,
285 val);
286
287 /* DAI clock polarity */
288 switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
289 case SND_SOC_DAIFMT_IB_IF:
290 /* Invert both clocks */
291 val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
292 SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED;
293 break;
294 case SND_SOC_DAIFMT_IB_NF:
295 /* Invert bit clock */
296 val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED |
297 SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
298 break;
299 case SND_SOC_DAIFMT_NB_IF:
300 /* Invert frame clock */
301 val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED |
302 SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL;
303 break;
304 case SND_SOC_DAIFMT_NB_NF:
305 /* Nothing to do for both normal cases */
306 val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL |
307 SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL;
308 break;
309 default:
310 return -EINVAL;
311 }
312
313 regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG,
314 SUN4I_I2S_FMT0_BCLK_POLARITY_MASK |
315 SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK,
316 val);
317
318 /* DAI clock master masks */
319 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
320 case SND_SOC_DAIFMT_CBS_CFS:
321 /* BCLK and LRCLK master */
322 val = SUN4I_I2S_CTRL_MODE_MASTER;
323 break;
324 case SND_SOC_DAIFMT_CBM_CFM:
325 /* BCLK and LRCLK slave */
326 val = SUN4I_I2S_CTRL_MODE_SLAVE;
327 break;
328 default:
329 return -EINVAL;
330 }
331
332 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
333 SUN4I_I2S_CTRL_MODE_MASK,
334 val);
335
336 /* Set significant bits in our FIFOs */
337 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
338 SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK |
339 SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK,
340 SUN4I_I2S_FIFO_CTRL_TX_MODE(1) |
341 SUN4I_I2S_FIFO_CTRL_RX_MODE(1));
342 return 0;
343}
344
ae73b34f
MR
345static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s)
346{
347 /* Flush RX FIFO */
348 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
349 SUN4I_I2S_FIFO_CTRL_FLUSH_RX,
350 SUN4I_I2S_FIFO_CTRL_FLUSH_RX);
351
352 /* Clear RX counter */
353 regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0);
354
355 /* Enable RX Block */
356 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
357 SUN4I_I2S_CTRL_RX_EN,
358 SUN4I_I2S_CTRL_RX_EN);
359
360 /* Enable RX DRQ */
361 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
362 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
363 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN);
364}
365
fa7c0d13
MR
366static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s)
367{
368 /* Flush TX FIFO */
369 regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG,
370 SUN4I_I2S_FIFO_CTRL_FLUSH_TX,
371 SUN4I_I2S_FIFO_CTRL_FLUSH_TX);
372
373 /* Clear TX counter */
374 regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0);
375
376 /* Enable TX Block */
377 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
378 SUN4I_I2S_CTRL_TX_EN,
379 SUN4I_I2S_CTRL_TX_EN);
380
381 /* Enable TX DRQ */
382 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
383 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,
384 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN);
385}
386
ae73b34f
MR
387static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s)
388{
389 /* Disable RX Block */
390 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
391 SUN4I_I2S_CTRL_RX_EN,
392 0);
393
394 /* Disable RX DRQ */
395 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
396 SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN,
397 0);
398}
fa7c0d13
MR
399
400static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s)
401{
402 /* Disable TX Block */
403 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
404 SUN4I_I2S_CTRL_TX_EN,
405 0);
406
407 /* Disable TX DRQ */
408 regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG,
409 SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN,
410 0);
411}
412
413static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
414 struct snd_soc_dai *dai)
415{
416 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
417
418 switch (cmd) {
419 case SNDRV_PCM_TRIGGER_START:
420 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
421 case SNDRV_PCM_TRIGGER_RESUME:
422 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
423 sun4i_i2s_start_playback(i2s);
424 else
ae73b34f 425 sun4i_i2s_start_capture(i2s);
fa7c0d13
MR
426 break;
427
428 case SNDRV_PCM_TRIGGER_STOP:
429 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
430 case SNDRV_PCM_TRIGGER_SUSPEND:
431 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
432 sun4i_i2s_stop_playback(i2s);
433 else
ae73b34f 434 sun4i_i2s_stop_capture(i2s);
fa7c0d13
MR
435 break;
436
437 default:
438 return -EINVAL;
439 }
440
441 return 0;
442}
443
444static int sun4i_i2s_startup(struct snd_pcm_substream *substream,
445 struct snd_soc_dai *dai)
446{
447 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
448
449 /* Enable the whole hardware block */
450 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG,
451 SUN4I_I2S_CTRL_GL_EN);
452
453 /* Enable the first output line */
454 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
455 SUN4I_I2S_CTRL_SDO_EN_MASK,
456 SUN4I_I2S_CTRL_SDO_EN(0));
457
458 /* Enable the first two channels */
459 regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG,
460 SUN4I_I2S_TX_CHAN_SEL(2));
461
462 /* Map them to the two first samples coming in */
463 regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG,
464 SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1));
465
466 return clk_prepare_enable(i2s->mod_clk);
467}
468
469static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream,
470 struct snd_soc_dai *dai)
471{
472 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
473
474 clk_disable_unprepare(i2s->mod_clk);
475
476 /* Disable our output lines */
477 regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG,
478 SUN4I_I2S_CTRL_SDO_EN_MASK, 0);
479
480 /* Disable the whole hardware block */
481 regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0);
482}
483
484static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = {
485 .hw_params = sun4i_i2s_hw_params,
486 .set_fmt = sun4i_i2s_set_fmt,
487 .shutdown = sun4i_i2s_shutdown,
488 .startup = sun4i_i2s_startup,
489 .trigger = sun4i_i2s_trigger,
490};
491
492static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai)
493{
494 struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai);
495
ae73b34f
MR
496 snd_soc_dai_init_dma_data(dai,
497 &i2s->playback_dma_data,
498 &i2s->capture_dma_data);
fa7c0d13
MR
499
500 snd_soc_dai_set_drvdata(dai, i2s);
501
502 return 0;
503}
504
505static struct snd_soc_dai_driver sun4i_i2s_dai = {
506 .probe = sun4i_i2s_dai_probe,
ae73b34f
MR
507 .capture = {
508 .stream_name = "Capture",
509 .channels_min = 2,
510 .channels_max = 2,
511 .rates = SNDRV_PCM_RATE_8000_192000,
512 .formats = SNDRV_PCM_FMTBIT_S16_LE,
513 },
fa7c0d13
MR
514 .playback = {
515 .stream_name = "Playback",
516 .channels_min = 2,
517 .channels_max = 2,
518 .rates = SNDRV_PCM_RATE_8000_192000,
519 .formats = SNDRV_PCM_FMTBIT_S16_LE,
520 },
521 .ops = &sun4i_i2s_dai_ops,
522 .symmetric_rates = 1,
523};
524
525static const struct snd_soc_component_driver sun4i_i2s_component = {
526 .name = "sun4i-dai",
527};
528
529static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg)
530{
531 switch (reg) {
532 case SUN4I_I2S_FIFO_TX_REG:
533 return false;
534
535 default:
536 return true;
537 }
538}
539
540static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg)
541{
542 switch (reg) {
543 case SUN4I_I2S_FIFO_RX_REG:
544 case SUN4I_I2S_FIFO_STA_REG:
545 return false;
546
547 default:
548 return true;
549 }
550}
551
552static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg)
553{
554 switch (reg) {
555 case SUN4I_I2S_FIFO_RX_REG:
556 case SUN4I_I2S_INT_STA_REG:
557 case SUN4I_I2S_RX_CNT_REG:
558 case SUN4I_I2S_TX_CNT_REG:
559 return true;
560
561 default:
562 return false;
563 }
564}
565
566static const struct reg_default sun4i_i2s_reg_defaults[] = {
567 { SUN4I_I2S_CTRL_REG, 0x00000000 },
568 { SUN4I_I2S_FMT0_REG, 0x0000000c },
569 { SUN4I_I2S_FMT1_REG, 0x00004020 },
570 { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 },
571 { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 },
572 { SUN4I_I2S_CLK_DIV_REG, 0x00000000 },
573 { SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 },
574 { SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 },
575 { SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 },
576 { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 },
577};
578
579static const struct regmap_config sun4i_i2s_regmap_config = {
580 .reg_bits = 32,
581 .reg_stride = 4,
582 .val_bits = 32,
583 .max_register = SUN4I_I2S_RX_CHAN_MAP_REG,
584
585 .cache_type = REGCACHE_FLAT,
586 .reg_defaults = sun4i_i2s_reg_defaults,
587 .num_reg_defaults = ARRAY_SIZE(sun4i_i2s_reg_defaults),
588 .writeable_reg = sun4i_i2s_wr_reg,
589 .readable_reg = sun4i_i2s_rd_reg,
590 .volatile_reg = sun4i_i2s_volatile_reg,
591};
592
593static int sun4i_i2s_runtime_resume(struct device *dev)
594{
595 struct sun4i_i2s *i2s = dev_get_drvdata(dev);
596 int ret;
597
598 ret = clk_prepare_enable(i2s->bus_clk);
599 if (ret) {
600 dev_err(dev, "Failed to enable bus clock\n");
601 return ret;
602 }
603
604 regcache_cache_only(i2s->regmap, false);
605 regcache_mark_dirty(i2s->regmap);
606
607 ret = regcache_sync(i2s->regmap);
608 if (ret) {
609 dev_err(dev, "Failed to sync regmap cache\n");
610 goto err_disable_clk;
611 }
612
613 return 0;
614
615err_disable_clk:
616 clk_disable_unprepare(i2s->bus_clk);
617 return ret;
618}
619
620static int sun4i_i2s_runtime_suspend(struct device *dev)
621{
622 struct sun4i_i2s *i2s = dev_get_drvdata(dev);
623
624 regcache_cache_only(i2s->regmap, true);
625
626 clk_disable_unprepare(i2s->bus_clk);
627
628 return 0;
629}
630
631static int sun4i_i2s_probe(struct platform_device *pdev)
632{
633 struct sun4i_i2s *i2s;
634 struct resource *res;
635 void __iomem *regs;
636 int irq, ret;
637
638 i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
639 if (!i2s)
640 return -ENOMEM;
641 platform_set_drvdata(pdev, i2s);
642
643 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
644 regs = devm_ioremap_resource(&pdev->dev, res);
62ee4ecb 645 if (IS_ERR(regs))
fa7c0d13 646 return PTR_ERR(regs);
fa7c0d13
MR
647
648 irq = platform_get_irq(pdev, 0);
649 if (irq < 0) {
650 dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
651 return irq;
652 }
653
654 i2s->bus_clk = devm_clk_get(&pdev->dev, "apb");
655 if (IS_ERR(i2s->bus_clk)) {
656 dev_err(&pdev->dev, "Can't get our bus clock\n");
657 return PTR_ERR(i2s->bus_clk);
658 }
659
660 i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs,
661 &sun4i_i2s_regmap_config);
662 if (IS_ERR(i2s->regmap)) {
663 dev_err(&pdev->dev, "Regmap initialisation failed\n");
664 return PTR_ERR(i2s->regmap);
dcf7d199 665 }
fa7c0d13
MR
666
667 i2s->mod_clk = devm_clk_get(&pdev->dev, "mod");
668 if (IS_ERR(i2s->mod_clk)) {
669 dev_err(&pdev->dev, "Can't get our mod clock\n");
670 return PTR_ERR(i2s->mod_clk);
671 }
672
673 i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG;
674 i2s->playback_dma_data.maxburst = 4;
675
ae73b34f
MR
676 i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG;
677 i2s->capture_dma_data.maxburst = 4;
678
fa7c0d13
MR
679 pm_runtime_enable(&pdev->dev);
680 if (!pm_runtime_enabled(&pdev->dev)) {
681 ret = sun4i_i2s_runtime_resume(&pdev->dev);
682 if (ret)
683 goto err_pm_disable;
684 }
685
686 ret = devm_snd_soc_register_component(&pdev->dev,
687 &sun4i_i2s_component,
688 &sun4i_i2s_dai, 1);
689 if (ret) {
690 dev_err(&pdev->dev, "Could not register DAI\n");
691 goto err_suspend;
692 }
693
694 ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
695 if (ret) {
696 dev_err(&pdev->dev, "Could not register PCM\n");
697 goto err_suspend;
698 }
699
700 return 0;
701
702err_suspend:
703 if (!pm_runtime_status_suspended(&pdev->dev))
704 sun4i_i2s_runtime_suspend(&pdev->dev);
705err_pm_disable:
706 pm_runtime_disable(&pdev->dev);
707
708 return ret;
709}
710
711static int sun4i_i2s_remove(struct platform_device *pdev)
712{
713 snd_dmaengine_pcm_unregister(&pdev->dev);
714
715 pm_runtime_disable(&pdev->dev);
716 if (!pm_runtime_status_suspended(&pdev->dev))
717 sun4i_i2s_runtime_suspend(&pdev->dev);
718
719 return 0;
720}
721
722static const struct of_device_id sun4i_i2s_match[] = {
723 { .compatible = "allwinner,sun4i-a10-i2s", },
724 {}
725};
726MODULE_DEVICE_TABLE(of, sun4i_i2s_match);
727
728static const struct dev_pm_ops sun4i_i2s_pm_ops = {
729 .runtime_resume = sun4i_i2s_runtime_resume,
730 .runtime_suspend = sun4i_i2s_runtime_suspend,
731};
732
733static struct platform_driver sun4i_i2s_driver = {
734 .probe = sun4i_i2s_probe,
735 .remove = sun4i_i2s_remove,
736 .driver = {
737 .name = "sun4i-i2s",
738 .of_match_table = sun4i_i2s_match,
739 .pm = &sun4i_i2s_pm_ops,
740 },
741};
742module_platform_driver(sun4i_i2s_driver);
743
744MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>");
745MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
746MODULE_DESCRIPTION("Allwinner A10 I2S driver");
747MODULE_LICENSE("GPL");