一、概述
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, constchar *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, constchar *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_tsize,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,constchar *src,size_tsize,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");
GPIO的驅動模型
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.