Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev/isa - catch up with OpenBSD driver, adding support f...
details: https://anonhg.NetBSD.org/src/rev/779e872f4deb
branches: trunk
changeset: 760886:779e872f4deb
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Sun Jan 16 01:05:45 2011 +0000
description:
- catch up with OpenBSD driver, adding support for newer Thinkpad models
- add module hooks
diffstat:
sys/dev/isa/aps.c | 373 ++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 249 insertions(+), 124 deletions(-)
diffs (truncated from 518 to 300 lines):
diff -r ee0656b57263 -r 779e872f4deb sys/dev/isa/aps.c
--- a/sys/dev/isa/aps.c Sat Jan 15 23:06:07 2011 +0000
+++ b/sys/dev/isa/aps.c Sun Jan 16 01:05:45 2011 +0000
@@ -1,8 +1,9 @@
-/* $NetBSD: aps.c,v 1.10 2010/02/24 22:37:58 dyoung Exp $ */
+/* $NetBSD: aps.c,v 1.11 2011/01/16 01:05:45 jmcneill Exp $ */
/* $OpenBSD: aps.c,v 1.15 2007/05/19 19:14:11 tedu Exp $ */
-
+/* $OpenBSD: aps.c,v 1.17 2008/06/27 06:08:43 canacar Exp $ */
/*
* Copyright (c) 2005 Jonathan Gray <jsg%openbsd.org@localhost>
+ * Copyright (c) 2008 Can Erkin Acar <canacar%openbsd.org@localhost>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -23,13 +24,14 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: aps.c,v 1.10 2010/02/24 22:37:58 dyoung Exp $");
+__KERNEL_RCSID(0, "$NetBSD: aps.c,v 1.11 2011/01/16 01:05:45 jmcneill Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/kernel.h>
#include <sys/callout.h>
+#include <sys/module.h>
#include <sys/bus.h>
@@ -44,23 +46,62 @@
#define DPRINTF(x)
#endif
-#define APS_ACCEL_STATE 0x04
-#define APS_INIT 0x10
-#define APS_STATE 0x11
-#define APS_XACCEL 0x12
-#define APS_YACCEL 0x14
-#define APS_TEMP 0x16
-#define APS_XVAR 0x17
-#define APS_YVAR 0x19
-#define APS_TEMP2 0x1b
-#define APS_UNKNOWN 0x1c
-#define APS_INPUT 0x1d
-#define APS_CMD 0x1f
+
+/*
+ * EC interface on Thinkpad Laptops, from Linux HDAPS driver notes.
+ * From Renesans H8S/2140B Group Hardware Manual
+ * http://documentation.renesas.com/eng/products/mpumcu/rej09b0300_2140bhm.pdf
+ *
+ * EC uses LPC Channel 3 registers TWR0..15
+ */
+
+/* STR3 status register */
+#define APS_STR3 0x04
+
+#define APS_STR3_IBF3B 0x80 /* Input buffer full (host->slave) */
+#define APS_STR3_OBF3B 0x40 /* Output buffer full (slave->host)*/
+#define APS_STR3_MWMF 0x20 /* Master write mode */
+#define APS_STR3_SWMF 0x10 /* Slave write mode */
+
+
+/* Base address of TWR registers */
+#define APS_TWR_BASE 0x10
+#define APS_TWR_RET 0x1f
-#define APS_STATE_NEWDATA 0x50
+/* TWR registers */
+#define APS_CMD 0x00
+#define APS_ARG1 0x01
+#define APS_ARG2 0x02
+#define APS_ARG3 0x03
+#define APS_RET 0x0f
-#define APS_CMD_START 0x01
+/* Sensor values */
+#define APS_STATE 0x01
+#define APS_XACCEL 0x02
+#define APS_YACCEL 0x04
+#define APS_TEMP 0x06
+#define APS_XVAR 0x07
+#define APS_YVAR 0x09
+#define APS_TEMP2 0x0b
+#define APS_UNKNOWN 0x0c
+#define APS_INPUT 0x0d
+/* write masks for I/O, send command + 0-3 arguments*/
+#define APS_WRITE_0 0x0001
+#define APS_WRITE_1 0x0003
+#define APS_WRITE_2 0x0007
+#define APS_WRITE_3 0x000f
+
+/* read masks for I/O, read 0-3 values (skip command byte) */
+#define APS_READ_0 0x0000
+#define APS_READ_1 0x0002
+#define APS_READ_2 0x0006
+#define APS_READ_3 0x000e
+
+#define APS_READ_RET 0x8000
+#define APS_READ_ALL 0xffff
+
+/* Bit definitions for APS_INPUT value */
#define APS_INPUT_KB (1 << 5)
#define APS_INPUT_MS (1 << 6)
#define APS_INPUT_LIDOPEN (1 << 7)
@@ -95,6 +136,7 @@
struct aps_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
+ bool sc_bus_space_valid;
struct sysmon_envsys *sc_sme;
envsys_data_t sc_sensor[APS_NUM_SENSORS];
@@ -108,23 +150,93 @@
static int aps_detach(device_t, int);
static int aps_init(struct aps_softc *);
-static uint8_t aps_mem_read_1(bus_space_tag_t, bus_space_handle_t,
- int, uint8_t);
-static void aps_refresh_sensor_data(struct aps_softc *sc);
+static int aps_read_data(struct aps_softc *);
+static void aps_refresh_sensor_data(struct aps_softc *);
static void aps_refresh(void *);
+static int aps_do_io(bus_space_tag_t, bus_space_handle_t,
+ unsigned char *, int, int);
static bool aps_suspend(device_t, const pmf_qual_t *);
static bool aps_resume(device_t, const pmf_qual_t *);
CFATTACH_DECL_NEW(aps, sizeof(struct aps_softc),
aps_match, aps_attach, aps_detach, NULL);
+/* properly communicate with the controller, writing a set of memory
+ * locations and reading back another set */
+static int
+aps_do_io(bus_space_tag_t iot, bus_space_handle_t ioh,
+ unsigned char *buf, int wmask, int rmask)
+{
+ int bp, stat, n;
+
+ DPRINTF(("aps_do_io: CMD: 0x%02x, wmask: 0x%04x, rmask: 0x%04x\n",
+ buf[0], wmask, rmask));
+
+ /* write init byte using arbitration */
+ for (n = 0; n < 100; n++) {
+ stat = bus_space_read_1(iot, ioh, APS_STR3);
+ if (stat & (APS_STR3_OBF3B | APS_STR3_SWMF)) {
+ bus_space_read_1(iot, ioh, APS_TWR_RET);
+ continue;
+ }
+ bus_space_write_1(iot, ioh, APS_TWR_BASE, buf[0]);
+ stat = bus_space_read_1(iot, ioh, APS_STR3);
+ if (stat & (APS_STR3_MWMF))
+ break;
+ delay(1);
+ }
+
+ if (n == 100) {
+ DPRINTF(("aps_do_io: Failed to get bus\n"));
+ return 1;
+ }
+
+ /* write data bytes, init already sent */
+ /* make sure last bye is always written as this will trigger slave */
+ wmask |= APS_READ_RET;
+ buf[APS_RET] = 0x01;
+
+ for (n = 1, bp = 2; n < 16; bp <<= 1, n++) {
+ if (wmask & bp) {
+ bus_space_write_1(iot, ioh, APS_TWR_BASE + n, buf[n]);
+ DPRINTF(("aps_do_io: write %2d 0x%02x\n", n, buf[n]));
+ }
+ }
+
+ for (n = 0; n < 100; n++) {
+ stat = bus_space_read_1(iot, ioh, APS_STR3);
+ if (stat & (APS_STR3_OBF3B))
+ break;
+ delay(5 * 100);
+ }
+
+ if (n == 100) {
+ DPRINTF(("aps_do_io: timeout waiting response\n"));
+ return 1;
+ }
+ /* wait for data available */
+ /* make sure to read the final byte to clear status */
+ rmask |= APS_READ_RET;
+
+ /* read cmd and data bytes */
+ for (n = 0, bp = 1; n < 16; bp <<= 1, n++) {
+ if (rmask & bp) {
+ buf[n] = bus_space_read_1(iot, ioh, APS_TWR_BASE + n);
+ DPRINTF(("aps_do_io: read %2d 0x%02x\n", n, buf[n]));
+ }
+ }
+
+ return 0;
+}
+
static int
aps_match(device_t parent, cfdata_t match, void *aux)
{
struct isa_attach_args *ia = aux;
bus_space_tag_t iot = ia->ia_iot;
bus_space_handle_t ioh;
- int iobase, i;
+ unsigned char iobuf[16];
+ int iobase;
uint8_t cr;
/* Must supply an address */
@@ -144,16 +256,12 @@
return 0;
}
+
/* See if this machine has APS */
- bus_space_write_1(iot, ioh, APS_INIT, 0x13);
- bus_space_write_1(iot, ioh, APS_CMD, 0x01);
- /* ask again as the X40 is slightly deaf in one ear */
- bus_space_read_1(iot, ioh, APS_CMD);
- bus_space_write_1(iot, ioh, APS_INIT, 0x13);
- bus_space_write_1(iot, ioh, APS_CMD, 0x01);
-
- if (!aps_mem_read_1(iot, ioh, APS_CMD, 0x00)) {
+ /* get APS mode */
+ iobuf[APS_CMD] = 0x13;
+ if (aps_do_io(iot, ioh, iobuf, APS_WRITE_0, APS_READ_1)) {
bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
return 0;
}
@@ -163,17 +271,15 @@
* 0x01: T42
* 0x02: chip already initialised
* 0x03: T41
+ * 0x05: T61
*/
- for (i = 0; i < 10; i++) {
- cr = bus_space_read_1(iot, ioh, APS_STATE);
- if (cr > 0 && cr < 6)
- break;
- delay(5 * 1000);
- }
-
+
+ cr = iobuf[APS_ARG1];
+
bus_space_unmap(iot, ioh, APS_ADDR_SIZE);
DPRINTF(("aps: state register 0x%x\n", cr));
- if (cr < 1 || cr > 5) {
+
+ if (iobuf[APS_RET] != 0 || cr < 1 || cr > 5) {
DPRINTF(("aps0: unsupported state %d\n", cr));
return 0;
}
@@ -197,16 +303,20 @@
sc->sc_iot = ia->ia_iot;
iobase = ia->ia_io[0].ir_addr;
+ callout_init(&sc->sc_callout, 0);
+ callout_setfunc(&sc->sc_callout, aps_refresh, sc);
+
if (bus_space_map(sc->sc_iot, iobase, APS_ADDR_SIZE, 0, &sc->sc_ioh)) {
aprint_error(": can't map i/o space\n");
return;
}
+ sc->sc_bus_space_valid = true;
aprint_naive("\n");
aprint_normal("\n");
- if (!aps_init(sc)) {
- aprint_error_dev(self, "failed to initialise\n");
+ if (aps_init(sc)) {
+ aprint_error_dev(self, "failed to initialize\n");
goto out;
}
@@ -252,8 +362,6 @@
aprint_error_dev(self, "couldn't establish power handler\n");
/* Refresh sensor data every 0.5 seconds */
- callout_init(&sc->sc_callout, 0);
- callout_setfunc(&sc->sc_callout, aps_refresh, sc);
callout_schedule(&sc->sc_callout, (hz) / 2);
aprint_normal_dev(self, "Thinkpad Active Protection System\n");
@@ -266,38 +374,49 @@
static int
aps_init(struct aps_softc *sc)
{
- bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_INIT, 0x17);
- bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_STATE, 0x81);
- bus_space_write_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x01);
- if (!aps_mem_read_1(sc->sc_iot, sc->sc_ioh, APS_CMD, 0x00))
- return 0;
Home |
Main Index |
Thread Index |
Old Index