FL2440驱动添加(4)LED 驱动添加

发布时间:2024-07-24  

硬件信息:FL2440板子,s3c2440CPU带四个LED,分别在链接GPB5,GPB6,GPB8,GPB10

内核版本:linux-3.8.0

 

led驱动代码如下:

值得注意地方地方:

1,定时器的使用:在include/linux/timer.h下定义struct timer_list

struct timer_list {

/*

* All fields that change during normal runtime grouped to the

* same cacheline

*/

struct list_head entry;

unsigned long expires;

struct tvec_base *base;


void (*function)(unsigned long);

unsigned long data;


int slack;


#ifdef CONFIG_TIMER_STATS

int start_pid;

void *start_site;

char start_comm[16];

#endif

#ifdef CONFIG_LOCKDEP

struct lockdep_map lockdep_map;

#endif

};


 详细参考:linux-2.4.18内核定时器的使用

 

2,设置GPIO函数有中,linux-3.8.0和linux-3.0.0有所不同,具体可以参考Documentation/arm/Samsung-S3C24XX/GPIO.txt中的说明,只列出遇到变换:


linux-3.8.0 linux-3.0.0 参数是否变化
设置GPIO高或低 gpio_set_value() s3c2410_gpio_setpin() 不变
设置GPIO工作方式 s3c_gpio_cfgpin() s3c2410_gpio_cfgpin() 不变


3,Linux核心几个重要跟时间有关的名词或变数,HZ、tick和jiffies之间关系。

HZ:Linux核心每隔固定周期会发出timer interrupt ,HZ是用来定义每一秒有几次timer interrupts,我的机器为100 timer interrupts。 

tick:就是HZ的倒数,以秒表示

jiffies:Jiffies为Linux核心变数(32位元变数,unsigned long),它被用来纪录系统自开机以来的tick数,每发生一次timer interrupt,Jiffies变数会被加一。

 

4,设备节点自动创建函数:class_create()和device_create()

从linux 内核2.6.24的某个版本之后,devfs不复存在,udev成为devfs的替代。udev处于应用层;加入对udev的支持很简单,以一个字符设备驱动led为例,在驱动初始化的代码里调用class_create为该设备创建一个class,再为每个设备调用 device_create创建对应的设备。

大致用法如下:
struct class *class = class_create(THIS_MODULE, “led”);
device_create(class, NULL, MKDEV(major_num, 0), NULL, “led”);
这样的module被加载时,udev daemon就会自动在/dev下创建led设备文件。


led驱动代码plat_led.c:


/*********************************************************************************

* Copyright: (C) 2011 Guo Wenxue 

* All rights reserved.

*

* Filename: s3c_led.c

* Description: This is the common LED driver runs on S3C24XX.

* Version: 1.0.0(10/27/2011~)

* Author: Guo Wenxue

* ChangeLog: 1, Release initial version on "10/27/2011 11:39:10 AM"

********************************************************************************/

#include "s3c_driver.h"


#define DRV_AUTHOR "Guo Wenxue "

#define DRV_DESC "S3C24XX LED driver"


/* Driver version*/

#define DRV_MAJOR_VER 1

#define DRV_MINOR_VER 0

#define DRV_REVER_VER 0


#define DEV_NAME DEV_LED_NAME


//#define DEV_MAJOR DEV_LED_MAJOR

#ifndef DEV_MAJOR

#define DEV_MAJOR 0 /* dynamic major by default */



#define TIMER_TIMEOUT 40


static int debug = DISABLE;

static int dev_major = DEV_MAJOR;

static int dev_minor = 0;




/* ============================ Platform Device part ===============================*/

/* LED hardware informtation structure*/

struct s3c_led_info

{

unsigned char num; /* The LED number */

unsigned int gpio; /* Which GPIO the LED used */

unsigned char active_level; /* The GPIO pin level(HIGHLEVEL or LOWLEVEL) to turn on or off */

unsigned char status; /* Current LED status: OFF/ON */

unsigned char blink; /* Blink or not */

};


/* The LED platform device private data structure */

struct s3c_led_platform_data

{

struct s3c_led_info *leds;

int nleds;

};




/* LED hardware informtation data*/

static struct s3c_led_info s3c_leds[] = {

[0] = {

.num = 1,

.gpio = S3C2410_GPB(5),

.active_level = LOWLEVEL,

.status = ON,

.blink = DISABLE,

},

[1] = {

.num = 2,

.gpio = S3C2410_GPB(6),

.active_level = LOWLEVEL,

.status = OFF,

.blink = DISABLE,

},

[2] = {

.num = 3,

.gpio = S3C2410_GPB(8),

.active_level = LOWLEVEL,

.status = OFF,

.blink = DISABLE,

},

[3] = {

.num = 4,

.gpio = S3C2410_GPB(10),


.active_level = LOWLEVEL,

.status = OFF,

.blink = DISABLE,

},

};




/* The LED platform device private data */

static struct s3c_led_platform_data s3c_led_data = {

.leds = s3c_leds,

.nleds = ARRAY_SIZE(s3c_leds),

};


struct led_device

{

struct s3c_led_platform_data *data;

struct cdev cdev;

struct class *dev_class;

struct timer_list blink_timer;

} led_device;




static void platform_led_release(struct device * dev)

{

int i;

struct s3c_led_platform_data *pdata = dev->platform_data;


dbg_print("%s():%dn", __FUNCTION__,__LINE__);


/* Turn all LED off */

for(i=0; inleds; i++)

{

/* for linux-3.8.0 */

gpio_set_value(pdata->leds[i].gpio, ~pdata->leds[i].active_level);


#if 0

/* for linux-3.0.0 check in s3c2410_gpio_setpin() in Documentation/arm/Samsung-S3C24XX/GPIO.txt*/

s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level);

#endif

}

}




static struct platform_device s3c_led_device = {

.name = "s3c_led",

.id = 1,

.dev =

{

.platform_data = &s3c_led_data,

.release = platform_led_release,

},

};



/* ===================== led device driver part ===========================*/


void led_timer_handler(unsigned long data)

{

    int  i;

    struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data;


    for(i=0; inleds; i++)

    {

        if(ON == pdata->leds[i].status)

        {

              gpio_set_value(pdata->leds[i].gpio, pdata->leds[i].active_level);

        }

        else

        {

              gpio_set_value(pdata->leds[i].gpio, ~pdata->leds[i].active_level);

        }


        if(ENABLE == pdata->leds[i].blink )  /* LED should blink */

        {

            /* Switch status between 0 and 1 to turn LED ON or off */

            pdata->leds[i].status = pdata->leds[i].status ^ 0x01;

        }


        /* time clock */

        mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT);

    }

}



static int led_open(struct inode *inode, struct file *file)

{

    struct led_device *pdev ;

    struct s3c_led_platform_data *pdata;


    pdev = container_of(inode->i_cdev, struct led_device, cdev);

    pdata = pdev->data;


    file->private_data = pdata;


    return 0;

}



static int led_release(struct inode *inode, struct file *file)

{

    return 0;

}



static void print_led_help(void)

{

    printk("Follow is the ioctl() command for LED driver:n");

    printk("Enable Driver debug command: %un", SET_DRV_DEBUG);

    printk("Get Driver verion  command : %un", GET_DRV_VER);

    printk("Turn LED on command        : %un", LED_ON);

    printk("Turn LED off command       : %un", LED_OFF);

    printk("Turn LED blink command     : %un", LED_BLINK);

}



/* compatible with kernel version >=2.6.38*/

static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)

{

    struct s3c_led_platform_data *pdata = file->private_data;


    switch (cmd)

    {

        case SET_DRV_DEBUG:

            dbg_print("%s driver debug now.n", DISABLE == arg ? "Disable" : "Enable");

            debug = (0==arg) ? DISABLE : ENABLE;

            break;

        case GET_DRV_VER:

            print_version(DRV_VERSION);

            return DRV_VERSION;


        case LED_OFF:

            if(pdata->nleds <= arg)

            {

               printk("LED%ld doesn't existn", arg);

               return -ENOTTY;

            }

            pdata->leds[arg].status = OFF;

            pdata->leds[arg].blink = DISABLE;

            break;


        case LED_ON:

              if(pdata->nleds <= arg)

            {

               printk("LED%ld doesn't existn", arg);

               return -ENOTTY;

            }

            pdata->leds[arg].status = ON;

            pdata->leds[arg].blink = DISABLE;

            break;


        case LED_BLINK:

            if(pdata->nleds <= arg)

            {

               printk("LED%ld doesn't existn", arg);

               return -ENOTTY;

            }

            pdata->leds[arg].blink = ENABLE;

            pdata->leds[arg].status = ON;

            break;


        default:

            dbg_print("%s driver don't support ioctl command=%dn", DEV_NAME, cmd);

            print_led_help();

            return -EINVAL;

 

    }

    return 0;

}



static struct file_operations led_fops = {

    .owner = THIS_MODULE,

    .open = led_open,

    .release = led_release,

    .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/

};



static int s3c_led_probe(struct platform_device *dev)

{

    struct s3c_led_platform_data *pdata = dev->dev.platform_data;

    int result = 0;

    int i;

    dev_t devno;


    /* Initialize the LED status */

    for(i=0; inleds; i++)

    {

         s3c_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT);

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>