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