File: [local] / funnyos / arch / sam7s64 / dev / gpio7seg.c (download)
Revision 1.1, Wed Jan 2 02:32:28 2008 UTC (16 years, 5 months ago) by nbrk
Branch: MAIN
CVS Tags: HEAD
New driver for 7-segment LED now found on my p64 board.
Driver capable to display decimal digit ranged from 0 to 9 and hexadecimal from 'A' to 'F'.
Full LED on/off (e.g. blinking) is a TODO but should be very trivial to implement.
Driver interfaces itself to the rest of the system via devctl.
~cool thing ;)
|
/*
* $Id: gpio7seg.c,v 1.1 2008/01/02 02:32:28 nbrk Exp $
*/
#include <sys/types.h>
#include <sys/device.h>
#include <sys/gpio.h>
#include <sys/devctl.h>
#include <arch/sam7s64/dev/gpio7segvar.h>
#include <libkern/printf.h>
/*
* Driver for 7-segment LED indicator.
*
* Well known way to describe segments is:
* _a_
* f| |b
* |_g_|
* e| |c
* |_d_|
*
* XXX: There is no way to associate pin to a segment but to hardcode that.
* TODO: Maybe this all gpio stuff should go into MI part.
*/
/* hardcode segments to lines (PA{23, 26-31} in my case) */
#define GPIO7SEG_PINA 26
#define GPIO7SEG_PINB 28
#define GPIO7SEG_PINC 31
#define GPIO7SEG_PIND 29
#define GPIO7SEG_PINE 30
#define GPIO7SEG_PINF 27
#define GPIO7SEG_PING 23
int gpio7seg_attach(struct device *, uint32_t, uint8_t);
int gpio7seg_devctl(struct device *self, uint32_t ctlcmd, void *ctldata);
uint8_t gpio7seg_digit(uint8_t digit);
void gpio7seg_update(struct gpio7seg_dd *ddp);
struct driver gpio7seg_dr = {
sizeof(struct gpio7seg_dd),
gpio7seg_attach,
NULL,
NULL
};
int
gpio7seg_attach(struct device *self, uint32_t loc, uint8_t flags)
{
struct gpio7seg_dd *ddp = self->dv_devdata;
uint8_t i;
/* grab parent's gpio_controller */
ddp->gs_gcp = self->dv_parent->dv_aux;
/*
* Configure pins.
*/
/* assign hardcoded pin numbers */
ddp->gs_pins[0].gp_pinno = GPIO7SEG_PINA;
ddp->gs_pins[1].gp_pinno = GPIO7SEG_PINB;
ddp->gs_pins[2].gp_pinno = GPIO7SEG_PINC;
ddp->gs_pins[3].gp_pinno = GPIO7SEG_PIND;
ddp->gs_pins[4].gp_pinno = GPIO7SEG_PINE;
ddp->gs_pins[5].gp_pinno = GPIO7SEG_PINF;
ddp->gs_pins[6].gp_pinno = GPIO7SEG_PING;
/* set all lines to output, value 1 means 'off' */
for(i = 0; i < 7; i++) {
ddp->gs_pins[i].gp_pio = 1;
ddp->gs_pins[i].gp_flags = GPIO_PIN_OUTPUT;
ddp->gs_pins[i].gp_value = 1; /* OFF by default */
/* talk to gpio controller */
ddp->gs_gcp->gc_pinset(ddp->gs_gcp->gc_selfdd, ddp->gs_pins[i]);
}
printf("p64 onboard 7-segment LED\n");
devctl_register(self, gpio7seg_devctl);
return(0);
}
int
gpio7seg_devctl(struct device *self, uint32_t ctlcmd, void *ctldata)
{
struct gpio7seg_dd *ddp;
uint8_t digit;
ddp = self->dv_devdata;
switch(ctlcmd) {
case(DCGPIO7SEG_OFF):
/*
* Switch all segments off.
*/
ddp->gs_mask &= ~(1 << 7);
gpio7seg_update(ddp);
break;
case(DCGPIO7SEG_ON):
/*
* Switch all segments on.
*/
ddp->gs_mask |= 1 << 7;
gpio7seg_update(ddp);
break;
case(DCGPIO7SEG_SETMASK):
/*
* Manually set indicator mask and update ourselves.
*/
ddp->gs_mask = *(uint8_t *)ctldata;
gpio7seg_update(ddp);
break;
case(DCGPIO7SEG_SETDIGIT):
/*
* Draw given digit. Valid digits are 0..15 (where 10 will be 'A').
*/
digit = *(uint8_t *)ctldata;
if (digit > 15)
/* overflow */
return(-1);
/* modify mask to determine which segments represent given digit */
ddp->gs_mask = gpio7seg_digit(digit);
/* update */
gpio7seg_update(ddp);
default:
break;
}
return(0);
}
uint8_t
gpio7seg_digit(uint8_t digit)
{
/*
* Return bitmask representing given digit.
* Nothing special: this is well-know way.
*/
switch (digit) {
case 0:
return(GPIO7SEG_A | GPIO7SEG_B | GPIO7SEG_C | GPIO7SEG_D | GPIO7SEG_E | GPIO7SEG_F);
case 1:
return(GPIO7SEG_B | GPIO7SEG_C);
case 2:
return(GPIO7SEG_A | GPIO7SEG_B | GPIO7SEG_G | GPIO7SEG_E | GPIO7SEG_D);
case 3:
return(GPIO7SEG_A | GPIO7SEG_B | GPIO7SEG_G | GPIO7SEG_C | GPIO7SEG_D);
case 4:
return(GPIO7SEG_F | GPIO7SEG_G | GPIO7SEG_B | GPIO7SEG_C);
case 5:
return(GPIO7SEG_A | GPIO7SEG_F | GPIO7SEG_G | GPIO7SEG_C | GPIO7SEG_D);
case 6:
return(GPIO7SEG_A | GPIO7SEG_F | GPIO7SEG_G | GPIO7SEG_C | GPIO7SEG_D | GPIO7SEG_E);
case 7:
return(GPIO7SEG_A | GPIO7SEG_B | GPIO7SEG_C);
case 8:
return(GPIO7SEG_A | GPIO7SEG_B | GPIO7SEG_C | GPIO7SEG_D | GPIO7SEG_E | GPIO7SEG_F | GPIO7SEG_G);
case 9:
return(GPIO7SEG_A | GPIO7SEG_F | GPIO7SEG_G | GPIO7SEG_B | GPIO7SEG_C);
case 10:
/* 'A' */
return(GPIO7SEG_E | GPIO7SEG_F | GPIO7SEG_A | GPIO7SEG_B | GPIO7SEG_C | GPIO7SEG_G);
case 11:
/* 'b' */
return(GPIO7SEG_F | GPIO7SEG_E | GPIO7SEG_D | GPIO7SEG_C | GPIO7SEG_G);
case 12:
/* 'C' */
return(GPIO7SEG_A | GPIO7SEG_F | GPIO7SEG_E | GPIO7SEG_D);
case 13:
/* 'd' */
return(GPIO7SEG_B | GPIO7SEG_C | GPIO7SEG_D | GPIO7SEG_E | GPIO7SEG_G);
case 14:
/* 'E' */
return(GPIO7SEG_A | GPIO7SEG_F | GPIO7SEG_G | GPIO7SEG_E | GPIO7SEG_D);
case 15:
/* 'F' */
return(GPIO7SEG_A | GPIO7SEG_F | GPIO7SEG_G | GPIO7SEG_E);
}
/* XXX else return 'OFF' mask */
return(GPIO7SEG_OFF);
}
void
gpio7seg_update(struct gpio7seg_dd *ddp)
{
/*
* Update gpio controller based on our mask.
*/
uint8_t i;
/* see if GPIO7SEG_OFF is given */
if (ddp->gs_mask & GPIO7SEG_OFF) {
/* TODO */
return;
}
for(i = 0; i < 7; i++) {
if (ddp->gs_mask & (1 << i)) {
/* corresponding bit is set */
ddp->gs_pins[i].gp_value = 0;
} else ddp->gs_pins[i].gp_value = 1;
/* kick pio controller */
ddp->gs_gcp->gc_pinset(ddp->gs_gcp->gc_selfdd, ddp->gs_pins[i]);
}
}