1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright (C) 2015 Andrea Venturi |
4 | * Andrea Venturi <be17068@iperbole.bo.it> |
5 | * |
6 | * Copyright (C) 2016 Maxime Ripard |
7 | * Maxime Ripard <maxime.ripard@free-electrons.com> |
8 | */ |
9 | |
10 | #include <linux/clk.h> |
11 | #include <linux/dmaengine.h> |
12 | #include <linux/module.h> |
13 | #include <linux/of.h> |
14 | #include <linux/platform_device.h> |
15 | #include <linux/pm_runtime.h> |
16 | #include <linux/regmap.h> |
17 | #include <linux/reset.h> |
18 | |
19 | #include <sound/dmaengine_pcm.h> |
20 | #include <sound/pcm_params.h> |
21 | #include <sound/soc.h> |
22 | #include <sound/soc-dai.h> |
23 | |
24 | #define SUN4I_I2S_CTRL_REG 0x00 |
25 | #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8) |
26 | #define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo)) |
27 | #define SUN4I_I2S_CTRL_MODE_MASK BIT(5) |
28 | #define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5) |
29 | #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5) |
30 | #define SUN4I_I2S_CTRL_TX_EN BIT(2) |
31 | #define SUN4I_I2S_CTRL_RX_EN BIT(1) |
32 | #define SUN4I_I2S_CTRL_GL_EN BIT(0) |
33 | |
34 | #define SUN4I_I2S_FMT0_REG 0x04 |
35 | #define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(7) |
36 | #define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 7) |
37 | #define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 7) |
38 | #define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK BIT(6) |
39 | #define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 6) |
40 | #define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 6) |
41 | #define SUN4I_I2S_FMT0_SR_MASK GENMASK(5, 4) |
42 | #define SUN4I_I2S_FMT0_SR(sr) ((sr) << 4) |
43 | #define SUN4I_I2S_FMT0_WSS_MASK GENMASK(3, 2) |
44 | #define SUN4I_I2S_FMT0_WSS(wss) ((wss) << 2) |
45 | #define SUN4I_I2S_FMT0_FMT_MASK GENMASK(1, 0) |
46 | #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) |
47 | #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) |
48 | #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) |
49 | |
50 | #define SUN4I_I2S_FMT1_REG 0x08 |
51 | #define SUN4I_I2S_FMT1_REG_SEXT_MASK BIT(8) |
52 | #define SUN4I_I2S_FMT1_REG_SEXT(sext) ((sext) << 8) |
53 | |
54 | #define SUN4I_I2S_FIFO_TX_REG 0x0c |
55 | #define SUN4I_I2S_FIFO_RX_REG 0x10 |
56 | |
57 | #define SUN4I_I2S_FIFO_CTRL_REG 0x14 |
58 | #define SUN4I_I2S_FIFO_CTRL_FLUSH_TX BIT(25) |
59 | #define SUN4I_I2S_FIFO_CTRL_FLUSH_RX BIT(24) |
60 | #define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK BIT(2) |
61 | #define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode) ((mode) << 2) |
62 | #define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK GENMASK(1, 0) |
63 | #define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode) (mode) |
64 | |
65 | #define SUN4I_I2S_FIFO_STA_REG 0x18 |
66 | |
67 | #define SUN4I_I2S_DMA_INT_CTRL_REG 0x1c |
68 | #define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN BIT(7) |
69 | #define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN BIT(3) |
70 | |
71 | #define SUN4I_I2S_INT_STA_REG 0x20 |
72 | |
73 | #define SUN4I_I2S_CLK_DIV_REG 0x24 |
74 | #define SUN4I_I2S_CLK_DIV_MCLK_EN BIT(7) |
75 | #define SUN4I_I2S_CLK_DIV_BCLK_MASK GENMASK(6, 4) |
76 | #define SUN4I_I2S_CLK_DIV_BCLK(bclk) ((bclk) << 4) |
77 | #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) |
78 | #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) |
79 | |
80 | #define SUN4I_I2S_TX_CNT_REG 0x28 |
81 | #define SUN4I_I2S_RX_CNT_REG 0x2c |
82 | |
83 | #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 |
84 | #define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) |
85 | #define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) |
86 | |
87 | #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 |
88 | #define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2)) |
89 | |
90 | #define SUN4I_I2S_RX_CHAN_SEL_REG 0x38 |
91 | #define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c |
92 | |
93 | /* Defines required for sun8i-h3 support */ |
94 | #define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) |
95 | #define SUN8I_I2S_CTRL_LRCK_OUT BIT(17) |
96 | |
97 | #define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) |
98 | #define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) |
99 | #define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) |
100 | #define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) |
101 | |
102 | #define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) |
103 | #define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) |
104 | #define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) |
105 | #define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) |
106 | #define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) |
107 | #define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) |
108 | #define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) |
109 | #define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) |
110 | |
111 | #define SUN8I_I2S_FMT1_REG_SEXT_MASK GENMASK(5, 4) |
112 | #define SUN8I_I2S_FMT1_REG_SEXT(sext) ((sext) << 4) |
113 | |
114 | #define SUN8I_I2S_INT_STA_REG 0x0c |
115 | #define SUN8I_I2S_FIFO_TX_REG 0x20 |
116 | |
117 | #define SUN8I_I2S_CHAN_CFG_REG 0x30 |
118 | #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(7, 4) |
119 | #define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) ((chan - 1) << 4) |
120 | #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(3, 0) |
121 | #define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1) |
122 | |
123 | #define SUN8I_I2S_TX_CHAN_MAP_REG 0x44 |
124 | #define SUN8I_I2S_TX_CHAN_SEL_REG 0x34 |
125 | #define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12) |
126 | #define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12) |
127 | #define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4) |
128 | #define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4) |
129 | |
130 | #define SUN8I_I2S_RX_CHAN_SEL_REG 0x54 |
131 | #define SUN8I_I2S_RX_CHAN_MAP_REG 0x58 |
132 | |
133 | /* Defines required for sun50i-h6 support */ |
134 | #define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20) |
135 | #define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20) |
136 | #define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16) |
137 | #define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16) |
138 | #define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0) |
139 | #define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1)) |
140 | |
141 | #define SUN50I_H6_I2S_TX_CHAN_SEL_REG(pin) (0x34 + 4 * (pin)) |
142 | #define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(pin) (0x44 + 8 * (pin)) |
143 | #define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(pin) (0x48 + 8 * (pin)) |
144 | |
145 | #define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64 |
146 | #define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68 |
147 | #define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C |
148 | |
149 | #define SUN50I_R329_I2S_RX_CHAN_MAP0_REG 0x68 |
150 | #define SUN50I_R329_I2S_RX_CHAN_MAP1_REG 0x6c |
151 | #define SUN50I_R329_I2S_RX_CHAN_MAP2_REG 0x70 |
152 | #define SUN50I_R329_I2S_RX_CHAN_MAP3_REG 0x74 |
153 | |
154 | struct sun4i_i2s; |
155 | |
156 | /** |
157 | * struct sun4i_i2s_quirks - Differences between SoC variants. |
158 | * @has_reset: SoC needs reset deasserted. |
159 | * @reg_offset_txdata: offset of the tx fifo. |
160 | * @sun4i_i2s_regmap: regmap config to use. |
161 | * @field_clkdiv_mclk_en: regmap field to enable mclk output. |
162 | * @field_fmt_wss: regmap field to set word select size. |
163 | * @field_fmt_sr: regmap field to set sample resolution. |
164 | * @num_din_pins: input pins |
165 | * @num_dout_pins: output pins (currently set but unused) |
166 | * @bclk_dividers: bit clock dividers array |
167 | * @num_bclk_dividers: number of bit clock dividers |
168 | * @mclk_dividers: mclk dividers array |
169 | * @num_mclk_dividers: number of mclk dividers |
170 | * @get_bclk_parent_rate: callback to get bclk parent rate |
171 | * @get_sr: callback to get sample resolution |
172 | * @get_wss: callback to get word select size |
173 | * @set_chan_cfg: callback to set channel configuration |
174 | * @set_fmt: callback to set format |
175 | */ |
176 | struct sun4i_i2s_quirks { |
177 | bool has_reset; |
178 | unsigned int reg_offset_txdata; /* TX FIFO */ |
179 | const struct regmap_config *sun4i_i2s_regmap; |
180 | |
181 | /* Register fields for i2s */ |
182 | struct reg_field field_clkdiv_mclk_en; |
183 | struct reg_field field_fmt_wss; |
184 | struct reg_field field_fmt_sr; |
185 | |
186 | unsigned int num_din_pins; |
187 | unsigned int num_dout_pins; |
188 | |
189 | const struct sun4i_i2s_clk_div *bclk_dividers; |
190 | unsigned int num_bclk_dividers; |
191 | const struct sun4i_i2s_clk_div *mclk_dividers; |
192 | unsigned int num_mclk_dividers; |
193 | |
194 | unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s); |
195 | int (*get_sr)(unsigned int width); |
196 | int (*get_wss)(unsigned int width); |
197 | |
198 | /* |
199 | * In the set_chan_cfg() function pointer: |
200 | * @slots: channels per frame + padding slots, regardless of format |
201 | * @slot_width: bits per sample + padding bits, regardless of format |
202 | */ |
203 | int (*set_chan_cfg)(const struct sun4i_i2s *i2s, |
204 | unsigned int channels, unsigned int slots, |
205 | unsigned int slot_width); |
206 | int (*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt); |
207 | }; |
208 | |
209 | struct sun4i_i2s { |
210 | struct clk *bus_clk; |
211 | struct clk *mod_clk; |
212 | struct regmap *regmap; |
213 | struct reset_control *rst; |
214 | |
215 | unsigned int format; |
216 | unsigned int mclk_freq; |
217 | unsigned int slots; |
218 | unsigned int slot_width; |
219 | |
220 | struct snd_dmaengine_dai_dma_data capture_dma_data; |
221 | struct snd_dmaengine_dai_dma_data playback_dma_data; |
222 | |
223 | /* Register fields for i2s */ |
224 | struct regmap_field *field_clkdiv_mclk_en; |
225 | struct regmap_field *field_fmt_wss; |
226 | struct regmap_field *field_fmt_sr; |
227 | |
228 | const struct sun4i_i2s_quirks *variant; |
229 | }; |
230 | |
231 | struct sun4i_i2s_clk_div { |
232 | u8 div; |
233 | u8 val; |
234 | }; |
235 | |
236 | static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = { |
237 | { .div = 2, .val = 0 }, |
238 | { .div = 4, .val = 1 }, |
239 | { .div = 6, .val = 2 }, |
240 | { .div = 8, .val = 3 }, |
241 | { .div = 12, .val = 4 }, |
242 | { .div = 16, .val = 5 }, |
243 | /* TODO - extend divide ratio supported by newer SoCs */ |
244 | }; |
245 | |
246 | static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { |
247 | { .div = 1, .val = 0 }, |
248 | { .div = 2, .val = 1 }, |
249 | { .div = 4, .val = 2 }, |
250 | { .div = 6, .val = 3 }, |
251 | { .div = 8, .val = 4 }, |
252 | { .div = 12, .val = 5 }, |
253 | { .div = 16, .val = 6 }, |
254 | { .div = 24, .val = 7 }, |
255 | /* TODO - extend divide ratio supported by newer SoCs */ |
256 | }; |
257 | |
258 | static const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { |
259 | { .div = 1, .val = 1 }, |
260 | { .div = 2, .val = 2 }, |
261 | { .div = 4, .val = 3 }, |
262 | { .div = 6, .val = 4 }, |
263 | { .div = 8, .val = 5 }, |
264 | { .div = 12, .val = 6 }, |
265 | { .div = 16, .val = 7 }, |
266 | { .div = 24, .val = 8 }, |
267 | { .div = 32, .val = 9 }, |
268 | { .div = 48, .val = 10 }, |
269 | { .div = 64, .val = 11 }, |
270 | { .div = 96, .val = 12 }, |
271 | { .div = 128, .val = 13 }, |
272 | { .div = 176, .val = 14 }, |
273 | { .div = 192, .val = 15 }, |
274 | }; |
275 | |
276 | static unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) |
277 | { |
278 | return i2s->mclk_freq; |
279 | } |
280 | |
281 | static unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) |
282 | { |
283 | return clk_get_rate(clk: i2s->mod_clk); |
284 | } |
285 | |
286 | static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, |
287 | unsigned long parent_rate, |
288 | unsigned int sampling_rate, |
289 | unsigned int channels, |
290 | unsigned int word_size) |
291 | { |
292 | const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; |
293 | int div = parent_rate / sampling_rate / word_size / channels; |
294 | int i; |
295 | |
296 | for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { |
297 | const struct sun4i_i2s_clk_div *bdiv = ÷rs[i]; |
298 | |
299 | if (bdiv->div == div) |
300 | return bdiv->val; |
301 | } |
302 | |
303 | return -EINVAL; |
304 | } |
305 | |
306 | static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, |
307 | unsigned long parent_rate, |
308 | unsigned long mclk_rate) |
309 | { |
310 | const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; |
311 | int div = parent_rate / mclk_rate; |
312 | int i; |
313 | |
314 | for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { |
315 | const struct sun4i_i2s_clk_div *mdiv = ÷rs[i]; |
316 | |
317 | if (mdiv->div == div) |
318 | return mdiv->val; |
319 | } |
320 | |
321 | return -EINVAL; |
322 | } |
323 | |
324 | static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; |
325 | static bool sun4i_i2s_oversample_is_valid(unsigned int oversample) |
326 | { |
327 | int i; |
328 | |
329 | for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++) |
330 | if (sun4i_i2s_oversample_rates[i] == oversample) |
331 | return true; |
332 | |
333 | return false; |
334 | } |
335 | |
336 | static int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, |
337 | unsigned int rate, |
338 | unsigned int slots, |
339 | unsigned int slot_width) |
340 | { |
341 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
342 | unsigned int oversample_rate, clk_rate, bclk_parent_rate; |
343 | int bclk_div, mclk_div; |
344 | int ret; |
345 | |
346 | switch (rate) { |
347 | case 176400: |
348 | case 88200: |
349 | case 44100: |
350 | case 22050: |
351 | case 11025: |
352 | clk_rate = 22579200; |
353 | break; |
354 | |
355 | case 192000: |
356 | case 128000: |
357 | case 96000: |
358 | case 64000: |
359 | case 48000: |
360 | case 32000: |
361 | case 24000: |
362 | case 16000: |
363 | case 12000: |
364 | case 8000: |
365 | clk_rate = 24576000; |
366 | break; |
367 | |
368 | default: |
369 | dev_err(dai->dev, "Unsupported sample rate: %u\n" , rate); |
370 | return -EINVAL; |
371 | } |
372 | |
373 | ret = clk_set_rate(clk: i2s->mod_clk, rate: clk_rate); |
374 | if (ret) |
375 | return ret; |
376 | |
377 | oversample_rate = i2s->mclk_freq / rate; |
378 | if (!sun4i_i2s_oversample_is_valid(oversample: oversample_rate)) { |
379 | dev_err(dai->dev, "Unsupported oversample rate: %d\n" , |
380 | oversample_rate); |
381 | return -EINVAL; |
382 | } |
383 | |
384 | bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); |
385 | bclk_div = sun4i_i2s_get_bclk_div(i2s, parent_rate: bclk_parent_rate, |
386 | sampling_rate: rate, channels: slots, word_size: slot_width); |
387 | if (bclk_div < 0) { |
388 | dev_err(dai->dev, "Unsupported BCLK divider: %d\n" , bclk_div); |
389 | return -EINVAL; |
390 | } |
391 | |
392 | mclk_div = sun4i_i2s_get_mclk_div(i2s, parent_rate: clk_rate, mclk_rate: i2s->mclk_freq); |
393 | if (mclk_div < 0) { |
394 | dev_err(dai->dev, "Unsupported MCLK divider: %d\n" , mclk_div); |
395 | return -EINVAL; |
396 | } |
397 | |
398 | regmap_write(map: i2s->regmap, SUN4I_I2S_CLK_DIV_REG, |
399 | SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | |
400 | SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); |
401 | |
402 | regmap_field_write(field: i2s->field_clkdiv_mclk_en, val: 1); |
403 | |
404 | return 0; |
405 | } |
406 | |
407 | static int sun4i_i2s_get_sr(unsigned int width) |
408 | { |
409 | switch (width) { |
410 | case 16: |
411 | return 0; |
412 | case 20: |
413 | return 1; |
414 | case 24: |
415 | return 2; |
416 | } |
417 | |
418 | return -EINVAL; |
419 | } |
420 | |
421 | static int sun4i_i2s_get_wss(unsigned int width) |
422 | { |
423 | switch (width) { |
424 | case 16: |
425 | return 0; |
426 | case 20: |
427 | return 1; |
428 | case 24: |
429 | return 2; |
430 | case 32: |
431 | return 3; |
432 | } |
433 | |
434 | return -EINVAL; |
435 | } |
436 | |
437 | static int sun8i_i2s_get_sr_wss(unsigned int width) |
438 | { |
439 | switch (width) { |
440 | case 8: |
441 | return 1; |
442 | case 12: |
443 | return 2; |
444 | case 16: |
445 | return 3; |
446 | case 20: |
447 | return 4; |
448 | case 24: |
449 | return 5; |
450 | case 28: |
451 | return 6; |
452 | case 32: |
453 | return 7; |
454 | } |
455 | |
456 | return -EINVAL; |
457 | } |
458 | |
459 | static int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, |
460 | unsigned int channels, unsigned int slots, |
461 | unsigned int slot_width) |
462 | { |
463 | /* Map the channels for playback and capture */ |
464 | regmap_write(map: i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, val: 0x76543210); |
465 | regmap_write(map: i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, val: 0x00003210); |
466 | |
467 | /* Configure the channels */ |
468 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, |
469 | SUN4I_I2S_CHAN_SEL_MASK, |
470 | SUN4I_I2S_CHAN_SEL(channels)); |
471 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, |
472 | SUN4I_I2S_CHAN_SEL_MASK, |
473 | SUN4I_I2S_CHAN_SEL(channels)); |
474 | |
475 | return 0; |
476 | } |
477 | |
478 | static int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, |
479 | unsigned int channels, unsigned int slots, |
480 | unsigned int slot_width) |
481 | { |
482 | unsigned int lrck_period; |
483 | |
484 | /* Map the channels for playback and capture */ |
485 | regmap_write(map: i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, val: 0x76543210); |
486 | regmap_write(map: i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, val: 0x76543210); |
487 | |
488 | /* Configure the channels */ |
489 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
490 | SUN4I_I2S_CHAN_SEL_MASK, |
491 | SUN4I_I2S_CHAN_SEL(channels)); |
492 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, |
493 | SUN4I_I2S_CHAN_SEL_MASK, |
494 | SUN4I_I2S_CHAN_SEL(channels)); |
495 | |
496 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
497 | SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, |
498 | SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); |
499 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
500 | SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, |
501 | SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); |
502 | |
503 | switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
504 | case SND_SOC_DAIFMT_DSP_A: |
505 | case SND_SOC_DAIFMT_DSP_B: |
506 | lrck_period = slot_width * slots; |
507 | break; |
508 | |
509 | case SND_SOC_DAIFMT_LEFT_J: |
510 | case SND_SOC_DAIFMT_RIGHT_J: |
511 | case SND_SOC_DAIFMT_I2S: |
512 | lrck_period = slot_width; |
513 | break; |
514 | |
515 | default: |
516 | return -EINVAL; |
517 | } |
518 | |
519 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT0_REG, |
520 | SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, |
521 | SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); |
522 | |
523 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
524 | SUN8I_I2S_TX_CHAN_EN_MASK, |
525 | SUN8I_I2S_TX_CHAN_EN(channels)); |
526 | |
527 | return 0; |
528 | } |
529 | |
530 | static int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, |
531 | unsigned int channels, unsigned int slots, |
532 | unsigned int slot_width) |
533 | { |
534 | unsigned int lrck_period; |
535 | |
536 | /* Map the channels for playback and capture */ |
537 | regmap_write(map: i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), val: 0xFEDCBA98); |
538 | regmap_write(map: i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), val: 0x76543210); |
539 | if (i2s->variant->num_din_pins > 1) { |
540 | regmap_write(map: i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP0_REG, val: 0x0F0E0D0C); |
541 | regmap_write(map: i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP1_REG, val: 0x0B0A0908); |
542 | regmap_write(map: i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP2_REG, val: 0x07060504); |
543 | regmap_write(map: i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP3_REG, val: 0x03020100); |
544 | } else { |
545 | regmap_write(map: i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, val: 0xFEDCBA98); |
546 | regmap_write(map: i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, val: 0x76543210); |
547 | } |
548 | |
549 | /* Configure the channels */ |
550 | regmap_update_bits(map: i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), |
551 | SUN50I_H6_I2S_TX_CHAN_SEL_MASK, |
552 | SUN50I_H6_I2S_TX_CHAN_SEL(channels)); |
553 | regmap_update_bits(map: i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, |
554 | SUN50I_H6_I2S_TX_CHAN_SEL_MASK, |
555 | SUN50I_H6_I2S_TX_CHAN_SEL(channels)); |
556 | |
557 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
558 | SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, |
559 | SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); |
560 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, |
561 | SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, |
562 | SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); |
563 | |
564 | switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
565 | case SND_SOC_DAIFMT_DSP_A: |
566 | case SND_SOC_DAIFMT_DSP_B: |
567 | lrck_period = slot_width * slots; |
568 | break; |
569 | |
570 | case SND_SOC_DAIFMT_LEFT_J: |
571 | case SND_SOC_DAIFMT_RIGHT_J: |
572 | case SND_SOC_DAIFMT_I2S: |
573 | lrck_period = slot_width; |
574 | break; |
575 | |
576 | default: |
577 | return -EINVAL; |
578 | } |
579 | |
580 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT0_REG, |
581 | SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, |
582 | SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); |
583 | |
584 | regmap_update_bits(map: i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), |
585 | SUN50I_H6_I2S_TX_CHAN_EN_MASK, |
586 | SUN50I_H6_I2S_TX_CHAN_EN(channels)); |
587 | |
588 | return 0; |
589 | } |
590 | |
591 | static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, |
592 | struct snd_pcm_hw_params *params, |
593 | struct snd_soc_dai *dai) |
594 | { |
595 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
596 | unsigned int word_size = params_width(p: params); |
597 | unsigned int slot_width = params_physical_width(p: params); |
598 | unsigned int channels = params_channels(p: params); |
599 | |
600 | unsigned int slots = channels; |
601 | |
602 | int ret, sr, wss; |
603 | u32 width; |
604 | |
605 | if (i2s->slots) |
606 | slots = i2s->slots; |
607 | |
608 | if (i2s->slot_width) |
609 | slot_width = i2s->slot_width; |
610 | |
611 | ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width); |
612 | if (ret < 0) { |
613 | dev_err(dai->dev, "Invalid channel configuration\n" ); |
614 | return ret; |
615 | } |
616 | |
617 | /* Set significant bits in our FIFOs */ |
618 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, |
619 | SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | |
620 | SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, |
621 | SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | |
622 | SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); |
623 | |
624 | switch (params_physical_width(p: params)) { |
625 | case 16: |
626 | width = DMA_SLAVE_BUSWIDTH_2_BYTES; |
627 | break; |
628 | case 32: |
629 | width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
630 | break; |
631 | default: |
632 | dev_err(dai->dev, "Unsupported physical sample width: %d\n" , |
633 | params_physical_width(params)); |
634 | return -EINVAL; |
635 | } |
636 | i2s->playback_dma_data.addr_width = width; |
637 | |
638 | sr = i2s->variant->get_sr(word_size); |
639 | if (sr < 0) |
640 | return -EINVAL; |
641 | |
642 | wss = i2s->variant->get_wss(slot_width); |
643 | if (wss < 0) |
644 | return -EINVAL; |
645 | |
646 | regmap_field_write(field: i2s->field_fmt_wss, val: wss); |
647 | regmap_field_write(field: i2s->field_fmt_sr, val: sr); |
648 | |
649 | return sun4i_i2s_set_clk_rate(dai, rate: params_rate(p: params), |
650 | slots, slot_width); |
651 | } |
652 | |
653 | static int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, |
654 | unsigned int fmt) |
655 | { |
656 | u32 val; |
657 | |
658 | /* DAI clock polarity */ |
659 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
660 | case SND_SOC_DAIFMT_IB_IF: |
661 | /* Invert both clocks */ |
662 | val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | |
663 | SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
664 | break; |
665 | case SND_SOC_DAIFMT_IB_NF: |
666 | /* Invert bit clock */ |
667 | val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; |
668 | break; |
669 | case SND_SOC_DAIFMT_NB_IF: |
670 | /* Invert frame clock */ |
671 | val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
672 | break; |
673 | case SND_SOC_DAIFMT_NB_NF: |
674 | val = 0; |
675 | break; |
676 | default: |
677 | return -EINVAL; |
678 | } |
679 | |
680 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT0_REG, |
681 | SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | |
682 | SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, |
683 | val); |
684 | |
685 | /* DAI Mode */ |
686 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
687 | case SND_SOC_DAIFMT_I2S: |
688 | val = SUN4I_I2S_FMT0_FMT_I2S; |
689 | break; |
690 | |
691 | case SND_SOC_DAIFMT_LEFT_J: |
692 | val = SUN4I_I2S_FMT0_FMT_LEFT_J; |
693 | break; |
694 | |
695 | case SND_SOC_DAIFMT_RIGHT_J: |
696 | val = SUN4I_I2S_FMT0_FMT_RIGHT_J; |
697 | break; |
698 | |
699 | default: |
700 | return -EINVAL; |
701 | } |
702 | |
703 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT0_REG, |
704 | SUN4I_I2S_FMT0_FMT_MASK, val); |
705 | |
706 | /* DAI clock master masks */ |
707 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
708 | case SND_SOC_DAIFMT_BP_FP: |
709 | /* BCLK and LRCLK master */ |
710 | val = SUN4I_I2S_CTRL_MODE_MASTER; |
711 | break; |
712 | |
713 | case SND_SOC_DAIFMT_BC_FC: |
714 | /* BCLK and LRCLK slave */ |
715 | val = SUN4I_I2S_CTRL_MODE_SLAVE; |
716 | break; |
717 | |
718 | default: |
719 | return -EINVAL; |
720 | } |
721 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
722 | SUN4I_I2S_CTRL_MODE_MASK, val); |
723 | |
724 | return 0; |
725 | } |
726 | |
727 | static int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, |
728 | unsigned int fmt) |
729 | { |
730 | u32 mode, val; |
731 | u8 offset; |
732 | |
733 | /* |
734 | * DAI clock polarity |
735 | * |
736 | * The setup for LRCK contradicts the datasheet, but under a |
737 | * scope it's clear that the LRCK polarity is reversed |
738 | * compared to the expected polarity on the bus. |
739 | */ |
740 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
741 | case SND_SOC_DAIFMT_IB_IF: |
742 | /* Invert both clocks */ |
743 | val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; |
744 | break; |
745 | case SND_SOC_DAIFMT_IB_NF: |
746 | /* Invert bit clock */ |
747 | val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | |
748 | SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
749 | break; |
750 | case SND_SOC_DAIFMT_NB_IF: |
751 | /* Invert frame clock */ |
752 | val = 0; |
753 | break; |
754 | case SND_SOC_DAIFMT_NB_NF: |
755 | val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
756 | break; |
757 | default: |
758 | return -EINVAL; |
759 | } |
760 | |
761 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT0_REG, |
762 | SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | |
763 | SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, |
764 | val); |
765 | |
766 | /* DAI Mode */ |
767 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
768 | case SND_SOC_DAIFMT_DSP_A: |
769 | mode = SUN8I_I2S_CTRL_MODE_PCM; |
770 | offset = 1; |
771 | break; |
772 | |
773 | case SND_SOC_DAIFMT_DSP_B: |
774 | mode = SUN8I_I2S_CTRL_MODE_PCM; |
775 | offset = 0; |
776 | break; |
777 | |
778 | case SND_SOC_DAIFMT_I2S: |
779 | mode = SUN8I_I2S_CTRL_MODE_LEFT; |
780 | offset = 1; |
781 | break; |
782 | |
783 | case SND_SOC_DAIFMT_LEFT_J: |
784 | mode = SUN8I_I2S_CTRL_MODE_LEFT; |
785 | offset = 0; |
786 | break; |
787 | |
788 | case SND_SOC_DAIFMT_RIGHT_J: |
789 | mode = SUN8I_I2S_CTRL_MODE_RIGHT; |
790 | offset = 0; |
791 | break; |
792 | |
793 | default: |
794 | return -EINVAL; |
795 | } |
796 | |
797 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
798 | SUN8I_I2S_CTRL_MODE_MASK, val: mode); |
799 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
800 | SUN8I_I2S_TX_CHAN_OFFSET_MASK, |
801 | SUN8I_I2S_TX_CHAN_OFFSET(offset)); |
802 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, |
803 | SUN8I_I2S_TX_CHAN_OFFSET_MASK, |
804 | SUN8I_I2S_TX_CHAN_OFFSET(offset)); |
805 | |
806 | /* DAI clock master masks */ |
807 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
808 | case SND_SOC_DAIFMT_BP_FP: |
809 | /* BCLK and LRCLK master */ |
810 | val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; |
811 | break; |
812 | |
813 | case SND_SOC_DAIFMT_BC_FC: |
814 | /* BCLK and LRCLK slave */ |
815 | val = 0; |
816 | break; |
817 | |
818 | default: |
819 | return -EINVAL; |
820 | } |
821 | |
822 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
823 | SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, |
824 | val); |
825 | |
826 | /* Set sign extension to pad out LSB with 0 */ |
827 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT1_REG, |
828 | SUN8I_I2S_FMT1_REG_SEXT_MASK, |
829 | SUN8I_I2S_FMT1_REG_SEXT(0)); |
830 | |
831 | return 0; |
832 | } |
833 | |
834 | static int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, |
835 | unsigned int fmt) |
836 | { |
837 | u32 mode, val; |
838 | u8 offset; |
839 | |
840 | /* |
841 | * DAI clock polarity |
842 | * |
843 | * The setup for LRCK contradicts the datasheet, but under a |
844 | * scope it's clear that the LRCK polarity is reversed |
845 | * compared to the expected polarity on the bus. |
846 | */ |
847 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
848 | case SND_SOC_DAIFMT_IB_IF: |
849 | /* Invert both clocks */ |
850 | val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; |
851 | break; |
852 | case SND_SOC_DAIFMT_IB_NF: |
853 | /* Invert bit clock */ |
854 | val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | |
855 | SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
856 | break; |
857 | case SND_SOC_DAIFMT_NB_IF: |
858 | /* Invert frame clock */ |
859 | val = 0; |
860 | break; |
861 | case SND_SOC_DAIFMT_NB_NF: |
862 | val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; |
863 | break; |
864 | default: |
865 | return -EINVAL; |
866 | } |
867 | |
868 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT0_REG, |
869 | SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | |
870 | SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, |
871 | val); |
872 | |
873 | /* DAI Mode */ |
874 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
875 | case SND_SOC_DAIFMT_DSP_A: |
876 | mode = SUN8I_I2S_CTRL_MODE_PCM; |
877 | offset = 1; |
878 | break; |
879 | |
880 | case SND_SOC_DAIFMT_DSP_B: |
881 | mode = SUN8I_I2S_CTRL_MODE_PCM; |
882 | offset = 0; |
883 | break; |
884 | |
885 | case SND_SOC_DAIFMT_I2S: |
886 | mode = SUN8I_I2S_CTRL_MODE_LEFT; |
887 | offset = 1; |
888 | break; |
889 | |
890 | case SND_SOC_DAIFMT_LEFT_J: |
891 | mode = SUN8I_I2S_CTRL_MODE_LEFT; |
892 | offset = 0; |
893 | break; |
894 | |
895 | case SND_SOC_DAIFMT_RIGHT_J: |
896 | mode = SUN8I_I2S_CTRL_MODE_RIGHT; |
897 | offset = 0; |
898 | break; |
899 | |
900 | default: |
901 | return -EINVAL; |
902 | } |
903 | |
904 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
905 | SUN8I_I2S_CTRL_MODE_MASK, val: mode); |
906 | regmap_update_bits(map: i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, |
907 | SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, |
908 | SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); |
909 | regmap_update_bits(map: i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, |
910 | SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, |
911 | SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); |
912 | |
913 | /* DAI clock master masks */ |
914 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
915 | case SND_SOC_DAIFMT_BP_FP: |
916 | /* BCLK and LRCLK master */ |
917 | val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; |
918 | break; |
919 | |
920 | case SND_SOC_DAIFMT_BC_FC: |
921 | /* BCLK and LRCLK slave */ |
922 | val = 0; |
923 | break; |
924 | |
925 | default: |
926 | return -EINVAL; |
927 | } |
928 | |
929 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
930 | SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, |
931 | val); |
932 | |
933 | /* Set sign extension to pad out LSB with 0 */ |
934 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FMT1_REG, |
935 | SUN8I_I2S_FMT1_REG_SEXT_MASK, |
936 | SUN8I_I2S_FMT1_REG_SEXT(0)); |
937 | |
938 | return 0; |
939 | } |
940 | |
941 | static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
942 | { |
943 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
944 | int ret; |
945 | |
946 | ret = i2s->variant->set_fmt(i2s, fmt); |
947 | if (ret) { |
948 | dev_err(dai->dev, "Unsupported format configuration\n" ); |
949 | return ret; |
950 | } |
951 | |
952 | i2s->format = fmt; |
953 | |
954 | return 0; |
955 | } |
956 | |
957 | static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s) |
958 | { |
959 | /* Flush RX FIFO */ |
960 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, |
961 | SUN4I_I2S_FIFO_CTRL_FLUSH_RX, |
962 | SUN4I_I2S_FIFO_CTRL_FLUSH_RX); |
963 | |
964 | /* Clear RX counter */ |
965 | regmap_write(map: i2s->regmap, SUN4I_I2S_RX_CNT_REG, val: 0); |
966 | |
967 | /* Enable RX Block */ |
968 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
969 | SUN4I_I2S_CTRL_RX_EN, |
970 | SUN4I_I2S_CTRL_RX_EN); |
971 | |
972 | /* Enable RX DRQ */ |
973 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, |
974 | SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, |
975 | SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN); |
976 | } |
977 | |
978 | static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) |
979 | { |
980 | /* Flush TX FIFO */ |
981 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, |
982 | SUN4I_I2S_FIFO_CTRL_FLUSH_TX, |
983 | SUN4I_I2S_FIFO_CTRL_FLUSH_TX); |
984 | |
985 | /* Clear TX counter */ |
986 | regmap_write(map: i2s->regmap, SUN4I_I2S_TX_CNT_REG, val: 0); |
987 | |
988 | /* Enable TX Block */ |
989 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
990 | SUN4I_I2S_CTRL_TX_EN, |
991 | SUN4I_I2S_CTRL_TX_EN); |
992 | |
993 | /* Enable TX DRQ */ |
994 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, |
995 | SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN, |
996 | SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); |
997 | } |
998 | |
999 | static void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s) |
1000 | { |
1001 | /* Disable RX Block */ |
1002 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
1003 | SUN4I_I2S_CTRL_RX_EN, |
1004 | val: 0); |
1005 | |
1006 | /* Disable RX DRQ */ |
1007 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, |
1008 | SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, |
1009 | val: 0); |
1010 | } |
1011 | |
1012 | static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) |
1013 | { |
1014 | /* Disable TX Block */ |
1015 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
1016 | SUN4I_I2S_CTRL_TX_EN, |
1017 | val: 0); |
1018 | |
1019 | /* Disable TX DRQ */ |
1020 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, |
1021 | SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN, |
1022 | val: 0); |
1023 | } |
1024 | |
1025 | static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, |
1026 | struct snd_soc_dai *dai) |
1027 | { |
1028 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
1029 | |
1030 | switch (cmd) { |
1031 | case SNDRV_PCM_TRIGGER_START: |
1032 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1033 | case SNDRV_PCM_TRIGGER_RESUME: |
1034 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
1035 | sun4i_i2s_start_playback(i2s); |
1036 | else |
1037 | sun4i_i2s_start_capture(i2s); |
1038 | break; |
1039 | |
1040 | case SNDRV_PCM_TRIGGER_STOP: |
1041 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1042 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1043 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
1044 | sun4i_i2s_stop_playback(i2s); |
1045 | else |
1046 | sun4i_i2s_stop_capture(i2s); |
1047 | break; |
1048 | |
1049 | default: |
1050 | return -EINVAL; |
1051 | } |
1052 | |
1053 | return 0; |
1054 | } |
1055 | |
1056 | static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
1057 | unsigned int freq, int dir) |
1058 | { |
1059 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
1060 | |
1061 | if (clk_id != 0) |
1062 | return -EINVAL; |
1063 | |
1064 | i2s->mclk_freq = freq; |
1065 | |
1066 | return 0; |
1067 | } |
1068 | |
1069 | static int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, |
1070 | unsigned int tx_mask, unsigned int rx_mask, |
1071 | int slots, int slot_width) |
1072 | { |
1073 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
1074 | |
1075 | if (slots > 8) |
1076 | return -EINVAL; |
1077 | |
1078 | i2s->slots = slots; |
1079 | i2s->slot_width = slot_width; |
1080 | |
1081 | return 0; |
1082 | } |
1083 | |
1084 | static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) |
1085 | { |
1086 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
1087 | |
1088 | snd_soc_dai_init_dma_data(dai, |
1089 | playback: &i2s->playback_dma_data, |
1090 | capture: &i2s->capture_dma_data); |
1091 | |
1092 | return 0; |
1093 | } |
1094 | |
1095 | static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { |
1096 | .probe = sun4i_i2s_dai_probe, |
1097 | .hw_params = sun4i_i2s_hw_params, |
1098 | .set_fmt = sun4i_i2s_set_fmt, |
1099 | .set_sysclk = sun4i_i2s_set_sysclk, |
1100 | .set_tdm_slot = sun4i_i2s_set_tdm_slot, |
1101 | .trigger = sun4i_i2s_trigger, |
1102 | }; |
1103 | |
1104 | #define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
1105 | SNDRV_PCM_FMTBIT_S20_LE | \ |
1106 | SNDRV_PCM_FMTBIT_S24_LE) |
1107 | |
1108 | static struct snd_soc_dai_driver sun4i_i2s_dai = { |
1109 | .capture = { |
1110 | .stream_name = "Capture" , |
1111 | .channels_min = 1, |
1112 | .channels_max = 8, |
1113 | .rates = SNDRV_PCM_RATE_8000_192000, |
1114 | .formats = SUN4I_FORMATS, |
1115 | }, |
1116 | .playback = { |
1117 | .stream_name = "Playback" , |
1118 | .channels_min = 1, |
1119 | .channels_max = 8, |
1120 | .rates = SNDRV_PCM_RATE_8000_192000, |
1121 | .formats = SUN4I_FORMATS, |
1122 | }, |
1123 | .ops = &sun4i_i2s_dai_ops, |
1124 | .symmetric_rate = 1, |
1125 | }; |
1126 | |
1127 | static const struct snd_soc_component_driver sun4i_i2s_component = { |
1128 | .name = "sun4i-dai" , |
1129 | .legacy_dai_naming = 1, |
1130 | }; |
1131 | |
1132 | static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg) |
1133 | { |
1134 | switch (reg) { |
1135 | case SUN4I_I2S_FIFO_TX_REG: |
1136 | return false; |
1137 | |
1138 | default: |
1139 | return true; |
1140 | } |
1141 | } |
1142 | |
1143 | static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg) |
1144 | { |
1145 | switch (reg) { |
1146 | case SUN4I_I2S_FIFO_RX_REG: |
1147 | case SUN4I_I2S_FIFO_STA_REG: |
1148 | return false; |
1149 | |
1150 | default: |
1151 | return true; |
1152 | } |
1153 | } |
1154 | |
1155 | static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg) |
1156 | { |
1157 | switch (reg) { |
1158 | case SUN4I_I2S_FIFO_RX_REG: |
1159 | case SUN4I_I2S_INT_STA_REG: |
1160 | case SUN4I_I2S_RX_CNT_REG: |
1161 | case SUN4I_I2S_TX_CNT_REG: |
1162 | return true; |
1163 | |
1164 | default: |
1165 | return false; |
1166 | } |
1167 | } |
1168 | |
1169 | static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg) |
1170 | { |
1171 | switch (reg) { |
1172 | case SUN8I_I2S_FIFO_TX_REG: |
1173 | return false; |
1174 | |
1175 | default: |
1176 | return true; |
1177 | } |
1178 | } |
1179 | |
1180 | static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) |
1181 | { |
1182 | switch (reg) { |
1183 | case SUN4I_I2S_FIFO_CTRL_REG: |
1184 | case SUN4I_I2S_FIFO_RX_REG: |
1185 | case SUN4I_I2S_FIFO_STA_REG: |
1186 | case SUN4I_I2S_RX_CNT_REG: |
1187 | case SUN4I_I2S_TX_CNT_REG: |
1188 | case SUN8I_I2S_FIFO_TX_REG: |
1189 | case SUN8I_I2S_INT_STA_REG: |
1190 | return true; |
1191 | |
1192 | default: |
1193 | return false; |
1194 | } |
1195 | } |
1196 | |
1197 | static const struct reg_default sun4i_i2s_reg_defaults[] = { |
1198 | { SUN4I_I2S_CTRL_REG, 0x00000000 }, |
1199 | { SUN4I_I2S_FMT0_REG, 0x0000000c }, |
1200 | { SUN4I_I2S_FMT1_REG, 0x00004020 }, |
1201 | { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, |
1202 | { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, |
1203 | { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, |
1204 | { SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 }, |
1205 | { SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 }, |
1206 | { SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 }, |
1207 | { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 }, |
1208 | }; |
1209 | |
1210 | static const struct reg_default sun8i_i2s_reg_defaults[] = { |
1211 | { SUN4I_I2S_CTRL_REG, 0x00060000 }, |
1212 | { SUN4I_I2S_FMT0_REG, 0x00000033 }, |
1213 | { SUN4I_I2S_FMT1_REG, 0x00000030 }, |
1214 | { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, |
1215 | { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, |
1216 | { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, |
1217 | { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 }, |
1218 | { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 }, |
1219 | { SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 }, |
1220 | { SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 }, |
1221 | { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 }, |
1222 | }; |
1223 | |
1224 | static const struct reg_default sun50i_h6_i2s_reg_defaults[] = { |
1225 | { SUN4I_I2S_CTRL_REG, 0x00060000 }, |
1226 | { SUN4I_I2S_FMT0_REG, 0x00000033 }, |
1227 | { SUN4I_I2S_FMT1_REG, 0x00000030 }, |
1228 | { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, |
1229 | { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, |
1230 | { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, |
1231 | { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 }, |
1232 | { SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 0x00000000 }, |
1233 | { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 }, |
1234 | { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x00000000 }, |
1235 | { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 }, |
1236 | { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 }, |
1237 | { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 }, |
1238 | }; |
1239 | |
1240 | static const struct regmap_config sun4i_i2s_regmap_config = { |
1241 | .reg_bits = 32, |
1242 | .reg_stride = 4, |
1243 | .val_bits = 32, |
1244 | .max_register = SUN4I_I2S_RX_CHAN_MAP_REG, |
1245 | |
1246 | .cache_type = REGCACHE_FLAT, |
1247 | .reg_defaults = sun4i_i2s_reg_defaults, |
1248 | .num_reg_defaults = ARRAY_SIZE(sun4i_i2s_reg_defaults), |
1249 | .writeable_reg = sun4i_i2s_wr_reg, |
1250 | .readable_reg = sun4i_i2s_rd_reg, |
1251 | .volatile_reg = sun4i_i2s_volatile_reg, |
1252 | }; |
1253 | |
1254 | static const struct regmap_config sun8i_i2s_regmap_config = { |
1255 | .reg_bits = 32, |
1256 | .reg_stride = 4, |
1257 | .val_bits = 32, |
1258 | .max_register = SUN8I_I2S_RX_CHAN_MAP_REG, |
1259 | .cache_type = REGCACHE_FLAT, |
1260 | .reg_defaults = sun8i_i2s_reg_defaults, |
1261 | .num_reg_defaults = ARRAY_SIZE(sun8i_i2s_reg_defaults), |
1262 | .writeable_reg = sun4i_i2s_wr_reg, |
1263 | .readable_reg = sun8i_i2s_rd_reg, |
1264 | .volatile_reg = sun8i_i2s_volatile_reg, |
1265 | }; |
1266 | |
1267 | static const struct regmap_config sun50i_h6_i2s_regmap_config = { |
1268 | .reg_bits = 32, |
1269 | .reg_stride = 4, |
1270 | .val_bits = 32, |
1271 | .max_register = SUN50I_R329_I2S_RX_CHAN_MAP3_REG, |
1272 | .cache_type = REGCACHE_FLAT, |
1273 | .reg_defaults = sun50i_h6_i2s_reg_defaults, |
1274 | .num_reg_defaults = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults), |
1275 | .writeable_reg = sun4i_i2s_wr_reg, |
1276 | .readable_reg = sun8i_i2s_rd_reg, |
1277 | .volatile_reg = sun8i_i2s_volatile_reg, |
1278 | }; |
1279 | |
1280 | static int sun4i_i2s_runtime_resume(struct device *dev) |
1281 | { |
1282 | struct sun4i_i2s *i2s = dev_get_drvdata(dev); |
1283 | int ret; |
1284 | |
1285 | ret = clk_prepare_enable(clk: i2s->bus_clk); |
1286 | if (ret) { |
1287 | dev_err(dev, "Failed to enable bus clock\n" ); |
1288 | return ret; |
1289 | } |
1290 | |
1291 | regcache_cache_only(map: i2s->regmap, enable: false); |
1292 | regcache_mark_dirty(map: i2s->regmap); |
1293 | |
1294 | ret = regcache_sync(map: i2s->regmap); |
1295 | if (ret) { |
1296 | dev_err(dev, "Failed to sync regmap cache\n" ); |
1297 | goto err_disable_clk; |
1298 | } |
1299 | |
1300 | /* Enable the whole hardware block */ |
1301 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
1302 | SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); |
1303 | |
1304 | /* Enable the first output line */ |
1305 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
1306 | SUN4I_I2S_CTRL_SDO_EN_MASK, |
1307 | SUN4I_I2S_CTRL_SDO_EN(0)); |
1308 | |
1309 | ret = clk_prepare_enable(clk: i2s->mod_clk); |
1310 | if (ret) { |
1311 | dev_err(dev, "Failed to enable module clock\n" ); |
1312 | goto err_disable_clk; |
1313 | } |
1314 | |
1315 | return 0; |
1316 | |
1317 | err_disable_clk: |
1318 | clk_disable_unprepare(clk: i2s->bus_clk); |
1319 | return ret; |
1320 | } |
1321 | |
1322 | static int sun4i_i2s_runtime_suspend(struct device *dev) |
1323 | { |
1324 | struct sun4i_i2s *i2s = dev_get_drvdata(dev); |
1325 | |
1326 | clk_disable_unprepare(clk: i2s->mod_clk); |
1327 | |
1328 | /* Disable our output lines */ |
1329 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
1330 | SUN4I_I2S_CTRL_SDO_EN_MASK, val: 0); |
1331 | |
1332 | /* Disable the whole hardware block */ |
1333 | regmap_update_bits(map: i2s->regmap, SUN4I_I2S_CTRL_REG, |
1334 | SUN4I_I2S_CTRL_GL_EN, val: 0); |
1335 | |
1336 | regcache_cache_only(map: i2s->regmap, enable: true); |
1337 | |
1338 | clk_disable_unprepare(clk: i2s->bus_clk); |
1339 | |
1340 | return 0; |
1341 | } |
1342 | |
1343 | static const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { |
1344 | .has_reset = false, |
1345 | .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG, |
1346 | .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, |
1347 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
1348 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
1349 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
1350 | .bclk_dividers = sun4i_i2s_bclk_div, |
1351 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
1352 | .mclk_dividers = sun4i_i2s_mclk_div, |
1353 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
1354 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
1355 | .get_sr = sun4i_i2s_get_sr, |
1356 | .get_wss = sun4i_i2s_get_wss, |
1357 | .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
1358 | .set_fmt = sun4i_i2s_set_soc_fmt, |
1359 | }; |
1360 | |
1361 | static const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { |
1362 | .has_reset = true, |
1363 | .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG, |
1364 | .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, |
1365 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
1366 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
1367 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
1368 | .bclk_dividers = sun4i_i2s_bclk_div, |
1369 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
1370 | .mclk_dividers = sun4i_i2s_mclk_div, |
1371 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
1372 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
1373 | .get_sr = sun4i_i2s_get_sr, |
1374 | .get_wss = sun4i_i2s_get_wss, |
1375 | .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
1376 | .set_fmt = sun4i_i2s_set_soc_fmt, |
1377 | }; |
1378 | |
1379 | /* |
1380 | * This doesn't describe the TDM controller documented in the A83t |
1381 | * datasheet, but the three undocumented I2S controller that use the |
1382 | * older design. |
1383 | */ |
1384 | static const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { |
1385 | .has_reset = true, |
1386 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
1387 | .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, |
1388 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
1389 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
1390 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
1391 | .bclk_dividers = sun4i_i2s_bclk_div, |
1392 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
1393 | .mclk_dividers = sun4i_i2s_mclk_div, |
1394 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
1395 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
1396 | .get_sr = sun4i_i2s_get_sr, |
1397 | .get_wss = sun4i_i2s_get_wss, |
1398 | .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
1399 | .set_fmt = sun4i_i2s_set_soc_fmt, |
1400 | }; |
1401 | |
1402 | static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { |
1403 | .has_reset = true, |
1404 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
1405 | .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, |
1406 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), |
1407 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), |
1408 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), |
1409 | .bclk_dividers = sun8i_i2s_clk_div, |
1410 | .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
1411 | .mclk_dividers = sun8i_i2s_clk_div, |
1412 | .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
1413 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, |
1414 | .get_sr = sun8i_i2s_get_sr_wss, |
1415 | .get_wss = sun8i_i2s_get_sr_wss, |
1416 | .set_chan_cfg = sun8i_i2s_set_chan_cfg, |
1417 | .set_fmt = sun8i_i2s_set_soc_fmt, |
1418 | }; |
1419 | |
1420 | static const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { |
1421 | .has_reset = true, |
1422 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
1423 | .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, |
1424 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), |
1425 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), |
1426 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), |
1427 | .bclk_dividers = sun4i_i2s_bclk_div, |
1428 | .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), |
1429 | .mclk_dividers = sun4i_i2s_mclk_div, |
1430 | .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), |
1431 | .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, |
1432 | .get_sr = sun4i_i2s_get_sr, |
1433 | .get_wss = sun4i_i2s_get_wss, |
1434 | .set_chan_cfg = sun4i_i2s_set_chan_cfg, |
1435 | .set_fmt = sun4i_i2s_set_soc_fmt, |
1436 | }; |
1437 | |
1438 | static const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { |
1439 | .has_reset = true, |
1440 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
1441 | .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, |
1442 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), |
1443 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), |
1444 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), |
1445 | .bclk_dividers = sun8i_i2s_clk_div, |
1446 | .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
1447 | .mclk_dividers = sun8i_i2s_clk_div, |
1448 | .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
1449 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, |
1450 | .get_sr = sun8i_i2s_get_sr_wss, |
1451 | .get_wss = sun8i_i2s_get_sr_wss, |
1452 | .set_chan_cfg = sun50i_h6_i2s_set_chan_cfg, |
1453 | .set_fmt = sun50i_h6_i2s_set_soc_fmt, |
1454 | }; |
1455 | |
1456 | static const struct sun4i_i2s_quirks sun50i_r329_i2s_quirks = { |
1457 | .has_reset = true, |
1458 | .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, |
1459 | .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, |
1460 | .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), |
1461 | .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), |
1462 | .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), |
1463 | .num_din_pins = 4, |
1464 | .num_dout_pins = 4, |
1465 | .bclk_dividers = sun8i_i2s_clk_div, |
1466 | .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
1467 | .mclk_dividers = sun8i_i2s_clk_div, |
1468 | .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), |
1469 | .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, |
1470 | .get_sr = sun8i_i2s_get_sr_wss, |
1471 | .get_wss = sun8i_i2s_get_sr_wss, |
1472 | .set_chan_cfg = sun50i_h6_i2s_set_chan_cfg, |
1473 | .set_fmt = sun50i_h6_i2s_set_soc_fmt, |
1474 | }; |
1475 | |
1476 | static int sun4i_i2s_init_regmap_fields(struct device *dev, |
1477 | struct sun4i_i2s *i2s) |
1478 | { |
1479 | i2s->field_clkdiv_mclk_en = |
1480 | devm_regmap_field_alloc(dev, regmap: i2s->regmap, |
1481 | reg_field: i2s->variant->field_clkdiv_mclk_en); |
1482 | if (IS_ERR(ptr: i2s->field_clkdiv_mclk_en)) |
1483 | return PTR_ERR(ptr: i2s->field_clkdiv_mclk_en); |
1484 | |
1485 | i2s->field_fmt_wss = |
1486 | devm_regmap_field_alloc(dev, regmap: i2s->regmap, |
1487 | reg_field: i2s->variant->field_fmt_wss); |
1488 | if (IS_ERR(ptr: i2s->field_fmt_wss)) |
1489 | return PTR_ERR(ptr: i2s->field_fmt_wss); |
1490 | |
1491 | i2s->field_fmt_sr = |
1492 | devm_regmap_field_alloc(dev, regmap: i2s->regmap, |
1493 | reg_field: i2s->variant->field_fmt_sr); |
1494 | if (IS_ERR(ptr: i2s->field_fmt_sr)) |
1495 | return PTR_ERR(ptr: i2s->field_fmt_sr); |
1496 | |
1497 | return 0; |
1498 | } |
1499 | |
1500 | static int sun4i_i2s_probe(struct platform_device *pdev) |
1501 | { |
1502 | struct sun4i_i2s *i2s; |
1503 | struct resource *res; |
1504 | void __iomem *regs; |
1505 | int irq, ret; |
1506 | |
1507 | i2s = devm_kzalloc(dev: &pdev->dev, size: sizeof(*i2s), GFP_KERNEL); |
1508 | if (!i2s) |
1509 | return -ENOMEM; |
1510 | platform_set_drvdata(pdev, data: i2s); |
1511 | |
1512 | regs = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
1513 | if (IS_ERR(ptr: regs)) |
1514 | return PTR_ERR(ptr: regs); |
1515 | |
1516 | irq = platform_get_irq(pdev, 0); |
1517 | if (irq < 0) |
1518 | return irq; |
1519 | |
1520 | i2s->variant = of_device_get_match_data(dev: &pdev->dev); |
1521 | if (!i2s->variant) { |
1522 | dev_err(&pdev->dev, "Failed to determine the quirks to use\n" ); |
1523 | return -ENODEV; |
1524 | } |
1525 | |
1526 | i2s->bus_clk = devm_clk_get(dev: &pdev->dev, id: "apb" ); |
1527 | if (IS_ERR(ptr: i2s->bus_clk)) { |
1528 | dev_err(&pdev->dev, "Can't get our bus clock\n" ); |
1529 | return PTR_ERR(ptr: i2s->bus_clk); |
1530 | } |
1531 | |
1532 | i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, |
1533 | i2s->variant->sun4i_i2s_regmap); |
1534 | if (IS_ERR(ptr: i2s->regmap)) { |
1535 | dev_err(&pdev->dev, "Regmap initialisation failed\n" ); |
1536 | return PTR_ERR(ptr: i2s->regmap); |
1537 | } |
1538 | |
1539 | i2s->mod_clk = devm_clk_get(dev: &pdev->dev, id: "mod" ); |
1540 | if (IS_ERR(ptr: i2s->mod_clk)) { |
1541 | dev_err(&pdev->dev, "Can't get our mod clock\n" ); |
1542 | return PTR_ERR(ptr: i2s->mod_clk); |
1543 | } |
1544 | |
1545 | if (i2s->variant->has_reset) { |
1546 | i2s->rst = devm_reset_control_get_exclusive(dev: &pdev->dev, NULL); |
1547 | if (IS_ERR(ptr: i2s->rst)) { |
1548 | dev_err(&pdev->dev, "Failed to get reset control\n" ); |
1549 | return PTR_ERR(ptr: i2s->rst); |
1550 | } |
1551 | } |
1552 | |
1553 | if (!IS_ERR(ptr: i2s->rst)) { |
1554 | ret = reset_control_deassert(rstc: i2s->rst); |
1555 | if (ret) { |
1556 | dev_err(&pdev->dev, |
1557 | "Failed to deassert the reset control\n" ); |
1558 | return -EINVAL; |
1559 | } |
1560 | } |
1561 | |
1562 | i2s->playback_dma_data.addr = res->start + |
1563 | i2s->variant->reg_offset_txdata; |
1564 | i2s->playback_dma_data.maxburst = 8; |
1565 | |
1566 | i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG; |
1567 | i2s->capture_dma_data.maxburst = 8; |
1568 | |
1569 | pm_runtime_enable(dev: &pdev->dev); |
1570 | if (!pm_runtime_enabled(dev: &pdev->dev)) { |
1571 | ret = sun4i_i2s_runtime_resume(dev: &pdev->dev); |
1572 | if (ret) |
1573 | goto err_pm_disable; |
1574 | } |
1575 | |
1576 | ret = sun4i_i2s_init_regmap_fields(dev: &pdev->dev, i2s); |
1577 | if (ret) { |
1578 | dev_err(&pdev->dev, "Could not initialise regmap fields\n" ); |
1579 | goto err_suspend; |
1580 | } |
1581 | |
1582 | ret = devm_snd_dmaengine_pcm_register(dev: &pdev->dev, NULL, flags: 0); |
1583 | if (ret) { |
1584 | dev_err(&pdev->dev, "Could not register PCM\n" ); |
1585 | goto err_suspend; |
1586 | } |
1587 | |
1588 | ret = devm_snd_soc_register_component(dev: &pdev->dev, |
1589 | component_driver: &sun4i_i2s_component, |
1590 | dai_drv: &sun4i_i2s_dai, num_dai: 1); |
1591 | if (ret) { |
1592 | dev_err(&pdev->dev, "Could not register DAI\n" ); |
1593 | goto err_suspend; |
1594 | } |
1595 | |
1596 | return 0; |
1597 | |
1598 | err_suspend: |
1599 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
1600 | sun4i_i2s_runtime_suspend(dev: &pdev->dev); |
1601 | err_pm_disable: |
1602 | pm_runtime_disable(dev: &pdev->dev); |
1603 | if (!IS_ERR(ptr: i2s->rst)) |
1604 | reset_control_assert(rstc: i2s->rst); |
1605 | |
1606 | return ret; |
1607 | } |
1608 | |
1609 | static void sun4i_i2s_remove(struct platform_device *pdev) |
1610 | { |
1611 | struct sun4i_i2s *i2s = dev_get_drvdata(dev: &pdev->dev); |
1612 | |
1613 | pm_runtime_disable(dev: &pdev->dev); |
1614 | if (!pm_runtime_status_suspended(dev: &pdev->dev)) |
1615 | sun4i_i2s_runtime_suspend(dev: &pdev->dev); |
1616 | |
1617 | if (!IS_ERR(ptr: i2s->rst)) |
1618 | reset_control_assert(rstc: i2s->rst); |
1619 | } |
1620 | |
1621 | static const struct of_device_id sun4i_i2s_match[] = { |
1622 | { |
1623 | .compatible = "allwinner,sun4i-a10-i2s" , |
1624 | .data = &sun4i_a10_i2s_quirks, |
1625 | }, |
1626 | { |
1627 | .compatible = "allwinner,sun6i-a31-i2s" , |
1628 | .data = &sun6i_a31_i2s_quirks, |
1629 | }, |
1630 | { |
1631 | .compatible = "allwinner,sun8i-a83t-i2s" , |
1632 | .data = &sun8i_a83t_i2s_quirks, |
1633 | }, |
1634 | { |
1635 | .compatible = "allwinner,sun8i-h3-i2s" , |
1636 | .data = &sun8i_h3_i2s_quirks, |
1637 | }, |
1638 | { |
1639 | .compatible = "allwinner,sun50i-a64-codec-i2s" , |
1640 | .data = &sun50i_a64_codec_i2s_quirks, |
1641 | }, |
1642 | { |
1643 | .compatible = "allwinner,sun50i-h6-i2s" , |
1644 | .data = &sun50i_h6_i2s_quirks, |
1645 | }, |
1646 | { |
1647 | .compatible = "allwinner,sun50i-r329-i2s" , |
1648 | .data = &sun50i_r329_i2s_quirks, |
1649 | }, |
1650 | {} |
1651 | }; |
1652 | MODULE_DEVICE_TABLE(of, sun4i_i2s_match); |
1653 | |
1654 | static const struct dev_pm_ops sun4i_i2s_pm_ops = { |
1655 | .runtime_resume = sun4i_i2s_runtime_resume, |
1656 | .runtime_suspend = sun4i_i2s_runtime_suspend, |
1657 | }; |
1658 | |
1659 | static struct platform_driver sun4i_i2s_driver = { |
1660 | .probe = sun4i_i2s_probe, |
1661 | .remove_new = sun4i_i2s_remove, |
1662 | .driver = { |
1663 | .name = "sun4i-i2s" , |
1664 | .of_match_table = sun4i_i2s_match, |
1665 | .pm = &sun4i_i2s_pm_ops, |
1666 | }, |
1667 | }; |
1668 | module_platform_driver(sun4i_i2s_driver); |
1669 | |
1670 | MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>" ); |
1671 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>" ); |
1672 | MODULE_DESCRIPTION("Allwinner A10 I2S driver" ); |
1673 | MODULE_LICENSE("GPL" ); |
1674 | |