Home | History | Annotate | Line # | Download | only in ic
hd44780_subr.c revision 1.1
      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