Module Name:    src
Committed By:   macallan
Date:           Fri Sep  1 20:10:08 UTC 2017

Modified Files:
        src/sys/arch/macppc/dev: pmu.c

Log Message:
support I2C bus and direct config of slave devices


To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/sys/arch/macppc/dev/pmu.c

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

Modified files:

Index: src/sys/arch/macppc/dev/pmu.c
diff -u src/sys/arch/macppc/dev/pmu.c:1.27 src/sys/arch/macppc/dev/pmu.c:1.28
--- src/sys/arch/macppc/dev/pmu.c:1.27	Wed Jun  1 05:27:40 2016
+++ src/sys/arch/macppc/dev/pmu.c	Fri Sep  1 20:10:08 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: pmu.c,v 1.27 2016/06/01 05:27:40 macallan Exp $ */
+/*	$NetBSD: pmu.c,v 1.28 2017/09/01 20:10:08 macallan Exp $ */
 
 /*-
  * Copyright (c) 2006 Michael Lorenz
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: pmu.c,v 1.27 2016/06/01 05:27:40 macallan Exp $");
+__KERNEL_RCSID(0, "$NetBSD: pmu.c,v 1.28 2017/09/01 20:10:08 macallan Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -36,6 +36,7 @@ __KERNEL_RCSID(0, "$NetBSD: pmu.c,v 1.27
 #include <sys/proc.h>
 #include <sys/kthread.h>
 #include <sys/atomic.h>
+#include <sys/mutex.h>
 
 #include <sys/bus.h>
 #include <machine/pio.h>
@@ -84,6 +85,7 @@ struct pmu_softc {
 	struct todr_chip_handle sc_todr;
 	struct adb_bus_accessops sc_adbops;
 	struct i2c_controller sc_i2c;
+	kmutex_t sc_i2c_lock;
 	struct pmu_ops sc_pmu_ops;
 	struct sysmon_pswitch sc_lidswitch;
 	struct sysmon_pswitch sc_powerbutton;
@@ -92,7 +94,6 @@ struct pmu_softc {
 	uint32_t sc_flags;
 #define PMU_HAS_BACKLIGHT_CONTROL	1
 	int sc_node;
-	int sc_iic_done;
 	int sc_error;
 	int sc_autopoll;
 	int sc_brightness, sc_brightness_wanted;
@@ -146,12 +147,10 @@ static 	int pmu_adb_send(void *, int, in
 static	int pmu_adb_set_handler(void *, void (*)(void *, int, uint8_t *), void *);
 
 /* i2c stuff */
-#if 0
 static int pmu_i2c_acquire_bus(void *, int);
 static void pmu_i2c_release_bus(void *, int);
 static int pmu_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
 		    void *, size_t, int);
-#endif
 
 static void pmu_attach_legacy_battery(struct pmu_softc *);
 static void pmu_attach_smart_battery(struct pmu_softc *, int);
@@ -262,9 +261,7 @@ pmu_attach(device_t parent, device_t sel
 {
 	struct confargs *ca = aux;
 	struct pmu_softc *sc = device_private(self);
-#if notyet
 	struct i2cbus_attach_args iba;
-#endif
 	uint32_t regs[16];
 	int irq = ca->ca_intr[0];
 	int node, extint_node, root_node;
@@ -273,6 +270,7 @@ pmu_attach(device_t parent, device_t sel
 	uint8_t cmd[2] = {2, 0};
 	uint8_t resp[16];
 	char name[256], model[32];
+	prop_dictionary_t dict = device_properties(self);
 
 	extint_node = of_getnode_byname(OF_parent(ca->ca_node), "extint-gpio1");
 	if (extint_node) {
@@ -344,7 +342,57 @@ pmu_attach(device_t parent, device_t sel
 			goto next;
 
 		if (strncmp(name, "pmu-i2c", 8) == 0) {
+			int devs;
+			uint32_t addr;
+			char compat[256];
+			prop_array_t cfg;
+			prop_dictionary_t dev;
+			prop_data_t data;
+
 			aprint_normal_dev(self, "initializing IIC bus\n");
+
+			cfg = prop_array_create();
+			prop_dictionary_set(dict, "i2c-child-devices", cfg);
+			prop_object_release(cfg);
+
+			/* look for i2c devices */
+			devs = OF_child(node);
+			while (devs != 0) {
+				if (OF_getprop(devs, "name", name, 256) == 0)
+					goto skip;
+				if (OF_getprop(devs, "compatible",
+				    compat, 256) == 0)
+					goto skip;
+				if (OF_getprop(devs, "reg", &addr, 4) == 0)
+					goto skip;
+				addr = (addr & 0xff) >> 1;
+				DPRINTF("-> %s@%x\n", name, addr);
+				dev = prop_dictionary_create();
+				prop_dictionary_set_cstring(dev, "name", name);
+				data = prop_data_create_data(compat, strlen(compat)+1);
+				prop_dictionary_set(dev, "compatible", data);
+				prop_object_release(data);
+				prop_dictionary_set_uint32(dev, "addr", addr);
+				prop_dictionary_set_uint64(dev, "cookie", node);
+				prop_array_add(cfg, dev);
+				prop_object_release(dev);
+			skip:
+				devs = OF_peer(devs);
+			}
+			memset(&iba, 0, sizeof(iba));
+			iba.iba_tag = &sc->sc_i2c;
+			mutex_init(&sc->sc_i2c_lock, MUTEX_DEFAULT, IPL_NONE);
+			sc->sc_i2c.ic_cookie = sc;
+			sc->sc_i2c.ic_acquire_bus = pmu_i2c_acquire_bus;
+			sc->sc_i2c.ic_release_bus = pmu_i2c_release_bus;
+			sc->sc_i2c.ic_send_start = NULL;
+			sc->sc_i2c.ic_send_stop = NULL;
+			sc->sc_i2c.ic_initiate_xfer = NULL;
+			sc->sc_i2c.ic_read_byte = NULL;
+			sc->sc_i2c.ic_write_byte = NULL;
+			sc->sc_i2c.ic_exec = pmu_i2c_exec;
+			config_found_ia(sc->sc_dev, "i2cbus", &iba,
+			    iicbus_print);
 			goto next;
 		}
 		if (strncmp(name, "adb", 4) == 0) {
@@ -410,21 +458,6 @@ next:
 			pmu_attach_smart_battery(sc, i);
 	}
 bat_done:
-
-#if notyet
-	memset(&iba, 0, sizeof(iba));
-	iba.iba_tag = &sc->sc_i2c;
-	sc->sc_i2c.ic_cookie = sc;
-	sc->sc_i2c.ic_acquire_bus = pmu_i2c_acquire_bus;
-	sc->sc_i2c.ic_release_bus = pmu_i2c_release_bus;
-	sc->sc_i2c.ic_send_start = NULL;
-	sc->sc_i2c.ic_send_stop = NULL;
-	sc->sc_i2c.ic_initiate_xfer = NULL;
-	sc->sc_i2c.ic_read_byte = NULL;
-	sc->sc_i2c.ic_write_byte = NULL;
-	sc->sc_i2c.ic_exec = pmu_i2c_exec;
-	config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
-#endif
 	
 	if (kthread_create(PRI_NONE, 0, NULL, pmu_thread, sc, &sc->sc_thread,
 	    "%s", "pmu") != 0) {
@@ -891,85 +924,81 @@ pmu_adb_set_handler(void *cookie, void (
 	sc->sc_adb_cookie = hcookie;
 	return 0;
 }
-#if 0
+
 static int
 pmu_i2c_acquire_bus(void *cookie, int flags)
 {
-	/* nothing yet */
+	struct pmu_softc *sc = cookie;
+
+	mutex_enter(&sc->sc_i2c_lock);
+
 	return 0;
 }
 
 static void
 pmu_i2c_release_bus(void *cookie, int flags)
 {
-	/* nothing here either */
+	struct pmu_softc *sc = cookie;
+
+	mutex_exit(&sc->sc_i2c_lock);
 }
 
 static int
 pmu_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr, const void *_send,
     size_t send_len, void *_recv, size_t recv_len, int flags)
 {
-#if 0
 	struct pmu_softc *sc = cookie;
 	const uint8_t *send = _send;
-	uint8_t *recv = _recv;
-	uint8_t command[16] = {PMU_POWERMGR, PMGR_IIC};
-
-	DPRINTF("pmu_i2c_exec(%02x)\n", addr);
-	command[2] = addr;
-
-	memcpy(&command[3], send, min((int)send_len, 12));
-
-	sc->sc_iic_done = 0;
-	pmu_send(sc, sc->sc_polling, send_len + 3, command);
-
-	while ((sc->sc_iic_done == 0) && (sc->sc_error == 0)) {
-		if (sc->sc_polling) {
-			pmu_poll(sc);
-		} else
-			tsleep(&sc->sc_todev, 0, "i2c", 1000);
-	}
-
-	if (sc->sc_error) {
-		sc->sc_error = 0;
-		return -1;
-	}
+	uint8_t command[32] = {1,	/* bus number */
+				PMU_I2C_MODE_SIMPLE,
+				0,	/* bus2 */
+				addr,
+				0,	/* sub address */
+				0,	/* comb address */
+				0,	/* count */
+				0	/* data */
+				};
+	uint8_t resp[16];
+	int len, rw;
 
-	/* see if we're supposed to do a read */
-	if (recv_len > 0) {
-		sc->sc_iic_done = 0;
-		command[2] |= 1;
-		command[3] = 0;
+	rw = addr << 1;
+	command[3] = rw;
+	if (send_len > 0) {
+		command[6] = send_len;
+		memcpy(&command[7], send, send_len);
+		len = send_len + 7;
+		DPRINTF("pmu_i2c_exec(%02x, %d)\n", addr, send_len);
 
-		/*
-		 * XXX we need to do something to limit the size of the answer
-		 * - apparently the chip keeps sending until we tell it to stop
-		 */
-		pmu_send(sc, sc->sc_polling, 3, command);
-		while ((sc->sc_iic_done == 0) && (sc->sc_error == 0)) {
-			if (sc->sc_polling) {
-				pmu_poll(sc);
-			} else
-				tsleep(&sc->sc_todev, 0, "i2c", 1000);
-		}
+		len = pmu_send(sc, PMU_I2C_CMD, len, command, 16, resp);
+		DPRINTF("resp(%d): %2x %2x\n", len, resp[0], resp[1]);
 
-		if (sc->sc_error) {
-			printf("error trying to read\n");
-			sc->sc_error = 0;
+		if (resp[1] != PMU_I2C_STATUS_OK) {
+			DPRINTF("%s: iic error %d\n", __func__, resp[1]);
 			return -1;
 		}
 	}
-
-	if ((sc->sc_iic_done > 3) && (recv_len > 0)) {
-		/* we got an answer */
-		recv[0] = sc->sc_iic_val;
-		printf("ret: %02x\n", sc->sc_iic_val);
-		return 1;
-	}
-#endif
+	/* see if we're supposed to read */
+	if (I2C_OP_READ_P(op)) {
+		rw |= 1;
+		command[3] = rw;
+		command[6] = recv_len;
+		len = pmu_send(sc, PMU_I2C_CMD, 7, command, 16, resp);
+		DPRINTF("resp2(%d): %2x %2x\n", len, resp[0], resp[1]);
+		
+		command[0] = 0;
+		len = pmu_send(sc, PMU_I2C_CMD, 1, command, 16, resp);
+		DPRINTF("resp3(%d): %2x %2x %2x\n", len, resp[0], resp[1],
+			resp[2]);
+		if ((len - 2) != recv_len) {
+			aprint_error_dev(sc->sc_dev, "%s(%d) - got %d\n",
+			    __func__, recv_len, len - 2);
+			return -1;
+		}
+		memcpy(_recv, &resp[2], len - 2);
+		return 0;
+	};
 	return 0;
 }
-#endif
 
 static void
 pmu_eject_card(struct pmu_softc *sc, int socket)

Reply via email to