dm: Introduce driver model for sunxi
Subsystems (11)
cover dm: Introduce driver model for sunxi
This series adds driver model support for serial and GPIO for sunxi. Since I only have a sun7i board to test with, I have added a new config for the pcDuino3, which uses device tree and driver model. This should make it fairly easy to enable for the other boards at some point.
Now that we have about 5 GPIO drivers it is clear that the request()/free() logic should be in the uclass rather than the driver. So far drivers don't have to do anything in those methods except adjust pin configuration. Patches are included to make this change, including removing the redundant code in the various GPIO drivers. The sunxi driver works the same way.
So far at least GPIO drivers don't tend to have anything special to report for the 'gpio status' command. Partly this is because we only support a simple concept of GPIOs so far (no drive strength, function selection, etc.) but even if this were to be supported it would be better to handle it generically where possible. So the get_state() call can be replaced with a generic one in the uclass. This can be implemented with the existing uclass interface: get_function() to find out if the pin is set as an input, output or not a GPIO, and get_value() to find its value.
As a result, it is safe to remove the get_state() method, and this series does that also.
This series is available at u-boot-dm/sunix-working.
Simon Glass (23):
dm: sunxi: dts: Add sun7i device tree files
dm: sunxi: Add a new config for an FDT-based pcDuino3
dm: core: Add support for simple-bus
dm: sunxi: Add pinmux functions which take a bank parameter
dm: sunxi: Make sure that GPIOs are requested
dm: sunxi: Modify the GPIO driver to support driver model
dm: sunxi: Add support for serial using driver model
dm: gpio: Implement GPIO reservation in the uclass
dm: gpio: Add gpio_get_function() and friends
dm: Move the function for getting GPIO status into the uclass
dm: gpio: sandbox: Implement the get_function() method
dm: gpio: sandbox: Implement the remove() method
dm: gpio: sandbox: Drop request()/free() in the driver
test: dm: Update GPIO tests for new gpio_request() method
dm: gpio: Add gpio_requestf() helper for printf() strings
test: dm: Support memory leak checking as a core feature
test: dm: Add additional GPIO tests
dm: gpio: tegra: Drop request()/free() in the driver
dm: gpio: omap3: Drop request()/free() in the driver
dm: gpio: rpi_b: Drop request()/free() in the driver
dm: gpio: exynos: Drop request()/free() in the driver
dm: gpio: imx: Drop request()/free() in the driver
dm: gpio: Remove unused get_state() uclass method
Makefile | 3 +- arch/arm/cpu/armv7/sunxi/pinmux.c | 32 +- arch/arm/dts/Makefile | 1 + arch/arm/dts/sun7i-a20-pcduino3.dts | 177 ++++++ arch/arm/dts/sun7i-a20.dtsi | 988 ++++++++++++++++++++++++++++++ arch/arm/dts/sunxi-common-regulators.dtsi | 89 +++ arch/arm/include/asm/arch-sunxi/gpio.h | 4 +- board/sunxi/MAINTAINERS | 1 + board/sunxi/ahci.c | 1 + common/cmd_gpio.c | 57 +- configs/Linksprite_pcDuino3_fdt_defconfig | 8 + doc/driver-model/README.txt | 29 +- drivers/core/Makefile | 1 + drivers/core/simple-bus.c | 33 + drivers/gpio/bcm2835_gpio.c | 89 --- drivers/gpio/gpio-uclass.c | 199 +++++- drivers/gpio/mxc_gpio.c | 116 ---- drivers/gpio/omap_gpio.c | 116 +--- drivers/gpio/s5p_gpio.c | 101 --- drivers/gpio/sandbox.c | 93 +-- drivers/gpio/sunxi_gpio.c | 170 +++++ drivers/gpio/tegra_gpio.c | 110 ---- drivers/serial/Makefile | 1 + drivers/serial/serial_dw.c | 39 ++ include/asm-generic/gpio.h | 70 ++- include/configs/sun7i.h | 8 + include/configs/sunxi-common.h | 12 +- include/dm/test.h | 23 + include/dm/uclass-id.h | 1 + include/dt-bindings/input/input.h | 525 ++++++++++++++++ test/dm/core.c | 46 +- test/dm/gpio.c | 111 +++- test/dm/test-main.c | 2 + 33 files changed, 2534 insertions(+), 722 deletions(-) create mode 100644 arch/arm/dts/sun7i-a20-pcduino3.dts create mode 100644 arch/arm/dts/sun7i-a20.dtsi create mode 100644 arch/arm/dts/sunxi-common-regulators.dtsi create mode 100644 configs/Linksprite_pcDuino3_fdt_defconfig create mode 100644 drivers/core/simple-bus.c create mode 100644 drivers/serial/serial_dw.c create mode 100644 include/dt-bindings/input/input.h
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 1/23 dm: sunxi: dts: Add sun7i device tree files
These are from Linux 3.17-rc7 (commit fe82dcec). U-Boot only uses a small portion of these, but we may as well have something to look forward to.
The total compiled size is about 25KB.
---
arch/arm/dts/sun7i-a20-pcduino3.dts | 173 ++++++ arch/arm/dts/sun7i-a20.dtsi | 988 ++++++++++++++++++++++++++++++ arch/arm/dts/sunxi-common-regulators.dtsi | 89 +++ include/dt-bindings/input/input.h | 525 ++++++++++++++++ 4 files changed, 1775 insertions(+) create mode 100644 arch/arm/dts/sun7i-a20-pcduino3.dts create mode 100644 arch/arm/dts/sun7i-a20.dtsi create mode 100644 arch/arm/dts/sunxi-common-regulators.dtsi create mode 100644 include/dt-bindings/input/input.h
arch/arm/dts/sun7i-a20-pcduino3.dts new file +173 -0
@@ -0,0 +1,173 @@ +/* + * Copyright 2014 Zoltan HERPAI + * Zoltan HERPAI <[email protected]> + * + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/dts-v1/; +/include/ "sun7i-a20.dtsi" +/include/ "sunxi-common-regulators.dtsi" +#include <dt-bindings/gpio/gpio.h> +#include <dt-bindings/input/input.h> + +/ { + model = "LinkSprite pcDuino3"; + compatible = "linksprite,pcduino3", "allwinner,sun7i-a20"; + + soc at 01c00000 { + mmc0: mmc at 01c0f000 { + pinctrl-names = "default"; + pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>; + vmmc-supply = <®_vcc3v3>; + bus-width = <4>; + cd-gpios = <&pio 7 1 0>; /* PH1 */ + cd-inverted; + status = "okay"; + }; + + usbphy: phy at 01c13400 { + usb1_vbus-supply = <®_usb1_vbus>; + usb2_vbus-supply = <®_usb2_vbus>; + status = "okay"; + }; + + ehci0: usb at 01c14000 { + status = "okay"; + }; + + ohci0: usb at 01c14400 { + status = "okay"; + }; + + ahci: sata at 01c18000 { + target-supply = <®_ahci_5v>; + status = "okay"; + }; + + ehci1: usb at 01c1c000 { + status = "okay"; + }; + + ohci1: usb at 01c1c400 { + status = "okay"; + }; + + pinctrl at 01c20800 { + ahci_pwr_pin_a: ahci_pwr_pin at 0 { + allwinner,pins = "PH2"; + }; + + led_pins_pcduino3: led_pins at 0 { + allwinner,pins = "PH15", "PH16"; + allwinner,function = "gpio_out"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + + key_pins_pcduino3: key_pins at 0 { + allwinner,pins = "PH17", "PH18", "PH19"; + allwinner,function = "gpio_in"; + allwinner,drive = <0>; + allwinner,pull = <0>; + }; + }; + + ir0: ir at 01c21800 { + pinctrl-names = "default"; + pinctrl-0 = <&ir0_pins_a>; + status = "okay"; + }; + + uart0: serial at 01c28000 { + pinctrl-names = "default"; + pinctrl-0 = <&uart0_pins_a>; + status = "okay"; + }; + + i2c0: i2c at 01c2ac00 { + pinctrl-names = "default"; + pinctrl-0 = <&i2c0_pins_a>; + status = "okay"; + + axp209: pmic at 34 { + compatible = "x-powers,axp209"; + reg = <0x34>; + interrupt-parent = <&nmi_intc>; + interrupts = <0 8>; + + interrupt-controller; + #interrupt-cells = <1>; + }; + }; + + gmac: ethernet at 01c50000 { + pinctrl-names = "default"; + pinctrl-0 = <&gmac_pins_mii_a>; + phy = <&phy1>; + phy-mode = "mii"; + status = "okay"; + + phy1: ethernet-phy at 1 { + reg = <1>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&led_pins_pcduino3>; + + tx { + label = "pcduino3:green:tx"; + gpios = <&pio 7 15 GPIO_ACTIVE_LOW>; + }; + + rx { + label = "pcduino3:green:rx"; + gpios = <&pio 7 16 GPIO_ACTIVE_LOW>; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + pinctrl-names = "default"; + pinctrl-0 = <&key_pins_pcduino3>; + #address-cells = <1>; + #size-cells = <0>; + button at 0 { + label = "Key Back"; + linux,code = <KEY_BACK>; + gpios = <&pio 7 17 GPIO_ACTIVE_LOW>; + }; + button at 1 { + label = "Key Home"; + linux,code = <KEY_HOME>; + gpios = <&pio 7 18 GPIO_ACTIVE_LOW>; + }; + button at 2 { + label = "Key Menu"; + linux,code = <KEY_MENU>; + gpios = <&pio 7 19 GPIO_ACTIVE_LOW>; + }; + }; + + reg_usb1_vbus: usb1-vbus { + status = "okay"; + }; + + reg_usb2_vbus: usb2-vbus { + status = "okay"; + }; + + reg_ahci_5v: ahci-5v { + gpio = <&pio 7 2 0>; + status = "okay"; + }; +};
arch/arm/dts/sun7i-a20.dtsi new file +988 -0
988 lines not on this page · raw message
arch/arm/dts/sunxi-common-regulators.dtsi new file +89 -0
89 lines not on this page · raw message
include/dt-bindings/input/input.h new file +525 -0
525 lines not on this page · raw message
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 2/23 dm: sunxi: Add a new config for an FDT-based pcDuino3
In reply to Simon GlassFor now we won't want to mess with the existing configurations. Create a new one which will enable device tree and driver model. Note that this brings the device tree binary into u-boot-sunxi-with-spl.bin.
---
Makefile | 3 ++- arch/arm/dts/Makefile | 1 + board/sunxi/MAINTAINERS | 1 + configs/Linksprite_pcDuino3_fdt_defconfig | 8 ++++++++ include/configs/sun7i.h | 4 ++++ 5 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 configs/Linksprite_pcDuino3_fdt_defconfig
Makefile +2 -1
@@ -941,7 +941,8 @@ u-boot-nand.gph: u-boot.bin FORCE ifneq ($(CONFIG_SUNXI),) OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \ --pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff -u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img FORCE +u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin \ + u-boot$(if $(CONFIG_OF_CONTROL),-dtb,).img FORCE $(call if_changed,pad_cat) endif
arch/arm/dts/Makefile +1 -0
@@ -1,3 +1,4 @@ +dtb-$(CONFIG_SUN7I) += sun7i-a20-pcduino3.dtb dtb-$(CONFIG_S5PC100) += s5pc1xx-smdkc100.dtb dtb-$(CONFIG_S5PC110) += s5pc1xx-goni.dtb dtb-$(CONFIG_EXYNOS4) += exynos4210-origen.dtb \
board/sunxi/MAINTAINERS +1 -0
@@ -21,6 +21,7 @@ F: configs/A20-OLinuXino_MICRO_defconfig F: configs/Bananapi_defconfig F: configs/i12-tvbox_defconfig F: configs/Linksprite_pcDuino3_defconfig +F: configs/Linksprite_pcDuino3_fdt_defconfig F: configs/qt840a_defconfig CUBIEBOARD2 BOARD
configs/Linksprite_pcDuino3_fdt_defconfig new file +8 -0
@@ -0,0 +1,8 @@ +CONFIG_SPL=y +CONFIG_SYS_EXTRA_OPTIONS="PCDUINO3,AXP209_POWER,SUNXI_GMAC,AHCI,SATAPWR=SUNXI_GPH(2),USB_EHCI,DM" +CONFIG_FDTFILE="sun7i-a20-pcduino3.dtb" +CONFIG_DEFAULT_DEVICE_TREE="sun7i-a20-pcduino3" +CONFIG_OF_CONTROL=y +CONFIG_OF_SEPARATE=y ++S:CONFIG_ARM=y ++S:CONFIG_TARGET_SUN7I=y
include/configs/sun7i.h +4 -0
@@ -36,6 +36,10 @@#define CONFIG_ARMV7_SECURE_BASE SUNXI_SRAM_B_BASE#define CONFIG_SYS_CLK_FREQ 24000000 +#if !defined(CONFIG_SPL_BUILD ) && defined(CONFIG_DM ) +# define CONFIG_CMD_DM +#endif +/* * Include common sunxi configuration where most the settings are */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 3/23 dm: core: Add support for simple-bus
In reply to Simon GlassAdd a driver for the simple-bus nodes, which allows devices within these nodes to be bound.
---
drivers/core/Makefile | 1 + drivers/core/simple-bus.c | 33 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 35 insertions(+) create mode 100644 drivers/core/simple-bus.c
drivers/core/Makefile +1 -0
@@ -5,3 +5,4 @@ # obj-y := device.o lists.o root.o uclass.o util.o +obj-$(CONFIG_OF_CONTROL) += simple-bus.o
drivers/core/simple-bus.c new file +33 -0
@@ -0,0 +1,33 @@ +/* +* Copyright (c) 2014 Google, Inc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <dm.h> +#include <dm/root.h> + +DECLARE_GLOBAL_DATA_PTR ; + +static int simple_bus_post_bind (struct udevice *dev) +{ +return dm_scan_fdt_node (dev, gd->fdt_blob, dev->of_offset, false); +} + +UCLASS_DRIVER (simple_bus) = { + .id =UCLASS_SIMPLE_BUS , + .name ="simple_bus" , + .post_bind = simple_bus_post_bind, +}; + +static const struct udevice_id generic_simple_bus_ids[] = { + { .compatible ="simple-bus" }, + { } +}; + +U_BOOT_DRIVER (simple_bus_drv) = { + .name ="generic_simple_bus" , + .id =UCLASS_SIMPLE_BUS , + .of_match = generic_simple_bus_ids, +};
include/dm/uclass-id.h +1 -0
@@ -19,6 +19,7 @@ enum uclass_id {UCLASS_TEST_FDT ,UCLASS_TEST_BUS ,UCLASS_SPI_EMUL ,/* sandbox SPI device emulator */ +UCLASS_SIMPLE_BUS ,/* U-Boot uclasses start here */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 3/23 dm: core: Add support for simple-bus
Quoted 12 lines · Simon Glass
Add a driver for the simple-bus nodes, which allows devices within these nodes to be bound.
Signed-off-by Simon Glass <[email protected]>---
drivers/core/Makefile | 1 + drivers/core/simple-bus.c | 33 +++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + 3 files changed, 35 insertions(+) create mode 100644 drivers/core/simple-bus.c
Applied to u-boot-dm/master.
PATCH 4/23 dm: sunxi: Add pinmux functions which take a bank parameter
In reply to Simon GlassWith driver model we will have access to a bank pointer, so we want to use it rather than converting back to a number, and then back to a bank pointer. Add functions to provide this feature.
---
arch/arm/cpu/armv7/sunxi/pinmux.c | 32 +++++++++++++++++++++----------- arch/arm/include/asm/arch-sunxi/gpio.h | 4 +++- 2 files changed, 24 insertions(+), 12 deletions(-)
arch/arm/cpu/armv7/sunxi/pinmux.c +21 -11
@@ -10,32 +10,42 @@#include <asm/io.h> #include <asm/arch/gpio.h> -int sunxi_gpio_set_cfgpin (u32 pin,u32 val) +void sunxi_gpio_set_cfgbank (struct sunxi_gpio *pio,int bank_offset,u32 val) { -u32 bank =GPIO_BANK (pin); -u32 index =GPIO_CFG_INDEX (pin); -u32 offset =GPIO_CFG_OFFSET (pin); -struct sunxi_gpio *pio =BANK_TO_GPIO (bank); +u32 index =GPIO_CFG_INDEX (bank_offset); +u32 offset =GPIO_CFG_OFFSET (bank_offset);clrsetbits_le32 (&pio->cfg[0 ] + index,0xf << offset, val << offset); - -return 0 ; } -int sunxi_gpio_get_cfgpin (u32 pin) +void sunxi_gpio_set_cfgpin (u32 pin,u32 val) { -u32 cfg;u32 bank =GPIO_BANK (pin); -u32 index =GPIO_CFG_INDEX (pin); -u32 offset =GPIO_CFG_OFFSET (pin);struct sunxi_gpio *pio =BANK_TO_GPIO (bank); +sunxi_gpio_set_cfgbank (pio, pin, val); +} + +int sunxi_gpio_get_cfgbank (struct sunxi_gpio *pio,int bank_offset) +{ +u32 index =GPIO_CFG_INDEX (bank_offset); +u32 offset =GPIO_CFG_OFFSET (bank_offset); +u32 cfg; + cfg =readl (&pio->cfg[0 ] + index); cfg >>= offset;return cfg &0xf ; } +int sunxi_gpio_get_cfgpin (u32 pin) +{ +u32 bank =GPIO_BANK (pin); +struct sunxi_gpio *pio =BANK_TO_GPIO (bank); + +return sunxi_gpio_get_cfgbank (pio, pin); +} +int sunxi_gpio_set_drv (u32 pin,u32 val) {u32 bank =GPIO_BANK (pin);
arch/arm/include/asm/arch-sunxi/gpio.h +3 -1
@@ -139,7 +139,9 @@ enum sunxi_gpio_number {#define SUNXI_GPIO_PULL_UP 1#define SUNXI_GPIO_PULL_DOWN 2 -int sunxi_gpio_set_cfgpin (u32 pin,u32 val); +void sunxi_gpio_set_cfgbank (struct sunxi_gpio *pio,int bank_offset,u32 val); +void sunxi_gpio_set_cfgpin (u32 pin,u32 val); +int sunxi_gpio_get_cfgbank (struct sunxi_gpio *pio,int bank_offset);int sunxi_gpio_get_cfgpin (u32 pin);int sunxi_gpio_set_drv (u32 pin,u32 val);int sunxi_gpio_set_pull (u32 pin,u32 val);
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 5/23 dm: sunxi: Make sure that GPIOs are requested
In reply to Simon GlassThe scsi_init() function uses a GPIO so should request it. There is no way to return an error here, and the request may be made multiple times, so just ignore errors for now.
---
board/sunxi/ahci.c | 1 + 1 file changed, 1 insertion(+)
board/sunxi/ahci.c +1 -0
@@ -74,6 +74,7 @@ void scsi_init(void) {printf ("SUNXI SCSI INIT\n" );#ifdef CONFIG_SATAPWR +gpio_request (CONFIG_SATAPWR ,"satapwr" );gpio_direction_output (CONFIG_SATAPWR ,1 );#endif
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 6/23 dm: sunxi: Modify the GPIO driver to support driver model
In reply to Simon GlassThis adds driver model support to the sunxi GPIO driver, using the device tree to trigger binding of the driver. The driver will still operate without driver model too.
---
drivers/gpio/sunxi_gpio.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++ include/configs/sun7i.h | 1 + 2 files changed, 171 insertions(+)
drivers/gpio/sunxi_gpio.c +170 -0
@@ -11,9 +11,25 @@*/ #include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> #include <asm/io.h> #include <asm/gpio.h> +#include <dm/device-internal.h> +DECLARE_GLOBAL_DATA_PTR ; + +#define SUNXI_GPIOS_PER_PORT SUNXI_GPIO_A_NR + +struct sunxi_gpio_platdata { +struct sunxi_gpio *regs; +const char *bank_name;/* Name of port, e.g. "B" */ +int gpio_count; +}; + +#ifndef CONFIG_DM_GPIO static int sunxi_gpio_output (u32 pin,u32 val) {u32 dat;
@@ -100,3 +116,157 @@ int sunxi_name_to_gpio(const char *name)return -1 ;return group *32 + pin; } +#endif + +#ifdef CONFIG_DM_GPIO +static int sunxi_gpio_direction_input (struct udevice *dev,unsigned offset) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); + +sunxi_gpio_set_cfgbank (plat->regs, offset,SUNXI_GPIO_INPUT ); + +return 0 ; +} + +static int sunxi_gpio_direction_output (struct udevice *dev,unsigned offset, +int value) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +u32 num =GPIO_NUM (offset); + +sunxi_gpio_set_cfgbank (plat->regs, offset,SUNXI_GPIO_OUTPUT ); +clrsetbits_le32 (&plat->regs->dat,1 << num, value ? (1 << num) :0 ); + +return 0 ; +} + +static int sunxi_gpio_get_value (struct udevice *dev,unsigned offset) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +u32 num =GPIO_NUM (offset); +unsigned dat; + + dat =readl (&plat->regs->dat); + dat >>= num; + +return dat &0x1 ; +} + +static int sunxi_gpio_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +u32 num =GPIO_NUM (offset); + +clrsetbits_le32 (&plat->regs->dat,1 << num, value ? (1 << num) :0 ); +return 0 ; +} + +static int sunxi_gpio_get_function (struct udevice *dev,unsigned offset) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +int func; + + func =sunxi_gpio_get_cfgbank (plat->regs, offset); +if (func ==SUNXI_GPIO_OUTPUT ) +return GPIOF_OUTPUT ; +else if (func ==SUNXI_GPIO_INPUT ) +return GPIOF_INPUT ; +else +return GPIOF_FUNC ; +} + +static const struct dm_gpio_ops gpio_sunxi_ops = { + .direction_input = sunxi_gpio_direction_input, + .direction_output = sunxi_gpio_direction_output, + .get_value = sunxi_gpio_get_value, + .set_value = sunxi_gpio_set_value, + .get_function = sunxi_gpio_get_function, +}; + +/** +* Returns the name of a GPIO bank +* +* GPIO banks are named A, B, C, ... +* +* @bank: Bank number (0, 1..n-1) +* @return allocated string containing the name +*/ +static char *gpio_bank_name (int bank) +{ +char *name; + + name =malloc (2 ); +if (name) { + name[0 ] ='A' + bank; + name[1 ] ='\0' ; + } + +return name; +} + +static int gpio_sunxi_probe (struct udevice *dev) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +struct gpio_dev_priv *uc_priv = dev->uclass_priv; + +/* Tell the uclass how many GPIOs we have */ +if (plat) { + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + } + +return 0 ; +} +/** +* We have a top-level GPIO device with no actual GPIOs. It has a child +* device for each Tegra port. +*/ +static int gpio_sunxi_bind (struct udevice *parent) +{ +struct sunxi_gpio_platdata *plat = parent->platdata; +struct sunxi_gpio_reg *ctlr; +int bank; +int ret; + +/* If this is a child device, there is nothing to do here */ +if (plat) +return 0 ; + + ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr (gd->fdt_blob, + parent->of_offset,"reg" ); +for (bank =0 ; bank <SUNXI_GPIO_BANKS ; bank++) { +struct sunxi_gpio_platdata *plat; +struct udevice *dev; + + plat =calloc (1 ,sizeof (*plat)); +if (!plat) +return -ENOMEM ; + plat->regs = &ctlr->gpio_bank[bank]; + plat->bank_name =gpio_bank_name (bank); + plat->gpio_count =SUNXI_GPIOS_PER_PORT ; + + ret =device_bind (parent, parent->driver, + plat->bank_name, plat,-1 , &dev); +if (ret) +return ret; + dev->of_offset = parent->of_offset; + } + +return 0 ; +} + +static const struct udevice_id exynos_gpio_ids[] = { + { .compatible ="allwinner,sun7i-a20-pinctrl" }, + { } +}; + +U_BOOT_DRIVER (gpio_sunxi) = { + .name ="gpio_sunxi" , + .id =UCLASS_GPIO , + .ops = &gpio_sunxi_ops, + .of_match = exynos_gpio_ids, + .bind = gpio_sunxi_bind, + .probe = gpio_sunxi_probe, +}; +#endif
include/configs/sun7i.h +1 -0
@@ -38,6 +38,7 @@#if !defined(CONFIG_SPL_BUILD ) && defined(CONFIG_DM )# define CONFIG_CMD_DM +# define CONFIG_DM_GPIO #endif /*
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 6/23 dm: sunxi: Modify the GPIO driver to support driver model
Hi,
Quoted 140 lines · Simon Glass
This adds driver model support to the sunxi GPIO driver, using the device tree to trigger binding of the driver. The driver will still operate without driver model too.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/sunxi_gpio.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++ include/configs/sun7i.h | 1 + 2 files changed, 171 insertions(+)drivers/gpio/sunxi_gpio.c +111
-0@@ -11,9 +11,25 @@*/ #include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> #include <asm/io.h> #include <asm/gpio.h> +#include <dm/device-internal.h> +DECLARE_GLOBAL_DATA_PTR ; + +#define SUNXI_GPIOS_PER_PORT SUNXI_GPIO_A_NR + +struct sunxi_gpio_platdata { +struct sunxi_gpio *regs; +const char *bank_name;/* Name of port, e.g. "B" */ +int gpio_count; +}; + +#ifndef CONFIG_DM_GPIO static int sunxi_gpio_output (u32 pin,u32 val) {u32 dat;@@ -100,3 +116,157 @@ int sunxi_name_to_gpio(const char *name)return -1 ;return group *32 + pin; } +#endif + +#ifdef CONFIG_DM_GPIO +static int sunxi_gpio_direction_input (struct udevice *dev,unsigned offset) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); + +sunxi_gpio_set_cfgbank (plat->regs, offset,SUNXI_GPIO_INPUT ); + +return 0 ; +} + +static int sunxi_gpio_direction_output (struct udevice *dev,unsigned offset, +int value) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +u32 num =GPIO_NUM (offset); + +sunxi_gpio_set_cfgbank (plat->regs, offset,SUNXI_GPIO_OUTPUT ); +clrsetbits_le32 (&plat->regs->dat,1 << num, value ? (1 << num) :0 ); + +return 0 ; +} + +static int sunxi_gpio_get_value (struct udevice *dev,unsigned offset) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +u32 num =GPIO_NUM (offset); +unsigned dat; + + dat =readl (&plat->regs->dat); + dat >>= num; + +return dat &0x1 ; +} + +static int sunxi_gpio_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +u32 num =GPIO_NUM (offset); + +clrsetbits_le32 (&plat->regs->dat,1 << num, value ? (1 << num) :0 ); +return 0 ; +} + +static int sunxi_gpio_get_function (struct udevice *dev,unsigned offset) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +int func; + + func =sunxi_gpio_get_cfgbank (plat->regs, offset); +if (func ==SUNXI_GPIO_OUTPUT ) +return GPIOF_OUTPUT ; +else if (func ==SUNXI_GPIO_INPUT ) +return GPIOF_INPUT ; +else +return GPIOF_FUNC ; +} + +static const struct dm_gpio_ops gpio_sunxi_ops = { + .direction_input = sunxi_gpio_direction_input, + .direction_output = sunxi_gpio_direction_output, + .get_value = sunxi_gpio_get_value, + .set_value = sunxi_gpio_set_value, + .get_function = sunxi_gpio_get_function, +}; + +/** +* Returns the name of a GPIO bank +* +* GPIO banks are named A, B, C, ... +* +* @bank: Bank number (0, 1..n-1) +* @return allocated string containing the name +*/ +static char *gpio_bank_name (int bank) +{ +char *name; + + name =malloc (2 ); +if (name) { + name[0 ] ='A' + bank; + name[1 ] ='\0' ; + } + +return name; +} + +static int gpio_sunxi_probe (struct udevice *dev) +{ +struct sunxi_gpio_platdata *plat =dev_get_platdata (dev); +struct gpio_dev_priv *uc_priv = dev->uclass_priv; + +/* Tell the uclass how many GPIOs we have */
drivers/gpio/sunxi_gpio.c int sunxi_name_to_gpio(const char *name) · line 223
Quoted 10 lines
drivers/gpio/sunxi_gpio.c +10
-0+if (plat) { + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + } + +return 0 ; +} +/** +* We have a top-level GPIO device with no actual GPIOs. It has a child +* device for each Tegra port.
Might we get rid of references to Tegra?
Quoted 26 lines
drivers/gpio/sunxi_gpio.c +26
-0+*/ +static int gpio_sunxi_bind (struct udevice *parent) +{ +struct sunxi_gpio_platdata *plat = parent->platdata; +struct sunxi_gpio_reg *ctlr; +int bank; +int ret; + +/* If this is a child device, there is nothing to do here */ +if (plat) +return 0 ; + + ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr (gd->fdt_blob, + parent->of_offset,"reg" ); +for (bank =0 ; bank <SUNXI_GPIO_BANKS ; bank++) { +struct sunxi_gpio_platdata *plat; +struct udevice *dev; + + plat =calloc (1 ,sizeof (*plat)); +if (!plat) +return -ENOMEM ; + plat->regs = &ctlr->gpio_bank[bank]; + plat->bank_name =gpio_bank_name (bank); + plat->gpio_count =SUNXI_GPIOS_PER_PORT ; + + ret = device_bind(parent, parent->driver,
drivers/gpio/sunxi_gpio.c int sunxi_name_to_gpio(const char *name) · line 259
Quoted 10 lines
drivers/gpio/sunxi_gpio.c +10
-0+ plat->bank_name, plat, -1, &dev); +if (ret) +return ret; + dev->of_offset = parent->of_offset; + } + +return 0 ; +} + +static const struct udevice_id exynos_gpio_ids[] = {
And Exynos?
Quoted 18 lines
drivers/gpio/sunxi_gpio.c +13
-0+ { .compatible = "allwinner,sun7i-a20-pinctrl" }, + { } +}; + +U_BOOT_DRIVER (gpio_sunxi) = { + .name ="gpio_sunxi" , + .id =UCLASS_GPIO , + .ops = &gpio_sunxi_ops, + .of_match = exynos_gpio_ids, + .bind = gpio_sunxi_bind, + .probe = gpio_sunxi_probe, +}; +#endif include/configs/sun7i.h +0
-0
include/configs/sun7i.h
Quoted 8 lines
include/configs/sun7i.h +1
-1@@ -38,6 +38,7 @@#if !defined(CONFIG_SPL_BUILD ) && defined(CONFIG_DM )# define CONFIG_CMD_DM +# define CONFIG_DM_GPIO #endif /* --
ChenYu
PATCH 7/23 dm: sunxi: Add support for serial using driver model
In reply to Simon GlassAdd a driver for the designware serial UART used on sunxi. This just redirects to the normal ns16550 driver.
Add a stdout-path to the device tree so that the correct UART is chosen.
---
arch/arm/dts/sun7i-a20-pcduino3.dts | 4 ++++ drivers/serial/Makefile | 1 + drivers/serial/serial_dw.c | 39 +++++++++++++++++++++++++++++++++++++ include/configs/sun7i.h | 3 +++ include/configs/sunxi-common.h | 12 +++++++----- 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 drivers/serial/serial_dw.c
arch/arm/dts/sun7i-a20-pcduino3.dts +4 -0
@@ -20,6 +20,10 @@ model = "LinkSprite pcDuino3"; compatible = "linksprite,pcduino3", "allwinner,sun7i-a20"; + chosen { + stdout-path = &uart0; + }; + soc at 01c00000 { mmc0: mmc at 01c0f000 { pinctrl-names = "default";
drivers/serial/Makefile +1 -0
@@ -19,6 +19,7 @@ obj-$(CONFIG_ALTERA_UART) += altera_uart.o obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o +obj-$(CONFIG_DW_SERIAL) += serial_dw.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o
drivers/serial/serial_dw.c new file +39 -0
@@ -0,0 +1,39 @@ +/* +* Copyright (c) 2014 Google, Inc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <dm.h> +#include <ns16550.h> +#include <serial.h> + +static const struct udevice_id dw_serial_ids[] = { + { .compatible ="snps,dw-apb-uart" }, + { } +}; + +static int dw_serial_ofdata_to_platdata (struct udevice *dev) +{ +struct ns16550_platdata *plat =dev_get_platdata (dev); +int ret; + + ret =ns16550_serial_ofdata_to_platdata (dev); +if (ret) +return ret; + plat->clock =CONFIG_SYS_NS16550_CLK ; + +return 0 ; +} + +U_BOOT_DRIVER (serial_ns16550) = { + .name ="serial_dw" , + .id =UCLASS_SERIAL , + .of_match = dw_serial_ids, + .ofdata_to_platdata = dw_serial_ofdata_to_platdata, + .platdata_auto_alloc_size =sizeof (struct ns16550_platdata ), + .priv_auto_alloc_size =sizeof (struct NS16550 ), + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, +};
include/configs/sun7i.h +3 -0
@@ -39,6 +39,9 @@#if !defined(CONFIG_SPL_BUILD ) && defined(CONFIG_DM )# define CONFIG_CMD_DM # define CONFIG_DM_GPIO +# define CONFIG_DM_SERIAL +# define CONFIG_SYS_MALLOC_F_LEN (1 << 10) +# define CONFIG_DW_SERIAL #endif /*
include/configs/sunxi-common.h +7 -5
@@ -36,12 +36,14 @@#define CONFIG_SYS_NS16550 #define CONFIG_SYS_NS16550_SERIAL /* ns16550 reg in the low bits of cpu reg */ -#define CONFIG_SYS_NS16550_REG_SIZE -4#define CONFIG_SYS_NS16550_CLK 24000000 -#define CONFIG_SYS_NS16550_COM1 SUNXI_UART0_BASE -#define CONFIG_SYS_NS16550_COM2 SUNXI_UART1_BASE -#define CONFIG_SYS_NS16550_COM3 SUNXI_UART2_BASE -#define CONFIG_SYS_NS16550_COM4 SUNXI_UART3_BASE +#ifndef CONFIG_DM_SERIAL +# define CONFIG_SYS_NS16550_REG_SIZE -4 +# define CONFIG_SYS_NS16550_COM1 SUNXI_UART0_BASE +# define CONFIG_SYS_NS16550_COM2 SUNXI_UART1_BASE +# define CONFIG_SYS_NS16550_COM3 SUNXI_UART2_BASE +# define CONFIG_SYS_NS16550_COM4 SUNXI_UART3_BASE +#endif /* DRAM Base */ #define CONFIG_SYS_SDRAM_BASE 0x40000000
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 7/23 dm: sunxi: Add support for serial using driver model
Hi,
Quoted 11 lines · Simon Glass
Add a driver for the designware serial UART used on sunxi. This just redirects to the normal ns16550 driver.
Add a stdout-path to the device tree so that the correct UART is chosen.
Signed-off-by Simon Glass <[email protected]>---
arch/arm/dts/sun7i-a20-pcduino3.dts | 4 ++++ drivers/serial/Makefile | 1 + drivers/serial/serial_dw.c | 39 +++++++++++++++++++++++++++++++++++++
This should probably be 2 or more patches. The first one adds the serial driver. The second one adds a user.
And maybe a third to add "stdout-path"?
ChenYu
Quoted 122 lines
include/configs/sun7i.h | 3 +++ include/configs/sunxi-common.h | 12 +++++++----- 5 files changed, 54 insertions(+), 5 deletions(-) create mode 100644 drivers/serial/serial_dw.carch/arm/dts/sun7i-a20-pcduino3.dts +4
-0@@ -20,6 +20,10 @@ model = "LinkSprite pcDuino3"; compatible = "linksprite,pcduino3", "allwinner,sun7i-a20"; + chosen { + stdout-path = &uart0; + }; + soc at 01c00000 { mmc0: mmc at 01c0f000 { pinctrl-names = "default";drivers/serial/Makefile +1
-0@@ -19,6 +19,7 @@ obj-$(CONFIG_ALTERA_UART) += altera_uart.o obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o +obj-$(CONFIG_DW_SERIAL) += serial_dw.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.odrivers/serial/serial_dw.c new file +39
-0@@ -0,0 +1,39 @@ +/* +* Copyright (c) 2014 Google, Inc +* +* SPDX-License-Identifier: GPL-2.0+ +*/ + +#include <common.h> +#include <dm.h> +#include <ns16550.h> +#include <serial.h> + +static const struct udevice_id dw_serial_ids[] = { + { .compatible ="snps,dw-apb-uart" }, + { } +}; + +static int dw_serial_ofdata_to_platdata (struct udevice *dev) +{ +struct ns16550_platdata *plat =dev_get_platdata (dev); +int ret; + + ret =ns16550_serial_ofdata_to_platdata (dev); +if (ret) +return ret; + plat->clock =CONFIG_SYS_NS16550_CLK ; + +return 0 ; +} + +U_BOOT_DRIVER (serial_ns16550) = { + .name ="serial_dw" , + .id =UCLASS_SERIAL , + .of_match = dw_serial_ids, + .ofdata_to_platdata = dw_serial_ofdata_to_platdata, + .platdata_auto_alloc_size =sizeof (struct ns16550_platdata ), + .priv_auto_alloc_size =sizeof (struct NS16550 ), + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, +};include/configs/sun7i.h +3
-0@@ -39,6 +39,9 @@#if !defined(CONFIG_SPL_BUILD ) && defined(CONFIG_DM )# define CONFIG_CMD_DM # define CONFIG_DM_GPIO +# define CONFIG_DM_SERIAL +# define CONFIG_SYS_MALLOC_F_LEN (1 << 10) +# define CONFIG_DW_SERIAL #endif /* include/configs/sunxi-common.h +7
-6@@ -36,12 +36,14 @@#define CONFIG_SYS_NS16550 #define CONFIG_SYS_NS16550_SERIAL /* ns16550 reg in the low bits of cpu reg */ -#define CONFIG_SYS_NS16550_REG_SIZE -4#define CONFIG_SYS_NS16550_CLK 24000000 -#define CONFIG_SYS_NS16550_COM1 SUNXI_UART0_BASE -#define CONFIG_SYS_NS16550_COM2 SUNXI_UART1_BASE -#define CONFIG_SYS_NS16550_COM3 SUNXI_UART2_BASE -#define CONFIG_SYS_NS16550_COM4 SUNXI_UART3_BASE +#ifndef CONFIG_DM_SERIAL +# define CONFIG_SYS_NS16550_REG_SIZE -4 +# define CONFIG_SYS_NS16550_COM1 SUNXI_UART0_BASE +# define CONFIG_SYS_NS16550_COM2 SUNXI_UART1_BASE +# define CONFIG_SYS_NS16550_COM3 SUNXI_UART2_BASE +# define CONFIG_SYS_NS16550_COM4 SUNXI_UART3_BASE +#endif /* DRAM Base */ #define CONFIG_SYS_SDRAM_BASE 0x40000000 --2.1.0.rc2.206.gedb03e5
_______________________________________________
U-Boot mailing list
U-Boot at lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot
PATCH 8/23 dm: gpio: Implement GPIO reservation in the uclass
In reply to Simon GlassWe have several GPIO drivers now and all are doing similar things to record which GPIOs are reserved.
Move this logic into the uclass to make the drivers similar.
We retain the request()/free() methods since currently one driver does use these for setting up the pin.
---
drivers/gpio/gpio-uclass.c | 92 +++++++++++++++++++++++++++++++++++++++------- include/asm-generic/gpio.h | 6 +++ 2 files changed, 84 insertions(+), 14 deletions(-)
drivers/gpio/gpio-uclass.c +78 -14
@@ -7,6 +7,7 @@#include <common.h> #include <dm.h> #include <errno.h> +#include <malloc.h> #include <asm/gpio.h> #include <linux/ctype.h>
@@ -92,24 +93,41 @@ int gpio_lookup_name(const char *name, struct udevice **devp,* gpio: GPIO number * label: Name for the requested GPIO * +* The label is copied and allocated so the caller does not need to keep +* the pointer around. +* * 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_dev_priv *uc_priv;unsigned int offset;struct udevice *dev; +char *str;int ret; ret =gpio_to_device (gpio, &dev, &offset);if (ret)return ret; -if (!gpio_get_ops (dev)->request) -return 0 ; + uc_priv = dev->uclass_priv; +if (uc_priv->name[offset]) +return -EBUSY ; + str =strdup (label); +if (!str) +return -ENOMEM ; +if (gpio_get_ops (dev)->request) { + ret =gpio_get_ops (dev)->request (dev, offset, label); +if (ret) { +free (str); +return ret; + } + } + uc_priv->name[offset] = str; -return gpio_get_ops (dev)->request (dev, offset, label); +return 0 ; }/**
@@ -122,6 +140,7 @@ int gpio_request(unsigned gpio, const char *label)*/ int gpio_free (unsigned gpio) { +struct gpio_dev_priv *uc_priv;unsigned int offset;struct udevice *dev;int ret;
@@ -130,9 +149,34 @@ int gpio_free(unsigned gpio)if (ret)return ret; -if (!gpio_get_ops (dev)->free) -return 0 ; -return gpio_get_ops (dev)->free (dev, offset); + uc_priv = dev->uclass_priv; +if (!uc_priv->name[offset]) +return -ENXIO ; +if (gpio_get_ops (dev)->free) { + ret =gpio_get_ops (dev)->free (dev, offset); +if (ret) +return ret; + } + +free (uc_priv->name[offset]); + uc_priv->name[offset] =NULL ; + +return 0 ; +} + +static int check_reserved (struct udevice *dev,unsigned offset, +const char *func) +{ +struct gpio_dev_priv *uc_priv = dev->uclass_priv; + +if (!uc_priv->name[offset]) { +printf ("%s: %s: error: gpio %s%d not reserved\n" , + dev->name, func, + uc_priv->bank_name ? uc_priv->bank_name :"" , offset); +return -EBUSY ; + } + +return 0 ; }/**
@@ -152,8 +196,9 @@ int gpio_direction_input(unsigned gpio) ret =gpio_to_device (gpio, &dev, &offset);if (ret)return ret; + ret =check_reserved (dev, offset,"dir_input" ); -return gpio_get_ops (dev)->direction_input (dev, offset); +return ret ? ret :gpio_get_ops (dev)->direction_input (dev, offset); }/**
@@ -174,8 +219,10 @@ int gpio_direction_output(unsigned gpio, int value) ret =gpio_to_device (gpio, &dev, &offset);if (ret)return ret; + ret =check_reserved (dev, offset,"dir_output" ); -return gpio_get_ops (dev)->direction_output (dev, offset, value); +return ret ? ret : +gpio_get_ops (dev)->direction_output (dev, offset, value); }/**
@@ -196,8 +243,9 @@ int gpio_get_value(unsigned gpio) ret =gpio_to_device (gpio, &dev, &offset);if (ret)return ret; + ret =check_reserved (dev, offset,"get_value" ); -return gpio_get_ops (dev)->get_value (dev, offset); +return ret ? ret :gpio_get_ops (dev)->get_value (dev, offset); }/**
@@ -218,8 +266,9 @@ int gpio_set_value(unsigned gpio, int value) ret =gpio_to_device (gpio, &dev, &offset);if (ret)return ret; + ret =check_reserved (dev, offset,"set_value" ); -return gpio_get_ops (dev)->set_value (dev, offset, value); +return ret ? ret :gpio_get_ops (dev)->set_value (dev, offset, value); }const char *gpio_get_bank_info (struct udevice *dev,int *bit_count)
@@ -235,7 +284,7 @@ const char *gpio_get_bank_info(struct udevice *dev, int *bit_count) }/* We need to renumber the GPIOs when any driver is probed/removed */ -static int gpio_renumber (void ) +static int gpio_renumber (struct udevice *removed_dev) {struct gpio_dev_priv *uc_priv;struct udevice *dev;
@@ -250,7 +299,7 @@ static int gpio_renumber(void)/* Ensure that we have a base for each bank */ base =0 ; uclass_foreach_dev(dev, uc) { -if (device_active (dev)) { +if (device_active (dev) && dev != removed_dev) { uc_priv = dev->uclass_priv; uc_priv->gpio_base = base; base += uc_priv->gpio_count;
@@ -262,12 +311,27 @@ static int gpio_renumber(void)static int gpio_post_probe (struct udevice *dev) { -return gpio_renumber (); +struct gpio_dev_priv *uc_priv = dev->uclass_priv; + + uc_priv->name =calloc (uc_priv->gpio_count,sizeof (char *)); +if (!uc_priv->name) +return -ENOMEM ; + +return gpio_renumber (NULL ); }static int gpio_pre_remove (struct udevice *dev) { -return gpio_renumber (); +struct gpio_dev_priv *uc_priv = dev->uclass_priv; +int i; + +for (i =0 ; i < uc_priv->gpio_count; i++) { +if (uc_priv->name[i]) +free (uc_priv->name[i]); + } +free (uc_priv->name); + +return gpio_renumber (dev); }UCLASS_DRIVER (gpio) = {
include/asm-generic/gpio.h +6 -0
@@ -29,6 +29,9 @@* Request a gpio. This should be called before any of the other functions * are used on this gpio. * +* Note: With driver model, the label is allocated so there is no need for +* the caller to preserve it. +* * @param gp GPIO number * @param label User label for this GPIO * @return 0 if ok, -1 on error
@@ -157,11 +160,14 @@ struct dm_gpio_ops {* @gpio_base: Base GPIO number for this device. For the first active device * this will be 0; the numbering for others will follow sequentially so that * @gpio_base for device 1 will equal the number of GPIOs in device 0. +* @name: Array of pointers to the name for each GPIO in this bank. The +* value of the pointer will be NULL if the GPIO has not been claimed. */ struct gpio_dev_priv {const char *bank_name;unsigned gpio_count;unsigned gpio_base; +char **name; };/* Access the GPIO operations for a device */
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 8/23 dm: gpio: Implement GPIO reservation in the uclass
Quoted 8 lines · Simon Glass
We have several GPIO drivers now and all are doing similar things to record which GPIOs are reserved.
Move this logic into the uclass to make the drivers similar.
We retain the request()/free() methods since currently one driver does use these for setting up the pin.
Quoted 6 lines
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/gpio-uclass.c | 92 +++++++++++++++++++++++++++++++++++++++------- include/asm-generic/gpio.h | 6 +++ 2 files changed, 84 insertions(+), 14 deletions(-)
Applied to u-boot-dm/master
PATCH 9/23 dm: gpio: Add gpio_get_function() and friends
In reply to Simon GlassAdd helpers to the uclass to allow finding out the pin function.
---
drivers/gpio/gpio-uclass.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ include/asm-generic/gpio.h | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-)
drivers/gpio/gpio-uclass.c +47 -0
@@ -283,6 +283,53 @@ const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)return priv->bank_name; } +static const char *const gpio_function[GPIOF_COUNT ] = { +"input" , +"output" , +"unused" , +"unknown" , +"func" , +}; + +int get_function (struct udevice *dev,int offset,bool skip_unused, +const char **namep) +{ +struct gpio_dev_priv *uc_priv = dev->uclass_priv; +struct dm_gpio_ops *ops =gpio_get_ops (dev); + +BUILD_BUG_ON (GPIOF_COUNT !=ARRAY_SIZE (gpio_function)); +if (!device_active (dev)) +return -ENODEV ; +if (offset <0 || offset >= uc_priv->gpio_count) +return -EINVAL ; +if (namep) + *namep = uc_priv->name[offset]; +if (skip_unused && !uc_priv->name[offset]) +return GPIOF_UNUSED ; +if (ops->get_function) { +int ret; + + ret = ops->get_function (dev, offset); +if (ret <0 ) +return ret; +if (ret >=ARRAY_SIZE (gpio_function)) +return -ENODATA ; +return ret; + } + +return GPIOF_UNKNOWN ; +} + +int gpio_get_function (struct udevice *dev,int offset,const char **namep) +{ +return get_function (dev, offset, true, namep); +} + +int gpio_get_raw_function (struct udevice *dev,int offset,const char **namep) +{ +return get_function (dev, offset, false, namep); +} +/* We need to renumber the GPIOs when any driver is probed/removed */ static int gpio_renumber (struct udevice *removed_dev) {
include/asm-generic/gpio.h +33 -1
@@ -83,7 +83,7 @@ int gpio_get_value(unsigned gpio);int gpio_set_value (unsigned gpio,int value);/* State of a GPIO, as reported by get_function() */ -enum { +enum gpio_func_t {GPIOF_INPUT =0 ,GPIOF_OUTPUT ,GPIOF_UNUSED ,/* Not claimed */
@@ -96,6 +96,38 @@ enum {struct udevice ;/** +* gpio_get_function() - get the current function for a GPIO pin +* +* Note this returns GPIOF_UNUSED if the GPIO is not requested. +* +* @dev: Device to check +* @offset: Offset of device GPIO to check +* @namep: If non-NULL, this is set to the nane given when the GPIO +* was requested, or -1 if it has not been requested +* @return -ENODATA if the driver returned an unknown function, +* -ENODEV if the device is not active, -EINVAL if the offset is invalid. +* GPIOF_UNUSED if the GPIO has not been requested. Otherwise returns the +* function from enum gpio_func_t. +*/ +int gpio_get_function (struct udevice *dev,int offset,const char **namep); + +/** +* gpio_get_raw_function() - get the current raw function for a GPIO pin +* +* Note this does not return GPIOF_UNUSED - it will always return the GPIO +* driver's view of a pin function, even if it is not correctly set up. +* +* @dev: Device to check +* @offset: Offset of device GPIO to check +* @namep: If non-NULL, this is set to the nane given when the GPIO +* was requested, or -1 if it has not been requested +* @return -ENODATA if the driver returned an unknown function, +* -ENODEV if the device is not active, -EINVAL if the offset is invalid. +* Otherwise returns the function from enum gpio_func_t. +*/ +int gpio_get_raw_function (struct udevice *dev,int offset,const char **namep); + +/** * struct struct dm_gpio_ops - Driver model GPIO operations * * Refer to functions above for description. These function largely copy
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 9/23 dm: gpio: Add gpio_get_function() and friends
Quoted 8 lines · Simon Glass
Add helpers to the uclass to allow finding out the pin function.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/gpio-uclass.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ include/asm-generic/gpio.h | 34 ++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-)
Applied to u-boot-dm/master
PATCH 10/23 dm: Move the function for getting GPIO status into the uclass
In reply to Simon GlassThis function can be more easily tested if it is in the uclass.
---
common/cmd_gpio.c | 57 +++++++++++++++++----------------------------- drivers/gpio/gpio-uclass.c | 39 +++++++++++++++++++++++++++++++ include/asm-generic/gpio.h | 18 +++++++++++++++ 3 files changed, 78 insertions(+), 36 deletions(-)
common/cmd_gpio.c +21 -36
@@ -25,13 +25,6 @@ enum gpio_cmd { };#if defined(CONFIG_DM_GPIO ) && !defined(gpio_status) -static const char *const gpio_function[GPIOF_COUNT ] = { -"input" , -"output" , -"unused" , -"unknown" , -"func" , -};/* A few flags used by show_gpio() */ enum {
@@ -40,22 +33,16 @@ enum { FLAG_SHOW_NEWLINE = 1 << 2, }; -static void show_gpio (struct udevice *dev,const char *bank_name,int offset, -int *flagsp) +static void gpio_get_description (struct udevice *dev,const char *bank_name, +int offset,int *flagsp) { -struct dm_gpio_ops *ops =gpio_get_ops (dev); -int func =GPIOF_UNKNOWN ;char buf[80 ];int ret; -BUILD_BUG_ON (GPIOF_COUNT !=ARRAY_SIZE (gpio_function)); - -if (ops->get_function) { - ret = ops->get_function (dev, offset); -if (ret >=0 && ret <ARRAY_SIZE (gpio_function)) - func = ret; - } -if (!(*flagsp &FLAG_SHOW_ALL ) && func ==GPIOF_UNUSED ) + ret =gpio_get_function (dev, offset,NULL ); +if (ret <0 ) + goto err; +if (!(*flagsp &FLAG_SHOW_ALL ) && ret ==GPIOF_UNUSED )return ;if ((*flagsp &FLAG_SHOW_BANK ) && bank_name) {if (*flagsp &FLAG_SHOW_NEWLINE ) {
@@ -65,20 +52,15 @@ static void show_gpio(struct udevice *dev, const char *bank_name, int offset,printf ("Bank %s:\n" , bank_name); *flagsp &= ~FLAG_SHOW_BANK ; } - *buf ='\0' ; -if (ops->get_state) { - ret = ops->get_state (dev, offset, buf,sizeof (buf)); -if (ret) { -puts ("<unknown>" ); -return ; - } - }else { -sprintf (buf,"%s%u: %8s %d" , bank_name, offset, - gpio_function[func], ops->get_value (dev, offset)); - } -puts (buf); -puts ("\n" ); + ret =gpio_get_status (dev, offset, buf,sizeof (buf)); +if (ret) + goto err; + +printf ("%s\n" , buf); +return ; +err: +printf ("Error %d\n" , ret); }static int do_gpio_status (bool all,const char *gpio_name)
@@ -101,8 +83,10 @@ static int do_gpio_status(bool all, const char *gpio_name)if (all) flags |=FLAG_SHOW_ALL ; bank_name =gpio_get_bank_info (dev, &num_bits); -if (!num_bits) +if (!num_bits) { +debug ("GPIO device %s has no bits\n" , dev->name);continue ; + } banklen = bank_name ?strlen (bank_name) :0 ; if (!gpio_name || !bank_name ||
@@ -113,11 +97,12 @@ static int do_gpio_status(bool all, const char *gpio_name) p = gpio_name + banklen;if (gpio_name && *p) { offset =simple_strtoul (p,NULL ,10 ); -show_gpio (dev, bank_name, offset, &flags); +gpio_get_description (dev, bank_name, offset, + &flags); }else {for (offset =0 ; offset < num_bits; offset++) { -show_gpio (dev, bank_name, offset, - &flags); +gpio_get_description (dev, bank_name, + offset, &flags); } } }
drivers/gpio/gpio-uclass.c +39 -0
@@ -330,6 +330,45 @@ int gpio_get_raw_function(struct udevice *dev, int offset, const char **namep)return get_function (dev, offset, false, namep); } +int gpio_get_status (struct udevice *dev,int offset,char *buf,int buffsize) +{ +struct dm_gpio_ops *ops =gpio_get_ops (dev); +struct gpio_dev_priv *priv; +char *str = buf; +int func; +int ret; +int len; + +BUILD_BUG_ON (GPIOF_COUNT !=ARRAY_SIZE (gpio_function)); + + *buf =0 ; + priv = dev->uclass_priv; + ret =gpio_get_raw_function (dev, offset,NULL ); +if (ret <0 ) +return ret; + func = ret; + len =snprintf (str, buffsize,"%s%d: %s" , + priv->bank_name ? priv->bank_name :"" , + offset, gpio_function[func]); +if (func ==GPIOF_INPUT || func ==GPIOF_OUTPUT || + func ==GPIOF_UNUSED ) { +const char *label; +bool used; + + ret = ops->get_value (dev, offset); +if (ret <0 ) +return ret; + used =gpio_get_function (dev, offset, &label) !=GPIOF_UNUSED ; +snprintf (str + len, buffsize - len,": %d [%c]%s%s" , + ret, + used ?'x' :' ' , + used ?" " :"" , + label ? label :"" ); + } + +return 0 ; +} +/* We need to renumber the GPIOs when any driver is probed/removed */ static int gpio_renumber (struct udevice *removed_dev) {
include/asm-generic/gpio.h +18 -0
@@ -96,6 +96,24 @@ enum gpio_func_t {struct udevice ;/** +* gpio_get_status() - get the current GPIO status as a string +* +* Obtain the current GPIO status as a string which can be presented to the +* user. A typical string is: +* +* "b4: in: 1 [x] sdmmc_cd" +* +* which means this is GPIO bank b, offset 4, currently set to input, current +* value 1, [x] means that it is requested and the owner is 'sdmmc_cd' +* +* @dev: Device to check +* @offset: Offset of device GPIO to check +* @buf: Place to put string +* @buffsize: Size of string including \0 +*/ +int gpio_get_status (struct udevice *dev,int offset,char *buf,int buffsize); + +/** * gpio_get_function() - get the current function for a GPIO pin * * Note this returns GPIOF_UNUSED if the GPIO is not requested.
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 10/23 dm: Move the function for getting GPIO status into the uclass
Quoted 9 lines · Simon Glass
This function can be more easily tested if it is in the uclass.
Signed-off-by Simon Glass <[email protected]>---
common/cmd_gpio.c | 57 +++++++++++++++++----------------------------- drivers/gpio/gpio-uclass.c | 39 +++++++++++++++++++++++++++++++ include/asm-generic/gpio.h | 18 +++++++++++++++ 3 files changed, 78 insertions(+), 36 deletions(-)
Applied to u-boot-dm/master
PATCH 11/23 dm: gpio: sandbox: Implement the get_function() method
In reply to Simon GlassImplement this method so that the 'gpio' command can do its job correctly. For sandbox we only support input and output states for a gpio.
---
drivers/gpio/sandbox.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/gpio/sandbox.c +8 -1
@@ -203,6 +203,13 @@ static int sb_gpio_get_state(struct udevice *dev, unsigned int offset,return 0 ; } +static int sb_gpio_get_function (struct udevice *dev,unsigned offset) +{ +if (get_gpio_flag (dev, offset,GPIOF_OUTPUT )) +return GPIOF_OUTPUT ; +return GPIOF_INPUT ; +} +static const struct dm_gpio_ops gpio_sandbox_ops = { .request = sb_gpio_request, .free = sb_gpio_free,
@@ -210,7 +217,7 @@ static const struct dm_gpio_ops gpio_sandbox_ops = { .direction_output = sb_gpio_direction_output, .get_value = sb_gpio_get_value, .set_value = sb_gpio_set_value, - .get_state = sb_gpio_get_state, + .get_function = sb_gpio_get_function, };static int sandbox_gpio_ofdata_to_platdata (struct udevice *dev)
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 11/23 dm: gpio: sandbox: Implement the get_function() method
Quoted 8 lines · Simon Glass
Implement this method so that the 'gpio' command can do its job correctly. For sandbox we only support input and output states for a gpio.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/sandbox.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
Applied to u-boot-dm/master
PATCH 12/23 dm: gpio: sandbox: Implement the remove() method
In reply to Simon GlassThis method frees memory so we must make sure to implement it.
---
drivers/gpio/sandbox.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/gpio/sandbox.c +8 -0
@@ -246,6 +246,13 @@ static int gpio_sandbox_probe(struct udevice *dev)return 0 ; } +static int gpio_sandbox_remove (struct udevice *dev) +{ +free (dev->priv); + +return 0 ; +} +static const struct udevice_id sandbox_gpio_ids[] = { { .compatible ="sandbox,gpio" }, { }
@@ -257,5 +264,6 @@ U_BOOT_DRIVER(gpio_sandbox) = { .of_match = sandbox_gpio_ids, .ofdata_to_platdata = sandbox_gpio_ofdata_to_platdata, .probe = gpio_sandbox_probe, + .remove = gpio_sandbox_remove, .ops = &gpio_sandbox_ops, };
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 12/23 dm: gpio: sandbox: Implement the remove() method
Quoted 8 lines · Simon Glass
This method frees memory so we must make sure to implement it.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/sandbox.c | 8 ++++++++ 1 file changed, 8 insertions(+)
Applied to u-boot-dm/master
PATCH 13/23 dm: gpio: sandbox: Drop request()/free() in the driver
In reply to Simon GlassNow that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
---
drivers/gpio/sandbox.c | 82 -------------------------------------------------- 1 file changed, 82 deletions(-)
drivers/gpio/sandbox.c +0 -82
@@ -14,7 +14,6 @@ DECLARE_GLOBAL_DATA_PTR;/* Flags for each GPIO */ #define GPIOF_OUTPUT (1 << 0)/* Currently set as an output */ #define GPIOF_HIGH (1 << 1)/* Currently set high */ -#define GPIOF_RESERVED (1 << 2)/* Is in use / requested */ struct gpio_state {const char *label;/* label given by requester */
@@ -54,18 +53,6 @@ static int set_gpio_flag(struct udevice *dev, unsigned offset, int flag,return 0 ; } -static int check_reserved (struct udevice *dev,unsigned offset, -const char *func) -{ -if (!get_gpio_flag (dev, offset,GPIOF_RESERVED )) { -printf ("sandbox_gpio: %s: error: offset %u not reserved\n" , - func, offset); -return -1 ; - } - -return 0 ; -} -/* * Back-channel sandbox-internal-only access to GPIO state */
@@ -101,9 +88,6 @@ static int sb_gpio_direction_input(struct udevice *dev, unsigned offset) {debug ("%s: offset:%u\n" , __func__, offset); -if (check_reserved (dev, offset, __func__)) -return -1 ; -return sandbox_gpio_set_direction (dev, offset,0 ); }
@@ -113,9 +97,6 @@ static int sb_gpio_direction_output(struct udevice *dev, unsigned offset, {debug ("%s: offset:%u, value = %d\n" , __func__, offset, value); -if (check_reserved (dev, offset, __func__)) -return -1 ; -return sandbox_gpio_set_direction (dev, offset,1 ) |sandbox_gpio_set_value (dev, offset, value); }
@@ -125,9 +106,6 @@ static int sb_gpio_get_value(struct udevice *dev, unsigned offset) {debug ("%s: offset:%u\n" , __func__, offset); -if (check_reserved (dev, offset, __func__)) -return -1 ; -return sandbox_gpio_get_value (dev, offset); }
@@ -136,9 +114,6 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value) {debug ("%s: offset:%u, value = %d\n" , __func__, offset, value); -if (check_reserved (dev, offset, __func__)) -return -1 ; -if (!sandbox_gpio_get_direction (dev, offset)) {printf ("sandbox_gpio: error: set_value on input gpio %u\n" , offset);
@@ -148,61 +123,6 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)return sandbox_gpio_set_value (dev, offset, value); } -static int sb_gpio_request (struct udevice *dev,unsigned offset, -const char *label) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct gpio_state *state =dev_get_priv (dev); - -debug ("%s: offset:%u, label:%s\n" , __func__, offset, label); - -if (offset >= uc_priv->gpio_count) { -printf ("sandbox_gpio: error: invalid gpio %u\n" , offset); -return -1 ; - } - -if (get_gpio_flag (dev, offset,GPIOF_RESERVED )) { -printf ("sandbox_gpio: error: gpio %u already reserved\n" , - offset); -return -1 ; - } - - state[offset].label = label; -return set_gpio_flag (dev, offset,GPIOF_RESERVED ,1 ); -} - -static int sb_gpio_free (struct udevice *dev,unsigned offset) -{ -struct gpio_state *state =dev_get_priv (dev); - -debug ("%s: offset:%u\n" , __func__, offset); - -if (check_reserved (dev, offset, __func__)) -return -1 ; - - state[offset].label =NULL ; -return set_gpio_flag (dev, offset,GPIOF_RESERVED ,0 ); -} - -static int sb_gpio_get_state (struct udevice *dev,unsigned int offset, -char *buf,int bufsize) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct gpio_state *state =dev_get_priv (dev); -const char *label; - - label = state[offset].label; -snprintf (buf, bufsize,"%s%d: %s: %d [%c]%s%s" , - uc_priv->bank_name ? uc_priv->bank_name :"" , offset, -sandbox_gpio_get_direction (dev, offset) ?"out" :" in" , -sandbox_gpio_get_value (dev, offset), -get_gpio_flag (dev, offset,GPIOF_RESERVED ) ?'x' :' ' , - label ?" " :"" , - label ? label :"" ); - -return 0 ; -} -static int sb_gpio_get_function (struct udevice *dev,unsigned offset) {if (get_gpio_flag (dev, offset,GPIOF_OUTPUT ))
@@ -211,8 +131,6 @@ static int sb_gpio_get_function(struct udevice *dev, unsigned offset) }static const struct dm_gpio_ops gpio_sandbox_ops = { - .request = sb_gpio_request, - .free = sb_gpio_free, .direction_input = sb_gpio_direction_input, .direction_output = sb_gpio_direction_output, .get_value = sb_gpio_get_value,
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 13/23 dm: gpio: sandbox: Drop request()/free() in the driver
Quoted 8 lines · Simon Glass
Now that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/sandbox.c | 82 -------------------------------------------------- 1 file changed, 82 deletions(-)
Applied to u-boot-dm/master
PATCH 14/23 test: dm: Update GPIO tests for new gpio_request() method
In reply to Simon GlassNow that gpio_request() is handled by the uclass, updates the tests accordingly.
---
doc/driver-model/README.txt | 25 +++++++++++++++++++-- test/dm/gpio.c | 55 +++++++++++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 24 deletions(-)
doc/driver-model/README.txt +23 -2
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try: You should see something like this: <...U-Boot banner...> - Running 22 driver model tests + Running 26 driver model tests Test: dm_test_autobind Test: dm_test_autoprobe Test: dm_test_bus_children
@@ -115,7 +115,8 @@ You should see something like this: Device 'd-test': seq 3 is in use by 'b-test' Device 'a-test': seq 0 is in use by 'd-test' Test: dm_test_gpio - sandbox_gpio: sb_gpio_get_value: error: offset 4 not reserved + extra-gpios: get_value: error: gpio b5 not reserved + Test: dm_test_gpio_anon Test: dm_test_leak Test: dm_test_lifecycle Test: dm_test_operations
@@ -123,6 +124,26 @@ You should see something like this: Test: dm_test_platdata Test: dm_test_pre_reloc Test: dm_test_remove + Test: dm_test_spi_find + Invalid chip select 0:0 (err=-19) + SF: Failed to get idcodes + Device 'name-emul': seq 0 is in use by 'name-emul' + SF: Detected M25P16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB + Test: dm_test_spi_flash + 2097152 bytes written in 0 ms + SF: Detected M25P16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB + SPI flash test: + 0 erase: 0 ticks, 65536000 KiB/s 524288.000 Mbps + 1 check: 0 ticks, 65536000 KiB/s 524288.000 Mbps + 2 write: 0 ticks, 65536000 KiB/s 524288.000 Mbps + 3 read: 0 ticks, 65536000 KiB/s 524288.000 Mbps + Test passed + 0 erase: 0 ticks, 65536000 KiB/s 524288.000 Mbps + 1 check: 0 ticks, 65536000 KiB/s 524288.000 Mbps + 2 write: 0 ticks, 65536000 KiB/s 524288.000 Mbps + 3 read: 0 ticks, 65536000 KiB/s 524288.000 Mbps + Test: dm_test_spi_xfer + SF: Detected M25P16 with page size 256 Bytes, erase size 64 KiB, total 2 MiB Test: dm_test_uclass Test: dm_test_uclass_before_ready Failures: 0
test/dm/gpio.c +33 -22
95 lines not on this page · raw message
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 14/23 test: dm: Update GPIO tests for new gpio_request() method
Quoted 9 lines · Simon Glass
Now that
gpio_request()is handled by the uclass, updates the tests accordingly.Signed-off-by Simon Glass <[email protected]>---
doc/driver-model/README.txt | 25 +++++++++++++++++++-- test/dm/gpio.c | 55 +++++++++++++++++++++++++++------------------ 2 files changed, 56 insertions(+), 24 deletions(-)
Applied to u-boot-dm/master
PATCH 15/23 dm: gpio: Add gpio_requestf() helper for printf() strings
In reply to Simon GlassAdd a helper which permits a printf()-style format string for the requester string.
---
doc/driver-model/README.txt | 3 ++- drivers/gpio/gpio-uclass.c | 21 +++++++++++++++++++++ include/asm-generic/gpio.h | 10 ++++++++++ test/dm/gpio.c | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-)
doc/driver-model/README.txt +2 -1
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try: You should see something like this: <...U-Boot banner...> - Running 26 driver model tests + Running 27 driver model tests Test: dm_test_autobind Test: dm_test_autoprobe Test: dm_test_bus_children
@@ -117,6 +117,7 @@ You should see something like this: Test: dm_test_gpio extra-gpios: get_value: error: gpio b5 not reserved Test: dm_test_gpio_anon + Test: dm_test_gpio_requestf Test: dm_test_leak Test: dm_test_lifecycle Test: dm_test_operations
drivers/gpio/gpio-uclass.c +21 -0
@@ -131,6 +131,27 @@ int gpio_request(unsigned gpio, const char *label) }/** +* gpio_requestf() - [COMPAT] Request GPIO +* @gpio: GPIO number +* @fmt: Format string for the requested GPIO +* @...: Arguments for the printf() format string +* +* 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_requestf (unsigned gpio,const char *fmt, ...) +{ +va_list args; +char buf[40 ]; + +va_start (args, fmt); +vscnprintf (buf,sizeof (buf), fmt, args); +va_end (args); +return gpio_request (gpio, buf); +} + +/** * gpio_free() - [COMPAT] Relinquish GPIO * gpio: GPIO number *
include/asm-generic/gpio.h +10 -0
@@ -146,6 +146,16 @@ int gpio_get_function(struct udevice *dev, int offset, const char **namep);int gpio_get_raw_function (struct udevice *dev,int offset,const char **namep);/** +* gpio_requestf() - request a GPIO using a format string for the owner +* +* This is a helper function for gpio_request(). It allows you to provide +* a printf()-format string for the GPIO owner. It calls gpio_request() with +* the string that is created +*/ +int gpio_requestf (unsigned gpio,const char *fmt, ...) + __attribute__ ((format (__printf__,2 ,3 ))); + +/** * struct struct dm_gpio_ops - Driver model GPIO operations * * Refer to functions above for description. These function largely copy
test/dm/gpio.c +18 -0
@@ -120,3 +120,21 @@ static int dm_test_gpio_anon(struct dm_test_state *dms)return 0 ; }DM_TEST (dm_test_gpio_anon,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); + +/* Test that gpio_requestf() works as expected */ +static int dm_test_gpio_requestf (struct dm_test_state *dms) +{ +unsigned int offset, gpio; +struct udevice *dev; +char buf[80 ]; + +ut_assertok (gpio_lookup_name ("b5" , &dev, &offset, &gpio)); +ut_assertok (gpio_requestf (gpio,"testing %d %s" ,1 ,"hi" )); +sandbox_gpio_set_direction (dev, offset,1 ); +sandbox_gpio_set_value (dev, offset,1 ); +ut_assertok (gpio_get_status (dev, offset, buf,sizeof (buf))); +ut_asserteq_str ("b5: output: 1 [x] testing 1 hi" , buf); + +return 0 ; +} +DM_TEST (dm_test_gpio_requestf,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT );
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 15/23 dm: gpio: Add gpio_requestf() helper for printf() strings
Quoted 11 lines · Simon Glass
Add a helper which permits a printf()-style format string for the requester string.
Signed-off-by Simon Glass <[email protected]>---
doc/driver-model/README.txt | 3 ++- drivers/gpio/gpio-uclass.c | 21 +++++++++++++++++++++ include/asm-generic/gpio.h | 10 ++++++++++ test/dm/gpio.c | 18 ++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-)
Applied to u-boot-dm/master
PATCH 16/23 test: dm: Support memory leak checking as a core feature
In reply to Simon GlassCheck the state of the malloc() heap before each test is run, so that tests can verify that all is well at the end. Provide helper functions to mark the heap and to check that it returns to its initial state.
---
include/dm/test.h | 23 +++++++++++++++++++++++ test/dm/core.c | 46 ++++++++++++++++++++++++++++++---------------- test/dm/test-main.c | 2 ++ 3 files changed, 55 insertions(+), 16 deletions(-)
include/dm/test.h +23 -0
@@ -8,6 +8,7 @@#define __DM_TEST_H#include <dm.h> +#include <malloc.h> /** * struct dm_test_cdata - configuration data for test instance
@@ -120,6 +121,7 @@ struct dm_test_state {int force_fail_alloc;int skip_post_probe;struct udevice *removed; +struct mallinfo start; };/* Test flags for each test */
@@ -178,6 +180,27 @@ int dm_check_operations(struct dm_test_state *dms, struct udevice *dev,int dm_check_devices (struct dm_test_state *dms,int num_devices);/** +* dm_leak_check_start() - Prepare to check for a memory leak +* +* Call this before allocating memory to record the amount of memory being +* used. +* +* @dms: Overall test state +*/ +void dm_leak_check_start (struct dm_test_state *dms); + +/** +* dm_leak_check_end() - Check that no memory has leaked +* +* Call this after dm_leak_check_start() and after you have hopefuilly freed +* all the memory that was allocated. This function will print an error if +* it sees a different amount of total memory allocated than before. +* +* @dms: Overall test state +*/ int dm_leak_check_end (struct dm_test_state *dms); + + +/** * dm_test_main() - Run all the tests * * This runs all available driver model tests
test/dm/core.c +30 -16
68 lines not on this page · raw message
test/dm/test-main.c +2 -0
@@ -7,6 +7,7 @@#include <common.h> #include <dm.h> #include <errno.h> +#include <malloc.h> #include <dm/test.h> #include <dm/root.h> #include <dm/uclass-internal.h>
@@ -88,6 +89,7 @@ int dm_test_main(void)printf ("Test: %s\n" , test->name);ut_assertok (dm_test_init (dms)); + dms->start =mallinfo ();if (test->flags &DM_TESTF_SCAN_PDATA )ut_assertok (dm_scan_platdata (false));if (test->flags &DM_TESTF_PROBE_TEST )
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 16/23 test: dm: Support memory leak checking as a core feature
Quoted 11 lines · Simon Glass
Check the state of the
malloc()heap before each test is run, so that tests can verify that all is well at the end. Provide helper functions to mark the heap and to check that it returns to its initial state.Signed-off-by Simon Glass <[email protected]>---
include/dm/test.h | 23 +++++++++++++++++++++++ test/dm/core.c | 46 ++++++++++++++++++++++++++++++---------------- test/dm/test-main.c | 2 ++ 3 files changed, 55 insertions(+), 16 deletions(-)
Applied to u-boot-dm/master
PATCH 17/23 test: dm: Add additional GPIO tests
In reply to Simon GlassAdd tests for gpio_requestf() and for memory leaks.
---
doc/driver-model/README.txt | 5 ++++- test/dm/gpio.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-)
doc/driver-model/README.txt +4 -1
@@ -95,7 +95,7 @@ are provided in test/dm. To run them, try: You should see something like this: <...U-Boot banner...> - Running 27 driver model tests + Running 29 driver model tests Test: dm_test_autobind Test: dm_test_autoprobe Test: dm_test_bus_children
@@ -117,6 +117,9 @@ You should see something like this: Test: dm_test_gpio extra-gpios: get_value: error: gpio b5 not reserved Test: dm_test_gpio_anon + Test: dm_test_gpio_copy + Test: dm_test_gpio_leak + extra-gpios: get_value: error: gpio b5 not reserved Test: dm_test_gpio_requestf Test: dm_test_leak Test: dm_test_lifecycle
test/dm/gpio.c +38 -0
@@ -7,11 +7,14 @@#include <common.h> #include <fdtdec.h> #include <dm.h> +#include <dm/root.h> #include <dm/ut.h> #include <dm/test.h> #include <dm/util.h> #include <asm/gpio.h> +DECLARE_GLOBAL_DATA_PTR ; +/* Test that sandbox GPIOs work correctly */ static int dm_test_gpio (struct dm_test_state *dms) {
@@ -138,3 +141,38 @@ static int dm_test_gpio_requestf(struct dm_test_state *dms)return 0 ; }DM_TEST (dm_test_gpio_requestf,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); + +/* Test that gpio_request() copies its string */ +static int dm_test_gpio_copy (struct dm_test_state *dms) +{ +unsigned int offset, gpio; +struct udevice *dev; +char buf[80 ], name[10 ]; + +ut_assertok (gpio_lookup_name ("b6" , &dev, &offset, &gpio)); +strcpy (name,"odd_name" ); +ut_assertok (gpio_request (gpio, name)); +sandbox_gpio_set_direction (dev, offset,1 ); +sandbox_gpio_set_value (dev, offset,1 ); +ut_assertok (gpio_get_status (dev, offset, buf,sizeof (buf))); +ut_asserteq_str ("b6: output: 1 [x] odd_name" , buf); +strcpy (name,"nothing" ); +ut_assertok (gpio_get_status (dev, offset, buf,sizeof (buf))); +ut_asserteq_str ("b6: output: 1 [x] odd_name" , buf); + +return 0 ; +} +DM_TEST (dm_test_gpio_copy,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT ); + +/* Test that we don't leak memory with GPIOs */ +static int dm_test_gpio_leak (struct dm_test_state *dms) +{ +ut_assertok (dm_test_gpio (dms)); +ut_assertok (dm_test_gpio_anon (dms)); +ut_assertok (dm_test_gpio_requestf (dms)); +ut_assertok (dm_leak_check_end (dms)); + +return 0 ; +} + +DM_TEST (dm_test_gpio_leak,DM_TESTF_SCAN_PDATA |DM_TESTF_SCAN_FDT );
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 17/23 test: dm: Add additional GPIO tests
Quoted 8 lines · Simon Glass
Add tests for
gpio_requestf()and for memory leaks.Signed-off-by Simon Glass <[email protected]>---
doc/driver-model/README.txt | 5 ++++- test/dm/gpio.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-)
Applied to u-boot-dm/master
PATCH 18/23 dm: gpio: tegra: Drop request()/free() in the driver
In reply to Simon GlassNow that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
---
drivers/gpio/tegra_gpio.c | 110 ---------------------------------------------- 1 file changed, 110 deletions(-)
drivers/gpio/tegra_gpio.c +0 -110
@@ -39,7 +39,6 @@ struct tegra_gpio_platdata {/* Information about each port at run-time */ struct tegra_port_info { -char label[TEGRA_GPIOS_PER_PORT ][GPIO_NAME_SIZE ];struct gpio_ctlr_bank *bank;int base_gpio;/* Port number for this port (0, 1,.., n-1) */ };
@@ -132,21 +131,6 @@ static void set_level(unsigned gpio, int high)writel (u, &bank->gpio_out[GPIO_PORT (gpio)]); } -static int check_reserved (struct udevice *dev,unsigned offset, -const char *func) -{ -struct tegra_port_info *state =dev_get_priv (dev); -struct gpio_dev_priv *uc_priv = dev->uclass_priv; - -if (!*state->label[offset]) { -printf ("tegra_gpio: %s: error: gpio %s%d not reserved\n" , - func, uc_priv->bank_name, offset); -return -EBUSY ; - } - -return 0 ; -} -/* set GPIO pin 'gpio' as an output, with polarity 'value' */ int tegra_spl_gpio_direction_output (int gpio,int value) {
@@ -171,56 +155,16 @@ static int tegra_gpio_request(struct udevice *dev, unsigned offset, {struct tegra_port_info *state =dev_get_priv (dev); -if (*state->label[offset]) -return -EBUSY ; - -strncpy (state->label[offset], label,GPIO_NAME_SIZE ); - state->label[offset][GPIO_NAME_SIZE -1 ] ='\0' ; -/* Configure as a GPIO */ set_config (state->base_gpio + offset,1 );return 0 ; } -static int tegra_gpio_free (struct udevice *dev,unsigned offset) -{ -struct tegra_port_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret; - state->label[offset][0 ] ='\0' ; - -return 0 ; -} - -/* read GPIO OUT value of pin 'gpio' */ -static int tegra_gpio_get_output_value (unsigned gpio) -{ -struct gpio_ctlr *ctlr = (struct gpio_ctlr *)NV_PA_GPIO_BASE ; -struct gpio_ctlr_bank *bank = &ctlr->gpio_bank[GPIO_BANK (gpio)]; -int val; - -debug ("gpio_get_output_value: pin = %d (port %d:bit %d)\n" , - gpio,GPIO_FULLPORT (gpio),GPIO_BIT (gpio)); - - val =readl (&bank->gpio_out[GPIO_PORT (gpio)]); - -return (val >>GPIO_BIT (gpio)) &1 ; -} - -/* set GPIO pin 'gpio' as an input */ static int tegra_gpio_direction_input (struct udevice *dev,unsigned offset) {struct tegra_port_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO direction as input. */ set_direction (state->base_gpio + offset,0 );
@@ -234,11 +178,6 @@ static int tegra_gpio_direction_output(struct udevice *dev, unsigned offset, {struct tegra_port_info *state =dev_get_priv (dev);int gpio = state->base_gpio + offset; -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO output value. */ set_level (gpio, value);
@@ -254,13 +193,8 @@ static int tegra_gpio_get_value(struct udevice *dev, unsigned offset) {struct tegra_port_info *state =dev_get_priv (dev);int gpio = state->base_gpio + offset; -int ret;int val; - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret; -debug ("%s: pin = %d (port %d:bit %d)\n" , __func__, gpio,GPIO_FULLPORT (gpio),GPIO_BIT (gpio));
@@ -274,11 +208,6 @@ static int tegra_gpio_set_value(struct udevice *dev, unsigned offset, int value) {struct tegra_port_info *state =dev_get_priv (dev);int gpio = state->base_gpio + offset; -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;debug ("gpio_set_value: pin = %d (port %d:bit %d), value = %d\n" , gpio,GPIO_FULLPORT (gpio),GPIO_BIT (gpio), value);
@@ -314,8 +243,6 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset)struct tegra_port_info *state =dev_get_priv (dev);int gpio = state->base_gpio + offset; -if (!*state->label[offset]) -return GPIOF_UNUSED ;if (!get_config (gpio))return GPIOF_FUNC ;else if (get_direction (gpio))
@@ -324,50 +251,13 @@ static int tegra_gpio_get_function(struct udevice *dev, unsigned offset)return GPIOF_INPUT ; } -static int tegra_gpio_get_state (struct udevice *dev,unsigned int offset, -char *buf,int bufsize) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct tegra_port_info *state =dev_get_priv (dev); -int gpio = state->base_gpio + offset; -const char *label; -int is_output; -int is_gpio; -int size; - - label = state->label[offset]; - is_gpio =get_config (gpio);/* GPIO, not SFPIO */ - size =snprintf (buf, bufsize,"%s%d: " , - uc_priv->bank_name ? uc_priv->bank_name :"" , offset); - buf += size; - bufsize -= size; -if (is_gpio) { - is_output =get_direction (gpio); - -snprintf (buf, bufsize,"%s: %d [%c]%s%s" , - is_output ?"out" :" in" , - is_output ? -tegra_gpio_get_output_value (gpio) : -tegra_gpio_get_value (dev, offset), - *label ?'x' :' ' , - *label ?" " :"" , - label); - }else { -snprintf (buf, bufsize,"sfpio" ); - } - -return 0 ; -} -static const struct dm_gpio_ops gpio_tegra_ops = { .request = tegra_gpio_request, - .free = tegra_gpio_free, .direction_input = tegra_gpio_direction_input, .direction_output = tegra_gpio_direction_output, .get_value = tegra_gpio_get_value, .set_value = tegra_gpio_set_value, .get_function = tegra_gpio_get_function, - .get_state = tegra_gpio_get_state, };/**
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 18/23 dm: gpio: tegra: Drop request()/free() in the driver
Quoted 8 lines · Simon Glass
Now that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/tegra_gpio.c | 110 ---------------------------------------------- 1 file changed, 110 deletions(-)
Applied to u-boot-dm/master
PATCH 19/23 dm: gpio: omap3: Drop request()/free() in the driver
In reply to Simon GlassNow that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
---
drivers/gpio/omap_gpio.c | 116 +---------------------------------------------- 1 file changed, 1 insertion(+), 115 deletions(-)
drivers/gpio/omap_gpio.c +1 -115
@@ -29,11 +29,9 @@ #ifdef CONFIG_DM_GPIO -#define GPIO_NAME_SIZE 20 #define GPIO_PER_BANK 32 struct gpio_bank { - char label[GPIO_PER_BANK][GPIO_NAME_SIZE]; /* TODO(sjg at chromium.org): Can we use a struct here? */ void *base; /* address of registers in physical memory */ enum gpio_method method;
@@ -246,47 +244,10 @@ int gpio_free(unsigned gpio)#else /* new driver model interface CONFIG_DM_GPIO */ -/** -* gpio_is_requested() - check if a GPIO has been requested -* -* @bank: Bank to check -* @offset: GPIO offset within bank to check -* @return true if marked as requested, false if not -*/ -static inline bool gpio_is_requested (struct gpio_bank *bank,int offset) -{ -return *bank->label[offset] !='\0' ; -} - -static int omap_gpio_is_output (struct gpio_bank *bank,int offset) -{ -return _get_gpio_direction (bank, offset) ==OMAP_GPIO_DIR_OUT ; -} - -static int check_requested (struct udevice *dev,unsigned offset, -const char *func) -{ -struct gpio_bank *bank =dev_get_priv (dev); -struct gpio_dev_priv *uc_priv = dev->uclass_priv; - -if (!gpio_is_requested (bank, offset)) { -printf ("omap_gpio: %s: error: gpio %s%d not requested\n" , - func, uc_priv->bank_name, offset); -return -EPERM ; - } - -return 0 ; -} -/* set GPIO pin 'gpio' as an input */ static int omap_gpio_direction_input (struct udevice *dev,unsigned offset) {struct gpio_bank *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO direction as input. */ _set_gpio_direction (bank, offset,1 );
@@ -299,11 +260,6 @@ static int omap_gpio_direction_output(struct udevice *dev, unsigned offset, int value) {struct gpio_bank *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;_set_gpio_dataout (bank, offset, value);_set_gpio_direction (bank, offset,0 );
@@ -315,11 +271,6 @@ static int omap_gpio_direction_output(struct udevice *dev, unsigned offset,static int omap_gpio_get_value (struct udevice *dev,unsigned offset) {struct gpio_bank *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;return _get_gpio_value (bank, offset); }
@@ -329,94 +280,29 @@ static int omap_gpio_set_value(struct udevice *dev, unsigned offset, int value) {struct gpio_bank *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;_set_gpio_dataout (bank, offset, value);return 0 ; } -static int omap_gpio_get_state (struct udevice *dev,unsigned int offset, -char *buf,int bufsize) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct gpio_bank *bank =dev_get_priv (dev); -const char *label; -bool requested; -bool is_output; -int size; - - label = bank->label[offset]; - is_output =omap_gpio_is_output (bank->base, offset); - size =snprintf (buf, bufsize,"%s%d: " , - uc_priv->bank_name ? uc_priv->bank_name :"" , offset); - buf += size; - bufsize -= size; - requested =gpio_is_requested (bank, offset); -snprintf (buf, bufsize,"%s: %d [%c]%s%s" , - is_output ?"out" :" in" , -_get_gpio_value (bank, offset), - requested ?'x' :' ' , - requested ?" " :"" , - label); - -return 0 ; -} - -static int omap_gpio_request (struct udevice *dev,unsigned offset, -const char *label) -{ -struct gpio_bank *bank =dev_get_priv (dev); - -if (gpio_is_requested (bank, offset)) -return -EBUSY ; - -strncpy (bank->label[offset], label,GPIO_NAME_SIZE ); - bank->label[offset][GPIO_NAME_SIZE -1 ] ='\0' ; - -return 0 ; -} - -static int omap_gpio_free (struct udevice *dev,unsigned offset) -{ -struct gpio_bank *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret; - bank->label[offset][0 ] ='\0' ; - -return 0 ; -} -static int omap_gpio_get_function (struct udevice *dev,unsigned offset) {struct gpio_bank *bank =dev_get_priv (dev); -if (!gpio_is_requested (bank, offset)) -return GPIOF_UNUSED ; -/* GPIOF_FUNC is not implemented yet */ -if (_get_gpio_direction (bank->base, offset)) +if (_get_gpio_direction (bank->base, offset) ==OMAP_GPIO_DIR_OUT )return GPIOF_OUTPUT ;else return GPIOF_INPUT ; }static const struct dm_gpio_ops gpio_omap_ops = { - .request = omap_gpio_request, - .free = omap_gpio_free, .direction_input = omap_gpio_direction_input, .direction_output = omap_gpio_direction_output, .get_value = omap_gpio_get_value, .set_value = omap_gpio_set_value, .get_function = omap_gpio_get_function, - .get_state = omap_gpio_get_state, };static int omap_gpio_probe (struct udevice *dev)
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 19/23 dm: gpio: omap3: Drop request()/free() in the driver
Quoted 8 lines · Simon Glass
Now that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/omap_gpio.c | 116 +---------------------------------------------- 1 file changed, 1 insertion(+), 115 deletions(-)
Applied to u-boot-dm/master
PATCH 20/23 dm: gpio: rpi_b: Drop request()/free() in the driver
In reply to Simon GlassNow that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
---
drivers/gpio/bcm2835_gpio.c | 89 --------------------------------------------- 1 file changed, 89 deletions(-)
drivers/gpio/bcm2835_gpio.c +0 -89
@@ -11,67 +11,10 @@#include <asm/gpio.h> #include <asm/io.h> -#define GPIO_NAME_SIZE 20 -struct bcm2835_gpios { -char label[BCM2835_GPIO_COUNT ][GPIO_NAME_SIZE ];struct bcm2835_gpio_regs *reg; }; -/** -* gpio_is_requested() - check if a GPIO has been requested -* -* @bank: Bank to check -* @offset: GPIO offset within bank to check -* @return true if marked as requested, false if not -*/ -static inline bool gpio_is_requested (struct bcm2835_gpios *gpios,int offset) -{ -return *gpios->label[offset] !='\0' ; -} - -static int check_requested (struct udevice *dev,unsigned offset, -const char *func) -{ -struct bcm2835_gpios *gpios =dev_get_priv (dev); -struct gpio_dev_priv *uc_priv = dev->uclass_priv; - -if (!gpio_is_requested (gpios, offset)) { -printf ("omap_gpio: %s: error: gpio %s%d not requested\n" , - func, uc_priv->bank_name, offset); -return -EPERM ; - } - -return 0 ; -} - -static int bcm2835_gpio_request (struct udevice *dev,unsigned offset, -const char *label) -{ -struct bcm2835_gpios *gpios =dev_get_priv (dev); - -if (gpio_is_requested (gpios, offset)) -return -EBUSY ; - -strncpy (gpios->label[offset], label,GPIO_NAME_SIZE ); - gpios->label[offset][GPIO_NAME_SIZE -1 ] ='\0' ; - -return 0 ; -} - -static int bcm2835_gpio_free (struct udevice *dev,unsigned offset) -{ -struct bcm2835_gpios *gpios =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret; - gpios->label[offset][0 ] ='\0' ; - -return 0 ; -} -static int bcm2835_gpio_direction_input (struct udevice *dev,unsigned gpio) {struct bcm2835_gpios *gpios =dev_get_priv (dev);
@@ -142,9 +85,6 @@ static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset) {struct bcm2835_gpios *gpios =dev_get_priv (dev); -if (!gpio_is_requested (gpios, offset)) -return GPIOF_UNUSED ; -/* GPIOF_FUNC is not implemented yet */ if (bcm2835_gpio_is_output (gpios, offset))return GPIOF_OUTPUT ;
@@ -152,42 +92,13 @@ static int bcm2835_gpio_get_function(struct udevice *dev, unsigned offset)return GPIOF_INPUT ; } -static int bcm2835_gpio_get_state (struct udevice *dev,unsigned int offset, -char *buf,int bufsize) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct bcm2835_gpios *gpios =dev_get_priv (dev); -const char *label; -bool requested; -bool is_output; -int size; - - label = gpios->label[offset]; - is_output =bcm2835_gpio_is_output (gpios, offset); - size =snprintf (buf, bufsize,"%s%d: " , - uc_priv->bank_name ? uc_priv->bank_name :"" , offset); - buf += size; - bufsize -= size; - requested =gpio_is_requested (gpios, offset); -snprintf (buf, bufsize,"%s: %d [%c]%s%s" , - is_output ?"out" :" in" , -bcm2835_get_value (gpios, offset), - requested ?'x' :' ' , - requested ?" " :"" , - label); - -return 0 ; -}static const struct dm_gpio_ops gpio_bcm2835_ops = { - .request = bcm2835_gpio_request, - .free = bcm2835_gpio_free, .direction_input = bcm2835_gpio_direction_input, .direction_output = bcm2835_gpio_direction_output, .get_value = bcm2835_gpio_get_value, .set_value = bcm2835_gpio_set_value, .get_function = bcm2835_gpio_get_function, - .get_state = bcm2835_gpio_get_state, };static int bcm2835_gpio_probe (struct udevice *dev)
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 20/23 dm: gpio: rpi_b: Drop request()/free() in the driver
Quoted 8 lines · Simon Glass
Now that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/bcm2835_gpio.c | 89 --------------------------------------------- 1 file changed, 89 deletions(-)
Applied to u-boot-dm/master
PATCH 21/23 dm: gpio: exynos: Drop request()/free() in the driver
In reply to Simon GlassNow that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
---
drivers/gpio/s5p_gpio.c | 101 ------------------------------------------------ 1 file changed, 101 deletions(-)
drivers/gpio/s5p_gpio.c +0 -101
@@ -33,8 +33,6 @@ DECLARE_GLOBAL_DATA_PTR;#define RATE_MASK (gpio) (0x1 << (gpio + 16))#define RATE_SET (gpio) (0x1 << (gpio + 16)) -#define GPIO_NAME_SIZE 20 -/* Platform data for each bank */ struct exynos_gpio_platdata {struct s5p_gpio_bank *bank;
@@ -43,7 +41,6 @@ struct exynos_gpio_platdata {/* Information about each bank@run-time */ struct exynos_bank_info { -char label[GPIO_PER_BANK ][GPIO_NAME_SIZE ];struct s5p_gpio_bank *bank; };
@@ -189,61 +186,10 @@ int s5p_gpio_get_pin(unsigned gpio)/* Driver model interface */ #ifndef CONFIG_SPL_BUILD -static int exynos_gpio_get_state (struct udevice *dev,unsigned int offset, -char *buf,int bufsize) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct exynos_bank_info *state =dev_get_priv (dev); -const char *label; -bool is_output; -int size; -int cfg; - - label = state->label[offset]; - cfg =s5p_gpio_get_cfg_pin (state->bank, offset); - is_output = cfg ==S5P_GPIO_OUTPUT ; - size =snprintf (buf, bufsize,"%s%d: " , - uc_priv->bank_name ? uc_priv->bank_name :"" , offset); - buf += size; - bufsize -= size; -if (is_output || cfg ==S5P_GPIO_INPUT ) { -snprintf (buf, bufsize,"%s: %d [%c]%s%s" , - is_output ?"out" :" in" , -s5p_gpio_get_value (state->bank, offset), - *label ?'x' :' ' , - *label ?" " :"" , - label); - }else { -snprintf (buf, bufsize,"sfpio" ); - } - -return 0 ; -} - -static int check_reserved (struct udevice *dev,unsigned offset, -const char *func) -{ -struct exynos_bank_info *state =dev_get_priv (dev); -struct gpio_dev_priv *uc_priv = dev->uclass_priv; - -if (!*state->label[offset]) { -printf ("exynos_gpio: %s: error: gpio %s%d not reserved\n" , - func, uc_priv->bank_name, offset); -return -EPERM ; - } - -return 0 ; -} -/* set GPIO pin 'gpio' as an input */ static int exynos_gpio_direction_input (struct udevice *dev,unsigned offset) {struct exynos_bank_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO direction as input. */ s5p_gpio_cfg_pin (state->bank, offset,S5P_GPIO_INPUT );
@@ -256,11 +202,6 @@ static int exynos_gpio_direction_output(struct udevice *dev, unsigned offset, int value) {struct exynos_bank_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO output value. */ s5p_gpio_set_value (state->bank, offset, value);
@@ -275,11 +216,6 @@ static int exynos_gpio_direction_output(struct udevice *dev, unsigned offset,static int exynos_gpio_get_value (struct udevice *dev,unsigned offset) {struct exynos_bank_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;return s5p_gpio_get_value (state->bank, offset); }
@@ -289,43 +225,11 @@ static int exynos_gpio_set_value(struct udevice *dev, unsigned offset, int value) {struct exynos_bank_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret;s5p_gpio_set_value (state->bank, offset, value);return 0 ; } - -static int exynos_gpio_request (struct udevice *dev,unsigned offset, -const char *label) -{ -struct exynos_bank_info *state =dev_get_priv (dev); - -if (*state->label[offset]) -return -EBUSY ; - -strncpy (state->label[offset], label,GPIO_NAME_SIZE ); - state->label[offset][GPIO_NAME_SIZE -1 ] ='\0' ; - -return 0 ; -} - -static int exynos_gpio_free (struct udevice *dev,unsigned offset) -{ -struct exynos_bank_info *state =dev_get_priv (dev); -int ret; - - ret =check_reserved (dev, offset, __func__); -if (ret) -return ret; - state->label[offset][0 ] ='\0' ; - -return 0 ; -}#endif /* nCONFIG_SPL_BUILD */ /*
@@ -362,8 +266,6 @@ static int exynos_gpio_get_function(struct udevice *dev, unsigned offset)struct exynos_bank_info *state =dev_get_priv (dev);int cfg; -if (!*state->label[offset]) -return GPIOF_UNUSED ; cfg =s5p_gpio_get_cfg_pin (state->bank, offset);if (cfg ==S5P_GPIO_OUTPUT )return GPIOF_OUTPUT ;
@@ -374,14 +276,11 @@ static int exynos_gpio_get_function(struct udevice *dev, unsigned offset) }static const struct dm_gpio_ops gpio_exynos_ops = { - .request = exynos_gpio_request, - .free = exynos_gpio_free, .direction_input = exynos_gpio_direction_input, .direction_output = exynos_gpio_direction_output, .get_value = exynos_gpio_get_value, .set_value = exynos_gpio_set_value, .get_function = exynos_gpio_get_function, - .get_state = exynos_gpio_get_state, };static int gpio_exynos_probe (struct udevice *dev)
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 21/23 dm: gpio: exynos: Drop request()/free() in the driver
Quoted 8 lines · Simon Glass
Now that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/s5p_gpio.c | 101 ------------------------------------------------ 1 file changed, 101 deletions(-)
Applied to u-boot-dm/master
PATCH 22/23 dm: gpio: imx: Drop request()/free() in the driver
In reply to Simon GlassNow that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
---
drivers/gpio/mxc_gpio.c | 116 ------------------------------------------------ 1 file changed, 116 deletions(-)
drivers/gpio/mxc_gpio.c +0 -116
@@ -20,7 +20,6 @@ enum mxc_gpio_direction { MXC_GPIO_DIRECTION_OUT, }; -#define GPIO_NAME_SIZE 20#define GPIO_PER_BANK 32struct mxc_gpio_plat {
@@ -28,7 +27,6 @@ struct mxc_gpio_plat { };struct mxc_bank_info { -char label[GPIO_PER_BANK ][GPIO_NAME_SIZE ];struct gpio_regs *regs; };
@@ -152,18 +150,6 @@ int gpio_direction_output(unsigned gpio, int value)#endif #ifdef CONFIG_DM_GPIO -/** -* gpio_is_requested() - check if a GPIO has been requested -* -* @bank: Bank to check -* @offset: GPIO offset within bank to check -* @return true if marked as requested, false if not -*/ -static inline bool gpio_is_requested (struct mxc_bank_info *bank,int offset) -{ -return *bank->label[offset] !='\0' ; -} -static int mxc_gpio_is_output (struct gpio_regs *regs,int offset) {u32 val;
@@ -208,35 +194,10 @@ static int mxc_gpio_bank_get_value(struct gpio_regs *regs, int offset)return (readl (®s->gpio_psr) >> offset) &0x01 ; } -static int mxc_gpio_bank_get_output_value (struct gpio_regs *regs,int offset) -{ -return (readl (®s->gpio_dr) >> offset) &0x01 ; -} - -static int check_requested (struct udevice *dev,unsigned offset, -const char *func) -{ -struct mxc_bank_info *bank =dev_get_priv (dev); -struct gpio_dev_priv *uc_priv = dev->uclass_priv; - -if (!gpio_is_requested (bank, offset)) { -printf ("mxc_gpio: %s: error: gpio %s%d not requested\n" , - func, uc_priv->bank_name, offset); -return -EPERM ; - } - -return 0 ; -} -/* set GPIO pin 'gpio' as an input */ static int mxc_gpio_direction_input (struct udevice *dev,unsigned offset) {struct mxc_bank_info *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO direction as input. */ mxc_gpio_bank_direction (bank->regs, offset,MXC_GPIO_DIRECTION_IN );
@@ -249,11 +210,6 @@ static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset, int value) {struct mxc_bank_info *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;/* Configure GPIO output value. */ mxc_gpio_bank_set_value (bank->regs, offset, value);
@@ -268,11 +224,6 @@ static int mxc_gpio_direction_output(struct udevice *dev, unsigned offset,static int mxc_gpio_get_value (struct udevice *dev,unsigned offset) {struct mxc_bank_info *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;return mxc_gpio_bank_get_value (bank->regs, offset); }
@@ -282,80 +233,16 @@ static int mxc_gpio_set_value(struct udevice *dev, unsigned offset, int value) {struct mxc_bank_info *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret;mxc_gpio_bank_set_value (bank->regs, offset, value);return 0 ; } -static int mxc_gpio_get_state (struct udevice *dev,unsigned int offset, -char *buf,int bufsize) -{ -struct gpio_dev_priv *uc_priv = dev->uclass_priv; -struct mxc_bank_info *bank =dev_get_priv (dev); -const char *label; -bool requested; -bool is_output; -int size; - - label = bank->label[offset]; - is_output =mxc_gpio_is_output (bank->regs, offset); - size =snprintf (buf, bufsize,"%s%d: " , - uc_priv->bank_name ? uc_priv->bank_name :"" , offset); - buf += size; - bufsize -= size; - requested =gpio_is_requested (bank, offset); -snprintf (buf, bufsize,"%s: %d [%c]%s%s" , - is_output ?"out" :" in" , - is_output ? -mxc_gpio_bank_get_output_value (bank->regs, offset) : -mxc_gpio_bank_get_value (bank->regs, offset), - requested ?'x' :' ' , - requested ?" " :"" , - label); - -return 0 ; -} - -static int mxc_gpio_request (struct udevice *dev,unsigned offset, -const char *label) -{ -struct mxc_bank_info *bank =dev_get_priv (dev); - -if (gpio_is_requested (bank, offset)) -return -EBUSY ; - -strncpy (bank->label[offset], label,GPIO_NAME_SIZE ); - bank->label[offset][GPIO_NAME_SIZE -1 ] ='\0' ; - -return 0 ; -} - -static int mxc_gpio_free (struct udevice *dev,unsigned offset) -{ -struct mxc_bank_info *bank =dev_get_priv (dev); -int ret; - - ret =check_requested (dev, offset, __func__); -if (ret) -return ret; - bank->label[offset][0 ] ='\0' ; - -return 0 ; -} -static int mxc_gpio_get_function (struct udevice *dev,unsigned offset) {struct mxc_bank_info *bank =dev_get_priv (dev); -if (!gpio_is_requested (bank, offset)) -return GPIOF_UNUSED ; -/* GPIOF_FUNC is not implemented yet */ if (mxc_gpio_is_output (bank->regs, offset))return GPIOF_OUTPUT ;
@@ -364,14 +251,11 @@ static int mxc_gpio_get_function(struct udevice *dev, unsigned offset) }static const struct dm_gpio_ops gpio_mxc_ops = { - .request = mxc_gpio_request, - .free = mxc_gpio_free, .direction_input = mxc_gpio_direction_input, .direction_output = mxc_gpio_direction_output, .get_value = mxc_gpio_get_value, .set_value = mxc_gpio_set_value, .get_function = mxc_gpio_get_function, - .get_state = mxc_gpio_get_state, };static const struct mxc_gpio_plat mxc_plat[] = {
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 22/23 dm: gpio: imx: Drop request()/free() in the driver
Quoted 8 lines · Simon Glass
Now that the uclass supports gpio_request/free() there is no need for the driver to implement it too. Drop this unnecessary code.
Signed-off-by Simon Glass <[email protected]>---
drivers/gpio/mxc_gpio.c | 116 ------------------------------------------------ 1 file changed, 116 deletions(-)
Applied to u-boot-dm/master
PATCH 23/23 dm: gpio: Remove unused get_state() uclass method
In reply to Simon GlassThis is no longer used so drop it.
---
include/asm-generic/gpio.h | 2 -- 1 file changed, 2 deletions(-)
include/asm-generic/gpio.h +0 -2
@@ -198,8 +198,6 @@ struct dm_gpio_ops {* @return current function - GPIOF_... */ int (*get_function)(struct udevice *dev,unsigned offset); -int (*get_state)(struct udevice *dev,unsigned offset,char *state, -int maxlen); };/**
Signature · 1 line
2.1.0.rc2.206.gedb03e5
PATCH 23/23 dm: gpio: Remove unused get_state() uclass method
Quoted 7 lines · Simon Glass
This is no longer used so drop it.
Signed-off-by Simon Glass <[email protected]>---
include/asm-generic/gpio.h | 2 -- 1 file changed, 2 deletions(-)
Applied to u-boot-dm/master
cover dm: Introduce driver model for sunxi
In reply to Simon GlassHi,
Quoted 20 lines · Simon Glass
This series adds driver model support for serial and GPIO for sunxi. Since I only have a sun7i board to test with, I have added a new config for the pcDuino3, which uses device tree and driver model. This should make it fairly easy to enable for the other boards at some point.
Now that we have about 5 GPIO drivers it is clear that the request()/free() logic should be in the uclass rather than the driver. So far drivers don't have to do anything in those methods except adjust pin configuration. Patches are included to make this change, including removing the redundant code in the various GPIO drivers. The sunxi driver works the same way.
So far at least GPIO drivers don't tend to have anything special to report for the 'gpio status' command. Partly this is because we only support a simple concept of GPIOs so far (no drive strength, function selection, etc.) but even if this were to be supported it would be better to handle it generically where possible. So the
get_state()call can be replaced with a generic one in the uclass. This can be implemented with the existing uclass interface:get_function()to find out if the pin is set as an input, output or not a GPIO, andget_value()to find its value.
Quoted 5 lines
As a result, it is safe to remove the
get_state()method, and this series does that also.This series is available at u-boot-dm/sunix-working.
Any more comments on this series please? I have a few nits so could respin.
Regards,
Simon
cover dm: Introduce driver model for sunxi
Quoted 2 lines · Simon Glass
Any more comments on this series please? I have a few nits so could respin.
I'm afraid I'm unlikely to get to look at this before the w/e. It looks like the majority of the series isn't actually about sunxi though?
Without having looked at the specifics I can say I'm broadly in favour of moving towards Device Model / Device Tree.
Ian.
cover dm: Introduce driver model for sunxi
Hi,
Quoted 7 lines · Ian Campbell
Quoted 2 lines · Simon Glass
Any more comments on this series please? I have a few nits so could respin.
I'm afraid I'm unlikely to get to look at this before the w/e. It looks like the majority of the series isn't actually about sunxi though?
Right, could v2 please be split into a generic series and a sunxi series on top of that, so that Ian and I can focus on reviewing the sunxi bits, and the wider community can hopefully review the generic bits ?
Quoted 2 lines
Without having looked at the specifics I can say I'm broadly in favour of moving towards Device Model / Device Tree.
Ack.
Regards,
Hans
cover dm: Introduce driver model for sunxi
HI Hans,
Quoted 8 lines · Hans de Goede
Hi,
Quoted 5 lines · Ian Campbell
Quoted 2 lines · Simon Glass
Any more comments on this series please? I have a few nits so could respin.
Quoted 6 lines
Quoted 2 lines
I'm afraid I'm unlikely to get to look at this before the w/e. It looks like the majority of the series isn't actually about sunxi though?
Right, could v2 please be split into a generic series and a sunxi series on top of that, so that Ian and I can focus on reviewing the sunxi bits, and the wider community can hopefully review the generic bits ?
Yes I can split it - there are an unusual number of additional patches as sunxi was the point at which I finally decided to change the uclass.
Quoted 5 lines
Quoted 3 lines
Without having looked at the specifics I can say I'm broadly in favour of moving towards Device Model / Device Tree.
Ack.
OK good. I think there will be benefits, even if they are thin on the ground with just these two drivers.
Regards,
Simon
cover dm: Introduce driver model for sunxi
Hi,
Quoted 23 lines · Simon Glass
HI Hans,
Quoted 8 lines · Hans de Goede
Hi,
Quoted 5 lines · Ian Campbell
Quoted 2 lines · Simon Glass
Any more comments on this series please? I have a few nits so could respin.
Quoted 6 lines
Quoted 2 lines
I'm afraid I'm unlikely to get to look at this before the w/e. It looks like the majority of the series isn't actually about sunxi though?
Right, could v2 please be split into a generic series and a sunxi series on top of that, so that Ian and I can focus on reviewing the sunxi bits, and the wider community can hopefully review the generic bits ?
Yes I can split it - there are an unusual number of additional patches as sunxi was the point at which I finally decided to change the uclass.
Quoted 1 line
Quoted 7 lines
Quoted 4 lines
Quoted 2 lines
Without having looked at the specifics I can say I'm broadly in favour of moving towards Device Model / Device Tree.
Ack.
OK good. I think there will be benefits, even if they are thin on the ground with just these two drivers.
I'm going to apply the non-sunxi patches to dm/master soon - please let me know if there are any comments. For sunxi I have sent v2 for review.
Regards,
Simon