linux驱动之gpio3

转载 2012年03月23日 10:37:42
/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中具体的实现。*/

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

gpio是一组可控件的脚,由多个寄存器同时控制。通过设置对应的寄存器可以达到设置GPIO口对应状态与功能。
数据状态,输入输出方向,清零,中断(那个边沿触发), 一般是一组(bank)一组的。
//****************linux 中 GPIO模型****************************************//
注册方法:
1:struct gpio_chip: 表示一个gpio controller.通过这个结构抽象化所有的 GPIO源,而让板上其它的模块可以用相同的接口调用使用这些GPIO。
2: struct gpio_desc: 表示一个gpio口,含对应的 gpio_chip.
3: ARCH_NR_GPIOS:  与板相关的GPIO口数量,即是全局GPIO数组:static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
4: 注册 gpio_chip时,就是根据 chip 的数据 修改全局 GPIO数组中 gpio_desc 字段(chip, flags)。


//************* twl4030 中 GPIO的实现 *******************//
首先 twl4030中的 GPIO模块: 在 twl4030的驱动注册时,probe中,生成了GPIO对应的 i2c_client 与 platform_device.
twl4030,当加载GPIO的驱动(匹配platform_device)时,首先进行对应的设置,GPIO设置。
然后设置结构: gpio_chip: twl_gpiochip: gpio_twl4030_pulls,pio_twl4030_debounce,
注册 之:ret = gpiochip_add(&twl_gpiochip);//添加到全局的 gpio_desc数组中。即是设置全局gpio_desc中这个gpio_chip对应的几个gpio的字段。

setup之:status = pdata->setup(&pdev->dev, pdata->gpio_base, TWL4030_GPIO_MAX);
setup(...) ==》 twl4030_mmc_init(mmc); //在添加完gpio后,进行探测MMC,然后注册之。Register MMC devices.

//*************** omap3430的实现 注册 GPIO ******************//
static int __init _omap_gpio_init(void)
gpio_bank_count: 多少组gpio组。
这里同时 注册了对应的中断处理例程: 
bank 主中断处理:gpio_irq_handler
bank 下的子GPIO全设为:handle_simple_irq。

//注册函数,即是把根据chip设备全局GPIO数组的对应gpio的字段。
int gpiochip_add(struct gpio_chip *chip)
{
for (id = base; id < base + chip->ngpio; id++) {
gpio_desc[id].chip = chip; //设置全局的gpio_desc中的 对应的成员的 chip 为,注册的这个chip.
gpio_desc[id].flags = !chip->direction_input ? (1 << FLAG_IS_OUT): 0; //及gpio方向。

}


//
"通用调用方法:"
static int __init wl127x_vio_leakage_fix(void)
{
int ret = 0;

ret = gpio_request(WL127X_BTEN_GPIO, "wl127x_bten");
if (ret < 0) {
printk(KERN_ERR "wl127x_bten gpio_%d request fail",
WL127X_BTEN_GPIO);
goto fail;
}

gpio_direction_output(WL127X_BTEN_GPIO, 1);
mdelay(10);
gpio_direction_output(WL127X_BTEN_GPIO, 0);
udelay(64);

gpio_free(WL127X_BTEN_GPIO);
fail:
return ret;
}


//********************//
一.  GPIO物理起始地址: 对于要控制GPIO的嵌入式编程人员来讲,GPIO的物理地址是必须要搞清楚的。STB02500SOC中GPIO的物理基本地址是:0x4006 0000空间长度是:0x44。(gpio_base = 0x4006 0000    len = 0x44)

二.     GPIO寄存器:
GPIO共有 9个寄存器分别是:
1.       GPO: GPO(32bit)寄存器用于设置或清除对应的GPIO引脚值(高,或者低)。具体控制时需要先读出GPIO引脚的值,然后再用”或”,”与”进行相应 的逻辑设置和清除操作,很显然这是非原子的操作,在多任务系统里,是有可能发生意外的,需要程序员在软件上实现相应的原子操作,这和ARM系统的 I/O操作相比应该是比较落后的)。
2.       GPTC: GPTC(32bit)寄存器用于设置对应的GPIO引脚是输出还是输入(这样比较好理解些)程序设置相应的bit为1对应的GPIO引脚就是输出否则就是输入(呵呵,这里还要声明一下下,该寄存器要起作用还要设置好GPTS寄存器)。
3.       GPOS: GPOS(64bit)寄存器用于控制GPIO相应的引脚是由GPO驱动还是有Alt_Output_x(1,2,3)驱动(就这样简单的理解吧,嘿嘿)。
4.       GPTS:  GPTS(64bit)这个寄存器功能还是比较难说清楚的呀,简单的讲如果需要用GPO驱动GPIO寄存器,就需要设置对应2bit为00选择GPTC作为输出使能控制器,这样GPTC寄存器才能够起作用的。
5.       GPOD: GPOD(32bit)这个寄存器是比较单纯的,如果对应位设置1相应的GPIO引脚就处于漏极开路状态,这样可以适应多电压系统,和多输出驱动单输入系统。
6.       GPI: GPI(32bit) 就是相应GPIO引脚的值(高电平,还是低电平)。
7.       GPIS1:我暂时还没有研究。
8.       GPIS2: 我暂时还没有研究。
9.       GPIS3: 我暂时还没有研究。
        注意:这里要特别声明:这里的GPIO0对应GPO的bit0,GPO的bit0实际是32位GPOd的bit31(以ARM系统来看)。

三:
 对于在不支持虚拟内存的操作系统和根本就没有使用操作系统的系统里操作GPIO直接读写对应的GPIO寄存器就可以啦,但是在linux这样的操作系统下,你必须编写一个操作GPIO的驱动,或者是使用一些变通的技巧来操作GPIO.
 目前我所知道的在linux下操作GPIO有两种方法:
1.  编写驱动,这当然要熟悉linux下驱动的编写方法和技巧,在驱动里可以使用ioremap函数获得GPIO物理基地址指针,然后使用这个指针根据ioctl命令进行GPIO寄存器的读写,并把结果回送到应用层.
2.  在应用层使用mmap函数在应用层获得GPIO物理基地址对应的虚拟地址指针,然后使用这个指针来读写GPIO寄存器

总结:
虽然GPIO寄存器很多但是熟悉后,使用起来也很简单的,关键是要理解透每个GPIO引脚的功能,和个寄存器的功能特点。其实如果只是做简单的I/O输入输出控制(大多数单片机开发人员最常用用到),只要熟悉 GPO,GPI,GPTC就可以啦。

GPIO是一种通用I/O协议,在读写的时候,需要对特定寄存器进行一些设置,在规范描述的时候,一般会说GPIO 0-12,GPIO 38-43等说法,GPIO和一般的寄存器读写很不一样,因此它是两个号码控制一个状态。

GPIO的一般读写顺序为:

1、首先设置需要进行操作的GPIO范围;

2、在读/写操作前,对GPIO的选择寄存器设置为1/0;

3、读/写寄存器(基地址+偏移)。
//*********************************************//













//***********************************************//
static struct gpio_desc gpio_desc[ARCH_NR_GPIOS]; //全局的gpio_chip 存放数组

static struct gpio_chip twl_gpiochip = {
.label = "twl4030",
.owner = THIS_MODULE,
.request = twl_request,
.free = twl_free,
.direction_input = twl_direction_in,
.get = twl_get,
.direction_output = twl_direction_out,
.set = twl_set,
.to_irq = twl_to_irq,
.can_sleep = 1,
};
/* gpio_lock prevents conflicts during gpio_desc[] table updates.
 * While any GPIO is requested, its gpio_chip is not removable;
 * each GPIO's "requested" flag serves as a lock and refcount.
 */
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 */

#ifdef CONFIG_DEBUG_FS
const char *label;
#endif
};
/**
 * struct gpio_chip - abstract a GPIO controller
 * @label: for diagnostics
 * @dev: optional device providing the GPIOs
 * @owner: helps prevent removal of modules exporting active GPIOs
 * @request: optional hook for chip-specific activation, such as
 * enabling module power and clock; may sleep
 * @free: optional hook for chip-specific deactivation, such as
 * disabling module power and clock; may sleep
 * @direction_input: configures signal "offset" as input, or returns error
 * @get: returns value for signal "offset"; for output signals this
 * returns either the value actually sensed, or zero
 * @direction_output: configures signal "offset" as output, or returns error
 * @set: assigns output value for signal "offset"
 * @to_irq: optional hook supporting non-static gpio_to_irq() mappings;
 * implementation may not sleep
 * @dbg_show: optional routine to show contents in debugfs; default code
 * will be used when this is omitted, but custom code can show extra
 * state (such as pullup/pulldown configuration).
 * @base: identifies the first GPIO number handled by this chip; or, if
 * negative during registration, requests dynamic ID allocation.
 * @ngpio: the number of GPIOs handled by this controller; the last GPIO
 * handled is (base + ngpio - 1).
 * @can_sleep: flag must be set iff get()/set() methods sleep, as they
 * must while accessing GPIO expander chips over I2C or SPI
 *
 * A gpio_chip can help platforms abstract various sources of GPIOs so
 * they can all be accessed through a common programing interface.
 * Example sources would be SOC controllers, FPGAs, multifunction
 * chips, dedicated GPIO expanders, and so on.
 *
 * Each chip controls a number of signals, identified in method calls
 * by "offset" values in the range 0..(@ngpio - 1).  When those signals
 * are referenced through calls like gpio_get_value(gpio), the offset
 * is calculated by subtracting @base from the gpio number.
 */
struct gpio_chip {
const char *label;
struct device *dev;
struct module *owner;

int (*request)(struct gpio_chip *chip,
unsigned offset);
void (*free)(struct gpio_chip *chip,
unsigned offset);

int (*direction_input)(struct gpio_chip *chip,
unsigned offset);
int (*get)(struct gpio_chip *chip,
unsigned offset);
int (*direction_output)(struct gpio_chip *chip,
unsigned offset, int value);
void (*set)(struct gpio_chip *chip,
unsigned offset, int value);

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

void (*dbg_show)(struct seq_file *s,
struct gpio_chip *chip);
int base;
u16 ngpio;
unsigned can_sleep:1;
unsigned exported:1;
};

linux应用项目(一)数码相框数码相框之电子书

一、整体思路 这一节我们重点学习框架,就是编程的思想。架构很重要。采用分层的思想,面向对象的编程思想。 1、怎样在LCD上显示一个文件 2、如何组织代码 分层的结构 main...
  • qq_27516841
  • qq_27516841
  • 2018年01月07日 11:17
  • 34

Linux 内核设备驱动之GPIO驱动之GPIO 管脚描述

用于描述一个个GPIO管脚: struct gpio_desc {  struct gpio_device *gdev;  unsigned long  flags; /* flag symb...
  • sunlei0625
  • sunlei0625
  • 2017年03月10日 09:07
  • 188

手把手教你写Linux设备驱动---中断(二)--tasklet实现(基于友善之臂4412开发板)

上节:http://blog.csdn.net/morixinguan/article/details/68958185在上一节博文中,教会了大家如何来写一个Linux设备的中断程序,实现也非常简单,...
  • morixinguan
  • morixinguan
  • 2017年04月08日 14:42
  • 849

Linux设备驱动开发详解-Note(14)--- Linux 设备驱动中的并发控制(1)

Linux 设备驱动中的并发控制(1) 成于坚持,败于止步 并发与竞态  并发(concurrency)指的是多个执行单元同时、并行被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静...
  • xinyuwuxian
  • xinyuwuxian
  • 2013年07月16日 19:58
  • 3469

linux驱动篇之 driver_register 过程分析(一)

driver_register 分析详解。本篇文章主要分析了 driver_find过程。
  • Richard_LiuJH
  • Richard_LiuJH
  • 2015年09月03日 19:33
  • 4566

Linux 设备驱动的并发控制

Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问,并发的访问会导致竞态,即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。 一、基础概念 1、Linu...
  • zqixiao_09
  • zqixiao_09
  • 2016年03月15日 19:26
  • 2728

linux驱动之按键(中断)

说明:以下由两部分组成,按键驱动、按键应用程序构成; 1.驱动程序; #include #include #include #include #include #include #incl...
  • chenliang0224
  • chenliang0224
  • 2016年02月21日 23:49
  • 566

Linux驱动最简单驱动-------helloworld

一直想学习Linux驱动开发,却一直没有时间,现在手头事儿终于轻松了!开始进行Linux驱动学习之旅。首先从最简单的helloworld开始!          Linux驱动可以直接编译进内核,也...
  • xingyu19871124
  • xingyu19871124
  • 2012年03月16日 19:26
  • 12587

MT2503 External Buck问题

公司项目使用SIM2_SCLK作为External Buck的Enable pin,Dws中配置为GPIO mode,output high; 但是开机却开不起来,量去Vcore以及Buck Ena...
  • raydom07
  • raydom07
  • 2017年05月19日 15:23
  • 322

linux驱动之input子系统之按键驱动编写流程(三)

的撒旦撒
  • u013256018
  • u013256018
  • 2015年11月21日 14:46
  • 734
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux驱动之gpio3
举报原因:
原因补充:

(最多只允许输入30个字)