11e5c9b1eSRomain Gantois // SPDX-License-Identifier: GPL-2.0-only
21e5c9b1eSRomain Gantois /*
31e5c9b1eSRomain Gantois * ti_fpc202.c - FPC202 Dual Port Controller driver
41e5c9b1eSRomain Gantois *
51e5c9b1eSRomain Gantois * Copyright (C) 2024 Bootlin
61e5c9b1eSRomain Gantois *
71e5c9b1eSRomain Gantois */
81e5c9b1eSRomain Gantois
91e5c9b1eSRomain Gantois #include <linux/cleanup.h>
101e5c9b1eSRomain Gantois #include <linux/err.h>
111e5c9b1eSRomain Gantois #include <linux/i2c.h>
121e5c9b1eSRomain Gantois #include <linux/i2c-atr.h>
131e5c9b1eSRomain Gantois #include <linux/gpio/consumer.h>
141e5c9b1eSRomain Gantois #include <linux/gpio/driver.h>
151e5c9b1eSRomain Gantois #include <linux/module.h>
161e5c9b1eSRomain Gantois
171e5c9b1eSRomain Gantois #define FPC202_NUM_PORTS 2
181e5c9b1eSRomain Gantois #define FPC202_ALIASES_PER_PORT 2
191e5c9b1eSRomain Gantois
201e5c9b1eSRomain Gantois /*
211e5c9b1eSRomain Gantois * GPIO: port mapping
221e5c9b1eSRomain Gantois *
231e5c9b1eSRomain Gantois * 0: P0_S0_IN_A
241e5c9b1eSRomain Gantois * 1: P0_S1_IN_A
251e5c9b1eSRomain Gantois * 2: P1_S0_IN_A
261e5c9b1eSRomain Gantois * 3: P1_S1_IN_A
271e5c9b1eSRomain Gantois * 4: P0_S0_IN_B
281e5c9b1eSRomain Gantois * ...
291e5c9b1eSRomain Gantois * 8: P0_S0_IN_C
301e5c9b1eSRomain Gantois * ...
311e5c9b1eSRomain Gantois * 12: P0_S0_OUT_A
321e5c9b1eSRomain Gantois * ...
331e5c9b1eSRomain Gantois * 16: P0_S0_OUT_B
341e5c9b1eSRomain Gantois * ...
351e5c9b1eSRomain Gantois * 19: P1_S1_OUT_B
361e5c9b1eSRomain Gantois *
371e5c9b1eSRomain Gantois */
381e5c9b1eSRomain Gantois
391e5c9b1eSRomain Gantois #define FPC202_GPIO_COUNT 20
401e5c9b1eSRomain Gantois #define FPC202_GPIO_P0_S0_IN_B 4
411e5c9b1eSRomain Gantois #define FPC202_GPIO_P0_S0_OUT_A 12
421e5c9b1eSRomain Gantois
431e5c9b1eSRomain Gantois #define FPC202_REG_IN_A_INT 0x6
441e5c9b1eSRomain Gantois #define FPC202_REG_IN_C_IN_B 0x7
451e5c9b1eSRomain Gantois #define FPC202_REG_OUT_A_OUT_B 0x8
461e5c9b1eSRomain Gantois
471e5c9b1eSRomain Gantois #define FPC202_REG_OUT_A_OUT_B_VAL 0xa
481e5c9b1eSRomain Gantois
491e5c9b1eSRomain Gantois #define FPC202_REG_MOD_DEV(port, dev) (0xb4 + ((port) * 4) + (dev))
501e5c9b1eSRomain Gantois #define FPC202_REG_AUX_DEV(port, dev) (0xb6 + ((port) * 4) + (dev))
511e5c9b1eSRomain Gantois
521e5c9b1eSRomain Gantois /*
531e5c9b1eSRomain Gantois * The FPC202 doesn't support turning off address translation on a single port.
541e5c9b1eSRomain Gantois * So just set an invalid I2C address as the translation target when no client
551e5c9b1eSRomain Gantois * address is attached.
561e5c9b1eSRomain Gantois */
571e5c9b1eSRomain Gantois #define FPC202_REG_DEV_INVALID 0
581e5c9b1eSRomain Gantois
591e5c9b1eSRomain Gantois /* Even aliases are assigned to device 0 and odd aliases to device 1 */
601e5c9b1eSRomain Gantois #define fpc202_dev_num_from_alias(alias) ((alias) % 2)
611e5c9b1eSRomain Gantois
621e5c9b1eSRomain Gantois struct fpc202_priv {
631e5c9b1eSRomain Gantois struct i2c_client *client;
641e5c9b1eSRomain Gantois struct i2c_atr *atr;
651e5c9b1eSRomain Gantois struct gpio_desc *en_gpio;
661e5c9b1eSRomain Gantois struct gpio_chip gpio;
671e5c9b1eSRomain Gantois
681e5c9b1eSRomain Gantois /* Lock REG_MOD/AUX_DEV and addr_caches during attach/detach */
691e5c9b1eSRomain Gantois struct mutex reg_dev_lock;
701e5c9b1eSRomain Gantois
711e5c9b1eSRomain Gantois /* Cached device addresses for both ports and their devices */
721e5c9b1eSRomain Gantois u8 addr_caches[2][2];
731e5c9b1eSRomain Gantois
741e5c9b1eSRomain Gantois /* Keep track of which ports were probed */
751e5c9b1eSRomain Gantois DECLARE_BITMAP(probed_ports, FPC202_NUM_PORTS);
761e5c9b1eSRomain Gantois };
771e5c9b1eSRomain Gantois
fpc202_fill_alias_table(struct i2c_client * client,u16 * aliases,int port_id)781e5c9b1eSRomain Gantois static void fpc202_fill_alias_table(struct i2c_client *client, u16 *aliases, int port_id)
791e5c9b1eSRomain Gantois {
801e5c9b1eSRomain Gantois u16 first_alias;
811e5c9b1eSRomain Gantois int i;
821e5c9b1eSRomain Gantois
831e5c9b1eSRomain Gantois /*
841e5c9b1eSRomain Gantois * There is a predefined list of aliases for each FPC202 I2C
851e5c9b1eSRomain Gantois * self-address. This allows daisy-chained FPC202 units to
861e5c9b1eSRomain Gantois * automatically take on different sets of aliases.
871e5c9b1eSRomain Gantois * Each port of an FPC202 unit is assigned two aliases from this list.
881e5c9b1eSRomain Gantois */
891e5c9b1eSRomain Gantois first_alias = 0x10 + 4 * port_id + 8 * ((u16)client->addr - 2);
901e5c9b1eSRomain Gantois
911e5c9b1eSRomain Gantois for (i = 0; i < FPC202_ALIASES_PER_PORT; i++)
921e5c9b1eSRomain Gantois aliases[i] = first_alias + i;
931e5c9b1eSRomain Gantois }
941e5c9b1eSRomain Gantois
fpc202_gpio_get_dir(int offset)951e5c9b1eSRomain Gantois static int fpc202_gpio_get_dir(int offset)
961e5c9b1eSRomain Gantois {
971e5c9b1eSRomain Gantois return offset < FPC202_GPIO_P0_S0_OUT_A ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
981e5c9b1eSRomain Gantois }
991e5c9b1eSRomain Gantois
fpc202_read(struct fpc202_priv * priv,u8 reg)1001e5c9b1eSRomain Gantois static int fpc202_read(struct fpc202_priv *priv, u8 reg)
1011e5c9b1eSRomain Gantois {
1021e5c9b1eSRomain Gantois int val;
1031e5c9b1eSRomain Gantois
1041e5c9b1eSRomain Gantois val = i2c_smbus_read_byte_data(priv->client, reg);
1051e5c9b1eSRomain Gantois return val;
1061e5c9b1eSRomain Gantois }
1071e5c9b1eSRomain Gantois
fpc202_write(struct fpc202_priv * priv,u8 reg,u8 value)1081e5c9b1eSRomain Gantois static int fpc202_write(struct fpc202_priv *priv, u8 reg, u8 value)
1091e5c9b1eSRomain Gantois {
1101e5c9b1eSRomain Gantois return i2c_smbus_write_byte_data(priv->client, reg, value);
1111e5c9b1eSRomain Gantois }
1121e5c9b1eSRomain Gantois
fpc202_set_enable(struct fpc202_priv * priv,int enable)1131e5c9b1eSRomain Gantois static void fpc202_set_enable(struct fpc202_priv *priv, int enable)
1141e5c9b1eSRomain Gantois {
1151e5c9b1eSRomain Gantois if (!priv->en_gpio)
1161e5c9b1eSRomain Gantois return;
1171e5c9b1eSRomain Gantois
1181e5c9b1eSRomain Gantois gpiod_set_value(priv->en_gpio, enable);
1191e5c9b1eSRomain Gantois }
1201e5c9b1eSRomain Gantois
fpc202_gpio_set(struct gpio_chip * chip,unsigned int offset,int value)1211e5c9b1eSRomain Gantois static void fpc202_gpio_set(struct gpio_chip *chip, unsigned int offset,
1221e5c9b1eSRomain Gantois int value)
1231e5c9b1eSRomain Gantois {
1241e5c9b1eSRomain Gantois struct fpc202_priv *priv = gpiochip_get_data(chip);
1251e5c9b1eSRomain Gantois int ret;
1261e5c9b1eSRomain Gantois u8 val;
1271e5c9b1eSRomain Gantois
1281e5c9b1eSRomain Gantois if (fpc202_gpio_get_dir(offset) == GPIO_LINE_DIRECTION_IN)
1291e5c9b1eSRomain Gantois return;
1301e5c9b1eSRomain Gantois
1311e5c9b1eSRomain Gantois ret = fpc202_read(priv, FPC202_REG_OUT_A_OUT_B_VAL);
1321e5c9b1eSRomain Gantois if (ret < 0) {
1331e5c9b1eSRomain Gantois dev_err(&priv->client->dev, "Failed to set GPIO %d value! err %d\n", offset, ret);
1341e5c9b1eSRomain Gantois return;
1351e5c9b1eSRomain Gantois }
1361e5c9b1eSRomain Gantois
1371e5c9b1eSRomain Gantois val = (u8)ret;
1381e5c9b1eSRomain Gantois
1391e5c9b1eSRomain Gantois if (value)
1401e5c9b1eSRomain Gantois val |= BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
1411e5c9b1eSRomain Gantois else
1421e5c9b1eSRomain Gantois val &= ~BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
1431e5c9b1eSRomain Gantois
1441e5c9b1eSRomain Gantois fpc202_write(priv, FPC202_REG_OUT_A_OUT_B_VAL, val);
1451e5c9b1eSRomain Gantois }
1461e5c9b1eSRomain Gantois
fpc202_gpio_get(struct gpio_chip * chip,unsigned int offset)1471e5c9b1eSRomain Gantois static int fpc202_gpio_get(struct gpio_chip *chip, unsigned int offset)
1481e5c9b1eSRomain Gantois {
1491e5c9b1eSRomain Gantois struct fpc202_priv *priv = gpiochip_get_data(chip);
1501e5c9b1eSRomain Gantois u8 reg, bit;
1511e5c9b1eSRomain Gantois int ret;
1521e5c9b1eSRomain Gantois
1531e5c9b1eSRomain Gantois if (offset < FPC202_GPIO_P0_S0_IN_B) {
1541e5c9b1eSRomain Gantois reg = FPC202_REG_IN_A_INT;
1551e5c9b1eSRomain Gantois bit = BIT(4 + offset);
1561e5c9b1eSRomain Gantois } else if (offset < FPC202_GPIO_P0_S0_OUT_A) {
1571e5c9b1eSRomain Gantois reg = FPC202_REG_IN_C_IN_B;
1581e5c9b1eSRomain Gantois bit = BIT(offset - FPC202_GPIO_P0_S0_IN_B);
1591e5c9b1eSRomain Gantois } else {
1601e5c9b1eSRomain Gantois reg = FPC202_REG_OUT_A_OUT_B_VAL;
1611e5c9b1eSRomain Gantois bit = BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
1621e5c9b1eSRomain Gantois }
1631e5c9b1eSRomain Gantois
1641e5c9b1eSRomain Gantois ret = fpc202_read(priv, reg);
1651e5c9b1eSRomain Gantois if (ret < 0)
1661e5c9b1eSRomain Gantois return ret;
1671e5c9b1eSRomain Gantois
1681e5c9b1eSRomain Gantois return !!(((u8)ret) & bit);
1691e5c9b1eSRomain Gantois }
1701e5c9b1eSRomain Gantois
fpc202_gpio_direction_input(struct gpio_chip * chip,unsigned int offset)1711e5c9b1eSRomain Gantois static int fpc202_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
1721e5c9b1eSRomain Gantois {
1731e5c9b1eSRomain Gantois if (fpc202_gpio_get_dir(offset) == GPIO_LINE_DIRECTION_OUT)
1741e5c9b1eSRomain Gantois return -EINVAL;
1751e5c9b1eSRomain Gantois
1761e5c9b1eSRomain Gantois return 0;
1771e5c9b1eSRomain Gantois }
1781e5c9b1eSRomain Gantois
fpc202_gpio_direction_output(struct gpio_chip * chip,unsigned int offset,int value)1791e5c9b1eSRomain Gantois static int fpc202_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
1801e5c9b1eSRomain Gantois int value)
1811e5c9b1eSRomain Gantois {
1821e5c9b1eSRomain Gantois struct fpc202_priv *priv = gpiochip_get_data(chip);
1831e5c9b1eSRomain Gantois int ret;
1841e5c9b1eSRomain Gantois u8 val;
1851e5c9b1eSRomain Gantois
1861e5c9b1eSRomain Gantois if (fpc202_gpio_get_dir(offset) == GPIO_LINE_DIRECTION_IN)
1871e5c9b1eSRomain Gantois return -EINVAL;
1881e5c9b1eSRomain Gantois
1891e5c9b1eSRomain Gantois fpc202_gpio_set(chip, offset, value);
1901e5c9b1eSRomain Gantois
1911e5c9b1eSRomain Gantois ret = fpc202_read(priv, FPC202_REG_OUT_A_OUT_B);
1921e5c9b1eSRomain Gantois if (ret < 0)
1931e5c9b1eSRomain Gantois return ret;
1941e5c9b1eSRomain Gantois
1951e5c9b1eSRomain Gantois val = (u8)ret | BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
1961e5c9b1eSRomain Gantois
1971e5c9b1eSRomain Gantois return fpc202_write(priv, FPC202_REG_OUT_A_OUT_B, val);
1981e5c9b1eSRomain Gantois }
1991e5c9b1eSRomain Gantois
2001e5c9b1eSRomain Gantois /*
2011e5c9b1eSRomain Gantois * Set the translation table entry associated with a port and device number.
2021e5c9b1eSRomain Gantois *
2031e5c9b1eSRomain Gantois * Each downstream port of the FPC202 has two fixed aliases corresponding to
2041e5c9b1eSRomain Gantois * device numbers 0 and 1. If one of these aliases is found in an incoming I2C
2051e5c9b1eSRomain Gantois * transfer, it will be translated to the address given by the corresponding
2061e5c9b1eSRomain Gantois * translation table entry.
2071e5c9b1eSRomain Gantois */
fpc202_write_dev_addr(struct fpc202_priv * priv,u32 port_id,int dev_num,u16 addr)2081e5c9b1eSRomain Gantois static int fpc202_write_dev_addr(struct fpc202_priv *priv, u32 port_id, int dev_num, u16 addr)
2091e5c9b1eSRomain Gantois {
2101e5c9b1eSRomain Gantois int ret, reg_mod, reg_aux;
2111e5c9b1eSRomain Gantois u8 val;
2121e5c9b1eSRomain Gantois
2131e5c9b1eSRomain Gantois guard(mutex)(&priv->reg_dev_lock);
2141e5c9b1eSRomain Gantois
2151e5c9b1eSRomain Gantois reg_mod = FPC202_REG_MOD_DEV(port_id, dev_num);
2161e5c9b1eSRomain Gantois reg_aux = FPC202_REG_AUX_DEV(port_id, dev_num);
2171e5c9b1eSRomain Gantois val = addr & 0x7f;
2181e5c9b1eSRomain Gantois
2191e5c9b1eSRomain Gantois ret = fpc202_write(priv, reg_mod, val);
2201e5c9b1eSRomain Gantois if (ret)
2211e5c9b1eSRomain Gantois return ret;
2221e5c9b1eSRomain Gantois
2231e5c9b1eSRomain Gantois /*
2241e5c9b1eSRomain Gantois * The FPC202 datasheet is unclear about the role of the AUX registers.
2251e5c9b1eSRomain Gantois * Empirically, writing to them as well seems to be necessary for
2261e5c9b1eSRomain Gantois * address translation to function properly.
2271e5c9b1eSRomain Gantois */
2281e5c9b1eSRomain Gantois ret = fpc202_write(priv, reg_aux, val);
2291e5c9b1eSRomain Gantois
2301e5c9b1eSRomain Gantois priv->addr_caches[port_id][dev_num] = val;
2311e5c9b1eSRomain Gantois
2321e5c9b1eSRomain Gantois return ret;
2331e5c9b1eSRomain Gantois }
2341e5c9b1eSRomain Gantois
fpc202_attach_addr(struct i2c_atr * atr,u32 chan_id,u16 addr,u16 alias)2351e5c9b1eSRomain Gantois static int fpc202_attach_addr(struct i2c_atr *atr, u32 chan_id,
2361e5c9b1eSRomain Gantois u16 addr, u16 alias)
2371e5c9b1eSRomain Gantois {
2381e5c9b1eSRomain Gantois struct fpc202_priv *priv = i2c_atr_get_driver_data(atr);
2391e5c9b1eSRomain Gantois
2401e5c9b1eSRomain Gantois dev_dbg(&priv->client->dev, "attaching address 0x%02x to alias 0x%02x\n", addr, alias);
2411e5c9b1eSRomain Gantois
2421e5c9b1eSRomain Gantois return fpc202_write_dev_addr(priv, chan_id, fpc202_dev_num_from_alias(alias), addr);
2431e5c9b1eSRomain Gantois }
2441e5c9b1eSRomain Gantois
fpc202_detach_addr(struct i2c_atr * atr,u32 chan_id,u16 addr)2451e5c9b1eSRomain Gantois static void fpc202_detach_addr(struct i2c_atr *atr, u32 chan_id,
2461e5c9b1eSRomain Gantois u16 addr)
2471e5c9b1eSRomain Gantois {
2481e5c9b1eSRomain Gantois struct fpc202_priv *priv = i2c_atr_get_driver_data(atr);
2491e5c9b1eSRomain Gantois int dev_num, reg_mod, val;
2501e5c9b1eSRomain Gantois
2511e5c9b1eSRomain Gantois for (dev_num = 0; dev_num < 2; dev_num++) {
2521e5c9b1eSRomain Gantois reg_mod = FPC202_REG_MOD_DEV(chan_id, dev_num);
2531e5c9b1eSRomain Gantois
2541e5c9b1eSRomain Gantois mutex_lock(&priv->reg_dev_lock);
2551e5c9b1eSRomain Gantois
2561e5c9b1eSRomain Gantois val = priv->addr_caches[chan_id][dev_num];
2571e5c9b1eSRomain Gantois
2581e5c9b1eSRomain Gantois mutex_unlock(&priv->reg_dev_lock);
2591e5c9b1eSRomain Gantois
2601e5c9b1eSRomain Gantois if (val < 0) {
2611e5c9b1eSRomain Gantois dev_err(&priv->client->dev, "failed to read register 0x%x while detaching address 0x%02x\n",
2621e5c9b1eSRomain Gantois reg_mod, addr);
2631e5c9b1eSRomain Gantois return;
2641e5c9b1eSRomain Gantois }
2651e5c9b1eSRomain Gantois
2661e5c9b1eSRomain Gantois if (val == (addr & 0x7f)) {
2671e5c9b1eSRomain Gantois fpc202_write_dev_addr(priv, chan_id, dev_num, FPC202_REG_DEV_INVALID);
2681e5c9b1eSRomain Gantois return;
2691e5c9b1eSRomain Gantois }
2701e5c9b1eSRomain Gantois }
2711e5c9b1eSRomain Gantois }
2721e5c9b1eSRomain Gantois
2731e5c9b1eSRomain Gantois static const struct i2c_atr_ops fpc202_atr_ops = {
2741e5c9b1eSRomain Gantois .attach_addr = fpc202_attach_addr,
2751e5c9b1eSRomain Gantois .detach_addr = fpc202_detach_addr,
2761e5c9b1eSRomain Gantois };
2771e5c9b1eSRomain Gantois
fpc202_probe_port(struct fpc202_priv * priv,struct device_node * i2c_handle,int port_id)2781e5c9b1eSRomain Gantois static int fpc202_probe_port(struct fpc202_priv *priv, struct device_node *i2c_handle, int port_id)
2791e5c9b1eSRomain Gantois {
2801e5c9b1eSRomain Gantois u16 aliases[FPC202_ALIASES_PER_PORT] = { };
2811e5c9b1eSRomain Gantois struct device *dev = &priv->client->dev;
2821e5c9b1eSRomain Gantois struct i2c_atr_adap_desc desc = { };
2831e5c9b1eSRomain Gantois int ret = 0;
2841e5c9b1eSRomain Gantois
2851e5c9b1eSRomain Gantois desc.chan_id = port_id;
2861e5c9b1eSRomain Gantois desc.parent = dev;
2871e5c9b1eSRomain Gantois desc.bus_handle = of_node_to_fwnode(i2c_handle);
2881e5c9b1eSRomain Gantois desc.num_aliases = FPC202_ALIASES_PER_PORT;
2891e5c9b1eSRomain Gantois
2901e5c9b1eSRomain Gantois fpc202_fill_alias_table(priv->client, aliases, port_id);
2911e5c9b1eSRomain Gantois desc.aliases = aliases;
2921e5c9b1eSRomain Gantois
2931e5c9b1eSRomain Gantois ret = i2c_atr_add_adapter(priv->atr, &desc);
2941e5c9b1eSRomain Gantois if (ret)
2951e5c9b1eSRomain Gantois return ret;
2961e5c9b1eSRomain Gantois
2971e5c9b1eSRomain Gantois set_bit(port_id, priv->probed_ports);
2981e5c9b1eSRomain Gantois
2991e5c9b1eSRomain Gantois ret = fpc202_write_dev_addr(priv, port_id, 0, FPC202_REG_DEV_INVALID);
3001e5c9b1eSRomain Gantois if (ret)
3011e5c9b1eSRomain Gantois return ret;
3021e5c9b1eSRomain Gantois
3031e5c9b1eSRomain Gantois return fpc202_write_dev_addr(priv, port_id, 1, FPC202_REG_DEV_INVALID);
3041e5c9b1eSRomain Gantois }
3051e5c9b1eSRomain Gantois
fpc202_remove_port(struct fpc202_priv * priv,int port_id)3061e5c9b1eSRomain Gantois static void fpc202_remove_port(struct fpc202_priv *priv, int port_id)
3071e5c9b1eSRomain Gantois {
3081e5c9b1eSRomain Gantois i2c_atr_del_adapter(priv->atr, port_id);
3091e5c9b1eSRomain Gantois clear_bit(port_id, priv->probed_ports);
3101e5c9b1eSRomain Gantois }
3111e5c9b1eSRomain Gantois
fpc202_probe(struct i2c_client * client)3121e5c9b1eSRomain Gantois static int fpc202_probe(struct i2c_client *client)
3131e5c9b1eSRomain Gantois {
3141e5c9b1eSRomain Gantois struct device *dev = &client->dev;
3151e5c9b1eSRomain Gantois struct device_node *i2c_handle;
3161e5c9b1eSRomain Gantois struct fpc202_priv *priv;
3171e5c9b1eSRomain Gantois int ret, port_id;
3181e5c9b1eSRomain Gantois
3191e5c9b1eSRomain Gantois priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
3201e5c9b1eSRomain Gantois if (!priv)
3211e5c9b1eSRomain Gantois return -ENOMEM;
3221e5c9b1eSRomain Gantois
3231e5c9b1eSRomain Gantois mutex_init(&priv->reg_dev_lock);
3241e5c9b1eSRomain Gantois
3251e5c9b1eSRomain Gantois priv->client = client;
3261e5c9b1eSRomain Gantois i2c_set_clientdata(client, priv);
3271e5c9b1eSRomain Gantois
3281e5c9b1eSRomain Gantois priv->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
3291e5c9b1eSRomain Gantois if (IS_ERR(priv->en_gpio)) {
3301e5c9b1eSRomain Gantois ret = PTR_ERR(priv->en_gpio);
3311e5c9b1eSRomain Gantois dev_err(dev, "failed to fetch enable GPIO! err %d\n", ret);
3321e5c9b1eSRomain Gantois goto destroy_mutex;
3331e5c9b1eSRomain Gantois }
3341e5c9b1eSRomain Gantois
3351e5c9b1eSRomain Gantois priv->gpio.label = "gpio-fpc202";
3361e5c9b1eSRomain Gantois priv->gpio.base = -1;
3371e5c9b1eSRomain Gantois priv->gpio.direction_input = fpc202_gpio_direction_input;
3381e5c9b1eSRomain Gantois priv->gpio.direction_output = fpc202_gpio_direction_output;
3391e5c9b1eSRomain Gantois priv->gpio.set = fpc202_gpio_set;
3401e5c9b1eSRomain Gantois priv->gpio.get = fpc202_gpio_get;
3411e5c9b1eSRomain Gantois priv->gpio.ngpio = FPC202_GPIO_COUNT;
3421e5c9b1eSRomain Gantois priv->gpio.parent = dev;
3431e5c9b1eSRomain Gantois priv->gpio.owner = THIS_MODULE;
3441e5c9b1eSRomain Gantois
3451e5c9b1eSRomain Gantois ret = gpiochip_add_data(&priv->gpio, priv);
3461e5c9b1eSRomain Gantois if (ret) {
3471e5c9b1eSRomain Gantois priv->gpio.parent = NULL;
3481e5c9b1eSRomain Gantois dev_err(dev, "failed to add gpiochip err %d\n", ret);
3491e5c9b1eSRomain Gantois goto disable_gpio;
3501e5c9b1eSRomain Gantois }
3511e5c9b1eSRomain Gantois
352*18355307SCosmin Tanislav priv->atr = i2c_atr_new(client->adapter, dev, &fpc202_atr_ops, 2, 0);
3531e5c9b1eSRomain Gantois if (IS_ERR(priv->atr)) {
3541e5c9b1eSRomain Gantois ret = PTR_ERR(priv->atr);
3551e5c9b1eSRomain Gantois dev_err(dev, "failed to create i2c atr err %d\n", ret);
3561e5c9b1eSRomain Gantois goto disable_gpio;
3571e5c9b1eSRomain Gantois }
3581e5c9b1eSRomain Gantois
3591e5c9b1eSRomain Gantois i2c_atr_set_driver_data(priv->atr, priv);
3601e5c9b1eSRomain Gantois
3611e5c9b1eSRomain Gantois bitmap_zero(priv->probed_ports, FPC202_NUM_PORTS);
3621e5c9b1eSRomain Gantois
3631e5c9b1eSRomain Gantois for_each_child_of_node(dev->of_node, i2c_handle) {
3641e5c9b1eSRomain Gantois ret = of_property_read_u32(i2c_handle, "reg", &port_id);
3651e5c9b1eSRomain Gantois if (ret) {
3661e5c9b1eSRomain Gantois if (ret == -EINVAL)
3671e5c9b1eSRomain Gantois continue;
3681e5c9b1eSRomain Gantois
3691e5c9b1eSRomain Gantois dev_err(dev, "failed to read 'reg' property of child node, err %d\n", ret);
3701e5c9b1eSRomain Gantois goto unregister_chans;
3711e5c9b1eSRomain Gantois }
3721e5c9b1eSRomain Gantois
3731e5c9b1eSRomain Gantois if (port_id > FPC202_NUM_PORTS) {
3741e5c9b1eSRomain Gantois dev_err(dev, "port ID %d is out of range!\n", port_id);
3751e5c9b1eSRomain Gantois ret = -EINVAL;
3761e5c9b1eSRomain Gantois goto unregister_chans;
3771e5c9b1eSRomain Gantois }
3781e5c9b1eSRomain Gantois
3791e5c9b1eSRomain Gantois ret = fpc202_probe_port(priv, i2c_handle, port_id);
3801e5c9b1eSRomain Gantois if (ret) {
3811e5c9b1eSRomain Gantois dev_err(dev, "Failed to probe port %d, err %d\n", port_id, ret);
3821e5c9b1eSRomain Gantois goto unregister_chans;
3831e5c9b1eSRomain Gantois }
3841e5c9b1eSRomain Gantois }
3851e5c9b1eSRomain Gantois
3861e5c9b1eSRomain Gantois goto out;
3871e5c9b1eSRomain Gantois
3881e5c9b1eSRomain Gantois unregister_chans:
3891e5c9b1eSRomain Gantois for_each_set_bit(port_id, priv->probed_ports, FPC202_NUM_PORTS)
3901e5c9b1eSRomain Gantois fpc202_remove_port(priv, port_id);
3911e5c9b1eSRomain Gantois
3921e5c9b1eSRomain Gantois i2c_atr_delete(priv->atr);
3931e5c9b1eSRomain Gantois disable_gpio:
3941e5c9b1eSRomain Gantois fpc202_set_enable(priv, 0);
3951e5c9b1eSRomain Gantois gpiochip_remove(&priv->gpio);
3961e5c9b1eSRomain Gantois destroy_mutex:
3971e5c9b1eSRomain Gantois mutex_destroy(&priv->reg_dev_lock);
3981e5c9b1eSRomain Gantois out:
3991e5c9b1eSRomain Gantois return ret;
4001e5c9b1eSRomain Gantois }
4011e5c9b1eSRomain Gantois
fpc202_remove(struct i2c_client * client)4021e5c9b1eSRomain Gantois static void fpc202_remove(struct i2c_client *client)
4031e5c9b1eSRomain Gantois {
4041e5c9b1eSRomain Gantois struct fpc202_priv *priv = i2c_get_clientdata(client);
4051e5c9b1eSRomain Gantois int port_id;
4061e5c9b1eSRomain Gantois
4071e5c9b1eSRomain Gantois for_each_set_bit(port_id, priv->probed_ports, FPC202_NUM_PORTS)
4081e5c9b1eSRomain Gantois fpc202_remove_port(priv, port_id);
4091e5c9b1eSRomain Gantois
4101e5c9b1eSRomain Gantois mutex_destroy(&priv->reg_dev_lock);
4111e5c9b1eSRomain Gantois
4121e5c9b1eSRomain Gantois i2c_atr_delete(priv->atr);
4131e5c9b1eSRomain Gantois
4141e5c9b1eSRomain Gantois fpc202_set_enable(priv, 0);
4151e5c9b1eSRomain Gantois gpiochip_remove(&priv->gpio);
4161e5c9b1eSRomain Gantois }
4171e5c9b1eSRomain Gantois
4181e5c9b1eSRomain Gantois static const struct of_device_id fpc202_of_match[] = {
4191e5c9b1eSRomain Gantois { .compatible = "ti,fpc202" },
4201e5c9b1eSRomain Gantois {}
4211e5c9b1eSRomain Gantois };
4221e5c9b1eSRomain Gantois MODULE_DEVICE_TABLE(of, fpc202_of_match);
4231e5c9b1eSRomain Gantois
4241e5c9b1eSRomain Gantois static struct i2c_driver fpc202_driver = {
4251e5c9b1eSRomain Gantois .driver = {
4261e5c9b1eSRomain Gantois .name = "fpc202",
4271e5c9b1eSRomain Gantois .of_match_table = fpc202_of_match,
4281e5c9b1eSRomain Gantois },
4291e5c9b1eSRomain Gantois .probe = fpc202_probe,
4301e5c9b1eSRomain Gantois .remove = fpc202_remove,
4311e5c9b1eSRomain Gantois };
4321e5c9b1eSRomain Gantois
4331e5c9b1eSRomain Gantois module_i2c_driver(fpc202_driver);
4341e5c9b1eSRomain Gantois
4351e5c9b1eSRomain Gantois MODULE_AUTHOR("Romain Gantois <romain.gantois@bootlin.com>");
4361e5c9b1eSRomain Gantois MODULE_DESCRIPTION("TI FPC202 Dual Port Controller driver");
4371e5c9b1eSRomain Gantois MODULE_LICENSE("GPL");
4381e5c9b1eSRomain Gantois MODULE_IMPORT_NS("I2C_ATR");
439