diff --git a/sys/dev/ic/hd44780_subr.c b/sys/dev/ic/hd44780_subr.c index 1765a3594d4e..d0aef56ed7f8 100644 --- a/sys/dev/ic/hd44780_subr.c +++ b/sys/dev/ic/hd44780_subr.c @@ -1,4 +1,4 @@ -/* $NetBSD: hd44780_subr.c,v 1.2 2005/01/08 20:17:22 joff Exp $ */ +/* $NetBSD: hd44780_subr.c,v 1.3 2005/01/09 15:43:56 joff Exp $ */ /* * Copyright (c) 2002 Dennis I. Chernoivanov @@ -32,7 +32,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: hd44780_subr.c,v 1.2 2005/01/08 20:17:22 joff Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hd44780_subr.c,v 1.3 2005/01/09 15:43:56 joff Exp $"); #include #include @@ -48,8 +48,6 @@ __KERNEL_RCSID(0, "$NetBSD: hd44780_subr.c,v 1.2 2005/01/08 20:17:22 joff Exp $" #include #include -static void hd44780_init(struct hd44780_chip *); - /* * Finish device attach. sc_writereg, sc_readreg and sc_flags must be properly * initialized prior to this call. @@ -58,6 +56,7 @@ void hd44780_attach_subr(sc) struct hd44780_chip *sc; { + int err = 0; /* Putc/getc are supposed to be set by platform-dependent code. */ if ((sc->sc_writereg == NULL) || (sc->sc_readreg == NULL)) sc->sc_dev_ok = 0; @@ -69,24 +68,25 @@ hd44780_attach_subr(sc) sc->sc_dev_ok = 0; if (sc->sc_dev_ok) { - if ((sc->sc_flags & HD_UP) == 0) - hd44780_init(sc); + if ((sc->sc_flags & HD_UP) == 0) + err = hd44780_init(sc); + if (err != 0) + printf("%s: not responding or unconnected\n", sc->sc_dev->dv_xname); - /* Turn display on and clear it. */ - hd44780_ir_write(sc, cmd_dispctl(1, 0, 0)); - hd44780_ir_write(sc, cmd_clear()); } } /* * Initialize 4-bit or 8-bit connected device. */ -static void +int hd44780_init(sc) struct hd44780_chip *sc; { - u_int8_t cmd; + u_int8_t cmd, dat; + sc->sc_flags &= ~(HD_TIMEDOUT|HD_UP); + sc->sc_dev_ok = 1; cmd = cmd_init(sc->sc_flags & HD_8BIT); hd44780_ir_write(sc, cmd); delay(HD_TIMEOUT_LONG); @@ -107,6 +107,28 @@ hd44780_init(sc) hd44780_ir_write(sc, cmd_dispctl(0, 0, 0)); hd44780_ir_write(sc, cmd_clear()); hd44780_ir_write(sc, cmd_modset(1, 0)); + + if (sc->sc_flags & HD_TIMEDOUT) { + sc->sc_flags &= ~HD_UP; + return EIO; + } + + /* Turn display on and clear it. */ + hd44780_ir_write(sc, cmd_clear()); + hd44780_ir_write(sc, cmd_dispctl(1, 0, 0)); + + /* Attempt a simple probe for presence */ + hd44780_ir_write(sc, cmd_ddramset(0x5)); + hd44780_ir_write(sc, cmd_shift(0, 1)); + hd44780_busy_wait(sc); + if ((dat = hd44780_ir_read(sc) & 0x7f) != 0x6) { + sc->sc_dev_ok = 0; + sc->sc_flags &= ~HD_UP; + return EIO; + } + hd44780_ir_write(sc, cmd_ddramset(0)); + + return 0; } /* @@ -163,13 +185,7 @@ hd44780_ioctl_subr(sc, cmd, data) /* Reset the LCD. */ case HLCD_RESET: - hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); - hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); - hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); - hd44780_ir_write(sc, cmd_init(sc->sc_flags & HD_8BIT)); - hd44780_ir_write(sc, cmd_modset(1, 0)); - hd44780_ir_write(sc, cmd_dispctl(1, 0, 0)); - hd44780_ir_write(sc, cmd_clear()); + error = hd44780_init(sc); break; /* Get the current cursor position. */ @@ -238,6 +254,9 @@ hd44780_ioctl_subr(sc, cmd, data) error = EINVAL; } + if (sc->sc_flags & HD_TIMEDOUT) + error = EIO; + return error; } @@ -308,6 +327,23 @@ hd44780_ddram_redraw(sc, io) hd44780_dr_write(sc, io->buf[i]); } +void +hd44780_busy_wait(sc) + struct hd44780_chip *sc; +{ + int nloops = 100; + + if (sc->sc_flags & HD_TIMEDOUT) + return; + + while(nloops-- && (hd44780_ir_read(sc) & BUSY_FLAG) == BUSY_FLAG); + + if (nloops == 0) { + sc->sc_flags |= HD_TIMEDOUT; + sc->sc_dev_ok = 0; + } +} + #if defined(HD44780_STD_WIDE) /* * Standard 8-bit version of 'sc_writereg' (8-bit port, 8-bit access) @@ -321,6 +357,9 @@ hd44780_writereg(sc, reg, cmd) bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh; + if (sc->sc_dev_ok == 0) + return; + if (reg == 0) ioh = sc->sc_ioir; else @@ -341,6 +380,9 @@ hd44780_readreg(sc, reg) bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh; + if (sc->sc_dev_ok == 0) + return; + if (reg == 0) ioh = sc->sc_ioir; else @@ -362,6 +404,9 @@ hd44780_writereg(sc, reg, cmd) bus_space_tag_t iot = sc->sc_iot; bus_space_handle_t ioh; + if (sc->sc_dev_ok == 0) + return; + if (reg == 0) ioh = sc->sc_ioir; else @@ -385,6 +430,9 @@ hd44780_readreg(sc, reg) bus_space_handle_t ioh; u_int8_t rd, dat; + if (sc->sc_dev_ok == 0) + return; + if (reg == 0) ioh = sc->sc_ioir; else diff --git a/sys/dev/ic/hd44780_subr.h b/sys/dev/ic/hd44780_subr.h index d2206aa57c00..6dafe853817b 100644 --- a/sys/dev/ic/hd44780_subr.h +++ b/sys/dev/ic/hd44780_subr.h @@ -1,4 +1,4 @@ -/* $NetBSD: hd44780_subr.h,v 1.2 2005/01/08 20:17:22 joff Exp $ */ +/* $NetBSD: hd44780_subr.h,v 1.3 2005/01/09 15:43:56 joff Exp $ */ /* * Copyright (c) 2002 Dennis I. Chernoivanov @@ -81,6 +81,7 @@ struct hd44780_chip { #define HD_BIGFONT 0x04 /* 5x10 if set, 5x8 otherwise */ #define HD_KEYPAD 0x08 /* if set, keypad is connected */ #define HD_UP 0x10 /* if set, lcd has been initialized */ +#define HD_TIMEDOUT 0x20 /* lcd has recently stopped talking */ u_char sc_flags; u_char sc_rows; /* visible rows */ @@ -99,9 +100,6 @@ struct hd44780_chip { u_int8_t (* sc_readreg)(struct hd44780_chip *, u_int32_t); }; -#define hd44780_busy_wait(sc) \ - while((hd44780_ir_read(sc) & BUSY_FLAG) == BUSY_FLAG) - #define hd44780_ir_write(sc, dat) \ do { \ hd44780_busy_wait(sc); \ @@ -118,6 +116,8 @@ struct hd44780_chip { (sc)->sc_readreg((sc), 1) void hd44780_attach_subr(struct hd44780_chip *); +void hd44780_busy_wait(struct hd44780_chip *); +int hd44780_init(struct hd44780_chip *); int hd44780_ioctl_subr(struct hd44780_chip *, u_long, caddr_t); void hd44780_ddram_redraw(struct hd44780_chip *, struct hd44780_io *);