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