umcpmio_subr.c revision 1.1 1 /* $NetBSD: umcpmio_subr.c,v 1.1 2024/12/16 16:37:38 brad Exp $ */
2
3 /*
4 * Copyright (c) 2024 Brad Spencer <brad (at) anduin.eldar.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/cdefs.h>
20 __KERNEL_RCSID(0, "$NetBSD: umcpmio_subr.c,v 1.1 2024/12/16 16:37:38 brad Exp $");
21
22 #ifdef _KERNEL_OPT
23 #include "opt_usb.h"
24 #endif
25
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/conf.h>
29 #include <sys/kernel.h>
30 #include <sys/kmem.h>
31 #include <sys/device.h>
32 #include <sys/sysctl.h>
33 #include <sys/tty.h>
34 #include <sys/file.h>
35 #include <sys/vnode.h>
36 #include <sys/kauth.h>
37 #include <sys/lwp.h>
38
39 #include <dev/usb/usb.h>
40 #include <dev/usb/usbhid.h>
41
42 #include <dev/usb/usbdi.h>
43 #include <dev/usb/usbdi_util.h>
44 #include <dev/usb/usbdevs.h>
45 #include <dev/usb/uhidev.h>
46 #include <dev/hid/hid.h>
47
48 #include <dev/usb/umcpmio.h>
49 #include <dev/usb/umcpmio_subr.h>
50 #include <dev/usb/umcpmio_hid_reports.h>
51
52 int umcpmio_send_report(struct umcpmio_softc *, uint8_t *, size_t, uint8_t *, int);
53
54 #define UMCPMIO_DEBUG 1
55 #ifdef UMCPMIO_DEBUG
56 #define DPRINTF(x) if (umcpmiodebug) printf x
57 #define DPRINTFN(n, x) if (umcpmiodebug > (n)) printf x
58 extern int umcpmiodebug;
59 #else
60 #define DPRINTF(x) __nothing
61 #define DPRINTFN(n,x) __nothing
62 #endif
63
64 /* Handy functions that do a bunch of things for the main driver code */
65
66 int
67 umcpmio_get_status(struct umcpmio_softc *sc,
68 struct mcp2221_status_res *res, bool takemutex)
69 {
70 struct mcp2221_status_req req;
71 int err = 0;
72
73 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
74 req.cmd = MCP2221_CMD_STATUS;
75
76 if (takemutex)
77 mutex_enter(&sc->sc_action_mutex);
78 err = umcpmio_send_report(sc, (uint8_t *)&req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
79 if (takemutex)
80 mutex_exit(&sc->sc_action_mutex);
81
82 return(err);
83 }
84
85 void
86 umcpmio_set_i2c_speed(struct mcp2221_status_req *req,
87 int flags)
88 {
89 int i2cbaud = MCP2221_DEFAULT_I2C_SPEED;
90
91 if (flags & I2C_F_SPEED)
92 i2cbaud = 400000;
93
94 req->set_i2c_speed = MCP2221_I2C_SET_SPEED;
95 if (i2cbaud <= 0)
96 i2cbaud = MCP2221_DEFAULT_I2C_SPEED;
97
98 /* Everyone and their brother seems to store the I2C divider like this,
99 * so do likewise */
100
101 req->i2c_clock_divider = (MCP2221_INTERNAL_CLOCK / i2cbaud) - 3;
102 }
103
104 int
105 umcpmio_put_status(struct umcpmio_softc *sc,
106 struct mcp2221_status_req *req, struct mcp2221_status_res *res,
107 bool takemutex)
108 {
109 int err = 0;
110
111 req->cmd = MCP2221_CMD_STATUS;
112
113 if (takemutex)
114 mutex_enter(&sc->sc_action_mutex);
115 err = umcpmio_send_report(sc, (uint8_t *)req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
116 if (takemutex)
117 mutex_exit(&sc->sc_action_mutex);
118
119 return(err);
120 }
121
122 int
123 umcpmio_set_i2c_speed_one(struct umcpmio_softc *sc,
124 int flags, bool takemutex)
125 {
126 int err = 0;
127 struct mcp2221_status_req req;
128 struct mcp2221_status_res res;
129
130 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
131 umcpmio_set_i2c_speed(&req, flags);
132 err = umcpmio_put_status(sc, &req, &res, takemutex);
133 if (! err) {
134 if (res.set_i2c_speed == MCP2221_I2C_SPEED_BUSY)
135 err = EBUSY;
136 }
137
138 return(err);
139 }
140
141 int
142 umcpmio_get_sram(struct umcpmio_softc *sc,
143 struct mcp2221_get_sram_res *res, bool takemutex)
144 {
145 struct mcp2221_get_sram_req req;
146 int err = 0;
147
148 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
149 req.cmd = MCP2221_CMD_GET_SRAM;
150
151 if (takemutex)
152 mutex_enter(&sc->sc_action_mutex);
153 err = umcpmio_send_report(sc, (uint8_t *)&req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
154 if (takemutex)
155 mutex_exit(&sc->sc_action_mutex);
156
157 return(err);
158 }
159
160 int
161 umcpmio_put_sram(struct umcpmio_softc *sc,
162 struct mcp2221_set_sram_req *req, struct mcp2221_set_sram_res *res,
163 bool takemutex)
164 {
165 int err = 0;
166
167 req->cmd = MCP2221_CMD_SET_SRAM;
168
169 if (takemutex)
170 mutex_enter(&sc->sc_action_mutex);
171 err = umcpmio_send_report(sc, (uint8_t *)req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
172 if (takemutex)
173 mutex_exit(&sc->sc_action_mutex);
174
175 return(err);
176 }
177
178 /* We call the dedicated function ALT3 everywhere */
179
180 uint32_t
181 umcpmio_sram_gpio_to_flags(uint8_t gp_setting)
182 {
183 uint32_t r = 0;
184
185 switch (gp_setting & MCP2221_SRAM_PIN_TYPE_MASK) {
186 case MCP2221_SRAM_PIN_IS_DED:
187 r |= GPIO_PIN_ALT3;
188 break;
189 case MCP2221_SRAM_PIN_IS_ALT0:
190 r |= GPIO_PIN_ALT0;
191 break;
192 case MCP2221_SRAM_PIN_IS_ALT1:
193 r |= GPIO_PIN_ALT1;
194 break;
195 case MCP2221_SRAM_PIN_IS_ALT2:
196 r |= GPIO_PIN_ALT2;
197 break;
198 case MCP2221_SRAM_PIN_IS_GPIO:
199 default:
200 if ((gp_setting & MCP2221_SRAM_GPIO_TYPE_MASK) == MCP2221_SRAM_GPIO_INPUT)
201 r |= GPIO_PIN_INPUT;
202 else
203 r |= GPIO_PIN_OUTPUT;
204 break;
205 }
206
207 return(r);
208 }
209
210 void
211 umcpmio_set_gpio_value_sram(struct mcp2221_set_sram_req *req, int pin, bool value)
212 {
213 uint8_t *alter = NULL;
214 uint8_t *newvalue = NULL;
215
216 if (pin >=0 && pin < MCP2221_NPINS) {
217 switch (pin) {
218 case 0:
219 alter = &req->alter_gpio_config;
220 newvalue = &req->gp0_settings;
221 break;
222 case 1:
223 alter = &req->alter_gpio_config;
224 newvalue = &req->gp1_settings;
225 break;
226 case 2:
227 alter = &req->alter_gpio_config;
228 newvalue = &req->gp2_settings;
229 break;
230 case 3:
231 alter = &req->alter_gpio_config;
232 newvalue = &req->gp3_settings;
233 break;
234 default:
235 break;
236 }
237
238 if (alter != NULL) {
239 *alter = MCP2221_SRAM_ALTER_GPIO;
240 if (value)
241 *newvalue |= MCP2221_SRAM_GPIO_HIGH;
242 else
243 *newvalue &= ~MCP2221_SRAM_GPIO_HIGH;
244 }
245 }
246 }
247
248 void
249 umcpmio_set_gpio_dir_sram(struct mcp2221_set_sram_req *req, int pin, int flags)
250 {
251 uint8_t *alter = NULL;
252 uint8_t *newvalue = NULL;
253
254 if (pin >=0 && pin < MCP2221_NPINS) {
255 switch (pin) {
256 case 0:
257 alter = &req->alter_gpio_config;
258 newvalue = &req->gp0_settings;
259 break;
260 case 1:
261 alter = &req->alter_gpio_config;
262 newvalue = &req->gp1_settings;
263 break;
264 case 2:
265 alter = &req->alter_gpio_config;
266 newvalue = &req->gp2_settings;
267 break;
268 case 3:
269 alter = &req->alter_gpio_config;
270 newvalue = &req->gp3_settings;
271 break;
272 default:
273 break;
274 }
275
276 if (alter != NULL) {
277 *alter = MCP2221_SRAM_ALTER_GPIO;
278 if (flags & GPIO_PIN_INPUT)
279 *newvalue |= MCP2221_SRAM_GPIO_INPUT;
280 else
281 *newvalue &= ~MCP2221_SRAM_GPIO_INPUT;
282 }
283 }
284 }
285
286 void
287 umcpmio_set_gpio_designation_sram(struct mcp2221_set_sram_req *req, int pin, int flags)
288 {
289 uint8_t *alter = NULL;
290 uint8_t *newvalue = NULL;
291 uint32_t altmask = GPIO_PIN_ALT0 | GPIO_PIN_ALT1 | GPIO_PIN_ALT2 | GPIO_PIN_ALT3;
292
293 if (pin >=0 && pin < MCP2221_NPINS) {
294 switch (pin) {
295 case 0:
296 alter = &req->alter_gpio_config;
297 newvalue = &req->gp0_settings;
298 break;
299 case 1:
300 alter = &req->alter_gpio_config;
301 newvalue = &req->gp1_settings;
302 break;
303 case 2:
304 alter = &req->alter_gpio_config;
305 newvalue = &req->gp2_settings;
306 break;
307 case 3:
308 alter = &req->alter_gpio_config;
309 newvalue = &req->gp3_settings;
310 break;
311 default:
312 break;
313 }
314
315 if (alter != NULL) {
316 int nv = *newvalue;
317
318 *alter = MCP2221_SRAM_ALTER_GPIO;
319 nv &= 0xF8;
320
321 if (flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) {
322 nv |= MCP2221_SRAM_PIN_IS_GPIO;
323 } else {
324 switch (flags & altmask) {
325 case GPIO_PIN_ALT0:
326 nv |= MCP2221_SRAM_PIN_IS_ALT0;
327 break;
328 case GPIO_PIN_ALT1:
329 nv |= MCP2221_SRAM_PIN_IS_ALT1;
330 break;
331 case GPIO_PIN_ALT2:
332 nv |= MCP2221_SRAM_PIN_IS_ALT2;
333 break;
334 /* ALT3 will always be used as the dedicated function specific to the pin.
335 * Not all of the pins will have the alt functions below #3.
336 */
337 case GPIO_PIN_ALT3:
338 nv |= MCP2221_SRAM_PIN_IS_DED;
339 break;
340 default:
341 break;
342 }
343 }
344 *newvalue = nv;
345 }
346 }
347 }
348
349 void
350 umcpmio_set_gpio_irq_sram(struct mcp2221_set_sram_req *req, int irqmode)
351 {
352 req->alter_gpio_config = MCP2221_SRAM_ALTER_GPIO;
353
354 if (irqmode & (GPIO_INTR_POS_EDGE | GPIO_INTR_DOUBLE_EDGE)) {
355 req->irq_config |= MCP2221_SRAM_ALTER_IRQ | MCP2221_SRAM_ALTER_POS_EDGE | MCP2221_SRAM_ENABLE_POS_EDGE | MCP2221_SRAM_CLEAR_IRQ;
356 }
357 if (irqmode & (GPIO_INTR_NEG_EDGE | GPIO_INTR_DOUBLE_EDGE)) {
358 req->irq_config |= MCP2221_SRAM_ALTER_IRQ | MCP2221_SRAM_ALTER_NEG_EDGE | MCP2221_SRAM_ENABLE_NEG_EDGE | MCP2221_SRAM_CLEAR_IRQ;
359 }
360
361 if (req->irq_config != 0) {
362 req->gp1_settings = MCP2221_SRAM_PIN_IS_ALT2;
363 } else {
364 req->irq_config = MCP2221_SRAM_ALTER_IRQ | MCP2221_SRAM_CLEAR_IRQ;
365 req->gp1_settings = MCP2221_SRAM_PIN_IS_GPIO | MCP2221_SRAM_GPIO_INPUT;
366 }
367 }
368
369 /* It is unfortunate that the GET and PUT requests are not symertric. That is,
370 * the bits sort of line up but not quite between a GET and PUT. */
371
372 static struct umcpmio_mapping_put umcpmio_vref_puts[] = {
373 {
374 .tname = "4.096V",
375 .mask = 0x06 | 0x01,
376 },
377 {
378 .tname = "2.048V",
379 .mask = 0x04 | 0x01,
380 },
381 {
382 .tname = "1.024V",
383 .mask = 0x02 | 0x01,
384 },
385 {
386 .tname = "OFF",
387 .mask = 0x00 | 0x01,
388 },
389 {
390 .tname = "VDD",
391 .mask = 0x00,
392 }
393 };
394
395 void
396 umcpmio_set_dac_vref(struct mcp2221_set_sram_req *req, char *newvref)
397 {
398 int i;
399
400 for (i = 0; i < __arraycount(umcpmio_vref_puts); i++) {
401 if (strncmp(newvref, umcpmio_vref_puts[i].tname,
402 UMCPMIO_VREF_NAME) == 0) {
403 break;
404 }
405 }
406
407 if (i == __arraycount(umcpmio_vref_puts))
408 return;
409
410 req->dac_voltage_reference |= umcpmio_vref_puts[i].mask | MCP2221_SRAM_CHANGE_DAC_VREF;
411 }
412
413 int
414 umcpmio_set_dac_vref_one(struct umcpmio_softc *sc, char *newvref, bool takemutex)
415 {
416 struct mcp2221_set_sram_req req;
417 struct mcp2221_set_sram_res res;
418 int err = 0;
419
420 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
421 umcpmio_set_dac_vref(&req, newvref);
422 err = umcpmio_put_sram(sc, &req, &res, takemutex);
423
424 return err;
425 }
426
427 void
428 umcpmio_set_dac_value(struct mcp2221_set_sram_req *req, uint8_t newvalue)
429 {
430 req->set_dac_output_value |= (newvalue & MCP2221_SRAM_DAC_VALUE_MASK) | MCP2221_SRAM_CHANGE_DAC_VREF;
431 }
432
433 int
434 umcpmio_set_dac_value_one(struct umcpmio_softc *sc, uint8_t newvalue, bool takemutex)
435 {
436 struct mcp2221_set_sram_req req;
437 struct mcp2221_set_sram_res res;
438 int err = 0;
439
440 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
441 umcpmio_set_dac_value(&req, newvalue);
442 err = umcpmio_put_sram(sc, &req, &res, takemutex);
443
444 return err;
445 }
446
447 void
448 umcpmio_set_adc_vref(struct mcp2221_set_sram_req *req, char *newvref)
449 {
450 int i;
451
452 for (i = 0; i < __arraycount(umcpmio_vref_puts); i++) {
453 if (strncmp(newvref, umcpmio_vref_puts[i].tname,
454 UMCPMIO_VREF_NAME) == 0) {
455 break;
456 }
457 }
458
459 if (i == __arraycount(umcpmio_vref_puts))
460 return;
461
462 req->adc_voltage_reference |= umcpmio_vref_puts[i].mask | MCP2221_SRAM_CHANGE_ADC_VREF;
463 }
464
465 int
466 umcpmio_set_adc_vref_one(struct umcpmio_softc *sc, char *newvref, bool takemutex)
467 {
468 struct mcp2221_set_sram_req req;
469 struct mcp2221_set_sram_res res;
470 int err = 0;
471
472 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
473 umcpmio_set_adc_vref(&req, newvref);
474 err = umcpmio_put_sram(sc, &req, &res, takemutex);
475
476 return err;
477 }
478
479 static struct umcpmio_mapping_put umcpmio_dc_puts[] = {
480 {
481 .tname = "75%",
482 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_75,
483 },
484 {
485 .tname = "50%",
486 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_50,
487 },
488 {
489 .tname = "25%",
490 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_25,
491 },
492 {
493 .tname = "0%",
494 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_0,
495 }
496 };
497
498 void
499 umcpmio_set_gpioclock_dc(struct mcp2221_set_sram_req *req, char *new_dc)
500 {
501 int i;
502
503 for (i = 0; i < __arraycount(umcpmio_dc_puts); i++) {
504 if (strncmp(new_dc, umcpmio_dc_puts[i].tname,
505 UMCPMIO_VREF_NAME) == 0) {
506 break;
507 }
508 }
509
510 if (i == __arraycount(umcpmio_dc_puts))
511 return;
512
513 req->clock_output_divider |= umcpmio_dc_puts[i].mask;
514 }
515
516 int
517 umcpmio_set_gpioclock_dc_one(struct umcpmio_softc *sc, char *new_dutycycle, bool takemutex)
518 {
519 struct mcp2221_get_sram_res current_sram_res;
520 struct mcp2221_set_sram_req req;
521 struct mcp2221_set_sram_res res;
522 int err = 0;
523
524 err = umcpmio_get_sram(sc, ¤t_sram_res, takemutex);
525 if (! err) {
526 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
527 umcpmio_set_gpioclock_dc(&req, new_dutycycle);
528 DPRINTF(("umcpmio_set_gpioclock_dc_one: req.clock_output_divider=%02x,current mask=%02x\n",req.clock_output_divider,current_sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_CD_MASK));
529 req.clock_output_divider |= (current_sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_CD_MASK) | MCP2221_SRAM_GPIO_CHANGE_DCCD;
530 DPRINTF(("umcpmio_set_gpioclock_dc_one: SET req.clock_output_divider=%02x\n",req.clock_output_divider));
531 err = umcpmio_put_sram(sc, &req, &res, takemutex);
532 }
533
534 return err;
535 }
536
537 static struct umcpmio_mapping_put umcpmio_cd_puts[] = {
538 {
539 .tname = "375kHz",
540 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_375KHZ,
541 },
542 {
543 .tname = "750kHz",
544 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_750KHZ,
545 },
546 {
547 .tname = "1.5MHz",
548 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_1P5MHZ,
549 },
550 {
551 .tname = "3MHz",
552 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_3MHZ,
553 },
554 {
555 .tname = "6MHz",
556 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_6MHZ,
557 },
558 {
559 .tname = "12MHz",
560 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_12MHZ,
561 },
562 {
563 .tname = "24MHz",
564 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_24MHZ,
565 }
566 };
567
568 void
569 umcpmio_set_gpioclock_cd(struct mcp2221_set_sram_req *req, char *new_cd)
570 {
571 int i;
572
573 for (i = 0; i < __arraycount(umcpmio_cd_puts); i++) {
574 if (strncmp(new_cd, umcpmio_cd_puts[i].tname,
575 UMCPMIO_CD_NAME) == 0) {
576 break;
577 }
578 }
579
580 if (i == __arraycount(umcpmio_cd_puts))
581 return;
582
583 req->clock_output_divider |= umcpmio_cd_puts[i].mask;
584 }
585
586 int
587 umcpmio_set_gpioclock_cd_one(struct umcpmio_softc *sc, char *new_clockdivider, bool takemutex)
588 {
589 struct mcp2221_get_sram_res current_sram_res;
590 struct mcp2221_set_sram_req req;
591 struct mcp2221_set_sram_res res;
592 int err = 0;
593
594 err = umcpmio_get_sram(sc, ¤t_sram_res, takemutex);
595 if (! err) {
596 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
597 umcpmio_set_gpioclock_cd(&req, new_clockdivider);
598 DPRINTF(("umcpmio_set_gpioclock_cd_one: req.clock_output_divider=%02x,current mask=%02x\n",req.clock_output_divider,current_sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_CD_MASK));
599 req.clock_output_divider |= (current_sram_res.clock_divider & MCP2221_SRAM_GPIO_CLOCK_DC_MASK) | MCP2221_SRAM_GPIO_CHANGE_DCCD;
600 DPRINTF(("umcpmio_set_gpioclock_cd_one: SET req.clock_output_divider=%02x\n",req.clock_output_divider));
601 err = umcpmio_put_sram(sc, &req, &res, takemutex);
602 }
603
604 return err;
605 }
606
607 int
608 umcpmio_get_gpio_cfg(struct umcpmio_softc *sc,
609 struct mcp2221_get_gpio_cfg_res *res, bool takemutex)
610 {
611 struct mcp2221_get_gpio_cfg_req req;
612 int err = 0;
613
614 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
615 req.cmd = MCP2221_CMD_GET_GPIO_CFG;
616
617 if (takemutex)
618 mutex_enter(&sc->sc_action_mutex);
619 err = umcpmio_send_report(sc, (uint8_t *)&req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
620 if (takemutex)
621 mutex_exit(&sc->sc_action_mutex);
622
623 return(err);
624 }
625
626 int
627 umcpmio_put_gpio_cfg(struct umcpmio_softc *sc,
628 struct mcp2221_set_gpio_cfg_req *req, struct mcp2221_set_gpio_cfg_res *res,
629 bool takemutex)
630 {
631 int err = 0;
632
633 req->cmd = MCP2221_CMD_SET_GPIO_CFG;
634
635 if (takemutex)
636 mutex_enter(&sc->sc_action_mutex);
637 err = umcpmio_send_report(sc, (uint8_t *)req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
638 if (takemutex)
639 mutex_exit(&sc->sc_action_mutex);
640
641 return(err);
642 }
643
644 /* So... if the pin isn't set to GPIO, just call the output LOW */
645
646 int
647 umcpmio_get_gpio_value(struct umcpmio_softc *sc,
648 int pin, bool takemutex)
649 {
650 struct mcp2221_get_gpio_cfg_res get_gpio_cfg_res;
651 int err = 0;
652 int r = GPIO_PIN_LOW;
653
654 err = umcpmio_get_gpio_cfg(sc, &get_gpio_cfg_res, takemutex);
655 if (! err) {
656 if (get_gpio_cfg_res.cmd == MCP2221_CMD_GET_GPIO_CFG &&
657 get_gpio_cfg_res.completion == MCP2221_CMD_COMPLETE_OK) {
658 switch (pin) {
659 case 0:
660 if (get_gpio_cfg_res.gp0_pin_value != MCP2221_GPIO_CFG_VALUE_NOT_GPIO)
661 if (get_gpio_cfg_res.gp0_pin_value == 0x01)
662 r = GPIO_PIN_HIGH;
663 break;
664 case 1:
665 if (get_gpio_cfg_res.gp1_pin_value != MCP2221_GPIO_CFG_VALUE_NOT_GPIO)
666 if (get_gpio_cfg_res.gp1_pin_value == 0x01)
667 r = GPIO_PIN_HIGH;
668 break;
669 case 2:
670 if (get_gpio_cfg_res.gp2_pin_value != MCP2221_GPIO_CFG_VALUE_NOT_GPIO)
671 if (get_gpio_cfg_res.gp2_pin_value == 0x01)
672 r = GPIO_PIN_HIGH;
673 break;
674 case 3:
675 if (get_gpio_cfg_res.gp3_pin_value != MCP2221_GPIO_CFG_VALUE_NOT_GPIO)
676 if (get_gpio_cfg_res.gp3_pin_value == 0x01)
677 r = GPIO_PIN_HIGH;
678 break;
679 default:
680 break;
681 }
682 } else {
683 device_printf(sc->sc_dev, "umcpmio_get_gpio_value: wrong command or error: %02x %02x\n",
684 get_gpio_cfg_res.cmd,
685 get_gpio_cfg_res.completion);
686 }
687 }
688
689 return(r);
690 }
691
692 void
693 umcpmio_set_gpio_value(struct mcp2221_set_gpio_cfg_req *req,
694 int pin, bool value)
695 {
696 uint8_t *alter = NULL;
697 uint8_t *newvalue = NULL;
698
699 if (pin >=0 && pin < MCP2221_NPINS) {
700 switch (pin) {
701 case 0:
702 alter = &req->alter_gp0_value;
703 newvalue = &req->new_gp0_value;
704 break;
705 case 1:
706 alter = &req->alter_gp1_value;
707 newvalue = &req->new_gp1_value;
708 break;
709 case 2:
710 alter = &req->alter_gp2_value;
711 newvalue = &req->new_gp2_value;
712 break;
713 case 3:
714 alter = &req->alter_gp3_value;
715 newvalue = &req->new_gp3_value;
716 break;
717 default:
718 break;
719 }
720
721 if (alter != NULL) {
722 *alter = MCP2221_GPIO_CFG_ALTER;
723 *newvalue = 0;
724 if (value)
725 *newvalue = 1;
726 }
727 }
728 }
729
730 int
731 umcpmio_set_gpio_value_one(struct umcpmio_softc *sc,
732 int pin, bool value, bool takemutex)
733 {
734 int err = 0;
735 struct mcp2221_set_gpio_cfg_req req;
736 struct mcp2221_set_gpio_cfg_res res;
737
738 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
739 umcpmio_set_gpio_value(&req, pin, value);
740 err = umcpmio_put_gpio_cfg(sc, &req, &res, takemutex);
741 if (! err) {
742 if (res.cmd == MCP2221_CMD_SET_GPIO_CFG &&
743 res.completion == MCP2221_CMD_COMPLETE_OK) {
744 } else {
745 err = EIO;
746 device_printf(sc->sc_dev, "umcpmio_gpio_pin_write: not the command desired, or error: %02x %02x\n",
747 res.cmd,
748 res.completion);
749 }
750 }
751
752 return(err);
753 }
754
755 int
756 umcpmio_get_flash(struct umcpmio_softc *sc, uint8_t subcode,
757 struct mcp2221_get_flash_res *res, bool takemutex)
758 {
759 struct mcp2221_get_flash_req req;
760 int err = 0;
761
762 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE);
763 req.cmd = MCP2221_CMD_GET_FLASH;
764
765 if (subcode < MCP2221_FLASH_SUBCODE_CS ||
766 subcode > MCP2221_FLASH_SUBCODE_CHIPSN)
767 return(EINVAL);
768
769 req.subcode = subcode;
770
771 if (takemutex)
772 mutex_enter(&sc->sc_action_mutex);
773 err = umcpmio_send_report(sc, (uint8_t *)&req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
774 if (takemutex)
775 mutex_exit(&sc->sc_action_mutex);
776
777 return(err);
778 }
779
780 int
781 umcpmio_put_flash(struct umcpmio_softc *sc, struct mcp2221_put_flash_req *req,
782 struct mcp2221_put_flash_res *res, bool takemutex)
783 {
784 int err = 0;
785
786 req->cmd = MCP2221_CMD_SET_FLASH;
787
788 if (req->subcode < MCP2221_FLASH_SUBCODE_CS ||
789 req->subcode > MCP2221_FLASH_SUBCODE_CHIPSN) {
790 DPRINTF(("umcpmio_put_flash: subcode out of range: subcode=%d\n",req->subcode));
791 return(EINVAL);
792 }
793
794 if (takemutex)
795 mutex_enter(&sc->sc_action_mutex);
796 err = umcpmio_send_report(sc, (uint8_t *)req, MCP2221_REQ_BUFFER_SIZE, (uint8_t *)res, sc->sc_cv_wait);
797 if (takemutex)
798 mutex_exit(&sc->sc_action_mutex);
799
800 return(err);
801 }
802
803