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