前言
基于imx283a的一个简单驱动程序
一、GPIO申请
int gpio_request(unsigned gpio, const char *label) //申请引脚资源
gpio:为对应哪一个引脚
label:引脚名
#define LED1_GPIO MXS_PIN_TO_GPIO(PINID_SAIF1_SDATA0)//p3.26
gpio_request(LED1_GPIO,"led1");
二、操作函数
int gpio_direction_output(unsigned gpio, int value)//引脚作为输出是一定要调此函数
int gpio_direction_input(unsigned gpio) //作为输入时调用
int gpio_get_value(unsigned int gpio) //读取引脚状态
void gpio_set_value(unsigned int gpio, int value) //写操作
gpio:哪个引脚
value:设置高低电平 0 or 1
gpio_direction_output(LED1_GPIO,data[0]); //写
gpio_direction_input(LED1_GPIO); //读引脚之前要调用
ret = gpio_get_value(LED1_GPIO); //读
gpio_set_value(LED1_GPIO,data[0]); //写
注:IO脚只能是输出或者输入 不能同时满足 即输出的值再用get_value得到的不一定正确 只能用变量来维护
三、GPIO释放
void gpio_free(unsigned gpio)
gpio_free(LED1_GPIO);
ioctl、write控制亮灭 read、ioctl实时读取 led.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/capability.h>
#include <linux/rtc.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <../arch/arm/mach-mx28/mx28_pins.h>
#define DEVICE_NAME "imx28x_led"
#define LED1_GPIO MXS_PIN_TO_GPIO(PINID_SAIF1_SDATA0)
static int led_open(struct inode *inode, struct file *filp);
static int led_release(struct inode *inode, struct file *filp);
static int led_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg);
static int led_init(void);
static void led_exit(void);
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos);
static ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
char ledstatu;
static int led_open(struct inode *inode, struct file *filp)
{
gpio_request(LED1_GPIO,"led1");
gpio_direction_output(LED1_GPIO,1);
ledstatu = 0;
return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
gpio_free(LED1_GPIO);
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
char data[2];
copy_from_user(data,buf,count);
gpio_direction_output(LED1_GPIO,data[0]);
ledstatu = data[0];
return count;
}
static ssize_t led_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
copy_to_user(buf, &ledstatu, 1);
return 1;
}
static int led_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
{
switch(command)
{
case 0:
gpio_direction_output(LED1_GPIO,1);
ledstatu = 0;
break;
case 1:
gpio_direction_output(LED1_GPIO,0);
ledstatu = 1;
break;
case 2:
copy_to_user(&arg,(int *)&ledstatu,1);
break;
}
return 0;
}
static struct file_operations led_fops =
{
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.ioctl = led_ioctl,
.read = led_read,
};
static struct miscdevice led_miscdevice =
{
.minor = MISC_DYNAMIC_MINOR, //次设备
.name = DEVICE_NAME, //设备名 open调用时的名称
.fops = &led_fops, //操作结构体实现功能
};
static int __init led_init(void)
{
misc_register(&led_miscdevice);
return 0;
}
static void __exit led_exit(void)
{
misc_deregister(&led_miscdevice);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("Dual BSD/GPL");
main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <time.h>
#include <pthread.h>
int main(void)
{
int fd;
char buf[2];
int cmd;
fd = open("/dev/imx28x_led", O_RDWR);
if (fd < 0)
{
perror("open /dev/imx283_led");
return;
}
while(1)
{
printf("pleasure input led1 status....\n");
scanf("%d", &cmd);
// write(fd,&(char)cmd,1);
ioctl(fd, cmd, 1); //写状态
// read(fd, buf, 1); //read 读取状态
ioctl(fd,2,cmd); //ioctl读取状态
printf("led1 status:%d\r\n",cmd);
}
close(fd);
}
实现一个混杂设备对应一个io。
init:
init时进行一个io对应一个混杂设备的注册(遍历注册)、对混杂设备的成员进行赋值,公用一个操作结构体,动态注册次设备号所得到的次设备号,作为数组的索引,类似于奖所有的io脚及信息按次设备号进行排序
操作时:
要进行某个io的操作时,用户层调用open进而进入gpio_open,根据调用时所得到的inode获得minor,
通过minor找到对应io脚的pin,再进行gpio_request的申请,之后将io信息的地址通过filp->private_data绑定,
方便之后调用write,read,ioctl时知道对应知道操作那个引脚
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/bcd.h>
#include <linux/capability.h>
#include <linux/rtc.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <../arch/arm/mach-mx28/mx28_pins.h>
#include "gpio.h"
#define ZLG_IMX_283 0
#define ZLG_IMX_287 1
#define ZLG_IMX_280 2
extern int zlg_board_type;
struct gpio_info {
u32 pin;
char pin_name[20];
struct miscdevice *pmiscdev;
};
static struct gpio_info *gpio_info_file[255];
static struct gpio_info *all_gpios_info;
static struct gpio_info all_gpios_info_287B[] ={
};
static struct gpio_info all_gpios_info_280[] ={
};
static struct gpio_info all_gpios_info_283[] ={
{PINID_AUART0_CTS, "gpio-DURX", NULL},
{PINID_AUART0_RTS, "gpio-DUTX", NULL},
{PINID_AUART0_RX, "gpio-URX0", NULL},
{PINID_AUART0_TX, "gpio-UTX0", NULL},
{PINID_AUART1_RX, "gpio-URX1", NULL},
{PINID_AUART1_TX, "gpio-UTX1", NULL},
{PINID_SSP2_SCK, "gpio-URX2", NULL},
{PINID_SSP2_MOSI, "gpio-UTX2", NULL},
{PINID_SSP2_MISO, "gpio-URX3", NULL},
{PINID_SSP2_SS0, "gpio-UTX3", NULL},
{PINID_SAIF0_BITCLK, "gpio-URX4", NULL},
{PINID_SAIF0_SDATA0, "gpio-UTX4", NULL},
/* modify by luozhizhuo*/
{PINID_GPMI_RDY3, "gpio-CRX0", NULL},
{PINID_GPMI_RDY2, "gpio-CTX0", NULL},
{PINID_GPMI_CE3N, "gpio-CRX1", NULL},
{PINID_GPMI_CE2N, "gpio-CTX1", NULL},
{PINID_LCD_D22, "gpio-RUN", NULL},
{PINID_LCD_D23, "gpio-ERR", NULL},
/*end modify*/
{PINID_SSP3_MISO, "gpio-MISO", NULL},
{PINID_SSP3_MOSI, "gpio-MOSI", NULL},
{PINID_SSP3_SCK, "gpio-CLK", NULL},
{PINID_SSP3_SS0, "gpio-CS", NULL},
{PINID_PWM1, "gpio-SDA", NULL},
{PINID_PWM0, "gpio-SCL", NULL},
{PINID_LCD_D17, "gpio-P1.17", NULL},
{PINID_LCD_D18, "gpio-P1.18", NULL},
{PINID_SSP0_DATA4, "gpio-P2.4", NULL},
{PINID_SSP0_DATA5, "gpio-P2.5", NULL},
{PINID_SSP0_DATA6, "gpio-P2.6", NULL},
{PINID_SSP0_DATA7, "gpio-P2.7", NULL},
{PINID_SSP1_SCK, "gpio-P2.12", NULL},
{PINID_SSP1_CMD, "gpio-P2.13", NULL},
{PINID_SSP1_DATA0, "gpio-P2.14", NULL},
{PINID_SSP1_DATA3, "gpio-P2.15", NULL},
{PINID_SAIF0_MCLK, "gpio-P3.20", NULL},
{PINID_SAIF0_LRCLK, "gpio-P3.21", NULL},
{PINID_SAIF1_SDATA0, "gpio-P3.26", NULL},
{PINID_SPDIF, "gpio-P3.27", NULL},
{0, "", NULL}, //the end
};
/*--------------------------------------------------------------------------------------------------------
*/
static int gpio_open(struct inode *inode, struct file *filp);
static int gpio_release(struct inode *inode, struct file *filp);
ssize_t gpio_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos);
static int gpio_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg);
static int gpio_init(void);
static void gpio_exit(void);
/*--------------------------------------------------------------------------------------------------------
*/
static int gpio_open(struct inode *inode, struct file *filp)
{
struct gpio_info *gpio_info_tmp;
u32 minor = iminor(inode);
gpio_info_tmp = gpio_info_file[minor];
gpio_free(MXS_PIN_TO_GPIO(gpio_info_tmp->pin));
if (gpio_request(MXS_PIN_TO_GPIO(gpio_info_tmp->pin), gpio_info_tmp->pin_name)) {
printk("request %s gpio faile \n", gpio_info_tmp->pin_name);
return -1;
}
filp->private_data = gpio_info_file[minor];
return 0;
}
static int gpio_release(struct inode *inode, struct file *filp)
{
struct gpio_info *gpio_info_tmp = (struct gpio_info *)filp->private_data;
gpio_free(MXS_PIN_TO_GPIO(gpio_info_tmp->pin));
return 0;
}
ssize_t gpio_write(struct file *filp, const char __user *buf, size_t count,
loff_t *f_pos)
{
struct gpio_info *gpio_info_tmp = (struct gpio_info *)filp->private_data;
char data[2];
//printk("make: %s \n", gpio_info_tmp->pin_name);
copy_from_user(data, buf, 2);
data[0] = data[0] - '0';
if (data[0] == 1 || data[0] == 0) {
gpio_direction_output(MXS_PIN_TO_GPIO(gpio_info_tmp->pin), data[0]);
}
return count;
}
static ssize_t gpio_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
struct gpio_info *gpio_info_tmp = (struct gpio_info *)file->private_data;
int value = 0;
char data[3];
static int flg = 0;
if (flg == 1) {
flg = 0;
return 0;
}
gpio_direction_input(MXS_PIN_TO_GPIO(gpio_info_tmp->pin));
value = gpio_get_value(MXS_PIN_TO_GPIO(gpio_info_tmp->pin));
data[0] = value ? 1 : 0;
data[0] = data[0] + '0';
data[1] = '\n';
data[3] = -1;
copy_to_user(buf, data, 2);
flg = 1;
return 3;
}
static int gpio_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
{
struct gpio_info *gpio_info_tmp = (struct gpio_info *)flip->private_data;
int data = 0;
switch (command) {
case SET_GPIO_HIGHT:
gpio_direction_output(MXS_PIN_TO_GPIO(gpio_info_tmp->pin), 1);
break;
case SET_GPIO_LOW:
gpio_direction_output(MXS_PIN_TO_GPIO(gpio_info_tmp->pin), 0);
break;
case GET_GPIO_VALUE:
gpio_direction_input(MXS_PIN_TO_GPIO(gpio_info_tmp->pin));
data = gpio_get_value(MXS_PIN_TO_GPIO(gpio_info_tmp->pin));
data = data ? 1 : 0;
copy_to_user((void *)arg, (void *)(&data), sizeof(int));
break;
default:
printk("cmd error \n");
return -1;
}
return 0;
}
static struct file_operations gpio_fops={
.owner = THIS_MODULE,
.open = gpio_open,
.write = gpio_write,
.read = gpio_read,
.release = gpio_release,
.ioctl = gpio_ioctl,
};
static int __init gpio_init(void)
{
int i = 0;
int ret = 0;
if (zlg_board_type == ZLG_IMX_283) {
all_gpios_info = all_gpios_info_283;
} else if(zlg_board_type == ZLG_IMX_287) {
all_gpios_info = all_gpios_info_287B;
} else if(zlg_board_type == ZLG_IMX_280) {
all_gpios_info = all_gpios_info_280;
}
for (i = 0; all_gpios_info[i].pin != 0; i++) {
all_gpios_info[i].pmiscdev = kmalloc(sizeof(struct miscdevice), GFP_KERNEL);
if (all_gpios_info[i].pmiscdev == NULL) {
printk("unable to malloc memory \n");
return -1;
}
memset(all_gpios_info[i].pmiscdev, 0, sizeof(struct miscdevice));
all_gpios_info[i].pmiscdev->name = all_gpios_info[i].pin_name;
all_gpios_info[i].pmiscdev->fops = &gpio_fops;
all_gpios_info[i].pmiscdev->minor = MISC_DYNAMIC_MINOR;
ret = misc_register(all_gpios_info[i].pmiscdev);
if (ret) {
printk("misc regist faile \n");
return -1;
}
gpio_info_file[all_gpios_info[i].pmiscdev->minor] = &(all_gpios_info[i]);
printk("build device i:%d dev:/dev/%s \n", i, all_gpios_info[i].pmiscdev->name);
}
if (zlg_board_type == ZLG_IMX_283) {
printk("zlg EasyARM-imx283 gpio driver up. \n");
} else if(zlg_board_type == ZLG_IMX_287) {
printk("zlg EasyARM-imx287 gpio driver up. \n");
} else if(zlg_board_type == ZLG_IMX_280) {
printk("zlg EasyARM-imx280 gpio driver up. \n");
}
return 0;
}
static void __exit gpio_exit(void)
{
int i = 0;
for (i = 0; all_gpios_info[i].pin != 0; i++) {
misc_deregister(all_gpios_info[i].pmiscdev);
}
printk("zlg EasyARM-imx28xx gpio driver down.\n");
}
module_init(gpio_init);
module_exit(gpio_exit);