-+ * Platform driver for PCA9564 I2C bus controller.
-+ *
-+ * (C) 2006 Andrew Victor
-+ *
-+ * Based on i2c-pca-isa.c driver for PCA9564 on ISA boards
-+ * Copyright (C) 2004 Arcom Control Systems
-+ *
-+ * 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/kernel.h>
-+#include <linux/module.h>
-+#include <linux/moduleparam.h>
-+#include <linux/delay.h>
-+#include <linux/init.h>
-+#include <linux/interrupt.h>
-+#include <linux/wait.h>
-+#include <linux/platform_device.h>
-+
-+#include <linux/i2c.h>
-+#include <linux/i2c-algo-pca.h>
-+
-+#include <asm/io.h>
-+
-+#include "../algos/i2c-algo-pca.h"
-+
-+#define PCA_OWN_ADDRESS 0x55 /* our address for slave mode */
-+#define PCA_CLOCK I2C_PCA_CON_59kHz
-+
-+//#define DEBUG_IO
-+
-+#define PCA_IO_SIZE 4
-+
-+static void __iomem *base_addr;
-+static int irq;
-+static wait_queue_head_t pca_wait;
-+
-+static int pca_getown(struct i2c_algo_pca_data *adap)
-+{
-+ return PCA_OWN_ADDRESS;
-+}
-+
-+static int pca_getclock(struct i2c_algo_pca_data *adap)
-+{
-+ return PCA_CLOCK;
-+}
-+
-+static void pca_writebyte(struct i2c_algo_pca_data *adap, int reg, int val)
-+{
-+#ifdef DEBUG_IO
-+ static char *names[] = { "T/O", "DAT", "ADR", "CON" };
-+ printk("*** write %s at %#lx <= %#04x\n", names[reg], (unsigned long) base_addr+reg, val);
-+#endif
-+ outb(val, base_addr+reg);
-+}
-+
-+static int pca_readbyte(struct i2c_algo_pca_data *adap, int reg)
-+{
-+ int res = inb(base_addr+reg);
-+#ifdef DEBUG_IO
-+ {
-+ static char *names[] = { "STA", "DAT", "ADR", "CON" };
-+ printk("*** read %s => %#04x\n", names[reg], res);
-+ }
-+#endif
-+ return res;
-+}
-+
-+static int pca_waitforinterrupt(struct i2c_algo_pca_data *adap)
-+{
-+ int ret = 0;
-+
-+ if (irq > -1) {
-+ ret = wait_event_interruptible(pca_wait,
-+ pca_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI);
-+ } else {
-+ while ((pca_readbyte(adap, I2C_PCA_CON) & I2C_PCA_CON_SI) == 0)
-+ udelay(100);
-+ }
-+ return ret;
-+}
-+
-+static irqreturn_t pca_handler(int this_irq, void *dev_id)
-+{
-+ wake_up_interruptible(&pca_wait);
-+ return IRQ_HANDLED;
-+}
-+
-+static struct i2c_algo_pca_data pca_i2c_data = {
-+ .get_own = pca_getown,
-+ .get_clock = pca_getclock,
-+ .write_byte = pca_writebyte,
-+ .read_byte = pca_readbyte,
-+ .wait_for_interrupt = pca_waitforinterrupt,
-+};
-+
-+static struct i2c_adapter pca_i2c_ops = {
-+ .owner = THIS_MODULE,
-+ .id = I2C_HW_A_PLAT,
-+ .algo_data = &pca_i2c_data,
-+ .name = "PCA9564",
-+};
-+
-+static int __devinit pca_i2c_probe(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+
-+ init_waitqueue_head(&pca_wait);
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res)
-+ return -ENODEV;
-+
-+ if (!request_mem_region(res->start, PCA_IO_SIZE, "PCA9564"))
-+ return -ENXIO;
-+
-+ base_addr = ioremap(res->start, PCA_IO_SIZE);
-+ if (base_addr == NULL)
-+ goto out_region;
-+
-+ irq = platform_get_irq(pdev, 0);
-+ if (irq > -1) {
-+ if (request_irq(irq, pca_handler, 0, "pca9564", NULL) < 0) {
-+ printk(KERN_ERR "i2c-pca: Request irq%d failed\n", irq);
-+ goto out_remap;
-+ }
-+ }
-+
-+ if (i2c_pca_add_bus(&pca_i2c_ops) < 0) {
-+ printk(KERN_ERR "i2c-pca: Failed to add i2c bus\n");
-+ goto out_irq;
-+ }
-+
-+ return 0;
-+
-+ out_irq:
-+ if (irq > -1)
-+ free_irq(irq, &pca_i2c_ops);
-+
-+ out_remap:
-+ iounmap(base_addr);
-+
-+ out_region:
-+ release_mem_region(res->start, PCA_IO_SIZE);
-+ return -ENODEV;
-+}
-+
-+static int __devexit pca_i2c_remove(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+
-+ i2c_pca_del_bus(&pca_i2c_ops);
-+
-+ if (irq > 0)
-+ free_irq(irq, NULL);
-+
-+ iounmap(base_addr);
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ release_mem_region(res->start, PCA_IO_SIZE);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver pca_i2c_driver = {
-+ .probe = pca_i2c_probe,
-+ .remove = __devexit_p(pca_i2c_remove),
-+ .driver = {
-+ .name = "pca9564",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init pca_i2c_init(void)
-+{
-+ return platform_driver_register(&pca_i2c_driver);
-+}
-+
-+static void __exit pca_i2c_exit(void)
-+{
-+ platform_driver_unregister(&pca_i2c_driver);
-+}
-+
-+module_init(pca_i2c_init);
-+module_exit(pca_i2c_exit);
-+
-+MODULE_AUTHOR("Andrew Victor");
-+MODULE_DESCRIPTION("PCA9564 platform driver");
-+MODULE_LICENSE("GPL");
-diff -urN -x CVS linux-2.6.19-final/drivers/leds/Kconfig linux-2.6.19/drivers/leds/Kconfig
---- linux-2.6.19-final/drivers/leds/Kconfig Mon Dec 4 16:33:34 2006
-+++ linux-2.6.19/drivers/leds/Kconfig Thu Nov 16 17:15:16 2006
-@@ -76,6 +76,13 @@
- This option enables support for the Soekris net4801 and net4826 error
- LED.
-
-+config LEDS_AT91
-+ tristate "LED support using AT91 GPIOs"
-+ depends LEDS_CLASS && ARCH_AT91 && !LEDS
-+ help
-+ This option enables support for LEDs connected to GPIO lines
-+ on AT91-based boards.
-+
- comment "LED Triggers"
-
- config LEDS_TRIGGERS
-diff -urN -x CVS linux-2.6.19-final/drivers/leds/Makefile linux-2.6.19/drivers/leds/Makefile
---- linux-2.6.19-final/drivers/leds/Makefile Mon Dec 4 16:33:34 2006
-+++ linux-2.6.19/drivers/leds/Makefile Thu Nov 16 12:52:06 2006
-@@ -13,6 +13,7 @@
- obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o
- obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
- obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
-+obj-$(CONFIG_LEDS_AT91) += leds-at91.o
-
- # LED Triggers
- obj-$(CONFIG_LEDS_TRIGGER_TIMER) += ledtrig-timer.o
-diff -urN -x CVS linux-2.6.19-final/drivers/leds/leds-at91.c linux-2.6.19/drivers/leds/leds-at91.c
---- linux-2.6.19-final/drivers/leds/leds-at91.c Thu Jan 1 02:00:00 1970
-+++ linux-2.6.19/drivers/leds/leds-at91.c Mon Nov 20 11:02:21 2006
-@@ -0,0 +1,140 @@
-+/*
-+ * AT91 GPIO based LED driver
-+ *
-+ * Copyright (C) 2006 David Brownell
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/platform_device.h>
-+#include <linux/leds.h>
-+
-+#include <asm/arch/board.h>
-+#include <asm/arch/gpio.h>
-+
-+static LIST_HEAD(at91_led_list); /* list of AT91 LEDs */
-+
-+struct at91_led {
-+ struct led_classdev cdev;
-+ struct list_head list;
-+ struct at91_gpio_led *led_data;
-+};
-+
-+/*
-+ * Change the state of the LED.
-+ */
-+static void at91_led_set(struct led_classdev *cdev, enum led_brightness value)
-+{
-+ struct at91_led *led = container_of(cdev, struct at91_led, cdev);
-+ short active = (value == LED_OFF);
-+
-+ if (led->led_data->flags & 1) /* active high/low? */
-+ active = !active;
-+ at91_set_gpio_value(led->led_data->gpio, value == LED_OFF);
-+}
-+
-+static int __devexit at91_led_remove(struct platform_device *pdev)
-+{
-+ struct at91_led *led;
-+
-+ list_for_each_entry (led, &at91_led_list, list)
-+ led_classdev_unregister(&led->cdev);
-+
-+#warning "Free allocated memory"
-+ // TODO: Free memory. kfree(led);
-+
-+ return 0;
-+}
-+
-+static int __init at91_led_probe(struct platform_device *pdev)
-+{
-+ int status = 0;
-+ struct at91_gpio_led *pdata = pdev->dev.platform_data;
-+ unsigned nr_leds;
-+ struct at91_led *led;
-+
-+ if (!pdata)
-+ return -ENODEV;
-+
-+ nr_leds = pdata->index; /* first index stores number of LEDs */
-+
-+ while (nr_leds--) {
-+ led = kzalloc(sizeof(struct at91_led), GFP_KERNEL);
-+ if (!led) {
-+ dev_err(&pdev->dev, "No memory for device\n");
-+ status = -ENOMEM;
-+ goto cleanup;
-+ }
-+ led->led_data = pdata;
-+ led->cdev.name = pdata->name;
-+ led->cdev.brightness_set = at91_led_set,
-+ led->cdev.default_trigger = pdata->trigger;
-+
-+ status = led_classdev_register(&pdev->dev, &led->cdev);
-+ if (status < 0) {
-+ dev_err(&pdev->dev, "led_classdev_register failed - %d\n", status);
-+cleanup:
-+ at91_led_remove(pdev);
-+ break;
-+ }
-+ list_add(&led->list, &at91_led_list);
-+ pdata++;
-+ }
-+ return status;
-+}
-+
-+#ifdef CONFIG_PM
-+static int at91_led_suspend(struct platform_device *dev, pm_message_t state)
-+{
-+ struct at91_led *led;
-+
-+ list_for_each_entry (led, &at91_led_list, list)
-+ led_classdev_suspend(&led->cdev);
-+
-+ return 0;
-+}
-+
-+static int at91_led_resume(struct platform_device *dev)
-+{
-+ struct at91_led *led;
-+
-+ list_for_each_entry (led, &at91_led_list, list)
-+ led_classdev_resume(&led->cdev);
-+
-+ return 0;
-+}
-+#else
-+#define at91_led_suspend NULL
-+#define at91_led_resume NULL
-+#endif
-+
-+static struct platform_driver at91_led_driver = {
-+ .probe = at91_led_probe,
-+ .remove = __devexit_p(at91_led_remove),
-+ .suspend = at91_led_suspend,
-+ .resume = at91_led_resume,
-+ .driver = {
-+ .name = "at91_leds",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init at91_led_init(void)
-+{
-+ return platform_driver_register(&at91_led_driver);
-+}
-+module_init(at91_led_init);
-+
-+static void __exit at91_led_exit(void)
-+{
-+ platform_driver_unregister(&at91_led_driver);
-+}
-+module_exit(at91_led_exit);
-+
-+MODULE_DESCRIPTION("AT91 GPIO LED driver");
-+MODULE_AUTHOR("David Brownell");
-+MODULE_LICENSE("GPL");
-diff -urN -x CVS linux-2.6.19-final/drivers/mmc/Kconfig linux-2.6.19/drivers/mmc/Kconfig
---- linux-2.6.19-final/drivers/mmc/Kconfig Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mmc/Kconfig Thu Nov 9 14:16:55 2006
-@@ -91,11 +91,11 @@
-
- If unsure, say N.
-
--config MMC_AT91RM9200
-- tristate "AT91RM9200 SD/MMC Card Interface support"
-- depends on ARCH_AT91RM9200 && MMC
-+config MMC_AT91
-+ tristate "AT91 SD/MMC Card Interface support"
-+ depends on ARCH_AT91 && MMC
- help
-- This selects the AT91RM9200 MCI controller.
-+ This selects the AT91 MCI controller.
-
- If unsure, say N.
-
-diff -urN -x CVS linux-2.6.19-final/drivers/mmc/Makefile linux-2.6.19/drivers/mmc/Makefile
---- linux-2.6.19-final/drivers/mmc/Makefile Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mmc/Makefile Thu Nov 9 14:17:47 2006
-@@ -22,7 +22,7 @@
- obj-$(CONFIG_MMC_WBSD) += wbsd.o
- obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
- obj-$(CONFIG_MMC_OMAP) += omap.o
--obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
-+obj-$(CONFIG_MMC_AT91) += at91_mci.o
- obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
-
- mmc_core-y := mmc.o mmc_sysfs.o
-diff -urN -x CVS linux-2.6.19-final/drivers/mmc/at91_mci.c linux-2.6.19/drivers/mmc/at91_mci.c
---- linux-2.6.19-final/drivers/mmc/at91_mci.c Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mmc/at91_mci.c Sat Nov 25 11:00:45 2006
-@@ -1,5 +1,5 @@
- /*
-- * linux/drivers/mmc/at91_mci.c - ATMEL AT91RM9200 MCI Driver
-+ * linux/drivers/mmc/at91_mci.c - ATMEL AT91 MCI Driver
- *
- * Copyright (C) 2005 Cougar Creek Computing Devices Ltd, All Rights Reserved
- *
-@@ -11,7 +11,7 @@
- */
-
- /*
-- This is the AT91RM9200 MCI driver that has been tested with both MMC cards
-+ This is the AT91 MCI driver that has been tested with both MMC cards
- and SD-cards. Boards that support write protect are now supported.
- The CCAT91SBC001 board does not support SD cards.
-
-@@ -38,8 +38,8 @@
- controller to manage the transfers.
-
- A read is done from the controller directly to the scatterlist passed in from the request.
-- Due to a bug in the controller, when a read is completed, all the words are byte
-- swapped in the scatterlist buffers.
-+ Due to a bug in the AT91RM9200 controller, when a read is completed, all the words are byte
-+ swapped in the scatterlist buffers. AT91SAM926x are not affected by this bug.
-
- The sequence of read interrupts is: ENDRX, RXBUFF, CMDRDY
-
-@@ -72,42 +72,27 @@
- #include <asm/irq.h>
- #include <asm/mach/mmc.h>
- #include <asm/arch/board.h>
-+#include <asm/arch/cpu.h>
- #include <asm/arch/gpio.h>
--#include <asm/arch/at91rm9200_mci.h>
--#include <asm/arch/at91rm9200_pdc.h>
-+#include <asm/arch/at91_mci.h>
-+#include <asm/arch/at91_pdc.h>
-
- #define DRIVER_NAME "at91_mci"
-
- #undef SUPPORT_4WIRE
-
--static struct clk *mci_clk;
-+#define FL_SENT_COMMAND (1 << 0)
-+#define FL_SENT_STOP (1 << 1)
-
--#define FL_SENT_COMMAND (1 << 0)
--#define FL_SENT_STOP (1 << 1)
-+#define AT91_MCI_ERRORS (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE \
-+ | AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE \
-+ | AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
-
-+#define at91_mci_read(host, reg) __raw_readl((host)->baseaddr + (reg))
-+#define at91_mci_write(host, reg, val) __raw_writel((val), (host)->baseaddr + (reg))
-
-
- /*
-- * Read from a MCI register.
-- */
--static inline unsigned long at91_mci_read(unsigned int reg)
--{
-- void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
--
-- return __raw_readl(mci_base + reg);
--}
--
--/*
-- * Write to a MCI register.
-- */
--static inline void at91_mci_write(unsigned int reg, unsigned long value)
--{
-- void __iomem *mci_base = (void __iomem *)AT91_VA_BASE_MCI;
--
-- __raw_writel(value, mci_base + reg);
--}
--
--/*
- * Low level type for this driver
- */
- struct at91mci_host
-@@ -116,9 +101,14 @@
- struct mmc_command *cmd;
- struct mmc_request *request;
-
-+ void __iomem *baseaddr;
-+ int irq;
-+
- struct at91_mmc_data *board;
- int present;
-
-+ struct clk *mci_clk;
-+
- /*
- * Flag indicating when the command has been sent. This is used to
- * work out whether or not to send the stop
-@@ -158,7 +148,6 @@
- for (i = 0; i < len; i++) {
- struct scatterlist *sg;
- int amount;
-- int index;
- unsigned int *sgbuffer;
-
- sg = &data->sg[i];
-@@ -166,10 +155,15 @@
- sgbuffer = kmap_atomic(sg->page, KM_BIO_SRC_IRQ) + sg->offset;
- amount = min(size, sg->length);
- size -= amount;
-- amount /= 4;
--
-- for (index = 0; index < amount; index++)
-- *dmabuf++ = swab32(sgbuffer[index]);
-+
-+ if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
-+ int index;
-+
-+ for (index = 0; index < (amount / 4); index++)
-+ *dmabuf++ = swab32(sgbuffer[index]);
-+ }
-+ else
-+ memcpy(dmabuf, sgbuffer, amount);
-
- kunmap_atomic(sgbuffer, KM_BIO_SRC_IRQ);
-
-@@ -217,13 +211,13 @@
-
- /* Check to see if this needs filling */
- if (i == 0) {
-- if (at91_mci_read(AT91_PDC_RCR) != 0) {
-+ if (at91_mci_read(host, AT91_PDC_RCR) != 0) {
- pr_debug("Transfer active in current\n");
- continue;
- }
- }
- else {
-- if (at91_mci_read(AT91_PDC_RNCR) != 0) {
-+ if (at91_mci_read(host, AT91_PDC_RNCR) != 0) {
- pr_debug("Transfer active in next\n");
- continue;
- }
-@@ -240,12 +234,12 @@
- pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
-
- if (i == 0) {
-- at91_mci_write(AT91_PDC_RPR, sg->dma_address);
-- at91_mci_write(AT91_PDC_RCR, sg->length / 4);
-+ at91_mci_write(host, AT91_PDC_RPR, sg->dma_address);
-+ at91_mci_write(host, AT91_PDC_RCR, sg->length / 4);
- }
- else {
-- at91_mci_write(AT91_PDC_RNPR, sg->dma_address);
-- at91_mci_write(AT91_PDC_RNCR, sg->length / 4);
-+ at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address);
-+ at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4);
- }
- }
-
-@@ -276,8 +270,6 @@
-
- while (host->in_use_index < host->transfer_index) {
- unsigned int *buffer;
-- int index;
-- int len;
-
- struct scatterlist *sg;
-
-@@ -295,11 +287,14 @@
-
- data->bytes_xfered += sg->length;
-
-- len = sg->length / 4;
--
-- for (index = 0; index < len; index++) {
-- buffer[index] = swab32(buffer[index]);
-+ if (cpu_is_at91rm9200()) { /* AT91RM9200 errata */
-+ int index;
-+
-+ for (index = 0; index < (sg->length / 4); index++) {
-+ buffer[index] = swab32(buffer[index]);
-+ }
- }
-+
- kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
- flush_dcache_page(sg->page);
- }
-@@ -308,57 +303,34 @@
- if (host->transfer_index < data->sg_len)
- at91mci_pre_dma_read(host);
- else {
-- at91_mci_write(AT91_MCI_IER, AT91_MCI_RXBUFF);
-- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
-+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
- }
-
- pr_debug("post dma read done\n");
- }
-
--/*
-- * Handle transmitted data
-- */
--static void at91_mci_handle_transmitted(struct at91mci_host *host)
--{
-- struct mmc_command *cmd;
-- struct mmc_data *data;
--
-- pr_debug("Handling the transmit\n");
--
-- /* Disable the transfer */
-- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
--
-- /* Now wait for cmd ready */
-- at91_mci_write(AT91_MCI_IDR, AT91_MCI_TXBUFE);
-- at91_mci_write(AT91_MCI_IER, AT91_MCI_NOTBUSY);
--
-- cmd = host->cmd;
-- if (!cmd) return;
--
-- data = cmd->data;
-- if (!data) return;
--
-- data->bytes_xfered = host->total_length;
--}
-
- /*
- * Enable the controller
- */
--static void at91_mci_enable(void)
-+static void at91_mci_enable(struct at91mci_host *host)
- {
-- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
-- at91_mci_write(AT91_MCI_IDR, 0xFFFFFFFF);
-- at91_mci_write(AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
-- at91_mci_write(AT91_MCI_MR, 0x834A);
-- at91_mci_write(AT91_MCI_SDCR, 0x0);
-+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-+ at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC);
-+ at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a);
-+
-+ /* use Slot A or B (only one at same time) */
-+ at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b);
- }
-
- /*
- * Disable the controller
- */
--static void at91_mci_disable(void)
-+static void at91_mci_disable(struct at91mci_host *host)
- {
-- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
-+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS | AT91_MCI_SWRST);
- }
-
- /*
-@@ -378,13 +350,13 @@
-
- /* Not sure if this is needed */
- #if 0
-- if ((at91_mci_read(AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
-+ if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) {
- pr_debug("Clearing timeout\n");
-- at91_mci_write(AT91_MCI_ARGR, 0);
-- at91_mci_write(AT91_MCI_CMDR, AT91_MCI_OPDCMD);
-- while (!(at91_mci_read(AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
-+ at91_mci_write(host, AT91_MCI_ARGR, 0);
-+ at91_mci_write(host, AT91_MCI_CMDR, AT91_MCI_OPDCMD);
-+ while (!(at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_CMDRDY)) {
- /* spin */
-- pr_debug("Clearing: SR = %08X\n", at91_mci_read(AT91_MCI_SR));
-+ pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR));
- }
- }
- #endif
-@@ -431,32 +403,32 @@
- /*
- * Set the arguments and send the command
- */
-- pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08lX)\n",
-- cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(AT91_MCI_MR));
-+ pr_debug("Sending command %d as %08X, arg = %08X, blocks = %d, length = %d (MR = %08X)\n",
-+ cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
-
- if (!data) {
-- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
-- at91_mci_write(AT91_PDC_RPR, 0);
-- at91_mci_write(AT91_PDC_RCR, 0);
-- at91_mci_write(AT91_PDC_RNPR, 0);
-- at91_mci_write(AT91_PDC_RNCR, 0);
-- at91_mci_write(AT91_PDC_TPR, 0);
-- at91_mci_write(AT91_PDC_TCR, 0);
-- at91_mci_write(AT91_PDC_TNPR, 0);
-- at91_mci_write(AT91_PDC_TNCR, 0);
-+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
-+ at91_mci_write(host, AT91_PDC_RPR, 0);
-+ at91_mci_write(host, AT91_PDC_RCR, 0);
-+ at91_mci_write(host, AT91_PDC_RNPR, 0);
-+ at91_mci_write(host, AT91_PDC_RNCR, 0);
-+ at91_mci_write(host, AT91_PDC_TPR, 0);
-+ at91_mci_write(host, AT91_PDC_TCR, 0);
-+ at91_mci_write(host, AT91_PDC_TNPR, 0);
-+ at91_mci_write(host, AT91_PDC_TNCR, 0);
-
-- at91_mci_write(AT91_MCI_ARGR, cmd->arg);
-- at91_mci_write(AT91_MCI_CMDR, cmdr);
-+ at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-+ at91_mci_write(host, AT91_MCI_CMDR, cmdr);
- return AT91_MCI_CMDRDY;
- }
-
-- mr = at91_mci_read(AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
-- at91_mci_write(AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
-+ mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; /* zero block length and PDC mode */
-+ at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE);
-
- /*
- * Disable the PDC controller
- */
-- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
-+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- data->bytes_xfered = 0;
-@@ -478,15 +450,15 @@
- */
- host->total_length = block_length * blocks;
- host->buffer = dma_alloc_coherent(NULL,
-- host->total_length,
-- &host->physical_address, GFP_KERNEL);
-+ host->total_length,
-+ &host->physical_address, GFP_KERNEL);
-
- at91mci_sg_to_dma(host, data);
-
- pr_debug("Transmitting %d bytes\n", host->total_length);
-
-- at91_mci_write(AT91_PDC_TPR, host->physical_address);
-- at91_mci_write(AT91_PDC_TCR, host->total_length / 4);
-+ at91_mci_write(host, AT91_PDC_TPR, host->physical_address);
-+ at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4);
- ier = AT91_MCI_TXBUFE;
- }
- }
-@@ -496,14 +468,14 @@
- * the data sheet says
- */
-
-- at91_mci_write(AT91_MCI_ARGR, cmd->arg);
-- at91_mci_write(AT91_MCI_CMDR, cmdr);
-+ at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
-+ at91_mci_write(host, AT91_MCI_CMDR, cmdr);
-
- if (cmdr & AT91_MCI_TRCMD_START) {
- if (cmdr & AT91_MCI_TRDIR)
-- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_RXTEN);
-+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN);
- else
-- at91_mci_write(AT91_PDC_PTCR, AT91_PDC_TXTEN);
-+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);
- }
- return ier;
- }
-@@ -520,7 +492,7 @@
- pr_debug("setting ier to %08X\n", ier);
-
- /* Stop on errors or the required value */
-- at91_mci_write(AT91_MCI_IER, 0xffff0000 | ier);
-+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier);
- }
-
- /*
-@@ -548,26 +520,24 @@
- struct mmc_command *cmd = host->cmd;
- unsigned int status;
-
-- at91_mci_write(AT91_MCI_IDR, 0xffffffff);
-+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
-
-- cmd->resp[0] = at91_mci_read(AT91_MCI_RSPR(0));
-- cmd->resp[1] = at91_mci_read(AT91_MCI_RSPR(1));
-- cmd->resp[2] = at91_mci_read(AT91_MCI_RSPR(2));
-- cmd->resp[3] = at91_mci_read(AT91_MCI_RSPR(3));
-+ cmd->resp[0] = at91_mci_read(host, AT91_MCI_RSPR(0));
-+ cmd->resp[1] = at91_mci_read(host, AT91_MCI_RSPR(1));
-+ cmd->resp[2] = at91_mci_read(host, AT91_MCI_RSPR(2));
-+ cmd->resp[3] = at91_mci_read(host, AT91_MCI_RSPR(3));
-
- if (host->buffer) {
- dma_free_coherent(NULL, host->total_length, host->buffer, host->physical_address);
- host->buffer = NULL;
- }
-
-- status = at91_mci_read(AT91_MCI_SR);
-+ status = at91_mci_read(host, AT91_MCI_SR);
-
- pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
- status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
-
-- if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
-- AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
-- AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
-+ if (status & AT91_MCI_ERRORS) {
- if ((status & AT91_MCI_RCRCE) &&
- ((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
- cmd->error = MMC_ERR_NONE;
-@@ -605,24 +575,50 @@
- }
-
- /*
-+ * Handle transmitted data
-+ */
-+static void at91_mci_handle_transmitted(struct at91mci_host *host)
-+{
-+ struct mmc_command *cmd;
-+ struct mmc_data *data;
-+
-+ pr_debug("Handling the transmit\n");
-+
-+ /* Disable the transfer */
-+ at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
-+
-+ /* Now wait for cmd ready */
-+ at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-+
-+ cmd = host->cmd;
-+ if (!cmd) return;
-+
-+ data = cmd->data;
-+ if (!data) return;
-+
-+ data->bytes_xfered = host->total_length;
-+}
-+
-+/*
- * Set the IOS
- */
- static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
- {
- int clkdiv;
- struct at91mci_host *host = mmc_priv(mmc);
-- unsigned long at91_master_clock = clk_get_rate(mci_clk);
-+ unsigned long at91_master_clock = clk_get_rate(host->mci_clk);
-
- host->bus_mode = ios->bus_mode;
-
- if (ios->clock == 0) {
- /* Disable the MCI controller */
-- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIDIS);
-+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIDIS);
- clkdiv = 0;
- }
- else {
- /* Enable the MCI controller */
-- at91_mci_write(AT91_MCI_CR, AT91_MCI_MCIEN);
-+ at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN);
-
- if ((at91_master_clock % (ios->clock * 2)) == 0)
- clkdiv = ((at91_master_clock / ios->clock) / 2) - 1;
-@@ -634,25 +630,25 @@
- }
- if (ios->bus_width == MMC_BUS_WIDTH_4 && host->board->wire4) {
- pr_debug("MMC: Setting controller bus width to 4\n");
-- at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
-+ at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) | AT91_MCI_SDCBUS);
- }
- else {
- pr_debug("MMC: Setting controller bus width to 1\n");
-- at91_mci_write(AT91_MCI_SDCR, at91_mci_read(AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
-+ at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
-
- /* Set the clock divider */
-- at91_mci_write(AT91_MCI_MR, (at91_mci_read(AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-+ at91_mci_write(host, AT91_MCI_MR, (at91_mci_read(host, AT91_MCI_MR) & ~AT91_MCI_CLKDIV) | clkdiv);
-
- /* maybe switch power to the card */
- if (host->board->vcc_pin) {
- switch (ios->power_mode) {
- case MMC_POWER_OFF:
-- at91_set_gpio_output(host->board->vcc_pin, 0);
-+ at91_set_gpio_value(host->board->vcc_pin, 0);
- break;
- case MMC_POWER_UP:
- case MMC_POWER_ON:
-- at91_set_gpio_output(host->board->vcc_pin, 1);
-+ at91_set_gpio_value(host->board->vcc_pin, 1);
- break;
- }
- }
-@@ -665,39 +661,40 @@
- {
- struct at91mci_host *host = devid;
- int completed = 0;
-+ unsigned int int_status, int_mask;
-
-- unsigned int int_status;
-+ int_status = at91_mci_read(host, AT91_MCI_SR);
-+ int_mask = at91_mci_read(host, AT91_MCI_IMR);
-
-- int_status = at91_mci_read(AT91_MCI_SR);
-- pr_debug("MCI irq: status = %08X, %08lX, %08lX\n", int_status, at91_mci_read(AT91_MCI_IMR),
-- int_status & at91_mci_read(AT91_MCI_IMR));
--
-- if ((int_status & at91_mci_read(AT91_MCI_IMR)) & 0xffff0000)
-- completed = 1;
-+ pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
-+ int_status & int_mask);
-
-- int_status &= at91_mci_read(AT91_MCI_IMR);
-+ int_status = int_status & int_mask;
-
-- if (int_status & AT91_MCI_UNRE)
-- pr_debug("MMC: Underrun error\n");
-- if (int_status & AT91_MCI_OVRE)
-- pr_debug("MMC: Overrun error\n");
-- if (int_status & AT91_MCI_DTOE)
-- pr_debug("MMC: Data timeout\n");
-- if (int_status & AT91_MCI_DCRCE)
-- pr_debug("MMC: CRC error in data\n");
-- if (int_status & AT91_MCI_RTOE)
-- pr_debug("MMC: Response timeout\n");
-- if (int_status & AT91_MCI_RENDE)
-- pr_debug("MMC: Response end bit error\n");
-- if (int_status & AT91_MCI_RCRCE)
-- pr_debug("MMC: Response CRC error\n");
-- if (int_status & AT91_MCI_RDIRE)
-- pr_debug("MMC: Response direction error\n");
-- if (int_status & AT91_MCI_RINDE)
-- pr_debug("MMC: Response index error\n");
-+ if (int_status & AT91_MCI_ERRORS) {
-+ completed = 1;
-+
-+ if (int_status & AT91_MCI_UNRE)
-+ pr_debug("MMC: Underrun error\n");
-+ if (int_status & AT91_MCI_OVRE)
-+ pr_debug("MMC: Overrun error\n");
-+ if (int_status & AT91_MCI_DTOE)
-+ pr_debug("MMC: Data timeout\n");
-+ if (int_status & AT91_MCI_DCRCE)
-+ pr_debug("MMC: CRC error in data\n");
-+ if (int_status & AT91_MCI_RTOE)
-+ pr_debug("MMC: Response timeout\n");
-+ if (int_status & AT91_MCI_RENDE)
-+ pr_debug("MMC: Response end bit error\n");
-+ if (int_status & AT91_MCI_RCRCE)
-+ pr_debug("MMC: Response CRC error\n");
-+ if (int_status & AT91_MCI_RDIRE)
-+ pr_debug("MMC: Response direction error\n");
-+ if (int_status & AT91_MCI_RINDE)
-+ pr_debug("MMC: Response index error\n");
-+ } else {
-+ /* Only continue processing if no errors */
-
-- /* Only continue processing if no errors */
-- if (!completed) {
- if (int_status & AT91_MCI_TXBUFE) {
- pr_debug("TX buffer empty\n");
- at91_mci_handle_transmitted(host);
-@@ -705,12 +702,11 @@
-
- if (int_status & AT91_MCI_RXBUFF) {
- pr_debug("RX buffer full\n");
-- at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
-+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
- }
-
-- if (int_status & AT91_MCI_ENDTX) {
-+ if (int_status & AT91_MCI_ENDTX)
- pr_debug("Transmit has ended\n");
-- }
-
- if (int_status & AT91_MCI_ENDRX) {
- pr_debug("Receive has ended\n");
-@@ -719,37 +715,33 @@
-
- if (int_status & AT91_MCI_NOTBUSY) {
- pr_debug("Card is ready\n");
-- at91_mci_write(AT91_MCI_IER, AT91_MCI_CMDRDY);
-+ at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY);
- }
-
-- if (int_status & AT91_MCI_DTIP) {
-+ if (int_status & AT91_MCI_DTIP)
- pr_debug("Data transfer in progress\n");
-- }
-
-- if (int_status & AT91_MCI_BLKE) {
-+ if (int_status & AT91_MCI_BLKE)
- pr_debug("Block transfer has ended\n");
-- }
-
-- if (int_status & AT91_MCI_TXRDY) {
-+ if (int_status & AT91_MCI_TXRDY)
- pr_debug("Ready to transmit\n");
-- }
-
-- if (int_status & AT91_MCI_RXRDY) {
-+ if (int_status & AT91_MCI_RXRDY)
- pr_debug("Ready to receive\n");
-- }
-
- if (int_status & AT91_MCI_CMDRDY) {
- pr_debug("Command ready\n");
- completed = 1;
- }
- }
-- at91_mci_write(AT91_MCI_IDR, int_status);
-
- if (completed) {
- pr_debug("Completed command\n");
-- at91_mci_write(AT91_MCI_IDR, 0xffffffff);
-+ at91_mci_write(host, AT91_MCI_IDR, 0xffffffff);
- at91mci_completed_command(host);
-- }
-+ } else
-+ at91_mci_write(host, AT91_MCI_IDR, int_status);
-
- return IRQ_HANDLED;
- }
-@@ -769,7 +761,7 @@
- present ? "insert" : "remove");
- if (!present) {
- pr_debug("****** Resetting SD-card bus width ******\n");
-- at91_mci_write(AT91_MCI_SDCR, 0);
-+ at91_mci_write(host, AT91_MCI_SDCR, at91_mci_read(host, AT91_MCI_SDCR) & ~AT91_MCI_SDCBUS);
- }
- mmc_detect_change(host->mmc, msecs_to_jiffies(100));
- }
-@@ -806,15 +798,22 @@
- {
- struct mmc_host *mmc;
- struct at91mci_host *host;
-+ struct resource *res;
- int ret;
-
- pr_debug("Probe MCI devices\n");
-- at91_mci_disable();
-- at91_mci_enable();
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res)
-+ return -ENXIO;
-+
-+ if (!request_mem_region(res->start, res->end - res->start + 1, DRIVER_NAME))
-+ return -EBUSY;
-
- mmc = mmc_alloc_host(sizeof(struct at91mci_host), &pdev->dev);
- if (!mmc) {
- pr_debug("Failed to allocate mmc host\n");
-+ release_mem_region(res->start, res->end - res->start + 1);
- return -ENOMEM;
- }
-
-@@ -822,7 +821,7 @@
- mmc->f_min = 375000;
- mmc->f_max = 25000000;
- mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-- mmc->caps = MMC_CAP_BYTEBLOCK;
-+ mmc->caps = MMC_CAP_BYTEBLOCK | MMC_CAP_MULTIWRITE;
-
- host = mmc_priv(mmc);
- host->mmc = mmc;
-@@ -833,29 +832,50 @@
- #ifdef SUPPORT_4WIRE
- mmc->caps |= MMC_CAP_4_BIT_DATA;
- #else
-- printk("MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
-+ printk("AT91 MMC: 4 wire bus mode not supported by this driver - using 1 wire\n");
- #endif
- }
-
- /*
- * Get Clock
- */
-- mci_clk = clk_get(&pdev->dev, "mci_clk");
-- if (IS_ERR(mci_clk)) {
-+ host->mci_clk = clk_get(&pdev->dev, "mci_clk");
-+ if (IS_ERR(host->mci_clk)) {
- printk(KERN_ERR "AT91 MMC: no clock defined.\n");
- mmc_free_host(mmc);
-+ release_mem_region(res->start, res->end - res->start + 1);
- return -ENODEV;
- }
-- clk_enable(mci_clk); /* Enable the peripheral clock */
-+
-+ /*
-+ * Map I/O region
-+ */
-+ host->baseaddr = ioremap(res->start, res->end - res->start + 1);
-+ if (!host->baseaddr) {
-+ clk_put(host->mci_clk);
-+ release_mem_region(res->start, res->end - res->start + 1);
-+ mmc_free_host(mmc);
-+ return -ENOMEM;
-+ }
-+
-+ /*
-+ * Reset hardware
-+ */
-+ clk_enable(host->mci_clk); /* Enable the peripheral clock */
-+ at91_mci_disable(host);
-+ at91_mci_enable(host);
-
- /*
- * Allocate the MCI interrupt
- */
-- ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
-+ host->irq = platform_get_irq(pdev, 0);
-+ ret = request_irq(host->irq, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
- if (ret) {
-- printk(KERN_ERR "Failed to request MCI interrupt\n");
-- clk_disable(mci_clk);
-- clk_put(mci_clk);
-+ printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
-+ clk_disable(host->mci_clk);
-+ clk_put(host->mci_clk);
-+ iounmap(host->baseaddr);
-+ release_mem_region(res->start, res->end - res->start + 1);
- mmc_free_host(mmc);
- return ret;
- }
-@@ -879,10 +899,10 @@
- ret = request_irq(host->board->det_pin, at91_mmc_det_irq,
- 0, DRIVER_NAME, host);
- if (ret)
-- printk(KERN_ERR "couldn't allocate MMC detect irq\n");
-+ printk(KERN_ERR "AT91 MMC: Couldn't allocate MMC detect irq\n");
- }
-
-- pr_debug(KERN_INFO "Added MCI driver\n");
-+ pr_debug("Added MCI driver\n");
-
- return 0;
- }
-@@ -894,6 +914,7 @@
- {
- struct mmc_host *mmc = platform_get_drvdata(pdev);
- struct at91mci_host *host;
-+ struct resource *res;
-
- if (!mmc)
- return -1;
-@@ -905,16 +926,19 @@
- cancel_delayed_work(&host->mmc->detect);
- }
-
-+ at91_mci_disable(host);
- mmc_remove_host(mmc);
-- at91_mci_disable();
-- free_irq(AT91RM9200_ID_MCI, host);
-- mmc_free_host(mmc);
-+ free_irq(host->irq, host);
-
-- clk_disable(mci_clk); /* Disable the peripheral clock */
-- clk_put(mci_clk);
-+ iounmap(host->baseaddr);
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ release_mem_region(res->start, res->end - res->start + 1);
-
-- platform_set_drvdata(pdev, NULL);
-+ clk_disable(host->mci_clk); /* Disable the peripheral clock */
-+ clk_put(host->mci_clk);
-
-+ mmc_free_host(mmc);
-+ platform_set_drvdata(pdev, NULL);
- pr_debug("MCI Removed\n");
-
- return 0;
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/devices/Kconfig linux-2.6.19/drivers/mtd/devices/Kconfig
---- linux-2.6.19-final/drivers/mtd/devices/Kconfig Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mtd/devices/Kconfig Wed Nov 22 09:22:03 2006
-@@ -267,5 +267,11 @@
- LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
- you have managed to wipe the first block.
-
--endmenu
-+config MTD_AT91_DATAFLASH
-+ tristate "AT91RM9200 DataFlash AT45DBxxx (legacy driver)"
-+ depends on MTD && ARCH_AT91RM9200 && AT91_SPI
-+ help
-+ This enables access to the DataFlash (AT45DBxxx) on the AT91RM9200.
-+ If you have such a board, say 'Y'.
-
-+endmenu
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/devices/Makefile linux-2.6.19/drivers/mtd/devices/Makefile
---- linux-2.6.19-final/drivers/mtd/devices/Makefile Mon Dec 4 16:33:42 2006
-+++ linux-2.6.19/drivers/mtd/devices/Makefile Thu Oct 12 17:07:39 2006
-@@ -17,3 +17,4 @@
- obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
- obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
- obj-$(CONFIG_MTD_M25P80) += m25p80.o
-+obj-$(CONFIG_MTD_AT91_DATAFLASH)+= at91_dataflash.o
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/devices/at91_dataflash.c linux-2.6.19/drivers/mtd/devices/at91_dataflash.c
---- linux-2.6.19-final/drivers/mtd/devices/at91_dataflash.c Thu Jan 1 02:00:00 1970
-+++ linux-2.6.19/drivers/mtd/devices/at91_dataflash.c Mon Dec 4 16:12:44 2006
-@@ -0,0 +1,640 @@
-+/*
-+ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
-+ *
-+ * Copyright (C) SAN People (Pty) Ltd
-+ *
-+ * 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/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/arch/spi.h>
-+
-+#undef DEBUG_DATAFLASH
-+
-+#define DATAFLASH_MAX_DEVICES 4 /* max number of dataflash devices */
-+#undef DATAFLASH_ALWAYS_ADD_DEVICE /* always add whole device when using partitions? */
-+
-+#define OP_READ_CONTINUOUS 0xE8
-+#define OP_READ_PAGE 0xD2
-+#define OP_READ_BUFFER1 0xD4
-+#define OP_READ_BUFFER2 0xD6
-+#define OP_READ_STATUS 0xD7
-+
-+#define OP_ERASE_PAGE 0x81
-+#define OP_ERASE_BLOCK 0x50
-+
-+#define OP_TRANSFER_BUF1 0x53
-+#define OP_TRANSFER_BUF2 0x55
-+#define OP_COMPARE_BUF1 0x60
-+#define OP_COMPARE_BUF2 0x61
-+
-+#define OP_PROGRAM_VIA_BUF1 0x82
-+#define OP_PROGRAM_VIA_BUF2 0x85
-+
-+struct dataflash_local
-+{
-+ int spi; /* SPI chip-select number */
-+
-+ unsigned int page_size; /* number of bytes per page */
-+ unsigned short page_offset; /* page offset in flash address */
-+};
-+
-+
-+/* Detected DataFlash devices */
-+static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
-+static int nr_devices = 0;
-+
-+/* ......................................................................... */
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+
-+static struct mtd_partition static_partitions_2M[] =
-+{
-+ {
-+ .name = "bootloader",
-+ .offset = 0,
-+ .size = 1 * 32 * 8 * 528, /* 1st sector = 32 blocks * 8 pages * 528 bytes */
-+ .mask_flags = MTD_WRITEABLE, /* read-only */
-+ },
-+ {
-+ .name = "kernel",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 6 * 32 * 8 * 528, /* 6 sectors */
-+ },
-+ {
-+ .name = "filesystem",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL, /* rest = 9 sectors */
-+ }
-+};
-+
-+static struct mtd_partition static_partitions_4M[] =
-+{
-+ {
-+ .name = "bootloader",
-+ .offset = 0,
-+ .size = 1 * 64 * 8 * 528, /* 1st sector = 64 blocks * 8 pages * 528 bytes */
-+ .mask_flags = MTD_WRITEABLE, /* read-only */
-+ },
-+ {
-+ .name = "kernel",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 4 * 64 * 8 * 528, /* 4 sectors */
-+ },
-+ {
-+ .name = "filesystem",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL, /* rest = 11 sectors */
-+ }
-+};
-+
-+#if defined(CONFIG_MACH_KAFA)
-+static struct mtd_partition static_partitions_8M[] =
-+{
-+ {
-+ name: "romboot",
-+ offset: 0,
-+ size: 16 * 1056, /* 160 Kb */
-+ mask_flags: MTD_WRITEABLE, /* read-only */
-+ },
-+ {
-+ name: "uboot",
-+ offset: MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */
-+ size: 128 * 1056, /* 1 MB */
-+ },
-+ {
-+ name: "kernel",
-+ offset: MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */
-+ size: 1024 * 1056, /* 1 MB */
-+ },
-+ {
-+ name: "filesystem",
-+ offset: MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */
-+ size: MTDPART_SIZ_FULL,
-+ }
-+};
-+
-+#else
-+
-+static struct mtd_partition static_partitions_8M[] =
-+{
-+ {
-+ .name = "bootloader",
-+ .offset = 0,
-+ .size = 1 * 32 * 8 * 1056, /* 1st sector = 32 blocks * 8 pages * 1056 bytes */
-+ .mask_flags = MTD_WRITEABLE, /* read-only */
-+ },
-+ {
-+ .name = "kernel",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = 5 * 32 * 8 * 1056, /* 5 sectors */
-+ },
-+ {
-+ .name = "filesystem",
-+ .offset = MTDPART_OFS_NXTBLK,
-+ .size = MTDPART_SIZ_FULL, /* rest = 26 sectors */
-+ }
-+};
-+#endif
-+
-+static const char *part_probes[] = { "cmdlinepart", NULL, };
-+
-+#endif
-+
-+/* ......................................................................... */
-+
-+/* Allocate a single SPI transfer descriptor. We're assuming that if multiple
-+ SPI transfers occur at the same time, spi_access_bus() will serialize them.
-+ If this is not valid, then either (i) each dataflash 'priv' structure
-+ needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
-+ another mechanism. */
-+static struct spi_transfer_list* spi_transfer_desc;
-+
-+/*
-+ * Perform a SPI transfer to access the DataFlash device.
-+ */
-+static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
-+ char* txnext, int txnext_len, char* rxnext, int rxnext_len)
-+{
-+ struct spi_transfer_list* list = spi_transfer_desc;
-+
-+ list->tx[0] = tx; list->txlen[0] = tx_len;
-+ list->rx[0] = rx; list->rxlen[0] = rx_len;
-+
-+ list->tx[1] = txnext; list->txlen[1] = txnext_len;
-+ list->rx[1] = rxnext; list->rxlen[1] = rxnext_len;
-+
-+ list->nr_transfers = nr;
-+
-+ return spi_transfer(list);
-+}
-+
-+/* ......................................................................... */
-+
-+/*
-+ * Poll the DataFlash device until it is READY.
-+ */
-+static void at91_dataflash_waitready(void)
-+{
-+ char* command = kmalloc(2, GFP_KERNEL);
-+
-+ if (!command)
-+ return;
-+
-+ do {
-+ command[0] = OP_READ_STATUS;
-+ command[1] = 0;
-+
-+ do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
-+ } while ((command[1] & 0x80) == 0);
-+
-+ kfree(command);
-+}
-+
-+/*
-+ * Return the status of the DataFlash device.
-+ */
-+static unsigned short at91_dataflash_status(void)
-+{
-+ unsigned short status;
-+ char* command = kmalloc(2, GFP_KERNEL);
-+
-+ if (!command)
-+ return 0;
-+
-+ command[0] = OP_READ_STATUS;
-+ command[1] = 0;
-+
-+ do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
-+ status = command[1];
-+
-+ kfree(command);
-+ return status;
-+}
-+
-+/* ......................................................................... */
-+
-+/*
-+ * Erase blocks of flash.
-+ */
-+static int at91_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
-+{
-+ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
-+ unsigned int pageaddr;
-+ char* command;
-+
-+#ifdef DEBUG_DATAFLASH
-+ printk("dataflash_erase: addr=%i len=%i\n", instr->addr, instr->len);
-+#endif
-+
-+ /* Sanity checks */
-+ if (instr->addr + instr->len > mtd->size)
-+ return -EINVAL;
-+ if ((instr->len % mtd->erasesize != 0) || (instr->len % priv->page_size != 0))
-+ return -EINVAL;
-+ if ((instr->addr % priv->page_size) != 0)
-+ return -EINVAL;
-+
-+ command = kmalloc(4, GFP_KERNEL);
-+ if (!command)
-+ return -ENOMEM;
-+
-+ while (instr->len > 0) {
-+ /* Calculate flash page address */
-+ pageaddr = (instr->addr / priv->page_size) << priv->page_offset;
-+
-+ command[0] = OP_ERASE_PAGE;
-+ command[1] = (pageaddr & 0x00FF0000) >> 16;
-+ command[2] = (pageaddr & 0x0000FF00) >> 8;
-+ command[3] = 0;
-+#ifdef DEBUG_DATAFLASH
-+ printk("ERASE: (%x) %x %x %x [%i]\n", command[0], command[1], command[2], command[3], pageaddr);
-+#endif
-+
-+ /* Send command to SPI device */
-+ spi_access_bus(priv->spi);
-+ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
-+
-+ at91_dataflash_waitready(); /* poll status until ready */
-+ spi_release_bus(priv->spi);
-+
-+ instr->addr += priv->page_size; /* next page */
-+ instr->len -= priv->page_size;
-+ }
-+
-+ kfree(command);
-+
-+ /* Inform MTD subsystem that erase is complete */
-+ instr->state = MTD_ERASE_DONE;
-+ if (instr->callback)
-+ instr->callback(instr);
-+
-+ return 0;
-+}
-+
-+/*
-+ * Read from the DataFlash device.
-+ * from : Start offset in flash device
-+ * len : Amount to read
-+ * retlen : About of data actually read
-+ * buf : Buffer containing the data
-+ */
-+static int at91_dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-+{
-+ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
-+ unsigned int addr;
-+ char* command;
-+
-+#ifdef DEBUG_DATAFLASH
-+ printk("dataflash_read: %lli .. %lli\n", from, from+len);
-+#endif
-+
-+ *retlen = 0;
-+
-+ /* Sanity checks */
-+ if (!len)
-+ return 0;
-+ if (from + len > mtd->size)
-+ return -EINVAL;
-+
-+ /* Calculate flash page/byte address */
-+ addr = (((unsigned)from / priv->page_size) << priv->page_offset) + ((unsigned)from % priv->page_size);
-+
-+ command = kmalloc(8, GFP_KERNEL);
-+ if (!command)
-+ return -ENOMEM;
-+
-+ command[0] = OP_READ_CONTINUOUS;
-+ command[1] = (addr & 0x00FF0000) >> 16;
-+ command[2] = (addr & 0x0000FF00) >> 8;
-+ command[3] = (addr & 0x000000FF);
-+#ifdef DEBUG_DATAFLASH
-+ printk("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
-+#endif
-+
-+ /* Send command to SPI device */
-+ spi_access_bus(priv->spi);
-+ do_spi_transfer(2, command, 8, command, 8, buf, len, buf, len);
-+ spi_release_bus(priv->spi);
-+
-+ *retlen = len;
-+ kfree(command);
-+ return 0;
-+}
-+
-+/*
-+ * Write to the DataFlash device.
-+ * to : Start offset in flash device
-+ * len : Amount to write
-+ * retlen : Amount of data actually written
-+ * buf : Buffer containing the data
-+ */
-+static int at91_dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
-+{
-+ struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
-+ unsigned int pageaddr, addr, offset, writelen;
-+ size_t remaining;
-+ u_char *writebuf;
-+ unsigned short status;
-+ int res = 0;
-+ char* command;
-+ char* tmpbuf = NULL;
-+
-+#ifdef DEBUG_DATAFLASH
-+ printk("dataflash_write: %lli .. %lli\n", to, to+len);
-+#endif
-+
-+ *retlen = 0;
-+
-+ /* Sanity checks */
-+ if (!len)
-+ return 0;
-+ if (to + len > mtd->size)
-+ return -EINVAL;
-+
-+ command = kmalloc(4, GFP_KERNEL);
-+ if (!command)
-+ return -ENOMEM;
-+
-+ pageaddr = ((unsigned)to / priv->page_size);
-+ offset = ((unsigned)to % priv->page_size);
-+ if (offset + len > priv->page_size)
-+ writelen = priv->page_size - offset;
-+ else
-+ writelen = len;
-+ writebuf = (u_char *)buf;
-+ remaining = len;
-+
-+ /* Allocate temporary buffer */
-+ tmpbuf = kmalloc(priv->page_size, GFP_KERNEL);
-+ if (!tmpbuf) {
-+ kfree(command);
-+ return -ENOMEM;
-+ }
-+
-+ /* Gain access to the SPI bus */
-+ spi_access_bus(priv->spi);
-+
-+ while (remaining > 0) {
-+#ifdef DEBUG_DATAFLASH
-+ printk("write @ %i:%i len=%i\n", pageaddr, offset, writelen);
-+#endif
-+
-+ /* (1) Transfer to Buffer1 */
-+ if (writelen != priv->page_size) {
-+ addr = pageaddr << priv->page_offset;
-+ command[0] = OP_TRANSFER_BUF1;
-+ command[1] = (addr & 0x00FF0000) >> 16;
-+ command[2] = (addr & 0x0000FF00) >> 8;
-+ command[3] = 0;
-+#ifdef DEBUG_DATAFLASH
-+ printk("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
-+#endif
-+ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
-+ at91_dataflash_waitready();
-+ }
-+
-+ /* (2) Program via Buffer1 */
-+ addr = (pageaddr << priv->page_offset) + offset;
-+ command[0] = OP_PROGRAM_VIA_BUF1;
-+ command[1] = (addr & 0x00FF0000) >> 16;
-+ command[2] = (addr & 0x0000FF00) >> 8;
-+ command[3] = (addr & 0x000000FF);
-+#ifdef DEBUG_DATAFLASH
-+ printk("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
-+#endif
-+ do_spi_transfer(2, command, 4, command, 4, writebuf, writelen, tmpbuf, writelen);
-+ at91_dataflash_waitready();
-+
-+ /* (3) Compare to Buffer1 */
-+ addr = pageaddr << priv->page_offset;
-+ command[0] = OP_COMPARE_BUF1;
-+ command[1] = (addr & 0x00FF0000) >> 16;
-+ command[2] = (addr & 0x0000FF00) >> 8;
-+ command[3] = 0;
-+#ifdef DEBUG_DATAFLASH
-+ printk("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
-+#endif
-+ do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
-+ at91_dataflash_waitready();
-+
-+ /* Get result of the compare operation */
-+ status = at91_dataflash_status();
-+ if ((status & 0x40) == 1) {
-+ printk("at91_dataflash: Write error on page %i\n", pageaddr);
-+ remaining = 0;
-+ res = -EIO;
-+ }
-+
-+ remaining = remaining - writelen;
-+ pageaddr++;
-+ offset = 0;
-+ writebuf += writelen;
-+ *retlen += writelen;
-+
-+ if (remaining > priv->page_size)
-+ writelen = priv->page_size;
-+ else
-+ writelen = remaining;
-+ }
-+
-+ /* Release SPI bus */
-+ spi_release_bus(priv->spi);
-+
-+ kfree(tmpbuf);
-+ kfree(command);
-+ return res;
-+}
-+
-+/* ......................................................................... */
-+
-+/*
-+ * Initialize and register DataFlash device with MTD subsystem.
-+ */
-+static int __init add_dataflash(int channel, char *name, int IDsize,
-+ int nr_pages, int pagesize, int pageoffset)
-+{
-+ struct mtd_info *device;
-+ struct dataflash_local *priv;
-+#ifdef CONFIG_MTD_PARTITIONS
-+ struct mtd_partition *mtd_parts = 0;
-+ int mtd_parts_nr = 0;
-+#endif
-+
-+ if (nr_devices >= DATAFLASH_MAX_DEVICES) {
-+ printk(KERN_ERR "at91_dataflash: Too many devices detected\n");
-+ return 0;
-+ }
-+
-+ device = kmalloc(sizeof(struct mtd_info) + strlen(name) + 8, GFP_KERNEL);
-+ if (!device)
-+ return -ENOMEM;
-+ memset(device, 0, sizeof(struct mtd_info));
-+
-+ device->name = (char *)&device[1];
-+ sprintf(device->name, "%s.spi%d", name, channel);
-+ device->size = nr_pages * pagesize;
-+ device->erasesize = pagesize;
-+ device->writesize = pagesize;
-+ device->owner = THIS_MODULE;
-+ device->type = MTD_DATAFLASH;
-+ device->flags = MTD_WRITEABLE;
-+ device->erase = at91_dataflash_erase;
-+ device->read = at91_dataflash_read;
-+ device->write = at91_dataflash_write;
-+
-+ priv = (struct dataflash_local *) kmalloc(sizeof(struct dataflash_local), GFP_KERNEL);
-+ if (!priv) {
-+ kfree(device);
-+ return -ENOMEM;
-+ }
-+ memset(priv, 0, sizeof(struct dataflash_local));
-+
-+ priv->spi = channel;
-+ priv->page_size = pagesize;
-+ priv->page_offset = pageoffset;
-+ device->priv = priv;
-+
-+ mtd_devices[nr_devices] = device;
-+ nr_devices++;
-+ printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, device->size);
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+#ifdef CONFIG_MTD_CMDLINE_PARTS
-+ mtd_parts_nr = parse_mtd_partitions(device, part_probes, &mtd_parts, 0);
-+#endif
-+ if (mtd_parts_nr <= 0) {
-+ switch (IDsize) {
-+ case SZ_2M:
-+ mtd_parts = static_partitions_2M;
-+ mtd_parts_nr = ARRAY_SIZE(static_partitions_2M);
-+ break;
-+ case SZ_4M:
-+ mtd_parts = static_partitions_4M;
-+ mtd_parts_nr = ARRAY_SIZE(static_partitions_4M);
-+ break;
-+ case SZ_8M:
-+ mtd_parts = static_partitions_8M;
-+ mtd_parts_nr = ARRAY_SIZE(static_partitions_8M);
-+ break;
-+ }
-+ }
-+
-+ if (mtd_parts_nr > 0) {
-+#ifdef DATAFLASH_ALWAYS_ADD_DEVICE
-+ add_mtd_device(device);
-+#endif
-+ return add_mtd_partitions(device, mtd_parts, mtd_parts_nr);
-+ }
-+#endif
-+ return add_mtd_device(device); /* add whole device */
-+}
-+
-+/*
-+ * Detect and initialize DataFlash device connected to specified SPI channel.
-+ *
-+ * Device Density ID code Nr Pages Page Size Page offset
-+ * AT45DB011B 1Mbit (128K) xx0011xx (0x0c) 512 264 9
-+ * AT45DB021B 2Mbit (256K) xx0101xx (0x14) 1025 264 9
-+ * AT45DB041B 4Mbit (512K) xx0111xx (0x1c) 2048 264 9
-+ * AT45DB081B 8Mbit (1M) xx1001xx (0x24) 4096 264 9
-+ * AT45DB0161B 16Mbit (2M) xx1011xx (0x2c) 4096 528 10
-+ * AT45DB0321B 32Mbit (4M) xx1101xx (0x34) 8192 528 10
-+ * AT45DB0642 64Mbit (8M) xx1111xx (0x3c) 8192 1056 11
-+ * AT45DB1282 128Mbit (16M) xx0100xx (0x10) 16384 1056 11
-+ */
-+static int __init at91_dataflash_detect(int channel)
-+{
-+ int res = 0;
-+ unsigned short status;
-+
-+ spi_access_bus(channel);
-+ status = at91_dataflash_status();
-+ spi_release_bus(channel);
-+ if (status != 0xff) { /* no dataflash device there */
-+ switch (status & 0x3c) {
-+ case 0x0c: /* 0 0 1 1 */
-+ res = add_dataflash(channel, "AT45DB011B", SZ_128K, 512, 264, 9);
-+ break;
-+ case 0x14: /* 0 1 0 1 */
-+ res = add_dataflash(channel, "AT45DB021B", SZ_256K, 1025, 264, 9);
-+ break;
-+ case 0x1c: /* 0 1 1 1 */
-+ res = add_dataflash(channel, "AT45DB041B", SZ_512K, 2048, 264, 9);
-+ break;
-+ case 0x24: /* 1 0 0 1 */
-+ res = add_dataflash(channel, "AT45DB081B", SZ_1M, 4096, 264, 9);
-+ break;
-+ case 0x2c: /* 1 0 1 1 */
-+ res = add_dataflash(channel, "AT45DB161B", SZ_2M, 4096, 528, 10);
-+ break;
-+ case 0x34: /* 1 1 0 1 */
-+ res = add_dataflash(channel, "AT45DB321B", SZ_4M, 8192, 528, 10);
-+ break;
-+ case 0x3c: /* 1 1 1 1 */
-+ res = add_dataflash(channel, "AT45DB642", SZ_8M, 8192, 1056, 11);
-+ break;
-+// Currently unsupported since Atmel removed the "Main Memory Program via Buffer" commands.
-+// case 0x10: /* 0 1 0 0 */
-+// res = add_dataflash(channel, "AT45DB1282", SZ_16M, 16384, 1056, 11);
-+// break;
-+ default:
-+ printk(KERN_ERR "at91_dataflash: Unknown device (%x)\n", status & 0x3c);
-+ }
-+ }
-+
-+ return res;
-+}
-+
-+static int __init at91_dataflash_init(void)
-+{
-+ spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL);
-+ if (!spi_transfer_desc)
-+ return -ENOMEM;
-+
-+ /* DataFlash (SPI chip select 0) */
-+ at91_dataflash_detect(0);
-+
-+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
-+ /* DataFlash card (SPI chip select 3) */
-+ at91_dataflash_detect(3);
-+#endif
-+
-+ return 0;
-+}
-+
-+static void __exit at91_dataflash_exit(void)
-+{
-+ int i;
-+
-+ for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
-+ if (mtd_devices[i]) {
-+#ifdef CONFIG_MTD_PARTITIONS
-+ del_mtd_partitions(mtd_devices[i]);
-+#else
-+ del_mtd_device(mtd_devices[i]);
-+#endif
-+ kfree(mtd_devices[i]->priv);
-+ kfree(mtd_devices[i]);
-+ }
-+ }
-+ nr_devices = 0;
-+ kfree(spi_transfer_desc);
-+}
-+
-+
-+module_init(at91_dataflash_init);
-+module_exit(at91_dataflash_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Andrew Victor");
-+MODULE_DESCRIPTION("DataFlash driver for Atmel AT91RM9200");
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/devices/mtd_dataflash.c linux-2.6.19/drivers/mtd/devices/mtd_dataflash.c
---- linux-2.6.19-final/drivers/mtd/devices/mtd_dataflash.c Mon Dec 4 16:33:42 2006
-+++ linux-2.6.19/drivers/mtd/devices/mtd_dataflash.c Mon Dec 4 16:12:32 2006
-@@ -480,7 +480,7 @@
- device->writesize = pagesize;
- device->owner = THIS_MODULE;
- device->type = MTD_DATAFLASH;
-- device->flags = MTD_CAP_NORFLASH;
-+ device->flags = MTD_WRITEABLE;
- device->erase = dataflash_erase;
- device->read = dataflash_read;
- device->write = dataflash_write;
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/maps/Kconfig linux-2.6.19/drivers/mtd/maps/Kconfig
---- linux-2.6.19-final/drivers/mtd/maps/Kconfig Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mtd/maps/Kconfig Mon Nov 20 10:49:27 2006
-@@ -622,5 +622,25 @@
-
- This selection automatically selects the map_ram driver.
-
-+config MTD_CSB337
-+ bool "Flash mapped on Cogent CSB337"
-+ depends on MTD && MACH_CSB337
-+ help
-+ This enables access to the flash chip on the Cogent CSB337
-+ single board computer. The default behavior of the startup
-+ script the comes with BSPs for that board is to pass the address
-+ of a file romfs.img, which is assumed to be a romfs filesystem image
-+ to be used as the initial root filesystem.
-+
-+config MTD_CSB637
-+ bool "Flash mapped on Cogent CSB637"
-+ depends on MTD && MACH_CSB637
-+ help
-+ This enables access to the flash chip on the Cogent CSB637
-+ single board computer. The default behavior of the startup
-+ script the comes with BSPs for that board is to pass the address
-+ of a file romfs.img, which is assumed to be a romfs filesystem image
-+ to be used as the initial root filesystem.
-+
- endmenu
-
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/maps/Makefile linux-2.6.19/drivers/mtd/maps/Makefile
---- linux-2.6.19-final/drivers/mtd/maps/Makefile Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mtd/maps/Makefile Mon Nov 20 10:49:37 2006
-@@ -70,3 +70,5 @@
- obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
- obj-$(CONFIG_MTD_MTX1) += mtx-1_flash.o
- obj-$(CONFIG_MTD_TQM834x) += tqm834x.o
-+obj-$(CONFIG_MTD_CSB337) += csbxxx.o
-+obj-$(CONFIG_MTD_CSB637) += csbxxx.o
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/maps/csbxxx.c linux-2.6.19/drivers/mtd/maps/csbxxx.c
---- linux-2.6.19-final/drivers/mtd/maps/csbxxx.c Thu Jan 1 02:00:00 1970
-+++ linux-2.6.19/drivers/mtd/maps/csbxxx.c Tue Oct 24 08:53:30 2006
-@@ -0,0 +1,143 @@
-+/*
-+ * Map driver for the Cogent CSBxxx boards.
-+ *
-+ * Author: Bill Gatliff
-+ * Copyright: (C) 2005 Bill Gatliff <bgat@billgatliff.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/map.h>
-+#include <linux/mtd/partitions.h>
-+#include <asm/io.h>
-+#include <asm/hardware.h>
-+
-+#define MTDID "flash00"
-+#define MSG_PREFIX "csbxxx: "
-+
-+#if defined(CONFIG_MACH_CSB337) || defined(CONFIG_MACH_CSB637)
-+#define WINDOW_ADDR 0x10000000
-+#define WINDOW_SIZE 0x1000000
-+#else
-+#error TODO: the MTD map you need goes here...
-+#endif
-+
-+/*
-+ * default map definition
-+ * (generally overridden on the command line)
-+ */
-+static struct mtd_partition csbxxx_partitions[] = {
-+ {
-+ .name = "uMON flash",
-+ .size = WINDOW_SIZE,
-+ .mask_flags = MTD_WRITEABLE /* force read-only */
-+ },
-+};
-+
-+static void csbxxx_map_inval_cache(struct map_info *map, unsigned long from, ssize_t len)
-+{
-+ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
-+}
-+static struct map_info csbxxx_map = {
-+ .size = WINDOW_SIZE,
-+ .phys = WINDOW_ADDR,
-+ .inval_cache = csbxxx_map_inval_cache,
-+ .bankwidth = 2,
-+ .name = MTDID,
-+};
-+
-+static const char *probes[] = { "cmdlinepart", NULL };
-+
-+static struct mtd_info *mymtd = 0;
-+static int mtd_parts_nb = 0;
-+static struct mtd_partition *mtd_parts = 0;
-+
-+static int __init init_csbxxx(void)
-+{
-+ int ret = 0;
-+ const char *part_type = 0;
-+
-+ csbxxx_map.virt = ioremap(csbxxx_map.phys, WINDOW_SIZE);
-+ if (!csbxxx_map.virt) {
-+ printk(KERN_WARNING "Failed to ioremap %s, MTD disabled\n", csbxxx_map.name);
-+ ret = -ENOMEM;
-+ goto err;
-+ }
-+ csbxxx_map.cached = ioremap_cached(csbxxx_map.phys, WINDOW_SIZE);
-+ if (!csbxxx_map.cached)
-+ printk(KERN_WARNING "Failed to ioremap cached %s\n", csbxxx_map.name);
-+
-+ simple_map_init(&csbxxx_map);
-+
-+ printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit bankwidth)\n",
-+ csbxxx_map.name, csbxxx_map.phys, csbxxx_map.bankwidth * 8);
-+
-+ mymtd = do_map_probe("cfi_probe", &csbxxx_map);
-+ if (!mymtd)
-+ goto err;
-+
-+ mymtd->owner = THIS_MODULE;
-+
-+ mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0);
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (mtd_parts_nb > 0)
-+ part_type = "command line";
-+ else if (mtd_parts_nb == 0) {
-+ mtd_parts = csbxxx_partitions;
-+ mtd_parts_nb = ARRAY_SIZE(csbxxx_partitions);
-+ part_type = "static";
-+ }
-+ else
-+ goto err;
-+
-+ if (mtd_parts_nb == 0)
-+ printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
-+ else {
-+ printk(KERN_NOTICE MSG_PREFIX "using %s partition definition\n", part_type);
-+ add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
-+ }
-+#else
-+ add_mtd_device(mymtd);
-+#endif
-+
-+ return 0;
-+
-+err:
-+ if (csbxxx_map.virt)
-+ iounmap(csbxxx_map.virt);
-+ if (csbxxx_map.cached)
-+ iounmap(csbxxx_map.cached);
-+ if (!ret)
-+ ret = -EIO;
-+
-+ return ret;
-+}
-+
-+static void __exit cleanup_csbxxx(void)
-+{
-+ if (!mymtd)
-+ return;
-+
-+ del_mtd_partitions(mymtd);
-+
-+ map_destroy(mymtd);
-+ iounmap((void *)csbxxx_map.virt);
-+ if (csbxxx_map.cached)
-+ iounmap(csbxxx_map.cached);
-+}
-+
-+module_init(init_csbxxx);
-+module_exit(cleanup_csbxxx);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Bill Gatliff <bgat@billgatliff.com>");
-+MODULE_DESCRIPTION("MTD map driver for Cogent CSBXXX");
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/nand/Kconfig linux-2.6.19/drivers/mtd/nand/Kconfig
---- linux-2.6.19-final/drivers/mtd/nand/Kconfig Mon Dec 4 16:40:13 2006
-+++ linux-2.6.19/drivers/mtd/nand/Kconfig Thu Oct 12 17:07:39 2006
-@@ -232,6 +232,13 @@
-
- If you say "m", the module will be called "cs553x_nand.ko".
-
-+config MTD_NAND_AT91
-+ bool "Support for NAND Flash / SmartMedia on AT91"
-+ depends on MTD_NAND && ARCH_AT91
-+ help
-+ Enables support for NAND Flash / Smart Media Card interface
-+ on Atmel AT91 processors.
-+
- config MTD_NAND_NANDSIM
- tristate "Support for NAND Flash Simulator"
- depends on MTD_NAND && MTD_PARTITIONS
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/nand/Makefile linux-2.6.19/drivers/mtd/nand/Makefile
---- linux-2.6.19-final/drivers/mtd/nand/Makefile Mon Dec 4 16:33:43 2006
-+++ linux-2.6.19/drivers/mtd/nand/Makefile Thu Oct 12 17:07:39 2006
-@@ -22,5 +22,6 @@
- obj-$(CONFIG_MTD_NAND_NANDSIM) += nandsim.o
- obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o
- obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
-+obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
-
- nand-objs = nand_base.o nand_bbt.o
-diff -urN -x CVS linux-2.6.19-final/drivers/mtd/nand/at91_nand.c linux-2.6.19/drivers/mtd/nand/at91_nand.c
---- linux-2.6.19-final/drivers/mtd/nand/at91_nand.c Thu Jan 1 02:00:00 1970
-+++ linux-2.6.19/drivers/mtd/nand/at91_nand.c Wed Nov 15 08:12:22 2006
-@@ -0,0 +1,223 @@
-+/*
-+ * drivers/mtd/nand/at91_nand.c
-+ *
-+ * Copyright (C) 2003 Rick Bronson
-+ *
-+ * Derived from drivers/mtd/nand/autcpu12.c
-+ * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
-+ *
-+ * Derived from drivers/mtd/spia.c
-+ * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ */
-+
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+
-+#include <asm/io.h>
-+#include <asm/sizes.h>
-+
-+#include <asm/hardware.h>
-+#include <asm/arch/board.h>
-+#include <asm/arch/gpio.h>
-+
-+struct at91_nand_host {
-+ struct nand_chip nand_chip;
-+ struct mtd_info mtd;
-+ void __iomem *io_base;
-+ struct at91_nand_data *board;
-+};
-+
-+/*
-+ * Hardware specific access to control-lines
-+ */
-+static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct at91_nand_host *host = nand_chip->priv;
-+
-+ if (cmd == NAND_CMD_NONE)
-+ return;
-+
-+ if (ctrl & NAND_CLE)
-+ writeb(cmd, host->io_base + (1 << host->board->cle));
-+ else
-+ writeb(cmd, host->io_base + (1 << host->board->ale));
-+}
-+
-+/*
-+ * Read the Device Ready pin.
-+ */
-+static int at91_nand_device_ready(struct mtd_info *mtd)
-+{
-+ struct nand_chip *nand_chip = mtd->priv;
-+ struct at91_nand_host *host = nand_chip->priv;
-+
-+ return at91_get_gpio_value(host->board->rdy_pin);
-+}
-+
-+/*
-+ * Enable NAND.
-+ */
-+static void at91_nand_enable(struct at91_nand_host *host)
-+{
-+ if (host->board->enable_pin)
-+ at91_set_gpio_value(host->board->enable_pin, 0);
-+}
-+
-+/*
-+ * Disable NAND.
-+ */
-+static void at91_nand_disable(struct at91_nand_host *host)
-+{
-+ if (host->board->enable_pin)
-+ at91_set_gpio_value(host->board->enable_pin, 1);
-+}
-+
-+/*
-+ * Probe for the NAND device.
-+ */
-+static int __init at91_nand_probe(struct platform_device *pdev)
-+{
-+ struct at91_nand_host *host;
-+ struct mtd_info *mtd;
-+ struct nand_chip *nand_chip;
-+ int res;
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ struct mtd_partition *partitions = NULL;
-+ int num_partitions = 0;
-+#endif
-+
-+ /* Allocate memory for the device structure (and zero it) */
-+ host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL);
-+ if (!host) {
-+ printk(KERN_ERR "at91_nand: failed to allocate device structure.\n");
-+ return -ENOMEM;
-+ }
-+
-+ host->io_base = ioremap(pdev->resource[0].start,
-+ pdev->resource[0].end - pdev->resource[0].start + 1);
-+ if (host->io_base == NULL) {
-+ printk(KERN_ERR "at91_nand: ioremap failed\n");
-+ kfree(host);
-+ return -EIO;
-+ }
-+
-+ mtd = &host->mtd;
-+ nand_chip = &host->nand_chip;
-+ host->board = pdev->dev.platform_data;
-+
-+ nand_chip->priv = host; /* link the private data structures */
-+ mtd->priv = nand_chip;
-+ mtd->owner = THIS_MODULE;
-+
-+ /* Set address of NAND IO lines */
-+ nand_chip->IO_ADDR_R = host->io_base;
-+ nand_chip->IO_ADDR_W = host->io_base;
-+ nand_chip->cmd_ctrl = at91_nand_cmd_ctrl;
-+ nand_chip->dev_ready = at91_nand_device_ready;
-+ nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */
-+ nand_chip->chip_delay = 20; /* 20us command delay time */
-+
-+ if (host->board->bus_width_16) /* 16-bit bus width */
-+ nand_chip->options |= NAND_BUSWIDTH_16;
-+
-+ platform_set_drvdata(pdev, host);
-+ at91_nand_enable(host);
-+
-+ if (host->board->det_pin) {
-+ if (at91_get_gpio_value(host->board->det_pin)) {
-+ printk ("No SmartMedia card inserted.\n");
-+ res = ENXIO;
-+ goto out;
-+ }
-+ }
-+
-+ /* Scan to find existance of the device */
-+ if (nand_scan(mtd, 1)) {
-+ res = -ENXIO;
-+ goto out;
-+ }
-+
-+#ifdef CONFIG_MTD_PARTITIONS
-+ if (host->board->partition_info)
-+ partitions = host->board->partition_info(mtd->size, &num_partitions);
-+
-+ if ((!partitions) || (num_partitions == 0)) {
-+ printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
-+ res = ENXIO;
-+ goto release;
-+ }
-+
-+ res = add_mtd_partitions(mtd, partitions, num_partitions);
-+#else
-+ res = add_mtd_device(mtd);
-+#endif
-+
-+ if (!res)
-+ return res;
-+
-+release:
-+ nand_release(mtd);
-+out:
-+ at91_nand_disable(host);
-+ platform_set_drvdata(pdev, NULL);
-+ iounmap(host->io_base);
-+ kfree(host);
-+ return res;
-+}
-+
-+/*
-+ * Remove a NAND device.
-+ */
-+static int __devexit at91_nand_remove(struct platform_device *pdev)
-+{
-+ struct at91_nand_host *host = platform_get_drvdata(pdev);
-+ struct mtd_info *mtd = &host->mtd;
-+
-+ nand_release(mtd);
-+
-+ at91_nand_disable(host);
-+
-+ iounmap(host->io_base);
-+ kfree(host);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver at91_nand_driver = {
-+ .probe = at91_nand_probe,
-+ .remove = at91_nand_remove,
-+ .driver = {
-+ .name = "at91_nand",
-+ .owner = THIS_MODULE,
-+ },
-+};
-+
-+static int __init at91_nand_init(void)
-+{
-+ return platform_driver_register(&at91_nand_driver);
-+}
-+
-+
-+static void __exit at91_nand_exit(void)
-+{
-+ platform_driver_unregister(&at91_nand_driver);
-+}
-+
-+
-+module_init(at91_nand_init);
-+module_exit(at91_nand_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Rick Bronson");
-+MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200");
-diff -urN -x CVS linux-2.6.19-final/drivers/net/arm/at91_ether.c linux-2.6.19/drivers/net/arm/at91_ether.c
---- linux-2.6.19-final/drivers/net/arm/at91_ether.c Mon Dec 4 16:40:14 2006
-+++ linux-2.6.19/drivers/net/arm/at91_ether.c Thu Nov 23 15:50:12 2006
-@@ -41,9 +41,6 @@
- #define DRV_NAME "at91_ether"
- #define DRV_VERSION "1.0"
-
--static struct net_device *at91_dev;
--
--static struct timer_list check_timer;
- #define LINK_POLL_INTERVAL (HZ)
-
- /* ..................................................................... */
-@@ -252,8 +249,8 @@
- * PHY doesn't have an IRQ pin (RTL8201, DP83847, AC101L),
- * or board does not have it connected.
- */
-- check_timer.expires = jiffies + LINK_POLL_INTERVAL;
-- add_timer(&check_timer);
-+ lp->check_timer.expires = jiffies + LINK_POLL_INTERVAL;
-+ add_timer(&lp->check_timer);
- return;
- }
-
-@@ -300,7 +297,7 @@
-
- irq_number = lp->board_data.phy_irq_pin;
- if (!irq_number) {
-- del_timer_sync(&check_timer);
-+ del_timer_sync(&lp->check_timer);
- return;
- }
-
-@@ -362,13 +359,14 @@
- static void at91ether_check_link(unsigned long dev_id)
- {
- struct net_device *dev = (struct net_device *) dev_id;
-+ struct at91_private *lp = (struct at91_private *) dev->priv;
-
- enable_mdi();
- update_linkspeed(dev, 1);
- disable_mdi();
-
-- check_timer.expires = jiffies + LINK_POLL_INTERVAL;
-- add_timer(&check_timer);
-+ lp->check_timer.expires = jiffies + LINK_POLL_INTERVAL;
-+ add_timer(&lp->check_timer);
- }
-
- /* ......................... ADDRESS MANAGEMENT ........................ */
-@@ -857,14 +855,13 @@
- while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) {
- p_recv = dlist->recv_buf[lp->rxBuffIndex];
- pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff; /* Length of frame including FCS */
-- skb = alloc_skb(pktlen + 2, GFP_ATOMIC);
-+ skb = dev_alloc_skb(pktlen + 2);
- if (skb != NULL) {
- skb_reserve(skb, 2);
- memcpy(skb_put(skb, pktlen), p_recv, pktlen);
-
- skb->dev = dev;
- skb->protocol = eth_type_trans(skb, dev);
-- skb->len = pktlen;
- dev->last_rx = jiffies;
- lp->stats.rx_bytes += pktlen;
- netif_rx(skb);
-@@ -927,27 +924,43 @@
- return IRQ_HANDLED;
- }
-
-+#ifdef CONFIG_NET_POLL_CONTROLLER
-+static void at91ether_poll_controller(struct net_device *dev)
-+{
-+ unsigned long flags;
-+
-+ local_irq_save(flags);
-+ at91ether_interrupt(dev->irq, dev, NULL);
-+ local_irq_restore(flags);
-+}
-+#endif
-+
- /*
- * Initialize the ethernet interface
- */
- static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address,
- struct platform_device *pdev, struct clk *ether_clk)
- {
-- struct at91_eth_data *board_data = pdev->dev.platform_data;
-+ struct eth_platform_data *board_data = pdev->dev.platform_data;
- struct net_device *dev;
- struct at91_private *lp;
- unsigned int val;
-- int res;
--
-- if (at91_dev) /* already initialized */
-- return 0;
-+ struct resource *res;
-+ int ret;
-
- dev = alloc_etherdev(sizeof(struct at91_private));
- if (!dev)
- return -ENOMEM;
-
-- dev->base_addr = AT91_VA_BASE_EMAC;
-- dev->irq = AT91RM9200_ID_EMAC;
-+ /* Get I/O base address and IRQ */
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ if (!res) {
-+ free_netdev(dev);
-+ return -ENODEV;
-+ }
-+ dev->base_addr = res->start;
-+ dev->irq = platform_get_irq(pdev, 0);
-+
- SET_MODULE_OWNER(dev);
-
- /* Install the interrupt handler */
-@@ -979,6 +992,9 @@
- dev->set_mac_address = set_mac_address;
- dev->ethtool_ops = &at91ether_ethtool_ops;
- dev->do_ioctl = at91ether_ioctl;
-+#ifdef CONFIG_NET_POLL_CONTROLLER
-+ dev->poll_controller = at91ether_poll_controller;
-+#endif
-
- SET_NETDEV_DEV(dev, &pdev->dev);
-
-@@ -1017,14 +1033,13 @@
- lp->phy_address = phy_address; /* MDI address of PHY */
-
- /* Register the network interface */
-- res = register_netdev(dev);
-- if (res) {
-+ ret = register_netdev(dev);
-+ if (ret) {
- free_irq(dev->irq, dev);
- free_netdev(dev);
- dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
-- return res;
-+ return ret;
- }
-- at91_dev = dev;
-
- /* Determine current link speed */
- spin_lock_irq(&lp->lock);
-@@ -1036,9 +1051,9 @@
-
- /* If board has no PHY IRQ, use a timer to poll the PHY */
- if (!lp->board_data.phy_irq_pin) {
-- init_timer(&check_timer);
-- check_timer.data = (unsigned long)dev;
-- check_timer.function = at91ether_check_link;
-+ init_timer(&lp->check_timer);
-+ lp->check_timer.data = (unsigned long)dev;
-+ lp->check_timer.function = at91ether_check_link;
- }
-
- /* Display ethernet banner */
-@@ -1115,15 +1130,16 @@
-
- static int __devexit at91ether_remove(struct platform_device *pdev)
- {
-- struct at91_private *lp = (struct at91_private *) at91_dev->priv;
-+ struct net_device *dev = platform_get_drvdata(pdev);
-+ struct at91_private *lp = (struct at91_private *) dev->priv;
-
-- unregister_netdev(at91_dev);
-- free_irq(at91_dev->irq, at91_dev);
-+ unregister_netdev(dev);
-+ free_irq(dev->irq, dev);
- dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
- clk_put(lp->ether_clk);
-
-- free_netdev(at91_dev);
-- at91_dev = NULL;
-+ platform_set_drvdata(pdev, NULL);
-+ free_netdev(dev);
- return 0;
- }
-
-@@ -1131,8 +1147,8 @@
-
- static int at91ether_suspend(struct platform_device *pdev, pm_message_t mesg)
- {
-- struct at91_private *lp = (struct at91_private *) at91_dev->priv;
- struct net_device *net_dev = platform_get_drvdata(pdev);
-+ struct at91_private *lp = (struct at91_private *) net_dev->priv;
- int phy_irq = lp->board_data.phy_irq_pin;
-
- if (netif_running(net_dev)) {
-@@ -1149,8 +1165,8 @@
-
- static int at91ether_resume(struct platform_device *pdev)
- {
-- struct at91_private *lp = (struct at91_private *) at91_dev->priv;
- struct net_device *net_dev = platform_get_drvdata(pdev);
-+ struct at91_private *lp = (struct at91_private *) net_dev->priv;
- int phy_irq = lp->board_data.phy_irq_pin;
-
- if (netif_running(net_dev)) {
-diff -urN -x CVS linux-2.6.19-final/drivers/net/arm/at91_ether.h linux-2.6.19/drivers/net/arm/at91_ether.h
---- linux-2.6.19-final/drivers/net/arm/at91_ether.h Mon Dec 4 16:33:44 2006
-+++ linux-2.6.19/drivers/net/arm/at91_ether.h Thu Nov 23 15:50:12 2006
-@@ -79,7 +79,7 @@
- {
- struct net_device_stats stats;
- struct mii_if_info mii; /* ethtool support */
-- struct at91_eth_data board_data; /* board-specific configuration */
-+ struct eth_platform_data board_data; /* board-specific configuration */
- struct clk *ether_clk; /* clock */
-
- /* PHY */
-@@ -87,6 +87,7 @@
- spinlock_t lock; /* lock for MDI interface */
- short phy_media; /* media interface type */
- unsigned short phy_address; /* 5-bit MDI address of PHY (0..31) */
-+ struct timer_list check_timer; /* Poll link status */
-
- /* Transmit */
- struct sk_buff *skb; /* holds skb until xmit interrupt completes */
-diff -urN -x CVS linux-2.6.19-final/drivers/pcmcia/at91_cf.c linux-2.6.19/drivers/pcmcia/at91_cf.c
---- linux-2.6.19-final/drivers/pcmcia/at91_cf.c Mon Dec 4 16:40:25 2006
-+++ linux-2.6.19/drivers/pcmcia/at91_cf.c Thu Nov 16 17:27:11 2006
-@@ -23,19 +23,20 @@
- #include <asm/io.h>
- #include <asm/sizes.h>
-
--#include <asm/arch/at91rm9200.h>
- #include <asm/arch/board.h>
- #include <asm/arch/gpio.h>
-+#include <asm/arch/at91rm9200_mc.h>
-
-
- /*
- * A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW;
- * some other bit in {A24,A22..A11} is nREG to flag memory access
- * (vs attributes). So more than 2KB/region would just be waste.
-+ * Note: These are offsets from the physical base address.
- */
--#define CF_ATTR_PHYS (AT91_CF_BASE)
--#define CF_IO_PHYS (AT91_CF_BASE + (1 << 23))
--#define CF_MEM_PHYS (AT91_CF_BASE + 0x017ff800)
-+#define CF_ATTR_PHYS (0)
-+#define CF_IO_PHYS (1 << 23)
-+#define CF_MEM_PHYS (0x017ff800)
-
- /*--------------------------------------------------------------------------*/
-
-@@ -48,6 +49,8 @@
-
- struct platform_device *pdev;
- struct at91_cf_data *board;
-+
-+ unsigned long phys_baseaddr;
- };
-
- #define SZ_2K (2 * SZ_1K)
-@@ -154,9 +157,8 @@
-
- /*
- * Use 16 bit accesses unless/until we need 8-bit i/o space.
-- * Always set CSR4 ... PCMCIA won't always unmap things.
- */
-- csr = at91_sys_read(AT91_SMC_CSR(4)) & ~AT91_SMC_DBW;
-+ csr = at91_sys_read(AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
-
- /*
- * NOTE: this CF controller ignores IOIS16, so we can't really do
-@@ -168,14 +170,14 @@
- * some cards only like that way to get at the odd byte, despite
- * CF 3.0 spec table 35 also giving the D8-D15 option.
- */
-- if (!(io->flags & (MAP_16BIT|MAP_AUTOSZ))) {
-+ if (!(io->flags & (MAP_16BIT | MAP_AUTOSZ))) {
- csr |= AT91_SMC_DBW_8;
- pr_debug("%s: 8bit i/o bus\n", driver_name);
- } else {
- csr |= AT91_SMC_DBW_16;
- pr_debug("%s: 16bit i/o bus\n", driver_name);
- }
-- at91_sys_write(AT91_SMC_CSR(4), csr);
-+ at91_sys_write(AT91_SMC_CSR(cf->board->chipselect), csr);
-
- io->start = cf->socket.io_offset;
- io->stop = io->start + SZ_2K - 1;
-@@ -194,11 +196,11 @@
-
- cf = container_of(s, struct at91_cf_socket, socket);
-
-- map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT;
-+ map->flags &= (MAP_ACTIVE | MAP_ATTRIB | MAP_16BIT);
- if (map->flags & MAP_ATTRIB)
-- map->static_start = CF_ATTR_PHYS;
-+ map->static_start = cf->phys_baseaddr + CF_ATTR_PHYS;
- else
-- map->static_start = CF_MEM_PHYS;
-+ map->static_start = cf->phys_baseaddr + CF_MEM_PHYS;
-
- return 0;
- }
-@@ -219,7 +221,6 @@
- struct at91_cf_socket *cf;
- struct at91_cf_data *board = pdev->dev.platform_data;
- struct resource *io;
-- unsigned int csa;
- int status;
-
- if (!board || !board->det_pin || !board->rst_pin)
-@@ -235,33 +236,11 @@
-
- cf->board = board;
- cf->pdev = pdev;
-+ cf->phys_baseaddr = io->start;
- platform_set_drvdata(pdev, cf);
-
-- /* CF takes over CS4, CS5, CS6 */
-- csa = at91_sys_read(AT91_EBI_CSA);
-- at91_sys_write(AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
--
-- /* nWAIT is _not_ a default setting */
-- (void) at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
--
-- /*
-- * Static memory controller timing adjustments.
-- * REVISIT: these timings are in terms of MCK cycles, so
-- * when MCK changes (cpufreq etc) so must these values...
-- */
-- at91_sys_write(AT91_SMC_CSR(4),
-- AT91_SMC_ACSS_STD
-- | AT91_SMC_DBW_16
-- | AT91_SMC_BAT
-- | AT91_SMC_WSEN
-- | AT91_SMC_NWS_(32) /* wait states */
-- | AT91_SMC_RWSETUP_(6) /* setup time */
-- | AT91_SMC_RWHOLD_(4) /* hold time */
-- );
--
- /* must be a GPIO; ergo must trigger on both edges */
-- status = request_irq(board->det_pin, at91_cf_irq,
-- IRQF_SAMPLE_RANDOM, driver_name, cf);
-+ status = request_irq(board->det_pin, at91_cf_irq, 0, driver_name, cf);
- if (status < 0)
- goto fail0;
- device_init_wakeup(&pdev->dev, 1);
-@@ -282,14 +261,18 @@
- cf->socket.pci_irq = NR_IRQS + 1;
-
- /* pcmcia layer only remaps "real" memory not iospace */
-- cf->socket.io_offset = (unsigned long) ioremap(CF_IO_PHYS, SZ_2K);
-- if (!cf->socket.io_offset)
-+ cf->socket.io_offset = (unsigned long) ioremap(cf->phys_baseaddr + CF_IO_PHYS, SZ_2K);
-+ if (!cf->socket.io_offset) {
-+ status = -ENXIO;
- goto fail1;
-+ }
-
-- /* reserve CS4, CS5, and CS6 regions; but use just CS4 */
-+ /* reserve chip-select regions */
- if (!request_mem_region(io->start, io->end + 1 - io->start,
-- driver_name))
-+ driver_name)) {
-+ status = -ENXIO;
- goto fail1;
-+ }
-
- pr_info("%s: irqs det #%d, io #%d\n", driver_name,
- board->det_pin, board->irq_pin);
-@@ -319,9 +302,7 @@
- fail0a:
- device_init_wakeup(&pdev->dev, 0);
- free_irq(board->det_pin, cf);
-- device_init_wakeup(&pdev->dev, 0);
- fail0:
-- at91_sys_write(AT91_EBI_CSA, csa);
- kfree(cf);
- return status;
- }
-@@ -331,19 +312,15 @@
- struct at91_cf_socket *cf = platform_get_drvdata(pdev);
- struct at91_cf_data *board = cf->board;
- struct resource *io = cf->socket.io[0].res;
-- unsigned int csa;
-
- pcmcia_unregister_socket(&cf->socket);
- if (board->irq_pin)
- free_irq(board->irq_pin, cf);
-- free_irq(board->det_pin, cf);
- device_init_wakeup(&pdev->dev, 0);
-+ free_irq(board->det_pin, cf);
- iounmap((void __iomem *) cf->socket.io_offset);
- release_mem_region(io->start, io->end + 1 - io->start);
-
-- csa = at91_sys_read(AT91_EBI_CSA);
-- at91_sys_write(AT91_EBI_CSA, csa & ~AT91_EBI_CS4A);
--
- kfree(cf);
- return 0;
- }
-diff -urN -x CVS linux-2.6.19-final/drivers/rtc/Kconfig linux-2.6.19/drivers/rtc/Kconfig
---- linux-2.6.19-final/drivers/rtc/Kconfig Mon Dec 4 16:40:27 2006
-+++ linux-2.6.19/drivers/rtc/Kconfig Thu Oct 12 17:07:39 2006
-@@ -280,7 +280,7 @@
- To compile this driver as a module, choose M here: the
- module will be called rtc-pl031.
-
--config RTC_DRV_AT91
-+config RTC_DRV_AT91RM9200
- tristate "AT91RM9200"
- depends on RTC_CLASS && ARCH_AT91RM9200
- help
-diff -urN -x CVS linux-2.6.19-final/drivers/rtc/Makefile linux-2.6.19/drivers/rtc/Makefile
---- linux-2.6.19-final/drivers/rtc/Makefile Mon Dec 4 16:40:27 2006
-+++ linux-2.6.19/drivers/rtc/Makefile Fri Oct 13 10:49:07 2006
-@@ -34,5 +34,5 @@
- obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
- obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
- obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
--obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o
-+obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
- obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
-diff -urN -x CVS linux-2.6.19-final/drivers/rtc/rtc-at91.c linux-2.6.19/drivers/rtc/rtc-at91.c
---- linux-2.6.19-final/drivers/rtc/rtc-at91.c Mon Dec 4 16:40:27 2006
-+++ linux-2.6.19/drivers/rtc/rtc-at91.c Thu Jan 1 02:00:00 1970
-@@ -1,429 +0,0 @@
--/*
-- * Real Time Clock interface for Linux on Atmel AT91RM9200
-- *
-- * Copyright (C) 2002 Rick Bronson
-- *
-- * Converted to RTC class model by Andrew Victor
-- *
-- * Ported to Linux 2.6 by Steven Scholz
-- * Based on s3c2410-rtc.c Simtec Electronics
-- *
-- * Based on sa1100-rtc.c by Nils Faerber
-- * Based on rtc.c by Paul Gortmaker
-- *
-- * 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/module.h>
--#include <linux/kernel.h>
--#include <linux/platform_device.h>
--#include <linux/time.h>
--#include <linux/rtc.h>
--#include <linux/bcd.h>
--#include <linux/interrupt.h>
--#include <linux/ioctl.h>
--#include <linux/completion.h>
--
--#include <asm/uaccess.h>
--#include <asm/rtc.h>
--
--#include <asm/mach/time.h>
--
--
--#define AT91_RTC_FREQ 1
--#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
--
--static DECLARE_COMPLETION(at91_rtc_updated);
--static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
--
--/*
-- * Decode time/date into rtc_time structure
-- */
--static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
-- struct rtc_time *tm)
--{
-- unsigned int time, date;
--
-- /* must read twice in case it changes */
-- do {
-- time = at91_sys_read(timereg);
-- date = at91_sys_read(calreg);
-- } while ((time != at91_sys_read(timereg)) ||
-- (date != at91_sys_read(calreg)));
--
-- tm->tm_sec = BCD2BIN((time & AT91_RTC_SEC) >> 0);
-- tm->tm_min = BCD2BIN((time & AT91_RTC_MIN) >> 8);
-- tm->tm_hour = BCD2BIN((time & AT91_RTC_HOUR) >> 16);
--
-- /*
-- * The Calendar Alarm register does not have a field for
-- * the year - so these will return an invalid value. When an
-- * alarm is set, at91_alarm_year wille store the current year.
-- */
-- tm->tm_year = BCD2BIN(date & AT91_RTC_CENT) * 100; /* century */
-- tm->tm_year += BCD2BIN((date & AT91_RTC_YEAR) >> 8); /* year */
--
-- tm->tm_wday = BCD2BIN((date & AT91_RTC_DAY) >> 21) - 1; /* day of the week [0-6], Sunday=0 */
-- tm->tm_mon = BCD2BIN((date & AT91_RTC_MONTH) >> 16) - 1;
-- tm->tm_mday = BCD2BIN((date & AT91_RTC_DATE) >> 24);
--}
--
--/*
-- * Read current time and date in RTC
-- */
--static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
--{
-- at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, tm);
-- tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
-- tm->tm_year = tm->tm_year - 1900;
--
-- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
-- tm->tm_hour, tm->tm_min, tm->tm_sec);
--
-- return 0;
--}
--
--/*
-- * Set current time and date in RTC
-- */
--static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
--{
-- unsigned long cr;
--
-- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
-- tm->tm_hour, tm->tm_min, tm->tm_sec);
--
-- /* Stop Time/Calendar from counting */
-- cr = at91_sys_read(AT91_RTC_CR);
-- at91_sys_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
--
-- at91_sys_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
-- wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
-- at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
--
-- at91_sys_write(AT91_RTC_TIMR,
-- BIN2BCD(tm->tm_sec) << 0
-- | BIN2BCD(tm->tm_min) << 8
-- | BIN2BCD(tm->tm_hour) << 16);
--
-- at91_sys_write(AT91_RTC_CALR,
-- BIN2BCD((tm->tm_year + 1900) / 100) /* century */
-- | BIN2BCD(tm->tm_year % 100) << 8 /* year */
-- | BIN2BCD(tm->tm_mon + 1) << 16 /* tm_mon starts at zero */
-- | BIN2BCD(tm->tm_wday + 1) << 21 /* day of the week [0-6], Sunday=0 */
-- | BIN2BCD(tm->tm_mday) << 24);
--
-- /* Restart Time/Calendar */
-- cr = at91_sys_read(AT91_RTC_CR);
-- at91_sys_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
--
-- return 0;
--}
--
--/*
-- * Read alarm time and date in RTC
-- */
--static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
--{
-- struct rtc_time *tm = &alrm->time;
--
-- at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
-- tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
-- tm->tm_year = at91_alarm_year - 1900;
--
-- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
-- tm->tm_hour, tm->tm_min, tm->tm_sec);
--
-- return 0;
--}
--
--/*
-- * Set alarm time and date in RTC
-- */
--static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
--{
-- struct rtc_time tm;
--
-- at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
--
-- at91_alarm_year = tm.tm_year;
--
-- tm.tm_hour = alrm->time.tm_hour;
-- tm.tm_min = alrm->time.tm_min;
-- tm.tm_sec = alrm->time.tm_sec;
--
-- at91_sys_write(AT91_RTC_TIMALR,
-- BIN2BCD(tm.tm_sec) << 0
-- | BIN2BCD(tm.tm_min) << 8
-- | BIN2BCD(tm.tm_hour) << 16
-- | AT91_RTC_HOUREN | AT91_RTC_MINEN | AT91_RTC_SECEN);
-- at91_sys_write(AT91_RTC_CALALR,
-- BIN2BCD(tm.tm_mon + 1) << 16 /* tm_mon starts at zero */
-- | BIN2BCD(tm.tm_mday) << 24
-- | AT91_RTC_DATEEN | AT91_RTC_MTHEN);
--
-- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-- at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
-- tm.tm_min, tm.tm_sec);
--
-- return 0;
--}
--
--/*
-- * Handle commands from user-space
-- */
--static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
-- unsigned long arg)
--{
-- int ret = 0;
--
-- pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
--
-- switch (cmd) {
-- case RTC_AIE_OFF: /* alarm off */
-- at91_sys_write(AT91_RTC_IDR, AT91_RTC_ALARM);
-- break;
-- case RTC_AIE_ON: /* alarm on */
-- at91_sys_write(AT91_RTC_IER, AT91_RTC_ALARM);
-- break;
-- case RTC_UIE_OFF: /* update off */
-- case RTC_PIE_OFF: /* periodic off */
-- at91_sys_write(AT91_RTC_IDR, AT91_RTC_SECEV);
-- break;
-- case RTC_UIE_ON: /* update on */
-- case RTC_PIE_ON: /* periodic on */
-- at91_sys_write(AT91_RTC_IER, AT91_RTC_SECEV);
-- break;
-- case RTC_IRQP_READ: /* read periodic alarm frequency */
-- ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
-- break;
-- case RTC_IRQP_SET: /* set periodic alarm frequency */
-- if (arg != AT91_RTC_FREQ)
-- ret = -EINVAL;
-- break;
-- default:
-- ret = -ENOIOCTLCMD;
-- break;
-- }
--
-- return ret;
--}
--
--/*
-- * Provide additional RTC information in /proc/driver/rtc
-- */
--static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
--{
-- unsigned long imr = at91_sys_read(AT91_RTC_IMR);
--
-- seq_printf(seq, "alarm_IRQ\t: %s\n",
-- (imr & AT91_RTC_ALARM) ? "yes" : "no");
-- seq_printf(seq, "update_IRQ\t: %s\n",
-- (imr & AT91_RTC_ACKUPD) ? "yes" : "no");
-- seq_printf(seq, "periodic_IRQ\t: %s\n",
-- (imr & AT91_RTC_SECEV) ? "yes" : "no");
-- seq_printf(seq, "periodic_freq\t: %ld\n",
-- (unsigned long) AT91_RTC_FREQ);
--
-- return 0;
--}
--
--/*
-- * IRQ handler for the RTC
-- */
--static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
--{
-- struct platform_device *pdev = dev_id;
-- struct rtc_device *rtc = platform_get_drvdata(pdev);
-- unsigned int rtsr;
-- unsigned long events = 0;
--
-- rtsr = at91_sys_read(AT91_RTC_SR) & at91_sys_read(AT91_RTC_IMR);
-- if (rtsr) { /* this interrupt is shared! Is it ours? */
-- if (rtsr & AT91_RTC_ALARM)
-- events |= (RTC_AF | RTC_IRQF);
-- if (rtsr & AT91_RTC_SECEV)
-- events |= (RTC_UF | RTC_IRQF);
-- if (rtsr & AT91_RTC_ACKUPD)
-- complete(&at91_rtc_updated);
--
-- at91_sys_write(AT91_RTC_SCCR, rtsr); /* clear status reg */
--
-- rtc_update_irq(&rtc->class_dev, 1, events);
--
-- pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
-- events >> 8, events & 0x000000FF);
--
-- return IRQ_HANDLED;
-- }
-- return IRQ_NONE; /* not handled */
--}
--
--static const struct rtc_class_ops at91_rtc_ops = {
-- .ioctl = at91_rtc_ioctl,
-- .read_time = at91_rtc_readtime,
-- .set_time = at91_rtc_settime,
-- .read_alarm = at91_rtc_readalarm,
-- .set_alarm = at91_rtc_setalarm,
-- .proc = at91_rtc_proc,
--};
--
--/*
-- * Initialize and install RTC driver
-- */
--static int __init at91_rtc_probe(struct platform_device *pdev)
--{
-- struct rtc_device *rtc;
-- int ret;
--
-- at91_sys_write(AT91_RTC_CR, 0);
-- at91_sys_write(AT91_RTC_MR, 0); /* 24 hour mode */
--
-- /* Disable all interrupts */
-- at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
-- AT91_RTC_SECEV | AT91_RTC_TIMEV |
-- AT91_RTC_CALEV);
--
-- ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
-- IRQF_DISABLED | IRQF_SHARED,
-- "at91_rtc", pdev);
-- if (ret) {
-- printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
-- AT91_ID_SYS);
-- return ret;
-- }
--
-- rtc = rtc_device_register(pdev->name, &pdev->dev,
-- &at91_rtc_ops, THIS_MODULE);
-- if (IS_ERR(rtc)) {
-- free_irq(AT91_ID_SYS, pdev);
-- return PTR_ERR(rtc);
-- }
-- platform_set_drvdata(pdev, rtc);
-- device_init_wakeup(&pdev->dev, 1);
--
-- printk(KERN_INFO "AT91 Real Time Clock driver.\n");
-- return 0;
--}
--
--/*
-- * Disable and remove the RTC driver
-- */
--static int __devexit at91_rtc_remove(struct platform_device *pdev)
--{
-- struct rtc_device *rtc = platform_get_drvdata(pdev);
--
-- /* Disable all interrupts */
-- at91_sys_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
-- AT91_RTC_SECEV | AT91_RTC_TIMEV |
-- AT91_RTC_CALEV);
-- free_irq(AT91_ID_SYS, pdev);
--
-- rtc_device_unregister(rtc);
-- platform_set_drvdata(pdev, NULL);
-- device_init_wakeup(&pdev->dev, 0);
--
-- return 0;
--}
--
--#ifdef CONFIG_PM
--
--/* AT91RM9200 RTC Power management control */
--
--static struct timespec at91_rtc_delta;
--static u32 at91_rtc_imr;
--
--static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
--{
-- struct rtc_time tm;
-- struct timespec time;
--
-- time.tv_nsec = 0;
--
-- /* calculate time delta for suspend */
-- at91_rtc_readtime(&pdev->dev, &tm);
-- rtc_tm_to_time(&tm, &time.tv_sec);
-- save_time_delta(&at91_rtc_delta, &time);
--
-- /* this IRQ is shared with DBGU and other hardware which isn't
-- * necessarily doing PM like we are...
-- */
-- at91_rtc_imr = at91_sys_read(AT91_RTC_IMR)
-- & (AT91_RTC_ALARM|AT91_RTC_SECEV);
-- if (at91_rtc_imr) {
-- if (device_may_wakeup(&pdev->dev))
-- enable_irq_wake(AT91_ID_SYS);
-- else
-- at91_sys_write(AT91_RTC_IDR, at91_rtc_imr);
-- }
--
-- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-- 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
-- tm.tm_hour, tm.tm_min, tm.tm_sec);
--
-- return 0;
--}
--
--static int at91_rtc_resume(struct platform_device *pdev)
--{
-- struct rtc_time tm;
-- struct timespec time;
--
-- time.tv_nsec = 0;
--
-- at91_rtc_readtime(&pdev->dev, &tm);
-- rtc_tm_to_time(&tm, &time.tv_sec);
-- restore_time_delta(&at91_rtc_delta, &time);
--
-- if (at91_rtc_imr) {
-- if (device_may_wakeup(&pdev->dev))
-- disable_irq_wake(AT91_ID_SYS);
-- else
-- at91_sys_write(AT91_RTC_IER, at91_rtc_imr);
-- }
--
-- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-- 1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
-- tm.tm_hour, tm.tm_min, tm.tm_sec);
--
-- return 0;
--}
--#else
--#define at91_rtc_suspend NULL
--#define at91_rtc_resume NULL
--#endif
--
--static struct platform_driver at91_rtc_driver = {
-- .probe = at91_rtc_probe,
-- .remove = at91_rtc_remove,
-- .suspend = at91_rtc_suspend,
-- .resume = at91_rtc_resume,
-- .driver = {
-- .name = "at91_rtc",
-- .owner = THIS_MODULE,
-- },
--};
--
--static int __init at91_rtc_init(void)
--{
-- return platform_driver_register(&at91_rtc_driver);
--}
--
--static void __exit at91_rtc_exit(void)
--{
-- platform_driver_unregister(&at91_rtc_driver);
--}
--
--module_init(at91_rtc_init);
--module_exit(at91_rtc_exit);
--
--MODULE_AUTHOR("Rick Bronson");
--MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
--MODULE_LICENSE("GPL");
-diff -urN -x CVS linux-2.6.19-final/drivers/rtc/rtc-at91rm9200.c linux-2.6.19/drivers/rtc/rtc-at91rm9200.c
---- linux-2.6.19-final/drivers/rtc/rtc-at91rm9200.c Thu Jan 1 02:00:00 1970
-+++ linux-2.6.19/drivers/rtc/rtc-at91rm9200.c Thu Nov 30 09:08:25 2006
-@@ -0,0 +1,430 @@
-+/*
-+ * Real Time Clock interface for Linux on Atmel AT91RM9200
-+ *
-+ * Copyright (C) 2002 Rick Bronson