硬件平台:mt7688
软件平台:原生sdk MediaTek_ApSoC_SDK_4300_20140916 linux-3.10.14内核
ws2811是单总线接口的led驱动芯片,通过单个GPIO模拟高低时序发出颜 {MOD}值,芯片收到后控制输出对应PWM改变三路RGB灯的颜 {MOD}。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "ralink_gpio.h"
static dev_t sys_led_dev;
static struct class* sys_led_class = 0;
static struct cdev* sys_led_cdev = 0;
#define SYS_LED_NAME "sys_led"
union _rgb
{
unsigned int color;
struct
{
unsigned char r;
unsigned char g;
unsigned char b;
}u_s;
};
#define set_led_hight() *(volatile u32*)(RALINK_REG_PIOSET1) = (1 << (44 - 32))
#define set_led_low() *(volatile u32*)(RALINK_REG_PIORESET1) = (1 << (44 - 32))
inline void set_out()//设置GPIO为输出以便控制WS2811
{
unsigned long tmp;
tmp = *(volatile u32 *)(RALINK_REG_GPIOMODE2);
tmp |= 1;
*(volatile u32 *)(RALINK_REG_GPIOMODE2) = tmp;
tmp = *(volatile u32*)(RALINK_REG_PIODIR1);
tmp |= (1 << (44 - 32));
*(volatile u32*)(RALINK_REG_PIODIR1) = tmp;
}
static void set_led_1(void)//发出二进制1
{
set_led_hight();
ndelay(678);
set_led_low();
ndelay(278);
}
static void set_led_0(void)//发出二进制0
{
set_led_hight();
ndelay(278);
set_led_low();
ndelay(678);
}
// >= 50us
static void reset_op(void)//发出Reset信号
{
set_led_hight();//首先将总线拉高ndelay
ndelay(300);//保持一段时间
set_led_low();//拉低
udelay(50);//至少保持50us,之后芯片等待接收新的数据
}
static int sys_led_open(struct inode* in, struct file* fi)
{
set_out();
return 0;
}
static int sys_led_ioctl(struct file* fi, unsigned int cmd, unsigned long data)
{
union _rgb rgb;
int i;
unsigned int fl;
switch (cmd)
{
case 0:
if (copy_from_user((char*)&rgb, (char*)data, sizeof(rgb)))//从用户空间获得颜 {MOD}值
{
return -1;
}
set_out();
reset_op();
local_irq_save(fl);//把当前中断状态保存到flags中,然后禁用当前处理器上的中断发送
for (i = 0; i < 24; ++i)//发出24bit的颜 {MOD}值
{
if (1 & rgb.color)
set_led_1();
else
set_led_0();
rgb.color >>= 1;
}
local_irq_restore(fl);//中断恢复
break;
case 1:
reset_op();
break;
}
return 0;
}
static ssize_t sys_led_write(struct file* fi, char* __user buf, size_t len, loff_t* ff)
{
union _rgb rgb;
unsigned int fl;
int i;
if (copy_from_user((char*)&rgb, (char*)buf, sizeof(rgb)))
{
return -1;
}
set_out();
reset_op();
local_irq_save(fl);
for (i = 0; i < 24; ++i)
{
if (1 & rgb.color)
set_led_1();
else
set_led_0();
rgb.color >>= 1;
}
local_irq_restore(fl);
return sizeof(union _rgb);
}
static struct file_operations led_file =
{
.owner = THIS_MODULE,
.open = sys_led_open,
.unlocked_ioctl = sys_led_ioctl,
.write = sys_led_write,
};
static void __exit sys_led_exit(void);
static int __init sys_led_init(void)
{
int ret;
sys_led_class = class_create(THIS_MODULE, "sys_led_class");
if (IS_ERR(sys_led_class))
{
printk("error : sys led class create failed
");
return -1;
}
ret = alloc_chrdev_region(&sys_led_dev, 0, 1, SYS_LED_NAME);
if (ret < 0)
{
printk("error : get dev number failed
");
goto error_exit;
}
device_create(sys_led_class, NULL, sys_led_dev, NULL, "%s", SYS_LED_NAME);
sys_led_cdev = cdev_alloc();
if (!sys_led_cdev)
{
printk("new memory cdev failed
");
goto error_exit;
}
cdev_init(sys_led_cdev, &led_file);
sys_led_cdev->owner = THIS_MODULE;
ret = cdev_add(sys_led_cdev, sys_led_dev, 1);
if (ret < 0)
{
printk("sys led cdev add failed
");
goto error_exit;
}
return 0;
error_exit:
sys_led_exit();
return -1;
}
static void __exit sys_led_exit(void)
{
if (sys_led_cdev)
{
cdev_del(sys_led_cdev);
}
if (sys_led_class)
{
device_destroy(sys_led_class, sys_led_dev);
class_destroy(sys_led_class);
}
unregister_chrdev_region(sys_led_dev, 1);
}
module_init(sys_led_init);
module_exit(sys_led_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("system status led control");
MODULE_AUTHOR("system led");