1677b5358SBeniamino Galvani /* 2677b5358SBeniamino Galvani * (C) Copyright 2016 - Beniamino Galvani <b.galvani@gmail.com> 3677b5358SBeniamino Galvani * 4677b5358SBeniamino Galvani * SPDX-License-Identifier: GPL-2.0+ 5677b5358SBeniamino Galvani */ 6677b5358SBeniamino Galvani 7677b5358SBeniamino Galvani #include <common.h> 8677b5358SBeniamino Galvani #include <dm/device.h> 9677b5358SBeniamino Galvani #include <dm/pinctrl.h> 10677b5358SBeniamino Galvani #include <fdt_support.h> 11677b5358SBeniamino Galvani #include <linux/err.h> 12677b5358SBeniamino Galvani #include <linux/io.h> 13677b5358SBeniamino Galvani #include <linux/sizes.h> 14677b5358SBeniamino Galvani 15677b5358SBeniamino Galvani #include "pinctrl-meson.h" 16677b5358SBeniamino Galvani 17677b5358SBeniamino Galvani DECLARE_GLOBAL_DATA_PTR; 18677b5358SBeniamino Galvani 19677b5358SBeniamino Galvani static const char *meson_pinctrl_dummy_name = "_dummy"; 20677b5358SBeniamino Galvani 21677b5358SBeniamino Galvani static int meson_pinctrl_get_groups_count(struct udevice *dev) 22677b5358SBeniamino Galvani { 23677b5358SBeniamino Galvani struct meson_pinctrl *priv = dev_get_priv(dev); 24677b5358SBeniamino Galvani 25677b5358SBeniamino Galvani return priv->data->num_groups; 26677b5358SBeniamino Galvani } 27677b5358SBeniamino Galvani 28677b5358SBeniamino Galvani static const char *meson_pinctrl_get_group_name(struct udevice *dev, 29677b5358SBeniamino Galvani unsigned selector) 30677b5358SBeniamino Galvani { 31677b5358SBeniamino Galvani struct meson_pinctrl *priv = dev_get_priv(dev); 32677b5358SBeniamino Galvani 33677b5358SBeniamino Galvani if (!priv->data->groups[selector].name) 34677b5358SBeniamino Galvani return meson_pinctrl_dummy_name; 35677b5358SBeniamino Galvani 36677b5358SBeniamino Galvani return priv->data->groups[selector].name; 37677b5358SBeniamino Galvani } 38677b5358SBeniamino Galvani 39677b5358SBeniamino Galvani static int meson_pinmux_get_functions_count(struct udevice *dev) 40677b5358SBeniamino Galvani { 41677b5358SBeniamino Galvani struct meson_pinctrl *priv = dev_get_priv(dev); 42677b5358SBeniamino Galvani 43677b5358SBeniamino Galvani return priv->data->num_funcs; 44677b5358SBeniamino Galvani } 45677b5358SBeniamino Galvani 46677b5358SBeniamino Galvani static const char *meson_pinmux_get_function_name(struct udevice *dev, 47677b5358SBeniamino Galvani unsigned selector) 48677b5358SBeniamino Galvani { 49677b5358SBeniamino Galvani struct meson_pinctrl *priv = dev_get_priv(dev); 50677b5358SBeniamino Galvani 51677b5358SBeniamino Galvani return priv->data->funcs[selector].name; 52677b5358SBeniamino Galvani } 53677b5358SBeniamino Galvani 54677b5358SBeniamino Galvani static void meson_pinmux_disable_other_groups(struct meson_pinctrl *priv, 55677b5358SBeniamino Galvani unsigned int pin, int sel_group) 56677b5358SBeniamino Galvani { 57677b5358SBeniamino Galvani struct meson_pmx_group *group; 58677b5358SBeniamino Galvani void __iomem *addr; 59677b5358SBeniamino Galvani int i, j; 60677b5358SBeniamino Galvani 61677b5358SBeniamino Galvani for (i = 0; i < priv->data->num_groups; i++) { 62677b5358SBeniamino Galvani group = &priv->data->groups[i]; 63677b5358SBeniamino Galvani if (group->is_gpio || i == sel_group) 64677b5358SBeniamino Galvani continue; 65677b5358SBeniamino Galvani 66677b5358SBeniamino Galvani for (j = 0; j < group->num_pins; j++) { 67677b5358SBeniamino Galvani if (group->pins[j] == pin) { 68677b5358SBeniamino Galvani /* We have found a group using the pin */ 69677b5358SBeniamino Galvani debug("pinmux: disabling %s\n", group->name); 70677b5358SBeniamino Galvani addr = priv->reg_mux + group->reg * 4; 71677b5358SBeniamino Galvani writel(readl(addr) & ~BIT(group->bit), addr); 72677b5358SBeniamino Galvani } 73677b5358SBeniamino Galvani } 74677b5358SBeniamino Galvani } 75677b5358SBeniamino Galvani } 76677b5358SBeniamino Galvani 77677b5358SBeniamino Galvani static int meson_pinmux_group_set(struct udevice *dev, 78677b5358SBeniamino Galvani unsigned group_selector, 79677b5358SBeniamino Galvani unsigned func_selector) 80677b5358SBeniamino Galvani { 81677b5358SBeniamino Galvani struct meson_pinctrl *priv = dev_get_priv(dev); 82677b5358SBeniamino Galvani const struct meson_pmx_group *group; 83677b5358SBeniamino Galvani const struct meson_pmx_func *func; 84677b5358SBeniamino Galvani void __iomem *addr; 85677b5358SBeniamino Galvani int i; 86677b5358SBeniamino Galvani 87677b5358SBeniamino Galvani group = &priv->data->groups[group_selector]; 88677b5358SBeniamino Galvani func = &priv->data->funcs[func_selector]; 89677b5358SBeniamino Galvani 90677b5358SBeniamino Galvani debug("pinmux: set group %s func %s\n", group->name, func->name); 91677b5358SBeniamino Galvani 92677b5358SBeniamino Galvani /* 93677b5358SBeniamino Galvani * Disable groups using the same pins. 94677b5358SBeniamino Galvani * The selected group is not disabled to avoid glitches. 95677b5358SBeniamino Galvani */ 96677b5358SBeniamino Galvani for (i = 0; i < group->num_pins; i++) { 97677b5358SBeniamino Galvani meson_pinmux_disable_other_groups(priv, 98677b5358SBeniamino Galvani group->pins[i], 99677b5358SBeniamino Galvani group_selector); 100677b5358SBeniamino Galvani } 101677b5358SBeniamino Galvani 102677b5358SBeniamino Galvani /* Function 0 (GPIO) doesn't need any additional setting */ 103677b5358SBeniamino Galvani if (func_selector) { 104677b5358SBeniamino Galvani addr = priv->reg_mux + group->reg * 4; 105677b5358SBeniamino Galvani writel(readl(addr) | BIT(group->bit), addr); 106677b5358SBeniamino Galvani } 107677b5358SBeniamino Galvani 108677b5358SBeniamino Galvani return 0; 109677b5358SBeniamino Galvani } 110677b5358SBeniamino Galvani 111677b5358SBeniamino Galvani const struct pinctrl_ops meson_pinctrl_ops = { 112677b5358SBeniamino Galvani .get_groups_count = meson_pinctrl_get_groups_count, 113677b5358SBeniamino Galvani .get_group_name = meson_pinctrl_get_group_name, 114677b5358SBeniamino Galvani .get_functions_count = meson_pinmux_get_functions_count, 115677b5358SBeniamino Galvani .get_function_name = meson_pinmux_get_function_name, 116677b5358SBeniamino Galvani .pinmux_group_set = meson_pinmux_group_set, 117677b5358SBeniamino Galvani .set_state = pinctrl_generic_set_state, 118677b5358SBeniamino Galvani }; 119677b5358SBeniamino Galvani 120677b5358SBeniamino Galvani static fdt_addr_t parse_address(int offset, const char *name, int na, int ns) 121677b5358SBeniamino Galvani { 122677b5358SBeniamino Galvani int index, len = 0; 123677b5358SBeniamino Galvani const fdt32_t *reg; 124677b5358SBeniamino Galvani 125b02e4044SSimon Glass index = fdt_stringlist_search(gd->fdt_blob, offset, "reg-names", name); 126677b5358SBeniamino Galvani if (index < 0) 127677b5358SBeniamino Galvani return FDT_ADDR_T_NONE; 128677b5358SBeniamino Galvani 129677b5358SBeniamino Galvani reg = fdt_getprop(gd->fdt_blob, offset, "reg", &len); 130677b5358SBeniamino Galvani if (!reg || (len <= (index * sizeof(fdt32_t) * (na + ns)))) 131677b5358SBeniamino Galvani return FDT_ADDR_T_NONE; 132677b5358SBeniamino Galvani 133677b5358SBeniamino Galvani reg += index * (na + ns); 134677b5358SBeniamino Galvani 135677b5358SBeniamino Galvani return fdt_translate_address((void *)gd->fdt_blob, offset, reg); 136677b5358SBeniamino Galvani } 137677b5358SBeniamino Galvani 138677b5358SBeniamino Galvani int meson_pinctrl_probe(struct udevice *dev) 139677b5358SBeniamino Galvani { 140677b5358SBeniamino Galvani struct meson_pinctrl *priv = dev_get_priv(dev); 141677b5358SBeniamino Galvani fdt_addr_t addr; 142677b5358SBeniamino Galvani int node, gpio = -1, len; 143677b5358SBeniamino Galvani int na, ns; 144677b5358SBeniamino Galvani 145*e160f7d4SSimon Glass na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent)); 146677b5358SBeniamino Galvani if (na < 1) { 147677b5358SBeniamino Galvani debug("bad #address-cells\n"); 148677b5358SBeniamino Galvani return -EINVAL; 149677b5358SBeniamino Galvani } 150677b5358SBeniamino Galvani 151*e160f7d4SSimon Glass ns = fdt_size_cells(gd->fdt_blob, dev_of_offset(dev->parent)); 152677b5358SBeniamino Galvani if (ns < 1) { 153677b5358SBeniamino Galvani debug("bad #size-cells\n"); 154677b5358SBeniamino Galvani return -EINVAL; 155677b5358SBeniamino Galvani } 156677b5358SBeniamino Galvani 157*e160f7d4SSimon Glass fdt_for_each_subnode(node, gd->fdt_blob, dev_of_offset(dev)) { 158677b5358SBeniamino Galvani if (fdt_getprop(gd->fdt_blob, node, "gpio-controller", &len)) { 159677b5358SBeniamino Galvani gpio = node; 160677b5358SBeniamino Galvani break; 161677b5358SBeniamino Galvani } 162677b5358SBeniamino Galvani } 163677b5358SBeniamino Galvani 164677b5358SBeniamino Galvani if (!gpio) { 165677b5358SBeniamino Galvani debug("gpio node not found\n"); 166677b5358SBeniamino Galvani return -EINVAL; 167677b5358SBeniamino Galvani } 168677b5358SBeniamino Galvani 169677b5358SBeniamino Galvani addr = parse_address(gpio, "mux", na, ns); 170677b5358SBeniamino Galvani if (addr == FDT_ADDR_T_NONE) { 171677b5358SBeniamino Galvani debug("mux not found\n"); 172677b5358SBeniamino Galvani return -EINVAL; 173677b5358SBeniamino Galvani } 174677b5358SBeniamino Galvani 175677b5358SBeniamino Galvani priv->reg_mux = (void __iomem *)addr; 176677b5358SBeniamino Galvani priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev); 177677b5358SBeniamino Galvani 178677b5358SBeniamino Galvani return 0; 179677b5358SBeniamino Galvani } 180