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 IQ31244. 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/i80321/iq80321reg.h> 55#include <arm/xscale/i80321/iq80321var.h> 56 57#define WRITE(x, v) *((__volatile uint8_t *) (x)) = (v) 58 59static int snakestate; 60 61/* 62 * The 7-segment display looks like so: 63 * 64 * A 65 * +-----+ 66 * | | 67 * F | | B 68 * | G | 69 * +-----+ 70 * | | 71 * E | | C 72 * | D | 73 * +-----+ o DP 74 * 75 * Setting a bit clears the corresponding segment on the 76 * display. 77 */ 78#define SEG_A (1 << 0) 79#define SEG_B (1 << 1) 80#define SEG_C (1 << 2) 81#define SEG_D (1 << 3) 82#define SEG_E (1 << 4) 83#define SEG_F (1 << 5) 84#define SEG_G (1 << 6) 85#define SEG_DP (1 << 7) 86 87static const uint8_t digitmap[] = { 88/* +#####+ 89 * # # 90 * # # 91 * # # 92 * +-----+ 93 * # # 94 * # # 95 * # # 96 * +#####+ 97 */ 98 SEG_G, 99 100/* +-----+ 101 * | # 102 * | # 103 * | # 104 * +-----+ 105 * | # 106 * | # 107 * | # 108 * +-----+ 109 */ 110 SEG_A|SEG_D|SEG_E|SEG_F|SEG_G, 111 112/* +#####+ 113 * | # 114 * | # 115 * | # 116 * +#####+ 117 * # | 118 * # | 119 * # | 120 * +#####+ 121 */ 122 SEG_C|SEG_F, 123 124/* +#####+ 125 * | # 126 * | # 127 * | # 128 * +#####+ 129 * | # 130 * | # 131 * | # 132 * +#####+ 133 */ 134 SEG_E|SEG_F, 135 136/* +-----+ 137 * # # 138 * # # 139 * # # 140 * +#####+ 141 * | # 142 * | # 143 * | # 144 * +-----+ 145 */ 146 SEG_A|SEG_D|SEG_E, 147 148/* +#####+ 149 * # | 150 * # | 151 * # | 152 * +#####+ 153 * | # 154 * | # 155 * | # 156 * +#####+ 157 */ 158 SEG_B|SEG_E, 159 160/* +#####+ 161 * # | 162 * # | 163 * # | 164 * +#####+ 165 * # # 166 * # # 167 * # # 168 * +#####+ 169 */ 170 SEG_B, 171 172/* +#####+ 173 * | # 174 * | # 175 * | # 176 * +-----+ 177 * | # 178 * | # 179 * | # 180 * +-----+ 181 */ 182 SEG_D|SEG_E|SEG_F, 183 184/* +#####+ 185 * # # 186 * # # 187 * # # 188 * +#####+ 189 * # # 190 * # # 191 * # # 192 * +#####+ 193 */ 194 0, 195 196/* +#####+ 197 * # # 198 * # # 199 * # # 200 * +#####+ 201 * | # 202 * | # 203 * | # 204 * +-----+ 205 */ 206 SEG_D|SEG_E, 207}; 208 209static uint8_t 210iq80321_7seg_xlate(char c) 211{ 212 uint8_t rv; 213 214 if (c >= '0' && c <= '9') 215 rv = digitmap[c - '0']; 216 else if (c == '.') 217 rv = (uint8_t) ~SEG_DP; 218 else 219 rv = 0xff; 220 221 return (rv); 222} 223 224void 225iq80321_7seg(char a, char b) 226{ 227 uint8_t msb, lsb; 228 229 msb = iq80321_7seg_xlate(a); 230 lsb = iq80321_7seg_xlate(b); 231 232 snakestate = 0; 233 234 WRITE(IQ80321_7SEG_MSB, msb); 235 WRITE(IQ80321_7SEG_LSB, lsb); 236} 237 238static const uint8_t snakemap[][2] = { 239 240/* +#####+ +#####+ 241 * | | | | 242 * | | | | 243 * | | | | 244 * +-----+ +-----+ 245 * | | | | 246 * | | | | 247 * | | | | 248 * +-----+ +-----+ 249 */ 250 { ~SEG_A, ~SEG_A }, 251 252/* +-----+ +-----+ 253 * # | | # 254 * # | | # 255 * # | | # 256 * +-----+ +-----+ 257 * | | | | 258 * | | | | 259 * | | | | 260 * +-----+ +-----+ 261 */ 262 { ~SEG_F, ~SEG_B }, 263 264/* +-----+ +-----+ 265 * | | | | 266 * | | | | 267 * | | | | 268 * +#####+ +#####+ 269 * | | | | 270 * | | | | 271 * | | | | 272 * +-----+ +-----+ 273 */ 274 { ~SEG_G, ~SEG_G }, 275 276/* +-----+ +-----+ 277 * | | | | 278 * | | | | 279 * | | | | 280 * +-----+ +-----+ 281 * | # # | 282 * | # # | 283 * | # # | 284 * +-----+ +-----+ 285 */ 286 { ~SEG_C, ~SEG_E }, 287 288/* +-----+ +-----+ 289 * | | | | 290 * | | | | 291 * | | | | 292 * +-----+ +-----+ 293 * | | | | 294 * | | | | 295 * | | | | 296 * +#####+ +#####+ 297 */ 298 { ~SEG_D, ~SEG_D }, 299 300/* +-----+ +-----+ 301 * | | | | 302 * | | | | 303 * | | | | 304 * +-----+ +-----+ 305 * # | | # 306 * # | | # 307 * # | | # 308 * +-----+ +-----+ 309 */ 310 { ~SEG_E, ~SEG_C }, 311 312/* +-----+ +-----+ 313 * | | | | 314 * | | | | 315 * | | | | 316 * +#####+ +#####+ 317 * | | | | 318 * | | | | 319 * | | | | 320 * +-----+ +-----+ 321 */ 322 { ~SEG_G, ~SEG_G }, 323 324/* +-----+ +-----+ 325 * | # # | 326 * | # # | 327 * | # # | 328 * +-----+ +-----+ 329 * | | | | 330 * | | | | 331 * | | | | 332 * +-----+ +-----+ 333 */ 334 { ~SEG_B, ~SEG_F }, 335}; 336 337static SYSCTL_NODE(_hw, OID_AUTO, sevenseg, CTLFLAG_RD, 0, "7 seg"); 338static int freq = 20; 339SYSCTL_INT(_hw_sevenseg, OID_AUTO, freq, CTLFLAG_RW, &freq, 0, 340 "7 Seg update frequency"); 341static void 342iq31244_7seg_snake(void) 343{ 344 static int snakefreq; 345 int cur = snakestate; 346 347 snakefreq++; 348 if ((snakefreq % freq)) 349 return; 350 WRITE(IQ80321_7SEG_MSB, snakemap[cur][0]); 351 WRITE(IQ80321_7SEG_LSB, snakemap[cur][1]); 352 353 snakestate = (cur + 1) & 7; 354} 355 356struct iq31244_7seg_softc { 357 device_t dev; 358}; 359 360static int 361iq31244_7seg_probe(device_t dev) 362{ 363 364 device_set_desc(dev, "IQ31244 7seg"); 365 return (0); 366} 367 368extern void (*i80321_hardclock_hook)(void); 369static int 370iq31244_7seg_attach(device_t dev) 371{ 372 373 i80321_hardclock_hook = iq31244_7seg_snake; 374 return (0); 375} 376 377static device_method_t iq31244_7seg_methods[] = { 378 DEVMETHOD(device_probe, iq31244_7seg_probe), 379 DEVMETHOD(device_attach, iq31244_7seg_attach), 380 {0, 0}, 381}; 382 383static driver_t iq31244_7seg_driver = { 384 "iqseg", 385 iq31244_7seg_methods, 386 sizeof(struct iq31244_7seg_softc), 387}; 388static devclass_t iq31244_7seg_devclass; 389 390DRIVER_MODULE(iqseg, iq, iq31244_7seg_driver, iq31244_7seg_devclass, 0, 0); 391