1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * PCF8575 I2C GPIO EXPANDER DRIVER 4 * 5 * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/ 6 * 7 * Vignesh R <vigneshr@ti.com> 8 * 9 * 10 * Driver for TI PCF-8575 16-bit I2C gpio expander. Based on 11 * gpio-pcf857x Linux Kernel(v4.7) driver. 12 * 13 * Copyright (C) 2007 David Brownell 14 * 15 */ 16 17 /* 18 * NOTE: The driver and devicetree bindings are borrowed from Linux 19 * Kernel, but driver does not support all PCF857x devices. It currently 20 * supports PCF8575 16-bit expander by TI and NXP. 21 * 22 * TODO(vigneshr@ti.com): 23 * Support 8 bit PCF857x compatible expanders. 24 */ 25 26 #include <common.h> 27 #include <dm.h> 28 #include <i2c.h> 29 #include <asm-generic/gpio.h> 30 31 DECLARE_GLOBAL_DATA_PTR; 32 33 struct pcf8575_chip { 34 int gpio_count; /* No. GPIOs supported by the chip */ 35 36 /* NOTE: these chips have strange "quasi-bidirectional" I/O pins. 37 * We can't actually know whether a pin is configured (a) as output 38 * and driving the signal low, or (b) as input and reporting a low 39 * value ... without knowing the last value written since the chip 40 * came out of reset (if any). We can't read the latched output. 41 * In short, the only reliable solution for setting up pin direction 42 * is to do it explicitly. 43 * 44 * Using "out" avoids that trouble. When left initialized to zero, 45 * our software copy of the "latch" then matches the chip's all-ones 46 * reset state. Otherwise it flags pins to be driven low. 47 */ 48 unsigned int out; /* software latch */ 49 const char *bank_name; /* Name of the expander bank */ 50 }; 51 52 /* Read/Write to 16-bit I/O expander */ 53 54 static int pcf8575_i2c_write_le16(struct udevice *dev, unsigned int word) 55 { 56 struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); 57 u8 buf[2] = { word & 0xff, word >> 8, }; 58 int ret; 59 60 ret = dm_i2c_write(dev, 0, buf, 2); 61 if (ret) 62 printf("%s i2c write failed to addr %x\n", __func__, 63 chip->chip_addr); 64 65 return ret; 66 } 67 68 static int pcf8575_i2c_read_le16(struct udevice *dev) 69 { 70 struct dm_i2c_chip *chip = dev_get_parent_platdata(dev); 71 u8 buf[2]; 72 int ret; 73 74 ret = dm_i2c_read(dev, 0, buf, 2); 75 if (ret) { 76 printf("%s i2c read failed from addr %x\n", __func__, 77 chip->chip_addr); 78 return ret; 79 } 80 81 return (buf[1] << 8) | buf[0]; 82 } 83 84 static int pcf8575_direction_input(struct udevice *dev, unsigned offset) 85 { 86 struct pcf8575_chip *plat = dev_get_platdata(dev); 87 int status; 88 89 plat->out |= BIT(offset); 90 status = pcf8575_i2c_write_le16(dev, plat->out); 91 92 return status; 93 } 94 95 static int pcf8575_direction_output(struct udevice *dev, 96 unsigned int offset, int value) 97 { 98 struct pcf8575_chip *plat = dev_get_platdata(dev); 99 int ret; 100 101 if (value) 102 plat->out |= BIT(offset); 103 else 104 plat->out &= ~BIT(offset); 105 106 ret = pcf8575_i2c_write_le16(dev, plat->out); 107 108 return ret; 109 } 110 111 static int pcf8575_get_value(struct udevice *dev, unsigned int offset) 112 { 113 int value; 114 115 value = pcf8575_i2c_read_le16(dev); 116 117 return (value < 0) ? value : ((value & BIT(offset)) >> offset); 118 } 119 120 static int pcf8575_set_value(struct udevice *dev, unsigned int offset, 121 int value) 122 { 123 return pcf8575_direction_output(dev, offset, value); 124 } 125 126 static int pcf8575_ofdata_platdata(struct udevice *dev) 127 { 128 struct pcf8575_chip *plat = dev_get_platdata(dev); 129 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 130 131 int n_latch; 132 133 uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 134 "gpio-count", 16); 135 uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), 136 "gpio-bank-name", NULL); 137 if (!uc_priv->bank_name) 138 uc_priv->bank_name = fdt_get_name(gd->fdt_blob, 139 dev_of_offset(dev), NULL); 140 141 n_latch = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev), 142 "lines-initial-states", 0); 143 plat->out = ~n_latch; 144 145 return 0; 146 } 147 148 static int pcf8575_gpio_probe(struct udevice *dev) 149 { 150 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 151 152 debug("%s GPIO controller with %d gpios probed\n", 153 uc_priv->bank_name, uc_priv->gpio_count); 154 155 return 0; 156 } 157 158 static const struct dm_gpio_ops pcf8575_gpio_ops = { 159 .direction_input = pcf8575_direction_input, 160 .direction_output = pcf8575_direction_output, 161 .get_value = pcf8575_get_value, 162 .set_value = pcf8575_set_value, 163 }; 164 165 static const struct udevice_id pcf8575_gpio_ids[] = { 166 { .compatible = "nxp,pcf8575" }, 167 { .compatible = "ti,pcf8575" }, 168 { } 169 }; 170 171 U_BOOT_DRIVER(gpio_pcf8575) = { 172 .name = "gpio_pcf8575", 173 .id = UCLASS_GPIO, 174 .ops = &pcf8575_gpio_ops, 175 .of_match = pcf8575_gpio_ids, 176 .ofdata_to_platdata = pcf8575_ofdata_platdata, 177 .probe = pcf8575_gpio_probe, 178 .platdata_auto_alloc_size = sizeof(struct pcf8575_chip), 179 }; 180