
On 04/27/2013 05:45 PM, Simon Glass wrote:
Hi Michal,
On Wed, Apr 24, 2013 at 1:27 AM, Michal Simek michal.simek@xilinx.com wrote:
Microblaze uses gpio which is connected to the system reset. Currently gpio subsystem wasn't used for it.
Add gpio driver and change Microblaze reset logic to be done via gpio subsystem.
There are various configurations which Microblaze can have that's why gpio_alloc/gpio_alloc_dual(for dual channel) function has been introduced and gpio can be allocated dynamically.
Adding several gpios IP is also possible and supported.
For listing gpio configuration please use "gpio status" command
Signed-off-by: Michal Simek michal.simek@xilinx.com
arch/microblaze/include/asm/gpio.h | 50 +--- .../xilinx/microblaze-generic/microblaze-generic.c | 17 +- drivers/gpio/Makefile | 1 + drivers/gpio/xilinx_gpio.c | 323 +++++++++++++++++++++ include/configs/microblaze-generic.h | 3 +- 5 files changed, 353 insertions(+), 41 deletions(-) create mode 100644 drivers/gpio/xilinx_gpio.c
diff --git a/arch/microblaze/include/asm/gpio.h b/arch/microblaze/include/asm/gpio.h index 883f4d4..69df8c5 100644 --- a/arch/microblaze/include/asm/gpio.h +++ b/arch/microblaze/include/asm/gpio.h @@ -1,41 +1,21 @@ #ifndef _ASM_MICROBLAZE_GPIO_H_ #define _ASM_MICROBLAZE_GPIO_H_
-#include <asm/io.h> +/* Allocation functions */ +extern int gpio_alloc_dual(u32 baseaddr, const char *name, u32 gpio_no0,
u32 gpio_no1);
+extern int gpio_alloc(u32 baseaddr, const char *name, u32 gpio_no);
+/* Standard functions */ +extern int gpio_request(unsigned gpio, const char *label); +extern int gpio_free(unsigned gpio); +extern int gpio_direction_input(unsigned gpio); +extern int gpio_direction_output(unsigned gpio, int value); +extern int gpio_get_value(unsigned gpio); +extern int gpio_set_value(unsigned gpio, int value); +extern int gpio_is_valid(int number);
You should just be able to include <asm-generic/gpio.h> for these.
Thanks for pointing to this.
+/* Get gpio pin name if used/setup */ +static char *get_name(unsigned gpio) +{
u32 gpio_priv;
debug("%s\n", __func__);
struct xilinx_gpio_priv *priv = gpio_get_controller(gpio);
It looks like gpio_get_controller() can return NULL, but you use it anyway?
yep. I have fixed that return path if gpio_get_controller returns NULL.
+int gpio_alloc(u32 baseaddr, const char *name, u32 gpio_no) +{
struct xilinx_gpio_priv *priv;
priv = calloc(1, sizeof(struct xilinx_gpio_priv));
/* Setup gpio name */
if (name != NULL) {
strncpy(priv->name, name, GPIO_NAME_SIZE);
priv->name[GPIO_NAME_SIZE - 1] = '\0';
}
priv->regs = (struct gpio_regs *)baseaddr;
priv->gpio_min = xilinx_gpio_max;
xilinx_gpio_max = priv->gpio_min + gpio_no;
priv->gpio_max = xilinx_gpio_max - 1;
priv->gpio_name = calloc(gpio_no, sizeof(struct gpio_names));
INIT_LIST_HEAD(&priv->list);
list_add_tail(&priv->list, &gpio_list);
printf("%s: Add %s (%d-%d)\n", __func__, name,
priv->gpio_min, priv->gpio_max);
/* Return the first gpio allocated for this device */
return priv->gpio_min;
+}
In terms of allocation, is this function intended to tell the GPIO driver that there are new GPIOs available?
yep. That was my intention. Just call it from board file to tell there are new gpios.
For device tree the GPIO banks can be split into individual nodes each with the same compatible string. Then during device init you can build a table of available GPIOs. Each bank gets a phandle so that it can be used elsewhere. For example you might do:
gpio-controllers { gpa: gpio-a { compatible = "xilinx,gpio-controller"; reg = <some_address size>; }; gpb: gpio-b { compatible = "xilinx,gpio-controller"; reg = <some_address size>; }; };
example-peripheral { gpios = <&gpa 5 ...>, <&gpb 6 ...>; };
The exact binding of GPIOs is up to you - use the same one as Linux if you have one there.
yep. I have designed these functions based on device-tree description and to be able to use it for binding.
In general while loop over dts with compatible string to call this gpio_alloc or gpio_alloc_dual based on properties.
Thanks, Michal