LED驱动程序分析

         混杂设备 LED驱动程序分析

/*******************************
 *
 *杂项设备驱动:miscdevice
 *majior=10;
 *
 * *****************************/


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/init.h>
//#include <linux/moduleparam.h>//#include <linux/slab.h>//kcalloc,kzalloc等内存分配函数
//---------ioctl------------
#include <linux/ioctl.h>
//---------misc_register----
#include <linux/miscdevice.h>
//----------cdev--------------
#include <linux/cdev.h>
//----------delay-------------
#include <linux/delay.h>
//----------GPIO---------------
#include <mach/gpio.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
 
 
#define S3C_GPIO_SPECIAL_MARK      (0xfffffff0)
#define S3C_GPIO_SPECIAL(x)        (S3C_GPIO_SPECIAL_MARK | (x))//内核当中定义

#define DEVICE_NAME "leds"
static int led_gpios[] = {
    S5PV210_MP04(4),
    S5PV210_MP04(5),
    S5PV210_MP04(6),
    S5PV210_MP04(7),
};//4个LED
#define LED_NUM        ARRAY_SIZE(led_gpios)

static long fl210_leds_ioctl(struct file *filp, unsigned int cmd,
        unsigned long arg)
{
    switch(cmd) {
        case 0:
        case 1:
            if (arg > LED_NUM) {
                return -EINVAL;
            }

            gpio_set_value(led_gpios[arg], !cmd);//根据cmd设置LED的暗灭
            printk(DEVICE_NAME": %ld %d
", arg, cmd);
            break;

        default:
            return -EINVAL;
    }

    return 0;
}
static struct file_operations fl210_led_dev_fops = {
    .owner            = THIS_MODULE,
    .unlocked_ioctl    = fl210_leds_ioctl,
};
//----------------miscdevice------------------static struct miscdevice fl210_led_dev = {
    .minor            = MISC_DYNAMIC_MINOR,
    .name            = DEVICE_NAME,
    .fops            = &fl210_led_dev_fops,
};//--------------------------------------------

static int __init fl210_led_dev_init(void) {
    int ret;
    int i;

    for (i = 0; i < LED_NUM; i++) {
        ret = gpio_request(led_gpios[i], "LED");//申请GPIO口
        if (ret) {
            printk("%s: request GPIO %d for LED failed, ret = %d
", DEVICE_NAME,
                    led_gpios[i], ret);
            return ret;
        }

        s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);//设置GPIO口为输出
        gpio_set_value(led_gpios[i], 1);//初始化GPIO口的值
    }

    ret = misc_register(&fl210_led_dev);//注册杂项设备

    printk(DEVICE_NAME"	initialized
");
    printk("led num is: %d
",LED_NUM);
    return ret;
}
static void __exit fl210_led_dev_exit(void) {
    int i;

    for (i = 0; i < LED_NUM; i++) {
        gpio_free(led_gpios[i]);//释放GPIO口
    }

    misc_deregister(&fl210_led_dev);//注销设备
}

module_init(fl210_led_dev_init);
module_exit(fl210_led_dev_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("");

S5PV210_MP04宏定义在linux/arch/arm/mach-s5pv210/include/mach/gpio.h

#define S5PV210_MP04(_nr) (S5PV210_GPIO_MP04_START + (_nr))

S5PV210_GPIO_MP04_START = S5PV210_GPIO_NEXT(S5PV210_GPIO_MP03),

#define S5PV210_GPIO_NEXT(__gpio) ((__gpio##_START) + (__gpio##_NR) + CONFIG_S3C_GPIO_SPACE + 1)

//这里的CONFIG_S3C_GPIO_SPAC是内核配置选项,在.config中可以找到,我的配置为:   CONFIG_S3C_GPIO_SPACE = 0

上述代码用到以下几个函数:

gpio_set_value();

s3c_gpio_cfgpin();

gpio_request();

gpio_free();

misc_register();

misc_deregister();

后面会逐个分析。

测试程序如下:

                   
   

#include <stdio.h>//#include "sys/types.h"
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>//read,write等等//#include "termios.h"//#include "sys/stat.h"
#include <fcntl.h>
#define LED2_ON 0x1#define LED2_OFF 0x0

main(int argc,char *argv[])
{
    int fd;

    if ((fd=open("/dev/leds",O_RDWR /*| O_NDELAY | O_NOCTTY*/)) < 0)
    {
        printf("Open Device  failed.
");
        exit(1);
    }
    else
    {
        printf("Open Device  successed.
");
    }
    if (argc<3)
    {
        /* code */
        printf("Usage: %s <on|off num>
",argv[0]);
        exit(1);
    }
    if(!strcmp(argv[1],"on"))
    {
        printf("led1 will on!!
");
       if(ioctl(fd,LED2_ON,atoi(argv[2]))<0)
       {
           printf("ioctl err!!
");     
       }
    
    }
    if(!strcmp(argv[1],"off"))
    {
        printf("led1 will off!!
");
        if(ioctl(fd,LED2_OFF,atoi(argv[2]))<0)
        {
            printf("ioctl err!!
");
        }
    }
    close(fd);
}
 
 
 

 首先来看s3c_gpio_cfgpin();

 
int s3c_gpio_cfgpin(unsigned int pin, unsigned int config)
{
    struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin);//得到对应GPIO结构体首指针,里面包含了该GPIO的各种参数
    unsigned long flags;
    int offset;
    int ret;

    if (!chip)
        return -EINVAL;

    offset = pin - chip->chip.base;

    s3c_gpio_lock(chip, flags);
    ret = s3c_gpio_do_setcfg(chip, offset, config);//设置该GPIO状态寄存器的数值为config
s3c_gpio_unlock(chip, flags);

    return ret;
}
 
static inline struct s3c_gpio_chip *s3c_gpiolib_getchip(unsigned int chip)
{
    return (chip < S3C_GPIO_END) ? s3c_gpios[chip] : NULL;
}
 
 
 
static inline int s3c_gpio_do_setcfg(struct s3c_gpio_chip *chip,
                     unsigned int off, unsigned int config)
{
    return (chip->config->set_config)(chip, off, config);
}
static struct s3c_gpio_cfg gpio_cfg = {
    .set_config    = s3c_gpio_setcfg_s3c64xx_4bit,
    .set_pull    = s3c_gpio_setpull_updown,
    .get_pull    = s3c_gpio_getpull_updown,
};
int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip,
                 unsigned int off, unsigned int cfg)
{
    void __iomem *reg = chip->base;
    unsigned int shift = (off & 7) * 4;
    u32 con;

    if (off < 8 && chip->chip.ngpio > 8)
        reg -= 4;

    if (s3c_gpio_is_cfg_special(cfg)) {
        cfg &= 0xf;
        cfg <<= shift;
    }

    con = __raw_readl(reg);//读GPXCON的值
    con &= ~(0xf << shift);//清零
    con |= cfg;//设置config
    __raw_writel(con, reg);//写值

    return 0;
}

 其中结构体s3c_gpio_chip如下:


 */struct s3c_gpio_chip {
    struct gpio_chip    chip;
    struct s3c_gpio_cfg    *config;
    struct s3c_gpio_pm    *pm;
    void __iomem        *base;
    int            eint_offset;
    spinlock_t         lock;
#ifdef CONFIG_PM
    u32            pm_save[7];#endif
};
static struct s3c_gpio_chip s5pv210_gpio_4bit[] = {//描述了芯片中所有的GPIO端口
    {
        .chip    = {
            .base    = S5PV210_GPA0(0),
            .ngpio    = S5PV210_GPIO_A0_NR,
            .label    = "GPA0",
            .to_irq = s5p_gpiolib_gpioint_to_irq,
        },
    },{
                 。。。。
             }
                 。。。。
};

接下来看gpio_set_value();

void __gpio_set_value(unsigned gpio, int value)
{
    struct gpio_chip    *chip;

    chip = gpio_to_chip(gpio);//返回对应于pin的gpio_desc[pin].chip指针 
    WARN_ON(extra_checks && chip->can_sleep);
    chip->set(chip, gpio - chip->base, value);//调用chip->set
}
 
 
原文地址:https://www.cnblogs.com/zxouxuewei/p/4937039.html