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