📄 at91_lowlevel.c
字号:
/* * 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 * <john+@cs.cmu.edu>. 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 <linux/module.h>#include <linux/init.h>#include <linux/config.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ioport.h>#include <pcmcia/version.h>#include <pcmcia/cs_types.h>#include <pcmcia/cs.h>#include <pcmcia/ss.h>#include <pcmcia/bulkmem.h>#include <pcmcia/cistpl.h>#include <pcmcia/bus_ops.h>#include "../../pcmcia/cs_internal.h"#include <asm/hardware.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/arch/AT91RM9200_SYS.h>#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; /*configure PIOC5*/ AT91_SYS->PIOC_PER = AT91C_PIO_PC5; AT91_SYS->PIOC_OER = AT91C_PIO_PC5; AT91_SYS->PIOC_SODR = AT91C_PIO_PC5; AT91_SYS->PIOC_CODR = AT91C_PIO_PC5; /* 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 | SM_TDF; 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,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -