11.1Sbrad/* $NetBSD: umcpmio_gpio.c,v 1.1 2025/11/29 18:39:14 brad Exp $ */ 21.1Sbrad 31.1Sbrad/* 41.1Sbrad * Copyright (c) 2024, 2025 Brad Spencer <brad@anduin.eldar.org> 51.1Sbrad * 61.1Sbrad * Permission to use, copy, modify, and distribute this software for any 71.1Sbrad * purpose with or without fee is hereby granted, provided that the above 81.1Sbrad * copyright notice and this permission notice appear in all copies. 91.1Sbrad * 101.1Sbrad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 111.1Sbrad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 121.1Sbrad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 131.1Sbrad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 141.1Sbrad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 151.1Sbrad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 161.1Sbrad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 171.1Sbrad */ 181.1Sbrad 191.1Sbrad#include <sys/cdefs.h> 201.1Sbrad__KERNEL_RCSID(0, "$NetBSD: umcpmio_gpio.c,v 1.1 2025/11/29 18:39:14 brad Exp $"); 211.1Sbrad 221.1Sbrad#ifdef _KERNEL_OPT 231.1Sbrad#include "opt_usb.h" 241.1Sbrad#endif 251.1Sbrad 261.1Sbrad#include <sys/param.h> 271.1Sbrad#include <sys/types.h> 281.1Sbrad 291.1Sbrad#include <sys/gpio.h> 301.1Sbrad 311.1Sbrad#include <dev/gpio/gpiovar.h> 321.1Sbrad 331.1Sbrad#include <dev/usb/umcpmio.h> 341.1Sbrad#include <dev/usb/umcpmio_hid_reports.h> 351.1Sbrad#include <dev/usb/umcpmio_transport.h> 361.1Sbrad#include <dev/usb/umcpmio_gpio.h> 371.1Sbrad#include <dev/usb/umcpmio_subr.h> 381.1Sbrad 391.1Sbrad#define UMCPMIO_DEBUG 1 401.1Sbrad#ifdef UMCPMIO_DEBUG 411.1Sbrad#define DPRINTF(x) do { if (umcpmiodebug) printf x; } while (0) 421.1Sbrad#define DPRINTFN(n, x) do { if (umcpmiodebug > (n)) printf x; } while (0) 431.1Sbradextern int umcpmiodebug; 441.1Sbrad#else 451.1Sbrad#define DPRINTF(x) __nothing 461.1Sbrad#define DPRINTFN(n, x) __nothing 471.1Sbrad#endif 481.1Sbrad 491.1Sbrad/* Stuff required to deal with the gpio on the MCP2210 and 501.1Sbrad * MCP2221 / MCP2221A */ 511.1Sbrad 521.1Sbrad/* The MCP2210 has more, but simpler, pins than the MCP2221 531.1Sbrad * / MCP2221A. 541.1Sbrad * 551.1Sbrad * 561.1Sbrad * The MCP2221 / MCP2221A does not have symetric behavior with 571.1Sbrad * respect to the get and puts of the SRAM. This means that you 581.1Sbrad * more or less can't just take the response buffer from a SRAM 591.1Sbrad * get and use it directly as a SRAM put. The MCP2210 is better 601.1Sbrad * in this respect. 611.1Sbrad */ 621.1Sbrad 631.1Sbrad 641.1Sbrad/* We call the dedicated function ALT3 everywhere */ 651.1Sbrad 661.1Sbradstatic uint32_t 671.1Sbradmcp2210_counter_gp_to_flags(uint8_t other_settings) 681.1Sbrad{ 691.1Sbrad uint32_t r = 0; 701.1Sbrad 711.1Sbrad switch ((other_settings >> 1) & 0x07) { 721.1Sbrad case MCP2210_COUNTER_FALLING_EDGE: 731.1Sbrad r |= GPIO_PIN_ALT3; 741.1Sbrad break; 751.1Sbrad case MCP2210_COUNTER_RISING_EDGE: 761.1Sbrad r |= GPIO_PIN_ALT4; 771.1Sbrad break; 781.1Sbrad case MCP2210_COUNTER_LOW_PULSE: 791.1Sbrad r |= GPIO_PIN_ALT5; 801.1Sbrad break; 811.1Sbrad case MCP2210_COUNTER_HIGH_PULSE: 821.1Sbrad r |= GPIO_PIN_ALT6; 831.1Sbrad break; 841.1Sbrad case MCP2210_COUNTER_OFF: 851.1Sbrad default: 861.1Sbrad printf("mcp2210_counter_gp_to_flags: Unhandled flag on counter pin: 0x%02x\n", other_settings); 871.1Sbrad } 881.1Sbrad 891.1Sbrad return r; 901.1Sbrad} 911.1Sbrad 921.1Sbradstatic uint32_t 931.1Sbradmcp2210_sram_gpio_to_flags(uint8_t *gp_settings, int pin) 941.1Sbrad{ 951.1Sbrad uint32_t r = 0; 961.1Sbrad 971.1Sbrad switch (gp_settings[pin]) { 981.1Sbrad case MCP2210_PIN_IS_ALT0: 991.1Sbrad r |= GPIO_PIN_ALT0; 1001.1Sbrad break; 1011.1Sbrad case MCP2210_PIN_IS_DED: 1021.1Sbrad if (pin == 6) { 1031.1Sbrad r |= mcp2210_counter_gp_to_flags(gp_settings[11]); 1041.1Sbrad } else { 1051.1Sbrad r |= GPIO_PIN_ALT3; 1061.1Sbrad } 1071.1Sbrad break; 1081.1Sbrad case MCP2210_PIN_IS_GPIO: 1091.1Sbrad default: 1101.1Sbrad if (pin < 8) { 1111.1Sbrad if (gp_settings[9] & (1 << pin)) 1121.1Sbrad r |= GPIO_PIN_INPUT; 1131.1Sbrad else 1141.1Sbrad r |= GPIO_PIN_OUTPUT; 1151.1Sbrad } else { 1161.1Sbrad r |= GPIO_PIN_INPUT; 1171.1Sbrad } 1181.1Sbrad break; 1191.1Sbrad } 1201.1Sbrad 1211.1Sbrad return r; 1221.1Sbrad} 1231.1Sbrad 1241.1Sbradstatic uint32_t 1251.1Sbradmcp2221_sram_gpio_to_flags(uint8_t gp_setting) 1261.1Sbrad{ 1271.1Sbrad uint32_t r = 0; 1281.1Sbrad 1291.1Sbrad switch (gp_setting & MCP2221_SRAM_PIN_TYPE_MASK) { 1301.1Sbrad case MCP2221_SRAM_PIN_IS_DED: 1311.1Sbrad r |= GPIO_PIN_ALT3; 1321.1Sbrad break; 1331.1Sbrad case MCP2221_SRAM_PIN_IS_ALT0: 1341.1Sbrad r |= GPIO_PIN_ALT0; 1351.1Sbrad break; 1361.1Sbrad case MCP2221_SRAM_PIN_IS_ALT1: 1371.1Sbrad r |= GPIO_PIN_ALT1; 1381.1Sbrad break; 1391.1Sbrad case MCP2221_SRAM_PIN_IS_ALT2: 1401.1Sbrad r |= GPIO_PIN_ALT2; 1411.1Sbrad break; 1421.1Sbrad case MCP2221_SRAM_PIN_IS_GPIO: 1431.1Sbrad default: 1441.1Sbrad if ((gp_setting & MCP2221_SRAM_GPIO_TYPE_MASK) == 1451.1Sbrad MCP2221_SRAM_GPIO_INPUT) 1461.1Sbrad r |= GPIO_PIN_INPUT; 1471.1Sbrad else 1481.1Sbrad r |= GPIO_PIN_OUTPUT; 1491.1Sbrad break; 1501.1Sbrad } 1511.1Sbrad 1521.1Sbrad return r; 1531.1Sbrad} 1541.1Sbrad 1551.1Sbradstatic void 1561.1Sbradmcp2221_set_gpio_dir_sram(struct mcp2221_set_sram_req *req, int pin, int flags) 1571.1Sbrad{ 1581.1Sbrad uint8_t *alter = NULL; 1591.1Sbrad uint8_t *newvalue = NULL; 1601.1Sbrad 1611.1Sbrad if (pin >= 0 && pin < MCP2221_NPINS) { 1621.1Sbrad switch (pin) { 1631.1Sbrad case 0: 1641.1Sbrad alter = &req->alter_gpio_config; 1651.1Sbrad newvalue = &req->gp0_settings; 1661.1Sbrad break; 1671.1Sbrad case 1: 1681.1Sbrad alter = &req->alter_gpio_config; 1691.1Sbrad newvalue = &req->gp1_settings; 1701.1Sbrad break; 1711.1Sbrad case 2: 1721.1Sbrad alter = &req->alter_gpio_config; 1731.1Sbrad newvalue = &req->gp2_settings; 1741.1Sbrad break; 1751.1Sbrad case 3: 1761.1Sbrad alter = &req->alter_gpio_config; 1771.1Sbrad newvalue = &req->gp3_settings; 1781.1Sbrad break; 1791.1Sbrad default: 1801.1Sbrad break; 1811.1Sbrad } 1821.1Sbrad 1831.1Sbrad if (alter != NULL) { 1841.1Sbrad *alter = MCP2221_SRAM_ALTER_GPIO; 1851.1Sbrad if (flags & GPIO_PIN_INPUT) 1861.1Sbrad *newvalue |= MCP2221_SRAM_GPIO_INPUT; 1871.1Sbrad else 1881.1Sbrad *newvalue &= ~MCP2221_SRAM_GPIO_INPUT; 1891.1Sbrad } 1901.1Sbrad } 1911.1Sbrad} 1921.1Sbrad 1931.1Sbradstatic int 1941.1Sbradmcp2210_get_gpio_sram(struct umcpmio_softc *sc, 1951.1Sbrad struct mcp2210_get_gpio_sram_res *res) 1961.1Sbrad{ 1971.1Sbrad struct mcp2210_get_gpio_sram_req req; 1981.1Sbrad int err = 0; 1991.1Sbrad 2001.1Sbrad memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 2011.1Sbrad req.cmd = MCP2210_CMD_GET_GPIO_SRAM; 2021.1Sbrad 2031.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 2041.1Sbrad 2051.1Sbrad err = umcpmio_send_report(sc, 2061.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 2071.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 2081.1Sbrad 2091.1Sbrad err = mcp2210_decode_errors(req.cmd, err, res->completion); 2101.1Sbrad 2111.1Sbrad return err; 2121.1Sbrad} 2131.1Sbrad 2141.1Sbradstatic int 2151.1Sbradmcp2210_set_gpio_sram(struct umcpmio_softc *sc, 2161.1Sbrad struct mcp2210_set_gpio_sram_req *req, struct mcp2210_set_gpio_sram_res *res) 2171.1Sbrad{ 2181.1Sbrad int err = 0; 2191.1Sbrad 2201.1Sbrad req->cmd = MCP2210_CMD_SET_GPIO_SRAM; 2211.1Sbrad 2221.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 2231.1Sbrad 2241.1Sbrad err = umcpmio_send_report(sc, 2251.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 2261.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 2271.1Sbrad 2281.1Sbrad err = mcp2210_decode_errors(req->cmd, err, res->completion); 2291.1Sbrad 2301.1Sbrad return err; 2311.1Sbrad} 2321.1Sbrad 2331.1Sbradstatic int 2341.1Sbradmcp2210_get_gpio_dir_sram(struct umcpmio_softc *sc, 2351.1Sbrad struct mcp2210_get_gpio_dir_res *res) 2361.1Sbrad{ 2371.1Sbrad struct mcp2210_get_gpio_dir_req req; 2381.1Sbrad int err = 0; 2391.1Sbrad 2401.1Sbrad memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 2411.1Sbrad req.cmd = MCP2210_CMD_GET_GPIO_DIR_SRAM; 2421.1Sbrad 2431.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 2441.1Sbrad 2451.1Sbrad err = umcpmio_send_report(sc, 2461.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 2471.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 2481.1Sbrad 2491.1Sbrad err = mcp2210_decode_errors(req.cmd, err, res->completion); 2501.1Sbrad 2511.1Sbrad return err; 2521.1Sbrad} 2531.1Sbrad 2541.1Sbradstatic int 2551.1Sbradmcp2210_get_gpio_value_sram(struct umcpmio_softc *sc, 2561.1Sbrad struct mcp2210_get_gpio_value_res *res) 2571.1Sbrad{ 2581.1Sbrad struct mcp2210_get_gpio_value_req req; 2591.1Sbrad int err = 0; 2601.1Sbrad 2611.1Sbrad memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 2621.1Sbrad req.cmd = MCP2210_CMD_GET_GPIO_VAL_SRAM; 2631.1Sbrad 2641.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 2651.1Sbrad 2661.1Sbrad err = umcpmio_send_report(sc, 2671.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 2681.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 2691.1Sbrad 2701.1Sbrad err = mcp2210_decode_errors(req.cmd, err, res->completion); 2711.1Sbrad 2721.1Sbrad return err; 2731.1Sbrad} 2741.1Sbrad 2751.1Sbradstatic int 2761.1Sbradmcp2210_set_gpio_dir_sram(struct umcpmio_softc *sc, 2771.1Sbrad struct mcp2210_set_gpio_dir_req *req, struct mcp2210_set_gpio_dir_res *res) 2781.1Sbrad{ 2791.1Sbrad int err = 0; 2801.1Sbrad 2811.1Sbrad req->cmd = MCP2210_CMD_SET_GPIO_DIR_SRAM; 2821.1Sbrad 2831.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 2841.1Sbrad 2851.1Sbrad err = umcpmio_send_report(sc, 2861.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 2871.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 2881.1Sbrad 2891.1Sbrad err = mcp2210_decode_errors(req->cmd, err, res->completion); 2901.1Sbrad 2911.1Sbrad return err; 2921.1Sbrad} 2931.1Sbrad 2941.1Sbradstatic int 2951.1Sbradmcp2210_set_gpio_value_sram(struct umcpmio_softc *sc, 2961.1Sbrad struct mcp2210_set_gpio_value_req *req, struct mcp2210_set_gpio_value_res *res) 2971.1Sbrad{ 2981.1Sbrad int err = 0; 2991.1Sbrad 3001.1Sbrad req->cmd = MCP2210_CMD_SET_GPIO_VAL_SRAM; 3011.1Sbrad 3021.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 3031.1Sbrad 3041.1Sbrad err = umcpmio_send_report(sc, 3051.1Sbrad (uint8_t *) req, MCP2210_REQ_BUFFER_SIZE, 3061.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 3071.1Sbrad 3081.1Sbrad err = mcp2210_decode_errors(req->cmd, err, res->completion); 3091.1Sbrad 3101.1Sbrad return err; 3111.1Sbrad} 3121.1Sbrad 3131.1Sbradstatic void 3141.1Sbradmcp2221_set_gpio_designation_sram(struct mcp2221_set_sram_req *req, int pin, 3151.1Sbrad int flags) 3161.1Sbrad{ 3171.1Sbrad uint8_t *alter = NULL; 3181.1Sbrad uint8_t *newvalue = NULL; 3191.1Sbrad uint32_t altmask = 3201.1Sbrad GPIO_PIN_ALT0 | GPIO_PIN_ALT1 | GPIO_PIN_ALT2 | GPIO_PIN_ALT3; 3211.1Sbrad 3221.1Sbrad if (pin >= 0 && pin < MCP2221_NPINS) { 3231.1Sbrad switch (pin) { 3241.1Sbrad case 0: 3251.1Sbrad alter = &req->alter_gpio_config; 3261.1Sbrad newvalue = &req->gp0_settings; 3271.1Sbrad break; 3281.1Sbrad case 1: 3291.1Sbrad alter = &req->alter_gpio_config; 3301.1Sbrad newvalue = &req->gp1_settings; 3311.1Sbrad break; 3321.1Sbrad case 2: 3331.1Sbrad alter = &req->alter_gpio_config; 3341.1Sbrad newvalue = &req->gp2_settings; 3351.1Sbrad break; 3361.1Sbrad case 3: 3371.1Sbrad alter = &req->alter_gpio_config; 3381.1Sbrad newvalue = &req->gp3_settings; 3391.1Sbrad break; 3401.1Sbrad default: 3411.1Sbrad break; 3421.1Sbrad } 3431.1Sbrad 3441.1Sbrad if (alter != NULL) { 3451.1Sbrad int nv = *newvalue; 3461.1Sbrad 3471.1Sbrad *alter = MCP2221_SRAM_ALTER_GPIO; 3481.1Sbrad nv &= 0xF8; 3491.1Sbrad 3501.1Sbrad if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 3511.1Sbrad nv |= MCP2221_SRAM_PIN_IS_GPIO; 3521.1Sbrad } else { 3531.1Sbrad switch (flags & altmask) { 3541.1Sbrad case GPIO_PIN_ALT0: 3551.1Sbrad nv |= MCP2221_SRAM_PIN_IS_ALT0; 3561.1Sbrad break; 3571.1Sbrad case GPIO_PIN_ALT1: 3581.1Sbrad nv |= MCP2221_SRAM_PIN_IS_ALT1; 3591.1Sbrad break; 3601.1Sbrad case GPIO_PIN_ALT2: 3611.1Sbrad nv |= MCP2221_SRAM_PIN_IS_ALT2; 3621.1Sbrad break; 3631.1Sbrad /* ALT3 will always be used as the 3641.1Sbrad * dedicated function specific to the 3651.1Sbrad * pin. Not all of the pins will have 3661.1Sbrad * the alt functions below #3. */ 3671.1Sbrad case GPIO_PIN_ALT3: 3681.1Sbrad nv |= MCP2221_SRAM_PIN_IS_DED; 3691.1Sbrad break; 3701.1Sbrad default: 3711.1Sbrad break; 3721.1Sbrad } 3731.1Sbrad } 3741.1Sbrad *newvalue = nv; 3751.1Sbrad } 3761.1Sbrad } 3771.1Sbrad} 3781.1Sbrad/* 3791.1Sbrad * It is unfortunate that the GET and PUT requests are not symertric. That is, 3801.1Sbrad * the bits sort of line up but not quite between a GET and PUT. 3811.1Sbrad */ 3821.1Sbrad 3831.1Sbradstatic struct umcpmio_mapping_put mcp2221_vref_puts[] = { 3841.1Sbrad { 3851.1Sbrad .tname = "4.096V", 3861.1Sbrad .mask = 0x06 | 0x01, 3871.1Sbrad }, 3881.1Sbrad { 3891.1Sbrad .tname = "2.048V", 3901.1Sbrad .mask = 0x04 | 0x01, 3911.1Sbrad }, 3921.1Sbrad { 3931.1Sbrad .tname = "1.024V", 3941.1Sbrad .mask = 0x02 | 0x01, 3951.1Sbrad }, 3961.1Sbrad { 3971.1Sbrad .tname = "OFF", 3981.1Sbrad .mask = 0x00 | 0x01, 3991.1Sbrad }, 4001.1Sbrad { 4011.1Sbrad .tname = "VDD", 4021.1Sbrad .mask = 0x00, 4031.1Sbrad } 4041.1Sbrad}; 4051.1Sbrad 4061.1Sbradvoid 4071.1Sbradmcp2221_set_dac_vref(struct mcp2221_set_sram_req *req, char *newvref) 4081.1Sbrad{ 4091.1Sbrad int i; 4101.1Sbrad 4111.1Sbrad for (i = 0; i < __arraycount(mcp2221_vref_puts); i++) { 4121.1Sbrad if (strncmp(newvref, mcp2221_vref_puts[i].tname, 4131.1Sbrad MCP2221_VREF_NAME) == 0) { 4141.1Sbrad break; 4151.1Sbrad } 4161.1Sbrad } 4171.1Sbrad 4181.1Sbrad if (i == __arraycount(mcp2221_vref_puts)) 4191.1Sbrad return; 4201.1Sbrad 4211.1Sbrad req->dac_voltage_reference |= mcp2221_vref_puts[i].mask | 4221.1Sbrad MCP2221_SRAM_CHANGE_DAC_VREF; 4231.1Sbrad} 4241.1Sbrad 4251.1Sbradint 4261.1Sbradmcp2221_set_dac_vref_one(struct umcpmio_softc *sc, char *newvref) 4271.1Sbrad{ 4281.1Sbrad struct mcp2221_set_sram_req req; 4291.1Sbrad struct mcp2221_set_sram_res res; 4301.1Sbrad int err = 0; 4311.1Sbrad 4321.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 4331.1Sbrad 4341.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 4351.1Sbrad mcp2221_set_dac_vref(&req, newvref); 4361.1Sbrad err = mcp2221_put_sram(sc, &req, &res); 4371.1Sbrad 4381.1Sbrad return err; 4391.1Sbrad} 4401.1Sbrad 4411.1Sbradvoid 4421.1Sbradmcp2221_set_dac_value(struct mcp2221_set_sram_req *req, uint8_t newvalue) 4431.1Sbrad{ 4441.1Sbrad req->set_dac_output_value |= (newvalue & MCP2221_SRAM_DAC_VALUE_MASK) | 4451.1Sbrad MCP2221_SRAM_CHANGE_DAC_VREF; 4461.1Sbrad} 4471.1Sbrad 4481.1Sbradint 4491.1Sbradmcp2221_set_dac_value_one(struct umcpmio_softc *sc, uint8_t newvalue) 4501.1Sbrad{ 4511.1Sbrad struct mcp2221_set_sram_req req; 4521.1Sbrad struct mcp2221_set_sram_res res; 4531.1Sbrad int err = 0; 4541.1Sbrad 4551.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 4561.1Sbrad 4571.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 4581.1Sbrad mcp2221_set_dac_value(&req, newvalue); 4591.1Sbrad err = mcp2221_put_sram(sc, &req, &res); 4601.1Sbrad 4611.1Sbrad return err; 4621.1Sbrad} 4631.1Sbrad 4641.1Sbradvoid 4651.1Sbradmcp2221_set_adc_vref(struct mcp2221_set_sram_req *req, char *newvref) 4661.1Sbrad{ 4671.1Sbrad int i; 4681.1Sbrad 4691.1Sbrad for (i = 0; i < __arraycount(mcp2221_vref_puts); i++) { 4701.1Sbrad if (strncmp(newvref, mcp2221_vref_puts[i].tname, 4711.1Sbrad MCP2221_VREF_NAME) == 0) { 4721.1Sbrad break; 4731.1Sbrad } 4741.1Sbrad } 4751.1Sbrad 4761.1Sbrad if (i == __arraycount(mcp2221_vref_puts)) 4771.1Sbrad return; 4781.1Sbrad 4791.1Sbrad req->adc_voltage_reference |= mcp2221_vref_puts[i].mask | 4801.1Sbrad MCP2221_SRAM_CHANGE_ADC_VREF; 4811.1Sbrad} 4821.1Sbrad 4831.1Sbradint 4841.1Sbradmcp2221_set_adc_vref_one(struct umcpmio_softc *sc, char *newvref) 4851.1Sbrad{ 4861.1Sbrad struct mcp2221_set_sram_req req; 4871.1Sbrad struct mcp2221_set_sram_res res; 4881.1Sbrad int err = 0; 4891.1Sbrad 4901.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 4911.1Sbrad 4921.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 4931.1Sbrad mcp2221_set_adc_vref(&req, newvref); 4941.1Sbrad err = mcp2221_put_sram(sc, &req, &res); 4951.1Sbrad 4961.1Sbrad return err; 4971.1Sbrad} 4981.1Sbrad 4991.1Sbradstatic struct umcpmio_mapping_put mcp2221_dc_puts[] = { 5001.1Sbrad { 5011.1Sbrad .tname = "75%", 5021.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_DC_75, 5031.1Sbrad }, 5041.1Sbrad { 5051.1Sbrad .tname = "50%", 5061.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_DC_50, 5071.1Sbrad }, 5081.1Sbrad { 5091.1Sbrad .tname = "25%", 5101.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_DC_25, 5111.1Sbrad }, 5121.1Sbrad { 5131.1Sbrad .tname = "0%", 5141.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_DC_0, 5151.1Sbrad } 5161.1Sbrad}; 5171.1Sbrad 5181.1Sbradvoid 5191.1Sbradmcp2221_set_gpioclock_dc(struct mcp2221_set_sram_req *req, char *new_dc) 5201.1Sbrad{ 5211.1Sbrad int i; 5221.1Sbrad 5231.1Sbrad for (i = 0; i < __arraycount(mcp2221_dc_puts); i++) { 5241.1Sbrad if (strncmp(new_dc, mcp2221_dc_puts[i].tname, 5251.1Sbrad MCP2221_DC_NAME) == 0) { 5261.1Sbrad break; 5271.1Sbrad } 5281.1Sbrad } 5291.1Sbrad 5301.1Sbrad if (i == __arraycount(mcp2221_dc_puts)) 5311.1Sbrad return; 5321.1Sbrad 5331.1Sbrad req->clock_output_divider |= mcp2221_dc_puts[i].mask; 5341.1Sbrad} 5351.1Sbrad 5361.1Sbradint 5371.1Sbradmcp2221_set_gpioclock_dc_one(struct umcpmio_softc *sc, char *new_dutycycle) 5381.1Sbrad{ 5391.1Sbrad struct mcp2221_get_sram_res current_sram_res; 5401.1Sbrad struct mcp2221_set_sram_req req; 5411.1Sbrad struct mcp2221_set_sram_res res; 5421.1Sbrad int err = 0; 5431.1Sbrad 5441.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 5451.1Sbrad 5461.1Sbrad err = mcp2221_get_sram(sc, ¤t_sram_res); 5471.1Sbrad if (err) 5481.1Sbrad goto out; 5491.1Sbrad 5501.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 5511.1Sbrad mcp2221_set_gpioclock_dc(&req, new_dutycycle); 5521.1Sbrad DPRINTF(("mcp2221_set_gpioclock_dc_one:" 5531.1Sbrad " req.clock_output_divider=%02x, current mask=%02x\n", 5541.1Sbrad req.clock_output_divider, 5551.1Sbrad (current_sram_res.clock_divider & 5561.1Sbrad MCP2221_SRAM_GPIO_CLOCK_CD_MASK))); 5571.1Sbrad req.clock_output_divider |= 5581.1Sbrad (current_sram_res.clock_divider & 5591.1Sbrad MCP2221_SRAM_GPIO_CLOCK_CD_MASK) | 5601.1Sbrad MCP2221_SRAM_GPIO_CHANGE_DCCD; 5611.1Sbrad DPRINTF(("mcp2221_set_gpioclock_dc_one:" 5621.1Sbrad " SET req.clock_output_divider=%02x\n", 5631.1Sbrad req.clock_output_divider)); 5641.1Sbrad err = mcp2221_put_sram(sc, &req, &res); 5651.1Sbradout: 5661.1Sbrad return err; 5671.1Sbrad} 5681.1Sbrad 5691.1Sbradstatic struct umcpmio_mapping_put mcp2221_cd_puts[] = { 5701.1Sbrad { 5711.1Sbrad .tname = "375kHz", 5721.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_375KHZ, 5731.1Sbrad }, 5741.1Sbrad { 5751.1Sbrad .tname = "750kHz", 5761.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_750KHZ, 5771.1Sbrad }, 5781.1Sbrad { 5791.1Sbrad .tname = "1.5MHz", 5801.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_1P5MHZ, 5811.1Sbrad }, 5821.1Sbrad { 5831.1Sbrad .tname = "3MHz", 5841.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_3MHZ, 5851.1Sbrad }, 5861.1Sbrad { 5871.1Sbrad .tname = "6MHz", 5881.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_6MHZ, 5891.1Sbrad }, 5901.1Sbrad { 5911.1Sbrad .tname = "12MHz", 5921.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_12MHZ, 5931.1Sbrad }, 5941.1Sbrad { 5951.1Sbrad .tname = "24MHz", 5961.1Sbrad .mask = MCP2221_SRAM_GPIO_CLOCK_CD_24MHZ, 5971.1Sbrad } 5981.1Sbrad}; 5991.1Sbrad 6001.1Sbradvoid 6011.1Sbradmcp2221_set_gpioclock_cd(struct mcp2221_set_sram_req *req, char *new_cd) 6021.1Sbrad{ 6031.1Sbrad int i; 6041.1Sbrad 6051.1Sbrad for (i = 0; i < __arraycount(mcp2221_cd_puts); i++) { 6061.1Sbrad if (strncmp(new_cd, mcp2221_cd_puts[i].tname, 6071.1Sbrad MCP2221_CD_NAME) == 0) { 6081.1Sbrad break; 6091.1Sbrad } 6101.1Sbrad } 6111.1Sbrad 6121.1Sbrad if (i == __arraycount(mcp2221_cd_puts)) 6131.1Sbrad return; 6141.1Sbrad 6151.1Sbrad req->clock_output_divider |= mcp2221_cd_puts[i].mask; 6161.1Sbrad} 6171.1Sbrad 6181.1Sbradint 6191.1Sbradmcp2221_set_gpioclock_cd_one(struct umcpmio_softc *sc, char *new_clockdivider) 6201.1Sbrad{ 6211.1Sbrad struct mcp2221_get_sram_res current_sram_res; 6221.1Sbrad struct mcp2221_set_sram_req req; 6231.1Sbrad struct mcp2221_set_sram_res res; 6241.1Sbrad int err = 0; 6251.1Sbrad 6261.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 6271.1Sbrad 6281.1Sbrad err = mcp2221_get_sram(sc, ¤t_sram_res); 6291.1Sbrad if (err) 6301.1Sbrad goto out; 6311.1Sbrad 6321.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 6331.1Sbrad mcp2221_set_gpioclock_cd(&req, new_clockdivider); 6341.1Sbrad DPRINTF(("mcp2221_set_gpioclock_cd_one:" 6351.1Sbrad " req.clock_output_divider=%02x, current mask=%02x\n", 6361.1Sbrad req.clock_output_divider, 6371.1Sbrad (current_sram_res.clock_divider & 6381.1Sbrad MCP2221_SRAM_GPIO_CLOCK_CD_MASK))); 6391.1Sbrad req.clock_output_divider |= 6401.1Sbrad (current_sram_res.clock_divider & 6411.1Sbrad MCP2221_SRAM_GPIO_CLOCK_DC_MASK) | 6421.1Sbrad MCP2221_SRAM_GPIO_CHANGE_DCCD; 6431.1Sbrad DPRINTF(("mcp2221_set_gpioclock_cd_one:" 6441.1Sbrad " SET req.clock_output_divider=%02x\n", 6451.1Sbrad req.clock_output_divider)); 6461.1Sbrad err = mcp2221_put_sram(sc, &req, &res); 6471.1Sbradout: 6481.1Sbrad return err; 6491.1Sbrad} 6501.1Sbrad 6511.1Sbradint 6521.1Sbradmcp2221_get_gpio_cfg(struct umcpmio_softc *sc, 6531.1Sbrad struct mcp2221_get_gpio_cfg_res *res) 6541.1Sbrad{ 6551.1Sbrad struct mcp2221_get_gpio_cfg_req req; 6561.1Sbrad int err = 0; 6571.1Sbrad 6581.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 6591.1Sbrad req.cmd = MCP2221_CMD_GET_GPIO_CFG; 6601.1Sbrad 6611.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 6621.1Sbrad 6631.1Sbrad err = umcpmio_send_report(sc, 6641.1Sbrad (uint8_t *) & req, MCP2221_REQ_BUFFER_SIZE, 6651.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 6661.1Sbrad 6671.1Sbrad return err; 6681.1Sbrad} 6691.1Sbrad 6701.1Sbradstatic int 6711.1Sbradmcp2221_put_gpio_cfg(struct umcpmio_softc *sc, 6721.1Sbrad struct mcp2221_set_gpio_cfg_req *req, struct mcp2221_set_gpio_cfg_res *res) 6731.1Sbrad{ 6741.1Sbrad int err = 0; 6751.1Sbrad 6761.1Sbrad req->cmd = MCP2221_CMD_SET_GPIO_CFG; 6771.1Sbrad 6781.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 6791.1Sbrad 6801.1Sbrad err = umcpmio_send_report(sc, 6811.1Sbrad (uint8_t *) req, MCP2221_REQ_BUFFER_SIZE, 6821.1Sbrad (uint8_t *) res, sc->sc_cv_wait); 6831.1Sbrad 6841.1Sbrad return err; 6851.1Sbrad} 6861.1Sbrad 6871.1Sbradstatic int 6881.1Sbradmcp2210_get_gpio_value(struct umcpmio_softc *sc, 6891.1Sbrad int pin) 6901.1Sbrad{ 6911.1Sbrad struct mcp2210_get_gpio_value_res res; 6921.1Sbrad uint16_t v; 6931.1Sbrad int err = 0; 6941.1Sbrad int r = GPIO_PIN_LOW; 6951.1Sbrad 6961.1Sbrad 6971.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 6981.1Sbrad 6991.1Sbrad err = mcp2210_get_gpio_value_sram(sc, &res); 7001.1Sbrad 7011.1Sbrad if (!err) { 7021.1Sbrad v = (res.pin_value_msb << 8) | res.pin_value_lsb; 7031.1Sbrad if (v & (1 << pin)) 7041.1Sbrad r = GPIO_PIN_HIGH; 7051.1Sbrad } 7061.1Sbrad return r; 7071.1Sbrad} 7081.1Sbrad/* So... if the pin isn't set to GPIO, just call the output LOW */ 7091.1Sbrad 7101.1Sbradstatic int 7111.1Sbradmcp2221_get_gpio_value(struct umcpmio_softc *sc, 7121.1Sbrad int pin) 7131.1Sbrad{ 7141.1Sbrad struct mcp2221_get_gpio_cfg_res get_gpio_cfg_res; 7151.1Sbrad int err = 0; 7161.1Sbrad int r = GPIO_PIN_LOW; 7171.1Sbrad 7181.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 7191.1Sbrad 7201.1Sbrad err = mcp2221_get_gpio_cfg(sc, &get_gpio_cfg_res); 7211.1Sbrad if (err) 7221.1Sbrad goto out; 7231.1Sbrad 7241.1Sbrad if (get_gpio_cfg_res.cmd != MCP2221_CMD_GET_GPIO_CFG || 7251.1Sbrad get_gpio_cfg_res.completion != MCP2221_CMD_COMPLETE_OK) { 7261.1Sbrad device_printf(sc->sc_dev, "mcp2221_get_gpio_value:" 7271.1Sbrad " wrong command or error: %02x %02x\n", 7281.1Sbrad get_gpio_cfg_res.cmd, 7291.1Sbrad get_gpio_cfg_res.completion); 7301.1Sbrad goto out; 7311.1Sbrad } 7321.1Sbrad switch (pin) { 7331.1Sbrad case 0: 7341.1Sbrad if (get_gpio_cfg_res.gp0_pin_value != 7351.1Sbrad MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 7361.1Sbrad if (get_gpio_cfg_res.gp0_pin_value == 0x01) 7371.1Sbrad r = GPIO_PIN_HIGH; 7381.1Sbrad break; 7391.1Sbrad case 1: 7401.1Sbrad if (get_gpio_cfg_res.gp1_pin_value != 7411.1Sbrad MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 7421.1Sbrad if (get_gpio_cfg_res.gp1_pin_value == 0x01) 7431.1Sbrad r = GPIO_PIN_HIGH; 7441.1Sbrad break; 7451.1Sbrad case 2: 7461.1Sbrad if (get_gpio_cfg_res.gp2_pin_value != 7471.1Sbrad MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 7481.1Sbrad if (get_gpio_cfg_res.gp2_pin_value == 0x01) 7491.1Sbrad r = GPIO_PIN_HIGH; 7501.1Sbrad break; 7511.1Sbrad case 3: 7521.1Sbrad if (get_gpio_cfg_res.gp3_pin_value != 7531.1Sbrad MCP2221_GPIO_CFG_VALUE_NOT_GPIO) 7541.1Sbrad if (get_gpio_cfg_res.gp3_pin_value == 0x01) 7551.1Sbrad r = GPIO_PIN_HIGH; 7561.1Sbrad break; 7571.1Sbrad default: 7581.1Sbrad break; 7591.1Sbrad } 7601.1Sbradout: 7611.1Sbrad return r; 7621.1Sbrad} 7631.1Sbrad 7641.1Sbradstatic int 7651.1Sbradmcp2210_set_gpio_value(struct umcpmio_softc *sc, 7661.1Sbrad int pin, bool value) 7671.1Sbrad{ 7681.1Sbrad int err = 0; 7691.1Sbrad struct mcp2210_get_gpio_value_res get_res; 7701.1Sbrad struct mcp2210_set_gpio_value_req set_req; 7711.1Sbrad struct mcp2210_set_gpio_value_res set_res; 7721.1Sbrad uint16_t v; 7731.1Sbrad 7741.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 7751.1Sbrad 7761.1Sbrad err = mcp2210_get_gpio_value_sram(sc, &get_res); 7771.1Sbrad if (!err && get_res.completion != MCP2210_CMD_COMPLETE_OK) 7781.1Sbrad err = EIO; 7791.1Sbrad 7801.1Sbrad if (!err) { 7811.1Sbrad v = (get_res.pin_value_msb << 8) | get_res.pin_value_lsb; 7821.1Sbrad 7831.1Sbrad if (value) 7841.1Sbrad v |= (1 << pin); 7851.1Sbrad else 7861.1Sbrad v &= ~(1 << pin); 7871.1Sbrad 7881.1Sbrad set_req.pin_value_lsb = v & 0x00ff; 7891.1Sbrad set_req.pin_value_msb = (v & 0xff00) >> 8; 7901.1Sbrad 7911.1Sbrad err = mcp2210_set_gpio_value_sram(sc, &set_req, &set_res); 7921.1Sbrad } 7931.1Sbrad return err; 7941.1Sbrad} 7951.1Sbrad 7961.1Sbradstatic void 7971.1Sbradmcp2221_set_gpio_value(struct mcp2221_set_gpio_cfg_req *req, 7981.1Sbrad int pin, bool value) 7991.1Sbrad{ 8001.1Sbrad uint8_t *alter = NULL; 8011.1Sbrad uint8_t *newvalue = NULL; 8021.1Sbrad 8031.1Sbrad if (pin < 0 || pin >= MCP2221_NPINS) 8041.1Sbrad return; 8051.1Sbrad 8061.1Sbrad switch (pin) { 8071.1Sbrad case 0: 8081.1Sbrad alter = &req->alter_gp0_value; 8091.1Sbrad newvalue = &req->new_gp0_value; 8101.1Sbrad break; 8111.1Sbrad case 1: 8121.1Sbrad alter = &req->alter_gp1_value; 8131.1Sbrad newvalue = &req->new_gp1_value; 8141.1Sbrad break; 8151.1Sbrad case 2: 8161.1Sbrad alter = &req->alter_gp2_value; 8171.1Sbrad newvalue = &req->new_gp2_value; 8181.1Sbrad break; 8191.1Sbrad case 3: 8201.1Sbrad alter = &req->alter_gp3_value; 8211.1Sbrad newvalue = &req->new_gp3_value; 8221.1Sbrad break; 8231.1Sbrad default: 8241.1Sbrad return; 8251.1Sbrad } 8261.1Sbrad 8271.1Sbrad *alter = MCP2221_GPIO_CFG_ALTER; 8281.1Sbrad *newvalue = 0; 8291.1Sbrad if (value) 8301.1Sbrad *newvalue = 1; 8311.1Sbrad} 8321.1Sbrad 8331.1Sbradstatic int 8341.1Sbradmcp2221_set_gpio_value_one(struct umcpmio_softc *sc, 8351.1Sbrad int pin, bool value) 8361.1Sbrad{ 8371.1Sbrad int err = 0; 8381.1Sbrad struct mcp2221_set_gpio_cfg_req req; 8391.1Sbrad struct mcp2221_set_gpio_cfg_res res; 8401.1Sbrad 8411.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 8421.1Sbrad 8431.1Sbrad memset(&req, 0, MCP2221_REQ_BUFFER_SIZE); 8441.1Sbrad mcp2221_set_gpio_value(&req, pin, value); 8451.1Sbrad err = mcp2221_put_gpio_cfg(sc, &req, &res); 8461.1Sbrad if (err) 8471.1Sbrad goto out; 8481.1Sbrad if (res.cmd != MCP2221_CMD_SET_GPIO_CFG || 8491.1Sbrad res.completion != MCP2221_CMD_COMPLETE_OK) { 8501.1Sbrad err = EIO; 8511.1Sbrad device_printf(sc->sc_dev, "umcpmio_gpio_pin_write:" 8521.1Sbrad " not the command desired, or error: %02x %02x\n", 8531.1Sbrad res.cmd, 8541.1Sbrad res.completion); 8551.1Sbrad } 8561.1Sbradout: 8571.1Sbrad return err; 8581.1Sbrad} 8591.1Sbrad 8601.1Sbrad/* These are standard gpio reads and set calls */ 8611.1Sbrad 8621.1Sbradstatic int 8631.1Sbradumcpmio_gpio_pin_read(void *arg, int pin) 8641.1Sbrad{ 8651.1Sbrad struct umcpmio_softc *sc = arg; 8661.1Sbrad int r = GPIO_PIN_LOW; 8671.1Sbrad 8681.1Sbrad mutex_enter(&sc->sc_action_mutex); 8691.1Sbrad 8701.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) 8711.1Sbrad r = mcp2210_get_gpio_value(sc, pin); 8721.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) 8731.1Sbrad r = mcp2221_get_gpio_value(sc, pin); 8741.1Sbrad 8751.1Sbrad mutex_exit(&sc->sc_action_mutex); 8761.1Sbrad 8771.1Sbrad return r; 8781.1Sbrad} 8791.1Sbrad 8801.1Sbradstatic void 8811.1Sbradumcpmio_gpio_pin_write(void *arg, int pin, int value) 8821.1Sbrad{ 8831.1Sbrad struct umcpmio_softc *sc = arg; 8841.1Sbrad 8851.1Sbrad mutex_enter(&sc->sc_action_mutex); 8861.1Sbrad 8871.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) 8881.1Sbrad mcp2210_set_gpio_value(sc, pin, value); 8891.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) 8901.1Sbrad mcp2221_set_gpio_value_one(sc, pin, value); 8911.1Sbrad 8921.1Sbrad mutex_exit(&sc->sc_action_mutex); 8931.1Sbrad} 8941.1Sbrad 8951.1Sbradstatic int 8961.1Sbradmcp2210_gpio_pin_ctl(void *arg, int pin, int flags) 8971.1Sbrad{ 8981.1Sbrad struct umcpmio_softc *sc = arg; 8991.1Sbrad struct mcp2210_set_gpio_sram_req mcp2210_set_gpio_sram_req; 9001.1Sbrad struct mcp2210_set_gpio_dir_req mcp2210_set_gpio_dir_sram_req; 9011.1Sbrad struct mcp2210_set_gpio_sram_res mcp2210_set_gpio_sram_res; 9021.1Sbrad struct mcp2210_set_gpio_dir_res mcp2210_set_gpio_dir_sram_res; 9031.1Sbrad struct mcp2210_set_gpio_value_req mcp2210_set_gpio_value_sram_req; 9041.1Sbrad struct mcp2210_set_gpio_value_res mcp2210_set_gpio_value_sram_res; 9051.1Sbrad 9061.1Sbrad struct mcp2210_get_gpio_sram_res mcp2210_get_gpio_sram_res; 9071.1Sbrad struct mcp2210_get_gpio_dir_res mcp2210_get_gpio_dir_sram_res; 9081.1Sbrad struct mcp2210_get_gpio_value_res mcp2210_get_gpio_value_sram_res; 9091.1Sbrad 9101.1Sbrad uint32_t altmask = 9111.1Sbrad GPIO_PIN_ALT0 | GPIO_PIN_ALT3 | GPIO_PIN_ALT4 | GPIO_PIN_ALT5 | GPIO_PIN_ALT6; 9121.1Sbrad int err = 0; 9131.1Sbrad uint16_t vdir; 9141.1Sbrad 9151.1Sbrad if (sc->sc_dying) 9161.1Sbrad return 0; 9171.1Sbrad 9181.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 9191.1Sbrad 9201.1Sbrad err = mcp2210_get_gpio_sram(sc, &mcp2210_get_gpio_sram_res); 9211.1Sbrad if (err) 9221.1Sbrad goto out; 9231.1Sbrad err = mcp2210_get_gpio_dir_sram(sc, &mcp2210_get_gpio_dir_sram_res); 9241.1Sbrad if (err) 9251.1Sbrad goto out; 9261.1Sbrad err = mcp2210_get_gpio_value_sram(sc, &mcp2210_get_gpio_value_sram_res); 9271.1Sbrad if (err) 9281.1Sbrad goto out; 9291.1Sbrad 9301.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 9311.1Sbrad (uint8_t *) & mcp2210_get_gpio_sram_res, MCP2210_RES_BUFFER_SIZE, 9321.1Sbrad "mcp2210_gpio_pin_ctl get gpio sram res"); 9331.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 9341.1Sbrad (uint8_t *) & mcp2210_get_gpio_dir_sram_res, MCP2210_RES_BUFFER_SIZE, 9351.1Sbrad "mcp2210_gpio_pin_ctl get gpio dir sram res"); 9361.1Sbrad 9371.1Sbrad memset(&mcp2210_set_gpio_sram_req.cmd, 0, MCP2210_REQ_BUFFER_SIZE); 9381.1Sbrad memcpy(&mcp2210_set_gpio_sram_req.gp0_designation, 9391.1Sbrad &mcp2210_get_gpio_sram_res.gp0_designation, 9401.1Sbrad &mcp2210_get_gpio_sram_res.nvram_protection - 9411.1Sbrad &mcp2210_get_gpio_sram_res.gp0_designation + 1); 9421.1Sbrad 9431.1Sbrad memset(&mcp2210_set_gpio_dir_sram_req.cmd, 0, MCP2210_REQ_BUFFER_SIZE); 9441.1Sbrad vdir = (mcp2210_get_gpio_dir_sram_res.pin_dir_msb << 8) | 9451.1Sbrad mcp2210_get_gpio_dir_sram_res.pin_dir_lsb; 9461.1Sbrad 9471.1Sbrad uint8_t *b = (uint8_t *) & mcp2210_set_gpio_sram_req.cmd; 9481.1Sbrad bool changed_sram = false; 9491.1Sbrad 9501.1Sbrad if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 9511.1Sbrad if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_GPIO) { 9521.1Sbrad b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_GPIO; 9531.1Sbrad changed_sram = true; 9541.1Sbrad } 9551.1Sbrad if (flags & GPIO_PIN_INPUT) 9561.1Sbrad vdir |= (1 << pin); 9571.1Sbrad else 9581.1Sbrad vdir &= ~(1 << pin); 9591.1Sbrad } else { 9601.1Sbrad switch (flags & altmask) { 9611.1Sbrad case GPIO_PIN_ALT0: 9621.1Sbrad if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_ALT0) { 9631.1Sbrad b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_ALT0; 9641.1Sbrad changed_sram = true; 9651.1Sbrad } 9661.1Sbrad break; 9671.1Sbrad case GPIO_PIN_ALT3: 9681.1Sbrad if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 9691.1Sbrad b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 9701.1Sbrad changed_sram = true; 9711.1Sbrad } 9721.1Sbrad if (pin == 6) { 9731.1Sbrad if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT3) { 9741.1Sbrad mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 9751.1Sbrad mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_FALLING_EDGE << 1; 9761.1Sbrad changed_sram = true; 9771.1Sbrad } 9781.1Sbrad } 9791.1Sbrad break; 9801.1Sbrad case GPIO_PIN_ALT4: 9811.1Sbrad if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 9821.1Sbrad b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 9831.1Sbrad changed_sram = true; 9841.1Sbrad } 9851.1Sbrad if (pin == 6) { 9861.1Sbrad if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT4) { 9871.1Sbrad mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 9881.1Sbrad mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_RISING_EDGE << 1; 9891.1Sbrad changed_sram = true; 9901.1Sbrad } 9911.1Sbrad } 9921.1Sbrad break; 9931.1Sbrad case GPIO_PIN_ALT5: 9941.1Sbrad if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 9951.1Sbrad b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 9961.1Sbrad changed_sram = true; 9971.1Sbrad } 9981.1Sbrad if (pin == 6) { 9991.1Sbrad if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT5) { 10001.1Sbrad mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 10011.1Sbrad mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_LOW_PULSE << 1; 10021.1Sbrad changed_sram = true; 10031.1Sbrad } 10041.1Sbrad } 10051.1Sbrad break; 10061.1Sbrad case GPIO_PIN_ALT6: 10071.1Sbrad if (b[MCP2210_GPIO_SRAM_GP0 + pin] != MCP2210_PIN_IS_DED) { 10081.1Sbrad b[MCP2210_GPIO_SRAM_GP0 + pin] = MCP2210_PIN_IS_DED; 10091.1Sbrad changed_sram = true; 10101.1Sbrad } 10111.1Sbrad if (pin == 6) { 10121.1Sbrad if (mcp2210_counter_gp_to_flags(mcp2210_get_gpio_sram_res.other_settings) != GPIO_PIN_ALT6) { 10131.1Sbrad mcp2210_set_gpio_sram_req.other_settings &= 0xf1; 10141.1Sbrad mcp2210_set_gpio_sram_req.other_settings |= MCP2210_COUNTER_HIGH_PULSE << 1; 10151.1Sbrad changed_sram = true; 10161.1Sbrad } 10171.1Sbrad } 10181.1Sbrad break; 10191.1Sbrad default: 10201.1Sbrad break; 10211.1Sbrad } 10221.1Sbrad } 10231.1Sbrad 10241.1Sbrad /* On the MCP-2210, if you change the purpose of the pin you have to 10251.1Sbrad * write the current direction and value of the pins back to the chip. 10261.1Sbrad * The reason for this is tha you can not change just one pins purpose 10271.1Sbrad * without setting the direction and values of all pins to the default. */ 10281.1Sbrad 10291.1Sbrad if (changed_sram) { 10301.1Sbrad err = mcp2210_set_gpio_sram(sc, &mcp2210_set_gpio_sram_req, 10311.1Sbrad &mcp2210_set_gpio_sram_res); 10321.1Sbrad if (err) 10331.1Sbrad goto out; 10341.1Sbrad 10351.1Sbrad mcp2210_set_gpio_dir_sram_req.pin_dir_msb = (vdir >> 8) & 0xff; 10361.1Sbrad mcp2210_set_gpio_dir_sram_req.pin_dir_lsb = vdir & 0x00ff; 10371.1Sbrad 10381.1Sbrad err = mcp2210_set_gpio_dir_sram(sc, &mcp2210_set_gpio_dir_sram_req, 10391.1Sbrad &mcp2210_set_gpio_dir_sram_res); 10401.1Sbrad if (err) 10411.1Sbrad goto out; 10421.1Sbrad 10431.1Sbrad mcp2210_set_gpio_value_sram_req.pin_value_msb = mcp2210_get_gpio_value_sram_res.pin_value_msb; 10441.1Sbrad mcp2210_set_gpio_value_sram_req.pin_value_lsb = mcp2210_get_gpio_value_sram_res.pin_value_lsb; 10451.1Sbrad 10461.1Sbrad /* Further, if the pin is for OUTPUT, then we will want to set 10471.1Sbrad * its value to the default, otherwise the default may never be 10481.1Sbrad * reflected in the pin state, as the pin might have been a 10491.1Sbrad * INPUT with the opposite value and just putting all of the 10501.1Sbrad * values back in that case would do the wrong thing. */ 10511.1Sbrad 10521.1Sbrad if (flags & GPIO_PIN_OUTPUT && pin < 8) { 10531.1Sbrad if (mcp2210_set_gpio_sram_req.default_output_lsb & (1 << pin)) 10541.1Sbrad mcp2210_set_gpio_value_sram_req.pin_value_lsb |= (1 << pin); 10551.1Sbrad else 10561.1Sbrad mcp2210_set_gpio_value_sram_req.pin_value_lsb &= ~(1 << pin); 10571.1Sbrad } 10581.1Sbrad err = mcp2210_set_gpio_value_sram(sc, &mcp2210_set_gpio_value_sram_req, &mcp2210_set_gpio_value_sram_res); 10591.1Sbrad } else { 10601.1Sbrad /* In this case, the pin purpose was not changed, so all that 10611.1Sbrad * needs to happen is the direction needs to be updated. This 10621.1Sbrad * actually won't matter unless the pin is strickly a GPIO pin. 10631.1Sbrad * ALT0, the CS purpose, is handled by the chip itself, ALT3 - 10641.1Sbrad * ALT6 is for the event / interrupt counter. So, we really 10651.1Sbrad * only have to care if the pin switches from INPUT to OUTPUT, 10661.1Sbrad * or vise versa. */ 10671.1Sbrad if (flags & (GPIO_PIN_OUTPUT | GPIO_PIN_INPUT)) { 10681.1Sbrad mcp2210_set_gpio_dir_sram_req.pin_dir_msb = (vdir >> 8) & 0xff; 10691.1Sbrad mcp2210_set_gpio_dir_sram_req.pin_dir_lsb = vdir & 0x00ff; 10701.1Sbrad 10711.1Sbrad err = mcp2210_set_gpio_dir_sram(sc, &mcp2210_set_gpio_dir_sram_req, 10721.1Sbrad &mcp2210_set_gpio_dir_sram_res); 10731.1Sbrad } 10741.1Sbrad } 10751.1Sbradout: 10761.1Sbrad return err; 10771.1Sbrad} 10781.1Sbrad/* 10791.1Sbrad * Internal function that does the dirty work of setting a gpio 10801.1Sbrad * pin to its "type" for the MCP-2221 / MCP-2221A 10811.1Sbrad * 10821.1Sbrad * There are really two ways to do some of this, one is to set the pin 10831.1Sbrad * to input and output, or whatever, using SRAM calls, the other is to 10841.1Sbrad * use the GPIO config calls to set input and output and SRAM for 10851.1Sbrad * everything else. This just uses SRAM for everything. 10861.1Sbrad */ 10871.1Sbrad 10881.1Sbradint 10891.1Sbradmcp2221_gpio_pin_ctl(void *arg, int pin, int flags) 10901.1Sbrad{ 10911.1Sbrad struct umcpmio_softc *sc = arg; 10921.1Sbrad struct mcp2221_set_sram_req set_sram_req; 10931.1Sbrad struct mcp2221_set_sram_res set_sram_res; 10941.1Sbrad struct mcp2221_get_sram_res current_sram_res; 10951.1Sbrad struct mcp2221_get_gpio_cfg_res current_gpio_cfg_res; 10961.1Sbrad int err = 0; 10971.1Sbrad 10981.1Sbrad if (sc->sc_dying) 10991.1Sbrad return 0; 11001.1Sbrad 11011.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 11021.1Sbrad 11031.1Sbrad err = mcp2221_get_sram(sc, ¤t_sram_res); 11041.1Sbrad if (err) 11051.1Sbrad goto out; 11061.1Sbrad 11071.1Sbrad err = mcp2221_get_gpio_cfg(sc, ¤t_gpio_cfg_res); 11081.1Sbrad if (err) 11091.1Sbrad goto out; 11101.1Sbrad 11111.1Sbrad /* You can't just set one pin, you must set all of them, so copy the 11121.1Sbrad * current settings for the pin we are not messing with. 11131.1Sbrad * 11141.1Sbrad * And, yes, of course, if the MCP-2210 is ever supported with this 11151.1Sbrad * driver, this sort of unrolling will need to be turned into something 11161.1Sbrad * different, but for now, just unroll as there are only 4 pins to care 11171.1Sbrad * about. 11181.1Sbrad * 11191.1Sbrad * */ 11201.1Sbrad 11211.1Sbrad memset(&set_sram_req, 0, MCP2221_REQ_BUFFER_SIZE); 11221.1Sbrad switch (pin) { 11231.1Sbrad case 0: 11241.1Sbrad set_sram_req.gp1_settings = current_sram_res.gp1_settings; 11251.1Sbrad set_sram_req.gp2_settings = current_sram_res.gp2_settings; 11261.1Sbrad set_sram_req.gp3_settings = current_sram_res.gp3_settings; 11271.1Sbrad break; 11281.1Sbrad case 1: 11291.1Sbrad set_sram_req.gp0_settings = current_sram_res.gp0_settings; 11301.1Sbrad set_sram_req.gp2_settings = current_sram_res.gp2_settings; 11311.1Sbrad set_sram_req.gp3_settings = current_sram_res.gp3_settings; 11321.1Sbrad break; 11331.1Sbrad case 2: 11341.1Sbrad set_sram_req.gp0_settings = current_sram_res.gp0_settings; 11351.1Sbrad set_sram_req.gp1_settings = current_sram_res.gp1_settings; 11361.1Sbrad set_sram_req.gp3_settings = current_sram_res.gp3_settings; 11371.1Sbrad break; 11381.1Sbrad case 3: 11391.1Sbrad set_sram_req.gp0_settings = current_sram_res.gp0_settings; 11401.1Sbrad set_sram_req.gp1_settings = current_sram_res.gp1_settings; 11411.1Sbrad set_sram_req.gp2_settings = current_sram_res.gp2_settings; 11421.1Sbrad break; 11431.1Sbrad } 11441.1Sbrad mcp2221_set_gpio_designation_sram(&set_sram_req, pin, flags); 11451.1Sbrad mcp2221_set_gpio_dir_sram(&set_sram_req, pin, flags); 11461.1Sbrad 11471.1Sbrad /* This part is unfortunate... if a pin is set to output, the value 11481.1Sbrad * set on the pin is not mirrored by the chip into SRAM, but the chip 11491.1Sbrad * will use the value from SRAM to set the value of the pin. What this 11501.1Sbrad * means is that we have to learn the value from the GPIO config and 11511.1Sbrad * make sure it is set properly when updating SRAM. */ 11521.1Sbrad 11531.1Sbrad if (current_gpio_cfg_res.gp0_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 11541.1Sbrad if (current_gpio_cfg_res.gp0_pin_value == 1) { 11551.1Sbrad set_sram_req.gp0_settings |= 11561.1Sbrad MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11571.1Sbrad } else { 11581.1Sbrad set_sram_req.gp0_settings &= 11591.1Sbrad ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11601.1Sbrad } 11611.1Sbrad } 11621.1Sbrad if (current_gpio_cfg_res.gp1_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 11631.1Sbrad if (current_gpio_cfg_res.gp1_pin_value == 1) { 11641.1Sbrad set_sram_req.gp1_settings |= 11651.1Sbrad MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11661.1Sbrad } else { 11671.1Sbrad set_sram_req.gp1_settings &= 11681.1Sbrad ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11691.1Sbrad } 11701.1Sbrad } 11711.1Sbrad if (current_gpio_cfg_res.gp2_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 11721.1Sbrad if (current_gpio_cfg_res.gp2_pin_value == 1) { 11731.1Sbrad set_sram_req.gp2_settings |= 11741.1Sbrad MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11751.1Sbrad } else { 11761.1Sbrad set_sram_req.gp2_settings &= 11771.1Sbrad ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11781.1Sbrad } 11791.1Sbrad } 11801.1Sbrad if (current_gpio_cfg_res.gp3_pin_dir == MCP2221_GPIO_CFG_DIR_OUTPUT) { 11811.1Sbrad if (current_gpio_cfg_res.gp3_pin_value == 1) { 11821.1Sbrad set_sram_req.gp3_settings |= 11831.1Sbrad MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11841.1Sbrad } else { 11851.1Sbrad set_sram_req.gp3_settings &= 11861.1Sbrad ~MCP2221_SRAM_GPIO_OUTPUT_HIGH; 11871.1Sbrad } 11881.1Sbrad } 11891.1Sbrad err = mcp2221_put_sram(sc, &set_sram_req, &set_sram_res); 11901.1Sbrad if (err) 11911.1Sbrad goto out; 11921.1Sbrad 11931.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 11941.1Sbrad (uint8_t *) & set_sram_res, MCP2221_RES_BUFFER_SIZE, 11951.1Sbrad "mcp2221_gpio_pin_ctl set sram buffer copy"); 11961.1Sbrad if (set_sram_res.cmd != MCP2221_CMD_SET_SRAM || 11971.1Sbrad set_sram_res.completion != MCP2221_CMD_COMPLETE_OK) { 11981.1Sbrad device_printf(sc->sc_dev, "mcp2221_gpio_pin_ctl:" 11991.1Sbrad " not the command desired, or error: %02x %02x\n", 12001.1Sbrad set_sram_res.cmd, 12011.1Sbrad set_sram_res.completion); 12021.1Sbrad err = EIO; 12031.1Sbrad goto out; 12041.1Sbrad } 12051.1Sbrad sc->sc_gpio_pins[pin].pin_flags = flags; 12061.1Sbrad err = 0; 12071.1Sbrad 12081.1Sbradout: 12091.1Sbrad return err; 12101.1Sbrad} 12111.1Sbrad 12121.1Sbradvoid 12131.1Sbradumcpmio_gpio_pin_ctl(void *arg, int pin, int flags) 12141.1Sbrad{ 12151.1Sbrad struct umcpmio_softc *sc = arg; 12161.1Sbrad 12171.1Sbrad if (sc->sc_dying) 12181.1Sbrad return; 12191.1Sbrad 12201.1Sbrad mutex_enter(&sc->sc_action_mutex); 12211.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) 12221.1Sbrad mcp2210_gpio_pin_ctl(sc, pin, flags); 12231.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) 12241.1Sbrad mcp2221_gpio_pin_ctl(sc, pin, flags); 12251.1Sbrad mutex_exit(&sc->sc_action_mutex); 12261.1Sbrad} 12271.1Sbrad 12281.1Sbradint 12291.1Sbradmcp2210_get_gp6_counter(struct umcpmio_softc *sc, int *counter, 12301.1Sbrad uint8_t reset) 12311.1Sbrad{ 12321.1Sbrad struct mcp2210_get_gp6_events_req req; 12331.1Sbrad struct mcp2210_get_gp6_events_res res; 12341.1Sbrad int err = 0; 12351.1Sbrad 12361.1Sbrad KASSERT(mutex_owned(&sc->sc_action_mutex)); 12371.1Sbrad 12381.1Sbrad memset(&req, 0, MCP2210_REQ_BUFFER_SIZE); 12391.1Sbrad req.cmd = MCP2210_CMD_GET_GP6_EVENTS; 12401.1Sbrad req.reset_counter = reset; 12411.1Sbrad 12421.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 12431.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 12441.1Sbrad "mcp2210_get_gp6_counter req"); 12451.1Sbrad 12461.1Sbrad err = umcpmio_send_report(sc, 12471.1Sbrad (uint8_t *) & req, MCP2210_REQ_BUFFER_SIZE, 12481.1Sbrad (uint8_t *) & res, sc->sc_cv_wait); 12491.1Sbrad 12501.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 12511.1Sbrad (uint8_t *) & res, MCP2210_RES_BUFFER_SIZE, 12521.1Sbrad "mcp2210_get_gp6_counter res"); 12531.1Sbrad 12541.1Sbrad err = mcp2210_decode_errors(req.cmd, err, res.completion); 12551.1Sbrad if (!err) { 12561.1Sbrad *counter = (res.counter_msb << 8) | res.counter_lsb; 12571.1Sbrad } 12581.1Sbrad return err; 12591.1Sbrad} 12601.1Sbrad 12611.1Sbradstatic int 12621.1Sbradumcpmio_extract_gpio_sram(struct umcpmio_softc *sc, 12631.1Sbrad uint8_t *extract) 12641.1Sbrad{ 12651.1Sbrad int err = 0; 12661.1Sbrad struct mcp2210_get_gpio_sram_res mcp2210_get_gpio_sram_res; 12671.1Sbrad struct mcp2210_get_gpio_dir_res mcp2210_get_gpio_dir_sram_res; 12681.1Sbrad struct mcp2221_get_sram_res mcp2221_get_sram_res; 12691.1Sbrad 12701.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) { 12711.1Sbrad mutex_enter(&sc->sc_action_mutex); 12721.1Sbrad err = mcp2210_get_gpio_sram(sc, &mcp2210_get_gpio_sram_res); 12731.1Sbrad mutex_exit(&sc->sc_action_mutex); 12741.1Sbrad if (err) 12751.1Sbrad return err; 12761.1Sbrad 12771.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 12781.1Sbrad (uint8_t *) & mcp2210_get_gpio_sram_res, MCP2210_RES_BUFFER_SIZE, 12791.1Sbrad "umcpmio_extract_gpio_sram mcp2210 get gpio sram buffer copy"); 12801.1Sbrad 12811.1Sbrad extract[0] = mcp2210_get_gpio_sram_res.gp0_designation; 12821.1Sbrad extract[1] = mcp2210_get_gpio_sram_res.gp1_designation; 12831.1Sbrad extract[2] = mcp2210_get_gpio_sram_res.gp2_designation; 12841.1Sbrad extract[3] = mcp2210_get_gpio_sram_res.gp3_designation; 12851.1Sbrad extract[4] = mcp2210_get_gpio_sram_res.gp4_designation; 12861.1Sbrad extract[5] = mcp2210_get_gpio_sram_res.gp5_designation; 12871.1Sbrad extract[6] = mcp2210_get_gpio_sram_res.gp6_designation; 12881.1Sbrad extract[7] = mcp2210_get_gpio_sram_res.gp7_designation; 12891.1Sbrad extract[8] = mcp2210_get_gpio_sram_res.gp8_designation; 12901.1Sbrad 12911.1Sbrad mutex_enter(&sc->sc_action_mutex); 12921.1Sbrad err = mcp2210_get_gpio_dir_sram(sc, &mcp2210_get_gpio_dir_sram_res); 12931.1Sbrad mutex_exit(&sc->sc_action_mutex); 12941.1Sbrad if (err) 12951.1Sbrad return err; 12961.1Sbrad 12971.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 12981.1Sbrad (uint8_t *) & mcp2210_get_gpio_dir_sram_res, MCP2210_RES_BUFFER_SIZE, 12991.1Sbrad "umcpmio_extract_gpio_sram mcp2210 get gpio dir sram buffer copy"); 13001.1Sbrad 13011.1Sbrad extract[9] = mcp2210_get_gpio_dir_sram_res.pin_dir_lsb; 13021.1Sbrad extract[10] = mcp2210_get_gpio_dir_sram_res.pin_dir_msb; 13031.1Sbrad extract[11] = mcp2210_get_gpio_sram_res.other_settings; 13041.1Sbrad } 13051.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) { 13061.1Sbrad mutex_enter(&sc->sc_action_mutex); 13071.1Sbrad err = mcp2221_get_sram(sc, &mcp2221_get_sram_res); 13081.1Sbrad mutex_exit(&sc->sc_action_mutex); 13091.1Sbrad if (err) 13101.1Sbrad return err; 13111.1Sbrad 13121.1Sbrad umcpmio_dump_buffer(sc->sc_dumpbuffer, 13131.1Sbrad (uint8_t *) & mcp2221_get_sram_res, MCP2221_RES_BUFFER_SIZE, 13141.1Sbrad "umcpmio_extract_gpio_sram mcp2221 get sram buffer copy"); 13151.1Sbrad 13161.1Sbrad extract[0] = mcp2221_get_sram_res.gp0_settings; 13171.1Sbrad extract[1] = mcp2221_get_sram_res.gp1_settings; 13181.1Sbrad extract[2] = mcp2221_get_sram_res.gp2_settings; 13191.1Sbrad extract[3] = mcp2221_get_sram_res.gp3_settings; 13201.1Sbrad } 13211.1Sbrad return err; 13221.1Sbrad} 13231.1Sbrad 13241.1Sbradvoid 13251.1Sbradumcpmio_gpio_attach(struct umcpmio_softc *sc) 13261.1Sbrad{ 13271.1Sbrad int err; 13281.1Sbrad struct gpiobus_attach_args gba; 13291.1Sbrad uint8_t extract[UMCPMIO_MAX_GPIO_PINS + 3]; 13301.1Sbrad 13311.1Sbrad err = umcpmio_extract_gpio_sram(sc, extract); 13321.1Sbrad if (err) { 13331.1Sbrad aprint_error_dev(sc->sc_dev, "umcpmio_gpio_attach:" 13341.1Sbrad " extract gpio from sram: err=%d\n", 13351.1Sbrad err); 13361.1Sbrad return; 13371.1Sbrad } 13381.1Sbrad 13391.1Sbrad /* The MCP2221 / MCP2221A has a pin that can have gpio interrupt 13401.1Sbrad * ability, but there are problems with making use of it as the 13411.1Sbrad * gpio framework runs with spin locks or hard interrupt level, 13421.1Sbrad * and you can't call into the USB framework in that state. 13431.1Sbrad * 13441.1Sbrad * It is largely the same reason using the umcpmio gpio pins 13451.1Sbrad * as attachments to gpiopps or gpioow doesn't work. Spin 13461.1Sbrad * locks are held there too. 13471.1Sbrad */ 13481.1Sbrad for (int c = 0; c < sc->sc_chipinfo->num_gpio_pins; c++){ 13491.1Sbrad sc->sc_gpio_pins[c].pin_num = c; 13501.1Sbrad sc->sc_gpio_pins[c].pin_caps = sc->sc_chipinfo->gpio_pin_ability[c]; 13511.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2210) { 13521.1Sbrad sc->sc_gpio_pins[c].pin_flags = 13531.1Sbrad mcp2210_sram_gpio_to_flags(extract, c); 13541.1Sbrad } 13551.1Sbrad if (sc->sc_chipinfo->usb_id == USB_PRODUCT_MICROCHIP_MCP2221) { 13561.1Sbrad sc->sc_gpio_pins[c].pin_flags = 13571.1Sbrad mcp2221_sram_gpio_to_flags(extract[c]); 13581.1Sbrad } 13591.1Sbrad sc->sc_gpio_pins[c].pin_intrcaps = 0; 13601.1Sbrad strncpy(sc->sc_gpio_pins[c].pin_defname, 13611.1Sbrad sc->sc_chipinfo->gpio_names[c], 13621.1Sbrad strlen(sc->sc_chipinfo->gpio_names[c]) + 1); 13631.1Sbrad } 13641.1Sbrad 13651.1Sbrad sc->sc_gpio_gc.gp_cookie = sc; 13661.1Sbrad sc->sc_gpio_gc.gp_pin_read = umcpmio_gpio_pin_read; 13671.1Sbrad sc->sc_gpio_gc.gp_pin_write = umcpmio_gpio_pin_write; 13681.1Sbrad sc->sc_gpio_gc.gp_pin_ctl = umcpmio_gpio_pin_ctl; 13691.1Sbrad 13701.1Sbrad gba.gba_gc = &sc->sc_gpio_gc; 13711.1Sbrad gba.gba_pins = sc->sc_gpio_pins; 13721.1Sbrad gba.gba_npins = sc->sc_chipinfo->num_gpio_pins; 13731.1Sbrad 13741.1Sbrad sc->sc_gpio_dev = config_found(sc->sc_dev, &gba, gpiobus_print, 13751.1Sbrad CFARGS(.iattr = "gpiobus")); 13761.1Sbrad} 1377