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@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