dm: spi: soft_spi: support linux way and bug fix
PATCH 1/2 dm: spi: soft_spi: support linux way and bug fix
1. Support compatible string "spi-gpio" which is used by Linux Linux use different bindings, so use UBOOT_COMPAT and LINUX_COMPAT to differentiate them.
2. Bug fix
When doing xfer, should use device->parent, but not device When doing bit xfer, should use "!!(tmpdout & 0x80)", but not "(tmpdout & 0x80)"
3. Introduce SPI_MASTER_NO_RX and SPI_MASTER_NO_TX to handle no rx or no tx case.
4. Tested on i.MX6 UltraLite board with 74LV595 spi-gpio chip.
--- drivers/spi/soft_spi.c | 75 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 18 deletions(-)
drivers/spi/soft_spi.c +57 -18
@@ -26,15 +26,23 @@ struct soft_spi_platdata {struct gpio_desc mosi;struct gpio_desc miso;int spi_delay_us; +int flags; }; +#define SPI_MASTER_NO_RX BIT(0) +#define SPI_MASTER_NO_TX BIT(1) + +#define UBOOT_COMPAT BIT(0) +#define LINUX_COMPAT BIT(1) +struct soft_spi_priv {unsigned int mode; };static int soft_spi_scl (struct udevice *dev,int bit) { -struct soft_spi_platdata *plat = dev->platdata; +struct udevice *bus =dev_get_parent (dev); +struct soft_spi_platdata *plat =dev_get_platdata (bus);dm_gpio_set_value (&plat->sclk, bit);
@@ -43,7 +51,8 @@ static int soft_spi_scl(struct udevice *dev, int bit)static int soft_spi_sda (struct udevice *dev,int bit) { -struct soft_spi_platdata *plat = dev->platdata; +struct udevice *bus =dev_get_parent (dev); +struct soft_spi_platdata *plat =dev_get_platdata (bus);dm_gpio_set_value (&plat->mosi, bit);
@@ -52,7 +61,8 @@ static int soft_spi_sda(struct udevice *dev, int bit)static int soft_spi_cs_activate (struct udevice *dev) { -struct soft_spi_platdata *plat = dev->platdata; +struct udevice *bus =dev_get_parent (dev); +struct soft_spi_platdata *plat =dev_get_platdata (bus);dm_gpio_set_value (&plat->cs,0 );dm_gpio_set_value (&plat->sclk,0 );
@@ -63,7 +73,8 @@ static int soft_spi_cs_activate(struct udevice *dev)static int soft_spi_cs_deactivate (struct udevice *dev) { -struct soft_spi_platdata *plat = dev->platdata; +struct udevice *bus =dev_get_parent (dev); +struct soft_spi_platdata *plat =dev_get_platdata (bus);dm_gpio_set_value (&plat->cs,0 );
@@ -100,8 +111,9 @@ static int soft_spi_release_bus(struct udevice *dev)static int soft_spi_xfer (struct udevice *dev,unsigned int bitlen,const void *dout,void *din,unsigned long flags) { -struct soft_spi_priv *priv =dev_get_priv (dev); -struct soft_spi_platdata *plat = dev->platdata; +struct udevice *bus =dev_get_parent (dev); +struct soft_spi_priv *priv =dev_get_priv (bus); +struct soft_spi_platdata *plat =dev_get_platdata (bus);uchar tmpdin =0 ;uchar tmpdout =0 ;const u8 *txd = dout;
@@ -134,14 +146,16 @@ static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,if (!cpha)soft_spi_scl (dev,0 ); -soft_spi_sda (dev, tmpdout &0x80 ); +if ((plat->flags &SPI_MASTER_NO_TX ) ==0 ) +soft_spi_sda (dev, !!(tmpdout &0x80 ));udelay (plat->spi_delay_us);if (cpha)soft_spi_scl (dev,0 );else soft_spi_scl (dev,1 ); tmpdin <<=1 ; - tmpdin |=dm_gpio_get_value (&plat->miso); +if ((plat->flags &SPI_MASTER_NO_RX ) ==0 ) + tmpdin |=dm_gpio_get_value (&plat->miso); tmpdout <<=1 ;udelay (plat->spi_delay_us);if (cpha)
@@ -202,25 +216,50 @@ static int soft_spi_probe(struct udevice *dev) {struct spi_slave *slave =dev_get_parent_priv (dev);struct soft_spi_platdata *plat = dev->platdata; +ulong driver_data =dev_get_driver_data (dev);int cs_flags, clk_flags; +int ret; cs_flags = (slave->mode &SPI_CS_HIGH ) ?0 :GPIOD_ACTIVE_LOW ; clk_flags = (slave->mode &SPI_CPOL ) ?GPIOD_ACTIVE_LOW :0 ; -if (gpio_request_by_name (dev,"cs-gpio" ,0 , &plat->cs, -GPIOD_IS_OUT | cs_flags) || -gpio_request_by_name (dev,"sclk-gpio" ,0 , &plat->sclk, -GPIOD_IS_OUT | clk_flags) || -gpio_request_by_name (dev,"mosi-gpio" ,0 , &plat->mosi, -GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE ) || -gpio_request_by_name (dev,"miso-gpio" ,0 , &plat->miso, -GPIOD_IS_IN )) -return -EINVAL ; +if (driver_data &UBOOT_COMPAT ) { +if (gpio_request_by_name (dev,"cs-gpio" ,0 , &plat->cs, +GPIOD_IS_OUT | cs_flags) || +gpio_request_by_name (dev,"sclk-gpio" ,0 , &plat->sclk, +GPIOD_IS_OUT | clk_flags) || +gpio_request_by_name (dev,"mosi-gpio" ,0 , &plat->mosi, +GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE ) || +gpio_request_by_name (dev,"miso-gpio" ,0 , &plat->miso, +GPIOD_IS_IN )) +return -EINVAL ; + }else if (driver_data &LINUX_COMPAT ) { +if (gpio_request_by_name (dev,"cs-gpios" ,0 , &plat->cs, +GPIOD_IS_OUT | cs_flags) || +gpio_request_by_name (dev,"gpio-sck" ,0 , &plat->sclk, +GPIOD_IS_OUT | clk_flags)) +return -EINVAL ; + + ret =gpio_request_by_name (dev,"gpio-mosi" ,0 , &plat->mosi, +GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE ); +if (ret) + plat->flags |=SPI_MASTER_NO_TX ; + + ret =gpio_request_by_name (dev,"gpio-miso" ,0 , &plat->miso, +GPIOD_IS_IN ); +if (ret) + plat->flags |=SPI_MASTER_NO_RX ; + +if ((plat->flags & (SPI_MASTER_NO_RX |SPI_MASTER_NO_TX )) == + (SPI_MASTER_NO_RX |SPI_MASTER_NO_TX )) +return -EINVAL ; + }return 0 ; }static const struct udevice_id soft_spi_ids[] = { - { .compatible ="u-boot,soft-spi" }, + { .compatible ="u-boot,soft-spi" , .data =UBOOT_COMPAT }, + { .compatible ="spi-gpio" , .data =LINUX_COMPAT }, { } };
Signature · 1 line
2.6.2
PATCH 2/2 dm: gpio: introduce 74x164 driver
Introduce driver to support "fairchild,74hc595" devices.
1. Take linux drivers/drivers/gpio/gpio-74x164.c as reference.
2. Following the naming used in Linux driver with gen_7x164 as the prefix.
3. Enable CONFIG_DM_74X164 to use this driver.
4. Follow Documentation/devicetree/bindings/gpio/gpio-74x164.txt to add device nodes
5. Tested on i.MX6 UltraLite with 74LV595 using gpio command and oscillograph.
--- drivers/gpio/74x164_gpio.c | 220 +++++++++++++++++++++++++++++++++++++++++++++ drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + 3 files changed, 229 insertions(+) create mode 100644 drivers/gpio/74x164_gpio.c
drivers/gpio/74x164_gpio.c new file +220 -0
@@ -0,0 +1,220 @@ +/* +* Take drivers/gpio/gpio-74x164.c as reference. +* +* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver +* +* Copyright (C) 2016 Peng Fan <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +* +*/ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/gpio.h> +#include <asm/io.h> +#include <dt-bindings/gpio/gpio.h> +#include <spi.h> + +DECLARE_GLOBAL_DATA_PTR ; + +/* +* struct gen_74x164_chip - Data for 74Hx164 +* +* @dev: udevice structure for the device +* @slave: spi slave +* @oe: OE pin +* @nregs: number of registers +* @buffer: buffer for chained chips +*/ +#define GEN_74X164_NUMBER_GPIOS 8 + +struct gen_74x164_info { +struct udevice *dev; +struct spi_slave *slave; +struct gpio_desc oe; +u32 nregs; +/* +* Since the nregs are chained, every byte sent will make +* the previous byte shift to the next register in the +* chain. Thus, the first byte sent will end up in the last +* register at the end of the transfer. So, to have a logical +* numbering, store the bytes in reverse order. +*/ +u8 *buffer; +}; + +static int gen_74x164_write_conf (struct udevice *dev) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +struct spi_slave *slave = info->slave; +int ret; + + ret =spi_claim_bus (slave); +if (ret) +return ret; + + ret =spi_xfer (slave, info->nregs *8 , info->buffer,NULL , +SPI_XFER_BEGIN |SPI_XFER_END ); + +spi_release_bus (slave); + +return ret; +} + +static int gen_74x164_get_value (struct udevice *dev,unsigned offset) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +u8 bank = info->nregs -1 - offset /8 ; +u8 pin = offset %8 ; + +return (info->buffer[bank] >> pin) &0x1 ; +} + +static int gen_74x164_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +u8 bank = info->nregs -1 - offset /8 ; +u8 pin = offset %8 ; +int ret; + +if (value) + info->buffer[bank] |=1 << pin; +else + info->buffer[bank] &= ~(1 << pin); + + ret =gen_74x164_write_conf (dev); +if (ret) +return ret; + +return 0 ; +} + +static int gen_74x164_direction_input (struct udevice *dev,unsigned offset) +{ +return -EINVAL ; +} + +static int gen_74x164_direction_output (struct udevice *dev,unsigned offset, +int value) +{ +return gen_74x164_set_value (dev, offset, value); +} + +static int gen_74x164_get_function (struct udevice *dev,unsigned offset) +{ +return GPIOF_OUTPUT ; +} + +static int gen_74x164_xlate (struct udevice *dev,struct gpio_desc *desc, +struct fdtdec_phandle_args *args) +{ + desc->offset = args->args[0 ]; + desc->flags = args->args[1 ] &GPIO_ACTIVE_LOW ?GPIOD_ACTIVE_LOW :0 ; + +return 0 ; +} + +static const struct dm_gpio_ops gen_74x164_ops = { + .direction_input = gen_74x164_direction_input, + .direction_output = gen_74x164_direction_output, + .get_value = gen_74x164_get_value, + .set_value = gen_74x164_set_value, + .get_function = gen_74x164_get_function, + .xlate = gen_74x164_xlate, +}; + +static int gen_74x164_probe (struct udevice *dev) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +struct gpio_dev_priv *uc_priv =dev_get_uclass_priv (dev); +char *str, *str1; +int ret; +const void *fdt = gd->fdt_blob; +int node = dev->of_offset; +struct udevice *bus; +int busnum; +char name[30 ]; + + str =strdup (dev->name); +if (!str) +return -ENOMEM ; + + info->nregs =fdtdec_get_int (fdt, node,"registers-number" ,1 ); + info->buffer =calloc (info->nregs,sizeof (u8)); +if (!info->buffer) { + ret = -ENOMEM ; + goto free_str; + } + + ret =fdtdec_get_byte_array (fdt, node,"registers-default" , + info->buffer, info->nregs); +if (ret) +dev_dbg (dev,"No registers-default property\n" ); + + ret =gpio_request_by_name (dev,"oe-gpios" ,0 , &info->oe, +GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE ); +if (ret) { +dev_err (dev,"No oe-pins property\n" ); + goto free_buf; + } + +/* output enable */ + ret =dm_gpio_set_value (&info->oe,0 ); +if (ret) { +dev_err (dev,"Set oe-pins value failure\n" ); + goto free_buf; + } + + uc_priv->bank_name = str; + uc_priv->gpio_count = info->nregs *8 ; + + bus =dev_get_parent (dev); + busnum = bus->seq; + +snprintf (name,sizeof (name),"generic_%d:%d" , busnum,0 ); + str1 =strdup (name); +if (!str1) { + ret = -ENOMEM ; + goto free_buf; + } + + ret =spi_get_bus_and_cs (busnum,0 ,1000000 ,SPI_MODE_0 , +"spi_generic_drv" , str, &bus, &info->slave); +if (ret) + goto free_str1; + + ret =gen_74x164_write_conf (dev); +if (ret) + goto free_str1; + +dev_dbg (dev,"%s is ready\n" , dev->name); + +return 0 ; + +free_str1: +free (str1); +free_buf: +free (info->buffer); +free_str: +free (str); +return ret; +} + +static const struct udevice_id gen_74x164_ids[] = { + { .compatible ="fairchild,74hc595" }, + { } +}; + +U_BOOT_DRIVER(74x164) = { + .name = "74x164", + .id = UCLASS_GPIO, + .ops = &gen_74x164_ops, + .probe = gen_74x164_probe, + .platdata_auto_alloc_size = sizeof(struct gen_74x164_info), + .of_match = gen_74x164_ids, +};
drivers/gpio/Kconfig +8 -0
@@ -96,6 +96,14 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. +config DM_74X164 + bool "74x164 serial-in/parallel-out 8-bits shift register" + depends on DM_GPIO + help + Driver for 74x164 compatible serial-in/parallel-out 8-outputs + shift registers. This driver can be used to provide access + to more gpio outputs. + config DM_PCA953X bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" depends on DM_GPIO
drivers/gpio/Makefile +1 -0
@@ -12,6 +12,7 @@ endif obj-$(CONFIG_DM_GPIO) += gpio-uclass.o obj-$(CONFIG_DM_PCA953X) += pca953x_gpio.o +obj-$(CONFIG_DM_74X164) += 74x164_gpio.o obj-$(CONFIG_AT91_GPIO) += at91_gpio.o obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o
Signature · 1 line
2.6.2
PATCH 2/2 dm: gpio: introduce 74x164 driver
Hi Peng,
Quoted 46 lines · Peng Fan
Introduce driver to support "fairchild,74hc595" devices.
1. Take linuxdrivers/drivers/gpio/gpio-74x164.cas reference.
2. Following the naming used in Linux driver withgen_7x164as the prefix.
3. EnableCONFIG_DM_74X164to use this driver.
4. FollowDocumentation/devicetree/bindings/gpio/gpio-74x164.txtto add device nodes
5. Tested on i.MX6 UltraLite with 74LV595 using gpio command and oscillograph.Signed-off-by Peng Fan <[email protected]>Cc Simon Glass <[email protected]>Cc Masahiro Yamada <[email protected]>Cc Chin Liang See <[email protected]>Cc Bhuvanchandra DV <[email protected]>Cc Daniel Schwierzeck <[email protected]>Cc Fabio Estevam <[email protected]>Cc Stefano Babic <[email protected]>--- drivers/gpio/74x164_gpio.c | 220 +++++++++++++++++++++++++++++++++++++++++++++ drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + 3 files changed, 229 insertions(+) create mode 100644 drivers/gpio/74x164_gpio.cdrivers/gpio/74x164_gpio.c new file +17
-0@@ -0,0 +1,220 @@ +/* +* Take drivers/gpio/gpio-74x164.c as reference. +* +* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver +* +* Copyright (C) 2016 Peng Fan <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +* +*/ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/gpio.h>
drivers/gpio/74x164_gpio.c line 27
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+#include <asm/io.h> +#include <dt-bindings/gpio/gpio.h> +#include <spi.h> + +DECLARE_GLOBAL_DATA_PTR ; + +/* +* struct gen_74x164_chip - Data for 74Hx164 +* +* @dev: udevice structure for the device
This doesn't appear to be u
drivers/gpio/74x164_gpio.c line 35
Quoted 8 lines
drivers/gpio/74x164_gpio.c new file +8
-0+* @slave: spi slave +* @oe: OE pin +* @nregs: number of registers +* @buffer: buffer for chained chips +*/ +#define GEN_74X164_NUMBER_GPIOS 8 + +struct gen_74x164_info {
How about gen_74x164_priv?
drivers/gpio/74x164_gpio.c line 36
Quoted 1 line
drivers/gpio/74x164_gpio.c new file +1
-0+struct udevice *dev;
This doesn't seem to be used
Quoted 36 lines
drivers/gpio/74x164_gpio.c new file +36
-0+struct spi_slave *slave; +struct gpio_desc oe; +u32 nregs; +/* +* Since the nregs are chained, every byte sent will make +* the previous byte shift to the next register in the +* chain. Thus, the first byte sent will end up in the last +* register at the end of the transfer. So, to have a logical +* numbering, store the bytes in reverse order. +*/ +u8 *buffer; +}; + +static int gen_74x164_write_conf (struct udevice *dev) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +struct spi_slave *slave = info->slave; +int ret; + + ret =spi_claim_bus (slave); +if (ret) +return ret; + + ret =spi_xfer (slave, info->nregs *8 , info->buffer,NULL , +SPI_XFER_BEGIN |SPI_XFER_END ); + +spi_release_bus (slave); + +return ret; +} + +static int gen_74x164_get_value (struct udevice *dev,unsigned offset) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +u8 bank = info->nregs -1 - offset /8 ; +u8 pin = offset %8 ;
drivers/gpio/74x164_gpio.c line 82
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+ +return (info->buffer[bank] >> pin) &0x1 ; +} + +static int gen_74x164_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +u8 bank = info->nregs -1 - offset /8 ; +u8 pin = offset %8 ;
uint should be good enough for these
Quoted 7 lines
drivers/gpio/74x164_gpio.c new file +7
-0+int ret; + +if (value) + info->buffer[bank] |=1 << pin; +else + info->buffer[bank] &= ~(1 << pin); +
drivers/gpio/74x164_gpio.c line 99
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+ ret =gen_74x164_write_conf (dev); +if (ret) +return ret; + +return 0 ; +} + +static int gen_74x164_direction_input (struct udevice *dev,unsigned offset) +{ +return -EINVAL ;
-ENOSYS if it is not supported
Quoted 39 lines
drivers/gpio/74x164_gpio.c new file +38
-0+} + +static int gen_74x164_direction_output (struct udevice *dev,unsigned offset, +int value) +{ +return gen_74x164_set_value (dev, offset, value); +} + +static int gen_74x164_get_function (struct udevice *dev,unsigned offset) +{ +return GPIOF_OUTPUT ; +} + +static int gen_74x164_xlate (struct udevice *dev,struct gpio_desc *desc, +struct fdtdec_phandle_args *args) +{ + desc->offset = args->args[0 ]; + desc->flags = args->args[1 ] &GPIO_ACTIVE_LOW ?GPIOD_ACTIVE_LOW :0 ; + +return 0 ; +} + +static const struct dm_gpio_ops gen_74x164_ops = { + .direction_input = gen_74x164_direction_input, + .direction_output = gen_74x164_direction_output, + .get_value = gen_74x164_get_value, + .set_value = gen_74x164_set_value, + .get_function = gen_74x164_get_function, + .xlate = gen_74x164_xlate, +}; + +static int gen_74x164_probe (struct udevice *dev) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +struct gpio_dev_priv *uc_priv =dev_get_uclass_priv (dev); +char *str, *str1; +int ret; +const void *fdt = gd->fdt_blob;
drivers/gpio/74x164_gpio.c line 147
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+int node = dev->of_offset; +struct udevice *bus; +int busnum; +char name[30 ]; + + str =strdup (dev->name); +if (!str) +return -ENOMEM ; + + info->nregs =fdtdec_get_int (fdt, node,"registers-number" ,1 );
Do you have a device tree binding file you can add for this?
drivers/gpio/74x164_gpio.c line 152
Quoted 5 lines
drivers/gpio/74x164_gpio.c new file +5
-0+ info->buffer =calloc (info->nregs,sizeof (u8)); +if (!info->buffer) { + ret = -ENOMEM ; + goto free_str; + }
What's the largest number of registers you can have? If it is small, like 32, consider making buffer a simple fixed-length array.
Quoted 9 lines
drivers/gpio/74x164_gpio.c new file +9
-0+ + ret =fdtdec_get_byte_array (fdt, node,"registers-default" , + info->buffer, info->nregs); +if (ret) +dev_dbg (dev,"No registers-default property\n" ); + + ret =gpio_request_by_name (dev,"oe-gpios" ,0 , &info->oe, +GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE ); +if (ret) {
drivers/gpio/74x164_gpio.c line 171
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+dev_err (dev,"No oe-pins property\n" ); + goto free_buf; + } + +/* output enable */ + ret =dm_gpio_set_value (&info->oe,0 ); +if (ret) { +dev_err (dev,"Set oe-pins value failure\n" ); + goto free_buf; + }
The GPIOD_IS_OUT_ACTIVE above will already activate this GPIO.
drivers/gpio/74x164_gpio.c line 180
Quoted 9 lines
drivers/gpio/74x164_gpio.c new file +9
-0+ + uc_priv->bank_name = str; + uc_priv->gpio_count = info->nregs *8 ; + + bus =dev_get_parent (dev); + busnum = bus->seq; + +snprintf (name,sizeof (name),"generic_%d:%d" , busnum,0 ); + str1 =strdup (name);
What is str1 used for?
drivers/gpio/74x164_gpio.c line 189
Quoted 9 lines
drivers/gpio/74x164_gpio.c new file +9
-0+if (!str1) { + ret = -ENOMEM ; + goto free_buf; + } + + ret =spi_get_bus_and_cs (busnum,0 ,1000000 ,SPI_MODE_0 , +"spi_generic_drv" , str, &bus, &info->slave); +if (ret) + goto free_str1;
Why do you need this? The parent device is the SPI bus. See drivers/misc/cros_ec_spi.c for how it probes. There really shouldn't be much to do.
I'd suggest:
infp->slave = dev_get_parent_priv(dev);
Quoted 19 lines
drivers/gpio/74x164_gpio.c new file +19
-0+ + ret =gen_74x164_write_conf (dev); +if (ret) + goto free_str1; + +dev_dbg (dev,"%s is ready\n" , dev->name); + +return 0 ; + +free_str1: +free (str1); +free_buf: +free (info->buffer); +free_str: +free (str); +return ret; +} + +static const struct udevice_id gen_74x164_ids[] = {
drivers/gpio/74x164_gpio.c line 218
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+ { .compatible = "fairchild,74hc595" }, + { } +}; + +U_BOOT_DRIVER(74x164) = { + .name = "74x164", + .id = UCLASS_GPIO, + .ops = &gen_74x164_ops, + .probe = gen_74x164_probe, + .platdata_auto_alloc_size = sizeof(struct gen_74x164_info),
It does not seem to be used before probe(), so I think this should be priv_auto_alloc_size.
Quoted 7 lines
drivers/gpio/74x164_gpio.c new file +2
-0+ .of_match = gen_74x164_ids, +};drivers/gpio/Kconfig +0
-0
drivers/gpio/Kconfig config PIC32_GPIO · line 103
Quoted 8 lines
drivers/gpio/Kconfig +5
-0@@ -96,6 +96,14 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. +config DM_74X164 + bool "74x164 serial-in/parallel-out 8-bits shift register" + depends on DM_GPIO + help + Driver for 74x164 compatible serial-in/parallel-out 8-outputs
74x164-compatible
Should you mention the oriiginal manufacturer. Also you could mention that it uses SPI.
Quoted 19 lines
drivers/gpio/Kconfig +3
-0+ shift registers. This driver can be used to provide access + to more gpio outputs. + config DM_PCA953X bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" depends on DM_GPIOdrivers/gpio/Makefile +1
-1@@ -12,6 +12,7 @@ endif obj-$(CONFIG_DM_GPIO) += gpio-uclass.o obj-$(CONFIG_DM_PCA953X) += pca953x_gpio.o +obj-$(CONFIG_DM_74X164) += 74x164_gpio.o obj-$(CONFIG_AT91_GPIO) += at91_gpio.o obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o --
Quoted 2 lines
2.6.2
Regards,
Simon
PATCH 2/2 dm: gpio: introduce 74x164 driver
Hi Simon,
Thanks for reviewing.
Quoted 72 lines · Simon Glass
Hi Peng,
Quoted 46 lines · Peng Fan
Introduce driver to support "fairchild,74hc595" devices.
1. Take linuxdrivers/drivers/gpio/gpio-74x164.cas reference.
2. Following the naming used in Linux driver withgen_7x164as the prefix.
3. EnableCONFIG_DM_74X164to use this driver.
4. FollowDocumentation/devicetree/bindings/gpio/gpio-74x164.txtto add device nodes
5. Tested on i.MX6 UltraLite with 74LV595 using gpio command and oscillograph.Signed-off-by Peng Fan <[email protected]>Cc Simon Glass <[email protected]>Cc Masahiro Yamada <[email protected]>Cc Chin Liang See <[email protected]>Cc Bhuvanchandra DV <[email protected]>Cc Daniel Schwierzeck <[email protected]>Cc Fabio Estevam <[email protected]>Cc Stefano Babic <[email protected]>--- drivers/gpio/74x164_gpio.c | 220 +++++++++++++++++++++++++++++++++++++++++++++ drivers/gpio/Kconfig | 8 ++ drivers/gpio/Makefile | 1 + 3 files changed, 229 insertions(+) create mode 100644 drivers/gpio/74x164_gpio.cdrivers/gpio/74x164_gpio.c new file +17
-0@@ -0,0 +1,220 @@ +/* +* Take drivers/gpio/gpio-74x164.c as reference. +* +* 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver +* +* Copyright (C) 2016 Peng Fan <[email protected]> +* +* SPDX-License-Identifier: GPL-2.0+ +* +*/ + +#include <common.h> +#include <errno.h> +#include <dm.h> +#include <fdtdec.h> +#include <malloc.h> +#include <asm/gpio.h> drivers/gpio/74x164_gpio.c line 27
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +10
-0+#include <asm/io.h> +#include <dt-bindings/gpio/gpio.h> +#include <spi.h> + +DECLARE_GLOBAL_DATA_PTR ; + +/* +* struct gen_74x164_chip - Data for 74Hx164 +* +* @dev: udevice structure for the device This doesn't appear to be u
drivers/gpio/74x164_gpio.c line 35
Quoted 8 lines
drivers/gpio/74x164_gpio.c new file +8
-0+* @slave: spi slave +* @oe: OE pin +* @nregs: number of registers +* @buffer: buffer for chained chips +*/ +#define GEN_74X164_NUMBER_GPIOS 8 + +struct gen_74x164_info {How about
gen_74x164_priv?
Quoted 3 lines
drivers/gpio/74x164_gpio.c line 36
Quoted 1 line
drivers/gpio/74x164_gpio.c new file +1
-0+struct udevice *dev;This doesn't seem to be used
Will drop it in V2.
Quoted 41 lines
Quoted 41 lines
drivers/gpio/74x164_gpio.c new file +40
-0+struct spi_slave *slave; +struct gpio_desc oe; +u32 nregs; +/* +* Since the nregs are chained, every byte sent will make +* the previous byte shift to the next register in the +* chain. Thus, the first byte sent will end up in the last +* register at the end of the transfer. So, to have a logical +* numbering, store the bytes in reverse order. +*/ +u8 *buffer; +}; + +static int gen_74x164_write_conf (struct udevice *dev) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +struct spi_slave *slave = info->slave; +int ret; + + ret =spi_claim_bus (slave); +if (ret) +return ret; + + ret =spi_xfer (slave, info->nregs *8 , info->buffer,NULL , +SPI_XFER_BEGIN |SPI_XFER_END ); + +spi_release_bus (slave); + +return ret; +} + +static int gen_74x164_get_value (struct udevice *dev,unsigned offset) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +u8 bank = info->nregs -1 - offset /8 ; +u8 pin = offset %8 ; + +return (info->buffer[bank] >> pin) &0x1 ; +} +
Quoted 8 lines
drivers/gpio/74x164_gpio.c line 82
Quoted 6 lines
drivers/gpio/74x164_gpio.c new file +6
-0+static int gen_74x164_set_value (struct udevice *dev,unsigned offset, +int value) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +u8 bank = info->nregs -1 - offset /8 ; +u8 pin = offset %8 ;uint should be good enough for these
Fix in V2.
Quoted 12 lines
Quoted 12 lines
drivers/gpio/74x164_gpio.c new file +11
-0+int ret; + +if (value) + info->buffer[bank] |=1 << pin; +else + info->buffer[bank] &= ~(1 << pin); + + ret =gen_74x164_write_conf (dev); +if (ret) +return ret; +
Quoted 8 lines
drivers/gpio/74x164_gpio.c line 99
Quoted 6 lines
drivers/gpio/74x164_gpio.c new file +6
-0+return 0 ; +} + +static int gen_74x164_direction_input (struct udevice *dev,unsigned offset) +{ +return -EINVAL ;
-ENOSYSif it is not supported
Fix in V2.
Quoted 44 lines
Quoted 44 lines
drivers/gpio/74x164_gpio.c new file +42
-0+} + +static int gen_74x164_direction_output (struct udevice *dev,unsigned offset, +int value) +{ +return gen_74x164_set_value (dev, offset, value); +} + +static int gen_74x164_get_function (struct udevice *dev,unsigned offset) +{ +return GPIOF_OUTPUT ; +} + +static int gen_74x164_xlate (struct udevice *dev,struct gpio_desc *desc, +struct fdtdec_phandle_args *args) +{ + desc->offset = args->args[0 ]; + desc->flags = args->args[1 ] &GPIO_ACTIVE_LOW ?GPIOD_ACTIVE_LOW :0 ; + +return 0 ; +} + +static const struct dm_gpio_ops gen_74x164_ops = { + .direction_input = gen_74x164_direction_input, + .direction_output = gen_74x164_direction_output, + .get_value = gen_74x164_get_value, + .set_value = gen_74x164_set_value, + .get_function = gen_74x164_get_function, + .xlate = gen_74x164_xlate, +}; + +static int gen_74x164_probe (struct udevice *dev) +{ +struct gen_74x164_info *info =dev_get_platdata (dev); +struct gpio_dev_priv *uc_priv =dev_get_uclass_priv (dev); +char *str, *str1; +int ret; +const void *fdt = gd->fdt_blob; +int node = dev->of_offset; +struct udevice *bus; +int busnum; +char name[30 ];
Quoted 8 lines
drivers/gpio/74x164_gpio.c line 147
Quoted 6 lines
drivers/gpio/74x164_gpio.c new file +6
-0+ + str =strdup (dev->name); +if (!str) +return -ENOMEM ; + + info->nregs =fdtdec_get_int (fdt, node,"registers-number" ,1 );Do you have a device tree binding file you can add for this?
In Kernel:Documentation/devicetree/bindings/gpio/gpio-74x164.txt
Quoted 9 lines
drivers/gpio/74x164_gpio.c line 152
Quoted 6 lines
drivers/gpio/74x164_gpio.c new file +5
-0+ info->buffer =calloc (info->nregs,sizeof (u8)); +if (!info->buffer) { + ret = -ENOMEM ; + goto free_str; + }What's the largest number of registers you can have? If it is small, like 32, consider making buffer a simple fixed-length array.
In general usage, only 1, but follow kernel, designed to be chained. So we do not have fixed value.
Quoted 15 lines
Quoted 15 lines
drivers/gpio/74x164_gpio.c new file +14
-0+ + ret =fdtdec_get_byte_array (fdt, node,"registers-default" , + info->buffer, info->nregs); +if (ret) +dev_dbg (dev,"No registers-default property\n" ); + + ret =gpio_request_by_name (dev,"oe-gpios" ,0 , &info->oe, +GPIOD_IS_OUT |GPIOD_IS_OUT_ACTIVE ); +if (ret) { +dev_err (dev,"No oe-pins property\n" ); + goto free_buf; + } + +/* output enable */
Quoted 8 lines
drivers/gpio/74x164_gpio.c line 171
Quoted 5 lines
drivers/gpio/74x164_gpio.c new file +5
-0+ ret =dm_gpio_set_value (&info->oe,0 ); +if (ret) { +dev_err (dev,"Set oe-pins value failure\n" ); + goto free_buf; + }The
GPIOD_IS_OUT_ACTIVEabove will already activate this GPIO.
Will fix in V2.
Quoted 12 lines
drivers/gpio/74x164_gpio.c line 180
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +9
-0+ + uc_priv->bank_name = str; + uc_priv->gpio_count = info->nregs *8 ; + + bus =dev_get_parent (dev); + busnum = bus->seq; + +snprintf (name,sizeof (name),"generic_%d:%d" , busnum,0 ); + str1 =strdup (name);What is str1 used for?
Oh. Should be used for spi_get_bus_and_cs, will fix in V2.
Quoted 11 lines
drivers/gpio/74x164_gpio.c line 189
Quoted 10 lines
drivers/gpio/74x164_gpio.c new file +9
-0+if (!str1) { + ret = -ENOMEM ; + goto free_buf; + } + + ret =spi_get_bus_and_cs (busnum,0 ,1000000 ,SPI_MODE_0 , +"spi_generic_drv" , str, &bus, &info->slave); +if (ret) + goto free_str1;
Quoted 7 lines
Why do you need this? The parent device is the SPI bus. See
drivers/misc/cros_ec_spi.cfor how it probes. There really shouldn't be much to do.I'd suggest:
infp->slave=dev_get_parent_priv(dev);
Ok. Will try this. Fix in V2.
Quoted 25 lines
Quoted 25 lines
drivers/gpio/74x164_gpio.c new file +24
-0+ + ret =gen_74x164_write_conf (dev); +if (ret) + goto free_str1; + +dev_dbg (dev,"%s is ready\n" , dev->name); + +return 0 ; + +free_str1: +free (str1); +free_buf: +free (info->buffer); +free_str: +free (str); +return ret; +} + +static const struct udevice_id gen_74x164_ids[] = { + { .compatible ="fairchild,74hc595" }, + { } +}; + +U_BOOT_DRIVER(74x164) = {
Quoted 8 lines
drivers/gpio/74x164_gpio.c line 218
Quoted 5 lines
drivers/gpio/74x164_gpio.c new file +5
-0+ .name = "74x164", + .id = UCLASS_GPIO, + .ops = &gen_74x164_ops, + .probe = gen_74x164_probe, + .platdata_auto_alloc_size = sizeof(struct gen_74x164_info),It does not seem to be used before
probe(), so I think this should bepriv_auto_alloc_size.
Fix in V2.
Quoted 19 lines
Quoted 8 lines
drivers/gpio/74x164_gpio.c new file +2
-0+ .of_match = gen_74x164_ids, +};drivers/gpio/Kconfig +0
-0drivers/gpio/Kconfig config PIC32_GPIO · line 103
Quoted 8 lines
drivers/gpio/Kconfig +5
-0@@ -96,6 +96,14 @@ config PIC32_GPIO help Say yes here to support Microchip PIC32 GPIOs. +config DM_74X164 + bool "74x164 serial-in/parallel-out 8-bits shift register" + depends on DM_GPIO + help + Driver for 74x164 compatible serial-in/parallel-out 8-outputs74x164-compatible
Quoted 2 lines
Should you mention the oriiginal manufacturer. Also you could mention that it uses SPI.
Will fix in V2.
Quoted 25 lines
Quoted 20 lines
drivers/gpio/Kconfig +3
-0+ shift registers. This driver can be used to provide access + to more gpio outputs. + config DM_PCA953X bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" depends on DM_GPIOdrivers/gpio/Makefile +1
-1@@ -12,6 +12,7 @@ endif obj-$(CONFIG_DM_GPIO) += gpio-uclass.o obj-$(CONFIG_DM_PCA953X) += pca953x_gpio.o +obj-$(CONFIG_DM_74X164) += 74x164_gpio.o obj-$(CONFIG_AT91_GPIO) += at91_gpio.o obj-$(CONFIG_ATMEL_PIO4) += atmel_pio4.o --Quoted 2 lines
2.6.2
Regards,
Simon
PATCH 1/2 dm: spi: soft_spi: support linux way and bug fix
In reply to Peng FanHi Peng,
Quoted 3 lines · Peng Fan
1. Support compatible string "spi-gpio" which is used by Linux Linux use different bindings, so use
UBOOT_COMPATandLINUX_COMPATto differentiate them.
There is only one user - instead of this, can you please drop the U-Boot binding and move the universal board over to use your new binding? There should be only one.
Quoted 6 lines
2. Bug fix
When doing xfer, should usedevice->parent, but not device When doing bit xfer, should use "!!(tmpdout &0x80)", but not "(tmpdout &0x80)"
3. IntroduceSPI_MASTER_NO_RXandSPI_MASTER_NO_TXto handle no rx or no tx case.
Perhaps put these two in separate patches?
Quoted 9 lines
4. Tested on i.MX6 UltraLite board with 74LV595 spi-gpio chip.
Signed-off-by Peng Fan <[email protected]>Cc Simon Glass <[email protected]>Cc Jagan Teki <[email protected]>Cc Stefano Babic <[email protected]>--- drivers/spi/soft_spi.c | 75 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 18 deletions(-)
Regards,
Simon
PATCH 1/2 dm: spi: soft_spi: support linux way and bug fix
Hi Simon,
Quoted 10 lines · Simon Glass
Hi Peng,
Quoted 3 lines · Peng Fan
1. Support compatible string "spi-gpio" which is used by Linux Linux use different bindings, so use
UBOOT_COMPATandLINUX_COMPATto differentiate them.There is only one user - instead of this, can you please drop the U-Boot binding and move the universal board over to use your new binding? There should be only one.
Ok. Will drop the U-Boot binding.
Quoted 9 lines
Quoted 7 lines
2. Bug fix
When doing xfer, should usedevice->parent, but not device When doing bit xfer, should use "!!(tmpdout &0x80)", but not "(tmpdout &0x80)"
3. IntroduceSPI_MASTER_NO_RXandSPI_MASTER_NO_TXto handle no rx or no tx case.Perhaps put these two in separate patches?
Will try it.
Thanks,
Peng.
Quoted 13 lines
Quoted 10 lines
4. Tested on i.MX6 UltraLite board with 74LV595 spi-gpio chip.
Signed-off-by Peng Fan <[email protected]>Cc Simon Glass <[email protected]>Cc Jagan Teki <[email protected]>Cc Stefano Babic <[email protected]>--- drivers/spi/soft_spi.c | 75 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 18 deletions(-)Regards,
Simon