1/* $NetBSD: umcpmio_gpio.c,v 1.1 2025/11/29 18:39:14 brad Exp $ */ 2 3/* 4 * Copyright (c) 2024, 2025 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_gpio.c,v 1.1 2025/11/29 18:39:14 brad Exp $"); 21 22#ifdef _KERNEL_OPT 23#include "opt_usb.h" 24#endif 25 26#include <sys/param.h> 27#include <sys/types.h> 28 29#include <sys/gpio.h> 30 31#include <dev/gpio/gpiovar.h> 32 33#include <dev/usb/umcpmio.h> 34#include <dev/usb/umcpmio_hid_reports.h> 35#include <dev/usb/umcpmio_transport.h> 36#include <dev/usb/umcpmio_gpio.h> 37#include <dev/usb/umcpmio_subr.h> 38 39#define UMCPMIO_DEBUG 1 40#ifdef UMCPMIO_DEBUG 41#define DPRINTF(x) do { if (umcpmiodebug) printf x; } while (0) 42#define DPRINTFN(n, x) do { if (umcpmiodebug > (n)) printf x; } while (0) 43extern int umcpmiodebug; 44#else 45#define DPRINTF(x) __nothing 46#define DPRINTFN(n, x) __nothing 47#endif 48 49/* Stuff required to deal with the gpio on the MCP2210 and 50 * MCP2221 / MCP2221A */ 51 52/* The MCP2210 has more, but simpler, pins than the MCP2221 53 * / MCP2221A. 54 * 55 * 56 * The MCP2221 / MCP2221A does not have symetric behavior with 57 * respect to the get and puts of the SRAM. This means that you 58 * more or less can't just take the response buffer from a SRAM 59 * get and use it directly as a SRAM put. The MCP2210 is better 60 * in this respect. 61 */ 62 63 64/* We call the dedicated function ALT3 everywhere */ 65 66static uint32_t 67mcp2210_counter_gp_to_flags(uint8_t other_settings) 68{ 69 uint32_t r = 0; 70 71 switch ((other_settings >> 1) & 0x07) { 72 case MCP2210_COUNTER_FALLING_EDGE: 73 r |= GPIO_PIN_ALT3; 74 break; 75 case MCP2210_COUNTER_RISING_EDGE: 76 r |= GPIO_PIN_ALT4; 77 break; 78 case MCP2210_COUNTER_LOW_PULSE: 79 r |= GPIO_PIN_ALT5; 80 break; 81 case MCP2210_COUNTER_HIGH_PULSE: 82 r |= GPIO_PIN_ALT6; 83 break; 84 case MCP2210_COUNTER_OFF: 85 default: 86 printf("mcp2210_counter_gp_to_flags: Unhandled flag on counter pin: 0x%02x\n", other_settings); 87 } 88 89 return r; 90} 91 92static uint32_t 93mcp2210_sram_gpio_to_flags(uint8_t *gp_settings, int pin) 94{ 95 uint32_t r = 0; 96 97 switch (gp_settings[pin]) { 98 case MCP2210_PIN_IS_ALT0: 99 r |= GPIO_PIN_ALT0; 100 break; 101 case MCP2210_PIN_IS_DED: 102 if (pin == 6) { 103 r |= mcp2210_counter_gp_to_flags(gp_settings[11]); 104 } else { 105 r |= GPIO_PIN_ALT3; 106 } 107 break; 108 case MCP2210_PIN_IS_GPIO: 109 default: 110 if (pin < 8) { 111 if (gp_settings[9] & (1 << pin)) 112 r |= GPIO_PIN_INPUT; 113 else 114 r |= GPIO_PIN_OUTPUT; 115 } else { 116 r |= GPIO_PIN_INPUT; 117 } 118 break; 119 } 120 121 return r; 122} 123 124static uint32_t 125mcp2221_sram_gpio_to_flags(uint8_t gp_setting) 126{ 127 uint32_t r = 0; 128 129 switch (gp_setting & MCP2221_SRAM_PIN_TYPE_MASK) { 130 case MCP2221_SRAM_PIN_IS_DED: 131 r |= GPIO_PIN_ALT3; 132 break; 133 case MCP2221_SRAM_PIN_IS_ALT0: 134 r |= GPIO_PIN_ALT0; 135 break; 136 case MCP2221_SRAM_PIN_IS_ALT1: 137 r |= GPIO_PIN_ALT1; 138 break; 139 case MCP2221_SRAM_PIN_IS_ALT2: 140 r |= GPIO_PIN_ALT2; 141 break; 142 case MCP2221_SRAM_PIN_IS_GPIO: 143 default: 144 if ((gp_setting & MCP2221_SRAM_GPIO_TYPE_MASK) == 145 MCP2221_SRAM_GPIO_INPUT) 146 r |= GPIO_PIN_INPUT; 147 else 148 r |= GPIO_PIN_OUTPUT; 149 break; 150 } 151 152 return r; 153} 154 155static void 156mcp2221_set_gpio_dir_sram(struct mcp2221_set_sram_req *req, int pin, int flags) 157{ 158 uint8_t *alter = NULL; 159 uint8_t *newvalue = NULL; 160 161 if (pin >= 0 && pin < MCP2221_NPINS) { 162 switch (pin) { 163 case 0: 164 alter = &req->alter_gpio_config; 165 newvalue = &req->gp0_settings; 166 break; 167 case 1: 168 alter = &req->alter_gpio_config; 169 newvalue = &req->gp1_settings; 170 break; 171 case 2: 172 alter = &req->alter_gpio_config; 173 newvalue = &req->gp2_settings; 174 break; 175 case 3: 176 alter = &req->alter_gpio_config; 177 newvalue = &req->gp3_settings; 178 break; 179 default: 180 break; 181 } 182 183 if (alter != NULL) { 184 *alter = MCP2221_SRAM_ALTER_GPIO; 185 if (flags & GPIO_PIN_INPUT) 186 *newvalue |= MCP2221_SRAM_GPIO_INPUT; 187 else 188 *newvalue &= ~MCP2221_SRAM_GPIO_INPUT; 189 } 190 } 191} 192 193static int 194mcp2210_get_gpio_sram(struct umcpmio_softc *sc, 195 struct mcp2210_get_gpio_sram_res *res) 196{ 197 struct mcp2210_get_gpio_sram_req req; 198 int err = 0; 199 200 memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 201 req.cmd = MCP2210_CMD_GET_GPIO_SRAM; 202 203 KASSERT(mutex_owned(&sc->sc_action_mutex)); 204 205 err = umcpmio_send_report(sc, 206 (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 207 (uint8_t *) res, sc->sc_cv_wait); 208 209 err = mcp2210_decode_errors(req.cmd, err, res->completion); 210 211 return err; 212} 213 214static int 215mcp2210_set_gpio_sram(struct umcpmio_softc *sc, 216 struct mcp2210_set_gpio_sram_req *req, struct mcp2210_set_gpio_sram_res *res) 217{ 218 int err = 0; 219 220 req->cmd = MCP2210_CMD_SET_GPIO_SRAM; 221 222 KASSERT(mutex_owned(&sc->sc_action_mutex)); 223 224 err = umcpmio_send_report(sc, 225 (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 226 (uint8_t *) res, sc->sc_cv_wait); 227 228 err = mcp2210_decode_errors(req->cmd, err, res->completion); 229 230 return err; 231} 232 233static int 234mcp2210_get_gpio_dir_sram(struct umcpmio_softc *sc, 235 struct mcp2210_get_gpio_dir_res *res) 236{ 237 struct mcp2210_get_gpio_dir_req req; 238 int err = 0; 239 240 memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 241 req.cmd = MCP2210_CMD_GET_GPIO_DIR_SRAM; 242 243 KASSERT(mutex_owned(&sc->sc_action_mutex)); 244 245 err = umcpmio_send_report(sc, 246 (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 247 (uint8_t *) res, sc->sc_cv_wait); 248 249 err = mcp2210_decode_errors(req.cmd, err, res->completion); 250 251 return err; 252} 253 254static int 255mcp2210_get_gpio_value_sram(struct umcpmio_softc *sc, 256 struct mcp2210_get_gpio_value_res *res) 257{ 258 struct mcp2210_get_gpio_value_req req; 259 int err = 0; 260 261 memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 262 req.cmd = MCP2210_CMD_GET_GPIO_VAL_SRAM; 263 264 KASSERT(mutex_owned(&sc->sc_action_mutex)); 265 266 err = umcpmio_send_report(sc, 267 (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 268 (uint8_t *) res, sc->sc_cv_wait); 269 270 err = mcp2210_decode_errors(req.cmd, err, res->completion); 271 272 return err; 273} 274 275static int 276mcp2210_set_gpio_dir_sram(struct umcpmio_softc *sc, 277 struct mcp2210_set_gpio_dir_req *req, struct mcp2210_set_gpio_dir_res *res) 278{ 279 int err = 0; 280 281 req->cmd = MCP2210_CMD_SET_GPIO_DIR_SRAM; 282 283 KASSERT(mutex_owned(&sc->sc_action_mutex)); 284 285 err = umcpmio_send_report(sc, 286 (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 287 (uint8_t *) res, sc->sc_cv_wait); 288 289 err = mcp2210_decode_errors(req->cmd, err, res->completion); 290 291 return err; 292} 293 294static int 295mcp2210_set_gpio_value_sram(struct umcpmio_softc *sc, 296 struct mcp2210_set_gpio_value_req *req, struct mcp2210_set_gpio_value_res *res) 297{ 298 int err = 0; 299 300 req->cmd = MCP2210_CMD_SET_GPIO_VAL_SRAM; 301 302 KASSERT(mutex_owned(&sc->sc_action_mutex)); 303 304 err = umcpmio_send_report(sc, 305 (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 306 (uint8_t *) res, sc->sc_cv_wait); 307 308 err = mcp2210_decode_errors(req->cmd, err, res->completion); 309 310 return err; 311} 312 313static void 314mcp2221_set_gpio_designation_sram(struct mcp2221_set_sram_req *req, int pin, 315 int flags) 316{ 317 uint8_t *alter = NULL; 318 uint8_t *newvalue = NULL; 319 uint32_t altmask = 320 GPIO_PIN_ALT0 | GPIO_PIN_ALT1 | GPIO_PIN_ALT2 | GPIO_PIN_ALT3; 321 322 if (pin >= 0 && pin < MCP2221_NPINS) { 323 switch (pin) { 324 case 0: 325 alter = &req->alter_gpio_config; 326 newvalue = &req->gp0_settings; 327 break; 328 case 1: 329 alter = &req->alter_gpio_config; 330 newvalue = &req->gp1_settings; 331 break; 332 case 2: 333 alter = &req->alter_gpio_config; 334 newvalue = &req->gp2_settings; 335 break; 336 case 3: 337 alter = &req->alter_gpio_config; 338 newvalue = &req->gp3_settings; 339 break; 340 default: 341 break; 342 } 343 344 if (alter != NULL) { 345 int nv = *newvalue; 346 347 *alter = MCP2221_SRAM_ALTER_GPIO; 348 nv &= 0xF8; 349 350 if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 351 nv |= MCP2221_SRAM_PIN_IS_GPIO; 352 } else { 353 switch (flags & altmask) { 354 case GPIO_PIN_ALT0: 355 nv |= MCP2221_SRAM_PIN_IS_ALT0; 356 break; 357 case GPIO_PIN_ALT1: 358 nv |= MCP2221_SRAM_PIN_IS_ALT1; 359 break; 360 case GPIO_PIN_ALT2: 361 nv |= MCP2221_SRAM_PIN_IS_ALT2; 362 break; 363 /* ALT3 will always be used as the 364 * dedicated function specific to the 365 * pin. Not all of the pins will have 366 * the alt functions below #3. */ 367 case GPIO_PIN_ALT3: 368 nv |= MCP2221_SRAM_PIN_IS_DED; 369 break; 370 default: 371 break; 372 } 373 } 374 *newvalue = nv; 375 } 376 } 377} 378/* 379 * It is unfortunate that the GET and PUT requests are not symertric. That is, 380 * the bits sort of line up but not quite between a GET and PUT. 381 */ 382 383static struct umcpmio_mapping_put mcp2221_vref_puts[] = { 384 { 385 .tname = "4.096V", 386 .mask = 0x06 | 0x01, 387 }, 388 { 389 .tname = "2.048V", 390 .mask = 0x04 | 0x01, 391 }, 392 { 393 .tname = "1.024V", 394 .mask = 0x02 | 0x01, 395 }, 396 { 397 .tname = "OFF", 398 .mask = 0x00 | 0x01, 399 }, 400 { 401 .tname = "VDD", 402 .mask = 0x00, 403 } 404}; 405 406void 407mcp2221_set_dac_vref(struct mcp2221_set_sram_req *req, char *newvref) 408{ 409 int i; 410 411 for (i = 0; i < __arraycount(mcp2221_vref_puts); i++) { 412 if (strncmp(newvref, mcp2221_vref_puts[i].tname, 413 MCP2221_VREF_NAME) == 0) { 414 break; 415 } 416 } 417 418 if (i == __arraycount(mcp2221_vref_puts)) 419 return; 420 421 req->dac_voltage_reference |= mcp2221_vref_puts[i].mask | 422 MCP2221_SRAM_CHANGE_DAC_VREF; 423} 424 425int 426mcp2221_set_dac_vref_one(struct umcpmio_softc *sc, char *newvref) 427{ 428 struct mcp2221_set_sram_req req; 429 struct mcp2221_set_sram_res res; 430 int err = 0; 431 432 KASSERT(mutex_owned(&sc->sc_action_mutex)); 433 434 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 435 mcp2221_set_dac_vref(&req, newvref); 436 err = mcp2221_put_sram(sc, &req, &res); 437 438 return err; 439} 440 441void 442mcp2221_set_dac_value(struct mcp2221_set_sram_req *req, uint8_t newvalue) 443{ 444 req->set_dac_output_value |= (newvalue & MCP2221_SRAM_DAC_VALUE_MASK) | 445 MCP2221_SRAM_CHANGE_DAC_VREF; 446} 447 448int 449mcp2221_set_dac_value_one(struct umcpmio_softc *sc, uint8_t newvalue) 450{ 451 struct mcp2221_set_sram_req req; 452 struct mcp2221_set_sram_res res; 453 int err = 0; 454 455 KASSERT(mutex_owned(&sc->sc_action_mutex)); 456 457 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 458 mcp2221_set_dac_value(&req, newvalue); 459 err = mcp2221_put_sram(sc, &req, &res); 460 461 return err; 462} 463 464void 465mcp2221_set_adc_vref(struct mcp2221_set_sram_req *req, char *newvref) 466{ 467 int i; 468 469 for (i = 0; i < __arraycount(mcp2221_vref_puts); i++) { 470 if (strncmp(newvref, mcp2221_vref_puts[i].tname, 471 MCP2221_VREF_NAME) == 0) { 472 break; 473 } 474 } 475 476 if (i == __arraycount(mcp2221_vref_puts)) 477 return; 478 479 req->adc_voltage_reference |= mcp2221_vref_puts[i].mask | 480 MCP2221_SRAM_CHANGE_ADC_VREF; 481} 482 483int 484mcp2221_set_adc_vref_one(struct umcpmio_softc *sc, char *newvref) 485{ 486 struct mcp2221_set_sram_req req; 487 struct mcp2221_set_sram_res res; 488 int err = 0; 489 490 KASSERT(mutex_owned(&sc->sc_action_mutex)); 491 492 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 493 mcp2221_set_adc_vref(&req, newvref); 494 err = mcp2221_put_sram(sc, &req, &res); 495 496 return err; 497} 498 499static struct umcpmio_mapping_put mcp2221_dc_puts[] = { 500 { 501 .tname = "75%", 502 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_75, 503 }, 504 { 505 .tname = "50%", 506 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_50, 507 }, 508 { 509 .tname = "25%", 510 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_25, 511 }, 512 { 513 .tname = "0%", 514 .mask = MCP2221_SRAM_GPIO_CLOCK_DC_0, 515 } 516}; 517 518void 519mcp2221_set_gpioclock_dc(struct mcp2221_set_sram_req *req, char *new_dc) 520{ 521 int i; 522 523 for (i = 0; i < __arraycount(mcp2221_dc_puts); i++) { 524 if (strncmp(new_dc, mcp2221_dc_puts[i].tname, 525 MCP2221_DC_NAME) == 0) { 526 break; 527 } 528 } 529 530 if (i == __arraycount(mcp2221_dc_puts)) 531 return; 532 533 req->clock_output_divider |= mcp2221_dc_puts[i].mask; 534} 535 536int 537mcp2221_set_gpioclock_dc_one(struct umcpmio_softc *sc, char *new_dutycycle) 538{ 539 struct mcp2221_get_sram_res current_sram_res; 540 struct mcp2221_set_sram_req req; 541 struct mcp2221_set_sram_res res; 542 int err = 0; 543 544 KASSERT(mutex_owned(&sc->sc_action_mutex)); 545 546 err = mcp2221_get_sram(sc, ¤t_sram_res); 547 if (err) 548 goto out; 549 550 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 551 mcp2221_set_gpioclock_dc(&req, new_dutycycle); 552 DPRINTF(("mcp2221_set_gpioclock_dc_one:" 553 " req.clock_output_divider=%02x, current mask=%02x\n", 554 req.clock_output_divider, 555 (current_sram_res.clock_divider & 556 MCP2221_SRAM_GPIO_CLOCK_CD_MASK))); 557 req.clock_output_divider |= 558 (current_sram_res.clock_divider & 559 MCP2221_SRAM_GPIO_CLOCK_CD_MASK) | 560 MCP2221_SRAM_GPIO_CHANGE_DCCD; 561 DPRINTF(("mcp2221_set_gpioclock_dc_one:" 562 " SET req.clock_output_divider=%02x\n", 563 req.clock_output_divider)); 564 err = mcp2221_put_sram(sc, &req, &res); 565out: 566 return err; 567} 568 569static struct umcpmio_mapping_put mcp2221_cd_puts[] = { 570 { 571 .tname = "375kHz", 572 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_375KHZ, 573 }, 574 { 575 .tname = "750kHz", 576 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_750KHZ, 577 }, 578 { 579 .tname = "1.5MHz", 580 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_1P5MHZ, 581 }, 582 { 583 .tname = "3MHz", 584 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_3MHZ, 585 }, 586 { 587 .tname = "6MHz", 588 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_6MHZ, 589 }, 590 { 591 .tname = "12MHz", 592 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_12MHZ, 593 }, 594 { 595 .tname = "24MHz", 596 .mask = MCP2221_SRAM_GPIO_CLOCK_CD_24MHZ, 597 } 598}; 599 600void 601mcp2221_set_gpioclock_cd(struct mcp2221_set_sram_req *req, char *new_cd) 602{ 603 int i; 604 605 for (i = 0; i < __arraycount(mcp2221_cd_puts); i++) { 606 if (strncmp(new_cd, mcp2221_cd_puts[i].tname, 607 MCP2221_CD_NAME) == 0) { 608 break; 609 } 610 } 611 612 if (i == __arraycount(mcp2221_cd_puts)) 613 return; 614 615 req->clock_output_divider |= mcp2221_cd_puts[i].mask; 616} 617 618int 619mcp2221_set_gpioclock_cd_one(struct umcpmio_softc *sc, char *new_clockdivider) 620{ 621 struct mcp2221_get_sram_res current_sram_res; 622 struct mcp2221_set_sram_req req; 623 struct mcp2221_set_sram_res res; 624 int err = 0; 625 626 KASSERT(mutex_owned(&sc->sc_action_mutex)); 627 628 err = mcp2221_get_sram(sc, ¤t_sram_res); 629 if (err) 630 goto out; 631 632 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 633 mcp2221_set_gpioclock_cd(&req, new_clockdivider); 634 DPRINTF(("mcp2221_set_gpioclock_cd_one:" 635 " req.clock_output_divider=%02x, current mask=%02x\n", 636 req.clock_output_divider, 637 (current_sram_res.clock_divider & 638 MCP2221_SRAM_GPIO_CLOCK_CD_MASK))); 639 req.clock_output_divider |= 640 (current_sram_res.clock_divider & 641 MCP2221_SRAM_GPIO_CLOCK_DC_MASK) | 642 MCP2221_SRAM_GPIO_CHANGE_DCCD; 643 DPRINTF(("mcp2221_set_gpioclock_cd_one:" 644 " SET req.clock_output_divider=%02x\n", 645 req.clock_output_divider)); 646 err = mcp2221_put_sram(sc, &req, &res); 647out: 648 return err; 649} 650 651int 652mcp2221_get_gpio_cfg(struct umcpmio_softc *sc, 653 struct mcp2221_get_gpio_cfg_res *res) 654{ 655 struct mcp2221_get_gpio_cfg_req req; 656 int err = 0; 657 658 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 659 req.cmd = MCP2221_CMD_GET_GPIO_CFG; 660 661 KASSERT(mutex_owned(&sc->sc_action_mutex)); 662 663 err = umcpmio_send_report(sc, 664 (uint8_t *) & req, MCP2221_REQ_BUFFER_SIZE, 665 (uint8_t *) res, sc->sc_cv_wait); 666 667 return err; 668} 669 670static int 671mcp2221_put_gpio_cfg(struct umcpmio_softc *sc, 672 struct mcp2221_set_gpio_cfg_req *req, struct mcp2221_set_gpio_cfg_res *res) 673{ 674 int err = 0; 675 676 req->cmd = MCP2221_CMD_SET_GPIO_CFG; 677 678 KASSERT(mutex_owned(&sc->sc_action_mutex)); 679 680 err = umcpmio_send_report(sc, 681 (uint8_t *) req, MCP2221_REQ_BUFFER_SIZE, 682 (uint8_t *) res, sc->sc_cv_wait); 683 684 return err; 685} 686 687static int 688mcp2210_get_gpio_value(struct umcpmio_softc *sc, 689 int pin) 690{ 691 struct mcp2210_get_gpio_value_res res; 692 uint16_t v; 693 int err = 0; 694 int r = GPIO_PIN_LOW; 695 696 697 KASSERT(mutex_owned(&sc->sc_action_mutex)); 698 699 err = mcp2210_get_gpio_value_sram(sc, &res); 700 701 if (!err) { 702 v = (res.pin_value_msb << 8) | res.pin_value_lsb; 703 if (v & (1 << pin)) 704 r = GPIO_PIN_HIGH; 705 } 706 return r; 707} 708/* So... if the pin isn't set to GPIO, just call the output LOW */ 709 710static int 711mcp2221_get_gpio_value(struct umcpmio_softc *sc, 712 int pin) 713{ 714 struct mcp2221_get_gpio_cfg_res get_gpio_cfg_res; 715 int err = 0; 716 int r = GPIO_PIN_LOW; 717 718 KASSERT(mutex_owned(&sc->sc_action_mutex)); 719 720 err = mcp2221_get_gpio_cfg(sc, &get_gpio_cfg_res); 721 if (err) 722 goto out; 723 724 if (get_gpio_cfg_res.cmd != MCP2221_CMD_GET_GPIO_CFG || 725 get_gpio_cfg_res.completion != MCP2221_CMD_COMPLETE_OK) { 726 device_printf(sc->sc_dev, "mcp2221_get_gpio_value:" 727 " wrong command or error: %02x %02x\n", 728 get_gpio_cfg_res.cmd, 729 get_gpio_cfg_res.completion); 730 goto out; 731 } 732 switch (pin) { 733 case 0: 734 if (get_gpio_cfg_res.gp0_pin_value != 735 MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 736 if (get_gpio_cfg_res.gp0_pin_value == 0x01) 737 r = GPIO_PIN_HIGH; 738 break; 739 case 1: 740 if (get_gpio_cfg_res.gp1_pin_value != 741 MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 742 if (get_gpio_cfg_res.gp1_pin_value == 0x01) 743 r = GPIO_PIN_HIGH; 744 break; 745 case 2: 746 if (get_gpio_cfg_res.gp2_pin_value != 747 MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 748 if (get_gpio_cfg_res.gp2_pin_value == 0x01) 749 r = GPIO_PIN_HIGH; 750 break; 751 case 3: 752 if (get_gpio_cfg_res.gp3_pin_value != 753 MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 754 if (get_gpio_cfg_res.gp3_pin_value == 0x01) 755 r = GPIO_PIN_HIGH; 756 break; 757 default: 758 break; 759 } 760out: 761 return r; 762} 763 764static int 765mcp2210_set_gpio_value(struct umcpmio_softc *sc, 766 int pin, bool value) 767{ 768 int err = 0; 769 struct mcp2210_get_gpio_value_res get_res; 770 struct mcp2210_set_gpio_value_req set_req; 771 struct mcp2210_set_gpio_value_res set_res; 772 uint16_t v; 773 774 KASSERT(mutex_owned(&sc->sc_action_mutex)); 775 776 err = mcp2210_get_gpio_value_sram(sc, &get_res); 777 if (!err && get_res.completion != MCP2210_CMD_COMPLETE_OK) 778 err = EIO; 779 780 if (!err) { 781 v = (get_res.pin_value_msb << 8) | get_res.pin_value_lsb; 782 783 if (value) 784 v |= (1 << pin); 785 else 786 v &= ~(1 << pin); 787 788 set_req.pin_value_lsb = v & 0x00ff; 789 set_req.pin_value_msb = (v & 0xff00) >> 8; 790 791 err = mcp2210_set_gpio_value_sram(sc, &set_req, &set_res); 792 } 793 return err; 794} 795 796static void 797mcp2221_set_gpio_value(struct mcp2221_set_gpio_cfg_req *req, 798 int pin, bool value) 799{ 800 uint8_t *alter = NULL; 801 uint8_t *newvalue = NULL; 802 803 if (pin < 0 || pin >= MCP2221_NPINS) 804 return; 805 806 switch (pin) { 807 case 0: 808 alter = &req->alter_gp0_value; 809 newvalue = &req->new_gp0_value; 810 break; 811 case 1: 812 alter = &req->alter_gp1_value; 813 newvalue = &req->new_gp1_value; 814 break; 815 case 2: 816 alter = &req->alter_gp2_value; 817 newvalue = &req->new_gp2_value; 818 break; 819 case 3: 820 alter = &req->alter_gp3_value; 821 newvalue = &req->new_gp3_value; 822 break; 823 default: 824 return; 825 } 826 827 *alter = MCP2221_GPIO_CFG_ALTER; 828 *newvalue = 0; 829 if (value) 830 *newvalue = 1; 831} 832 833static int 834mcp2221_set_gpio_value_one(struct umcpmio_softc *sc, 835 int pin, bool value) 836{ 837 int err = 0; 838 struct mcp2221_set_gpio_cfg_req req; 839 struct mcp2221_set_gpio_cfg_res res; 840 841 KASSERT(mutex_owned(&sc->sc_action_mutex)); 842 843 memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 844 mcp2221_set_gpio_value(&req, pin, value); 845 err = mcp2221_put_gpio_cfg(sc, &req, &res); 846 if (err) 847 goto out; 848 if (res.cmd != MCP2221_CMD_SET_GPIO_CFG || 849 res.completion != MCP2221_CMD_COMPLETE_OK) { 850 err = EIO; 851 device_printf(sc->sc_dev, "umcpmio_gpio_pin_write:" 852 " not the command desired, or error: %02x %02x\n", 853 res.cmd, 854 res.completion); 855 } 856out: 857 return err; 858} 859 860/* These are standard gpio reads and set calls */ 861 862static int 863umcpmio_gpio_pin_read(void *arg, int pin) 864{ 865 struct umcpmio_softc *sc = arg; 866 int r = GPIO_PIN_LOW; 867 868 mutex_enter(&sc->sc_action_mutex); 869 870 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) 871 r = mcp2210_get_gpio_value(sc, pin); 872 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) 873 r = mcp2221_get_gpio_value(sc, pin); 874 875 mutex_exit(&sc->sc_action_mutex); 876 877 return r; 878} 879 880static void 881umcpmio_gpio_pin_write(void *arg, int pin, int value) 882{ 883 struct umcpmio_softc *sc = arg; 884 885 mutex_enter(&sc->sc_action_mutex); 886 887 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) 888 mcp2210_set_gpio_value(sc, pin, value); 889 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) 890 mcp2221_set_gpio_value_one(sc, pin, value); 891 892 mutex_exit(&sc->sc_action_mutex); 893} 894 895static int 896mcp2210_gpio_pin_ctl(void *arg, int pin, int flags) 897{ 898 struct umcpmio_softc *sc = arg; 899 struct mcp2210_set_gpio_sram_req mcp2210_set_gpio_sram_req; 900 struct mcp2210_set_gpio_dir_req mcp2210_set_gpio_dir_sram_req; 901 struct mcp2210_set_gpio_sram_res mcp2210_set_gpio_sram_res; 902 struct mcp2210_set_gpio_dir_res mcp2210_set_gpio_dir_sram_res; 903 struct mcp2210_set_gpio_value_req mcp2210_set_gpio_value_sram_req; 904 struct mcp2210_set_gpio_value_res mcp2210_set_gpio_value_sram_res; 905 906 struct mcp2210_get_gpio_sram_res mcp2210_get_gpio_sram_res; 907 struct mcp2210_get_gpio_dir_res mcp2210_get_gpio_dir_sram_res; 908 struct mcp2210_get_gpio_value_res mcp2210_get_gpio_value_sram_res; 909 910 uint32_t altmask = 911 GPIO_PIN_ALT0 | GPIO_PIN_ALT3 | GPIO_PIN_ALT4 | GPIO_PIN_ALT5 | GPIO_PIN_ALT6; 912 int err = 0; 913 uint16_t vdir; 914 915 if (sc->sc_dying) 916 return 0; 917 918 KASSERT(mutex_owned(&sc->sc_action_mutex)); 919 920 err = mcp2210_get_gpio_sram(sc, &mcp2210_get_gpio_sram_res); 921 if (err) 922 goto out; 923 err = mcp2210_get_gpio_dir_sram(sc, &mcp2210_get_gpio_dir_sram_res); 924 if (err) 925 goto out; 926 err = mcp2210_get_gpio_value_sram(sc, &mcp2210_get_gpio_value_sram_res); 927 if (err) 928 goto out; 929 930 umcpmio_dump_buffer(sc->sc_dumpbuffer, 931 (uint8_t *) & mcp2210_get_gpio_sram_res, MCP2210_RES_BUFFER_SIZE, 932 "mcp2210_gpio_pin_ctl get gpio sram res"); 933 umcpmio_dump_buffer(sc->sc_dumpbuffer, 934 (uint8_t *) & mcp2210_get_gpio_dir_sram_res, MCP2210_RES_BUFFER_SIZE, 935 "mcp2210_gpio_pin_ctl get gpio dir sram res"); 936 937 memset(&mcp2210_set_gpio_sram_req.cmd, 0, MCP2210_REQ_BUFFER_SIZE); 938 memcpy(&mcp2210_set_gpio_sram_req.gp0_designation, 939 &mcp2210_get_gpio_sram_res.gp0_designation, 940 &mcp2210_get_gpio_sram_res.nvram_protection - 941 &mcp2210_get_gpio_sram_res.gp0_designation + 1); 942 943 memset(&mcp2210_set_gpio_dir_sram_req.cmd, 0, MCP2210_REQ_BUFFER_SIZE); 944 vdir = (mcp2210_get_gpio_dir_sram_res.pin_dir_msb << 8) | 945 mcp2210_get_gpio_dir_sram_res.pin_dir_lsb; 946 947 uint8_t *b = (uint8_t *) & mcp2210_set_gpio_sram_req.cmd; 948 bool changed_sram = false; 949 950 if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 951 if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_GPIO) { 952 b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_GPIO; 953 changed_sram = true; 954 } 955 if (flags & GPIO_PIN_INPUT) 956 vdir |= (1 << pin); 957 else 958 vdir &= ~(1 << pin); 959 } else { 960 switch (flags & altmask) { 961 case GPIO_PIN_ALT0: 962 if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_ALT0) { 963 b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_ALT0; 964 changed_sram = true; 965 } 966 break; 967 case GPIO_PIN_ALT3: 968 if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 969 b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 970 changed_sram = true; 971 } 972 if (pin == 6) { 973 if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT3) { 974 mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 975 mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_FALLING_EDGE << 1; 976 changed_sram = true; 977 } 978 } 979 break; 980 case GPIO_PIN_ALT4: 981 if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 982 b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 983 changed_sram = true; 984 } 985 if (pin == 6) { 986 if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT4) { 987 mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 988 mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_RISING_EDGE << 1; 989 changed_sram = true; 990 } 991 } 992 break; 993 case GPIO_PIN_ALT5: 994 if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 995 b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 996 changed_sram = true; 997 } 998 if (pin == 6) { 999 if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT5) { 1000 mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 1001 mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_LOW_PULSE << 1; 1002 changed_sram = true; 1003 } 1004 } 1005 break; 1006 case GPIO_PIN_ALT6: 1007 if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 1008 b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 1009 changed_sram = true; 1010 } 1011 if (pin == 6) { 1012 if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT6) { 1013 mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 1014 mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_HIGH_PULSE << 1; 1015 changed_sram = true; 1016 } 1017 } 1018 break; 1019 default: 1020 break; 1021 } 1022 } 1023 1024 /* On the MCP-2210, if you change the purpose of the pin you have to 1025 * write the current direction and value of the pins back to the chip. 1026 * The reason for this is tha you can not change just one pins purpose 1027 * without setting the direction and values of all pins to the default. */ 1028 1029 if (changed_sram) { 1030 err = mcp2210_set_gpio_sram(sc, &mcp2210_set_gpio_sram_req, 1031 &mcp2210_set_gpio_sram_res); 1032 if (err) 1033 goto out; 1034 1035 mcp2210_set_gpio_dir_sram_req.pin_dir_msb = (vdir >> 8) & 0xff; 1036 mcp2210_set_gpio_dir_sram_req.pin_dir_lsb = vdir & 0x00ff; 1037 1038 err = mcp2210_set_gpio_dir_sram(sc, &mcp2210_set_gpio_dir_sram_req, 1039 &mcp2210_set_gpio_dir_sram_res); 1040 if (err) 1041 goto out; 1042 1043 mcp2210_set_gpio_value_sram_req.pin_value_msb = mcp2210_get_gpio_value_sram_res.pin_value_msb; 1044 mcp2210_set_gpio_value_sram_req.pin_value_lsb = mcp2210_get_gpio_value_sram_res.pin_value_lsb; 1045 1046 /* Further, if the pin is for OUTPUT, then we will want to set 1047 * its value to the default, otherwise the default may never be 1048 * reflected in the pin state, as the pin might have been a 1049 * INPUT with the opposite value and just putting all of the 1050 * values back in that case would do the wrong thing. */ 1051 1052 if (flags & GPIO_PIN_OUTPUT && pin < 8) { 1053 if (mcp2210_set_gpio_sram_req.default_output_lsb & (1 << pin)) 1054 mcp2210_set_gpio_value_sram_req.pin_value_lsb |= (1 << pin); 1055 else 1056 mcp2210_set_gpio_value_sram_req.pin_value_lsb &= ~(1 << pin); 1057 } 1058 err = mcp2210_set_gpio_value_sram(sc, &mcp2210_set_gpio_value_sram_req, &mcp2210_set_gpio_value_sram_res); 1059 } else { 1060 /* In this case, the pin purpose was not changed, so all that 1061 * needs to happen is the direction needs to be updated. This 1062 * actually won't matter unless the pin is strickly a GPIO pin. 1063 * ALT0, the CS purpose, is handled by the chip itself, ALT3 - 1064 * ALT6 is for the event / interrupt counter. So, we really 1065 * only have to care if the pin switches from INPUT to OUTPUT, 1066 * or vise versa. */ 1067 if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 1068 mcp2210_set_gpio_dir_sram_req.pin_dir_msb = (vdir >> 8) & 0xff; 1069 mcp2210_set_gpio_dir_sram_req.pin_dir_lsb = vdir & 0x00ff; 1070 1071 err = mcp2210_set_gpio_dir_sram(sc, &mcp2210_set_gpio_dir_sram_req, 1072 &mcp2210_set_gpio_dir_sram_res); 1073 } 1074 } 1075out: 1076 return err; 1077} 1078/* 1079 * Internal function that does the dirty work of setting a gpio 1080 * pin to its "type" for the MCP-2221 / MCP-2221A 1081 * 1082 * There are really two ways to do some of this, one is to set the pin 1083 * to input and output, or whatever, using SRAM calls, the other is to 1084 * use the GPIO config calls to set input and output and SRAM for 1085 * everything else. This just uses SRAM for everything. 1086 */ 1087 1088int 1089mcp2221_gpio_pin_ctl(void *arg, int pin, int flags) 1090{ 1091 struct umcpmio_softc *sc = arg; 1092 struct mcp2221_set_sram_req set_sram_req; 1093 struct mcp2221_set_sram_res set_sram_res; 1094 struct mcp2221_get_sram_res current_sram_res; 1095 struct mcp2221_get_gpio_cfg_res current_gpio_cfg_res; 1096 int err = 0; 1097 1098 if (sc->sc_dying) 1099 return 0; 1100 1101 KASSERT(mutex_owned(&sc->sc_action_mutex)); 1102 1103 err = mcp2221_get_sram(sc, ¤t_sram_res); 1104 if (err) 1105 goto out; 1106 1107 err = mcp2221_get_gpio_cfg(sc, ¤t_gpio_cfg_res); 1108 if (err) 1109 goto out; 1110 1111 /* You can't just set one pin, you must set all of them, so copy the 1112 * current settings for the pin we are not messing with. 1113 * 1114 * And, yes, of course, if the MCP-2210 is ever supported with this 1115 * driver, this sort of unrolling will need to be turned into something 1116 * different, but for now, just unroll as there are only 4 pins to care 1117 * about. 1118 * 1119 * */ 1120 1121 memset(&set_sram_req, 0, MCP2221_REQ_BUFFER_SIZE); 1122 switch (pin) { 1123 case 0: 1124 set_sram_req.gp1_settings = current_sram_res.gp1_settings; 1125 set_sram_req.gp2_settings = current_sram_res.gp2_settings; 1126 set_sram_req.gp3_settings = current_sram_res.gp3_settings; 1127 break; 1128 case 1: 1129 set_sram_req.gp0_settings = current_sram_res.gp0_settings; 1130 set_sram_req.gp2_settings = current_sram_res.gp2_settings; 1131 set_sram_req.gp3_settings = current_sram_res.gp3_settings; 1132 break; 1133 case 2: 1134 set_sram_req.gp0_settings = current_sram_res.gp0_settings; 1135 set_sram_req.gp1_settings = current_sram_res.gp1_settings; 1136 set_sram_req.gp3_settings = current_sram_res.gp3_settings; 1137 break; 1138 case 3: 1139 set_sram_req.gp0_settings = current_sram_res.gp0_settings; 1140 set_sram_req.gp1_settings = current_sram_res.gp1_settings; 1141 set_sram_req.gp2_settings = current_sram_res.gp2_settings; 1142 break; 1143 } 1144 mcp2221_set_gpio_designation_sram(&set_sram_req, pin, flags); 1145 mcp2221_set_gpio_dir_sram(&set_sram_req, pin, flags); 1146 1147 /* This part is unfortunate... if a pin is set to output, the value 1148 * set on the pin is not mirrored by the chip into SRAM, but the chip 1149 * will use the value from SRAM to set the value of the pin. What this 1150 * means is that we have to learn the value from the GPIO config and 1151 * make sure it is set properly when updating SRAM. */ 1152 1153 if (current_gpio_cfg_res.gp0_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 1154 if (current_gpio_cfg_res.gp0_pin_value == 1) { 1155 set_sram_req.gp0_settings |= 1156 MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1157 } else { 1158 set_sram_req.gp0_settings &= 1159 ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1160 } 1161 } 1162 if (current_gpio_cfg_res.gp1_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 1163 if (current_gpio_cfg_res.gp1_pin_value == 1) { 1164 set_sram_req.gp1_settings |= 1165 MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1166 } else { 1167 set_sram_req.gp1_settings &= 1168 ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1169 } 1170 } 1171 if (current_gpio_cfg_res.gp2_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 1172 if (current_gpio_cfg_res.gp2_pin_value == 1) { 1173 set_sram_req.gp2_settings |= 1174 MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1175 } else { 1176 set_sram_req.gp2_settings &= 1177 ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1178 } 1179 } 1180 if (current_gpio_cfg_res.gp3_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 1181 if (current_gpio_cfg_res.gp3_pin_value == 1) { 1182 set_sram_req.gp3_settings |= 1183 MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1184 } else { 1185 set_sram_req.gp3_settings &= 1186 ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 1187 } 1188 } 1189 err = mcp2221_put_sram(sc, &set_sram_req, &set_sram_res); 1190 if (err) 1191 goto out; 1192 1193 umcpmio_dump_buffer(sc->sc_dumpbuffer, 1194 (uint8_t *) & set_sram_res, MCP2221_RES_BUFFER_SIZE, 1195 "mcp2221_gpio_pin_ctl set sram buffer copy"); 1196 if (set_sram_res.cmd != MCP2221_CMD_SET_SRAM || 1197 set_sram_res.completion != MCP2221_CMD_COMPLETE_OK) { 1198 device_printf(sc->sc_dev, "mcp2221_gpio_pin_ctl:" 1199 " not the command desired, or error: %02x %02x\n", 1200 set_sram_res.cmd, 1201 set_sram_res.completion); 1202 err = EIO; 1203 goto out; 1204 } 1205 sc->sc_gpio_pins[pin].pin_flags = flags; 1206 err = 0; 1207 1208out: 1209 return err; 1210} 1211 1212void 1213umcpmio_gpio_pin_ctl(void *arg, int pin, int flags) 1214{ 1215 struct umcpmio_softc *sc = arg; 1216 1217 if (sc->sc_dying) 1218 return; 1219 1220 mutex_enter(&sc->sc_action_mutex); 1221 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) 1222 mcp2210_gpio_pin_ctl(sc, pin, flags); 1223 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) 1224 mcp2221_gpio_pin_ctl(sc, pin, flags); 1225 mutex_exit(&sc->sc_action_mutex); 1226} 1227 1228int 1229mcp2210_get_gp6_counter(struct umcpmio_softc *sc, int *counter, 1230 uint8_t reset) 1231{ 1232 struct mcp2210_get_gp6_events_req req; 1233 struct mcp2210_get_gp6_events_res res; 1234 int err = 0; 1235 1236 KASSERT(mutex_owned(&sc->sc_action_mutex)); 1237 1238 memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 1239 req.cmd = MCP2210_CMD_GET_GP6_EVENTS; 1240 req.reset_counter = reset; 1241 1242 umcpmio_dump_buffer(sc->sc_dumpbuffer, 1243 (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 1244 "mcp2210_get_gp6_counter req"); 1245 1246 err = umcpmio_send_report(sc, 1247 (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 1248 (uint8_t *) & res, sc->sc_cv_wait); 1249 1250 umcpmio_dump_buffer(sc->sc_dumpbuffer, 1251 (uint8_t *) & res, MCP2210_RES_BUFFER_SIZE, 1252 "mcp2210_get_gp6_counter res"); 1253 1254 err = mcp2210_decode_errors(req.cmd, err, res.completion); 1255 if (!err) { 1256 *counter = (res.counter_msb << 8) | res.counter_lsb; 1257 } 1258 return err; 1259} 1260 1261static int 1262umcpmio_extract_gpio_sram(struct umcpmio_softc *sc, 1263 uint8_t *extract) 1264{ 1265 int err = 0; 1266 struct mcp2210_get_gpio_sram_res mcp2210_get_gpio_sram_res; 1267 struct mcp2210_get_gpio_dir_res mcp2210_get_gpio_dir_sram_res; 1268 struct mcp2221_get_sram_res mcp2221_get_sram_res; 1269 1270 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) { 1271 mutex_enter(&sc->sc_action_mutex); 1272 err = mcp2210_get_gpio_sram(sc, &mcp2210_get_gpio_sram_res); 1273 mutex_exit(&sc->sc_action_mutex); 1274 if (err) 1275 return err; 1276 1277 umcpmio_dump_buffer(sc->sc_dumpbuffer, 1278 (uint8_t *) & mcp2210_get_gpio_sram_res, MCP2210_RES_BUFFER_SIZE, 1279 "umcpmio_extract_gpio_sram mcp2210 get gpio sram buffer copy"); 1280 1281 extract[0] = mcp2210_get_gpio_sram_res.gp0_designation; 1282 extract[1] = mcp2210_get_gpio_sram_res.gp1_designation; 1283 extract[2] = mcp2210_get_gpio_sram_res.gp2_designation; 1284 extract[3] = mcp2210_get_gpio_sram_res.gp3_designation; 1285 extract[4] = mcp2210_get_gpio_sram_res.gp4_designation; 1286 extract[5] = mcp2210_get_gpio_sram_res.gp5_designation; 1287 extract[6] = mcp2210_get_gpio_sram_res.gp6_designation; 1288 extract[7] = mcp2210_get_gpio_sram_res.gp7_designation; 1289 extract[8] = mcp2210_get_gpio_sram_res.gp8_designation; 1290 1291 mutex_enter(&sc->sc_action_mutex); 1292 err = mcp2210_get_gpio_dir_sram(sc, &mcp2210_get_gpio_dir_sram_res); 1293 mutex_exit(&sc->sc_action_mutex); 1294 if (err) 1295 return err; 1296 1297 umcpmio_dump_buffer(sc->sc_dumpbuffer, 1298 (uint8_t *) & mcp2210_get_gpio_dir_sram_res, MCP2210_RES_BUFFER_SIZE, 1299 "umcpmio_extract_gpio_sram mcp2210 get gpio dir sram buffer copy"); 1300 1301 extract[9] = mcp2210_get_gpio_dir_sram_res.pin_dir_lsb; 1302 extract[10] = mcp2210_get_gpio_dir_sram_res.pin_dir_msb; 1303 extract[11] = mcp2210_get_gpio_sram_res.other_settings; 1304 } 1305 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) { 1306 mutex_enter(&sc->sc_action_mutex); 1307 err = mcp2221_get_sram(sc, &mcp2221_get_sram_res); 1308 mutex_exit(&sc->sc_action_mutex); 1309 if (err) 1310 return err; 1311 1312 umcpmio_dump_buffer(sc->sc_dumpbuffer, 1313 (uint8_t *) & mcp2221_get_sram_res, MCP2221_RES_BUFFER_SIZE, 1314 "umcpmio_extract_gpio_sram mcp2221 get sram buffer copy"); 1315 1316 extract[0] = mcp2221_get_sram_res.gp0_settings; 1317 extract[1] = mcp2221_get_sram_res.gp1_settings; 1318 extract[2] = mcp2221_get_sram_res.gp2_settings; 1319 extract[3] = mcp2221_get_sram_res.gp3_settings; 1320 } 1321 return err; 1322} 1323 1324void 1325umcpmio_gpio_attach(struct umcpmio_softc *sc) 1326{ 1327 int err; 1328 struct gpiobus_attach_args gba; 1329 uint8_t extract[UMCPMIO_MAX_GPIO_PINS + 3]; 1330 1331 err = umcpmio_extract_gpio_sram(sc, extract); 1332 if (err) { 1333 aprint_error_dev(sc->sc_dev, "umcpmio_gpio_attach:" 1334 " extract gpio from sram: err=%d\n", 1335 err); 1336 return; 1337 } 1338 1339 /* The MCP2221 / MCP2221A has a pin that can have gpio interrupt 1340 * ability, but there are problems with making use of it as the 1341 * gpio framework runs with spin locks or hard interrupt level, 1342 * and you can't call into the USB framework in that state. 1343 * 1344 * It is largely the same reason using the umcpmio gpio pins 1345 * as attachments to gpiopps or gpioow doesn't work. Spin 1346 * locks are held there too. 1347 */ 1348 for (int c = 0; c < sc->sc_chipinfo->num_gpio_pins; c++){ 1349 sc->sc_gpio_pins[c].pin_num = c; 1350 sc->sc_gpio_pins[c].pin_caps = sc->sc_chipinfo->gpio_pin_ability[c]; 1351 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) { 1352 sc->sc_gpio_pins[c].pin_flags = 1353 mcp2210_sram_gpio_to_flags(extract, c); 1354 } 1355 if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) { 1356 sc->sc_gpio_pins[c].pin_flags = 1357 mcp2221_sram_gpio_to_flags(extract[c]); 1358 } 1359 sc->sc_gpio_pins[c].pin_intrcaps = 0; 1360 strncpy(sc->sc_gpio_pins[c].pin_defname, 1361 sc->sc_chipinfo->gpio_names[c], 1362 strlen(sc->sc_chipinfo->gpio_names[c]) + 1); 1363 } 1364 1365 sc->sc_gpio_gc.gp_cookie = sc; 1366 sc->sc_gpio_gc.gp_pin_read = umcpmio_gpio_pin_read; 1367 sc->sc_gpio_gc.gp_pin_write = umcpmio_gpio_pin_write; 1368 sc->sc_gpio_gc.gp_pin_ctl = umcpmio_gpio_pin_ctl; 1369 1370 gba.gba_gc = &sc->sc_gpio_gc; 1371 gba.gba_pins = sc->sc_gpio_pins; 1372 gba.gba_npins = sc->sc_chipinfo->num_gpio_pins; 1373 1374 sc->sc_gpio_dev = config_found(sc->sc_dev, &gba, gpiobus_print, 1375 CFARGS(.iattr = "gpiobus")); 1376} 1377