--- linux/arch/mips/am5120/led.c 2006-11-04 14:42:28.000000000 +0100 +++ linux-2.4.32-adm5120/arch/mips/am5120/led.c 2006-05-24 21:00:58.000000000 +0200 @@ -19,21 +19,10 @@ #include #include #include "led.h" +#include "asm/am5120/adm5120.h" #define BUF_LEN 30 -struct LED_DATA { - char sts_buf[BUF_LEN+1]; - unsigned long sts; -}; - -struct LED_DATA led_data[LED_DEV_NUM]; -// sam 01-30-2004 for watchdog -static struct timer_list watchdog; -// end sam - -static struct timer_list blink_timer[LED_DEV_NUM]; -static char cmd_buf[BUF_LEN+1]; //------------------------------------------------------------ static long atoh(char *p) @@ -48,6 +37,7 @@ return v; } +#define REG_BASE (0xb2000000) #define GPIO_VAL (*(unsigned long *)0xb20000b8) #define GPIO_SEL (*(unsigned long *)0xb20000bc) @@ -55,6 +45,13 @@ #define GPIO_O_EN (*(unsigned long *)0xb20000b8) #define INIT_WATCHDOG_REGISTER 0x20 + +#define PORT0_LED (*(unsigned long *)0xb2000100) +#define PORT1_LED (*(unsigned long *)0xb2000104) +#define PORT2_LED (*(unsigned long *)0xb2000108) +#define PORT3_LED (*(unsigned long *)0xb200010c) +#define PORT4_LED (*(unsigned long *)0xb2000110) + // sam 1-30-2004 LED status // bit map as following // BIT 4:0 Link status -->PHY Link ->1 = up, 0 = down @@ -67,9 +64,52 @@ #define WATCHDOG_SET_TMR_SHIFT 16 // bit 16:30 -> watchdog timer set // end sam //------------------------------------------------------------ + +typedef struct { + u32 reg_offset; + u32 bit_no; + int f_inverted; +} led_config_struct; + +static led_config_struct led_config[] = +{ + {GPIO_conf0_REG, 24, 0}, + {GPIO_conf0_REG, 25, 1}, + {Port0_LED_REG, 0, 0}, + {Port1_LED_REG, 0, 0}, + {Port2_LED_REG, 0, 0}, + {Port3_LED_REG, 0, 0}, + {Port4_LED_REG, 0, 0}, + {GPIO_conf0_REG, 27, 1}, + {Port0_LED_REG, 4, 0}, + {Port1_LED_REG, 4, 0}, + {Port2_LED_REG, 4, 0}, + {Port3_LED_REG, 4, 0}, + {Port4_LED_REG, 4, 0}, + {Port0_LED_REG, 8, 0}, + {Port1_LED_REG, 8, 0}, + {Port2_LED_REG, 8, 0}, + {Port3_LED_REG, 8, 0}, + {Port4_LED_REG, 8, 0}, +}; + +struct LED_DATA { + char sts_buf[BUF_LEN+1]; + unsigned long sts; +}; + +struct LED_DATA led_data[ARRAY_SIZE(led_config)]; +// sam 01-30-2004 for watchdog +static struct timer_list watchdog; +// end sam + +static struct timer_list blink_timer[ARRAY_SIZE(led_config)]; +static char cmd_buf[BUF_LEN+1]; + static void turn_led(int id, int on) { unsigned long led_bit,led_bit_val; + if(id <= 7 && id >= 0) { led_bit = 1 << (id); @@ -164,11 +204,49 @@ turn_led(id, 0); } +void +get_led ( + int id, + int* pf_on) +{ + u32* p_reg = (u32*)(led_config[id].reg_offset + REG_BASE); + + + *pf_on = *p_reg & (1 << (led_config[id].bit_no)); + if (( *pf_on && !led_config[id].f_inverted) || + (!(*pf_on) && led_config[id].f_inverted )) + { + *pf_on = 1; + } + else + { + *pf_on = 0; + } + +} +void +set_led ( + int id, + int f_on) +{ + u32* p_reg = (u32*)(led_config[id].reg_offset + REG_BASE); + + if (( f_on && !led_config[id].f_inverted) || + (!f_on && led_config[id].f_inverted )) + { + *p_reg |= (1 << (led_config[id].bit_no)); + } + else + { + *p_reg &= ~(1 << (led_config[id].bit_no)); + } + +} //---------------------------------------------------------------------- static int led_read_proc(char *buf, char **start, off_t fpos, int length, int *eof, void *data) { int len, dev; - for ( len = dev = 0 ; dev < LED_DEV_NUM ; dev++ ) { + for ( len = dev = 0 ; dev < ARRAY_SIZE(led_config) ; dev++ ) { len += sprintf(buf+len, "%d: %s", dev, led_data[dev].sts_buf); } len = strlen(buf) - fpos; @@ -185,26 +263,45 @@ //---------------------------------------------------------------------- static int led_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int id = (int)file->private_data; - switch ( cmd ) { - case LED_ON: - strcpy(led_data[id].sts_buf, "LED ON\n"); - set_led_status_by_str(id); - break; - case LED_OFF: - strcpy(led_data[id].sts_buf, "LED OFF\n"); - set_led_status_by_str(id); - break; - default: + int id = (int)file->private_data; + int* p_leds = (int*)arg; + int f_on; + int i; + + if (arg < ARRAY_SIZE(led_config)) + { + id = arg; + } + switch ( cmd ) { + case 0: // set OFF + set_led(id, 0); + break; + + case 1: // set ON + set_led(id, 1); + break; + + case 2: // get leds state + *p_leds = 0; + for (i = 0; i < 13; i++) + { + get_led(i, &f_on); + *p_leds |= (f_on << i); + } + break; + + default: if ( (cmd & LED_BLINK_CMD) != LED_BLINK_CMD ) - break; - case LED_BLINK: - case LED_BLINK_FAST: - case LED_BLINK_SLOW: - case LED_BLINK_EXTRA_SLOW: + { + break; + } + case LED_BLINK: + case LED_BLINK_FAST: + case LED_BLINK_SLOW: + case LED_BLINK_EXTRA_SLOW: sprintf(led_data[id].sts_buf, "LED BLINK %d\n", (int)(cmd & LED_BLINK_PERIOD)); - set_led_status_by_str(id); - break; + set_led_status_by_str(id); + break; } return 0; } @@ -214,9 +311,11 @@ int led_id = MINOR(inode->i_rdev); unsigned long led_bit = 1 << (led_id); - if ( led_id >= LED_DEV_NUM ) + if ( led_id >= ARRAY_SIZE(led_config) ) + { + printk ("led open %d error ENODEV\n", led_id); return -ENODEV; - + } GPIO_SEL_I_O &= ~led_bit; // 0 to GPIO GPIO_O_EN |= (led_bit << 16); // 0 to Output @@ -377,11 +476,31 @@ return 0; } +static ssize_t gpio_write(struct file *file, const char *buf, size_t count, loff_t *fpos) +{ + int len; + int id = (int)file->private_data; + char *p = id == REG_MINOR ? cmd_buf : led_data[id].sts_buf; + memset(p, 0, BUF_LEN); + p += *fpos; + len = 0; + while ( count > 0 ) { + if ( *fpos < BUF_LEN ) { + int c = *buf++; + p[len] = c>='a' && c<='z' ? c-'a'+'A' : c; + } + (*fpos)++; + len++; + count--; + } + return len; +} + static struct file_operations gpio_fops = { read: gpio_read, open: gpio_open, flush: gpio_flush, - write: led_write, + write: gpio_write, }; //---------------------------------------------- @@ -403,7 +522,7 @@ static void led_exit(void) { int id; - for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { + for ( id = 0 ; id < ARRAY_SIZE(led_config) ; id++ ) { del_timer(&blink_timer[id]); turn_led(id, 0); } @@ -420,10 +539,26 @@ release_region(GPIO_IO_BASE, GPIO_IO_EXTENT); } +#define GPIO_MODE_INPUT 0 +#define GPIO_MODE_OUTPUT 1 + +/* default configuration for Edimax BR-6104K */ +static int adm5120gpio_init_data[] __initdata = { + GPIO_MODE_OUTPUT, /* 0 - Power LED */ + GPIO_MODE_OUTPUT, /* 1 */ + GPIO_MODE_INPUT, /* 2 - Reset switch */ + GPIO_MODE_OUTPUT, /* 3 */ + GPIO_MODE_OUTPUT, /* 4 */ + GPIO_MODE_OUTPUT, /* 5 */ + GPIO_MODE_OUTPUT, /* 6 */ + GPIO_MODE_OUTPUT, /* 7 */ +}; + static int __init led_init(void) { int result, id; - init_status = 0; + int init_status = 0; + unsigned long mode_bit = (1 << (id+16)); //---- request region -------------------------- /* @@ -482,13 +617,32 @@ // reg_addr = (unsigned long *)0xB4000000; reg_addr = (unsigned long *)0xB2000000; dump_len = 4; - for ( id = 0 ; id < LED_DEV_NUM ; id++ ) { - strcpy(led_data[id].sts_buf, "LED OFF\n" ); + printk(KERN_INFO "LED & GPIO Driver " LED_VERSION ", regval %08x, %08x\n", + GPIO_VAL, GPIO_SEL); + for ( id = 0 ; id < ARRAY_SIZE(led_config) ; id++ ) { + GPIO_VAL &= ~mode_bit; + if (adm5120gpio_init_data[id] == GPIO_MODE_OUTPUT) + GPIO_VAL |= mode_bit; + + strcpy(led_data[id].sts_buf, "LED ON\n" ); set_led_status_by_str(id); + mode_bit = mode_bit << 1; + } + printk(KERN_INFO "LED & GPIO Driver " LED_VERSION ", regval %08x, %08x\n", + GPIO_VAL, GPIO_SEL); +#if 1 + //initialize port led registers + PORT0_LED = 0x222; + PORT1_LED = 0x222; + PORT2_LED = 0x222; + PORT3_LED = 0x222; + PORT4_LED = 0x222; + + for ( id = 0 ; id < ARRAY_SIZE(led_config) ; id++ ) + { + set_led(id, 1); } - strcpy(led_data[0].sts_buf,"LED BLINK 100\n"); - set_led_status_by_str(0); - printk(KERN_INFO "LED & GPIO Driver " LED_VERSION "\n"); +#endif return 0; } --- linux/arch/mips/am5120/led.h 2006-11-04 14:42:28.000000000 +0100 +++ linux-2.4.32-adm5120/arch/mips/am5120/led.h 2006-11-04 21:06:51.000000000 +0100 @@ -3,9 +3,9 @@ #include -#define LED_VERSION "v1.1" +#define LED_VERSION "v1.2" #define LED_MAJOR 166 -#define LED_DEV_NUM 8 +#define LED_DEV_NUM 13 #define LED_GPIO_START 1 #define GPIO_MAJOR 167 #define GPIO_DEV_NUM 16 @@ -23,4 +23,8 @@ #define LED_BLINK_SLOW (LED_BLINK_CMD|500) #define LED_BLINK_EXTRA_SLOW (LED_BLINK_CMD|2000) +#define LED_SET_OFF _IOC(_IOC_WRITE, 'j', 0, 4) +#define LED_SET_ON _IOC(_IOC_WRITE, 'j', 1, 4) + +#define LED_GET _IOC(_IOC_READ , 'j', 12, 4) #endif