1 /* $NetBSD: sc16is7xx.c,v 1.1 2025/10/24 23:16:11 brad Exp $ */ 2 3 /* 4 * Copyright (c) 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 "opt_fdt.h" 20 21 #include <sys/cdefs.h> 22 __KERNEL_RCSID(0, "$NetBSD: sc16is7xx.c,v 1.1 2025/10/24 23:16:11 brad Exp $"); 23 24 /* Common driver for the frontend to the NXP SC16IS7xx UART bridge */ 25 26 #include <sys/param.h> 27 #include <sys/systm.h> 28 #include <sys/kernel.h> 29 #include <sys/kthread.h> 30 #include <sys/device.h> 31 #include <sys/module.h> 32 #include <sys/sysctl.h> 33 #include <sys/mutex.h> 34 #include <sys/pool.h> 35 #include <sys/proc.h> 36 #include <sys/workqueue.h> 37 38 #ifdef FDT 39 #include <dev/fdt/fdtvar.h> 40 #endif 41 42 #include <dev/ic/sc16is7xxreg.h> 43 #include <dev/ic/sc16is7xxvar.h> 44 #include <dev/ic/sc16is7xx_ttyvar.h> 45 46 const struct device_compatible_entry sc16is7xx_compat_data[] = { 47 {.compat = "nxp,sc16is740"}, 48 {.compat = "nxp,sc16is741"}, 49 {.compat = "nxp,sc16is750"}, 50 {.compat = "nxp,sc16is752"}, 51 {.compat = "nxp,sc16is760"}, 52 {.compat = "nxp,sc16is762"}, 53 54 DEVICE_COMPAT_EOL 55 }; 56 57 void sc16is7xx_attach(struct sc16is7xx_sc *); 58 static int sc16is7xx_verify_poll(SYSCTLFN_ARGS); 59 static int sc16is7xx_verify_freq_sysctl(SYSCTLFN_ARGS); 60 void sc16is7xx_thread(void *); 61 62 /* Artifical interrupts and the like */ 63 64 static void 65 sc16is7xx_comintr(struct sc16is7xx_sc *sc) 66 { 67 struct sc16is7xx_tty_softc *csc; 68 69 for (int i = 0; i <= 1; i++){ 70 if (sc->sc_ttydevchannel[i] != NULL) { 71 csc = device_private(sc->sc_ttydevchannel[i]); 72 if (csc != NULL) 73 comintr(&csc->sc_com); 74 } 75 } 76 } 77 78 void 79 sc16is7xx_thread(void *arg) 80 { 81 struct sc16is7xx_sc *sc = arg; 82 83 while (sc->sc_thread_run) { 84 sc16is7xx_comintr(sc); 85 86 kpause(device_xname(sc->sc_dev), false, mstohz(sc->sc_poll), NULL); 87 } 88 kthread_exit(0); 89 } 90 91 #ifdef FDT 92 /* This song and dance is needed because: 93 94 sc16is7xx_intr is entered in a hard interrupt context. It is not 95 allowed to call workqueue_enqueue() and can't call comintr() 96 because that might need to talk to the I2C or SPI bus, allocate 97 memory, or otherwise wait. 98 99 sc16is7xx_softintr wasn't able to call comintr() directly as that 100 resulted in a panic. 101 102 Hence.. sc16is7xx_comintr() and then comintr() needed to be 103 entered from a thread or a workqueue worker. 104 */ 105 106 static void 107 sc16is7xx_wq(struct work *wk, void *arg) 108 { 109 struct sc16is7xx_sc *sc = arg; 110 111 112 sc16is7xx_comintr(sc); 113 114 pool_cache_put(sc->sc_wk_pool, wk); 115 } 116 117 static void 118 sc16is7xx_softintr(void *arg) 119 { 120 struct sc16is7xx_sc *sc = arg; 121 int *wk; 122 123 /* This is a little strange, but ensures that there is unique work to 124 * be done. See workqueue(9) about "A work must not be enqueued again 125 * until the callback is called by the workqueue framework." 126 * 127 * If one tries to use a variable from the stack here you will panic if 128 * there are a number of interrupts coming in quickly. kmem_alloc() 129 * also panic'ed. This is running in a interrupt context, although it 130 * is soft and kmem(9) didn't like that. 131 * 132 * There could be a lot of interrupts going on if the there is a lot to 133 * receive or transmit. 134 * 135 * It may be possble to get clever and send a couple of work items, one 136 * for each possible channel. */ 137 138 wk = pool_cache_get(sc->sc_wk_pool, PR_NOWAIT); 139 140 if (wk != NULL) { 141 workqueue_enqueue(sc->sc_wq, (struct work *)wk, NULL); 142 } 143 } 144 145 static int 146 sc16is7xx_intr(void *arg) 147 { 148 struct sc16is7xx_sc *sc = arg; 149 150 softint_schedule(sc->sc_sih); 151 152 return 1; 153 } 154 #endif 155 156 /* GPIO */ 157 158 static uint32_t 159 sc16is7xx_to_gpio_flags(struct sc16is7xx_sc *sc, int pin, int nc, 160 uint8_t iocontrol, uint8_t iodir) 161 { 162 int f = 0; 163 164 if (pin <= 3) { 165 if (nc == 2) { 166 if (iocontrol & SC16IS7XX_IOCONTROL_3_0) 167 f = GPIO_PIN_ALT0; 168 } 169 if (f == 0) { 170 if (iodir & (1 << pin)) 171 f = GPIO_PIN_OUTPUT; 172 else 173 f = GPIO_PIN_INPUT; 174 } 175 } else { 176 if (iocontrol & SC16IS7XX_IOCONTROL_7_4) 177 f = GPIO_PIN_ALT0; 178 else if (iodir & (1 << pin)) 179 f = GPIO_PIN_OUTPUT; 180 else 181 f = GPIO_PIN_INPUT; 182 } 183 184 return f; 185 } 186 187 static int 188 sc16is7xx_gpio_pin_read(void *arg, int pin) 189 { 190 struct sc16is7xx_sc *sc = arg; 191 uint8_t r; 192 int rr = GPIO_PIN_LOW, error; 193 194 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOSTATE, 1, &r, 1); 195 if (!error && (r & (1 << pin))) 196 rr = GPIO_PIN_HIGH; 197 198 return rr; 199 } 200 201 static void 202 sc16is7xx_gpio_pin_write(void *arg, int pin, int value) 203 { 204 struct sc16is7xx_sc *sc = arg; 205 uint8_t r; 206 int error; 207 208 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOSTATE, 1, &r, 1); 209 if (!error) { 210 if (value) 211 r |= (1 << pin); 212 else 213 r &= ~(1 << pin); 214 error = sc->sc_funcs->write_reg(sc, SC16IS7XX_REGISTER_IOSTATE, 1, &r, 1); 215 } 216 } 217 218 static void 219 sc16is7xx_gpio_ctl_alt0(struct sc16is7xx_sc *sc, uint8_t bank_mask, 220 int low_pin, int high_pin, uint32_t flags) 221 { 222 int error; 223 uint8_t iocontrol; 224 225 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol, 1); 226 if (!error) { 227 iocontrol |= bank_mask; 228 error = sc->sc_funcs->write_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol, 1); 229 if (!error) { 230 for (int i = low_pin; i <= high_pin; i++) 231 sc->sc_gpio_pins[i].pin_flags = flags; 232 } 233 } 234 } 235 236 static void 237 sc16is7xx_gpio_ctl_inout(struct sc16is7xx_sc *sc, uint8_t bank_mask, 238 int low_pin, int high_pin, int a_pin, uint32_t flags) 239 { 240 int error; 241 uint8_t iocontrol, iodir; 242 243 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol, 1); 244 if (!error) { 245 iocontrol &= ~bank_mask; 246 error = sc->sc_funcs->write_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol, 1); 247 if (!error) { 248 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IODIR, 1, &iodir, 1); 249 if (flags & GPIO_PIN_OUTPUT) 250 iodir |= (1 << a_pin); 251 if (flags & GPIO_PIN_INPUT) 252 iodir &= ~(1 << a_pin); 253 error = sc->sc_funcs->write_reg(sc, SC16IS7XX_REGISTER_IODIR, 1, &iodir, 1); 254 if (!error) { 255 for (int i = low_pin; i <= high_pin; i++) 256 sc->sc_gpio_pins[i].pin_flags = sc16is7xx_to_gpio_flags(sc, i, sc->sc_num_channels, iocontrol, iodir); 257 } 258 } 259 } 260 } 261 262 static void 263 sc16is7xx_gpio_pin_ctl(void *arg, int pin, int flags) 264 { 265 struct sc16is7xx_sc *sc = arg; 266 uint8_t bank_mask; 267 int low_pin, high_pin; 268 269 if (pin <= 3) { 270 bank_mask = SC16IS7XX_IOCONTROL_3_0; 271 low_pin = 0; 272 high_pin = 3; 273 } else { 274 bank_mask = SC16IS7XX_IOCONTROL_7_4; 275 low_pin = 4; 276 high_pin = SC16IS7XX_NPINS - 1; 277 } 278 279 if (flags & GPIO_PIN_ALT0) { 280 sc16is7xx_gpio_ctl_alt0(sc, bank_mask, low_pin, high_pin, flags); 281 } else { 282 sc16is7xx_gpio_ctl_inout(sc, bank_mask, low_pin, high_pin, pin, flags); 283 } 284 } 285 /* sysctl */ 286 287 int 288 sc16is7xx_verify_poll(SYSCTLFN_ARGS) 289 { 290 int error, t; 291 struct sysctlnode node; 292 293 node = *rnode; 294 t = *(int *)rnode->sysctl_data; 295 node.sysctl_data = &t; 296 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 297 if (error || newp == NULL) 298 return error; 299 300 if (t < 1) 301 return EINVAL; 302 303 *(int *)rnode->sysctl_data = t; 304 305 return 0; 306 } 307 308 int 309 sc16is7xx_verify_freq_sysctl(SYSCTLFN_ARGS) 310 { 311 struct sc16is7xx_sc *sc; 312 struct sc16is7xx_tty_softc *csc; 313 int error, t; 314 struct sysctlnode node; 315 316 node = *rnode; 317 sc = node.sysctl_data; 318 t = sc->sc_frequency; 319 node.sysctl_data = &t; 320 error = sysctl_lookup(SYSCTLFN_CALL(&node)); 321 if (error || newp == NULL) 322 return error; 323 324 if (t < 1) 325 return EINVAL; 326 327 sc->sc_frequency = t; 328 329 for (int i = 0; i <= 1; i++){ 330 if (sc->sc_ttydevchannel[i] != NULL) { 331 csc = device_private(sc->sc_ttydevchannel[i]); 332 if (csc != NULL) 333 csc->sc_com.sc_frequency = sc->sc_frequency; 334 } 335 } 336 337 return 0; 338 } 339 340 static int 341 sc16is7xx_sysctl_init(struct sc16is7xx_sc *sc) 342 { 343 int error; 344 const struct sysctlnode *cnode; 345 int sysctlroot_num; 346 347 if ((error = sysctl_createv(&sc->sc_sc16is7xx_log, 0, NULL, &cnode, 348 0, CTLTYPE_NODE, device_xname(sc->sc_dev), 349 SYSCTL_DESCR("sc16ix7xx controls"), NULL, 0, NULL, 0, CTL_HW, 350 CTL_CREATE, CTL_EOL)) != 0) 351 return error; 352 353 sysctlroot_num = cnode->sysctl_num; 354 355 if ((error = sysctl_createv(&sc->sc_sc16is7xx_log, 0, NULL, &cnode, 356 CTLFLAG_READWRITE, CTLTYPE_INT, "frequency", 357 SYSCTL_DESCR("Frequency of the oscillator in Hz"), sc16is7xx_verify_freq_sysctl, 0, 358 (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, 359 CTL_EOL)) != 0) 360 return error; 361 362 if ((error = sysctl_createv(&sc->sc_sc16is7xx_log, 0, NULL, &cnode, 363 CTLFLAG_READWRITE, CTLTYPE_INT, "poll", 364 SYSCTL_DESCR("In polling mode, how often to check the status register in ms"), sc16is7xx_verify_poll, 0, 365 &sc->sc_poll, 0, CTL_HW, sysctlroot_num, CTL_CREATE, 366 CTL_EOL)) != 0) 367 return error; 368 369 return 0; 370 } 371 /* attach, detach and such */ 372 373 static int 374 sc16is7xx_print(void *aux, const char *pnp) 375 { 376 struct sc16is7xx_tty_attach_args *aa = aux; 377 378 if (pnp) 379 aprint_normal("PNP = %s", pnp); 380 aprint_normal(" channel %d", aa->aa_channel); 381 return (UNCONF); 382 } 383 384 void 385 sc16is7xx_attach(struct sc16is7xx_sc *sc) 386 { 387 int error; 388 char chip_type[SC16IS7XX_TYPE_STRINGLEN]; 389 int num_channels; 390 int num_gpio; 391 uint8_t buf[1]; 392 uint8_t iocontrol_reg; 393 struct sc16is7xx_tty_attach_args aa; 394 int reset_count = 0; 395 396 aprint_normal("\n"); 397 398 sc->sc_frequency = SC16IS7XX_DEFAULT_FREQUENCY; 399 sc->sc_poll = SC16IS7XX_DEFAULT_POLL; 400 sc->sc_thread_run = false; 401 sc->sc_thread = NULL; 402 sc->sc_wq = NULL; 403 sc->sc_ih = NULL; 404 sc->sc_sih = NULL; 405 406 if ((error = sc16is7xx_sysctl_init(sc)) != 0) { 407 aprint_error_dev(sc->sc_dev, "Can't setup sysctl tree (%d)\n", error); 408 goto out; 409 } 410 411 /* Reset of the chip is a little odd. Setting the SRESET bit is the 412 * only write that will NACK. So, an expected error will result in 413 * that case. Just ignore the error and read a few times to make sure 414 * that the reset is done. After the reset, one must delay at least 415 * 3us before trying to talk to the chip again. */ 416 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 0, &iocontrol_reg, 1); 417 if (!error) { 418 iocontrol_reg |= SC16IS7XX_IOCONTROL_SRESET; 419 sc->sc_funcs->write_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 0, &iocontrol_reg, 1); 420 delay(5); 421 do { 422 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 0, &iocontrol_reg, 1); 423 if (!error) { 424 if (iocontrol_reg & SC16IS7XX_IOCONTROL_SRESET) { 425 delay(2); 426 } 427 reset_count++; 428 } 429 } while ((iocontrol_reg & SC16IS7XX_IOCONTROL_SRESET) && 430 (reset_count < 100) && 431 (!error)); 432 } 433 if (!error) { 434 if (iocontrol_reg & SC16IS7XX_IOCONTROL_SRESET) { 435 aprint_error_dev(sc->sc_dev, 436 "Chip did not reset in time. reset_count=%d\n", reset_count); 437 } 438 } else { 439 aprint_error_dev(sc->sc_dev, 440 "Error reseting chip: error=%d, reset_count=%d\n", 441 error, reset_count); 442 } 443 444 /* After a reset, the LCR register will be 0x1d. If this isn't the 445 * case with channel 1, then channel 1 does not exist and this is a 446 * single UART chip, that is a SC16IS740, SC16IS750 or SC16IS760 and 447 * not a SC16IS752 or SC16IS762. 448 * 449 * There does not appear to be a way to distinguish a SC16IS740 / 450 * SC16IS741 from a SC16IS750 / SC16IS760. The GPIO registers exist in 451 * both varients and appear to behave the same. Obviously the physical 452 * pins are missing from the SC16IS74x branch of the family. A bit 453 * more detail is available if you have a system with FDT. 454 * 455 * */ 456 457 num_channels = 1; 458 num_gpio = SC16IS7XX_NPINS; 459 strncpy(chip_type, "UNKNOWN", SC16IS7XX_TYPE_STRINGLEN); 460 461 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_LCR, 1, buf, 1); 462 if (!error) { 463 if (buf[0] == 0x1d) { 464 strncpy(chip_type, "SC16IS752/SC16IS762", SC16IS7XX_TYPE_STRINGLEN); 465 num_channels = 2; 466 } else { 467 strncpy(chip_type, "SC16IS740/SC16IS741/SC16IS750/SC16IS760", SC16IS7XX_TYPE_STRINGLEN); 468 } 469 } 470 sc->sc_num_channels = num_channels; 471 472 aprint_normal_dev(sc->sc_dev, "NXP %s\n", chip_type); 473 474 sc->sc_ttydevchannel[0] = sc->sc_ttydevchannel[1] = NULL; 475 476 sc->sc_wk_pool = pool_cache_init(sizeof(int), 0, 0, 0, "sc16pool", NULL, IPL_SOFTSERIAL, NULL, NULL, NULL); 477 478 bool use_polling = true; 479 480 #ifdef FDT 481 482 error = workqueue_create(&sc->sc_wq, device_xname(sc->sc_dev), 483 sc16is7xx_wq, sc, PRI_SOFTSERIAL, IPL_SOFTSERIAL, WQ_MPSAFE); 484 if (error) { 485 aprint_error_dev(sc->sc_dev, 486 "Could not create workqueue: %d\n", 487 error); 488 } 489 if (!error && 490 devhandle_type(device_handle(sc->sc_dev)) == DEVHANDLE_TYPE_OF) { 491 char intrstr[128]; 492 493 sc->sc_phandle = devhandle_to_of(device_handle(sc->sc_dev)); 494 495 if (!of_hasprop(sc->sc_phandle, "gpio-controller")) { 496 num_gpio = 0; 497 498 /* If there is an indication that the GPIO is not 499 * desired, turn the pins into modem control pins. */ 500 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol_reg, 1); 501 if (error) 502 goto out; 503 if (num_channels == 2) 504 iocontrol_reg |= SC16IS7XX_IOCONTROL_7_4 | SC16IS7XX_IOCONTROL_3_0; 505 else 506 iocontrol_reg |= SC16IS7XX_IOCONTROL_7_4; /* No strictly correct 507 * for the SC16IS74x */ 508 error = sc->sc_funcs->write_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol_reg, 1); 509 if (error) 510 goto out; 511 } 512 if (fdtbus_intr_str(sc->sc_phandle, 0, 513 intrstr, sizeof(intrstr))) { 514 515 aprint_normal_dev(sc->sc_dev, "interrupting on %s\n", intrstr); 516 517 sc->sc_ih = fdtbus_intr_establish(sc->sc_phandle, 0, IPL_VM, 0, 518 sc16is7xx_intr, sc); 519 520 if (sc->sc_ih == NULL) { 521 aprint_error_dev(sc->sc_dev, 522 "unable to establish interrupt\n"); 523 } else { 524 sc->sc_sih = 525 softint_establish(SOFTINT_SERIAL, sc16is7xx_softintr, sc); 526 if (sc->sc_sih == NULL) { 527 aprint_error_dev(sc->sc_dev, 528 "unable to establish soft interrupt\n"); 529 fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 530 sc->sc_ih = NULL; 531 } else { 532 use_polling = false; 533 } 534 } 535 } 536 const u_int * cf; 537 int len; 538 cf = fdtbus_get_prop(sc->sc_phandle, "clock-frequency", &len); 539 if (cf != NULL && len > 0) { 540 sc->sc_frequency = be32toh(cf[0]); 541 } 542 } 543 544 #endif 545 546 if (use_polling) { 547 aprint_normal_dev(sc->sc_dev, "polling for interrupts\n"); 548 549 sc->sc_thread_run = true; 550 error = kthread_create(PRI_SOFTSERIAL, KTHREAD_MUSTJOIN | KTHREAD_MPSAFE, NULL, 551 sc16is7xx_thread, sc, &sc->sc_thread, "%s", device_xname(sc->sc_dev)); 552 if (error) { 553 aprint_error_dev(sc->sc_dev, 554 "Could not create kernel thread for polling: %d\n", 555 error); 556 sc->sc_thread_run = false; 557 } 558 } 559 for (int i = 0; i < num_channels; i++){ 560 aa.aa_channel = i; 561 562 sc->sc_ttydevchannel[i] = config_found(sc->sc_dev, &aa, sc16is7xx_print, 563 CFARGS(.submatch = config_stdsubmatch, 564 .iattr = "sc16is7xxbus")); 565 566 } 567 568 if (num_gpio > 0) { 569 struct gpiobus_attach_args gba; 570 uint8_t iodir_reg; 571 int c = 3; 572 573 if (num_channels == 2) 574 c = -1; 575 576 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IOCONTROL, 1, &iocontrol_reg, 1); 577 if (error) 578 goto out; 579 error = sc->sc_funcs->read_reg(sc, SC16IS7XX_REGISTER_IODIR, 1, &iodir_reg, 1); 580 if (error) 581 goto out; 582 583 for (int i = 0; i < num_gpio; i++){ 584 sc->sc_gpio_pins[i].pin_num = i; 585 sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT; 586 sc->sc_gpio_pins[i].pin_caps |= GPIO_PIN_OUTPUT; 587 if (i > c) 588 sc->sc_gpio_pins[i].pin_caps |= GPIO_PIN_ALT0; 589 sc->sc_gpio_pins[i].pin_flags = 590 sc16is7xx_to_gpio_flags(sc, i, num_channels, iocontrol_reg, iodir_reg); 591 sc->sc_gpio_pins[i].pin_intrcaps = 0; 592 snprintf(sc->sc_gpio_pins[i].pin_defname, 4, "GP%d", i); 593 } 594 595 sc->sc_gpio_gc.gp_cookie = sc; 596 sc->sc_gpio_gc.gp_pin_read = sc16is7xx_gpio_pin_read; 597 sc->sc_gpio_gc.gp_pin_write = sc16is7xx_gpio_pin_write; 598 sc->sc_gpio_gc.gp_pin_ctl = sc16is7xx_gpio_pin_ctl; 599 600 gba.gba_gc = &sc->sc_gpio_gc; 601 gba.gba_pins = sc->sc_gpio_pins; 602 gba.gba_npins = SC16IS7XX_NPINS; 603 604 sc->sc_gpio_dev = config_found(sc->sc_dev, &gba, gpiobus_print, 605 CFARGS(.iattr = "gpiobus")); 606 } 607 608 out: 609 610 return; 611 } 612 613 int 614 sc16is7xx_detach(struct sc16is7xx_sc *sc, int flags) 615 { 616 int err = 0; 617 618 err = config_detach_children(sc->sc_dev, flags); 619 620 if (sc->sc_thread && 621 sc->sc_thread_run) { 622 sc->sc_thread_run = false; 623 kthread_join(sc->sc_thread); 624 } 625 #ifdef FDT 626 if (sc->sc_ih != NULL) 627 fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih); 628 629 if (sc->sc_sih != NULL) 630 softint_disestablish(sc->sc_sih); 631 #endif 632 633 pool_cache_destroy(sc->sc_wk_pool); 634 635 sysctl_teardown(&sc->sc_sc16is7xx_log); 636 637 return err; 638 } 639