Home | History | Annotate | Download | only in gpio
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Take drivers/gpio/gpio-74x164.c as reference.
      4  *
      5  * 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
      6  *
      7  * Copyright (C) 2016 Peng Fan <van.freenix (at) gmail.com>
      8  *
      9  */
     10 
     11 #include <common.h>
     12 #include <errno.h>
     13 #include <dm.h>
     14 #include <fdtdec.h>
     15 #include <malloc.h>
     16 #include <asm/gpio.h>
     17 #include <asm/io.h>
     18 #include <dt-bindings/gpio/gpio.h>
     19 #include <spi.h>
     20 
     21 DECLARE_GLOBAL_DATA_PTR;
     22 
     23 /*
     24  * struct gen_74x164_chip - Data for 74Hx164
     25  *
     26  * @oe: OE pin
     27  * @nregs: number of registers
     28  * @buffer: buffer for chained chips
     29  */
     30 #define GEN_74X164_NUMBER_GPIOS 8
     31 
     32 struct gen_74x164_priv {
     33 	struct gpio_desc oe;
     34 	u32 nregs;
     35 	/*
     36 	 * Since the nregs are chained, every byte sent will make
     37 	 * the previous byte shift to the next register in the
     38 	 * chain. Thus, the first byte sent will end up in the last
     39 	 * register at the end of the transfer. So, to have a logical
     40 	 * numbering, store the bytes in reverse order.
     41 	 */
     42 	u8 *buffer;
     43 };
     44 
     45 static int gen_74x164_write_conf(struct udevice *dev)
     46 {
     47 	struct gen_74x164_priv *priv = dev_get_priv(dev);
     48 	int ret;
     49 
     50 	ret = dm_spi_claim_bus(dev);
     51 	if (ret)
     52 		return ret;
     53 
     54 	ret = dm_spi_xfer(dev, priv->nregs * 8, priv->buffer, NULL,
     55 			  SPI_XFER_BEGIN | SPI_XFER_END);
     56 
     57 	dm_spi_release_bus(dev);
     58 
     59 	return ret;
     60 }
     61 
     62 static int gen_74x164_get_value(struct udevice *dev, unsigned offset)
     63 {
     64 	struct gen_74x164_priv *priv = dev_get_priv(dev);
     65 	uint bank = priv->nregs - 1 - offset / 8;
     66 	uint pin = offset % 8;
     67 
     68 	return (priv->buffer[bank] >> pin) & 0x1;
     69 }
     70 
     71 static int gen_74x164_set_value(struct udevice *dev, unsigned offset,
     72 				int value)
     73 {
     74 	struct gen_74x164_priv *priv = dev_get_priv(dev);
     75 	uint bank = priv->nregs - 1 - offset / 8;
     76 	uint pin = offset % 8;
     77 	int ret;
     78 
     79 	if (value)
     80 		priv->buffer[bank] |= 1 << pin;
     81 	else
     82 		priv->buffer[bank] &= ~(1 << pin);
     83 
     84 	ret = gen_74x164_write_conf(dev);
     85 	if (ret)
     86 		return ret;
     87 
     88 	return 0;
     89 }
     90 
     91 static int gen_74x164_direction_input(struct udevice *dev, unsigned offset)
     92 {
     93 	return -ENOSYS;
     94 }
     95 
     96 static int gen_74x164_direction_output(struct udevice *dev, unsigned offset,
     97 				      int value)
     98 {
     99 	return gen_74x164_set_value(dev, offset, value);
    100 }
    101 
    102 static int gen_74x164_get_function(struct udevice *dev, unsigned offset)
    103 {
    104 	return GPIOF_OUTPUT;
    105 }
    106 
    107 static int gen_74x164_xlate(struct udevice *dev, struct gpio_desc *desc,
    108 			    struct ofnode_phandle_args *args)
    109 {
    110 	desc->offset = args->args[0];
    111 	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
    112 
    113 	return 0;
    114 }
    115 
    116 static const struct dm_gpio_ops gen_74x164_ops = {
    117 	.direction_input	= gen_74x164_direction_input,
    118 	.direction_output	= gen_74x164_direction_output,
    119 	.get_value		= gen_74x164_get_value,
    120 	.set_value		= gen_74x164_set_value,
    121 	.get_function		= gen_74x164_get_function,
    122 	.xlate			= gen_74x164_xlate,
    123 };
    124 
    125 static int gen_74x164_probe(struct udevice *dev)
    126 {
    127 	struct gen_74x164_priv *priv = dev_get_priv(dev);
    128 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
    129 	char *str, name[32];
    130 	int ret;
    131 	const void *fdt = gd->fdt_blob;
    132 	int node = dev_of_offset(dev);
    133 
    134 	snprintf(name, sizeof(name), "%s_", dev->name);
    135 	str = strdup(name);
    136 	if (!str)
    137 		return -ENOMEM;
    138 
    139 	/*
    140 	 * See Linux kernel:
    141 	 * Documentation/devicetree/bindings/gpio/gpio-74x164.txt
    142 	 */
    143 	priv->nregs = fdtdec_get_int(fdt, node, "registers-number", 1);
    144 	priv->buffer = calloc(priv->nregs, sizeof(u8));
    145 	if (!priv->buffer) {
    146 		ret = -ENOMEM;
    147 		goto free_str;
    148 	}
    149 
    150 	ret = fdtdec_get_byte_array(fdt, node, "registers-default",
    151 				    priv->buffer, priv->nregs);
    152 	if (ret)
    153 		dev_dbg(dev, "No registers-default property\n");
    154 
    155 	ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe,
    156 				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
    157 	if (ret) {
    158 		dev_dbg(dev, "No oe-pins property\n");
    159 	}
    160 
    161 	uc_priv->bank_name = str;
    162 	uc_priv->gpio_count = priv->nregs * 8;
    163 
    164 	ret = gen_74x164_write_conf(dev);
    165 	if (ret)
    166 		goto free_buf;
    167 
    168 	dev_dbg(dev, "%s is ready\n", dev->name);
    169 
    170 	return 0;
    171 
    172 free_buf:
    173 	free(priv->buffer);
    174 free_str:
    175 	free(str);
    176 	return ret;
    177 }
    178 
    179 static const struct udevice_id gen_74x164_ids[] = {
    180 	{ .compatible = "fairchild,74hc595" },
    181 	{ }
    182 };
    183 
    184 U_BOOT_DRIVER(74x164) = {
    185 	.name		= "74x164",
    186 	.id		= UCLASS_GPIO,
    187 	.ops		= &gen_74x164_ops,
    188 	.probe		= gen_74x164_probe,
    189 	.priv_auto_alloc_size = sizeof(struct gen_74x164_priv),
    190 	.of_match	= gen_74x164_ids,
    191 };
    192