From: Peng Fan <van.freenix@gmail.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 2/2] dm: gpio: introduce 74x164 driver
Date: Mon, 11 Apr 2016 13:44:20 +0800 [thread overview]
Message-ID: <20160411054419.GC8379@linux-7smt.suse> (raw)
In-Reply-To: <CAPnjgZ23bJRppzUvJMC=i+wm_+aM86AcdKV1ZB9dXJa=9wnSCA@mail.gmail.com>
Hi Simon,
Thanks for reviewing.
On Sat, Apr 09, 2016 at 12:33:40PM -0600, Simon Glass wrote:
>Hi Peng,
>
>On 21 March 2016 at 02:29, Peng Fan <van.freenix@gmail.com> wrote:
>> 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.
>>
>> Signed-off-by: Peng Fan <van.freenix@gmail.com>
>> Cc: Simon Glass <sjg@chromium.org>
>> Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
>> Cc: Chin Liang See <clsee@altera.com>
>> Cc: Bhuvanchandra DV <bhuvanchandra.dv@toradex.com>
>> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
>> Cc: Fabio Estevam <fabio.estevam@nxp.com>
>> Cc: Stefano Babic <sbabic@denx.de>
>> ---
>> 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
>>
>> diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c
>> new file mode 100644
>> index 0000000..5d12a9a
>> --- /dev/null
>> +++ b/drivers/gpio/74x164_gpio.c
>> @@ -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 <van.freenix@gmail.com>
>> + *
>> + * 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
>
>This doesn't appear to be u
>> + * @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?
>
>> + struct udevice *dev;
>
>This doesn't seem to be used
Will drop it in V2.
>
>> + 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;
>
>uint should be good enough for these
Fix in V2.
>
>> + 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;
>
>-ENOSYS if it is not supported
Fix in V2.
>
>> +}
>> +
>> +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);
>
>Do you have a device tree binding file you can add for this?
In Kernel:
Documentation/devicetree/bindings/gpio/gpio-74x164.txt
>
>> + 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.
>
>> +
>> + 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;
>> + }
>
>
>The GPIOD_IS_OUT_ACTIVE above will already activate this GPIO.
Will fix in V2.
>
>> +
>> + 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.
>
>> + 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);
Ok. Will try this. Fix in V2.
>
>> +
>> + 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),
>
>It does not seem to be used before probe(), so I think this should be
>priv_auto_alloc_size.
Fix in V2.
>
>> + .of_match = gen_74x164_ids,
>> +};
>> diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
>> index 51658f1..43fc9c4 100644
>> --- a/drivers/gpio/Kconfig
>> +++ b/drivers/gpio/Kconfig
>> @@ -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.
Will fix in V2.
>
>> + 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
>> diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
>> index bfc67d2..393b148 100644
>> --- a/drivers/gpio/Makefile
>> +++ b/drivers/gpio/Makefile
>> @@ -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
>> --
>> 2.6.2
>>
>
>Regards,
>Simon
next prev parent reply other threads:[~2016-04-11 5:44 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-03-21 8:29 [U-Boot] [PATCH 1/2] dm: spi: soft_spi: support linux way and bug fix Peng Fan
2016-03-21 8:29 ` [U-Boot] [PATCH 2/2] dm: gpio: introduce 74x164 driver Peng Fan
2016-04-09 18:33 ` Simon Glass
2016-04-11 5:44 ` Peng Fan [this message]
2016-04-09 18:33 ` [U-Boot] [PATCH 1/2] dm: spi: soft_spi: support linux way and bug fix Simon Glass
2016-04-11 5:45 ` Peng Fan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160411054419.GC8379@linux-7smt.suse \
--to=van.freenix@gmail.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.