4 * SPDX-License-Identifier: GPL-2.0+
9 #include <dm/pinctrl.h>
10 #include <fdt_support.h>
11 #include <linux/err.h>
13 #include <linux/sizes.h>
15 #include "pinctrl-meson.h"
17 DECLARE_GLOBAL_DATA_PTR;
19 static const char *meson_pinctrl_dummy_name = "_dummy";
21 static int meson_pinctrl_get_groups_count(struct udevice *dev)
23 struct meson_pinctrl *priv = dev_get_priv(dev);
25 return priv->data->num_groups;
28 static const char *meson_pinctrl_get_group_name(struct udevice *dev,
31 struct meson_pinctrl *priv = dev_get_priv(dev);
33 if (!priv->data->groups[selector].name)
34 return meson_pinctrl_dummy_name;
36 return priv->data->groups[selector].name;
39 static int meson_pinmux_get_functions_count(struct udevice *dev)
41 struct meson_pinctrl *priv = dev_get_priv(dev);
43 return priv->data->num_funcs;
46 static const char *meson_pinmux_get_function_name(struct udevice *dev,
49 struct meson_pinctrl *priv = dev_get_priv(dev);
51 return priv->data->funcs[selector].name;
54 static void meson_pinmux_disable_other_groups(struct meson_pinctrl *priv,
55 unsigned int pin, int sel_group)
57 struct meson_pmx_group *group;
61 for (i = 0; i < priv->data->num_groups; i++) {
62 group = &priv->data->groups[i];
63 if (group->is_gpio || i == sel_group)
66 for (j = 0; j < group->num_pins; j++) {
67 if (group->pins[j] == pin) {
68 /* We have found a group using the pin */
69 debug("pinmux: disabling %s\n", group->name);
70 addr = priv->reg_mux + group->reg * 4;
71 writel(readl(addr) & ~BIT(group->bit), addr);
77 static int meson_pinmux_group_set(struct udevice *dev,
78 unsigned group_selector,
79 unsigned func_selector)
81 struct meson_pinctrl *priv = dev_get_priv(dev);
82 const struct meson_pmx_group *group;
83 const struct meson_pmx_func *func;
87 group = &priv->data->groups[group_selector];
88 func = &priv->data->funcs[func_selector];
90 debug("pinmux: set group %s func %s\n", group->name, func->name);
93 * Disable groups using the same pins.
94 * The selected group is not disabled to avoid glitches.
96 for (i = 0; i < group->num_pins; i++) {
97 meson_pinmux_disable_other_groups(priv,
102 /* Function 0 (GPIO) doesn't need any additional setting */
104 addr = priv->reg_mux + group->reg * 4;
105 writel(readl(addr) | BIT(group->bit), addr);
111 const struct pinctrl_ops meson_pinctrl_ops = {
112 .get_groups_count = meson_pinctrl_get_groups_count,
113 .get_group_name = meson_pinctrl_get_group_name,
114 .get_functions_count = meson_pinmux_get_functions_count,
115 .get_function_name = meson_pinmux_get_function_name,
116 .pinmux_group_set = meson_pinmux_group_set,
117 .set_state = pinctrl_generic_set_state,
120 static fdt_addr_t parse_address(int offset, const char *name, int na, int ns)
125 index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name);
127 return FDT_ADDR_T_NONE;
129 reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
130 if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns))))
131 return FDT_ADDR_T_NONE;
133 reg += index * (na + ns);
135 return fdt_translate_address((void *)gd->fdt_blob, offset, reg);
138 int meson_pinctrl_probe(struct udevice *dev)
140 struct meson_pinctrl *priv = dev_get_priv(dev);
142 int node, gpio = -1, len;
145 na = fdt_address_cells(gd->fdt_blob, dev->parent->of_offset);
147 debug("bad #address-cells\n");
151 ns = fdt_size_cells(gd->fdt_blob, dev->parent->of_offset);
153 debug("bad #size-cells\n");
157 fdt_for_each_subnode(gd->fdt_blob, node, dev->of_offset) {
158 if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) {
165 debug("gpio node not found\n");
169 addr = parse_address(gpio, "mux", na, ns);
170 if (addr == FDT_ADDR_T_NONE) {
171 debug("mux not found\n");
175 priv->reg_mux = (void __iomem *)addr;
176 priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev);