您的位置:首页 > 运维架构 > Linux

GPIO的驱动模型——linux

2015-12-17 08:52 465 查看
一、概述

GPIO是嵌入式系统最简单、最常用的资源了,比如点亮LED,控制蜂鸣器,输出高低电平,检测按键,等等。GPIO分输入和输出,在davinci linux中,有关GPIO的最底层的寄存器驱动,\arch\arm\mach-davinci目录下的gpio.c,这个是寄存器级的驱动,搞过单片机MCU的朋友应该比较熟悉寄存器级的驱动。

GPIO的驱动主要就是读取GPIO口的状态,或者设置GPIO口的状态。就是这么简单,但是为了能够写好的这个驱动,在LINUX上作了一些软件上的分层。为了让其它驱动可以方便的操作到GPIO,在LINUX里实现了对GPIO操作的统一接口,这个接口实则上就是GPIO驱动的框架,具体的实现文件为gpiolib.c在配置内核的时候,我们必须使用CONFIG_GENERIC_GPIO这个宏来支持GPIO驱动。

GPIO是与硬件体系密切相关的,linux提供一个模型来让驱动统一处理GPIO,即各个板卡都有实现自己的gpio_chip控制模块:request, free, input,output, get,set,irq...然后把控制模块注册到内核中,这时会改变全局gpio数组:gpio_desc[]. 当用户请求gpio时,就会到这个数组中找到,并调用这个GPIO对应的gpio_chip的处理函数。gpio实现为一组可用的
gpio_chip, 由驱动传入对应 gpio的全局序号去 request, dataout ,datain, free. 这时会调用gpio_chip中具体的实现。

gpio是一组可控件的脚,由多个寄存器同时控制。通过设置对应的寄存器可以达到设置GPIO口对应状态与功能。数据状态,输入输出方向,清零,中断(那个边沿触发), 一般是一组(bank)一组的。

寄存器读写函数: __raw_writel() __raw_writeb() __raw_readl() __raw_readb()

二、linux 中GPIO模型的结构

//表示一个gpio口,含对应的gpio_chip.

//对于每一个gpio,都有一个gpio描述符,这个描述符包含了这个gpio所属的控制器即chip和一些标志,label等

struct gpio_desc {

struct gpio_chip *chip;

unsigned long flags;

/* flag symbols are bit numbers */

#define FLAG_REQUESTED 0

#define FLAG_IS_OUT 1

#define FLAG_RESERVED 2

#define FLAG_EXPORT 3 /* protected by sysfs_lock */

#define FLAG_SYSFS 4 /* exported via /sys/class/gpio/control */

#define FLAG_TRIG_FALL 5 /* trigger on falling edge */

#define FLAG_TRIG_RISE 6 /* trigger on rising edge */

#define FLAG_ACTIVE_LOW 7 /* sysfs value has active low */

#define FLAG_OPEN_DRAIN 8 /* Gpio is open drain type */

#define FLAG_OPEN_SOURCE 9 /* Gpio is open source type */

#define ID_SHIFT 16 /* add new flags before this one */

#define GPIO_FLAGS_MASK ((1 << ID_SHIFT) - 1)

#define GPIO_TRIGGER_MASK (BIT(FLAG_TRIG_FALL) | BIT(FLAG_TRIG_RISE))

#ifdef CONFIG_DEBUG_FS

const char *label;

#endif

};

//采用了一个具有ARCH_NR_GPIOS大小的gpio描述符数组。这个描述符数组便代表了系统所有的gpio。

static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];//ARCH_NR_GPIOS=144,即系统现在有144个GPIO口

//static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//将144个GPIO分成每32个一组

//一组GPIO控制器结构,例如GPIO0和GPIO1是一组(共32个GPIO口),共用一组寄存器,所以GPIO0和GPIO1荷载一起用chips[0]来控制

///共有144个GPIO,分为4组(GPIO0~GPIO8),每组有2个banks(即GPIO0和GPIO1为1组),每组最多可以有32个GPIO,每组的控制寄存器空间有10个。

struct davinci_gpio_controller {

struct gpio_chip chip;//每组对应的gpio_chip

int irq_base;//每组对应的中断

spinlock_t lock;//自旋锁

void __iomem *regs;//每组的寄存器地址

void __iomem *set_data;//设置数据寄存器地址

void __iomem *clr_data;//清除数据寄存器地址

void __iomem *in_data;//输入数据寄存器地址

};

//每一个davinci_gpio_controller结构都对应于一个gpio_chip结构,gpio_chip既可看成是davinci_gpio_controller结构的补充

//表示一个gpio controller.通过这个结构抽象化所有的GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO。

struct gpio_chip {

const char *label;

struct device *dev;

struct module *owner;

int (*request)(struct
gpio_chip *chip,unsigned offset);//请求gpio

void *free)(struct gpio_chip *chip,unsigned offset);//释放gpio

int (*get_direction)(struct
gpio_chip *chip,unsigned offset);

int (*direction_input)(struct
gpio_chip *chip,unsigned offset);//配置gpio为输入,返回当前gpio状态

int (*get)(struct
gpio_chip *chip,unsigned offset);//获取gpio的状态

int (*direction_output)(struct
gpio_chip *chip,unsigned offset, int value);//配置gpio为输出,并设置为value

int (*set_debounce)(struct
gpio_chip *chip,unsigned offset, unsigned debounce);//设置消抖动时间,尤其是gpio按键时有用

void (*set)(struct
gpio_chip *chip,unsigned offset, int value);//设置gpio为value值

int (*to_irq)(struct
gpio_chip *chip,unsigned offset);//把gpio号转换为中断号

void (*dbg_show)(struct
seq_file *s,struct gpio_chip *chip);

int base;// 这个gpio控制器的gpio开始编号

u16 ngpio;//这个gpio控制器说控制的gpio数

const char *const *names;

unsigned can_sleep:1;

unsigned exported:1;

#if defined(CONFIG_OF_GPIO)

struct device_node *of_node;

int of_gpio_n_cells;

int (*of_xlate)(struct
gpio_chip *gc,const struct of_phandle_args *gpiospec, u32 *flags);

#endif

#ifdef CONFIG_PINCTRL

struct list_head pin_ranges;

#endif

};

//GPIO寄存器结构

struct davinci_gpio_regs {

u32 dir; // gpio方向设置寄存器

u32 out_data; // gpio设置为输出时,表示输出状态(0或1)

u32 set_data; // gpio设置为输出时,用于输出高电平

u32 clr_data; // gpio设置为输出时,用于输出低电平

u32 in_data; // gpio设置为输入时,用于读取输入值

u32 set_rising; // gpio中断上升沿触发设置

u32 clr_rising; // gpio中断上升沿触发清除

u32 set_falling; // gpio中断下降沿触发设置

u32 clr_falling; // gpio中断下降沿触发清除

u32 intstat; // gpio中断状态位,由硬件设置,可读取,写1时清除。

};

struct gpio {

unsigned gpio;//gpio号

unsigned long flags;//gpio标志

const char *label;//gpio名

};

三、GPIO的初始化

1.首先设置GPIO的管脚复用寄存器

static __init void da850_evm_init(void)

{

//.......

ret = davinci_cfg_reg_list(da850_gpio_test_pins);

if (ret)

pr_warning("da850_evm_init: gpio test ping mux setup failed: %d\n", ret);

//.......

}

2.根据板级结构的资源初始化chips数组,此函数在系统初始化时自动调用

static struct davinci_gpio_controller chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];//将144个GPIO分成每32个一组

static int __init davinci_gpio_setup(void)

{

int i, base;

unsigned ngpio;

struct davinci_soc_info *soc_info = &davinci_soc_info;//板级资源结构

struct davinci_gpio_regs *regs;

if (soc_info->gpio_type != GPIO_TYPE_DAVINCI)//判断GPIO类型

return 0;

ngpio = soc_info->gpio_num;//GPIO数量144

if (ngpio == 0) {

pr_err("GPIO setup: how many GPIOs?\n");

return -EINVAL;

}

if (WARN_ON(DAVINCI_N_GPIO < ngpio))//DAVINCI_N_GPIO=144

ngpio = DAVINCI_N_GPIO;

gpio_base = ioremap(soc_info->gpio_base, SZ_4K);//将GPIO的寄存器物理基地址(#define
DA8XX_GPIO_BASE 0x01e26000)映射到内存中

if (WARN_ON(!gpio_base))

return -ENOMEM;

//共有144个GPIO,分为4组(GPIO0~GPIO8),每组有2个banks(即GPIO0和GPIO1为1组),每组最多可以有32个GPIO,每组的控制寄存器空间有10个。

//chips[0]--chips[4],base值为0,32,64,96,128,ngpio分别为:32,32,32,32,16

for (i = 0, base = 0; base
< ngpio; i++, base
+= 32) {

chips[i].chip.label = "DaVinci";

//设置操作函数

chips[i].chip.direction_input = davinci_direction_in;

chips[i].chip.get = davinci_gpio_get;

chips[i].chip.direction_output = davinci_direction_out;

chips[i].chip.set = davinci_gpio_set;

chips[i].chip.base = base;//每一组开始的GPIO号

//每组控制的GPIO个数,一般为32个

chips[i].chip.ngpio = ngpio
- base;

if (chips[i].chip.ngpio
> 32)

chips[i].chip.ngpio = 32;

spin_lock_init(&chips[i].lock);

//找到这组GPIO的寄存器地址,初始化chips结构

regs = gpio2regs(base);

chips[i].regs = regs;//设置每组的寄存器

chips[i].set_data = ?s->set_data;

chips[i].clr_data = ?s->clr_data;

chips[i].in_data = ?s->in_data;

gpiochip_add(&chips[i].chip);//注册gpio_chip

}

//chips数组添加到板级资源中

soc_info->gpio_ctlrs = chips;

soc_info->gpio_ctlrs_num = DIV_ROUND_UP(ngpio, 32);

davinci_gpio_irq_setup();//设置GPIO中断

return 0;

}

pure_initcall(davinci_gpio_setup);//linux初始化时会自动调用

static struct davinci_gpio_regs __iomem __init *gpio2regs(unsigned gpio)

{

void __iomem *ptr;

//根据GPIO的基地址累加,其中基地址(gpio_base+0)是REVID(Revision ID Register)寄存器

//(gpio_base+8)是BINTEN (GPIO Interrupt Per-Bank Enable Register)寄存器

//所以第一组寄存器从基地址+0x10开始

if (gpio < 32 * 1)

ptr = gpio_base + 0x10;

else if (gpio < 32 * 2)

ptr = gpio_base + 0x38;

else if (gpio < 32 * 3)

ptr = gpio_base + 0x60;

else if (gpio < 32 * 4)

ptr = gpio_base + 0x88;

else if (gpio < 32 * 5)

ptr = gpio_base + 0xb0;

else

ptr = NULL;

return ptr;

}

int gpiochip_add(struct gpio_chip *chip)

{

unsigned long flags;

int status = 0;

unsigned id;

int base = chip->base;

//检测gpio的有效性,判断这组GPIO的起始号是否在有效范围内

if ((!gpio_is_valid(base) ||
!gpio_is_valid(base + chip->ngpio - 1))&& base
>= 0) {

status = -EINVAL;

goto fail;

}

spin_lock_irqsave(&gpio_lock, flags);

//如果这组GPIO的起始号小于0,则动态的分配gpio的开始索引。

if (base < 0) {

base = gpiochip_find_base(chip->ngpio);//这个函数在gpiolib.c中,在gpio_desc[]中分配chip->ngpio个空间(从最后往前分配),返回第一个index

if (base < 0) {

status = base;

goto unlock;

}

chip->base = base;

}

//确保这些分配的gpio号没有被其他chip占用

for (id = base; id < base + chip->ngpio; id++) {

if (gpio_desc[id].chip != NULL) {

status = -EBUSY;

break;

}

}

//填充gpio_desc,将该组内的每个GPIO口的gpio_desc结构和该组的控制结构chip联系起来

if (status == 0) {

for (id = base; id < base + chip->ngpio; id++) {

gpio_desc[id].chip = chip;

gpio_desc[id].flags = !chip->direction_input? (1 << FLAG_IS_OUT): 0;//设置GPIO口标志

}

}

of_gpiochip_add(chip);

unlock:

spin_unlock_irqrestore(&gpio_lock, flags);

if (status)

goto fail;

status = gpiochip_export(chip);//与sysfs文件系统有关,这里不关心

if (status)

goto fail;

return 0;

fail:

/* failures here can mean systems won't boot... */

pr_err("gpiochip_add: gpios %d..%d (%s) failed to register\n",chip->base, chip->base
+ chip->ngpio - 1,chip->label ? : "generic");

return status;

}

四.gpio的申请

//所谓申请就是检测GPIO描述符desc->flags的FLAG_REQUESTED标志,已申请的话该标志是1,否则是0

//往往多个gpio作为一个数组来进行申请

int gpio_request_array(struct gpio *array, size_t num)

{

int i, err;

for (i = 0; i <
num; i++, array++) {//遍历数组中的每一个GPIO,gpio是GPIO号,flags是输入输出标志等,label是其取一个名字

err = gpio_request_one(array->gpio, array->flags, array->label);

if (err)

goto err_free;

}

return 0;

err_free:

while (i--)

gpio_free((--array)->gpio);

return err;

}

int gpio_request_one(unsigned gpio, unsigned long flags, const char *label)

{

int err;

//gpio则为你要申请的哪一个管脚,label则是为其取一个名字。

err = gpio_request(gpio, label);

if (err)

return err;

if (flags & GPIOF_DIR_IN)//GPIO标志是输入

err = gpio_direction_input(gpio);//设置管脚为输入

else//GPIO标志是输出

err = gpio_direction_output(gpio,(flags
& GPIOF_INIT_HIGH) ? 1 : 0);//根据标志确定输出1还是0

if (err)

gpio_free(gpio);

return err;

}

int gpio_request(unsigned gpio, const char *label)

{

struct gpio_desc *desc;

struct gpio_chip *chip;

int status = -EINVAL;

unsigned long flags;

//屏蔽中断

spin_lock_irqsave(&gpio_lock, flags);

if (!gpio_is_valid(gpio))//判断是否有效,也就是参数的取值范围判断

goto done;

//根据GPIO号找到对应的GPIO描述符结构

desc = &gpio_desc[gpio];

chip = desc->chip;//找到该GPIO所在的组控制器

if (chip == NULL)

goto done;

//计数加1

if (!try_module_get(chip->owner))

goto done;

//这里测试并设置flags的第FLAG_REQUESTED位,如果没有被申请就返回该位的原值0

if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {

desc_set_label(desc, label ? : "?");//设置GPIO描述符结构desc的label字段

status = 0;

} else {

status = -EBUSY;

module_put(chip->owner);

goto done;

}

if (chip->request) {/*
chip->request may sleep */

spin_unlock_irqrestore(&gpio_lock, flags);

status = chip->request(chip, gpio - chip->base);

spin_lock_irqsave(&gpio_lock, flags);

if (status < 0) {

desc_set_label(desc, NULL);

module_put(chip->owner);

clear_bit(FLAG_REQUESTED, &desc->flags);

}

}

done:

if (status)

pr_debug("gpio_request: gpio-%d (%s) status %d\n",gpio, label ? : "?", status);

spin_unlock_irqrestore(&gpio_lock, flags);

return status;

}

五.GPIO的操作

1.设置GPIO为输出或输入

int gpio_direction_input(unsigned gpio)

{

unsigned long flags;

struct gpio_chip *chip;

struct gpio_desc *desc = &gpio_desc[gpio];

int status = -EINVAL;

spin_lock_irqsave(&gpio_lock, flags);

//判断GPIO号是否有效

if (!gpio_is_valid(gpio))

goto fail;

//找到GPIO对应的gpio_chip结构

chip = desc->chip;

if (!chip || !chip->get || !chip->direction_input)

goto fail;

//确保此GPIO是在此组内,chip->base是此组GPIO的起始号,chip->ngpio是此组GPIO的个数

gpio -= chip->base;

if (gpio >= chip->ngpio)

goto fail;

//确保GPIO已申请

status = gpio_ensure_requested(desc, gpio);

if (status < 0)

goto fail;

//到这里可以确保GPIO是有效的

spin_unlock_irqrestore(&gpio_lock, flags);

might_sleep_if(chip->can_sleep);

//status=0

if (status) {

status = chip->request(chip, gpio);

if (status < 0) {

pr_debug("GPIO-%d: chip request fail, %d\n",chip->base +
gpio, status);

goto lose;

}

}

//调用底层的已经设置过的操作,这里即davinci_direction_in

status = chip->direction_input(chip, gpio);

if (status == 0)//返回成功

clear_bit(FLAG_IS_OUT, &desc->flags);//清除输出标志

lose:

return status;

fail:

spin_unlock_irqrestore(&gpio_lock, flags);

if (status)

pr_debug("%s: gpio-%d status %d\n",__func__, gpio, status);

return status;

}

int gpio_direction_output(unsigned gpio, int value)

{

//.........GPIO的检查,同上函数

//调用底层的已经设置过的操作,这里即davinci_direction_out

status = chip->direction_output(chip, gpio, value);

if (status == 0)//返回成功

set_bit(FLAG_IS_OUT, &desc->flags);//设置输出标志

lose:

return status;

fail:

spin_unlock_irqrestore(&gpio_lock, flags);

if (status)

pr_debug("%s: gpio-%d status %d\n",__func__, gpio, status);

return status;

}

//根据前边对gpio_chip结构的初始化,会调用\arch\arm\mach-davinci\gpio.c里的函数

static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)

{

return __davinci_direction(chip, offset, false, 0);

}

static int davinci_direction_out(struct gpio_chip *chip, unsigned offset, int
value)

{

return __davinci_direction(chip, offset, true, value);

}

static inline int __davinci_direction(struct gpio_chip *chip,unsigned
offset, bool out, int value)

{

struct davinci_gpio_controller *d = chip2controller(chip);

struct davinci_gpio_regs __iomem *g = d->regs;//找到此组GPIO的控制寄存器地址

unsigned long flags;

u32 temp;

u32 mask = 1 << offset;

spin_lock_irqsave(&d->lock, flags);

temp = __raw_readl(&g->dir);//读出当前寄存器的输入输出方向

if (out) {//为1设置输出

temp &= ~mask;

__raw_writel(mask, value ? &g->set_data : &g->clr_data);//确定是用于输出高电平还是输出低电平

}

else {//为0设置为输入

temp |= mask;

}

__raw_writel(temp, &g->dir);//写入方向寄存器

spin_unlock_irqrestore(&d->lock, flags);

return 0;

}

2.获取gpio的状态

int __gpio_get_value(unsigned gpio)

{

struct gpio_chip *chip;

chip = gpio_to_chip(gpio);

WARN_ON(chip->can_sleep);

return chip->get ? chip->get(chip, gpio - chip->base) : 0;//调用davinci_gpio_get

}

static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)

{

struct davinci_gpio_controller *d = chip2controller(chip);

struct davinci_gpio_regs __iomem *g = d->regs;

return (1 << offset) & __raw_readl(&g->in_data);

}

3.设置GPIO的值

void __gpio_set_value(unsigned gpio, int value)

{

struct gpio_chip *chip;

chip = gpio_to_chip(gpio);

WARN_ON(chip->can_sleep);

chip->set(chip, gpio - chip->base, value);//调用davinci_gpio_set

}

static void davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int
value)

{

struct davinci_gpio_controller *d = chip2controller(chip);

struct davinci_gpio_regs __iomem *g = d->regs;

__raw_writel((1 << offset), value
? &g->set_data : &g->clr_data);

}

六、GPIO驱动编写

1.首先要申请GPIO口

2.注册设备

3.创建GPIO的sysfs相关文件

#define GPIO_MAJOR 199 // major device NO.

#define GPIO_MINOR 0 // minor device NO.

#define DEVICE_NAME "omapl138_gpios" /*定义设备驱动的名字,或设备节点名称*/

#define SET_OUTPUT_LOW 0

#define SET_OUTPUT_HIGH 1

#define GET_VALUE 2

#define SET_INPUT 3

static struct class *gpio_class;

static struct gpio gpio_array[] =

{

/*{ GPIO_TO_PIN(0, 0), GPIOF_OUT_INIT_LOW, "RTU_WDI_SIGNAL" },will request fail*/

{ GPIO_TO_PIN(0, 1), GPIOF_OUT_INIT_HIGH, "RTU_PLC_BAK_IO1"},

{ GPIO_TO_PIN(0, 2), GPIOF_OUT_INIT_LOW, "RTU_CHG_EN" },

{ GPIO_TO_PIN(0, 3), GPIOF_IN, "RTU_CHG_PG" },

{ GPIO_TO_PIN(0, 5), GPIOF_IN, "RTU_USB_OC_OUT" },

{ GPIO_TO_PIN(0, 6), GPIOF_OUT_INIT_LOW, "RTU_RUN_IND_LED" },

{ GPIO_TO_PIN(1, 10), GPIOF_IN, "RTU_TSC_BUSY"},

{ GPIO_TO_PIN(1, 11), GPIOF_IN, "RTU_PENIRQn" },

{ GPIO_TO_PIN(1, 12), GPIOF_OUT_INIT_LOW, "RTU_uP_Q26x_RESET" },

{ GPIO_TO_PIN(1, 13), GPIOF_OUT_INIT_HIGH, "RTU_uP_GPRS_PWR_EN" },

{ GPIO_TO_PIN(1, 14), GPIOF_OUT_INIT_HIGH, "RTU_uP_Q26x_ON/OFF" },

{ GPIO_TO_PIN(2, 1), GPIOF_OUT_INIT_LOW, "RTU_PLC_Reset" },

{ GPIO_TO_PIN(2, 2), GPIOF_OUT_INIT_LOW, "RTU_PLC_T_Reg" },

{ GPIO_TO_PIN(2, 4), GPIOF_OUT_INIT_LOW, "RTU_PLC_BAK_IO2" },

{ GPIO_TO_PIN(2, 5), GPIOF_OUT_INIT_LOW, "RTU_RS485_RE" },

{ GPIO_TO_PIN(2, 15), GPIOF_OUT_INIT_HIGH, "RTU_CHPWR_CS" },

{ GPIO_TO_PIN(3, 9), GPIOF_OUT_INIT_HIGH, "RTU_RS485_DE" },

{ GPIO_TO_PIN(6, 1), GPIOF_OUT_INIT_HIGH, "RTU_uP_VPIF_CLKO3" },

{ GPIO_TO_PIN(6, 9), GPIOF_IN, "RTU_KEY_IN2" },

{ GPIO_TO_PIN(6, 11), GPIOF_IN, "RTU_ALARM_IN5" },

{ GPIO_TO_PIN(6, 15), GPIOF_OUT_INIT_HIGH,"RTU_uP_RESETOUTn" },

};

static int gpio_open(struct inode *inode,struct file *file)

{

printk(KERN_WARNING"gpio open success!\n");

return 0;

}

static int gpio_release(struct inode *inode, struct file *filp)

{

printk (KERN_ALERT "Device gpio released\n");

return 0;

}

static int gpio_read(struct file*f,char *dst,size_t size,loff_t*offset)

{

unsigned char num;

__copy_to_user(&num,dst,1);

#ifdef DEBUG

printk("__copy_to_user:%d\n",num);

#endif

return 0;

}

static int gpio_write(struct file*f,const char *src,size_t size,loff_t
*offset)

{

unsigned char num;

__copy_from_user(&num,src,1);

#ifdef DEBUG

printk("__copy_from_user:%d\n",num);

#endif

return 0;

}

static long gpio_ioctl(struct file *file,unsigned int cmd,unsigned
long gpio)

{

int i;

unsigned long gpio_num = (gpio/100)*16+gpio%100;

for (i = 0; i <
ARRAY_SIZE(gpio_array); i++) {

if(gpio_array[i].gpio == gpio_num)

goto valid_gpio;

}

return -1;

valid_gpio:

switch(cmd)//cmd表示应用程序传入的
GPIO 动作

{

case SET_OUTPUT_LOW://0

{

gpio_direction_output(gpio_num, 0);

break;

}

case SET_OUTPUT_HIGH://1

{

gpio_direction_output(gpio_num, 1);

break;

}

case GET_VALUE://2

{

return gpio_get_value(gpio_num);

}

case SET_INPUT://3

{

gpio_direction_input(gpio_num);

break;

}

default:

{

printk(KERN_EMERG "GPIO command mistake!!!\n");

break;

}

}

return 0;

}

static const struct file_operations gpio_fops =

{

.owner = THIS_MODULE,

.open = gpio_open,

.release = gpio_release,

.read = gpio_read,

.write = gpio_write,

.unlocked_ioctl = gpio_ioctl,

};

static int __init gpio_init(void) /*内核初始化会调用该函数*/

{

int ret;

ret = gpio_request_array(gpio_array, ARRAY_SIZE(gpio_array));

if (ret < 0)

{

printk(KERN_EMERG "GPIO request failed\n");

goto request_failed;

}

dev_t my_dev_no;

struct cdev *gpio_cdev;

gpio_cdev = cdev_alloc();

if(gpio_cdev == NULL)

{

printk(KERN_EMERG "Cannot alloc cdev\n");

goto request_failed;

}

cdev_init(gpio_cdev,&gpio_fops);

gpio_cdev->owner=THIS_MODULE;

int result=alloc_chrdev_region(&my_dev_no,0,1,DEVICE_NAME);

if(result < 0)

{

printk(KERN_EMERG "alloc_chrdev_region failed\n");

goto request_failed;

}

ret=cdev_add(gpio_cdev,my_dev_no,1);

ret = register_chrdev(GPIO_MAJOR, DEVICE_NAME, &gpio_fops);//驱动字符设备

if(ret < 0)

{

printk(KERN_EMERG "GPIO register failed\n");

goto request_failed;

}

//在sysfs文件系统下创建一个类

gpio_class = class_create(THIS_MODULE, DEVICE_NAME);

//device_create-->device_create_vargs-->device_register创建相应的sysfs文件(如dev文件),用于udev根据sysfs文件系统下的dev文件创建设备节点

device_create(gpio_class, NULL, MKDEV(GPIO_MAJOR, GPIO_MINOR), NULL, DEVICE_NAME);

return ret;

request_failed:

gpio_free_array(gpio_array, ARRAY_SIZE(gpio_array));

return ret;

}

static void __exit gpio_exit(void)

{

device_destroy(gpio_class, MKDEV(GPIO_MAJOR, GPIO_MINOR));

class_unregister(gpio_class);

class_destroy(gpio_class);

unregister_chrdev(GPIO_MAJOR, DEVICE_NAME);

}

module_init(gpio_init);

module_exit(gpio_exit);

MODULE_LICENSE("GPL");

MODULE_VERSION ("v2.0");

MODULE_AUTHOR("wbl <>");

MODULE_DESCRIPTION("OMAPL138 GPIO driver");

http://blog.chinaunix.net/uid-27717694-id-3624294.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: