zoukankan      html  css  js  c++  java
  • 基于sys文件系统的LED驱动的移植【原创】

    基于RK3188平台LED驱动程序的移植的移植。如有不正确之处,欢迎大家指点。

    本文的LED驱动程序不是通过打开设备节点来访问和控制LED的,是通过sys文件系统来控制LED。

    板子上有四盏灯以及对应的GPIO的引脚如下:

     

    基于sys文件系统的LED驱动内核已经提供了,我们需要做的事情没有那么多。内核通过的LED驱动程序走的是平台总线的方式,板级文件Board-rk3188-u4301.c (kernelarcharmmach-rk3188) 里添加LED的GPIO的信息。

     1 static struct gpio_led rk29_leds[] = {
     2     {    
     3         .name = "power",    //在/sys/class/leds/ 目录下显示的文件名
     4         .gpio = RK30_PIN0_PB4,      //LED的GPIO口的引脚
     5         .default_state = LEDS_GPIO_DEFSTATE_OFF,    //设置默认的状态
     6     },
     7     {    
     8         .name = "paper",
     9         .gpio = RK30_PIN0_PB5,
    10         .default_state = LEDS_GPIO_DEFSTATE_OFF,
    11     },
    12     {    
    13         .name = "connect",
    14         .gpio = RK30_PIN0_PB6,
    15         .default_state = LEDS_GPIO_DEFSTATE_OFF,
    16     },
    17     {    
    18         .name = "status",
    19         .gpio = RK30_PIN0_PB7,
    20         .default_state = LEDS_GPIO_DEFSTATE_OFF,
    21     },
    22 };
    23 
    24 static struct gpio_led_platform_data rk29_leds_pdata = {
    25     .leds = rk29_leds,
    26     .num_leds = ARRAY_SIZE(rk29_leds),
    27 };
    28 
    29 static struct platform_device rk29_device_gpio_leds = {
    30     .name    = "leds-gpio",          //设备的名称,驱动就是根据这个文件匹配的啊。
    31     .id    = -1,
    32     .dev    = {
    33         .platform_data  = &rk29_leds_pdata,
    34     },
    35 };

    我们在看看驱动文件Leds-gpio.c (\192.168.1.144zsf k3188_5.1androidkerneldriversleds)

      1 /*
      2  * LEDs driver for GPIOs
      3  *
      4  * Copyright (C) 2007 8D Technologies inc.
      5  * Raphael Assenat <raph@8d.com>
      6  * Copyright (C) 2008 Freescale Semiconductor, Inc.
      7  *
      8  * This program is free software; you can redistribute it and/or modify
      9  * it under the terms of the GNU General Public License version 2 as
     10  * published by the Free Software Foundation.
     11  *
     12  */
     13 #include <linux/kernel.h>
     14 #include <linux/init.h>
     15 #include <linux/platform_device.h>
     16 #include <linux/leds.h>
     17 #include <linux/of_platform.h>
     18 #include <linux/of_gpio.h>
     19 #include <linux/slab.h>
     20 #include <linux/workqueue.h>
     21 
     22 #include <asm/gpio.h>
     23 
     24 struct gpio_led_data {
     25     struct led_classdev cdev;
     26     unsigned gpio;
     27     struct work_struct work;
     28     u8 new_level;
     29     u8 can_sleep;
     30     u8 active_low;
     31     u8 blinking;
     32     int (*platform_gpio_blink_set)(unsigned gpio, int state,
     33             unsigned long *delay_on, unsigned long *delay_off);
     34 };
     35 
     36 static void gpio_led_work(struct work_struct *work)
     37 {
     38     struct gpio_led_data    *led_dat =
     39         container_of(work, struct gpio_led_data, work);
     40 
     41     if (led_dat->blinking) {
     42         led_dat->platform_gpio_blink_set(led_dat->gpio,
     43                          led_dat->new_level,
     44                          NULL, NULL);
     45         led_dat->blinking = 0;
     46     } else
     47         gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
     48 }
     49 
     50 static void gpio_led_set(struct led_classdev *led_cdev,
     51     enum led_brightness value)
     52 {
     53     struct gpio_led_data *led_dat =
     54         container_of(led_cdev, struct gpio_led_data, cdev);
     55     int level;
     56 
     57     if (value == LED_OFF)
     58         level = 0;
     59     else
     60         level = 1;
     61 
     62     if (led_dat->active_low)
     63         level = !level;
     64 
     65     /* Setting GPIOs with I2C/etc requires a task context, and we don't
     66      * seem to have a reliable way to know if we're already in one; so
     67      * let's just assume the worst.
     68      */
     69     if (led_dat->can_sleep) {
     70         led_dat->new_level = level;
     71         schedule_work(&led_dat->work);
     72     } else {
     73         if (led_dat->blinking) {
     74             led_dat->platform_gpio_blink_set(led_dat->gpio, level,
     75                              NULL, NULL);
     76             led_dat->blinking = 0;
     77         } else
     78             gpio_set_value(led_dat->gpio, level);
     79     }
     80 }
     81 
     82 static int gpio_blink_set(struct led_classdev *led_cdev,
     83     unsigned long *delay_on, unsigned long *delay_off)
     84 {
     85     struct gpio_led_data *led_dat =
     86         container_of(led_cdev, struct gpio_led_data, cdev);
     87 
     88     led_dat->blinking = 1;
     89     return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
     90                         delay_on, delay_off);
     91 }
     92 
     93 static int __devinit create_gpio_led(const struct gpio_led *template,
     94     struct gpio_led_data *led_dat, struct device *parent,
     95     int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
     96 {
     97     int ret, state;
     98 
     99     led_dat->gpio = -1;
    100 
    101     /* skip leds that aren't available */
    102     if (!gpio_is_valid(template->gpio)) {
    103         printk(KERN_INFO "Skipping unavailable LED gpio %d (%s)
    ",
    104                 template->gpio, template->name);
    105         return 0;
    106     }
    107 
    108     ret = gpio_request(template->gpio, template->name);
    109     if (ret < 0)
    110         return ret;
    111 
    112     led_dat->cdev.name = template->name;
    113     led_dat->cdev.default_trigger = template->default_trigger;
    114     led_dat->gpio = template->gpio;
    115     led_dat->can_sleep = gpio_cansleep(template->gpio);
    116     led_dat->active_low = template->active_low;
    117     led_dat->blinking = 0;
    118     if (blink_set) {
    119         led_dat->platform_gpio_blink_set = blink_set;
    120         led_dat->cdev.blink_set = gpio_blink_set;
    121     }
    122     led_dat->cdev.brightness_set = gpio_led_set;
    123     if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
    124         state = !!gpio_get_value(led_dat->gpio) ^ led_dat->active_low;
    125     else
    126         state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
    127     led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
    128     if (!template->retain_state_suspended)
    129         led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
    130 
    131     ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
    132     if (ret < 0)
    133         goto err;
    134         
    135     INIT_WORK(&led_dat->work, gpio_led_work);
    136 
    137     ret = led_classdev_register(parent, &led_dat->cdev);
    138     if (ret < 0)
    139         goto err;
    140 
    141     return 0;
    142 err:
    143     gpio_free(led_dat->gpio);
    144     return ret;
    145 }
    146 
    147 static void delete_gpio_led(struct gpio_led_data *led)
    148 {
    149     if (!gpio_is_valid(led->gpio))
    150         return;
    151     led_classdev_unregister(&led->cdev);
    152     cancel_work_sync(&led->work);
    153     gpio_free(led->gpio);
    154 }
    155 
    156 struct gpio_leds_priv {
    157     int num_leds;
    158     struct gpio_led_data leds[];
    159 };
    160 
    161 static inline int sizeof_gpio_leds_priv(int num_leds)
    162 {
    163     return sizeof(struct gpio_leds_priv) +
    164         (sizeof(struct gpio_led_data) * num_leds);
    165 }
    166 
    167 /* Code to create from OpenFirmware platform devices */
    168 #ifdef CONFIG_LEDS_GPIO_OF
    169 static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev)
    170 {
    171     struct device_node *np = pdev->dev.of_node, *child;
    172     struct gpio_leds_priv *priv;
    173     int count = 0, ret;
    174 
    175     /* count LEDs in this device, so we know how much to allocate */
    176     for_each_child_of_node(np, child)
    177         count++;
    178     if (!count)
    179         return NULL;
    180 
    181     priv = kzalloc(sizeof_gpio_leds_priv(count), GFP_KERNEL);
    182     if (!priv)
    183         return NULL;
    184 
    185     for_each_child_of_node(np, child) {
    186         struct gpio_led led = {};
    187         enum of_gpio_flags flags;
    188         const char *state;
    189 
    190         led.gpio = of_get_gpio_flags(child, 0, &flags);
    191         led.active_low = flags & OF_GPIO_ACTIVE_LOW;
    192         led.name = of_get_property(child, "label", NULL) ? : child->name;
    193         led.default_trigger =
    194             of_get_property(child, "linux,default-trigger", NULL);
    195         state = of_get_property(child, "default-state", NULL);
    196         if (state) {
    197             if (!strcmp(state, "keep"))
    198                 led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
    199             else if (!strcmp(state, "on"))
    200                 led.default_state = LEDS_GPIO_DEFSTATE_ON;
    201             else
    202                 led.default_state = LEDS_GPIO_DEFSTATE_OFF;
    203         }
    204 
    205         ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
    206                       &pdev->dev, NULL);
    207         if (ret < 0) {
    208             of_node_put(child);
    209             goto err;
    210         }
    211     }
    212 
    213     return priv;
    214 
    215 err:
    216     for (count = priv->num_leds - 2; count >= 0; count--)
    217         delete_gpio_led(&priv->leds[count]);
    218     kfree(priv);
    219     return NULL;
    220 }
    221 
    222 static const struct of_device_id of_gpio_leds_match[] = {
    223     { .compatible = "gpio-leds", },
    224     {},
    225 };
    226 #else
    227 static struct gpio_leds_priv * __devinit gpio_leds_create_of(struct platform_device *pdev)
    228 {
    229     return NULL;
    230 }
    231 #define of_gpio_leds_match NULL
    232 #endif
    233 
    234 
    235 static int __devinit gpio_led_probe(struct platform_device *pdev)
    236 {
    237     struct gpio_led_platform_data *pdata = pdev->dev.platform_data;
    238     struct gpio_leds_priv *priv;
    239     int i, ret = 0;
    240 
    241     if (pdata && pdata->num_leds) {
    242         priv = kzalloc(sizeof_gpio_leds_priv(pdata->num_leds),
    243                 GFP_KERNEL);
    244         if (!priv)
    245             return -ENOMEM;
    246 
    247         priv->num_leds = pdata->num_leds;
    248         for (i = 0; i < priv->num_leds; i++) {
    249             ret = create_gpio_led(&pdata->leds[i],
    250                           &priv->leds[i],
    251                           &pdev->dev, pdata->gpio_blink_set);
    252             if (ret < 0) {
    253                 /* On failure: unwind the led creations */
    254                 for (i = i - 1; i >= 0; i--)
    255                     delete_gpio_led(&priv->leds[i]);
    256                 kfree(priv);
    257                 return ret;
    258             }
    259         }
    260     } else {
    261         priv = gpio_leds_create_of(pdev);
    262         if (!priv)
    263             return -ENODEV;
    264     }
    265 
    266     platform_set_drvdata(pdev, priv);
    267 
    268     return 0;
    269 }
    270 
    271 static int __devexit gpio_led_remove(struct platform_device *pdev)
    272 {
    273     struct gpio_leds_priv *priv = dev_get_drvdata(&pdev->dev);
    274     int i;
    275 
    276     for (i = 0; i < priv->num_leds; i++)
    277         delete_gpio_led(&priv->leds[i]);
    278 
    279     dev_set_drvdata(&pdev->dev, NULL);
    280     kfree(priv);
    281 
    282     return 0;
    283 }
    284 
    285 static struct platform_driver gpio_led_driver = {
    286     .probe        = gpio_led_probe,
    287     .remove        = __devexit_p(gpio_led_remove),
    288     .driver        = {
    289         .name    = "leds-gpio",
    290         .owner    = THIS_MODULE,
    291         .of_match_table = of_gpio_leds_match,
    292     },
    293 };
    294 
    295 MODULE_ALIAS("platform:leds-gpio");
    296 
    297 static int __init gpio_led_init(void)
    298 {
    299     printk(KERN_ERR"zbzhuang leds");
    300 
    301 
    302     return platform_driver_register(&gpio_led_driver);
    303 }
    304 
    305 static void __exit gpio_led_exit(void)
    306 {
    307     platform_driver_unregister(&gpio_led_driver);
    308 }
    309 
    310 module_init(gpio_led_init);
    311 module_exit(gpio_led_exit);
    312 
    313 MODULE_AUTHOR("Raphael Assenat <raph@8d.com>, Trent Piepho <tpiepho@freescale.com>");
    314 MODULE_DESCRIPTION("GPIO LED driver");
    315 MODULE_LICENSE("GPL");
    View Code

     驱动文件就是根据名字跟 设备进行匹配。匹配成功之后就会在创建sys文件系统提供接口给应用程序控制设备。

     在内核执行make menuconfig,要配置LED驱动的一些功能如闪烁和呼吸灯等功能,编译进内核。

    重新烧录开发板的内核。之后通过串口进入开发板。在/sys/class/leds目录下创建出了,我们板级文件下添加的4个LED驱动。

    下面我们演示如何通过sys文件系统控制LED的亮灭。进入connect目录。执行下面三条命令就可控制LED灯的亮灭和进入呼吸灯的模式。

     

     

     

     

  • 相关阅读:
    Java技术路线--2循环
    Java技术路线--1基本类型与包装类
    Linux内存管理之UMA模型和NUMA模型
    最长XX子串/数组/子序列
    epoll LT 模式和 ET 模式详解
    OS篇:OS中进程的阻塞与挂起的区别
    约瑟夫环问题
    最大公约数和最小公倍数
    C++之寻找素数(素数筛)
    Linux OOM机制分析
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6944765.html
Copyright © 2011-2022 走看看