1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (C) 2019 Spreadtrum Communications Inc. |
3 | |
4 | #include <linux/errno.h> |
5 | #include <linux/interrupt.h> |
6 | #include <linux/io.h> |
7 | #include <linux/kernel.h> |
8 | #include <linux/module.h> |
9 | #include <linux/mutex.h> |
10 | #include <linux/of.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/spinlock.h> |
13 | |
14 | #include "sprd-mcdt.h" |
15 | |
16 | /* MCDT registers definition */ |
17 | #define MCDT_CH0_TXD 0x0 |
18 | #define MCDT_CH0_RXD 0x28 |
19 | #define MCDT_DAC0_WTMK 0x60 |
20 | #define MCDT_ADC0_WTMK 0x88 |
21 | #define MCDT_DMA_EN 0xb0 |
22 | |
23 | #define MCDT_INT_EN0 0xb4 |
24 | #define MCDT_INT_EN1 0xb8 |
25 | #define MCDT_INT_EN2 0xbc |
26 | |
27 | #define MCDT_INT_CLR0 0xc0 |
28 | #define MCDT_INT_CLR1 0xc4 |
29 | #define MCDT_INT_CLR2 0xc8 |
30 | |
31 | #define MCDT_INT_RAW1 0xcc |
32 | #define MCDT_INT_RAW2 0xd0 |
33 | #define MCDT_INT_RAW3 0xd4 |
34 | |
35 | #define MCDT_INT_MSK1 0xd8 |
36 | #define MCDT_INT_MSK2 0xdc |
37 | #define MCDT_INT_MSK3 0xe0 |
38 | |
39 | #define MCDT_DAC0_FIFO_ADDR_ST 0xe4 |
40 | #define MCDT_ADC0_FIFO_ADDR_ST 0xe8 |
41 | |
42 | #define MCDT_CH_FIFO_ST0 0x134 |
43 | #define MCDT_CH_FIFO_ST1 0x138 |
44 | #define MCDT_CH_FIFO_ST2 0x13c |
45 | |
46 | #define MCDT_INT_MSK_CFG0 0x140 |
47 | #define MCDT_INT_MSK_CFG1 0x144 |
48 | |
49 | #define MCDT_DMA_CFG0 0x148 |
50 | #define MCDT_FIFO_CLR 0x14c |
51 | #define MCDT_DMA_CFG1 0x150 |
52 | #define MCDT_DMA_CFG2 0x154 |
53 | #define MCDT_DMA_CFG3 0x158 |
54 | #define MCDT_DMA_CFG4 0x15c |
55 | #define MCDT_DMA_CFG5 0x160 |
56 | |
57 | /* Channel water mark definition */ |
58 | #define MCDT_CH_FIFO_AE_SHIFT 16 |
59 | #define MCDT_CH_FIFO_AE_MASK GENMASK(24, 16) |
60 | #define MCDT_CH_FIFO_AF_MASK GENMASK(8, 0) |
61 | |
62 | /* DMA channel select definition */ |
63 | #define MCDT_DMA_CH0_SEL_MASK GENMASK(3, 0) |
64 | #define MCDT_DMA_CH0_SEL_SHIFT 0 |
65 | #define MCDT_DMA_CH1_SEL_MASK GENMASK(7, 4) |
66 | #define MCDT_DMA_CH1_SEL_SHIFT 4 |
67 | #define MCDT_DMA_CH2_SEL_MASK GENMASK(11, 8) |
68 | #define MCDT_DMA_CH2_SEL_SHIFT 8 |
69 | #define MCDT_DMA_CH3_SEL_MASK GENMASK(15, 12) |
70 | #define MCDT_DMA_CH3_SEL_SHIFT 12 |
71 | #define MCDT_DMA_CH4_SEL_MASK GENMASK(19, 16) |
72 | #define MCDT_DMA_CH4_SEL_SHIFT 16 |
73 | #define MCDT_DAC_DMA_SHIFT 16 |
74 | |
75 | /* DMA channel ACK select definition */ |
76 | #define MCDT_DMA_ACK_SEL_MASK GENMASK(3, 0) |
77 | |
78 | /* Channel FIFO definition */ |
79 | #define MCDT_CH_FIFO_ADDR_SHIFT 16 |
80 | #define MCDT_CH_FIFO_ADDR_MASK GENMASK(9, 0) |
81 | #define MCDT_ADC_FIFO_SHIFT 16 |
82 | #define MCDT_FIFO_LENGTH 512 |
83 | |
84 | #define MCDT_ADC_CHANNEL_NUM 10 |
85 | #define MCDT_DAC_CHANNEL_NUM 10 |
86 | #define MCDT_CHANNEL_NUM (MCDT_ADC_CHANNEL_NUM + MCDT_DAC_CHANNEL_NUM) |
87 | |
88 | enum sprd_mcdt_fifo_int { |
89 | MCDT_ADC_FIFO_AE_INT, |
90 | MCDT_ADC_FIFO_AF_INT, |
91 | MCDT_DAC_FIFO_AE_INT, |
92 | MCDT_DAC_FIFO_AF_INT, |
93 | MCDT_ADC_FIFO_OV_INT, |
94 | MCDT_DAC_FIFO_OV_INT |
95 | }; |
96 | |
97 | enum sprd_mcdt_fifo_sts { |
98 | MCDT_ADC_FIFO_REAL_FULL, |
99 | MCDT_ADC_FIFO_REAL_EMPTY, |
100 | MCDT_ADC_FIFO_AF, |
101 | MCDT_ADC_FIFO_AE, |
102 | MCDT_DAC_FIFO_REAL_FULL, |
103 | MCDT_DAC_FIFO_REAL_EMPTY, |
104 | MCDT_DAC_FIFO_AF, |
105 | MCDT_DAC_FIFO_AE |
106 | }; |
107 | |
108 | struct sprd_mcdt_dev { |
109 | struct device *dev; |
110 | void __iomem *base; |
111 | spinlock_t lock; |
112 | struct sprd_mcdt_chan chan[MCDT_CHANNEL_NUM]; |
113 | }; |
114 | |
115 | static LIST_HEAD(sprd_mcdt_chan_list); |
116 | static DEFINE_MUTEX(sprd_mcdt_list_mutex); |
117 | |
118 | static void sprd_mcdt_update(struct sprd_mcdt_dev *mcdt, u32 reg, u32 val, |
119 | u32 mask) |
120 | { |
121 | u32 orig = readl_relaxed(mcdt->base + reg); |
122 | u32 tmp; |
123 | |
124 | tmp = (orig & ~mask) | val; |
125 | writel_relaxed(tmp, mcdt->base + reg); |
126 | } |
127 | |
128 | static void sprd_mcdt_dac_set_watermark(struct sprd_mcdt_dev *mcdt, u8 channel, |
129 | u32 full, u32 empty) |
130 | { |
131 | u32 reg = MCDT_DAC0_WTMK + channel * 4; |
132 | u32 water_mark = |
133 | (empty << MCDT_CH_FIFO_AE_SHIFT) & MCDT_CH_FIFO_AE_MASK; |
134 | |
135 | water_mark |= full & MCDT_CH_FIFO_AF_MASK; |
136 | sprd_mcdt_update(mcdt, reg, val: water_mark, |
137 | MCDT_CH_FIFO_AE_MASK | MCDT_CH_FIFO_AF_MASK); |
138 | } |
139 | |
140 | static void sprd_mcdt_adc_set_watermark(struct sprd_mcdt_dev *mcdt, u8 channel, |
141 | u32 full, u32 empty) |
142 | { |
143 | u32 reg = MCDT_ADC0_WTMK + channel * 4; |
144 | u32 water_mark = |
145 | (empty << MCDT_CH_FIFO_AE_SHIFT) & MCDT_CH_FIFO_AE_MASK; |
146 | |
147 | water_mark |= full & MCDT_CH_FIFO_AF_MASK; |
148 | sprd_mcdt_update(mcdt, reg, val: water_mark, |
149 | MCDT_CH_FIFO_AE_MASK | MCDT_CH_FIFO_AF_MASK); |
150 | } |
151 | |
152 | static void sprd_mcdt_dac_dma_enable(struct sprd_mcdt_dev *mcdt, u8 channel, |
153 | bool enable) |
154 | { |
155 | u32 shift = MCDT_DAC_DMA_SHIFT + channel; |
156 | |
157 | if (enable) |
158 | sprd_mcdt_update(mcdt, MCDT_DMA_EN, BIT(shift), BIT(shift)); |
159 | else |
160 | sprd_mcdt_update(mcdt, MCDT_DMA_EN, val: 0, BIT(shift)); |
161 | } |
162 | |
163 | static void sprd_mcdt_adc_dma_enable(struct sprd_mcdt_dev *mcdt, u8 channel, |
164 | bool enable) |
165 | { |
166 | if (enable) |
167 | sprd_mcdt_update(mcdt, MCDT_DMA_EN, BIT(channel), BIT(channel)); |
168 | else |
169 | sprd_mcdt_update(mcdt, MCDT_DMA_EN, val: 0, BIT(channel)); |
170 | } |
171 | |
172 | static void sprd_mcdt_ap_int_enable(struct sprd_mcdt_dev *mcdt, u8 channel, |
173 | bool enable) |
174 | { |
175 | if (enable) |
176 | sprd_mcdt_update(mcdt, MCDT_INT_MSK_CFG0, BIT(channel), |
177 | BIT(channel)); |
178 | else |
179 | sprd_mcdt_update(mcdt, MCDT_INT_MSK_CFG0, val: 0, BIT(channel)); |
180 | } |
181 | |
182 | static void sprd_mcdt_dac_write_fifo(struct sprd_mcdt_dev *mcdt, u8 channel, |
183 | u32 val) |
184 | { |
185 | u32 reg = MCDT_CH0_TXD + channel * 4; |
186 | |
187 | writel_relaxed(val, mcdt->base + reg); |
188 | } |
189 | |
190 | static void sprd_mcdt_adc_read_fifo(struct sprd_mcdt_dev *mcdt, u8 channel, |
191 | u32 *val) |
192 | { |
193 | u32 reg = MCDT_CH0_RXD + channel * 4; |
194 | |
195 | *val = readl_relaxed(mcdt->base + reg); |
196 | } |
197 | |
198 | static void sprd_mcdt_dac_dma_chn_select(struct sprd_mcdt_dev *mcdt, u8 channel, |
199 | enum sprd_mcdt_dma_chan dma_chan) |
200 | { |
201 | switch (dma_chan) { |
202 | case SPRD_MCDT_DMA_CH0: |
203 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG0, |
204 | val: channel << MCDT_DMA_CH0_SEL_SHIFT, |
205 | MCDT_DMA_CH0_SEL_MASK); |
206 | break; |
207 | |
208 | case SPRD_MCDT_DMA_CH1: |
209 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG0, |
210 | val: channel << MCDT_DMA_CH1_SEL_SHIFT, |
211 | MCDT_DMA_CH1_SEL_MASK); |
212 | break; |
213 | |
214 | case SPRD_MCDT_DMA_CH2: |
215 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG0, |
216 | val: channel << MCDT_DMA_CH2_SEL_SHIFT, |
217 | MCDT_DMA_CH2_SEL_MASK); |
218 | break; |
219 | |
220 | case SPRD_MCDT_DMA_CH3: |
221 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG0, |
222 | val: channel << MCDT_DMA_CH3_SEL_SHIFT, |
223 | MCDT_DMA_CH3_SEL_MASK); |
224 | break; |
225 | |
226 | case SPRD_MCDT_DMA_CH4: |
227 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG0, |
228 | val: channel << MCDT_DMA_CH4_SEL_SHIFT, |
229 | MCDT_DMA_CH4_SEL_MASK); |
230 | break; |
231 | } |
232 | } |
233 | |
234 | static void sprd_mcdt_adc_dma_chn_select(struct sprd_mcdt_dev *mcdt, u8 channel, |
235 | enum sprd_mcdt_dma_chan dma_chan) |
236 | { |
237 | switch (dma_chan) { |
238 | case SPRD_MCDT_DMA_CH0: |
239 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG1, |
240 | val: channel << MCDT_DMA_CH0_SEL_SHIFT, |
241 | MCDT_DMA_CH0_SEL_MASK); |
242 | break; |
243 | |
244 | case SPRD_MCDT_DMA_CH1: |
245 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG1, |
246 | val: channel << MCDT_DMA_CH1_SEL_SHIFT, |
247 | MCDT_DMA_CH1_SEL_MASK); |
248 | break; |
249 | |
250 | case SPRD_MCDT_DMA_CH2: |
251 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG1, |
252 | val: channel << MCDT_DMA_CH2_SEL_SHIFT, |
253 | MCDT_DMA_CH2_SEL_MASK); |
254 | break; |
255 | |
256 | case SPRD_MCDT_DMA_CH3: |
257 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG1, |
258 | val: channel << MCDT_DMA_CH3_SEL_SHIFT, |
259 | MCDT_DMA_CH3_SEL_MASK); |
260 | break; |
261 | |
262 | case SPRD_MCDT_DMA_CH4: |
263 | sprd_mcdt_update(mcdt, MCDT_DMA_CFG1, |
264 | val: channel << MCDT_DMA_CH4_SEL_SHIFT, |
265 | MCDT_DMA_CH4_SEL_MASK); |
266 | break; |
267 | } |
268 | } |
269 | |
270 | static u32 sprd_mcdt_dma_ack_shift(u8 channel) |
271 | { |
272 | switch (channel) { |
273 | default: |
274 | case 0: |
275 | case 8: |
276 | return 0; |
277 | case 1: |
278 | case 9: |
279 | return 4; |
280 | case 2: |
281 | return 8; |
282 | case 3: |
283 | return 12; |
284 | case 4: |
285 | return 16; |
286 | case 5: |
287 | return 20; |
288 | case 6: |
289 | return 24; |
290 | case 7: |
291 | return 28; |
292 | } |
293 | } |
294 | |
295 | static void sprd_mcdt_dac_dma_ack_select(struct sprd_mcdt_dev *mcdt, u8 channel, |
296 | enum sprd_mcdt_dma_chan dma_chan) |
297 | { |
298 | u32 reg, shift = sprd_mcdt_dma_ack_shift(channel), ack = dma_chan; |
299 | |
300 | switch (channel) { |
301 | case 0 ... 7: |
302 | reg = MCDT_DMA_CFG2; |
303 | break; |
304 | |
305 | case 8 ... 9: |
306 | reg = MCDT_DMA_CFG3; |
307 | break; |
308 | |
309 | default: |
310 | return; |
311 | } |
312 | |
313 | sprd_mcdt_update(mcdt, reg, val: ack << shift, |
314 | MCDT_DMA_ACK_SEL_MASK << shift); |
315 | } |
316 | |
317 | static void sprd_mcdt_adc_dma_ack_select(struct sprd_mcdt_dev *mcdt, u8 channel, |
318 | enum sprd_mcdt_dma_chan dma_chan) |
319 | { |
320 | u32 reg, shift = sprd_mcdt_dma_ack_shift(channel), ack = dma_chan; |
321 | |
322 | switch (channel) { |
323 | case 0 ... 7: |
324 | reg = MCDT_DMA_CFG4; |
325 | break; |
326 | |
327 | case 8 ... 9: |
328 | reg = MCDT_DMA_CFG5; |
329 | break; |
330 | |
331 | default: |
332 | return; |
333 | } |
334 | |
335 | sprd_mcdt_update(mcdt, reg, val: ack << shift, |
336 | MCDT_DMA_ACK_SEL_MASK << shift); |
337 | } |
338 | |
339 | static bool sprd_mcdt_chan_fifo_sts(struct sprd_mcdt_dev *mcdt, u8 channel, |
340 | enum sprd_mcdt_fifo_sts fifo_sts) |
341 | { |
342 | u32 reg, shift; |
343 | |
344 | switch (channel) { |
345 | case 0 ... 3: |
346 | reg = MCDT_CH_FIFO_ST0; |
347 | break; |
348 | case 4 ... 7: |
349 | reg = MCDT_CH_FIFO_ST1; |
350 | break; |
351 | case 8 ... 9: |
352 | reg = MCDT_CH_FIFO_ST2; |
353 | break; |
354 | default: |
355 | return false; |
356 | } |
357 | |
358 | switch (channel) { |
359 | case 0: |
360 | case 4: |
361 | case 8: |
362 | shift = fifo_sts; |
363 | break; |
364 | |
365 | case 1: |
366 | case 5: |
367 | case 9: |
368 | shift = 8 + fifo_sts; |
369 | break; |
370 | |
371 | case 2: |
372 | case 6: |
373 | shift = 16 + fifo_sts; |
374 | break; |
375 | |
376 | case 3: |
377 | case 7: |
378 | shift = 24 + fifo_sts; |
379 | break; |
380 | |
381 | default: |
382 | return false; |
383 | } |
384 | |
385 | return !!(readl_relaxed(mcdt->base + reg) & BIT(shift)); |
386 | } |
387 | |
388 | static void sprd_mcdt_dac_fifo_clear(struct sprd_mcdt_dev *mcdt, u8 channel) |
389 | { |
390 | sprd_mcdt_update(mcdt, MCDT_FIFO_CLR, BIT(channel), BIT(channel)); |
391 | } |
392 | |
393 | static void sprd_mcdt_adc_fifo_clear(struct sprd_mcdt_dev *mcdt, u8 channel) |
394 | { |
395 | u32 shift = MCDT_ADC_FIFO_SHIFT + channel; |
396 | |
397 | sprd_mcdt_update(mcdt, MCDT_FIFO_CLR, BIT(shift), BIT(shift)); |
398 | } |
399 | |
400 | static u32 sprd_mcdt_dac_fifo_avail(struct sprd_mcdt_dev *mcdt, u8 channel) |
401 | { |
402 | u32 reg = MCDT_DAC0_FIFO_ADDR_ST + channel * 8; |
403 | u32 r_addr = (readl_relaxed(mcdt->base + reg) >> |
404 | MCDT_CH_FIFO_ADDR_SHIFT) & MCDT_CH_FIFO_ADDR_MASK; |
405 | u32 w_addr = readl_relaxed(mcdt->base + reg) & MCDT_CH_FIFO_ADDR_MASK; |
406 | |
407 | if (w_addr >= r_addr) |
408 | return 4 * (MCDT_FIFO_LENGTH - w_addr + r_addr); |
409 | else |
410 | return 4 * (r_addr - w_addr); |
411 | } |
412 | |
413 | static u32 sprd_mcdt_adc_fifo_avail(struct sprd_mcdt_dev *mcdt, u8 channel) |
414 | { |
415 | u32 reg = MCDT_ADC0_FIFO_ADDR_ST + channel * 8; |
416 | u32 r_addr = (readl_relaxed(mcdt->base + reg) >> |
417 | MCDT_CH_FIFO_ADDR_SHIFT) & MCDT_CH_FIFO_ADDR_MASK; |
418 | u32 w_addr = readl_relaxed(mcdt->base + reg) & MCDT_CH_FIFO_ADDR_MASK; |
419 | |
420 | if (w_addr >= r_addr) |
421 | return 4 * (w_addr - r_addr); |
422 | else |
423 | return 4 * (MCDT_FIFO_LENGTH - r_addr + w_addr); |
424 | } |
425 | |
426 | static u32 sprd_mcdt_int_type_shift(u8 channel, |
427 | enum sprd_mcdt_fifo_int int_type) |
428 | { |
429 | switch (channel) { |
430 | case 0: |
431 | case 4: |
432 | case 8: |
433 | return int_type; |
434 | |
435 | case 1: |
436 | case 5: |
437 | case 9: |
438 | return 8 + int_type; |
439 | |
440 | case 2: |
441 | case 6: |
442 | return 16 + int_type; |
443 | |
444 | case 3: |
445 | case 7: |
446 | return 24 + int_type; |
447 | |
448 | default: |
449 | return 0; |
450 | } |
451 | } |
452 | |
453 | static void sprd_mcdt_chan_int_en(struct sprd_mcdt_dev *mcdt, u8 channel, |
454 | enum sprd_mcdt_fifo_int int_type, bool enable) |
455 | { |
456 | u32 reg, shift = sprd_mcdt_int_type_shift(channel, int_type); |
457 | |
458 | switch (channel) { |
459 | case 0 ... 3: |
460 | reg = MCDT_INT_EN0; |
461 | break; |
462 | case 4 ... 7: |
463 | reg = MCDT_INT_EN1; |
464 | break; |
465 | case 8 ... 9: |
466 | reg = MCDT_INT_EN2; |
467 | break; |
468 | default: |
469 | return; |
470 | } |
471 | |
472 | if (enable) |
473 | sprd_mcdt_update(mcdt, reg, BIT(shift), BIT(shift)); |
474 | else |
475 | sprd_mcdt_update(mcdt, reg, val: 0, BIT(shift)); |
476 | } |
477 | |
478 | static void sprd_mcdt_chan_int_clear(struct sprd_mcdt_dev *mcdt, u8 channel, |
479 | enum sprd_mcdt_fifo_int int_type) |
480 | { |
481 | u32 reg, shift = sprd_mcdt_int_type_shift(channel, int_type); |
482 | |
483 | switch (channel) { |
484 | case 0 ... 3: |
485 | reg = MCDT_INT_CLR0; |
486 | break; |
487 | case 4 ... 7: |
488 | reg = MCDT_INT_CLR1; |
489 | break; |
490 | case 8 ... 9: |
491 | reg = MCDT_INT_CLR2; |
492 | break; |
493 | default: |
494 | return; |
495 | } |
496 | |
497 | sprd_mcdt_update(mcdt, reg, BIT(shift), BIT(shift)); |
498 | } |
499 | |
500 | static bool sprd_mcdt_chan_int_sts(struct sprd_mcdt_dev *mcdt, u8 channel, |
501 | enum sprd_mcdt_fifo_int int_type) |
502 | { |
503 | u32 reg, shift = sprd_mcdt_int_type_shift(channel, int_type); |
504 | |
505 | switch (channel) { |
506 | case 0 ... 3: |
507 | reg = MCDT_INT_MSK1; |
508 | break; |
509 | case 4 ... 7: |
510 | reg = MCDT_INT_MSK2; |
511 | break; |
512 | case 8 ... 9: |
513 | reg = MCDT_INT_MSK3; |
514 | break; |
515 | default: |
516 | return false; |
517 | } |
518 | |
519 | return !!(readl_relaxed(mcdt->base + reg) & BIT(shift)); |
520 | } |
521 | |
522 | static irqreturn_t sprd_mcdt_irq_handler(int irq, void *dev_id) |
523 | { |
524 | struct sprd_mcdt_dev *mcdt = (struct sprd_mcdt_dev *)dev_id; |
525 | int i; |
526 | |
527 | spin_lock(lock: &mcdt->lock); |
528 | |
529 | for (i = 0; i < MCDT_ADC_CHANNEL_NUM; i++) { |
530 | if (sprd_mcdt_chan_int_sts(mcdt, channel: i, int_type: MCDT_ADC_FIFO_AF_INT)) { |
531 | struct sprd_mcdt_chan *chan = &mcdt->chan[i]; |
532 | |
533 | sprd_mcdt_chan_int_clear(mcdt, channel: i, int_type: MCDT_ADC_FIFO_AF_INT); |
534 | if (chan->cb) |
535 | chan->cb->notify(chan->cb->data); |
536 | } |
537 | } |
538 | |
539 | for (i = 0; i < MCDT_DAC_CHANNEL_NUM; i++) { |
540 | if (sprd_mcdt_chan_int_sts(mcdt, channel: i, int_type: MCDT_DAC_FIFO_AE_INT)) { |
541 | struct sprd_mcdt_chan *chan = |
542 | &mcdt->chan[i + MCDT_ADC_CHANNEL_NUM]; |
543 | |
544 | sprd_mcdt_chan_int_clear(mcdt, channel: i, int_type: MCDT_DAC_FIFO_AE_INT); |
545 | if (chan->cb) |
546 | chan->cb->notify(chan->cb->data); |
547 | } |
548 | } |
549 | |
550 | spin_unlock(lock: &mcdt->lock); |
551 | |
552 | return IRQ_HANDLED; |
553 | } |
554 | |
555 | /** |
556 | * sprd_mcdt_chan_write - write data to the MCDT channel's fifo |
557 | * @chan: the MCDT channel |
558 | * @tx_buf: send buffer |
559 | * @size: data size |
560 | * |
561 | * Note: We can not write data to the channel fifo when enabling the DMA mode, |
562 | * otherwise the channel fifo data will be invalid. |
563 | * |
564 | * If there are not enough space of the channel fifo, it will return errors |
565 | * to users. |
566 | * |
567 | * Returns 0 on success, or an appropriate error code on failure. |
568 | */ |
569 | int sprd_mcdt_chan_write(struct sprd_mcdt_chan *chan, char *tx_buf, u32 size) |
570 | { |
571 | struct sprd_mcdt_dev *mcdt = chan->mcdt; |
572 | unsigned long flags; |
573 | int avail, i = 0, words = size / 4; |
574 | u32 *buf = (u32 *)tx_buf; |
575 | |
576 | spin_lock_irqsave(&mcdt->lock, flags); |
577 | |
578 | if (chan->dma_enable) { |
579 | dev_err(mcdt->dev, |
580 | "Can not write data when DMA mode enabled\n" ); |
581 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
582 | return -EINVAL; |
583 | } |
584 | |
585 | if (sprd_mcdt_chan_fifo_sts(mcdt, channel: chan->id, fifo_sts: MCDT_DAC_FIFO_REAL_FULL)) { |
586 | dev_err(mcdt->dev, "Channel fifo is full now\n" ); |
587 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
588 | return -EBUSY; |
589 | } |
590 | |
591 | avail = sprd_mcdt_dac_fifo_avail(mcdt, channel: chan->id); |
592 | if (size > avail) { |
593 | dev_err(mcdt->dev, |
594 | "Data size is larger than the available fifo size\n" ); |
595 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
596 | return -EBUSY; |
597 | } |
598 | |
599 | while (i++ < words) |
600 | sprd_mcdt_dac_write_fifo(mcdt, channel: chan->id, val: *buf++); |
601 | |
602 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
603 | return 0; |
604 | } |
605 | EXPORT_SYMBOL_GPL(sprd_mcdt_chan_write); |
606 | |
607 | /** |
608 | * sprd_mcdt_chan_read - read data from the MCDT channel's fifo |
609 | * @chan: the MCDT channel |
610 | * @rx_buf: receive buffer |
611 | * @size: data size |
612 | * |
613 | * Note: We can not read data from the channel fifo when enabling the DMA mode, |
614 | * otherwise the reading data will be invalid. |
615 | * |
616 | * Usually user need start to read data once receiving the fifo full interrupt. |
617 | * |
618 | * Returns data size of reading successfully, or an error code on failure. |
619 | */ |
620 | int sprd_mcdt_chan_read(struct sprd_mcdt_chan *chan, char *rx_buf, u32 size) |
621 | { |
622 | struct sprd_mcdt_dev *mcdt = chan->mcdt; |
623 | unsigned long flags; |
624 | int i = 0, avail, words = size / 4; |
625 | u32 *buf = (u32 *)rx_buf; |
626 | |
627 | spin_lock_irqsave(&mcdt->lock, flags); |
628 | |
629 | if (chan->dma_enable) { |
630 | dev_err(mcdt->dev, "Can not read data when DMA mode enabled\n" ); |
631 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
632 | return -EINVAL; |
633 | } |
634 | |
635 | if (sprd_mcdt_chan_fifo_sts(mcdt, channel: chan->id, fifo_sts: MCDT_ADC_FIFO_REAL_EMPTY)) { |
636 | dev_err(mcdt->dev, "Channel fifo is empty\n" ); |
637 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
638 | return -EBUSY; |
639 | } |
640 | |
641 | avail = sprd_mcdt_adc_fifo_avail(mcdt, channel: chan->id); |
642 | if (size > avail) |
643 | words = avail / 4; |
644 | |
645 | while (i++ < words) |
646 | sprd_mcdt_adc_read_fifo(mcdt, channel: chan->id, val: buf++); |
647 | |
648 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
649 | return words * 4; |
650 | } |
651 | EXPORT_SYMBOL_GPL(sprd_mcdt_chan_read); |
652 | |
653 | /** |
654 | * sprd_mcdt_chan_int_enable - enable the interrupt mode for the MCDT channel |
655 | * @chan: the MCDT channel |
656 | * @water_mark: water mark to trigger a interrupt |
657 | * @cb: callback when a interrupt happened |
658 | * |
659 | * Now it only can enable fifo almost full interrupt for ADC channel and fifo |
660 | * almost empty interrupt for DAC channel. Morevoer for interrupt mode, user |
661 | * should use sprd_mcdt_chan_read() or sprd_mcdt_chan_write() to read or write |
662 | * data manually. |
663 | * |
664 | * For ADC channel, user can start to read data once receiving one fifo full |
665 | * interrupt. For DAC channel, user can start to write data once receiving one |
666 | * fifo empty interrupt or just call sprd_mcdt_chan_write() to write data |
667 | * directly. |
668 | * |
669 | * Returns 0 on success, or an error code on failure. |
670 | */ |
671 | int sprd_mcdt_chan_int_enable(struct sprd_mcdt_chan *chan, u32 water_mark, |
672 | struct sprd_mcdt_chan_callback *cb) |
673 | { |
674 | struct sprd_mcdt_dev *mcdt = chan->mcdt; |
675 | unsigned long flags; |
676 | int ret = 0; |
677 | |
678 | spin_lock_irqsave(&mcdt->lock, flags); |
679 | |
680 | if (chan->dma_enable || chan->int_enable) { |
681 | dev_err(mcdt->dev, "Failed to set interrupt mode.\n" ); |
682 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
683 | return -EINVAL; |
684 | } |
685 | |
686 | switch (chan->type) { |
687 | case SPRD_MCDT_ADC_CHAN: |
688 | sprd_mcdt_adc_fifo_clear(mcdt, channel: chan->id); |
689 | sprd_mcdt_adc_set_watermark(mcdt, channel: chan->id, full: water_mark, |
690 | MCDT_FIFO_LENGTH - 1); |
691 | sprd_mcdt_chan_int_en(mcdt, channel: chan->id, |
692 | int_type: MCDT_ADC_FIFO_AF_INT, enable: true); |
693 | sprd_mcdt_ap_int_enable(mcdt, channel: chan->id, enable: true); |
694 | break; |
695 | |
696 | case SPRD_MCDT_DAC_CHAN: |
697 | sprd_mcdt_dac_fifo_clear(mcdt, channel: chan->id); |
698 | sprd_mcdt_dac_set_watermark(mcdt, channel: chan->id, |
699 | MCDT_FIFO_LENGTH - 1, empty: water_mark); |
700 | sprd_mcdt_chan_int_en(mcdt, channel: chan->id, |
701 | int_type: MCDT_DAC_FIFO_AE_INT, enable: true); |
702 | sprd_mcdt_ap_int_enable(mcdt, channel: chan->id, enable: true); |
703 | break; |
704 | |
705 | default: |
706 | dev_err(mcdt->dev, "Unsupported channel type\n" ); |
707 | ret = -EINVAL; |
708 | } |
709 | |
710 | if (!ret) { |
711 | chan->cb = cb; |
712 | chan->int_enable = true; |
713 | } |
714 | |
715 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
716 | |
717 | return ret; |
718 | } |
719 | EXPORT_SYMBOL_GPL(sprd_mcdt_chan_int_enable); |
720 | |
721 | /** |
722 | * sprd_mcdt_chan_int_disable - disable the interrupt mode for the MCDT channel |
723 | * @chan: the MCDT channel |
724 | */ |
725 | void sprd_mcdt_chan_int_disable(struct sprd_mcdt_chan *chan) |
726 | { |
727 | struct sprd_mcdt_dev *mcdt = chan->mcdt; |
728 | unsigned long flags; |
729 | |
730 | spin_lock_irqsave(&mcdt->lock, flags); |
731 | |
732 | if (!chan->int_enable) { |
733 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
734 | return; |
735 | } |
736 | |
737 | switch (chan->type) { |
738 | case SPRD_MCDT_ADC_CHAN: |
739 | sprd_mcdt_chan_int_en(mcdt, channel: chan->id, |
740 | int_type: MCDT_ADC_FIFO_AF_INT, enable: false); |
741 | sprd_mcdt_chan_int_clear(mcdt, channel: chan->id, int_type: MCDT_ADC_FIFO_AF_INT); |
742 | sprd_mcdt_ap_int_enable(mcdt, channel: chan->id, enable: false); |
743 | break; |
744 | |
745 | case SPRD_MCDT_DAC_CHAN: |
746 | sprd_mcdt_chan_int_en(mcdt, channel: chan->id, |
747 | int_type: MCDT_DAC_FIFO_AE_INT, enable: false); |
748 | sprd_mcdt_chan_int_clear(mcdt, channel: chan->id, int_type: MCDT_DAC_FIFO_AE_INT); |
749 | sprd_mcdt_ap_int_enable(mcdt, channel: chan->id, enable: false); |
750 | break; |
751 | |
752 | default: |
753 | break; |
754 | } |
755 | |
756 | chan->int_enable = false; |
757 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
758 | } |
759 | EXPORT_SYMBOL_GPL(sprd_mcdt_chan_int_disable); |
760 | |
761 | /** |
762 | * sprd_mcdt_chan_dma_enable - enable the DMA mode for the MCDT channel |
763 | * @chan: the MCDT channel |
764 | * @dma_chan: specify which DMA channel will be used for this MCDT channel |
765 | * @water_mark: water mark to trigger a DMA request |
766 | * |
767 | * Enable the DMA mode for the MCDT channel, that means we can use DMA to |
768 | * transfer data to the channel fifo and do not need reading/writing data |
769 | * manually. |
770 | * |
771 | * Returns 0 on success, or an error code on failure. |
772 | */ |
773 | int sprd_mcdt_chan_dma_enable(struct sprd_mcdt_chan *chan, |
774 | enum sprd_mcdt_dma_chan dma_chan, |
775 | u32 water_mark) |
776 | { |
777 | struct sprd_mcdt_dev *mcdt = chan->mcdt; |
778 | unsigned long flags; |
779 | int ret = 0; |
780 | |
781 | spin_lock_irqsave(&mcdt->lock, flags); |
782 | |
783 | if (chan->dma_enable || chan->int_enable || |
784 | dma_chan > SPRD_MCDT_DMA_CH4) { |
785 | dev_err(mcdt->dev, "Failed to set DMA mode\n" ); |
786 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
787 | return -EINVAL; |
788 | } |
789 | |
790 | switch (chan->type) { |
791 | case SPRD_MCDT_ADC_CHAN: |
792 | sprd_mcdt_adc_fifo_clear(mcdt, channel: chan->id); |
793 | sprd_mcdt_adc_set_watermark(mcdt, channel: chan->id, |
794 | full: water_mark, MCDT_FIFO_LENGTH - 1); |
795 | sprd_mcdt_adc_dma_enable(mcdt, channel: chan->id, enable: true); |
796 | sprd_mcdt_adc_dma_chn_select(mcdt, channel: chan->id, dma_chan); |
797 | sprd_mcdt_adc_dma_ack_select(mcdt, channel: chan->id, dma_chan); |
798 | break; |
799 | |
800 | case SPRD_MCDT_DAC_CHAN: |
801 | sprd_mcdt_dac_fifo_clear(mcdt, channel: chan->id); |
802 | sprd_mcdt_dac_set_watermark(mcdt, channel: chan->id, |
803 | MCDT_FIFO_LENGTH - 1, empty: water_mark); |
804 | sprd_mcdt_dac_dma_enable(mcdt, channel: chan->id, enable: true); |
805 | sprd_mcdt_dac_dma_chn_select(mcdt, channel: chan->id, dma_chan); |
806 | sprd_mcdt_dac_dma_ack_select(mcdt, channel: chan->id, dma_chan); |
807 | break; |
808 | |
809 | default: |
810 | dev_err(mcdt->dev, "Unsupported channel type\n" ); |
811 | ret = -EINVAL; |
812 | } |
813 | |
814 | if (!ret) |
815 | chan->dma_enable = true; |
816 | |
817 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
818 | |
819 | return ret; |
820 | } |
821 | EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_enable); |
822 | |
823 | /** |
824 | * sprd_mcdt_chan_dma_disable - disable the DMA mode for the MCDT channel |
825 | * @chan: the MCDT channel |
826 | */ |
827 | void sprd_mcdt_chan_dma_disable(struct sprd_mcdt_chan *chan) |
828 | { |
829 | struct sprd_mcdt_dev *mcdt = chan->mcdt; |
830 | unsigned long flags; |
831 | |
832 | spin_lock_irqsave(&mcdt->lock, flags); |
833 | |
834 | if (!chan->dma_enable) { |
835 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
836 | return; |
837 | } |
838 | |
839 | switch (chan->type) { |
840 | case SPRD_MCDT_ADC_CHAN: |
841 | sprd_mcdt_adc_dma_enable(mcdt, channel: chan->id, enable: false); |
842 | sprd_mcdt_adc_fifo_clear(mcdt, channel: chan->id); |
843 | break; |
844 | |
845 | case SPRD_MCDT_DAC_CHAN: |
846 | sprd_mcdt_dac_dma_enable(mcdt, channel: chan->id, enable: false); |
847 | sprd_mcdt_dac_fifo_clear(mcdt, channel: chan->id); |
848 | break; |
849 | |
850 | default: |
851 | break; |
852 | } |
853 | |
854 | chan->dma_enable = false; |
855 | spin_unlock_irqrestore(lock: &mcdt->lock, flags); |
856 | } |
857 | EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_disable); |
858 | |
859 | /** |
860 | * sprd_mcdt_request_chan - request one MCDT channel |
861 | * @channel: channel id |
862 | * @type: channel type, it can be one ADC channel or DAC channel |
863 | * |
864 | * Rreturn NULL if no available channel. |
865 | */ |
866 | struct sprd_mcdt_chan *sprd_mcdt_request_chan(u8 channel, |
867 | enum sprd_mcdt_channel_type type) |
868 | { |
869 | struct sprd_mcdt_chan *temp; |
870 | |
871 | mutex_lock(&sprd_mcdt_list_mutex); |
872 | |
873 | list_for_each_entry(temp, &sprd_mcdt_chan_list, list) { |
874 | if (temp->type == type && temp->id == channel) { |
875 | list_del_init(entry: &temp->list); |
876 | break; |
877 | } |
878 | } |
879 | |
880 | if (list_entry_is_head(temp, &sprd_mcdt_chan_list, list)) |
881 | temp = NULL; |
882 | |
883 | mutex_unlock(lock: &sprd_mcdt_list_mutex); |
884 | |
885 | return temp; |
886 | } |
887 | EXPORT_SYMBOL_GPL(sprd_mcdt_request_chan); |
888 | |
889 | /** |
890 | * sprd_mcdt_free_chan - free one MCDT channel |
891 | * @chan: the channel to be freed |
892 | */ |
893 | void sprd_mcdt_free_chan(struct sprd_mcdt_chan *chan) |
894 | { |
895 | struct sprd_mcdt_chan *temp; |
896 | |
897 | sprd_mcdt_chan_dma_disable(chan); |
898 | sprd_mcdt_chan_int_disable(chan); |
899 | |
900 | mutex_lock(&sprd_mcdt_list_mutex); |
901 | |
902 | list_for_each_entry(temp, &sprd_mcdt_chan_list, list) { |
903 | if (temp == chan) { |
904 | mutex_unlock(lock: &sprd_mcdt_list_mutex); |
905 | return; |
906 | } |
907 | } |
908 | |
909 | list_add_tail(new: &chan->list, head: &sprd_mcdt_chan_list); |
910 | mutex_unlock(lock: &sprd_mcdt_list_mutex); |
911 | } |
912 | EXPORT_SYMBOL_GPL(sprd_mcdt_free_chan); |
913 | |
914 | static void sprd_mcdt_init_chans(struct sprd_mcdt_dev *mcdt, |
915 | struct resource *res) |
916 | { |
917 | int i; |
918 | |
919 | for (i = 0; i < MCDT_CHANNEL_NUM; i++) { |
920 | struct sprd_mcdt_chan *chan = &mcdt->chan[i]; |
921 | |
922 | if (i < MCDT_ADC_CHANNEL_NUM) { |
923 | chan->id = i; |
924 | chan->type = SPRD_MCDT_ADC_CHAN; |
925 | chan->fifo_phys = res->start + MCDT_CH0_RXD + i * 4; |
926 | } else { |
927 | chan->id = i - MCDT_ADC_CHANNEL_NUM; |
928 | chan->type = SPRD_MCDT_DAC_CHAN; |
929 | chan->fifo_phys = res->start + MCDT_CH0_TXD + |
930 | (i - MCDT_ADC_CHANNEL_NUM) * 4; |
931 | } |
932 | |
933 | chan->mcdt = mcdt; |
934 | INIT_LIST_HEAD(list: &chan->list); |
935 | |
936 | mutex_lock(&sprd_mcdt_list_mutex); |
937 | list_add_tail(new: &chan->list, head: &sprd_mcdt_chan_list); |
938 | mutex_unlock(lock: &sprd_mcdt_list_mutex); |
939 | } |
940 | } |
941 | |
942 | static int sprd_mcdt_probe(struct platform_device *pdev) |
943 | { |
944 | struct sprd_mcdt_dev *mcdt; |
945 | struct resource *res; |
946 | int ret, irq; |
947 | |
948 | mcdt = devm_kzalloc(dev: &pdev->dev, size: sizeof(*mcdt), GFP_KERNEL); |
949 | if (!mcdt) |
950 | return -ENOMEM; |
951 | |
952 | mcdt->base = devm_platform_get_and_ioremap_resource(pdev, index: 0, res: &res); |
953 | if (IS_ERR(ptr: mcdt->base)) |
954 | return PTR_ERR(ptr: mcdt->base); |
955 | |
956 | mcdt->dev = &pdev->dev; |
957 | spin_lock_init(&mcdt->lock); |
958 | platform_set_drvdata(pdev, data: mcdt); |
959 | |
960 | irq = platform_get_irq(pdev, 0); |
961 | if (irq < 0) |
962 | return irq; |
963 | |
964 | ret = devm_request_irq(dev: &pdev->dev, irq, handler: sprd_mcdt_irq_handler, |
965 | irqflags: 0, devname: "sprd-mcdt" , dev_id: mcdt); |
966 | if (ret) { |
967 | dev_err(&pdev->dev, "Failed to request MCDT IRQ\n" ); |
968 | return ret; |
969 | } |
970 | |
971 | sprd_mcdt_init_chans(mcdt, res); |
972 | |
973 | return 0; |
974 | } |
975 | |
976 | static void sprd_mcdt_remove(struct platform_device *pdev) |
977 | { |
978 | struct sprd_mcdt_chan *chan, *temp; |
979 | |
980 | mutex_lock(&sprd_mcdt_list_mutex); |
981 | |
982 | list_for_each_entry_safe(chan, temp, &sprd_mcdt_chan_list, list) |
983 | list_del(entry: &chan->list); |
984 | |
985 | mutex_unlock(lock: &sprd_mcdt_list_mutex); |
986 | } |
987 | |
988 | static const struct of_device_id sprd_mcdt_of_match[] = { |
989 | { .compatible = "sprd,sc9860-mcdt" , }, |
990 | { } |
991 | }; |
992 | MODULE_DEVICE_TABLE(of, sprd_mcdt_of_match); |
993 | |
994 | static struct platform_driver sprd_mcdt_driver = { |
995 | .probe = sprd_mcdt_probe, |
996 | .remove_new = sprd_mcdt_remove, |
997 | .driver = { |
998 | .name = "sprd-mcdt" , |
999 | .of_match_table = sprd_mcdt_of_match, |
1000 | }, |
1001 | }; |
1002 | |
1003 | module_platform_driver(sprd_mcdt_driver); |
1004 | |
1005 | MODULE_DESCRIPTION("Spreadtrum Multi-Channel Data Transfer Driver" ); |
1006 | MODULE_LICENSE("GPL v2" ); |
1007 | |