1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Driver for Microchip I2S Multi-channel controller |
4 | // |
5 | // Copyright (C) 2018 Microchip Technology Inc. and its subsidiaries |
6 | // |
7 | // Author: Codrin Ciubotariu <codrin.ciubotariu@microchip.com> |
8 | |
9 | #include <linux/init.h> |
10 | #include <linux/module.h> |
11 | #include <linux/device.h> |
12 | #include <linux/slab.h> |
13 | |
14 | #include <linux/delay.h> |
15 | #include <linux/io.h> |
16 | #include <linux/clk.h> |
17 | #include <linux/mfd/syscon.h> |
18 | #include <linux/lcm.h> |
19 | #include <linux/of.h> |
20 | |
21 | #include <sound/core.h> |
22 | #include <sound/pcm.h> |
23 | #include <sound/pcm_params.h> |
24 | #include <sound/initval.h> |
25 | #include <sound/soc.h> |
26 | #include <sound/dmaengine_pcm.h> |
27 | |
28 | /* |
29 | * ---- I2S Controller Register map ---- |
30 | */ |
31 | #define MCHP_I2SMCC_CR 0x0000 /* Control Register */ |
32 | #define MCHP_I2SMCC_MRA 0x0004 /* Mode Register A */ |
33 | #define MCHP_I2SMCC_MRB 0x0008 /* Mode Register B */ |
34 | #define MCHP_I2SMCC_SR 0x000C /* Status Register */ |
35 | #define MCHP_I2SMCC_IERA 0x0010 /* Interrupt Enable Register A */ |
36 | #define MCHP_I2SMCC_IDRA 0x0014 /* Interrupt Disable Register A */ |
37 | #define MCHP_I2SMCC_IMRA 0x0018 /* Interrupt Mask Register A */ |
38 | #define MCHP_I2SMCC_ISRA 0X001C /* Interrupt Status Register A */ |
39 | |
40 | #define MCHP_I2SMCC_IERB 0x0020 /* Interrupt Enable Register B */ |
41 | #define MCHP_I2SMCC_IDRB 0x0024 /* Interrupt Disable Register B */ |
42 | #define MCHP_I2SMCC_IMRB 0x0028 /* Interrupt Mask Register B */ |
43 | #define MCHP_I2SMCC_ISRB 0X002C /* Interrupt Status Register B */ |
44 | |
45 | #define MCHP_I2SMCC_RHR 0x0030 /* Receiver Holding Register */ |
46 | #define MCHP_I2SMCC_THR 0x0034 /* Transmitter Holding Register */ |
47 | |
48 | #define MCHP_I2SMCC_RHL0R 0x0040 /* Receiver Holding Left 0 Register */ |
49 | #define MCHP_I2SMCC_RHR0R 0x0044 /* Receiver Holding Right 0 Register */ |
50 | |
51 | #define MCHP_I2SMCC_RHL1R 0x0048 /* Receiver Holding Left 1 Register */ |
52 | #define MCHP_I2SMCC_RHR1R 0x004C /* Receiver Holding Right 1 Register */ |
53 | |
54 | #define MCHP_I2SMCC_RHL2R 0x0050 /* Receiver Holding Left 2 Register */ |
55 | #define MCHP_I2SMCC_RHR2R 0x0054 /* Receiver Holding Right 2 Register */ |
56 | |
57 | #define MCHP_I2SMCC_RHL3R 0x0058 /* Receiver Holding Left 3 Register */ |
58 | #define MCHP_I2SMCC_RHR3R 0x005C /* Receiver Holding Right 3 Register */ |
59 | |
60 | #define MCHP_I2SMCC_THL0R 0x0060 /* Transmitter Holding Left 0 Register */ |
61 | #define MCHP_I2SMCC_THR0R 0x0064 /* Transmitter Holding Right 0 Register */ |
62 | |
63 | #define MCHP_I2SMCC_THL1R 0x0068 /* Transmitter Holding Left 1 Register */ |
64 | #define MCHP_I2SMCC_THR1R 0x006C /* Transmitter Holding Right 1 Register */ |
65 | |
66 | #define MCHP_I2SMCC_THL2R 0x0070 /* Transmitter Holding Left 2 Register */ |
67 | #define MCHP_I2SMCC_THR2R 0x0074 /* Transmitter Holding Right 2 Register */ |
68 | |
69 | #define MCHP_I2SMCC_THL3R 0x0078 /* Transmitter Holding Left 3 Register */ |
70 | #define MCHP_I2SMCC_THR3R 0x007C /* Transmitter Holding Right 3 Register */ |
71 | |
72 | #define MCHP_I2SMCC_VERSION 0x00FC /* Version Register */ |
73 | |
74 | /* |
75 | * ---- Control Register (Write-only) ---- |
76 | */ |
77 | #define MCHP_I2SMCC_CR_RXEN BIT(0) /* Receiver Enable */ |
78 | #define MCHP_I2SMCC_CR_RXDIS BIT(1) /* Receiver Disable */ |
79 | #define MCHP_I2SMCC_CR_CKEN BIT(2) /* Clock Enable */ |
80 | #define MCHP_I2SMCC_CR_CKDIS BIT(3) /* Clock Disable */ |
81 | #define MCHP_I2SMCC_CR_TXEN BIT(4) /* Transmitter Enable */ |
82 | #define MCHP_I2SMCC_CR_TXDIS BIT(5) /* Transmitter Disable */ |
83 | #define MCHP_I2SMCC_CR_SWRST BIT(7) /* Software Reset */ |
84 | |
85 | /* |
86 | * ---- Mode Register A (Read/Write) ---- |
87 | */ |
88 | #define MCHP_I2SMCC_MRA_MODE_MASK GENMASK(0, 0) |
89 | #define MCHP_I2SMCC_MRA_MODE_SLAVE (0 << 0) |
90 | #define MCHP_I2SMCC_MRA_MODE_MASTER (1 << 0) |
91 | |
92 | #define MCHP_I2SMCC_MRA_DATALENGTH_MASK GENMASK(3, 1) |
93 | #define MCHP_I2SMCC_MRA_DATALENGTH_32_BITS (0 << 1) |
94 | #define MCHP_I2SMCC_MRA_DATALENGTH_24_BITS (1 << 1) |
95 | #define MCHP_I2SMCC_MRA_DATALENGTH_20_BITS (2 << 1) |
96 | #define MCHP_I2SMCC_MRA_DATALENGTH_18_BITS (3 << 1) |
97 | #define MCHP_I2SMCC_MRA_DATALENGTH_16_BITS (4 << 1) |
98 | #define MCHP_I2SMCC_MRA_DATALENGTH_16_BITS_COMPACT (5 << 1) |
99 | #define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS (6 << 1) |
100 | #define MCHP_I2SMCC_MRA_DATALENGTH_8_BITS_COMPACT (7 << 1) |
101 | |
102 | #define MCHP_I2SMCC_MRA_WIRECFG_MASK GENMASK(5, 4) |
103 | #define MCHP_I2SMCC_MRA_WIRECFG_TDM(pin) (((pin) << 4) & \ |
104 | MCHP_I2SMCC_MRA_WIRECFG_MASK) |
105 | #define MCHP_I2SMCC_MRA_WIRECFG_I2S_1_TDM_0 (0 << 4) |
106 | #define MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1 (1 << 4) |
107 | #define MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2 (2 << 4) |
108 | #define MCHP_I2SMCC_MRA_WIRECFG_TDM_3 (3 << 4) |
109 | |
110 | #define MCHP_I2SMCC_MRA_FORMAT_MASK GENMASK(7, 6) |
111 | #define MCHP_I2SMCC_MRA_FORMAT_I2S (0 << 6) |
112 | #define MCHP_I2SMCC_MRA_FORMAT_LJ (1 << 6) /* Left Justified */ |
113 | #define MCHP_I2SMCC_MRA_FORMAT_TDM (2 << 6) |
114 | #define MCHP_I2SMCC_MRA_FORMAT_TDMLJ (3 << 6) |
115 | |
116 | /* Transmitter uses one DMA channel ... */ |
117 | /* Left audio samples duplicated to right audio channel */ |
118 | #define MCHP_I2SMCC_MRA_RXMONO BIT(8) |
119 | |
120 | /* I2SDO output of I2SC is internally connected to I2SDI input */ |
121 | #define MCHP_I2SMCC_MRA_RXLOOP BIT(9) |
122 | |
123 | /* Receiver uses one DMA channel ... */ |
124 | /* Left audio samples duplicated to right audio channel */ |
125 | #define MCHP_I2SMCC_MRA_TXMONO BIT(10) |
126 | |
127 | /* x sample transmitted when underrun */ |
128 | #define MCHP_I2SMCC_MRA_TXSAME_ZERO (0 << 11) /* Zero sample */ |
129 | #define MCHP_I2SMCC_MRA_TXSAME_PREVIOUS (1 << 11) /* Previous sample */ |
130 | |
131 | /* select between peripheral clock and generated clock */ |
132 | #define MCHP_I2SMCC_MRA_SRCCLK_PCLK (0 << 12) |
133 | #define MCHP_I2SMCC_MRA_SRCCLK_GCLK (1 << 12) |
134 | |
135 | /* Number of TDM Channels - 1 */ |
136 | #define MCHP_I2SMCC_MRA_NBCHAN_MASK GENMASK(15, 13) |
137 | #define MCHP_I2SMCC_MRA_NBCHAN(ch) \ |
138 | ((((ch) - 1) << 13) & MCHP_I2SMCC_MRA_NBCHAN_MASK) |
139 | |
140 | /* Selected Clock to I2SMCC Master Clock ratio */ |
141 | #define MCHP_I2SMCC_MRA_IMCKDIV_MASK GENMASK(21, 16) |
142 | #define MCHP_I2SMCC_MRA_IMCKDIV(div) \ |
143 | (((div) << 16) & MCHP_I2SMCC_MRA_IMCKDIV_MASK) |
144 | |
145 | /* TDM Frame Synchronization */ |
146 | #define MCHP_I2SMCC_MRA_TDMFS_MASK GENMASK(23, 22) |
147 | #define MCHP_I2SMCC_MRA_TDMFS_SLOT (0 << 22) |
148 | #define MCHP_I2SMCC_MRA_TDMFS_HALF (1 << 22) |
149 | #define MCHP_I2SMCC_MRA_TDMFS_BIT (2 << 22) |
150 | |
151 | /* Selected Clock to I2SMC Serial Clock ratio */ |
152 | #define MCHP_I2SMCC_MRA_ISCKDIV_MASK GENMASK(29, 24) |
153 | #define MCHP_I2SMCC_MRA_ISCKDIV(div) \ |
154 | (((div) << 24) & MCHP_I2SMCC_MRA_ISCKDIV_MASK) |
155 | |
156 | /* Master Clock mode */ |
157 | #define MCHP_I2SMCC_MRA_IMCKMODE_MASK GENMASK(30, 30) |
158 | /* 0: No master clock generated*/ |
159 | #define MCHP_I2SMCC_MRA_IMCKMODE_NONE (0 << 30) |
160 | /* 1: master clock generated (internally generated clock drives I2SMCK pin) */ |
161 | #define MCHP_I2SMCC_MRA_IMCKMODE_GEN (1 << 30) |
162 | |
163 | /* Slot Width */ |
164 | /* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */ |
165 | /* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */ |
166 | #define MCHP_I2SMCC_MRA_IWS BIT(31) |
167 | |
168 | /* |
169 | * ---- Mode Register B (Read/Write) ---- |
170 | */ |
171 | /* all enabled I2S left channels are filled first, then I2S right channels */ |
172 | #define MCHP_I2SMCC_MRB_CRAMODE_LEFT_FIRST (0 << 0) |
173 | /* |
174 | * an enabled I2S left channel is filled, then the corresponding right |
175 | * channel, until all channels are filled |
176 | */ |
177 | #define MCHP_I2SMCC_MRB_CRAMODE_REGULAR (1 << 0) |
178 | |
179 | #define MCHP_I2SMCC_MRB_FIFOEN BIT(4) |
180 | |
181 | #define MCHP_I2SMCC_MRB_DMACHUNK_MASK GENMASK(9, 8) |
182 | #define MCHP_I2SMCC_MRB_DMACHUNK(no_words) \ |
183 | (((fls(no_words) - 1) << 8) & MCHP_I2SMCC_MRB_DMACHUNK_MASK) |
184 | |
185 | #define MCHP_I2SMCC_MRB_CLKSEL_MASK GENMASK(16, 16) |
186 | #define MCHP_I2SMCC_MRB_CLKSEL_EXT (0 << 16) |
187 | #define MCHP_I2SMCC_MRB_CLKSEL_INT (1 << 16) |
188 | |
189 | /* |
190 | * ---- Status Registers (Read-only) ---- |
191 | */ |
192 | #define MCHP_I2SMCC_SR_RXEN BIT(0) /* Receiver Enabled */ |
193 | #define MCHP_I2SMCC_SR_TXEN BIT(4) /* Transmitter Enabled */ |
194 | |
195 | /* |
196 | * ---- Interrupt Enable/Disable/Mask/Status Registers A ---- |
197 | */ |
198 | #define MCHP_I2SMCC_INT_TXRDY_MASK(ch) GENMASK((ch) - 1, 0) |
199 | #define MCHP_I2SMCC_INT_TXRDYCH(ch) BIT(ch) |
200 | #define MCHP_I2SMCC_INT_TXUNF_MASK(ch) GENMASK((ch) + 7, 8) |
201 | #define MCHP_I2SMCC_INT_TXUNFCH(ch) BIT((ch) + 8) |
202 | #define MCHP_I2SMCC_INT_RXRDY_MASK(ch) GENMASK((ch) + 15, 16) |
203 | #define MCHP_I2SMCC_INT_RXRDYCH(ch) BIT((ch) + 16) |
204 | #define MCHP_I2SMCC_INT_RXOVF_MASK(ch) GENMASK((ch) + 23, 24) |
205 | #define MCHP_I2SMCC_INT_RXOVFCH(ch) BIT((ch) + 24) |
206 | |
207 | /* |
208 | * ---- Interrupt Enable/Disable/Mask/Status Registers B ---- |
209 | */ |
210 | #define MCHP_I2SMCC_INT_WERR BIT(0) |
211 | #define MCHP_I2SMCC_INT_TXFFRDY BIT(8) |
212 | #define MCHP_I2SMCC_INT_TXFFEMP BIT(9) |
213 | #define MCHP_I2SMCC_INT_RXFFRDY BIT(12) |
214 | #define MCHP_I2SMCC_INT_RXFFFUL BIT(13) |
215 | |
216 | /* |
217 | * ---- Version Register (Read-only) ---- |
218 | */ |
219 | #define MCHP_I2SMCC_VERSION_MASK GENMASK(11, 0) |
220 | |
221 | #define MCHP_I2SMCC_MAX_CHANNELS 8 |
222 | #define MCHP_I2MCC_TDM_SLOT_WIDTH 32 |
223 | |
224 | static const struct regmap_config mchp_i2s_mcc_regmap_config = { |
225 | .reg_bits = 32, |
226 | .reg_stride = 4, |
227 | .val_bits = 32, |
228 | .max_register = MCHP_I2SMCC_VERSION, |
229 | }; |
230 | |
231 | struct mchp_i2s_mcc_soc_data { |
232 | unsigned int data_pin_pair_num; |
233 | bool has_fifo; |
234 | }; |
235 | |
236 | struct mchp_i2s_mcc_dev { |
237 | struct wait_queue_head wq_txrdy; |
238 | struct wait_queue_head wq_rxrdy; |
239 | struct device *dev; |
240 | struct regmap *regmap; |
241 | struct clk *pclk; |
242 | struct clk *gclk; |
243 | const struct mchp_i2s_mcc_soc_data *soc; |
244 | struct snd_dmaengine_dai_dma_data playback; |
245 | struct snd_dmaengine_dai_dma_data capture; |
246 | unsigned int fmt; |
247 | unsigned int sysclk; |
248 | unsigned int frame_length; |
249 | int tdm_slots; |
250 | int channels; |
251 | u8 tdm_data_pair; |
252 | unsigned int gclk_use:1; |
253 | unsigned int gclk_running:1; |
254 | unsigned int tx_rdy:1; |
255 | unsigned int rx_rdy:1; |
256 | }; |
257 | |
258 | static irqreturn_t mchp_i2s_mcc_interrupt(int irq, void *dev_id) |
259 | { |
260 | struct mchp_i2s_mcc_dev *dev = dev_id; |
261 | u32 sra, imra, srb, imrb, pendinga, pendingb, idra = 0, idrb = 0; |
262 | irqreturn_t ret = IRQ_NONE; |
263 | |
264 | regmap_read(map: dev->regmap, MCHP_I2SMCC_IMRA, val: &imra); |
265 | regmap_read(map: dev->regmap, MCHP_I2SMCC_ISRA, val: &sra); |
266 | pendinga = imra & sra; |
267 | |
268 | regmap_read(map: dev->regmap, MCHP_I2SMCC_IMRB, val: &imrb); |
269 | regmap_read(map: dev->regmap, MCHP_I2SMCC_ISRB, val: &srb); |
270 | pendingb = imrb & srb; |
271 | |
272 | if (!pendinga && !pendingb) |
273 | return IRQ_NONE; |
274 | |
275 | /* |
276 | * Tx/Rx ready interrupts are enabled when stopping only, to assure |
277 | * availability and to disable clocks if necessary |
278 | */ |
279 | if (dev->soc->has_fifo) { |
280 | idrb |= pendingb & (MCHP_I2SMCC_INT_TXFFRDY | |
281 | MCHP_I2SMCC_INT_RXFFRDY); |
282 | } else { |
283 | idra |= pendinga & (MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels) | |
284 | MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); |
285 | } |
286 | if (idra || idrb) |
287 | ret = IRQ_HANDLED; |
288 | |
289 | if ((!dev->soc->has_fifo && |
290 | (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) && |
291 | (imra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)) == |
292 | (idra & MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels))) || |
293 | (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_TXFFRDY)) { |
294 | dev->tx_rdy = 1; |
295 | wake_up_interruptible(&dev->wq_txrdy); |
296 | } |
297 | if ((!dev->soc->has_fifo && |
298 | (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) && |
299 | (imra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)) == |
300 | (idra & MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels))) || |
301 | (dev->soc->has_fifo && imrb & MCHP_I2SMCC_INT_RXFFRDY)) { |
302 | dev->rx_rdy = 1; |
303 | wake_up_interruptible(&dev->wq_rxrdy); |
304 | } |
305 | if (dev->soc->has_fifo) |
306 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IDRB, val: idrb); |
307 | else |
308 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IDRA, val: idra); |
309 | |
310 | return ret; |
311 | } |
312 | |
313 | static int mchp_i2s_mcc_set_sysclk(struct snd_soc_dai *dai, |
314 | int clk_id, unsigned int freq, int dir) |
315 | { |
316 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
317 | |
318 | dev_dbg(dev->dev, "%s() clk_id=%d freq=%u dir=%d\n" , |
319 | __func__, clk_id, freq, dir); |
320 | |
321 | /* We do not need SYSCLK */ |
322 | if (dir == SND_SOC_CLOCK_IN) |
323 | return 0; |
324 | |
325 | dev->sysclk = freq; |
326 | |
327 | return 0; |
328 | } |
329 | |
330 | static int mchp_i2s_mcc_set_bclk_ratio(struct snd_soc_dai *dai, |
331 | unsigned int ratio) |
332 | { |
333 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
334 | |
335 | dev_dbg(dev->dev, "%s() ratio=%u\n" , __func__, ratio); |
336 | |
337 | dev->frame_length = ratio; |
338 | |
339 | return 0; |
340 | } |
341 | |
342 | static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) |
343 | { |
344 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
345 | |
346 | dev_dbg(dev->dev, "%s() fmt=%#x\n" , __func__, fmt); |
347 | |
348 | /* We don't support any kind of clock inversion */ |
349 | if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) |
350 | return -EINVAL; |
351 | |
352 | /* We can't generate only FSYNC */ |
353 | if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_BC_FP) |
354 | return -EINVAL; |
355 | |
356 | /* We can only reconfigure the IP when it's stopped */ |
357 | if (fmt & SND_SOC_DAIFMT_CONT) |
358 | return -EINVAL; |
359 | |
360 | dev->fmt = fmt; |
361 | |
362 | return 0; |
363 | } |
364 | |
365 | static int mchp_i2s_mcc_set_dai_tdm_slot(struct snd_soc_dai *dai, |
366 | unsigned int tx_mask, |
367 | unsigned int rx_mask, |
368 | int slots, int slot_width) |
369 | { |
370 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
371 | |
372 | dev_dbg(dev->dev, |
373 | "%s() tx_mask=0x%08x rx_mask=0x%08x slots=%d width=%d\n" , |
374 | __func__, tx_mask, rx_mask, slots, slot_width); |
375 | |
376 | if (slots < 0 || slots > MCHP_I2SMCC_MAX_CHANNELS || |
377 | slot_width != MCHP_I2MCC_TDM_SLOT_WIDTH) |
378 | return -EINVAL; |
379 | |
380 | if (slots) { |
381 | /* We do not support daisy chain */ |
382 | if (rx_mask != GENMASK(slots - 1, 0) || |
383 | rx_mask != tx_mask) |
384 | return -EINVAL; |
385 | } |
386 | |
387 | dev->tdm_slots = slots; |
388 | dev->frame_length = slots * MCHP_I2MCC_TDM_SLOT_WIDTH; |
389 | |
390 | return 0; |
391 | } |
392 | |
393 | static int mchp_i2s_mcc_clk_get_rate_diff(struct clk *clk, |
394 | unsigned long rate, |
395 | struct clk **best_clk, |
396 | unsigned long *best_rate, |
397 | unsigned long *best_diff_rate) |
398 | { |
399 | long round_rate; |
400 | unsigned int diff_rate; |
401 | |
402 | round_rate = clk_round_rate(clk, rate); |
403 | if (round_rate < 0) |
404 | return (int)round_rate; |
405 | |
406 | diff_rate = abs(rate - round_rate); |
407 | if (diff_rate < *best_diff_rate) { |
408 | *best_clk = clk; |
409 | *best_diff_rate = diff_rate; |
410 | *best_rate = rate; |
411 | } |
412 | |
413 | return 0; |
414 | } |
415 | |
416 | static int mchp_i2s_mcc_config_divs(struct mchp_i2s_mcc_dev *dev, |
417 | unsigned int bclk, unsigned int *mra, |
418 | unsigned long *best_rate) |
419 | { |
420 | unsigned long clk_rate; |
421 | unsigned long lcm_rate; |
422 | unsigned long best_diff_rate = ~0; |
423 | unsigned int sysclk; |
424 | struct clk *best_clk = NULL; |
425 | int ret; |
426 | |
427 | /* For code simplification */ |
428 | if (!dev->sysclk) |
429 | sysclk = bclk; |
430 | else |
431 | sysclk = dev->sysclk; |
432 | |
433 | /* |
434 | * MCLK is Selected CLK / (2 * IMCKDIV), |
435 | * BCLK is Selected CLK / (2 * ISCKDIV); |
436 | * if IMCKDIV or ISCKDIV are 0, MCLK or BCLK = Selected CLK |
437 | */ |
438 | lcm_rate = lcm(a: sysclk, b: bclk); |
439 | if ((lcm_rate / sysclk % 2 == 1 && lcm_rate / sysclk > 2) || |
440 | (lcm_rate / bclk % 2 == 1 && lcm_rate / bclk > 2)) |
441 | lcm_rate *= 2; |
442 | |
443 | for (clk_rate = lcm_rate; |
444 | (clk_rate == sysclk || clk_rate / (sysclk * 2) <= GENMASK(5, 0)) && |
445 | (clk_rate == bclk || clk_rate / (bclk * 2) <= GENMASK(5, 0)); |
446 | clk_rate += lcm_rate) { |
447 | ret = mchp_i2s_mcc_clk_get_rate_diff(clk: dev->gclk, rate: clk_rate, |
448 | best_clk: &best_clk, best_rate, |
449 | best_diff_rate: &best_diff_rate); |
450 | if (ret) { |
451 | dev_err(dev->dev, "gclk error for rate %lu: %d" , |
452 | clk_rate, ret); |
453 | } else { |
454 | if (!best_diff_rate) { |
455 | dev_dbg(dev->dev, "found perfect rate on gclk: %lu\n" , |
456 | clk_rate); |
457 | break; |
458 | } |
459 | } |
460 | |
461 | ret = mchp_i2s_mcc_clk_get_rate_diff(clk: dev->pclk, rate: clk_rate, |
462 | best_clk: &best_clk, best_rate, |
463 | best_diff_rate: &best_diff_rate); |
464 | if (ret) { |
465 | dev_err(dev->dev, "pclk error for rate %lu: %d" , |
466 | clk_rate, ret); |
467 | } else { |
468 | if (!best_diff_rate) { |
469 | dev_dbg(dev->dev, "found perfect rate on pclk: %lu\n" , |
470 | clk_rate); |
471 | break; |
472 | } |
473 | } |
474 | } |
475 | |
476 | /* check if clocks returned only errors */ |
477 | if (!best_clk) { |
478 | dev_err(dev->dev, "unable to change rate to clocks\n" ); |
479 | return -EINVAL; |
480 | } |
481 | |
482 | dev_dbg(dev->dev, "source CLK is %s with rate %lu, diff %lu\n" , |
483 | best_clk == dev->pclk ? "pclk" : "gclk" , |
484 | *best_rate, best_diff_rate); |
485 | |
486 | /* Configure divisors */ |
487 | if (dev->sysclk) |
488 | *mra |= MCHP_I2SMCC_MRA_IMCKDIV(*best_rate / (2 * sysclk)); |
489 | *mra |= MCHP_I2SMCC_MRA_ISCKDIV(*best_rate / (2 * bclk)); |
490 | |
491 | if (best_clk == dev->gclk) |
492 | *mra |= MCHP_I2SMCC_MRA_SRCCLK_GCLK; |
493 | else |
494 | *mra |= MCHP_I2SMCC_MRA_SRCCLK_PCLK; |
495 | |
496 | return 0; |
497 | } |
498 | |
499 | static int mchp_i2s_mcc_is_running(struct mchp_i2s_mcc_dev *dev) |
500 | { |
501 | u32 sr; |
502 | |
503 | regmap_read(map: dev->regmap, MCHP_I2SMCC_SR, val: &sr); |
504 | return !!(sr & (MCHP_I2SMCC_SR_TXEN | MCHP_I2SMCC_SR_RXEN)); |
505 | } |
506 | |
507 | static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream, |
508 | struct snd_pcm_hw_params *params, |
509 | struct snd_soc_dai *dai) |
510 | { |
511 | unsigned long rate = 0; |
512 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
513 | u32 mra = 0; |
514 | u32 mrb = 0; |
515 | unsigned int channels = params_channels(p: params); |
516 | unsigned int frame_length = dev->frame_length; |
517 | unsigned int bclk_rate; |
518 | int set_divs = 0; |
519 | int ret; |
520 | bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); |
521 | |
522 | dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n" , |
523 | __func__, params_rate(params), params_format(params), |
524 | params_width(params), params_channels(params)); |
525 | |
526 | switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
527 | case SND_SOC_DAIFMT_I2S: |
528 | if (dev->tdm_slots) { |
529 | dev_err(dev->dev, "I2S with TDM is not supported\n" ); |
530 | return -EINVAL; |
531 | } |
532 | mra |= MCHP_I2SMCC_MRA_FORMAT_I2S; |
533 | break; |
534 | case SND_SOC_DAIFMT_LEFT_J: |
535 | if (dev->tdm_slots) { |
536 | dev_err(dev->dev, "Left-Justified with TDM is not supported\n" ); |
537 | return -EINVAL; |
538 | } |
539 | mra |= MCHP_I2SMCC_MRA_FORMAT_LJ; |
540 | break; |
541 | case SND_SOC_DAIFMT_DSP_A: |
542 | mra |= MCHP_I2SMCC_MRA_FORMAT_TDM; |
543 | break; |
544 | default: |
545 | dev_err(dev->dev, "unsupported bus format\n" ); |
546 | return -EINVAL; |
547 | } |
548 | |
549 | switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
550 | case SND_SOC_DAIFMT_BP_FP: |
551 | /* cpu is BCLK and LRC master */ |
552 | mra |= MCHP_I2SMCC_MRA_MODE_MASTER; |
553 | if (dev->sysclk) |
554 | mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN; |
555 | set_divs = 1; |
556 | break; |
557 | case SND_SOC_DAIFMT_BP_FC: |
558 | /* cpu is BCLK master */ |
559 | mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT; |
560 | set_divs = 1; |
561 | fallthrough; |
562 | case SND_SOC_DAIFMT_BC_FC: |
563 | /* cpu is slave */ |
564 | mra |= MCHP_I2SMCC_MRA_MODE_SLAVE; |
565 | if (dev->sysclk) |
566 | dev_warn(dev->dev, "Unable to generate MCLK in Slave mode\n" ); |
567 | break; |
568 | default: |
569 | dev_err(dev->dev, "unsupported master/slave mode\n" ); |
570 | return -EINVAL; |
571 | } |
572 | |
573 | if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) { |
574 | /* for I2S and LEFT_J one pin is needed for every 2 channels */ |
575 | if (channels > dev->soc->data_pin_pair_num * 2) { |
576 | dev_err(dev->dev, |
577 | "unsupported number of audio channels: %d\n" , |
578 | channels); |
579 | return -EINVAL; |
580 | } |
581 | |
582 | /* enable for interleaved format */ |
583 | mrb |= MCHP_I2SMCC_MRB_CRAMODE_REGULAR; |
584 | |
585 | switch (channels) { |
586 | case 1: |
587 | if (is_playback) |
588 | mra |= MCHP_I2SMCC_MRA_TXMONO; |
589 | else |
590 | mra |= MCHP_I2SMCC_MRA_RXMONO; |
591 | break; |
592 | case 2: |
593 | break; |
594 | case 4: |
595 | mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1; |
596 | break; |
597 | case 8: |
598 | mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2; |
599 | break; |
600 | default: |
601 | dev_err(dev->dev, "unsupported number of audio channels\n" ); |
602 | return -EINVAL; |
603 | } |
604 | |
605 | if (!frame_length) |
606 | frame_length = 2 * params_physical_width(p: params); |
607 | } else if (dev->fmt & SND_SOC_DAIFMT_DSP_A) { |
608 | mra |= MCHP_I2SMCC_MRA_WIRECFG_TDM(dev->tdm_data_pair); |
609 | |
610 | if (dev->tdm_slots) { |
611 | if (channels % 2 && channels * 2 <= dev->tdm_slots) { |
612 | /* |
613 | * Duplicate data for even-numbered channels |
614 | * to odd-numbered channels |
615 | */ |
616 | if (is_playback) |
617 | mra |= MCHP_I2SMCC_MRA_TXMONO; |
618 | else |
619 | mra |= MCHP_I2SMCC_MRA_RXMONO; |
620 | } |
621 | channels = dev->tdm_slots; |
622 | } |
623 | |
624 | mra |= MCHP_I2SMCC_MRA_NBCHAN(channels); |
625 | if (!frame_length) |
626 | frame_length = channels * MCHP_I2MCC_TDM_SLOT_WIDTH; |
627 | } |
628 | |
629 | /* |
630 | * We must have the same burst size configured |
631 | * in the DMA transfer and in out IP |
632 | */ |
633 | mrb |= MCHP_I2SMCC_MRB_DMACHUNK(channels); |
634 | if (is_playback) |
635 | dev->playback.maxburst = 1 << (fls(x: channels) - 1); |
636 | else |
637 | dev->capture.maxburst = 1 << (fls(x: channels) - 1); |
638 | |
639 | switch (params_format(p: params)) { |
640 | case SNDRV_PCM_FORMAT_S8: |
641 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_8_BITS; |
642 | break; |
643 | case SNDRV_PCM_FORMAT_S16_LE: |
644 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_16_BITS; |
645 | break; |
646 | case SNDRV_PCM_FORMAT_S18_3LE: |
647 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_18_BITS | |
648 | MCHP_I2SMCC_MRA_IWS; |
649 | break; |
650 | case SNDRV_PCM_FORMAT_S20_3LE: |
651 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_20_BITS | |
652 | MCHP_I2SMCC_MRA_IWS; |
653 | break; |
654 | case SNDRV_PCM_FORMAT_S24_3LE: |
655 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_24_BITS | |
656 | MCHP_I2SMCC_MRA_IWS; |
657 | break; |
658 | case SNDRV_PCM_FORMAT_S24_LE: |
659 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_24_BITS; |
660 | break; |
661 | case SNDRV_PCM_FORMAT_S32_LE: |
662 | mra |= MCHP_I2SMCC_MRA_DATALENGTH_32_BITS; |
663 | break; |
664 | default: |
665 | dev_err(dev->dev, "unsupported size/endianness for audio samples\n" ); |
666 | return -EINVAL; |
667 | } |
668 | |
669 | if (set_divs) { |
670 | bclk_rate = frame_length * params_rate(p: params); |
671 | ret = mchp_i2s_mcc_config_divs(dev, bclk: bclk_rate, mra: &mra, |
672 | best_rate: &rate); |
673 | if (ret) { |
674 | dev_err(dev->dev, |
675 | "unable to configure the divisors: %d\n" , ret); |
676 | return ret; |
677 | } |
678 | } |
679 | |
680 | /* enable FIFO if available */ |
681 | if (dev->soc->has_fifo) |
682 | mrb |= MCHP_I2SMCC_MRB_FIFOEN; |
683 | |
684 | /* |
685 | * If we are already running, the wanted setup must be |
686 | * the same with the one that's currently ongoing |
687 | */ |
688 | if (mchp_i2s_mcc_is_running(dev)) { |
689 | u32 mra_cur; |
690 | u32 mrb_cur; |
691 | |
692 | regmap_read(map: dev->regmap, MCHP_I2SMCC_MRA, val: &mra_cur); |
693 | regmap_read(map: dev->regmap, MCHP_I2SMCC_MRB, val: &mrb_cur); |
694 | if (mra != mra_cur || mrb != mrb_cur) |
695 | return -EINVAL; |
696 | |
697 | return 0; |
698 | } |
699 | |
700 | if (mra & MCHP_I2SMCC_MRA_SRCCLK_GCLK && !dev->gclk_use) { |
701 | /* set the rate */ |
702 | ret = clk_set_rate(clk: dev->gclk, rate); |
703 | if (ret) { |
704 | dev_err(dev->dev, |
705 | "unable to set rate %lu to GCLK: %d\n" , |
706 | rate, ret); |
707 | return ret; |
708 | } |
709 | |
710 | ret = clk_prepare(clk: dev->gclk); |
711 | if (ret < 0) { |
712 | dev_err(dev->dev, "unable to prepare GCLK: %d\n" , ret); |
713 | return ret; |
714 | } |
715 | dev->gclk_use = 1; |
716 | } |
717 | |
718 | /* Save the number of channels to know what interrupts to enable */ |
719 | dev->channels = channels; |
720 | |
721 | ret = regmap_write(map: dev->regmap, MCHP_I2SMCC_MRA, val: mra); |
722 | if (ret < 0) { |
723 | if (dev->gclk_use) { |
724 | clk_unprepare(clk: dev->gclk); |
725 | dev->gclk_use = 0; |
726 | } |
727 | return ret; |
728 | } |
729 | return regmap_write(map: dev->regmap, MCHP_I2SMCC_MRB, val: mrb); |
730 | } |
731 | |
732 | static int mchp_i2s_mcc_hw_free(struct snd_pcm_substream *substream, |
733 | struct snd_soc_dai *dai) |
734 | { |
735 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
736 | bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); |
737 | long err; |
738 | |
739 | if (is_playback) { |
740 | err = wait_event_interruptible_timeout(dev->wq_txrdy, |
741 | dev->tx_rdy, |
742 | msecs_to_jiffies(500)); |
743 | if (err == 0) { |
744 | dev_warn_once(dev->dev, |
745 | "Timeout waiting for Tx ready\n" ); |
746 | if (dev->soc->has_fifo) |
747 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IDRB, |
748 | MCHP_I2SMCC_INT_TXFFRDY); |
749 | else |
750 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IDRA, |
751 | MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels)); |
752 | |
753 | dev->tx_rdy = 1; |
754 | } |
755 | } else { |
756 | err = wait_event_interruptible_timeout(dev->wq_rxrdy, |
757 | dev->rx_rdy, |
758 | msecs_to_jiffies(500)); |
759 | if (err == 0) { |
760 | dev_warn_once(dev->dev, |
761 | "Timeout waiting for Rx ready\n" ); |
762 | if (dev->soc->has_fifo) |
763 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IDRB, |
764 | MCHP_I2SMCC_INT_RXFFRDY); |
765 | else |
766 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IDRA, |
767 | MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels)); |
768 | dev->rx_rdy = 1; |
769 | } |
770 | } |
771 | |
772 | if (!mchp_i2s_mcc_is_running(dev)) { |
773 | regmap_write(map: dev->regmap, MCHP_I2SMCC_CR, MCHP_I2SMCC_CR_CKDIS); |
774 | |
775 | if (dev->gclk_running) { |
776 | clk_disable(clk: dev->gclk); |
777 | dev->gclk_running = 0; |
778 | } |
779 | if (dev->gclk_use) { |
780 | clk_unprepare(clk: dev->gclk); |
781 | dev->gclk_use = 0; |
782 | } |
783 | } |
784 | |
785 | return 0; |
786 | } |
787 | |
788 | static int mchp_i2s_mcc_trigger(struct snd_pcm_substream *substream, int cmd, |
789 | struct snd_soc_dai *dai) |
790 | { |
791 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
792 | bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); |
793 | u32 cr = 0; |
794 | u32 iera = 0, ierb = 0; |
795 | u32 sr; |
796 | int err; |
797 | |
798 | switch (cmd) { |
799 | case SNDRV_PCM_TRIGGER_START: |
800 | case SNDRV_PCM_TRIGGER_RESUME: |
801 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
802 | if (is_playback) |
803 | cr = MCHP_I2SMCC_CR_TXEN | MCHP_I2SMCC_CR_CKEN; |
804 | else |
805 | cr = MCHP_I2SMCC_CR_RXEN | MCHP_I2SMCC_CR_CKEN; |
806 | break; |
807 | case SNDRV_PCM_TRIGGER_STOP: |
808 | case SNDRV_PCM_TRIGGER_SUSPEND: |
809 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
810 | regmap_read(map: dev->regmap, MCHP_I2SMCC_SR, val: &sr); |
811 | if (is_playback && (sr & MCHP_I2SMCC_SR_TXEN)) { |
812 | cr = MCHP_I2SMCC_CR_TXDIS; |
813 | dev->tx_rdy = 0; |
814 | /* |
815 | * Enable Tx Ready interrupts on all channels |
816 | * to assure all data is sent |
817 | */ |
818 | if (dev->soc->has_fifo) |
819 | ierb = MCHP_I2SMCC_INT_TXFFRDY; |
820 | else |
821 | iera = MCHP_I2SMCC_INT_TXRDY_MASK(dev->channels); |
822 | } else if (!is_playback && (sr & MCHP_I2SMCC_SR_RXEN)) { |
823 | cr = MCHP_I2SMCC_CR_RXDIS; |
824 | dev->rx_rdy = 0; |
825 | /* |
826 | * Enable Rx Ready interrupts on all channels |
827 | * to assure all data is received |
828 | */ |
829 | if (dev->soc->has_fifo) |
830 | ierb = MCHP_I2SMCC_INT_RXFFRDY; |
831 | else |
832 | iera = MCHP_I2SMCC_INT_RXRDY_MASK(dev->channels); |
833 | } |
834 | break; |
835 | default: |
836 | return -EINVAL; |
837 | } |
838 | |
839 | if ((cr & MCHP_I2SMCC_CR_CKEN) && dev->gclk_use && |
840 | !dev->gclk_running) { |
841 | err = clk_enable(clk: dev->gclk); |
842 | if (err) { |
843 | dev_err_once(dev->dev, "failed to enable GCLK: %d\n" , |
844 | err); |
845 | } else { |
846 | dev->gclk_running = 1; |
847 | } |
848 | } |
849 | |
850 | if (dev->soc->has_fifo) |
851 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IERB, val: ierb); |
852 | else |
853 | regmap_write(map: dev->regmap, MCHP_I2SMCC_IERA, val: iera); |
854 | regmap_write(map: dev->regmap, MCHP_I2SMCC_CR, val: cr); |
855 | |
856 | return 0; |
857 | } |
858 | |
859 | static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream, |
860 | struct snd_soc_dai *dai) |
861 | { |
862 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
863 | |
864 | /* Software reset the IP if it's not running */ |
865 | if (!mchp_i2s_mcc_is_running(dev)) { |
866 | return regmap_write(map: dev->regmap, MCHP_I2SMCC_CR, |
867 | MCHP_I2SMCC_CR_SWRST); |
868 | } |
869 | |
870 | return 0; |
871 | } |
872 | |
873 | static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai) |
874 | { |
875 | struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai); |
876 | |
877 | init_waitqueue_head(&dev->wq_txrdy); |
878 | init_waitqueue_head(&dev->wq_rxrdy); |
879 | dev->tx_rdy = 1; |
880 | dev->rx_rdy = 1; |
881 | |
882 | snd_soc_dai_init_dma_data(dai, playback: &dev->playback, capture: &dev->capture); |
883 | |
884 | return 0; |
885 | } |
886 | |
887 | static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = { |
888 | .probe = mchp_i2s_mcc_dai_probe, |
889 | .set_sysclk = mchp_i2s_mcc_set_sysclk, |
890 | .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio, |
891 | .startup = mchp_i2s_mcc_startup, |
892 | .trigger = mchp_i2s_mcc_trigger, |
893 | .hw_params = mchp_i2s_mcc_hw_params, |
894 | .hw_free = mchp_i2s_mcc_hw_free, |
895 | .set_fmt = mchp_i2s_mcc_set_dai_fmt, |
896 | .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot, |
897 | }; |
898 | |
899 | #define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000 |
900 | |
901 | #define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ |
902 | SNDRV_PCM_FMTBIT_S16_LE | \ |
903 | SNDRV_PCM_FMTBIT_S18_3LE | \ |
904 | SNDRV_PCM_FMTBIT_S20_3LE | \ |
905 | SNDRV_PCM_FMTBIT_S24_3LE | \ |
906 | SNDRV_PCM_FMTBIT_S24_LE | \ |
907 | SNDRV_PCM_FMTBIT_S32_LE) |
908 | |
909 | static struct snd_soc_dai_driver mchp_i2s_mcc_dai = { |
910 | .playback = { |
911 | .stream_name = "I2SMCC-Playback" , |
912 | .channels_min = 1, |
913 | .channels_max = 8, |
914 | .rates = MCHP_I2SMCC_RATES, |
915 | .formats = MCHP_I2SMCC_FORMATS, |
916 | }, |
917 | .capture = { |
918 | .stream_name = "I2SMCC-Capture" , |
919 | .channels_min = 1, |
920 | .channels_max = 8, |
921 | .rates = MCHP_I2SMCC_RATES, |
922 | .formats = MCHP_I2SMCC_FORMATS, |
923 | }, |
924 | .ops = &mchp_i2s_mcc_dai_ops, |
925 | .symmetric_rate = 1, |
926 | .symmetric_sample_bits = 1, |
927 | .symmetric_channels = 1, |
928 | }; |
929 | |
930 | static const struct snd_soc_component_driver mchp_i2s_mcc_component = { |
931 | .name = "mchp-i2s-mcc" , |
932 | .legacy_dai_naming = 1, |
933 | }; |
934 | |
935 | #ifdef CONFIG_OF |
936 | static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = { |
937 | .data_pin_pair_num = 1, |
938 | }; |
939 | |
940 | static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = { |
941 | .data_pin_pair_num = 4, |
942 | .has_fifo = true, |
943 | }; |
944 | |
945 | static const struct of_device_id mchp_i2s_mcc_dt_ids[] = { |
946 | { |
947 | .compatible = "microchip,sam9x60-i2smcc" , |
948 | .data = &mchp_i2s_mcc_sam9x60, |
949 | }, |
950 | { |
951 | .compatible = "microchip,sama7g5-i2smcc" , |
952 | .data = &mchp_i2s_mcc_sama7g5, |
953 | }, |
954 | { /* sentinel */ } |
955 | }; |
956 | MODULE_DEVICE_TABLE(of, mchp_i2s_mcc_dt_ids); |
957 | #endif |
958 | |
959 | static int mchp_i2s_mcc_soc_data_parse(struct platform_device *pdev, |
960 | struct mchp_i2s_mcc_dev *dev) |
961 | { |
962 | int err; |
963 | |
964 | if (!dev->soc) { |
965 | dev_err(&pdev->dev, "failed to get soc data\n" ); |
966 | return -ENODEV; |
967 | } |
968 | |
969 | if (dev->soc->data_pin_pair_num == 1) |
970 | return 0; |
971 | |
972 | err = of_property_read_u8(np: pdev->dev.of_node, propname: "microchip,tdm-data-pair" , |
973 | out_value: &dev->tdm_data_pair); |
974 | if (err < 0 && err != -EINVAL) { |
975 | dev_err(&pdev->dev, |
976 | "bad property data for 'microchip,tdm-data-pair': %d" , |
977 | err); |
978 | return err; |
979 | } |
980 | if (err == -EINVAL) { |
981 | dev_info(&pdev->dev, |
982 | "'microchip,tdm-data-pair' not found; assuming DIN/DOUT 0 for TDM\n" ); |
983 | dev->tdm_data_pair = 0; |
984 | } else { |
985 | if (dev->tdm_data_pair > dev->soc->data_pin_pair_num - 1) { |
986 | dev_err(&pdev->dev, |
987 | "invalid value for 'microchip,tdm-data-pair': %d\n" , |
988 | dev->tdm_data_pair); |
989 | return -EINVAL; |
990 | } |
991 | dev_dbg(&pdev->dev, "TMD format on DIN/DOUT %d pins\n" , |
992 | dev->tdm_data_pair); |
993 | } |
994 | |
995 | return 0; |
996 | } |
997 | |
998 | static int mchp_i2s_mcc_probe(struct platform_device *pdev) |
999 | { |
1000 | struct mchp_i2s_mcc_dev *dev; |
1001 | struct resource *mem; |
1002 | struct regmap *regmap; |
1003 | void __iomem *base; |
1004 | u32 version; |
1005 | int irq; |
1006 | int err; |
1007 | |
1008 | dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*dev), GFP_KERNEL); |
1009 | if (!dev) |
1010 | return -ENOMEM; |
1011 | |
1012 | base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &mem); |
1013 | if (IS_ERR(ptr: base)) |
1014 | return PTR_ERR(ptr: base); |
1015 | |
1016 | regmap = devm_regmap_init_mmio(&pdev->dev, base, |
1017 | &mchp_i2s_mcc_regmap_config); |
1018 | if (IS_ERR(ptr: regmap)) |
1019 | return PTR_ERR(ptr: regmap); |
1020 | |
1021 | irq = platform_get_irq(pdev, 0); |
1022 | if (irq < 0) |
1023 | return irq; |
1024 | |
1025 | err = devm_request_irq(dev: &pdev->dev, irq, handler: mchp_i2s_mcc_interrupt, irqflags: 0, |
1026 | devname: dev_name(dev: &pdev->dev), dev_id: dev); |
1027 | if (err) |
1028 | return err; |
1029 | |
1030 | dev->pclk = devm_clk_get(dev: &pdev->dev, id: "pclk" ); |
1031 | if (IS_ERR(ptr: dev->pclk)) { |
1032 | err = PTR_ERR(ptr: dev->pclk); |
1033 | dev_err(&pdev->dev, |
1034 | "failed to get the peripheral clock: %d\n" , err); |
1035 | return err; |
1036 | } |
1037 | |
1038 | /* Get the optional generated clock */ |
1039 | dev->gclk = devm_clk_get(dev: &pdev->dev, id: "gclk" ); |
1040 | if (IS_ERR(ptr: dev->gclk)) { |
1041 | if (PTR_ERR(ptr: dev->gclk) == -EPROBE_DEFER) |
1042 | return -EPROBE_DEFER; |
1043 | dev_warn(&pdev->dev, |
1044 | "generated clock not found: %d\n" , err); |
1045 | dev->gclk = NULL; |
1046 | } |
1047 | |
1048 | dev->soc = of_device_get_match_data(dev: &pdev->dev); |
1049 | err = mchp_i2s_mcc_soc_data_parse(pdev, dev); |
1050 | if (err < 0) |
1051 | return err; |
1052 | |
1053 | dev->dev = &pdev->dev; |
1054 | dev->regmap = regmap; |
1055 | platform_set_drvdata(pdev, data: dev); |
1056 | |
1057 | err = clk_prepare_enable(clk: dev->pclk); |
1058 | if (err) { |
1059 | dev_err(&pdev->dev, |
1060 | "failed to enable the peripheral clock: %d\n" , err); |
1061 | return err; |
1062 | } |
1063 | |
1064 | err = devm_snd_soc_register_component(dev: &pdev->dev, |
1065 | component_driver: &mchp_i2s_mcc_component, |
1066 | dai_drv: &mchp_i2s_mcc_dai, num_dai: 1); |
1067 | if (err) { |
1068 | dev_err(&pdev->dev, "failed to register DAI: %d\n" , err); |
1069 | clk_disable_unprepare(clk: dev->pclk); |
1070 | return err; |
1071 | } |
1072 | |
1073 | dev->playback.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_THR; |
1074 | dev->capture.addr = (dma_addr_t)mem->start + MCHP_I2SMCC_RHR; |
1075 | |
1076 | err = devm_snd_dmaengine_pcm_register(dev: &pdev->dev, NULL, flags: 0); |
1077 | if (err) { |
1078 | dev_err(&pdev->dev, "failed to register PCM: %d\n" , err); |
1079 | clk_disable_unprepare(clk: dev->pclk); |
1080 | return err; |
1081 | } |
1082 | |
1083 | /* Get IP version. */ |
1084 | regmap_read(map: dev->regmap, MCHP_I2SMCC_VERSION, val: &version); |
1085 | dev_info(&pdev->dev, "hw version: %#lx\n" , |
1086 | version & MCHP_I2SMCC_VERSION_MASK); |
1087 | |
1088 | return 0; |
1089 | } |
1090 | |
1091 | static void mchp_i2s_mcc_remove(struct platform_device *pdev) |
1092 | { |
1093 | struct mchp_i2s_mcc_dev *dev = platform_get_drvdata(pdev); |
1094 | |
1095 | clk_disable_unprepare(clk: dev->pclk); |
1096 | } |
1097 | |
1098 | static struct platform_driver mchp_i2s_mcc_driver = { |
1099 | .driver = { |
1100 | .name = "mchp_i2s_mcc" , |
1101 | .of_match_table = mchp_i2s_mcc_dt_ids, |
1102 | }, |
1103 | .probe = mchp_i2s_mcc_probe, |
1104 | .remove_new = mchp_i2s_mcc_remove, |
1105 | }; |
1106 | module_platform_driver(mchp_i2s_mcc_driver); |
1107 | |
1108 | MODULE_DESCRIPTION("Microchip I2S Multi-Channel Controller driver" ); |
1109 | MODULE_AUTHOR("Codrin Ciubotariu <codrin.ciubotariu@microchip.com>" ); |
1110 | MODULE_LICENSE("GPL v2" ); |
1111 | |