xref: /OK3568_Linux_fs/kernel/drivers/dma/dw/platform.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Platform driver for the Synopsys DesignWare DMA Controller
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2007-2008 Atmel Corporation
6*4882a593Smuzhiyun  * Copyright (C) 2010-2011 ST Microelectronics
7*4882a593Smuzhiyun  * Copyright (C) 2013 Intel Corporation
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Some parts of this driver are derived from the original dw_dmac.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/device.h>
14*4882a593Smuzhiyun #include <linux/clk.h>
15*4882a593Smuzhiyun #include <linux/pm_runtime.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/dmaengine.h>
18*4882a593Smuzhiyun #include <linux/dma-mapping.h>
19*4882a593Smuzhiyun #include <linux/of.h>
20*4882a593Smuzhiyun #include <linux/acpi.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #include "internal.h"
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define DRV_NAME	"dw_dmac"
25*4882a593Smuzhiyun 
dw_probe(struct platform_device * pdev)26*4882a593Smuzhiyun static int dw_probe(struct platform_device *pdev)
27*4882a593Smuzhiyun {
28*4882a593Smuzhiyun 	const struct dw_dma_chip_pdata *match;
29*4882a593Smuzhiyun 	struct dw_dma_chip_pdata *data;
30*4882a593Smuzhiyun 	struct dw_dma_chip *chip;
31*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
32*4882a593Smuzhiyun 	int err;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	match = device_get_match_data(dev);
35*4882a593Smuzhiyun 	if (!match)
36*4882a593Smuzhiyun 		return -ENODEV;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	data = devm_kmemdup(&pdev->dev, match, sizeof(*match), GFP_KERNEL);
39*4882a593Smuzhiyun 	if (!data)
40*4882a593Smuzhiyun 		return -ENOMEM;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
43*4882a593Smuzhiyun 	if (!chip)
44*4882a593Smuzhiyun 		return -ENOMEM;
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	chip->irq = platform_get_irq(pdev, 0);
47*4882a593Smuzhiyun 	if (chip->irq < 0)
48*4882a593Smuzhiyun 		return chip->irq;
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun 	chip->regs = devm_platform_ioremap_resource(pdev, 0);
51*4882a593Smuzhiyun 	if (IS_ERR(chip->regs))
52*4882a593Smuzhiyun 		return PTR_ERR(chip->regs);
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 	err = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
55*4882a593Smuzhiyun 	if (err)
56*4882a593Smuzhiyun 		return err;
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	if (!data->pdata)
59*4882a593Smuzhiyun 		data->pdata = dev_get_platdata(dev);
60*4882a593Smuzhiyun 	if (!data->pdata)
61*4882a593Smuzhiyun 		data->pdata = dw_dma_parse_dt(pdev);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	chip->dev = dev;
64*4882a593Smuzhiyun 	chip->id = pdev->id;
65*4882a593Smuzhiyun 	chip->pdata = data->pdata;
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	data->chip = chip;
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 	chip->clk = devm_clk_get_optional(chip->dev, "hclk");
70*4882a593Smuzhiyun 	if (IS_ERR(chip->clk))
71*4882a593Smuzhiyun 		return PTR_ERR(chip->clk);
72*4882a593Smuzhiyun 	err = clk_prepare_enable(chip->clk);
73*4882a593Smuzhiyun 	if (err)
74*4882a593Smuzhiyun 		return err;
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun 	pm_runtime_enable(&pdev->dev);
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	err = data->probe(chip);
79*4882a593Smuzhiyun 	if (err)
80*4882a593Smuzhiyun 		goto err_dw_dma_probe;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	platform_set_drvdata(pdev, data);
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	dw_dma_of_controller_register(chip->dw);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	dw_dma_acpi_controller_register(chip->dw);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	return 0;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun err_dw_dma_probe:
91*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
92*4882a593Smuzhiyun 	clk_disable_unprepare(chip->clk);
93*4882a593Smuzhiyun 	return err;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
dw_remove(struct platform_device * pdev)96*4882a593Smuzhiyun static int dw_remove(struct platform_device *pdev)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev);
99*4882a593Smuzhiyun 	struct dw_dma_chip *chip = data->chip;
100*4882a593Smuzhiyun 	int ret;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	dw_dma_acpi_controller_free(chip->dw);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	dw_dma_of_controller_free(chip->dw);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	ret = data->remove(chip);
107*4882a593Smuzhiyun 	if (ret)
108*4882a593Smuzhiyun 		dev_warn(chip->dev, "can't remove device properly: %d\n", ret);
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	pm_runtime_disable(&pdev->dev);
111*4882a593Smuzhiyun 	clk_disable_unprepare(chip->clk);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	return 0;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
dw_shutdown(struct platform_device * pdev)116*4882a593Smuzhiyun static void dw_shutdown(struct platform_device *pdev)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	struct dw_dma_chip_pdata *data = platform_get_drvdata(pdev);
119*4882a593Smuzhiyun 	struct dw_dma_chip *chip = data->chip;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	/*
122*4882a593Smuzhiyun 	 * We have to call do_dw_dma_disable() to stop any ongoing transfer. On
123*4882a593Smuzhiyun 	 * some platforms we can't do that since DMA device is powered off.
124*4882a593Smuzhiyun 	 * Moreover we have no possibility to check if the platform is affected
125*4882a593Smuzhiyun 	 * or not. That's why we call pm_runtime_get_sync() / pm_runtime_put()
126*4882a593Smuzhiyun 	 * unconditionally. On the other hand we can't use
127*4882a593Smuzhiyun 	 * pm_runtime_suspended() because runtime PM framework is not fully
128*4882a593Smuzhiyun 	 * used by the driver.
129*4882a593Smuzhiyun 	 */
130*4882a593Smuzhiyun 	pm_runtime_get_sync(chip->dev);
131*4882a593Smuzhiyun 	do_dw_dma_disable(chip);
132*4882a593Smuzhiyun 	pm_runtime_put_sync_suspend(chip->dev);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	clk_disable_unprepare(chip->clk);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun #ifdef CONFIG_OF
138*4882a593Smuzhiyun static const struct of_device_id dw_dma_of_id_table[] = {
139*4882a593Smuzhiyun 	{ .compatible = "snps,dma-spear1340", .data = &dw_dma_chip_pdata },
140*4882a593Smuzhiyun 	{}
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, dw_dma_of_id_table);
143*4882a593Smuzhiyun #endif
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun #ifdef CONFIG_ACPI
146*4882a593Smuzhiyun static const struct acpi_device_id dw_dma_acpi_id_table[] = {
147*4882a593Smuzhiyun 	{ "INTL9C60", (kernel_ulong_t)&dw_dma_chip_pdata },
148*4882a593Smuzhiyun 	{ "80862286", (kernel_ulong_t)&dw_dma_chip_pdata },
149*4882a593Smuzhiyun 	{ "808622C0", (kernel_ulong_t)&dw_dma_chip_pdata },
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* Elkhart Lake iDMA 32-bit (PSE DMA) */
152*4882a593Smuzhiyun 	{ "80864BB4", (kernel_ulong_t)&idma32_chip_pdata },
153*4882a593Smuzhiyun 	{ "80864BB5", (kernel_ulong_t)&idma32_chip_pdata },
154*4882a593Smuzhiyun 	{ "80864BB6", (kernel_ulong_t)&idma32_chip_pdata },
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	{ }
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, dw_dma_acpi_id_table);
159*4882a593Smuzhiyun #endif
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
162*4882a593Smuzhiyun 
dw_suspend_late(struct device * dev)163*4882a593Smuzhiyun static int dw_suspend_late(struct device *dev)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	struct dw_dma_chip_pdata *data = dev_get_drvdata(dev);
166*4882a593Smuzhiyun 	struct dw_dma_chip *chip = data->chip;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	do_dw_dma_disable(chip);
169*4882a593Smuzhiyun 	clk_disable_unprepare(chip->clk);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	return 0;
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
dw_resume_early(struct device * dev)174*4882a593Smuzhiyun static int dw_resume_early(struct device *dev)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	struct dw_dma_chip_pdata *data = dev_get_drvdata(dev);
177*4882a593Smuzhiyun 	struct dw_dma_chip *chip = data->chip;
178*4882a593Smuzhiyun 	int ret;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	ret = clk_prepare_enable(chip->clk);
181*4882a593Smuzhiyun 	if (ret)
182*4882a593Smuzhiyun 		return ret;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	return do_dw_dma_enable(chip);
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun #endif /* CONFIG_PM_SLEEP */
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun static const struct dev_pm_ops dw_dev_pm_ops = {
190*4882a593Smuzhiyun 	SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_suspend_late, dw_resume_early)
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun static struct platform_driver dw_driver = {
194*4882a593Smuzhiyun 	.probe		= dw_probe,
195*4882a593Smuzhiyun 	.remove		= dw_remove,
196*4882a593Smuzhiyun 	.shutdown       = dw_shutdown,
197*4882a593Smuzhiyun 	.driver = {
198*4882a593Smuzhiyun 		.name	= DRV_NAME,
199*4882a593Smuzhiyun 		.pm	= &dw_dev_pm_ops,
200*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(dw_dma_of_id_table),
201*4882a593Smuzhiyun 		.acpi_match_table = ACPI_PTR(dw_dma_acpi_id_table),
202*4882a593Smuzhiyun 	},
203*4882a593Smuzhiyun };
204*4882a593Smuzhiyun 
dw_init(void)205*4882a593Smuzhiyun static int __init dw_init(void)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	return platform_driver_register(&dw_driver);
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun subsys_initcall(dw_init);
210*4882a593Smuzhiyun 
dw_exit(void)211*4882a593Smuzhiyun static void __exit dw_exit(void)
212*4882a593Smuzhiyun {
213*4882a593Smuzhiyun 	platform_driver_unregister(&dw_driver);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun module_exit(dw_exit);
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
218*4882a593Smuzhiyun MODULE_DESCRIPTION("Synopsys DesignWare DMA Controller platform driver");
219*4882a593Smuzhiyun MODULE_ALIAS("platform:" DRV_NAME);
220