1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * omap-mcbsp.c -- OMAP ALSA SoC DAI driver using McBSP port |
4 | * |
5 | * Copyright (C) 2008 Nokia Corporation |
6 | * |
7 | * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com> |
8 | * Peter Ujfalusi <peter.ujfalusi@ti.com> |
9 | */ |
10 | |
11 | #include <linux/init.h> |
12 | #include <linux/module.h> |
13 | #include <linux/device.h> |
14 | #include <linux/pm_runtime.h> |
15 | #include <linux/of.h> |
16 | #include <sound/core.h> |
17 | #include <sound/pcm.h> |
18 | #include <sound/pcm_params.h> |
19 | #include <sound/initval.h> |
20 | #include <sound/soc.h> |
21 | #include <sound/dmaengine_pcm.h> |
22 | |
23 | #include "omap-mcbsp-priv.h" |
24 | #include "omap-mcbsp.h" |
25 | #include "sdma-pcm.h" |
26 | |
27 | #define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) |
28 | |
29 | enum { |
30 | OMAP_MCBSP_WORD_8 = 0, |
31 | OMAP_MCBSP_WORD_12, |
32 | OMAP_MCBSP_WORD_16, |
33 | OMAP_MCBSP_WORD_20, |
34 | OMAP_MCBSP_WORD_24, |
35 | OMAP_MCBSP_WORD_32, |
36 | }; |
37 | |
38 | static void omap_mcbsp_dump_reg(struct omap_mcbsp *mcbsp) |
39 | { |
40 | dev_dbg(mcbsp->dev, "**** McBSP%d regs ****\n" , mcbsp->id); |
41 | dev_dbg(mcbsp->dev, "DRR2: 0x%04x\n" , MCBSP_READ(mcbsp, DRR2)); |
42 | dev_dbg(mcbsp->dev, "DRR1: 0x%04x\n" , MCBSP_READ(mcbsp, DRR1)); |
43 | dev_dbg(mcbsp->dev, "DXR2: 0x%04x\n" , MCBSP_READ(mcbsp, DXR2)); |
44 | dev_dbg(mcbsp->dev, "DXR1: 0x%04x\n" , MCBSP_READ(mcbsp, DXR1)); |
45 | dev_dbg(mcbsp->dev, "SPCR2: 0x%04x\n" , MCBSP_READ(mcbsp, SPCR2)); |
46 | dev_dbg(mcbsp->dev, "SPCR1: 0x%04x\n" , MCBSP_READ(mcbsp, SPCR1)); |
47 | dev_dbg(mcbsp->dev, "RCR2: 0x%04x\n" , MCBSP_READ(mcbsp, RCR2)); |
48 | dev_dbg(mcbsp->dev, "RCR1: 0x%04x\n" , MCBSP_READ(mcbsp, RCR1)); |
49 | dev_dbg(mcbsp->dev, "XCR2: 0x%04x\n" , MCBSP_READ(mcbsp, XCR2)); |
50 | dev_dbg(mcbsp->dev, "XCR1: 0x%04x\n" , MCBSP_READ(mcbsp, XCR1)); |
51 | dev_dbg(mcbsp->dev, "SRGR2: 0x%04x\n" , MCBSP_READ(mcbsp, SRGR2)); |
52 | dev_dbg(mcbsp->dev, "SRGR1: 0x%04x\n" , MCBSP_READ(mcbsp, SRGR1)); |
53 | dev_dbg(mcbsp->dev, "PCR0: 0x%04x\n" , MCBSP_READ(mcbsp, PCR0)); |
54 | dev_dbg(mcbsp->dev, "***********************\n" ); |
55 | } |
56 | |
57 | static int omap2_mcbsp_set_clks_src(struct omap_mcbsp *mcbsp, u8 fck_src_id) |
58 | { |
59 | struct clk *fck_src; |
60 | const char *src; |
61 | int r; |
62 | |
63 | if (fck_src_id == MCBSP_CLKS_PAD_SRC) |
64 | src = "pad_fck" ; |
65 | else if (fck_src_id == MCBSP_CLKS_PRCM_SRC) |
66 | src = "prcm_fck" ; |
67 | else |
68 | return -EINVAL; |
69 | |
70 | fck_src = clk_get(dev: mcbsp->dev, id: src); |
71 | if (IS_ERR(ptr: fck_src)) { |
72 | dev_info(mcbsp->dev, "CLKS: could not clk_get() %s\n" , src); |
73 | return 0; |
74 | } |
75 | |
76 | if (mcbsp->active) |
77 | pm_runtime_put_sync(dev: mcbsp->dev); |
78 | |
79 | r = clk_set_parent(clk: mcbsp->fclk, parent: fck_src); |
80 | if (r) |
81 | dev_err(mcbsp->dev, "CLKS: could not clk_set_parent() to %s\n" , |
82 | src); |
83 | |
84 | if (mcbsp->active) |
85 | pm_runtime_get_sync(dev: mcbsp->dev); |
86 | |
87 | clk_put(clk: fck_src); |
88 | |
89 | return r; |
90 | } |
91 | |
92 | static irqreturn_t omap_mcbsp_irq_handler(int irq, void *data) |
93 | { |
94 | struct omap_mcbsp *mcbsp = data; |
95 | u16 irqst; |
96 | |
97 | irqst = MCBSP_READ(mcbsp, IRQST); |
98 | dev_dbg(mcbsp->dev, "IRQ callback : 0x%x\n" , irqst); |
99 | |
100 | if (irqst & RSYNCERREN) |
101 | dev_err(mcbsp->dev, "RX Frame Sync Error!\n" ); |
102 | if (irqst & RFSREN) |
103 | dev_dbg(mcbsp->dev, "RX Frame Sync\n" ); |
104 | if (irqst & REOFEN) |
105 | dev_dbg(mcbsp->dev, "RX End Of Frame\n" ); |
106 | if (irqst & RRDYEN) |
107 | dev_dbg(mcbsp->dev, "RX Buffer Threshold Reached\n" ); |
108 | if (irqst & RUNDFLEN) |
109 | dev_err(mcbsp->dev, "RX Buffer Underflow!\n" ); |
110 | if (irqst & ROVFLEN) |
111 | dev_err(mcbsp->dev, "RX Buffer Overflow!\n" ); |
112 | |
113 | if (irqst & XSYNCERREN) |
114 | dev_err(mcbsp->dev, "TX Frame Sync Error!\n" ); |
115 | if (irqst & XFSXEN) |
116 | dev_dbg(mcbsp->dev, "TX Frame Sync\n" ); |
117 | if (irqst & XEOFEN) |
118 | dev_dbg(mcbsp->dev, "TX End Of Frame\n" ); |
119 | if (irqst & XRDYEN) |
120 | dev_dbg(mcbsp->dev, "TX Buffer threshold Reached\n" ); |
121 | if (irqst & XUNDFLEN) |
122 | dev_err(mcbsp->dev, "TX Buffer Underflow!\n" ); |
123 | if (irqst & XOVFLEN) |
124 | dev_err(mcbsp->dev, "TX Buffer Overflow!\n" ); |
125 | if (irqst & XEMPTYEOFEN) |
126 | dev_dbg(mcbsp->dev, "TX Buffer empty at end of frame\n" ); |
127 | |
128 | MCBSP_WRITE(mcbsp, IRQST, irqst); |
129 | |
130 | return IRQ_HANDLED; |
131 | } |
132 | |
133 | static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *data) |
134 | { |
135 | struct omap_mcbsp *mcbsp = data; |
136 | u16 irqst_spcr2; |
137 | |
138 | irqst_spcr2 = MCBSP_READ(mcbsp, SPCR2); |
139 | dev_dbg(mcbsp->dev, "TX IRQ callback : 0x%x\n" , irqst_spcr2); |
140 | |
141 | if (irqst_spcr2 & XSYNC_ERR) { |
142 | dev_err(mcbsp->dev, "TX Frame Sync Error! : 0x%x\n" , |
143 | irqst_spcr2); |
144 | /* Writing zero to XSYNC_ERR clears the IRQ */ |
145 | MCBSP_WRITE(mcbsp, SPCR2, MCBSP_READ_CACHE(mcbsp, SPCR2)); |
146 | } |
147 | |
148 | return IRQ_HANDLED; |
149 | } |
150 | |
151 | static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *data) |
152 | { |
153 | struct omap_mcbsp *mcbsp = data; |
154 | u16 irqst_spcr1; |
155 | |
156 | irqst_spcr1 = MCBSP_READ(mcbsp, SPCR1); |
157 | dev_dbg(mcbsp->dev, "RX IRQ callback : 0x%x\n" , irqst_spcr1); |
158 | |
159 | if (irqst_spcr1 & RSYNC_ERR) { |
160 | dev_err(mcbsp->dev, "RX Frame Sync Error! : 0x%x\n" , |
161 | irqst_spcr1); |
162 | /* Writing zero to RSYNC_ERR clears the IRQ */ |
163 | MCBSP_WRITE(mcbsp, SPCR1, MCBSP_READ_CACHE(mcbsp, SPCR1)); |
164 | } |
165 | |
166 | return IRQ_HANDLED; |
167 | } |
168 | |
169 | /* |
170 | * omap_mcbsp_config simply write a config to the |
171 | * appropriate McBSP. |
172 | * You either call this function or set the McBSP registers |
173 | * by yourself before calling omap_mcbsp_start(). |
174 | */ |
175 | static void omap_mcbsp_config(struct omap_mcbsp *mcbsp, |
176 | const struct omap_mcbsp_reg_cfg *config) |
177 | { |
178 | dev_dbg(mcbsp->dev, "Configuring McBSP%d phys_base: 0x%08lx\n" , |
179 | mcbsp->id, mcbsp->phys_base); |
180 | |
181 | /* We write the given config */ |
182 | MCBSP_WRITE(mcbsp, SPCR2, config->spcr2); |
183 | MCBSP_WRITE(mcbsp, SPCR1, config->spcr1); |
184 | MCBSP_WRITE(mcbsp, RCR2, config->rcr2); |
185 | MCBSP_WRITE(mcbsp, RCR1, config->rcr1); |
186 | MCBSP_WRITE(mcbsp, XCR2, config->xcr2); |
187 | MCBSP_WRITE(mcbsp, XCR1, config->xcr1); |
188 | MCBSP_WRITE(mcbsp, SRGR2, config->srgr2); |
189 | MCBSP_WRITE(mcbsp, SRGR1, config->srgr1); |
190 | MCBSP_WRITE(mcbsp, MCR2, config->mcr2); |
191 | MCBSP_WRITE(mcbsp, MCR1, config->mcr1); |
192 | MCBSP_WRITE(mcbsp, PCR0, config->pcr0); |
193 | if (mcbsp->pdata->has_ccr) { |
194 | MCBSP_WRITE(mcbsp, XCCR, config->xccr); |
195 | MCBSP_WRITE(mcbsp, RCCR, config->rccr); |
196 | } |
197 | /* Enable wakeup behavior */ |
198 | if (mcbsp->pdata->has_wakeup) |
199 | MCBSP_WRITE(mcbsp, WAKEUPEN, XRDYEN | RRDYEN); |
200 | |
201 | /* Enable TX/RX sync error interrupts by default */ |
202 | if (mcbsp->irq) |
203 | MCBSP_WRITE(mcbsp, IRQEN, RSYNCERREN | XSYNCERREN | |
204 | RUNDFLEN | ROVFLEN | XUNDFLEN | XOVFLEN); |
205 | } |
206 | |
207 | /** |
208 | * omap_mcbsp_dma_reg_params - returns the address of mcbsp data register |
209 | * @mcbsp: omap_mcbsp struct for the McBSP instance |
210 | * @stream: Stream direction (playback/capture) |
211 | * |
212 | * Returns the address of mcbsp data transmit register or data receive register |
213 | * to be used by DMA for transferring/receiving data |
214 | */ |
215 | static int omap_mcbsp_dma_reg_params(struct omap_mcbsp *mcbsp, |
216 | unsigned int stream) |
217 | { |
218 | int data_reg; |
219 | |
220 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
221 | if (mcbsp->pdata->reg_size == 2) |
222 | data_reg = OMAP_MCBSP_REG_DXR1; |
223 | else |
224 | data_reg = OMAP_MCBSP_REG_DXR; |
225 | } else { |
226 | if (mcbsp->pdata->reg_size == 2) |
227 | data_reg = OMAP_MCBSP_REG_DRR1; |
228 | else |
229 | data_reg = OMAP_MCBSP_REG_DRR; |
230 | } |
231 | |
232 | return mcbsp->phys_dma_base + data_reg * mcbsp->pdata->reg_step; |
233 | } |
234 | |
235 | /* |
236 | * omap_mcbsp_set_rx_threshold configures the transmit threshold in words. |
237 | * The threshold parameter is 1 based, and it is converted (threshold - 1) |
238 | * for the THRSH2 register. |
239 | */ |
240 | static void omap_mcbsp_set_tx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) |
241 | { |
242 | if (threshold && threshold <= mcbsp->max_tx_thres) |
243 | MCBSP_WRITE(mcbsp, THRSH2, threshold - 1); |
244 | } |
245 | |
246 | /* |
247 | * omap_mcbsp_set_rx_threshold configures the receive threshold in words. |
248 | * The threshold parameter is 1 based, and it is converted (threshold - 1) |
249 | * for the THRSH1 register. |
250 | */ |
251 | static void omap_mcbsp_set_rx_threshold(struct omap_mcbsp *mcbsp, u16 threshold) |
252 | { |
253 | if (threshold && threshold <= mcbsp->max_rx_thres) |
254 | MCBSP_WRITE(mcbsp, THRSH1, threshold - 1); |
255 | } |
256 | |
257 | /* |
258 | * omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO |
259 | */ |
260 | static u16 omap_mcbsp_get_tx_delay(struct omap_mcbsp *mcbsp) |
261 | { |
262 | u16 buffstat; |
263 | |
264 | /* Returns the number of free locations in the buffer */ |
265 | buffstat = MCBSP_READ(mcbsp, XBUFFSTAT); |
266 | |
267 | /* Number of slots are different in McBSP ports */ |
268 | return mcbsp->pdata->buffer_size - buffstat; |
269 | } |
270 | |
271 | /* |
272 | * omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO |
273 | * to reach the threshold value (when the DMA will be triggered to read it) |
274 | */ |
275 | static u16 omap_mcbsp_get_rx_delay(struct omap_mcbsp *mcbsp) |
276 | { |
277 | u16 buffstat, threshold; |
278 | |
279 | /* Returns the number of used locations in the buffer */ |
280 | buffstat = MCBSP_READ(mcbsp, RBUFFSTAT); |
281 | /* RX threshold */ |
282 | threshold = MCBSP_READ(mcbsp, THRSH1); |
283 | |
284 | /* Return the number of location till we reach the threshold limit */ |
285 | if (threshold <= buffstat) |
286 | return 0; |
287 | else |
288 | return threshold - buffstat; |
289 | } |
290 | |
291 | static int omap_mcbsp_request(struct omap_mcbsp *mcbsp) |
292 | { |
293 | void *reg_cache; |
294 | int err; |
295 | |
296 | reg_cache = kzalloc(size: mcbsp->reg_cache_size, GFP_KERNEL); |
297 | if (!reg_cache) |
298 | return -ENOMEM; |
299 | |
300 | spin_lock(lock: &mcbsp->lock); |
301 | if (!mcbsp->free) { |
302 | dev_err(mcbsp->dev, "McBSP%d is currently in use\n" , mcbsp->id); |
303 | err = -EBUSY; |
304 | goto err_kfree; |
305 | } |
306 | |
307 | mcbsp->free = false; |
308 | mcbsp->reg_cache = reg_cache; |
309 | spin_unlock(lock: &mcbsp->lock); |
310 | |
311 | if(mcbsp->pdata->ops && mcbsp->pdata->ops->request) |
312 | mcbsp->pdata->ops->request(mcbsp->id - 1); |
313 | |
314 | /* |
315 | * Make sure that transmitter, receiver and sample-rate generator are |
316 | * not running before activating IRQs. |
317 | */ |
318 | MCBSP_WRITE(mcbsp, SPCR1, 0); |
319 | MCBSP_WRITE(mcbsp, SPCR2, 0); |
320 | |
321 | if (mcbsp->irq) { |
322 | err = request_irq(irq: mcbsp->irq, handler: omap_mcbsp_irq_handler, flags: 0, |
323 | name: "McBSP" , dev: (void *)mcbsp); |
324 | if (err != 0) { |
325 | dev_err(mcbsp->dev, "Unable to request IRQ\n" ); |
326 | goto err_clk_disable; |
327 | } |
328 | } else { |
329 | err = request_irq(irq: mcbsp->tx_irq, handler: omap_mcbsp_tx_irq_handler, flags: 0, |
330 | name: "McBSP TX" , dev: (void *)mcbsp); |
331 | if (err != 0) { |
332 | dev_err(mcbsp->dev, "Unable to request TX IRQ\n" ); |
333 | goto err_clk_disable; |
334 | } |
335 | |
336 | err = request_irq(irq: mcbsp->rx_irq, handler: omap_mcbsp_rx_irq_handler, flags: 0, |
337 | name: "McBSP RX" , dev: (void *)mcbsp); |
338 | if (err != 0) { |
339 | dev_err(mcbsp->dev, "Unable to request RX IRQ\n" ); |
340 | goto err_free_irq; |
341 | } |
342 | } |
343 | |
344 | return 0; |
345 | err_free_irq: |
346 | free_irq(mcbsp->tx_irq, (void *)mcbsp); |
347 | err_clk_disable: |
348 | if(mcbsp->pdata->ops && mcbsp->pdata->ops->free) |
349 | mcbsp->pdata->ops->free(mcbsp->id - 1); |
350 | |
351 | /* Disable wakeup behavior */ |
352 | if (mcbsp->pdata->has_wakeup) |
353 | MCBSP_WRITE(mcbsp, WAKEUPEN, 0); |
354 | |
355 | spin_lock(lock: &mcbsp->lock); |
356 | mcbsp->free = true; |
357 | mcbsp->reg_cache = NULL; |
358 | err_kfree: |
359 | spin_unlock(lock: &mcbsp->lock); |
360 | kfree(objp: reg_cache); |
361 | |
362 | return err; |
363 | } |
364 | |
365 | static void omap_mcbsp_free(struct omap_mcbsp *mcbsp) |
366 | { |
367 | void *reg_cache; |
368 | |
369 | if(mcbsp->pdata->ops && mcbsp->pdata->ops->free) |
370 | mcbsp->pdata->ops->free(mcbsp->id - 1); |
371 | |
372 | /* Disable wakeup behavior */ |
373 | if (mcbsp->pdata->has_wakeup) |
374 | MCBSP_WRITE(mcbsp, WAKEUPEN, 0); |
375 | |
376 | /* Disable interrupt requests */ |
377 | if (mcbsp->irq) { |
378 | MCBSP_WRITE(mcbsp, IRQEN, 0); |
379 | |
380 | free_irq(mcbsp->irq, (void *)mcbsp); |
381 | } else { |
382 | free_irq(mcbsp->rx_irq, (void *)mcbsp); |
383 | free_irq(mcbsp->tx_irq, (void *)mcbsp); |
384 | } |
385 | |
386 | reg_cache = mcbsp->reg_cache; |
387 | |
388 | /* |
389 | * Select CLKS source from internal source unconditionally before |
390 | * marking the McBSP port as free. |
391 | * If the external clock source via MCBSP_CLKS pin has been selected the |
392 | * system will refuse to enter idle if the CLKS pin source is not reset |
393 | * back to internal source. |
394 | */ |
395 | if (!mcbsp_omap1()) |
396 | omap2_mcbsp_set_clks_src(mcbsp, MCBSP_CLKS_PRCM_SRC); |
397 | |
398 | spin_lock(lock: &mcbsp->lock); |
399 | if (mcbsp->free) |
400 | dev_err(mcbsp->dev, "McBSP%d was not reserved\n" , mcbsp->id); |
401 | else |
402 | mcbsp->free = true; |
403 | mcbsp->reg_cache = NULL; |
404 | spin_unlock(lock: &mcbsp->lock); |
405 | |
406 | kfree(objp: reg_cache); |
407 | } |
408 | |
409 | /* |
410 | * Here we start the McBSP, by enabling transmitter, receiver or both. |
411 | * If no transmitter or receiver is active prior calling, then sample-rate |
412 | * generator and frame sync are started. |
413 | */ |
414 | static void omap_mcbsp_start(struct omap_mcbsp *mcbsp, int stream) |
415 | { |
416 | int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); |
417 | int rx = !tx; |
418 | int enable_srg = 0; |
419 | u16 w; |
420 | |
421 | if (mcbsp->st_data) |
422 | omap_mcbsp_st_start(mcbsp); |
423 | |
424 | /* Only enable SRG, if McBSP is master */ |
425 | w = MCBSP_READ_CACHE(mcbsp, PCR0); |
426 | if (w & (FSXM | FSRM | CLKXM | CLKRM)) |
427 | enable_srg = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | |
428 | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); |
429 | |
430 | if (enable_srg) { |
431 | /* Start the sample generator */ |
432 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); |
433 | MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 6)); |
434 | } |
435 | |
436 | /* Enable transmitter and receiver */ |
437 | tx &= 1; |
438 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); |
439 | MCBSP_WRITE(mcbsp, SPCR2, w | tx); |
440 | |
441 | rx &= 1; |
442 | w = MCBSP_READ_CACHE(mcbsp, SPCR1); |
443 | MCBSP_WRITE(mcbsp, SPCR1, w | rx); |
444 | |
445 | /* |
446 | * Worst case: CLKSRG*2 = 8000khz: (1/8000) * 2 * 2 usec |
447 | * REVISIT: 100us may give enough time for two CLKSRG, however |
448 | * due to some unknown PM related, clock gating etc. reason it |
449 | * is now at 500us. |
450 | */ |
451 | udelay(500); |
452 | |
453 | if (enable_srg) { |
454 | /* Start frame sync */ |
455 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); |
456 | MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7)); |
457 | } |
458 | |
459 | if (mcbsp->pdata->has_ccr) { |
460 | /* Release the transmitter and receiver */ |
461 | w = MCBSP_READ_CACHE(mcbsp, XCCR); |
462 | w &= ~(tx ? XDISABLE : 0); |
463 | MCBSP_WRITE(mcbsp, XCCR, w); |
464 | w = MCBSP_READ_CACHE(mcbsp, RCCR); |
465 | w &= ~(rx ? RDISABLE : 0); |
466 | MCBSP_WRITE(mcbsp, RCCR, w); |
467 | } |
468 | |
469 | /* Dump McBSP Regs */ |
470 | omap_mcbsp_dump_reg(mcbsp); |
471 | } |
472 | |
473 | static void omap_mcbsp_stop(struct omap_mcbsp *mcbsp, int stream) |
474 | { |
475 | int tx = (stream == SNDRV_PCM_STREAM_PLAYBACK); |
476 | int rx = !tx; |
477 | int idle; |
478 | u16 w; |
479 | |
480 | /* Reset transmitter */ |
481 | tx &= 1; |
482 | if (mcbsp->pdata->has_ccr) { |
483 | w = MCBSP_READ_CACHE(mcbsp, XCCR); |
484 | w |= (tx ? XDISABLE : 0); |
485 | MCBSP_WRITE(mcbsp, XCCR, w); |
486 | } |
487 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); |
488 | MCBSP_WRITE(mcbsp, SPCR2, w & ~tx); |
489 | |
490 | /* Reset receiver */ |
491 | rx &= 1; |
492 | if (mcbsp->pdata->has_ccr) { |
493 | w = MCBSP_READ_CACHE(mcbsp, RCCR); |
494 | w |= (rx ? RDISABLE : 0); |
495 | MCBSP_WRITE(mcbsp, RCCR, w); |
496 | } |
497 | w = MCBSP_READ_CACHE(mcbsp, SPCR1); |
498 | MCBSP_WRITE(mcbsp, SPCR1, w & ~rx); |
499 | |
500 | idle = !((MCBSP_READ_CACHE(mcbsp, SPCR2) | |
501 | MCBSP_READ_CACHE(mcbsp, SPCR1)) & 1); |
502 | |
503 | if (idle) { |
504 | /* Reset the sample rate generator */ |
505 | w = MCBSP_READ_CACHE(mcbsp, SPCR2); |
506 | MCBSP_WRITE(mcbsp, SPCR2, w & ~(1 << 6)); |
507 | } |
508 | |
509 | if (mcbsp->st_data) |
510 | omap_mcbsp_st_stop(mcbsp); |
511 | } |
512 | |
513 | #define max_thres(m) (mcbsp->pdata->buffer_size) |
514 | #define valid_threshold(m, val) ((val) <= max_thres(m)) |
515 | #define THRESHOLD_PROP_BUILDER(prop) \ |
516 | static ssize_t prop##_show(struct device *dev, \ |
517 | struct device_attribute *attr, char *buf) \ |
518 | { \ |
519 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ |
520 | \ |
521 | return sysfs_emit(buf, "%u\n", mcbsp->prop); \ |
522 | } \ |
523 | \ |
524 | static ssize_t prop##_store(struct device *dev, \ |
525 | struct device_attribute *attr, \ |
526 | const char *buf, size_t size) \ |
527 | { \ |
528 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); \ |
529 | unsigned long val; \ |
530 | int status; \ |
531 | \ |
532 | status = kstrtoul(buf, 0, &val); \ |
533 | if (status) \ |
534 | return status; \ |
535 | \ |
536 | if (!valid_threshold(mcbsp, val)) \ |
537 | return -EDOM; \ |
538 | \ |
539 | mcbsp->prop = val; \ |
540 | return size; \ |
541 | } \ |
542 | \ |
543 | static DEVICE_ATTR_RW(prop) |
544 | |
545 | THRESHOLD_PROP_BUILDER(max_tx_thres); |
546 | THRESHOLD_PROP_BUILDER(max_rx_thres); |
547 | |
548 | static const char * const dma_op_modes[] = { |
549 | "element" , "threshold" , |
550 | }; |
551 | |
552 | static ssize_t dma_op_mode_show(struct device *dev, |
553 | struct device_attribute *attr, char *buf) |
554 | { |
555 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); |
556 | int dma_op_mode, i = 0; |
557 | ssize_t len = 0; |
558 | const char * const *s; |
559 | |
560 | dma_op_mode = mcbsp->dma_op_mode; |
561 | |
562 | for (s = &dma_op_modes[i]; i < ARRAY_SIZE(dma_op_modes); s++, i++) { |
563 | if (dma_op_mode == i) |
564 | len += sysfs_emit_at(buf, at: len, fmt: "[%s] " , *s); |
565 | else |
566 | len += sysfs_emit_at(buf, at: len, fmt: "%s " , *s); |
567 | } |
568 | len += sysfs_emit_at(buf, at: len, fmt: "\n" ); |
569 | |
570 | return len; |
571 | } |
572 | |
573 | static ssize_t dma_op_mode_store(struct device *dev, |
574 | struct device_attribute *attr, const char *buf, |
575 | size_t size) |
576 | { |
577 | struct omap_mcbsp *mcbsp = dev_get_drvdata(dev); |
578 | int i; |
579 | |
580 | i = sysfs_match_string(dma_op_modes, buf); |
581 | if (i < 0) |
582 | return i; |
583 | |
584 | spin_lock_irq(lock: &mcbsp->lock); |
585 | if (!mcbsp->free) { |
586 | size = -EBUSY; |
587 | goto unlock; |
588 | } |
589 | mcbsp->dma_op_mode = i; |
590 | |
591 | unlock: |
592 | spin_unlock_irq(lock: &mcbsp->lock); |
593 | |
594 | return size; |
595 | } |
596 | |
597 | static DEVICE_ATTR_RW(dma_op_mode); |
598 | |
599 | static const struct attribute *additional_attrs[] = { |
600 | &dev_attr_max_tx_thres.attr, |
601 | &dev_attr_max_rx_thres.attr, |
602 | &dev_attr_dma_op_mode.attr, |
603 | NULL, |
604 | }; |
605 | |
606 | static const struct attribute_group additional_attr_group = { |
607 | .attrs = (struct attribute **)additional_attrs, |
608 | }; |
609 | |
610 | /* |
611 | * McBSP1 and McBSP3 are directly mapped on 1610 and 1510. |
612 | * 730 has only 2 McBSP, and both of them are MPU peripherals. |
613 | */ |
614 | static int omap_mcbsp_init(struct platform_device *pdev) |
615 | { |
616 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); |
617 | struct resource *res; |
618 | int ret; |
619 | |
620 | spin_lock_init(&mcbsp->lock); |
621 | mcbsp->free = true; |
622 | |
623 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu" ); |
624 | if (!res) |
625 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
626 | |
627 | mcbsp->io_base = devm_ioremap_resource(dev: &pdev->dev, res); |
628 | if (IS_ERR(ptr: mcbsp->io_base)) |
629 | return PTR_ERR(ptr: mcbsp->io_base); |
630 | |
631 | mcbsp->phys_base = res->start; |
632 | mcbsp->reg_cache_size = resource_size(res); |
633 | |
634 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma" ); |
635 | if (!res) |
636 | mcbsp->phys_dma_base = mcbsp->phys_base; |
637 | else |
638 | mcbsp->phys_dma_base = res->start; |
639 | |
640 | /* |
641 | * OMAP1, 2 uses two interrupt lines: TX, RX |
642 | * OMAP2430, OMAP3 SoC have combined IRQ line as well. |
643 | * OMAP4 and newer SoC only have the combined IRQ line. |
644 | * Use the combined IRQ if available since it gives better debugging |
645 | * possibilities. |
646 | */ |
647 | mcbsp->irq = platform_get_irq_byname(pdev, "common" ); |
648 | if (mcbsp->irq == -ENXIO) { |
649 | mcbsp->tx_irq = platform_get_irq_byname(pdev, "tx" ); |
650 | |
651 | if (mcbsp->tx_irq == -ENXIO) { |
652 | mcbsp->irq = platform_get_irq(pdev, 0); |
653 | mcbsp->tx_irq = 0; |
654 | } else { |
655 | mcbsp->rx_irq = platform_get_irq_byname(pdev, "rx" ); |
656 | mcbsp->irq = 0; |
657 | } |
658 | } |
659 | |
660 | if (!pdev->dev.of_node) { |
661 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx" ); |
662 | if (!res) { |
663 | dev_err(&pdev->dev, "invalid tx DMA channel\n" ); |
664 | return -ENODEV; |
665 | } |
666 | mcbsp->dma_req[0] = res->start; |
667 | mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0]; |
668 | |
669 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx" ); |
670 | if (!res) { |
671 | dev_err(&pdev->dev, "invalid rx DMA channel\n" ); |
672 | return -ENODEV; |
673 | } |
674 | mcbsp->dma_req[1] = res->start; |
675 | mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1]; |
676 | } else { |
677 | mcbsp->dma_data[0].filter_data = "tx" ; |
678 | mcbsp->dma_data[1].filter_data = "rx" ; |
679 | } |
680 | |
681 | mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, |
682 | stream: SNDRV_PCM_STREAM_PLAYBACK); |
683 | mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, |
684 | stream: SNDRV_PCM_STREAM_CAPTURE); |
685 | |
686 | mcbsp->fclk = devm_clk_get(dev: &pdev->dev, id: "fck" ); |
687 | if (IS_ERR(ptr: mcbsp->fclk)) { |
688 | ret = PTR_ERR(ptr: mcbsp->fclk); |
689 | dev_err(mcbsp->dev, "unable to get fck: %d\n" , ret); |
690 | return ret; |
691 | } |
692 | |
693 | mcbsp->dma_op_mode = MCBSP_DMA_MODE_ELEMENT; |
694 | if (mcbsp->pdata->buffer_size) { |
695 | /* |
696 | * Initially configure the maximum thresholds to a safe value. |
697 | * The McBSP FIFO usage with these values should not go under |
698 | * 16 locations. |
699 | * If the whole FIFO without safety buffer is used, than there |
700 | * is a possibility that the DMA will be not able to push the |
701 | * new data on time, causing channel shifts in runtime. |
702 | */ |
703 | mcbsp->max_tx_thres = max_thres(mcbsp) - 0x10; |
704 | mcbsp->max_rx_thres = max_thres(mcbsp) - 0x10; |
705 | |
706 | ret = devm_device_add_group(dev: mcbsp->dev, grp: &additional_attr_group); |
707 | if (ret) { |
708 | dev_err(mcbsp->dev, |
709 | "Unable to create additional controls\n" ); |
710 | return ret; |
711 | } |
712 | } |
713 | |
714 | return omap_mcbsp_st_init(pdev); |
715 | } |
716 | |
717 | /* |
718 | * Stream DMA parameters. DMA request line and port address are set runtime |
719 | * since they are different between OMAP1 and later OMAPs |
720 | */ |
721 | static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream, |
722 | unsigned int packet_size) |
723 | { |
724 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
725 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
726 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
727 | int words; |
728 | |
729 | /* No need to proceed further if McBSP does not have FIFO */ |
730 | if (mcbsp->pdata->buffer_size == 0) |
731 | return; |
732 | |
733 | /* |
734 | * Configure McBSP threshold based on either: |
735 | * packet_size, when the sDMA is in packet mode, or based on the |
736 | * period size in THRESHOLD mode, otherwise use McBSP threshold = 1 |
737 | * for mono streams. |
738 | */ |
739 | if (packet_size) |
740 | words = packet_size; |
741 | else |
742 | words = 1; |
743 | |
744 | /* Configure McBSP internal buffer usage */ |
745 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
746 | omap_mcbsp_set_tx_threshold(mcbsp, threshold: words); |
747 | else |
748 | omap_mcbsp_set_rx_threshold(mcbsp, threshold: words); |
749 | } |
750 | |
751 | static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params, |
752 | struct snd_pcm_hw_rule *rule) |
753 | { |
754 | struct snd_interval *buffer_size = hw_param_interval(params, |
755 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE); |
756 | struct snd_interval *channels = hw_param_interval(params, |
757 | SNDRV_PCM_HW_PARAM_CHANNELS); |
758 | struct omap_mcbsp *mcbsp = rule->private; |
759 | struct snd_interval frames; |
760 | int size; |
761 | |
762 | snd_interval_any(i: &frames); |
763 | size = mcbsp->pdata->buffer_size; |
764 | |
765 | frames.min = size / channels->min; |
766 | frames.integer = 1; |
767 | return snd_interval_refine(i: buffer_size, v: &frames); |
768 | } |
769 | |
770 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, |
771 | struct snd_soc_dai *cpu_dai) |
772 | { |
773 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
774 | int err = 0; |
775 | |
776 | if (!snd_soc_dai_active(dai: cpu_dai)) |
777 | err = omap_mcbsp_request(mcbsp); |
778 | |
779 | /* |
780 | * OMAP3 McBSP FIFO is word structured. |
781 | * McBSP2 has 1024 + 256 = 1280 word long buffer, |
782 | * McBSP1,3,4,5 has 128 word long buffer |
783 | * This means that the size of the FIFO depends on the sample format. |
784 | * For example on McBSP3: |
785 | * 16bit samples: size is 128 * 2 = 256 bytes |
786 | * 32bit samples: size is 128 * 4 = 512 bytes |
787 | * It is simpler to place constraint for buffer and period based on |
788 | * channels. |
789 | * McBSP3 as example again (16 or 32 bit samples): |
790 | * 1 channel (mono): size is 128 frames (128 words) |
791 | * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words) |
792 | * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words) |
793 | */ |
794 | if (mcbsp->pdata->buffer_size) { |
795 | /* |
796 | * Rule for the buffer size. We should not allow |
797 | * smaller buffer than the FIFO size to avoid underruns. |
798 | * This applies only for the playback stream. |
799 | */ |
800 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
801 | snd_pcm_hw_rule_add(runtime: substream->runtime, cond: 0, |
802 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, |
803 | func: omap_mcbsp_hwrule_min_buffersize, |
804 | private: mcbsp, |
805 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
806 | |
807 | /* Make sure, that the period size is always even */ |
808 | snd_pcm_hw_constraint_step(runtime: substream->runtime, cond: 0, |
809 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, step: 2); |
810 | } |
811 | |
812 | return err; |
813 | } |
814 | |
815 | static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream, |
816 | struct snd_soc_dai *cpu_dai) |
817 | { |
818 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
819 | int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); |
820 | int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; |
821 | int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; |
822 | |
823 | if (mcbsp->latency[stream2]) |
824 | cpu_latency_qos_update_request(req: &mcbsp->pm_qos_req, |
825 | new_value: mcbsp->latency[stream2]); |
826 | else if (mcbsp->latency[stream1]) |
827 | cpu_latency_qos_remove_request(req: &mcbsp->pm_qos_req); |
828 | |
829 | mcbsp->latency[stream1] = 0; |
830 | |
831 | if (!snd_soc_dai_active(dai: cpu_dai)) { |
832 | omap_mcbsp_free(mcbsp); |
833 | mcbsp->configured = 0; |
834 | } |
835 | } |
836 | |
837 | static int omap_mcbsp_dai_prepare(struct snd_pcm_substream *substream, |
838 | struct snd_soc_dai *cpu_dai) |
839 | { |
840 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
841 | struct pm_qos_request *pm_qos_req = &mcbsp->pm_qos_req; |
842 | int tx = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); |
843 | int stream1 = tx ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; |
844 | int stream2 = tx ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; |
845 | int latency = mcbsp->latency[stream2]; |
846 | |
847 | /* Prevent omap hardware from hitting off between FIFO fills */ |
848 | if (!latency || mcbsp->latency[stream1] < latency) |
849 | latency = mcbsp->latency[stream1]; |
850 | |
851 | if (cpu_latency_qos_request_active(req: pm_qos_req)) |
852 | cpu_latency_qos_update_request(req: pm_qos_req, new_value: latency); |
853 | else if (latency) |
854 | cpu_latency_qos_add_request(req: pm_qos_req, value: latency); |
855 | |
856 | return 0; |
857 | } |
858 | |
859 | static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, |
860 | struct snd_soc_dai *cpu_dai) |
861 | { |
862 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
863 | |
864 | switch (cmd) { |
865 | case SNDRV_PCM_TRIGGER_START: |
866 | case SNDRV_PCM_TRIGGER_RESUME: |
867 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
868 | mcbsp->active++; |
869 | omap_mcbsp_start(mcbsp, stream: substream->stream); |
870 | break; |
871 | |
872 | case SNDRV_PCM_TRIGGER_STOP: |
873 | case SNDRV_PCM_TRIGGER_SUSPEND: |
874 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
875 | omap_mcbsp_stop(mcbsp, stream: substream->stream); |
876 | mcbsp->active--; |
877 | break; |
878 | default: |
879 | return -EINVAL; |
880 | } |
881 | |
882 | return 0; |
883 | } |
884 | |
885 | static snd_pcm_sframes_t omap_mcbsp_dai_delay( |
886 | struct snd_pcm_substream *substream, |
887 | struct snd_soc_dai *dai) |
888 | { |
889 | struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); |
890 | struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); |
891 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
892 | u16 fifo_use; |
893 | snd_pcm_sframes_t delay; |
894 | |
895 | /* No need to proceed further if McBSP does not have FIFO */ |
896 | if (mcbsp->pdata->buffer_size == 0) |
897 | return 0; |
898 | |
899 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
900 | fifo_use = omap_mcbsp_get_tx_delay(mcbsp); |
901 | else |
902 | fifo_use = omap_mcbsp_get_rx_delay(mcbsp); |
903 | |
904 | /* |
905 | * Divide the used locations with the channel count to get the |
906 | * FIFO usage in samples (don't care about partial samples in the |
907 | * buffer). |
908 | */ |
909 | delay = fifo_use / substream->runtime->channels; |
910 | |
911 | return delay; |
912 | } |
913 | |
914 | static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, |
915 | struct snd_pcm_hw_params *params, |
916 | struct snd_soc_dai *cpu_dai) |
917 | { |
918 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
919 | struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; |
920 | struct snd_dmaengine_dai_dma_data *dma_data; |
921 | int wlen, channels, wpf; |
922 | int pkt_size = 0; |
923 | unsigned int format, div, framesize, master; |
924 | unsigned int buffer_size = mcbsp->pdata->buffer_size; |
925 | |
926 | dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream); |
927 | channels = params_channels(p: params); |
928 | |
929 | switch (params_format(p: params)) { |
930 | case SNDRV_PCM_FORMAT_S16_LE: |
931 | wlen = 16; |
932 | break; |
933 | case SNDRV_PCM_FORMAT_S32_LE: |
934 | wlen = 32; |
935 | break; |
936 | default: |
937 | return -EINVAL; |
938 | } |
939 | if (buffer_size) { |
940 | int latency; |
941 | |
942 | if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { |
943 | int period_words, max_thrsh; |
944 | int divider = 0; |
945 | |
946 | period_words = params_period_bytes(p: params) / (wlen / 8); |
947 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
948 | max_thrsh = mcbsp->max_tx_thres; |
949 | else |
950 | max_thrsh = mcbsp->max_rx_thres; |
951 | /* |
952 | * Use sDMA packet mode if McBSP is in threshold mode: |
953 | * If period words less than the FIFO size the packet |
954 | * size is set to the number of period words, otherwise |
955 | * Look for the biggest threshold value which divides |
956 | * the period size evenly. |
957 | */ |
958 | divider = period_words / max_thrsh; |
959 | if (period_words % max_thrsh) |
960 | divider++; |
961 | while (period_words % divider && |
962 | divider < period_words) |
963 | divider++; |
964 | if (divider == period_words) |
965 | return -EINVAL; |
966 | |
967 | pkt_size = period_words / divider; |
968 | } else if (channels > 1) { |
969 | /* Use packet mode for non mono streams */ |
970 | pkt_size = channels; |
971 | } |
972 | |
973 | latency = (buffer_size - pkt_size) / channels; |
974 | latency = latency * USEC_PER_SEC / |
975 | (params->rate_num / params->rate_den); |
976 | mcbsp->latency[substream->stream] = latency; |
977 | |
978 | omap_mcbsp_set_threshold(substream, packet_size: pkt_size); |
979 | } |
980 | |
981 | dma_data->maxburst = pkt_size; |
982 | |
983 | if (mcbsp->configured) { |
984 | /* McBSP already configured by another stream */ |
985 | return 0; |
986 | } |
987 | |
988 | regs->rcr2 &= ~(RPHASE | RFRLEN2(0x7f) | RWDLEN2(7)); |
989 | regs->xcr2 &= ~(RPHASE | XFRLEN2(0x7f) | XWDLEN2(7)); |
990 | regs->rcr1 &= ~(RFRLEN1(0x7f) | RWDLEN1(7)); |
991 | regs->xcr1 &= ~(XFRLEN1(0x7f) | XWDLEN1(7)); |
992 | format = mcbsp->fmt & SND_SOC_DAIFMT_FORMAT_MASK; |
993 | wpf = channels; |
994 | if (channels == 2 && (format == SND_SOC_DAIFMT_I2S || |
995 | format == SND_SOC_DAIFMT_LEFT_J)) { |
996 | /* Use dual-phase frames */ |
997 | regs->rcr2 |= RPHASE; |
998 | regs->xcr2 |= XPHASE; |
999 | /* Set 1 word per (McBSP) frame for phase1 and phase2 */ |
1000 | wpf--; |
1001 | regs->rcr2 |= RFRLEN2(wpf - 1); |
1002 | regs->xcr2 |= XFRLEN2(wpf - 1); |
1003 | } |
1004 | |
1005 | regs->rcr1 |= RFRLEN1(wpf - 1); |
1006 | regs->xcr1 |= XFRLEN1(wpf - 1); |
1007 | |
1008 | switch (params_format(p: params)) { |
1009 | case SNDRV_PCM_FORMAT_S16_LE: |
1010 | /* Set word lengths */ |
1011 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); |
1012 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); |
1013 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); |
1014 | regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16); |
1015 | break; |
1016 | case SNDRV_PCM_FORMAT_S32_LE: |
1017 | /* Set word lengths */ |
1018 | regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); |
1019 | regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); |
1020 | regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); |
1021 | regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_32); |
1022 | break; |
1023 | default: |
1024 | /* Unsupported PCM format */ |
1025 | return -EINVAL; |
1026 | } |
1027 | |
1028 | /* In McBSP master modes, FRAME (i.e. sample rate) is generated |
1029 | * by _counting_ BCLKs. Calculate frame size in BCLKs */ |
1030 | master = mcbsp->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; |
1031 | if (master == SND_SOC_DAIFMT_BP_FP) { |
1032 | div = mcbsp->clk_div ? mcbsp->clk_div : 1; |
1033 | framesize = (mcbsp->in_freq / div) / params_rate(p: params); |
1034 | |
1035 | if (framesize < wlen * channels) { |
1036 | printk(KERN_ERR "%s: not enough bandwidth for desired rate and " |
1037 | "channels\n" , __func__); |
1038 | return -EINVAL; |
1039 | } |
1040 | } else |
1041 | framesize = wlen * channels; |
1042 | |
1043 | /* Set FS period and length in terms of bit clock periods */ |
1044 | regs->srgr2 &= ~FPER(0xfff); |
1045 | regs->srgr1 &= ~FWID(0xff); |
1046 | switch (format) { |
1047 | case SND_SOC_DAIFMT_I2S: |
1048 | case SND_SOC_DAIFMT_LEFT_J: |
1049 | regs->srgr2 |= FPER(framesize - 1); |
1050 | regs->srgr1 |= FWID((framesize >> 1) - 1); |
1051 | break; |
1052 | case SND_SOC_DAIFMT_DSP_A: |
1053 | case SND_SOC_DAIFMT_DSP_B: |
1054 | regs->srgr2 |= FPER(framesize - 1); |
1055 | regs->srgr1 |= FWID(0); |
1056 | break; |
1057 | } |
1058 | |
1059 | omap_mcbsp_config(mcbsp, config: &mcbsp->cfg_regs); |
1060 | mcbsp->wlen = wlen; |
1061 | mcbsp->configured = 1; |
1062 | |
1063 | return 0; |
1064 | } |
1065 | |
1066 | /* |
1067 | * This must be called before _set_clkdiv and _set_sysclk since McBSP register |
1068 | * cache is initialized here |
1069 | */ |
1070 | static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
1071 | unsigned int fmt) |
1072 | { |
1073 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
1074 | struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; |
1075 | bool inv_fs = false; |
1076 | |
1077 | if (mcbsp->configured) |
1078 | return 0; |
1079 | |
1080 | mcbsp->fmt = fmt; |
1081 | memset(regs, 0, sizeof(*regs)); |
1082 | /* Generic McBSP register settings */ |
1083 | regs->spcr2 |= XINTM(3) | FREE; |
1084 | regs->spcr1 |= RINTM(3); |
1085 | /* RFIG and XFIG are not defined in 2430 and on OMAP3+ */ |
1086 | if (!mcbsp->pdata->has_ccr) { |
1087 | regs->rcr2 |= RFIG; |
1088 | regs->xcr2 |= XFIG; |
1089 | } |
1090 | |
1091 | /* Configure XCCR/RCCR only for revisions which have ccr registers */ |
1092 | if (mcbsp->pdata->has_ccr) { |
1093 | regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; |
1094 | regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; |
1095 | } |
1096 | |
1097 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
1098 | case SND_SOC_DAIFMT_I2S: |
1099 | /* 1-bit data delay */ |
1100 | regs->rcr2 |= RDATDLY(1); |
1101 | regs->xcr2 |= XDATDLY(1); |
1102 | break; |
1103 | case SND_SOC_DAIFMT_LEFT_J: |
1104 | /* 0-bit data delay */ |
1105 | regs->rcr2 |= RDATDLY(0); |
1106 | regs->xcr2 |= XDATDLY(0); |
1107 | regs->spcr1 |= RJUST(2); |
1108 | /* Invert FS polarity configuration */ |
1109 | inv_fs = true; |
1110 | break; |
1111 | case SND_SOC_DAIFMT_DSP_A: |
1112 | /* 1-bit data delay */ |
1113 | regs->rcr2 |= RDATDLY(1); |
1114 | regs->xcr2 |= XDATDLY(1); |
1115 | /* Invert FS polarity configuration */ |
1116 | inv_fs = true; |
1117 | break; |
1118 | case SND_SOC_DAIFMT_DSP_B: |
1119 | /* 0-bit data delay */ |
1120 | regs->rcr2 |= RDATDLY(0); |
1121 | regs->xcr2 |= XDATDLY(0); |
1122 | /* Invert FS polarity configuration */ |
1123 | inv_fs = true; |
1124 | break; |
1125 | default: |
1126 | /* Unsupported data format */ |
1127 | return -EINVAL; |
1128 | } |
1129 | |
1130 | switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { |
1131 | case SND_SOC_DAIFMT_BP_FP: |
1132 | /* McBSP master. Set FS and bit clocks as outputs */ |
1133 | regs->pcr0 |= FSXM | FSRM | |
1134 | CLKXM | CLKRM; |
1135 | /* Sample rate generator drives the FS */ |
1136 | regs->srgr2 |= FSGM; |
1137 | break; |
1138 | case SND_SOC_DAIFMT_BC_FP: |
1139 | /* McBSP slave. FS clock as output */ |
1140 | regs->srgr2 |= FSGM; |
1141 | regs->pcr0 |= FSXM | FSRM; |
1142 | break; |
1143 | case SND_SOC_DAIFMT_BC_FC: |
1144 | /* McBSP slave */ |
1145 | break; |
1146 | default: |
1147 | /* Unsupported master/slave configuration */ |
1148 | return -EINVAL; |
1149 | } |
1150 | |
1151 | /* Set bit clock (CLKX/CLKR) and FS polarities */ |
1152 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
1153 | case SND_SOC_DAIFMT_NB_NF: |
1154 | /* |
1155 | * Normal BCLK + FS. |
1156 | * FS active low. TX data driven on falling edge of bit clock |
1157 | * and RX data sampled on rising edge of bit clock. |
1158 | */ |
1159 | regs->pcr0 |= FSXP | FSRP | |
1160 | CLKXP | CLKRP; |
1161 | break; |
1162 | case SND_SOC_DAIFMT_NB_IF: |
1163 | regs->pcr0 |= CLKXP | CLKRP; |
1164 | break; |
1165 | case SND_SOC_DAIFMT_IB_NF: |
1166 | regs->pcr0 |= FSXP | FSRP; |
1167 | break; |
1168 | case SND_SOC_DAIFMT_IB_IF: |
1169 | break; |
1170 | default: |
1171 | return -EINVAL; |
1172 | } |
1173 | if (inv_fs) |
1174 | regs->pcr0 ^= FSXP | FSRP; |
1175 | |
1176 | return 0; |
1177 | } |
1178 | |
1179 | static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, |
1180 | int div_id, int div) |
1181 | { |
1182 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
1183 | struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; |
1184 | |
1185 | if (div_id != OMAP_MCBSP_CLKGDV) |
1186 | return -ENODEV; |
1187 | |
1188 | mcbsp->clk_div = div; |
1189 | regs->srgr1 &= ~CLKGDV(0xff); |
1190 | regs->srgr1 |= CLKGDV(div - 1); |
1191 | |
1192 | return 0; |
1193 | } |
1194 | |
1195 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
1196 | int clk_id, unsigned int freq, |
1197 | int dir) |
1198 | { |
1199 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai: cpu_dai); |
1200 | struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; |
1201 | int err = 0; |
1202 | |
1203 | if (mcbsp->active) { |
1204 | if (freq == mcbsp->in_freq) |
1205 | return 0; |
1206 | else |
1207 | return -EBUSY; |
1208 | } |
1209 | |
1210 | mcbsp->in_freq = freq; |
1211 | regs->srgr2 &= ~CLKSM; |
1212 | regs->pcr0 &= ~SCLKME; |
1213 | |
1214 | switch (clk_id) { |
1215 | case OMAP_MCBSP_SYSCLK_CLK: |
1216 | regs->srgr2 |= CLKSM; |
1217 | break; |
1218 | case OMAP_MCBSP_SYSCLK_CLKS_FCLK: |
1219 | if (mcbsp_omap1()) { |
1220 | err = -EINVAL; |
1221 | break; |
1222 | } |
1223 | err = omap2_mcbsp_set_clks_src(mcbsp, |
1224 | MCBSP_CLKS_PRCM_SRC); |
1225 | break; |
1226 | case OMAP_MCBSP_SYSCLK_CLKS_EXT: |
1227 | if (mcbsp_omap1()) { |
1228 | err = 0; |
1229 | break; |
1230 | } |
1231 | err = omap2_mcbsp_set_clks_src(mcbsp, |
1232 | MCBSP_CLKS_PAD_SRC); |
1233 | break; |
1234 | |
1235 | case OMAP_MCBSP_SYSCLK_CLKX_EXT: |
1236 | regs->srgr2 |= CLKSM; |
1237 | regs->pcr0 |= SCLKME; |
1238 | /* |
1239 | * If McBSP is master but yet the CLKX/CLKR pin drives the SRG, |
1240 | * disable output on those pins. This enables to inject the |
1241 | * reference clock through CLKX/CLKR. For this to work |
1242 | * set_dai_sysclk() _needs_ to be called after set_dai_fmt(). |
1243 | */ |
1244 | regs->pcr0 &= ~CLKXM; |
1245 | break; |
1246 | case OMAP_MCBSP_SYSCLK_CLKR_EXT: |
1247 | regs->pcr0 |= SCLKME; |
1248 | /* Disable ouput on CLKR pin in master mode */ |
1249 | regs->pcr0 &= ~CLKRM; |
1250 | break; |
1251 | default: |
1252 | err = -ENODEV; |
1253 | } |
1254 | |
1255 | return err; |
1256 | } |
1257 | |
1258 | static int omap_mcbsp_probe(struct snd_soc_dai *dai) |
1259 | { |
1260 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); |
1261 | |
1262 | pm_runtime_enable(dev: mcbsp->dev); |
1263 | |
1264 | snd_soc_dai_init_dma_data(dai, |
1265 | playback: &mcbsp->dma_data[SNDRV_PCM_STREAM_PLAYBACK], |
1266 | capture: &mcbsp->dma_data[SNDRV_PCM_STREAM_CAPTURE]); |
1267 | |
1268 | return 0; |
1269 | } |
1270 | |
1271 | static int omap_mcbsp_remove(struct snd_soc_dai *dai) |
1272 | { |
1273 | struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(dai); |
1274 | |
1275 | pm_runtime_disable(dev: mcbsp->dev); |
1276 | |
1277 | return 0; |
1278 | } |
1279 | |
1280 | static const struct snd_soc_dai_ops mcbsp_dai_ops = { |
1281 | .probe = omap_mcbsp_probe, |
1282 | .remove = omap_mcbsp_remove, |
1283 | .startup = omap_mcbsp_dai_startup, |
1284 | .shutdown = omap_mcbsp_dai_shutdown, |
1285 | .prepare = omap_mcbsp_dai_prepare, |
1286 | .trigger = omap_mcbsp_dai_trigger, |
1287 | .delay = omap_mcbsp_dai_delay, |
1288 | .hw_params = omap_mcbsp_dai_hw_params, |
1289 | .set_fmt = omap_mcbsp_dai_set_dai_fmt, |
1290 | .set_clkdiv = omap_mcbsp_dai_set_clkdiv, |
1291 | .set_sysclk = omap_mcbsp_dai_set_dai_sysclk, |
1292 | }; |
1293 | |
1294 | static struct snd_soc_dai_driver omap_mcbsp_dai = { |
1295 | .playback = { |
1296 | .channels_min = 1, |
1297 | .channels_max = 16, |
1298 | .rates = OMAP_MCBSP_RATES, |
1299 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, |
1300 | }, |
1301 | .capture = { |
1302 | .channels_min = 1, |
1303 | .channels_max = 16, |
1304 | .rates = OMAP_MCBSP_RATES, |
1305 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, |
1306 | }, |
1307 | .ops = &mcbsp_dai_ops, |
1308 | }; |
1309 | |
1310 | static const struct snd_soc_component_driver omap_mcbsp_component = { |
1311 | .name = "omap-mcbsp" , |
1312 | .legacy_dai_naming = 1, |
1313 | }; |
1314 | |
1315 | static struct omap_mcbsp_platform_data omap2420_pdata = { |
1316 | .reg_step = 4, |
1317 | .reg_size = 2, |
1318 | }; |
1319 | |
1320 | static struct omap_mcbsp_platform_data omap2430_pdata = { |
1321 | .reg_step = 4, |
1322 | .reg_size = 4, |
1323 | .has_ccr = true, |
1324 | }; |
1325 | |
1326 | static struct omap_mcbsp_platform_data omap3_pdata = { |
1327 | .reg_step = 4, |
1328 | .reg_size = 4, |
1329 | .has_ccr = true, |
1330 | .has_wakeup = true, |
1331 | }; |
1332 | |
1333 | static struct omap_mcbsp_platform_data omap4_pdata = { |
1334 | .reg_step = 4, |
1335 | .reg_size = 4, |
1336 | .has_ccr = true, |
1337 | .has_wakeup = true, |
1338 | }; |
1339 | |
1340 | static const struct of_device_id omap_mcbsp_of_match[] = { |
1341 | { |
1342 | .compatible = "ti,omap2420-mcbsp" , |
1343 | .data = &omap2420_pdata, |
1344 | }, |
1345 | { |
1346 | .compatible = "ti,omap2430-mcbsp" , |
1347 | .data = &omap2430_pdata, |
1348 | }, |
1349 | { |
1350 | .compatible = "ti,omap3-mcbsp" , |
1351 | .data = &omap3_pdata, |
1352 | }, |
1353 | { |
1354 | .compatible = "ti,omap4-mcbsp" , |
1355 | .data = &omap4_pdata, |
1356 | }, |
1357 | { }, |
1358 | }; |
1359 | MODULE_DEVICE_TABLE(of, omap_mcbsp_of_match); |
1360 | |
1361 | static int asoc_mcbsp_probe(struct platform_device *pdev) |
1362 | { |
1363 | struct omap_mcbsp_platform_data *pdata = dev_get_platdata(dev: &pdev->dev); |
1364 | const struct omap_mcbsp_platform_data *match_pdata = |
1365 | device_get_match_data(dev: &pdev->dev); |
1366 | struct omap_mcbsp *mcbsp; |
1367 | int ret; |
1368 | |
1369 | if (match_pdata) { |
1370 | struct device_node *node = pdev->dev.of_node; |
1371 | struct omap_mcbsp_platform_data *pdata_quirk = pdata; |
1372 | int buffer_size; |
1373 | |
1374 | pdata = devm_kmemdup(dev: &pdev->dev, src: match_pdata, |
1375 | len: sizeof(struct omap_mcbsp_platform_data), |
1376 | GFP_KERNEL); |
1377 | if (!pdata) |
1378 | return -ENOMEM; |
1379 | |
1380 | if (!of_property_read_u32(np: node, propname: "ti,buffer-size" , out_value: &buffer_size)) |
1381 | pdata->buffer_size = buffer_size; |
1382 | if (pdata_quirk) |
1383 | pdata->force_ick_on = pdata_quirk->force_ick_on; |
1384 | } else if (!pdata) { |
1385 | dev_err(&pdev->dev, "missing platform data.\n" ); |
1386 | return -EINVAL; |
1387 | } |
1388 | mcbsp = devm_kzalloc(dev: &pdev->dev, size: sizeof(struct omap_mcbsp), GFP_KERNEL); |
1389 | if (!mcbsp) |
1390 | return -ENOMEM; |
1391 | |
1392 | mcbsp->id = pdev->id; |
1393 | mcbsp->pdata = pdata; |
1394 | mcbsp->dev = &pdev->dev; |
1395 | platform_set_drvdata(pdev, data: mcbsp); |
1396 | |
1397 | ret = omap_mcbsp_init(pdev); |
1398 | if (ret) |
1399 | return ret; |
1400 | |
1401 | if (mcbsp->pdata->reg_size == 2) { |
1402 | omap_mcbsp_dai.playback.formats = SNDRV_PCM_FMTBIT_S16_LE; |
1403 | omap_mcbsp_dai.capture.formats = SNDRV_PCM_FMTBIT_S16_LE; |
1404 | } |
1405 | |
1406 | ret = devm_snd_soc_register_component(dev: &pdev->dev, |
1407 | component_driver: &omap_mcbsp_component, |
1408 | dai_drv: &omap_mcbsp_dai, num_dai: 1); |
1409 | if (ret) |
1410 | return ret; |
1411 | |
1412 | return sdma_pcm_platform_register(dev: &pdev->dev, txdmachan: "tx" , rxdmachan: "rx" ); |
1413 | } |
1414 | |
1415 | static void asoc_mcbsp_remove(struct platform_device *pdev) |
1416 | { |
1417 | struct omap_mcbsp *mcbsp = platform_get_drvdata(pdev); |
1418 | |
1419 | if (mcbsp->pdata->ops && mcbsp->pdata->ops->free) |
1420 | mcbsp->pdata->ops->free(mcbsp->id); |
1421 | |
1422 | if (cpu_latency_qos_request_active(req: &mcbsp->pm_qos_req)) |
1423 | cpu_latency_qos_remove_request(req: &mcbsp->pm_qos_req); |
1424 | } |
1425 | |
1426 | static struct platform_driver asoc_mcbsp_driver = { |
1427 | .driver = { |
1428 | .name = "omap-mcbsp" , |
1429 | .of_match_table = omap_mcbsp_of_match, |
1430 | }, |
1431 | |
1432 | .probe = asoc_mcbsp_probe, |
1433 | .remove_new = asoc_mcbsp_remove, |
1434 | }; |
1435 | |
1436 | module_platform_driver(asoc_mcbsp_driver); |
1437 | |
1438 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@bitmer.com>" ); |
1439 | MODULE_DESCRIPTION("OMAP I2S SoC Interface" ); |
1440 | MODULE_LICENSE("GPL" ); |
1441 | MODULE_ALIAS("platform:omap-mcbsp" ); |
1442 | |