diff options
Diffstat (limited to 'target/linux/rdc/files/arch/x86')
| -rw-r--r-- | target/linux/rdc/files/arch/x86/kernel/cpu/rdc.c | 24 | ||||
| -rw-r--r-- | target/linux/rdc/files/arch/x86/mach-rdc/Makefile | 5 | ||||
| -rw-r--r-- | target/linux/rdc/files/arch/x86/mach-rdc/gpio.c | 91 | ||||
| -rw-r--r-- | target/linux/rdc/files/arch/x86/mach-rdc/platform.c | 114 | ||||
| -rw-r--r-- | target/linux/rdc/files/arch/x86/mach-rdc/setup.c | 14 | ||||
| -rw-r--r-- | target/linux/rdc/files/arch/x86/mach-rdc/wdt.c | 272 | 
6 files changed, 520 insertions, 0 deletions
| diff --git a/target/linux/rdc/files/arch/x86/kernel/cpu/rdc.c b/target/linux/rdc/files/arch/x86/kernel/cpu/rdc.c new file mode 100644 index 000000000..f4b9083bf --- /dev/null +++ b/target/linux/rdc/files/arch/x86/kernel/cpu/rdc.c @@ -0,0 +1,24 @@ +#include <linux/init.h> +#include <linux/bitops.h> +#include <linux/mm.h> +#include <asm/io.h> +#include <asm/processor.h> + +#include "cpu.h" + +static struct cpu_dev rdc_cpu_dev __cpuinitdata = { +        .c_vendor       = "RDC", +        .c_models = { +                { .vendor = X86_VENDOR_RDC, .family = 4, .model_names = +                  { +                          [0] = "R861x(-G)", +                  } +                }, +        }, +}; + +int __init rdc_init_cpu(void) +{ +        cpu_devs[X86_VENDOR_RDC] = &rdc_cpu_dev; +        return 0; +} diff --git a/target/linux/rdc/files/arch/x86/mach-rdc/Makefile b/target/linux/rdc/files/arch/x86/mach-rdc/Makefile new file mode 100644 index 000000000..5961bc791 --- /dev/null +++ b/target/linux/rdc/files/arch/x86/mach-rdc/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the RDC321x specific parts of the kernel +# +obj-$(CONFIG_X86_RDC)        := gpio.o platform.o wdt.o + diff --git a/target/linux/rdc/files/arch/x86/mach-rdc/gpio.c b/target/linux/rdc/files/arch/x86/mach-rdc/gpio.c new file mode 100644 index 000000000..dbd03270f --- /dev/null +++ b/target/linux/rdc/files/arch/x86/mach-rdc/gpio.c @@ -0,0 +1,91 @@ +/* + *  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> + +#include <asm/mach-rdc/rdc321x_defs.h> + +static inline int rdc_gpio_is_valid(unsigned gpio) +{ +	return (gpio <= RDC_MAX_GPIO); +} + +static unsigned int rdc_gpio_read(unsigned gpio) +{ +	unsigned int val; + +	val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x84:0x48)); +        outl(val, RDC3210_CFGREG_ADDR); +        udelay(10); +        val = inl(RDC3210_CFGREG_DATA); +        val |= (0x1 << (gpio & 0x1F)); +        outl(val, RDC3210_CFGREG_DATA); +        udelay(10); +        val = 0x80000000 | (7 << 11) | ((gpio&0x20?0x88:0x4C)); +        outl(val, RDC3210_CFGREG_ADDR); +        udelay(10); +        val = inl(RDC3210_CFGREG_DATA); + +	return val; +} + +static void rdc_gpio_write(unsigned int val) +{ +	if (val) { +		outl(val, RDC3210_CFGREG_DATA); +		udelay(10); +	} +} + +int rdc_gpio_get_value(unsigned gpio) +{ +	if (rdc_gpio_is_valid(gpio)) +		return (int)rdc_gpio_read(gpio); +	else +		return -EINVAL; +} +EXPORT_SYMBOL(rdc_gpio_get_value); + +void rdc_gpio_set_value(unsigned gpio, int value) +{ +	unsigned int val; + +	if (!rdc_gpio_is_valid(gpio)) +		return; +	 +	val = rdc_gpio_read(gpio); + +	if (value) +		val &= ~(0x1 << (gpio & 0x1F)); +	else +		val |= (0x1 << (gpio & 0x1F)); + +	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); + + diff --git a/target/linux/rdc/files/arch/x86/mach-rdc/platform.c b/target/linux/rdc/files/arch/x86/mach-rdc/platform.c new file mode 100644 index 000000000..31af6fcc3 --- /dev/null +++ b/target/linux/rdc/files/arch/x86/mach-rdc/platform.c @@ -0,0 +1,114 @@ +/* + *  $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 <linux/version.h> +#include <linux/leds.h> +#include <linux/gpio_keys.h> +#include <linux/input.h> + +#include <asm/gpio.h> + +/* Flash */ +static struct resource rdc_flash_resource[] = { +	[0] = { +		.start = (u32)-CONFIG_MTD_RDC3210_SIZE, +		.end = (u32)-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 gpio_led default_leds[] = { +        { .name = "rdc321x:dmz", .gpio = 1, }, +}; + +static struct gpio_led_platform_data rdc321x_led_data = { +	.num_leds = ARRAY_SIZE(default_leds), +	.leds = default_leds, +}; + +static struct platform_device rdc321x_leds = { +	.name = "leds-gpio", +	.id = -1, +	.dev = { +		.platform_data = &rdc321x_led_data, +	} +}; + +/* Watchdog */ +static struct platform_device rdc321x_wdt = { +	.name = "rdc321x-wdt", +	.id = -1, +	.num_resources = 0, +}; + +/* Button */ +static struct gpio_keys_button rdc321x_gpio_btn[] = { +	{ +		.gpio = 0, +		.code = BTN_0, +		.desc = "Reset", +		.active_low = 1, +	} +}; + +static struct gpio_keys_platform_data rdc321x_gpio_btn_data = { +	.buttons = rdc321x_gpio_btn, +	.nbuttons = ARRAY_SIZE(rdc321x_gpio_btn), +}; + +static struct platform_device rdc321x_button = { +	.name = "gpio-keys", +	.id = -1, +	.dev = { +		.platform_data = &rdc321x_gpio_btn_data, +	} +}; + +static struct platform_device *rdc321x_devs[] = { +	&rdc_flash_device, +	&rdc321x_leds, +	&rdc321x_wdt, +	&rdc321x_button +}; + +static int __init rdc_board_setup(void) +{ +	return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs)); +} + +arch_initcall(rdc_board_setup); diff --git a/target/linux/rdc/files/arch/x86/mach-rdc/setup.c b/target/linux/rdc/files/arch/x86/mach-rdc/setup.c new file mode 100644 index 000000000..ad206c3d0 --- /dev/null +++ b/target/linux/rdc/files/arch/x86/mach-rdc/setup.c @@ -0,0 +1,14 @@ +/* + *	Machine specific setup for generic + */ + +#include <linux/init.h> +#include <linux/interrupt.h> +#include <asm/arch_hooks.h> +#include <asm/io.h> +#include <asm/setup.h> + +char * __init machine_specific_memory_setup(void) +{ +	return "RDC R-321x"; +} diff --git a/target/linux/rdc/files/arch/x86/mach-rdc/wdt.c b/target/linux/rdc/files/arch/x86/mach-rdc/wdt.c new file mode 100644 index 000000000..13b69f68a --- /dev/null +++ b/target/linux/rdc/files/arch/x86/mach-rdc/wdt.c @@ -0,0 +1,272 @@ +/* + * RDC321x watchdog driver + * + * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> + * + * This driver is highly inspired from the cpu5_wdt driver + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/timer.h> +#include <linux/completion.h> +#include <linux/jiffies.h> +#include <linux/platform_device.h> +#include <linux/watchdog.h> + +#include <asm/io.h> +#include <asm/uaccess.h> + +#include <asm/mach-rdc/rdc321x_defs.h> + +#define RDC_WDT_MASK		0x80000000	/* Mask */ +#define RDC_WDT_EN		0x00800000 	/* Enable bit */ +#define RDC_WDT_WTI		0x00200000	/* Generate a CPU reset/NMI/WDT irq when WDT timeout is reached */ +#define RDC_WDT_RST		0x00100000	/* Reset bit */ +#define RDC_WDT_WIF		0x00040000	/* WDT IRQ Flag */ +#define RDC_WDT_IRT		0x00000100	/* IRQ Routing table */ +#define RDC_WDT_CNT		0x00000001	/* WDT count */ + +#define RDC_CLS_TMR		0x80003844	/* Clear timer */ + +#define RDC_WDT_INTERVAL	(HZ/10+1) + +int nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static int ticks = 1000; + +/* some device data */ + +static struct { +	struct completion stop; +	volatile int running; +	struct timer_list timer; +	volatile int queue; +	int default_ticks; +	unsigned long inuse; +} rdc321x_wdt_device; + +/* generic helper functions */ + +static void rdc321x_wdt_trigger(unsigned long unused) +{ +	if( rdc321x_wdt_device.running ) +		ticks--; + +	/* keep watchdog alive */ +	outl(RDC_WDT_EN|inl(RDC3210_CFGREG_DATA), RDC3210_CFGREG_DATA);	 +	 +	/* requeue?? */ +	if (rdc321x_wdt_device.queue && ticks) +		mod_timer(&rdc321x_wdt_device.timer, jiffies + RDC_WDT_INTERVAL); +	else { +		/* ticks doesn't matter anyway */ +		complete(&rdc321x_wdt_device.stop); +	} + +} + +static void rdc321x_wdt_reset(void) +{ +	ticks = rdc321x_wdt_device.default_ticks; +} + +static void rdc321x_wdt_start(void) +{ +	if (!rdc321x_wdt_device.queue) { +		rdc321x_wdt_device.queue = 1; + +		/* Clear the timer */ +		outl(RDC_CLS_TMR, RDC3210_CFGREG_ADDR); +		 +		/* Enable watchdog and set the timeout to 81.92 us */ +		outl(RDC_WDT_EN|RDC_WDT_CNT, RDC3210_CFGREG_DATA); + +		mod_timer(&rdc321x_wdt_device.timer, jiffies + RDC_WDT_INTERVAL); +	} + +	/* if process dies, counter is not decremented */ +	rdc321x_wdt_device.running++; +} + +static int rdc321x_wdt_stop(void) +{ +	if (rdc321x_wdt_device.running) +		rdc321x_wdt_device.running = 0; + +	ticks = rdc321x_wdt_device.default_ticks; + +	return -EIO; +} + +/* filesystem operations */ + +static int rdc321x_wdt_open(struct inode *inode, struct file *file) +{ +	if (test_and_set_bit(0, &rdc321x_wdt_device.inuse)) +		return -EBUSY; + +	return nonseekable_open(inode, file); +} + +static int rdc321x_wdt_release(struct inode *inode, struct file *file) +{ +	clear_bit(0, &rdc321x_wdt_device.inuse); +	return 0; +} + +static int rdc321x_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ +	void __user *argp = (void __user *)arg; +	unsigned int value; +	static struct watchdog_info ident = +	{ +		.options = WDIOF_CARDRESET, +		.identity = "RDC321x WDT", +	}; + +	switch(cmd) { +		case WDIOC_KEEPALIVE: +			rdc321x_wdt_reset(); +			break; +		case WDIOC_GETSTATUS: +			/* Read the value from the DATA register */ +			value = inl(RDC3210_CFGREG_DATA); +			if ( copy_to_user(argp, &value, sizeof(int)) ) +				return -EFAULT; +			break; +		case WDIOC_GETSUPPORT: +			if ( copy_to_user(argp, &ident, sizeof(ident)) ) +				return -EFAULT; +			break; +		case WDIOC_SETOPTIONS: +			if ( copy_from_user(&value, argp, sizeof(int)) ) +				return -EFAULT; +			switch(value) { +				case WDIOS_ENABLECARD: +					rdc321x_wdt_start(); +					break; +				case WDIOS_DISABLECARD: +					return rdc321x_wdt_stop(); +				default: +					return -EINVAL; +			} +			break; +		default: +    			return -ENOTTY; +	} +	return 0; +} + +static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ +	if ( !count ) +		return -EIO; + +	rdc321x_wdt_reset(); + +	return count; +} + +static const struct file_operations rdc321x_wdt_fops = { +	.owner		= THIS_MODULE, +	.llseek		= no_llseek, +	.ioctl		= rdc321x_wdt_ioctl, +	.open		= rdc321x_wdt_open, +	.write		= rdc321x_wdt_write, +	.release	= rdc321x_wdt_release, +}; + +static struct miscdevice rdc321x_wdt_misc = { +	.minor	= WATCHDOG_MINOR, +	.name	= "watchdog", +	.fops	= &rdc321x_wdt_fops, +}; + +static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) +{ +	int err; + +	if ( (err = misc_register(&rdc321x_wdt_misc)) < 0 ) { +		printk(KERN_ERR PFX "misc_register failed\n"); +		return err; +	} + +	/* Reset the watchdog */ +	outl(RDC_WDT_RST, RDC3210_CFGREG_DATA); + +	init_completion(&rdc321x_wdt_device.stop); +	rdc321x_wdt_device.queue = 0; + +	clear_bit(0, &rdc321x_wdt_device.inuse); + +	setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0); + +	rdc321x_wdt_device.default_ticks = ticks; + +	printk(KERN_INFO PFX "init success\n"); + +	return 0; +} + +static int rdc321x_wdt_remove(struct platform_device *pdev) +{ +	if (rdc321x_wdt_device.queue) { +		rdc321x_wdt_device.queue = 0; +		wait_for_completion(&rdc321x_wdt_device.stop); +	} + +	misc_deregister(&rdc321x_wdt_misc); + +	return 0; +} + +static struct platform_driver rdc321x_wdt_driver = { +	.probe = rdc321x_wdt_probe, +	.remove = rdc321x_wdt_remove, +	.driver = { +		.owner = THIS_MODULE, +		.name = "rdc321x-wdt", +	}, +}; + +static int __init rdc321x_wdt_init(void) +{ +	return platform_driver_register(&rdc321x_wdt_driver); +} + +static void __exit rdc321x_wdt_exit(void) +{ +	platform_driver_unregister(&rdc321x_wdt_driver); +} + +module_init(rdc321x_wdt_init); +module_exit(rdc321x_wdt_exit); + +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); +MODULE_DESCRIPTION("RDC321x watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | 
