brintos

brintos / linux-shallow public Read only

0
0
Text · 23.5 KiB · 814a1cd Raw
1007 lines · c
1// SPDX-License-Identifier: GPL-2.02// 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		0x018#define MCDT_CH0_RXD		0x2819#define MCDT_DAC0_WTMK		0x6020#define MCDT_ADC0_WTMK		0x8821#define MCDT_DMA_EN		0xb022 23#define MCDT_INT_EN0		0xb424#define MCDT_INT_EN1		0xb825#define MCDT_INT_EN2		0xbc26 27#define MCDT_INT_CLR0		0xc028#define MCDT_INT_CLR1		0xc429#define MCDT_INT_CLR2		0xc830 31#define MCDT_INT_RAW1		0xcc32#define MCDT_INT_RAW2		0xd033#define MCDT_INT_RAW3		0xd434 35#define MCDT_INT_MSK1		0xd836#define MCDT_INT_MSK2		0xdc37#define MCDT_INT_MSK3		0xe038 39#define MCDT_DAC0_FIFO_ADDR_ST	0xe440#define MCDT_ADC0_FIFO_ADDR_ST	0xe841 42#define MCDT_CH_FIFO_ST0	0x13443#define MCDT_CH_FIFO_ST1	0x13844#define MCDT_CH_FIFO_ST2	0x13c45 46#define MCDT_INT_MSK_CFG0	0x14047#define MCDT_INT_MSK_CFG1	0x14448 49#define MCDT_DMA_CFG0		0x14850#define MCDT_FIFO_CLR		0x14c51#define MCDT_DMA_CFG1		0x15052#define MCDT_DMA_CFG2		0x15453#define MCDT_DMA_CFG3		0x15854#define MCDT_DMA_CFG4		0x15c55#define MCDT_DMA_CFG5		0x16056 57/* Channel water mark definition */58#define MCDT_CH_FIFO_AE_SHIFT	1659#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	065#define MCDT_DMA_CH1_SEL_MASK	GENMASK(7, 4)66#define MCDT_DMA_CH1_SEL_SHIFT	467#define MCDT_DMA_CH2_SEL_MASK	GENMASK(11, 8)68#define MCDT_DMA_CH2_SEL_SHIFT	869#define MCDT_DMA_CH3_SEL_MASK	GENMASK(15, 12)70#define MCDT_DMA_CH3_SEL_SHIFT	1271#define MCDT_DMA_CH4_SEL_MASK	GENMASK(19, 16)72#define MCDT_DMA_CH4_SEL_SHIFT	1673#define MCDT_DAC_DMA_SHIFT	1674 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	1680#define MCDT_CH_FIFO_ADDR_MASK	GENMASK(9, 0)81#define MCDT_ADC_FIFO_SHIFT	1682#define MCDT_FIFO_LENGTH	51283 84#define MCDT_ADC_CHANNEL_NUM	1085#define MCDT_DAC_CHANNEL_NUM	1086#define MCDT_CHANNEL_NUM	(MCDT_ADC_CHANNEL_NUM + MCDT_DAC_CHANNEL_NUM)87 88enum 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_INT95};96 97enum 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_AE106};107 108struct 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 115static LIST_HEAD(sprd_mcdt_chan_list);116static DEFINE_MUTEX(sprd_mcdt_list_mutex);117 118static 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 128static 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, water_mark,137			 MCDT_CH_FIFO_AE_MASK | MCDT_CH_FIFO_AF_MASK);138}139 140static 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, water_mark,149			 MCDT_CH_FIFO_AE_MASK | MCDT_CH_FIFO_AF_MASK);150}151 152static 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	else160		sprd_mcdt_update(mcdt, MCDT_DMA_EN, 0, BIT(shift));161}162 163static 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	else169		sprd_mcdt_update(mcdt, MCDT_DMA_EN, 0, BIT(channel));170}171 172static 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	else179		sprd_mcdt_update(mcdt, MCDT_INT_MSK_CFG0, 0, BIT(channel));180}181 182static 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 190static 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 198static 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				 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				 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				 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				 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				 channel << MCDT_DMA_CH4_SEL_SHIFT,229				 MCDT_DMA_CH4_SEL_MASK);230		break;231	}232}233 234static 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				 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				 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				 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				 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				 channel << MCDT_DMA_CH4_SEL_SHIFT,265				 MCDT_DMA_CH4_SEL_MASK);266		break;267	}268}269 270static 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 295static 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, ack << shift,314			 MCDT_DMA_ACK_SEL_MASK << shift);315}316 317static 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, ack << shift,336			 MCDT_DMA_ACK_SEL_MASK << shift);337}338 339static 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 388static 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 393static 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 400static 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	else410		return 4 * (r_addr - w_addr);411}412 413static 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	else423		return 4 * (MCDT_FIFO_LENGTH - r_addr + w_addr);424}425 426static 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 453static 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	else475		sprd_mcdt_update(mcdt, reg, 0, BIT(shift));476}477 478static 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 500static 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 522static 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(&mcdt->lock);528 529	for (i = 0; i < MCDT_ADC_CHANNEL_NUM; i++) {530		if (sprd_mcdt_chan_int_sts(mcdt, i, MCDT_ADC_FIFO_AF_INT)) {531			struct sprd_mcdt_chan *chan = &mcdt->chan[i];532 533			sprd_mcdt_chan_int_clear(mcdt, i, 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, i, 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, i, MCDT_DAC_FIFO_AE_INT);545			if (chan->cb)546				chan->cb->notify(chan->cb->data);547		}548	}549 550	spin_unlock(&mcdt->lock);551 552	return IRQ_HANDLED;553}554 555/**556 * sprd_mcdt_chan_write - write data to the MCDT channel's fifo557 * @chan: the MCDT channel558 * @tx_buf: send buffer559 * @size: data size560 *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 errors565 * to users.566 *567 * Returns 0 on success, or an appropriate error code on failure.568 */569int 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(&mcdt->lock, flags);582		return -EINVAL;583	}584 585	if (sprd_mcdt_chan_fifo_sts(mcdt, chan->id, MCDT_DAC_FIFO_REAL_FULL)) {586		dev_err(mcdt->dev, "Channel fifo is full now\n");587		spin_unlock_irqrestore(&mcdt->lock, flags);588		return -EBUSY;589	}590 591	avail = sprd_mcdt_dac_fifo_avail(mcdt, 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(&mcdt->lock, flags);596		return -EBUSY;597	}598 599	while (i++ < words)600		sprd_mcdt_dac_write_fifo(mcdt, chan->id, *buf++);601 602	spin_unlock_irqrestore(&mcdt->lock, flags);603	return 0;604}605EXPORT_SYMBOL_GPL(sprd_mcdt_chan_write);606 607/**608 * sprd_mcdt_chan_read - read data from the MCDT channel's fifo609 * @chan: the MCDT channel610 * @rx_buf: receive buffer611 * @size: data size612 *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 */620int 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(&mcdt->lock, flags);632		return -EINVAL;633	}634 635	if (sprd_mcdt_chan_fifo_sts(mcdt, chan->id, MCDT_ADC_FIFO_REAL_EMPTY)) {636		dev_err(mcdt->dev, "Channel fifo is empty\n");637		spin_unlock_irqrestore(&mcdt->lock, flags);638		return -EBUSY;639	}640 641	avail = sprd_mcdt_adc_fifo_avail(mcdt, chan->id);642	if (size > avail)643		words = avail / 4;644 645	while (i++ < words)646		sprd_mcdt_adc_read_fifo(mcdt, chan->id, buf++);647 648	spin_unlock_irqrestore(&mcdt->lock, flags);649	return words * 4;650}651EXPORT_SYMBOL_GPL(sprd_mcdt_chan_read);652 653/**654 * sprd_mcdt_chan_int_enable - enable the interrupt mode for the MCDT channel655 * @chan: the MCDT channel656 * @water_mark: water mark to trigger a interrupt657 * @cb: callback when a interrupt happened658 *659 * Now it only can enable fifo almost full interrupt for ADC channel and fifo660 * almost empty interrupt for DAC channel. Morevoer for interrupt mode, user661 * should use sprd_mcdt_chan_read() or sprd_mcdt_chan_write() to read or write662 * data manually.663 *664 * For ADC channel, user can start to read data once receiving one fifo full665 * interrupt. For DAC channel, user can start to write data once receiving one666 * fifo empty interrupt or just call sprd_mcdt_chan_write() to write data667 * directly.668 *669 * Returns 0 on success, or an error code on failure.670 */671int 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(&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, chan->id);689		sprd_mcdt_adc_set_watermark(mcdt, chan->id, water_mark,690					    MCDT_FIFO_LENGTH - 1);691		sprd_mcdt_chan_int_en(mcdt, chan->id,692				      MCDT_ADC_FIFO_AF_INT, true);693		sprd_mcdt_ap_int_enable(mcdt, chan->id, true);694		break;695 696	case SPRD_MCDT_DAC_CHAN:697		sprd_mcdt_dac_fifo_clear(mcdt, chan->id);698		sprd_mcdt_dac_set_watermark(mcdt, chan->id,699					    MCDT_FIFO_LENGTH - 1, water_mark);700		sprd_mcdt_chan_int_en(mcdt, chan->id,701				      MCDT_DAC_FIFO_AE_INT, true);702		sprd_mcdt_ap_int_enable(mcdt, chan->id, 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(&mcdt->lock, flags);716 717	return ret;718}719EXPORT_SYMBOL_GPL(sprd_mcdt_chan_int_enable);720 721/**722 * sprd_mcdt_chan_int_disable - disable the interrupt mode for the MCDT channel723 * @chan: the MCDT channel724 */725void 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(&mcdt->lock, flags);734		return;735	}736 737	switch (chan->type) {738	case SPRD_MCDT_ADC_CHAN:739		sprd_mcdt_chan_int_en(mcdt, chan->id,740				      MCDT_ADC_FIFO_AF_INT, false);741		sprd_mcdt_chan_int_clear(mcdt, chan->id, MCDT_ADC_FIFO_AF_INT);742		sprd_mcdt_ap_int_enable(mcdt, chan->id, false);743		break;744 745	case SPRD_MCDT_DAC_CHAN:746		sprd_mcdt_chan_int_en(mcdt, chan->id,747				      MCDT_DAC_FIFO_AE_INT, false);748		sprd_mcdt_chan_int_clear(mcdt, chan->id, MCDT_DAC_FIFO_AE_INT);749		sprd_mcdt_ap_int_enable(mcdt, chan->id, false);750		break;751 752	default:753		break;754	}755 756	chan->int_enable = false;757	spin_unlock_irqrestore(&mcdt->lock, flags);758}759EXPORT_SYMBOL_GPL(sprd_mcdt_chan_int_disable);760 761/**762 * sprd_mcdt_chan_dma_enable - enable the DMA mode for the MCDT channel763 * @chan: the MCDT channel764 * @dma_chan: specify which DMA channel will be used for this MCDT channel765 * @water_mark: water mark to trigger a DMA request766 *767 * Enable the DMA mode for the MCDT channel, that means we can use DMA to768 * transfer data to the channel fifo and do not need reading/writing data769 * manually.770 *771 * Returns 0 on success, or an error code on failure.772 */773int 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(&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, chan->id);793		sprd_mcdt_adc_set_watermark(mcdt, chan->id,794					    water_mark, MCDT_FIFO_LENGTH - 1);795		sprd_mcdt_adc_dma_enable(mcdt, chan->id, true);796		sprd_mcdt_adc_dma_chn_select(mcdt, chan->id, dma_chan);797		sprd_mcdt_adc_dma_ack_select(mcdt, chan->id, dma_chan);798		break;799 800	case SPRD_MCDT_DAC_CHAN:801		sprd_mcdt_dac_fifo_clear(mcdt, chan->id);802		sprd_mcdt_dac_set_watermark(mcdt, chan->id,803					    MCDT_FIFO_LENGTH - 1, water_mark);804		sprd_mcdt_dac_dma_enable(mcdt, chan->id, true);805		sprd_mcdt_dac_dma_chn_select(mcdt, chan->id, dma_chan);806		sprd_mcdt_dac_dma_ack_select(mcdt, 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(&mcdt->lock, flags);818 819	return ret;820}821EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_enable);822 823/**824 * sprd_mcdt_chan_dma_disable - disable the DMA mode for the MCDT channel825 * @chan: the MCDT channel826 */827void 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(&mcdt->lock, flags);836		return;837	}838 839	switch (chan->type) {840	case SPRD_MCDT_ADC_CHAN:841		sprd_mcdt_adc_dma_enable(mcdt, chan->id, false);842		sprd_mcdt_adc_fifo_clear(mcdt, chan->id);843		break;844 845	case SPRD_MCDT_DAC_CHAN:846		sprd_mcdt_dac_dma_enable(mcdt, chan->id, false);847		sprd_mcdt_dac_fifo_clear(mcdt, chan->id);848		break;849 850	default:851		break;852	}853 854	chan->dma_enable = false;855	spin_unlock_irqrestore(&mcdt->lock, flags);856}857EXPORT_SYMBOL_GPL(sprd_mcdt_chan_dma_disable);858 859/**860 * sprd_mcdt_request_chan - request one MCDT channel861 * @channel: channel id862 * @type: channel type, it can be one ADC channel or DAC channel863 *864 * Rreturn NULL if no available channel.865 */866struct 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(&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(&sprd_mcdt_list_mutex);884 885	return temp;886}887EXPORT_SYMBOL_GPL(sprd_mcdt_request_chan);888 889/**890 * sprd_mcdt_free_chan - free one MCDT channel891 * @chan: the channel to be freed892 */893void 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(&sprd_mcdt_list_mutex);905			return;906		}907	}908 909	list_add_tail(&chan->list, &sprd_mcdt_chan_list);910	mutex_unlock(&sprd_mcdt_list_mutex);911}912EXPORT_SYMBOL_GPL(sprd_mcdt_free_chan);913 914static 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(&chan->list);935 936		mutex_lock(&sprd_mcdt_list_mutex);937		list_add_tail(&chan->list, &sprd_mcdt_chan_list);938		mutex_unlock(&sprd_mcdt_list_mutex);939	}940}941 942static 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(&pdev->dev, sizeof(*mcdt), GFP_KERNEL);949	if (!mcdt)950		return -ENOMEM;951 952	mcdt->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);953	if (IS_ERR(mcdt->base))954		return PTR_ERR(mcdt->base);955 956	mcdt->dev = &pdev->dev;957	spin_lock_init(&mcdt->lock);958	platform_set_drvdata(pdev, mcdt);959 960	irq = platform_get_irq(pdev, 0);961	if (irq < 0)962		return irq;963 964	ret = devm_request_irq(&pdev->dev, irq, sprd_mcdt_irq_handler,965			       0, "sprd-mcdt", 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 976static 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(&chan->list);984 985	mutex_unlock(&sprd_mcdt_list_mutex);986}987 988static const struct of_device_id sprd_mcdt_of_match[] = {989	{ .compatible = "sprd,sc9860-mcdt", },990	{ }991};992MODULE_DEVICE_TABLE(of, sprd_mcdt_of_match);993 994static struct platform_driver sprd_mcdt_driver = {995	.probe = sprd_mcdt_probe,996	.remove = sprd_mcdt_remove,997	.driver = {998		.name = "sprd-mcdt",999		.of_match_table = sprd_mcdt_of_match,1000	},1001};1002 1003module_platform_driver(sprd_mcdt_driver);1004 1005MODULE_DESCRIPTION("Spreadtrum Multi-Channel Data Transfer Driver");1006MODULE_LICENSE("GPL v2");1007