1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com>
4 */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <dm/device-internal.h>
9 #include <dm/lists.h>
10 #include <dm/pinctrl.h>
11 #include <fdt_support.h>
12 #include <linux/err.h>
13 #include <linux/io.h>
14 #include <linux/sizes.h>
15 #include <asm/gpio.h>
16
17 #include "pinctrl-meson.h"
18
19 DECLARE_GLOBAL_DATA_PTR;
20
21 static const char *meson_pinctrl_dummy_name = "_dummy";
22
meson_pinctrl_get_groups_count(struct udevice * dev)23 int meson_pinctrl_get_groups_count(struct udevice *dev)
24 {
25 struct meson_pinctrl *priv = dev_get_priv(dev);
26
27 return priv->data->num_groups;
28 }
29
meson_pinctrl_get_group_name(struct udevice * dev,unsigned int selector)30 const char *meson_pinctrl_get_group_name(struct udevice *dev,
31 unsigned int selector)
32 {
33 struct meson_pinctrl *priv = dev_get_priv(dev);
34
35 if (!priv->data->groups[selector].name)
36 return meson_pinctrl_dummy_name;
37
38 return priv->data->groups[selector].name;
39 }
40
meson_pinmux_get_functions_count(struct udevice * dev)41 int meson_pinmux_get_functions_count(struct udevice *dev)
42 {
43 struct meson_pinctrl *priv = dev_get_priv(dev);
44
45 return priv->data->num_funcs;
46 }
47
meson_pinmux_get_function_name(struct udevice * dev,unsigned int selector)48 const char *meson_pinmux_get_function_name(struct udevice *dev,
49 unsigned int selector)
50 {
51 struct meson_pinctrl *priv = dev_get_priv(dev);
52
53 return priv->data->funcs[selector].name;
54 }
55
meson_gpio_calc_reg_and_bit(struct udevice * dev,unsigned int offset,enum meson_reg_type reg_type,unsigned int * reg,unsigned int * bit)56 static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset,
57 enum meson_reg_type reg_type,
58 unsigned int *reg, unsigned int *bit)
59 {
60 struct meson_pinctrl *priv = dev_get_priv(dev);
61 struct meson_bank *bank = NULL;
62 struct meson_reg_desc *desc;
63 unsigned int pin;
64 int i;
65
66 pin = priv->data->pin_base + offset;
67
68 for (i = 0; i < priv->data->num_banks; i++) {
69 if (pin >= priv->data->banks[i].first &&
70 pin <= priv->data->banks[i].last) {
71 bank = &priv->data->banks[i];
72 break;
73 }
74 }
75
76 if (!bank)
77 return -EINVAL;
78
79 desc = &bank->regs[reg_type];
80 *reg = desc->reg * 4;
81 *bit = desc->bit + pin - bank->first;
82
83 return 0;
84 }
85
meson_gpio_get(struct udevice * dev,unsigned int offset)86 int meson_gpio_get(struct udevice *dev, unsigned int offset)
87 {
88 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
89 unsigned int reg, bit;
90 int ret;
91
92 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_IN, ®,
93 &bit);
94 if (ret)
95 return ret;
96
97 return !!(readl(priv->reg_gpio + reg) & BIT(bit));
98 }
99
meson_gpio_set(struct udevice * dev,unsigned int offset,int value)100 int meson_gpio_set(struct udevice *dev, unsigned int offset, int value)
101 {
102 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
103 unsigned int reg, bit;
104 int ret;
105
106 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, ®,
107 &bit);
108 if (ret)
109 return ret;
110
111 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
112
113 return 0;
114 }
115
meson_gpio_get_direction(struct udevice * dev,unsigned int offset)116 int meson_gpio_get_direction(struct udevice *dev, unsigned int offset)
117 {
118 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
119 unsigned int reg, bit, val;
120 int ret;
121
122 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, ®,
123 &bit);
124 if (ret)
125 return ret;
126
127 val = readl(priv->reg_gpio + reg);
128
129 return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT;
130 }
131
meson_gpio_direction_input(struct udevice * dev,unsigned int offset)132 int meson_gpio_direction_input(struct udevice *dev, unsigned int offset)
133 {
134 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
135 unsigned int reg, bit;
136 int ret;
137
138 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, ®,
139 &bit);
140 if (ret)
141 return ret;
142
143 setbits_le32(priv->reg_gpio + reg, BIT(bit));
144
145 return 0;
146 }
147
meson_gpio_direction_output(struct udevice * dev,unsigned int offset,int value)148 int meson_gpio_direction_output(struct udevice *dev,
149 unsigned int offset, int value)
150 {
151 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
152 unsigned int reg, bit;
153 int ret;
154
155 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_DIR, ®,
156 &bit);
157 if (ret)
158 return ret;
159
160 clrbits_le32(priv->reg_gpio + reg, BIT(bit));
161
162 ret = meson_gpio_calc_reg_and_bit(dev->parent, offset, REG_OUT, ®,
163 &bit);
164 if (ret)
165 return ret;
166
167 clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0);
168
169 return 0;
170 }
171
meson_pinconf_bias_set(struct udevice * dev,unsigned int pin,unsigned int param)172 static int meson_pinconf_bias_set(struct udevice *dev, unsigned int pin,
173 unsigned int param)
174 {
175 struct meson_pinctrl *priv = dev_get_priv(dev);
176 unsigned int offset = pin - priv->data->pin_base;
177 unsigned int reg, bit;
178 int ret;
179
180 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULLEN, ®, &bit);
181 if (ret)
182 return ret;
183
184 if (param == PIN_CONFIG_BIAS_DISABLE) {
185 clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 0);
186 return 0;
187 }
188
189 /* othewise, enable the bias and select level */
190 clrsetbits_le32(priv->reg_pullen + reg, BIT(bit), 1);
191 ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_PULL, ®, &bit);
192 if (ret)
193 return ret;
194
195 clrsetbits_le32(priv->reg_pull + reg, BIT(bit),
196 param == PIN_CONFIG_BIAS_PULL_UP);
197
198 return 0;
199 }
200
meson_pinconf_set(struct udevice * dev,unsigned int pin,unsigned int param,unsigned int arg)201 int meson_pinconf_set(struct udevice *dev, unsigned int pin,
202 unsigned int param, unsigned int arg)
203 {
204 int ret;
205
206 switch (param) {
207 case PIN_CONFIG_BIAS_DISABLE:
208 case PIN_CONFIG_BIAS_PULL_UP:
209 case PIN_CONFIG_BIAS_PULL_DOWN:
210 ret = meson_pinconf_bias_set(dev, pin, param);
211 break;
212
213 default:
214 dev_err(dev, "unsupported configuration parameter %u\n", param);
215 return -EINVAL;
216 }
217
218 return ret;
219 }
220
meson_pinconf_group_set(struct udevice * dev,unsigned int group_selector,unsigned int param,unsigned int arg)221 int meson_pinconf_group_set(struct udevice *dev,
222 unsigned int group_selector,
223 unsigned int param, unsigned int arg)
224 {
225 struct meson_pinctrl *priv = dev_get_priv(dev);
226 struct meson_pmx_group *grp = &priv->data->groups[group_selector];
227 int i, ret;
228
229 for (i = 0; i < grp->num_pins; i++) {
230 ret = meson_pinconf_set(dev, grp->pins[i], param, arg);
231 if (ret)
232 return ret;
233 }
234
235 return 0;
236 }
237
meson_gpio_probe(struct udevice * dev)238 int meson_gpio_probe(struct udevice *dev)
239 {
240 struct meson_pinctrl *priv = dev_get_priv(dev->parent);
241 struct gpio_dev_priv *uc_priv;
242
243 uc_priv = dev_get_uclass_priv(dev);
244 uc_priv->bank_name = priv->data->name;
245 uc_priv->gpio_count = priv->data->num_pins;
246
247 return 0;
248 }
249
parse_address(int offset,const char * name,int na,int ns)250 static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
251 {
252 int index, len = 0;
253 const fdt32_t *reg;
254
255 index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
256 if (index < 0)
257 return FDT_ADDR_T_NONE;
258
259 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
260 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
261 return FDT_ADDR_T_NONE;
262
263 reg += index * (na + ns);
264
265 return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
266 }
267
meson_pinctrl_probe(struct udevice * dev)268 int meson_pinctrl_probe(struct udevice *dev)
269 {
270 struct meson_pinctrl *priv = dev_get_priv(dev);
271 struct uclass_driver *drv;
272 struct udevice *gpio_dev;
273 fdt_addr_t addr;
274 int node, gpio = -1, len;
275 int na, ns;
276 char *name;
277
278 na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent));
279 if (na < 1) {
280 debug("bad #address-cells\n");
281 return -EINVAL;
282 }
283
284 ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent));
285 if (ns < 1) {
286 debug("bad #size-cells\n");
287 return -EINVAL;
288 }
289
290 fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) {
291 if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
292 gpio = node;
293 break;
294 }
295 }
296
297 if (!gpio) {
298 debug("gpio node not found\n");
299 return -EINVAL;
300 }
301
302 addr = parse_address(gpio, "mux", na, ns);
303 if (addr == FDT_ADDR_T_NONE) {
304 debug("mux address not found\n");
305 return -EINVAL;
306 }
307 priv->reg_mux = (void __iomem *)addr;
308
309 addr = parse_address(gpio, "gpio", na, ns);
310 if (addr == FDT_ADDR_T_NONE) {
311 debug("gpio address not found\n");
312 return -EINVAL;
313 }
314 priv->reg_gpio = (void __iomem *)addr;
315
316 addr = parse_address(gpio, "pull", na, ns);
317 if (addr == FDT_ADDR_T_NONE) {
318 debug("pull address not found\n");
319 return -EINVAL;
320 }
321 priv->reg_pull = (void __iomem *)addr;
322
323 addr = parse_address(gpio, "pull-enable", na, ns);
324 /* Use pull region if pull-enable one is not present */
325 if (addr == FDT_ADDR_T_NONE)
326 priv->reg_pullen = priv->reg_pull;
327 else
328 priv->reg_pullen = (void __iomem *)addr;
329
330 priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);
331
332 /* Lookup GPIO driver */
333 drv = lists_uclass_lookup(UCLASS_GPIO);
334 if (!drv) {
335 puts("Cannot find GPIO driver\n");
336 return -ENOENT;
337 }
338
339 name = calloc(1, 32);
340 sprintf(name, "meson-gpio");
341
342 /* Create child device UCLASS_GPIO and bind it */
343 device_bind(dev, priv->data->gpio_driver, name, NULL, gpio, &gpio_dev);
344 dev_set_of_offset(gpio_dev, gpio);
345
346 return 0;
347 }
348