X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=drivers%2Fpinctrl%2Fmeson%2Fpinctrl-meson.c;h=a860200dfb035392da545050fc7235d223f8c37d;hb=19d1f1a2f3ccfbf85125150f7876ce22714b38bd;hp=b5486b8fe4bff10f9df263b5b7dec7c9cbb64cd8;hpb=21342d4aed6c77a4aa7a5b2579b3c23e21aea31a;p=platform%2Fkernel%2Fu-boot.git diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c index b5486b8..a860200 100644 --- a/drivers/pinctrl/meson/pinctrl-meson.c +++ b/drivers/pinctrl/meson/pinctrl-meson.c @@ -5,12 +5,15 @@ */ #include -#include +#include +#include +#include #include #include #include #include #include +#include #include "pinctrl-meson.h" @@ -117,6 +120,143 @@ const struct pinctrl_ops meson_pinctrl_ops = { .set_state = pinctrl_generic_set_state, }; +static int meson_gpio_calc_reg_and_bit(struct udevice *dev, unsigned int offset, + enum meson_reg_type reg_type, + unsigned int *reg, unsigned int *bit) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + struct meson_bank *bank = NULL; + struct meson_reg_desc *desc; + unsigned int pin; + int i; + + pin = priv->data->pin_base + offset; + + for (i = 0; i < priv->data->num_banks; i++) { + if (pin >= priv->data->banks[i].first && + pin <= priv->data->banks[i].last) { + bank = &priv->data->banks[i]; + break; + } + } + + if (!bank) + return -EINVAL; + + desc = &bank->regs[reg_type]; + *reg = desc->reg * 4; + *bit = desc->bit + pin - bank->first; + + return 0; +} + +static int meson_gpio_get(struct udevice *dev, unsigned int offset) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_IN, ®, &bit); + if (ret) + return ret; + + return !!(readl(priv->reg_gpio + reg) & BIT(bit)); +} + +static int meson_gpio_set(struct udevice *dev, unsigned int offset, int value) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0); + + return 0; +} + +static int meson_gpio_get_direction(struct udevice *dev, unsigned int offset) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit, val; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + if (ret) + return ret; + + val = readl(priv->reg_gpio + reg); + + return (val & BIT(bit)) ? GPIOF_INPUT : GPIOF_OUTPUT; +} + +static int meson_gpio_direction_input(struct udevice *dev, unsigned int offset) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 1); + + return 0; +} + +static int meson_gpio_direction_output(struct udevice *dev, + unsigned int offset, int value) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + unsigned int reg, bit; + int ret; + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_DIR, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), 0); + + ret = meson_gpio_calc_reg_and_bit(dev, offset, REG_OUT, ®, &bit); + if (ret) + return ret; + + clrsetbits_le32(priv->reg_gpio + reg, BIT(bit), value ? BIT(bit) : 0); + + return 0; +} + +static int meson_gpio_probe(struct udevice *dev) +{ + struct meson_pinctrl *priv = dev_get_priv(dev->parent); + struct gpio_dev_priv *uc_priv; + + uc_priv = dev_get_uclass_priv(dev); + uc_priv->bank_name = priv->data->name; + uc_priv->gpio_count = priv->data->num_pins; + + return 0; +} + +static const struct dm_gpio_ops meson_gpio_ops = { + .set_value = meson_gpio_set, + .get_value = meson_gpio_get, + .get_function = meson_gpio_get_direction, + .direction_input = meson_gpio_direction_input, + .direction_output = meson_gpio_direction_output, +}; + +static struct driver meson_gpio_driver = { + .name = "meson-gpio", + .id = UCLASS_GPIO, + .probe = meson_gpio_probe, + .ops = &meson_gpio_ops, +}; + static fdt_addr_t parse_address(int offset, const char *name, int na, int ns) { int index, len = 0; @@ -138,9 +278,12 @@ static fdt_addr_t parse_address(int offset, const char *name, int na, int ns) int meson_pinctrl_probe(struct udevice *dev) { struct meson_pinctrl *priv = dev_get_priv(dev); + struct uclass_driver *drv; + struct udevice *gpio_dev; fdt_addr_t addr; int node, gpio = -1, len; int na, ns; + char *name; na = fdt_address_cells(gd->fdt_blob, dev_of_offset(dev->parent)); if (na < 1) { @@ -168,12 +311,32 @@ int meson_pinctrl_probe(struct udevice *dev) addr = parse_address(gpio, "mux", na, ns); if (addr == FDT_ADDR_T_NONE) { - debug("mux not found\n"); + debug("mux address not found\n"); return -EINVAL; } - priv->reg_mux = (void __iomem *)addr; + + addr = parse_address(gpio, "gpio", na, ns); + if (addr == FDT_ADDR_T_NONE) { + debug("gpio address not found\n"); + return -EINVAL; + } + priv->reg_gpio = (void __iomem *)addr; priv->data = (struct meson_pinctrl_data *)dev_get_driver_data(dev); + /* Lookup GPIO driver */ + drv = lists_uclass_lookup(UCLASS_GPIO); + if (!drv) { + puts("Cannot find GPIO driver\n"); + return -ENOENT; + } + + name = calloc(1, 32); + sprintf(name, "meson-gpio"); + + /* Create child device UCLASS_GPIO and bind it */ + device_bind(dev, &meson_gpio_driver, name, NULL, gpio, &gpio_dev); + dev_set_of_offset(gpio_dev, gpio); + return 0; }