1 /* $NetBSD: nbppcon.c,v 1.2 2012/06/16 05:58:03 kiyohara Exp $ */ 2 /* 3 * Copyright (c) 2011 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 #include <sys/cdefs.h> 28 __KERNEL_RCSID(0, "$NetBSD: nbppcon.c,v 1.2 2012/06/16 05:58:03 kiyohara Exp $"); 29 30 #include <sys/param.h> 31 #include <sys/device.h> 32 #include <sys/errno.h> 33 34 #include <machine/platid.h> 35 #include <machine/platid_mask.h> 36 37 #include <arm/xscale/pxa2x0_i2c.h> 38 39 #include <hpcarm/dev/nbppconvar.h> 40 41 #include <dev/i2c/i2cvar.h> 42 #include <dev/i2c/at24cxxvar.h> 43 44 #include "locators.h" 45 46 #define NBPPCON_ADDR 0x13 47 48 49 struct nbppcon_softc { 50 device_t sc_dev; 51 i2c_tag_t sc_tag; 52 int sc_address; 53 54 struct callback { 55 int cb_tag; 56 int (*cb_func)(void *, int, char *); 57 void *cb_arg; 58 } sc_cbs[2]; 59 }; 60 61 static int nbppcon_match(device_t, cfdata_t, void *); 62 static void nbppcon_attach(device_t, device_t, void *); 63 64 static int nbppcon_search(device_t, cfdata_t, const int *, void *); 65 static int nbppcon_print(void *aux, const char *pnp); 66 67 CFATTACH_DECL_NEW(nbppcon, sizeof(struct nbppcon_softc), 68 nbppcon_match, nbppcon_attach, NULL, NULL); 69 70 71 /* ARGSUSED */ 72 static int 73 nbppcon_match(device_t parent, cfdata_t match, void *aux) 74 { 75 struct i2c_attach_args *ia = aux; 76 77 if (ia->ia_addr != NBPPCON_ADDR || 78 !platid_match(&platid, &platid_mask_MACH_PSIONTEKLOGIX_NETBOOK_PRO)) 79 return 0; 80 81 return 1; 82 } 83 84 /* ARGSUSED */ 85 static void 86 nbppcon_attach(device_t parent, device_t self, void *aux) 87 { 88 struct nbppcon_softc *sc = device_private(self); 89 struct i2c_attach_args *ia = aux; 90 int rv; 91 char buf[128]; 92 93 sc->sc_dev = self; 94 sc->sc_tag = ia->ia_tag; 95 sc->sc_address = ia->ia_addr; 96 97 aprint_naive("\n"); 98 aprint_normal(": NETBOOK PRO PCon\n"); 99 100 #define NVRAM_ADDR 0x53 101 #define NVRAM_DATA_REV 0x14 102 rv = seeprom_bootstrap_read(sc->sc_tag, NVRAM_ADDR, 0x00, 128, 103 buf, sizeof(buf)); 104 if (rv == 0) 105 aprint_normal_dev(self, "NETBOOK PRO Rev.%c\n", 106 buf[NVRAM_DATA_REV] - '0' + '@'); 107 else 108 aprint_error_dev(self, "NVRAM read failed\n"); 109 110 config_search_ia(nbppcon_search, self, "nbppcon", NULL); 111 } 112 113 /* ARGSUSED */ 114 static int 115 nbppcon_search(device_t self, cfdata_t cf, const int *ldesc, void *aux) 116 { 117 struct nbppcon_attach_args pcon; 118 119 pcon.aa_name = cf->cf_name; 120 pcon.aa_tag = cf->cf_loc[NBPPCONCF_TAG]; 121 122 if (config_match(self, cf, &pcon)) 123 config_attach(self, cf, &pcon, nbppcon_print); 124 125 return 0; 126 } 127 128 /* ARGSUSED */ 129 static int 130 nbppcon_print(void *aux, const char *pnp) 131 { 132 133 if (pnp != NULL) 134 aprint_normal("%s", pnp); 135 return UNCONF; 136 } 137 138 139 void * 140 nbppcon_regist_callback(device_t self, 141 int tag, int (*func)(void *, int, char *), void *arg) 142 { 143 struct nbppcon_softc *sc = device_private(self); 144 int i; 145 146 for (i = 0; i < __arraycount(sc->sc_cbs); i++) 147 if (sc->sc_cbs[i].cb_func == NULL) { 148 sc->sc_cbs[i].cb_tag = tag; 149 sc->sc_cbs[i].cb_func = func; 150 sc->sc_cbs[i].cb_arg = arg; 151 return func; 152 } 153 154 return NULL; 155 } 156 157 int 158 nbppcon_intr(device_t self, int buflen, char *buf) 159 { 160 struct nbppcon_softc *sc = device_private(self); 161 struct callback *cb; 162 int i; 163 164 for (i = 0; i < __arraycount(sc->sc_cbs); i++) { 165 cb = &sc->sc_cbs[i]; 166 if (cb->cb_func != NULL && 167 cb->cb_tag == buf[0]) 168 return cb->cb_func(cb->cb_arg, buflen, buf); 169 } 170 aprint_error_dev(sc->sc_dev, "unknown tag received: 0x%02x\n", buf[0]); 171 return 0; 172 } 173 174 int 175 nbppcon_poll(device_t self, int tag, int buflen, char *buf) 176 { 177 struct nbppcon_softc *sc = device_private(self); 178 int rv; 179 180 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 181 aprint_error_dev(sc->sc_dev, 182 "%s: acquire bus failed\n", __func__); 183 return -1; 184 } 185 186 do { 187 extern int nbpiic_poll(void *, int, char *); 188 189 rv = nbpiic_poll(sc->sc_tag->ic_cookie, buflen, buf); 190 if (rv > 0 && buf[0] == tag) 191 break; 192 } while (rv == 0 || buf[0] != tag); 193 194 iic_release_bus(sc->sc_tag, I2C_F_POLL); 195 196 return rv; 197 } 198 199 int 200 nbppcon_kbd_ready(device_t self) 201 { 202 struct nbppcon_softc *sc = device_private(self); 203 int rv; 204 char cmd[1], data[1]; 205 206 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 207 aprint_error_dev(sc->sc_dev, 208 "%s: acquire bus failed\n", __func__); 209 return -1; 210 } 211 212 cmd[0] = 0x00; /* Keyboard */ 213 data[0] = 0x00; /* 0x00:Ready, 0x01:Busy? */ 214 rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 215 cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL); 216 217 cpu_dcache_wbinv_all(); /* XXXX: Why? */ 218 219 iic_release_bus(sc->sc_tag, I2C_F_POLL); 220 221 return rv; 222 } 223 224 int 225 nbppcon_pwr_hwreset(device_t self) 226 { 227 struct nbppcon_softc *sc = device_private(self); 228 int rv; 229 char cmd[1], data[1]; 230 231 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 232 aprint_error_dev(sc->sc_dev, 233 "%s: acquire bus failed\n", __func__); 234 return -1; 235 } 236 237 cmd[0] = 0x05; /* POWER */ 238 data[0] = 0x00; /* HWReset */ 239 #if 0 240 rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 241 cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL); 242 #else /* XXXX: Oops, ensure HWReset, ignore cmd and data. */ 243 rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address + 1, 244 cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL); 245 #endif 246 247 iic_release_bus(sc->sc_tag, I2C_F_POLL); 248 249 return rv; 250 } 251