1 1.1 brad /* $NetBSD: sc16is7xx_tty.c,v 1.1 2025/10/24 23:16:11 brad Exp $ */ 2 1.1 brad 3 1.1 brad /* 4 1.1 brad * Copyright (c) 2025 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.1 brad __KERNEL_RCSID(0, "$NetBSD: sc16is7xx_tty.c,v 1.1 2025/10/24 23:16:11 brad Exp $"); 21 1.1 brad 22 1.1 brad /* TTY specific common driver to the NXP SC16IS7xx UART bridge */ 23 1.1 brad 24 1.1 brad #include <sys/param.h> 25 1.1 brad #include <sys/device.h> 26 1.1 brad #include <sys/tty.h> 27 1.1 brad #ifdef __REMOVE 28 1.1 brad #include <sys/sysctl.h> 29 1.1 brad #endif 30 1.1 brad #include <sys/systm.h> 31 1.1 brad 32 1.1 brad #include <sys/bus.h> 33 1.1 brad 34 1.1 brad #include <dev/ic/sc16is7xxreg.h> 35 1.1 brad #include <dev/ic/sc16is7xxvar.h> 36 1.1 brad #include <dev/ic/sc16is7xx_ttyvar.h> 37 1.1 brad 38 1.1 brad #include <dev/ic/comreg.h> 39 1.1 brad #include <dev/ic/comvar.h> 40 1.1 brad 41 1.1 brad static int sc16is7xx_tty_match(device_t, cfdata_t, void *); 42 1.1 brad static void sc16is7xx_tty_attach(device_t, device_t, void *); 43 1.1 brad static int sc16is7xx_tty_detach(device_t, int); 44 1.1 brad #ifdef __REMOVE 45 1.1 brad static int sc16is7xx_tty_verify_prescale(SYSCTLFN_ARGS); 46 1.1 brad #endif 47 1.1 brad 48 1.1 brad CFATTACH_DECL_NEW(sc16is7xx_tty, sizeof(struct sc16is7xx_tty_softc), 49 1.1 brad sc16is7xx_tty_match, sc16is7xx_tty_attach, sc16is7xx_tty_detach, NULL); 50 1.1 brad 51 1.1 brad #ifdef __REMOVE 52 1.1 brad int 53 1.1 brad sc16is7xx_tty_verify_prescale(SYSCTLFN_ARGS) 54 1.1 brad { 55 1.1 brad struct sc16is7xx_tty_softc *sc; 56 1.1 brad int error; 57 1.1 brad bool t = false; 58 1.1 brad struct sysctlnode node; 59 1.1 brad 60 1.1 brad node = *rnode; 61 1.1 brad sc = node.sysctl_data; 62 1.1 brad if (ISSET(sc->sc_com.sc_mcr, MCR_PRESCALE)) 63 1.1 brad t = true; 64 1.1 brad node.sysctl_data = &t; 65 1.1 brad error = sysctl_lookup(SYSCTLFN_CALL(&node)); 66 1.1 brad if (error || newp == NULL) 67 1.1 brad return error; 68 1.1 brad 69 1.1 brad if (t) 70 1.1 brad SET(sc->sc_com.sc_mcr, MCR_PRESCALE); 71 1.1 brad else 72 1.1 brad CLR(sc->sc_com.sc_mcr, MCR_PRESCALE); 73 1.1 brad 74 1.1 brad return 0; 75 1.1 brad } 76 1.1 brad 77 1.1 brad static int 78 1.1 brad sc16is7xx_tty_sysctl_init(struct sc16is7xx_tty_softc *sc) 79 1.1 brad { 80 1.1 brad int error; 81 1.1 brad const struct sysctlnode *cnode; 82 1.1 brad int sysctlroot_num; 83 1.1 brad 84 1.1 brad if ((error = sysctl_createv(&sc->sc_sc16is7xx_tty_log, 0, NULL, &cnode, 85 1.1 brad 0, CTLTYPE_NODE, device_xname(sc->sc_com.sc_dev), 86 1.1 brad SYSCTL_DESCR("sc16ix7xx tty controls"), NULL, 0, NULL, 0, CTL_HW, 87 1.1 brad CTL_CREATE, CTL_EOL)) != 0) 88 1.1 brad return error; 89 1.1 brad 90 1.1 brad sysctlroot_num = cnode->sysctl_num; 91 1.1 brad 92 1.1 brad if ((error = sysctl_createv(&sc->sc_sc16is7xx_tty_log, 0, NULL, &cnode, 93 1.1 brad CTLFLAG_READWRITE, CTLTYPE_BOOL, "prescale", 94 1.1 brad SYSCTL_DESCR("Prescale"), sc16is7xx_tty_verify_prescale, 0, 95 1.1 brad (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, 96 1.1 brad CTL_EOL)) != 0) 97 1.1 brad return error; 98 1.1 brad 99 1.1 brad return 0; 100 1.1 brad } 101 1.1 brad #endif 102 1.1 brad 103 1.1 brad static int 104 1.1 brad sc16is7xx_tty_match(device_t parent, cfdata_t match, void *aux) 105 1.1 brad { 106 1.1 brad return 1; 107 1.1 brad } 108 1.1 brad 109 1.1 brad void 110 1.1 brad sc16is7xx_tty_attach(device_t parent, device_t self, void *aux) 111 1.1 brad { 112 1.1 brad struct sc16is7xx_tty_attach_args *caa = aux; 113 1.1 brad struct sc16is7xx_tty_softc *sc = device_private(self); 114 1.1 brad struct sc16is7xx_sc *psc = device_private(parent); 115 1.1 brad #ifdef __REMOVE 116 1.1 brad int error; 117 1.1 brad #endif 118 1.1 brad 119 1.1 brad sc->sc_com.sc_dev = self; 120 1.1 brad 121 1.1 brad #ifdef __REMOVE 122 1.1 brad if ((error = sc16is7xx_tty_sysctl_init(sc)) != 0) { 123 1.1 brad aprint_error_dev(sc->sc_com.sc_dev, "Can't setup sysctl tree (%d)\n", error); 124 1.1 brad goto out; 125 1.1 brad } 126 1.1 brad #endif 127 1.1 brad 128 1.1 brad /* Set and then override the callouts to read and write the registers. */ 129 1.1 brad com_init_regs(&sc->sc_com.sc_regs, 0, 0, 0); 130 1.1 brad sc->sc_com.sc_regs.cr_read = psc->sc_com_funcs->com_read_1; 131 1.1 brad sc->sc_com.sc_regs.cr_write = psc->sc_com_funcs->com_write_1; 132 1.1 brad sc->sc_com.sc_regs.cr_write_multi = psc->sc_com_funcs->com_write_multi_1; 133 1.1 brad sc->sc_com.sc_regs.cr_channel = caa->aa_channel; 134 1.1 brad 135 1.1 brad psc->sc_funcs->copy_handles(psc, &sc->sc_com.sc_regs); 136 1.1 brad 137 1.1 brad /* We will get a 64 byte FIFO and hardware flow control if we use this */ 138 1.1 brad sc->sc_com.sc_type = COM_TYPE_SC16IS7XX; 139 1.1 brad 140 1.1 brad /* The master frequency is pushed down from the bus layer as both 141 1.1 brad * channels use the same clock. However it needs to be set here as 142 1.1 brad * com(4) wants it. */ 143 1.1 brad sc->sc_com.sc_frequency = psc->sc_frequency; 144 1.1 brad 145 1.1 brad /* This will always be 0, as the polling will occur at the bus layer, 146 1.1 brad * if needed. */ 147 1.1 brad sc->sc_com.sc_poll_ticks = 0; 148 1.1 brad 149 1.1 brad /* Tell com(4) to run in a soft context whenever possible */ 150 1.1 brad SET(sc->sc_com.sc_hwflags, COM_HW_SOFTIRQ); 151 1.1 brad 152 1.1 brad com_attach_subr(&sc->sc_com); 153 1.1 brad #ifdef __REMOVE 154 1.1 brad out: 155 1.1 brad #endif 156 1.1 brad 157 1.1 brad return; 158 1.1 brad } 159 1.1 brad 160 1.1 brad int 161 1.1 brad sc16is7xx_tty_detach(device_t self, int flags) 162 1.1 brad { 163 1.1 brad #ifdef __REMOVE 164 1.1 brad struct sc16is7xx_tty_softc *sc = device_private(self); 165 1.1 brad #endif 166 1.1 brad int error; 167 1.1 brad 168 1.1 brad #ifdef __REMOVE 169 1.1 brad sysctl_teardown(&sc->sc_sc16is7xx_tty_log); 170 1.1 brad #endif 171 1.1 brad 172 1.1 brad if ((error = com_detach(self, flags)) != 0) 173 1.1 brad return error; 174 1.1 brad 175 1.1 brad return 0; 176 1.1 brad 177 1.1 brad } 178