1172297Scognet/*	$NetBSD: iq31244_7seg.c,v 1.2 2003/07/15 00:25:01 lukem Exp $	*/
2172297Scognet
3172297Scognet/*-
4172297Scognet * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
5172297Scognet * All rights reserved.
6172297Scognet *
7172297Scognet * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8172297Scognet *
9172297Scognet * Redistribution and use in source and binary forms, with or without
10172297Scognet * modification, are permitted provided that the following conditions
11172297Scognet * are met:
12172297Scognet * 1. Redistributions of source code must retain the above copyright
13172297Scognet *    notice, this list of conditions and the following disclaimer.
14172297Scognet * 2. Redistributions in binary form must reproduce the above copyright
15172297Scognet *    notice, this list of conditions and the following disclaimer in the
16172297Scognet *    documentation and/or other materials provided with the distribution.
17172297Scognet * 3. All advertising materials mentioning features or use of this software
18172297Scognet *    must display the following acknowledgement:
19172297Scognet *	This product includes software developed for the NetBSD Project by
20172297Scognet *	Wasabi Systems, Inc.
21172297Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22172297Scognet *    or promote products derived from this software without specific prior
23172297Scognet *    written permission.
24172297Scognet *
25172297Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26172297Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27172297Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28172297Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29172297Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30172297Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31172297Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32172297Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33172297Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34172297Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35172297Scognet * POSSIBILITY OF SUCH DAMAGE.
36172297Scognet */
37172297Scognet
38172297Scognet/*
39172297Scognet * Support for the 7-segment display on the Intel IQ81342.
40172297Scognet */
41172297Scognet
42172297Scognet#include <sys/cdefs.h>
43172297Scognet__FBSDID("$FreeBSD$");
44172297Scognet
45172297Scognet#include <sys/param.h>
46172297Scognet#include <sys/systm.h>
47172297Scognet#include <sys/kernel.h>
48172297Scognet#include <sys/module.h>
49172297Scognet#include <sys/bus.h>
50172297Scognet#include <sys/sysctl.h>
51172297Scognet
52172297Scognet#include <machine/bus.h>
53172297Scognet
54172297Scognet#include <arm/xscale/i8134x/i81342reg.h>
55172297Scognet#include <arm/xscale/i8134x/iq81342reg.h>
56172297Scognet#include <arm/xscale/i8134x/iq81342var.h>
57172297Scognet
58172297Scognet#define	WRITE(x, v)	*((__volatile uint8_t *) (x)) = (v)
59172297Scognet
60172297Scognetstatic int snakestate;
61172297Scognet
62172297Scognet/*
63172297Scognet * The 7-segment display looks like so:
64172297Scognet *
65172297Scognet *         A
66172297Scognet *	+-----+
67172297Scognet *	|     |
68172297Scognet *    F	|     | B
69172297Scognet *	|  G  |
70172297Scognet *	+-----+
71172297Scognet *	|     |
72172297Scognet *    E	|     | C
73172297Scognet *	|  D  |
74172297Scognet *	+-----+ o  DP
75172297Scognet *
76172297Scognet * Setting a bit clears the corresponding segment on the
77172297Scognet * display.
78172297Scognet */
79172297Scognet#define	SEG_A			(1 << 1)
80172297Scognet#define	SEG_B			(1 << 2)
81172297Scognet#define	SEG_C			(1 << 3)
82172297Scognet#define	SEG_D			(1 << 4)
83172297Scognet#define	SEG_E			(1 << 5)
84172297Scognet#define	SEG_F			(1 << 6)
85172297Scognet#define	SEG_G			(1 << 7)
86172297Scognet#define	SEG_DP			(1 << 0)
87172297Scognet
88172297Scognetstatic const uint8_t digitmap[] = {
89172297Scognet/*	+#####+
90172297Scognet *	#     #
91172297Scognet *	#     #
92172297Scognet *	#     #
93172297Scognet *	+-----+
94172297Scognet *	#     #
95172297Scognet *	#     #
96172297Scognet *	#     #
97172297Scognet *	+#####+
98172297Scognet */
99172297Scognet	(unsigned char)~SEG_G,
100172297Scognet
101172297Scognet/*	+-----+
102172297Scognet *	|     #
103172297Scognet *	|     #
104172297Scognet *	|     #
105172297Scognet *	+-----+
106172297Scognet *	|     #
107172297Scognet *	|     #
108172297Scognet *	|     #
109172297Scognet *	+-----+
110172297Scognet */
111172297Scognet	SEG_B|SEG_C,
112172297Scognet
113172297Scognet/*	+#####+
114172297Scognet *	|     #
115172297Scognet *	|     #
116172297Scognet *	|     #
117172297Scognet *	+#####+
118172297Scognet *	#     |
119172297Scognet *	#     |
120172297Scognet *	#     |
121172297Scognet *	+#####+
122172297Scognet */
123172297Scognet	~(SEG_C|SEG_F),
124172297Scognet
125172297Scognet/*	+#####+
126172297Scognet *	|     #
127172297Scognet *	|     #
128172297Scognet *	|     #
129172297Scognet *	+#####+
130172297Scognet *	|     #
131172297Scognet *	|     #
132172297Scognet *	|     #
133172297Scognet *	+#####+
134172297Scognet */
135172297Scognet	~(SEG_E|SEG_F),
136172297Scognet
137172297Scognet/*	+-----+
138172297Scognet *	#     #
139172297Scognet *	#     #
140172297Scognet *	#     #
141172297Scognet *	+#####+
142172297Scognet *	|     #
143172297Scognet *	|     #
144172297Scognet *	|     #
145172297Scognet *	+-----+
146172297Scognet */
147172297Scognet	~(SEG_A|SEG_D|SEG_E),
148172297Scognet
149172297Scognet/*	+#####+
150172297Scognet *	#     |
151172297Scognet *	#     |
152172297Scognet *	#     |
153172297Scognet *	+#####+
154172297Scognet *	|     #
155172297Scognet *	|     #
156172297Scognet *	|     #
157172297Scognet *	+#####+
158172297Scognet */
159172297Scognet	~(SEG_B|SEG_E),
160172297Scognet
161172297Scognet/*	+#####+
162172297Scognet *	#     |
163172297Scognet *	#     |
164172297Scognet *	#     |
165172297Scognet *	+#####+
166172297Scognet *	#     #
167172297Scognet *	#     #
168172297Scognet *	#     #
169172297Scognet *	+#####+
170172297Scognet */
171172297Scognet	~(SEG_B),
172172297Scognet
173172297Scognet/*	+#####+
174172297Scognet *	|     #
175172297Scognet *	|     #
176172297Scognet *	|     #
177172297Scognet *	+-----+
178172297Scognet *	|     #
179172297Scognet *	|     #
180172297Scognet *	|     #
181172297Scognet *	+-----+
182172297Scognet */
183172297Scognet	~(SEG_D|SEG_E|SEG_F),
184172297Scognet
185172297Scognet/*	+#####+
186172297Scognet *	#     #
187172297Scognet *	#     #
188172297Scognet *	#     #
189172297Scognet *	+#####+
190172297Scognet *	#     #
191172297Scognet *	#     #
192172297Scognet *	#     #
193172297Scognet *	+#####+
194172297Scognet */
195172297Scognet	~0,
196172297Scognet
197172297Scognet/*	+#####+
198172297Scognet *	#     #
199172297Scognet *	#     #
200172297Scognet *	#     #
201172297Scognet *	+#####+
202172297Scognet *	|     #
203172297Scognet *	|     #
204172297Scognet *	|     #
205172297Scognet *	+-----+
206172297Scognet */
207172297Scognet	~(SEG_D|SEG_E),
208172297Scognet};
209172297Scognet
210236987Simpstatic uint8_t
211172297Scognetiq81342_7seg_xlate(char c)
212172297Scognet{
213172297Scognet	uint8_t rv;
214172297Scognet
215172297Scognet	if (c >= '0' && c <= '9')
216172297Scognet		rv = digitmap[c - '0'];
217172297Scognet	else if (c == '.')
218172297Scognet		rv = (uint8_t) ~SEG_DP;
219172297Scognet	else
220172297Scognet		rv = 0xff;
221172297Scognet
222172297Scognet	return (rv);
223172297Scognet}
224172297Scognet
225172297Scognetvoid
226172297Scognetiq81342_7seg(char a, char b)
227172297Scognet{
228172297Scognet	uint8_t msb, lsb;
229172297Scognet
230172297Scognet	msb = iq81342_7seg_xlate(a);
231172297Scognet	lsb = iq81342_7seg_xlate(b);
232172297Scognet
233172297Scognet	snakestate = 0;
234172297Scognet
235172297Scognet	WRITE(IQ8134X_7SEG_MSB, msb);
236172297Scognet	WRITE(IQ8134X_7SEG_LSB, lsb);
237172297Scognet}
238172297Scognet
239172297Scognetstatic const uint8_t snakemap[][2] = {
240172297Scognet
241172297Scognet/*	+#####+		+#####+
242172297Scognet *	|     |		|     |
243172297Scognet *	|     |		|     |
244172297Scognet *	|     |		|     |
245172297Scognet *	+-----+		+-----+
246172297Scognet *	|     |		|     |
247172297Scognet *	|     |		|     |
248172297Scognet *	|     |		|     |
249172297Scognet *	+-----+		+-----+
250172297Scognet */
251172297Scognet	{ SEG_A,	SEG_A },
252172297Scognet
253172297Scognet/*	+-----+		+-----+
254172297Scognet *	#     |		|     #
255172297Scognet *	#     |		|     #
256172297Scognet *	#     |		|     #
257172297Scognet *	+-----+		+-----+
258172297Scognet *	|     |		|     |
259172297Scognet *	|     |		|     |
260172297Scognet *	|     |		|     |
261172297Scognet *	+-----+		+-----+
262172297Scognet */
263172297Scognet	{ SEG_F,	SEG_B },
264172297Scognet
265172297Scognet/*	+-----+		+-----+
266172297Scognet *	|     |		|     |
267172297Scognet *	|     |		|     |
268172297Scognet *	|     |		|     |
269172297Scognet *	+#####+		+#####+
270172297Scognet *	|     |		|     |
271172297Scognet *	|     |		|     |
272172297Scognet *	|     |		|     |
273172297Scognet *	+-----+		+-----+
274172297Scognet */
275172297Scognet	{ SEG_G,	SEG_G },
276172297Scognet
277172297Scognet/*	+-----+		+-----+
278172297Scognet *	|     |		|     |
279172297Scognet *	|     |		|     |
280172297Scognet *	|     |		|     |
281172297Scognet *	+-----+		+-----+
282172297Scognet *	|     #		#     |
283172297Scognet *	|     #		#     |
284172297Scognet *	|     #		#     |
285172297Scognet *	+-----+		+-----+
286172297Scognet */
287172297Scognet	{ SEG_C,	SEG_E },
288172297Scognet
289172297Scognet/*	+-----+		+-----+
290172297Scognet *	|     |		|     |
291172297Scognet *	|     |		|     |
292172297Scognet *	|     |		|     |
293172297Scognet *	+-----+		+-----+
294172297Scognet *	|     |		|     |
295172297Scognet *	|     |		|     |
296172297Scognet *	|     |		|     |
297172297Scognet *	+#####+		+#####+
298172297Scognet */
299172297Scognet	{ SEG_D,	SEG_D },
300172297Scognet
301172297Scognet/*	+-----+		+-----+
302172297Scognet *	|     |		|     |
303172297Scognet *	|     |		|     |
304172297Scognet *	|     |		|     |
305172297Scognet *	+-----+		+-----+
306172297Scognet *	#     |		|     #
307172297Scognet *	#     |		|     #
308172297Scognet *	#     |		|     #
309172297Scognet *	+-----+		+-----+
310172297Scognet */
311172297Scognet	{ SEG_E,	SEG_C },
312172297Scognet
313172297Scognet/*	+-----+		+-----+
314172297Scognet *	|     |		|     |
315172297Scognet *	|     |		|     |
316172297Scognet *	|     |		|     |
317172297Scognet *	+#####+		+#####+
318172297Scognet *	|     |		|     |
319172297Scognet *	|     |		|     |
320172297Scognet *	|     |		|     |
321172297Scognet *	+-----+		+-----+
322172297Scognet */
323172297Scognet	{ SEG_G,	SEG_G },
324172297Scognet
325172297Scognet/*	+-----+		+-----+
326172297Scognet *	|     #		#     |
327172297Scognet *	|     #		#     |
328172297Scognet *	|     #		#     |
329172297Scognet *	+-----+		+-----+
330172297Scognet *	|     |		|     |
331172297Scognet *	|     |		|     |
332172297Scognet *	|     |		|     |
333172297Scognet *	+-----+		+-----+
334172297Scognet */
335172297Scognet	{ SEG_B,	SEG_F },
336172297Scognet};
337172297Scognet
338227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, sevenseg, CTLFLAG_RD, 0, "7 seg");
339172297Scognetstatic int freq = 20;
340236987SimpSYSCTL_INT(_hw_sevenseg, OID_AUTO, freq, CTLFLAG_RW, &freq, 0,
341172297Scognet    "7 Seg update frequency");
342172297Scognetstatic void
343172297Scognetiq81342_7seg_snake(void)
344172297Scognet{
345172297Scognet	static int snakefreq;
346172297Scognet	int cur = snakestate;
347172297Scognet
348172297Scognet	snakefreq++;
349172297Scognet	if ((snakefreq % freq))
350172297Scognet		return;
351172297Scognet	WRITE(IQ8134X_7SEG_MSB, snakemap[cur][0]);
352172297Scognet	WRITE(IQ8134X_7SEG_LSB, snakemap[cur][1]);
353172297Scognet
354172297Scognet	snakestate = (cur + 1) & 7;
355172297Scognet}
356172297Scognet
357172297Scognetstruct iq81342_7seg_softc {
358172297Scognet	device_t	dev;
359172297Scognet};
360172297Scognet
361172297Scognetstatic int
362172297Scognetiq81342_7seg_probe(device_t dev)
363172297Scognet{
364172297Scognet
365172297Scognet	device_set_desc(dev, "IQ81342 7seg");
366172297Scognet	return (0);
367172297Scognet}
368172297Scognet
369172297Scognetextern void (*i80321_hardclock_hook)(void);
370172297Scognetstatic int
371172297Scognetiq81342_7seg_attach(device_t dev)
372172297Scognet{
373172297Scognet
374172297Scognet	i80321_hardclock_hook = iq81342_7seg_snake;
375172297Scognet	return (0);
376172297Scognet}
377172297Scognet
378172297Scognetstatic device_method_t iq81342_7seg_methods[] = {
379172297Scognet	DEVMETHOD(device_probe, iq81342_7seg_probe),
380172297Scognet	DEVMETHOD(device_attach, iq81342_7seg_attach),
381172297Scognet	{0, 0},
382172297Scognet};
383172297Scognet
384172297Scognetstatic driver_t iq81342_7seg_driver = {
385172297Scognet	"iqseg",
386172297Scognet	iq81342_7seg_methods,
387172297Scognet	sizeof(struct iq81342_7seg_softc),
388172297Scognet};
389172297Scognetstatic devclass_t iq81342_7seg_devclass;
390172297Scognet
391172297ScognetDRIVER_MODULE(iqseg, iq, iq81342_7seg_driver, iq81342_7seg_devclass, 0, 0);
392