xref: /netbsd-src/sys/arch/hpcarm/dev/ipaq_atmelgpio.c (revision 7433666e375b3ac4cc764df5a6726be98bc1cdd5)
1*7433666eSthorpej /*	$NetBSD: ipaq_atmelgpio.c,v 1.19 2023/12/20 14:50:02 thorpej Exp $	*/
21af1e2f9Sichiro 
31af1e2f9Sichiro /*-
41af1e2f9Sichiro  * Copyright (c) 2001 The NetBSD Foundation, Inc.  All rights reserved.
51af1e2f9Sichiro  *
61af1e2f9Sichiro  * This code is derived from software contributed to The NetBSD Foundation
71af1e2f9Sichiro  * by Ichiro FUKUHARA (ichiro@ichiro.org).
81af1e2f9Sichiro  *
91af1e2f9Sichiro  * Redistribution and use in source and binary forms, with or without
101af1e2f9Sichiro  * modification, are permitted provided that the following conditions
111af1e2f9Sichiro  * are met:
121af1e2f9Sichiro  * 1. Redistributions of source code must retain the above copyright
131af1e2f9Sichiro  *    notice, this list of conditions and the following disclaimer.
141af1e2f9Sichiro  * 2. Redistributions in binary form must reproduce the above copyright
151af1e2f9Sichiro  *    notice, this list of conditions and the following disclaimer in the
161af1e2f9Sichiro  *    documentation and/or other materials provided with the distribution.
171af1e2f9Sichiro  *
181af1e2f9Sichiro  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
191af1e2f9Sichiro  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
201af1e2f9Sichiro  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
211af1e2f9Sichiro  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
221af1e2f9Sichiro  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
231af1e2f9Sichiro  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
241af1e2f9Sichiro  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
251af1e2f9Sichiro  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
261af1e2f9Sichiro  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
271af1e2f9Sichiro  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
281af1e2f9Sichiro  * POSSIBILITY OF SUCH DAMAGE.
291af1e2f9Sichiro  */
301af1e2f9Sichiro /*
311af1e2f9Sichiro  * iPAQ uses Atmel microcontroller to service a few of peripheral devices.
321af1e2f9Sichiro  * This controller connect to UART1 of SA11x0.
331af1e2f9Sichiro  */
341af1e2f9Sichiro 
3508716eaeSlukem #include <sys/cdefs.h>
36*7433666eSthorpej __KERNEL_RCSID(0, "$NetBSD: ipaq_atmelgpio.c,v 1.19 2023/12/20 14:50:02 thorpej Exp $");
3708716eaeSlukem 
381af1e2f9Sichiro #include <sys/param.h>
391af1e2f9Sichiro #include <sys/systm.h>
401af1e2f9Sichiro #include <sys/types.h>
411af1e2f9Sichiro #include <sys/conf.h>
421af1e2f9Sichiro #include <sys/file.h>
431af1e2f9Sichiro #include <sys/device.h>
441af1e2f9Sichiro #include <sys/kernel.h>
451af1e2f9Sichiro #include <sys/kthread.h>
469edf49b0Sdyoung #include <sys/bus.h>
471af1e2f9Sichiro 
481af1e2f9Sichiro #include <hpcarm/dev/ipaq_saipvar.h>
491af1e2f9Sichiro #include <hpcarm/dev/ipaq_gpioreg.h>
501af1e2f9Sichiro #include <hpcarm/dev/ipaq_atmel.h>
519ada1599Sichiro #include <hpcarm/dev/ipaq_atmelvar.h>
52d846a6e2Speter 
53d846a6e2Speter #include <arm/sa11x0/sa11x0_gpioreg.h>
54d846a6e2Speter #include <arm/sa11x0/sa11x0_comreg.h>
55d846a6e2Speter #include <arm/sa11x0/sa11x0_reg.h>
561af1e2f9Sichiro 
579ada1599Sichiro #ifdef ATMEL_DEBUG
584c494f76Srjs #define DPRINTF(x) aprint_normal x
599ada1599Sichiro #else
609ada1599Sichiro #define DPRINTF(x)
619ada1599Sichiro #endif
621af1e2f9Sichiro 
634c494f76Srjs static	int	atmelgpio_match(device_t, cfdata_t, void *);
644c494f76Srjs static	void	atmelgpio_attach(device_t, device_t, void *);
651af1e2f9Sichiro static	int	atmelgpio_print(void *, const char *);
664c494f76Srjs static	int	atmelgpio_search(device_t, cfdata_t, const int *, void *);
671af1e2f9Sichiro static	void	atmelgpio_init(struct atmelgpio_softc *);
681af1e2f9Sichiro 
699ada1599Sichiro static	void	rxtx_data(struct atmelgpio_softc *, int, int,
704a5a04e4Speter 			 uint8_t *, struct atmel_rx *);
719ada1599Sichiro 
724c494f76Srjs CFATTACH_DECL_NEW(atmelgpio, sizeof(struct atmelgpio_softc),
73c5e91d44Sthorpej     atmelgpio_match, atmelgpio_attach, NULL, NULL);
741af1e2f9Sichiro 
751af1e2f9Sichiro static int
atmelgpio_match(device_t parent,cfdata_t cf,void * aux)764c494f76Srjs atmelgpio_match(device_t parent, cfdata_t cf, void *aux)
771af1e2f9Sichiro {
781af1e2f9Sichiro 	return (1);
791af1e2f9Sichiro }
801af1e2f9Sichiro 
811af1e2f9Sichiro static void
atmelgpio_attach(device_t parent,device_t self,void * aux)824c494f76Srjs atmelgpio_attach(device_t parent, device_t self, void *aux)
831af1e2f9Sichiro {
844c494f76Srjs 	struct atmelgpio_softc *sc = device_private(self);
854c494f76Srjs 	struct ipaq_softc *psc = device_private(parent);
861af1e2f9Sichiro 
87d846a6e2Speter 	struct atmel_rx rxbuf;
889ada1599Sichiro 
894c494f76Srjs 	aprint_normal("\n");
904c494f76Srjs 	aprint_normal_dev(self, "Atmel microcontroller GPIO\n");
911af1e2f9Sichiro 
921af1e2f9Sichiro 	sc->sc_iot = psc->sc_iot;
931af1e2f9Sichiro 	sc->sc_ioh = psc->sc_ioh;
944c494f76Srjs 	sc->sc_parent = psc;
951af1e2f9Sichiro 
961af1e2f9Sichiro 	if (bus_space_map(sc->sc_iot, SACOM1_BASE, SACOM_NPORTS, 0,
971af1e2f9Sichiro                         &sc->sc_ioh)) {
984c494f76Srjs                 aprint_normal_dev(self, "unable to map of UART1 registers\n");
991af1e2f9Sichiro                 return;
1001af1e2f9Sichiro         }
1011af1e2f9Sichiro 
1021af1e2f9Sichiro 	atmelgpio_init(sc);
1031af1e2f9Sichiro 
1047741a20aSrjs 	rxbuf.idx = 0;
1057741a20aSrjs 	rxbuf.len = 0;
1067741a20aSrjs 
1079ada1599Sichiro #if 1  /* this is sample */
108d846a6e2Speter 	rxtx_data(sc, STATUS_BATTERY, 0, NULL, &rxbuf);
1099ada1599Sichiro 
1104c494f76Srjs 	aprint_normal("ac_status          = %x\n", rxbuf.data[0]);
1114c494f76Srjs 	aprint_normal("Battery kind       = %x\n", rxbuf.data[1]);
1124c494f76Srjs 	aprint_normal("Voltage            = %d mV\n",
113d846a6e2Speter 		1000 * (rxbuf.data[3] << 8 | rxbuf.data[2]) /228);
1144c494f76Srjs 	aprint_normal("Battery Status     = %x\n", rxbuf.data[4]);
1154c494f76Srjs 	aprint_normal("Battery percentage = %d\n",
116d846a6e2Speter 		425 * (rxbuf.data[3] << 8 | rxbuf.data[2]) /1000 - 298);
1179ada1599Sichiro #endif
1189ada1599Sichiro 
119f99ba5e5Srjs 	rxtx_data(sc, READ_IIC, 0, NULL, &rxbuf);
120f99ba5e5Srjs 
1211af1e2f9Sichiro 	/*
1221af1e2f9Sichiro 	 *  Attach each devices
1231af1e2f9Sichiro 	 */
1241af1e2f9Sichiro 
1252685996bSthorpej 	config_search(self, NULL,
126c7fb772bSthorpej 	    CFARGS(.search = atmelgpio_search));
1271af1e2f9Sichiro }
1281af1e2f9Sichiro 
1291af1e2f9Sichiro static int
atmelgpio_search(device_t parent,cfdata_t cf,const int * ldesc,void * aux)1304c494f76Srjs atmelgpio_search(device_t parent, cfdata_t cf, const int *ldesc,
131f99ba5e5Srjs 		 void *aux)
1321af1e2f9Sichiro {
1332685996bSthorpej 	if (config_probe(parent, cf, NULL))
134c7fb772bSthorpej 		config_attach(parent, cf, NULL, atmelgpio_print, CFARGS_NONE);
1351af1e2f9Sichiro 	return 0;
1361af1e2f9Sichiro }
1371af1e2f9Sichiro 
1381af1e2f9Sichiro 
1391af1e2f9Sichiro static int
atmelgpio_print(void * aux,const char * name)140f99ba5e5Srjs atmelgpio_print(void *aux, const char *name)
1411af1e2f9Sichiro {
1421af1e2f9Sichiro 	return (UNCONF);
1431af1e2f9Sichiro }
1441af1e2f9Sichiro 
1451af1e2f9Sichiro static void
atmelgpio_init(struct atmelgpio_softc * sc)146f99ba5e5Srjs atmelgpio_init(struct atmelgpio_softc *sc)
1471af1e2f9Sichiro {
1481af1e2f9Sichiro 	/* 8 bits no parity 1 stop bit */
1491af1e2f9Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_CR0, CR0_DSS);
1501af1e2f9Sichiro 
1511af1e2f9Sichiro 	/* Set baud rate 115k */
1521af1e2f9Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_CR1, 0);
1531af1e2f9Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_CR2, SACOMSPEED(115200));
1549ada1599Sichiro 
1559ada1599Sichiro 	/* RX/TX enable, RX/TX FIFO interrupt enable */
1569ada1599Sichiro 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_CR3,
1579ada1599Sichiro 			 (CR3_RXE | CR3_TXE | CR3_RIE | CR3_TIE));
1589ada1599Sichiro }
1599ada1599Sichiro 
1609ada1599Sichiro static void
rxtx_data(struct atmelgpio_softc * sc,int id,int size,uint8_t * buf,struct atmel_rx * rxbuf)161f99ba5e5Srjs rxtx_data(struct atmelgpio_softc  *sc, int id, int size, uint8_t *buf,
162f99ba5e5Srjs 	  struct atmel_rx *rxbuf)
1639ada1599Sichiro {
1649ada1599Sichiro 	int 		i, checksum, length, rx_data;
1654a5a04e4Speter 	uint8_t		data[MAX_SENDSIZE];
1669ada1599Sichiro 
1679ada1599Sichiro 	length = size + FRAME_OVERHEAD_SIZE;
1689ada1599Sichiro 
1699ada1599Sichiro 	while (! (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SACOM_SR0) & SR0_TFS))
1709ada1599Sichiro 		;
1719ada1599Sichiro 
1724a5a04e4Speter 		data[0] = (uint8_t)FRAME_SOF;
1734a5a04e4Speter 		data[1] = (uint8_t)((id << 4) | size);
1749ada1599Sichiro 		checksum = data[1];
1759ada1599Sichiro 		i = 2;
1769ada1599Sichiro 		while (size--)	{
1779ada1599Sichiro 			data[i++] = *buf;
1784a5a04e4Speter 			checksum += (uint8_t)(*buf++);
1799ada1599Sichiro 		}
1809ada1599Sichiro 		data[length-1] = checksum;
1819ada1599Sichiro 
1829ada1599Sichiro 	while (! (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SACOM_SR1) & SR1_TNF))
1839ada1599Sichiro 		;
1849ada1599Sichiro 		i = 0;
1859ada1599Sichiro 		while (i < length)
1869ada1599Sichiro 			bus_space_write_4(sc->sc_iot, sc->sc_ioh, SACOM_DR, data[i++]);
1879ada1599Sichiro 
1889ada1599Sichiro 	delay(10000);
1899ada1599Sichiro #if 0
1909ada1599Sichiro 	while (! (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SACOM_SR0) &
1919ada1599Sichiro 		 (SR0_RID | SR0_RFS)))
1929ada1599Sichiro #endif
1939ada1599Sichiro 	rxbuf->state = STATE_SOF;
1949ada1599Sichiro 	while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, SACOM_SR1) & SR1_RNE) {
1959ada1599Sichiro 
1969ada1599Sichiro 		rx_data = bus_space_read_4(sc->sc_iot, sc->sc_ioh, SACOM_DR);
1979ada1599Sichiro 			DPRINTF(("DATA = %x\n", rx_data));
1989ada1599Sichiro 
1999ada1599Sichiro 		switch (rxbuf->state) {
2009ada1599Sichiro 		case STATE_SOF:
2019ada1599Sichiro 			if (rx_data == FRAME_SOF)
2029ada1599Sichiro 				rxbuf->state = STATE_ID;
2039ada1599Sichiro 			break;
2049ada1599Sichiro 		case STATE_ID:
2059ada1599Sichiro 			rxbuf->id = (rx_data & 0xf0) >> 4;
2069ada1599Sichiro 			rxbuf->len = rx_data & 0x0f;
2079ada1599Sichiro 			rxbuf->idx = 0;
2089ada1599Sichiro 			rxbuf->checksum = rx_data;
2099ada1599Sichiro 			rxbuf->state = (rxbuf->len > 0 ) ? STATE_DATA : STATE_EOF;
2109ada1599Sichiro 			break;
2119ada1599Sichiro 		case STATE_DATA:
2129ada1599Sichiro 			rxbuf->checksum += rx_data;
2139ada1599Sichiro 			rxbuf->data[rxbuf->idx] = rx_data;
2149ada1599Sichiro 			if (++rxbuf->idx == rxbuf->len)
2159ada1599Sichiro 				rxbuf->state = STATE_EOF;
2169ada1599Sichiro 			break;
2179ada1599Sichiro 		case STATE_EOF:
2189ada1599Sichiro 			rxbuf->state = STATE_SOF;
2199ada1599Sichiro 			if (rx_data == FRAME_EOF || rx_data == rxbuf->checksum)
2209ada1599Sichiro 				DPRINTF(("frame EOF\n"));
2219ada1599Sichiro 			else
2229ada1599Sichiro 				DPRINTF(("BadFrame\n"));
2239ada1599Sichiro 			break;
2249ada1599Sichiro 		default:
2259ada1599Sichiro 			break;
2269ada1599Sichiro 		}
2279ada1599Sichiro 	}
2281af1e2f9Sichiro }
229