xref: /linux/drivers/gpio/gpio-ltc4283.c (revision d2c9a99135da931377240942d44f3dea104cedb8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Analog Devices LTC4283 GPIO driver
4  *
5  * Copyright 2025 Analog Devices Inc.
6  */
7 
8 #include <linux/auxiliary_bus.h>
9 #include <linux/bitfield.h>
10 #include <linux/bitmap.h>
11 #include <linux/bits.h>
12 #include <linux/device.h>
13 #include <linux/gpio/driver.h>
14 #include <linux/module.h>
15 #include <linux/regmap.h>
16 
17 #define LTC4283_PINS_MAX			8
18 #define LTC4283_PGIOX_START_NR			4
19 #define LTC4283_INPUT_STATUS			0x02
20 #define LTC4283_PGIO_CONFIG			0x10
21 #define   LTC4283_PGIO_CFG_MASK(pin) \
22 	GENMASK(((pin) - LTC4283_PGIOX_START_NR) * 2 + 1, (((pin) - LTC4283_PGIOX_START_NR) * 2))
23 #define LTC4283_PGIO_CONFIG_2			0x11
24 
25 #define LTC4283_ADIO_CONFIG			0x12
26 /* starts at bit 4 */
27 #define   LTC4283_ADIOX_CONFIG_MASK(pin)	BIT((pin) + 4)
28 #define LTC4283_PGIO_DIR_IN			3
29 #define LTC4283_PGIO_DIR_OUT			2
30 
31 struct ltc4283_gpio {
32 	struct gpio_chip gpio_chip;
33 	struct regmap *regmap;
34 };
35 
ltc4283_pgio_get_direction(const struct ltc4283_gpio * st,unsigned int off)36 static int ltc4283_pgio_get_direction(const struct ltc4283_gpio *st, unsigned int off)
37 {
38 	unsigned int val;
39 	int ret;
40 
41 	ret = regmap_read(st->regmap, LTC4283_PGIO_CONFIG, &val);
42 	if (ret)
43 		return ret;
44 
45 	val = field_get(LTC4283_PGIO_CFG_MASK(off), val);
46 	if (val == LTC4283_PGIO_DIR_IN)
47 		return GPIO_LINE_DIRECTION_IN;
48 
49 	return GPIO_LINE_DIRECTION_OUT;
50 }
51 
ltc4283_gpio_get_direction(struct gpio_chip * gc,unsigned int off)52 static int ltc4283_gpio_get_direction(struct gpio_chip *gc, unsigned int off)
53 {
54 	struct ltc4283_gpio *st = gpiochip_get_data(gc);
55 	unsigned int val;
56 	int ret;
57 
58 	if (off >= LTC4283_PGIOX_START_NR)
59 		return ltc4283_pgio_get_direction(st, off);
60 
61 	ret = regmap_read(st->regmap, LTC4283_ADIO_CONFIG, &val);
62 	if (ret)
63 		return ret;
64 
65 	if (val & LTC4283_ADIOX_CONFIG_MASK(off))
66 		return GPIO_LINE_DIRECTION_IN;
67 
68 	return GPIO_LINE_DIRECTION_OUT;
69 }
70 
ltc4283_gpio_direction_set(const struct ltc4283_gpio * st,unsigned int off,bool input)71 static int ltc4283_gpio_direction_set(const struct ltc4283_gpio *st,
72 				      unsigned int off, bool input)
73 {
74 	if (off >= LTC4283_PGIOX_START_NR) {
75 		unsigned int val = LTC4283_PGIO_DIR_OUT;
76 
77 		if (input)
78 			val = LTC4283_PGIO_DIR_IN;
79 
80 		val = field_prep(LTC4283_PGIO_CFG_MASK(off), val);
81 		return regmap_update_bits(st->regmap, LTC4283_PGIO_CONFIG,
82 					  LTC4283_PGIO_CFG_MASK(off), val);
83 	}
84 
85 	return regmap_update_bits(st->regmap, LTC4283_ADIO_CONFIG,
86 				  LTC4283_ADIOX_CONFIG_MASK(off),
87 				  field_prep(LTC4283_ADIOX_CONFIG_MASK(off), input));
88 }
89 
__ltc4283_gpio_set_value(const struct ltc4283_gpio * st,unsigned int off,int val)90 static int __ltc4283_gpio_set_value(const struct ltc4283_gpio *st,
91 				    unsigned int off, int val)
92 {
93 	u32 reg = off < LTC4283_PGIOX_START_NR ? LTC4283_ADIO_CONFIG : LTC4283_PGIO_CONFIG_2;
94 
95 	return regmap_update_bits(st->regmap, reg, BIT(off),
96 				  field_prep(BIT(off), !!val));
97 }
98 
ltc4283_gpio_direction_input(struct gpio_chip * gc,unsigned int off)99 static int ltc4283_gpio_direction_input(struct gpio_chip *gc, unsigned int off)
100 {
101 	struct ltc4283_gpio *st = gpiochip_get_data(gc);
102 
103 	return ltc4283_gpio_direction_set(st, off, true);
104 }
105 
ltc4283_gpio_direction_output(struct gpio_chip * gc,unsigned int off,int val)106 static int ltc4283_gpio_direction_output(struct gpio_chip *gc, unsigned int off, int val)
107 {
108 	struct ltc4283_gpio *st = gpiochip_get_data(gc);
109 	int ret;
110 
111 	ret = ltc4283_gpio_direction_set(st, off, false);
112 	if (ret)
113 		return ret;
114 
115 	return __ltc4283_gpio_set_value(st, off, val);
116 }
117 
ltc4283_gpio_get_value(struct gpio_chip * gc,unsigned int off)118 static int ltc4283_gpio_get_value(struct gpio_chip *gc, unsigned int off)
119 {
120 	struct ltc4283_gpio *st = gpiochip_get_data(gc);
121 	unsigned int val, reg;
122 	int ret, dir;
123 
124 	dir = ltc4283_gpio_get_direction(gc, off);
125 	if (dir < 0)
126 		return dir;
127 
128 	if (dir == GPIO_LINE_DIRECTION_IN) {
129 		ret = regmap_read(st->regmap, LTC4283_INPUT_STATUS, &val);
130 		if (ret)
131 			return ret;
132 
133 		/* ADIO1 is at bit 3. */
134 		if (off < LTC4283_PGIOX_START_NR)
135 			return !!(val & BIT(3 - off));
136 
137 		/* PGIO1 is at bit 7. */
138 		return !!(val & BIT(7 - (off - LTC4283_PGIOX_START_NR)));
139 	}
140 
141 	if (off < LTC4283_PGIOX_START_NR)
142 		reg = LTC4283_ADIO_CONFIG;
143 	else
144 		reg = LTC4283_PGIO_CONFIG_2;
145 
146 	ret = regmap_read(st->regmap, reg, &val);
147 	if (ret)
148 		return ret;
149 
150 	return !!(val & BIT(off));
151 }
152 
ltc4283_gpio_set_value(struct gpio_chip * gc,unsigned int off,int val)153 static int ltc4283_gpio_set_value(struct gpio_chip *gc, unsigned int off, int val)
154 {
155 	struct ltc4283_gpio *st = gpiochip_get_data(gc);
156 
157 	return __ltc4283_gpio_set_value(st, off, val);
158 }
159 
ltc4283_init_valid_mask(struct gpio_chip * gc,unsigned long * valid_mask,unsigned int ngpios)160 static int ltc4283_init_valid_mask(struct gpio_chip *gc, unsigned long *valid_mask,
161 				   unsigned int ngpios)
162 {
163 	unsigned long *mask = dev_get_platdata(gc->parent);
164 
165 	bitmap_copy(valid_mask, mask, ngpios);
166 	return 0;
167 }
168 
ltc4283_gpio_probe(struct auxiliary_device * adev,const struct auxiliary_device_id * id)169 static int ltc4283_gpio_probe(struct auxiliary_device *adev,
170 			      const struct auxiliary_device_id *id)
171 {
172 	struct device *dev = &adev->dev;
173 	struct ltc4283_gpio *st;
174 	struct gpio_chip *gc;
175 
176 	st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
177 	if (!st)
178 		return -ENOMEM;
179 
180 	st->regmap = dev_get_regmap(dev->parent, NULL);
181 	if (!st->regmap)
182 		return dev_err_probe(dev, -ENODEV,
183 				     "Failed to get regmap\n");
184 
185 	gc = &st->gpio_chip;
186 	gc->parent = dev;
187 	gc->get_direction = ltc4283_gpio_get_direction;
188 	gc->direction_input = ltc4283_gpio_direction_input;
189 	gc->direction_output = ltc4283_gpio_direction_output;
190 	gc->get = ltc4283_gpio_get_value;
191 	gc->set = ltc4283_gpio_set_value;
192 	gc->init_valid_mask = ltc4283_init_valid_mask;
193 	gc->can_sleep = true;
194 
195 	gc->base = -1;
196 	gc->ngpio = LTC4283_PINS_MAX;
197 	gc->label = adev->name;
198 	gc->owner = THIS_MODULE;
199 
200 	return devm_gpiochip_add_data(dev, &st->gpio_chip, st);
201 }
202 
203 static const struct auxiliary_device_id ltc4283_aux_id_table[] = {
204 	{ "ltc4283.gpio" },
205 	{ }
206 };
207 MODULE_DEVICE_TABLE(auxiliary, ltc4283_aux_id_table);
208 
209 static struct auxiliary_driver ltc4283_gpio_driver = {
210 	.probe = ltc4283_gpio_probe,
211 	.id_table = ltc4283_aux_id_table,
212 };
213 module_auxiliary_driver(ltc4283_gpio_driver);
214 
215 MODULE_AUTHOR("Nuno Sá <nuno.sa@analog.com>");
216 MODULE_DESCRIPTION("GPIO LTC4283 Driver");
217 MODULE_LICENSE("GPL");
218