diff options
| author | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-04-28 09:54:20 +0000 | 
|---|---|---|
| committer | florian <florian@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2010-04-28 09:54:20 +0000 | 
| commit | 4d6e8198995599f4e82c09561bffc08c97cf092c (patch) | |
| tree | 8113f55ea98bc73251148c81f9dbb68b416b9cea /target/linux/rdc | |
| parent | dac867236df7563d94f533920a95e8370a3a4c74 (diff) | |
[rdc] resync 2.6.32 support with changes in 2.6.30
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@21220 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/rdc')
| -rw-r--r-- | target/linux/rdc/config-2.6.32 | 5 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/001-rdc321x_mfd_southbridge.patch | 202 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/002-rdc321x_gpio.patch | 288 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/003-rdc321x_watchdog_southbridge.patch | 150 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/004-rdc321x_defs_remove.patch | 26 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/006-yenta_mistery.patch (renamed from target/linux/rdc/patches-2.6.32/004-yenta_mystery.patch) | 0 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/012-export_erase_write.patch | 28 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/100-platform_support.patch (renamed from target/linux/rdc/patches-2.6.32/002-platform_support.patch) | 0 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/100-rdc_boards.patch | 740 | ||||
| -rw-r--r-- | target/linux/rdc/patches-2.6.32/110-rdc321x_watchdog_fix.patch | 315 | 
10 files changed, 1752 insertions, 2 deletions
diff --git a/target/linux/rdc/config-2.6.32 b/target/linux/rdc/config-2.6.32 index 4a1f9f38e..61ba26f5c 100644 --- a/target/linux/rdc/config-2.6.32 +++ b/target/linux/rdc/config-2.6.32 @@ -78,6 +78,7 @@ CONFIG_GENERIC_ISA_DMA=y  # CONFIG_GENERIC_TIME_VSYSCALL is not set  # CONFIG_GEN_RTC is not set  CONFIG_GPIOLIB=y +CONFIG_GPIO_RDC321X=y  CONFIG_GPIO_SYSFS=y  # CONFIG_HAMRADIO is not set  # CONFIG_HANGCHECK_TIMER is not set @@ -169,6 +170,8 @@ CONFIG_MATH_EMULATION=y  # CONFIG_MCYRIXIII is not set  # CONFIG_MEFFICEON is not set  # CONFIG_MEMTEST is not set +CONFIG_MFD_CORE=y +CONFIG_MFD_RDC321X=y  # CONFIG_MGEODEGX1 is not set  # CONFIG_MGEODE_LX is not set  # CONFIG_MICROCODE is not set @@ -185,8 +188,6 @@ CONFIG_MODULE_FORCE_UNLOAD=y  # CONFIG_MTD_COMPLEX_MAPPINGS is not set  # CONFIG_MTD_NETSC520 is not set  CONFIG_MTD_PHYSMAP=y -# CONFIG_MTD_R8610 is not set -# CONFIG_MTD_RDC3210 is not set  # CONFIG_MTD_TS5500 is not set  # CONFIG_MTRR is not set  # CONFIG_MVIAC3_2 is not set diff --git a/target/linux/rdc/patches-2.6.32/001-rdc321x_mfd_southbridge.patch b/target/linux/rdc/patches-2.6.32/001-rdc321x_mfd_southbridge.patch new file mode 100644 index 000000000..75b0d1b13 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/001-rdc321x_mfd_southbridge.patch @@ -0,0 +1,202 @@ +This patch adds a new MFD driver for the RDC321x southbridge. This southbridge +is always present in the RDC321x System-on-a-Chip and provides access to some +GPIOs as well as a watchdog. Access to these two functions is done using the +southbridge PCI device configuration space. + +Signed-off-by: Florian Fainelli <florian@openwrt.org> +--- +Changes from v2: +- pass the pci_dev pointer to MFD cell drivers as platform_data +- remove the printk(KERN_ERR and use dev_err instead +- removed pci_dev accessors +- use DEFINE_PCI_DEVICE_TABLE + +Index: linux-2.6.32.10/drivers/mfd/Kconfig +=================================================================== +--- linux-2.6.32.10.orig/drivers/mfd/Kconfig	2010-03-15 16:52:04.000000000 +0100 ++++ linux-2.6.32.10/drivers/mfd/Kconfig	2010-04-28 11:38:27.000000000 +0200 +@@ -305,6 +305,15 @@ + 	  This enables the PCAP ASIC present on EZX Phones. This is + 	  needed for MMC, TouchScreen, Sound, USB, etc.. +  ++config MFD_RDC321X ++	tristate "Support for RDC-R321x southbridge" ++	select MFD_CORE ++	depends on PCI ++	help ++	  Say yes here if you want to have support for the RDC R-321x SoC ++	  southbridge which provides access to GPIOs and Watchdog using the ++	  southbridge PCI device configuration space. ++ + endmenu +  + menu "Multimedia Capabilities Port drivers" +Index: linux-2.6.32.10/drivers/mfd/Makefile +=================================================================== +--- linux-2.6.32.10.orig/drivers/mfd/Makefile	2010-03-15 16:52:04.000000000 +0100 ++++ linux-2.6.32.10/drivers/mfd/Makefile	2010-04-28 11:38:53.000000000 +0200 +@@ -50,3 +50,5 @@ + obj-$(CONFIG_PCF50633_GPIO)	+= pcf50633-gpio.o + obj-$(CONFIG_AB3100_CORE)	+= ab3100-core.o + obj-$(CONFIG_AB3100_OTP)	+= ab3100-otp.o ++ ++obj-$(CONFIG_MFD_RDC321X)	+= rdc321x-southbridge.o +Index: linux-2.6.32.10/drivers/mfd/rdc321x-southbridge.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/drivers/mfd/rdc321x-southbridge.c	2010-04-28 11:38:27.000000000 +0200 +@@ -0,0 +1,123 @@ ++/* ++ * RDC321x MFD southbrige driver ++ * ++ * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> ++ * Copyright (C) 2010 Bernhard Loos <bernhardloos@googlemail.com> ++ * ++ * 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/init.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/pci.h> ++#include <linux/mfd/core.h> ++#include <linux/mfd/rdc321x.h> ++ ++static struct rdc321x_wdt_pdata rdc321x_wdt_pdata; ++ ++static struct resource rdc321x_wdt_resource[] = { ++	{ ++		.name	= "wdt-reg", ++		.start	= RDC321X_WDT_CTRL, ++		.end	= RDC321X_WDT_CTRL + 0x3, ++		.flags	= IORESOURCE_MEM, ++	} ++}; ++ ++static struct rdc321x_gpio_pdata rdc321x_gpio_pdata = { ++	.max_gpios	= RDC321X_MAX_GPIO, ++}; ++ ++static struct resource rdc321x_gpio_resources[] = { ++	{ ++		.name	= "gpio-reg1", ++		.start	= RDC321X_GPIO_CTRL_REG1, ++		.end	= RDC321X_GPIO_CTRL_REG1 + 0x7, ++		.flags	= IORESOURCE_MEM, ++	}, { ++		.name	= "gpio-reg2", ++		.start	= RDC321X_GPIO_CTRL_REG2, ++		.end	= RDC321X_GPIO_CTRL_REG2 + 0x7, ++		.flags	= IORESOURCE_MEM, ++	} ++}; ++ ++static struct mfd_cell rdc321x_sb_cells[] = { ++	{ ++		.name		= "rdc321x-wdt", ++		.resources	= rdc321x_wdt_resource, ++		.num_resources	= ARRAY_SIZE(rdc321x_wdt_resource), ++		.driver_data	= &rdc321x_wdt_pdata, ++	}, { ++		.name		= "rdc321x-gpio", ++		.resources	= rdc321x_gpio_resources, ++		.num_resources	= ARRAY_SIZE(rdc321x_gpio_resources), ++		.driver_data	= &rdc321x_gpio_pdata, ++	}, ++}; ++ ++static int __devinit rdc321x_sb_probe(struct pci_dev *pdev, ++					const struct pci_device_id *ent) ++{ ++	int err; ++ ++	err = pci_enable_device(pdev); ++	if (err) { ++		dev_err(&pdev->dev, "failed to enable device\n"); ++		return err; ++	} ++ ++	rdc321x_gpio_pdata.sb_pdev = pdev; ++	rdc321x_wdt_pdata.sb_pdev = pdev; ++ ++	return mfd_add_devices(&pdev->dev, -1, ++		rdc321x_sb_cells, ARRAY_SIZE(rdc321x_sb_cells), NULL, 0); ++} ++ ++static void __devexit rdc321x_sb_remove(struct pci_dev *pdev) ++{ ++	mfd_remove_devices(&pdev->dev); ++} ++ ++static DEFINE_PCI_DEVICE_TABLE(rdc321x_sb_table) = { ++	{ PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, ++	{} ++}; ++ ++static struct pci_driver rdc321x_sb_driver = { ++	.name		= "RDC321x Southbridge", ++	.id_table	= rdc321x_sb_table, ++	.probe		= rdc321x_sb_probe, ++	.remove		= __devexit_p(rdc321x_sb_remove), ++}; ++ ++static int __init rdc321x_sb_init(void) ++{ ++	return pci_register_driver(&rdc321x_sb_driver); ++} ++ ++static void __exit rdc321x_sb_exit(void) ++{ ++	pci_unregister_driver(&rdc321x_sb_driver); ++} ++ ++module_init(rdc321x_sb_init); ++module_exit(rdc321x_sb_exit); ++ ++MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); ++MODULE_LICENSE("GPL"); ++MODULE_DESCRIPTION("RDC R-321x MFD southbridge driver"); +Index: linux-2.6.32.10/include/linux/mfd/rdc321x.h +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/include/linux/mfd/rdc321x.h	2010-04-28 11:38:27.000000000 +0200 +@@ -0,0 +1,26 @@ ++#ifndef __RDC321X_MFD_H ++#define __RDC321X_MFD_H ++ ++#include <linux/types.h> ++#include <linux/pci.h> ++ ++/* Offsets to be accessed in the southbridge PCI ++ * device configuration register */ ++#define RDC321X_WDT_CTRL	0x44 ++#define RDC321X_GPIO_CTRL_REG1	0x48 ++#define RDC321X_GPIO_DATA_REG1	0x4c ++#define RDC321X_GPIO_CTRL_REG2	0x84 ++#define RDC321X_GPIO_DATA_REG2	0x88 ++ ++#define RDC321X_MAX_GPIO	58 ++ ++struct rdc321x_gpio_pdata { ++	struct pci_dev *sb_pdev; ++	unsigned max_gpios; ++}; ++ ++struct rdc321x_wdt_pdata { ++	struct pci_dev *sb_pdev; ++}; ++ ++#endif /* __RDC321X_MFD_H */ diff --git a/target/linux/rdc/patches-2.6.32/002-rdc321x_gpio.patch b/target/linux/rdc/patches-2.6.32/002-rdc321x_gpio.patch new file mode 100644 index 000000000..e83d27ef8 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/002-rdc321x_gpio.patch @@ -0,0 +1,288 @@ +This patch adds a new GPIO driver for the RDC321x SoC GPIO controller. + +Signed-off-by: Florian Fainelli <florian@openwrt.org> +--- +Changes from v2: +- initialize spinlock earlier +- do not declare and assign gpch variables on the same line +- use the pci_dev pointer passed as platform data +- replaced rdc321x_pci_{read,write} + +Index: linux-2.6.32.10/drivers/gpio/Kconfig +=================================================================== +--- linux-2.6.32.10.orig/drivers/gpio/Kconfig	2010-03-15 16:52:04.000000000 +0100 ++++ linux-2.6.32.10/drivers/gpio/Kconfig	2010-04-28 11:39:02.000000000 +0200 +@@ -196,6 +196,14 @@ + 	help + 	  Say Y here to support Intel Moorestown platform GPIO. +  ++config GPIO_RDC321X ++	tristate "RDC R-321x GPIO support" ++	depends on PCI && GPIOLIB ++	select MFD_RDC321X ++	help ++	  Support for the RDC R321x SoC GPIOs over southbridge ++	  PCI configuration space. ++ + comment "SPI GPIO expanders:" +  + config GPIO_MAX7301 +Index: linux-2.6.32.10/drivers/gpio/Makefile +=================================================================== +--- linux-2.6.32.10.orig/drivers/gpio/Makefile	2010-03-15 16:52:04.000000000 +0100 ++++ linux-2.6.32.10/drivers/gpio/Makefile	2010-04-28 11:39:17.000000000 +0200 +@@ -19,3 +19,4 @@ + obj-$(CONFIG_GPIO_BT8XX)	+= bt8xxgpio.o + obj-$(CONFIG_GPIO_VR41XX)	+= vr41xx_giu.o + obj-$(CONFIG_GPIO_WM831X)	+= wm831x-gpio.o ++obj-$(CONFIG_GPIO_RDC321X)	+= rdc321x-gpio.o +Index: linux-2.6.32.10/drivers/gpio/rdc321x-gpio.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/drivers/gpio/rdc321x-gpio.c	2010-04-28 11:39:02.000000000 +0200 +@@ -0,0 +1,245 @@ ++/* ++ * RDC321x GPIO driver ++ * ++ * Copyright (C) 2008, Volker Weiss <dev@tintuc.de> ++ * Copyright (C) 2007-2010 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., 675 Mass Ave, Cambridge, MA 02139, USA. ++ * ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/spinlock.h> ++#include <linux/platform_device.h> ++#include <linux/pci.h> ++#include <linux/gpio.h> ++#include <linux/mfd/rdc321x.h> ++ ++struct rdc321x_gpio { ++	spinlock_t		lock; ++	struct pci_dev		*sb_pdev; ++	u32			data_reg[2]; ++	int			reg1_ctrl_base; ++	int			reg1_data_base; ++	int			reg2_ctrl_base; ++	int			reg2_data_base; ++	struct gpio_chip	chip; ++}; ++ ++/* read GPIO pin */ ++static int rdc_gpio_get_value(struct gpio_chip *chip, unsigned gpio) ++{ ++	struct rdc321x_gpio *gpch; ++	u32 value = 0; ++	int reg; ++ ++	gpch = container_of(chip, struct rdc321x_gpio, chip); ++	reg = gpio < 32 ? gpch->reg1_data_base : gpch->reg2_data_base; ++ ++	spin_lock(&gpch->lock); ++	pci_write_config_dword(gpch->sb_pdev, reg, ++					gpch->data_reg[gpio < 32 ? 0 : 1]); ++	pci_read_config_dword(gpch->sb_pdev, reg, &value); ++	spin_unlock(&gpch->lock); ++ ++	return (1 << (gpio & 0x1f)) & value ? 1 : 0; ++} ++ ++static void rdc_gpio_set_value_impl(struct gpio_chip *chip, ++				unsigned gpio, int value) ++{ ++	struct rdc321x_gpio *gpch; ++	int reg = (gpio < 32) ? 0 : 1; ++ ++	gpch = container_of(chip, struct rdc321x_gpio, chip); ++ ++	if (value) ++		gpch->data_reg[reg] |= 1 << (gpio & 0x1f); ++	else ++		gpch->data_reg[reg] &= ~(1 << (gpio & 0x1f)); ++ ++	pci_write_config_dword(gpch->sb_pdev, ++			reg ? gpch->reg1_data_base : gpch->reg2_data_base, ++			gpch->data_reg[reg]); ++} ++ ++/* set GPIO pin to value */ ++static void rdc_gpio_set_value(struct gpio_chip *chip, ++				unsigned gpio, int value) ++{ ++	struct rdc321x_gpio *gpch; ++ ++	gpch = container_of(chip, struct rdc321x_gpio, chip); ++	spin_lock(&gpch->lock); ++	rdc_gpio_set_value_impl(chip, gpio, value); ++	spin_unlock(&gpch->lock); ++} ++ ++static int rdc_gpio_config(struct gpio_chip *chip, ++				unsigned gpio, int value) ++{ ++	struct rdc321x_gpio *gpch; ++	int err; ++	u32 reg; ++ ++	gpch = container_of(chip, struct rdc321x_gpio, chip); ++ ++	spin_lock(&gpch->lock); ++	err = pci_read_config_dword(gpch->sb_pdev, gpio < 32 ? ++			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, ®); ++	if (err) ++		goto unlock; ++ ++	reg |= 1 << (gpio & 0x1f); ++ ++	err = pci_write_config_dword(gpch->sb_pdev, gpio < 32 ? ++			gpch->reg1_ctrl_base : gpch->reg2_ctrl_base, reg); ++	if (err) ++		goto unlock; ++ ++	rdc_gpio_set_value_impl(chip, gpio, value); ++ ++unlock: ++	spin_unlock(&gpch->lock); ++ ++	return err; ++} ++ ++/* configure GPIO pin as input */ ++static int rdc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) ++{ ++	return rdc_gpio_config(chip, gpio, 1); ++} ++ ++/* ++ * Cache the initial value of both GPIO data registers ++ */ ++static int __devinit rdc321x_gpio_probe(struct platform_device *pdev) ++{ ++	int err; ++	struct resource *r; ++	struct rdc321x_gpio *rdc321x_gpio_dev; ++	struct rdc321x_gpio_pdata *pdata; ++ ++	pdata = pdev->dev.platform_data; ++	if (!pdata) { ++		dev_err(&pdev->dev, "no platform data supplied\n"); ++		return -ENODEV; ++	} ++ ++	rdc321x_gpio_dev = kzalloc(sizeof(struct rdc321x_gpio), GFP_KERNEL); ++	if (!rdc321x_gpio_dev) { ++		dev_err(&pdev->dev, "failed to allocate private data\n"); ++		return -ENOMEM; ++	} ++ ++	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio-reg1"); ++	if (!r) { ++		dev_err(&pdev->dev, "failed to get gpio-reg1 resource\n"); ++		err = -ENODEV; ++		goto out_free; ++	} ++ ++	spin_lock_init(&rdc321x_gpio_dev->lock); ++	rdc321x_gpio_dev->sb_pdev = pdata->sb_pdev; ++	rdc321x_gpio_dev->reg1_ctrl_base = r->start; ++	rdc321x_gpio_dev->reg1_data_base = r->start + 0x4; ++ ++	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio-reg2"); ++	if (!r) { ++		dev_err(&pdev->dev, "failed to get gpio-reg2 resource\n"); ++		err = -ENODEV; ++		goto out_free; ++	} ++ ++	rdc321x_gpio_dev->reg2_ctrl_base = r->start; ++	rdc321x_gpio_dev->reg2_data_base = r->start + 0x4; ++ ++	rdc321x_gpio_dev->chip.label = "rdc321x-gpio"; ++	rdc321x_gpio_dev->chip.direction_input = rdc_gpio_direction_input; ++	rdc321x_gpio_dev->chip.direction_output = rdc_gpio_config; ++	rdc321x_gpio_dev->chip.get = rdc_gpio_get_value; ++	rdc321x_gpio_dev->chip.set = rdc_gpio_set_value; ++	rdc321x_gpio_dev->chip.base = 0; ++	rdc321x_gpio_dev->chip.ngpio = pdata->max_gpios; ++ ++	platform_set_drvdata(pdev, rdc321x_gpio_dev); ++ ++	/* This might not be, what others (BIOS, bootloader, etc.) ++	   wrote to these registers before, but it's a good guess. Still ++	   better than just using 0xffffffff. */ ++	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, ++					rdc321x_gpio_dev->reg1_data_base, ++					&rdc321x_gpio_dev->data_reg[0]); ++	if (err) ++		goto out_drvdata; ++ ++	err = pci_read_config_dword(rdc321x_gpio_dev->sb_pdev, ++					rdc321x_gpio_dev->reg2_data_base, ++					&rdc321x_gpio_dev->data_reg[1]); ++	if (err) ++		goto out_drvdata; ++ ++	dev_info(&pdev->dev, "registering %d GPIOs\n", ++					rdc321x_gpio_dev->chip.ngpio); ++	return gpiochip_add(&rdc321x_gpio_dev->chip); ++ ++out_drvdata: ++	platform_set_drvdata(pdev, NULL); ++out_free: ++	kfree(rdc321x_gpio_dev); ++	return err; ++} ++ ++static int __devexit rdc321x_gpio_remove(struct platform_device *pdev) ++{ ++	int ret; ++	struct rdc321x_gpio *rdc321x_gpio_dev = platform_get_drvdata(pdev); ++ ++	ret = gpiochip_remove(&rdc321x_gpio_dev->chip); ++	if (ret) ++		dev_err(&pdev->dev, "failed to unregister chip\n"); ++ ++	kfree(rdc321x_gpio_dev); ++	platform_set_drvdata(pdev, NULL); ++ ++	return ret; ++} ++ ++static struct platform_driver rdc321x_gpio_driver = { ++	.driver.name	= "rdc321x-gpio", ++	.driver.owner	= THIS_MODULE, ++	.probe		= rdc321x_gpio_probe, ++	.remove		= __devexit_p(rdc321x_gpio_remove), ++}; ++ ++static int __init rdc321x_gpio_init(void) ++{ ++	return platform_driver_register(&rdc321x_gpio_driver); ++} ++ ++static void __exit rdc321x_gpio_exit(void) ++{ ++	platform_driver_unregister(&rdc321x_gpio_driver); ++} ++ ++module_init(rdc321x_gpio_init); ++module_exit(rdc321x_gpio_exit); ++ ++MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); ++MODULE_DESCRIPTION("RDC321x GPIO driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:rdc321x-gpio"); diff --git a/target/linux/rdc/patches-2.6.32/003-rdc321x_watchdog_southbridge.patch b/target/linux/rdc/patches-2.6.32/003-rdc321x_watchdog_southbridge.patch new file mode 100644 index 000000000..103199996 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/003-rdc321x_watchdog_southbridge.patch @@ -0,0 +1,150 @@ +The RDC321x MFD southbridge driver will pass a reference to the southbridge +PCI device which should be used by the watchdog driver for its operations. +This patch converts the watchdog driver to use the pci_dev pointer and make use +of the base register resource which is passed along with the platform device. + +Acked-by: Wim Van Sebroeck <wim@iguana.be> +Signed-off-by: Florian Fainelli <florian@openwrt.org> +--- +Changes from v2: +- replaced rdc321x_pci_{read,write} +- use the pci_dev pointer passed as platform_data + +Index: linux-2.6.30.10/drivers/watchdog/rdc321x_wdt.c +=================================================================== +--- linux-2.6.30.10.orig/drivers/watchdog/rdc321x_wdt.c	2009-12-04 07:00:07.000000000 +0100 ++++ linux-2.6.30.10/drivers/watchdog/rdc321x_wdt.c	2010-04-28 10:17:46.000000000 +0200 +@@ -1,7 +1,7 @@ + /* +  * RDC321x watchdog driver +  * +- * Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> ++ * Copyright (C) 2007-2010 Florian Fainelli <florian@openwrt.org> +  * +  * This driver is highly inspired from the cpu5_wdt driver +  * +@@ -36,8 +36,7 @@ + #include <linux/watchdog.h> + #include <linux/io.h> + #include <linux/uaccess.h> +- +-#include <asm/rdc321x_defs.h> ++#include <linux/mfd/rdc321x.h> +  + #define RDC_WDT_MASK	0x80000000 /* Mask */ + #define RDC_WDT_EN	0x00800000 /* Enable bit */ +@@ -63,6 +62,8 @@ + 	int default_ticks; + 	unsigned long inuse; + 	spinlock_t lock; ++	struct pci_dev *sb_pdev; ++	int base_reg; + } rdc321x_wdt_device; +  + /* generic helper functions */ +@@ -70,14 +71,18 @@ + static void rdc321x_wdt_trigger(unsigned long unused) + { + 	unsigned long flags; ++	u32 val; +  + 	if (rdc321x_wdt_device.running) + 		ticks--; +  + 	/* keep watchdog alive */ + 	spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); +-	outl(RDC_WDT_EN | inl(RDC3210_CFGREG_DATA), +-		RDC3210_CFGREG_DATA); ++	pci_read_config_dword(rdc321x_wdt_device.sb_pdev, ++					rdc321x_wdt_device.base_reg, &val); ++	val |= RDC_WDT_EN; ++	pci_write_config_dword(rdc321x_wdt_device.sb_pdev, ++					rdc321x_wdt_device.base_reg, val); + 	spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); +  + 	/* requeue?? */ +@@ -105,10 +110,13 @@ +  + 		/* Clear the timer */ + 		spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); +-		outl(RDC_CLS_TMR, RDC3210_CFGREG_ADDR); ++		pci_write_config_dword(rdc321x_wdt_device.sb_pdev, ++				rdc321x_wdt_device.base_reg, RDC_CLS_TMR); +  + 		/* Enable watchdog and set the timeout to 81.92 us */ +-		outl(RDC_WDT_EN | RDC_WDT_CNT, RDC3210_CFGREG_DATA); ++		pci_write_config_dword(rdc321x_wdt_device.sb_pdev, ++					rdc321x_wdt_device.base_reg, ++					RDC_WDT_EN | RDC_WDT_CNT); + 		spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); +  + 		mod_timer(&rdc321x_wdt_device.timer, +@@ -148,7 +156,7 @@ + 				unsigned long arg) + { + 	void __user *argp = (void __user *)arg; +-	unsigned int value; ++	u32 value; + 	static struct watchdog_info ident = { + 		.options = WDIOF_CARDRESET, + 		.identity = "RDC321x WDT", +@@ -162,9 +170,10 @@ + 	case WDIOC_GETSTATUS: + 		/* Read the value from the DATA register */ + 		spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); +-		value = inl(RDC3210_CFGREG_DATA); ++		pci_read_config_dword(rdc321x_wdt_device.sb_pdev, ++					rdc321x_wdt_device.base_reg, &value); + 		spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); +-		if (copy_to_user(argp, &value, sizeof(int))) ++		if (copy_to_user(argp, &value, sizeof(u32))) + 			return -EFAULT; + 		break; + 	case WDIOC_GETSUPPORT: +@@ -219,17 +228,35 @@ + static int __devinit rdc321x_wdt_probe(struct platform_device *pdev) + { + 	int err; ++	struct resource *r; ++	struct rdc321x_wdt_pdata *pdata; ++ ++	pdata = pdev->dev.platform_data; ++	if (!pdata) { ++		dev_err(&pdev->dev, "no platform data supplied\n"); ++		return -ENODEV; ++	} ++ ++	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wdt-reg"); ++	if (!r) { ++		dev_err(&pdev->dev, "failed to get wdt-reg resource\n"); ++		return -ENODEV; ++	} ++ ++	rdc321x_wdt_device.sb_pdev = pdata->sb_pdev; ++	rdc321x_wdt_device.base_reg = r->start; +  + 	err = misc_register(&rdc321x_wdt_misc); + 	if (err < 0) { +-		printk(KERN_ERR PFX "watchdog misc_register failed\n"); ++		dev_err(&pdev->dev, "misc_register failed\n"); + 		return err; + 	} +  + 	spin_lock_init(&rdc321x_wdt_device.lock); +  + 	/* Reset the watchdog */ +-	outl(RDC_WDT_RST, RDC3210_CFGREG_DATA); ++	pci_write_config_dword(rdc321x_wdt_device.sb_pdev, ++				rdc321x_wdt_device.base_reg, RDC_WDT_RST); +  + 	init_completion(&rdc321x_wdt_device.stop); + 	rdc321x_wdt_device.queue = 0; +@@ -240,7 +267,7 @@ +  + 	rdc321x_wdt_device.default_ticks = ticks; +  +-	printk(KERN_INFO PFX "watchdog init success\n"); ++	dev_info(&pdev->dev, "watchdog init success\n"); +  + 	return 0; + } diff --git a/target/linux/rdc/patches-2.6.32/004-rdc321x_defs_remove.patch b/target/linux/rdc/patches-2.6.32/004-rdc321x_defs_remove.patch new file mode 100644 index 000000000..3bafb401f --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/004-rdc321x_defs_remove.patch @@ -0,0 +1,26 @@ +This file is replaced by a cleaner version with the adding of a MFD driver for +the southbridge. + +Signed-off-by: Florian Fainelli <florian@openwrt.org> +--- +diff --git a/arch/x86/include/asm/rdc321x_defs.h b/arch/x86/include/asm/rdc321x_defs.h +deleted file mode 100644 +index c8e9c8b..0000000 +--- a/arch/x86/include/asm/rdc321x_defs.h ++++ /dev/null +@@ -1,12 +0,0 @@ +-#define PFX	"rdc321x: " +- +-/* General purpose configuration and data registers */ +-#define RDC3210_CFGREG_ADDR     0x0CF8 +-#define RDC3210_CFGREG_DATA     0x0CFC +- +-#define RDC321X_GPIO_CTRL_REG1	0x48 +-#define RDC321X_GPIO_CTRL_REG2	0x84 +-#define RDC321X_GPIO_DATA_REG1	0x4c +-#define RDC321X_GPIO_DATA_REG2	0x88 +- +-#define RDC321X_MAX_GPIO	58 + + + diff --git a/target/linux/rdc/patches-2.6.32/004-yenta_mystery.patch b/target/linux/rdc/patches-2.6.32/006-yenta_mistery.patch index 92589ea54..92589ea54 100644 --- a/target/linux/rdc/patches-2.6.32/004-yenta_mystery.patch +++ b/target/linux/rdc/patches-2.6.32/006-yenta_mistery.patch diff --git a/target/linux/rdc/patches-2.6.32/012-export_erase_write.patch b/target/linux/rdc/patches-2.6.32/012-export_erase_write.patch new file mode 100644 index 000000000..2d6feba24 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/012-export_erase_write.patch @@ -0,0 +1,28 @@ +Index: linux-2.6.30.10/drivers/mtd/mtdblock.c +=================================================================== +--- linux-2.6.30.10.orig/drivers/mtd/mtdblock.c	2010-03-19 00:17:37.000000000 +0100 ++++ linux-2.6.30.10/drivers/mtd/mtdblock.c	2010-03-19 00:17:54.000000000 +0100 +@@ -45,7 +45,7 @@ + 	wake_up(wait_q); + } +  +-static int erase_write (struct mtd_info *mtd, unsigned long pos, ++int erase_write (struct mtd_info *mtd, unsigned long pos, + 			int len, const char *buf) + { + 	struct erase_info erase; +Index: linux-2.6.30.10/include/linux/mtd/mtd.h +=================================================================== +--- linux-2.6.30.10.orig/include/linux/mtd/mtd.h	2010-03-19 00:17:42.000000000 +0100 ++++ linux-2.6.30.10/include/linux/mtd/mtd.h	2010-03-19 00:21:22.000000000 +0100 +@@ -319,6 +319,10 @@ + int default_mtd_readv(struct mtd_info *mtd, struct kvec *vecs, + 		      unsigned long count, loff_t from, size_t *retlen); +  ++int erase_write (struct mtd_info *mtd, unsigned long pos, ++		      int len, const char *buf); ++ ++ + #ifdef CONFIG_MTD_PARTITIONS + void mtd_erase_callback(struct erase_info *instr); + #else diff --git a/target/linux/rdc/patches-2.6.32/002-platform_support.patch b/target/linux/rdc/patches-2.6.32/100-platform_support.patch index 26b732a3f..26b732a3f 100644 --- a/target/linux/rdc/patches-2.6.32/002-platform_support.patch +++ b/target/linux/rdc/patches-2.6.32/100-platform_support.patch diff --git a/target/linux/rdc/patches-2.6.32/100-rdc_boards.patch b/target/linux/rdc/patches-2.6.32/100-rdc_boards.patch new file mode 100644 index 000000000..e88e6ee85 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/100-rdc_boards.patch @@ -0,0 +1,740 @@ +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/Makefile +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/Makefile	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,5 @@ ++# ++# Makefile for the RDC321x specific parts of the kernel ++# ++obj-$(CONFIG_X86_RDC321X)	:= platform.o reboot.o boards/sitecom.o boards/ar525w.o boards/bifferboard.o boards/r8610.o ++ +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/platform.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/platform.c	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,115 @@ ++/* ++ *  Generic RDC321x platform devices ++ * ++ *  Copyright (C) 2007-2009 OpenWrt.org ++ *  Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> ++ *  Copyright (C) 2008-2009 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> ++ * ++ *  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/platform_device.h> ++#include <linux/mtd/map.h> ++#include <linux/mtd/mtd.h> ++#include <linux/mtd/physmap.h> ++#include <linux/root_dev.h> ++ ++#include <asm/rdc_boards.h> ++ ++static struct rdc_platform_data rdcplat_data; ++ ++/* LEDS */ ++static struct platform_device rdc321x_leds = { ++	.name = "leds-gpio", ++	.id = -1, ++	.dev = { ++		.platform_data = &rdcplat_data.led_data, ++	} ++}; ++ ++/* Button */ ++static struct platform_device rdc321x_buttons = { ++	.name = "gpio-buttons", ++	.id = -1, ++	.dev = { ++		.platform_data = &rdcplat_data.button_data, ++	} ++}; ++ ++static __initdata struct platform_device *rdc321x_devs[] = { ++	&rdc321x_leds, ++	&rdc321x_buttons, ++}; ++ ++const char *__initdata boards[] = { ++	"Sitecom", ++	"AR525W", ++	"Bifferboard", ++	"R8610", ++	0 ++}; ++ ++static struct map_info rdc_map_info = { ++	.name		= "rdc_flash", ++	.size		= 0x800000,	/* 8MB */ ++	.phys		= 0xFF800000,	/* (u32) -rdc_map_info.size */ ++	.bankwidth	= 2, ++}; ++ ++static int __init rdc_board_setup(void) ++{ ++	struct mtd_partition *partitions; ++	int count, res; ++	struct mtd_info *mtdinfo; ++ ++	simple_map_init(&rdc_map_info); ++ ++	while (1) { ++		rdc_map_info.virt = ioremap(rdc_map_info.phys, ++							rdc_map_info.size); ++		if (rdc_map_info.virt == NULL) ++			continue; ++ ++		mtdinfo = do_map_probe("cfi_probe", &rdc_map_info); ++		if (mtdinfo == NULL) ++			mtdinfo = do_map_probe("jedec_probe", &rdc_map_info); ++		if (mtdinfo != NULL) ++			break; ++ ++		iounmap(rdc_map_info.virt); ++		if ((rdc_map_info.size >>= 1) < 0x100000)	/* 1MB */ ++			panic("RDC321x: Could not find start of flash!"); ++		rdc_map_info.phys = (u32) -rdc_map_info.size; ++	} ++ ++	count = parse_mtd_partitions(mtdinfo, boards, &partitions, ++						(unsigned long) &rdcplat_data); ++ ++	if (count <= 0) { ++		panic("RDC321x: can't identify board type"); ++		return -ENOSYS; ++	} ++ ++	ROOT_DEV = 0; ++	res = add_mtd_partitions(mtdinfo, partitions, count); ++	if (res) ++		return res; ++ ++	return platform_add_devices(rdc321x_devs, ARRAY_SIZE(rdc321x_devs)); ++} ++late_initcall(rdc_board_setup); +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/boards/ar525w.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/boards/ar525w.c	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,243 @@ ++/* ++ * ar525w RDC321x platform devices ++ * ++ *  Copyright (C) 2007-2009 OpenWrt.org ++ *  Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> ++ *  Copyright (C) 2008-2009 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> ++ * ++ *  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/mtd/physmap.h> ++#include <linux/input.h> ++#include <linux/vmalloc.h> ++#include <linux/mtd/mtd.h> ++ ++#include <asm/rdc_boards.h> ++ ++struct image_header { ++	char magic[4];              /* ASICII: GMTK */ ++	u32 checksum;               /* CRC32 */ ++	u32 version;                /* x.x.x.x */ ++	u32 kernelsz;               /* The size of the kernel image */ ++	u32 imagesz;                /* The length of this image file ( kernel + romfs + this header) */ ++	u32 pid;                    /* Product ID */ ++	u32 fastcksum;              /* Partial CRC32 on (First(256), medium(256), last(512)) */ ++	u32 reserved; ++}; ++ ++static struct gpio_led ar525w_leds[] = { ++	{ .name = "rdc321x:dmz", .gpio = 1, .active_low = 1}, ++}; ++static struct gpio_button ar525w_btns[] = { ++	{ ++		.gpio = 6, ++		.code = BTN_0, ++		.desc = "Reset", ++		.active_low = 1, ++	} ++}; ++ ++static u32 __initdata crctab[257] = { ++	0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, ++	0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, ++	0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, ++	0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, ++	0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++	0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, ++	0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, ++	0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, ++	0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, ++	0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++	0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, ++	0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, ++	0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, ++	0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, ++	0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++	0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, ++	0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, ++	0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, ++	0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, ++	0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++	0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, ++	0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, ++	0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, ++	0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, ++	0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++	0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, ++	0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, ++	0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, ++	0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, ++	0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++	0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, ++	0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, ++	0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, ++	0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, ++	0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++	0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, ++	0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, ++	0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, ++	0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, ++	0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++	0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, ++	0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, ++	0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, ++	0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, ++	0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++	0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, ++	0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, ++	0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, ++	0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, ++	0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++	0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, ++	0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, ++	0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, ++	0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, ++	0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++	0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, ++	0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, ++	0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, ++	0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, ++	0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++	0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, ++	0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, ++	0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, ++	0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, ++	0 ++}; ++ ++static u32 __init crc32(u8 * buf, u32 len) ++{ ++	register int i; ++	u32 sum; ++	register u32 s0; ++	s0 = ~0; ++	for (i = 0; i < len; i++) { ++		s0 = (s0 >> 8) ^ crctab[(u8) (s0 & 0xFF) ^ buf[i]]; ++	} ++	sum = ~s0; ++	return sum; ++} ++ ++static int __init fixup_ar525w_header(struct mtd_info *master, struct image_header *header) ++{ ++	char *buffer; ++	int res; ++	u32 bufferlength = header->kernelsz + sizeof(struct image_header); ++	u32 len; ++	char crcbuf[0x400]; ++ ++	printk(KERN_INFO "Fixing up AR525W header, old image size: %u, new image size: %u\n", ++		   header->imagesz, bufferlength); ++ ++	buffer = vmalloc(bufferlength); ++	if (!buffer) { ++		printk(KERN_ERR "Can't allocate %u bytes\n", bufferlength); ++		return -ENOMEM; ++	} ++ ++	res =  master->read(master, 0x0, bufferlength, &len, buffer); ++	if (res || len != bufferlength) ++		goto out; ++ ++	header = (struct image_header *) buffer; ++	header->imagesz = bufferlength; ++	header->checksum = 0; ++	header->fastcksum = 0; ++ ++	memcpy(crcbuf, buffer, 0x100); ++	memcpy(crcbuf + 0x100, buffer + (bufferlength >> 1) - ((bufferlength & 0x6) >> 1), 0x100); ++	memcpy(crcbuf + 0x200, buffer + bufferlength - 0x200, 0x200); ++ ++	header->fastcksum = crc32(crcbuf, sizeof(crcbuf)); ++	header->checksum = crc32(buffer, bufferlength); ++ ++	if (master->unlock) ++		master->unlock(master, 0, master->erasesize); ++	res = erase_write (master, 0, master->erasesize, buffer); ++	if (res) ++		printk(KERN_ERR "Can't rewrite image header\n"); ++ ++out: ++	vfree(buffer); ++	return res; ++} ++ ++static int __init parse_ar525w_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long plat_data) ++{ ++	struct image_header header; ++	int res; ++	size_t len; ++	struct mtd_partition *rdc_flash_parts; ++	struct rdc_platform_data *pdata = (struct rdc_platform_data *) plat_data; ++ ++	if (master->size != 0x400000) //4MB ++		return -ENOSYS; ++ ++	res =  master->read(master, 0x0, sizeof(header), &len, (char *)&header); ++	if (res) ++		return res; ++ ++	if (strncmp(header.magic, "GMTK", 4)) ++		return -ENOSYS; ++ ++	if (header.kernelsz > 0x400000 || header.kernelsz < master->erasesize) { ++		printk(KERN_ERR "AR525W image header found, but seems corrupt, kernel size %u\n", header.kernelsz); ++		return -EINVAL; ++	} ++ ++	if (header.kernelsz + sizeof(header) != header.imagesz) { ++		res = fixup_ar525w_header(master, &header); ++		if (res) ++			return res; ++	} ++ ++	rdc_flash_parts = kzalloc(sizeof(struct mtd_partition) * 3, GFP_KERNEL); ++ ++	rdc_flash_parts[0].name = "firmware"; ++	rdc_flash_parts[0].offset = 0x0; ++	rdc_flash_parts[0].size = 0x3E0000; ++	rdc_flash_parts[1].name = "rootfs"; ++	rdc_flash_parts[1].offset = header.kernelsz + sizeof(header); ++	rdc_flash_parts[1].size = rdc_flash_parts[0].size - rdc_flash_parts[1].offset; ++	rdc_flash_parts[2].name = "bootloader"; ++	rdc_flash_parts[2].offset = 0x3E0000; ++	rdc_flash_parts[2].size = 0x20000; ++ ++	*pparts = rdc_flash_parts; ++ ++	pdata->led_data.num_leds = ARRAY_SIZE(ar525w_leds); ++	pdata->led_data.leds = ar525w_leds; ++	pdata->button_data.nbuttons = ARRAY_SIZE(ar525w_btns); ++	pdata->button_data.buttons = ar525w_btns; ++ ++	return 3; ++} ++ ++static struct mtd_part_parser __initdata ar525w_parser = { ++	.owner = THIS_MODULE, ++	.parse_fn = parse_ar525w_partitions, ++	.name = "AR525W", ++}; ++ ++static int __init ar525w_setup(void) ++{ ++	return register_mtd_parser(&ar525w_parser); ++} ++ ++arch_initcall(ar525w_setup); +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/boards/bifferboard.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/boards/bifferboard.c	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,81 @@ ++/* ++ *  Bifferboard RDC321x platform devices ++ * ++ *  Copyright (C) 2010 bifferos@yahoo.co.uk ++ * ++ *  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/mtd/physmap.h> ++#include <linux/input.h> ++ ++#include <asm/rdc_boards.h> ++ ++static int __init parse_bifferboard_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long plat_data) ++{ ++	int res; ++	size_t len; ++	struct mtd_partition *rdc_flash_parts; ++	u32 kernel_len; ++	u16 tmp; ++ ++	if (master->size == 0x100000) ++		kernel_len = master->size - 0x10000; ++	else { ++		res =  master->read(master, 0x4000 + 1036, 2, &len, (char *) &tmp); ++		if (res) ++			return res; ++		kernel_len = tmp * master->erasesize; ++	} ++ ++	rdc_flash_parts = kzalloc(sizeof(struct mtd_partition) * 4, GFP_KERNEL); ++ ++	*pparts = rdc_flash_parts; ++ ++	rdc_flash_parts[0].name = "biffboot"; ++	rdc_flash_parts[0].offset = master->size - 0x10000; ++	rdc_flash_parts[0].size = 0x10000; ++	rdc_flash_parts[0].mask_flags = MTD_WRITEABLE; ++	rdc_flash_parts[1].name = "firmware"; ++	rdc_flash_parts[1].offset = 0; ++	rdc_flash_parts[1].size = rdc_flash_parts[0].offset; ++	rdc_flash_parts[2].name = "kernel"; ++	rdc_flash_parts[2].offset = 0x00000000; ++	rdc_flash_parts[2].size = kernel_len; ++ ++	if (master->size == 0x100000) ++		return 2; ++ ++	rdc_flash_parts[3].name = "rootfs"; ++	rdc_flash_parts[3].offset = MTDPART_OFS_APPEND; ++	rdc_flash_parts[3].size = rdc_flash_parts[1].size - rdc_flash_parts[2].size; ++ ++	return 4; ++} ++ ++struct mtd_part_parser __initdata bifferboard_parser = { ++	.owner = THIS_MODULE, ++	.parse_fn = parse_bifferboard_partitions, ++	.name = "Bifferboard", ++}; ++ ++static int __init bifferboard_setup(void) ++{ ++	return register_mtd_parser(&bifferboard_parser); ++} ++arch_initcall(bifferboard_setup); +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/boards/r8610.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/boards/r8610.c	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,65 @@ ++/* ++ *  R8610 RDC321x platform devices ++ * ++ *  Copyright (C) 2009, 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/mtd/physmap.h> ++#include <linux/input.h> ++ ++#include <asm/rdc_boards.h> ++ ++static int __init parse_r8610_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long plat_data) ++{ ++	struct mtd_partition *rdc_flash_parts; ++ ++	rdc_flash_parts = kzalloc(sizeof(struct mtd_partition) * 4, GFP_KERNEL); ++ ++	*pparts = rdc_flash_parts; ++ ++	rdc_flash_parts[0].name = "kernel"; ++	rdc_flash_parts[0].size = 0x001f0000; ++	rdc_flash_parts[0].offset = 0; ++	rdc_flash_parts[1].name = "config"; ++	rdc_flash_parts[1].size = 0x10000; ++	rdc_flash_parts[1].offset = MTDPART_OFS_APPEND; ++	rdc_flash_parts[2].name = "rootfs"; ++	rdc_flash_parts[2].size = 0x1E0000; ++	rdc_flash_parts[2].offset = MTDPART_OFS_APPEND; ++	rdc_flash_parts[3].name = "redboot"; ++	rdc_flash_parts[3].size = 0x20000; ++	rdc_flash_parts[3].offset = MTDPART_OFS_APPEND; ++	rdc_flash_parts[3].mask_flags = MTD_WRITEABLE; ++ ++	return 4; ++} ++ ++struct mtd_part_parser __initdata r8610_parser = { ++	.owner = THIS_MODULE, ++	.parse_fn = parse_r8610_partitions, ++	.name = "R8610", ++}; ++ ++static int __init r8610_setup(void) ++{ ++	return register_mtd_parser(&r8610_parser); ++} ++ ++arch_initcall(r8610_setup); +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/boards/sitecom.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/boards/sitecom.c	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,111 @@ ++/* ++ *  Sitecom RDC321x platform devices ++ * ++ *  Copyright (C) 2007-2009 OpenWrt.org ++ *  Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> ++ *  Copyright (C) 2008-2009 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> ++ * ++ *  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/mtd/physmap.h> ++#include <linux/input.h> ++ ++#include <asm/rdc_boards.h> ++ ++struct image_header { ++	char	magic[4]; ++	u32	kernel_length; ++	u32	ramdisk_length; ++	char	magic2[4]; ++	u32	kernel_length2; ++}; ++ ++static struct gpio_led sitecom_leds[] = { ++	{ .name = "rdc321x:power", .gpio = 15, .active_low = 1}, ++	{ .name = "rdc321x:usb0", .gpio = 0, .active_low = 1}, ++	{ .name = "rdc321x:usb1", .gpio = 1, .active_low = 1}, ++}; ++ ++static struct gpio_button sitecom_btns[] = { ++	{ ++		.gpio = 6, ++		.code = BTN_0, ++		.desc = "Reset", ++		.active_low = 1, ++	} ++}; ++ ++static int __init parse_sitecom_partitions(struct mtd_info *master, struct mtd_partition **pparts, unsigned long plat_data) ++{ ++	struct image_header header; ++	int res; ++	size_t len; ++	struct mtd_partition *rdc_flash_parts; ++	struct rdc_platform_data *pdata = (struct rdc_platform_data *) plat_data; ++ ++	if (master->size != 0x400000) /* 4MB */ ++		return -ENOSYS; ++ ++	res =  master->read(master, 0x8000, sizeof(header), &len, (char *)&header); ++	if (res) ++		return res; ++ ++	if (strncmp(header.magic, "CSYS", 4) || strncmp(header.magic2, "WRRM", 4)) ++		return -ENOSYS; ++ ++	rdc_flash_parts = kzalloc(sizeof(struct mtd_partition) * 5, GFP_KERNEL); ++ ++	rdc_flash_parts[0].name = "firmware"; ++	rdc_flash_parts[0].offset = 0x8000; ++	rdc_flash_parts[0].size = 0x3F0000; ++	rdc_flash_parts[1].name = "config"; ++	rdc_flash_parts[1].offset = 0; ++	rdc_flash_parts[1].size = 0x8000; ++	rdc_flash_parts[2].name = "kernel"; ++	rdc_flash_parts[2].offset = 0x8014; ++	rdc_flash_parts[2].size = header.kernel_length; ++	rdc_flash_parts[3].name = "rootfs"; ++	rdc_flash_parts[3].offset = 0x8014 + header.kernel_length; ++	rdc_flash_parts[3].size = 0x3F0000 - rdc_flash_parts[3].offset; ++	rdc_flash_parts[4].name = "bootloader"; ++	rdc_flash_parts[4].offset = 0x3F0000; ++	rdc_flash_parts[4].size = 0x10000; ++ ++	*pparts = rdc_flash_parts; ++ ++	pdata->led_data.num_leds = ARRAY_SIZE(sitecom_leds); ++	pdata->led_data.leds = sitecom_leds; ++	pdata->button_data.nbuttons = ARRAY_SIZE(sitecom_btns); ++	pdata->button_data.buttons = sitecom_btns; ++ ++	return 5; ++} ++ ++struct mtd_part_parser __initdata sitecom_parser = { ++	.owner = THIS_MODULE, ++	.parse_fn = parse_sitecom_partitions, ++	.name = "Sitecom", ++}; ++ ++static int __init sitecom_setup(void) ++{ ++	return register_mtd_parser(&sitecom_parser); ++} ++ ++arch_initcall(sitecom_setup); +Index: linux-2.6.32.10/arch/x86/mach-rdc321x/reboot.c +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/mach-rdc321x/reboot.c	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,44 @@ ++/* ++ *  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 <asm/reboot.h> ++#include <asm/io.h> ++ ++static void rdc321x_reset(void) ++{ ++	unsigned i; ++ ++	/* write to southbridge config register 0x41 ++	   enable pci reset on cpu reset, make internal port 0x92 writeable ++	   and switch port 0x92 to internal */ ++	outl(0x80003840, 0xCF8); ++	i = inl(0xCFC); ++	i |= 0x1600; ++	outl(i, 0xCFC); ++ ++	/* soft reset */ ++	outb(1, 0x92); ++} ++ ++static int __init rdc_setup_reset(void) ++{ ++	machine_ops.emergency_restart = rdc321x_reset; ++	return 0; ++} ++ ++arch_initcall(rdc_setup_reset); +Index: linux-2.6.32.10/arch/x86/include/asm/rdc_boards.h +=================================================================== +--- /dev/null	1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.32.10/arch/x86/include/asm/rdc_boards.h	2010-04-28 11:39:32.000000000 +0200 +@@ -0,0 +1,36 @@ ++/* ++ *  RDC321x boards ++ * ++ *  Copyright (C) 2007-2009 OpenWrt.org ++ *  Copyright (C) 2007 Florian Fainelli <florian@openwrt.org> ++ *  Copyright (C) 2008-2009 Daniel Gimpelevich <daniel@gimpelevich.san-francisco.ca.us> ++ * ++ *  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. ++ * ++ */ ++ ++#ifndef _RDC_BOARDS_H__ ++#define _RDC_BOARDS_H__ ++ ++#include <linux/leds.h> ++#include <linux/gpio_buttons.h> ++ ++struct rdc_platform_data { ++	struct gpio_led_platform_data led_data; ++	struct gpio_buttons_platform_data button_data; ++}; ++ ++#endif diff --git a/target/linux/rdc/patches-2.6.32/110-rdc321x_watchdog_fix.patch b/target/linux/rdc/patches-2.6.32/110-rdc321x_watchdog_fix.patch new file mode 100644 index 000000000..ce4fd1fd9 --- /dev/null +++ b/target/linux/rdc/patches-2.6.32/110-rdc321x_watchdog_fix.patch @@ -0,0 +1,315 @@ +Index: linux-2.6.32.10/drivers/watchdog/rdc321x_wdt.c +=================================================================== +--- linux-2.6.32.10.orig/drivers/watchdog/rdc321x_wdt.c	2010-04-28 11:39:28.000000000 +0200 ++++ linux-2.6.32.10/drivers/watchdog/rdc321x_wdt.c	2010-04-28 11:40:11.000000000 +0200 +@@ -36,111 +36,99 @@ + #include <linux/watchdog.h> + #include <linux/io.h> + #include <linux/uaccess.h> ++#include <linux/pci.h> ++#include <linux/delay.h> + #include <linux/mfd/rdc321x.h> +  +-#define RDC_WDT_MASK	0x80000000 /* Mask */ ++#define RDC321X_WDT_REG 0x00000044 ++ + #define RDC_WDT_EN	0x00800000 /* Enable bit */ +-#define RDC_WDT_WTI	0x00200000 /* Generate CPU reset/NMI/WDT on timeout */ +-#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_WDT_WDTIRQ	0x00400000 /* Create WDT IRQ before CPU reset */ ++#define RDC_WDT_NMIIRQ	0x00200000 /* Create NMI IRQ before CPU reset */ ++#define RDC_WDT_RST	0x00100000 /* Reset wdt */ ++#define RDC_WDT_NIF	0x00080000 /* NMI interrupt occured */ ++#define RDC_WDT_WIF	0x00040000 /* WDT interrupt occured */ ++#define RDC_WDT_IRT	0x00000700 /* IRQ Routing table */ ++#define RDC_WDT_CNT	0x0000007F /* WDT count */ +  +-#define RDC_CLS_TMR	0x80003844 /* Clear timer */ ++/* default counter value (2.34 s) */ ++#define RDC_WDT_DFLT_CNT 0x00000040 +  +-#define RDC_WDT_INTERVAL	(HZ/10+1) ++#define RDC_WDT_SETUP (RDC_WDT_EN | RDC_WDT_NMIIRQ | RDC_WDT_RST | RDC_WDT_DFLT_CNT) +  + static int ticks = 1000; +  + /* some device data */ +  + static struct { +-	struct completion stop; +-	int running; + 	struct timer_list timer; +-	int queue; +-	int default_ticks; +-	unsigned long inuse; +-	spinlock_t lock; ++	int seconds_left; ++	int total_seconds; ++	bool inuse; ++	bool running; ++	bool close_expected; ++ + 	struct pci_dev *sb_pdev; + 	int base_reg; + } rdc321x_wdt_device; +  +-/* generic helper functions */ ++static struct watchdog_info ident = { ++	.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, ++	.identity = "RDC321x WDT", ++}; ++ +  +-static void rdc321x_wdt_trigger(unsigned long unused) ++/* generic helper functions */ ++static void rdc321x_wdt_timer(unsigned long unused) + { +-	unsigned long flags; +-	u32 val; ++        if (!rdc321x_wdt_device.running) { ++                pci_write_config_dword(rdc321x_wdt_device.sb_pdev, ++						rdc321x_wdt_device.base_reg, 0); ++                return; ++        } +  +-	if (rdc321x_wdt_device.running) +-		ticks--; ++        rdc321x_wdt_device.seconds_left--; +  +-	/* keep watchdog alive */ +-	spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); +-	pci_read_config_dword(rdc321x_wdt_device.sb_pdev, +-					rdc321x_wdt_device.base_reg, &val); +-	val |= RDC_WDT_EN; +-	pci_write_config_dword(rdc321x_wdt_device.sb_pdev, +-					rdc321x_wdt_device.base_reg, val); +-	spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); ++        if (rdc321x_wdt_device.seconds_left < 1) ++                return; +  +-	/* 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); +-	} ++	pci_write_config_dword(rdc321x_wdt_device.sb_pdev, ++				rdc321x_wdt_device.base_reg, RDC_WDT_SETUP); +  ++        mod_timer(&rdc321x_wdt_device.timer, HZ * 2 + jiffies); + } +  + static void rdc321x_wdt_reset(void) + { +-	ticks = rdc321x_wdt_device.default_ticks; ++	rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds; + } +  + static void rdc321x_wdt_start(void) + { +-	unsigned long flags; +- +-	if (!rdc321x_wdt_device.queue) { +-		rdc321x_wdt_device.queue = 1; +- +-		/* Clear the timer */ +-		spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); +-		pci_write_config_dword(rdc321x_wdt_device.sb_pdev, +-				rdc321x_wdt_device.base_reg, RDC_CLS_TMR); +- +-		/* Enable watchdog and set the timeout to 81.92 us */ +-		pci_write_config_dword(rdc321x_wdt_device.sb_pdev, +-					rdc321x_wdt_device.base_reg, +-					RDC_WDT_EN | RDC_WDT_CNT); +-		spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); ++	if (rdc321x_wdt_device.running) ++		return; +  +-		mod_timer(&rdc321x_wdt_device.timer, +-				jiffies + RDC_WDT_INTERVAL); +-	} ++	rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds; ++	rdc321x_wdt_device.running = true; ++	rdc321x_wdt_timer(0); +  +-	/* if process dies, counter is not decremented */ +-	rdc321x_wdt_device.running++; ++	return; + } +  + static int rdc321x_wdt_stop(void) + { +-	if (rdc321x_wdt_device.running) +-		rdc321x_wdt_device.running = 0; ++	if (WATCHDOG_NOWAYOUT) ++		return -ENOSYS; +  +-	ticks = rdc321x_wdt_device.default_ticks; ++	rdc321x_wdt_device.running = false; +  +-	return -EIO; ++	return 0; + } +  + /* filesystem operations */ + static int rdc321x_wdt_open(struct inode *inode, struct file *file) + { +-	if (test_and_set_bit(0, &rdc321x_wdt_device.inuse)) ++	if (xchg(&rdc321x_wdt_device.inuse, true)) + 		return -EBUSY; +  + 	return nonseekable_open(inode, file); +@@ -148,7 +136,16 @@ +  + static int rdc321x_wdt_release(struct inode *inode, struct file *file) + { +-	clear_bit(0, &rdc321x_wdt_device.inuse); ++	int ret; ++ ++	if (rdc321x_wdt_device.close_expected) { ++		ret = rdc321x_wdt_stop(); ++		if (ret) ++			return ret; ++	} ++ ++	rdc321x_wdt_device.inuse = false; ++ + 	return 0; + } +  +@@ -156,30 +153,29 @@ + 				unsigned long arg) + { + 	void __user *argp = (void __user *)arg; +-	u32 value; +-	static struct watchdog_info ident = { +-		.options = WDIOF_CARDRESET, +-		.identity = "RDC321x WDT", +-	}; +-	unsigned long flags; ++	int value; +  + 	switch (cmd) { + 	case WDIOC_KEEPALIVE: + 		rdc321x_wdt_reset(); + 		break; +-	case WDIOC_GETSTATUS: +-		/* Read the value from the DATA register */ +-		spin_lock_irqsave(&rdc321x_wdt_device.lock, flags); +-		pci_read_config_dword(rdc321x_wdt_device.sb_pdev, +-					rdc321x_wdt_device.base_reg, &value); +-		spin_unlock_irqrestore(&rdc321x_wdt_device.lock, flags); +-		if (copy_to_user(argp, &value, sizeof(u32))) +-			return -EFAULT; +-		break; + 	case WDIOC_GETSUPPORT: + 		if (copy_to_user(argp, &ident, sizeof(ident))) + 			return -EFAULT; + 		break; ++	case WDIOC_SETTIMEOUT: ++		if (copy_from_user(&rdc321x_wdt_device.total_seconds, argp, sizeof(int))) ++			return -EFAULT; ++		rdc321x_wdt_device.seconds_left = rdc321x_wdt_device.total_seconds; ++		break; ++	case WDIOC_GETTIMEOUT: ++		if (copy_to_user(argp, &rdc321x_wdt_device.total_seconds, sizeof(int))) ++			return -EFAULT; ++		break; ++	case WDIOC_GETTIMELEFT: ++		if (copy_to_user(argp, &rdc321x_wdt_device.seconds_left, sizeof(int))) ++			return -EFAULT; ++		break; + 	case WDIOC_SETOPTIONS: + 		if (copy_from_user(&value, argp, sizeof(int))) + 			return -EFAULT; +@@ -194,17 +190,34 @@ + 		} + 		break; + 	default: +-		return -ENOTTY; ++		return -EINVAL; + 	} ++ + 	return 0; + } +  + static ssize_t rdc321x_wdt_write(struct file *file, const char __user *buf, + 				size_t count, loff_t *ppos) + { ++	size_t i; ++ + 	if (!count) + 		return -EIO; +  ++	rdc321x_wdt_device.close_expected = false; ++ ++	for (i = 0; i != count; i++) { ++		char c; ++ ++		if (get_user(c, buf + i)) ++			return -EFAULT; ++ ++		if (c == 'V') { ++			rdc321x_wdt_device.close_expected = true; ++			break; ++		} ++	} ++ + 	rdc321x_wdt_reset(); +  + 	return count; +@@ -246,27 +259,18 @@ + 	rdc321x_wdt_device.sb_pdev = pdata->sb_pdev; + 	rdc321x_wdt_device.base_reg = r->start; +  ++	rdc321x_wdt_device.running = false; ++	rdc321x_wdt_device.close_expected = false; ++	rdc321x_wdt_device.inuse = 0; ++	setup_timer(&rdc321x_wdt_device.timer, rdc321x_wdt_timer, 0); ++	rdc321x_wdt_device.total_seconds = 100; ++ + 	err = misc_register(&rdc321x_wdt_misc); + 	if (err < 0) { + 		dev_err(&pdev->dev, "misc_register failed\n"); + 		return err; + 	} +  +-	spin_lock_init(&rdc321x_wdt_device.lock); +- +-	/* Reset the watchdog */ +-	pci_write_config_dword(rdc321x_wdt_device.sb_pdev, +-				rdc321x_wdt_device.base_reg, RDC_WDT_RST); +- +-	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; +- + 	dev_info(&pdev->dev, "watchdog init success\n"); +  + 	return 0; +@@ -274,10 +278,11 @@ +  + static int __devexit rdc321x_wdt_remove(struct platform_device *pdev) + { +-	if (rdc321x_wdt_device.queue) { +-		rdc321x_wdt_device.queue = 0; +-		wait_for_completion(&rdc321x_wdt_device.stop); +-	} ++	if (rdc321x_wdt_device.inuse) ++		rdc321x_wdt_device.inuse = 0; ++ ++	while (timer_pending(&rdc321x_wdt_device.timer)) ++		msleep(100); +  + 	misc_deregister(&rdc321x_wdt_misc); +   | 
