On Fri, Oct 24, 2008 at 1:59 PM, John Linn <[EMAIL PROTECTED]> wrote:
> This driver supports the Xilinx XPS GPIO IP core which has the typical
> GPIO features.
>
> Signed-off-by: Kiran Sutariya <[EMAIL PROTECTED]>
> Signed-off-by: John Linn <[EMAIL PROTECTED]>

Acked-by: Grant Likely <[EMAIL PROTECTED]>

> ---
>  drivers/gpio/Kconfig       |    8 ++
>  drivers/gpio/Makefile      |    1 +
>  drivers/gpio/xilinx_gpio.c |  240 
> ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 249 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/gpio/xilinx_gpio.c
>
> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
> index 7f2ee27..f6b0da8 100644
> --- a/drivers/gpio/Kconfig
> +++ b/drivers/gpio/Kconfig
> @@ -65,6 +65,14 @@ config GPIO_SYSFS
>
>  # put expanders in the right section, in alphabetical order
>
> +comment "Memory mapped GPIO expanders:"
> +
> +config GPIO_XILINX
> +       bool "Xilinx GPIO support"
> +       depends on OF
> +       help
> +         Say yes here to support the Xilinx FPGA GPIO device
> +
>  comment "I2C GPIO expanders:"
>
>  config GPIO_MAX732X
> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
> index 6aafdeb..49ac64e 100644
> --- a/drivers/gpio/Makefile
> +++ b/drivers/gpio/Makefile
> @@ -10,4 +10,5 @@ obj-$(CONFIG_GPIO_MCP23S08)   += mcp23s08.o
>  obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
>  obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
>  obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
> +obj-$(CONFIG_GPIO_XILINX)      += xilinx_gpio.o
>  obj-$(CONFIG_GPIO_BT8XX)       += bt8xxgpio.o
> diff --git a/drivers/gpio/xilinx_gpio.c b/drivers/gpio/xilinx_gpio.c
> new file mode 100644
> index 0000000..224d0d5
> --- /dev/null
> +++ b/drivers/gpio/xilinx_gpio.c
> @@ -0,0 +1,240 @@
> +/*
> + * Xilinx gpio driver
> + *
> + * Copyright 2008 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
> + * as published by the Free Software Foundation.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_gpio.h>
> +#include <linux/io.h>
> +#include <linux/gpio.h>
> +
> +/* Register Offset Definitions */
> +#define XGPIO_DATA_OFFSET   (0x0)      /* Data register  */
> +#define XGPIO_TRI_OFFSET    (0x4)      /* I/O direction register  */
> +
> +struct xgpio_instance {
> +       struct of_mm_gpio_chip mmchip;
> +       u32 gpio_state;         /* GPIO state shadow register */
> +       u32 gpio_dir;           /* GPIO direction shadow register */
> +       spinlock_t gpio_lock;   /* Lock used for synchronization */
> +};
> +
> +/**
> + * xgpio_get - Read the specified signal of the GPIO device.
> + * @gc:     Pointer to gpio_chip device structure.
> + * @gpio:   GPIO signal number.
> + *
> + * This function reads the specified signal of the GPIO device. It returns 0 
> if
> + * the signal clear, 1 if signal is set or negative value on error.
> + */
> +static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
> +{
> +       struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
> +
> +       return (in_be32(mm_gc->regs + XGPIO_DATA_OFFSET) >> gpio) & 1;
> +}
> +
> +/**
> + * xgpio_set - Write the specified signal of the GPIO device.
> + * @gc:     Pointer to gpio_chip device structure.
> + * @gpio:   GPIO signal number.
> + * @val:    Value to be written to specified signal.
> + *
> + * This function writes the specified value in to the specified signal of the
> + * GPIO device.
> + */
> +static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
> +{
> +       unsigned long flags;
> +       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);
> +
> +       spin_lock_irqsave(&chip->gpio_lock, flags);
> +
> +       /* Write to GPIO signal and set its direction to output */
> +       if (val)
> +               chip->gpio_state |= 1 << gpio;
> +       else
> +               chip->gpio_state &= ~(1 << gpio);
> +       out_be32(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state);
> +
> +       spin_unlock_irqrestore(&chip->gpio_lock, flags);
> +}
> +
> +/**
> + * xgpio_dir_in - Set the direction of the specified GPIO signal as input.
> + * @gc:     Pointer to gpio_chip device structure.
> + * @gpio:   GPIO signal number.
> + *
> + * This function sets the direction of specified GPIO signal as input.
> + * It returns 0 if direction of GPIO signals is set as input otherwise it
> + * returns negative error value.
> + */
> +static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
> +{
> +       unsigned long flags;
> +       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);
> +
> +       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);
> +
> +       spin_unlock_irqrestore(&chip->gpio_lock, flags);
> +
> +       return 0;
> +}
> +
> +/**
> + * xgpio_dir_out - Set the direction of the specified GPIO signal as output.
> + * @gc:     Pointer to gpio_chip device structure.
> + * @gpio:   GPIO signal number.
> + * @val:    Value to be written to specified signal.
> + *
> + * This function sets the direction of specified GPIO signal as output. If 
> all
> + * GPIO signals of GPIO chip is configured as input then it returns
> + * error otherwise it returns 0.
> + */
> +static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
> +{
> +       unsigned long flags;
> +       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);
> +
> +       spin_lock_irqsave(&chip->gpio_lock, flags);
> +
> +       /* Write state of GPIO signal */
> +       if (val)
> +               chip->gpio_state |= 1 << gpio;
> +       else
> +               chip->gpio_state &= ~(1 << gpio);
> +       out_be32(mm_gc->regs + 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);
> +
> +       spin_unlock_irqrestore(&chip->gpio_lock, flags);
> +
> +       return 0;
> +}
> +
> +/**
> + * xgpio_of_probe - Probe method for the GPIO device.
> + * @of_dev: pointer to OF device structure.
> + * @match:  pointer to the structure used for matching a device.
> + *
> + * This function probes the GPIO device in the device tree. It initializes 
> the
> + * driver data structure. It returns 0, if the driver is bound to the GPIO
> + * device, or a negative value if there is an error.
> + */
> +static int __devinit xgpio_of_probe(struct of_device *ofdev,
> +                                   const struct of_device_id *match)
> +{
> +       struct xgpio_instance *chip;
> +       struct of_gpio_chip *ofchip;
> +       int status = 0;
> +       const u32 *tree_info;
> +
> +       chip = kzalloc(sizeof(*chip), GFP_KERNEL);
> +       if (!chip)
> +               return -ENOMEM;
> +       ofchip = &chip->mmchip.of_gc;
> +
> +       /* Update GPIO state shadow register with default value */
> +       tree_info = of_get_property(ofdev->node, "xlnx,dout-default", NULL);
> +       if (tree_info)
> +               chip->gpio_state = *tree_info;
> +
> +       /* Update GPIO direction shadow register with default value */
> +       chip->gpio_dir = 0xFFFFFFFF; /* By default, all pins are inputs */
> +       tree_info = of_get_property(ofdev->node, "xlnx,tri-default", NULL);
> +       if (tree_info)
> +               chip->gpio_dir = *tree_info;
> +
> +       /* Check device node and parent device node for device width */
> +       ofchip->gc.ngpio = 32; /* By default assume full GPIO controller */
> +       tree_info = of_get_property(ofdev->node, "xlnx,gpio-width", NULL);
> +       if (!tree_info)
> +               tree_info = of_get_property(ofdev->node->parent,
> +                                           "xlnx,gpio-width", NULL);
> +       if (tree_info)
> +               ofchip->gc.ngpio = *tree_info;
> +
> +       spin_lock_init(&chip->gpio_lock);
> +
> +       ofchip->gpio_cells = 2;
> +       ofchip->gc.direction_input = xgpio_dir_in;
> +       ofchip->gc.direction_output = xgpio_dir_out;
> +       ofchip->gc.get = xgpio_get;
> +       ofchip->gc.set = xgpio_set;
> +
> +       /* Call the OF gpio helper to setup and register the GPIO device */
> +       status = of_mm_gpiochip_add(ofdev->node, &chip->mmchip);
> +       if (status) {
> +               kfree(chip);
> +               dev_err(&ofdev->dev, "Error in probe function error value 
> %d\n",
> +                       status);
> +               return status;
> +       }
> +
> +       /* Finally, write the initial state to the device */
> +       out_be32(chip->mmchip.regs + XGPIO_DATA_OFFSET, chip->gpio_state);
> +       out_be32(chip->mmchip.regs + XGPIO_TRI_OFFSET, chip->gpio_dir);
> +
> +       dev_info(&ofdev->dev, "registered Xilinx GPIO controller\n");
> +       return 0;
> +}
> +
> +/**
> + * xgpio_of_remove - Remove method for the GPIO device.
> + * @of_dev: pointer to OF device structure.
> + *
> + * This function returns a negative error as we cannot unregister GPIO chips.
> + */
> +static int __devexit xgpio_of_remove(struct of_device *ofdev)
> +{
> +       return -EBUSY;
> +}
> +
> +static struct of_device_id xgpio_of_match[] __devinitdata = {
> +       { .compatible = "xlnx,xps-gpio-1.00.a", },
> +       { /* end of list */ },
> +};
> +
> +MODULE_DEVICE_TABLE(of, xgpio_of_match);
> +
> +static struct of_platform_driver xgpio_of_driver = {
> +       .name = "xilinx_gpio",
> +       .match_table = xgpio_of_match,
> +       .probe = xgpio_of_probe,
> +       .remove = __devexit_p(xgpio_of_remove),
> +};
> +
> +static int __init xgpio_init(void)
> +{
> +       return of_register_platform_driver(&xgpio_of_driver);
> +}
> +
> +/* Make sure we get initialized before anyone else tries to use us */
> +subsys_initcall(xgpio_init);
> +/* No exit call at the moment as we cannot unregister of GPIO chips */
> +
> +MODULE_AUTHOR("Xilinx, Inc.");
> +MODULE_DESCRIPTION("Xilinx GPIO driver");
> +MODULE_LICENSE("GPL");
> --
> 1.5.2.1
>
>
>
> This email and any attachments are intended for the sole use of the named 
> recipient(s) and contain(s) confidential information that may be proprietary, 
> privileged or copyrighted under applicable law. If you are not the intended 
> recipient, do not read, copy, or forward this email message or any 
> attachments. Delete this email message and any attachments immediately.
>
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to