📄 pd6700.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 + -