[BACK]Return to gpio7seg.c CVS log [TXT][DIR] Up to [local] / funnyos / arch / sam7s64 / dev

File: [local] / funnyos / arch / sam7s64 / dev / gpio7seg.c (download)

Revision 1.1, Wed Jan 2 02:32:28 2008 UTC (16 years, 4 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]);
	}

}