1 /* $NetBSD: nbppcon.c,v 1.4 2021/04/24 23:36:37 thorpej 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.4 2021/04/24 23:36:37 thorpej 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 I2C_MATCH_ADDRESS_AND_PROBE; 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(self, NULL, 111 CFARG_SEARCH, nbppcon_search, 112 CFARG_EOL); 113 } 114 115 /* ARGSUSED */ 116 static int 117 nbppcon_search(device_t self, cfdata_t cf, const int *ldesc, void *aux) 118 { 119 struct nbppcon_attach_args pcon; 120 121 pcon.aa_name = cf->cf_name; 122 pcon.aa_tag = cf->cf_loc[NBPPCONCF_TAG]; 123 124 if (config_probe(self, cf, &pcon)) 125 config_attach(self, cf, &pcon, nbppcon_print, CFARG_EOL); 126 127 return 0; 128 } 129 130 /* ARGSUSED */ 131 static int 132 nbppcon_print(void *aux, const char *pnp) 133 { 134 135 if (pnp != NULL) 136 aprint_normal("%s", pnp); 137 return UNCONF; 138 } 139 140 141 void * 142 nbppcon_regist_callback(device_t self, 143 int tag, int (*func)(void *, int, char *), void *arg) 144 { 145 struct nbppcon_softc *sc = device_private(self); 146 int i; 147 148 for (i = 0; i < __arraycount(sc->sc_cbs); i++) 149 if (sc->sc_cbs[i].cb_func == NULL) { 150 sc->sc_cbs[i].cb_tag = tag; 151 sc->sc_cbs[i].cb_func = func; 152 sc->sc_cbs[i].cb_arg = arg; 153 return func; 154 } 155 156 return NULL; 157 } 158 159 int 160 nbppcon_intr(device_t self, int buflen, char *buf) 161 { 162 struct nbppcon_softc *sc = device_private(self); 163 struct callback *cb; 164 int i; 165 166 for (i = 0; i < __arraycount(sc->sc_cbs); i++) { 167 cb = &sc->sc_cbs[i]; 168 if (cb->cb_func != NULL && 169 cb->cb_tag == buf[0]) 170 return cb->cb_func(cb->cb_arg, buflen, buf); 171 } 172 aprint_error_dev(sc->sc_dev, "unknown tag received: 0x%02x\n", buf[0]); 173 return 0; 174 } 175 176 int 177 nbppcon_poll(device_t self, int tag, int buflen, char *buf) 178 { 179 struct nbppcon_softc *sc = device_private(self); 180 int rv; 181 182 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 183 aprint_error_dev(sc->sc_dev, 184 "%s: acquire bus failed\n", __func__); 185 return -1; 186 } 187 188 do { 189 extern int nbpiic_poll(void *, int, char *); 190 191 rv = nbpiic_poll(sc->sc_tag->ic_cookie, buflen, buf); 192 if (rv > 0 && buf[0] == tag) 193 break; 194 } while (rv == 0 || buf[0] != tag); 195 196 iic_release_bus(sc->sc_tag, I2C_F_POLL); 197 198 return rv; 199 } 200 201 int 202 nbppcon_kbd_ready(device_t self) 203 { 204 struct nbppcon_softc *sc = device_private(self); 205 int rv; 206 char cmd[1], data[1]; 207 208 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 209 aprint_error_dev(sc->sc_dev, 210 "%s: acquire bus failed\n", __func__); 211 return -1; 212 } 213 214 cmd[0] = 0x00; /* Keyboard */ 215 data[0] = 0x00; /* 0x00:Ready, 0x01:Busy? */ 216 rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 217 cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL); 218 219 cpu_dcache_wbinv_all(); /* XXXX: Why? */ 220 221 iic_release_bus(sc->sc_tag, I2C_F_POLL); 222 223 return rv; 224 } 225 226 int 227 nbppcon_pwr_hwreset(device_t self) 228 { 229 struct nbppcon_softc *sc = device_private(self); 230 int rv; 231 char cmd[1], data[1]; 232 233 if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) { 234 aprint_error_dev(sc->sc_dev, 235 "%s: acquire bus failed\n", __func__); 236 return -1; 237 } 238 239 cmd[0] = 0x05; /* POWER */ 240 data[0] = 0x00; /* HWReset */ 241 #if 0 242 rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address, 243 cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL); 244 #else /* XXXX: Oops, ensure HWReset, ignore cmd and data. */ 245 rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address + 1, 246 cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL); 247 #endif 248 249 iic_release_bus(sc->sc_tag, I2C_F_POLL); 250 251 return rv; 252 } 253