18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * MediaTek UART APDMA driver.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2019 MediaTek Inc.
68c2ecf20Sopenharmony_ci * Author: Long Cheng <long.cheng@mediatek.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/dmaengine.h>
118c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
128c2ecf20Sopenharmony_ci#include <linux/err.h>
138c2ecf20Sopenharmony_ci#include <linux/init.h>
148c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
158c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/list.h>
188c2ecf20Sopenharmony_ci#include <linux/module.h>
198c2ecf20Sopenharmony_ci#include <linux/of_device.h>
208c2ecf20Sopenharmony_ci#include <linux/of_dma.h>
218c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h>
238c2ecf20Sopenharmony_ci#include <linux/slab.h>
248c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#include "../virt-dma.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* The default number of virtual channel */
298c2ecf20Sopenharmony_ci#define MTK_UART_APDMA_NR_VCHANS	8
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define VFF_EN_B		BIT(0)
328c2ecf20Sopenharmony_ci#define VFF_STOP_B		BIT(0)
338c2ecf20Sopenharmony_ci#define VFF_FLUSH_B		BIT(0)
348c2ecf20Sopenharmony_ci#define VFF_4G_EN_B		BIT(0)
358c2ecf20Sopenharmony_ci/* rx valid size >=  vff thre */
368c2ecf20Sopenharmony_ci#define VFF_RX_INT_EN_B		(BIT(0) | BIT(1))
378c2ecf20Sopenharmony_ci/* tx left size >= vff thre */
388c2ecf20Sopenharmony_ci#define VFF_TX_INT_EN_B		BIT(0)
398c2ecf20Sopenharmony_ci#define VFF_WARM_RST_B		BIT(0)
408c2ecf20Sopenharmony_ci#define VFF_RX_INT_CLR_B	(BIT(0) | BIT(1))
418c2ecf20Sopenharmony_ci#define VFF_TX_INT_CLR_B	0
428c2ecf20Sopenharmony_ci#define VFF_STOP_CLR_B		0
438c2ecf20Sopenharmony_ci#define VFF_EN_CLR_B		0
448c2ecf20Sopenharmony_ci#define VFF_INT_EN_CLR_B	0
458c2ecf20Sopenharmony_ci#define VFF_4G_SUPPORT_CLR_B	0
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/*
488c2ecf20Sopenharmony_ci * interrupt trigger level for tx
498c2ecf20Sopenharmony_ci * if threshold is n, no polling is required to start tx.
508c2ecf20Sopenharmony_ci * otherwise need polling VFF_FLUSH.
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_ci#define VFF_TX_THRE(n)		(n)
538c2ecf20Sopenharmony_ci/* interrupt trigger level for rx */
548c2ecf20Sopenharmony_ci#define VFF_RX_THRE(n)		((n) * 3 / 4)
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#define VFF_RING_SIZE	0xffff
578c2ecf20Sopenharmony_ci/* invert this bit when wrap ring head again */
588c2ecf20Sopenharmony_ci#define VFF_RING_WRAP	0x10000
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#define VFF_INT_FLAG		0x00
618c2ecf20Sopenharmony_ci#define VFF_INT_EN		0x04
628c2ecf20Sopenharmony_ci#define VFF_EN			0x08
638c2ecf20Sopenharmony_ci#define VFF_RST			0x0c
648c2ecf20Sopenharmony_ci#define VFF_STOP		0x10
658c2ecf20Sopenharmony_ci#define VFF_FLUSH		0x14
668c2ecf20Sopenharmony_ci#define VFF_ADDR		0x1c
678c2ecf20Sopenharmony_ci#define VFF_LEN			0x24
688c2ecf20Sopenharmony_ci#define VFF_THRE		0x28
698c2ecf20Sopenharmony_ci#define VFF_WPT			0x2c
708c2ecf20Sopenharmony_ci#define VFF_RPT			0x30
718c2ecf20Sopenharmony_ci/* TX: the buffer size HW can read. RX: the buffer size SW can read. */
728c2ecf20Sopenharmony_ci#define VFF_VALID_SIZE		0x3c
738c2ecf20Sopenharmony_ci/* TX: the buffer size SW can write. RX: the buffer size HW can write. */
748c2ecf20Sopenharmony_ci#define VFF_LEFT_SIZE		0x40
758c2ecf20Sopenharmony_ci#define VFF_DEBUG_STATUS	0x50
768c2ecf20Sopenharmony_ci#define VFF_4G_SUPPORT		0x54
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistruct mtk_uart_apdmadev {
798c2ecf20Sopenharmony_ci	struct dma_device ddev;
808c2ecf20Sopenharmony_ci	struct clk *clk;
818c2ecf20Sopenharmony_ci	bool support_33bits;
828c2ecf20Sopenharmony_ci	unsigned int dma_requests;
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistruct mtk_uart_apdma_desc {
868c2ecf20Sopenharmony_ci	struct virt_dma_desc vd;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	dma_addr_t addr;
898c2ecf20Sopenharmony_ci	unsigned int avail_len;
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistruct mtk_chan {
938c2ecf20Sopenharmony_ci	struct virt_dma_chan vc;
948c2ecf20Sopenharmony_ci	struct dma_slave_config	cfg;
958c2ecf20Sopenharmony_ci	struct mtk_uart_apdma_desc *desc;
968c2ecf20Sopenharmony_ci	enum dma_transfer_direction dir;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	void __iomem *base;
998c2ecf20Sopenharmony_ci	unsigned int irq;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	unsigned int rx_status;
1028c2ecf20Sopenharmony_ci};
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic inline struct mtk_uart_apdmadev *
1058c2ecf20Sopenharmony_cito_mtk_uart_apdma_dev(struct dma_device *d)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	return container_of(d, struct mtk_uart_apdmadev, ddev);
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic inline struct mtk_chan *to_mtk_uart_apdma_chan(struct dma_chan *c)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	return container_of(c, struct mtk_chan, vc.chan);
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic inline struct mtk_uart_apdma_desc *to_mtk_uart_apdma_desc
1168c2ecf20Sopenharmony_ci	(struct dma_async_tx_descriptor *t)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	return container_of(t, struct mtk_uart_apdma_desc, vd.tx);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_write(struct mtk_chan *c,
1228c2ecf20Sopenharmony_ci			       unsigned int reg, unsigned int val)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	writel(val, c->base + reg);
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic unsigned int mtk_uart_apdma_read(struct mtk_chan *c, unsigned int reg)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	return readl(c->base + reg);
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_desc_free(struct virt_dma_desc *vd)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	kfree(container_of(vd, struct mtk_uart_apdma_desc, vd));
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_start_tx(struct mtk_chan *c)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd =
1408c2ecf20Sopenharmony_ci				to_mtk_uart_apdma_dev(c->vc.chan.device);
1418c2ecf20Sopenharmony_ci	struct mtk_uart_apdma_desc *d = c->desc;
1428c2ecf20Sopenharmony_ci	unsigned int wpt, vff_sz;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	vff_sz = c->cfg.dst_port_window_size;
1458c2ecf20Sopenharmony_ci	if (!mtk_uart_apdma_read(c, VFF_LEN)) {
1468c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
1478c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
1488c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_THRE, VFF_TX_THRE(vff_sz));
1498c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_WPT, 0);
1508c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci		if (mtkd->support_33bits)
1538c2ecf20Sopenharmony_ci			mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
1578c2ecf20Sopenharmony_ci	if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
1588c2ecf20Sopenharmony_ci		dev_err(c->vc.chan.device->dev, "Enable TX fail\n");
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (!mtk_uart_apdma_read(c, VFF_LEFT_SIZE)) {
1618c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
1628c2ecf20Sopenharmony_ci		return;
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	wpt = mtk_uart_apdma_read(c, VFF_WPT);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	wpt += c->desc->avail_len;
1688c2ecf20Sopenharmony_ci	if ((wpt & VFF_RING_SIZE) == vff_sz)
1698c2ecf20Sopenharmony_ci		wpt = (wpt & VFF_RING_WRAP) ^ VFF_RING_WRAP;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* Let DMA start moving data */
1728c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_WPT, wpt);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	/* HW auto set to 0 when left size >= threshold */
1758c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_TX_INT_EN_B);
1768c2ecf20Sopenharmony_ci	if (!mtk_uart_apdma_read(c, VFF_FLUSH))
1778c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_start_rx(struct mtk_chan *c)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd =
1838c2ecf20Sopenharmony_ci				to_mtk_uart_apdma_dev(c->vc.chan.device);
1848c2ecf20Sopenharmony_ci	struct mtk_uart_apdma_desc *d = c->desc;
1858c2ecf20Sopenharmony_ci	unsigned int vff_sz;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	vff_sz = c->cfg.src_port_window_size;
1888c2ecf20Sopenharmony_ci	if (!mtk_uart_apdma_read(c, VFF_LEN)) {
1898c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_ADDR, d->addr);
1908c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_LEN, vff_sz);
1918c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_THRE, VFF_RX_THRE(vff_sz));
1928c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_RPT, 0);
1938c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci		if (mtkd->support_33bits)
1968c2ecf20Sopenharmony_ci			mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_EN_B);
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_RX_INT_EN_B);
2008c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_B);
2018c2ecf20Sopenharmony_ci	if (mtk_uart_apdma_read(c, VFF_EN) != VFF_EN_B)
2028c2ecf20Sopenharmony_ci		dev_err(c->vc.chan.device->dev, "Enable RX fail\n");
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_tx_handler(struct mtk_chan *c)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
2088c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
2098c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_rx_handler(struct mtk_chan *c)
2138c2ecf20Sopenharmony_ci{
2148c2ecf20Sopenharmony_ci	struct mtk_uart_apdma_desc *d = c->desc;
2158c2ecf20Sopenharmony_ci	unsigned int len, wg, rg;
2168c2ecf20Sopenharmony_ci	int cnt;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	if (!mtk_uart_apdma_read(c, VFF_VALID_SIZE))
2218c2ecf20Sopenharmony_ci		return;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
2248c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	len = c->cfg.src_port_window_size;
2278c2ecf20Sopenharmony_ci	rg = mtk_uart_apdma_read(c, VFF_RPT);
2288c2ecf20Sopenharmony_ci	wg = mtk_uart_apdma_read(c, VFF_WPT);
2298c2ecf20Sopenharmony_ci	cnt = (wg & VFF_RING_SIZE) - (rg & VFF_RING_SIZE);
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	/*
2328c2ecf20Sopenharmony_ci	 * The buffer is ring buffer. If wrap bit different,
2338c2ecf20Sopenharmony_ci	 * represents the start of the next cycle for WPT
2348c2ecf20Sopenharmony_ci	 */
2358c2ecf20Sopenharmony_ci	if ((rg ^ wg) & VFF_RING_WRAP)
2368c2ecf20Sopenharmony_ci		cnt += len;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	c->rx_status = d->avail_len - cnt;
2398c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_RPT, wg);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_chan_complete_handler(struct mtk_chan *c)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct mtk_uart_apdma_desc *d = c->desc;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if (d) {
2478c2ecf20Sopenharmony_ci		list_del(&d->vd.node);
2488c2ecf20Sopenharmony_ci		vchan_cookie_complete(&d->vd);
2498c2ecf20Sopenharmony_ci		c->desc = NULL;
2508c2ecf20Sopenharmony_ci	}
2518c2ecf20Sopenharmony_ci}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_cistatic irqreturn_t mtk_uart_apdma_irq_handler(int irq, void *dev_id)
2548c2ecf20Sopenharmony_ci{
2558c2ecf20Sopenharmony_ci	struct dma_chan *chan = (struct dma_chan *)dev_id;
2568c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
2578c2ecf20Sopenharmony_ci	unsigned long flags;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	spin_lock_irqsave(&c->vc.lock, flags);
2608c2ecf20Sopenharmony_ci	if (c->dir == DMA_DEV_TO_MEM)
2618c2ecf20Sopenharmony_ci		mtk_uart_apdma_rx_handler(c);
2628c2ecf20Sopenharmony_ci	else if (c->dir == DMA_MEM_TO_DEV)
2638c2ecf20Sopenharmony_ci		mtk_uart_apdma_tx_handler(c);
2648c2ecf20Sopenharmony_ci	mtk_uart_apdma_chan_complete_handler(c);
2658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&c->vc.lock, flags);
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
2688c2ecf20Sopenharmony_ci}
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_alloc_chan_resources(struct dma_chan *chan)
2718c2ecf20Sopenharmony_ci{
2728c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
2738c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
2748c2ecf20Sopenharmony_ci	unsigned int status;
2758c2ecf20Sopenharmony_ci	int ret;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	ret = pm_runtime_resume_and_get(mtkd->ddev.dev);
2788c2ecf20Sopenharmony_ci	if (ret < 0) {
2798c2ecf20Sopenharmony_ci		pm_runtime_put_noidle(chan->device->dev);
2808c2ecf20Sopenharmony_ci		return ret;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_ADDR, 0);
2848c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_THRE, 0);
2858c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_LEN, 0);
2868c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_RST, VFF_WARM_RST_B);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	ret = readx_poll_timeout(readl, c->base + VFF_EN,
2898c2ecf20Sopenharmony_ci			  status, !status, 10, 100);
2908c2ecf20Sopenharmony_ci	if (ret)
2918c2ecf20Sopenharmony_ci		goto err_pm;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	ret = request_irq(c->irq, mtk_uart_apdma_irq_handler,
2948c2ecf20Sopenharmony_ci			  IRQF_TRIGGER_NONE, KBUILD_MODNAME, chan);
2958c2ecf20Sopenharmony_ci	if (ret < 0) {
2968c2ecf20Sopenharmony_ci		dev_err(chan->device->dev, "Can't request dma IRQ\n");
2978c2ecf20Sopenharmony_ci		ret = -EINVAL;
2988c2ecf20Sopenharmony_ci		goto err_pm;
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (mtkd->support_33bits)
3028c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_4G_SUPPORT, VFF_4G_SUPPORT_CLR_B);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_cierr_pm:
3058c2ecf20Sopenharmony_ci	pm_runtime_put_noidle(mtkd->ddev.dev);
3068c2ecf20Sopenharmony_ci	return ret;
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_free_chan_resources(struct dma_chan *chan)
3108c2ecf20Sopenharmony_ci{
3118c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = to_mtk_uart_apdma_dev(chan->device);
3128c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	free_irq(c->irq, chan);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	tasklet_kill(&c->vc.task);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	vchan_free_chan_resources(&c->vc);
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	pm_runtime_put_sync(mtkd->ddev.dev);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic enum dma_status mtk_uart_apdma_tx_status(struct dma_chan *chan,
3248c2ecf20Sopenharmony_ci					 dma_cookie_t cookie,
3258c2ecf20Sopenharmony_ci					 struct dma_tx_state *txstate)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
3288c2ecf20Sopenharmony_ci	enum dma_status ret;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	ret = dma_cookie_status(chan, cookie, txstate);
3318c2ecf20Sopenharmony_ci	if (!txstate)
3328c2ecf20Sopenharmony_ci		return ret;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	dma_set_residue(txstate, c->rx_status);
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return ret;
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci/*
3408c2ecf20Sopenharmony_ci * dmaengine_prep_slave_single will call the function. and sglen is 1.
3418c2ecf20Sopenharmony_ci * 8250 uart using one ring buffer, and deal with one sg.
3428c2ecf20Sopenharmony_ci */
3438c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *mtk_uart_apdma_prep_slave_sg
3448c2ecf20Sopenharmony_ci	(struct dma_chan *chan, struct scatterlist *sgl,
3458c2ecf20Sopenharmony_ci	unsigned int sglen, enum dma_transfer_direction dir,
3468c2ecf20Sopenharmony_ci	unsigned long tx_flags, void *context)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
3498c2ecf20Sopenharmony_ci	struct mtk_uart_apdma_desc *d;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (!is_slave_direction(dir) || sglen != 1)
3528c2ecf20Sopenharmony_ci		return NULL;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	/* Now allocate and setup the descriptor */
3558c2ecf20Sopenharmony_ci	d = kzalloc(sizeof(*d), GFP_NOWAIT);
3568c2ecf20Sopenharmony_ci	if (!d)
3578c2ecf20Sopenharmony_ci		return NULL;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	d->avail_len = sg_dma_len(sgl);
3608c2ecf20Sopenharmony_ci	d->addr = sg_dma_address(sgl);
3618c2ecf20Sopenharmony_ci	c->dir = dir;
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return vchan_tx_prep(&c->vc, &d->vd, tx_flags);
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_issue_pending(struct dma_chan *chan)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
3698c2ecf20Sopenharmony_ci	struct virt_dma_desc *vd;
3708c2ecf20Sopenharmony_ci	unsigned long flags;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	spin_lock_irqsave(&c->vc.lock, flags);
3738c2ecf20Sopenharmony_ci	if (vchan_issue_pending(&c->vc) && !c->desc) {
3748c2ecf20Sopenharmony_ci		vd = vchan_next_desc(&c->vc);
3758c2ecf20Sopenharmony_ci		c->desc = to_mtk_uart_apdma_desc(&vd->tx);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		if (c->dir == DMA_DEV_TO_MEM)
3788c2ecf20Sopenharmony_ci			mtk_uart_apdma_start_rx(c);
3798c2ecf20Sopenharmony_ci		else if (c->dir == DMA_MEM_TO_DEV)
3808c2ecf20Sopenharmony_ci			mtk_uart_apdma_start_tx(c);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&c->vc.lock, flags);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_slave_config(struct dma_chan *chan,
3878c2ecf20Sopenharmony_ci				   struct dma_slave_config *config)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	memcpy(&c->cfg, config, sizeof(*config));
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_terminate_all(struct dma_chan *chan)
3978c2ecf20Sopenharmony_ci{
3988c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
3998c2ecf20Sopenharmony_ci	unsigned long flags;
4008c2ecf20Sopenharmony_ci	unsigned int status;
4018c2ecf20Sopenharmony_ci	LIST_HEAD(head);
4028c2ecf20Sopenharmony_ci	int ret;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_FLUSH, VFF_FLUSH_B);
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	ret = readx_poll_timeout(readl, c->base + VFF_FLUSH,
4078c2ecf20Sopenharmony_ci			  status, status != VFF_FLUSH_B, 10, 100);
4088c2ecf20Sopenharmony_ci	if (ret)
4098c2ecf20Sopenharmony_ci		dev_err(c->vc.chan.device->dev, "flush: fail, status=0x%x\n",
4108c2ecf20Sopenharmony_ci			mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/*
4138c2ecf20Sopenharmony_ci	 * Stop need 3 steps.
4148c2ecf20Sopenharmony_ci	 * 1. set stop to 1
4158c2ecf20Sopenharmony_ci	 * 2. wait en to 0
4168c2ecf20Sopenharmony_ci	 * 3. set stop as 0
4178c2ecf20Sopenharmony_ci	 */
4188c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_B);
4198c2ecf20Sopenharmony_ci	ret = readx_poll_timeout(readl, c->base + VFF_EN,
4208c2ecf20Sopenharmony_ci			  status, !status, 10, 100);
4218c2ecf20Sopenharmony_ci	if (ret)
4228c2ecf20Sopenharmony_ci		dev_err(c->vc.chan.device->dev, "stop: fail, status=0x%x\n",
4238c2ecf20Sopenharmony_ci			mtk_uart_apdma_read(c, VFF_DEBUG_STATUS));
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_STOP, VFF_STOP_CLR_B);
4268c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	if (c->dir == DMA_DEV_TO_MEM)
4298c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_RX_INT_CLR_B);
4308c2ecf20Sopenharmony_ci	else if (c->dir == DMA_MEM_TO_DEV)
4318c2ecf20Sopenharmony_ci		mtk_uart_apdma_write(c, VFF_INT_FLAG, VFF_TX_INT_CLR_B);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	synchronize_irq(c->irq);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&c->vc.lock, flags);
4368c2ecf20Sopenharmony_ci	vchan_get_all_descriptors(&c->vc, &head);
4378c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&c->vc.lock, flags);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	vchan_dma_desc_free_list(&c->vc, &head);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	return 0;
4428c2ecf20Sopenharmony_ci}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_device_pause(struct dma_chan *chan)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	struct mtk_chan *c = to_mtk_uart_apdma_chan(chan);
4478c2ecf20Sopenharmony_ci	unsigned long flags;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	spin_lock_irqsave(&c->vc.lock, flags);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_EN, VFF_EN_CLR_B);
4528c2ecf20Sopenharmony_ci	mtk_uart_apdma_write(c, VFF_INT_EN, VFF_INT_EN_CLR_B);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&c->vc.lock, flags);
4558c2ecf20Sopenharmony_ci	synchronize_irq(c->irq);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return 0;
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic void mtk_uart_apdma_free(struct mtk_uart_apdmadev *mtkd)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	while (!list_empty(&mtkd->ddev.channels)) {
4638c2ecf20Sopenharmony_ci		struct mtk_chan *c = list_first_entry(&mtkd->ddev.channels,
4648c2ecf20Sopenharmony_ci			struct mtk_chan, vc.chan.device_node);
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		list_del(&c->vc.chan.device_node);
4678c2ecf20Sopenharmony_ci		tasklet_kill(&c->vc.task);
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic const struct of_device_id mtk_uart_apdma_match[] = {
4728c2ecf20Sopenharmony_ci	{ .compatible = "mediatek,mt6577-uart-dma", },
4738c2ecf20Sopenharmony_ci	{ /* sentinel */ },
4748c2ecf20Sopenharmony_ci};
4758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mtk_uart_apdma_match);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_probe(struct platform_device *pdev)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
4808c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd;
4818c2ecf20Sopenharmony_ci	int bit_mask = 32, rc;
4828c2ecf20Sopenharmony_ci	struct mtk_chan *c;
4838c2ecf20Sopenharmony_ci	unsigned int i;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	mtkd = devm_kzalloc(&pdev->dev, sizeof(*mtkd), GFP_KERNEL);
4868c2ecf20Sopenharmony_ci	if (!mtkd)
4878c2ecf20Sopenharmony_ci		return -ENOMEM;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	mtkd->clk = devm_clk_get(&pdev->dev, NULL);
4908c2ecf20Sopenharmony_ci	if (IS_ERR(mtkd->clk)) {
4918c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "No clock specified\n");
4928c2ecf20Sopenharmony_ci		rc = PTR_ERR(mtkd->clk);
4938c2ecf20Sopenharmony_ci		return rc;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (of_property_read_bool(np, "mediatek,dma-33bits"))
4978c2ecf20Sopenharmony_ci		mtkd->support_33bits = true;
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	if (mtkd->support_33bits)
5008c2ecf20Sopenharmony_ci		bit_mask = 33;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(bit_mask));
5038c2ecf20Sopenharmony_ci	if (rc)
5048c2ecf20Sopenharmony_ci		return rc;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	dma_cap_set(DMA_SLAVE, mtkd->ddev.cap_mask);
5078c2ecf20Sopenharmony_ci	mtkd->ddev.device_alloc_chan_resources =
5088c2ecf20Sopenharmony_ci				mtk_uart_apdma_alloc_chan_resources;
5098c2ecf20Sopenharmony_ci	mtkd->ddev.device_free_chan_resources =
5108c2ecf20Sopenharmony_ci				mtk_uart_apdma_free_chan_resources;
5118c2ecf20Sopenharmony_ci	mtkd->ddev.device_tx_status = mtk_uart_apdma_tx_status;
5128c2ecf20Sopenharmony_ci	mtkd->ddev.device_issue_pending = mtk_uart_apdma_issue_pending;
5138c2ecf20Sopenharmony_ci	mtkd->ddev.device_prep_slave_sg = mtk_uart_apdma_prep_slave_sg;
5148c2ecf20Sopenharmony_ci	mtkd->ddev.device_config = mtk_uart_apdma_slave_config;
5158c2ecf20Sopenharmony_ci	mtkd->ddev.device_pause = mtk_uart_apdma_device_pause;
5168c2ecf20Sopenharmony_ci	mtkd->ddev.device_terminate_all = mtk_uart_apdma_terminate_all;
5178c2ecf20Sopenharmony_ci	mtkd->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
5188c2ecf20Sopenharmony_ci	mtkd->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE);
5198c2ecf20Sopenharmony_ci	mtkd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
5208c2ecf20Sopenharmony_ci	mtkd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
5218c2ecf20Sopenharmony_ci	mtkd->ddev.dev = &pdev->dev;
5228c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&mtkd->ddev.channels);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	mtkd->dma_requests = MTK_UART_APDMA_NR_VCHANS;
5258c2ecf20Sopenharmony_ci	if (of_property_read_u32(np, "dma-requests", &mtkd->dma_requests)) {
5268c2ecf20Sopenharmony_ci		dev_info(&pdev->dev,
5278c2ecf20Sopenharmony_ci			 "Using %u as missing dma-requests property\n",
5288c2ecf20Sopenharmony_ci			 MTK_UART_APDMA_NR_VCHANS);
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	for (i = 0; i < mtkd->dma_requests; i++) {
5328c2ecf20Sopenharmony_ci		c = devm_kzalloc(mtkd->ddev.dev, sizeof(*c), GFP_KERNEL);
5338c2ecf20Sopenharmony_ci		if (!c) {
5348c2ecf20Sopenharmony_ci			rc = -ENODEV;
5358c2ecf20Sopenharmony_ci			goto err_no_dma;
5368c2ecf20Sopenharmony_ci		}
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci		c->base = devm_platform_ioremap_resource(pdev, i);
5398c2ecf20Sopenharmony_ci		if (IS_ERR(c->base)) {
5408c2ecf20Sopenharmony_ci			rc = PTR_ERR(c->base);
5418c2ecf20Sopenharmony_ci			goto err_no_dma;
5428c2ecf20Sopenharmony_ci		}
5438c2ecf20Sopenharmony_ci		c->vc.desc_free = mtk_uart_apdma_desc_free;
5448c2ecf20Sopenharmony_ci		vchan_init(&c->vc, &mtkd->ddev);
5458c2ecf20Sopenharmony_ci
5468c2ecf20Sopenharmony_ci		rc = platform_get_irq(pdev, i);
5478c2ecf20Sopenharmony_ci		if (rc < 0)
5488c2ecf20Sopenharmony_ci			goto err_no_dma;
5498c2ecf20Sopenharmony_ci		c->irq = rc;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	pm_runtime_enable(&pdev->dev);
5538c2ecf20Sopenharmony_ci	pm_runtime_set_active(&pdev->dev);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	rc = dma_async_device_register(&mtkd->ddev);
5568c2ecf20Sopenharmony_ci	if (rc)
5578c2ecf20Sopenharmony_ci		goto rpm_disable;
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, mtkd);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	/* Device-tree DMA controller registration */
5628c2ecf20Sopenharmony_ci	rc = of_dma_controller_register(np, of_dma_xlate_by_chan_id, mtkd);
5638c2ecf20Sopenharmony_ci	if (rc)
5648c2ecf20Sopenharmony_ci		goto dma_remove;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	return rc;
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_cidma_remove:
5698c2ecf20Sopenharmony_ci	dma_async_device_unregister(&mtkd->ddev);
5708c2ecf20Sopenharmony_cirpm_disable:
5718c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
5728c2ecf20Sopenharmony_cierr_no_dma:
5738c2ecf20Sopenharmony_ci	mtk_uart_apdma_free(mtkd);
5748c2ecf20Sopenharmony_ci	return rc;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_remove(struct platform_device *pdev)
5788c2ecf20Sopenharmony_ci{
5798c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = platform_get_drvdata(pdev);
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	of_dma_controller_free(pdev->dev.of_node);
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	mtk_uart_apdma_free(mtkd);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	dma_async_device_unregister(&mtkd->ddev);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	pm_runtime_disable(&pdev->dev);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return 0;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
5938c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_suspend(struct device *dev)
5948c2ecf20Sopenharmony_ci{
5958c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (!pm_runtime_suspended(dev))
5988c2ecf20Sopenharmony_ci		clk_disable_unprepare(mtkd->clk);
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	return 0;
6018c2ecf20Sopenharmony_ci}
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_resume(struct device *dev)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	int ret;
6068c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	if (!pm_runtime_suspended(dev)) {
6098c2ecf20Sopenharmony_ci		ret = clk_prepare_enable(mtkd->clk);
6108c2ecf20Sopenharmony_ci		if (ret)
6118c2ecf20Sopenharmony_ci			return ret;
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_ci	return 0;
6158c2ecf20Sopenharmony_ci}
6168c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */
6178c2ecf20Sopenharmony_ci
6188c2ecf20Sopenharmony_ci#ifdef CONFIG_PM
6198c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_runtime_suspend(struct device *dev)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	clk_disable_unprepare(mtkd->clk);
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return 0;
6268c2ecf20Sopenharmony_ci}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_cistatic int mtk_uart_apdma_runtime_resume(struct device *dev)
6298c2ecf20Sopenharmony_ci{
6308c2ecf20Sopenharmony_ci	struct mtk_uart_apdmadev *mtkd = dev_get_drvdata(dev);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	return clk_prepare_enable(mtkd->clk);
6338c2ecf20Sopenharmony_ci}
6348c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cistatic const struct dev_pm_ops mtk_uart_apdma_pm_ops = {
6378c2ecf20Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(mtk_uart_apdma_suspend, mtk_uart_apdma_resume)
6388c2ecf20Sopenharmony_ci	SET_RUNTIME_PM_OPS(mtk_uart_apdma_runtime_suspend,
6398c2ecf20Sopenharmony_ci			   mtk_uart_apdma_runtime_resume, NULL)
6408c2ecf20Sopenharmony_ci};
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_cistatic struct platform_driver mtk_uart_apdma_driver = {
6438c2ecf20Sopenharmony_ci	.probe	= mtk_uart_apdma_probe,
6448c2ecf20Sopenharmony_ci	.remove	= mtk_uart_apdma_remove,
6458c2ecf20Sopenharmony_ci	.driver = {
6468c2ecf20Sopenharmony_ci		.name		= KBUILD_MODNAME,
6478c2ecf20Sopenharmony_ci		.pm		= &mtk_uart_apdma_pm_ops,
6488c2ecf20Sopenharmony_ci		.of_match_table = of_match_ptr(mtk_uart_apdma_match),
6498c2ecf20Sopenharmony_ci	},
6508c2ecf20Sopenharmony_ci};
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_cimodule_platform_driver(mtk_uart_apdma_driver);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MediaTek UART APDMA Controller Driver");
6558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Long Cheng <long.cheng@mediatek.com>");
6568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
657