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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, 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, ®, &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