File Index
Files and directories
Sign in
FILE

ti_fpc202.c

File preview with syntax highlighting.

linux-6.19.14/drivers/misc/ti_fpc202.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * ti_fpc202.c - FPC202 Dual Port Controller driver
  4 *
  5 * Copyright (C) 2024 Bootlin
  6 *
  7 */
  8
  9#include <linux/cleanup.h>
 10#include <linux/err.h>
 11#include <linux/i2c.h>
 12#include <linux/i2c-atr.h>
 13#include <linux/gpio/consumer.h>
 14#include <linux/gpio/driver.h>
 15#include <linux/module.h>
 16
 17#define FPC202_NUM_PORTS 2
 18#define FPC202_ALIASES_PER_PORT 2
 19
 20/*
 21 * GPIO: port mapping
 22 *
 23 * 0: P0_S0_IN_A
 24 * 1: P0_S1_IN_A
 25 * 2: P1_S0_IN_A
 26 * 3: P1_S1_IN_A
 27 * 4: P0_S0_IN_B
 28 * ...
 29 * 8: P0_S0_IN_C
 30 * ...
 31 * 12: P0_S0_OUT_A
 32 * ...
 33 * 16: P0_S0_OUT_B
 34 * ...
 35 * 19: P1_S1_OUT_B
 36 *
 37 */
 38
 39#define FPC202_GPIO_COUNT 20
 40#define FPC202_GPIO_P0_S0_IN_B  4
 41#define FPC202_GPIO_P0_S0_OUT_A 12
 42
 43#define FPC202_REG_IN_A_INT    0x6
 44#define FPC202_REG_IN_C_IN_B   0x7
 45#define FPC202_REG_OUT_A_OUT_B 0x8
 46
 47#define FPC202_REG_OUT_A_OUT_B_VAL 0xa
 48
 49#define FPC202_REG_MOD_DEV(port, dev) (0xb4 + ((port) * 4) + (dev))
 50#define FPC202_REG_AUX_DEV(port, dev) (0xb6 + ((port) * 4) + (dev))
 51
 52/*
 53 * The FPC202 doesn't support turning off address translation on a single port.
 54 * So just set an invalid I2C address as the translation target when no client
 55 * address is attached.
 56 */
 57#define FPC202_REG_DEV_INVALID 0
 58
 59/* Even aliases are assigned to device 0 and odd aliases to device 1 */
 60#define fpc202_dev_num_from_alias(alias) ((alias) % 2)
 61
 62struct fpc202_priv {
 63	struct i2c_client *client;
 64	struct i2c_atr *atr;
 65	struct gpio_desc *en_gpio;
 66	struct gpio_chip gpio;
 67
 68	/* Lock REG_MOD/AUX_DEV and addr_caches during attach/detach */
 69	struct mutex reg_dev_lock;
 70
 71	/* Cached device addresses for both ports and their devices */
 72	u8 addr_caches[2][2];
 73
 74	/* Keep track of which ports were probed */
 75	DECLARE_BITMAP(probed_ports, FPC202_NUM_PORTS);
 76};
 77
 78static void fpc202_fill_alias_table(struct i2c_client *client, u16 *aliases, int port_id)
 79{
 80	u16 first_alias;
 81	int i;
 82
 83	/*
 84	 * There is a predefined list of aliases for each FPC202 I2C
 85	 * self-address.  This allows daisy-chained FPC202 units to
 86	 * automatically take on different sets of aliases.
 87	 * Each port of an FPC202 unit is assigned two aliases from this list.
 88	 */
 89	first_alias = 0x10 + 4 * port_id + 8 * ((u16)client->addr - 2);
 90
 91	for (i = 0; i < FPC202_ALIASES_PER_PORT; i++)
 92		aliases[i] = first_alias + i;
 93}
 94
 95static int fpc202_gpio_get_dir(int offset)
 96{
 97	return offset < FPC202_GPIO_P0_S0_OUT_A ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
 98}
 99
100static int fpc202_read(struct fpc202_priv *priv, u8 reg)
101{
102	int val;
103
104	val = i2c_smbus_read_byte_data(priv->client, reg);
105	return val;
106}
107
108static int fpc202_write(struct fpc202_priv *priv, u8 reg, u8 value)
109{
110	return i2c_smbus_write_byte_data(priv->client, reg, value);
111}
112
113static void fpc202_set_enable(struct fpc202_priv *priv, int enable)
114{
115	if (!priv->en_gpio)
116		return;
117
118	gpiod_set_value(priv->en_gpio, enable);
119}
120
121static int fpc202_gpio_set(struct gpio_chip *chip, unsigned int offset,
122			   int value)
123{
124	struct fpc202_priv *priv = gpiochip_get_data(chip);
125	int ret;
126	u8 val;
127
128	ret = fpc202_read(priv, FPC202_REG_OUT_A_OUT_B_VAL);
129	if (ret < 0) {
130		dev_err(&priv->client->dev, "Failed to set GPIO %d value! err %d\n", offset, ret);
131		return ret;
132	}
133
134	val = (u8)ret;
135
136	if (value)
137		val |= BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
138	else
139		val &= ~BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
140
141	return fpc202_write(priv, FPC202_REG_OUT_A_OUT_B_VAL, val);
142}
143
144static int fpc202_gpio_get(struct gpio_chip *chip, unsigned int offset)
145{
146	struct fpc202_priv *priv = gpiochip_get_data(chip);
147	u8 reg, bit;
148	int ret;
149
150	if (offset < FPC202_GPIO_P0_S0_IN_B) {
151		reg = FPC202_REG_IN_A_INT;
152		bit = BIT(4 + offset);
153	} else if (offset < FPC202_GPIO_P0_S0_OUT_A) {
154		reg = FPC202_REG_IN_C_IN_B;
155		bit = BIT(offset - FPC202_GPIO_P0_S0_IN_B);
156	} else {
157		reg = FPC202_REG_OUT_A_OUT_B_VAL;
158		bit = BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
159	}
160
161	ret = fpc202_read(priv, reg);
162	if (ret < 0)
163		return ret;
164
165	return !!(((u8)ret) & bit);
166}
167
168static int fpc202_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
169{
170	if (fpc202_gpio_get_dir(offset) == GPIO_LINE_DIRECTION_OUT)
171		return -EINVAL;
172
173	return 0;
174}
175
176static int fpc202_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
177					int value)
178{
179	struct fpc202_priv *priv = gpiochip_get_data(chip);
180	int ret;
181	u8 val;
182
183	if (fpc202_gpio_get_dir(offset) == GPIO_LINE_DIRECTION_IN)
184		return -EINVAL;
185
186	fpc202_gpio_set(chip, offset, value);
187
188	ret = fpc202_read(priv, FPC202_REG_OUT_A_OUT_B);
189	if (ret < 0)
190		return ret;
191
192	val = (u8)ret | BIT(offset - FPC202_GPIO_P0_S0_OUT_A);
193
194	return fpc202_write(priv, FPC202_REG_OUT_A_OUT_B, val);
195}
196
197/*
198 * Set the translation table entry associated with a port and device number.
199 *
200 * Each downstream port of the FPC202 has two fixed aliases corresponding to
201 * device numbers 0 and 1. If one of these aliases is found in an incoming I2C
202 * transfer, it will be translated to the address given by the corresponding
203 * translation table entry.
204 */
205static int fpc202_write_dev_addr(struct fpc202_priv *priv, u32 port_id, int dev_num, u16 addr)
206{
207	int ret, reg_mod, reg_aux;
208	u8 val;
209
210	guard(mutex)(&priv->reg_dev_lock);
211
212	reg_mod = FPC202_REG_MOD_DEV(port_id, dev_num);
213	reg_aux = FPC202_REG_AUX_DEV(port_id, dev_num);
214	val = addr & 0x7f;
215
216	ret = fpc202_write(priv, reg_mod, val);
217	if (ret)
218		return ret;
219
220	/*
221	 * The FPC202 datasheet is unclear about the role of the AUX registers.
222	 * Empirically, writing to them as well seems to be necessary for
223	 * address translation to function properly.
224	 */
225	ret = fpc202_write(priv, reg_aux, val);
226
227	priv->addr_caches[port_id][dev_num] = val;
228
229	return ret;
230}
231
232static int fpc202_attach_addr(struct i2c_atr *atr, u32 chan_id,
233			      u16 addr, u16 alias)
234{
235	struct fpc202_priv *priv = i2c_atr_get_driver_data(atr);
236
237	dev_dbg(&priv->client->dev, "attaching address 0x%02x to alias 0x%02x\n", addr, alias);
238
239	return fpc202_write_dev_addr(priv, chan_id, fpc202_dev_num_from_alias(alias), addr);
240}
241
242static void fpc202_detach_addr(struct i2c_atr *atr, u32 chan_id,
243			       u16 addr)
244{
245	struct fpc202_priv *priv = i2c_atr_get_driver_data(atr);
246	int dev_num, reg_mod, val;
247
248	for (dev_num = 0; dev_num < 2; dev_num++) {
249		reg_mod = FPC202_REG_MOD_DEV(chan_id, dev_num);
250
251		mutex_lock(&priv->reg_dev_lock);
252
253		val = priv->addr_caches[chan_id][dev_num];
254
255		mutex_unlock(&priv->reg_dev_lock);
256
257		if (val < 0) {
258			dev_err(&priv->client->dev, "failed to read register 0x%x while detaching address 0x%02x\n",
259				reg_mod, addr);
260			return;
261		}
262
263		if (val == (addr & 0x7f)) {
264			fpc202_write_dev_addr(priv, chan_id, dev_num, FPC202_REG_DEV_INVALID);
265			return;
266		}
267	}
268}
269
270static const struct i2c_atr_ops fpc202_atr_ops = {
271	.attach_addr = fpc202_attach_addr,
272	.detach_addr = fpc202_detach_addr,
273};
274
275static int fpc202_probe_port(struct fpc202_priv *priv, struct device_node *i2c_handle, int port_id)
276{
277	u16 aliases[FPC202_ALIASES_PER_PORT] = { };
278	struct device *dev = &priv->client->dev;
279	struct i2c_atr_adap_desc desc = { };
280	int ret = 0;
281
282	desc.chan_id = port_id;
283	desc.parent = dev;
284	desc.bus_handle = of_fwnode_handle(i2c_handle);
285	desc.num_aliases = FPC202_ALIASES_PER_PORT;
286
287	fpc202_fill_alias_table(priv->client, aliases, port_id);
288	desc.aliases = aliases;
289
290	ret = i2c_atr_add_adapter(priv->atr, &desc);
291	if (ret)
292		return ret;
293
294	set_bit(port_id, priv->probed_ports);
295
296	ret = fpc202_write_dev_addr(priv, port_id, 0, FPC202_REG_DEV_INVALID);
297	if (ret)
298		return ret;
299
300	return fpc202_write_dev_addr(priv, port_id, 1, FPC202_REG_DEV_INVALID);
301}
302
303static void fpc202_remove_port(struct fpc202_priv *priv, int port_id)
304{
305	i2c_atr_del_adapter(priv->atr, port_id);
306	clear_bit(port_id, priv->probed_ports);
307}
308
309static int fpc202_probe(struct i2c_client *client)
310{
311	struct device *dev = &client->dev;
312	struct fpc202_priv *priv;
313	int ret, port_id;
314
315	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
316	if (!priv)
317		return -ENOMEM;
318
319	mutex_init(&priv->reg_dev_lock);
320
321	priv->client = client;
322	i2c_set_clientdata(client, priv);
323
324	priv->en_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH);
325	if (IS_ERR(priv->en_gpio)) {
326		ret = PTR_ERR(priv->en_gpio);
327		dev_err(dev, "failed to fetch enable GPIO! err %d\n", ret);
328		goto destroy_mutex;
329	}
330
331	priv->gpio.label = "gpio-fpc202";
332	priv->gpio.base = -1;
333	priv->gpio.direction_input = fpc202_gpio_direction_input;
334	priv->gpio.direction_output = fpc202_gpio_direction_output;
335	priv->gpio.set = fpc202_gpio_set;
336	priv->gpio.get = fpc202_gpio_get;
337	priv->gpio.ngpio = FPC202_GPIO_COUNT;
338	priv->gpio.parent = dev;
339	priv->gpio.owner = THIS_MODULE;
340
341	ret = gpiochip_add_data(&priv->gpio, priv);
342	if (ret) {
343		priv->gpio.parent = NULL;
344		dev_err(dev, "failed to add gpiochip err %d\n", ret);
345		goto disable_gpio;
346	}
347
348	priv->atr = i2c_atr_new(client->adapter, dev, &fpc202_atr_ops, 2, 0);
349	if (IS_ERR(priv->atr)) {
350		ret = PTR_ERR(priv->atr);
351		dev_err(dev, "failed to create i2c atr err %d\n", ret);
352		goto disable_gpio;
353	}
354
355	i2c_atr_set_driver_data(priv->atr, priv);
356
357	bitmap_zero(priv->probed_ports, FPC202_NUM_PORTS);
358
359	for_each_child_of_node_scoped(dev->of_node, i2c_handle) {
360		ret = of_property_read_u32(i2c_handle, "reg", &port_id);
361		if (ret) {
362			if (ret == -EINVAL)
363				continue;
364
365			dev_err(dev, "failed to read 'reg' property of child node, err %d\n", ret);
366			goto unregister_chans;
367		}
368
369		if (port_id > FPC202_NUM_PORTS) {
370			dev_err(dev, "port ID %d is out of range!\n", port_id);
371			ret = -EINVAL;
372			goto unregister_chans;
373		}
374
375		ret = fpc202_probe_port(priv, i2c_handle, port_id);
376		if (ret) {
377			dev_err(dev, "Failed to probe port %d, err %d\n", port_id, ret);
378			goto unregister_chans;
379		}
380	}
381
382	goto out;
383
384unregister_chans:
385	for_each_set_bit(port_id, priv->probed_ports, FPC202_NUM_PORTS)
386		fpc202_remove_port(priv, port_id);
387
388	i2c_atr_delete(priv->atr);
389disable_gpio:
390	fpc202_set_enable(priv, 0);
391	gpiochip_remove(&priv->gpio);
392destroy_mutex:
393	mutex_destroy(&priv->reg_dev_lock);
394out:
395	return ret;
396}
397
398static void fpc202_remove(struct i2c_client *client)
399{
400	struct fpc202_priv *priv = i2c_get_clientdata(client);
401	int port_id;
402
403	for_each_set_bit(port_id, priv->probed_ports, FPC202_NUM_PORTS)
404		fpc202_remove_port(priv, port_id);
405
406	mutex_destroy(&priv->reg_dev_lock);
407
408	i2c_atr_delete(priv->atr);
409
410	fpc202_set_enable(priv, 0);
411	gpiochip_remove(&priv->gpio);
412}
413
414static const struct of_device_id fpc202_of_match[] = {
415	{ .compatible = "ti,fpc202" },
416	{}
417};
418MODULE_DEVICE_TABLE(of, fpc202_of_match);
419
420static struct i2c_driver fpc202_driver = {
421	.driver = {
422		.name = "fpc202",
423		.of_match_table = fpc202_of_match,
424	},
425	.probe = fpc202_probe,
426	.remove = fpc202_remove,
427};
428
429module_i2c_driver(fpc202_driver);
430
431MODULE_AUTHOR("Romain Gantois <romain.gantois@bootlin.com>");
432MODULE_DESCRIPTION("TI FPC202 Dual Port Controller driver");
433MODULE_LICENSE("GPL");
434MODULE_IMPORT_NS("I2C_ATR");
~/ Read-only file preview.