1/*	$NetBSD: iq31244_7seg.c,v 1.2 2003/07/15 00:25:01 lukem Exp $	*/
2
3/*-
4 * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *	This product includes software developed for the NetBSD Project by
20 *	Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 *    or promote products derived from this software without specific prior
23 *    written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
36 */
37
38/*
39 * Support for the 7-segment display on the Intel IQ81342.
40 */
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD$");
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/module.h>
49#include <sys/bus.h>
50#include <sys/sysctl.h>
51
52#include <machine/bus.h>
53
54#include <arm/xscale/i8134x/i81342reg.h>
55#include <arm/xscale/i8134x/iq81342reg.h>
56#include <arm/xscale/i8134x/iq81342var.h>
57
58#define	WRITE(x, v)	*((__volatile uint8_t *) (x)) = (v)
59
60static int snakestate;
61
62/*
63 * The 7-segment display looks like so:
64 *
65 *         A
66 *	+-----+
67 *	|     |
68 *    F	|     | B
69 *	|  G  |
70 *	+-----+
71 *	|     |
72 *    E	|     | C
73 *	|  D  |
74 *	+-----+ o  DP
75 *
76 * Setting a bit clears the corresponding segment on the
77 * display.
78 */
79#define	SEG_A			(1 << 1)
80#define	SEG_B			(1 << 2)
81#define	SEG_C			(1 << 3)
82#define	SEG_D			(1 << 4)
83#define	SEG_E			(1 << 5)
84#define	SEG_F			(1 << 6)
85#define	SEG_G			(1 << 7)
86#define	SEG_DP			(1 << 0)
87
88static const uint8_t digitmap[] = {
89/*	+#####+
90 *	#     #
91 *	#     #
92 *	#     #
93 *	+-----+
94 *	#     #
95 *	#     #
96 *	#     #
97 *	+#####+
98 */
99	(unsigned char)~SEG_G,
100
101/*	+-----+
102 *	|     #
103 *	|     #
104 *	|     #
105 *	+-----+
106 *	|     #
107 *	|     #
108 *	|     #
109 *	+-----+
110 */
111	SEG_B|SEG_C,
112
113/*	+#####+
114 *	|     #
115 *	|     #
116 *	|     #
117 *	+#####+
118 *	#     |
119 *	#     |
120 *	#     |
121 *	+#####+
122 */
123	~(SEG_C|SEG_F),
124
125/*	+#####+
126 *	|     #
127 *	|     #
128 *	|     #
129 *	+#####+
130 *	|     #
131 *	|     #
132 *	|     #
133 *	+#####+
134 */
135	~(SEG_E|SEG_F),
136
137/*	+-----+
138 *	#     #
139 *	#     #
140 *	#     #
141 *	+#####+
142 *	|     #
143 *	|     #
144 *	|     #
145 *	+-----+
146 */
147	~(SEG_A|SEG_D|SEG_E),
148
149/*	+#####+
150 *	#     |
151 *	#     |
152 *	#     |
153 *	+#####+
154 *	|     #
155 *	|     #
156 *	|     #
157 *	+#####+
158 */
159	~(SEG_B|SEG_E),
160
161/*	+#####+
162 *	#     |
163 *	#     |
164 *	#     |
165 *	+#####+
166 *	#     #
167 *	#     #
168 *	#     #
169 *	+#####+
170 */
171	~(SEG_B),
172
173/*	+#####+
174 *	|     #
175 *	|     #
176 *	|     #
177 *	+-----+
178 *	|     #
179 *	|     #
180 *	|     #
181 *	+-----+
182 */
183	~(SEG_D|SEG_E|SEG_F),
184
185/*	+#####+
186 *	#     #
187 *	#     #
188 *	#     #
189 *	+#####+
190 *	#     #
191 *	#     #
192 *	#     #
193 *	+#####+
194 */
195	~0,
196
197/*	+#####+
198 *	#     #
199 *	#     #
200 *	#     #
201 *	+#####+
202 *	|     #
203 *	|     #
204 *	|     #
205 *	+-----+
206 */
207	~(SEG_D|SEG_E),
208};
209
210static uint8_t
211iq81342_7seg_xlate(char c)
212{
213	uint8_t rv;
214
215	if (c >= '0' && c <= '9')
216		rv = digitmap[c - '0'];
217	else if (c == '.')
218		rv = (uint8_t) ~SEG_DP;
219	else
220		rv = 0xff;
221
222	return (rv);
223}
224
225void
226iq81342_7seg(char a, char b)
227{
228	uint8_t msb, lsb;
229
230	msb = iq81342_7seg_xlate(a);
231	lsb = iq81342_7seg_xlate(b);
232
233	snakestate = 0;
234
235	WRITE(IQ8134X_7SEG_MSB, msb);
236	WRITE(IQ8134X_7SEG_LSB, lsb);
237}
238
239static const uint8_t snakemap[][2] = {
240
241/*	+#####+		+#####+
242 *	|     |		|     |
243 *	|     |		|     |
244 *	|     |		|     |
245 *	+-----+		+-----+
246 *	|     |		|     |
247 *	|     |		|     |
248 *	|     |		|     |
249 *	+-----+		+-----+
250 */
251	{ SEG_A,	SEG_A },
252
253/*	+-----+		+-----+
254 *	#     |		|     #
255 *	#     |		|     #
256 *	#     |		|     #
257 *	+-----+		+-----+
258 *	|     |		|     |
259 *	|     |		|     |
260 *	|     |		|     |
261 *	+-----+		+-----+
262 */
263	{ SEG_F,	SEG_B },
264
265/*	+-----+		+-----+
266 *	|     |		|     |
267 *	|     |		|     |
268 *	|     |		|     |
269 *	+#####+		+#####+
270 *	|     |		|     |
271 *	|     |		|     |
272 *	|     |		|     |
273 *	+-----+		+-----+
274 */
275	{ SEG_G,	SEG_G },
276
277/*	+-----+		+-----+
278 *	|     |		|     |
279 *	|     |		|     |
280 *	|     |		|     |
281 *	+-----+		+-----+
282 *	|     #		#     |
283 *	|     #		#     |
284 *	|     #		#     |
285 *	+-----+		+-----+
286 */
287	{ SEG_C,	SEG_E },
288
289/*	+-----+		+-----+
290 *	|     |		|     |
291 *	|     |		|     |
292 *	|     |		|     |
293 *	+-----+		+-----+
294 *	|     |		|     |
295 *	|     |		|     |
296 *	|     |		|     |
297 *	+#####+		+#####+
298 */
299	{ SEG_D,	SEG_D },
300
301/*	+-----+		+-----+
302 *	|     |		|     |
303 *	|     |		|     |
304 *	|     |		|     |
305 *	+-----+		+-----+
306 *	#     |		|     #
307 *	#     |		|     #
308 *	#     |		|     #
309 *	+-----+		+-----+
310 */
311	{ SEG_E,	SEG_C },
312
313/*	+-----+		+-----+
314 *	|     |		|     |
315 *	|     |		|     |
316 *	|     |		|     |
317 *	+#####+		+#####+
318 *	|     |		|     |
319 *	|     |		|     |
320 *	|     |		|     |
321 *	+-----+		+-----+
322 */
323	{ SEG_G,	SEG_G },
324
325/*	+-----+		+-----+
326 *	|     #		#     |
327 *	|     #		#     |
328 *	|     #		#     |
329 *	+-----+		+-----+
330 *	|     |		|     |
331 *	|     |		|     |
332 *	|     |		|     |
333 *	+-----+		+-----+
334 */
335	{ SEG_B,	SEG_F },
336};
337
338static SYSCTL_NODE(_hw, OID_AUTO, sevenseg, CTLFLAG_RD, 0, "7 seg");
339static int freq = 20;
340SYSCTL_INT(_hw_sevenseg, OID_AUTO, freq, CTLFLAG_RW, &freq, 0,
341    "7 Seg update frequency");
342static void
343iq81342_7seg_snake(void)
344{
345	static int snakefreq;
346	int cur = snakestate;
347
348	snakefreq++;
349	if ((snakefreq % freq))
350		return;
351	WRITE(IQ8134X_7SEG_MSB, snakemap[cur][0]);
352	WRITE(IQ8134X_7SEG_LSB, snakemap[cur][1]);
353
354	snakestate = (cur + 1) & 7;
355}
356
357struct iq81342_7seg_softc {
358	device_t	dev;
359};
360
361static int
362iq81342_7seg_probe(device_t dev)
363{
364
365	device_set_desc(dev, "IQ81342 7seg");
366	return (0);
367}
368
369extern void (*i80321_hardclock_hook)(void);
370static int
371iq81342_7seg_attach(device_t dev)
372{
373
374	i80321_hardclock_hook = iq81342_7seg_snake;
375	return (0);
376}
377
378static device_method_t iq81342_7seg_methods[] = {
379	DEVMETHOD(device_probe, iq81342_7seg_probe),
380	DEVMETHOD(device_attach, iq81342_7seg_attach),
381	{0, 0},
382};
383
384static driver_t iq81342_7seg_driver = {
385	"iqseg",
386	iq81342_7seg_methods,
387	sizeof(struct iq81342_7seg_softc),
388};
389static devclass_t iq81342_7seg_devclass;
390
391DRIVER_MODULE(iqseg, iq, iq81342_7seg_driver, iq81342_7seg_devclass, 0, 0);
392