[PATCH, arm] CompactFlash card driver for AT91SAM9260

From: Uros Bizjak
Date: Fri Oct 10 2008 - 06:19:37 EST


Hello!

Attached patch implements driver for CF card on AT91SAM9260.The patch
supportsMemory & IO mode hardware configuration, as shown in section
20.7.6.1 of AT91SAM9260 hardware manual. CF timings are based on
Common Memory Read/Write Timing Specification of "CF+ and CompactFlash
Specification Revision 2.0", the implementation includes TDF
optimization of SMC.

The patch was tested together witn pata_pcmcia driver, resulting in:

kernel: scsi0 : pata_pcmcia
kernel: ata1: PATA max PIO0 cmd 0xc480c000 ctl 0xc480c00e irq 110
kernel: ata1.00: CFA: TOSHIBA THNCF064MBA, 2.20, max PIO2
kernel: ata1.00: 125184 sectors, multi 1
kernel: ata1.00: configured for PIO0
kernel: ata1.00: configured for PIO0
kernel: ata1: EH complete
kernel: isa bounce pool size: 16 pages
kernel: scsi 0:0:0:0: Direct-Access ATA TOSHIBA THNCF064
2.20PQ: 0 ANSI: 5
...

Signed-off-by: Uros Bizjak <ubizjak@xxxxxxxxx>

Uros.
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 7774d17..a75906f 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -195,6 +195,103 @@ void __init at91_add_device_eth(struct at91_eth_data *data)
void __init at91_add_device_eth(struct at91_eth_data *data) {}
#endif

+/* --------------------------------------------------------------------
+ * Compact Flash / PCMCIA
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE)
+static struct at91_cf_data cf_data;
+
+#define CF_BASE AT91_CHIPSELECT_4
+
+static struct resource cf_resources[] = {
+ [0] = {
+ .start = CF_BASE,
+ /* ties up CS4 and CS5 */
+ .end = CF_BASE + SZ_512M - 1,
+ .flags = IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT,
+ },
+};
+
+static struct platform_device at91sam9260_cf_device = {
+ .name = "at91_cf",
+ .id = -1,
+ .dev = {
+ .platform_data = &cf_data,
+ },
+ .resource = cf_resources,
+ .num_resources = ARRAY_SIZE(cf_resources),
+};
+
+void __init at91_add_device_cf(struct at91_cf_data *data)
+{
+ unsigned int csa;
+ int cs;
+
+ if (!data)
+ return;
+
+ cs = data->chipselect;
+
+ csa = at91_sys_read(AT91_MATRIX_EBICSA);
+ if (cs == 4)
+ csa |= AT91_MATRIX_CS4A_SMC_CF1;
+ else if (cs == 5)
+ csa |= AT91_MATRIX_CS5A_SMC_CF2;
+ else
+ BUG();
+
+ at91_sys_write(AT91_MATRIX_EBICSA, csa);
+
+ /* Timing for sam9260 */
+ /* set the bus interface characteristics */
+ at91_sys_write(AT91_SMC_SETUP(cs),
+ AT91_SMC_NWESETUP_(3) | AT91_SMC_NCS_WRSETUP_(3)
+ | AT91_SMC_NRDSETUP_(3) | AT91_SMC_NCS_RDSETUP_(3));
+
+ at91_sys_write(AT91_SMC_PULSE(cs),
+ AT91_SMC_NWEPULSE_(15) | AT91_SMC_NCS_WRPULSE_(17)
+ | AT91_SMC_NRDPULSE_(13) | AT91_SMC_NCS_RDPULSE_(15));
+
+ at91_sys_write(AT91_SMC_CYCLE(cs),
+ AT91_SMC_NWECYCLE_(21) | AT91_SMC_NRDCYCLE_(18));
+
+ at91_sys_write(AT91_SMC_MODE(cs),
+ AT91_SMC_READMODE | AT91_SMC_WRITEMODE
+ | AT91_SMC_EXNWMODE_READY
+ | AT91_SMC_BAT_SELECT | AT91_SMC_DBW_16
+ | AT91_SMC_TDF_(10) | AT91_SMC_TDFMODE);
+
+ /* input/irq */
+ if (data->irq_pin) {
+ at91_set_gpio_input(data->irq_pin, 1);
+ at91_set_deglitch(data->irq_pin, 1);
+ }
+ at91_set_gpio_input(data->det_pin, 1);
+ at91_set_deglitch(data->det_pin, 1);
+
+ /* outputs, initially off */
+ if (data->vcc_pin)
+ at91_set_gpio_output(data->vcc_pin, 0);
+ at91_set_gpio_output(data->rst_pin, 0);
+
+ /* force poweron defaults for this pin ... */
+ at91_set_A_periph(AT91_PIN_PC10, 0); /* A25/CFRNW */
+
+ if (cs == 4)
+ at91_set_A_periph(AT91_PIN_PC8, 0); /* NCS4/CFCS0 */
+ else
+ at91_set_A_periph(AT91_PIN_PC9, 0); /* NCS5/CFCS1 */
+ at91_set_A_periph(AT91_PIN_PC15, 1); /* nWAIT */
+ at91_set_B_periph(AT91_PIN_PC6, 0); /* CFCE1 */
+ at91_set_B_periph(AT91_PIN_PC7, 0); /* CFCE2 */
+
+ cf_data = *data;
+ platform_device_register(&at91sam9260_cf_device);
+}
+#else
+void __init at91_add_device_cf(struct at91_cf_data *data) {}
+#endif

/* --------------------------------------------------------------------
* MMC / SD
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
index cb20e70..d18f80d 100644
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ b/arch/arm/mach-at91/board-sam9260ek.c
@@ -84,6 +84,16 @@ static struct at91_udc_data __initdata ek_udc_data = {
.pullup_pin = 0, /* pull-up driven by UDC */
};

+/*
+ * Compact Flash
+ */
+static struct at91_cf_data __initdata ek_cf_data = {
+ .irq_pin = AT91_PIN_PC14,
+ .det_pin = AT91_PIN_PC9,
+ // .vcc_pin = ... always powered
+ .rst_pin = AT91_PIN_PC11,
+ .chipselect = 4,
+};

/*
* Audio
@@ -240,6 +250,8 @@ static void __init ek_board_init(void)
at91_add_device_mmc(0, &ek_mmc_data);
/* I2C */
at91_add_device_i2c(NULL, 0);
+ /* Compact Flash */
+ at91_add_device_cf(&ek_cf_data);
/* SSC (to AT73C213) */
at73c213_set_clk(&at73c213_data);
at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index e0f8840..48bfb3e 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -273,7 +273,7 @@ config BFIN_CFPCMCIA

config AT91_CF
tristate "AT91 CompactFlash Controller"
- depends on PCMCIA && ARCH_AT91RM9200
+ depends on PCMCIA && (ARCH_AT91RM9200 || ARCH_AT91SAM9260)
help
Say Y here to support the CompactFlash controller on AT91 chips.
Or choose M to compile the driver as a module named "at91_cf".
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index a0ffb8e..fa40174 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -24,8 +24,14 @@
#include <asm/gpio.h>

#include <mach/board.h>
-#include <mach/at91rm9200_mc.h>

+#if defined(CONFIG_ARCH_AT91RM9200)
+#include <mach/at91rm9200_mc.h>
+#elif defined(CONFIG_ARCH_AT91SAM9260)
+#include <mach/at91sam9_smc.h>
+#else
+#error "Unsupported AT91 processor"
+#endif

/*
* A0..A10 work in each range; A23 indicates I/O space; A25 is CFRNW;
@@ -157,7 +163,11 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
/*
* Use 16 bit accesses unless/until we need 8-bit i/o space.
*/
+#if defined(CONFIG_ARCH_AT91RM9200)
csr = at91_sys_read(AT91_SMC_CSR(cf->board->chipselect)) & ~AT91_SMC_DBW;
+#else
+ csr = at91_sys_read(AT91_SMC_MODE(cf->board->chipselect)) & ~AT91_SMC_DBW;
+#endif

/*
* NOTE: this CF controller ignores IOIS16, so we can't really do
@@ -176,7 +186,11 @@ static int at91_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io)
csr |= AT91_SMC_DBW_16;
pr_debug("%s: 16bit i/o bus\n", driver_name);
}
+#if defined(CONFIG_ARCH_AT91RM9200)
at91_sys_write(AT91_SMC_CSR(cf->board->chipselect), csr);
+#else
+ at91_sys_write(AT91_SMC_MODE(cf->board->chipselect), csr);
+#endif

io->start = cf->socket.io_offset;
io->stop = io->start + SZ_2K - 1;