sc16is7xx_tty.c revision 1.1 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