Add generic gpio support to rdc, convert the led driver to be a platform driver, need to convert the flash driver as well

SVN-Revision: 8348
lede-17.01
Florian Fainelli 2007-08-06 14:15:57 +00:00
parent 9474a045bf
commit ca7294b986
8 changed files with 261 additions and 845 deletions

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2007, OpenWrt.org, Florian Fainelli <florian@openwrt.org>
* RDC321x architecture specific GPIO support
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/delay.h>
#define RDC3210_CFGREG_ADDR 0x0CF8
#define RDC3210_CFGREG_DATA 0x0CFC
static unsigned int rdc_gpio_read(unsigned gpio)
{
unsigned int val;
val = 0x80000000 | (7 << 11) | ((0x48));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
val |= (0x1 << gpio);
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
val = 0x80000000 | (7 << 11) | ((0x4C));
outl(val, RDC3210_CFGREG_ADDR);
udelay(10);
val = inl(RDC3210_CFGREG_DATA);
return val;
}
void rdc_gpio_write(unsigned int val)
{
if (val) {
outl(val, RDC3210_CFGREG_DATA);
udelay(10);
}
}
int rdc_gpio_get_value(unsigned gpio)
{
return ((int)rdc_gpio_read(gpio));
}
EXPORT_SYMBOL(rdc_gpio_get_value);
void rdc_gpio_set_value(unsigned gpio, int value)
{
unsigned int val;
val = rdc_gpio_read(gpio);
if (value)
val &= ~(0x1 << gpio);
else
val |= (0x1 << gpio);
rdc_gpio_write(val);
}
EXPORT_SYMBOL(rdc_gpio_set_value);
int rdc_gpio_direction_input(unsigned gpio)
{
return 0;
}
EXPORT_SYMBOL(rdc_gpio_direction_input);
int rdc_gpio_direction_output(unsigned gpio, int value)
{
return 0;
}
EXPORT_SYMBOL(rdc_gpio_direction_output);

View File

@ -0,0 +1,73 @@
/*
* $Id: platform.c 8331 2007-08-03 15:59:23Z florian $
*
* Generic RDC321x platform devices
*
* Copyright (C) 2007 OpenWrt.org
* Copyright (C) 2007 Florian Fainelli <florian@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <asm/gpio.h>
#include <asm/mach-rdc/rdc321x_defs.h>
/* FIXME : Flash */
static struct resource rdc_flash_resource[] = {
[0] = {
.start = RDC_FLASH_BASE,
.end = RDC_FLASH_BASE+CONFIG_MTD_RDC3210_SIZE-1,
.flags = IORESOURCE_MEM,
},
};
static struct platform_device rdc_flash_device = {
.name = "rdc321x-flash",
.id = -1,
.num_resources = ARRAY_SIZE(rdc_flash_resource),
.resource = rdc_flash_resource,
};
/* LEDS */
static struct platform_device rdc321x_leds = {
.name = "rdc321x-leds",
.id = -1,
.num_resources = 0,
};
static int __init rdc_board_setup(void)
{
int err;
err = platform_device_register(&rdc_flash_device);
if (err)
printk(KERN_ALERT "rdc321x: failed to register flash\n");
err = platform_device_register(&rdc321x_leds);
if (err)
printk(KERN_ALERT "rdc321x: failed to register LEDS\n");
return err;
}
arch_initcall(rdc_board_setup);

View File

@ -10,100 +10,67 @@
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/gpio.h>
#define LED_VAL 0x8000384C // the data ofset of gpio 0~30
int gpio;
module_param(gpio, int, 0444);
MODULE_PARM_DESC(gpio, " GPIO line");
static struct platform_device *pdev;
static void rdc3211_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
static void rdc321x_led_set(struct led_classdev *led_cdev, enum led_brightness brightness)
{
unsigned long ul_ledstat = 0xffffffff;
unsigned long led_bit = 1 << (led_cdev->flags);
if (brightness)
ul_ledstat &= ~led_bit;
else
ul_ledstat|= led_bit;
outl(LED_VAL, 0xcf8);
outl(ul_ledstat, 0xcfc);
gpio_set_value(gpio, brightness ? 1 : 0);
}
static struct led_classdev rdc3211_power_led = {
.name = "rdc3211:power",
.flags = 15,
.brightness_set = rdc3211_led_set,
static struct led_classdev rdc321x_dmz_led = {
.name = "rdc321x:dmz",
.brightness_set = rdc321x_led_set,
};
static struct led_classdev rdc3211_dmz_led = {
.name = "rdc3211:dmz",
.flags = 16,
.brightness_set = rdc3211_led_set,
};
static int rdc3211_leds_probe(struct platform_device *pdev)
static int rdc321x_leds_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &rdc3211_power_led);
if (ret < 0)
return ret;
ret = led_classdev_register(&pdev->dev, &rdc3211_dmz_led);
if (ret < 0)
led_classdev_unregister(&rdc3211_power_led);
return ret;
return led_classdev_register(&pdev->dev, &rdc321x_dmz_led);
}
static int rdc3211_leds_remove(struct platform_device *pdev)
static int rdc321x_leds_remove(struct platform_device *pdev)
{
led_classdev_unregister(&rdc3211_power_led);
led_classdev_unregister(&rdc3211_dmz_led);
led_classdev_unregister(&rdc321x_dmz_led);
return 0;
}
static struct platform_driver rdc3211_leds_driver = {
.probe = rdc3211_leds_probe,
.remove = rdc3211_leds_remove,
static struct platform_driver rdc321x_leds_driver = {
.probe = rdc321x_leds_probe,
.remove = rdc321x_leds_remove,
.driver = {
.name = "rdc3211-leds",
.name = "rdc321x-leds",
.owner = THIS_MODULE,
}
};
static int __init rdc3211_leds_init(void)
static int __init rdc321x_leds_init(void)
{
int ret;
ret = platform_driver_register(&rdc3211_leds_driver);
if (ret < 0)
goto out;
ret = platform_driver_register(&rdc321x_leds_driver);
pdev = platform_device_register_simple("rdc3211-leds", -1, NULL, 0);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
platform_driver_unregister(&rdc3211_leds_driver);
goto out;
}
out:
return ret;
}
static void __exit rdc3211_leds_exit(void)
static void __exit rdc321x_leds_exit(void)
{
platform_driver_unregister(&rdc3211_leds_driver);
platform_driver_unregister(&rdc321x_leds_driver);
}
module_init(rdc3211_leds_init);
module_exit(rdc3211_leds_exit);
module_init(rdc321x_leds_init);
module_exit(rdc321x_leds_exit);
MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>");
MODULE_DESCRIPTION("RDC3211 LED driver");
MODULE_DESCRIPTION("RDC321x LED driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,6 @@
#ifndef _ASM_I386_GPIO_H
#define _ASM_I386_GPIO_H
#include <gpio.h>
#endif /* _ASM_I386_GPIO_H */

View File

@ -0,0 +1,15 @@
#ifndef __ASM_MACH_GENERIC_GPIO_H
#define __ASM_MACH_GENERIC_GPIO_H
int gpio_request(unsigned gpio, const char *label);
void gpio_free(unsigned gpio);
int gpio_direction_input(unsigned gpio);
int gpio_direction_output(unsigned gpio, int value);
int gpio_get_value(unsigned gpio);
void gpio_set_value(unsigned gpio, int value);
int gpio_to_irq(unsigned gpio);
int irq_to_gpio(unsigned irq);
#include <asm-generic/gpio.h> /* cansleep wrappers */
#endif /* __ASM_MACH_GENERIC_GPIO_H */

View File

@ -0,0 +1,56 @@
#ifndef _RDC_GPIO_H
#define _RDC_GPIO_H
extern int rdc_gpio_get_value(unsigned gpio);
extern void rdc_gpio_set_value(unsigned gpio, int value);
extern int rdc_gpio_direction_input(unsigned gpio);
extern int rdc_gpio_direction_output(unsigned gpio, int value);
/* Wrappers for the arch-neutral GPIO API */
static inline int gpio_request(unsigned gpio, const char *label)
{
/* Not yet implemented */
return 0;
}
static inline void gpio_free(unsigned gpio)
{
/* Not yet implemented */
}
static inline int gpio_direction_input(unsigned gpio)
{
return rdc_gpio_direction_input(gpio);
}
static inline int gpio_direction_output(unsigned gpio, int value)
{
return rdc_gpio_direction_output(gpio, value);
}
static inline int gpio_get_value(unsigned gpio)
{
return rdc_gpio_get_value(gpio);
}
static inline void gpio_set_value(unsigned gpio, int value)
{
rdc_gpio_set_value(gpio, value);
}
static inline int gpio_to_irq(unsigned gpio)
{
return gpio;
}
static inline int irq_to_gpio(unsigned irq)
{
return irq;
}
/* For cansleep */
#include <asm-generic/gpio.h>
#endif /* _RDC_GPIO_H_ */

View File

@ -0,0 +1 @@
#define RDC_FLASH_BASE 0xffc00000

View File

@ -24,7 +24,7 @@ diff -urN linux-2.6.19/arch/i386/Makefile linux-2.6.19.new/arch/i386/Makefile
mcore-$(CONFIG_X86_ES7000) := mach-default
core-$(CONFIG_X86_ES7000) := arch/i386/mach-es7000/
+# RDC subarch support
+mflags-$(CONFIG_X86_RDC) := -Iinclude/asm-i386/mach-generic
+mflags-$(CONFIG_X86_RDC) := -Iinclude/asm-i386/mach-rdc
+mcore-$(CONFIG_X86_RDC) := mach-default
+core-$(CONFIG_X86_RDC) += arch/i386/mach-rdc/
@ -38,787 +38,4 @@ diff -urN linux-2.6.19/arch/i386/mach-rdc/Makefile linux-2.6.19.new/arch/i386/ma
+# Makefile for the linux kernel.
+#
+
+obj-$(CONFIG_X86_RDC) := led.o
diff -urN linux-2.6.19/arch/i386/mach-rdc/led.c linux-2.6.19.new/arch/i386/mach-rdc/led.c
--- linux-2.6.19/arch/i386/mach-rdc/led.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.new/arch/i386/mach-rdc/led.c 2006-12-17 17:13:33.000000000 +0100
@@ -0,0 +1,743 @@
+/*
+ * LED interface for WP3200
+ *
+ * Copyright (C) 2002, by Allen Hung
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/reboot.h>
+
+#include "led.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
+unsigned long ul_ledstat = 0xffffffff;
+
+
+static struct timer_list blink_timer[LED_DEV_NUM];
+// sam 01-30-2004 for watchdog
+static struct timer_list watchdog;
+// end sam
+static char cmd_buf[BUF_LEN+1];
+
+//------------------------------------------------------------
+static long atoh(char *p)
+{
+ long v = 0, c;
+ while ( (c = *p++) ) {
+ if ( c >= '0' && c <= '9' ) v = (v << 4) + c - '0';
+ else if ( c >= 'a' && c <= 'f' ) v = (v << 4) + c - 'a' + 0xA;
+ else if ( c >= 'A' && c <= 'F' ) v = (v << 4) + c - 'A' + 0xA;
+ else break;
+ }
+ return v;
+}
+
+static int reset_flash_default(void *data)
+{
+ char *argv[3], *envp[1] = {NULL};
+ int i = 0;
+
+ int reset_default=(int) data;
+
+ argv[i++] = "/bin/flash";
+ argv[i++] = "default";
+ argv[i] = NULL;
+ if(reset_default)
+ if (call_usermodehelper(argv[0], argv, envp, 1))
+ printk("failed to Reset to default\n");
+ machine_restart(0);
+ return 0;
+}
+
+// sam for ps 3205U -- using CSx1 (0xb0e00000)
+// bit map as following
+// BIT 1 2 3 4 5
+// POWER WLEN PORT1 PORT2 PORT3
+//
+// value 0 --> led on
+// value 1 --> led off
+
+#define _ROUTER_
+
+#ifdef _ROUTER_
+ #define LED_VAL 0x8000384C // the data ofset of gpio 0~30
+#else
+ #define LED_VAL 0x80003888 // the ofset of gpio 31~58
+#endif
+#define GPIO_VAL 0x8000384C // the offset of gpio 0-30
+
+
+
+// sam 1-30-2004 LED status
+// bit map as following
+// BIT 4:0 Link status -->PHY Link ->1 = up, 0 = down
+#define LINK_STATUS (*(unsigned long *)0xb2000014)
+#define WATCHDOG_VAL (*(unsigned long *)0xb20000c0)
+#define WATCHDOG_PERIOD 500 // unit ms
+#define EXPIRE_TIME 300 // unit 10 ms
+#define CLEAR_TIMEER 0xffffa000l // bit 14:0 -> count up timer, write 0 to clear
+#define ENABLE_WATCHDOG 0x80000000l // bit 31 -> 1 enable , 0 disable watchdog
+#define WATCHDOG_SET_TMR_SHIFT 16 // bit 16:30 -> watchdog timer set
+// end sam
+
+
+//------------------------------------------------------------
+static void turn_led(int id, int on)
+{
+ unsigned long led_bit = 1 << (id);
+ unsigned long led_bit_val;
+
+ // since we define we have 8 led devices and use gpio 53, 55, 57, 58
+ // which locate at bit21~26, so we rotate left 20bit
+
+#ifdef _ROUTER_
+ led_bit_val = led_bit;
+#else
+ led_bit_val = led_bit << 20;
+#endif
+
+ switch ( on ) {
+ case 0:
+ ul_ledstat|= led_bit_val;
+ outl(LED_VAL, 0xcf8);
+ outl(ul_ledstat, 0xcfc);
+ break; // LED OFF
+ case 1:
+ ul_ledstat &= ~led_bit_val;
+ outl(LED_VAL, 0xcf8);
+ outl(ul_ledstat, 0xcfc);
+ break; // LED ON
+ case 2:
+ ul_ledstat ^= led_bit_val;
+ outl(LED_VAL, 0xcf8);
+ outl(ul_ledstat, 0xcfc);
+ break; // LED inverse
+ }
+}
+
+
+static int led_flash[30]={20,10,100,5,5,150,100,5,5,50,20,50,50,20,60,5,20,10,30,10,5,10,50,2,5,5,5,70,10,50};//Erwin
+static unsigned int wlan_counter; //Erwin
+static void blink_wrapper(u_long id)
+{
+ u_long sts = led_data[id].sts;
+
+ if ( (sts & LED_BLINK_CMD) == LED_BLINK_CMD ) {
+ unsigned long period = sts & LED_BLINK_PERIOD;
+ if(period == 0xffff) // BLINK random
+ {
+ blink_timer[id].expires = jiffies + 3*led_flash[wlan_counter%30]*HZ/1000;
+ wlan_counter++;
+ }
+ else
+ blink_timer[id].expires = jiffies + (period * HZ / 1000);
+ turn_led(id, 2);
+ add_timer(&blink_timer[id]);
+ }
+ else if ( sts == LED_ON || sts == LED_OFF )
+ turn_led(id, sts==LED_ON ? 1 : 0);
+}
+//------------------------------------------------------------
+static void get_token_str(char *str, char token[][21], int token_num)
+{
+ int t, i;
+
+ for ( t = 0 ; t < token_num ; t++ ) {
+ memset(token[t], 0, 21);
+ while ( *str == ' ' ) str++;
+ for ( i = 0 ; str[i] ; i++ ) {
+ if ( str[i] == '\t' || str[i] == ' ' || str[i] == '\n' ) break;
+ if ( i < 20 ) token[t][i] = str[i];
+ }
+ str += i;
+ }
+}
+
+//------------------------------------------------------------
+static void set_led_status_by_str(int id)
+{
+ char token[3][21], *p;
+
+
+ get_token_str(led_data[id].sts_buf, token, 3);
+
+ if ( strcmp(token[0], "LED") )
+ {
+ goto set_led_off;
+ }
+ if ( !strcmp(token[1], "ON") )
+ {
+
+ turn_led(id, 1);
+ led_data[id].sts = LED_ON;
+ }
+ else if ( !strcmp(token[1], "OFF") )
+ {
+
+ goto set_led_off;
+ }
+ else if ( !strcmp(token[1], "BLINK") )
+ {
+ unsigned int period = 0;
+ p = token[2];
+ if ( !strcmp(p, "FAST") )
+ period = LED_BLINK_FAST & LED_BLINK_PERIOD;
+ else if ( !strcmp(p, "SLOW") )
+ period = LED_BLINK_SLOW & LED_BLINK_PERIOD;
+ else if ( !strcmp(p, "EXTRA_SLOW") )
+ period = LED_BLINK_EXTRA_SLOW & LED_BLINK_PERIOD;
+ else if ( !strcmp(p, "RANDOM") )
+ period = LED_BLINK_RANDOM & LED_BLINK_PERIOD;
+ else if ( !strcmp(p, "OFF") )
+ goto set_led_off;
+ else if ( *p >= '0' && *p <= '9' )
+ {
+ while ( *p >= '0' && *p <= '9' )
+ period = period * 10 + (*p++) - '0';
+// if ( period > 10000 )
+// period = 10000;
+ }
+ else
+ period = LED_BLINK & LED_BLINK_PERIOD;
+
+ if ( period == 0 )
+ goto set_led_off;
+
+ sprintf(led_data[id].sts_buf, "LED BLINK %d\n", period);
+ led_data[id].sts = LED_BLINK_CMD + period;
+ turn_led(id, 2);
+ // Set timer for next blink
+ del_timer(&blink_timer[id]);
+ blink_timer[id].function = blink_wrapper;
+ blink_timer[id].data = id;
+ init_timer(&blink_timer[id]);
+
+ blink_timer[id].expires = jiffies + (1000 * HZ / 1000);
+
+ add_timer(&blink_timer[id]);
+ }
+ else
+ {
+ goto set_led_off;
+ }
+ return;
+ set_led_off:
+ strcpy(led_data[id].sts_buf, "LED OFF\n");
+ led_data[id].sts = LED_OFF;
+ turn_led(id, 0);
+}
+
+//----------------------------------------------------------------------
+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++ ) {
+ len += sprintf(buf+len, "%d: %s", dev, led_data[dev].sts_buf);
+ }
+ len = strlen(buf) - fpos;
+ if ( len <= 0 ) {
+ *start = buf;
+ *eof = 1;
+ return 0;
+ }
+ *start = buf + fpos;
+ if ( len <= length ) *eof = 1;
+ return len < length ? len : length;
+}
+
+//----------------------------------------------------------------------
+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:
+ 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:
+ case LED_BLINK_RANDOM:
+ sprintf(led_data[id].sts_buf, "LED BLINK %d\n", (int)(cmd & LED_BLINK_PERIOD));
+ set_led_status_by_str(id);
+ break;
+ }
+ return 0;
+}
+
+static int led_open(struct inode *inode, struct file *file)
+{
+ int led_id = MINOR(inode->i_rdev);
+// unsigned long led_bit = 1 << (led_id);
+
+ if ( led_id >= LED_DEV_NUM )
+ return -ENODEV;
+/* sam 12/02/2003
+ GPIO_SEL_I_O &= ~led_bit; // 0 to GPIO
+ GPIO_O_EN |= (led_bit << 16); // 0 to Output
+*/
+
+ file->private_data = (void*)led_id;
+ return 0;
+}
+
+static long led_read(struct file *file, char *buf, size_t count, loff_t *fpos)
+{
+ int rem, len;
+ int id = (int)file->private_data;
+ char *p = led_data[id].sts_buf;
+
+ len = strlen(p);
+ rem = len - *fpos;
+ if ( rem <= 0 ) {
+ *fpos = len;
+ return 0;
+ }
+ if ( rem > count ) rem = count;
+ memcpy(buf, p+(*fpos), rem);
+ *fpos += rem;
+ return rem;
+}
+
+static long led_write(struct file *file, 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--;
+ }
+ // sam
+ set_led_status_by_str(id);
+ (*fpos) = 0;
+ //
+
+ return len;
+}
+
+static int led_flush(struct file *file)
+{
+ int id = (int)file->private_data;
+
+ if ( file->f_mode & FMODE_WRITE )
+ {
+ set_led_status_by_str(id);
+ }
+ return 0;
+}
+
+static struct file_operations led_fops = {
+ read: led_read,
+ write: led_write,
+ flush: led_flush,
+ ioctl: led_ioctl,
+ open: led_open,
+};
+
+//----------------------------------------------
+static unsigned long *reg_addr;
+static int dump_len;
+
+static int dump_content(char *buf)
+{
+ return 0;
+}
+
+static long gpio_read(struct file *file, char *buf, size_t count, loff_t *fpos)
+{
+ int rem, len;
+ int id = (int)file->private_data;
+ char temp[80*10];
+ unsigned long gpio_regval =0;
+
+ outl(GPIO_VAL, 0xcf8);
+ gpio_regval = inl(0xcfc);
+ gpio_regval |= 0x40;
+ outl(gpio_regval, 0xcfc); // each in, need out 1 first
+ gpio_regval = inl(0xcfc);
+
+
+ // sam debug
+ //printk(KERN_ERR "gpio_id:%d, gpio_regval:%08X\n", id, gpio_regval);
+ //end sam
+
+ if ( id < GPIO_DEV_NUM ) {
+ int gpio_bit = 1 << id;
+
+ len = sprintf(temp, "%d\n", (gpio_regval & gpio_bit) ? 1 : 0);
+ }
+ else // REG device
+ len = dump_content(temp);
+ rem = len - *fpos;
+ if ( rem <= 0 ) {
+ *fpos = len;
+ return 0;
+ }
+ if ( rem > count ) rem = count;
+ memcpy(buf, temp+(*fpos), rem);
+ *fpos += rem;
+ return rem;
+}
+
+static int gpio_flush(struct file *file)
+{
+ return 0;
+}
+
+static int gpio_open(struct inode *inode, struct file *file)
+{
+ int id = MINOR(inode->i_rdev);
+ if ( id >= GPIO_DEV_NUM && id != REG_MINOR )
+ return -ENODEV;
+ file->private_data = (void*)id;
+ return 0;
+}
+
+static struct file_operations gpio_fops = {
+ read: gpio_read,
+ open: gpio_open,
+ flush: gpio_flush,
+ write: led_write,
+};
+
+// ---------------------------------------------
+// sam 1-30-2004 LAN_STATUS Device
+
+//static unsigned long *reg_addr;
+//static int dump_len;
+
+//static int lanSt_content(char *buf)
+//{
+// int i, j, len;
+// unsigned long *p = (unsigned long *)0xb2000014; // PHY_ST
+// // j = dump_len/4 + ((dump_len&3) ? 1 : 0);
+// len = sprintf(buf, "Reg Addr = %08lX, Value = \n", (unsigned long)p);
+// // for ( i = 0 ; i < j ; i++, p++ )
+// len += sprintf(buf+len,"%08lX\n", *p);
+
+// return len;
+//}
+
+#define MAC_IOBASE 0xe800 // Eth0
+#define PHY_ADDR 1 // For Eth0
+#define MII_STATUS_ADDR 1
+// where "id" value means which bit of PHY reg 1 we want to check
+static long lanSt_read(struct file *file, char *buf, size_t count, loff_t *fpos)
+{
+ int rem, len;
+// unsigned long *p = (unsigned long *)0xb2000014; // PHY_ST
+ unsigned short status;
+ unsigned int i = 0;
+ int id = (int)file->private_data;
+ char temp[80*10];
+
+ outw(0x2000 + MII_STATUS_ADDR + (PHY_ADDR << 8), MAC_IOBASE + 0x20);
+ do{}while( (i++ < 2048) && (inw(MAC_IOBASE+0x20) & 0x2000) );
+
+ status = inw(MAC_IOBASE + 0x24);
+
+ // sam debug
+ //printk(KERN_ERR "PHY REG1 Status:%04x\n", status );
+ // end sam
+
+ if ( id < LAN_DEV_NUM ) {
+ unsigned long lanSt_bit = 1 << id;
+// len = lanSt_content(temp);
+ len = sprintf(temp, "%d\n",(status & lanSt_bit) ? 1 : 0);
+ }
+ else // REG device
+ {
+ len = sprintf(temp, "-1\n");
+ }
+ rem = len - *fpos;
+ if ( rem <= 0 ) {
+ *fpos = len;
+ return 0;
+ }
+ if ( rem > count ) rem = count;
+ memcpy(buf, temp+(*fpos), rem);
+ *fpos += rem;
+ return rem;
+}
+
+static int lanSt_flush(struct file *file)
+{
+ return 0;
+}
+
+static int lanSt_open(struct inode *inode, struct file *file)
+{
+ int id = MINOR(inode->i_rdev);
+ if ( id >= LAN_DEV_NUM && id != REG_MINOR )
+ return -ENODEV;
+ file->private_data = (void*)id;
+ return 0;
+}
+
+static struct file_operations lanSt_fops = {
+ read: lanSt_read,
+ open: lanSt_open,
+ flush: lanSt_flush,
+ write: led_write,
+};
+
+//----------------------------------------------
+static int SwResetPress = 0;
+static int SwResetCounter = 0;
+static int RebootFlag = 0;
+static void watchdog_wrapper(unsigned int period)
+{
+ // { RexHua add for restore default, by press SwReset 5 second, 2 sec to restart
+#if 0 //
+ u_long reg;
+
+ outl(GPIO_VAL, 0xcf8);
+ reg = inl(0xcfc);
+ reg |= 0x40;
+ outl(reg, 0xcfc); // each in, need out 1 first
+ reg = inl(0xcfc);
+
+ if( (reg & 0x40) == 0)
+ {
+ if(SwResetPress == 0)
+ {
+ SwResetCounter=0;
+ strcpy(led_data[15].sts_buf, "LED BLINK 500\n" );
+ set_led_status_by_str(15);
+ }
+ SwResetPress=1;
+ printk("SwReset press!\n");
+
+ }
+ else
+ {
+ if(SwResetPress=1)
+ {
+ strcpy(led_data[15].sts_buf, "LED ON\n" );
+ set_led_status_by_str(15);
+ }
+
+ SwResetPress=0;
+ if(RebootFlag == 1)
+ machine_restart(0);
+ }
+
+ if(SwResetPress == 1)
+ {
+ if(SwResetCounter > 10)
+ {
+ turn_led(15, 0);
+// kernel_thread(reset_flash_default, 1, SIGCHLD);
+ reset_flash_default(1);
+ turn_led(15, 1);
+ }
+ else if(SwResetCounter == 3)
+ {
+ RebootFlag=1;
+ strcpy(led_data[15].sts_buf, "LED BLINK 100\n" );
+ set_led_status_by_str(15);
+ }
+ }
+
+ SwResetCounter++;
+#endif
+
+ // clear timer count
+ outl(0x80003844, 0xcf8);
+ outl(0x00800080, 0xcfc); // enable watchdog and set the timeout = 1.34s
+ //printk(KERN_ERR "wdt\n" );
+ watchdog.expires = jiffies + (period * HZ / 1000);
+ add_timer(&watchdog);
+}
+
+//----------------------------------------------
+static int init_status;
+
+#define INIT_REGION 0x01
+#define INIT_LED_REGISTER 0x02
+#define INIT_LED_PROC_READ 0x04
+#define INIT_GPIO_REGISTER 0x08
+// sam 1-30-2004 LAN_STATUS
+#define INIT_LAN_STATUS_REGISTER 0x10
+#define INIT_WATCHDOG_REGISTER 0x20
+
+static void led_exit(void)
+{
+ int id;
+ for ( id = 0 ; id < LED_DEV_NUM ; id++ ) {
+ del_timer(&blink_timer[id]);
+ turn_led(id, 0);
+ }
+ if ( init_status & INIT_LED_PROC_READ )
+ remove_proc_entry("driver/led", NULL);
+
+ if ( init_status & INIT_LED_REGISTER )
+ unregister_chrdev(LED_MAJOR, "led");
+
+ if ( init_status & INIT_GPIO_REGISTER )
+ unregister_chrdev(GPIO_MAJOR, "gpio");
+ // sam 1-30-2004
+
+ if( init_status & INIT_LAN_STATUS_REGISTER )
+ unregister_chrdev(LAN_STATUS_MAJOR, "lanSt");
+
+ if( init_status & INIT_WATCHDOG_REGISTER)
+ del_timer(&watchdog);
+
+
+ // end sam
+
+}
+
+static int __init led_init(void)
+{
+ int result, id, i, j;
+ unsigned long reg;
+ init_status = 0;
+
+ //----- register device (LED)-------------------------
+
+
+ result = register_chrdev(LED_MAJOR, "led", &led_fops);
+ if ( result < 0 ) {
+ printk(KERN_ERR "led: can't register char device\n" );
+ led_exit();
+ return result;
+ }
+ init_status |= INIT_LED_REGISTER;
+ //----- register device (GPIO)-------------------------
+ result = register_chrdev(GPIO_MAJOR, "gpio", &gpio_fops);
+ if ( result < 0 ) {
+ printk(KERN_ERR "gpio: can't register char device\n" );
+ led_exit();
+ return result;
+ }
+ init_status |= INIT_GPIO_REGISTER;
+
+ // sam 1-30-2004 LAN Status
+ // ----- register device (LAN_STATUS)-------------------
+
+ //--> sam 5-1802995
+
+ result = register_chrdev(LAN_STATUS_MAJOR, "lanSt", &lanSt_fops);
+ if ( result < 0 ) {
+ printk(KERN_ERR "lanSt: can't register char device\n" );
+ led_exit();
+ return result;
+ }
+ init_status |= INIT_LAN_STATUS_REGISTER;
+
+ // <-- end sam
+
+ // -----------init watchdog timer-------------------------
+ //del_timer(&blink_timer[id]);
+
+ outl(0x80003840, 0xcf8);
+ reg = inl(0xcfc);
+ reg |= 0x1600; // ensable SRC bit
+ outl(reg, 0xcfc);
+#ifdef _ROUTER_
+ outl(0x80003848, 0xcf8);
+ reg = inl(0xcfc);
+ reg |= 0x18040; // enable GPIO, PowerLED:15, WLAN_LED0:16, SwReset:6
+ outl(reg, 0xcfc);
+
+ outl(0x8000384c, 0xcf8);
+ reg = inl(0xcfc);
+ reg |= 0x40; // output SwReset:6 1, Set SwReset as Input
+ outl(reg, 0xcfc);
+#endif
+ // sam debug
+ //reg = inl(0xcfc);
+ //printk(KERN_ERR "REG40:%08X\n", reg);
+ // end sam
+ outl(0x80003844, 0xcf8);
+ outl(0x00800080, 0xcfc); // enable watchdog and set the timeout = 1.34s
+
+ watchdog.function = watchdog_wrapper;
+ watchdog.data = WATCHDOG_PERIOD;
+ init_timer(&watchdog);
+ watchdog.expires = jiffies + (WATCHDOG_PERIOD * HZ / 1000);
+ add_timer(&watchdog);
+ init_status |= INIT_WATCHDOG_REGISTER;
+
+ // end sam
+ //------ read proc -------------------
+ if ( !create_proc_read_entry("driver/led", 0, 0, led_read_proc, NULL) ) {
+ printk(KERN_ERR "led: can't create /proc/driver/led\n");
+ led_exit();
+ return -ENOMEM;
+ }
+ init_status |= INIT_LED_PROC_READ;
+ //------------------------------
+// reg_addr = (unsigned long *)0xB4000000;
+// dump_len = 4;
+
+ for ( id = 0 ; id < LED_DEV_NUM ; id++ ) {
+ strcpy(led_data[id].sts_buf, "LED ON\n" );
+ set_led_status_by_str(id);
+ }
+
+// for (i = 0; i < 0xffff; i++)
+// for (j = 0; j < 0x6000; j++);
+
+/* sam 5-18-2005 remark
+ for ( id = 0 ; id < LED_DEV_NUM ; id++ ) {
+ strcpy(led_data[id].sts_buf, "LED ON\n" );
+ set_led_status_by_str(id);
+ }
+*/
+ printk(KERN_INFO "LED & GPIO & LAN Status Driver LED_VERSION \n");
+ return 0;
+}
+
+module_init(led_init);
+module_exit(led_exit);
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.6.19/arch/i386/mach-rdc/led.h linux-2.6.19.new/arch/i386/mach-rdc/led.h
--- linux-2.6.19/arch/i386/mach-rdc/led.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.19.new/arch/i386/mach-rdc/led.h 2006-12-17 17:13:33.000000000 +0100
@@ -0,0 +1,32 @@
+#ifndef _LED_H_INCLUDED
+#define _LED_H_INCLUDED
+
+#include <linux/autoconf.h>
+
+#define LED_VERSION "v1.0"
+#define LED_MAJOR 166
+#define LED_DEV_NUM 32
+#define LED_GPIO_START 1
+#define GPIO_MAJOR 167
+#define GPIO_DEV_NUM 32
+#define REG_MINOR 128
+// sam 1-30-2004 for LAN_STATUS
+#define LAN_STATUS_MAJOR 168
+#define LAN_DEV_NUM 5
+// end sam
+
+//#define GPIO_IO_BASE 0xB4002480
+//#define GPIO_IO_BASE ((unsigned long)0xb20000b8)
+//#define GPIO_IO_EXTENT 0x40
+
+#define LED_ON 0x010000
+#define LED_OFF 0x020000
+#define LED_BLINK_CMD 0x030000
+#define LED_BLINK_PERIOD 0x00FFFF
+#define LED_BLINK (LED_BLINK_CMD|1000)
+#define LED_BLINK_FAST (LED_BLINK_CMD|250)
+#define LED_BLINK_SLOW (LED_BLINK_CMD|500)
+#define LED_BLINK_EXTRA_SLOW (LED_BLINK_CMD|2000)
+#define LED_BLINK_RANDOM (LED_BLINK_CMD|0xffff)
+
+#endif
+obj-$(CONFIG_X86_RDC) := gpio.o platform.o