* [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c
@ 2013-05-29 11:27 Michal Simek
2013-05-29 11:27 ` [PATCH 2/2] DT: Add documentation for gpio-xilinx Michal Simek
[not found] ` <4b90b06fce0475b579cfba4d968b4778359154f6.1369826814.git.michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
0 siblings, 2 replies; 17+ messages in thread
From: Michal Simek @ 2013-05-29 11:27 UTC (permalink / raw)
To: linux-kernel
Cc: Michal Simek, Michal Simek, Grant Likely, Linus Walleij,
Rob Herring, devicetree-discuss
[-- Attachment #1: Type: text/plain, Size: 6872 bytes --]
Supporting the second channel in the driver.
Offset is 0x8 and both channnels share the same
IRQ.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
drivers/gpio/gpio-xilinx.c | 93 ++++++++++++++++++++++++++++++++++++++++------
1 file changed, 81 insertions(+), 12 deletions(-)
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index 9ae7aa8..385dcb0 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -1,7 +1,7 @@
/*
- * Xilinx gpio driver
+ * Xilinx gpio driver for xps/axi_gpio IP.
*
- * Copyright 2008 Xilinx, Inc.
+ * Copyright 2008 - 2013 Xilinx, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -26,10 +26,17 @@
#define XGPIO_DATA_OFFSET (0x0) /* Data register */
#define XGPIO_TRI_OFFSET (0x4) /* I/O direction register */
+#define XGPIO_CHANNEL_OFFSET 0x8
+
+/* Read/Write access to the GPIO registers */
+#define xgpio_readreg(offset) __raw_readl(offset)
+#define xgpio_writereg(offset, val) __raw_writel(val, offset)
+
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
u32 gpio_state; /* GPIO state shadow register */
u32 gpio_dir; /* GPIO direction shadow register */
+ u32 offset;
spinlock_t gpio_lock; /* Lock used for synchronization */
};
@@ -44,8 +51,12 @@ struct xgpio_instance {
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+ struct xgpio_instance *chip =
+ container_of(mm_gc, struct xgpio_instance, mmchip);
+
+ void __iomem *regs = mm_gc->regs + chip->offset;
- return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
+ return (xgpio_readreg(regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
}
/**
@@ -63,6 +74,7 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
@@ -71,7 +83,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
chip->gpio_state |= 1 << gpio;
else
chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->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);
}
@@ -91,12 +105,13 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
/* Set the GPIO bit in shadow register and set direction as input */
chip->gpio_dir |= (1 << gpio);
- out_be32(mm_gc->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);
@@ -119,6 +134,7 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ void __iomem *regs = mm_gc->regs;
spin_lock_irqsave(&chip->gpio_lock, flags);
@@ -127,11 +143,12 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
chip->gpio_state |= 1 << gpio;
else
chip->gpio_state &= ~(1 << gpio);
- out_be32(mm_gc->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));
- out_be32(mm_gc->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);
@@ -147,8 +164,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);
- out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
- out_be32(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);
}
/**
@@ -183,9 +202,6 @@ static int xgpio_of_probe(struct device_node *np)
/* Check device node and parent device node for device width */
chip->mmchip.gc.ngpio = 32; /* By default assume full GPIO controller */
tree_info = of_get_property(np, "xlnx,gpio-width", NULL);
- if (!tree_info)
- tree_info = of_get_property(np->parent,
- "xlnx,gpio-width", NULL);
if (tree_info)
chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
@@ -206,6 +222,59 @@ static int xgpio_of_probe(struct device_node *np)
np->full_name, status);
return status;
}
+
+ 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)
+ 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;
}
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related [flat|nested] 17+ messages in thread* [PATCH 2/2] DT: Add documentation for gpio-xilinx
2013-05-29 11:27 [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c Michal Simek
@ 2013-05-29 11:27 ` Michal Simek
[not found] ` <4b90b06fce0475b579cfba4d968b4778359154f6.1369826814.git.michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
1 sibling, 0 replies; 17+ messages in thread
From: Michal Simek @ 2013-05-29 11:27 UTC (permalink / raw)
To: linux-kernel
Cc: Michal Simek, Michal Simek, Grant Likely, Rob Herring,
Rob Landley, devicetree-discuss, linux-doc
[-- Attachment #1: Type: text/plain, Size: 2154 bytes --]
Describe gpio-xilinx binding.
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
---
.../devicetree/bindings/gpio/gpio-xilinx.txt | 43 ++++++++++++++++++++++
1 file changed, 43 insertions(+)
create mode 100644 Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
diff --git a/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt b/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
new file mode 100644
index 0000000..65bf386
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio-xilinx.txt
@@ -0,0 +1,43 @@
+Xilinx plb/axi GPIO controller
+
+Required properties:
+- compatible : Should be "xlnx,xps-gpio-1.00.a"
+- reg : Address and length of the register set for the device
+- #gpio-cells : Should be two. The first cell is the pin number and the
+ second cell is used to specify optional parameters (currently unused).
+- gpio-controller : Marks the device node as a GPIO controller.
+
+Optional properties:
+- interrupts : Interrupt mapping for GPIO IRQ.
+- interrupt-parent : Phandle for the interrupt controller that
+ services interrupts for this device.
+- xlnx,all-inputs : if n-th bit is setup, GPIO-n is input
+- xlnx,dout-default : if n-th bit is 1, GPIO-n default value is 1
+- xlnx,gpio-width : gpio width
+- xlnx,tri-default : if n-th bit is 1, GPIO-n is in tristate mode
+- xlnx,is-dual : if 1, controller also uses the second channel
+- xlnx,all-inputs-2 : as above but for the second channel
+- xlnx,dout-default-2 : as above but the second channel
+- xlnx,gpio2-width : as above but for the second channel
+- xlnx,tri-default-2 : as above but for the second channel
+
+
+Example:
+gpio: gpio@40000000 {
+ #gpio-cells = <2>;
+ compatible = "xlnx,xps-gpio-1.00.a";
+ gpio-controller ;
+ interrupt-parent = <µblaze_0_intc>;
+ interrupts = < 6 2 >;
+ reg = < 0x40000000 0x10000 >;
+ xlnx,all-inputs = <0x0>;
+ xlnx,all-inputs-2 = <0x0>;
+ xlnx,dout-default = <0x0>;
+ xlnx,dout-default-2 = <0x0>;
+ xlnx,gpio-width = <0x2>;
+ xlnx,gpio2-width = <0x2>;
+ xlnx,interrupt-present = <0x1>;
+ xlnx,is-dual = <0x1>;
+ xlnx,tri-default = <0xffffffff>;
+ xlnx,tri-default-2 = <0xffffffff>;
+} ;
--
1.8.2.3
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply related [flat|nested] 17+ messages in thread[parent not found: <4b90b06fce0475b579cfba4d968b4778359154f6.1369826814.git.michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>]
* Re: [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c
2013-05-29 11:27 [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c Michal Simek
@ 2013-05-30 19:46 ` Linus Walleij
[not found] ` <4b90b06fce0475b579cfba4d968b4778359154f6.1369826814.git.michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
1 sibling, 0 replies; 17+ messages in thread
From: Linus Walleij @ 2013-05-30 19:46 UTC (permalink / raw)
To: Michal Simek
Cc: Grant Likely,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Rob Herring,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
On Wed, May 29, 2013 at 1:27 PM, Michal Simek <michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org> wrote:
> Supporting the second channel in the driver.
> Offset is 0x8 and both channnels share the same
> IRQ.
>
> Signed-off-by: Michal Simek <michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
(...)
> +/* Read/Write access to the GPIO registers */
> +#define xgpio_readreg(offset) __raw_readl(offset)
> +#define xgpio_writereg(offset, val) __raw_writel(val, offset)
So you're swithing in_be32/out_be32 to the CPU-dependent
__raw_readl/__raw_writel functions? Why?
Can you explain exactly why you are using __raw_* accessors
rather than e.g. atleast readl_relaxed()/writel_relaxed()
or even plain readl/writel so you know the writes will hit
the hardware as immediately as possible?
I'd prefer this step to be a separate patch.
> struct xgpio_instance {
> struct of_mm_gpio_chip mmchip;
> u32 gpio_state; /* GPIO state shadow register */
> u32 gpio_dir; /* GPIO direction shadow register */
> + u32 offset;
> spinlock_t gpio_lock; /* Lock used for synchronization */
> };
Why not take this opportunity to move the comments out to
kerneldoc above this struct, plus document what "offset"
means.
> - return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
> + return (xgpio_readreg(regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
Another way would be:
#include <linux/bitops.h>
return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET & BIT(gpio));
> +
> + 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);
This looks like you want to use of_property_read_bool().
Have you documented these new bindings? It doesn't seem so.
Documentation/devicetree/bindings/gpio/*...
If it's undocumented so far, this is a good oppotunity to add it.
> + 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);
This is basically a jam table (hardware set-up) in the device tree.
I don't exactly like this. Is this necessary?
> + /* 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);
Dito.
> + /* 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)
> + chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
Seems fine, but document it in the binding.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c
@ 2013-05-30 19:46 ` Linus Walleij
0 siblings, 0 replies; 17+ messages in thread
From: Linus Walleij @ 2013-05-30 19:46 UTC (permalink / raw)
To: Michal Simek
Cc: linux-kernel@vger.kernel.org, Michal Simek, Grant Likely,
Rob Herring, devicetree-discuss@lists.ozlabs.org
On Wed, May 29, 2013 at 1:27 PM, Michal Simek <michal.simek@xilinx.com> wrote:
> Supporting the second channel in the driver.
> Offset is 0x8 and both channnels share the same
> IRQ.
>
> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
(...)
> +/* Read/Write access to the GPIO registers */
> +#define xgpio_readreg(offset) __raw_readl(offset)
> +#define xgpio_writereg(offset, val) __raw_writel(val, offset)
So you're swithing in_be32/out_be32 to the CPU-dependent
__raw_readl/__raw_writel functions? Why?
Can you explain exactly why you are using __raw_* accessors
rather than e.g. atleast readl_relaxed()/writel_relaxed()
or even plain readl/writel so you know the writes will hit
the hardware as immediately as possible?
I'd prefer this step to be a separate patch.
> struct xgpio_instance {
> struct of_mm_gpio_chip mmchip;
> u32 gpio_state; /* GPIO state shadow register */
> u32 gpio_dir; /* GPIO direction shadow register */
> + u32 offset;
> spinlock_t gpio_lock; /* Lock used for synchronization */
> };
Why not take this opportunity to move the comments out to
kerneldoc above this struct, plus document what "offset"
means.
> - return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
> + return (xgpio_readreg(regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
Another way would be:
#include <linux/bitops.h>
return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET & BIT(gpio));
> +
> + 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);
This looks like you want to use of_property_read_bool().
Have you documented these new bindings? It doesn't seem so.
Documentation/devicetree/bindings/gpio/*...
If it's undocumented so far, this is a good oppotunity to add it.
> + 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);
This is basically a jam table (hardware set-up) in the device tree.
I don't exactly like this. Is this necessary?
> + /* 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);
Dito.
> + /* 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)
> + chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
Seems fine, but document it in the binding.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 17+ messages in thread[parent not found: <CACRpkdY4xaCOe28nu-NrYQ7pafjhj8-xqFcJRF9iJUy3SrCVrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c
2013-05-30 19:46 ` Linus Walleij
@ 2013-05-31 5:43 ` Michal Simek
-1 siblings, 0 replies; 17+ messages in thread
From: Michal Simek @ 2013-05-31 5:43 UTC (permalink / raw)
To: Linus Walleij
Cc: Grant Likely,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
Michal Simek, Rob Herring,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
[-- Attachment #1.1: Type: text/plain, Size: 5591 bytes --]
Hi Linus,
On 05/30/2013 09:46 PM, Linus Walleij wrote:
> On Wed, May 29, 2013 at 1:27 PM, Michal Simek <michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org> wrote:
>
>> Supporting the second channel in the driver.
>> Offset is 0x8 and both channnels share the same
>> IRQ.
>>
>> Signed-off-by: Michal Simek <michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
>
> (...)
>> +/* Read/Write access to the GPIO registers */
>> +#define xgpio_readreg(offset) __raw_readl(offset)
>> +#define xgpio_writereg(offset, val) __raw_writel(val, offset)
>
> So you're swithing in_be32/out_be32 to the CPU-dependent
> __raw_readl/__raw_writel functions? Why?
The reason is that this driver can be used on ARM where in_be32/out_be32
is not implemented.
> Can you explain exactly why you are using __raw_* accessors
> rather than e.g. atleast readl_relaxed()/writel_relaxed()
> or even plain readl/writel so you know the writes will hit
> the hardware as immediately as possible?
Using __raw* function ensure that it is working on all
cpus. Microblaze big/little endian, PPC big endian and ARM little endian.
The correct way how to implement this is based on my previous
discussion to detect endians directly on IP.
But for this gpio case without interrupt connected(it means without
interrupt logic) there are just 2 registers data and tristate
(http://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v1_01_b/ds744_axi_gpio.pdf)
and auto detection can't be done.
> I'd prefer this step to be a separate patch.
ok. Will do based on my discussion around xilinxfb.
>> struct xgpio_instance {
>> struct of_mm_gpio_chip mmchip;
>> u32 gpio_state; /* GPIO state shadow register */
>> u32 gpio_dir; /* GPIO direction shadow register */
>> + u32 offset;
>> spinlock_t gpio_lock; /* Lock used for synchronization */
>> };
>
> Why not take this opportunity to move the comments out to
> kerneldoc above this struct, plus document what "offset"
> means.
Good point. Will fix.
>
>> - return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
>> + return (xgpio_readreg(regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
>
>
> Another way would be:
>
> #include <linux/bitops.h>
>
> return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET & BIT(gpio));
>
>> +
>> + 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);
>
> This looks like you want to use of_property_read_bool().
Ah yeah.
> Have you documented these new bindings? It doesn't seem so.
> Documentation/devicetree/bindings/gpio/*...
>
> If it's undocumented so far, this is a good oppotunity to add it.
Isn't it enough what it is in 2/2?
Or do you want to describe current binding in the first patch
and then extend it in this patch when dual channel is added?
>> + 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);
>
> This is basically a jam table (hardware set-up) in the device tree.
Not sure what you mean by that. Xilinx GPIO is soft IP which can be configured
to different configurations before bitstream is generated.
At the end you will get different setting/addresses setup for every pin
which is described by these xlnx,X descriptions.
> I don't exactly like this. Is this necessary?
If you mean names or values in there that all of them are autogenerated
from design tools and they are reflect IP hardware description and all
configuration options which you can have there.
It means that all these values give you exact hardware description.
Do I answer your question?
>
>> + /* 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);
>
> Dito.
>
>> + /* 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)
>> + chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
>
> Seems fine, but document it in the binding.
I will look at new fdt function to shorten this code to look better.
Thanks for your review,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]
[-- Attachment #2: Type: text/plain, Size: 192 bytes --]
_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c
@ 2013-05-31 5:43 ` Michal Simek
0 siblings, 0 replies; 17+ messages in thread
From: Michal Simek @ 2013-05-31 5:43 UTC (permalink / raw)
To: Linus Walleij
Cc: Michal Simek, linux-kernel@vger.kernel.org, Grant Likely,
Rob Herring, devicetree-discuss@lists.ozlabs.org
[-- Attachment #1: Type: text/plain, Size: 5533 bytes --]
Hi Linus,
On 05/30/2013 09:46 PM, Linus Walleij wrote:
> On Wed, May 29, 2013 at 1:27 PM, Michal Simek <michal.simek@xilinx.com> wrote:
>
>> Supporting the second channel in the driver.
>> Offset is 0x8 and both channnels share the same
>> IRQ.
>>
>> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
>
> (...)
>> +/* Read/Write access to the GPIO registers */
>> +#define xgpio_readreg(offset) __raw_readl(offset)
>> +#define xgpio_writereg(offset, val) __raw_writel(val, offset)
>
> So you're swithing in_be32/out_be32 to the CPU-dependent
> __raw_readl/__raw_writel functions? Why?
The reason is that this driver can be used on ARM where in_be32/out_be32
is not implemented.
> Can you explain exactly why you are using __raw_* accessors
> rather than e.g. atleast readl_relaxed()/writel_relaxed()
> or even plain readl/writel so you know the writes will hit
> the hardware as immediately as possible?
Using __raw* function ensure that it is working on all
cpus. Microblaze big/little endian, PPC big endian and ARM little endian.
The correct way how to implement this is based on my previous
discussion to detect endians directly on IP.
But for this gpio case without interrupt connected(it means without
interrupt logic) there are just 2 registers data and tristate
(http://www.xilinx.com/support/documentation/ip_documentation/axi_gpio/v1_01_b/ds744_axi_gpio.pdf)
and auto detection can't be done.
> I'd prefer this step to be a separate patch.
ok. Will do based on my discussion around xilinxfb.
>> struct xgpio_instance {
>> struct of_mm_gpio_chip mmchip;
>> u32 gpio_state; /* GPIO state shadow register */
>> u32 gpio_dir; /* GPIO direction shadow register */
>> + u32 offset;
>> spinlock_t gpio_lock; /* Lock used for synchronization */
>> };
>
> Why not take this opportunity to move the comments out to
> kerneldoc above this struct, plus document what "offset"
> means.
Good point. Will fix.
>
>> - return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
>> + return (xgpio_readreg(regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
>
>
> Another way would be:
>
> #include <linux/bitops.h>
>
> return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET & BIT(gpio));
>
>> +
>> + 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);
>
> This looks like you want to use of_property_read_bool().
Ah yeah.
> Have you documented these new bindings? It doesn't seem so.
> Documentation/devicetree/bindings/gpio/*...
>
> If it's undocumented so far, this is a good oppotunity to add it.
Isn't it enough what it is in 2/2?
Or do you want to describe current binding in the first patch
and then extend it in this patch when dual channel is added?
>> + 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);
>
> This is basically a jam table (hardware set-up) in the device tree.
Not sure what you mean by that. Xilinx GPIO is soft IP which can be configured
to different configurations before bitstream is generated.
At the end you will get different setting/addresses setup for every pin
which is described by these xlnx,X descriptions.
> I don't exactly like this. Is this necessary?
If you mean names or values in there that all of them are autogenerated
from design tools and they are reflect IP hardware description and all
configuration options which you can have there.
It means that all these values give you exact hardware description.
Do I answer your question?
>
>> + /* 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);
>
> Dito.
>
>> + /* 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)
>> + chip->mmchip.gc.ngpio = be32_to_cpup(tree_info);
>
> Seems fine, but document it in the binding.
I will look at new fdt function to shorten this code to look better.
Thanks for your review,
Michal
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 263 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread* Re: [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c
2013-05-31 5:43 ` Michal Simek
(?)
@ 2013-05-31 7:14 ` Linus Walleij
[not found] ` <CACRpkdbHiaK6YPgXyxNgEeZxAsddK4x0vS-q3YfyXnj_BgHvuw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
-1 siblings, 1 reply; 17+ messages in thread
From: Linus Walleij @ 2013-05-31 7:14 UTC (permalink / raw)
To: Michal Simek
Cc: Michal Simek, linux-kernel@vger.kernel.org, Grant Likely,
Rob Herring, devicetree-discuss@lists.ozlabs.org
On Fri, May 31, 2013 at 7:43 AM, Michal Simek <monstr@monstr.eu> wrote:
> On 05/30/2013 09:46 PM, Linus Walleij wrote:
>> (...)
>>> +/* Read/Write access to the GPIO registers */
>>> +#define xgpio_readreg(offset) __raw_readl(offset)
>>> +#define xgpio_writereg(offset, val) __raw_writel(val, offset)
>>
>> So you're swithing in_be32/out_be32 to the CPU-dependent
>> __raw_readl/__raw_writel functions? Why?
>
> The reason is that this driver can be used on ARM where in_be32/out_be32
> is not implemented.
OK I buy this (and the following explanation).
I think readl/writel is always in LE (PCI) endianness anyway, which
is likely not what you want. (I suspect the next point was about
that.)
>> Have you documented these new bindings? It doesn't seem so.
>> Documentation/devicetree/bindings/gpio/*...
>>
>> If it's undocumented so far, this is a good oppotunity to add it.
>
> Isn't it enough what it is in 2/2?
I didn't see 2/2, I guess I wasn't on CC...
Anyway I guess it's this:
http://marc.info/?l=linux-kernel&m=136982686732560&w=2
It's OK, but fix the boolean member so as to just needing to
be present:
xlnx,is-dual;
Rather than
xlnx,is-dual = <1>;
> Or do you want to describe current binding in the first patch
> and then extend it in this patch when dual channel is added?
Nah. 2/2 is fine.
>> This is basically a jam table (hardware set-up) in the device tree.
>
> Not sure what you mean by that. Xilinx GPIO is soft IP which can be configured
> to different configurations before bitstream is generated.
> At the end you will get different setting/addresses setup for every pin
> which is described by these xlnx,X descriptions.
>
>> I don't exactly like this. Is this necessary?
>
> If you mean names or values in there that all of them are autogenerated
> from design tools and they are reflect IP hardware description and all
> configuration options which you can have there.
> It means that all these values give you exact hardware description.
>
> Do I answer your question?
Yes, this is OK, I buy that explanation. I thought it was
something else.
I think the overall problem is that I do not understand what a
"channel" is in this context, and thus it is hard to understand the
patch as a whole. 2/2 could add some more verbose explanation
about the HW IP so I get comfortable and can understand the
whole hardware block...
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2013-06-24 10:01 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-29 11:27 [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c Michal Simek
2013-05-29 11:27 ` [PATCH 2/2] DT: Add documentation for gpio-xilinx Michal Simek
[not found] ` <4b90b06fce0475b579cfba4d968b4778359154f6.1369826814.git.michal.simek-gjFFaj9aHVfQT0dZR+AlfA@public.gmane.org>
2013-05-30 19:46 ` [PATCH 1/2] GPIO: Add support for dual channel in gpio-xilinx.c Linus Walleij
2013-05-30 19:46 ` Linus Walleij
[not found] ` <CACRpkdY4xaCOe28nu-NrYQ7pafjhj8-xqFcJRF9iJUy3SrCVrA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-05-31 5:43 ` Michal Simek
2013-05-31 5:43 ` Michal Simek
2013-05-31 7:14 ` Linus Walleij
[not found] ` <CACRpkdbHiaK6YPgXyxNgEeZxAsddK4x0vS-q3YfyXnj_BgHvuw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-05-31 7:34 ` Michal Simek
2013-05-31 7:34 ` Michal Simek
2013-06-17 5:29 ` Linus Walleij
2013-06-20 7:51 ` Michal Simek
2013-06-20 9:23 ` Linus Walleij
[not found] ` <CACRpkdbWXFLgcUJ-gcUArRotJMoX4JBU9mmheooJBWsLR=QHOA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2013-06-20 10:59 ` Michal Simek
2013-06-20 10:59 ` Michal Simek
2013-06-20 11:33 ` Linus Walleij
2013-06-20 12:12 ` Michal Simek
2013-06-24 10:01 ` Linus Walleij
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.