1 /* $NetBSD: hd44780_subr.c,v 1.1 2003/01/20 01:20:50 soren Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Dennis I. Chernoivanov 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 /* 31 * Subroutines for Hitachi HD44870 style displays 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: hd44780_subr.c,v 1.1 2003/01/20 01:20:50 soren Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/conf.h> 40 #include <sys/kernel.h> 41 #include <sys/types.h> 42 #include <sys/ioccom.h> 43 44 #include <machine/autoconf.h> 45 #include <machine/intr.h> 46 #include <machine/bus.h> 47 48 #include <dev/ic/hd44780reg.h> 49 #include <dev/ic/hd44780_subr.h> 50 51 static void hd44780_init(struct hd44780_chip *); 52 53 /* 54 * Finish device attach. sc_writereg, sc_readreg and sc_flags must be properly 55 * initialized prior to this call. 56 */ 57 void 58 hd44780_attach_subr(sc) 59 struct hd44780_chip *sc; 60 { 61 /* Putc/getc are supposed to be set by platform-dependent code. */ 62 if ((sc->sc_rwrite == NULL) || (sc->sc_rread == NULL)) 63 sc->sc_dev_ok = 0; 64 65 /* Make sure that HD_MAX_CHARS is enough. */ 66 if ((sc->sc_flags & HD_MULTILINE) && (2 * sc->sc_rows > HD_MAX_CHARS)) 67 sc->sc_dev_ok = 0; 68 else if (sc->sc_rows > HD_MAX_CHARS) 69 sc->sc_dev_ok = 0; 70 71 if (sc->sc_dev_ok) { 72 hd44780_init(sc); 73 74 /* Turn display on and clear it. */ 75 hd44780_ir_write(sc, cmd_dispctl(1, 0, 0)); 76 hd44780_ir_write(sc, cmd_clear()); 77 } 78 } 79 80 /* 81 * Initialize 4-bit or 8-bit connected device. 82 */ 83 static void 84 hd44780_init(sc) 85 struct hd44780_chip *sc; 86 { 87 u_int8_t cmd; 88 89 bus_space_tag_t iot; 90 bus_space_handle_t ioh; 91 92 iot = sc->sc_iot; 93 ioh = sc->sc_ioir; 94 95 if (sc->sc_irwrite == NULL) 96 sc->sc_irwrite = sc->sc_rwrite; 97 98 cmd = cmd_init(sc->sc_flags & HD_8BIT); 99 sc->sc_irwrite(iot, ioh, cmd); 100 delay(TIMEOUT_LONG); 101 sc->sc_irwrite(iot, ioh, cmd); 102 sc->sc_irwrite(iot, ioh, cmd); 103 104 cmd = cmd_funcset( 105 sc->sc_flags & HD_8BIT, 106 sc->sc_flags & HD_MULTILINE, 107 sc->sc_flags & HD_BIGFONT); 108 109 if ((sc->sc_flags & HD_8BIT) == 0) 110 sc->sc_irwrite(iot, ioh, cmd); 111 112 /* Interface is set to the proper width, use normal 'write' op. */ 113 sc->sc_rwrite(iot, ioh, cmd); 114 cmd = cmd_dispctl(0, 0, 0); 115 sc->sc_rwrite(iot, ioh, cmd); 116 cmd = cmd_clear(); 117 sc->sc_rwrite(iot, ioh, cmd); 118 cmd = cmd_modset(1, 0); 119 sc->sc_rwrite(iot, ioh, cmd); 120 } 121 122 /* 123 * Standard hd44780 ioctl() functions. 124 */ 125 int 126 hd44780_ioctl_subr(sc, cmd, data) 127 struct hd44780_chip *sc; 128 u_long cmd; 129 caddr_t data; 130 { 131 u_int8_t tmp; 132 int error = 0; 133 134 #define hd44780_io() ((struct hd44780_io *)data) 135 #define hd44780_info() ((struct hd44780_info*)data) 136 #define hd44780_ctrl() ((struct hd44780_dispctl*)data) 137 138 switch (cmd) { 139 /* Clear the LCD. */ 140 case HLCD_CLEAR: 141 hd44780_ir_write(sc, cmd_clear()); 142 break; 143 144 /* Move the cursor one position to the left. */ 145 case HLCD_CURSOR_LEFT: 146 hd44780_ir_write(sc, cmd_shift(0, 0)); 147 break; 148 149 /* Move the cursor one position to the right. */ 150 case HLCD_CURSOR_RIGHT: 151 hd44780_ir_write(sc, cmd_shift(0, 1)); 152 break; 153 154 /* Control the LCD. */ 155 case HLCD_DISPCTL: 156 hd44780_ir_write(sc, cmd_dispctl( 157 hd44780_ctrl()->display_on, 158 hd44780_ctrl()->cursor_on, 159 hd44780_ctrl()->blink_on)); 160 break; 161 162 /* Get LCD configuration. */ 163 case HLCD_GET_INFO: 164 hd44780_info()->lines 165 = (sc->sc_flags & HD_MULTILINE) ? 2 : 1; 166 hd44780_info()->phys_rows = sc->sc_rows; 167 hd44780_info()->virt_rows = sc->sc_vrows; 168 hd44780_info()->is_wide = sc->sc_flags & HD_8BIT; 169 hd44780_info()->is_bigfont = sc->sc_flags & HD_BIGFONT; 170 hd44780_info()->kp_present = sc->sc_flags & HD_KEYPAD; 171 break; 172 173 174 /* Reset the LCD. */ 175 case HLCD_RESET: 176 hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); 177 hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); 178 hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); 179 hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); 180 hd44780_ir_write(sc, cmd_modset(1, 0)); 181 hd44780_ir_write(sc, cmd_dispctl(1, 0, 0)); 182 hd44780_ir_write(sc, cmd_clear()); 183 break; 184 185 /* Get the current cursor position. */ 186 case HLCD_GET_CURSOR_POS: 187 hd44780_io()->dat = (hd44780_ir_read(sc) & 0x7f); 188 break; 189 190 /* Set the cursor position. */ 191 case HLCD_SET_CURSOR_POS: 192 hd44780_ir_write(sc, cmd_ddramset(hd44780_io()->dat)); 193 break; 194 195 /* Get the value at the current cursor position. */ 196 case HLCD_GETC: 197 tmp = (hd44780_ir_read(sc) & 0x7f); 198 hd44780_ir_write(sc, cmd_ddramset(tmp)); 199 hd44780_io()->dat = hd44780_dr_read(sc); 200 break; 201 202 /* Set the character at the cursor position + advance cursor. */ 203 case HLCD_PUTC: 204 hd44780_dr_write(sc, hd44780_io()->dat); 205 break; 206 207 /* Shift display left. */ 208 case HLCD_SHIFT_LEFT: 209 hd44780_ir_write(sc, cmd_shift(1, 0)); 210 break; 211 212 /* Shift display right. */ 213 case HLCD_SHIFT_RIGHT: 214 hd44780_ir_write(sc, cmd_shift(1, 1)); 215 break; 216 217 /* Return home. */ 218 case HLCD_HOME: 219 hd44780_ir_write(sc, cmd_rethome()); 220 break; 221 222 /* Write a string to the LCD virtual area. */ 223 case HLCD_WRITE: 224 error = hd44780_ddram_io(sc, hd44780_io(), HD_DDRAM_WRITE); 225 break; 226 227 /* Read LCD virtual area. */ 228 case HLCD_READ: 229 error = hd44780_ddram_io(sc, hd44780_io(), HD_DDRAM_READ); 230 break; 231 232 /* Write to the LCD visible area. */ 233 case HLCD_REDRAW: 234 hd44780_ddram_redraw(sc, hd44780_io()); 235 break; 236 237 /* Write raw instruction. */ 238 case HLCD_WRITE_INST: 239 hd44780_ir_write(sc, hd44780_io()->dat); 240 break; 241 242 /* Write raw data. */ 243 case HLCD_WRITE_DATA: 244 hd44780_dr_write(sc, hd44780_io()->dat); 245 break; 246 247 default: 248 error = EINVAL; 249 } 250 251 return error; 252 } 253 254 /* 255 * Read/write particular area of the LCD screen. 256 */ 257 int 258 hd44780_ddram_io(sc, io, dir) 259 struct hd44780_chip *sc; 260 struct hd44780_io *io; 261 u_char dir; 262 { 263 u_int8_t hi; 264 u_int8_t addr; 265 266 int error = 0; 267 u_int8_t i = 0; 268 269 if (io->dat < sc->sc_vrows) { 270 hi = HD_ROW1_ADDR + sc->sc_vrows; 271 addr = HD_ROW1_ADDR + io->dat; 272 for (; (addr < hi) && (i < io->len); addr++, i++) { 273 hd44780_ir_write(sc, cmd_ddramset(addr)); 274 if (dir == HD_DDRAM_READ) 275 io->buf[i] = hd44780_dr_read(sc); 276 else 277 hd44780_dr_write(sc, io->buf[i]); 278 } 279 } 280 if (io->dat < 2 * sc->sc_vrows) { 281 hi = HD_ROW2_ADDR + sc->sc_vrows; 282 if (io->dat >= sc->sc_vrows) 283 addr = HD_ROW2_ADDR + io->dat - sc->sc_vrows; 284 else 285 addr = HD_ROW2_ADDR; 286 for (; (addr < hi) && (i < io->len); addr++, i++) { 287 hd44780_ir_write(sc, cmd_ddramset(addr)); 288 if (dir == HD_DDRAM_READ) 289 io->buf[i] = hd44780_dr_read(sc); 290 else 291 hd44780_dr_write(sc, io->buf[i]); 292 } 293 if (i < io->len) 294 io->len = i; 295 } else { 296 error = EINVAL; 297 } 298 return error; 299 } 300 301 /* 302 * Write to the visible area of the display. 303 */ 304 void 305 hd44780_ddram_redraw(sc, io) 306 struct hd44780_chip *sc; 307 struct hd44780_io *io; 308 { 309 u_int8_t i; 310 311 hd44780_ir_write(sc, cmd_clear()); 312 hd44780_ir_write(sc, cmd_rethome()); 313 for (i = 0; (i < io->len) && (i < sc->sc_rows); i++) { 314 hd44780_dr_write(sc, io->buf[i]); 315 } 316 hd44780_ir_write(sc, cmd_ddramset(HD_ROW2_ADDR)); 317 for (; (i < io->len); i++) 318 hd44780_dr_write(sc, io->buf[i]); 319 } 320 321 #if defined(HD44780_STD_WIDE) 322 /* 323 * Standard 8-bit version of 'sc_rwrite' (8-bit port, 8-bit access) 324 */ 325 void 326 hd44780_rwrite(iot, ioh, cmd) 327 bus_space_tag_t iot; 328 bus_space_handle_t ioh; 329 u_int8_t cmd; 330 { 331 bus_space_write_1(iot, ioh, 0x00, cmd); 332 delay(TIMEOUT_NORMAL); 333 } 334 335 /* 336 * Standard 8-bit version of 'sc_rread' (8-bit port, 8-bit access) 337 */ 338 u_int8_t 339 hd44780_rread(iot, ioh) 340 bus_space_tag_t iot; 341 bus_space_handle_t ioh; 342 { 343 delay(TIMEOUT_NORMAL); 344 return bus_space_read_1(iot, ioh, 0x00); 345 } 346 #elif defined(HD44780_STD_SHORT) 347 /* 348 * Standard 4-bit version of 'sc_irwrite' (4-bit port, 8-bit access) 349 */ 350 void 351 hd44780_irwrite(iot, ioh, cmd) 352 bus_space_tag_t iot; 353 bus_space_handle_t ioh; 354 u_int8_t cmd; 355 { 356 /* first four instructions emitted in 8-bit mode */ 357 bus_space_write_1(iot, ioh, 0x00, hi_bits(cmd)); 358 delay(TIMEOUT_NORMAL); 359 } 360 361 /* 362 * Standard 4-bit version of 'sc_rrwrite' (4-bit port, 8-bit access) 363 */ 364 void 365 hd44780_rwrite(iot, ioh, cmd) 366 bus_space_tag_t iot; 367 bus_space_handle_t ioh; 368 u_int8_t cmd; 369 { 370 bus_space_write_1(iot, ioh, 0x00, hi_bits(cmd)); 371 bus_space_write_1(iot, ioh, 0x00, lo_bits(cmd)); 372 delay(TIMEOUT_NORMAL); 373 } 374 375 /* 376 * Standard 4-bit version of 'sc_rread' (4-bit port, 8-bit access) 377 */ 378 u_int8_t 379 hd44780_rread(iot, ioh) 380 bus_space_tag_t iot; 381 bus_space_handle_t ioh; 382 { 383 u_int8_t rd; 384 u_int8_t dat; 385 386 delay(TIMEOUT_NORMAL); 387 rd = bus_space_read_1(iot, ioh, 0x00); 388 dat = (rd & 0x0f) << 4; 389 rd = bus_space_read_1(iot, ioh, 0x00); 390 return (dat | (rd & 0x0f)); 391 } 392 #endif 393