1*c7fb772bSthorpej /* $NetBSD: nbppcon.c,v 1.5 2021/08/07 16:18:53 thorpej Exp $ */
2587ef940Skiyohara /*
3587ef940Skiyohara * Copyright (c) 2011 KIYOHARA Takashi
4587ef940Skiyohara * All rights reserved.
5587ef940Skiyohara *
6587ef940Skiyohara * Redistribution and use in source and binary forms, with or without
7587ef940Skiyohara * modification, are permitted provided that the following conditions
8587ef940Skiyohara * are met:
9587ef940Skiyohara * 1. Redistributions of source code must retain the above copyright
10587ef940Skiyohara * notice, this list of conditions and the following disclaimer.
11587ef940Skiyohara * 2. Redistributions in binary form must reproduce the above copyright
12587ef940Skiyohara * notice, this list of conditions and the following disclaimer in the
13587ef940Skiyohara * documentation and/or other materials provided with the distribution.
14587ef940Skiyohara *
15587ef940Skiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16587ef940Skiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17587ef940Skiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18587ef940Skiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19587ef940Skiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20587ef940Skiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21587ef940Skiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22587ef940Skiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23587ef940Skiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24587ef940Skiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25587ef940Skiyohara * POSSIBILITY OF SUCH DAMAGE.
26587ef940Skiyohara */
27587ef940Skiyohara #include <sys/cdefs.h>
28*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: nbppcon.c,v 1.5 2021/08/07 16:18:53 thorpej Exp $");
29587ef940Skiyohara
30587ef940Skiyohara #include <sys/param.h>
31587ef940Skiyohara #include <sys/device.h>
32587ef940Skiyohara #include <sys/errno.h>
33587ef940Skiyohara
34587ef940Skiyohara #include <machine/platid.h>
35587ef940Skiyohara #include <machine/platid_mask.h>
36587ef940Skiyohara
37587ef940Skiyohara #include <arm/xscale/pxa2x0_i2c.h>
38587ef940Skiyohara
39587ef940Skiyohara #include <hpcarm/dev/nbppconvar.h>
40587ef940Skiyohara
41587ef940Skiyohara #include <dev/i2c/i2cvar.h>
42587ef940Skiyohara #include <dev/i2c/at24cxxvar.h>
43587ef940Skiyohara
44587ef940Skiyohara #include "locators.h"
45587ef940Skiyohara
46587ef940Skiyohara #define NBPPCON_ADDR 0x13
47587ef940Skiyohara
48587ef940Skiyohara
49587ef940Skiyohara struct nbppcon_softc {
50587ef940Skiyohara device_t sc_dev;
51587ef940Skiyohara i2c_tag_t sc_tag;
52587ef940Skiyohara int sc_address;
53587ef940Skiyohara
54587ef940Skiyohara struct callback {
55587ef940Skiyohara int cb_tag;
56587ef940Skiyohara int (*cb_func)(void *, int, char *);
57587ef940Skiyohara void *cb_arg;
58587ef940Skiyohara } sc_cbs[2];
59587ef940Skiyohara };
60587ef940Skiyohara
61587ef940Skiyohara static int nbppcon_match(device_t, cfdata_t, void *);
62587ef940Skiyohara static void nbppcon_attach(device_t, device_t, void *);
63587ef940Skiyohara
64587ef940Skiyohara static int nbppcon_search(device_t, cfdata_t, const int *, void *);
65587ef940Skiyohara static int nbppcon_print(void *aux, const char *pnp);
66587ef940Skiyohara
67587ef940Skiyohara CFATTACH_DECL_NEW(nbppcon, sizeof(struct nbppcon_softc),
68587ef940Skiyohara nbppcon_match, nbppcon_attach, NULL, NULL);
69587ef940Skiyohara
70587ef940Skiyohara
71587ef940Skiyohara /* ARGSUSED */
72587ef940Skiyohara static int
nbppcon_match(device_t parent,cfdata_t match,void * aux)73587ef940Skiyohara nbppcon_match(device_t parent, cfdata_t match, void *aux)
74587ef940Skiyohara {
75587ef940Skiyohara struct i2c_attach_args *ia = aux;
76587ef940Skiyohara
77587ef940Skiyohara if (ia->ia_addr != NBPPCON_ADDR ||
78587ef940Skiyohara !platid_match(&platid, &platid_mask_MACH_PSIONTEKLOGIX_NETBOOK_PRO))
79587ef940Skiyohara return 0;
80587ef940Skiyohara
81aa41e992Sthorpej return I2C_MATCH_ADDRESS_AND_PROBE;
82587ef940Skiyohara }
83587ef940Skiyohara
84587ef940Skiyohara /* ARGSUSED */
85587ef940Skiyohara static void
nbppcon_attach(device_t parent,device_t self,void * aux)86587ef940Skiyohara nbppcon_attach(device_t parent, device_t self, void *aux)
87587ef940Skiyohara {
88587ef940Skiyohara struct nbppcon_softc *sc = device_private(self);
89587ef940Skiyohara struct i2c_attach_args *ia = aux;
90587ef940Skiyohara int rv;
91587ef940Skiyohara char buf[128];
92587ef940Skiyohara
93587ef940Skiyohara sc->sc_dev = self;
94587ef940Skiyohara sc->sc_tag = ia->ia_tag;
95587ef940Skiyohara sc->sc_address = ia->ia_addr;
96587ef940Skiyohara
97587ef940Skiyohara aprint_naive("\n");
98587ef940Skiyohara aprint_normal(": NETBOOK PRO PCon\n");
99587ef940Skiyohara
100587ef940Skiyohara #define NVRAM_ADDR 0x53
101587ef940Skiyohara #define NVRAM_DATA_REV 0x14
102587ef940Skiyohara rv = seeprom_bootstrap_read(sc->sc_tag, NVRAM_ADDR, 0x00, 128,
103587ef940Skiyohara buf, sizeof(buf));
104587ef940Skiyohara if (rv == 0)
105fbd7a1abSkiyohara aprint_normal_dev(self, "NETBOOK PRO Rev.%c\n",
106587ef940Skiyohara buf[NVRAM_DATA_REV] - '0' + '@');
107587ef940Skiyohara else
108587ef940Skiyohara aprint_error_dev(self, "NVRAM read failed\n");
109587ef940Skiyohara
1102685996bSthorpej config_search(self, NULL,
111*c7fb772bSthorpej CFARGS(.search = nbppcon_search));
112587ef940Skiyohara }
113587ef940Skiyohara
114587ef940Skiyohara /* ARGSUSED */
115587ef940Skiyohara static int
nbppcon_search(device_t self,cfdata_t cf,const int * ldesc,void * aux)116587ef940Skiyohara nbppcon_search(device_t self, cfdata_t cf, const int *ldesc, void *aux)
117587ef940Skiyohara {
118587ef940Skiyohara struct nbppcon_attach_args pcon;
119587ef940Skiyohara
120587ef940Skiyohara pcon.aa_name = cf->cf_name;
121587ef940Skiyohara pcon.aa_tag = cf->cf_loc[NBPPCONCF_TAG];
122587ef940Skiyohara
1232685996bSthorpej if (config_probe(self, cf, &pcon))
124*c7fb772bSthorpej config_attach(self, cf, &pcon, nbppcon_print, CFARGS_NONE);
125587ef940Skiyohara
126587ef940Skiyohara return 0;
127587ef940Skiyohara }
128587ef940Skiyohara
129587ef940Skiyohara /* ARGSUSED */
130587ef940Skiyohara static int
nbppcon_print(void * aux,const char * pnp)131587ef940Skiyohara nbppcon_print(void *aux, const char *pnp)
132587ef940Skiyohara {
133587ef940Skiyohara
134587ef940Skiyohara if (pnp != NULL)
135587ef940Skiyohara aprint_normal("%s", pnp);
136587ef940Skiyohara return UNCONF;
137587ef940Skiyohara }
138587ef940Skiyohara
139587ef940Skiyohara
140587ef940Skiyohara void *
nbppcon_regist_callback(device_t self,int tag,int (* func)(void *,int,char *),void * arg)141587ef940Skiyohara nbppcon_regist_callback(device_t self,
142587ef940Skiyohara int tag, int (*func)(void *, int, char *), void *arg)
143587ef940Skiyohara {
144587ef940Skiyohara struct nbppcon_softc *sc = device_private(self);
145587ef940Skiyohara int i;
146587ef940Skiyohara
147587ef940Skiyohara for (i = 0; i < __arraycount(sc->sc_cbs); i++)
148587ef940Skiyohara if (sc->sc_cbs[i].cb_func == NULL) {
149587ef940Skiyohara sc->sc_cbs[i].cb_tag = tag;
150587ef940Skiyohara sc->sc_cbs[i].cb_func = func;
151587ef940Skiyohara sc->sc_cbs[i].cb_arg = arg;
152587ef940Skiyohara return func;
153587ef940Skiyohara }
154587ef940Skiyohara
155587ef940Skiyohara return NULL;
156587ef940Skiyohara }
157587ef940Skiyohara
158587ef940Skiyohara int
nbppcon_intr(device_t self,int buflen,char * buf)159587ef940Skiyohara nbppcon_intr(device_t self, int buflen, char *buf)
160587ef940Skiyohara {
161587ef940Skiyohara struct nbppcon_softc *sc = device_private(self);
162587ef940Skiyohara struct callback *cb;
163587ef940Skiyohara int i;
164587ef940Skiyohara
165587ef940Skiyohara for (i = 0; i < __arraycount(sc->sc_cbs); i++) {
166587ef940Skiyohara cb = &sc->sc_cbs[i];
167587ef940Skiyohara if (cb->cb_func != NULL &&
168587ef940Skiyohara cb->cb_tag == buf[0])
169587ef940Skiyohara return cb->cb_func(cb->cb_arg, buflen, buf);
170587ef940Skiyohara }
171587ef940Skiyohara aprint_error_dev(sc->sc_dev, "unknown tag received: 0x%02x\n", buf[0]);
172587ef940Skiyohara return 0;
173587ef940Skiyohara }
174587ef940Skiyohara
175587ef940Skiyohara int
nbppcon_poll(device_t self,int tag,int buflen,char * buf)176587ef940Skiyohara nbppcon_poll(device_t self, int tag, int buflen, char *buf)
177587ef940Skiyohara {
178587ef940Skiyohara struct nbppcon_softc *sc = device_private(self);
179587ef940Skiyohara int rv;
180587ef940Skiyohara
181587ef940Skiyohara if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) {
182587ef940Skiyohara aprint_error_dev(sc->sc_dev,
183587ef940Skiyohara "%s: acquire bus failed\n", __func__);
184587ef940Skiyohara return -1;
185587ef940Skiyohara }
186587ef940Skiyohara
187587ef940Skiyohara do {
188587ef940Skiyohara extern int nbpiic_poll(void *, int, char *);
189587ef940Skiyohara
190587ef940Skiyohara rv = nbpiic_poll(sc->sc_tag->ic_cookie, buflen, buf);
191587ef940Skiyohara if (rv > 0 && buf[0] == tag)
192587ef940Skiyohara break;
193587ef940Skiyohara } while (rv == 0 || buf[0] != tag);
194587ef940Skiyohara
195587ef940Skiyohara iic_release_bus(sc->sc_tag, I2C_F_POLL);
196587ef940Skiyohara
197587ef940Skiyohara return rv;
198587ef940Skiyohara }
199587ef940Skiyohara
200587ef940Skiyohara int
nbppcon_kbd_ready(device_t self)201587ef940Skiyohara nbppcon_kbd_ready(device_t self)
202587ef940Skiyohara {
203587ef940Skiyohara struct nbppcon_softc *sc = device_private(self);
204587ef940Skiyohara int rv;
205587ef940Skiyohara char cmd[1], data[1];
206587ef940Skiyohara
207587ef940Skiyohara if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) {
208587ef940Skiyohara aprint_error_dev(sc->sc_dev,
209587ef940Skiyohara "%s: acquire bus failed\n", __func__);
210587ef940Skiyohara return -1;
211587ef940Skiyohara }
212587ef940Skiyohara
213587ef940Skiyohara cmd[0] = 0x00; /* Keyboard */
214587ef940Skiyohara data[0] = 0x00; /* 0x00:Ready, 0x01:Busy? */
215587ef940Skiyohara rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address,
216587ef940Skiyohara cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL);
217587ef940Skiyohara
218587ef940Skiyohara cpu_dcache_wbinv_all(); /* XXXX: Why? */
219587ef940Skiyohara
220587ef940Skiyohara iic_release_bus(sc->sc_tag, I2C_F_POLL);
221587ef940Skiyohara
222587ef940Skiyohara return rv;
223587ef940Skiyohara }
224587ef940Skiyohara
225587ef940Skiyohara int
nbppcon_pwr_hwreset(device_t self)226587ef940Skiyohara nbppcon_pwr_hwreset(device_t self)
227587ef940Skiyohara {
228587ef940Skiyohara struct nbppcon_softc *sc = device_private(self);
229587ef940Skiyohara int rv;
230587ef940Skiyohara char cmd[1], data[1];
231587ef940Skiyohara
232587ef940Skiyohara if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL)) {
233587ef940Skiyohara aprint_error_dev(sc->sc_dev,
234587ef940Skiyohara "%s: acquire bus failed\n", __func__);
235587ef940Skiyohara return -1;
236587ef940Skiyohara }
237587ef940Skiyohara
238587ef940Skiyohara cmd[0] = 0x05; /* POWER */
239587ef940Skiyohara data[0] = 0x00; /* HWReset */
240587ef940Skiyohara #if 0
241587ef940Skiyohara rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address,
242587ef940Skiyohara cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL);
243587ef940Skiyohara #else /* XXXX: Oops, ensure HWReset, ignore cmd and data. */
244587ef940Skiyohara rv = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address + 1,
245587ef940Skiyohara cmd, sizeof(cmd), data, sizeof(data), I2C_F_POLL);
246587ef940Skiyohara #endif
247587ef940Skiyohara
248587ef940Skiyohara iic_release_bus(sc->sc_tag, I2C_F_POLL);
249587ef940Skiyohara
250587ef940Skiyohara return rv;
251587ef940Skiyohara }
252