/* * $Id: gpio7seg.c,v 1.1 2008/01/02 02:32:28 nbrk Exp $ */ #include #include #include #include #include #include /* * 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]); } }