xref: /netbsd/sys/arch/hpcarm/dev/nbppcon.c (revision beecddb6)
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