GPIO驱动

本文主要是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);


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: GPIO是英文General Purpose Input/Output的缩写,翻译过来就是通用输入输出。Linux内核提供了GPIO驱动框架,可以通过该框架来控制硬件上的GPIO,实现对外设的控制。 在Linux内核中,GPIO驱动可以分为两类:基于平台的GPIO驱动和基于设备的GPIO驱动。基于平台的GPIO驱动是针对整个平台的GPIO控制,而基于设备的GPIO驱动则是针对单个设备的GPIO控制。 在使用GPIO驱动时,需要先找到所使用的GPIO引脚的编号,并将其映射到内存中的地址。然后通过读写内存中的寄存器来控制GPIO的状态。 对于GPIO的操作可以通过Linux内核提供的sysfs接口来实现。在sysfs中,每个GPIO都被表示为一个文件,可以通过读写文件来进行GPIO的操作。 需要注意的是,在使用GPIO驱动时,需要谨慎操作,避免对硬件造成损坏。同时,还需要了解所使用的硬件设备的特性和限制,以确保GPIO驱动的正确使用。补充说明: 在Linux内核中,GPIO驱动主要由GPIO子系统和GPIO控制器驱动两部分组成。GPIO子系统提供了一个通用的接口,用于操作GPIO控制器驱动,而GPIO控制器驱动则是实际控制硬件的部分。 GPIO子系统可以分为两个部分:GPIO框架和GPIO API。GPIO框架是一个通用的框架,用于管理GPIO控制器和GPIO设备,它定义了一些数据结构和函数接口,用于注册和管理GPIO控制器和GPIO设备。GPIO API是一个用户空间的API,提供了一些函数接口,用于操作GPIOGPIO控制器驱动是针对特定的GPIO控制器的驱动程序,它负责实际控制GPIO的硬件操作。在Linux内核中,每种GPIO控制器都有一个对应的GPIO控制器驱动程序。当使用GPIO时,首先需要通过GPIO子系统将GPIO控制器驱动注册到系统中,然后才能使用GPIO API对GPIO进行操作。 需要注意的是,在使用GPIO驱动时,需要注意GPIO的电气特性,避免对硬件造成损坏。同时,在进行GPIO操作时,还需要注意GPIO的并发访问和竞争问题,以确保系统的正确性和稳定性。 ### 回答2: Linux GPI驱动指的是Linux系统中通过General Purpose Input/Output(GPIO)接口与硬件设备进行交互的驱动程序。GPIO接口是一组通用的、可编程的多功能引脚,可用于连接各种外部设备,例如开关、LED、传感器、驱动器等。 Linux GPIO驱动可以实现对GPIO引脚的读写操作、中断处理等功能。它不仅可以与单片机等嵌入式设备进行通信,还可与各种外接硬件设备进行连接和通信。 在Linux系统中,用户可以通过/sys/class/gpio文件系统来访问GPIO引脚。在使用GPIO驱动时,用户需要首先加载相应的内核模块,然后使用GPIO API来对引脚进行读写操作或开启中断。 GPIO驱动程序需要实现以下功能: 1. 查询GPIO可用性及分配资源。通常,由于GPIO是多路的,因此设备需要分配资源共享GPIO。 2. 初始化GPIO引脚,包括定义方向及设置上下拉电阻等。 3. 实现GPIO引脚的读写操作。 4. 解除分配资源并释放相关资源。 正常情况下,GPIO驱动程序会提供一个设备文件,用户可以通过读写该文件实现GPIO引脚的操作。 总之,Linux GPIO驱动具有良好的可移植性和稳定性,可以方便地与其他硬件设备进行交互,因此被广泛应用于各种嵌入式设备和嵌入式系统中。 ### 回答3: Linux GPIO驱动是一种在嵌入式系统中实现通用输入输出(GPIO,General Purpose Input/Output)功能的软件驱动GPIO是一种非常有用的硬件资源,它可以连接到外部设备,例如LED灯、按键和触摸屏等。 Linux内核支持GPIO操作,当你的嵌入式系统上有GPIO设备时,你可以利用GPIO来读取或设置其状态。驱动程序能够将GPIO标记为输入或输出,并且它们可以在运行时进行配置。 在Linux中,一般有两种方式将GPIO驱动程序添加到内核中:一种是将其编译到内核中,另一种是将其作为模块加载。 GPIO驱动程序等价于操作系统提供的设备文件,例如/dev/gpiochip0,它允许用户空间应用程序访问GPIO。这些设备文件可用于读取或写入GPIO状态。例如,要控制一个LED,需要将GPIO设置为输出模式,然后将其电平设置为高或低即可。 除此之外,GPIO驱动程序也可以实现中断(interrupt)机制,GPIO的状态变化时可以产生中断事件,这常用于处理GPIO键盘或GPIO中断信号的应用场景。 总结来说,Linux内核支持GPIO驱动需要有以下几个步骤:配置GPIO硬件;添加驱动程序;编写用户空间应用程序,按需要读取或设置GPIO状态来和外设交互。GPIO驱动程序是嵌入式系统中非常必要的组成部分,它们能够随时提供接口以方便对外部设备的读写访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值