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