Commit d2d92bd71cfc78802e7af7585a3ef0f57bd99b24

Authored by Gregory CLEMENT
Committed by Stefan Roese
1 parent 0871806629

pinctrl: armada-37xx: Add gpio support

GPIO management is pretty simple and is part of the same IP than the pin
controller for the Armada 37xx SoCs.  This patch adds the GPIO support to
the pinctrl-armada-37xx.c file, it also allows sharing common functions
between the gpio and the pinctrl drivers.

Ported to U-Boot based on the Linux version by Stefan Roese.

Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Signed-off-by: Stefan Roese <sr@denx.de>
Cc: Gregory CLEMENT <gregory.clement@free-electrons.com>
Cc: Konstantin Porotchkin <kostap@marvell.com>
Cc: Nadav Haklai <nadavh@marvell.com>

Showing 1 changed file with 162 additions and 0 deletions Side-by-side Diff

drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
... ... @@ -20,17 +20,22 @@
20 20 #include <common.h>
21 21 #include <config.h>
22 22 #include <dm.h>
  23 +#include <dm/device-internal.h>
  24 +#include <dm/lists.h>
23 25 #include <dm/pinctrl.h>
24 26 #include <dm/root.h>
25 27 #include <errno.h>
26 28 #include <fdtdec.h>
27 29 #include <regmap.h>
  30 +#include <asm/gpio.h>
28 31 #include <asm/system.h>
29 32 #include <asm/io.h>
30 33  
31 34 DECLARE_GLOBAL_DATA_PTR;
32 35  
33 36 #define OUTPUT_EN 0x0
  37 +#define INPUT_VAL 0x10
  38 +#define OUTPUT_VAL 0x18
34 39 #define OUTPUT_CTL 0x20
35 40 #define SELECTION 0x30
36 41  
... ... @@ -189,6 +194,16 @@
189 194 .ngroups = ARRAY_SIZE(armada_37xx_sb_groups),
190 195 };
191 196  
  197 +static inline void armada_37xx_update_reg(unsigned int *reg,
  198 + unsigned int offset)
  199 +{
  200 + /* We never have more than 2 registers */
  201 + if (offset >= GPIO_PER_REG) {
  202 + offset -= GPIO_PER_REG;
  203 + *reg += sizeof(u32);
  204 + }
  205 +}
  206 +
192 207 static int armada_37xx_get_func_reg(struct armada_37xx_pin_group *grp,
193 208 const char *func)
194 209 {
... ... @@ -399,6 +414,149 @@
399 414 return 0;
400 415 }
401 416  
  417 +static int armada_37xx_gpio_get(struct udevice *dev, unsigned int offset)
  418 +{
  419 + struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
  420 + unsigned int reg = INPUT_VAL;
  421 + unsigned int val, mask;
  422 +
  423 + armada_37xx_update_reg(&reg, offset);
  424 + mask = BIT(offset);
  425 +
  426 + val = readl(info->base + reg);
  427 +
  428 + return (val & mask) != 0;
  429 +}
  430 +
  431 +static int armada_37xx_gpio_set(struct udevice *dev, unsigned int offset,
  432 + int value)
  433 +{
  434 + struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
  435 + unsigned int reg = OUTPUT_VAL;
  436 + unsigned int mask, val;
  437 +
  438 + armada_37xx_update_reg(&reg, offset);
  439 + mask = BIT(offset);
  440 + val = value ? mask : 0;
  441 +
  442 + clrsetbits_le32(info->base + reg, mask, val);
  443 +
  444 + return 0;
  445 +}
  446 +
  447 +static int armada_37xx_gpio_get_direction(struct udevice *dev,
  448 + unsigned int offset)
  449 +{
  450 + struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
  451 + unsigned int reg = OUTPUT_EN;
  452 + unsigned int val, mask;
  453 +
  454 + armada_37xx_update_reg(&reg, offset);
  455 + mask = BIT(offset);
  456 + val = readl(info->base + reg);
  457 +
  458 + if (val & mask)
  459 + return GPIOF_OUTPUT;
  460 + else
  461 + return GPIOF_INPUT;
  462 +}
  463 +
  464 +static int armada_37xx_gpio_direction_input(struct udevice *dev,
  465 + unsigned int offset)
  466 +{
  467 + struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
  468 + unsigned int reg = OUTPUT_EN;
  469 + unsigned int mask;
  470 +
  471 + armada_37xx_update_reg(&reg, offset);
  472 + mask = BIT(offset);
  473 +
  474 + clrbits_le32(info->base + reg, mask);
  475 +
  476 + return 0;
  477 +}
  478 +
  479 +static int armada_37xx_gpio_direction_output(struct udevice *dev,
  480 + unsigned int offset, int value)
  481 +{
  482 + struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
  483 + unsigned int reg = OUTPUT_EN;
  484 + unsigned int mask;
  485 +
  486 + armada_37xx_update_reg(&reg, offset);
  487 + mask = BIT(offset);
  488 +
  489 + setbits_le32(info->base + reg, mask);
  490 +
  491 + /* And set the requested value */
  492 + return armada_37xx_gpio_set(dev, offset, value);
  493 +}
  494 +
  495 +static int armada_37xx_gpio_probe(struct udevice *dev)
  496 +{
  497 + struct armada_37xx_pinctrl *info = dev_get_priv(dev->parent);
  498 + struct gpio_dev_priv *uc_priv;
  499 +
  500 + uc_priv = dev_get_uclass_priv(dev);
  501 + uc_priv->bank_name = info->data->name;
  502 + uc_priv->gpio_count = info->data->nr_pins;
  503 +
  504 + return 0;
  505 +}
  506 +
  507 +static const struct dm_gpio_ops armada_37xx_gpio_ops = {
  508 + .set_value = armada_37xx_gpio_set,
  509 + .get_value = armada_37xx_gpio_get,
  510 + .get_function = armada_37xx_gpio_get_direction,
  511 + .direction_input = armada_37xx_gpio_direction_input,
  512 + .direction_output = armada_37xx_gpio_direction_output,
  513 +};
  514 +
  515 +static struct driver armada_37xx_gpio_driver = {
  516 + .name = "armada-37xx-gpio",
  517 + .id = UCLASS_GPIO,
  518 + .probe = armada_37xx_gpio_probe,
  519 + .ops = &armada_37xx_gpio_ops,
  520 +};
  521 +
  522 +static int armada_37xx_gpiochip_register(struct udevice *parent,
  523 + struct armada_37xx_pinctrl *info)
  524 +{
  525 + const void *blob = gd->fdt_blob;
  526 + int node = dev_of_offset(parent);
  527 + struct uclass_driver *drv;
  528 + struct udevice *dev;
  529 + int ret = -ENODEV;
  530 + int subnode;
  531 + char *name;
  532 +
  533 + /* Lookup GPIO driver */
  534 + drv = lists_uclass_lookup(UCLASS_GPIO);
  535 + if (!drv) {
  536 + puts("Cannot find GPIO driver\n");
  537 + return -ENOENT;
  538 + }
  539 +
  540 + fdt_for_each_subnode(subnode, blob, node) {
  541 + if (!fdtdec_get_bool(blob, subnode, "gpio-controller")) {
  542 + ret = 0;
  543 + break;
  544 + }
  545 + };
  546 + if (ret)
  547 + return ret;
  548 +
  549 + name = calloc(1, 32);
  550 + sprintf(name, "armada-37xx-gpio");
  551 +
  552 + /* Create child device UCLASS_GPIO and bind it */
  553 + device_bind(parent, &armada_37xx_gpio_driver, name, NULL, subnode,
  554 + &dev);
  555 + dev_set_of_offset(dev, subnode);
  556 +
  557 + return 0;
  558 +}
  559 +
402 560 const struct pinctrl_ops armada_37xx_pinctrl_ops = {
403 561 .get_groups_count = armada_37xx_pmx_get_groups_count,
404 562 .get_group_name = armada_37xx_pmx_get_group_name,
... ... @@ -441,6 +599,10 @@
441 599 return ret;
442 600  
443 601 ret = armada_37xx_fill_func(info);
  602 + if (ret)
  603 + return ret;
  604 +
  605 + ret = armada_37xx_gpiochip_register(dev, info);
444 606 if (ret)
445 607 return ret;
446 608