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\n", 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\n", 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"\tinitialized\n");
    printk("led num is: %d\n",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.\r\n");
        exit(1);
    }
    else
    {
        printf("Open Device  successed.\r\n");
    }
    if (argc<3)
    {
        /* code */
        printf("Usage: %s <on|off num>\n",argv[0]);
        exit(1);
    }
    if(!strcmp(argv[1],"on"))
    {
        printf("led1 will on!!\n");
       if(ioctl(fd,LED2_ON,atoi(argv[2]))<0)
       {
           printf("ioctl err!!\n");     
       }
    
    }
    if(!strcmp(argv[1],"off"))
    {
        printf("led1 will off!!\n");
        if(ioctl(fd,LED2_OFF,atoi(argv[2]))<0)
        {
            printf("ioctl err!!\n");
        }
    }
    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
}
 
 
时间: 2024-12-16 14:10:51

LED驱动程序分析的相关文章

20150223 IMX257 LED驱动程序实现

20150223 IMX257 LED驱动程序实现 2015-02-23 李海沿 由于昨天对IMX257的地址分配不了解,所以前面只能用s3c24xx的驱动程序来了解ioremap等对IO端口的工作原理. 但是经过昨晚对IMX257芯片的细细梳理,今天早上起来又把IMX257的芯片资料看了一遍,终于成功看懂了,下面意义给大家道来. 我们此处使用ERR_LED 也就是GPIO3_23引脚 一.IMX257 芯片资料分析 1.确定相关寄存器基址 确定IOMUX地址 GPIO3的地址 2.确定相关寄存

TQ2440按键点亮LED驱动程序

一,硬件分析: 1.打开TQ2440的底板原理图找到按键测试的模块,如下图所示: 从图我们知道,控制按键k1 k2 k3 k4 的管脚为EINT1 EINT4 EINT2 EINT0 ,当按键按下时,管脚输出低电平,当按键没有被按下时,管脚输出高电平. 2.打开TQ2440核心板原理图找到EINT1  EINT4 EINT2 EINT0所对应的cpu控制引脚,如下图所示: 从图我们可以知道,EINT1  EINT4 EINT2 EINT0 对应的cpu控制引脚为GPF1 GPF4 GPF2 GP

字符设备驱动程序分析

字符设备驱动程序分析 下面是针对jz2440开发板写的一个led驱动程序,重点不在于该程序,而是以此为例,对字符设备驱动程序框架的分析总结: /* * jz2440 leds driver **/ #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #in

Linux中块设备驱动程序分析

基于<Linux设备驱动程序>书中的sbull程序以对Linux块设备驱动总结分析. 开始之前先来了解这个块设备中的核心数据结构: struct sbull_dev { int size;                       /* Device size in sectors */ u8 *data;                       /* The data array */ short users;                    /* How many users

【Linux驱动】TQ2440 LED驱动程序

★总体介绍 LED驱动程序主要实现了TQ2440开发板上的4个LED灯的硬件驱动,实现了对引脚GPIOB5.GPIOB6.GPIOB7.GPIOB8的高低电平设置(common-smdk.c中已经实现了对引脚的配置),利用测试程序调用该驱动程序,通过命令控制LED灯的亮灭. ★详细介绍 1.驱动程序代码:My_led.c #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #

LED驱动程序 S3C6410

这两天写了个LED驱动程序,网上也看了好多的帖子. 开始思路很清晰了,就是先看电路图,发现LED灯是接在GPM端口上的, 然后看S3C6410数据手册,先向GPMCON口写命令字,让GPM0-5设置为输出,再向GPMDAT口写数据字,在GPM0-5引脚拉低或拉高电平, 从而控制LED的亮灭. 1.电路图 很显然LED灯是接在GPM口引脚下面的 2.数据手册 3.LED驱动程序 #include <linux/module.h> #include <linux/kernel.h> #

android 电容屏(三):驱动调试之驱动程序分析篇

平台信息: 内核:linux3.4.39系统:android4.4 平台:S5P4418(cortex a9) 作者:瘋耔(欢迎转载,请注明作者) 欢迎指正错误,共同学习.共同进步!! 关注博主新浪博客:http://weibo.com/cpjphone   以goodix的gt8105为例 一.总体架构 硬件部分:先看一个总体的图吧,其实触摸屏原理也比较简单,触摸屏和主控芯片间的联系,如下主要有三部分: 1.IIC部分,初始化gt8105的数据和传回主控制的坐标位置信息就是通过IIC这条线传输

led驱动程序的设计

1.led驱动程序属于字符设备->又是内核模块->字符驱动:a.open:b.ioctl 编写led.c led.h makefile led_app.c 把应用程序集驱动程序都拷贝到开发板->先安装insmod led.ko->查看对应设备号->cat /proc/devices ->创建设备文件->mknod /dev/myled c 253 0 ->运行应用程序 ./led_app 1点亮:./led_app 0熄灭.

ok6410之led驱动程序编写

led驱动程序编写 本文主要包含三部分,led驱动程序led.c编写,编译驱动程序的makefile的编写,以及使用驱动程序的应用程序led_app的编写 一.led.c编写 1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/cdev.h> 4 #include <linux/fs.h> 5 #include <linux/io.h> 6 #includ