From patchwork Thu Nov 7 16:32:09 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 289418 X-Patchwork-Delegate: trini@ti.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id C15382C0087 for ; Fri, 8 Nov 2013 03:35:17 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id B26CD4A3B9; Thu, 7 Nov 2013 17:35:02 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id C85YW7MLe84c; Thu, 7 Nov 2013 17:35:02 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 209C34A3D2; Thu, 7 Nov 2013 17:33:56 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id ECEE84A395 for ; Thu, 7 Nov 2013 17:33:48 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 2bIZoyLSagcQ for ; Thu, 7 Nov 2013 17:33:43 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-ob0-f201.google.com (mail-ob0-f201.google.com [209.85.214.201]) by theia.denx.de (Postfix) with ESMTPS id 745C04A3B7 for ; Thu, 7 Nov 2013 17:33:29 +0100 (CET) Received: by mail-ob0-f201.google.com with SMTP id vb8so54015obc.4 for ; Thu, 07 Nov 2013 08:33:28 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-type:content-transfer-encoding; bh=i0bcjkCUjmDRGhlQuuss9HalszKmrc0UvBr/2gaYl5g=; b=QDUAVGCVPKLIBc7idW83wSAJF1CxNLEUhIUo5b9GE6TCwZn3uxoIWvbhosL+2MCXDb EbZMNQ4nmFFt/eTuLYaAVr1Mt/aZzeZLRylNChLIiguxm7p6WIzDj/DnFrI6Srb8yqGm mcFTZPQxGPWoIKdJvQBaJIvqX57GvX6hRtscKR0WtmzqD+8KZPK9JnQvUlEeAvBEUBHv wBD4ifJU3+et7/iqX9ztj1SQ3oSWZjsmJ4fLNwfTEXnd3IWjjtXJvBMjh24g2WB8PnIX dVwS45bo6d/87TCAMsi1yEc8zoAMIyzlFNQ2D9r913ZrE/7IMPzu5NW4+Lpo+4mIuVKr EweQ== X-Gm-Message-State: ALoCoQlMXzt0P6TQ2ZYBENQxMPVVEjTXH6ve1V9raU+r3onz/6lfx9HjoQWLtXSd2Z+eX3PeCPUYNaQebxhGkF/ci2JQ2J9H8oZxEEp2IvSEaD8vgPUXaHvMUp6fFp38fFZJ7Km0CKnKpkSK/SdutY+3HWADHMVfbwsSvtX+SU6woz8q5cn+BAN2JryKV9uNo6D2p1vKGAKg X-Received: by 10.42.62.8 with SMTP id w8mr2595917ich.23.1383842008409; Thu, 07 Nov 2013 08:33:28 -0800 (PST) Received: from corp2gmr1-2.hot.corp.google.com (corp2gmr1-2.hot.corp.google.com [172.24.189.93]) by gmr-mx.google.com with ESMTPS id a49si611459yhc.5.2013.11.07.08.33.28 for (version=TLSv1.1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 07 Nov 2013 08:33:28 -0800 (PST) Received: from kaki.bld.corp.google.com (kaki.bld.corp.google.com [172.29.216.32]) by corp2gmr1-2.hot.corp.google.com (Postfix) with ESMTP id 379215A41EA; Thu, 7 Nov 2013 08:33:28 -0800 (PST) Received: by kaki.bld.corp.google.com (Postfix, from userid 121222) id 721EC221405; Thu, 7 Nov 2013 09:32:33 -0700 (MST) From: Simon Glass To: U-Boot Mailing List Date: Thu, 7 Nov 2013 09:32:09 -0700 Message-Id: <1383841933-1800-14-git-send-email-sjg@chromium.org> X-Mailer: git-send-email 1.8.4.1 In-Reply-To: <1383841933-1800-1-git-send-email-sjg@chromium.org> References: <1383841933-1800-1-git-send-email-sjg@chromium.org> MIME-Version: 1.0 Cc: Marek Vasut , u-boot-review@google.com, Tom Rini Subject: [U-Boot] [PATCH v6 13/17] dm: Add a demonstration/example driver X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de As an example of how to write a uclass and a driver, provide a demo version of each, accessible through the 'demo' command. To use these with driver model, define CONFIG_CMD_DEMO and CONFIG_DM_DEMO. The two demo drivers are enabled with CONFIG_DM_DEMO_SIMPLE and CONFIG_DM_DEMO_SHAPE. Signed-off-by: Simon Glass Signed-off-by: Marek Vasut Signed-off-by: Pavel Herrmann Signed-off-by: Viktor Křivák Signed-off-by: Tomas Hlavacek --- Changes in v6: - Convert Makefiles to new Kconfig format - Rename platform_data to platdata - Use ofdata_to_platdata method to convert device tree data to platdata Changes in v5: - Change to new SPDX license headers Changes in v4: - Remove duplicated .op line Changes in v3: - Fix up demo command help - Update demo driver to use device tree Changes in v2: None Makefile | 1 + common/Makefile | 1 + common/cmd_demo.c | 102 ++++++++++++++++++++++++++++++++++++ drivers/demo/Makefile | 9 ++++ drivers/demo/demo-pdata.c | 47 +++++++++++++++++ drivers/demo/demo-shape.c | 127 +++++++++++++++++++++++++++++++++++++++++++++ drivers/demo/demo-simple.c | 47 +++++++++++++++++ drivers/demo/demo-uclass.c | 58 +++++++++++++++++++++ include/configs/sandbox.h | 4 ++ include/dm-demo.h | 36 +++++++++++++ 10 files changed, 432 insertions(+) create mode 100644 common/cmd_demo.c create mode 100644 drivers/demo/Makefile create mode 100644 drivers/demo/demo-pdata.c create mode 100644 drivers/demo/demo-shape.c create mode 100644 drivers/demo/demo-simple.c create mode 100644 drivers/demo/demo-uclass.c create mode 100644 include/dm-demo.h diff --git a/Makefile b/Makefile index f4badca..7eaf6c9 100644 --- a/Makefile +++ b/Makefile @@ -301,6 +301,7 @@ LIBS-y += post/libpost.o LIBS-y += test/libtest.o LIBS-$(CONFIG_DM) += drivers/core/libdm.o LIBS-y += test/dm/libtestdm.o +LIBS-$(CONFIG_DM_DEMO) += drivers/demo/libdemo.o ifneq (,$(filter $(SOC), mx25 mx27 mx5 mx6 mx31 mx35 mxs vf610)) LIBS-y += arch/$(ARCH)/imx-common/libimx-common.o diff --git a/common/Makefile b/common/Makefile index 32acbf9..f67c7f7 100644 --- a/common/Makefile +++ b/common/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_CMD_CONSOLE) += cmd_console.o obj-$(CONFIG_CMD_CPLBINFO) += cmd_cplbinfo.o obj-$(CONFIG_DATAFLASH_MMC_SELECT) += cmd_dataflash_mmc_mux.o obj-$(CONFIG_CMD_DATE) += cmd_date.o +obj-$(CONFIG_CMD_DEMO) += cmd_demo.o obj-$(CONFIG_CMD_SOUND) += cmd_sound.o ifdef CONFIG_4xx obj-$(CONFIG_CMD_SETGETDCR) += cmd_dcr.o diff --git a/common/cmd_demo.c b/common/cmd_demo.c new file mode 100644 index 0000000..a3bba7f --- /dev/null +++ b/common/cmd_demo.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +struct device *demo_dev; + +static int do_demo_hello(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int ch = 0; + + if (argc) + ch = *argv[0]; + + return demo_hello(demo_dev, ch); +} + +static int do_demo_status(cmd_tbl_t *cmdtp, int flag, int argc, + char * const argv[]) +{ + int status; + int ret; + + ret = demo_status(demo_dev, &status); + if (ret) + return ret; + + printf("Status: %d\n", status); + + return 0; +} + +int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + struct device *dev; + int i, ret; + + puts("Demo uclass entries:\n"); + + for (i = 0, ret = uclass_first_device(UCLASS_DEMO, &dev); + dev; + ret = uclass_next_device(&dev)) { + printf("entry %d - instance %08x, ops %08x, platdata %08x\n", + i++, map_to_sysmem(dev), + map_to_sysmem(dev->driver->ops), + map_to_sysmem(dev_get_platdata(dev))); + } + + return cmd_process_error(cmdtp, ret); +} + +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(status, 1, 1, do_demo_status, "", ""), +}; + +static int do_demo(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ + cmd_tbl_t *demo_cmd; + int devnum = 0; + int ret; + + if (argc < 2) + return CMD_RET_USAGE; + demo_cmd = find_cmd_tbl(argv[1], demo_commands, + ARRAY_SIZE(demo_commands)); + argc -= 2; + argv += 2; + if (!demo_cmd || argc > demo_cmd->maxargs) + return CMD_RET_USAGE; + + if (argc) { + devnum = simple_strtoul(argv[0], NULL, 10); + ret = uclass_get_device(UCLASS_DEMO, devnum, &demo_dev); + if (ret) + return cmd_process_error(cmdtp, ret); + argc--; + argv++; + } + + ret = demo_cmd->cmd(demo_cmd, flag, argc, argv); + + return cmd_process_error(demo_cmd, ret); +} + +U_BOOT_CMD( + demo, 4, 1, do_demo, + "Driver model (dm) demo operations", + "list List available demo devices\n" + "demo hello [] Say hello\n" + "demo status Get demo device status" +); diff --git a/drivers/demo/Makefile b/drivers/demo/Makefile new file mode 100644 index 0000000..baaa2ba --- /dev/null +++ b/drivers/demo/Makefile @@ -0,0 +1,9 @@ +# +# Copyright (c) 2013 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_DM_DEMO) += demo-uclass.o demo-pdata.o +obj-$(CONFIG_DM_DEMO_SIMPLE) += demo-simple.o +obj-$(CONFIG_DM_DEMO_SHAPE) += demo-shape.o diff --git a/drivers/demo/demo-pdata.c b/drivers/demo/demo-pdata.c new file mode 100644 index 0000000..e92841d --- /dev/null +++ b/drivers/demo/demo-pdata.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include + +static const struct dm_demo_pdata red_square = { + .colour = "red", + .sides = 4. +}; +static const struct dm_demo_pdata green_triangle = { + .colour = "green", + .sides = 3. +}; +static const struct dm_demo_pdata yellow_hexagon = { + .colour = "yellow", + .sides = 6. +}; + +U_BOOT_DEVICE(demo0) = { + .name = "demo_shape_drv", + .platdata = &red_square, +}; + +U_BOOT_DEVICE(demo1) = { + .name = "demo_simple_drv", + .platdata = &red_square, +}; + +U_BOOT_DEVICE(demo2) = { + .name = "demo_shape_drv", + .platdata = &green_triangle, +}; + +U_BOOT_DEVICE(demo3) = { + .name = "demo_simple_drv", + .platdata = &yellow_hexagon, +}; + +U_BOOT_DEVICE(demo4) = { + .name = "demo_shape_drv", + .platdata = &yellow_hexagon, +}; diff --git a/drivers/demo/demo-shape.c b/drivers/demo/demo-shape.c new file mode 100644 index 0000000..a8da1cb --- /dev/null +++ b/drivers/demo/demo-shape.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* Shape size */ +#define WIDTH 8 +#define HEIGHT 6 + +struct shape_data { + int num_chars; /* Number of non-space characters output so far */ +}; + +/* Crazy little function to draw shapes on the console */ +static int shape_hello(struct device *dev, int ch) +{ + const struct dm_demo_pdata *pdata = dev_get_platdata(dev); + struct shape_data *data = dev_get_priv(dev); + static const struct shape { + int start; + int end; + int dstart; + int dend; + } shapes[3] = { + { 0, 1, 0, 1 }, + { 0, WIDTH, 0, 0 }, + { HEIGHT / 2 - 1, WIDTH - HEIGHT / 2 + 1, -1, 1}, + }; + struct shape shape; + unsigned int index; + int line, pos, inside; + const char *colour = pdata->colour; + int first = 0; + + if (!ch) + ch = pdata->default_char; + if (!ch) + ch = '@'; + + index = (pdata->sides / 2) - 1; + if (index >= ARRAY_SIZE(shapes)) + return -EIO; + shape = shapes[index]; + + for (line = 0; line < HEIGHT; line++) { + first = 1; + for (pos = 0; pos < WIDTH; pos++) { + inside = pos >= shape.start && pos < shape.end; + if (inside) { + putc(first ? *colour++ : ch); + data->num_chars++; + first = 0; + if (!*colour) + colour = pdata->colour; + } else { + putc(' '); + } + } + putc('\n'); + shape.start += shape.dstart; + shape.end += shape.dend; + if (shape.start < 0) { + shape.dstart = -shape.dstart; + shape.dend = -shape.dend; + shape.start += shape.dstart; + shape.end += shape.dend; + } + } + + return 0; +} + +static int shape_status(struct device *dev, int *status) +{ + struct shape_data *data = dev_get_priv(dev); + + *status = data->num_chars; + return 0; +} + +static const struct demo_ops simple_ops = { + .hello = shape_hello, + .status = shape_status, +}; + +static int shape_ofdata_to_platdata(struct device *dev) +{ + struct dm_demo_pdata *pdata = dev_get_platdata(dev); + int ret; + + /* Parse the data that is common with all demo devices */ + ret = demo_parse_dt(dev); + if (ret) + return ret; + + /* Parse the data that only we need */ + pdata->default_char = fdtdec_get_int(gd->fdt_blob, dev->of_offset, + "character", '@'); + + return 0; +} + +static const struct device_id demo_shape_id[] = { + { "demo-shape", 0 }, + { }, +}; + +U_BOOT_DRIVER(demo_shape_drv) = { + .name = "demo_shape_drv", + .of_match = demo_shape_id, + .id = UCLASS_DEMO, + .ofdata_to_platdata = shape_ofdata_to_platdata, + .ops = &simple_ops, + .priv_auto_alloc_size = sizeof(struct shape_data), + .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata), +}; diff --git a/drivers/demo/demo-simple.c b/drivers/demo/demo-simple.c new file mode 100644 index 0000000..6ba8131 --- /dev/null +++ b/drivers/demo/demo-simple.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include + +static int simple_hello(struct device *dev, int ch) +{ + const struct dm_demo_pdata *pdata = dev_get_platdata(dev); + + printf("Hello from %08x: %s %d\n", map_to_sysmem(dev), pdata->colour, + pdata->sides); + + return 0; +} + +static const struct demo_ops simple_ops = { + .hello = simple_hello, +}; + +static int demo_shape_ofdata_to_platdata(struct device *dev) +{ + /* Parse the data that is common with all demo devices */ + return demo_parse_dt(dev); +} + +static const struct device_id demo_shape_id[] = { + { "demo-simple", 0 }, + { }, +}; + +U_BOOT_DRIVER(demo_simple_drv) = { + .name = "demo_simple_drv", + .of_match = demo_shape_id, + .id = UCLASS_DEMO, + .ofdata_to_platdata = demo_shape_ofdata_to_platdata, + .ops = &simple_ops, + .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata), +}; diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c new file mode 100644 index 0000000..48588be --- /dev/null +++ b/drivers/demo/demo-uclass.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +UCLASS_DRIVER(demo) = { + .id = UCLASS_DEMO, +}; + +int demo_hello(struct device *dev, int ch) +{ + const struct demo_ops *ops = device_get_ops(dev); + + if (!ops->hello) + return -ENOSYS; + + return ops->hello(dev, ch); +} + +int demo_status(struct device *dev, int *status) +{ + const struct demo_ops *ops = device_get_ops(dev); + + if (!ops->status) + return -ENOSYS; + + return ops->status(dev, status); +} + +int demo_parse_dt(struct device *dev) +{ + struct dm_demo_pdata *pdata = dev_get_platdata(dev); + int dn = dev->of_offset; + + pdata->sides = fdtdec_get_int(gd->fdt_blob, dn, "sides", 0); + pdata->colour = fdt_getprop(gd->fdt_blob, dn, "colour", NULL); + if (!pdata->sides || !pdata->colour) { + debug("%s: Invalid device tree data\n", __func__); + return -EINVAL; + } + + return 0; +} diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h index 66a6a89..30c7204 100644 --- a/include/configs/sandbox.h +++ b/include/configs/sandbox.h @@ -19,7 +19,11 @@ #define CONFIG_BOOTSTAGE #define CONFIG_BOOTSTAGE_REPORT #define CONFIG_DM +#define CONFIG_CMD_DEMO #define CONFIG_CMD_DM +#define CONFIG_DM_DEMO +#define CONFIG_DM_DEMO_SIMPLE +#define CONFIG_DM_DEMO_SHAPE #define CONFIG_DM_TEST /* Number of bits in a C 'long' on this architecture */ diff --git a/include/dm-demo.h b/include/dm-demo.h new file mode 100644 index 0000000..6e38d3c --- /dev/null +++ b/include/dm-demo.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __DM_DEMO_H +#define __DM_DEMO_H + +#include + +/** + * struct dm_demo_pdata - configuration data for demo instance + * + * @colour: Color of the demo + * @sides: Numbers of sides + * @default_char: Default ASCII character to output (65 = 'A') + */ +struct dm_demo_pdata { + const char *colour; + int sides; + int default_char; +}; + +struct demo_ops { + int (*hello)(struct device *dev, int ch); + int (*status)(struct device *dev, int *status); +}; + +int demo_hello(struct device *dev, int ch); +int demo_status(struct device *dev, int *status); +int demo_list(void); + +int demo_parse_dt(struct device *dev); + +#endif