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