xref: /linux/drivers/spi/spi-pxa2xx-platform.c (revision cb787f4ac0c2e439ea8d7e6387b925f74576bdf8)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <linux/acpi.h>
4 #include <linux/clk.h>
5 #include <linux/device.h>
6 #include <linux/err.h>
7 #include <linux/init.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/platform_device.h>
10 #include <linux/pm_runtime.h>
11 #include <linux/property.h>
12 #include <linux/types.h>
13 
14 #include "spi-pxa2xx.h"
15 
16 static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param)
17 {
18 	return param == chan->device->dev;
19 }
20 
21 static int
22 pxa2xx_spi_init_ssp(struct platform_device *pdev, struct ssp_device *ssp, enum pxa_ssp_type type)
23 {
24 	struct device *dev = &pdev->dev;
25 	struct resource *res;
26 	int status;
27 	u64 uid;
28 
29 	ssp->mmio_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
30 	if (IS_ERR(ssp->mmio_base))
31 		return PTR_ERR(ssp->mmio_base);
32 
33 	ssp->phys_base = res->start;
34 
35 	ssp->clk = devm_clk_get(dev, NULL);
36 	if (IS_ERR(ssp->clk))
37 		return PTR_ERR(ssp->clk);
38 
39 	ssp->irq = platform_get_irq(pdev, 0);
40 	if (ssp->irq < 0)
41 		return ssp->irq;
42 
43 	ssp->type = type;
44 	ssp->dev = dev;
45 
46 	status = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid);
47 	if (status)
48 		ssp->port_id = -1;
49 	else
50 		ssp->port_id = uid;
51 
52 	return 0;
53 }
54 
55 static void pxa2xx_spi_ssp_release(void *ssp)
56 {
57 	pxa_ssp_free(ssp);
58 }
59 
60 static struct ssp_device *pxa2xx_spi_ssp_request(struct platform_device *pdev)
61 {
62 	struct ssp_device *ssp;
63 	int status;
64 
65 	ssp = pxa_ssp_request(pdev->id, pdev->name);
66 	if (!ssp)
67 		return NULL;
68 
69 	status = devm_add_action_or_reset(&pdev->dev, pxa2xx_spi_ssp_release, ssp);
70 	if (status)
71 		return ERR_PTR(status);
72 
73 	return ssp;
74 }
75 
76 static struct pxa2xx_spi_controller *
77 pxa2xx_spi_init_pdata(struct platform_device *pdev)
78 {
79 	struct pxa2xx_spi_controller *pdata;
80 	struct device *dev = &pdev->dev;
81 	struct device *parent = dev->parent;
82 	const void *match = device_get_match_data(dev);
83 	enum pxa_ssp_type type = SSP_UNDEFINED;
84 	struct ssp_device *ssp;
85 	bool is_lpss_priv;
86 	u32 num_cs = 1;
87 	int status;
88 
89 	ssp = pxa2xx_spi_ssp_request(pdev);
90 	if (IS_ERR(ssp))
91 		return ERR_CAST(ssp);
92 	if (ssp) {
93 		type = ssp->type;
94 	} else if (match) {
95 		type = (enum pxa_ssp_type)(uintptr_t)match;
96 	} else {
97 		u32 value;
98 
99 		status = device_property_read_u32(dev, "intel,spi-pxa2xx-type", &value);
100 		if (status)
101 			return ERR_PTR(status);
102 
103 		type = (enum pxa_ssp_type)value;
104 	}
105 
106 	/* Validate the SSP type correctness */
107 	if (!(type > SSP_UNDEFINED && type < SSP_MAX))
108 		return ERR_PTR(-EINVAL);
109 
110 	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
111 	if (!pdata)
112 		return ERR_PTR(-ENOMEM);
113 
114 	/* Platforms with iDMA 64-bit */
115 	is_lpss_priv = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpss_priv");
116 	if (is_lpss_priv) {
117 		pdata->tx_param = parent;
118 		pdata->rx_param = parent;
119 		pdata->dma_filter = pxa2xx_spi_idma_filter;
120 	}
121 
122 	/* Read number of chip select pins, if provided */
123 	device_property_read_u32(dev, "num-cs", &num_cs);
124 
125 	pdata->num_chipselect = num_cs;
126 	pdata->is_target = device_property_read_bool(dev, "spi-slave");
127 	pdata->enable_dma = true;
128 	pdata->dma_burst_size = 1;
129 
130 	/* If SSP has been already enumerated, use it */
131 	if (ssp)
132 		return pdata;
133 
134 	status = pxa2xx_spi_init_ssp(pdev, &pdata->ssp, type);
135 	if (status)
136 		return ERR_PTR(status);
137 
138 	return pdata;
139 }
140 
141 static int pxa2xx_spi_platform_probe(struct platform_device *pdev)
142 {
143 	struct pxa2xx_spi_controller *platform_info;
144 	struct device *dev = &pdev->dev;
145 	struct ssp_device *ssp;
146 	int ret;
147 
148 	platform_info = dev_get_platdata(dev);
149 	if (!platform_info) {
150 		platform_info = pxa2xx_spi_init_pdata(pdev);
151 		if (IS_ERR(platform_info))
152 			return dev_err_probe(dev, PTR_ERR(platform_info), "missing platform data\n");
153 	}
154 
155 	ssp = pxa2xx_spi_ssp_request(pdev);
156 	if (IS_ERR(ssp))
157 		return PTR_ERR(ssp);
158 	if (!ssp)
159 		ssp = &platform_info->ssp;
160 
161 	pm_runtime_set_autosuspend_delay(dev, 50);
162 	pm_runtime_use_autosuspend(dev);
163 	pm_runtime_set_active(dev);
164 	pm_runtime_enable(dev);
165 
166 	ret = pxa2xx_spi_probe(dev, ssp, platform_info);
167 	if (ret)
168 		pm_runtime_disable(dev);
169 
170 	return ret;
171 }
172 
173 static void pxa2xx_spi_platform_remove(struct platform_device *pdev)
174 {
175 	struct device *dev = &pdev->dev;
176 
177 	pm_runtime_get_sync(dev);
178 
179 	pxa2xx_spi_remove(dev);
180 
181 	pm_runtime_put_noidle(dev);
182 	pm_runtime_disable(dev);
183 }
184 
185 static const struct acpi_device_id pxa2xx_spi_acpi_match[] = {
186 	{ "80860F0E" },
187 	{ "8086228E" },
188 	{ "INT33C0" },
189 	{ "INT33C1" },
190 	{ "INT3430" },
191 	{ "INT3431" },
192 	{}
193 };
194 MODULE_DEVICE_TABLE(acpi, pxa2xx_spi_acpi_match);
195 
196 static const struct of_device_id pxa2xx_spi_of_match[] = {
197 	{ .compatible = "marvell,mmp2-ssp", .data = (void *)MMP2_SSP },
198 	{}
199 };
200 MODULE_DEVICE_TABLE(of, pxa2xx_spi_of_match);
201 
202 static struct platform_driver driver = {
203 	.driver = {
204 		.name	= "pxa2xx-spi",
205 		.pm	= pm_ptr(&pxa2xx_spi_pm_ops),
206 		.acpi_match_table = pxa2xx_spi_acpi_match,
207 		.of_match_table = pxa2xx_spi_of_match,
208 	},
209 	.probe = pxa2xx_spi_platform_probe,
210 	.remove_new = pxa2xx_spi_platform_remove,
211 };
212 
213 static int __init pxa2xx_spi_init(void)
214 {
215 	return platform_driver_register(&driver);
216 }
217 subsys_initcall(pxa2xx_spi_init);
218 
219 static void __exit pxa2xx_spi_exit(void)
220 {
221 	platform_driver_unregister(&driver);
222 }
223 module_exit(pxa2xx_spi_exit);
224 
225 MODULE_AUTHOR("Stephen Street");
226 MODULE_DESCRIPTION("PXA2xx SSP SPI Controller platform driver");
227 MODULE_LICENSE("GPL");
228 MODULE_IMPORT_NS(SPI_PXA2xx);
229 MODULE_ALIAS("platform:pxa2xx-spi");
230 MODULE_SOFTDEP("pre: dw_dmac");
231