1 1.20 thorpej /* $NetBSD: tslcd.c,v 1.20 2021/08/07 16:18:50 thorpej Exp $ */ 2 1.1 joff 3 1.1 joff /*- 4 1.1 joff * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 1.1 joff * All rights reserved. 6 1.1 joff * 7 1.1 joff * This code is derived from software contributed to The NetBSD Foundation 8 1.1 joff * by Jesse Off. 9 1.1 joff * 10 1.1 joff * Redistribution and use in source and binary forms, with or without 11 1.1 joff * modification, are permitted provided that the following conditions 12 1.1 joff * are met: 13 1.1 joff * 1. Redistributions of source code must retain the above copyright 14 1.1 joff * notice, this list of conditions and the following disclaimer. 15 1.1 joff * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 joff * notice, this list of conditions and the following disclaimer in the 17 1.1 joff * documentation and/or other materials provided with the distribution. 18 1.1 joff * 19 1.1 joff * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 joff * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 joff * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 joff * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 joff * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 joff * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 joff * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 joff * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 joff * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 joff * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 joff * POSSIBILITY OF SUCH DAMAGE. 30 1.1 joff */ 31 1.1 joff #include <sys/cdefs.h> 32 1.20 thorpej __KERNEL_RCSID(0, "$NetBSD: tslcd.c,v 1.20 2021/08/07 16:18:50 thorpej Exp $"); 33 1.1 joff 34 1.1 joff #include <sys/param.h> 35 1.1 joff #include <sys/systm.h> 36 1.1 joff #include <sys/proc.h> 37 1.1 joff #include <sys/poll.h> 38 1.1 joff #include <sys/conf.h> 39 1.1 joff #include <sys/uio.h> 40 1.1 joff #include <sys/types.h> 41 1.1 joff #include <sys/kernel.h> 42 1.1 joff #include <sys/device.h> 43 1.1 joff #include <sys/callout.h> 44 1.1 joff #include <sys/select.h> 45 1.1 joff 46 1.14 dyoung #include <sys/bus.h> 47 1.1 joff #include <machine/autoconf.h> 48 1.1 joff 49 1.4 joff #include <dev/wscons/wsdisplayvar.h> 50 1.4 joff #include <dev/wscons/wsconsio.h> 51 1.4 joff #include <dev/wscons/wscons_callbacks.h> 52 1.4 joff 53 1.1 joff #include <arm/ep93xx/ep93xxreg.h> 54 1.7 matt #include <arm/ep93xx/epgpioreg.h> 55 1.1 joff #include <dev/ic/hd44780reg.h> 56 1.3 joff #include <dev/ic/hd44780var.h> 57 1.1 joff #include <evbarm/tsarm/tspldvar.h> 58 1.1 joff #include <evbarm/tsarm/tsarmreg.h> 59 1.1 joff 60 1.1 joff struct tslcd_softc { 61 1.4 joff struct hd44780_chip sc_hlcd; 62 1.1 joff bus_space_tag_t sc_iot; 63 1.1 joff bus_space_handle_t sc_gpioh; 64 1.1 joff }; 65 1.1 joff 66 1.15 chs static int tslcd_match(device_t, cfdata_t, void *); 67 1.15 chs static void tslcd_attach(device_t, device_t, void *); 68 1.1 joff 69 1.16 skrll static void tslcd_writereg(struct hd44780_chip *, uint32_t, uint32_t, uint8_t); 70 1.16 skrll static uint8_t tslcd_readreg(struct hd44780_chip *, uint32_t, uint32_t); 71 1.1 joff 72 1.1 joff dev_type_open(tslcdopen); 73 1.1 joff dev_type_close(tslcdclose); 74 1.1 joff dev_type_read(tslcdread); 75 1.1 joff dev_type_write(tslcdwrite); 76 1.1 joff dev_type_ioctl(tslcdioctl); 77 1.1 joff dev_type_poll(tslcdpoll); 78 1.1 joff 79 1.1 joff const struct cdevsw tslcd_cdevsw = { 80 1.17 dholland .d_open = tslcdopen, 81 1.17 dholland .d_close = tslcdclose, 82 1.17 dholland .d_read = tslcdread, 83 1.17 dholland .d_write = tslcdwrite, 84 1.17 dholland .d_ioctl = tslcdioctl, 85 1.17 dholland .d_stop = nostop, 86 1.17 dholland .d_tty = notty, 87 1.17 dholland .d_poll = tslcdpoll, 88 1.17 dholland .d_mmap = nommap, 89 1.17 dholland .d_kqfilter = nokqfilter, 90 1.18 dholland .d_discard = nodiscard, 91 1.17 dholland .d_flag = 0 92 1.1 joff }; 93 1.1 joff 94 1.4 joff extern const struct wsdisplay_emulops hlcd_emulops; 95 1.4 joff extern const struct wsdisplay_accessops hlcd_accessops; 96 1.1 joff extern struct cfdriver tslcd_cd; 97 1.1 joff 98 1.15 chs CFATTACH_DECL_NEW(tslcd, sizeof(struct tslcd_softc), 99 1.1 joff tslcd_match, tslcd_attach, NULL, NULL); 100 1.1 joff 101 1.4 joff static const struct wsscreen_descr tslcd_stdscreen = { 102 1.4 joff "std_tslcd", 24, 2, 103 1.4 joff &hlcd_emulops, 104 1.4 joff 5, 7, 105 1.4 joff 0, 106 1.4 joff }; 107 1.4 joff 108 1.4 joff static const struct wsscreen_descr *_tslcd_scrlist[] = { 109 1.4 joff &tslcd_stdscreen, 110 1.4 joff }; 111 1.4 joff 112 1.4 joff static const struct wsscreen_list tslcd_screenlist = { 113 1.4 joff sizeof(_tslcd_scrlist) / sizeof(struct wsscreen_descr *), 114 1.4 joff _tslcd_scrlist, 115 1.4 joff }; 116 1.4 joff 117 1.1 joff static int 118 1.15 chs tslcd_match(device_t parent, cfdata_t match, void *aux) 119 1.1 joff { 120 1.1 joff return 1; 121 1.1 joff } 122 1.1 joff 123 1.1 joff #define GPIO_GET(x) bus_space_read_1(sc->sc_iot, sc->sc_gpioh, \ 124 1.1 joff (EP93XX_GPIO_ ## x)) 125 1.1 joff 126 1.1 joff #define GPIO_SET(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \ 127 1.1 joff (EP93XX_GPIO_ ## x), (y)) 128 1.1 joff 129 1.1 joff #define GPIO_SETBITS(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \ 130 1.1 joff (EP93XX_GPIO_ ## x), GPIO_GET(x) | (y)) 131 1.1 joff 132 1.1 joff #define GPIO_CLEARBITS(x, y) bus_space_write_1(sc->sc_iot, sc->sc_gpioh, \ 133 1.1 joff (EP93XX_GPIO_ ## x), GPIO_GET(x) & (~(y))) 134 1.1 joff 135 1.1 joff static void 136 1.15 chs tslcd_attach(device_t parent, device_t self, void *aux) 137 1.1 joff { 138 1.15 chs struct tslcd_softc *sc = device_private(self); 139 1.1 joff struct tspld_attach_args *taa = aux; 140 1.4 joff struct wsemuldisplaydev_attach_args waa; 141 1.1 joff 142 1.1 joff sc->sc_iot = taa->ta_iot; 143 1.1 joff if (bus_space_map(sc->sc_iot, EP93XX_APB_HWBASE + EP93XX_APB_GPIO, 144 1.1 joff EP93XX_APB_GPIO_SIZE, 0, &sc->sc_gpioh)) 145 1.1 joff panic("tslcd_attach: couldn't map GPIO registers"); 146 1.1 joff 147 1.4 joff sc->sc_hlcd.sc_dev_ok = 1; 148 1.4 joff sc->sc_hlcd.sc_cols = 24; 149 1.4 joff sc->sc_hlcd.sc_vcols = 40; 150 1.4 joff sc->sc_hlcd.sc_flags = HD_8BIT | HD_MULTILINE; 151 1.4 joff sc->sc_hlcd.sc_dev = self; 152 1.1 joff 153 1.4 joff sc->sc_hlcd.sc_writereg = tslcd_writereg; 154 1.4 joff sc->sc_hlcd.sc_readreg = tslcd_readreg; 155 1.1 joff 156 1.1 joff GPIO_SET(PADDR, 0); /* Port A to inputs */ 157 1.1 joff GPIO_SETBITS(PHDDR, 0x38); /* Bits 3:5 of Port H to outputs */ 158 1.1 joff GPIO_CLEARBITS(PHDR, 0x18); /* De-assert EN, De-assert RS */ 159 1.1 joff 160 1.2 joff printf("\n"); 161 1.2 joff 162 1.4 joff hd44780_attach_subr(&sc->sc_hlcd); 163 1.4 joff 164 1.4 joff waa.console = 0; 165 1.4 joff waa.scrdata = &tslcd_screenlist; 166 1.4 joff waa.accessops = &hlcd_accessops; 167 1.4 joff waa.accesscookie = &sc->sc_hlcd.sc_screen; 168 1.20 thorpej config_found(self, &waa, wsemuldisplaydevprint, CFARGS_NONE); 169 1.1 joff } 170 1.1 joff 171 1.1 joff static void 172 1.16 skrll tslcd_writereg(struct hd44780_chip *hd, uint32_t en, uint32_t rs, uint8_t cmd) 173 1.1 joff { 174 1.15 chs struct tslcd_softc *sc = device_private(hd->sc_dev); 175 1.16 skrll uint8_t ctrl; 176 1.2 joff 177 1.2 joff if (hd->sc_dev_ok == 0) 178 1.2 joff return; 179 1.1 joff 180 1.1 joff /* Step 1: Apply RS & WR, Send data */ 181 1.2 joff ctrl = GPIO_GET(PHDR); 182 1.1 joff GPIO_SET(PADDR, 0xff); /* set port A to outputs */ 183 1.1 joff GPIO_SET(PADR, cmd); 184 1.1 joff if (rs) { 185 1.1 joff ctrl |= 0x10; /* assert RS */ 186 1.1 joff ctrl &= ~0x20; /* assert WR */ 187 1.1 joff } else { 188 1.1 joff ctrl &= ~0x30; /* de-assert WR, de-assert RS */ 189 1.1 joff } 190 1.1 joff GPIO_SET(PHDR, ctrl); 191 1.1 joff 192 1.1 joff /* Step 2: setup time delay */ 193 1.1 joff delay(1); 194 1.1 joff 195 1.1 joff /* Step 3: assert EN */ 196 1.1 joff ctrl |= 0x8; 197 1.1 joff GPIO_SET(PHDR, ctrl); 198 1.1 joff 199 1.1 joff /* Step 4: pulse time delay */ 200 1.1 joff delay(1); 201 1.1 joff 202 1.1 joff /* Step 5: de-assert EN */ 203 1.1 joff ctrl &= ~0x8; 204 1.1 joff GPIO_SET(PHDR, ctrl); 205 1.1 joff 206 1.1 joff /* Step 6: hold time delay */ 207 1.1 joff delay(1); 208 1.1 joff 209 1.1 joff /* Step 7: de-assert WR */ 210 1.1 joff ctrl |= 0x2; 211 1.1 joff GPIO_SET(PHDR, ctrl); 212 1.1 joff 213 1.1 joff /* Step 8: minimum delay till next bus-cycle */ 214 1.1 joff delay(1000); 215 1.1 joff } 216 1.1 joff 217 1.16 skrll static uint8_t 218 1.16 skrll tslcd_readreg(struct hd44780_chip *hd, uint32_t en, uint32_t rs) 219 1.1 joff { 220 1.15 chs struct tslcd_softc *sc = device_private(hd->sc_dev); 221 1.16 skrll uint8_t ret, ctrl; 222 1.2 joff 223 1.2 joff if (hd->sc_dev_ok == 0) 224 1.2 joff return 0; 225 1.1 joff 226 1.1 joff /* Step 1: Apply RS & WR, Send data */ 227 1.2 joff ctrl = GPIO_GET(PHDR); 228 1.1 joff GPIO_SET(PADDR, 0x0); /* set port A to inputs */ 229 1.1 joff if (rs) { 230 1.2 joff ctrl |= 0x30; /* de-assert WR, assert RS */ 231 1.2 joff } else { 232 1.1 joff ctrl |= 0x20; /* de-assert WR */ 233 1.1 joff ctrl &= ~0x10; /* de-assert RS */ 234 1.1 joff } 235 1.1 joff GPIO_SET(PHDR, ctrl); 236 1.1 joff 237 1.1 joff /* Step 2: setup time delay */ 238 1.1 joff delay(1); 239 1.1 joff 240 1.1 joff /* Step 3: assert EN */ 241 1.1 joff ctrl |= 0x8; 242 1.1 joff GPIO_SET(PHDR, ctrl); 243 1.1 joff 244 1.1 joff /* Step 4: pulse time delay */ 245 1.1 joff delay(1); 246 1.1 joff 247 1.1 joff /* Step 5: de-assert EN */ 248 1.1 joff ret = GPIO_GET(PADR) & 0xff; 249 1.1 joff ctrl &= ~0x8; 250 1.1 joff GPIO_SET(PHDR, ctrl); 251 1.1 joff 252 1.1 joff /* Step 6: hold time delay + min bus cycle interval*/ 253 1.1 joff delay(1000); 254 1.1 joff return ret; 255 1.1 joff } 256 1.1 joff 257 1.1 joff int 258 1.11 cegger tslcdopen(dev_t dev, int flag, int mode, struct lwp *l) 259 1.1 joff { 260 1.11 cegger struct tslcd_softc *sc = device_lookup_private(&tslcd_cd, minor(dev)); 261 1.2 joff 262 1.4 joff if (sc->sc_hlcd.sc_dev_ok == 0) 263 1.4 joff return hd44780_init(&sc->sc_hlcd); 264 1.2 joff else 265 1.2 joff return 0; 266 1.1 joff } 267 1.1 joff 268 1.1 joff int 269 1.11 cegger tslcdclose(dev_t dev, int flag, int mode, struct lwp *l) 270 1.1 joff { 271 1.1 joff return 0; 272 1.1 joff } 273 1.1 joff 274 1.1 joff int 275 1.11 cegger tslcdread(dev_t dev, struct uio *uio, int flag) 276 1.1 joff { 277 1.1 joff return EIO; 278 1.1 joff } 279 1.1 joff 280 1.1 joff int 281 1.11 cegger tslcdwrite(dev_t dev, struct uio *uio, int flag) 282 1.1 joff { 283 1.1 joff int error; 284 1.1 joff struct hd44780_io io; 285 1.11 cegger struct tslcd_softc *sc = device_lookup_private(&tslcd_cd, minor(dev)); 286 1.1 joff 287 1.4 joff if (sc->sc_hlcd.sc_dev_ok == 0) 288 1.2 joff return EIO; 289 1.2 joff 290 1.1 joff io.dat = 0; 291 1.1 joff io.len = uio->uio_resid; 292 1.1 joff if (io.len > HD_MAX_CHARS) 293 1.1 joff io.len = HD_MAX_CHARS; 294 1.1 joff 295 1.1 joff if ((error = uiomove((void*)io.buf, io.len, uio)) != 0) 296 1.1 joff return error; 297 1.1 joff 298 1.5 joff hd44780_ddram_redraw(&sc->sc_hlcd, sc->sc_hlcd.sc_curchip, &io); 299 1.1 joff return 0; 300 1.1 joff } 301 1.1 joff 302 1.1 joff int 303 1.11 cegger tslcdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 304 1.1 joff { 305 1.11 cegger struct tslcd_softc *sc = device_lookup_private(&tslcd_cd, minor(dev)); 306 1.4 joff return hd44780_ioctl_subr(&sc->sc_hlcd, cmd, data); 307 1.1 joff } 308 1.1 joff 309 1.1 joff int 310 1.11 cegger tslcdpoll(dev_t dev, int events, struct lwp *l) 311 1.1 joff { 312 1.1 joff return 0; 313 1.1 joff } 314