[PATCH 02/22] of: gpio: Add support for dual xilinx GPIO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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



[Index of Archives]     [Linux SPI]     [Linux Kernel]     [Linux ARM (vger)]     [Linux ARM MSM]     [Linux Omap]     [Linux Arm]     [Linux Tegra]     [Fedora ARM]     [Linux for Samsung SOC]     [eCos]     [Linux Fastboot]     [Gcc Help]     [Git]     [DCCP]     [IETF Announce]     [Security]     [Linux MIPS]     [Yosemite Campsites]

  Powered by Linux