[U-Boot] [PATCH 5/7] dm: gpio: Add draft GPIO core and convert sandbox to use it
Marek Vasut
marex at denx.de
Tue Aug 21 18:00:51 CEST 2012
Signed-off-by: Marek Vasut <marex at 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
More information about the U-Boot
mailing list