Module Name:    src
Committed By:   jmcneill
Date:           Mon Jan 25 12:08:47 UTC 2021

Modified Files:
        src/sys/dev/i2c: motoi2c.c motoi2cvar.h

Log Message:
NXP Layerscape LX2160A has an almost compatible controller, with a few
quirks:
 - IBCR bit 7 is "module disable" instead of "module enable".
 - Status bits in IBSR are W1C.
Add quirk flags for both.


To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/i2c/motoi2c.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/i2c/motoi2cvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/motoi2c.c
diff -u src/sys/dev/i2c/motoi2c.c:1.9 src/sys/dev/i2c/motoi2c.c:1.10
--- src/sys/dev/i2c/motoi2c.c:1.9	Sun Jan 24 18:01:13 2021
+++ src/sys/dev/i2c/motoi2c.c	Mon Jan 25 12:08:47 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: motoi2c.c,v 1.9 2021/01/24 18:01:13 jmcneill Exp $ */
+/* $NetBSD: motoi2c.c,v 1.10 2021/01/25 12:08:47 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2007, 2010 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: motoi2c.c,v 1.9 2021/01/24 18:01:13 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: motoi2c.c,v 1.10 2021/01/25 12:08:47 jmcneill Exp $");
 
 #if defined(__arm__) || defined(__aarch64__)
 #include "opt_fdt.h"
@@ -109,11 +109,23 @@ motoi2c_attach_common(device_t self, str
 	iba.iba_tag = &sc->sc_i2c;
 	iba.iba_child_devices = sc->sc_child_devices;
 
-	I2C_WRITE(I2CCR, 0);		/* reset before changing anything */
+	if ((sc->sc_flags & MOTOI2C_F_ENABLE_INV) != 0) {
+		sc->sc_enable_mask = 0;
+		sc->sc_disable_mask = CR_MEN;
+	} else {
+		sc->sc_enable_mask = CR_MEN;
+		sc->sc_disable_mask = 0;
+	}
+
+	I2C_WRITE(I2CCR, sc->sc_disable_mask);	/* reset before config */
 	I2C_WRITE(I2CDFSRR, i2c->i2c_dfsrr);	/* sampling units */
 	I2C_WRITE(I2CFDR, i2c->i2c_fdr);	/* divider 3072 (0x31) */
 	I2C_WRITE(I2CADR, i2c->i2c_adr);	/* our slave address is 0x7f */
-	I2C_WRITE(I2CSR, 0);		/* clear status flags */
+	if ((sc->sc_flags & MOTOI2C_F_STATUS_W1C) != 0) {
+		I2C_WRITE(I2CSR, I2C_READ(I2CSR)); /* clear status flags */
+	} else {
+		I2C_WRITE(I2CSR, 0);		/* clear status flags */
+	}
 
 #ifdef FDT
 	if (sc->sc_phandle != 0) {
@@ -130,7 +142,7 @@ motoi2c_acquire_bus(void *v, int flags)
 {
 	struct motoi2c_softc * const sc = v;
 
-	I2C_WRITE(I2CCR, CR_MEN);	/* enable the I2C module */
+	I2C_WRITE(I2CCR, sc->sc_enable_mask);	/* enable the I2C module */
 
 	return 0;
 }
@@ -140,7 +152,7 @@ motoi2c_release_bus(void *v, int flags)
 {
 	struct motoi2c_softc * const sc = v;
 
-	I2C_WRITE(I2CCR, 0);		/* reset before changing anything */
+	I2C_WRITE(I2CCR, sc->sc_disable_mask);	/* disable the I2C module */
 }
 
 static int
@@ -161,6 +173,16 @@ motoi2c_stop_wait(struct motoi2c_softc *
 	return error;
 }
 
+static void
+motoi2c_clear_status(struct motoi2c_softc *sc, uint8_t sr)
+{
+	if ((sc->sc_flags & MOTOI2C_F_STATUS_W1C) != 0) {
+		I2C_WRITE(I2CSR, sr);
+	} else {
+		I2C_WRITE(I2CSR, 0);
+	}
+}
+
 /* busy waiting for byte data transfer completion */
 static int
 motoi2c_busy_wait(struct motoi2c_softc *sc, uint8_t cr)
@@ -186,7 +208,7 @@ motoi2c_busy_wait(struct motoi2c_softc *
 		    __func__, sr, 1000 - timo));
 		error = EIO;
 	}
-	I2C_WRITE(I2CSR, 0);
+	motoi2c_clear_status(sc, sr);
 	return error;
 }
 
@@ -228,13 +250,13 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a
 	}
 
 	/* reset interrupt and arbitration-lost flags (all others are RO) */
-	I2C_WRITE(I2CSR, 0);
+	motoi2c_clear_status(sc, sr);
 	sr = I2C_READ(I2CSR);
 
 	/*
 	 * Generate start condition
 	 */
-	cr = CR_MEN | CR_MTX | CR_MSTA;
+	cr = sc->sc_enable_mask | CR_MTX | CR_MSTA;
 	I2C_WRITE(I2CCR, cr);
 
 	DPRINTF(("%s: started: sr=%#x cr=%#x/%#x\n",
@@ -244,9 +266,9 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a
 	if (sr & SR_MAL) {
 		DPRINTF(("%s: lost bus: sr=%#x cr=%#x/%#x\n",
 		    __func__, I2C_READ(I2CSR), cr, I2C_READ(I2CCR)));
-		I2C_WRITE(I2CCR, 0);
+		I2C_WRITE(I2CCR, sc->sc_disable_mask);
 		DELAY(10);
-		I2C_WRITE(I2CCR, CR_MEN | CR_MTX | CR_MSTA);
+		I2C_WRITE(I2CCR, sc->sc_enable_mask | CR_MTX | CR_MSTA);
 		DELAY(10);
 		sr = I2C_READ(I2CSR);
 		if (sr & SR_MAL) {
@@ -329,14 +351,14 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a
 				cr |= CR_TXAK;
 				I2C_WRITE(I2CCR, cr);
 			} else if (i == datalen - 1 && I2C_OP_STOP_P(op)) {
-				cr = CR_MEN | CR_TXAK;
+				cr = sc->sc_enable_mask | CR_TXAK;
 				I2C_WRITE(I2CCR, cr);
 			}
 			*dataptr++ = I2C_READ(I2CDR);
 		}
 		if (datalen == 0) {
 			if (I2C_OP_STOP_P(op)) {
-				cr = CR_MEN | CR_TXAK;
+				cr = sc->sc_enable_mask | CR_TXAK;
 				I2C_WRITE(I2CCR, cr);
 			}
 			(void)I2C_READ(I2CDR);	/* dummy read */
@@ -366,7 +388,7 @@ motoi2c_exec(void *v, i2c_op_t op, i2c_a
 	 * send a STOP.
 	 */
 	if (error || (cr & CR_TXAK) || ((cr & CR_MSTA) && I2C_OP_STOP_P(op))) {
-		cr = CR_MEN;
+		cr = sc->sc_enable_mask;
 		I2C_WRITE(I2CCR, cr);
 		motoi2c_stop_wait(sc);
 		DPRINTF(("%s: stopping: cr=%#x/%#x\n", __func__,

Index: src/sys/dev/i2c/motoi2cvar.h
diff -u src/sys/dev/i2c/motoi2cvar.h:1.7 src/sys/dev/i2c/motoi2cvar.h:1.8
--- src/sys/dev/i2c/motoi2cvar.h:1.7	Sun Jan 24 18:01:13 2021
+++ src/sys/dev/i2c/motoi2cvar.h	Mon Jan 25 12:08:47 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: motoi2cvar.h,v 1.7 2021/01/24 18:01:13 jmcneill Exp $ */
+/* $NetBSD: motoi2cvar.h,v 1.8 2021/01/25 12:08:47 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2007, 2010 The NetBSD Foundation, Inc.
@@ -52,6 +52,11 @@ struct motoi2c_softc {
 	motoi2c_iowr_t		sc_iowr;
 	int			sc_phandle;
 	prop_array_t		sc_child_devices;
+	int			sc_flags;
+#define	MOTOI2C_F_ENABLE_INV	__BIT(0)
+#define	MOTOI2C_F_STATUS_W1C	__BIT(1)
+	uint8_t			sc_enable_mask;
+	uint8_t			sc_disable_mask;
 };
 
 #define	MOTOI2C_ADR_DEFAULT	(0x7e << 1)

Reply via email to