1140308Scognet/*	$NetBSD: iq31244_7seg.c,v 1.2 2003/07/15 00:25:01 lukem Exp $	*/
2140308Scognet
3140308Scognet/*-
4140308Scognet * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
5140308Scognet * All rights reserved.
6140308Scognet *
7140308Scognet * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8140308Scognet *
9140308Scognet * Redistribution and use in source and binary forms, with or without
10140308Scognet * modification, are permitted provided that the following conditions
11140308Scognet * are met:
12140308Scognet * 1. Redistributions of source code must retain the above copyright
13140308Scognet *    notice, this list of conditions and the following disclaimer.
14140308Scognet * 2. Redistributions in binary form must reproduce the above copyright
15140308Scognet *    notice, this list of conditions and the following disclaimer in the
16140308Scognet *    documentation and/or other materials provided with the distribution.
17140308Scognet * 3. All advertising materials mentioning features or use of this software
18140308Scognet *    must display the following acknowledgement:
19140308Scognet *	This product includes software developed for the NetBSD Project by
20140308Scognet *	Wasabi Systems, Inc.
21140308Scognet * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22140308Scognet *    or promote products derived from this software without specific prior
23140308Scognet *    written permission.
24140308Scognet *
25140308Scognet * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26140308Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27140308Scognet * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28140308Scognet * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29140308Scognet * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30140308Scognet * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31140308Scognet * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32140308Scognet * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33140308Scognet * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34140308Scognet * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35140308Scognet * POSSIBILITY OF SUCH DAMAGE.
36140308Scognet */
37140308Scognet
38140308Scognet/*
39140308Scognet * Support for the 7-segment display on the Intel IQ31244.
40140308Scognet */
41140308Scognet
42140308Scognet#include <sys/cdefs.h>
43140308Scognet__FBSDID("$FreeBSD: releng/10.2/sys/arm/xscale/i80321/iq31244_7seg.c 236987 2012-06-13 04:38:09Z imp $");
44140308Scognet
45140308Scognet#include <sys/param.h>
46140308Scognet#include <sys/systm.h>
47140308Scognet#include <sys/kernel.h>
48140308Scognet#include <sys/module.h>
49140308Scognet#include <sys/bus.h>
50140350Scognet#include <sys/sysctl.h>
51140308Scognet
52140308Scognet#include <machine/bus.h>
53140308Scognet
54140308Scognet#include <arm/xscale/i80321/iq80321reg.h>
55140308Scognet#include <arm/xscale/i80321/iq80321var.h>
56140308Scognet
57140308Scognet#define	WRITE(x, v)	*((__volatile uint8_t *) (x)) = (v)
58140308Scognet
59140308Scognetstatic int snakestate;
60140308Scognet
61140308Scognet/*
62140308Scognet * The 7-segment display looks like so:
63140308Scognet *
64140308Scognet *         A
65140308Scognet *	+-----+
66140308Scognet *	|     |
67140308Scognet *    F	|     | B
68140308Scognet *	|  G  |
69140308Scognet *	+-----+
70140308Scognet *	|     |
71140308Scognet *    E	|     | C
72140308Scognet *	|  D  |
73140308Scognet *	+-----+ o  DP
74140308Scognet *
75140308Scognet * Setting a bit clears the corresponding segment on the
76140308Scognet * display.
77140308Scognet */
78140308Scognet#define	SEG_A			(1 << 0)
79140308Scognet#define	SEG_B			(1 << 1)
80140308Scognet#define	SEG_C			(1 << 2)
81140308Scognet#define	SEG_D			(1 << 3)
82140308Scognet#define	SEG_E			(1 << 4)
83140308Scognet#define	SEG_F			(1 << 5)
84140308Scognet#define	SEG_G			(1 << 6)
85140308Scognet#define	SEG_DP			(1 << 7)
86140308Scognet
87140308Scognetstatic const uint8_t digitmap[] = {
88140308Scognet/*	+#####+
89140308Scognet *	#     #
90140308Scognet *	#     #
91140308Scognet *	#     #
92140308Scognet *	+-----+
93140308Scognet *	#     #
94140308Scognet *	#     #
95140308Scognet *	#     #
96140308Scognet *	+#####+
97140308Scognet */
98140308Scognet	SEG_G,
99140308Scognet
100140308Scognet/*	+-----+
101140308Scognet *	|     #
102140308Scognet *	|     #
103140308Scognet *	|     #
104140308Scognet *	+-----+
105140308Scognet *	|     #
106140308Scognet *	|     #
107140308Scognet *	|     #
108140308Scognet *	+-----+
109140308Scognet */
110140308Scognet	SEG_A|SEG_D|SEG_E|SEG_F|SEG_G,
111140308Scognet
112140308Scognet/*	+#####+
113140308Scognet *	|     #
114140308Scognet *	|     #
115140308Scognet *	|     #
116140308Scognet *	+#####+
117140308Scognet *	#     |
118140308Scognet *	#     |
119140308Scognet *	#     |
120140308Scognet *	+#####+
121140308Scognet */
122140308Scognet	SEG_C|SEG_F,
123140308Scognet
124140308Scognet/*	+#####+
125140308Scognet *	|     #
126140308Scognet *	|     #
127140308Scognet *	|     #
128140308Scognet *	+#####+
129140308Scognet *	|     #
130140308Scognet *	|     #
131140308Scognet *	|     #
132140308Scognet *	+#####+
133140308Scognet */
134140308Scognet	SEG_E|SEG_F,
135140308Scognet
136140308Scognet/*	+-----+
137140308Scognet *	#     #
138140308Scognet *	#     #
139140308Scognet *	#     #
140140308Scognet *	+#####+
141140308Scognet *	|     #
142140308Scognet *	|     #
143140308Scognet *	|     #
144140308Scognet *	+-----+
145140308Scognet */
146140308Scognet	SEG_A|SEG_D|SEG_E,
147140308Scognet
148140308Scognet/*	+#####+
149140308Scognet *	#     |
150140308Scognet *	#     |
151140308Scognet *	#     |
152140308Scognet *	+#####+
153140308Scognet *	|     #
154140308Scognet *	|     #
155140308Scognet *	|     #
156140308Scognet *	+#####+
157140308Scognet */
158140308Scognet	SEG_B|SEG_E,
159140308Scognet
160140308Scognet/*	+#####+
161140308Scognet *	#     |
162140308Scognet *	#     |
163140308Scognet *	#     |
164140308Scognet *	+#####+
165140308Scognet *	#     #
166140308Scognet *	#     #
167140308Scognet *	#     #
168140308Scognet *	+#####+
169140308Scognet */
170140308Scognet	SEG_B,
171140308Scognet
172140308Scognet/*	+#####+
173140308Scognet *	|     #
174140308Scognet *	|     #
175140308Scognet *	|     #
176140308Scognet *	+-----+
177140308Scognet *	|     #
178140308Scognet *	|     #
179140308Scognet *	|     #
180140308Scognet *	+-----+
181140308Scognet */
182140308Scognet	SEG_D|SEG_E|SEG_F,
183140308Scognet
184140308Scognet/*	+#####+
185140308Scognet *	#     #
186140308Scognet *	#     #
187140308Scognet *	#     #
188140308Scognet *	+#####+
189140308Scognet *	#     #
190140308Scognet *	#     #
191140308Scognet *	#     #
192140308Scognet *	+#####+
193140308Scognet */
194140308Scognet	0,
195140308Scognet
196140308Scognet/*	+#####+
197140308Scognet *	#     #
198140308Scognet *	#     #
199140308Scognet *	#     #
200140308Scognet *	+#####+
201140308Scognet *	|     #
202140308Scognet *	|     #
203140308Scognet *	|     #
204140308Scognet *	+-----+
205140308Scognet */
206140308Scognet	SEG_D|SEG_E,
207140308Scognet};
208140308Scognet
209236987Simpstatic uint8_t
210140308Scognetiq80321_7seg_xlate(char c)
211140308Scognet{
212140308Scognet	uint8_t rv;
213140308Scognet
214140308Scognet	if (c >= '0' && c <= '9')
215140308Scognet		rv = digitmap[c - '0'];
216140308Scognet	else if (c == '.')
217140308Scognet		rv = (uint8_t) ~SEG_DP;
218140308Scognet	else
219140308Scognet		rv = 0xff;
220140308Scognet
221140308Scognet	return (rv);
222140308Scognet}
223140308Scognet
224140308Scognetvoid
225140308Scognetiq80321_7seg(char a, char b)
226140308Scognet{
227140308Scognet	uint8_t msb, lsb;
228140308Scognet
229140308Scognet	msb = iq80321_7seg_xlate(a);
230140308Scognet	lsb = iq80321_7seg_xlate(b);
231140308Scognet
232140308Scognet	snakestate = 0;
233140308Scognet
234140308Scognet	WRITE(IQ80321_7SEG_MSB, msb);
235140308Scognet	WRITE(IQ80321_7SEG_LSB, lsb);
236140308Scognet}
237140308Scognet
238140308Scognetstatic const uint8_t snakemap[][2] = {
239140308Scognet
240140308Scognet/*	+#####+		+#####+
241140308Scognet *	|     |		|     |
242140308Scognet *	|     |		|     |
243140308Scognet *	|     |		|     |
244140308Scognet *	+-----+		+-----+
245140308Scognet *	|     |		|     |
246140308Scognet *	|     |		|     |
247140308Scognet *	|     |		|     |
248140308Scognet *	+-----+		+-----+
249140308Scognet */
250140308Scognet	{ ~SEG_A,	~SEG_A },
251140308Scognet
252140308Scognet/*	+-----+		+-----+
253140308Scognet *	#     |		|     #
254140308Scognet *	#     |		|     #
255140308Scognet *	#     |		|     #
256140308Scognet *	+-----+		+-----+
257140308Scognet *	|     |		|     |
258140308Scognet *	|     |		|     |
259140308Scognet *	|     |		|     |
260140308Scognet *	+-----+		+-----+
261140308Scognet */
262140308Scognet	{ ~SEG_F,	~SEG_B },
263140308Scognet
264140308Scognet/*	+-----+		+-----+
265140308Scognet *	|     |		|     |
266140308Scognet *	|     |		|     |
267140308Scognet *	|     |		|     |
268140308Scognet *	+#####+		+#####+
269140308Scognet *	|     |		|     |
270140308Scognet *	|     |		|     |
271140308Scognet *	|     |		|     |
272140308Scognet *	+-----+		+-----+
273140308Scognet */
274140308Scognet	{ ~SEG_G,	~SEG_G },
275140308Scognet
276140308Scognet/*	+-----+		+-----+
277140308Scognet *	|     |		|     |
278140308Scognet *	|     |		|     |
279140308Scognet *	|     |		|     |
280140308Scognet *	+-----+		+-----+
281140308Scognet *	|     #		#     |
282140308Scognet *	|     #		#     |
283140308Scognet *	|     #		#     |
284140308Scognet *	+-----+		+-----+
285140308Scognet */
286140308Scognet	{ ~SEG_C,	~SEG_E },
287140308Scognet
288140308Scognet/*	+-----+		+-----+
289140308Scognet *	|     |		|     |
290140308Scognet *	|     |		|     |
291140308Scognet *	|     |		|     |
292140308Scognet *	+-----+		+-----+
293140308Scognet *	|     |		|     |
294140308Scognet *	|     |		|     |
295140308Scognet *	|     |		|     |
296140308Scognet *	+#####+		+#####+
297140308Scognet */
298140308Scognet	{ ~SEG_D,	~SEG_D },
299140308Scognet
300140308Scognet/*	+-----+		+-----+
301140308Scognet *	|     |		|     |
302140308Scognet *	|     |		|     |
303140308Scognet *	|     |		|     |
304140308Scognet *	+-----+		+-----+
305140308Scognet *	#     |		|     #
306140308Scognet *	#     |		|     #
307140308Scognet *	#     |		|     #
308140308Scognet *	+-----+		+-----+
309140308Scognet */
310140308Scognet	{ ~SEG_E,	~SEG_C },
311140308Scognet
312140308Scognet/*	+-----+		+-----+
313140308Scognet *	|     |		|     |
314140308Scognet *	|     |		|     |
315140308Scognet *	|     |		|     |
316140308Scognet *	+#####+		+#####+
317140308Scognet *	|     |		|     |
318140308Scognet *	|     |		|     |
319140308Scognet *	|     |		|     |
320140308Scognet *	+-----+		+-----+
321140308Scognet */
322140308Scognet	{ ~SEG_G,	~SEG_G },
323140308Scognet
324140308Scognet/*	+-----+		+-----+
325140308Scognet *	|     #		#     |
326140308Scognet *	|     #		#     |
327140308Scognet *	|     #		#     |
328140308Scognet *	+-----+		+-----+
329140308Scognet *	|     |		|     |
330140308Scognet *	|     |		|     |
331140308Scognet *	|     |		|     |
332140308Scognet *	+-----+		+-----+
333140308Scognet */
334140308Scognet	{ ~SEG_B,	~SEG_F },
335140308Scognet};
336140308Scognet
337227309Sedstatic SYSCTL_NODE(_hw, OID_AUTO, sevenseg, CTLFLAG_RD, 0, "7 seg");
338146618Scognetstatic int freq = 20;
339236987SimpSYSCTL_INT(_hw_sevenseg, OID_AUTO, freq, CTLFLAG_RW, &freq, 0,
340140350Scognet    "7 Seg update frequency");
341140308Scognetstatic void
342140308Scognetiq31244_7seg_snake(void)
343140308Scognet{
344140308Scognet	static int snakefreq;
345140308Scognet	int cur = snakestate;
346140308Scognet
347140308Scognet	snakefreq++;
348140350Scognet	if ((snakefreq % freq))
349140308Scognet		return;
350140308Scognet	WRITE(IQ80321_7SEG_MSB, snakemap[cur][0]);
351140308Scognet	WRITE(IQ80321_7SEG_LSB, snakemap[cur][1]);
352140308Scognet
353140308Scognet	snakestate = (cur + 1) & 7;
354140308Scognet}
355140308Scognet
356140308Scognetstruct iq31244_7seg_softc {
357140308Scognet	device_t	dev;
358140308Scognet};
359140308Scognet
360140308Scognetstatic int
361140308Scognetiq31244_7seg_probe(device_t dev)
362140308Scognet{
363140308Scognet
364140308Scognet	device_set_desc(dev, "IQ31244 7seg");
365140308Scognet	return (0);
366140308Scognet}
367140308Scognet
368140308Scognetextern void (*i80321_hardclock_hook)(void);
369140308Scognetstatic int
370140308Scognetiq31244_7seg_attach(device_t dev)
371140308Scognet{
372140308Scognet
373140308Scognet	i80321_hardclock_hook = iq31244_7seg_snake;
374140308Scognet	return (0);
375140308Scognet}
376140308Scognet
377140308Scognetstatic device_method_t iq31244_7seg_methods[] = {
378140308Scognet	DEVMETHOD(device_probe, iq31244_7seg_probe),
379140308Scognet	DEVMETHOD(device_attach, iq31244_7seg_attach),
380140308Scognet	{0, 0},
381140308Scognet};
382140308Scognet
383140308Scognetstatic driver_t iq31244_7seg_driver = {
384140308Scognet	"iqseg",
385140308Scognet	iq31244_7seg_methods,
386140308Scognet	sizeof(struct iq31244_7seg_softc),
387140308Scognet};
388140308Scognetstatic devclass_t iq31244_7seg_devclass;
389140308Scognet
390140308ScognetDRIVER_MODULE(iqseg, iq, iq31244_7seg_driver, iq31244_7seg_devclass, 0, 0);
391