⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_lowlevel.c

📁 AT91RM9200驱动CF卡的原代码。
💻 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 + -