xref: /illumos-gate/usr/src/uts/common/io/i2c/gpio/pca953x/pca953x.c (revision a3ebb524df668b0fc3a38f33d0049380f5f11ec1)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2025 Oxide Computer Company
14  */
15 
16 /*
17  * GPIO Controller for devices that are in the PCA953x style. These devices have
18  * a group of 4 control registers for every 8 bits of GPIOs. These control
19  * registers are:
20  *
21  *  - Input Register: Read-only current value, subject to polarity
22  *  - Output Register: Output values
23  *  - Polarity Inversion: Controls whether the input/output polarity is inverted
24  *  - I/O Configuration: Controls whether the pin is an input or output
25  *
26  * The devices families change up how these are laid out. For the 4-bit and
27  * 8-bit devies such as the PCA9536/7 and PCA9538, these are laid out as
28  * registers 0-3. The 4-bit version just ignores the upper bits.
29  *
30  * For the 16-bit versions such as the PCA9535 and PCA9539, the registers are
31  * doubled up. Meaning you have both Input registers at 0/1, both output
32  * registers at at 2/3, etc.
33  *
34  * For the 40-bit PCA9506, this is set up so that all 40-bits for a given device
35  * are in a row with reserved registers up to the next 8 byte gap. So input
36  * registers cover 0-7, output 8-15, etc.
37  */
38 
39 #include <sys/modctl.h>
40 #include <sys/conf.h>
41 #include <sys/devops.h>
42 #include <sys/ddi.h>
43 #include <sys/sunddi.h>
44 #include <sys/sysmacros.h>
45 #include <sys/debug.h>
46 #include <sys/bitext.h>
47 
48 #include <sys/i2c/client.h>
49 #include <sys/gpio/kgpio_provider.h>
50 #include <sys/gpio/pca953x.h>
51 
52 /*
53  * These are the logical registers that exist in this series of devices. There
54  * are multiple different instances of them and their spacing depends on the
55  * device. There is an additional MASK register that is present on some devices,
56  * but not all. Currently those are not exposed.
57  */
58 typedef enum {
59 	PCA953X_R_INPUT	=	0,
60 	PCA953X_R_OUTPUT,
61 	PCA953X_R_POLARITY,
62 	PCA953X_R_CONFIG
63 } pca953x_regs_t;
64 
65 #define	PCA953X_R_INPUT_GET_IN(r, idx)		bitx8(r, idx, idx)
66 #define	PCA953X_R_INPUT_GET_OUT(r, idx)		bitx8(r, idx, idx)
67 #define	PCA953X_R_INPUT_SET_OUT(r, idx, v)	bitset8(r, idx, idx, v)
68 #define	PCA953X_R_POLARITY_GET_POL(r, idx)	bitx8(r, idx, idx)
69 #define	PCA953X_R_POLARITY_SET_POL(r, idx, v)	bitset8(r, idx, idx, v)
70 #define	PCA953X_R_POLARITY_DEF		0
71 #define	PCA953X_R_POLARITY_INVERT	0
72 #define	PCA953X_R_CONFIG_GET_CFG(r, idx)	bitx8(r, idx, idx)
73 #define	PCA953X_R_CONFIG_SET_CFG(r, idx, v)	bitset8(r, idx, idx, v)
74 #define	PCA953X_R_CONFIG_OUTPUT		0
75 #define	PCA953X_R_CONFIG_INPUT		1
76 
77 typedef struct pca953x_ident {
78 	const char *pi_name;
79 	const char *pi_compat;
80 	/*
81 	 * Maximum register for the device, inclusive.
82 	 */
83 	uint32_t pi_nregs;
84 	/*
85 	 * Total number of GPIOs per device.
86 	 */
87 	uint32_t pi_ngpios;
88 	/*
89 	 * The number of banks of 8 GPIOs between register groups.
90 	 */
91 	uint32_t pi_nbanks;
92 } pca953x_ident_t;
93 
94 typedef struct pca953x {
95 	dev_info_t *pca_dip;
96 	const pca953x_ident_t *pca_ident;
97 	i2c_client_t *pca_client;
98 	i2c_reg_hdl_t *pca_regs;
99 } pca953x_t;
100 
101 static const pca953x_ident_t pca953x_idents[] = {
102 	{ "pca9505", "nxp,pca9505", 39, 40, 8 },
103 	{ "pca9506", "nxp,pca9506", 39, 40, 8 },
104 	{ "pca9535", "nxp,pca9535", 7, 16, 2 },
105 	{ "pca9539", "nxp,pca9539", 7, 16, 2 },
106 };
107 
108 /*
109  * Map a given gpio_id and register to the corrseponding bit and byte. Each
110  * register has nbanks worth of reigsters. This may be more than there are
111  * GPIOs.
112  */
113 static void
pca953x_gpio_to_reg_bit(const pca953x_t * pca,const uint32_t gpio_id,const pca953x_regs_t reg,uint8_t * regp,uint8_t * bitp)114 pca953x_gpio_to_reg_bit(const pca953x_t *pca, const uint32_t gpio_id,
115     const pca953x_regs_t reg, uint8_t *regp, uint8_t *bitp)
116 {
117 	VERIFY3U(gpio_id, <=, UINT8_MAX);
118 	VERIFY3U(gpio_id, <, pca->pca_ident->pi_ngpios);
119 
120 	if (bitp != NULL)
121 		*bitp = gpio_id % NBBY;
122 	if (regp != NULL)
123 		*regp = pca->pca_ident->pi_nbanks * reg + gpio_id / NBBY;
124 }
125 
126 static int
pca953x_gpio_regs_get(pca953x_t * pca,uint32_t gpio_id,i2c_txn_t ** txnp,uint8_t * inp,uint8_t * outp,uint8_t * polp,uint8_t * cfgp)127 pca953x_gpio_regs_get(pca953x_t *pca, uint32_t gpio_id, i2c_txn_t **txnp,
128     uint8_t *inp, uint8_t *outp, uint8_t *polp, uint8_t *cfgp)
129 {
130 	i2c_error_t err;
131 	uint8_t reg;
132 
133 	err.i2c_error = i2c_bus_lock(pca->pca_client, 0, txnp);
134 	if (err.i2c_error == I2C_CORE_E_LOCK_WAIT_SIGNAL) {
135 		return (EINTR);
136 	} else if (err.i2c_error != I2C_CORE_E_OK) {
137 		dev_err(pca->pca_dip, CE_WARN, "!unexpected i2c error while "
138 		    "attempting to take bus lock: 0x%x", err.i2c_error);
139 		return (EIO);
140 	}
141 
142 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_INPUT, &reg, NULL);
143 	if (inp != NULL && !i2c_reg_get(*txnp, pca->pca_regs, reg, inp,
144 	    sizeof (uint8_t), &err)) {
145 		dev_err(pca->pca_dip, CE_WARN, "!failed to read input "
146 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
147 		    err.i2c_ctrl);
148 		goto err;
149 	}
150 
151 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_OUTPUT, &reg, NULL);
152 	if (outp != NULL && !i2c_reg_get(*txnp, pca->pca_regs, reg, outp,
153 	    sizeof (uint8_t), &err)) {
154 		dev_err(pca->pca_dip, CE_WARN, "!failed to read output "
155 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
156 		    err.i2c_ctrl);
157 		goto err;
158 	}
159 
160 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_POLARITY, &reg, NULL);
161 	if (polp != NULL && !i2c_reg_get(*txnp, pca->pca_regs, reg, polp,
162 	    sizeof (uint8_t), &err)) {
163 		dev_err(pca->pca_dip, CE_WARN, "!failed to read polarity "
164 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
165 		    err.i2c_ctrl);
166 		goto err;
167 	}
168 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_CONFIG, &reg, NULL);
169 	if (cfgp != NULL && !i2c_reg_get(*txnp, pca->pca_regs, reg, cfgp,
170 	    sizeof (uint8_t), &err)) {
171 		dev_err(pca->pca_dip, CE_WARN, "!failed to read config "
172 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
173 		    err.i2c_ctrl);
174 		goto err;
175 	}
176 
177 	return (0);
178 
179 err:
180 	i2c_bus_unlock(*txnp);
181 	*txnp = NULL;
182 	return (EIO);
183 }
184 
185 static int
pca953x_gpio_regs_put(pca953x_t * pca,i2c_txn_t * txn,uint32_t gpio_id,uint8_t out,uint8_t nout,uint8_t pol,uint8_t npol,uint8_t cfg,uint8_t ncfg)186 pca953x_gpio_regs_put(pca953x_t *pca, i2c_txn_t *txn, uint32_t gpio_id,
187     uint8_t out, uint8_t nout, uint8_t pol, uint8_t npol, uint8_t cfg,
188     uint8_t ncfg)
189 {
190 	uint8_t reg;
191 	i2c_error_t err;
192 
193 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_OUTPUT, &reg, NULL);
194 	if (out != nout && i2c_reg_put(txn, pca->pca_regs, reg, &nout,
195 	    sizeof (uint8_t), &err)) {
196 		dev_err(pca->pca_dip, CE_WARN, "!failed to write output "
197 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
198 		    err.i2c_ctrl);
199 		return (EIO);
200 	}
201 
202 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_POLARITY, &reg, NULL);
203 	if (pol != npol && i2c_reg_put(txn, pca->pca_regs, reg, &npol,
204 	    sizeof (uint8_t), &err)) {
205 		dev_err(pca->pca_dip, CE_WARN, "!failed to write polarity "
206 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
207 		    err.i2c_ctrl);
208 		return (EIO);
209 	}
210 
211 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_CONFIG, &reg, NULL);
212 	if (cfg != ncfg && i2c_reg_put(txn, pca->pca_regs, reg, &ncfg,
213 	    sizeof (uint8_t), &err)) {
214 		dev_err(pca->pca_dip, CE_WARN, "!failed to write config "
215 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
216 		    err.i2c_ctrl);
217 		return (EIO);
218 	}
219 
220 	return (0);
221 }
222 
223 /*
224  * The PCA953x family describes GPIO names as IO<BANK>_<BIT>, e.g. IO0_3, IO4_7,
225  * etc. We basically try to parse out the bank and bit. <BIT> usually goes from
226  * [7:0] but some devices with less GPIOs won't fit there.
227  */
228 static int
pca953x_op_name2id(void * arg,const char * name,uint32_t * idp)229 pca953x_op_name2id(void *arg, const char *name, uint32_t *idp)
230 {
231 	char *eptr;
232 	u_longlong_t bank, bit;
233 	const pca953x_t *pca = arg;
234 	uint32_t gpio;
235 
236 	if (name[0] != 'I' || name[1] != 'O' || name[2] == '\0') {
237 		return (ENOENT);
238 	}
239 
240 	if (ddi_strtoull(name + 2, &eptr, 10, &bank) != 0 ||
241 	    *eptr != '_') {
242 		return (ENOENT);
243 	}
244 
245 	if (ddi_strtoull(eptr + 1, &eptr, 10, &bit) != 0 || *eptr != '\0') {
246 		return (ENOENT);
247 	}
248 
249 	if (bank > pca->pca_ident->pi_ngpios / NBBY ||
250 	    bit >= NBBY) {
251 		return (ENOENT);
252 	}
253 
254 	gpio = bank * NBBY + bit;
255 	if (gpio > pca->pca_ident->pi_ngpios) {
256 		return (ENOENT);
257 	}
258 
259 	*idp = gpio;
260 	return (0);
261 }
262 
263 static void
pca953x_gpio_attr_get_name(uint32_t gpio,nvlist_t * nvl,nvlist_t * meta,uint8_t in,uint8_t out,uint8_t pol,uint8_t cfg)264 pca953x_gpio_attr_get_name(uint32_t gpio, nvlist_t *nvl, nvlist_t *meta,
265     uint8_t in, uint8_t out, uint8_t pol, uint8_t cfg)
266 {
267 	char buf[32];
268 	uint8_t bit = gpio % NBBY;
269 	uint8_t bank = gpio / NBBY;
270 
271 	(void) snprintf(buf, sizeof (buf), "IO%u_%u", bank, bit);
272 	kgpio_nvl_attr_fill_str(nvl, meta, KGPIO_ATTR_NAME, buf, 0, NULL,
273 	    KGPIO_PROT_RO);
274 }
275 
276 static void
pca953x_gpio_attr_get_input(uint32_t gpio,nvlist_t * nvl,nvlist_t * meta,uint8_t in,uint8_t out,uint8_t pol,uint8_t cfg)277 pca953x_gpio_attr_get_input(uint32_t gpio, nvlist_t *nvl, nvlist_t *meta,
278     uint8_t in, uint8_t out, uint8_t pol, uint8_t cfg)
279 {
280 	uint8_t bit = gpio % NBBY;
281 	pca953x_gpio_input_t input;
282 	uint32_t input_pos[2] = { PCA953X_GPIO_INPUT_LOW,
283 	    PCA953X_GPIO_INPUT_HIGH };
284 
285 	if (PCA953X_R_INPUT_GET_IN(in, bit) == 0) {
286 		input = PCA953X_GPIO_INPUT_LOW;
287 	} else {
288 		input = PCA953X_GPIO_INPUT_HIGH;
289 	}
290 
291 	kgpio_nvl_attr_fill_u32(nvl, meta, PCA953X_GPIO_ATTR_INPUT, input,
292 	    ARRAY_SIZE(input_pos), input_pos, KGPIO_PROT_RO);
293 }
294 
295 static void
pca953x_gpio_attr_get_output(uint32_t gpio,nvlist_t * nvl,nvlist_t * meta,uint8_t in,uint8_t out,uint8_t pol,uint8_t cfg)296 pca953x_gpio_attr_get_output(uint32_t gpio, nvlist_t *nvl, nvlist_t *meta,
297     uint8_t in, uint8_t out, uint8_t pol, uint8_t cfg)
298 {
299 	uint8_t bit = gpio % NBBY;
300 	pca953x_gpio_output_t output;
301 	uint32_t output_pos[3] = { PCA953X_GPIO_OUTPUT_DISABLED,
302 	    PCA953X_GPIO_OUTPUT_LOW, PCA953X_GPIO_OUTPUT_HIGH };
303 
304 	if (PCA953X_R_CONFIG_GET_CFG(cfg, bit) == PCA953X_R_CONFIG_INPUT) {
305 		output = PCA953X_GPIO_OUTPUT_DISABLED;
306 	} else if (PCA953X_R_INPUT_GET_OUT(out, bit) == 0) {
307 		output = PCA953X_GPIO_OUTPUT_LOW;
308 	} else {
309 		output = PCA953X_GPIO_OUTPUT_HIGH;
310 	}
311 
312 	kgpio_nvl_attr_fill_u32(nvl, meta, PCA953X_GPIO_ATTR_OUTPUT, output,
313 	    ARRAY_SIZE(output_pos), output_pos, KGPIO_PROT_RW);
314 }
315 
316 static void
pca953x_gpio_attr_get_polarity(uint32_t gpio,nvlist_t * nvl,nvlist_t * meta,uint8_t in,uint8_t out,uint8_t pol,uint8_t cfg)317 pca953x_gpio_attr_get_polarity(uint32_t gpio, nvlist_t *nvl, nvlist_t *meta,
318     uint8_t in, uint8_t out, uint8_t pol, uint8_t cfg)
319 {
320 	uint8_t bit = gpio % NBBY;
321 	pca953x_gpio_polarity_t polarity;
322 	uint32_t polarity_pos[2] = { PCA953X_GPIO_POLARITY_NORMAL,
323 	    PCA953X_GPIO_POLARITY_INVERTED };
324 
325 	if (PCA953X_R_POLARITY_GET_POL(pol, bit) == PCA953X_R_POLARITY_DEF) {
326 		polarity = PCA953X_GPIO_POLARITY_NORMAL;
327 	} else {
328 		polarity = PCA953X_GPIO_POLARITY_INVERTED;
329 	}
330 
331 	kgpio_nvl_attr_fill_u32(nvl, meta, PCA953X_GPIO_ATTR_POLARITY, polarity,
332 	    ARRAY_SIZE(polarity_pos), polarity_pos, KGPIO_PROT_RW);
333 }
334 
335 static bool
pca953x_gpio_attr_set_ro(uint8_t bit,nvpair_t * pair,nvlist_t * errs,uint8_t * outp,uint8_t * polp,uint8_t * cfgp)336 pca953x_gpio_attr_set_ro(uint8_t bit, nvpair_t *pair, nvlist_t *errs,
337     uint8_t *outp, uint8_t *polp, uint8_t *cfgp)
338 {
339 	const char *name = nvpair_name(pair);
340 	fnvlist_add_uint32(errs, name, (uint32_t)KGPIO_ATTR_ERR_ATTR_RO);
341 	return (false);
342 }
343 
344 static bool
pca953x_gpio_attr_set_output(uint8_t bit,nvpair_t * pair,nvlist_t * errs,uint8_t * outp,uint8_t * polp,uint8_t * cfgp)345 pca953x_gpio_attr_set_output(uint8_t bit, nvpair_t *pair, nvlist_t *errs,
346     uint8_t *outp, uint8_t *polp, uint8_t *cfgp)
347 {
348 	uint32_t val;
349 
350 	if (nvpair_value_uint32(pair, &val) != 0) {
351 		fnvlist_add_uint32(errs, nvpair_name(pair),
352 		    (uint32_t)KGPIO_ATTR_ERR_BAD_TYPE);
353 		return (false);
354 	}
355 
356 	switch (val) {
357 	case PCA953X_GPIO_OUTPUT_DISABLED:
358 		*cfgp = PCA953X_R_CONFIG_SET_CFG(*cfgp, bit,
359 		    PCA953X_R_CONFIG_INPUT);
360 		break;
361 	case PCA953X_GPIO_OUTPUT_LOW:
362 		*cfgp = PCA953X_R_CONFIG_SET_CFG(*cfgp, bit,
363 		    PCA953X_R_CONFIG_OUTPUT);
364 		*outp = PCA953X_R_INPUT_SET_OUT(*outp, bit, 0);
365 		break;
366 	case PCA953X_GPIO_OUTPUT_HIGH:
367 		*cfgp = PCA953X_R_CONFIG_SET_CFG(*cfgp, bit,
368 		    PCA953X_R_CONFIG_OUTPUT);
369 		*outp = PCA953X_R_INPUT_SET_OUT(*outp, bit, 1);
370 		break;
371 	default:
372 		fnvlist_add_uint32(errs, nvpair_name(pair),
373 		    (uint32_t)KGPIO_ATTR_ERR_UNKNOWN_VAL);
374 		return (false);
375 	}
376 
377 	return (true);
378 }
379 
380 static bool
pca953x_gpio_attr_set_polarity(uint8_t bit,nvpair_t * pair,nvlist_t * errs,uint8_t * outp,uint8_t * polp,uint8_t * cfgp)381 pca953x_gpio_attr_set_polarity(uint8_t bit, nvpair_t *pair, nvlist_t *errs,
382     uint8_t *outp, uint8_t *polp, uint8_t *cfgp)
383 {
384 	uint32_t val;
385 
386 	if (nvpair_value_uint32(pair, &val) != 0) {
387 		fnvlist_add_uint32(errs, nvpair_name(pair),
388 		    (uint32_t)KGPIO_ATTR_ERR_BAD_TYPE);
389 		return (false);
390 	}
391 
392 	switch (val) {
393 	case PCA953X_GPIO_POLARITY_NORMAL:
394 		*polp = PCA953X_R_POLARITY_SET_POL(*polp, bit,
395 		    PCA953X_R_POLARITY_DEF);
396 		break;
397 	case PCA953X_GPIO_POLARITY_INVERTED:
398 		*polp = PCA953X_R_POLARITY_SET_POL(*polp, bit,
399 		    PCA953X_R_POLARITY_INVERT);
400 		break;
401 	default:
402 		fnvlist_add_uint32(errs, nvpair_name(pair),
403 		    (uint32_t)KGPIO_ATTR_ERR_UNKNOWN_VAL);
404 		return (false);
405 	}
406 
407 	return (true);
408 }
409 
410 typedef void (*pca953x_gpio_attr_get_f)(uint32_t, nvlist_t *, nvlist_t *,
411     uint8_t, uint8_t, uint8_t, uint8_t);
412 typedef bool (*pca953x_gpio_attr_set_f)(uint8_t, nvpair_t *, nvlist_t *,
413     uint8_t *, uint8_t *, uint8_t *);
414 
415 typedef struct {
416 	const char *pgat_attr;
417 	pca953x_gpio_attr_get_f pgat_get;
418 	pca953x_gpio_attr_set_f pgat_set;
419 } pca953x_gpio_attr_table_t;
420 
421 static const pca953x_gpio_attr_table_t pca953x_gpio_attrs[] = {
422 	{ KGPIO_ATTR_NAME, pca953x_gpio_attr_get_name,
423 	    pca953x_gpio_attr_set_ro },
424 	{ PCA953X_GPIO_ATTR_INPUT, pca953x_gpio_attr_get_input,
425 	    pca953x_gpio_attr_set_ro },
426 	{ PCA953X_GPIO_ATTR_OUTPUT, pca953x_gpio_attr_get_output,
427 	    pca953x_gpio_attr_set_output },
428 	{ PCA953X_GPIO_ATTR_POLARITY, pca953x_gpio_attr_get_polarity,
429 	    pca953x_gpio_attr_set_polarity},
430 };
431 
432 static int
pca953x_op_attr_get(void * arg,uint32_t gpio_id,nvlist_t * nvl)433 pca953x_op_attr_get(void *arg, uint32_t gpio_id, nvlist_t *nvl)
434 {
435 	int ret;
436 	i2c_txn_t *txn;
437 	uint8_t in, out, pol, cfg;
438 	pca953x_t *pca = arg;
439 
440 	if ((ret = pca953x_gpio_regs_get(pca, gpio_id, &txn, &in, &out, &pol,
441 	    &cfg)) != 0) {
442 		return (ret);
443 	}
444 
445 	nvlist_t *meta = fnvlist_alloc();
446 	for (size_t i = 0; i < ARRAY_SIZE(pca953x_gpio_attrs); i++) {
447 		pca953x_gpio_attrs[i].pgat_get(gpio_id, nvl, meta, in, out,
448 		    pol, cfg);
449 	}
450 
451 	fnvlist_add_nvlist(nvl, KGPIO_ATTR_META, meta);
452 	fnvlist_free(meta);
453 
454 	i2c_bus_unlock(txn);
455 	return (0);
456 }
457 
458 static int
pca953x_op_attr_set(void * arg,uint32_t gpio_id,nvlist_t * nvl,nvlist_t * errs)459 pca953x_op_attr_set(void *arg, uint32_t gpio_id, nvlist_t *nvl, nvlist_t *errs)
460 {
461 	int ret;
462 	i2c_txn_t *txn;
463 	uint8_t out, pol, cfg, nout, npol, ncfg;
464 	pca953x_t *pca = arg;
465 	uint8_t bit = gpio_id % NBBY;
466 	bool valid = true;
467 
468 	if ((ret = pca953x_gpio_regs_get(pca, gpio_id, &txn, NULL, &out, &pol,
469 	    &cfg)) != 0) {
470 		return (ret);
471 	}
472 
473 	nvlist_t *meta = fnvlist_alloc();
474 	for (nvpair_t *nvpair = nvlist_next_nvpair(nvl, NULL); nvpair != NULL;
475 	    nvpair = nvlist_next_nvpair(nvl, nvpair)) {
476 		for (size_t i = 0; i < ARRAY_SIZE(pca953x_gpio_attrs); i++) {
477 			const char *name = nvpair_name(nvpair);
478 
479 			if (strcmp(pca953x_gpio_attrs[i].pgat_attr, name) == 0)
480 				continue;
481 
482 			if (!pca953x_gpio_attrs[i].pgat_set(bit, nvpair, errs,
483 			    &nout, &npol, &ncfg)) {
484 				valid = false;
485 			}
486 		}
487 	}
488 
489 	if (valid) {
490 		ret = pca953x_gpio_regs_put(pca, txn, gpio_id, out, nout, pol,
491 		    npol, cfg, ncfg);
492 	} else {
493 		ret = EINVAL;
494 	}
495 
496 	fnvlist_add_nvlist(nvl, KGPIO_ATTR_META, meta);
497 	fnvlist_free(meta);
498 
499 	i2c_bus_unlock(txn);
500 	return (0);
501 }
502 
503 /*
504  * When the broader DPIO framework supports polling more fully, then we can add
505  * DPIO_C_POLL here on models that support interrupt notification, if we know
506  * how it's wired up (likely itself a GPIO).
507  */
508 static int
pca953x_op_cap(void * arg,uint32_t gpio_id,dpio_caps_t * caps)509 pca953x_op_cap(void *arg, uint32_t gpio_id, dpio_caps_t *caps)
510 {
511 	return (DPIO_C_READ | DPIO_C_WRITE);
512 }
513 
514 static int
pca953x_op_dpio_input(void * arg,uint32_t gpio_id,dpio_input_t * input)515 pca953x_op_dpio_input(void *arg, uint32_t gpio_id, dpio_input_t *input)
516 {
517 	i2c_error_t err;
518 	uint8_t reg, bit, val;
519 	pca953x_t *pca = arg;
520 
521 	pca953x_gpio_to_reg_bit(pca, gpio_id, PCA953X_R_INPUT, &reg, &bit);
522 	if (!i2c_reg_get(NULL, pca->pca_regs, reg, &val, sizeof (val), &err)) {
523 		dev_err(pca->pca_dip, CE_WARN, "!failed to read GPIO "
524 		    "register 0x%x: 0x%x/0x%x", reg, err.i2c_error,
525 		    err.i2c_ctrl);
526 		return (EIO);
527 	}
528 
529 	if (PCA953X_R_INPUT_GET_IN(val, bit) == 0) {
530 		*input = DPIO_INPUT_LOW;
531 	} else {
532 		*input = DPIO_INPUT_HIGH;
533 	}
534 
535 	return (0);
536 }
537 
538 static int
pca953x_op_dpio_output_state(void * arg,uint32_t gpio_id,dpio_output_t * outputp)539 pca953x_op_dpio_output_state(void *arg, uint32_t gpio_id,
540     dpio_output_t *outputp)
541 {
542 	int ret;
543 	i2c_txn_t *txn;
544 	uint8_t output, config;
545 	uint8_t bit = gpio_id % NBBY;
546 	pca953x_t *pca = arg;
547 
548 	if ((ret = pca953x_gpio_regs_get(pca, gpio_id, &txn, NULL, &output,
549 	    NULL, &config)) != 0) {
550 		return (ret);
551 	}
552 
553 	if (PCA953X_R_CONFIG_GET_CFG(config, bit) == PCA953X_R_CONFIG_INPUT) {
554 		*outputp = DPIO_OUTPUT_DISABLE;
555 	} else if (PCA953X_R_INPUT_GET_OUT(output, bit) == 0) {
556 		*outputp = DPIO_OUTPUT_LOW;
557 	} else {
558 		*outputp = DPIO_OUTPUT_HIGH;
559 	}
560 
561 	i2c_bus_unlock(txn);
562 	return (0);
563 }
564 
565 static int
pca953x_op_dpio_output(void * arg,uint32_t gpio_id,dpio_output_t val)566 pca953x_op_dpio_output(void *arg, uint32_t gpio_id, dpio_output_t val)
567 {
568 	int ret;
569 	i2c_txn_t *txn;
570 	uint8_t out, cfg, nout, ncfg;
571 	uint8_t bit = gpio_id % NBBY;
572 	pca953x_t *pca = arg;
573 
574 	if ((ret = pca953x_gpio_regs_get(pca, gpio_id, &txn, NULL, &out, NULL,
575 	    &cfg)) != 0) {
576 		return (ret);
577 	}
578 
579 	switch (val) {
580 	case DPIO_OUTPUT_LOW:
581 		ncfg = PCA953X_R_CONFIG_SET_CFG(cfg, bit,
582 		    PCA953X_R_CONFIG_OUTPUT);
583 		nout = PCA953X_R_INPUT_SET_OUT(out, bit, 0);
584 		break;
585 	case DPIO_OUTPUT_HIGH:
586 		ncfg = PCA953X_R_CONFIG_SET_CFG(cfg, bit,
587 		    PCA953X_R_CONFIG_OUTPUT);
588 		nout = PCA953X_R_INPUT_SET_OUT(out, bit, 1);
589 		break;
590 	case DPIO_OUTPUT_DISABLE:
591 		ncfg = PCA953X_R_CONFIG_SET_CFG(cfg, bit,
592 		    PCA953X_R_CONFIG_INPUT);
593 		nout = out;
594 		break;
595 	default:
596 		ret = EINVAL;
597 		goto out;
598 	}
599 
600 	ret = pca953x_gpio_regs_put(pca, txn, gpio_id, out, nout,
601 	    0, 0, cfg, ncfg);
602 out:
603 	i2c_bus_unlock(txn);
604 	return (ret);
605 }
606 
607 static const kgpio_ops_t pca953x_gpio_ops = {
608 	.kgo_name2id = pca953x_op_name2id,
609 	.kgo_get = pca953x_op_attr_get,
610 	.kgo_set = pca953x_op_attr_set,
611 	.kgo_cap = pca953x_op_cap,
612 	.kgo_input = pca953x_op_dpio_input,
613 	.kgo_output_state = pca953x_op_dpio_output_state,
614 	.kgo_output = pca953x_op_dpio_output
615 };
616 
617 static bool
pca953x_identify(pca953x_t * pca)618 pca953x_identify(pca953x_t *pca)
619 {
620 	const char *bind = ddi_binding_name(pca->pca_dip);
621 	const char *name = ddi_node_name(pca->pca_dip);
622 
623 	for (size_t i = 0; i < ARRAY_SIZE(pca953x_idents); i++) {
624 		if (strcmp(bind, pca953x_idents[i].pi_name) == 0 ||
625 		    strcmp(bind, pca953x_idents[i].pi_compat) == 0 ||
626 		    strcmp(name, pca953x_idents[i].pi_name) == 0 ||
627 		    strcmp(name, pca953x_idents[i].pi_compat) == 0) {
628 			pca->pca_ident = &pca953x_idents[i];
629 			return (true);
630 		}
631 	}
632 
633 
634 	dev_err(pca->pca_dip, CE_WARN, "failed to match against node name %s "
635 	    "and binding name %s", name, bind);
636 	return (false);
637 }
638 
639 static bool
pca953x_i2c_init(pca953x_t * pca)640 pca953x_i2c_init(pca953x_t *pca)
641 {
642 	i2c_errno_t err;
643 	i2c_reg_acc_attr_t attr;
644 
645 	if ((err = i2c_client_init(pca->pca_dip, 0, &pca->pca_client)) !=
646 	    I2C_CORE_E_OK) {
647 		dev_err(pca->pca_dip, CE_WARN, "failed to create i2c client: "
648 		    "0x%x", err);
649 		return (false);
650 	}
651 
652 	bzero(&attr, sizeof (attr));
653 	attr.i2cacc_version = I2C_REG_ACC_ATTR_V0;
654 	attr.i2cacc_addr_len = 1;
655 	attr.i2cacc_reg_len = 1;
656 	attr.i2cacc_addr_max = pca->pca_ident->pi_nregs;
657 
658 	if ((err = i2c_reg_handle_init(pca->pca_client, &attr,
659 	    &pca->pca_regs)) != I2C_CORE_E_OK) {
660 		dev_err(pca->pca_dip, CE_WARN, "failed to create register "
661 		    "handle: %s (0x%x)", i2c_client_errtostr(pca->pca_client,
662 		    err), err);
663 		return (false);
664 	}
665 
666 	return (true);
667 }
668 
669 static void
pca953x_cleanup(pca953x_t * pca)670 pca953x_cleanup(pca953x_t *pca)
671 {
672 	i2c_reg_handle_destroy(pca->pca_regs);
673 	i2c_client_destroy(pca->pca_client);
674 	ddi_set_driver_private(pca->pca_dip, NULL);
675 	pca->pca_dip = NULL;
676 	kmem_free(pca, sizeof (pca953x_t));
677 }
678 
679 int
pca953x_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)680 pca953x_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
681 {
682 	int ret;
683 	pca953x_t *pca;
684 
685 	switch (cmd) {
686 	case DDI_ATTACH:
687 		break;
688 	case DDI_RESUME:
689 		return (DDI_SUCCESS);
690 	default:
691 		return (DDI_FAILURE);
692 	}
693 
694 	pca = kmem_zalloc(sizeof (pca953x_t), KM_SLEEP);
695 	pca->pca_dip = dip;
696 	ddi_set_driver_private(dip, pca);
697 
698 	if (!pca953x_identify(pca))
699 		goto cleanup;
700 
701 	if (!pca953x_i2c_init(pca))
702 		goto cleanup;
703 
704 	if ((ret = kgpio_register(pca->pca_dip, &pca953x_gpio_ops, pca,
705 	    pca->pca_ident->pi_ngpios)) != 0) {
706 		dev_err(pca->pca_dip, CE_WARN, "failed to register with gpio "
707 		    "framework: 0x%x", ret);
708 		goto cleanup;
709 	}
710 
711 	return (DDI_SUCCESS);
712 
713 cleanup:
714 	pca953x_cleanup(pca);
715 	return (DDI_FAILURE);
716 }
717 
718 int
pca953x_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)719 pca953x_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
720 {
721 	int ret;
722 	pca953x_t *pca;
723 
724 	switch (cmd) {
725 	case DDI_DETACH:
726 		break;
727 	case DDI_SUSPEND:
728 		return (DDI_SUCCESS);
729 	default:
730 		return (DDI_FAILURE);
731 	}
732 
733 	pca = ddi_get_driver_private(dip);
734 	if (pca == NULL) {
735 		dev_err(dip, CE_WARN, "asked to detach, but missing private "
736 		    "data");
737 		return (DDI_FAILURE);
738 	}
739 	VERIFY3P(pca->pca_dip, ==, dip);
740 
741 	if ((ret = kgpio_unregister(pca->pca_dip)) != 0) {
742 		dev_err(pca->pca_dip, CE_WARN, "failed to unregister from "
743 		    "gpio framework: 0x%x", ret);
744 		return (DDI_FAILURE);
745 	}
746 
747 	pca953x_cleanup(pca);
748 	return (DDI_SUCCESS);
749 }
750 
751 static struct dev_ops pca953x_dev_ops = {
752 	.devo_rev = DEVO_REV,
753 	.devo_refcnt = 0,
754 	.devo_identify = nulldev,
755 	.devo_probe = nulldev,
756 	.devo_attach = pca953x_attach,
757 	.devo_detach = pca953x_detach,
758 	.devo_reset = nodev,
759 	.devo_quiesce = ddi_quiesce_not_needed
760 };
761 
762 static struct modldrv pca953x_modldrv = {
763 	.drv_modops = &mod_driverops,
764 	.drv_linkinfo = "PCA953x GPIO driver",
765 	.drv_dev_ops = &pca953x_dev_ops
766 };
767 
768 static struct modlinkage pca953x_modlinkage = {
769 	.ml_rev = MODREV_1,
770 	.ml_linkage = { &pca953x_modldrv, NULL }
771 };
772 
773 
774 int
_init(void)775 _init(void)
776 {
777 	return (mod_install(&pca953x_modlinkage));
778 }
779 
780 int
_info(struct modinfo * modinfop)781 _info(struct modinfo *modinfop)
782 {
783 	return (mod_info(&pca953x_modlinkage, modinfop));
784 }
785 
786 int
_fini(void)787 _fini(void)
788 {
789 	return (mod_remove(&pca953x_modlinkage));
790 }
791