From: Michal Simek <monstr@xxxxxxxxx> Date: Fri, 19 Oct 2012 10:49:31 +0200 Register new gpiochip for the second channel. The first channel name is: /plb@0/gpio@81420000 The second channel name is: /plb@0/gpio@81420008 Updated version based on previous patches. Signed-off-by: Michal Simek <monstr@xxxxxxxxx> Signed-off-by: Alexander Hedges <ahedges@xxxxxxx> (cherry picked from commit fb2379e7035e9855543e49637828aca4b7e72f58) --- drivers/gpio/gpio-xilinx.c | 120 +++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 37 deletions(-) diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c index 4fd15f537b90..815af3647d81 100644 --- a/drivers/gpio/gpio-xilinx.c +++ b/drivers/gpio/gpio-xilinx.c @@ -55,6 +55,7 @@ struct xgpio_instance { #endif u32 gpio_state; /* GPIO state shadow register */ u32 gpio_dir; /* GPIO direction shadow register */ + u32 offset; spinlock_t gpio_lock; /* Lock used for synchronization */ }; @@ -73,7 +74,10 @@ static int xgpio_get(struct gpio_chip *gc, unsigned int gpio) { #ifdef CONFIG_OF struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); - void __iomem *regs = mm_gc->regs; + struct xgpio_instance *chip = + container_of(mm_gc, struct xgpio_instance, mmchip); + + void __iomem *regs = mm_gc->regs + chip->offset; #else struct xgpio_instance *chip = container_of(gc, struct xgpio_instance, gc); @@ -113,7 +117,8 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) else chip->gpio_state &= ~BIT(gpio); - xgpio_writereg(regs + XGPIO_DATA_OFFSET, chip->gpio_state); + xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, + chip->gpio_state); spin_unlock_irqrestore(&chip->gpio_lock, flags); } @@ -182,7 +187,7 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) /* Set the GPIO bit in shadow register and set direction as input */ chip->gpio_dir |= (1 << gpio); - xgpio_writereg(regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); spin_unlock_irqrestore(&chip->gpio_lock, flags); @@ -221,11 +226,11 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) chip->gpio_state |= BIT(gpio); else chip->gpio_state &= ~(1 << gpio); - xgpio_writereg(regs + XGPIO_DATA_OFFSET, chip->gpio_state); + xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET, chip->gpio_state); /* Clear the GPIO bit in shadow register and set direction as output */ chip->gpio_dir &= (~(1 << gpio)); - xgpio_writereg(regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir); spin_unlock_irqrestore(&chip->gpio_lock, flags); @@ -242,8 +247,10 @@ static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc) struct xgpio_instance *chip = container_of(mm_gc, struct xgpio_instance, mmchip); - xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state); - xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir); + xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET, + chip->gpio_state); + xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET, + chip->gpio_dir); } /** @@ -271,13 +278,13 @@ static int xgpio_remove(struct platform_device *pdev) * It returns 0, if the driver is bound to the GPIO device, or * a negative value if there is an error. */ -static int xgpio_probe(struct platform_device *pdev) +static int xgpio_of_probe(struct platform_device *pdev) { struct xgpio_instance *chip; int status = 0; - u32 is_dual; struct device_node *np = pdev->dev.of_node; u32 ngpio; + const u32 *tree_info; chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -301,30 +308,6 @@ static int xgpio_probe(struct platform_device *pdev) spin_lock_init(&chip->gpio_lock); - if (of_property_read_u32(np, "xlnx,is-dual", &is_dual)) - is_dual = 0; - - if (is_dual) { - /* Update GPIO state shadow register with default value */ - of_property_read_u32(np, "xlnx,dout-default-2", - &chip->gpio_state); - - /* Update GPIO direction shadow register with default value */ - if (of_property_read_u32(np, "xlnx,tri-default-2", - &chip->gpio_dir)) - chip->gpio_dir = 0xFFFFFFFF; - - /* - * Check device node and parent device node for device width - * and assume default width of 32 - */ - if (of_property_read_u32(np, "xlnx,gpio2-width", - &ngpio)) - ngpio = 32; - - spin_lock_init(&chip->gpio_lock); - } - chip->mmchip.gc.ngpio = (u16)ngpio;; chip->mmchip.gc.parent = &pdev->dev; chip->mmchip.gc.direction_input = xgpio_dir_in; @@ -342,7 +325,62 @@ static int xgpio_probe(struct platform_device *pdev) np, status); return status; } - pr_info("XGpio: %s: registered\n", np->full_name); + + pr_info("XGpio: %s: registered, base is %d\n", np->full_name, + chip->mmchip.gc.base); + + tree_info = of_get_property(np, "xlnx,is-dual", NULL); + if (tree_info && be32_to_cpup(tree_info)) { + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + /* Add dual channel offset */ + chip->offset = XGPIO_CHANNEL_OFFSET; + + /* Update GPIO state shadow register with default value */ + tree_info = of_get_property(np, "xlnx,dout-default-2", NULL); + if (tree_info) + chip->gpio_state = be32_to_cpup(tree_info); + + /* Update GPIO direction shadow register with default value */ + /* By default, all pins are inputs */ + chip->gpio_dir = 0xFFFFFFFF; + tree_info = of_get_property(np, "xlnx,tri-default-2", NULL); + if (tree_info) + chip->gpio_dir = be32_to_cpup(tree_info); + + /* Check device node and parent device node for device width */ + /* By default assume full GPIO controller */ + chip->mmchip.gc.ngpio = 32; + tree_info = of_get_property(np, "xlnx,gpio2-width", NULL); + if (!tree_info) + tree_info = of_get_property(np->parent, + "xlnx,gpio2-width", NULL); + if (tree_info) + chip->mmchip.gc.ngpio = be32_to_cpup(tree_info); + + spin_lock_init(&chip->gpio_lock); + + chip->mmchip.gc.direction_input = xgpio_dir_in; + chip->mmchip.gc.direction_output = xgpio_dir_out; + chip->mmchip.gc.get = xgpio_get; + chip->mmchip.gc.set = xgpio_set; + + chip->mmchip.save_regs = xgpio_save_regs; + + /* Call the OF gpio helper to setup and register the GPIO dev */ + status = of_mm_gpiochip_add(np, &chip->mmchip); + if (status) { + kfree(chip); + pr_err("%s: error in probe function with status %d\n", + np->full_name, status); + return status; + } + pr_info("XGpio: %s: dual channel registered, base is %d\n", + np->full_name, chip->mmchip.gc.base); + } + return 0; } @@ -351,6 +389,15 @@ static const struct of_device_id xgpio_of_match[] = { { /* end of list */ }, }; +static struct platform_driver xgpio_driver = { + .probe = xgpio_of_probe, + .remove = xgpio_remove, + .driver = { + .name = "xilinx_gpio", + .owner = THIS_MODULE, + }, +}; + #else /** @@ -449,9 +496,6 @@ static int __init xgpio_probe(struct platform_device *pdev) return ret; } -#endif /* CONFIG_OF */ - - static struct platform_driver xgpio_driver = { .probe = xgpio_probe, .remove = xgpio_remove, @@ -461,6 +505,8 @@ static struct platform_driver xgpio_driver = { }, }; +#endif /* CONFIG_OF */ + static int __init xgpio_init(void) { #ifdef CONFIG_OF -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-gpio" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html