Signed-off-by: Marek Vasut <ma...@denx.de>
---
 arch/sandbox/lib/board.c    |    6 +
 drivers/gpio/Makefile       |    2 +
 drivers/gpio/core.c         |  365 +++++++++++++++++++++++++++++++++++++++++++
 drivers/gpio/sandbox.c      |   58 ++++++-
 include/asm-generic/gpio.h  |   19 +++
 include/configs/sandbox.h   |    2 +
 include/dm/core_numbering.h |    1 +
 7 files changed, 447 insertions(+), 6 deletions(-)
 create mode 100644 drivers/gpio/core.c

diff --git a/arch/sandbox/lib/board.c b/arch/sandbox/lib/board.c
index b6b3768..c79cc62 100644
--- a/arch/sandbox/lib/board.c
+++ b/arch/sandbox/lib/board.c
@@ -239,6 +239,11 @@ void board_init_r(gd_t *id, ulong dest_addr)
                .name = "demo_drv",
                .platform_data = NULL
        };
+       static const struct driver_info gs_info = {
+               .name = "gpio_sandbox",
+               .platform_data = NULL
+       };
+
        struct instance *root = get_root_instance();
        struct instance *demo1, *demo2, *demo3;
        demo1 = driver_bind(root, &info);
@@ -248,6 +253,7 @@ void board_init_r(gd_t *id, ulong dest_addr)
                        demo2 = driver_bind(demo1, &info);
                                demo3 = driver_bind(demo2, &info);
        driver_bind(demo2, &info);
+       driver_bind(root, &gs_info);
 
        demo_hello(demo2);
 
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4b99b85..1d3aa02 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -25,6 +25,8 @@ include $(TOPDIR)/config.mk
 
 LIB    := $(obj)libgpio.o
 
+COBJS-$(CONFIG_DM)             += core.o
+
 COBJS-$(CONFIG_AT91_GPIO)      += at91_gpio.o
 COBJS-$(CONFIG_KIRKWOOD_GPIO)  += kw_gpio.o
 COBJS-$(CONFIG_MARVELL_GPIO)   += mvgpio.o
diff --git a/drivers/gpio/core.c b/drivers/gpio/core.c
new file mode 100644
index 0000000..8fd83b5
--- /dev/null
+++ b/drivers/gpio/core.c
@@ -0,0 +1,365 @@
+#include <common.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <dm/manager.h>
+#include <linux/list.h>
+
+/*
+ * The idea here is to have GPIOs numbered like this from user point of view:
+ *
+ * 32             24 23            16 15                             0
+ * [ GPIO block ID ] [ GPIO chip ID ] [ GPIO ID within the GPIO chip ]
+ *
+ */
+
+#define GPIO_TO_BLOCK_ID(x)    (((x) >> 24) & 0xff)
+#define GPIO_TO_CHIP_ID(x)     (((x) >> 16) & 0xff)
+#define GPIO_TO_CHIP_OFFSET(x) ((x) & 0xffff)
+
+struct gpio_core_entry {
+       struct list_head        list;
+       struct instance         *instance;
+       struct dm_gpio_ops      *ops;
+       int                     id;
+};
+
+/**
+ * gpio_to_entry() - Convert GPIO number to entry in the list
+ * gpio:       The numeric representation of the GPIO
+ *
+ * Convert the GPIO number to an entry in the list of GPIOs
+ * or GPIO blocks registered with the GPIO controller. Returns
+ * entry on success, NULL on error.
+ */
+static struct gpio_core_entry *gpio_to_entry(unsigned gpio)
+{
+       uint8_t block = GPIO_TO_BLOCK_ID(gpio);
+       uint8_t chip = GPIO_TO_CHIP_ID(gpio);
+       uint8_t offset = GPIO_TO_CHIP_OFFSET(gpio);
+       struct core_instance *core = get_core_instance(CORE_GPIO);
+       struct gpio_core_entry *tmp, *ret = NULL;
+
+       list_for_each_entry(tmp, &core->succ, list) {
+               if (tmp->id != block)
+                       continue;
+               if (tmp->ops->base != chip)
+                       continue;
+               if (tmp->ops->ngpio < offset)
+                       return NULL;
+               else {
+                       ret = tmp;
+                       break;
+               }
+       }
+
+       if (ret)
+               driver_activate(ret->instance);
+
+       return ret;
+}
+
+/**
+ * gpio_request() - [COMPAT] Request GPIO
+ * gpio:       GPIO number
+ * label:      Name for the requested GPIO
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_request(unsigned gpio, const char *label)
+{
+       struct gpio_core_entry *e = gpio_to_entry(gpio);
+       if (!e)
+               return -EINVAL;
+
+       return e->ops->gpio_request(gpio, label);
+}
+
+/**
+ * gpio_free() - [COMPAT] Relinquish GPIO
+ * gpio:       GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_free(unsigned gpio)
+{
+       struct gpio_core_entry *e = gpio_to_entry(gpio);
+       if (!e)
+               return -EINVAL;
+
+       return e->ops->gpio_free(gpio);
+}
+
+/**
+ * gpio_direction_input() - [COMPAT] Set GPIO direction to input
+ * gpio:       GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_direction_input(unsigned gpio)
+{
+       struct gpio_core_entry *e = gpio_to_entry(gpio);
+       if (!e)
+               return -EINVAL;
+
+       return e->ops->gpio_direction_input(gpio);
+}
+
+/**
+ * gpio_direction_output() - [COMPAT] Set GPIO direction to output and set 
value
+ * gpio:       GPIO number
+ * value:      Logical value to be set on the GPIO pin
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_direction_output(unsigned gpio, int value)
+{
+       struct gpio_core_entry *e = gpio_to_entry(gpio);
+       if (!e)
+               return -EINVAL;
+
+       return e->ops->gpio_direction_output(gpio, value);
+}
+
+/**
+ * gpio_get_value() - [COMPAT] Sample GPIO pin and return it's value
+ * gpio:       GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns the value of the GPIO pin, or negative value
+ * on error.
+ */
+int gpio_get_value(unsigned gpio)
+{
+       struct gpio_core_entry *e = gpio_to_entry(gpio);
+       if (!e)
+               return -EINVAL;
+
+       return e->ops->gpio_get_value(gpio);
+}
+
+/**
+ * gpio_set_value() - [COMPAT] Configure logical value on GPIO pin
+ * gpio:       GPIO number
+ * value:      Logical value to be set on the GPIO pin.
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_set_value(unsigned gpio, int value)
+{
+       struct gpio_core_entry *e = gpio_to_entry(gpio);
+       if (!e)
+               return -EINVAL;
+
+       return e->ops->gpio_set_value(gpio, value);
+}
+
+/**
+ * gpio_core_init() - Initialize the GPIO core
+ * core:       Instance of the GPIO core
+ *
+ * This function does the initial configuration of the GPIO core's
+ * internal structures. Returns 0 always.
+ */
+static int gpio_core_init(struct core_instance *core)
+{
+       INIT_LIST_HEAD(&core->succ);
+       core->private_data = NULL;
+
+       return 0;
+}
+
+/**
+ * gpio_core_reloc() - Relocate the GPIO core
+ * new:                New instance of the GPIO core
+ * old:                Old instance of the GPIO core
+ *
+ * This function relocates the GPIO core.
+ * FIXME: Implement this.
+ */
+static int gpio_core_reloc(struct core_instance *new, struct core_instance 
*old)
+{
+       return 0;       /* FIXME */
+}
+
+/**
+ * gpio_core_destroy() - Stop the GPIO core
+ * core:       Instance of the GPIO core
+ *
+ * This function stops the GPIO core operation and disconnects all drivers from
+ * it. Returns 0 always.
+ */
+static int gpio_core_destroy(struct core_instance *core)
+{
+       struct gpio_core_entry *tmp, *n;
+
+       list_for_each_entry_safe(tmp, n, &core->succ, list) {
+               list_del(&tmp->list);
+               free(tmp);
+       }
+
+       return 0;
+}
+
+/**
+ * gpio_core_get_count() - Return number of drivers connected to GPIO core
+ * core:       Instance of the GPIO core
+ *
+ * This function counts the number of driver instances associated with the
+ * GPIO core and returns this number.
+ */
+static int gpio_core_get_count(struct core_instance *core)
+{
+       struct gpio_core_entry *tmp;
+       int i = 0;
+
+       list_for_each_entry(tmp, &core->succ, list)
+               i++;
+
+       return i;
+}
+
+/**
+ * gpio_core_get_count() - Return n-th driver connected to GPIO core
+ * core:       Instance of the GPIO core
+ * idx:                Index of the driver
+ *
+ * This function returns the idx-th driver instance associated with the GPIO
+ * core. Returns the instance on success, NULL on error.
+ */
+static struct instance *gpio_core_get_child(struct core_instance *core, int 
idx)
+{
+       struct gpio_core_entry *tmp;
+       int i = 0;
+
+       list_for_each_entry(tmp, &core->succ, list) {
+               if (i == idx)
+                       return tmp->instance;
+               i++;
+       }
+
+       return NULL;
+}
+
+/**
+ * gpio_core_bind() - Bind instance of a driver to a GPIO core
+ * core:       Instance of the GPIO core
+ * dev:                Instance of the driver
+ * ops:                Operations supplied by this driver, struct dm_gpio_ops *
+ * data:       Auxiliary data, must be NULL for GPIO core
+ *
+ * This function binds a driver with a GPIO core. The driver is inserted into
+ * the list of driver instances the GPIO core tracks, so the GPIO core is aware
+ * of the driver. The driver instance is not yet activated.
+ *
+ * Returns 0 on success, negative value on error.
+ */
+static int gpio_core_bind(struct core_instance *core, struct instance *dev,
+                       void *ops, void *data)
+{
+       struct gpio_core_entry *new, *tmp, *last = NULL;
+
+       if (data || !ops)
+               return -EINVAL;
+
+       new = malloc(sizeof(*new));
+       if (!new)
+               return -ENOMEM;
+
+       new->instance = dev;
+       new->ops = ops;
+
+       list_for_each_entry(tmp, &core->succ, list) {
+               if (tmp->instance == dev)
+                       last = tmp;
+       }
+
+       if (!last) {
+               if (list_empty(&core->succ)) {
+                       new->id = 0;
+               } else {
+                       tmp = list_entry(core->succ.prev,
+                                       struct gpio_core_entry, list);
+                       new->id = tmp->id + 1;
+               }
+       } else {
+               tmp = list_entry(&last->list, struct gpio_core_entry, list);
+               new->id = tmp->id;
+       }
+
+       list_add_tail(&new->list, &core->succ);
+
+       return 0;
+}
+
+/**
+ * gpio_core_unbind() - Unbind instance of a driver from a GPIO core
+ * core:       Instance of the GPIO core
+ * dev:                Instance of the driver
+ *
+ * This function unbinds a driver from a GPIO core. The driver is removed from
+ * the list of driver instances the GPIO core tracks, so the GPIO core is no
+ * longer aware of the driver. The driver instance is not deactivated.
+ *
+ * Returns 0 always.
+ */
+static int gpio_core_unbind(struct core_instance *core, struct instance *dev)
+{
+       struct gpio_core_entry *tmp, *n;
+
+       list_for_each_entry_safe(tmp, n, &core->succ, list) {
+               if (tmp->instance == dev) {
+                       list_del(&tmp->list);
+                       free(tmp);
+               }
+       }
+
+       return 0;
+}
+
+/**
+ * gpio_core_replace() - Find and replace instance of a driver in the list
+ * core:       Instance of the GPIO core
+ * new:                New instance of the driver, post relocation one
+ * old:                Old instance of the driver, pre relocation one
+ *
+ * This function replaces pointers to pre-relocation driver instances in the
+ * core's list of drivers with pointers to post-relocation driver instances.
+ * Returns 0 on success, negative value on error.
+ */
+static int gpio_core_replace(struct core_instance *core, struct instance *new,
+                                               struct instance *old)
+{
+       struct gpio_core_entry *tmp;
+
+       if (!core || !new || !old)
+               return -EINVAL;
+
+       list_for_each_entry(tmp, &core->succ, list) {
+               if (tmp->instance != old)
+                       continue;
+               tmp->instance = new;
+       }
+
+       return 0;
+}
+
+U_BOOT_CORE(CORE_GPIO,
+       gpio_core_init,
+       gpio_core_reloc,
+       gpio_core_destroy,
+       gpio_core_get_count,
+       gpio_core_get_child,
+       gpio_core_bind,
+       gpio_core_unbind,
+       gpio_core_replace);
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 19d2db0..89ecdc5 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -21,6 +21,7 @@
 
 #include <common.h>
 #include <asm/gpio.h>
+#include <dm/manager.h>
 
 /* Flags for each GPIO */
 #define GPIOF_OUTPUT   (1 << 0)        /* Currently set as an output */
@@ -111,7 +112,7 @@ int sandbox_gpio_set_direction(unsigned gp, int output)
  */
 
 /* set GPIO port 'gp' as an input */
-int gpio_direction_input(unsigned gp)
+static int sb_gpio_direction_input(unsigned gp)
 {
        debug("%s: gp:%u\n", __func__, gp);
 
@@ -122,7 +123,7 @@ int gpio_direction_input(unsigned gp)
 }
 
 /* set GPIO port 'gp' as an output, with polarity 'value' */
-int gpio_direction_output(unsigned gp, int value)
+static int sb_gpio_direction_output(unsigned gp, int value)
 {
        debug("%s: gp:%u, value = %d\n", __func__, gp, value);
 
@@ -134,7 +135,7 @@ int gpio_direction_output(unsigned gp, int value)
 }
 
 /* read GPIO IN value of port 'gp' */
-int gpio_get_value(unsigned gp)
+static int sb_gpio_get_value(unsigned gp)
 {
        debug("%s: gp:%u\n", __func__, gp);
 
@@ -145,7 +146,7 @@ int gpio_get_value(unsigned gp)
 }
 
 /* write GPIO OUT value to port 'gp' */
-int gpio_set_value(unsigned gp, int value)
+static int sb_gpio_set_value(unsigned gp, int value)
 {
        debug("%s: gp:%u, value = %d\n", __func__, gp, value);
 
@@ -160,7 +161,7 @@ int gpio_set_value(unsigned gp, int value)
        return sandbox_gpio_set_value(gp, value);
 }
 
-int gpio_request(unsigned gp, const char *label)
+static int sb_gpio_request(unsigned gp, const char *label)
 {
        debug("%s: gp:%u, label:%s\n", __func__, gp, label);
 
@@ -178,7 +179,7 @@ int gpio_request(unsigned gp, const char *label)
        return set_gpio_flag(gp, GPIOF_RESERVED, 1);
 }
 
-int gpio_free(unsigned gp)
+static int sb_gpio_free(unsigned gp)
 {
        debug("%s: gp:%u\n", __func__, gp);
 
@@ -207,3 +208,48 @@ void gpio_info(void)
                        label ? label : "");
        }
 }
+
+#ifdef CONFIG_DM
+static struct dm_gpio_ops gpio_sandbox_ops = {
+       .base                   = 0,
+       .ngpio                  = CONFIG_SANDBOX_GPIO_COUNT,
+       .gpio_request           = sb_gpio_request,
+       .gpio_free              = sb_gpio_free,
+       .gpio_direction_input   = sb_gpio_direction_input,
+       .gpio_direction_output  = sb_gpio_direction_output,
+       .gpio_get_value         = sb_gpio_get_value,
+       .gpio_set_value         = sb_gpio_set_value,
+};
+
+static int gpio_sandbox_bind(struct instance *dev)
+{
+       return core_bind(CORE_GPIO, dev, &gpio_sandbox_ops, NULL);
+}
+
+static int gpio_sandbox_probe(struct instance *dev)
+{
+       return 0;
+}
+
+static int gpio_sandbox_reloc(struct instance *new, struct instance *old)
+{
+       return 0;
+}
+
+static int gpio_sandbox_remove(struct instance *dev)
+{
+       return 0;
+}
+
+static int gpio_sandbox_unbind(struct instance *dev)
+{
+       return core_unbind(CORE_GPIO, dev);
+}
+
+U_BOOT_DRIVER(gpio_sandbox,
+       gpio_sandbox_bind,
+       gpio_sandbox_probe,
+       gpio_sandbox_reloc,
+       gpio_sandbox_remove,
+       gpio_sandbox_unbind);
+#endif
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index c19e16c..fac73ae 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -94,4 +94,23 @@ int gpio_get_value(unsigned gpio);
  */
 int gpio_set_value(unsigned gpio, int value);
 
+/**
+ * Driver model GPIO operations, refer to functions above for description.
+ * These function copy the old API.
+ *
+ * This is trying to be close to Linux GPIO API. Once the U-Boot uses the
+ * new DM GPIO API, this should be really easy to flip over to the Linux
+ * GPIO API-alike interface.
+ */
+struct dm_gpio_ops {
+       int     base;
+       u16     ngpio;
+       int     (*gpio_request)(unsigned gpio, const char *label);
+       int     (*gpio_free)(unsigned gpio);
+       int     (*gpio_direction_input)(unsigned gpio);
+       int     (*gpio_direction_output)(unsigned gpio, int value);
+       int     (*gpio_get_value)(unsigned gpio);
+       int     (*gpio_set_value)(unsigned gpio, int value);
+};
+
 #endif /* _ASM_GENERIC_GPIO_H_ */
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 9c431bf..0220386 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -22,6 +22,8 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
+#define CONFIG_DM
+
 #define CONFIG_NR_DRAM_BANKS   1
 #define CONFIG_DRAM_SIZE       (128 << 20)
 
diff --git a/include/dm/core_numbering.h b/include/dm/core_numbering.h
index 75a023f..b543b48 100644
--- a/include/dm/core_numbering.h
+++ b/include/dm/core_numbering.h
@@ -28,6 +28,7 @@
 
 enum core_id {
        CORE_INVALID = 0,
+       CORE_GPIO,
 };
 
 #endif
-- 
1.7.10.4

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to