📄 at91_port.c
字号:
/************************************************************
Copyright (C), 2005-2010, Embedded System of China Tech. Co., Ltd.
www.emsyschina.com
FileName: at91_port.c
Author: Version : Date: Casiawu(wujh@emsyschina.com)
Description: // PORT驱动程序模块
1. -------
History: // 历史修改记录
<author> <time> <version > <desc>
casiawu 2008/2/12 1.0 build this module for linux (2.6.21)
***********************************************************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#include <linux/timer.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <asm/uaccess.h>
#include <asm/arch/hardware.h> //必须
#include <asm/arch/io.h> //包含at91_sys_write()
#include <asm/arch/at91rm9200.h> //包含各个基地址(必须)
#include <asm/arch/at91rm9200_mc.h> //包含EBI_SMC2_CSR[]
#include <asm/arch/at91_pio.h> //包含GPIO寄存器
#include <asm/arch/at91_pmc.h> //包含GPIO寄存器
#include <asm/arch/gpio.h>
#undef DPRINTK /* undef it, just in case */
#ifdef PORT_DEBUG
/* This one if debugging is on, and kernel space */
#define DPRINTK(fmt, args...) printk("port: "fmt, ## args)
#else
#define DPRINTK(fmt, args...) /* not debugging: nothing */
#endif
//定义设置读写的PORT地址
static unsigned int PortAddr=0x0;
module_param(PortAddr, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(PortAddr, "The PortAddr for Reading and Writing");
//定义设置读写的数据宽度
static unsigned short WrRdWidth=16;
module_param(WrRdWidth, short, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(WrRdWidth, "The DataWidth for Reading and Writing");
//定义设置读写的PORT设备名
static unsigned int PortLen =0x10;
module_param(PortLen, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(PortLen, "The PortLen for Reading and Writing");
#define PORTDEV "port0"
typedef struct _para_s
{
unsigned int data;
unsigned short offset;
unsigned short type;
}para_s,*para_t;
/*---------------------------------------------------------
//全局变量、常量定义:
---------------------------------------------------------*/
static int port_major=0;
static struct class* port_class;
//设备指针
static struct platform_device* port_devices = NULL;
static struct cdev port_chrdev;
static unsigned long Port_VirAddr=0;
/*---------------------------------------------------------
//open函数;
//---------------------------------------------------------*/
static int port_open(struct inode * s_node,struct file * s_file)
{
try_module_get(THIS_MODULE);
return 0;
}
/*---------------------------------------------------------
//close函数;
//---------------------------------------------------------*/
static int port_close(struct inode * s_node,struct file * s_file)
{
module_put(THIS_MODULE);
return 0;
}
/*---------------------------------------------------------
//read函数;
//
//---------------------------------------------------------*/
static int port_read(struct file*s_file, char *r_buf,int len,loff_t* loff)
{
unsigned char IO_data0=0;
unsigned short IO_data1=0;
unsigned int IO_data2=0;
para_s parameter;
if(copy_from_user(¶meter,r_buf,sizeof(para_s)))
return -EFAULT;
switch(parameter.type)
{
//byte
case 1:
IO_data0 = __raw_readb(Port_VirAddr + parameter.offset);
rmb();
parameter.data = IO_data0;
break;
//half-word
case 2:
IO_data1 = __raw_readw(Port_VirAddr + parameter.offset);
rmb();
parameter.data = IO_data1;
break;
//word
case 4:
IO_data2 = __raw_readl(Port_VirAddr + parameter.offset);
rmb();
parameter.data = IO_data2;
break;
default:
return -1;
}
if((copy_to_user(r_buf,¶meter,sizeof(para_s))))
return -EFAULT;
return sizeof(para_s);
}
/*---------------------------------------------------------
//write函数;
//---------------------------------------------------------*/
static int port_write(struct file*s_file, const char *w_buf,int len,loff_t* loff)
{
unsigned char IO_data0=0;
unsigned short IO_data1=0;
unsigned int IO_data2=0;
para_s parameter;
if(copy_from_user(¶meter,w_buf,sizeof(para_s)))
return -EFAULT;
switch(parameter.type)
{
//byte
case 1:
//printk("offset=%d\n\r",parameter.offset);
IO_data0 = parameter.data;
//printk("IO_data0=%x\n\r",IO_data0);
__raw_writeb(IO_data0, Port_VirAddr + parameter.offset);
wmb();
udelay(10);
break;
//half-word
case 2:
IO_data1 = parameter.data;
__raw_writew(IO_data1, Port_VirAddr + parameter.offset);
wmb();
break;
//word
case 4:
IO_data2 = parameter.data;
__raw_writel(IO_data2,Port_VirAddr+parameter.offset);
wmb();
break;
default:
break;
}
return sizeof(para_s);
}
/*---------------------------------------------------------
//文件操作结构体;
---------------------------------------------------------*/
struct file_operations port_fops =
{
.read = (void(*)) port_read,
.write = (void(*)) port_write,
.open = (void(*)) port_open,
.release = (void(*)) port_close,
};
// 板载GPIO寄存器设置
static int port_config(void)
{
unsigned char bank=0,csr=0;
unsigned int width=0;
bank = (unsigned char)((PortAddr & 0xF0000000) >> 28) ;
printk("bank=%d\n\r",bank);
//设置所有端口
switch(bank)
{
//bank 7
case 8:
//PIO Enable A Register
at91_set_A_periph(AT91_PIN_PC13, 0);
csr = 7;
switch(WrRdWidth)
{
case 8:
width = AT91_SMC_DBW_8;
break;
case 16:
default:
width = AT91_SMC_DBW_16;
break;
}
break;
//bank 6
case 7:
//PIO Enable A Register
at91_set_A_periph(AT91_PIN_PC12, 0);
csr = 6;
switch(WrRdWidth)
{
case 8:
width = AT91_SMC_DBW_8;
break;
case 16:
default:
width = AT91_SMC_DBW_16;
break;
}
break;
//bank 5
case 6:
//PIO Enable A Register
at91_set_A_periph(AT91_PIN_PC11, 0);
csr = 5;
switch(WrRdWidth)
{
case 8:
width = AT91_SMC_DBW_8;
break;
case 16:
default:
width = AT91_SMC_DBW_16;
break;
}
break;
//bank 4
case 5:
//PIO Enable A Register
at91_set_A_periph(AT91_PIN_PC10, 0);
csr = 4;
switch(WrRdWidth)
{
case 8:
width = AT91_SMC_DBW_8;
break;
case 16:
default:
width = AT91_SMC_DBW_16;
break;
}
break;
default:
return -1;
}
//定义EBI控制寄存器的读写参数
at91_sys_write(AT91_SMC_CSR(csr),((AT91_SMC_NWS & 0x3) | AT91_SMC_WSEN
| (AT91_SMC_TDF & 0x100) | AT91_SMC_BAT | width | (AT91_SMC_RWHOLD & (0x1<<28))));
//申请内存区域,以检测该地址空间是否被使用;
if (!request_mem_region(PortAddr,PortLen,PORTDEV))
printk("Error request mem address! \r\n");
//进行内存区域的映射,把物理地址映射为逻辑地址;
Port_VirAddr = (unsigned long)ioremap_nocache(PortAddr,PortLen);
return 0;
}
//系统探测函数
static int __devinit port_probe(struct platform_device *pdev)
{
int ret;
dev_t dev_id;
struct class_device* cls_port_dev;
//PORT 寄存器配置
if(port_config() < 0 )
return -1;
printk("device %s-%d detected!\n", pdev->name, pdev->id);
dev_id = MKDEV(port_major, 0);
pdev->dev.devt = dev_id;
cdev_init(&port_chrdev, &port_fops);
port_chrdev.owner = THIS_MODULE;
ret = cdev_add(&port_chrdev, dev_id, 1);
if (ret)
{
printk("fail to register driver for %s %d!\n",PORTDEV, pdev->id);
return ret;
}
platform_set_drvdata(pdev, &port_chrdev);
cls_port_dev = class_device_create(port_class,NULL,dev_id,&pdev->dev,PORTDEV);
if (IS_ERR(cls_port_dev))
return PTR_ERR(cls_port_dev);
DPRINTK("driver for %s.%d (%d,%d) registered\n",PORTDEV, 0, MAJOR(dev_id), MINOR(dev_id));
return ret;
}
static int __devexit port_remove(struct platform_device *pdev)
{
struct cdev* chrdev;
iounmap((void *)Port_VirAddr);
//释放申请的内存区域; release_mem_region(PortAddr,PortLen);
class_device_destroy(port_class, pdev->dev.devt);
chrdev = platform_get_drvdata(pdev);
if (chrdev)
cdev_del(&port_chrdev);
platform_set_drvdata(pdev, NULL);
pdev->dev.devt = 0;
printk("%s removed!\n",PORTDEV);
return 0;
}
#ifdef CONFIG_PM
static int port_suspend(struct platform_device *pdev, pm_message_t state)
{
return 0;
}
static int port_resume(struct platform_device *pdev)
{
return 0;
}
#else
#define port_suspend NULL
#define port_resume NULL
#endif
static struct platform_driver port_driver =
{
.probe = port_probe,
.remove = __devexit_p(port_remove),
#ifdef CONFIG_PM
.suspend = port_suspend,
.resume = port_resume,
#endif
.driver =
{
.name = PORTDEV,
.owner = THIS_MODULE,
},
};
//*********************************************************
//初始化模块函数;
//*********************************************************
static int __init port_init_module(void)
{
int ret;
dev_t dev = MKDEV(port_major, 0);
printk("PortAddr is the port phyaddr: 0x%x\n", PortAddr);
printk("WrRdWidth is the operation width: %d\n", WrRdWidth);
printk("PortLen is port devname: 0x%x\n", PortLen);
port_devices = platform_device_alloc(PORTDEV, 0);
if (!port_devices)
return -ENOMEM;
ret = platform_device_add(port_devices);
if (ret < 0) {
platform_device_put(port_devices);
return ret;
}
/* Figure out our device number. */
if (port_major)
ret = register_chrdev_region(dev, 1, PORTDEV);
else
{
ret = alloc_chrdev_region(&dev, 0, 1, PORTDEV);
if (ret)
{
printk(KERN_WARNING "GPIO_MODULE_NAME: unable to get major %d\n", port_major);
return ret;
}
port_major = MAJOR(dev);
}
//create class
port_class = class_create(THIS_MODULE, PORTDEV);
if (IS_ERR(port_class))
return PTR_ERR(port_class);
ret = platform_driver_register(&port_driver);
return ret;
}
//*********************************************************
//清除模块函数;
//*********************************************************
static void __exit port_cleanup_module(void)
{
platform_driver_unregister(&port_driver);
class_destroy(port_class);
unregister_chrdev_region(MKDEV(port_major, 0), 1);
platform_device_unregister(port_devices);
}
module_init(port_init_module);
module_exit(port_cleanup_module);
MODULE_AUTHOR("casiawu");
MODULE_DESCRIPTION("AT91 PORT Driver (PORT)");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -