blob: 307ed1db8750ccc613b4fa36248570460136d6d5 [file] [log] [blame]
Gregory CLEMENT2a626432018-12-08 09:59:01 +01001// SPDX-License-Identifier: (GPL-2.0 OR MIT)
2/*
3 * Microsemi SoCs pinctrl driver
4 *
5 * Author: <alexandre.belloni@free-electrons.com>
6 * Author: <gregory.clement@bootlin.com>
7 * License: Dual MIT/GPL
8 * Copyright (c) 2017 Microsemi Corporation
9 */
10
11#include <asm/gpio.h>
12#include <asm/system.h>
13#include <common.h>
14#include <config.h>
15#include <dm.h>
16#include <dm/device-internal.h>
Simon Glass9bc15642020-02-03 07:36:16 -070017#include <dm/device_compat.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <dm/devres.h>
Gregory CLEMENT2a626432018-12-08 09:59:01 +010019#include <dm/lists.h>
20#include <dm/pinctrl.h>
21#include <dm/root.h>
22#include <errno.h>
23#include <fdtdec.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060024#include <linux/bitops.h>
Gregory CLEMENT2a626432018-12-08 09:59:01 +010025#include <linux/io.h>
26#include "mscc-common.h"
27
Horatiu Vultur2d4fb842019-01-12 18:56:55 +010028static void mscc_writel(unsigned int offset, void *addr)
29{
30 if (offset < 32)
31 writel(BIT(offset), addr);
32 else
33 writel(BIT(offset % 32), addr + 4);
34}
35
36static unsigned int mscc_readl(unsigned int offset, void *addr)
37{
38 if (offset < 32)
39 return readl(addr);
40 else
41 return readl(addr + 4);
42}
43
44static void mscc_setbits(unsigned int offset, void *addr)
45{
46 if (offset < 32)
47 writel(readl(addr) | BIT(offset), addr);
48 else
49 writel(readl(addr + 4) | BIT(offset % 32), addr + 4);
50}
51
52static void mscc_clrbits(unsigned int offset, void *addr)
53{
54 if (offset < 32)
55 writel(readl(addr) & ~BIT(offset), addr);
56 else
57 writel(readl(addr + 4) & ~BIT(offset % 32), addr + 4);
58}
Gregory CLEMENT2a626432018-12-08 09:59:01 +010059
60static int mscc_get_functions_count(struct udevice *dev)
61{
62 struct mscc_pinctrl *info = dev_get_priv(dev);
63
64 return info->num_func;
65}
66
67static const char *mscc_get_function_name(struct udevice *dev,
68 unsigned int function)
69{
70 struct mscc_pinctrl *info = dev_get_priv(dev);
71
72 return info->function_names[function];
73}
74
75static int mscc_pin_function_idx(unsigned int pin, unsigned int function,
76 const struct mscc_pin_data *mscc_pins)
77{
78 struct mscc_pin_caps *p = mscc_pins[pin].drv_data;
79 int i;
80
81 for (i = 0; i < MSCC_FUNC_PER_PIN; i++) {
82 if (function == p->functions[i])
83 return i;
84 }
85
86 return -1;
87}
88
89static int mscc_pinmux_set_mux(struct udevice *dev,
90 unsigned int pin_selector, unsigned int selector)
91{
92 struct mscc_pinctrl *info = dev_get_priv(dev);
93 struct mscc_pin_caps *pin = info->mscc_pins[pin_selector].drv_data;
Horatiu Vultur2d4fb842019-01-12 18:56:55 +010094 int f, offset, regoff;
Gregory CLEMENT2a626432018-12-08 09:59:01 +010095
96 f = mscc_pin_function_idx(pin_selector, selector, info->mscc_pins);
97 if (f < 0)
98 return -EINVAL;
99 /*
100 * f is encoded on two bits.
101 * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of
102 * ALT1
103 * This is racy because both registers can't be updated at the same time
104 * but it doesn't matter much for now.
105 */
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100106 offset = pin->pin;
107 regoff = info->mscc_gpios[MSCC_GPIO_ALT0];
108 if (offset >= 32) {
109 offset = offset % 32;
110 regoff = info->mscc_gpios[MSCC_GPIO_ALT1];
111 }
112
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100113 if (f & BIT(0))
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100114 mscc_setbits(offset, info->regs + regoff);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100115 else
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100116 mscc_clrbits(offset, info->regs + regoff);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100117
118 if (f & BIT(1))
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100119 mscc_setbits(offset, info->regs + regoff + 4);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100120 else
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100121 mscc_clrbits(offset, info->regs + regoff + 4);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100122
123 return 0;
124}
125
126static int mscc_pctl_get_groups_count(struct udevice *dev)
127{
128 struct mscc_pinctrl *info = dev_get_priv(dev);
129
130 return info->num_pins;
131}
132
133static const char *mscc_pctl_get_group_name(struct udevice *dev,
134 unsigned int group)
135{
136 struct mscc_pinctrl *info = dev_get_priv(dev);
137
138 return info->mscc_pins[group].name;
139}
140
141static int mscc_create_group_func_map(struct udevice *dev,
142 struct mscc_pinctrl *info)
143{
144 u16 pins[info->num_pins];
145 int f, npins, i;
146
147 for (f = 0; f < info->num_func; f++) {
148 for (npins = 0, i = 0; i < info->num_pins; i++) {
149 if (mscc_pin_function_idx(i, f, info->mscc_pins) >= 0)
150 pins[npins++] = i;
151 }
152
153 info->func[f].ngroups = npins;
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100154 info->func[f].groups = devm_kzalloc(dev, npins * sizeof(char *),
155 GFP_KERNEL);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100156 if (!info->func[f].groups)
157 return -ENOMEM;
158
159 for (i = 0; i < npins; i++)
160 info->func[f].groups[i] = info->mscc_pins[pins[i]].name;
161 }
162
163 return 0;
164}
165
166static int mscc_pinctrl_register(struct udevice *dev, struct mscc_pinctrl *info)
167{
168 int ret;
169
170 ret = mscc_create_group_func_map(dev, info);
171 if (ret) {
172 dev_err(dev, "Unable to create group func map.\n");
173 return ret;
174 }
175
176 return 0;
177}
178
179static int mscc_gpio_get(struct udevice *dev, unsigned int offset)
180{
181 struct mscc_pinctrl *info = dev_get_priv(dev->parent);
182 unsigned int val;
183
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100184 if (mscc_readl(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]) &
185 BIT(offset % 32))
186 val = mscc_readl(offset,
187 info->regs + info->mscc_gpios[MSCC_GPIO_OUT]);
188 else
189 val = mscc_readl(offset,
190 info->regs + info->mscc_gpios[MSCC_GPIO_IN]);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100191
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100192 return !!(val & BIT(offset % 32));
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100193}
194
195static int mscc_gpio_set(struct udevice *dev, unsigned int offset, int value)
196{
197 struct mscc_pinctrl *info = dev_get_priv(dev->parent);
198
199 if (value)
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100200 mscc_writel(offset,
201 info->regs + info->mscc_gpios[MSCC_GPIO_OUT_SET]);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100202 else
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100203 mscc_writel(offset,
204 info->regs + info->mscc_gpios[MSCC_GPIO_OUT_CLR]);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100205
206 return 0;
207}
208
209static int mscc_gpio_get_direction(struct udevice *dev, unsigned int offset)
210{
211 struct mscc_pinctrl *info = dev_get_priv(dev->parent);
212 unsigned int val;
213
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100214 val = mscc_readl(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100215
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100216 return (val & BIT(offset % 32)) ? GPIOF_OUTPUT : GPIOF_INPUT;
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100217}
218
219static int mscc_gpio_direction_input(struct udevice *dev, unsigned int offset)
220{
221 struct mscc_pinctrl *info = dev_get_priv(dev->parent);
222
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100223 mscc_clrbits(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100224
225 return 0;
226}
227
228static int mscc_gpio_direction_output(struct udevice *dev,
229 unsigned int offset, int value)
230{
231 struct mscc_pinctrl *info = dev_get_priv(dev->parent);
232
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100233 mscc_setbits(offset, info->regs + info->mscc_gpios[MSCC_GPIO_OE]);
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100234
235 return mscc_gpio_set(dev, offset, value);
236}
237
238const struct dm_gpio_ops mscc_gpio_ops = {
239 .set_value = mscc_gpio_set,
240 .get_value = mscc_gpio_get,
241 .get_function = mscc_gpio_get_direction,
242 .direction_input = mscc_gpio_direction_input,
243 .direction_output = mscc_gpio_direction_output,
244};
245
246const struct pinctrl_ops mscc_pinctrl_ops = {
247 .get_pins_count = mscc_pctl_get_groups_count,
248 .get_pin_name = mscc_pctl_get_group_name,
249 .get_functions_count = mscc_get_functions_count,
250 .get_function_name = mscc_get_function_name,
251 .pinmux_set = mscc_pinmux_set_mux,
252 .set_state = pinctrl_generic_set_state,
253};
254
255int mscc_pinctrl_probe(struct udevice *dev, int num_func,
256 const struct mscc_pin_data *mscc_pins, int num_pins,
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100257 char * const *function_names,
258 const unsigned long *mscc_gpios)
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100259{
260 struct mscc_pinctrl *priv = dev_get_priv(dev);
261 int ret;
262
263 priv->regs = dev_remap_addr(dev);
264 if (!priv->regs)
265 return -EINVAL;
266
267 priv->func = devm_kzalloc(dev, num_func * sizeof(struct mscc_pmx_func),
268 GFP_KERNEL);
269 priv->num_func = num_func;
270 priv->mscc_pins = mscc_pins;
271 priv->num_pins = num_pins;
272 priv->function_names = function_names;
Horatiu Vultur2d4fb842019-01-12 18:56:55 +0100273 priv->mscc_gpios = mscc_gpios;
Gregory CLEMENT2a626432018-12-08 09:59:01 +0100274 ret = mscc_pinctrl_register(dev, priv);
275
276 return ret;
277}