xref: /linux/drivers/pinctrl/mvebu/pinctrl-orion.c (revision fd67f884782a281eb033e40b0f8eae623416035e)
1*fd67f884SThomas Petazzoni /*
2*fd67f884SThomas Petazzoni  * Marvell Orion pinctrl driver based on mvebu pinctrl core
3*fd67f884SThomas Petazzoni  *
4*fd67f884SThomas Petazzoni  * Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
5*fd67f884SThomas Petazzoni  *
6*fd67f884SThomas Petazzoni  * This program is free software; you can redistribute it and/or modify
7*fd67f884SThomas Petazzoni  * it under the terms of the GNU General Public License as published by
8*fd67f884SThomas Petazzoni  * the Free Software Foundation; either version 2 of the License, or
9*fd67f884SThomas Petazzoni  * (at your option) any later version.
10*fd67f884SThomas Petazzoni  *
11*fd67f884SThomas Petazzoni  * The first 16 MPP pins on Orion are easy to handle: they are
12*fd67f884SThomas Petazzoni  * configured through 2 consecutive registers, located at the base
13*fd67f884SThomas Petazzoni  * address of the MPP device.
14*fd67f884SThomas Petazzoni  *
15*fd67f884SThomas Petazzoni  * However the last 4 MPP pins are handled by a register at offset
16*fd67f884SThomas Petazzoni  * 0x50 from the base address, so it is not consecutive with the first
17*fd67f884SThomas Petazzoni  * two registers.
18*fd67f884SThomas Petazzoni  */
19*fd67f884SThomas Petazzoni 
20*fd67f884SThomas Petazzoni #include <linux/err.h>
21*fd67f884SThomas Petazzoni #include <linux/init.h>
22*fd67f884SThomas Petazzoni #include <linux/io.h>
23*fd67f884SThomas Petazzoni #include <linux/module.h>
24*fd67f884SThomas Petazzoni #include <linux/platform_device.h>
25*fd67f884SThomas Petazzoni #include <linux/clk.h>
26*fd67f884SThomas Petazzoni #include <linux/of.h>
27*fd67f884SThomas Petazzoni #include <linux/of_device.h>
28*fd67f884SThomas Petazzoni #include <linux/pinctrl/pinctrl.h>
29*fd67f884SThomas Petazzoni 
30*fd67f884SThomas Petazzoni #include "pinctrl-mvebu.h"
31*fd67f884SThomas Petazzoni 
32*fd67f884SThomas Petazzoni static void __iomem *mpp_base;
33*fd67f884SThomas Petazzoni static void __iomem *high_mpp_base;
34*fd67f884SThomas Petazzoni 
35*fd67f884SThomas Petazzoni static int orion_mpp_ctrl_get(unsigned pid, unsigned long *config)
36*fd67f884SThomas Petazzoni {
37*fd67f884SThomas Petazzoni 	unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
38*fd67f884SThomas Petazzoni 
39*fd67f884SThomas Petazzoni 	if (pid < 16) {
40*fd67f884SThomas Petazzoni 		unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
41*fd67f884SThomas Petazzoni 		*config = (readl(mpp_base + off) >> shift) & MVEBU_MPP_MASK;
42*fd67f884SThomas Petazzoni 	}
43*fd67f884SThomas Petazzoni 	else {
44*fd67f884SThomas Petazzoni 		*config = (readl(high_mpp_base) >> shift) & MVEBU_MPP_MASK;
45*fd67f884SThomas Petazzoni 	}
46*fd67f884SThomas Petazzoni 
47*fd67f884SThomas Petazzoni 	return 0;
48*fd67f884SThomas Petazzoni }
49*fd67f884SThomas Petazzoni 
50*fd67f884SThomas Petazzoni static int orion_mpp_ctrl_set(unsigned pid, unsigned long config)
51*fd67f884SThomas Petazzoni {
52*fd67f884SThomas Petazzoni 	unsigned shift = (pid % MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
53*fd67f884SThomas Petazzoni 
54*fd67f884SThomas Petazzoni 	if (pid < 16) {
55*fd67f884SThomas Petazzoni 		unsigned off = (pid / MVEBU_MPPS_PER_REG) * MVEBU_MPP_BITS;
56*fd67f884SThomas Petazzoni 		u32 reg = readl(mpp_base + off) & ~(MVEBU_MPP_MASK << shift);
57*fd67f884SThomas Petazzoni 		writel(reg | (config << shift), mpp_base + off);
58*fd67f884SThomas Petazzoni 	}
59*fd67f884SThomas Petazzoni 	else {
60*fd67f884SThomas Petazzoni 		u32 reg = readl(high_mpp_base) & ~(MVEBU_MPP_MASK << shift);
61*fd67f884SThomas Petazzoni 		writel(reg | (config << shift), high_mpp_base);
62*fd67f884SThomas Petazzoni 	}
63*fd67f884SThomas Petazzoni 
64*fd67f884SThomas Petazzoni 	return 0;
65*fd67f884SThomas Petazzoni }
66*fd67f884SThomas Petazzoni 
67*fd67f884SThomas Petazzoni #define V(f5181l, f5182, f5281) \
68*fd67f884SThomas Petazzoni 	((f5181l << 0) | (f5182 << 1) | (f5281 << 2))
69*fd67f884SThomas Petazzoni 
70*fd67f884SThomas Petazzoni enum orion_variant {
71*fd67f884SThomas Petazzoni 	V_5181L = V(1, 0, 0),
72*fd67f884SThomas Petazzoni 	V_5182  = V(0, 1, 0),
73*fd67f884SThomas Petazzoni 	V_5281  = V(0, 0, 1),
74*fd67f884SThomas Petazzoni 	V_ALL   = V(1, 1, 1),
75*fd67f884SThomas Petazzoni };
76*fd67f884SThomas Petazzoni 
77*fd67f884SThomas Petazzoni static struct mvebu_mpp_mode orion_mpp_modes[] = {
78*fd67f884SThomas Petazzoni 	MPP_MODE(0,
79*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "pcie", "rstout",    V_ALL),
80*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "req2",       V_ALL),
81*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x3, "gpio", NULL,        V_ALL)),
82*fd67f884SThomas Petazzoni 	MPP_MODE(1,
83*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
84*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "gnt2",       V_ALL)),
85*fd67f884SThomas Petazzoni 	MPP_MODE(2,
86*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
87*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "req3",       V_ALL),
88*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x3, "pci-1", "pme",      V_ALL)),
89*fd67f884SThomas Petazzoni 	MPP_MODE(3,
90*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
91*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "gnt3",       V_ALL)),
92*fd67f884SThomas Petazzoni 	MPP_MODE(4,
93*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
94*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "req4",       V_ALL),
95*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "bootnand", "re",    V_5182 | V_5281),
96*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata0", "prsnt",    V_5182)),
97*fd67f884SThomas Petazzoni 	MPP_MODE(5,
98*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
99*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "gnt4",       V_ALL),
100*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "bootnand", "we",    V_5182 | V_5281),
101*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata1", "prsnt",    V_5182)),
102*fd67f884SThomas Petazzoni 	MPP_MODE(6,
103*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
104*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "req5",       V_ALL),
105*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "nand", "re0",       V_5182 | V_5281),
106*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "pci-1", "clk",      V_5181L),
107*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata0", "act",      V_5182)),
108*fd67f884SThomas Petazzoni 	MPP_MODE(7,
109*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
110*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x2, "pci", "gnt5",       V_ALL),
111*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "nand", "we0",       V_5182 | V_5281),
112*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "pci-1", "clk",      V_5181L),
113*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata1", "act",      V_5182)),
114*fd67f884SThomas Petazzoni 	MPP_MODE(8,
115*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
116*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "col",         V_ALL)),
117*fd67f884SThomas Petazzoni 	MPP_MODE(9,
118*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
119*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "rxerr",       V_ALL)),
120*fd67f884SThomas Petazzoni 	MPP_MODE(10,
121*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
122*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "crs",         V_ALL)),
123*fd67f884SThomas Petazzoni 	MPP_MODE(11,
124*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
125*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "txerr",       V_ALL)),
126*fd67f884SThomas Petazzoni 	MPP_MODE(12,
127*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
128*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "txd4",        V_ALL),
129*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "nand", "re1",       V_5182 | V_5281),
130*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata0", "ledprsnt", V_5182)),
131*fd67f884SThomas Petazzoni 	MPP_MODE(13,
132*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
133*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "txd5",        V_ALL),
134*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "nand", "we1",       V_5182 | V_5281),
135*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata1", "ledprsnt", V_5182)),
136*fd67f884SThomas Petazzoni 	MPP_MODE(14,
137*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
138*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "txd6",        V_ALL),
139*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "nand", "re2",       V_5182 | V_5281),
140*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata0", "ledact",   V_5182)),
141*fd67f884SThomas Petazzoni 	MPP_MODE(15,
142*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "gpio", NULL,        V_ALL),
143*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "txd7",        V_ALL),
144*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x4, "nand", "we2",       V_5182 | V_5281),
145*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "sata1", "ledact",   V_5182)),
146*fd67f884SThomas Petazzoni 	MPP_MODE(16,
147*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "uart1", "rxd",      V_5182 | V_5281),
148*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "rxd4",        V_ALL),
149*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
150*fd67f884SThomas Petazzoni 	MPP_MODE(17,
151*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "uart1", "txd",      V_5182 | V_5281),
152*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "rxd5",        V_ALL),
153*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
154*fd67f884SThomas Petazzoni 	MPP_MODE(18,
155*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "uart1", "cts",      V_5182 | V_5281),
156*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "rxd6",        V_ALL),
157*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
158*fd67f884SThomas Petazzoni 	MPP_MODE(19,
159*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x0, "uart1", "rts",      V_5182 | V_5281),
160*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x1, "ge", "rxd7",        V_ALL),
161*fd67f884SThomas Petazzoni 		 MPP_VAR_FUNCTION(0x5, "gpio", NULL,        V_5182)),
162*fd67f884SThomas Petazzoni };
163*fd67f884SThomas Petazzoni 
164*fd67f884SThomas Petazzoni static struct mvebu_mpp_ctrl orion_mpp_controls[] = {
165*fd67f884SThomas Petazzoni 	MPP_FUNC_CTRL(0, 19, NULL, orion_mpp_ctrl),
166*fd67f884SThomas Petazzoni };
167*fd67f884SThomas Petazzoni 
168*fd67f884SThomas Petazzoni static struct pinctrl_gpio_range mv88f5181l_gpio_ranges[] = {
169*fd67f884SThomas Petazzoni 	MPP_GPIO_RANGE(0, 0, 0, 16),
170*fd67f884SThomas Petazzoni };
171*fd67f884SThomas Petazzoni 
172*fd67f884SThomas Petazzoni static struct pinctrl_gpio_range mv88f5182_gpio_ranges[] = {
173*fd67f884SThomas Petazzoni 	MPP_GPIO_RANGE(0, 0, 0, 19),
174*fd67f884SThomas Petazzoni };
175*fd67f884SThomas Petazzoni 
176*fd67f884SThomas Petazzoni static struct pinctrl_gpio_range mv88f5281_gpio_ranges[] = {
177*fd67f884SThomas Petazzoni 	MPP_GPIO_RANGE(0, 0, 0, 16),
178*fd67f884SThomas Petazzoni };
179*fd67f884SThomas Petazzoni 
180*fd67f884SThomas Petazzoni static struct mvebu_pinctrl_soc_info mv88f5181l_info = {
181*fd67f884SThomas Petazzoni 	.variant = V_5181L,
182*fd67f884SThomas Petazzoni 	.controls = orion_mpp_controls,
183*fd67f884SThomas Petazzoni 	.ncontrols = ARRAY_SIZE(orion_mpp_controls),
184*fd67f884SThomas Petazzoni 	.modes = orion_mpp_modes,
185*fd67f884SThomas Petazzoni 	.nmodes = ARRAY_SIZE(orion_mpp_modes),
186*fd67f884SThomas Petazzoni 	.gpioranges = mv88f5181l_gpio_ranges,
187*fd67f884SThomas Petazzoni 	.ngpioranges = ARRAY_SIZE(mv88f5181l_gpio_ranges),
188*fd67f884SThomas Petazzoni };
189*fd67f884SThomas Petazzoni 
190*fd67f884SThomas Petazzoni static struct mvebu_pinctrl_soc_info mv88f5182_info = {
191*fd67f884SThomas Petazzoni 	.variant = V_5182,
192*fd67f884SThomas Petazzoni 	.controls = orion_mpp_controls,
193*fd67f884SThomas Petazzoni 	.ncontrols = ARRAY_SIZE(orion_mpp_controls),
194*fd67f884SThomas Petazzoni 	.modes = orion_mpp_modes,
195*fd67f884SThomas Petazzoni 	.nmodes = ARRAY_SIZE(orion_mpp_modes),
196*fd67f884SThomas Petazzoni 	.gpioranges = mv88f5182_gpio_ranges,
197*fd67f884SThomas Petazzoni 	.ngpioranges = ARRAY_SIZE(mv88f5182_gpio_ranges),
198*fd67f884SThomas Petazzoni };
199*fd67f884SThomas Petazzoni 
200*fd67f884SThomas Petazzoni static struct mvebu_pinctrl_soc_info mv88f5281_info = {
201*fd67f884SThomas Petazzoni 	.variant = V_5281,
202*fd67f884SThomas Petazzoni 	.controls = orion_mpp_controls,
203*fd67f884SThomas Petazzoni 	.ncontrols = ARRAY_SIZE(orion_mpp_controls),
204*fd67f884SThomas Petazzoni 	.modes = orion_mpp_modes,
205*fd67f884SThomas Petazzoni 	.nmodes = ARRAY_SIZE(orion_mpp_modes),
206*fd67f884SThomas Petazzoni 	.gpioranges = mv88f5281_gpio_ranges,
207*fd67f884SThomas Petazzoni 	.ngpioranges = ARRAY_SIZE(mv88f5281_gpio_ranges),
208*fd67f884SThomas Petazzoni };
209*fd67f884SThomas Petazzoni 
210*fd67f884SThomas Petazzoni /*
211*fd67f884SThomas Petazzoni  * There are multiple variants of the Orion SoCs, but in terms of pin
212*fd67f884SThomas Petazzoni  * muxing, they are identical.
213*fd67f884SThomas Petazzoni  */
214*fd67f884SThomas Petazzoni static struct of_device_id orion_pinctrl_of_match[] = {
215*fd67f884SThomas Petazzoni 	{ .compatible = "marvell,88f5181l-pinctrl", .data = &mv88f5181l_info },
216*fd67f884SThomas Petazzoni 	{ .compatible = "marvell,88f5182-pinctrl", .data = &mv88f5182_info },
217*fd67f884SThomas Petazzoni 	{ .compatible = "marvell,88f5281-pinctrl", .data = &mv88f5281_info },
218*fd67f884SThomas Petazzoni 	{ }
219*fd67f884SThomas Petazzoni };
220*fd67f884SThomas Petazzoni 
221*fd67f884SThomas Petazzoni static int orion_pinctrl_probe(struct platform_device *pdev)
222*fd67f884SThomas Petazzoni {
223*fd67f884SThomas Petazzoni 	const struct of_device_id *match =
224*fd67f884SThomas Petazzoni 		of_match_device(orion_pinctrl_of_match, &pdev->dev);
225*fd67f884SThomas Petazzoni 	struct resource *res;
226*fd67f884SThomas Petazzoni 
227*fd67f884SThomas Petazzoni 	pdev->dev.platform_data = (void*)match->data;
228*fd67f884SThomas Petazzoni 
229*fd67f884SThomas Petazzoni 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
230*fd67f884SThomas Petazzoni 	mpp_base = devm_ioremap_resource(&pdev->dev, res);
231*fd67f884SThomas Petazzoni 	if (IS_ERR(mpp_base))
232*fd67f884SThomas Petazzoni 		return PTR_ERR(mpp_base);
233*fd67f884SThomas Petazzoni 
234*fd67f884SThomas Petazzoni 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
235*fd67f884SThomas Petazzoni 	high_mpp_base = devm_ioremap_resource(&pdev->dev, res);
236*fd67f884SThomas Petazzoni 	if (IS_ERR(high_mpp_base))
237*fd67f884SThomas Petazzoni 		return PTR_ERR(high_mpp_base);
238*fd67f884SThomas Petazzoni 
239*fd67f884SThomas Petazzoni 	return mvebu_pinctrl_probe(pdev);
240*fd67f884SThomas Petazzoni }
241*fd67f884SThomas Petazzoni 
242*fd67f884SThomas Petazzoni static int orion_pinctrl_remove(struct platform_device *pdev)
243*fd67f884SThomas Petazzoni {
244*fd67f884SThomas Petazzoni 	return mvebu_pinctrl_remove(pdev);
245*fd67f884SThomas Petazzoni }
246*fd67f884SThomas Petazzoni 
247*fd67f884SThomas Petazzoni static struct platform_driver orion_pinctrl_driver = {
248*fd67f884SThomas Petazzoni 	.driver = {
249*fd67f884SThomas Petazzoni 		.name = "orion-pinctrl",
250*fd67f884SThomas Petazzoni 		.owner = THIS_MODULE,
251*fd67f884SThomas Petazzoni 		.of_match_table = of_match_ptr(orion_pinctrl_of_match),
252*fd67f884SThomas Petazzoni 	},
253*fd67f884SThomas Petazzoni 	.probe = orion_pinctrl_probe,
254*fd67f884SThomas Petazzoni 	.remove = orion_pinctrl_remove,
255*fd67f884SThomas Petazzoni };
256*fd67f884SThomas Petazzoni 
257*fd67f884SThomas Petazzoni module_platform_driver(orion_pinctrl_driver);
258*fd67f884SThomas Petazzoni 
259*fd67f884SThomas Petazzoni MODULE_AUTHOR("Thomas Petazzoni <thomas.petazzoni@free-electrons.com>");
260*fd67f884SThomas Petazzoni MODULE_DESCRIPTION("Marvell Orion pinctrl driver");
261*fd67f884SThomas Petazzoni MODULE_LICENSE("GPL v2");
262