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

📄 pd6700.c

📁 嵌入式linux 开发板驱动程序
💻 C
字号:

#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/device.h>			//platform_bus
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>			
#include <linux/ioport.h>	
#include <linux/blkdev.h>
#include <linux/ide.h>
#include <linux/mm.h>
#include <linux/errno.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/hardware.h>
#include <asm/semaphore.h>
#include <asm/arch/regs-gpio.h>	

#include "pd6700.h"

#define S3C2410_CF_BASE		0x12000000	
#define	S3C2410_CFP_IRQ		IRQ_EINT8

static void  *cf_base;
static int 	ide_index;
/********************************************************************************************************/

//static spinlock_t bus_lock = SPIN_LOCK_UNLOCKED;
/*********************************************************************************************************
** Function name: pd67_get
** Descriptions: 获取接口寄存器的值
** Input:sock,接口号
**  			reg,寄存器索引
** Output :
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static unsigned  char pd67_get(unsigned short sock, unsigned char reg)
{   //unsigned long flags;
	void *addr;
    //spin_lock_irqsave(&bus_lock,flags);				// 关中断
    {		int port = 0x3e0;				// IO地址
				unsigned  char val;
				//reg = reg// 获取寄存器索引
				//io_base(port) = (unsigned  char) reg;							// 写寄存器地址
				addr=cf_base+port;
				writeb(reg, addr);
				addr=cf_base+port+1;
				val=readb(addr);
				//val = io_base(port+1);										// 读寄存器值
				//spin_unlock_irqrestore(&bus_lock,flags);		// 开中断
			printk(KERN_ERR "reg = 0x%x ,port = 0x%x , val = 0x%x \n", reg, port ,val);
				return val;
    }
}
/*********************************************************************************************************
** Function name: pd67_set
** Descriptions: 写入指定寄存器的值
** Input:
** Output :
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void pd67_set(unsigned short sock, unsigned short reg, unsigned  char data)
{   //unsigned long flags;
	void * addr;
    //spin_lock_irqsave(&bus_lock,flags);
    {		int port = 0x3e0;
				unsigned  char index = reg;
				addr=cf_base+port;
				writeb(index, addr);
				addr=cf_base+port+1;
				writeb(data, addr);
				//io_base(port) = (unsigned  char)index;
				//io_base(port+1) = (unsigned  char)data;
			printk(KERN_ERR "reg = 0x%x ,port = 0x%x , val = 0x%x \n", index, port ,data);
				//spin_unlock_irqrestore(&bus_lock,flags);
    }
}


/*********************************************************************************************************
** Function name: pd67_bset
** Descriptions: 设置寄存器标记位.先读出寄存器的值,再将该值与mask求或,最后写入到寄存器
** Input:sock, 接口索引号
** 			 reg,寄存器索引号
**			 mask,屏蔽位
** Output : 无
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void pd67_bset(unsigned short sock, unsigned short reg, unsigned  char mask)
{
    unsigned  char d = pd67_get(sock, reg);
    d |= mask;
    pd67_set(sock, reg, d);
}
/*********************************************************************************************************
** Function name: pd67_bclr
** Descriptions: 清零标志位,将寄存器中mask相应的位清零
** Input:sock, 接口索引号
** 			 reg,寄存器索引号
**			 mask,屏蔽位
** Output :
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void pd67_bclr(unsigned short sock, unsigned short reg, unsigned  char mask)
{
    unsigned  char d = pd67_get(sock, reg);
    d &= ~mask;
    pd67_set(sock, reg, d);
}

/*********************************************************************************************************
** Function name: pd67_bflip
** Descriptions: 该函数集成了pd67_bset和pd67_bclr的功能,通过b的值选择相关的操作,b为0清标志位,反之置标志位
** Input:sock,接口索引
**			 reg, 寄存器索引
**			 mask, 屏蔽位
**			 b, 操作标志位
** Output : 无
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void pd67_bflip(unsigned short sock, unsigned short reg, unsigned  char mask, int b)
{
    unsigned  char d = pd67_get(sock, reg);					// 读出寄存器原值
    if (b)	d |= mask;
    else		d &= ~mask;
    pd67_set(sock, reg, d);								// 写入寄存器
}
/*********************************************************************************************************
** Function name: pd67_get_pair
** Descriptions: 获取寄存器连续两个值,将寄存器reg和reg+1(高8位)组成一个16位的值,
** Input:sock , 接口号
**			 reg , 寄存器索引
** Output : 返回16位的值
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static unsigned short pd67_get_pair(unsigned short sock, unsigned short reg)
{
    unsigned short a, b;
    a = pd67_get(sock, reg);						// 读出寄存器
    b = pd67_get(sock, reg+1);					// 读出寄存器+1
    return (a + (b<<8));
}
/*********************************************************************************************************
** Function name: pd67_set_pair
** Descriptions: 写双寄存器
** Input:sock,接口号
**			 reg,寄存器索引
**			 data, 写入的16位数据值
** Output : 无
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void pd67_set_pair(unsigned short sock, unsigned short reg, unsigned short data)
{
    pd67_set(sock, reg, data & 0xff);				// 写入寄存器
    pd67_set(sock, reg+1, data >> 8);				// 写入寄存器
}


/*********************************************************************************************************
** Function name: pd6710_ata
** Descriptions: 初始化PCMCIA卡的ATA模式参数.
** Input:sock,接口号
** Output : 无
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static void pd6710_ini_ata(unsigned short sock)
{
	unsigned char i;
	
	// This code need to be modified to fit your hardware and software system environment

	pd67_set(sock,PD67_POWER,0x00);					// 关闭电源输出
	
	// Disable IRQ lines 
	pd67_set(sock,PD67_INTCTL,0);						// 禁止所有中断
	// Disable memory and I/O windows	
	pd67_set(sock,PD67_MAP_ENA,0);					// 禁止所有MAP
	
	
	// 设置总线时序
	pd67_set(sock,PD67_FIFO_CTL,0x80);			//清空FIFO
	pd67_set(sock,PD67_SET_TIME0, 0);				// 80ns
	pd67_set(sock,PD67_CMD_TIME0, 3);					// 320ns
	pd67_set(sock,PD67_REC_TIME0, 0);		// 80ns
	
	// Set ATA mode and enable LED
	pd67_set(sock,PD67_ATA_CTL,0x03);
	// Reset card,configure for I/O, and set IRQ line to IRQ14
	pd67_set(sock,PD67_INTCTL, 3|PD67_PC_RESET|PD67_PC_IOCARD);	// 设置中断\IO卡使能、复位
										

	
	// Set I/O windows 0 for 1f0-1f7h
	pd67_set_pair(sock,PD67_IO(0),0x01f0);								// IO0 MAP开始地址
	pd67_set_pair(sock,PD67_IO(0)+PD67_W_STOP,0x01f7);		// IO0 MAP结束地址
	pd67_set_pair(sock,PD67_IO(0)+PD67_W_OFF,0x0000);			// IO0 OFFSET结束地址
	
	// Set I/O windows 1 for 3f6-3f7h
	pd67_set_pair(sock,PD67_IO(1),0x03f6);								// IO0 MAP开始地址
	pd67_set_pair(sock,PD67_IO(1)+PD67_W_STOP,0x03f7);		// IO0 MAP结束地址
	pd67_set_pair(sock,PD67_IO(1)+PD67_W_OFF,0x0000);			// IO0 OFFSET结束地址
	
	// Set I/O width for Auto-Data width
	pd67_set(sock,PD67_IOCTL,PD67_IOCTL_IOCS16(0)|PD67_IOCTL_IOCS16(1));
	
	// Enable I/O window 0 and 1
	pd67_set(sock,PD67_MAP_ENA,PD67_ENA_IO(0)|PD67_ENA_IO(1));	// 使能IO0和IO1 MAP

	
	// Drive LED and enable three-state bit 7
	pd67_set(sock,PD67_MISC_CTL_2,PD67_MC2_LED_ENA|PD67_MC2_3STATE_BIT7);
	//pd67_set(sock,PD67_MISC_CTL_1,0);													// 输出5V 中断为电平触发
	pd67_set(sock,PD67_MISC_CTL_1,2);	   //3.3V												// 输出5V 中断为电平触发
	
	// Apply power and enable outputs
	//pd67_set(sock,PD67_POWER,0x90);														// 输出电源

	pd67_set(sock,PD67_POWER,0xf0);														// 输出电源
	
	// Add some delay. The delay tome depends on the drive specifications.
	mdelay(100);
	// Activate the reset pin
	pd67_bclr(sock,PD67_INTCTL,PD67_PC_RESET);				// ATA复位
	// Add some delay. The delay time depends on the drive specifications
	mdelay(100);
	// Remove the reset signal
	pd67_bset(sock,PD67_INTCTL,PD67_PC_RESET);
	mdelay(100);
/*
	printk("now print the register value\n");
	for(i=0; i<0x3d; i++) {
		pd67_get(sock, i);
	}
*/
}


/*********************************************************************************************************
** Function name: ini_pcmcia_bridge
** Descriptions: 初始化PCMCIA桥芯片,并分配系统硬件资源,仅在init_pd6700()函数中使用.
** Input: 无
** Output : 无
** Created by:
** Created Date: 
**-------------------------------------------------------------------------------------------------------
** Modified by:
** Modified Date: 
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
static int __init ini_pcmcia_bridge(unsigned short sock)
{  	pd67_set(sock,PD67_CHIP_INFO,0);
		if((pd67_get(sock,PD67_CHIP_INFO)&0xc0)!=0xc0||(pd67_get(sock,PD67_CHIP_INFO)&0xc0)!=0x00)
		{			return -1;
		}
    
   if (pd67_get(sock, PD67_IDENT) & 0x70) {			// 辩认PCMCIA控制器ID
				return -1;
    }
		return 0;
}

static  void cf_ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq)
{
	unsigned long reg;
	int i;
	int regincr = 1;
	
	regincr = 1 <<0;

	memset(hw, 0, sizeof(*hw));

	 reg = (unsigned long)data_port;

	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
		hw->io_ports[i] = reg;
		reg += regincr;
	}
	
	hw->io_ports[IDE_CONTROL_OFFSET] = (unsigned long) ctrl_port;
	
	if (irq)
		*irq = 0;
 }

static void release_none(struct device * dev)
{
}

static struct device_driver pd6710_driver = {
	.name = "pd6710",
	.bus = &platform_bus_type,
};

static struct platform_device pd6710_device = {
	.name = "pd6710",
	.id = 0,
	.dev={
			.release = release_none,
		}
};

static int __init init_pd6710(void)
{
    	int ret;
	int cf_base_io, cf_base_ctrl;
	hw_regs_t hw_ide;

	cf_base = ioremap(S3C2410_CF_BASE, 0x10000);
	if(cf_base==NULL) {
		printk("unable to remap,NULL pointer!!!\n");
		return -1;
	}

   	ret = driver_register(&pd6710_driver);
    	if (ret)
		goto failed_driver;

    	ret = platform_device_register(&pd6710_device);
    	if (ret) 
		goto failed_device;

	//pd6710--nGCS2--bank2
	//BWSCON =BWSCON & ~(0x0f<< 8) | (0x0d << 8);
	//BANKCON2=(0<<13) | (3<<11) | (7<<8) | (1 <<6) | (0<<4) | (3<<2) |0;
	
 	if (ini_pcmcia_bridge(0) != 0) {				// 添加PCMCIA桥接口处理函数,
		printk("pd6710 not found.\n");
		goto failed_device;
	}

  	pd6710_ini_ata(0);							// 初始化PD6710 ATA 模式相关寄存器

	cf_base_io = (int)cf_base+0x1f0;
	cf_base_ctrl = (int)cf_base+0x3f6;

	// init the interface
	cf_ide_init_hwif_ports(&hw_ide, cf_base_io, cf_base_ctrl, NULL);
	
	hw_ide.irq = S3C2410_CFP_IRQ;
	writel((readl(S3C2410_GPGUP) & ~(0x01)) | (0x01), S3C2410_GPGUP);		//pull up disable
	writel((readl(S3C2410_GPGCON) & ~(0x03)) | (0x02), S3C2410_GPGCON);  	//Pin function EINT8
	//writel((readl(S3C2410_EXTINT1) & ~(0x0f)) | (0x04), S3C2410_EXTINT1);  	//rising edge  triger
	//set_irq_type(hw_ide.irq, IRQT_RISING);
	writel((readl(S3C2410_EXTINT1) & ~(0x0f)) | (0x01), S3C2410_EXTINT1);  	//high level triger
	set_irq_type(hw_ide.irq, IRQT_HIGH);

	ide_index = ide_register_hw(&hw_ide, NULL);
	if(ide_index < 0) {
		printk(KERN_INFO "ide_register_hw return %d,failed\n", ide_index);
		goto failed_device;
	}
	printk(KERN_INFO "ide_register_hw return %d,successed\n", ide_index);

	return 0;
	
failed_device:
	platform_device_unregister(&pd6710_device);
	
failed_driver:

	iounmap(cf_base);
	driver_unregister(&pd6710_driver);
	
	return -ENODEV;   
}

static void __exit exit_pd6710(void)
{
	printk("exit the module!!!\n");
	if(ide_index != -1) 
		ide_unregister(ide_index);
	
    	platform_device_unregister(&pd6710_device);
    	driver_unregister(&pd6710_driver);
	iounmap(cf_base);
} 

module_init(init_pd6710);
module_exit(exit_pd6710);

MODULE_LICENSE("Dual MPL/GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -