本文主要是MPC8347 GPIO控制驱动程序
驱动代码:
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm-powerpc/io.h>
MODULE_LICENSE("GPL");
#define GPIO_MODULE_MAJOR 249
#define GPIO_MODULE_NAME "mpc8347_gpio"
#define MEM_SIZE 0x200000
#define MPC8347_GPIO_ADDR 0xe0000c00
#define MPC8347_GPIO_MAPSIZE 0xff
#define FPGA_DOWNLOAD 0
#define FAN1_CONTROL 1
#define FAN2_CONTROL 2
#define MEM_CLEAR 3
#define MPC8347_GPIO_BYTENUMBER 8
#define MPC8347_GPIO_FPGA_CONFIG_RISE_DELAY_COUNTER 50
#define MPC8347_GPIO_FAN1_CONTROL_INDEX 0
#define MPC8347_GPIO_FAN2_CONTROL_INDEX 9
#define MPC8347_GPIO_FPGA_DONE_INDEX 1
#define MPC8347_GPIO_FPGA_DATA_INDEX 2
#define MPC8347_GPIO_FPGA_DCLK_INDEX 3
#define MPC8347_GPIO_FPGA_STATUS_INDEX 4
#define MPC8347_GPIO_FPGA_CONFIG_INDEX 5
#define MPC8347_GPIO_FPGA_INITDONE_INDEX 6
struct mpc8347_gpio_dev
{
struct cdev cdev;
u8 mem[MEM_SIZE];
};
struct mpc8347_gpio_dev *mpc8347_gpio_devp = NULL;
typedef struct mpc8347_gpio
{
u32 dir; /* direction register */
u32 odr; /* open drain register */
u32 dat; /* data register */
u32 ier; /* interrupt event register */
u32 imr; /* interrupt mask register */
u32 icr; /* external interrupt control register */
u8 res0[0xe8];
}mpc8347_gpio;
typedef struct mpc8347_gpio_0
{
mpc8347_gpio gpio[1];
}MPC8347_GPIO;
static unsigned int mpc8347_gpio_addr = 0;
static void mpc8347_gpio_setdirectionin(u8 bitnumber)
{
volatile MPC8347_GPIO *im = (MPC8347_GPIO *)mpc8347_gpio_addr;
u32 direction = 0;
direction = im->gpio[0].dir;
direction &= (~(1<<(31-bitnumber)));
im->gpio[0].dir = direction;
}
static void mpc8347_gpio_setdirectionout(u8 bitnumber)
{
volatile MPC8347_GPIO *im = (MPC8347_GPIO *)mpc8347_gpio_addr;
u32 direction = 0;
direction = im->gpio[0].dir;
direction |= (1<<(31-bitnumber));
im->gpio[0].dir = direction;
}
static void mpc8347_gpio_setbitlow(u8 bitnumber)
{
volatile MPC8347_GPIO *im = (MPC8347_GPIO *)mpc8347_gpio_addr;
u32 gpiodata = 0;
gpiodata = im->gpio[0].dat;
gpiodata &= (~(1<<(31-bitnumber)));
im->gpio[0].dat = gpiodata;
}
static void mpc8347_gpio_setbithigh(u8 bitnumber)
{
volatile MPC8347_GPIO *im = (MPC8347_GPIO *)mpc8347_gpio_addr;
u32 gpiodata = 0;
gpiodata = im->gpio[0].dat;
gpiodata |= (1<<(31-bitnumber));
im->gpio[0].dat = gpiodata;
}
int mpc8347_gpio_getbit(u8 bitnumber)
{
volatile MPC8347_GPIO *im = (MPC8347_GPIO *)mpc8347_gpio_addr;
u32 gpiodata = 0;
gpiodata = ((im->gpio[0].dat)>>(31-bitnumber))&0x1;
return gpiodata;
}
static int mpc8347_gpio_fpga_config_init()
{
u32 timer = MPC8347_GPIO_FPGA_CONFIG_RISE_DELAY_COUNTER;
/* keep the FPGA_CONFIG high & FPGA_DCLK low */
mpc8347_gpio_setbithigh(MPC8347_GPIO_FPGA_CONFIG_INDEX);
mpc8347_gpio_setbitlow(MPC8347_GPIO_FPGA_DCLK_INDEX);
/* delay 10us */
udelay(10);
/* need to set program low*/
mpc8347_gpio_setbitlow(MPC8347_GPIO_FPGA_CONFIG_INDEX);
/* delay 2us at least, delay 5us here */
udelay(5);
/* pull up the program pin high */
mpc8347_gpio_setbithigh(MPC8347_GPIO_FPGA_CONFIG_INDEX);
/* delay at least 40 us from high on CONFIG to first rising edge on CLK, delay 100us here */
while(timer--)
{
udelay(1);
}
return 0;
}
static int mpc8347_gpio_checkfpgacfgdone()
{
return mpc8347_gpio_getbit(MPC8347_GPIO_FPGA_DONE_INDEX);
}
int fpga_download(u8 *imageaddr,int imagesize)
{
u8 bitnum = 0, bitvalue = 0;
u32 curpos = 0;
u8 imagebyte = 0,cfgdone = 0;
/* fpga config init */
mpc8347_gpio_fpga_config_init();
/*download fpga image ,it's rbf format*/
for(curpos = 0; curpos < imagesize ; curpos++)
{
/* get fpga image byte */
imagebyte = *(imageaddr+curpos);
/* down dowload bit */
for(bitnum = 0 ;bitnum < MPC8347_GPIO_BYTENUMBER ; bitnum++)
{
bitvalue = (imagebyte>>bitnum) & 0x1;
if(1 == bitvalue )
{
/*set data high*/
mpc8347_gpio_setbithigh(MPC8347_GPIO_FPGA_DATA_INDEX);
//udelay(1);
/*set clock high*/
mpc8347_gpio_setbithigh(MPC8347_GPIO_FPGA_DCLK_INDEX);
//udelay(1);
/*set clock low*/
mpc8347_gpio_setbitlow(MPC8347_GPIO_FPGA_DCLK_INDEX);
}
if(0 == bitvalue )
{
/*set data low*/
mpc8347_gpio_setbitlow(MPC8347_GPIO_FPGA_DATA_INDEX);
//udelay(1);
/*set clock high*/
mpc8347_gpio_setbithigh(MPC8347_GPIO_FPGA_DCLK_INDEX);
//udelay(1);
/*set clock low*/
mpc8347_gpio_setbitlow(MPC8347_GPIO_FPGA_DCLK_INDEX);
}
}
}
/* config is finished ,now we check the config done*/
cfgdone = mpc8347_gpio_checkfpgacfgdone();
return cfgdone ;
}
int mpc8347_gpio_fpga_setGP1DIR(void)
{
mpc8347_gpio_setdirectionin(MPC8347_GPIO_FPGA_DONE_INDEX);
mpc8347_gpio_setdirectionout(MPC8347_GPIO_FPGA_DATA_INDEX);
mpc8347_gpio_setdirectionout(MPC8347_GPIO_FPGA_DCLK_INDEX);
mpc8347_gpio_setdirectionin(MPC8347_GPIO_FPGA_STATUS_INDEX);
mpc8347_gpio_setdirectionout(MPC8347_GPIO_FPGA_CONFIG_INDEX);
mpc8347_gpio_setdirectionin(MPC8347_GPIO_FPGA_INITDONE_INDEX);
return 0;
}
int mpc8347_gpio_fancontrol_setGP1DIR()
{
mpc8347_gpio_setdirectionout(MPC8347_GPIO_FAN1_CONTROL_INDEX);
mpc8347_gpio_setdirectionout(MPC8347_GPIO_FAN2_CONTROL_INDEX);
return 0;
}
int mpc8347_gpio_open(struct inode *inode,struct file *filp)
{
printk("mpc8347 gpio open\n");
filp->private_data = mpc8347_gpio_devp;
return 0;
}
int mpc8347_gpio_release(struct inode *inode,struct file *filp)
{
printk("mpc8347 gpio release\n");
filp->private_data = NULL;
return 0;
}
static ssize_t mpc8347_gpio_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
unsigned long p = *ppos;
int ret = 0;
struct mpc8347_gpio_dev *dev = filp->private_data;
if(p >= MEM_SIZE)
return 0;
if(count > MEM_SIZE -p)
count = MEM_SIZE -p;
if(0 != copy_from_user(dev->mem + p,buf,count))
{
printk("mpc8347_gpio_write copy_from_user error!\n");
ret = -EFAULT;
}
else
{
*ppos += count;
ret = count;
}
return ret;
}
int mpc8347_gpio_ioctl(struct inode *inode,struct file *filp,unsigned int cmd,unsigned long arg)
{
int ret = 0;
u8 *imageaddr = NULL;
int imagesize = 0;
struct mpc8347_gpio_dev *dev = filp->private_data;
switch(cmd)
{
case MEM_CLEAR:
memset(dev->mem,0,MEM_SIZE);
break;
case FPGA_DOWNLOAD:
mpc8347_gpio_fpga_setGP1DIR();/* set GP1DIR direction register */
imageaddr = (dev->mem);
imagesize = (int)arg;
ret = fpga_download(imageaddr,imagesize);
if(ret)/* fpga download success,delay 10us,complete the fpga initialization*/
{
//udelay(10);
printk("fpga download success\n");
}
else
{
printk("fpga download failed!\n");
return -1;
}
break;
case FAN1_CONTROL:
mpc8347_gpio_fancontrol_setGP1DIR();
if(arg == 1)
{
mpc8347_gpio_setbithigh(MPC8347_GPIO_FAN1_CONTROL_INDEX);
}
else if(arg == 0)
{
mpc8347_gpio_setbitlow(MPC8347_GPIO_FAN1_CONTROL_INDEX);
}
else
{
printk("fan1 control invalid parameters\n");
return -1;
}
break;
case FAN2_CONTROL:
mpc8347_gpio_fancontrol_setGP1DIR();
if(arg == 1)
{
mpc8347_gpio_setbithigh(MPC8347_GPIO_FAN2_CONTROL_INDEX);
}
else if(arg == 0)
{
mpc8347_gpio_setbitlow(MPC8347_GPIO_FAN2_CONTROL_INDEX);
}
else
{
printk("fan2 control invalid parameters\n");
return -1;
}
break;
default:
break;
}
return 0;
}
static struct file_operations mpc8347_gpio_fops=
{
.owner = THIS_MODULE,
.open = mpc8347_gpio_open,
.release = mpc8347_gpio_release,
.write = mpc8347_gpio_write,
.ioctl = mpc8347_gpio_ioctl,
};
static void mpc8347_gpio_setup_cdev(struct mpc8347_gpio_dev *dev,int index)
{
int err = -1;
int devno = MKDEV(GPIO_MODULE_MAJOR,index);
cdev_init(&dev->cdev,&mpc8347_gpio_fops);
dev->cdev.owner = THIS_MODULE;
err = cdev_add(&dev->cdev,devno,1);
if(err)
{
printk("Error %d adding mpc8347 gpio %d\n",err,index);
}
}
static int __init mpc8347_gpio_init(void)
{
int ret = -1;
dev_t devno;
mpc8347_gpio_addr = (unsigned int)ioremap_nocache(MPC8347_GPIO_ADDR,MPC8347_GPIO_MAPSIZE);
if(mpc8347_gpio_addr == 0)
{
printk("failed to ioremap\n");
return -EIO;
}
devno = MKDEV(GPIO_MODULE_MAJOR,0);
ret = register_chrdev_region(devno,1,GPIO_MODULE_NAME);
if(ret != 0)
{
printk("%s:can't get major %d\n",GPIO_MODULE_NAME,GPIO_MODULE_MAJOR);
goto iounmap_gpio;
}
mpc8347_gpio_devp = kmalloc(sizeof(struct mpc8347_gpio_dev),GFP_KERNEL);
if(mpc8347_gpio_devp == NULL)
{
goto unregister_chrdev;
}
memset(mpc8347_gpio_devp,0,sizeof(struct mpc8347_gpio_dev));
mpc8347_gpio_setup_cdev(mpc8347_gpio_devp,0);
goto out;
unregister_chrdev:
unregister_chrdev_region(devno,1);
iounmap_gpio:
iounmap ((void *)mpc8347_gpio_addr);
mpc8347_gpio_addr = 0;
return -1;
out:
return 0;
}
static void __exit mpc8347_gpio_exit(void)
{
if(mpc8347_gpio_addr)
{
iounmap((void *)mpc8347_gpio_addr);
mpc8347_gpio_addr = 0;
}
cdev_del(&mpc8347_gpio_devp->cdev);
kfree(mpc8347_gpio_devp);
mpc8347_gpio_devp = NULL;
unregister_chrdev_region(MKDEV(GPIO_MODULE_MAJOR,0),1);
}
module_init(mpc8347_gpio_init);
module_exit(mpc8347_gpio_exit);