Home | History | Annotate | Line # | Download | only in usb
      1 /*	$NetBSD: umcpmio_gpio.c,v 1.2 2025/12/12 17:49:35 andvar Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2024, 2025 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_gpio.c,v 1.2 2025/12/12 17:49:35 andvar 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)
     43 extern 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 symmetric 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 
     66 static uint32_t
     67 mcp2210_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 
     92 static uint32_t
     93 mcp2210_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 
    124 static uint32_t
    125 mcp2221_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 
    155 static void
    156 mcp2221_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 
    193 static int
    194 mcp2210_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 
    214 static int
    215 mcp2210_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 
    233 static int
    234 mcp2210_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 
    254 static int
    255 mcp2210_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 
    275 static int
    276 mcp2210_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 
    294 static int
    295 mcp2210_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 
    313 static void
    314 mcp2221_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 symmetric.  That is,
    380  * the bits sort of line up but not quite between a GET and PUT.
    381  */
    382 
    383 static 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 
    406 void
    407 mcp2221_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 
    425 int
    426 mcp2221_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 
    441 void
    442 mcp2221_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 
    448 int
    449 mcp2221_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 
    464 void
    465 mcp2221_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 
    483 int
    484 mcp2221_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 
    499 static 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 
    518 void
    519 mcp2221_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 
    536 int
    537 mcp2221_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, &current_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);
    565 out:
    566 	return err;
    567 }
    568 
    569 static 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 
    600 void
    601 mcp2221_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 
    618 int
    619 mcp2221_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, &current_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);
    647 out:
    648 	return err;
    649 }
    650 
    651 int
    652 mcp2221_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 
    670 static int
    671 mcp2221_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 
    687 static int
    688 mcp2210_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 
    710 static int
    711 mcp2221_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 	}
    760 out:
    761 	return r;
    762 }
    763 
    764 static int
    765 mcp2210_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 
    796 static void
    797 mcp2221_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 
    833 static int
    834 mcp2221_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 	}
    856 out:
    857 	return err;
    858 }
    859 
    860 /* These are standard gpio reads and set calls */
    861 
    862 static int
    863 umcpmio_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 
    880 static void
    881 umcpmio_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 
    895 static int
    896 mcp2210_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 that 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 strictly 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 	}
   1075 out:
   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 
   1088 int
   1089 mcp2221_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, &current_sram_res);
   1104 	if (err)
   1105 		goto out;
   1106 
   1107 	err = mcp2221_get_gpio_cfg(sc, &current_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 
   1208 out:
   1209 	return err;
   1210 }
   1211 
   1212 void
   1213 umcpmio_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 
   1228 int
   1229 mcp2210_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 
   1261 static int
   1262 umcpmio_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 
   1324 void
   1325 umcpmio_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