xref: /openbmc/linux/drivers/gpio/gpio-pca9570.c (revision 16d44b6085c1d90884b264deb938a34ab85a9c6d)
1*16d44b60SSungbo Eo // SPDX-License-Identifier: GPL-2.0-only
2*16d44b60SSungbo Eo /*
3*16d44b60SSungbo Eo  * Driver for PCA9570 I2C GPO expander
4*16d44b60SSungbo Eo  *
5*16d44b60SSungbo Eo  * Copyright (C) 2020 Sungbo Eo <mans0n@gorani.run>
6*16d44b60SSungbo Eo  *
7*16d44b60SSungbo Eo  * Based on gpio-tpic2810.c
8*16d44b60SSungbo Eo  * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/
9*16d44b60SSungbo Eo  *	Andrew F. Davis <afd@ti.com>
10*16d44b60SSungbo Eo  */
11*16d44b60SSungbo Eo 
12*16d44b60SSungbo Eo #include <linux/gpio/driver.h>
13*16d44b60SSungbo Eo #include <linux/i2c.h>
14*16d44b60SSungbo Eo #include <linux/module.h>
15*16d44b60SSungbo Eo #include <linux/mutex.h>
16*16d44b60SSungbo Eo #include <linux/property.h>
17*16d44b60SSungbo Eo 
18*16d44b60SSungbo Eo /**
19*16d44b60SSungbo Eo  * struct pca9570 - GPIO driver data
20*16d44b60SSungbo Eo  * @chip: GPIO controller chip
21*16d44b60SSungbo Eo  * @lock: Protects write sequences
22*16d44b60SSungbo Eo  * @out: Buffer for device register
23*16d44b60SSungbo Eo  */
24*16d44b60SSungbo Eo struct pca9570 {
25*16d44b60SSungbo Eo 	struct gpio_chip chip;
26*16d44b60SSungbo Eo 	struct mutex lock;
27*16d44b60SSungbo Eo 	u8 out;
28*16d44b60SSungbo Eo };
29*16d44b60SSungbo Eo 
30*16d44b60SSungbo Eo static int pca9570_read(struct pca9570 *gpio, u8 *value)
31*16d44b60SSungbo Eo {
32*16d44b60SSungbo Eo 	struct i2c_client *client = to_i2c_client(gpio->chip.parent);
33*16d44b60SSungbo Eo 	int ret;
34*16d44b60SSungbo Eo 
35*16d44b60SSungbo Eo 	ret = i2c_smbus_read_byte(client);
36*16d44b60SSungbo Eo 	if (ret < 0)
37*16d44b60SSungbo Eo 		return ret;
38*16d44b60SSungbo Eo 
39*16d44b60SSungbo Eo 	*value = ret;
40*16d44b60SSungbo Eo 	return 0;
41*16d44b60SSungbo Eo }
42*16d44b60SSungbo Eo 
43*16d44b60SSungbo Eo static int pca9570_write(struct pca9570 *gpio, u8 value)
44*16d44b60SSungbo Eo {
45*16d44b60SSungbo Eo 	struct i2c_client *client = to_i2c_client(gpio->chip.parent);
46*16d44b60SSungbo Eo 
47*16d44b60SSungbo Eo 	return i2c_smbus_write_byte(client, value);
48*16d44b60SSungbo Eo }
49*16d44b60SSungbo Eo 
50*16d44b60SSungbo Eo static int pca9570_get_direction(struct gpio_chip *chip,
51*16d44b60SSungbo Eo 				 unsigned offset)
52*16d44b60SSungbo Eo {
53*16d44b60SSungbo Eo 	/* This device always output */
54*16d44b60SSungbo Eo 	return GPIO_LINE_DIRECTION_OUT;
55*16d44b60SSungbo Eo }
56*16d44b60SSungbo Eo 
57*16d44b60SSungbo Eo static int pca9570_get(struct gpio_chip *chip, unsigned offset)
58*16d44b60SSungbo Eo {
59*16d44b60SSungbo Eo 	struct pca9570 *gpio = gpiochip_get_data(chip);
60*16d44b60SSungbo Eo 	u8 buffer;
61*16d44b60SSungbo Eo 	int ret;
62*16d44b60SSungbo Eo 
63*16d44b60SSungbo Eo 	ret = pca9570_read(gpio, &buffer);
64*16d44b60SSungbo Eo 	if (ret)
65*16d44b60SSungbo Eo 		return ret;
66*16d44b60SSungbo Eo 
67*16d44b60SSungbo Eo 	return !!(buffer & BIT(offset));
68*16d44b60SSungbo Eo }
69*16d44b60SSungbo Eo 
70*16d44b60SSungbo Eo static void pca9570_set(struct gpio_chip *chip, unsigned offset, int value)
71*16d44b60SSungbo Eo {
72*16d44b60SSungbo Eo 	struct pca9570 *gpio = gpiochip_get_data(chip);
73*16d44b60SSungbo Eo 	u8 buffer;
74*16d44b60SSungbo Eo 	int ret;
75*16d44b60SSungbo Eo 
76*16d44b60SSungbo Eo 	mutex_lock(&gpio->lock);
77*16d44b60SSungbo Eo 
78*16d44b60SSungbo Eo 	buffer = gpio->out;
79*16d44b60SSungbo Eo 	if (value)
80*16d44b60SSungbo Eo 		buffer |= BIT(offset);
81*16d44b60SSungbo Eo 	else
82*16d44b60SSungbo Eo 		buffer &= ~BIT(offset);
83*16d44b60SSungbo Eo 
84*16d44b60SSungbo Eo 	ret = pca9570_write(gpio, buffer);
85*16d44b60SSungbo Eo 	if (ret)
86*16d44b60SSungbo Eo 		goto out;
87*16d44b60SSungbo Eo 
88*16d44b60SSungbo Eo 	gpio->out = buffer;
89*16d44b60SSungbo Eo 
90*16d44b60SSungbo Eo out:
91*16d44b60SSungbo Eo 	mutex_unlock(&gpio->lock);
92*16d44b60SSungbo Eo }
93*16d44b60SSungbo Eo 
94*16d44b60SSungbo Eo static int pca9570_probe(struct i2c_client *client)
95*16d44b60SSungbo Eo {
96*16d44b60SSungbo Eo 	struct pca9570 *gpio;
97*16d44b60SSungbo Eo 
98*16d44b60SSungbo Eo 	gpio = devm_kzalloc(&client->dev, sizeof(*gpio), GFP_KERNEL);
99*16d44b60SSungbo Eo 	if (!gpio)
100*16d44b60SSungbo Eo 		return -ENOMEM;
101*16d44b60SSungbo Eo 
102*16d44b60SSungbo Eo 	gpio->chip.label = client->name;
103*16d44b60SSungbo Eo 	gpio->chip.parent = &client->dev;
104*16d44b60SSungbo Eo 	gpio->chip.owner = THIS_MODULE;
105*16d44b60SSungbo Eo 	gpio->chip.get_direction = pca9570_get_direction;
106*16d44b60SSungbo Eo 	gpio->chip.get = pca9570_get;
107*16d44b60SSungbo Eo 	gpio->chip.set = pca9570_set;
108*16d44b60SSungbo Eo 	gpio->chip.base = -1;
109*16d44b60SSungbo Eo 	gpio->chip.ngpio = (uintptr_t)device_get_match_data(&client->dev);
110*16d44b60SSungbo Eo 	gpio->chip.can_sleep = true;
111*16d44b60SSungbo Eo 
112*16d44b60SSungbo Eo 	mutex_init(&gpio->lock);
113*16d44b60SSungbo Eo 
114*16d44b60SSungbo Eo 	/* Read the current output level */
115*16d44b60SSungbo Eo 	pca9570_read(gpio, &gpio->out);
116*16d44b60SSungbo Eo 
117*16d44b60SSungbo Eo 	i2c_set_clientdata(client, gpio);
118*16d44b60SSungbo Eo 
119*16d44b60SSungbo Eo 	return devm_gpiochip_add_data(&client->dev, &gpio->chip, gpio);
120*16d44b60SSungbo Eo }
121*16d44b60SSungbo Eo 
122*16d44b60SSungbo Eo static const struct i2c_device_id pca9570_id_table[] = {
123*16d44b60SSungbo Eo 	{ "pca9570", 4 },
124*16d44b60SSungbo Eo 	{ /* sentinel */ }
125*16d44b60SSungbo Eo };
126*16d44b60SSungbo Eo MODULE_DEVICE_TABLE(i2c, pca9570_id_table);
127*16d44b60SSungbo Eo 
128*16d44b60SSungbo Eo static const struct of_device_id pca9570_of_match_table[] = {
129*16d44b60SSungbo Eo 	{ .compatible = "nxp,pca9570", .data = (void *)4 },
130*16d44b60SSungbo Eo 	{ /* sentinel */ }
131*16d44b60SSungbo Eo };
132*16d44b60SSungbo Eo MODULE_DEVICE_TABLE(of, pca9570_of_match_table);
133*16d44b60SSungbo Eo 
134*16d44b60SSungbo Eo static struct i2c_driver pca9570_driver = {
135*16d44b60SSungbo Eo 	.driver = {
136*16d44b60SSungbo Eo 		.name = "pca9570",
137*16d44b60SSungbo Eo 		.of_match_table = pca9570_of_match_table,
138*16d44b60SSungbo Eo 	},
139*16d44b60SSungbo Eo 	.probe_new = pca9570_probe,
140*16d44b60SSungbo Eo 	.id_table = pca9570_id_table,
141*16d44b60SSungbo Eo };
142*16d44b60SSungbo Eo module_i2c_driver(pca9570_driver);
143*16d44b60SSungbo Eo 
144*16d44b60SSungbo Eo MODULE_AUTHOR("Sungbo Eo <mans0n@gorani.run>");
145*16d44b60SSungbo Eo MODULE_DESCRIPTION("GPIO expander driver for PCA9570");
146*16d44b60SSungbo Eo MODULE_LICENSE("GPL v2");
147