diff -urN linux-2.4.26-vrs1.orig/arch/arm/def-configs/csb337 linux-2.4.26-vrs1/arch/arm/def-configs/csb337 --- linux-2.4.26-vrs1.orig/arch/arm/def-configs/csb337 Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/arch/arm/def-configs/csb337 Mon Apr 26 16:18:22 2004 @@ -246,7 +246,7 @@ # # CONFIG_MTD_PMC551 is not set # CONFIG_MTD_SLRAM is not set -CONFIG_MTD_AT91_DATAFLASH=y +# CONFIG_MTD_AT91_DATAFLASH is not set # CONFIG_MTD_AT91_DATAFLASH_CARD is not set # CONFIG_MTD_MTDRAM is not set # CONFIG_MTD_BLKMTD is not set diff -urN linux-2.4.26-vrs1.orig/arch/arm/kernel/armksyms.c linux-2.4.26-vrs1/arch/arm/kernel/armksyms.c --- linux-2.4.26-vrs1.orig/arch/arm/kernel/armksyms.c Mon Aug 25 13:44:39 2003 +++ linux-2.4.26-vrs1/arch/arm/kernel/armksyms.c Mon May 3 10:45:07 2004 @@ -268,3 +268,7 @@ EXPORT_SYMBOL_NOVERS(__up_wakeup); EXPORT_SYMBOL(get_wchan); + +#ifdef CONFIG_ARCH_AT91RM9200 +EXPORT_SYMBOL(AT91_SYS); +#endif diff -urN linux-2.4.26-vrs1.orig/drivers/Makefile linux-2.4.26-vrs1/drivers/Makefile --- linux-2.4.26-vrs1.orig/drivers/Makefile Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/Makefile Thu Apr 29 18:54:36 2004 @@ -8,7 +8,7 @@ mod-subdirs := dio hil mtd sbus video macintosh usb input telephony ide \ message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ - fc4 net/hamradio i2c l3 acpi bluetooth serial usb/gadget + fc4 net/hamradio i2c l3 acpi bluetooth serial usb/gadget at91 subdir-y := parport serial char block net sound misc media cdrom hotplug pld subdir-m := $(subdir-y) diff -urN linux-2.4.26-vrs1.orig/drivers/at91/Makefile linux-2.4.26-vrs1/drivers/at91/Makefile --- linux-2.4.26-vrs1.orig/drivers/at91/Makefile Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/Makefile Mon Apr 26 21:41:19 2004 @@ -7,7 +7,7 @@ O_TARGET := at91drv.o -subdir-y := serial net watchdog rtc usb i2c spi mtd +subdir-y := serial net watchdog rtc usb i2c spi mtd pcmcia subdir-m := $(subdir-y) obj-$(CONFIG_SERIAL_AT91) += serial/at91serial.o @@ -19,5 +19,6 @@ obj-$(CONFIG_AT91_SPIDEV) += spi/at91spi.o obj-$(CONFIG_MTD_AT91_DATAFLASH) += spi/at91spi.o mtd/at91mtd.o obj-$(CONFIG_MTD_AT91_SMARTMEDIA) += mtd/at91mtd.o +obj-$(CONFIG_PCMCIA_AT91) += pcmcia/at91pcmcia.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.26-vrs1.orig/drivers/at91/mtd/at91_dataflash.c linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.c --- linux-2.4.26-vrs1.orig/drivers/at91/mtd/at91_dataflash.c Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.c Mon Apr 26 15:45:51 2004 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -68,12 +69,12 @@ 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. */ -struct spi_transfer_list* spi_transfer_desc; +static struct spi_transfer_list* spi_transfer_desc; /* * Perform a SPI transfer to access the DataFlash device. */ -int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len, +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; @@ -94,7 +95,7 @@ /* * Poll the DataFlash device until it is READY. */ -void at91_dataflash_waitready(void) +static void at91_dataflash_waitready(void) { char* command = kmalloc(2, GFP_KERNEL); @@ -114,7 +115,7 @@ /* * Return the status of the DataFlash device. */ -unsigned short at91_dataflash_status(void) +static unsigned short at91_dataflash_status(void) { unsigned short status; char* command = kmalloc(2, GFP_KERNEL); @@ -137,7 +138,7 @@ /* * Erase blocks of flash. */ -int at91_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr) +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; @@ -199,7 +200,7 @@ * retlen : About of data actually read * buf : Buffer containing the data */ -int at91_dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) +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; @@ -249,7 +250,7 @@ * retlen : Amount of data actually written * buf : Buffer containing the data */ -int at91_dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +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; @@ -371,7 +372,7 @@ /* * Initialize and register DataFlash device with MTD subsystem. */ -int add_dataflash(int channel, char *name, int size, int pagesize, int pageoffset) +static int add_dataflash(int channel, char *name, int IDsize, int nr_pages, int pagesize, int pageoffset) { struct mtd_info *device; struct dataflash_local *priv; @@ -390,7 +391,7 @@ memset(device, 0, sizeof(struct mtd_info)); device->name = name; - device->size = size; + device->size = nr_pages * pagesize; device->erasesize = pagesize; device->module = THIS_MODULE; device->type = MTD_NORFLASH; @@ -413,7 +414,7 @@ mtd_devices[nr_devices] = device; nr_devices++; - printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, size); + printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, device->size); #ifdef CONFIG_MTD_PARTITIONS #ifdef CONFIG_MTD_CMDLINE_PARTS @@ -425,16 +426,30 @@ mtd_parts_nr = NB_OF(static_partitions); } - return add_mtd_partitions(device, mtd_parts, mtd_parts_nr); -#else - return add_mtd_device(device); + 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 */ -int at91_dataflash_detect(int channel) +static int at91_dataflash_detect(int channel) { int res = 0; unsigned short status; @@ -443,15 +458,31 @@ status = at91_dataflash_status(); if (status != 0xff) { /* no dataflash device there */ switch (status & 0x3c) { + case 0x0c: /* 0 0 1 1 */ + res = add_dataflash(channel, "Atmel AT45DB011B", SZ_128K, 512, 264, 9); + break; + case 0x14: /* 0 1 0 1 */ + res = add_dataflash(channel, "Atmel AT45DB021B", SZ_256K, 1025, 264, 9); + break; + case 0x1c: /* 0 1 1 1 */ + res = add_dataflash(channel, "Atmel AT45DB041B", SZ_512K, 2048, 264, 9); + break; + case 0x24: /* 1 0 0 1 */ + res = add_dataflash(channel, "Atmel AT45DB081B", SZ_1M, 4096, 264, 9); + break; case 0x2c: /* 1 0 1 1 */ - res = add_dataflash(channel, "Atmel AT45DB161B", 4096*528, 528, 10); + res = add_dataflash(channel, "Atmel AT45DB161B", SZ_2M, 4096, 528, 10); break; case 0x34: /* 1 1 0 1 */ - res = add_dataflash(channel, "Atmel AT45DB321B", 8192*528, 528, 10); + res = add_dataflash(channel, "Atmel AT45DB321B", SZ_4M, 8192, 528, 10); break; case 0x3c: /* 1 1 1 1 */ - res = add_dataflash(channel, "Atmel AT45DB642", 8192*1056, 1056, 11); + res = add_dataflash(channel, "Atmel 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, "Atmel AT45DB1282", SZ_16M, 16384, 1056, 11); +// break; default: printk(KERN_ERR "at91_dataflash: Unknown device (%x)\n", status & 0x3c); } @@ -461,7 +492,7 @@ return res; } -int __init at91_dataflash_init(void) +static int __init at91_dataflash_init(void) { spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL); if (!spi_transfer_desc) @@ -479,7 +510,7 @@ return 0; } -void __exit at91_dataflash_exit(void) +static void __exit at91_dataflash_exit(void) { int i; diff -urN linux-2.4.26-vrs1.orig/drivers/at91/mtd/at91_dataflash.h linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.h --- linux-2.4.26-vrs1.orig/drivers/at91/mtd/at91_dataflash.h Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/mtd/at91_dataflash.h Mon Apr 26 15:45:51 2004 @@ -13,6 +13,7 @@ #define AT91_DATAFLASH_H #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 diff -urN linux-2.4.26-vrs1.orig/drivers/at91/net/at91_ether.c linux-2.4.26-vrs1/drivers/at91/net/at91_ether.c --- linux-2.4.26-vrs1.orig/drivers/at91/net/at91_ether.c Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/net/at91_ether.c Sun May 2 20:53:52 2004 @@ -273,12 +273,21 @@ /* Check if bootloader set address in Specific-Address 1 */ hi = regs->EMAC_SA1H; lo = regs->EMAC_SA1L; +#ifdef CONFIG_MACH_CSB337 + addr[5] = (lo & 0xff); /* The CSB337 bootloader stores the MAC the wrong-way around */ + addr[4] = (lo & 0xff00) >> 8; + addr[3] = (lo & 0xff0000) >> 16; + addr[2] = (lo & 0xff000000) >> 24; + addr[1] = (hi & 0xff); + addr[0] = (hi & 0xff00) >> 8; +#else addr[0] = (lo & 0xff); addr[1] = (lo & 0xff00) >> 8; addr[2] = (lo & 0xff0000) >> 16; addr[3] = (lo & 0xff000000) >> 24; addr[4] = (hi & 0xff); addr[5] = (hi & 0xff00) >> 8; +#endif if (is_valid_ether_addr(addr)) { memcpy(dev->dev_addr, &addr, 6); @@ -288,12 +297,21 @@ /* Check if bootloader set address in Specific-Address 2 */ hi = regs->EMAC_SA2H; lo = regs->EMAC_SA2L; +#ifdef CONFIG_MACH_CSB337 + addr[5] = (lo & 0xff); /* The CSB337 bootloader stores the MAC the wrong-way around */ + addr[4] = (lo & 0xff00) >> 8; + addr[3] = (lo & 0xff0000) >> 16; + addr[2] = (lo & 0xff000000) >> 24; + addr[1] = (hi & 0xff); + addr[0] = (hi & 0xff00) >> 8; +#else addr[0] = (lo & 0xff); addr[1] = (lo & 0xff00) >> 8; addr[2] = (lo & 0xff0000) >> 16; addr[3] = (lo & 0xff000000) >> 24; addr[4] = (hi & 0xff); addr[5] = (hi & 0xff00) >> 8; +#endif if (is_valid_ether_addr(addr)) { memcpy(dev->dev_addr, &addr, 6); @@ -310,9 +328,11 @@ regs->EMAC_SA1L = (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0]); regs->EMAC_SA1H = (dev->dev_addr[5] << 8) | (dev->dev_addr[4]); + + regs->EMAC_SA2L = 0; + regs->EMAC_SA2H = 0; } -#ifdef AT91_ETHER_ADDR_CONFIGURABLE /* * Store the new hardware address in dev->dev_addr, and update the MAC. */ @@ -332,7 +352,6 @@ return 0; } -#endif /* * Add multicast addresses to the internal multicast-hash table. @@ -518,6 +537,9 @@ AT91_SYS->PMC_PCER = 1 << AT91C_ID_EMAC; /* Re-enable Peripheral clock */ regs->EMAC_CTL |= AT91C_EMAC_CSR; /* Clear internal statistics */ + + /* Update the MAC address (incase user has changed it) */ + update_mac_address(dev); /* Enable PHY interrupt */ enable_phyirq(dev, regs); @@ -757,10 +779,7 @@ dev->get_stats = at91ether_stats; dev->set_multicast_list = at91ether_set_rx_mode; dev->do_ioctl = at91ether_ioctl; - -#ifdef AT91_ETHER_ADDR_CONFIGURABLE dev->set_mac_address = set_mac_address; -#endif get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */ update_mac_address(dev); /* Program ethernet address into MAC */ diff -urN linux-2.4.26-vrs1.orig/drivers/at91/net/at91_ether.h linux-2.4.26-vrs1/drivers/at91/net/at91_ether.h --- linux-2.4.26-vrs1.orig/drivers/at91/net/at91_ether.h Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/net/at91_ether.h Mon Apr 26 18:44:49 2004 @@ -15,8 +15,6 @@ #ifndef AT91_ETHERNET #define AT91_ETHERNET -#undef AT91_ETHER_ADDR_CONFIGURABLE /* MAC address can be changed? */ - /* Davicom 9161 PHY */ #define MII_DM9161_ID 0x0181b880 diff -urN linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/Makefile linux-2.4.26-vrs1/drivers/at91/pcmcia/Makefile --- linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/Makefile Thu Jan 1 02:00:00 1970 +++ linux-2.4.26-vrs1/drivers/at91/pcmcia/Makefile Mon Apr 26 21:40:27 2004 @@ -0,0 +1,15 @@ +# File: drivers/at91/pcmcia/Makefile +# +# Makefile for the Atmel AT91RM9200 pcmcia (Compact Flash) +# + +O_TARGET := at91pcmcia.o + +obj-y := +obj-m := +obj-n := +obj- := + +obj-$(CONFIG_PCMCIA_AT91) += at91_pcmcia.o at91_lowlevel.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/at91_lowlevel.c linux-2.4.26-vrs1/drivers/at91/pcmcia/at91_lowlevel.c --- linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/at91_lowlevel.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.26-vrs1/drivers/at91/pcmcia/at91_lowlevel.c Mon Apr 26 21:40:27 2004 @@ -0,0 +1,205 @@ +/* + * linux/drivers/at91/pcmcia/at91_lowlevel.c + * + * We implement a AT91RM9200 PCMCIA driver. This + * basically means we handle everything except controlling the + * power. + * + * (c) Rick Bronson + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is John G. Dorsey + * . Portions created by John G. Dorsey are + * Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + */ + +/* + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../../pcmcia/cs_internal.h" + +#include +#include +#include +#include + +#include +#include "at91_pcmcia.h" + +static spinlock_t irq_lock; /* spinlock for saving/restoring interrupt levels */ + +struct irqs at91_pcmcia_irqs[] = { + { AT91C_ID_PIOB, AT91C_CF_PB0_CD1 | AT91C_CF_PB1_CD2 | AT91C_CF_PB2_IOIS16 | AT91C_CF_PB3_STSCHG | AT91C_CF_PB4_RDY, "AT91 PCMCIA IRQ" }, +}; + +static int at91_pcmcia_low_level_init(struct pcmcia_init *init) +{ + int ret = 0; + unsigned long access; + + /* do the formalities */ + AT91_SYS->PIOC_PDR = AT91C_PC6_NWAIT | AT91C_PC7_A23 | AT91C_PC9_A25_CFRNW | + AT91C_PC10_NCS4_CFCS | AT91C_PC11_NCS5_CFCE1 | AT91C_PC12_NCS6_CFCE2; + AT91_SYS->PIOC_ASR = AT91C_PC6_NWAIT | AT91C_PC7_A23 | AT91C_PC9_A25_CFRNW | + AT91C_PC10_NCS4_CFCS | AT91C_PC11_NCS5_CFCE1 | AT91C_PC12_NCS6_CFCE2; /* set up for periph A */ + + AT91_SYS->PIOB_PER = AT91C_CF_PB0_CD1 | AT91C_CF_PB1_CD2 | AT91C_CF_PB2_IOIS16 | AT91C_CF_PB3_STSCHG + | AT91C_CF_PB4_RDY | AT91C_CF_PB5_RESET | AT91C_CF_PB6_ENABLE; /* enable the pio */ + AT91_SYS->PIOB_OER = AT91C_CF_PB5_RESET | AT91C_CF_PB6_ENABLE; /* enable it */ + AT91_SYS->PIOB_CODR = AT91C_CF_PB5_RESET | AT91C_CF_PB6_ENABLE; /* clear it */ + + /* Setup Compact Flash, enable the address range of CS4 */ + AT91_SYS->EBI_CSA |= AT91C_EBI_CS4A_SMC_COMPACTFLASH; + +#define SM_RWH (4 << 28) /* hold time, was 2 */ +#define SM_RWS (6 << 24) /* setup time, was 6 */ +#define SM_TDF (1 << 8) /* data float time, */ +#define SM_NWS (32) /* wait states, NOTE: 0=1.5, 1=2.5, etc */ + + /* debug only */ + access = (AT91_SYS->PIOB_PDSR & AT91C_CF_PB2_IOIS16) ? AT91C_SMC2_DBW_8 : AT91C_SMC2_DBW_16 | AT91C_SMC2_BAT; /* access type (8 or 16-bit) */ + AT91_SYS->EBI_SMC2_CSR[4] = SM_RWH | SM_RWS | AT91C_SMC2_ACSS_STANDARD | + AT91C_SMC2_DBW_16 | AT91C_SMC2_BAT | AT91C_SMC2_WSEN | SM_NWS; + + printk("AT91 CF driver v1.0\n"); + + spin_lock_init(&irq_lock); /* for int's */ + ret = request_irq(at91_pcmcia_irqs[0].irq, init->handler, SA_SHIRQ, + at91_pcmcia_irqs[0].str, at91_pcmcia_irqs); + if (ret) + printk ("AT91 PCMCIA: Can't get interrupt %d\n", at91_pcmcia_irqs[0].irq); + + return ret ? -1 : AT91_PCMCIA_MAX_SOCK; /* return the number of sockets */ +} + +static int at91_pcmcia_shutdown(void) +{ + free_irq(at91_pcmcia_irqs[0].irq, at91_pcmcia_irqs); + return 0; +} + +static int at91_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if (info->sock >= AT91_PCMCIA_MAX_SOCK) + return -1; + info->irq = at91_pcmcia_irqs[0].irq; + return 0; +} + +static int at91_pcmcia_socket_init(int sock) /* enable int's */ +{ + unsigned long temp, flags; + + spin_lock_irqsave(&irq_lock, flags); /* stop int's else we wakeup b4 we sleep */ + AT91_SYS->PIOB_ODR = at91_pcmcia_irqs[0].bits; /* disable output */ + temp = AT91_SYS->PIOB_ISR; /* read to reset int's for this port */ + AT91_SYS->PIOB_IER = at91_pcmcia_irqs[0].bits; /* enable it */ + spin_unlock_irqrestore(&irq_lock, flags); + return 0; +} + +static int at91_pcmcia_socket_suspend(int sock) /* disable int's */ +{ + unsigned long flags; + + spin_lock_irqsave(&irq_lock, flags); /* stop int's else we wakeup b4 we sleep */ + AT91_SYS->PIOB_ODR = at91_pcmcia_irqs[0].bits; /* disable output */ + AT91_SYS->PIOB_IDR = at91_pcmcia_irqs[0].bits; /* disable it */ + spin_unlock_irqrestore(&irq_lock, flags); + return 0; +} + +static int at91_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + memset(state_array->state, 0, (state_array->size)*sizeof(struct pcmcia_state)); + + /* + * This is tricky. The READY pin is also the #IRQ pin. We'll treat + * READY as #IRQ and set state_array->state[0].ready to 1 whenever state_array->state[0].detect + * is true. + */ + + /* + * CD1/2 are active low; so are the VSS pins; Ready is active high + */ + if (!(AT91_SYS->PIOB_PDSR & (AT91C_CF_PB0_CD1 | AT91C_CF_PB1_CD2))) { + state_array->state[0].detect = 1; + state_array->state[0].vs_3v = 1; + } + + if (state_array->state[0].detect) { + state_array->state[0].ready = (AT91_SYS->PIOB_PDSR & AT91C_CF_PB4_RDY) ? 1 : 0; + state_array->state[0].bvd1 = (AT91_SYS->PIOB_PDSR & AT91C_CF_PB3_STSCHG) ? 1 : 0; /* used for STSCHG only */ + state_array->state[0].iois16 = (AT91_SYS->PIOB_PDSR & AT91C_CF_PB2_IOIS16) ? 1 : 0; /* access type (8 or 16-bit) */ + } + return 1; +} + +static int at91_pcmcia_configure_socket(const struct pcmcia_configure *conf) +{ + printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__, + conf->sock, conf->vcc, conf->vpp); /* debug only */ + + if (conf->sock >= AT91_PCMCIA_MAX_SOCK) + return -1; + + if (conf->vpp != 33 && conf->vpp != conf->vcc && conf->vpp != 0) { + printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n", __FUNCTION__, conf->vpp); + return -1; + } + + /* debug only, turn off int's */ + if (conf->reset) + AT91_SYS->PIOB_SODR = AT91C_CF_PB5_RESET; /* set it */ + else + AT91_SYS->PIOB_CODR = AT91C_CF_PB5_RESET; /* clear it */ + + return 0; +} + +struct pcmcia_low_level at91_pcmcia_ops = { + init: at91_pcmcia_low_level_init, + shutdown: at91_pcmcia_shutdown, + socket_state: at91_pcmcia_socket_state, + get_irq_info: at91_pcmcia_get_irq_info, + configure_socket: at91_pcmcia_configure_socket, + + socket_init: at91_pcmcia_socket_init, + socket_suspend: at91_pcmcia_socket_suspend, +}; diff -urN linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/at91_pcmcia.c linux-2.4.26-vrs1/drivers/at91/pcmcia/at91_pcmcia.c --- linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/at91_pcmcia.c Thu Jan 1 02:00:00 1970 +++ linux-2.4.26-vrs1/drivers/at91/pcmcia/at91_pcmcia.c Mon Apr 26 21:40:27 2004 @@ -0,0 +1,886 @@ +/*====================================================================== + + Device driver for the PCMCIA control functionality of Atmel + AT91RM9200 microprocessor. + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is John G. Dorsey + . Portions created by John G. Dorsey are + Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + + This version by Rick Bronson. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ +/* + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "../../pcmcia/cs_internal.h" + +#include +#include +#include +#include + +#include +#include "at91_pcmcia.h" + +#ifdef PCMCIA_DEBUG +int pc_debug = PCMCIA_DEBUG; +#endif + +/* This structure maintains housekeeping state for each socket, such + * as the last known values of the card detect pins, or the Card Services + * callback value associated with the socket: + */ +static int at91_pcmcia_socket_count; +static struct at91_pcmcia_socket at91_pcmcia_socket[AT91_PCMCIA_MAX_SOCK]; + +#define PCMCIA_SOCKET(x) (at91_pcmcia_socket + (x)) + +/* Returned by the low-level PCMCIA interface: */ +static struct pcmcia_low_level *low_level_pcmcia; + +static struct timer_list poll_timer; +static struct tq_struct at91_pcmcia_task; + +/* + * at91_pcmcia_state_to_config + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Convert PCMCIA socket state to our socket configure structure. + */ +static struct pcmcia_configure +at91_pcmcia_state_to_config(unsigned int sock, socket_state_t *state) +{ + struct pcmcia_configure conf; + + conf.sock = sock; + conf.vcc = state->Vcc; + conf.vpp = state->Vpp; + conf.reset = state->flags & SS_RESET ? 1 : 0; + conf.irq = state->io_irq != 0; + + return conf; +} + + +/* at91_pcmcia_init() + * ^^^^^^^^^^^^^^^^^^ + * (Re-)Initialise the socket, turning on status interrupts + * and PCMCIA bus. This must wait for power to stabilise + * so that the card status signals report correctly. + * + * Returns: 0 + */ +static int at91_pcmcia_init(unsigned int sock) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; + + DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); + + skt->cs_state = dead_socket; + + conf = at91_pcmcia_state_to_config(sock, &dead_socket); + + low_level_pcmcia->configure_socket(&conf); + + return low_level_pcmcia->socket_init(sock); +} + + +/* + * at91_pcmcia_suspend() + * ^^^^^^^^^^^^^^^^^^^^^ + * Remove power on the socket, disable IRQs from the card. + * Turn off status interrupts, and disable the PCMCIA bus. + * + * Returns: 0 + */ +static int at91_pcmcia_suspend(unsigned int sock) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; + int ret; + + DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); + + conf = at91_pcmcia_state_to_config(sock, &dead_socket); + + ret = low_level_pcmcia->configure_socket(&conf); + + if (ret == 0) { + skt->cs_state = dead_socket; + ret = low_level_pcmcia->socket_suspend(sock); + } + + return ret; +} + + +/* at91_pcmcia_events() + * ^^^^^^^^^^^^^^^^^^^^ + * Helper routine to generate a Card Services event mask based on + * state information obtained from the kernel low-level PCMCIA layer + * in a recent (and previous) sampling. Updates `prev_state'. + * + * Returns: an event mask for the given socket state. + */ +static inline unsigned int +at91_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, unsigned int flags) +{ + unsigned int events = 0; + + if (state->detect != prev_state->detect) { + DEBUG(3, "%s(): card detect value %u\n", __FUNCTION__, state->detect); + + events |= SS_DETECT; + } + + if (state->ready != prev_state->ready) { + udelay(100); +// DEBUG(3, "%s(): card ready value %u\n", __FUNCTION__, state->ready); + + events |= flags & SS_IOCARD ? 0 : SS_READY; + } + + if (state->bvd1 != prev_state->bvd1) { + DEBUG(3, "%s(): card SS_STSCHG value %u\n", __FUNCTION__, state->bvd1); + + events |= flags & SS_IOCARD ? SS_STSCHG : 0; + } + + *prev_state = *state; + + events &= mask; + +/* DEBUG(2, "events: %s%s%s%s\n", + events == 0 ? "" : "", + events & SS_DETECT ? "DETECT " : "", + events & SS_READY ? "READY " : "", + events & SS_STSCHG ? "STSCHG " : ""); */ + + return events; +} /* at91_pcmcia_events() */ + + +/* at91_pcmcia_task_handler() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Processes serviceable socket events using the "eventd" thread context. + * + * Event processing (specifically, the invocation of the Card Services event + * callback) occurs in this thread rather than in the actual interrupt + * handler due to the use of scheduling operations in the PCMCIA core. + */ +static void at91_pcmcia_task_handler(void *data) +{ + struct pcmcia_state state[AT91_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + unsigned int all_events; + +// DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + + state_array.size = at91_pcmcia_socket_count; + state_array.state = state; + + do { + unsigned int events; + int ret, i; + + memset(state, 0, sizeof(state)); + +// DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); + + ret = low_level_pcmcia->socket_state(&state_array); + if (ret < 0) { + printk(KERN_ERR "at91_pcmcia: unable to read socket status\n"); + break; + } + + all_events = 0; + + for (i = 0; i < state_array.size; i++, all_events |= events) { + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(i); + + events = at91_pcmcia_events(&state[i], &skt->k_state, + skt->cs_state.csc_mask, + skt->cs_state.flags); + + if (events && at91_pcmcia_socket[i].handler != NULL) + skt->handler(skt->handler_info, events); + } + } while(all_events); +} /* at91_pcmcia_task_handler() */ + + +static struct tq_struct at91_pcmcia_task = { + routine: at91_pcmcia_task_handler +}; + + +/* at91_pcmcia_poll_event() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Let's poll for events in addition to IRQs since IRQ only is unreliable... + */ +static void at91_pcmcia_poll_event(unsigned long dummy) +{ +// DEBUG(4, "%s(): polling for events\n", __FUNCTION__); + poll_timer.function = at91_pcmcia_poll_event; + poll_timer.expires = jiffies + AT91_PCMCIA_POLL_PERIOD; + add_timer(&poll_timer); + schedule_task(&at91_pcmcia_task); +} + + +/* at91_pcmcia_interrupt() + * ^^^^^^^^^^^^^^^^^^^^^^^ + * Service routine for socket driver interrupts (requested by the + * low-level PCMCIA init() operation via at91_pcmcia_thread()). + * The actual interrupt-servicing work is performed by + * at91_pcmcia_thread(), largely because the Card Services event- + * handling code performs scheduling operations which cannot be + * executed from within an interrupt context. + */ +static void at91_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) +{ +// AT91PS_PIO p_pio; /* pointer to the port */ +// p_pio = at91_pcmcia_irqs[0].base; /* pointer to the port */ +// if (p_pio->PIO_ISR & p_pio->PIO_IMR & at91_pcmcia_irqs[0].bits) /* debug only */ + { + udelay(100); +// DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); + schedule_task(&at91_pcmcia_task); + } +} + + +/* at91_pcmcia_register_callback() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the register_callback() operation for the in-kernel + * PCMCIA service (formerly SS_RegisterCallback in Card Services). If + * the function pointer `handler' is not NULL, remember the callback + * location in the state for `sock', and increment the usage counter + * for the driver module. (The callback is invoked from the interrupt + * service routine, at91_pcmcia_interrupt(), to notify Card Services + * of interesting events.) Otherwise, clear the callback pointer in the + * socket state and decrement the module usage count. + * + * Returns: 0 + */ +static int +at91_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), + void *info) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + if (handler == NULL) { + skt->handler = NULL; + MOD_DEC_USE_COUNT; + } else { + MOD_INC_USE_COUNT; + skt->handler_info = info; + skt->handler = handler; + } + + return 0; +} + + +/* at91_pcmcia_inquire_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). Of note is + * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of + * `cap' to "trick" Card Services into tolerating large "I/O memory" + * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory + * resource database check. (Mapped memory is set up within the socket + * driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + * + * Return value is irrelevant; the pcmcia subsystem ignores it. + */ +static int +at91_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + if (sock < at91_pcmcia_socket_count) { + cap->features = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD; + cap->irq_mask = 0; + cap->map_size = PAGE_SIZE; + cap->pci_irq = skt->irq; + cap->io_offset = (unsigned long)skt->virt_io; + ret = 0; + } + + return ret; +} + + +/* at91_pcmcia_get_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_status() operation for the in-kernel PCMCIA + * service (formerly SS_GetStatus in Card Services). Essentially just + * fills in bits in `status' according to internal driver state or + * the value of the voltage detect chipselect register. + * + * As a debugging note, during card startup, the PCMCIA core issues + * three set_socket() commands in a row the first with RESET deasserted, + * the second with RESET asserted, and the last with RESET deasserted + * again. Following the third set_socket(), a get_status() command will + * be issued. The kernel is looking for the SS_READY flag (see + * setup_socket(), reset_socket(), and unreset_socket() in cs.c). + * + * Returns: 0 + */ +static int +at91_pcmcia_get_status(unsigned int sock, unsigned int *status) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_state state[AT91_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + unsigned int stat; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + state_array.size = at91_pcmcia_socket_count; + state_array.state = state; + + memset(state, 0, sizeof(state)); + + if ((low_level_pcmcia->socket_state(&state_array)) < 0) { + printk(KERN_ERR "at91_pcmcia: unable to get socket status\n"); + return -1; + } + + skt->k_state = state[sock]; + + stat = state[sock].detect ? SS_DETECT : 0; + stat |= state[sock].ready ? SS_READY : 0; + stat |= state[sock].vs_3v ? SS_3VCARD : 0; + + /* The power status of individual sockets is not available + * explicitly from the hardware, so we just remember the state + * and regurgitate it upon request: + */ + stat |= skt->cs_state.Vcc ? SS_POWERON : 0; + + if (skt->cs_state.flags & SS_IOCARD) + stat |= state[sock].bvd1 ? SS_STSCHG : 0; + + DEBUG(3, "\tstatus: %s%s%s%s%s\n", + stat & SS_DETECT ? "DETECT " : "", + stat & SS_READY ? "READY " : "", + stat & SS_POWERON ? "POWERON " : "", + stat & SS_STSCHG ? "STSCHG " : "", + stat & SS_3VCARD ? "3VCARD " : ""); + + *status = stat; + + return 0; +} /* at91_pcmcia_get_status() */ + + +/* at91_pcmcia_get_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_socket() operation for the in-kernel PCMCIA + * service (formerly SS_GetSocket in Card Services). Not a very + * exciting routine. + * + * Returns: 0 + */ +static int +at91_pcmcia_get_socket(unsigned int sock, socket_state_t *state) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + *state = skt->cs_state; + + return 0; +} + +/* at91_pcmcia_set_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_socket() operation for the in-kernel PCMCIA + * service (formerly SS_SetSocket in Card Services). We more or + * less punt all of this work and let the kernel handle the details + * of power configuration, reset, &c. We also record the value of + * `state' in order to regurgitate it to the PCMCIA core later. + * + * Returns: 0 + */ +static int +at91_pcmcia_set_socket(unsigned int sock, socket_state_t *state) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + struct pcmcia_configure conf; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s\n", + (state->csc_mask==0)?"":"", + (state->csc_mask&SS_DETECT)?"DETECT ":"", + (state->csc_mask&SS_READY)?"READY ":"", + (state->csc_mask&SS_STSCHG)?"STSCHG ":"", + (state->flags==0)?"":"", + (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", + (state->flags&SS_IOCARD)?"IOCARD ":"", + (state->flags&SS_RESET)?"RESET ":"", + (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", + (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); + DEBUG(3, "\tVcc %d Vpp %d irq %d\n", + state->Vcc, state->Vpp, state->io_irq); + + conf = at91_pcmcia_state_to_config(sock, state); + + if (low_level_pcmcia->configure_socket(&conf) < 0) { + printk(KERN_ERR "at91_pcmcia: unable to configure socket %d\n", sock); + return -1; + } + + skt->cs_state = *state; + + return 0; +} /* at91_pcmcia_set_socket() */ + + +/* at91_pcmcia_get_io_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_io_map() operation for the in-kernel PCMCIA + * service (formerly SS_GetIOMap in Card Services). Just returns an + * I/O map descriptor which was assigned earlier by a set_io_map(). + * + * Returns: 0 on success, -1 if the map index was out of range + */ +static int +at91_pcmcia_get_io_map(unsigned int sock, struct pccard_io_map *map) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + if (map->map < MAX_IO_WIN) { + *map = skt->io_map[map->map]; + ret = 0; + } + + return ret; +} + + +/* at91_pcmcia_set_io_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_io_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetIOMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +at91_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + unsigned long start; + + start = map->start; + + if (map->stop == 1) { + map->stop = PAGE_SIZE - 1; + } + + map->start = (int) at91_pcmcia_socket[sock].virt_io; + map->stop = map->start + (map->stop - start); + at91_pcmcia_socket[sock].io_map[map->map] = *map; + return 0; +} /* at91_pcmcia_set_io_map() */ + + +/* at91_pcmcia_get_mem_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_mem_map() operation for the in-kernel PCMCIA + * service (formerly SS_GetMemMap in Card Services). Just returns a + * memory map descriptor which was assigned earlier by a + * set_mem_map() request. + * + * Returns: 0 on success, -1 if the map index was out of range + */ +static int +at91_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + int ret = -1; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + if (map->map < MAX_WIN) { + *map = skt->mem_map[map->map]; + ret = 0; + } + + return ret; +} + + +/* at91_pcmcia_set_mem_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_mem_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetMemMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +at91_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + unsigned long start; + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n", + map->map, map->speed, map->sys_start, map->sys_stop, map->card_start); + DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", + (map->flags==0)?"":"", + (map->flags & MAP_ACTIVE)?"ACTIVE ":"", + (map->flags & MAP_16BIT)?"16BIT ":"", + (map->flags & MAP_AUTOSZ)?"AUTOSZ ":"", + (map->flags & MAP_0WS)?"0WS ":"", + (map->flags & MAP_WRPROT)?"WRPROT ":"", + (map->flags & MAP_ATTRIB)?"ATTRIB ":"", + (map->flags & MAP_USE_WAIT)?"USE_WAIT ":""); + + if (map->map >= MAX_WIN){ + printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, + map->map); + return -1; + } + + start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; + + if (map->sys_stop == 0) + map->sys_stop = PAGE_SIZE - 1; + + map->sys_stop -= map->sys_start; + map->sys_stop += start; + map->sys_start = start; + + skt->mem_map[map->map] = *map; + + return 0; +} /* at91_pcmcia_set_mem_map() */ + + +#if defined(CONFIG_PROC_FS) + +/* at91_pcmcia_proc_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the /proc/bus/pccard/??/status file. + * + * Returns: the number of characters added to the buffer + */ +static int +at91_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + unsigned int sock = (unsigned int)data; + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(sock); + char *p = buf; + + p += sprintf(p, "k_state : %s%s%s%s%s%s\n", + skt->k_state.detect ? "detect " : "", + skt->k_state.ready ? "ready " : "", + skt->k_state.bvd1 ? "bvd1 " : "", + skt->k_state.iois16 ? "iois16 " : "", + skt->k_state.wrprot ? "wrprot " : "", + skt->k_state.vs_3v ? "vs_3v " : ""); + + p += sprintf(p, "status : %s%s%s%s%s%s%s\n", + skt->k_state.detect ? "SS_DETECT " : "", + skt->k_state.ready ? "SS_READY " : "", + skt->cs_state.Vcc ? "SS_POWERON " : "", + skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", + (skt->cs_state.flags & SS_IOCARD && + skt->k_state.bvd1) ? "SS_STSCHG " : "", + skt->k_state.iois16 ? "SS_IOIS16 " : "", + skt->k_state.vs_3v ? "SS_3VCARD " : ""); + + p += sprintf(p, "mask : %s%s%s\n", + skt->cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "", + skt->cs_state.csc_mask & SS_READY ? "SS_READY " : "", + skt->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : ""); + + p += sprintf(p, "cs_flags : %s%s%s%s%s\n", + skt->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO " : "", + skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", + skt->cs_state.flags & SS_RESET ? "SS_RESET " : "", + skt->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA " : "", + skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : ""); + + p += sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); + p += sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); + p += sprintf(p, "IRQ : %d\n", skt->cs_state.io_irq); + + return p-buf; +} + +/* at91_pcmcia_proc_setup() + * ^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the proc_setup() operation for the in-kernel PCMCIA + * service (formerly SS_ProcSetup in Card Services). + * + * Returns: 0 on success, -1 on error + */ +static void +at91_pcmcia_proc_setup(unsigned int sock, struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + + if ((entry = create_proc_entry("status", 0, base)) == NULL){ + printk(KERN_ERR "unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc = at91_pcmcia_proc_status; + entry->data = (void *)sock; +} + +#endif /* defined(CONFIG_PROC_FS) */ + + +static struct pccard_operations at91_pcmcia_operations = { + init: at91_pcmcia_init, + suspend: at91_pcmcia_suspend, + register_callback: at91_pcmcia_register_callback, + inquire_socket: at91_pcmcia_inquire_socket, + get_status: at91_pcmcia_get_status, + get_socket: at91_pcmcia_get_socket, + set_socket: at91_pcmcia_set_socket, + get_io_map: at91_pcmcia_get_io_map, + set_io_map: at91_pcmcia_set_io_map, + get_mem_map: at91_pcmcia_get_mem_map, + set_mem_map: at91_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + proc_setup: at91_pcmcia_proc_setup +#endif +}; + + +static int __init at91_pcmcia_machine_init(void) +{ + low_level_pcmcia = &at91_pcmcia_ops; + + return 0; +} + + +/* at91_pcmcia_driver_init() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * This routine performs a basic sanity check to ensure that this + * kernel has been built with the appropriate board-specific low-level + * PCMCIA support, performs low-level PCMCIA initialization, registers + * this socket driver with Card Services, and then spawns the daemon + * thread which is the real workhorse of the socket driver. + * + * Returns: 0 on success, -1 on error + */ +static int __init at91_pcmcia_driver_init(void) +{ + servinfo_t info; + struct pcmcia_init pcmcia_init; + struct pcmcia_state state[AT91_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + unsigned int i; + int ret; + + CardServices(GetCardServicesInfo, &info); + + if (info.Revision != CS_RELEASE_CODE) { + printk(KERN_ERR "Card Services release codes do not match\n"); + return -EINVAL; + } + + ret = at91_pcmcia_machine_init(); + if (ret) + return ret; + + pcmcia_init.handler = at91_pcmcia_interrupt; + + ret = low_level_pcmcia->init(&pcmcia_init); + if (ret < 0) { + printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); + return ret == -1 ? -EIO : ret; + } + + at91_pcmcia_socket_count = ret; + state_array.size = at91_pcmcia_socket_count; + state_array.state = state; + + memset(state, 0, sizeof(state)); + + if (low_level_pcmcia->socket_state(&state_array) < 0) { + low_level_pcmcia->shutdown(); + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -EIO; + } + + printk(KERN_INFO "AT91 PCMCIA (CS release %s) IO at ", CS_RELEASE); + for (i = 0; i < at91_pcmcia_socket_count; i++) { + struct at91_pcmcia_socket *skt = PCMCIA_SOCKET(i); + struct pcmcia_irq_info irq_info; + + if (!request_mem_region(AT91_PCMCIA_BASE(i), AT91_PCMCIA_INC, "PCMCIA")) { + ret = -EBUSY; + goto out_err; + } + + irq_info.sock = i; + irq_info.irq = -1; + ret = low_level_pcmcia->get_irq_info(&irq_info); + if (ret < 0) + printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret); + + skt->irq = irq_info.irq; + skt->k_state = state[i]; + skt->phys_attr = AT91_PCMCIA_AT_BASE(i); + skt->phys_mem = AT91_PCMCIA_CM_BASE(i); + skt->virt_io = ioremap(AT91_PCMCIA_IO_BASE(i), 0x800); + + if (skt->virt_io == NULL) { + ret = -ENOMEM; + goto out_err; + } + printk(KERN_INFO "0x%x ", (unsigned int) skt->virt_io); + + } + printk(KERN_INFO "\n"); + + /* Only advertise as many sockets as we can detect */ + ret = register_ss_entry(at91_pcmcia_socket_count, + &at91_pcmcia_operations); + if (ret < 0) { + printk(KERN_ERR "Unable to register sockets\n"); + goto out_err; + } + + /* + * Start the event poll timer. It will reschedule by itself afterwards. + */ + at91_pcmcia_poll_event(0); + + return 0; + + out_err: + for (i = 0; i < at91_pcmcia_socket_count; i++) { + iounmap(at91_pcmcia_socket[i].virt_io); + release_mem_region(AT91_PCMCIA_BASE(i), AT91_PCMCIA_INC); + } + + low_level_pcmcia->shutdown(); + + return ret; +} /* at91_pcmcia_driver_init() */ + + +/* at91_pcmcia_driver_shutdown() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Invokes the low-level kernel service to free IRQs associated with this + * socket controller and reset GPIO edge detection. + */ +static void __exit at91_pcmcia_driver_shutdown(void) +{ + int i; + + del_timer_sync(&poll_timer); + + unregister_ss_entry(&at91_pcmcia_operations); + + for (i = 0; i < at91_pcmcia_socket_count; i++) { + iounmap(at91_pcmcia_socket[i].virt_io); + release_mem_region(AT91_PCMCIA_BASE(i), AT91_PCMCIA_INC); + } + + low_level_pcmcia->shutdown(); + + flush_scheduled_tasks(); +} + +MODULE_AUTHOR("Rick Bronson"); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: AT91 Socket Controller"); +MODULE_LICENSE("Dual MPL/GPL"); + +module_init(at91_pcmcia_driver_init); +module_exit(at91_pcmcia_driver_shutdown); diff -urN linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/at91_pcmcia.h linux-2.4.26-vrs1/drivers/at91/pcmcia/at91_pcmcia.h --- linux-2.4.26-vrs1.orig/drivers/at91/pcmcia/at91_pcmcia.h Thu Jan 1 02:00:00 1970 +++ linux-2.4.26-vrs1/drivers/at91/pcmcia/at91_pcmcia.h Mon Apr 26 21:40:27 2004 @@ -0,0 +1,149 @@ +/*====================================================================== + + Device driver for the PCMCIA control functionality of Atmel + AT91RM9200 microprocessor. + + (c) Rick Bronson + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is John G. Dorsey + . Portions created by John G. Dorsey are + Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ +/* + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + */ + +#define AT91C_CF_PB0_CD1 AT91C_PIO_PB0 /* Compact Flash port pin aliases */ +#define AT91C_CF_PB1_CD2 AT91C_PIO_PB1 +#define AT91C_CF_PB2_IOIS16 AT91C_PIO_PB2 /* The access type (8 [high] or 16-bit [low]) + is based on the state of the -IOIS16 signal */ +#define AT91C_CF_PB3_STSCHG AT91C_PIO_PB3 +#define AT91C_CF_PB4_RDY AT91C_PIO_PB4 +#define AT91C_CF_PB5_RESET AT91C_PIO_PB5 +#define AT91C_CF_PB6_ENABLE AT91C_PIO_PB6 + +#define AT91_PCMCIA_INC 0x10000000 /* increment value to go to next PCMCIA BASE */ +#define AT91_PCMCIA_BASE(n) (0x50000000 + (AT91_PCMCIA_INC * n)) +#define AT91_PCMCIA_A23 (1 << 23) /* A23 is just A23 */ +#define AT91_PCMCIA_REG (1 << 22) /* REG is A22 */ +#define AT91_PCMCIA_IO_BASE(n) (AT91_PCMCIA_BASE(n) | AT91_PCMCIA_A23) /* io mode */ +#define AT91_PCMCIA_CM_BASE(n) (AT91_PCMCIA_BASE(n) | AT91_PCMCIA_REG) /* common memory mode */ +#define AT91_PCMCIA_AT_BASE(n) AT91_PCMCIA_BASE(n) /* attribute memory mode */ + +#define AT91_PCMCIA_MAX_SOCK 1 +#define AT91_PCMCIA_POLL_PERIOD 55 /* debug only */ +#define MAX_IO_WIN 2 +#define AT91_PCMCIA_IO_ACCESS (165) /* in ns */ +#define AT91_PCMCIA_3V_MEM_ACCESS (150) /* in ns */ +#define AT91_PCMCIA_5V_MEM_ACCESS (300) /* in ns */ + +struct pcmcia_configure { + unsigned sock: 8, + vcc: 8, + vpp: 8, + reset: 1, + irq: 1; +}; + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, /* used for STSCHG only */ + iois16: 1, /* 8/16 select */ + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +/* + * This structure encapsulates per-socket state which we might need to + * use when responding to a Card Services query of some kind. + */ +struct at91_pcmcia_socket { + /* + * Core PCMCIA state + */ + socket_state_t cs_state; + pccard_io_map io_map[MAX_IO_WIN]; + pccard_mem_map mem_map[MAX_WIN]; + void (*handler)(void *, unsigned int); + void *handler_info; + + struct pcmcia_state k_state; + ioaddr_t phys_attr, phys_mem; + void *virt_io; + + /* + * Info from low level handler + */ + unsigned int irq; +}; + +struct pcmcia_init { + void (*handler)(int irq, void *dev, struct pt_regs *regs); +}; + +struct pcmcia_state_array { + unsigned int size; + struct pcmcia_state *state; +}; + +struct pcmcia_irq_info { + unsigned int sock; + unsigned int irq; +}; + +struct pcmcia_low_level { + int (*init)(struct pcmcia_init *); + int (*shutdown)(void); + int (*socket_state)(struct pcmcia_state_array *); + int (*get_irq_info)(struct pcmcia_irq_info *); + int (*configure_socket)(const struct pcmcia_configure *); + + /* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ + int (*socket_init)(int sock); + + /* + * Disable card status IRQs and PCMCIA bus on suspend. + */ + int (*socket_suspend)(int sock); +}; + +struct irqs { + int irq; +// AT91PS_PIO base; + int bits; + const char *str; +}; + +extern struct irqs at91_pcmcia_irqs[]; + +extern struct pcmcia_low_level at91_pcmcia_ops; + diff -urN linux-2.4.26-vrs1.orig/drivers/at91/serial/at91_serial.c linux-2.4.26-vrs1/drivers/at91/serial/at91_serial.c --- linux-2.4.26-vrs1.orig/drivers/at91/serial/at91_serial.c Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/serial/at91_serial.c Mon Apr 26 16:36:52 2004 @@ -77,11 +77,19 @@ static struct tty_driver normal, callout; static struct tty_struct *at91_table[AT91C_NR_UART]; static struct termios *at91_termios[AT91C_NR_UART], *at91_termios_locked[AT91C_NR_UART]; +static int (*at91_open)(struct uart_port *); +static void (*at91_close)(struct uart_port *); const int at91_serialmap[AT91C_NR_UART] = AT91C_UART_MAP; -static int (*at91_open)(struct uart_port *); -static void (*at91_close)(struct uart_port *); +/* + * We wrap our port structure around the generic uart_port. + */ +struct at91_serial_port { + struct uart_port uart; +}; + +static struct at91_serial_port at91_ports[AT91C_NR_UART]; #ifdef SUPPORT_SYSRQ static struct console at91_console; @@ -90,18 +98,29 @@ /* * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. */ -static u_int at91_tx_empty(struct uart_port *port) +static u_int at91_tx_empty(struct uart_port *uart) { - return UART_GET_CSR(port) & AT91C_US_TXEMPTY ? TIOCSER_TEMT : 0; + return UART_GET_CSR(uart) & AT91C_US_TXEMPTY ? TIOCSER_TEMT : 0; } /* * Set state of the modem control output lines */ -static void at91_set_mctrl(struct uart_port *port, u_int mctrl) +static void at91_set_mctrl(struct uart_port *uart, u_int mctrl) { unsigned int control = 0; + /* + * Errata #39: RTS0 is not internally connected to PA21. We need to drive + * the pin manually. + */ + if (uart->mapbase == AT91C_VA_BASE_US0) { + if (mctrl & TIOCM_RTS) + AT91_SYS->PIOA_CODR = AT91C_PA21_RTS0; + else + AT91_SYS->PIOA_SODR = AT91C_PA21_RTS0; + } + if (mctrl & TIOCM_RTS) control |= AT91C_US_RTSEN; else @@ -112,17 +131,17 @@ else control |= AT91C_US_DTRDIS; - UART_PUT_CR(port,control); + UART_PUT_CR(uart, control); } /* * Get state of the modem control input lines */ -static u_int at91_get_mctrl(struct uart_port *port) +static u_int at91_get_mctrl(struct uart_port *uart) { unsigned int status, ret = 0; - status = UART_GET_CSR(port); + status = UART_GET_CSR(uart); if (status & AT91C_US_DCD) ret |= TIOCM_CD; if (status & AT91C_US_CTS) @@ -138,68 +157,68 @@ /* * Stop transmitting. */ -static void at91_stop_tx(struct uart_port *port, u_int from_tty) +static void at91_stop_tx(struct uart_port *uart, u_int from_tty) { - UART_PUT_IDR(port, AT91C_US_TXRDY); - port->read_status_mask &= ~AT91C_US_TXRDY; + UART_PUT_IDR(uart, AT91C_US_TXRDY); + uart->read_status_mask &= ~AT91C_US_TXRDY; } /* * Start transmitting. */ -static void at91_start_tx(struct uart_port *port, u_int from_tty) +static void at91_start_tx(struct uart_port *uart, u_int from_tty) { unsigned long flags; local_irq_save(flags); - port->read_status_mask |= AT91C_US_TXRDY; - UART_PUT_IER(port, AT91C_US_TXRDY); + uart->read_status_mask |= AT91C_US_TXRDY; + UART_PUT_IER(uart, AT91C_US_TXRDY); local_irq_restore(flags); } /* * Stop receiving - port is in process of being closed. */ -static void at91_stop_rx(struct uart_port *port) +static void at91_stop_rx(struct uart_port *uart) { - UART_PUT_IDR(port, AT91C_US_RXRDY); + UART_PUT_IDR(uart, AT91C_US_RXRDY); } /* * Enable modem status interrupts */ -static void at91_enable_ms(struct uart_port *port) +static void at91_enable_ms(struct uart_port *uart) { - UART_PUT_IER(port, AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC); + UART_PUT_IER(uart, AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC); } /* * Control the transmission of a break signal */ -static void at91_break_ctl(struct uart_port *port, int break_state) +static void at91_break_ctl(struct uart_port *uart, int break_state) { if (break_state != 0) - UART_PUT_CR(port, AT91C_US_STTBRK); /* start break */ + UART_PUT_CR(uart, AT91C_US_STTBRK); /* start break */ else - UART_PUT_CR(port, AT91C_US_STPBRK); /* stop break */ + UART_PUT_CR(uart, AT91C_US_STPBRK); /* stop break */ } /* * Characters received (called from interrupt handler) */ -static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs) +static void at91_rx_chars(struct at91_serial_port *port, struct pt_regs *regs) { - struct uart_info *info = port->info; - struct tty_struct *tty = info->tty; + struct uart_port *uart = &port->uart; + struct tty_struct *tty = uart->info->tty; unsigned int status, ch, flg, ignored = 0; - status = UART_GET_CSR(port); + status = UART_GET_CSR(uart); while (status & (AT91C_US_RXRDY)) { - ch = UART_GET_CHAR(port); + ch = UART_GET_CHAR(uart); if (tty->flip.count >= TTY_FLIPBUF_SIZE) goto ignore_char; - port->icount.rx++; + uart->icount.rx++; flg = TTY_NORMAL; @@ -210,7 +229,7 @@ if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE)) goto handle_error; - if (uart_handle_sysrq_char(port, ch, regs)) + if (uart_handle_sysrq_char(uart, ch, regs)) goto ignore_char; error_return: @@ -218,7 +237,7 @@ *tty->flip.char_buf_ptr++ = ch; tty->flip.count++; ignore_char: - status = UART_GET_CSR(port); + status = UART_GET_CSR(uart); } out: tty_flip_buffer_push(tty); @@ -226,23 +245,23 @@ handle_error: if (status & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE)) - UART_PUT_CR(port, AT91C_US_RSTSTA); /* clear error */ + UART_PUT_CR(uart, AT91C_US_RSTSTA); /* clear error */ if (status & (AT91C_US_PARE)) - port->icount.parity++; + uart->icount.parity++; else if (status & (AT91C_US_FRAME)) - port->icount.frame++; + uart->icount.frame++; if (status & (AT91C_US_OVRE)) - port->icount.overrun++; + uart->icount.overrun++; - if (status & port->ignore_status_mask) { + if (status & uart->ignore_status_mask) { if (++ignored > 100) goto out; goto ignore_char; } - status &= port->read_status_mask; + status &= uart->read_status_mask; - UART_PUT_CR(port, AT91C_US_RSTSTA); /* clear error */ + UART_PUT_CR(uart, AT91C_US_RSTSTA); /* clear error */ if (status & AT91C_US_PARE) flg = TTY_PARITY; else if (status & AT91C_US_FRAME) @@ -262,7 +281,7 @@ flg = TTY_OVERRUN; } #ifdef SUPPORT_SYSRQ - port->sysrq = 0; + uart->sysrq = 0; #endif goto error_return; } @@ -270,34 +289,36 @@ /* * Transmit characters (called from interrupt handler) */ -static void at91_tx_chars(struct uart_port *port) +static void at91_tx_chars(struct at91_serial_port *port) { - struct circ_buf *xmit = &port->info->xmit; + struct uart_port *uart = &port->uart; + struct circ_buf *xmit = &uart->info->xmit; - if (port->x_char) { - UART_PUT_CHAR(port, port->x_char); - port->icount.tx++; - port->x_char = 0; + if (uart->x_char) { + UART_PUT_CHAR(uart, uart->x_char); + uart->icount.tx++; + uart->x_char = 0; return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - at91_stop_tx(port, 0); + + if (uart_circ_empty(xmit) || uart_tx_stopped(uart)) { + at91_stop_tx(uart, 0); return; } - while (UART_GET_CSR(port) & AT91C_US_TXRDY) { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + while (UART_GET_CSR(uart) & AT91C_US_TXRDY) { + UART_PUT_CHAR(uart, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; + uart->icount.tx++; if (uart_circ_empty(xmit)) break; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); + uart_write_wakeup(uart); if (uart_circ_empty(xmit)) - at91_stop_tx(port, 0); + at91_stop_tx(uart, 0); } /* @@ -305,11 +326,12 @@ */ static void at91_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct uart_port *port = dev_id; + struct at91_serial_port *port = dev_id; + struct uart_port *uart = &port->uart; unsigned int status, pending, pass_counter = 0; - status = UART_GET_CSR(port); - pending = status & port->read_status_mask; + status = UART_GET_CSR(uart); + pending = status & uart->read_status_mask; if (pending) { do { if (pending & AT91C_US_RXRDY) @@ -317,36 +339,37 @@ /* Clear the relevent break bits */ if (pending & AT91C_US_RXBRK) { - UART_PUT_CR(port, AT91C_US_RSTSTA); - port->icount.brk++; + UART_PUT_CR(uart, AT91C_US_RSTSTA); + uart->icount.brk++; #ifdef SUPPORT_SYSRQ - if (port->line == at91_console.index && !port->sysrq) { - port->sysrq = jiffies + HZ*5; + if (uart->line == at91_console.index && !uart->sysrq) { + uart->sysrq = jiffies + HZ*5; } #endif } // TODO: All reads to CSR will clear these interrupts! - if (pending & AT91C_US_RIIC) port->icount.rng++; - if (pending & AT91C_US_DSRIC) port->icount.dsr++; + if (pending & AT91C_US_RIIC) uart->icount.rng++; + if (pending & AT91C_US_DSRIC) uart->icount.dsr++; if (pending & AT91C_US_DCDIC) { - port->icount.dcd++; - uart_handle_dcd_change(port, status & AT91C_US_DCD); + uart->icount.dcd++; + uart_handle_dcd_change(uart, status & AT91C_US_DCD); } if (pending & AT91C_US_CTSIC) { - port->icount.cts++; - uart_handle_cts_change(port, status & AT91C_US_CTS); + uart->icount.cts++; + uart_handle_cts_change(uart, status & AT91C_US_CTS); } if (pending & (AT91C_US_RIIC | AT91C_US_DSRIC | AT91C_US_DCDIC | AT91C_US_CTSIC)) - wake_up_interruptible(&port->info->delta_msr_wait); + wake_up_interruptible(&uart->info->delta_msr_wait); if (pending & AT91C_US_TXRDY) at91_tx_chars(port); + if (pass_counter++ > AT91_ISR_PASS_LIMIT) break; - status = UART_GET_CSR(port); - pending = status & port->read_status_mask; + status = UART_GET_CSR(uart); + pending = status & uart->read_status_mask; } while (pending); } } @@ -354,14 +377,14 @@ /* * Perform initialization and enable port for reception */ -static int at91_startup(struct uart_port *port) +static int at91_startup(struct uart_port *uart) { int retval; /* * Allocate the IRQ */ - retval = request_irq(port->irq, at91_interrupt, SA_SHIRQ, "at91_serial", port); + retval = request_irq(uart->irq, at91_interrupt, SA_SHIRQ, "at91_serial", uart); if (retval) { printk("at91_serial: at91_startup - Can't get irq\n"); return retval; @@ -371,54 +394,54 @@ * control line interrupts) */ if (at91_open) { - retval = at91_open(port); + retval = at91_open(uart); if (retval) { - free_irq(port->irq, port); + free_irq(uart->irq, uart); return retval; } } /* Enable peripheral clock if required */ - if (port->irq != AT91C_ID_SYS) - AT91_SYS->PMC_PCER = 1 << port->irq; + if (uart->irq != AT91C_ID_SYS) + AT91_SYS->PMC_PCER = 1 << uart->irq; - port->read_status_mask = AT91C_US_RXRDY | AT91C_US_TXRDY | AT91C_US_OVRE + uart->read_status_mask = AT91C_US_RXRDY | AT91C_US_TXRDY | AT91C_US_OVRE | AT91C_US_FRAME | AT91C_US_PARE | AT91C_US_RXBRK; /* * Finally, clear and enable interrupts */ - UART_PUT_IDR(port, -1); - UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); /* enable xmit & rcvr */ - UART_PUT_IER(port, AT91C_US_RXRDY); /* do receive only */ + UART_PUT_IDR(uart, -1); + UART_PUT_CR(uart, AT91C_US_TXEN | AT91C_US_RXEN); /* enable xmit & rcvr */ + UART_PUT_IER(uart, AT91C_US_RXRDY); /* do receive only */ return 0; } /* * Disable the port */ -static void at91_shutdown(struct uart_port *port) +static void at91_shutdown(struct uart_port *uart) { /* * Free the interrupt */ - free_irq(port->irq, port); + free_irq(uart->irq, uart); /* * If there is a specific "close" function (to unregister * control line interrupts) */ if (at91_close) - at91_close(port); + at91_close(uart); /* * Disable all interrupts, port and break condition. */ - UART_PUT_CR(port, AT91C_US_RSTSTA); - UART_PUT_IDR(port, -1); + UART_PUT_CR(uart, AT91C_US_RSTSTA); + UART_PUT_IDR(uart, -1); /* Disable peripheral clock if required */ - if (port->irq != AT91C_ID_SYS) - AT91_SYS->PMC_PCDR = 1 << port->irq; + if (uart->irq != AT91C_ID_SYS) + AT91_SYS->PMC_PCDR = 1 << uart->irq; } static struct uart_ops at91_pops; /* forward declaration */ @@ -426,13 +449,13 @@ /* * Change the port parameters */ -static void at91_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) +static void at91_change_speed(struct uart_port *uart, u_int cflag, u_int iflag, u_int quot) { unsigned long flags; unsigned int mode, imr; /* Get current mode register */ - mode = UART_GET_MR(port) & ~(AT91C_US_CHRL | AT91C_US_NBSTOP | AT91C_US_PAR); + mode = UART_GET_MR(uart) & ~(AT91C_US_CHRL | AT91C_US_NBSTOP | AT91C_US_PAR); /* byte size */ switch (cflag & CSIZE) { @@ -470,79 +493,79 @@ else mode |= AT91C_US_PAR_NONE; - port->read_status_mask |= AT91C_US_OVRE; + uart->read_status_mask |= AT91C_US_OVRE; if (iflag & INPCK) - port->read_status_mask |= AT91C_US_FRAME | AT91C_US_PARE; + uart->read_status_mask |= AT91C_US_FRAME | AT91C_US_PARE; if (iflag & (BRKINT | PARMRK)) - port->read_status_mask |= AT91C_US_RXBRK; + uart->read_status_mask |= AT91C_US_RXBRK; /* * Characters to ignore */ - port->ignore_status_mask = 0; + uart->ignore_status_mask = 0; if (iflag & IGNPAR) - port->ignore_status_mask |= (AT91C_US_FRAME | AT91C_US_PARE); + uart->ignore_status_mask |= (AT91C_US_FRAME | AT91C_US_PARE); if (iflag & IGNBRK) { - port->ignore_status_mask |= AT91C_US_RXBRK; + uart->ignore_status_mask |= AT91C_US_RXBRK; /* * If we're ignoring parity and break indicators, * ignore overruns too (for real raw support). */ if (iflag & IGNPAR) - port->ignore_status_mask |= AT91C_US_OVRE; + uart->ignore_status_mask |= AT91C_US_OVRE; } // TODO: Ignore all characters if CREAD is set. /* first, disable interrupts and drain transmitter */ local_irq_save(flags); - imr = UART_GET_IMR(port); /* get interrupt mask */ - UART_PUT_IDR(port, -1); /* disable all interrupts */ + imr = UART_GET_IMR(uart); /* get interrupt mask */ + UART_PUT_IDR(uart, -1); /* disable all interrupts */ local_irq_restore(flags); - while (!(UART_GET_CSR(port) & AT91C_US_TXEMPTY)) { barrier(); } + while (!(UART_GET_CSR(uart) & AT91C_US_TXEMPTY)) { barrier(); } /* disable receiver and transmitter */ - UART_PUT_CR(port, AT91C_US_TXDIS | AT91C_US_RXDIS); + UART_PUT_CR(uart, AT91C_US_TXDIS | AT91C_US_RXDIS); /* set the parity, stop bits and data size */ - UART_PUT_MR(port, mode); + UART_PUT_MR(uart, mode); /* set the baud rate */ - UART_PUT_BRGR(port, quot); - UART_PUT_CR(port, AT91C_US_TXEN | AT91C_US_RXEN); + UART_PUT_BRGR(uart, quot); + UART_PUT_CR(uart, AT91C_US_TXEN | AT91C_US_RXEN); /* restore interrupts */ - UART_PUT_IER(port, imr); + UART_PUT_IER(uart, imr); /* CTS flow-control and modem-status interrupts */ - if (UART_ENABLE_MS(port, cflag)) - at91_pops.enable_ms(port); + if (UART_ENABLE_MS(uart, cflag)) + at91_pops.enable_ms(uart); } /* * Return string describing the specified port */ -static const char *at91_type(struct uart_port *port) +static const char *at91_type(struct uart_port *uart) { - return port->type == PORT_AT91RM9200 ? "AT91_SERIAL" : NULL; + return uart->type == PORT_AT91RM9200 ? "AT91_SERIAL" : NULL; } /* * Release the memory region(s) being used by 'port'. */ -static void at91_release_port(struct uart_port *port) +static void at91_release_port(struct uart_port *uart) { - release_mem_region(port->mapbase, - port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K); + release_mem_region(uart->mapbase, + uart->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K); } /* * Request the memory region(s) being used by 'port'. */ -static int at91_request_port(struct uart_port *port) +static int at91_request_port(struct uart_port *uart) { - return request_mem_region(port->mapbase, - port->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K, + return request_mem_region(uart->mapbase, + uart->mapbase == AT91C_VA_BASE_DBGU ? 512 : SZ_16K, "at91_serial") != NULL ? 0 : -EBUSY; } @@ -550,31 +573,31 @@ /* * Configure/autoconfigure the port. */ -static void at91_config_port(struct uart_port *port, int flags) +static void at91_config_port(struct uart_port *uart, int flags) { if (flags & UART_CONFIG_TYPE) { - port->type = PORT_AT91RM9200; - at91_request_port(port); + uart->type = PORT_AT91RM9200; + at91_request_port(uart); } } /* * Verify the new serial_struct (for TIOCSSERIAL). */ -static int at91_verify_port(struct uart_port *port, struct serial_struct *ser) +static int at91_verify_port(struct uart_port *uart, struct serial_struct *ser) { int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91RM9200) ret = -EINVAL; - if (port->irq != ser->irq) + if (uart->irq != ser->irq) ret = -EINVAL; if (ser->io_type != SERIAL_IO_MEM) ret = -EINVAL; - if (port->uartclk / 16 != ser->baud_base) + if (uart->uartclk / 16 != ser->baud_base) ret = -EINVAL; - if ((void *)port->mapbase != ser->iomem_base) + if ((void *)uart->mapbase != ser->iomem_base) ret = -EINVAL; - if (port->iobase != ser->port) + if (uart->iobase != ser->port) ret = -EINVAL; if (ser->hub6 != 0) ret = -EINVAL; @@ -600,8 +623,6 @@ verify_port: at91_verify_port, }; -static struct uart_port at91_ports[AT91C_NR_UART]; - void __init at91_init_ports(void) { static int first = 1; @@ -612,13 +633,13 @@ first = 0; for (i = 0; i < AT91C_NR_UART; i++) { - at91_ports[i].iotype = SERIAL_IO_MEM; - at91_ports[i].flags = ASYNC_BOOT_AUTOCONF; - at91_ports[i].uartclk = AT91C_MASTER_CLOCK; - at91_ports[i].ops = &at91_pops; - at91_ports[i].fifosize = 1; - at91_ports[i].line = i; - } + at91_ports[i].uart.iotype = SERIAL_IO_MEM; + at91_ports[i].uart.flags = ASYNC_BOOT_AUTOCONF; + at91_ports[i].uart.uartclk = AT91C_MASTER_CLOCK; + at91_ports[i].uart.ops = &at91_pops; + at91_ports[i].uart.fifosize = 1; + at91_ports[i].uart.line = i; + } } void __init at91_register_uart_fns(struct at91rm9200_port_fns *fns) @@ -647,33 +668,33 @@ switch (port) { case 0: - at91_ports[idx].membase = (void *) AT91C_VA_BASE_US0; - at91_ports[idx].mapbase = AT91C_VA_BASE_US0; - at91_ports[idx].irq = AT91C_ID_US0; + at91_ports[idx].uart.membase = (void *) AT91C_VA_BASE_US0; + at91_ports[idx].uart.mapbase = AT91C_VA_BASE_US0; + at91_ports[idx].uart.irq = AT91C_ID_US0; AT91_CfgPIO_USART0(); break; case 1: - at91_ports[idx].membase = (void *) AT91C_VA_BASE_US1; - at91_ports[idx].mapbase = AT91C_VA_BASE_US1; - at91_ports[idx].irq = AT91C_ID_US1; + at91_ports[idx].uart.membase = (void *) AT91C_VA_BASE_US1; + at91_ports[idx].uart.mapbase = AT91C_VA_BASE_US1; + at91_ports[idx].uart.irq = AT91C_ID_US1; AT91_CfgPIO_USART1(); break; case 2: - at91_ports[idx].membase = (void *) AT91C_VA_BASE_US2; - at91_ports[idx].mapbase = AT91C_VA_BASE_US2; - at91_ports[idx].irq = AT91C_ID_US2; + at91_ports[idx].uart.membase = (void *) AT91C_VA_BASE_US2; + at91_ports[idx].uart.mapbase = AT91C_VA_BASE_US2; + at91_ports[idx].uart.irq = AT91C_ID_US2; AT91_CfgPIO_USART2(); break; case 3: - at91_ports[idx].membase = (void *) AT91C_VA_BASE_US3; - at91_ports[idx].mapbase = AT91C_VA_BASE_US3; - at91_ports[idx].irq = AT91C_ID_US3; + at91_ports[idx].uart.membase = (void *) AT91C_VA_BASE_US3; + at91_ports[idx].uart.mapbase = AT91C_VA_BASE_US3; + at91_ports[idx].uart.irq = AT91C_ID_US3; AT91_CfgPIO_USART3(); break; case 4: - at91_ports[idx].membase = (void *) AT91C_VA_BASE_DBGU; - at91_ports[idx].mapbase = AT91C_VA_BASE_DBGU; - at91_ports[idx].irq = AT91C_ID_SYS; + at91_ports[idx].uart.membase = (void *) AT91C_VA_BASE_DBGU; + at91_ports[idx].uart.mapbase = AT91C_VA_BASE_DBGU; + at91_ports[idx].uart.irq = AT91C_ID_SYS; AT91_CfgPIO_DBGU(); break; default: @@ -688,28 +709,28 @@ */ static void at91_console_write(struct console *co, const char *s, u_int count) { - struct uart_port *port = at91_ports + co->index; + struct uart_port *uart = &at91_ports[co->index].uart; unsigned int status, i, imr; /* * First, save IMR and then disable interrupts */ - imr = UART_GET_IMR(port); /* get interrupt mask */ - UART_PUT_IDR(port, AT91C_US_RXRDY | AT91C_US_TXRDY); + imr = UART_GET_IMR(uart); /* get interrupt mask */ + UART_PUT_IDR(uart, AT91C_US_RXRDY | AT91C_US_TXRDY); /* * Now, do each character */ for (i = 0; i < count; i++) { do { - status = UART_GET_CSR(port); + status = UART_GET_CSR(uart); } while (!(status & AT91C_US_TXRDY)); - UART_PUT_CHAR(port, s[i]); + UART_PUT_CHAR(uart, s[i]); if (s[i] == '\n') { do { - status = UART_GET_CSR(port); + status = UART_GET_CSR(uart); } while (!(status & AT91C_US_TXRDY)); - UART_PUT_CHAR(port, '\r'); + UART_PUT_CHAR(uart, '\r'); } } @@ -718,9 +739,9 @@ * and restore IMR */ do { - status = UART_GET_CSR(port); - } while (status & AT91C_US_TXRDY); - UART_PUT_IER(port, imr); /* set interrupts back the way they were */ + status = UART_GET_CSR(uart); + } while (!(status & AT91C_US_TXRDY)); + UART_PUT_IER(uart, imr); /* set interrupts back the way they were */ } static kdev_t at91_console_device(struct console *co) @@ -732,14 +753,14 @@ * If the port was already initialised (eg, by a boot loader), try to determine * the current setup. */ -static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +static void __init at91_console_get_options(struct uart_port *uart, int *baud, int *parity, int *bits) { unsigned int mr, quot; // TODO: CR is a write-only register // unsigned int cr; // -// cr = UART_GET_CR(port) & (AT91C_US_RXEN | AT91C_US_TXEN); +// cr = UART_GET_CR(uart) & (AT91C_US_RXEN | AT91C_US_TXEN); // if (cr == (AT91C_US_RXEN | AT91C_US_TXEN)) { // /* ok, the port was enabled */ // @@ -752,19 +773,19 @@ // *parity = 'o'; // } - mr = UART_GET_MR(port) & AT91C_US_CHRL; + mr = UART_GET_MR(uart) & AT91C_US_CHRL; if (mr == AT91C_US_CHRL_8_BITS) *bits = 8; else *bits = 7; - quot = UART_GET_BRGR(port); - *baud = port->uartclk / (16 * (quot)); + quot = UART_GET_BRGR(uart); + *baud = uart->uartclk / (16 * (quot)); } static int __init at91_console_setup(struct console *co, char *options) { - struct uart_port *port; + struct uart_port *uart; int baud = AT91C_CONSOLE_DEFAULT_BAUDRATE; int bits = 8; int parity = 'n'; @@ -775,7 +796,9 @@ * if so, search for the first available port that does have * console support. */ - port = uart_get_console(at91_ports, AT91C_NR_UART, co); + if (co->index >= AT91C_NR_UART) + co->index = 0; + uart = &at91_ports[co->index].uart; // TODO: The console port should be initialized, and clock enabled if // we're not relying on the bootloader to do it. @@ -783,9 +806,9 @@ if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - at91_console_get_options(port, &baud, &parity, &bits); + at91_console_get_options(uart, &baud, &parity, &bits); - return uart_set_options(port, co, baud, parity, bits, flow); + return uart_set_options(uart, co, baud, parity, bits, flow); } static struct console at91_console = { @@ -809,7 +832,7 @@ #define AT91_CONSOLE_DEVICE NULL #endif -static struct uart_driver at91_reg = { +static struct uart_driver at91_uart = { owner: THIS_MODULE, normal_major: SERIAL_AT91_MAJOR, #ifdef CONFIG_DEVFS_FS @@ -836,13 +859,13 @@ at91_init_ports(); - ret = uart_register_driver(&at91_reg); + ret = uart_register_driver(&at91_uart); if (ret) return ret; for (i = 0; i < AT91C_NR_UART; i++) { if (at91_serialmap[i] >= 0) - uart_add_one_port(&at91_reg, &at91_ports[i]); + uart_add_one_port(&at91_uart, &at91_ports[i].uart); } return 0; @@ -853,11 +876,11 @@ int i; for (i = 0; i < AT91C_NR_UART; i++) { - if (at91_serialmap[i] >= 0) - uart_remove_one_port(&at91_reg, &at91_ports[i]); - } + if (at91_serialmap[i] >= 0) + uart_remove_one_port(&at91_uart, &at91_ports[i].uart); + } - uart_unregister_driver(&at91_reg); + uart_unregister_driver(&at91_uart); } module_init(at91_serial_init); diff -urN linux-2.4.26-vrs1.orig/drivers/at91/spi/at91_spi.c linux-2.4.26-vrs1/drivers/at91/spi/at91_spi.c --- linux-2.4.26-vrs1.orig/drivers/at91/spi/at91_spi.c Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/at91/spi/at91_spi.c Mon Apr 26 15:49:38 2004 @@ -61,10 +61,10 @@ /* Enable PIO */ if (!spi_dev[device].pio_enabled) { switch (device) { - case 0: AT91_CfgPIO_SPI_CS0(); - case 1: AT91_CfgPIO_SPI_CS1(); - case 2: AT91_CfgPIO_SPI_CS2(); - case 3: AT91_CfgPIO_SPI_CS3(); + case 0: AT91_CfgPIO_SPI_CS0(); break; + case 1: AT91_CfgPIO_SPI_CS1(); break; + case 2: AT91_CfgPIO_SPI_CS2(); break; + case 3: AT91_CfgPIO_SPI_CS3(); break; } spi_dev[device].pio_enabled = 1; #ifdef DEBUG_SPI diff -urN linux-2.4.26-vrs1.orig/drivers/pcmcia/Config.in linux-2.4.26-vrs1/drivers/pcmcia/Config.in --- linux-2.4.26-vrs1.orig/drivers/pcmcia/Config.in Mon May 3 10:12:14 2004 +++ linux-2.4.26-vrs1/drivers/pcmcia/Config.in Mon Apr 26 21:40:27 2004 @@ -45,6 +45,7 @@ if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA + dep_tristate ' AT91RM9200 support' CONFIG_PCMCIA_AT91 $CONFIG_ARCH_AT91RM9200 $CONFIG_PCMCIA fi endmenu diff -urN linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/AT91RM9200_SYS.h linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/AT91RM9200_SYS.h --- linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/AT91RM9200_SYS.h Mon Aug 25 13:44:43 2003 +++ linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/AT91RM9200_SYS.h Mon Apr 26 21:40:27 2004 @@ -613,7 +613,7 @@ #define AT91C_EBI_CS3A_SMC_SmartMedia (0x1 << 3) // (EBI) Chip Select 3 is assigned to the Static Memory Controller and the SmartMedia Logic is activated. #define AT91C_EBI_CS4A (0x1 << 4) // (EBI) Chip Select 4 Assignment #define AT91C_EBI_CS4A_SMC (0x0 << 4) // (EBI) Chip Select 4 is assigned to the Static Memory Controller and NCS4,NCS5 and NCS6 behave as defined by the SMC2. -#define AT91C_EBI_CS4A_SMC_CompactFlash (0x1 << 4) // (EBI) Chip Select 4 is assigned to the Static Memory Controller and the CompactFlash Logic is activated. +#define AT91C_EBI_CS4A_SMC_COMPACTFLASH (0x1 << 4) // (EBI) Chip Select 4 is assigned to the Static Memory Controller and the CompactFlash Logic is activated. // -------- EBI_CFGR : (EBI Offset: 0x4) Configuration Register -------- #define AT91C_EBI_DBPUC (0x1 << 0) // (EBI) Data Bus Pull-Up Configuration #define AT91C_EBI_EBSEN (0x1 << 1) // (EBI) Bus Sharing Enable diff -urN linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/at91rm9200dk.h linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/at91rm9200dk.h --- linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/at91rm9200dk.h Mon May 3 10:12:15 2004 +++ linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/at91rm9200dk.h Wed Apr 28 11:54:36 2004 @@ -19,7 +19,7 @@ #define AT91C_MAIN_CLOCK 179712000 /* from 18.432 MHz crystal (18432000 / 4 * 39) */ #define AT91C_MASTER_CLOCK 59904000 /* peripheral clock (AT91C_MAIN_CLOCK / 3) */ #define AT91C_SLOW_CLOCK 32768 /* slow clock */ -#define AT91_PLLB_INIT 0x1048be0e /* (18.432 / 14 * 73) /2 = 47.9714 * +#define AT91_PLLB_INIT 0x1048be0e /* (18.432 * (72+1) / 14) / 2 = 48.054857 */ /* FLASH */ #define AT91_FLASH_BASE 0x10000000 // NCS0: Flash physical base address diff -urN linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/csb337.h linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/csb337.h --- linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/csb337.h Mon May 3 10:12:15 2004 +++ linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/csb337.h Wed Apr 28 11:53:52 2004 @@ -19,7 +19,7 @@ #define AT91C_MAIN_CLOCK 184320000 #define AT91C_MASTER_CLOCK 46080000 /* peripheral clock (AT91C_MAIN_CLOCK / 4) */ #define AT91C_SLOW_CLOCK 32768 /* slow clock */ -#define AT91_PLLB_INIT 0x1257be17 /* (3.68 / 23 * 600) /2 = 96/2 = 48 */ +#define AT91_PLLB_INIT 0x128a3e19 /* (3.6864 * (650+1) / 25) /2 = 47.9969 */ /* FLASH */ #define AT91_FLASH_BASE 0x10000000 // NCS0: Flash physical base address diff -urN linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/pio.h linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/pio.h --- linux-2.4.26-vrs1.orig/include/asm-arm/arch-at91rm9200/pio.h Mon May 3 10:12:15 2004 +++ linux-2.4.26-vrs1/include/asm-arm/arch-at91rm9200/pio.h Mon May 3 10:29:08 2004 @@ -17,7 +17,15 @@ static inline void AT91_CfgPIO_USART0(void) { AT91_SYS->PIOA_PDR = AT91C_PA17_TXD0 | AT91C_PA18_RXD0 - | AT91C_PA20_CTS0 | AT91C_PA21_RTS0; + | AT91C_PA20_CTS0; + + /* + * Errata #39 - RTS0 is not internally connected to PA21. We need to drive + * the pin manually. Default is off (RTS is active low). + */ + AT91_SYS->PIOA_PER = AT91C_PA21_RTS0; + AT91_SYS->PIOA_OER = AT91C_PA21_RTS0; + AT91_SYS->PIOA_SODR = AT91C_PA21_RTS0; } static inline void AT91_CfgPIO_USART1(void) { @@ -46,8 +54,8 @@ AT91_SYS->PIOA_PDR = AT91C_PA16_EMDIO | AT91C_PA15_EMDC | AT91C_PA14_ERXER | AT91C_PA13_ERX1 | AT91C_PA12_ERX0 | AT91C_PA11_ECRS_ECRSDV | AT91C_PA10_ETX1 | AT91C_PA9_ETX0 | AT91C_PA8_ETXEN | AT91C_PA7_ETXCK_EREFCK; - AT91_SYS->PIOB_PDR = AT91C_PB25_EF100 | AT91C_PB19_ERXCK; - AT91_SYS->PIOB_BSR = AT91C_PB25_EF100 | AT91C_PB19_ERXCK; + AT91_SYS->PIOB_PDR = AT91C_PB19_ERXCK; + AT91_SYS->PIOB_BSR = AT91C_PB19_ERXCK; } /* @@ -57,10 +65,10 @@ AT91_SYS->PIOA_PDR = AT91C_PA16_EMDIO | AT91C_PA15_EMDC | AT91C_PA14_ERXER | AT91C_PA13_ERX1 | AT91C_PA12_ERX0 | AT91C_PA11_ECRS_ECRSDV | AT91C_PA10_ETX1 | AT91C_PA9_ETX0 | AT91C_PA8_ETXEN | AT91C_PA7_ETXCK_EREFCK; - AT91_SYS->PIOB_PDR = AT91C_PB25_EF100 | AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV + AT91_SYS->PIOB_PDR = AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV | AT91C_PB16_ERX3 | AT91C_PB15_ERX2 | AT91C_PB14_ETXER | AT91C_PB13_ETX3 | AT91C_PB12_ETX2; - AT91_SYS->PIOB_BSR = AT91C_PB25_EF100 | AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV + AT91_SYS->PIOB_BSR = AT91C_PB19_ERXCK | AT91C_PB18_ECOL | AT91C_PB17_ERXDV | AT91C_PB16_ERX3 | AT91C_PB15_ERX2 | AT91C_PB14_ETXER | AT91C_PB13_ETX3 | AT91C_PB12_ETX2; } @@ -83,6 +91,7 @@ static inline void AT91_CfgPIO_TWI(void) { AT91_SYS->PIOA_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK; AT91_SYS->PIOA_ASR = AT91C_PA25_TWD | AT91C_PA26_TWCK; + AT91_SYS->PIOA_MDER = AT91C_PA25_TWD | AT91C_PA26_TWCK; /* open drain */ } /*