dm: demo: Add a simple GPIO demonstration
authorSimon Glass <sjg@chromium.org>
Tue, 6 Jan 2015 03:05:31 +0000 (20:05 -0700)
committerSimon Glass <sjg@chromium.org>
Fri, 30 Jan 2015 00:09:51 +0000 (17:09 -0700)
Add a new 'demo light' command which uses GPIOs to control imaginary lights.
Each light is assigned a bit number in the overall value. This provides an
example driver for using the new GPIO API.

Signed-off-by: Simon Glass <sjg@chromium.org>
arch/sandbox/dts/sandbox.dts
common/cmd_demo.c
drivers/demo/demo-shape.c
drivers/demo/demo-uclass.c
include/dm-demo.h

index 11748aec7990e1ff40f9d625842a154d8d278cc1..4c63e4f9ede8fc01636c35389852a15622185a04 100644 (file)
@@ -19,6 +19,7 @@
                colour = "cyan";
                sides = <3>;
                character = <83>;
+               light-gpios = <&gpio_a 2>, <&gpio_b 6 0>;
        };
        square {
                compatible = "demo-shape";
                        0x070b0067 0x070c0069>;
        };
 
-       gpio_a: gpios {
+       gpio_a: gpios@0 {
                gpio-controller;
                compatible = "sandbox,gpio";
                #gpio-cells = <1>;
                num-gpios = <20>;
        };
 
+       gpio_b: gpios@1 {
+               gpio-controller;
+               compatible = "sandbox,gpio";
+               #gpio-cells = <2>;
+               gpio-bank-name = "b";
+               num-gpios = <10>;
+       };
+
        i2c@0 {
                #address-cells = <1>;
                #size-cells = <0>;
index 652c61c70779bdab10116e80bca99e554f20a786..bcb34d904569d98612317dcc4e0712db6edd6410 100644 (file)
@@ -39,6 +39,26 @@ static int do_demo_status(cmd_tbl_t *cmdtp, int flag, int argc,
        return 0;
 }
 
+static int do_demo_light(cmd_tbl_t *cmdtp, int flag, int argc,
+                        char * const argv[])
+{
+       int light;
+       int ret;
+
+       if (argc) {
+               light = simple_strtoul(argv[0], NULL, 16);
+               ret = demo_set_light(demo_dev, light);
+       } else {
+               ret = demo_get_light(demo_dev);
+               if (ret >= 0) {
+                       printf("Light: %x\n", ret);
+                       ret = 0;
+               }
+       }
+
+       return ret;
+}
+
 int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
        struct udevice *dev;
@@ -61,6 +81,7 @@ int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 static cmd_tbl_t demo_commands[] = {
        U_BOOT_CMD_MKENT(list, 0, 1, do_demo_list, "", ""),
        U_BOOT_CMD_MKENT(hello, 2, 1, do_demo_hello, "", ""),
+       U_BOOT_CMD_MKENT(light, 2, 1, do_demo_light, "", ""),
        U_BOOT_CMD_MKENT(status, 1, 1, do_demo_status, "", ""),
 };
 
@@ -86,6 +107,10 @@ static int do_demo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                        return cmd_process_error(cmdtp, ret);
                argc--;
                argv++;
+       } else {
+               demo_dev = NULL;
+               if (demo_cmd->cmd != do_demo_list)
+                       return CMD_RET_USAGE;
        }
 
        ret = demo_cmd->cmd(demo_cmd, flag, argc, argv);
@@ -98,5 +123,7 @@ U_BOOT_CMD(
        "Driver model (dm) demo operations",
        "list                     List available demo devices\n"
        "demo hello <num> [<char>]     Say hello\n"
-       "demo status <num>             Get demo device status"
+       "demo light [<num>]            Set or get the lights\n"
+       "demo status <num>             Get demo device status\n"
+       "demo list                     List available demo devices"
 );
index 3fa9c5994703d473494a4d2199ecae3e34a0c9c0..d908736cffe31e2acb1bfa787bc12b05265543b7 100644 (file)
@@ -11,6 +11,7 @@
 #include <malloc.h>
 #include <dm-demo.h>
 #include <asm/io.h>
+#include <asm/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -20,6 +21,8 @@ DECLARE_GLOBAL_DATA_PTR;
 
 struct shape_data {
        int num_chars;  /* Number of non-space characters output so far */
+       struct gpio_desc gpio_desc[8];
+       int gpio_count;
 };
 
 /* Crazy little function to draw shapes on the console */
@@ -89,9 +92,52 @@ static int shape_status(struct udevice *dev, int *status)
        return 0;
 }
 
+static int set_light(struct udevice *dev, int light)
+{
+       struct shape_data *priv = dev_get_priv(dev);
+       struct gpio_desc *desc;
+       int ret;
+       int i;
+
+       desc = priv->gpio_desc;
+       for (i = 0; i < priv->gpio_count; i++, desc++) {
+               uint mask = 1 << i;
+
+               ret = dm_gpio_set_value(desc, light & mask);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int get_light(struct udevice *dev)
+{
+       struct shape_data *priv = dev_get_priv(dev);
+       struct gpio_desc *desc;
+       uint value = 0;
+       int ret;
+       int i;
+
+       desc = priv->gpio_desc;
+       for (i = 0; i < priv->gpio_count; i++, desc++) {
+               uint mask = 1 << i;
+
+               ret = dm_gpio_get_value(desc);
+               if (ret < 0)
+                       return ret;
+               if (ret)
+                       value |= mask;
+       }
+
+       return value;
+}
+
 static const struct demo_ops shape_ops = {
        .hello = shape_hello,
        .status = shape_status,
+       .get_light = get_light,
+       .set_light = set_light,
 };
 
 static int shape_ofdata_to_platdata(struct udevice *dev)
@@ -111,6 +157,29 @@ static int shape_ofdata_to_platdata(struct udevice *dev)
        return 0;
 }
 
+static int dm_shape_probe(struct udevice *dev)
+{
+       struct shape_data *priv = dev_get_priv(dev);
+       int ret;
+
+       ret = gpio_request_list_by_name(dev, "light-gpios", priv->gpio_desc,
+                                       ARRAY_SIZE(priv->gpio_desc),
+                                       GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+       if (ret < 0)
+               return ret;
+       priv->gpio_count = ret;
+       debug("%s: %d GPIOs\n", __func__, priv->gpio_count);
+
+       return 0;
+}
+
+static int dm_shape_remove(struct udevice *dev)
+{
+       struct shape_data *priv = dev_get_priv(dev);
+
+       return gpio_free_list(dev, priv->gpio_desc, priv->gpio_count);
+}
+
 static const struct udevice_id demo_shape_id[] = {
        { "demo-shape", 0 },
        { },
@@ -122,6 +191,8 @@ U_BOOT_DRIVER(demo_shape_drv) = {
        .id     = UCLASS_DEMO,
        .ofdata_to_platdata = shape_ofdata_to_platdata,
        .ops    = &shape_ops,
+       .probe = dm_shape_probe,
+       .remove = dm_shape_remove,
        .priv_auto_alloc_size = sizeof(struct shape_data),
        .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
 };
index f6510d602c83472695065b66c0f01e55f75b881b..725f06898f33deb8d7e827f016d1a63da90b71aa 100644 (file)
@@ -43,6 +43,26 @@ int demo_status(struct udevice *dev, int *status)
        return ops->status(dev, status);
 }
 
+int demo_get_light(struct udevice *dev)
+{
+       const struct demo_ops *ops = device_get_ops(dev);
+
+       if (!ops->get_light)
+               return -ENOSYS;
+
+       return ops->get_light(dev);
+}
+
+int demo_set_light(struct udevice *dev, int light)
+{
+       const struct demo_ops *ops = device_get_ops(dev);
+
+       if (!ops->set_light)
+               return -ENOSYS;
+
+       return ops->set_light(dev, light);
+}
+
 int demo_parse_dt(struct udevice *dev)
 {
        struct dm_demo_pdata *pdata = dev_get_platdata(dev);
index a24fec6658e8e9bb1df82235222befc404411b32..03722d0c14dc14de253bc203185da4c59503cd99 100644 (file)
@@ -25,10 +25,14 @@ struct dm_demo_pdata {
 struct demo_ops {
        int (*hello)(struct udevice *dev, int ch);
        int (*status)(struct udevice *dev, int *status);
+       int (*set_light)(struct udevice *dev, int light);
+       int (*get_light)(struct udevice *dev);
 };
 
 int demo_hello(struct udevice *dev, int ch);
 int demo_status(struct udevice *dev, int *status);
+int demo_set_light(struct udevice *dev, int light);
+int demo_get_light(struct udevice *dev);
 int demo_list(void);
 
 int demo_parse_dt(struct udevice *dev);