platform平台总线编写LED驱动

1.使用之前LED驱动框架的代码为基础来改写。
先改写driver部分,也就是leds-x210.c部分。
添加platform_driver:
static int s5pv210_led_probe(struct platform_device *dev)
{
printk(KERN_INFO, “s5pv210_led_probe\n”);
return 0;
}

static int s5pv210_led_remove(struct platform_device *dev)
{
printk(KERN_INFO, “s5pv210_led_remove\n”);
return 0;
}

static struct platform_driver s5pv210_led_driver = {
.probe = s5pv210_led_probe,
.remove = s5pv210_led_remove,
.driver = {
.name = “s5pv210_led”,
.owner = THIS_MODULE,
},
};

static int __init s5pv210_led_init(void)
{
return platform_driver_register(&s5pv210_led_driver);
}

static void __exit s5pv210_led_exit(void)
{
platform_driver_unregister(&s5pv210_led_driver);
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);

2.添加platform_device,在mach-x210.c中添加:
static struct s5pv210_led_platdata x210_led1_pdata = {
.name = “led1”,
.gpio = S5PV210_GPJ0(3),
};

static struct s5pv210_led_platdata x210_led2_pdata = {
.name = “led2”,
.gpio = S5PV210_GPJ0(4),
};

static struct s5pv210_led_platdata x210_led3_pdata = {
.name = “led3”,
.gpio = S5PV210_GPJ0(5),
};
//led的platform device
static struct platform_device x210_led1 = {
.name = “s5pv210_led”,
.id = 1,
.dev = {
.platform_data = &x210_led1_pdata,
},
};
//led的platform device
static struct platform_device x210_led2 = {
.name = “s5pv210_led”,
.id = 2,
.dev = {
.platform_data = &x210_led2_pdata,
},
};
//led的platform device
static struct platform_device x210_led3 = {
.name = “s5pv210_led”,
.id = 3,
.dev = {
.platform_data = &x210_led3_pdata,
},
};
我们把s5pv210_led_platdata的类型定义在了:
arch/arm/mach-s5pv210/include/mach/leds-gpio.h中。
我们把platform_device 都添加到smdkc110_devices这个数组里面去。
smdkc110_machine_init
调用:
platform_add_devices就会添加这个数组。


最终完整版代码如下:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/leds.h>
#include <linux/io.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <mach/leds-gpio.h>
#include <linux/kernel.h>
#include <linux/device.h>

struct s5pv210_gpio_led
{
struct led_classdev cdev;
struct s5pv210_led_platdata *pdata;
};

static inline struct s5pv210_gpio_led * s5pv210_to_gpio(struct led_classdev *led_cdev)
{
return container_of(led_cdev, struct s5pv210_gpio_led, cdev);
}

static void s5pv210_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct s5pv210_gpio_led * led = s5pv210_to_gpio(led_cdev);
struct s5pv210_led_platdata * pd = led->pdata;

gpio_set_value(pd->gpio, (brightness > 0? 0:1));

}

static int s5pv210_led_probe(struct platform_device *dev)
{
int ret = -1;
struct s5pv210_led_platdata * pdata = dev->dev.platform_data;
struct s5pv210_gpio_led * led = NULL;
led = kzalloc(sizeof(struct s5pv210_gpio_led), GFP_KERNEL);
if (NULL == led)
{
dev_err(&dev->dev, “No memory for device\n”);
return -ENOMEM;
}
platform_set_drvdata(dev, led);

led->cdev.name = pdata->name;
led->cdev.brightness_set = s5pv210_led_set;
led->pdata = pdata;

if (gpio_request(pdata->gpio, pdata->name))
{
	printk(KERN_INFO "gpio_request %s fail\n", pdata->name);
}
else
{
	gpio_direction_output(pdata->gpio, 1);
}

ret = led_classdev_register(&dev->dev, &led->cdev);
if (ret < 0) 
{		
	dev_err(&dev->dev, "led_classdev_register failed\n");		
	kfree(led);		
	return ret;	
}

printk(KERN_INFO "s5pv210_led_probe\n");
return 0;

}

static inline struct s5pv210_gpio_led * s5pv210_pdev_to_gpio(struct platform_device *dev)
{
return platform_get_drvdata(dev);
}

static int s5pv210_led_remove(struct platform_device *dev)
{
struct s5pv210_gpio_led *led = s5pv210_pdev_to_gpio(dev);
led_classdev_unregister(&led->cdev);
gpio_free(led->pdata->gpio);
kfree(led);
printk(KERN_INFO “s5pv210_led_remove\n”);
return 0;
}

static struct platform_driver s5pv210_led_driver = {
.probe = s5pv210_led_probe,
.remove = s5pv210_led_remove,
.driver = {
.name = “s5pv210_led”,
.owner = THIS_MODULE,
},
};

static int __init s5pv210_led_init(void)
{
return platform_driver_register(&s5pv210_led_driver);
}

static void __exit s5pv210_led_exit(void)
{
platform_driver_unregister(&s5pv210_led_driver);
}

module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);

// MODULE_xxx这种宏作用是用来添加模块描述信息
MODULE_LICENSE(“GPL”); // 描述模块的许可证
MODULE_AUTHOR(“Mark 867439374@qq.com”); // 描述模块的作者
MODULE_DESCRIPTION(“s5pv210 led driver”); // 描述模块的介绍信息
MODULE_ALIAS(“s5pv210_led”); // 描述模块的别名信息


对上述代码进行简单的分析和解释:
1.s5pv210_led_init函数中调用platform_driver_register函数。
platform_driver_register函数调用中会去match。
当platform_driver遇到(match上)platform_device的时候,就会去执行driver里面定义的probe函数。
2.有两个很关键的结构体:
struct s5pv210_led_platdata {
unsigned int gpio;
unsigned int flags;
char *name;
char *def_trigger;
};
struct s5pv210_gpio_led
{
struct led_classdev cdev;
struct s5pv210_led_platdata *pdata;
};
3.probe函数中首先会去拿platform_device那边的platform_data,然后给
s5pv210_gpio_led 分配内存,分配内存之后,把s5pv210_gpio_led 存到
platform_device.dev.p.driver_data中,使用platform_set_drvdata函数,相当于把driver这边分配的内存的指针又存到platform_device那边去了。
然后就是led_classdev的填充和注册、以及gpio权限的申请和设置gpio的输出方向等。
4.s5pv210_led_set这个函数很简单,先用container_of得到s5pv210_gpio_led的指针,然后再得到s5pv210_led_platdata的指针。
最后调用gpio_set_value(pd->gpio, (brightness > 0? 0:1));来设置gpio的高低电平。echo的值大于0时,gpio就会是低电平,灯就会亮。
5.最后就是s5pv210_led_remove函数:
先从platform_device里面拿到s5pv210_gpio_led的指针,刚才platform_set_drvdata存进去的。
然后led_classdev_unregister,注销led设备
gpio_free(led->pdata->gpio);
最后释放s5pv210_gpio_led的动态内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值