1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
25746b0dfSVignesh R /*
35746b0dfSVignesh R * PCF8575 I2C GPIO EXPANDER DRIVER
45746b0dfSVignesh R *
55746b0dfSVignesh R * Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
65746b0dfSVignesh R *
75746b0dfSVignesh R * Vignesh R <vigneshr@ti.com>
85746b0dfSVignesh R *
95746b0dfSVignesh R *
105746b0dfSVignesh R * Driver for TI PCF-8575 16-bit I2C gpio expander. Based on
115746b0dfSVignesh R * gpio-pcf857x Linux Kernel(v4.7) driver.
125746b0dfSVignesh R *
135746b0dfSVignesh R * Copyright (C) 2007 David Brownell
145746b0dfSVignesh R *
155746b0dfSVignesh R */
165746b0dfSVignesh R
175746b0dfSVignesh R /*
185746b0dfSVignesh R * NOTE: The driver and devicetree bindings are borrowed from Linux
195746b0dfSVignesh R * Kernel, but driver does not support all PCF857x devices. It currently
205746b0dfSVignesh R * supports PCF8575 16-bit expander by TI and NXP.
215746b0dfSVignesh R *
225746b0dfSVignesh R * TODO(vigneshr@ti.com):
235746b0dfSVignesh R * Support 8 bit PCF857x compatible expanders.
245746b0dfSVignesh R */
255746b0dfSVignesh R
265746b0dfSVignesh R #include <common.h>
275746b0dfSVignesh R #include <dm.h>
285746b0dfSVignesh R #include <i2c.h>
295746b0dfSVignesh R #include <asm-generic/gpio.h>
305746b0dfSVignesh R
315746b0dfSVignesh R DECLARE_GLOBAL_DATA_PTR;
325746b0dfSVignesh R
335746b0dfSVignesh R struct pcf8575_chip {
345746b0dfSVignesh R int gpio_count; /* No. GPIOs supported by the chip */
355746b0dfSVignesh R
365746b0dfSVignesh R /* NOTE: these chips have strange "quasi-bidirectional" I/O pins.
375746b0dfSVignesh R * We can't actually know whether a pin is configured (a) as output
385746b0dfSVignesh R * and driving the signal low, or (b) as input and reporting a low
395746b0dfSVignesh R * value ... without knowing the last value written since the chip
405746b0dfSVignesh R * came out of reset (if any). We can't read the latched output.
415746b0dfSVignesh R * In short, the only reliable solution for setting up pin direction
425746b0dfSVignesh R * is to do it explicitly.
435746b0dfSVignesh R *
445746b0dfSVignesh R * Using "out" avoids that trouble. When left initialized to zero,
455746b0dfSVignesh R * our software copy of the "latch" then matches the chip's all-ones
465746b0dfSVignesh R * reset state. Otherwise it flags pins to be driven low.
475746b0dfSVignesh R */
485746b0dfSVignesh R unsigned int out; /* software latch */
495746b0dfSVignesh R const char *bank_name; /* Name of the expander bank */
505746b0dfSVignesh R };
515746b0dfSVignesh R
525746b0dfSVignesh R /* Read/Write to 16-bit I/O expander */
535746b0dfSVignesh R
pcf8575_i2c_write_le16(struct udevice * dev,unsigned int word)545746b0dfSVignesh R static int pcf8575_i2c_write_le16(struct udevice *dev, unsigned int word)
555746b0dfSVignesh R {
565746b0dfSVignesh R struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
575746b0dfSVignesh R u8 buf[2] = { word & 0xff, word >> 8, };
585746b0dfSVignesh R int ret;
595746b0dfSVignesh R
605746b0dfSVignesh R ret = dm_i2c_write(dev, 0, buf, 2);
615746b0dfSVignesh R if (ret)
625746b0dfSVignesh R printf("%s i2c write failed to addr %x\n", __func__,
635746b0dfSVignesh R chip->chip_addr);
645746b0dfSVignesh R
655746b0dfSVignesh R return ret;
665746b0dfSVignesh R }
675746b0dfSVignesh R
pcf8575_i2c_read_le16(struct udevice * dev)685746b0dfSVignesh R static int pcf8575_i2c_read_le16(struct udevice *dev)
695746b0dfSVignesh R {
705746b0dfSVignesh R struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
715746b0dfSVignesh R u8 buf[2];
725746b0dfSVignesh R int ret;
735746b0dfSVignesh R
745746b0dfSVignesh R ret = dm_i2c_read(dev, 0, buf, 2);
755746b0dfSVignesh R if (ret) {
765746b0dfSVignesh R printf("%s i2c read failed from addr %x\n", __func__,
775746b0dfSVignesh R chip->chip_addr);
785746b0dfSVignesh R return ret;
795746b0dfSVignesh R }
805746b0dfSVignesh R
815746b0dfSVignesh R return (buf[1] << 8) | buf[0];
825746b0dfSVignesh R }
835746b0dfSVignesh R
pcf8575_direction_input(struct udevice * dev,unsigned offset)845746b0dfSVignesh R static int pcf8575_direction_input(struct udevice *dev, unsigned offset)
855746b0dfSVignesh R {
865746b0dfSVignesh R struct pcf8575_chip *plat = dev_get_platdata(dev);
875746b0dfSVignesh R int status;
885746b0dfSVignesh R
895746b0dfSVignesh R plat->out |= BIT(offset);
905746b0dfSVignesh R status = pcf8575_i2c_write_le16(dev, plat->out);
915746b0dfSVignesh R
925746b0dfSVignesh R return status;
935746b0dfSVignesh R }
945746b0dfSVignesh R
pcf8575_direction_output(struct udevice * dev,unsigned int offset,int value)955746b0dfSVignesh R static int pcf8575_direction_output(struct udevice *dev,
965746b0dfSVignesh R unsigned int offset, int value)
975746b0dfSVignesh R {
985746b0dfSVignesh R struct pcf8575_chip *plat = dev_get_platdata(dev);
995746b0dfSVignesh R int ret;
1005746b0dfSVignesh R
1015746b0dfSVignesh R if (value)
1025746b0dfSVignesh R plat->out |= BIT(offset);
1035746b0dfSVignesh R else
1045746b0dfSVignesh R plat->out &= ~BIT(offset);
1055746b0dfSVignesh R
1065746b0dfSVignesh R ret = pcf8575_i2c_write_le16(dev, plat->out);
1075746b0dfSVignesh R
1085746b0dfSVignesh R return ret;
1095746b0dfSVignesh R }
1105746b0dfSVignesh R
pcf8575_get_value(struct udevice * dev,unsigned int offset)1115746b0dfSVignesh R static int pcf8575_get_value(struct udevice *dev, unsigned int offset)
1125746b0dfSVignesh R {
1135746b0dfSVignesh R int value;
1145746b0dfSVignesh R
1155746b0dfSVignesh R value = pcf8575_i2c_read_le16(dev);
1165746b0dfSVignesh R
1175746b0dfSVignesh R return (value < 0) ? value : ((value & BIT(offset)) >> offset);
1185746b0dfSVignesh R }
1195746b0dfSVignesh R
pcf8575_set_value(struct udevice * dev,unsigned int offset,int value)1205746b0dfSVignesh R static int pcf8575_set_value(struct udevice *dev, unsigned int offset,
1215746b0dfSVignesh R int value)
1225746b0dfSVignesh R {
1235746b0dfSVignesh R return pcf8575_direction_output(dev, offset, value);
1245746b0dfSVignesh R }
1255746b0dfSVignesh R
pcf8575_ofdata_platdata(struct udevice * dev)1265746b0dfSVignesh R static int pcf8575_ofdata_platdata(struct udevice *dev)
1275746b0dfSVignesh R {
1285746b0dfSVignesh R struct pcf8575_chip *plat = dev_get_platdata(dev);
1295746b0dfSVignesh R struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1305746b0dfSVignesh R
1315746b0dfSVignesh R int n_latch;
1325746b0dfSVignesh R
133e160f7d4SSimon Glass uc_priv->gpio_count = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
1345746b0dfSVignesh R "gpio-count", 16);
135e160f7d4SSimon Glass uc_priv->bank_name = fdt_getprop(gd->fdt_blob, dev_of_offset(dev),
1365746b0dfSVignesh R "gpio-bank-name", NULL);
1375746b0dfSVignesh R if (!uc_priv->bank_name)
1385746b0dfSVignesh R uc_priv->bank_name = fdt_get_name(gd->fdt_blob,
139e160f7d4SSimon Glass dev_of_offset(dev), NULL);
1405746b0dfSVignesh R
141e160f7d4SSimon Glass n_latch = fdtdec_get_uint(gd->fdt_blob, dev_of_offset(dev),
1425746b0dfSVignesh R "lines-initial-states", 0);
1435746b0dfSVignesh R plat->out = ~n_latch;
1445746b0dfSVignesh R
1455746b0dfSVignesh R return 0;
1465746b0dfSVignesh R }
1475746b0dfSVignesh R
pcf8575_gpio_probe(struct udevice * dev)1485746b0dfSVignesh R static int pcf8575_gpio_probe(struct udevice *dev)
1495746b0dfSVignesh R {
1505746b0dfSVignesh R struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
1515746b0dfSVignesh R
1525746b0dfSVignesh R debug("%s GPIO controller with %d gpios probed\n",
1535746b0dfSVignesh R uc_priv->bank_name, uc_priv->gpio_count);
1545746b0dfSVignesh R
1555746b0dfSVignesh R return 0;
1565746b0dfSVignesh R }
1575746b0dfSVignesh R
1585746b0dfSVignesh R static const struct dm_gpio_ops pcf8575_gpio_ops = {
1595746b0dfSVignesh R .direction_input = pcf8575_direction_input,
1605746b0dfSVignesh R .direction_output = pcf8575_direction_output,
1615746b0dfSVignesh R .get_value = pcf8575_get_value,
1625746b0dfSVignesh R .set_value = pcf8575_set_value,
1635746b0dfSVignesh R };
1645746b0dfSVignesh R
1655746b0dfSVignesh R static const struct udevice_id pcf8575_gpio_ids[] = {
1665746b0dfSVignesh R { .compatible = "nxp,pcf8575" },
1675746b0dfSVignesh R { .compatible = "ti,pcf8575" },
1685746b0dfSVignesh R { }
1695746b0dfSVignesh R };
1705746b0dfSVignesh R
1715746b0dfSVignesh R U_BOOT_DRIVER(gpio_pcf8575) = {
1725746b0dfSVignesh R .name = "gpio_pcf8575",
1735746b0dfSVignesh R .id = UCLASS_GPIO,
1745746b0dfSVignesh R .ops = &pcf8575_gpio_ops,
1755746b0dfSVignesh R .of_match = pcf8575_gpio_ids,
1765746b0dfSVignesh R .ofdata_to_platdata = pcf8575_ofdata_platdata,
1775746b0dfSVignesh R .probe = pcf8575_gpio_probe,
1785746b0dfSVignesh R .platdata_auto_alloc_size = sizeof(struct pcf8575_chip),
1795746b0dfSVignesh R };
180