Index: src/sys/dev/ic/hd44780_subr.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/hd44780_subr.c,v
retrieving revision 1.21
diff -u -p -r1.21 hd44780_subr.c
--- src/sys/dev/ic/hd44780_subr.c	13 Nov 2010 13:52:01 -0000	1.21
+++ src/sys/dev/ic/hd44780_subr.c	21 Nov 2018 08:55:25 -0000
@@ -393,6 +393,15 @@ hd44780_attach_subr(struct hd44780_chip 
 	callout_setfunc(&sc->redraw, hlcd_redraw, sc);
 }
 
+void hd44780_detach(struct hd44780_chip *sc)
+{
+	callout_stop(&sc->redraw);
+	callout_destroy(&sc->redraw);
+
+	if (sc->sc_screen.image)
+		free(sc->sc_screen.image, M_DEVBUF);
+}
+
 int hd44780_init(struct hd44780_chip *sc)
 {
 	int ret;
@@ -427,7 +436,7 @@ hd44780_chipinit(struct hd44780_chip *sc
 			sc->sc_flags & HD_BIGFONT);
 
 	if ((sc->sc_flags & HD_8BIT) == 0)
-		hd44780_ir_write(sc, en, cmd);
+		hd44780_ir_write(sc, en, HD_INIT_4BIT);
 
 	sc->sc_flags |= HD_UP;
 
@@ -449,7 +458,7 @@ hd44780_chipinit(struct hd44780_chip *sc
 	hd44780_ir_write(sc, en, cmd_ddramset(0x5));
 	hd44780_ir_write(sc, en, cmd_shift(0, 1));
 	hd44780_busy_wait(sc, en);
-	if ((dat = hd44780_ir_read(sc, en) & 0x7f) != 0x6) {
+	if (!sc->sc_simplex && (dat = hd44780_ir_read(sc, en) & 0x7f) != 0x6) {
 		sc->sc_dev_ok = 0;
 		sc->sc_flags &= ~HD_UP;
 		return EIO;
Index: src/sys/dev/ic/hd44780reg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/hd44780reg.h,v
retrieving revision 1.4
diff -u -p -r1.4 hd44780reg.h
--- src/sys/dev/ic/hd44780reg.h	30 Aug 2009 02:07:05 -0000	1.4
+++ src/sys/dev/ic/hd44780reg.h	21 Nov 2018 08:55:25 -0000
@@ -43,6 +43,8 @@
 #define HD_TIMEOUT_SHORT	100
 #define HD_TIMEOUT_NORMAL	200
 
+#define HD_INIT_4BIT	0x02
+
 #define	BUSY_FLAG	0x80
 
 /* Bit set helper */
Index: src/sys/dev/ic/hd44780var.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/hd44780var.h,v
retrieving revision 1.8
diff -u -p -r1.8 hd44780var.h
--- src/sys/dev/ic/hd44780var.h	6 Sep 2015 06:01:00 -0000	1.8
+++ src/sys/dev/ic/hd44780var.h	21 Nov 2018 08:55:25 -0000
@@ -118,6 +118,7 @@ struct hd44780_chip {
 	void     (* sc_writereg)(struct hd44780_chip *, uint32_t, uint32_t,
 	  uint8_t);
 	uint8_t (* sc_readreg)(struct hd44780_chip *, uint32_t, uint32_t);
+	bool sc_simplex;		/* Output only device */
 };
 
 #define hd44780_ir_write(sc, en, dat) \
@@ -136,6 +137,7 @@ struct hd44780_chip {
 	(sc)->sc_readreg((sc), (en), 1)
 
 void hd44780_attach_subr(struct hd44780_chip *);
+void hd44780_detach(struct hd44780_chip *);
 void hd44780_busy_wait(struct hd44780_chip *, uint32_t);
 int  hd44780_init(struct hd44780_chip *);
 int  hd44780_chipinit(struct hd44780_chip *, uint32_t);
Index: src/sys/dev/i2c/files.i2c
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/files.i2c,v
retrieving revision 1.96
diff -u -p -r1.96 files.i2c
--- src/sys/dev/i2c/files.i2c	2 Sep 2018 01:16:58 -0000	1.96
+++ src/sys/dev/i2c/files.i2c	21 Nov 2018 08:56:05 -0000
@@ -356,3 +356,8 @@ device	rkreg: rkpmic
 attach	rkpmic at iic
 attach	rkreg at rkpmic
 file	dev/i2c/rkpmic.c			rkpmic
+
+# 1602A IIC LCD MODULE
+device	i2clcd: hd44780, wsemuldisplaydev
+attach	i2clcd at iic
+file	dev/i2c/i2clcd.c			i2clcd
--- /dev/null	2018-11-21 17:30:31.000000000 +1100
+++ src/sys/dev/i2c/i2clcd.c	2018-10-16 11:09:02.000000000 +1100
@@ -0,0 +1,512 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2018 Nathanial Sloss <nathanialsloss@yahoo.com.au>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2002 Dennis I. Chernoivanov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Device driver for an Hitachi 44780 compatible LCD display and PCF8574 i2c
+ * interface.
+ *
+ *  This driver was based on sys/arch/cobalt/dev/lcdpanel.c.
+ */
+
+/*
+ * The PCF8574 connects to an Hitachi LCD display as follows:
+ *	P0 - R/S
+ *	P1 - R/W
+ *	P2 - E / CLOCK
+ *	P3 - BACKLIGHT (1/0) ON/OFF
+ *	P4 - DATA 4
+ *	P5 - DATA 5
+ *	P6 - DATA 6
+ *	P7 - DATA 7
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/types.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/callout.h>
+#include <sys/select.h>
+#include <sys/sysctl.h>
+#include <sys/endian.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <machine/autoconf.h>
+
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wscons_callbacks.h>
+
+#include <dev/ic/hd44780reg.h>
+#include <dev/ic/hd44780var.h>
+
+#include "ioconf.h"
+
+#define	LCD_ADDR_MIN		0x27	/* I2C address 001 1xxx */
+#define	LCD_ADDR_MAX		0x47	/* I2C address 001 1xxx */
+#define LCD_I2C_ENB		0x04
+#define LCD_I2C_BACKLIGHT	0x08
+#define LCDPANEL_POLLRATE	(hz / 10)
+#define LCDPANEL_REGION	0x20
+#define DATA_OFFSET	0x0
+#define LCDPANEL_COLS	16
+#define LCDPANEL_VCOLS	40
+#define LCDPANEL_ROWS	2
+
+struct i2clcd_softc {
+	device_t		 sc_dev;
+	i2c_tag_t		 sc_tag;
+	int			 sc_address;
+
+	struct hd44780_chip	 sc_lcd;
+
+	struct sysctllog	*sc_log;	/* sysctl log */
+	bool			 sc_backlight;
+	int			 sc_rows;
+	struct selinfo		 sc_selq;
+};
+
+struct lcd_message {
+	char firstrow[LCDPANEL_VCOLS];
+	char secondrow[LCDPANEL_VCOLS];
+};
+static struct lcd_message startup_message = {
+	"PCF8574 I2C LCD ",
+	"Address:        "
+};
+
+static int	i2clcd_match(device_t, cfdata_t, void *);
+static void	i2clcd_attach(device_t, device_t, void *);
+static int  	i2clcd_detach(device_t, int);
+static int	i2clcd_reattach(struct i2clcd_softc *);
+
+static int	i2clcd_sysctl_columns(SYSCTLFN_PROTO);
+static int	i2clcd_sysctl_rows(SYSCTLFN_PROTO);
+
+static uint8_t	i2clcd_hdreadreg(struct hd44780_chip *, uint32_t, uint32_t);
+static void	i2clcd_hdwritereg(struct hd44780_chip *, uint32_t, uint32_t,
+    uint8_t);
+static void	i2clcd_hdwrite_nibble(struct hd44780_chip *, uint32_t, uint8_t);
+
+dev_type_open(i2clcdopen);
+dev_type_close(i2clcdclose);
+dev_type_read(i2clcdread);
+dev_type_write(i2clcdwrite);
+dev_type_ioctl(i2clcdioctl);
+
+const struct cdevsw i2clcd_cdevsw = {
+	.d_open = i2clcdopen,
+	.d_close = i2clcdclose,
+	.d_read = noread,
+	.d_write = i2clcdwrite,
+	.d_ioctl = i2clcdioctl,
+	.d_stop = nostop,
+	.d_tty = notty,
+	.d_poll = nopoll,
+	.d_mmap = nommap,
+	.d_kqfilter = nokqfilter,
+	.d_discard = nodiscard,
+	.d_flag = 0
+};
+
+extern const struct wsdisplay_emulops hlcd_emulops;
+extern const struct wsdisplay_accessops hlcd_accessops;
+
+static struct wsscreen_descr i2clcd_stdscreen = {
+	"std_tslcd", 16, 2,
+	&hlcd_emulops,
+	5, 7,
+	0,
+};
+
+static const struct wsscreen_descr *_i2clcd_scrlist[] = {
+	&i2clcd_stdscreen,
+};
+
+static const struct wsscreen_list i2clcd_screenlist = {
+	sizeof(_i2clcd_scrlist) / sizeof(struct wsscreen_descr *),
+	_i2clcd_scrlist,
+};
+
+CFATTACH_DECL_NEW(i2clcd, sizeof(struct i2clcd_softc),
+    i2clcd_match, i2clcd_attach, i2clcd_detach, NULL);
+
+static int
+i2clcd_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct i2c_attach_args *ia = aux;
+	uint8_t error, loc;
+
+	if (ia->ia_addr < LCD_ADDR_MIN || ia->ia_addr > LCD_ADDR_MAX)
+		return 0;
+
+	if (iic_acquire_bus(ia->ia_tag, 0) != 0)
+		return 0;
+
+	loc = 0;
+	iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP,
+	    ia->ia_addr, &loc, 1, &error, sizeof(error), 0);
+	iic_release_bus(ia->ia_tag, 0);
+
+	return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
+
+}
+
+static void
+i2clcd_attach(device_t parent, device_t self, void *aux)
+{
+	struct i2clcd_softc *sc = device_private(self);
+	struct i2c_attach_args *ia = aux;
+	struct hd44780_io io;
+	struct wsemuldisplaydev_attach_args waa;
+	const struct sysctlnode *node;
+
+	sc->sc_dev = self;
+	sc->sc_tag = ia->ia_tag;
+	sc->sc_address = ia->ia_addr;
+	sc->sc_rows = 2;
+	sc->sc_backlight = true;
+
+	sc->sc_lcd.sc_dev = self;
+	sc->sc_lcd.sc_iot = NULL;
+	sc->sc_lcd.sc_ioir = 0x0;
+	sc->sc_lcd.sc_iodr = sc->sc_lcd.sc_ioir + DATA_OFFSET;
+
+	aprint_normal("\n");
+
+	sc->sc_lcd.sc_dev_ok = 1;
+	/* Dont test reading the instruction register as this fails */
+	sc->sc_lcd.sc_simplex = true;
+	sc->sc_lcd.sc_cols = LCDPANEL_COLS;
+	sc->sc_lcd.sc_vcols = LCDPANEL_VCOLS;
+	sc->sc_lcd.sc_flags = HD_MULTILINE;
+
+	sc->sc_lcd.sc_writereg = i2clcd_hdwritereg;
+	sc->sc_lcd.sc_readreg = i2clcd_hdreadreg;
+
+	hd44780_attach_subr(&sc->sc_lcd);
+
+	snprintf(startup_message.secondrow, LCDPANEL_VCOLS,
+		 " Address: 0x%03x ", sc->sc_address);
+
+	/* Hello World */
+	io.dat = 0;
+	io.len = LCDPANEL_VCOLS * LCDPANEL_ROWS;
+	memcpy(io.buf, &startup_message, io.len);
+	hd44780_ddram_io(&sc->sc_lcd, sc->sc_lcd.sc_curchip, &io,
+	    HD_DDRAM_WRITE);
+
+	sysctl_createv(&sc->sc_log, 0, NULL, &node,
+		0,
+		CTLTYPE_NODE, device_xname(sc->sc_dev),
+		SYSCTL_DESCR("I2C LCD parameters"),
+		NULL, 0,
+		NULL, 0,
+		CTL_HW,
+		CTL_CREATE, CTL_EOL);
+
+	if (node != NULL) {
+		sysctl_createv(&sc->sc_log, 0, NULL, NULL,
+			CTLFLAG_READWRITE,
+			CTLTYPE_BOOL, "backlight",
+			SYSCTL_DESCR("enable backlight"),
+			NULL, 0,
+			&sc->sc_backlight, 0,
+			CTL_HW, node->sysctl_num,
+			CTL_CREATE, CTL_EOL);
+
+		sysctl_createv(&sc->sc_log, 0, NULL, NULL,
+			CTLFLAG_READWRITE,
+			CTLTYPE_INT, "columns",
+			SYSCTL_DESCR("no. of columns"),
+			i2clcd_sysctl_columns, 0,
+			(void *)sc, 0,
+			CTL_HW, node->sysctl_num,
+			CTL_CREATE, CTL_EOL);
+
+		sysctl_createv(&sc->sc_log, 0, NULL, NULL,
+			CTLFLAG_READWRITE,
+			CTLTYPE_INT, "rows",
+			SYSCTL_DESCR("no. of rows"),
+			i2clcd_sysctl_rows, 0,
+			(void *)sc, 0,
+			CTL_HW, node->sysctl_num,
+			CTL_CREATE, CTL_EOL);
+
+	}
+
+	selinit(&sc->sc_selq);
+
+	waa.console = 0;
+	waa.scrdata = &i2clcd_screenlist;
+	waa.accessops = &hlcd_accessops;
+	waa.accesscookie = &sc->sc_lcd.sc_screen;
+	config_found(self, &waa, wsemuldisplaydevprint);
+}
+
+static int
+i2clcd_reattach(struct i2clcd_softc *sc)
+{
+	struct wsemuldisplaydev_attach_args waa;
+	int rc;
+
+	if ((rc = config_detach_children(sc->sc_dev, 0)) != 0)
+		return rc;
+
+	hd44780_detach(&sc->sc_lcd);
+
+	if (sc->sc_rows == 2)
+		sc->sc_lcd.sc_flags = HD_MULTILINE;
+	else
+		sc->sc_lcd.sc_flags = 0;
+
+	hd44780_attach_subr(&sc->sc_lcd);
+
+	i2clcd_stdscreen.ncols = sc->sc_lcd.sc_cols;
+	i2clcd_stdscreen.nrows = sc->sc_rows;
+
+	waa.console = 0;
+	waa.scrdata = &i2clcd_screenlist;
+	waa.accessops = &hlcd_accessops;
+	waa.accesscookie = &sc->sc_lcd.sc_screen;
+
+	config_found(sc->sc_dev, &waa, wsemuldisplaydevprint);
+
+	return 0;
+}
+
+static int
+i2clcd_detach(device_t self, int flags)
+{
+	struct i2clcd_softc *sc = device_private(self);
+	int rc;
+
+	if ((rc = config_detach_children(self, flags | DETACH_FORCE)) != 0)
+		return rc;
+
+	/* delete sysctl nodes */
+	sysctl_teardown(&sc->sc_log);
+
+	hd44780_detach(&sc->sc_lcd);
+
+	seldestroy(&sc->sc_selq);
+
+	return 0;
+}
+
+static void
+i2clcd_hdwritereg(struct hd44780_chip *hd, uint32_t en, uint32_t rs,
+    uint8_t dat)
+{
+	struct i2clcd_softc *sc = device_private(hd->sc_dev);
+
+	if (sc == NULL)
+		return;
+
+	i2clcd_hdwrite_nibble(hd, rs, (dat & 0xf0) >> 4);
+	i2clcd_hdwrite_nibble(hd, rs, dat & 0x0f);
+}
+
+static void
+i2clcd_hdwrite_nibble(struct hd44780_chip *hd, uint32_t rs, uint8_t dat)
+{
+	struct i2clcd_softc *sc = device_private(hd->sc_dev);
+
+	dat = ((dat << 4) & 0xf0) | rs;
+	if (sc->sc_backlight)
+		dat |= LCD_I2C_BACKLIGHT;
+
+	delay(HD_TIMEOUT_NORMAL);
+	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+	    sc->sc_address, &sc->sc_lcd.sc_ioir, 1, &dat, sizeof(dat), 0);
+	delay(HD_TIMEOUT_NORMAL);
+
+	dat |= LCD_I2C_ENB;
+	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+	    sc->sc_address, &sc->sc_lcd.sc_ioir, 1, &dat, sizeof(dat), 0);
+	delay(HD_TIMEOUT_NORMAL);
+
+	dat &= ~LCD_I2C_ENB;
+	iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+	    sc->sc_address, &sc->sc_lcd.sc_ioir, 1, &dat, sizeof(dat), 0);
+	delay(HD_TIMEOUT_NORMAL);
+}
+
+static uint8_t
+i2clcd_hdreadreg(struct hd44780_chip *hd, uint32_t en, uint32_t rs)
+{
+	struct i2clcd_softc *sc = device_private(hd->sc_dev);
+
+	if (sc == NULL)
+		return 0;
+
+	/*
+	 * The PCF8574 can only be used as a simplex device as it is 
+	 * quasi bidirectonal.
+	 */
+
+	delay(HD_TIMEOUT_NORMAL);
+
+	return 0;
+
+}
+
+int
+i2clcdopen(dev_t dev, int flag, int mode, struct lwp *l)
+{
+	struct i2clcd_softc *sc = device_lookup_private(&i2clcd_cd, minor(dev));
+
+	if (sc == NULL)
+		return ENXIO;
+
+	return sc->sc_lcd.sc_dev_ok == 0 ? ENXIO : 0;
+}
+
+int
+i2clcdclose(dev_t dev, int flag, int mode, struct lwp *l)
+{
+	struct i2clcd_softc *sc = device_lookup_private(&i2clcd_cd, minor(dev));
+
+	selnotify(&sc->sc_selq, 0, 0);
+	return 0;
+}
+
+int
+i2clcdwrite(dev_t dev, struct uio *uio, int flag)
+{
+	int error;
+	struct hd44780_io io;
+	struct i2clcd_softc *sc = device_lookup_private(&i2clcd_cd, minor(dev));
+
+	io.dat = 0;
+	io.len = uio->uio_resid;
+	if (io.len > HD_MAX_CHARS)
+		io.len = HD_MAX_CHARS;
+
+	if ((error = uiomove((void*)io.buf, io.len, uio)) != 0)
+		return error;
+
+	hd44780_ddram_redraw(&sc->sc_lcd, 0, &io);
+	return 0;
+}
+
+int
+i2clcdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
+{
+	struct i2clcd_softc *sc = device_lookup_private(&i2clcd_cd, minor(dev));
+
+	return hd44780_ioctl_subr(&sc->sc_lcd, cmd, data);
+}
+
+/* sysctl helper to set display coloumns */
+static int
+i2clcd_sysctl_columns(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct i2clcd_softc *sc;
+	int t, error;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+
+	t = sc->sc_lcd.sc_cols;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (t <= 0 || t > LCDPANEL_VCOLS)
+		return EINVAL;
+
+	sc->sc_lcd.sc_cols = t;
+	error = i2clcd_reattach(sc);
+
+	return error;
+}
+
+/* sysctl helper to set display rows */
+static int
+i2clcd_sysctl_rows(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	struct i2clcd_softc *sc;
+	int t, error;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+
+	t = sc->sc_rows;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (t < 1 || t > 2)
+		return EINVAL;
+
+	sc->sc_rows = t;
+	error = i2clcd_reattach(sc);
+
+	return error;
+}
+
Index: src/sys/conf/majors
===================================================================
RCS file: /cvsroot/src/sys/conf/majors,v
retrieving revision 1.80
diff -u -p -r1.80 majors
--- src/sys/conf/majors	7 Nov 2018 07:43:07 -0000	1.80
+++ src/sys/conf/majors	21 Nov 2018 08:57:36 -0000
@@ -72,6 +74,7 @@ device-major lua       char 209		   lua
 # 310-339 reserved for previously not MI storage devices
 
 device-major spkr      char 240		   spkr
+device-major i2clcd    char 241		   i2clcd
 
 device-major hdmicec   char 340		   hdmicec
 device-major nvme      char 341		   nvme
--- /dev/null	2018-11-21 17:30:31.000000000 +1100
+++ src/share/man/man4/i2clcd.4	2018-11-21 19:54:29.000000000 +1100
@@ -0,0 +1,76 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2018  Nathanial Sloss <nathanialsloss@yahoo.com.au>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd November 21, 2018
+.Dt I2CLCD 4
+.Os
+.Sh NAME
+.Nm i2clcd
+.Nd i2c PCF8574(A) LCD graphics driver for wscons
+.Sh SYNOPSIS
+.Cd "i2clcd* at iic0 addr 0x27 flags 0"
+.Pp
+.Cd "wsdisplay* at i2clcd? console ?"
+.Sh DESCRIPTION
+This driver handles a display (Hitachi 44780 or compatible) driven by a PCF8574
+or PCF8574A i2c 8-bit IO expander.
+.Pp
+The number of columns and rows of the display are set by
+.Xr sysctl 8
+interface.
+The display is initally set to 16x2 with the i2c address displayed on screen
+when the device is attached.
+.Pp
+The following
+.Xr sysctl 8
+variables are used to set the display properties:
+.Bl -tag -width "hw.i2clcdN.backlight" -compact -offset indent
+.It Li hw. Ns Ar i2clcdN Ns Li .backlight
+(0 / 1) defaults to 1 (on) turns on the backlight.
+.It Li hw. Ns Ar i2clcdN Ns Li .coloumns
+(1-64) defaults to 16 columns.
+.It Li hw. Ns Ar i2clcdN Ns Li .rows
+(1 / 2) defaults to 2 rows.
+.El
+.Pp
+It is possible to write characters when writing to the device (See files below)
+or the attached wscons device.
+.Pp
+Reading the character generator memory (CGRAM) or status bit are not supported.
+It is only possible to write to the display.
+The display is operated in 4 bit mode with the lower 4 data lines unconnected.
+.Pp
+The PCF8574 modules may operate using a different i2c address which is user
+configurable by jumpers or solder pads on the module.
+Addresses usually range from 0x27 through to 0x3f.
+.Sh FILES
+/dev/lcd0
+.Sh SEE ALSO
+.Xr wscons 4 ,
+.Xr sysctl 8 ,
+.Xr wsconscfg 8
+.Sh AUTHORS
+.An Nathanial Sloss
Index: src/distrib/sets/lists/man/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.1627
diff -u -p -r1.1627 mi
--- src/distrib/sets/lists/man/mi	30 Sep 2018 15:56:47 -0000	1.1627
+++ src/distrib/sets/lists/man/mi	21 Nov 2018 09:08:26 -0000
@@ -1231,6 +1231,7 @@
 ./usr/share/man/cat4/hpqlb.0			man-sys-catman		.cat
 ./usr/share/man/cat4/hptide.0			man-sys-catman		.cat
 ./usr/share/man/cat4/hythygtemp.0		man-sys-catman		.cat
+./usr/share/man/cat4/i2clcd.0			man-sys-catman		.cat
 ./usr/share/man/cat4/i386/PCIBIOS.0		man-sys-catman		.cat
 ./usr/share/man/cat4/i386/apm.0			man-sys-catman		.cat
 ./usr/share/man/cat4/i386/autoconf.0		man-sys-catman		.cat
@@ -4373,6 +4374,7 @@
 ./usr/share/man/html4/hpqlb.html		man-sys-htmlman		html
 ./usr/share/man/html4/hptide.html		man-sys-htmlman		html
 ./usr/share/man/html4/hythygtemp.html		man-sys-htmlman		html
+./usr/share/man/html4/i2clcd.html		man-sys-htmlman		html
 ./usr/share/man/html4/i386/PCIBIOS.html		man-sys-htmlman		html
 ./usr/share/man/html4/i386/apm.html		man-sys-htmlman		html
 ./usr/share/man/html4/i386/autoconf.html	man-sys-htmlman		html
@@ -7307,6 +7309,7 @@
 ./usr/share/man/man4/hpqlb.4			man-sys-man		.man
 ./usr/share/man/man4/hptide.4			man-sys-man		.man
 ./usr/share/man/man4/hythygtemp.4		man-sys-man		.man
+./usr/share/man/man4/i2clcd.4			man-sys-man		.man
 ./usr/share/man/man4/i386/PCIBIOS.4		man-sys-man		.man
 ./usr/share/man/man4/i386/apm.4			man-sys-man		.man
 ./usr/share/man/man4/i386/autoconf.4		man-sys-man		.man
