在上篇blog中,我们已经准备好做这个小设计的物品了,现在到了真正开始做的时候了,其主要部分就是aw2013这颗芯片的控制,通过它就可以随意的控制灯了,但是,总感觉这颗芯片用在这里明显制约了这个照明系统,因为aw2013是用来控制led灯的,所以亮度上总感觉有点不够,不过后面我们可以慢慢完善,先来看看驱动代码吧。
#include
#include
#include
#include
#include
unsigned int light;
unsigned int blink;
unsigned int breath;
#define AW2013_I2C_MAX_LOOP 10
#define I2C_delay 2 //这颗芯片的最高频率400k,所以要保证I2C速度不高于400k
#define aw2013_DBG
#ifdef aw2013_DBG
#define DBG_PRINT(x...) printk(KERN_ERR x)
#else
#define DBG_PRINT(x...)
#endif
static unsigned char LED_ON_FLAG = 0x0;
#define TST_BIT(flag,bit) (flag & (0x1 << bit))
#define CLR_BIT(flag,bit) (flag &= (~(0x1 << bit)))
#define SET_BIT(flag,bit) (flag |= (0x1 << bit))
//以下为调节呼吸效果的参数
#define Imax 0x01
#define Rise_time 0x02
#define Hold_time 0x01
#define Fall_time 0x02
#define Off_time 0x01
#define Delay_time 0x00
#define Period_Num 0x00
...............
//*******************************白灯呼吸***********************************///
void aw2013_breath_all(int led0,int led1,int led2) //led on=0x01 ledoff=0x00
{
//write_reg(0x00, 0x55); // Reset
aw2013_i2c_write_reg(0x01, 0x01); // enable LED 不使用中断
aw2013_i2c_write_reg(0x31, Imax|0x70); //config mode, IMAX = 5mA
aw2013_i2c_write_reg(0x32, Imax|0x70);
aw2013_i2c_write_reg(0x33, Imax|0x70);
aw2013_i2c_write_reg(0x34, 0xff); // LED0 level,
aw2013_i2c_write_reg(0x35, 0xff); // LED1 level,
aw2013_i2c_write_reg(0x36, 0xff); // LED2 level,
aw2013_i2c_write_reg(0x37, Rise_time<<4 | Hold_time); // 上升时间,保持时间设定
aw2013_i2c_write_reg(0x3a, Rise_time<<4 | Hold_time);
aw2013_i2c_write_reg(0x3d, Rise_time<<4 | Hold_time);
aw2013_i2c_write_reg(0x38, Fall_time<<4 | Off_time); // 下降时间,关闭时间设定
aw2013_i2c_write_reg(0x3b, Fall_time<<4 | Off_time);
aw2013_i2c_write_reg(0x3e, Fall_time<<4 | Off_time);
aw2013_i2c_write_reg(0x39, Delay_time<<4| Period_Num); // 呼吸延迟时间,呼吸周期设定
aw2013_i2c_write_reg(0x3c, Delay_time<<4| Period_Num);
aw2013_i2c_write_reg(0x3f, Delay_time<<4| Period_Num);
aw2013_i2c_write_reg(0x30, led2<<2|led1<<1|led0); //led on=0x01 ledoff=0x00
aw2013_delay_1us(8);//需延时5us以上
}
void led_bright(int enable)
{
if(enable){
//write_reg(0x00, 0x55); // Reset
aw2013_i2c_write_reg(0x00, 0x54);
aw2013_i2c_write_reg(0x01, 0x01); // enable LED 不使用中断
aw2013_i2c_write_reg(0x31, Imax); //config mode, IMAX = 5mA
aw2013_i2c_write_reg(0x32, Imax); //config mode, IMAX = 5mA
aw2013_i2c_write_reg(0x33, Imax); //config mode, IMAX = 5mA
aw2013_i2c_write_reg(0x34, 0xff); // LED0 level,
aw2013_i2c_write_reg(0x35, 0xff); // LED1 level,
aw2013_i2c_write_reg(0x36, 0xff); // LED2 level,
aw2013_i2c_write_reg(0x30, 0x07); //led on=0x01 ledoff=0x00
}else{
aw2013_i2c_write_reg(0x30, 0x00); //led on=0x01 ledoff=0x00
}
}
void led_off_aw2013(void)//( unsigned int id )
{
aw2013_i2c_write_reg(0x30, 0); //led off
aw2013_i2c_write_reg(0x01,0);
}
void aw2013_delay_1us(u16 wTime) //
{
udelay(wTime);
}
static bool aw2013_i2c_write_reg_org(unsigned char reg,unsigned char data)
{
bool ack=0;
unsigned char ret;
unsigned char wrbuf[2];
wrbuf[0] = reg;
wrbuf[1] = data;
ret = i2c_master_send(aw2013_i2c_client, wrbuf, 2);
if (ret != 2) {
dev_err(&aw2013_i2c_client->dev,
"%s: i2c_master_recv() failed, ret=%dn",
__func__, ret);
ack = 1;
}
return ack;
}
bool aw2013_i2c_write_reg(unsigned char reg,unsigned char data)
{
bool ack=0;
unsigned char i;
for (i=0; i
{
ack = aw2013_i2c_write_reg_org(reg,data);
if (ack == 0) // ack success
break;
}
return ack;
}
unsigned char aw2013_i2c_read_reg(unsigned char regaddr)
{
unsigned char rdbuf[1], wrbuf[1], ret, i;
wrbuf[0] = regaddr;
for (i=0; i
{
ret = i2c_master_send(aw2013_i2c_client, wrbuf, 1);
if (ret == 1)
break;
}
ret = i2c_master_recv(aw2013_i2c_client, rdbuf, 1);
if (ret != 1)
{
dev_err(&aw2013_i2c_client->dev,"%s: i2c_master_recv() failed, ret=%dn",
__func__, ret);
}
return rdbuf[0];
}
extern struct i2c_adapter * get_mt_i2c_adaptor(int);
int breathlight_master_send(char * buf ,int count)
{
unsigned char ret;
ret = i2c_master_send(aw2013_i2c_client, buf, count);
if (ret != count)
{
dev_err(&aw2013_i2c_client->dev,"%s: i2c_master_recv() failed, ret=%dn",
__func__, ret);
}
return ret;
}
static void led_close(void){
char buf[2];
buf[0] = 0x00;
buf[1] = 0x54;
breathlight_master_send(buf, 2);
}
//*******************************亮灯***********************************///
void led_light(int enable)
{
char buf[2];
if(enable){
buf[0]=0x00;
buf[1]=0x54;
breathlight_master_send(buf,2);
buf[0]=0x01;
buf[1]=0x01;
breathlight_master_send(buf,2);
buf[0]=0x31+(enable-1);
buf[1]=Imax;
breathlight_master_send(buf,2);
buf[0]=0x34+(enable-1);
buf[1]=0xff;
breathlight_master_send(buf,2);
buf[0]=0x30;
buf[1]=1<<(enable-1);
breathlight_master_send(buf,2);
}else{
buf[0]=0x30;
buf[1]=0<<(enable-1);
breathlight_master_send(buf,2);
}
}
//*******************************单色呼吸***********************************///
void led_breath(int enable)
{
char buf[2];
if(enable) {
buf[0]=0x00;
buf[1]=0x54;
breathlight_master_send(buf,2);
buf[0]=0x01;
buf[1]=0x01;
breathlight_master_send(buf,2);
buf[0]=0x31+(enable-7);
buf[1]=0x73;
breathlight_master_send(buf,2);
buf[0]=0x34+(enable-7);
buf[1]=0xff;
breathlight_master_send(buf,2);
buf[0]=0x37+(enable-7)*3;
buf[1]=0x32;
breathlight_master_send(buf,2);
buf[0]=0x38+(enable-7)*3;
buf[1]=0x33;
breathlight_master_send(buf,2);
buf[0]=0x39+(enable-7)*3;
buf[1]=0x00;
breathlight_master_send(buf,2);
buf[0]=0x30;
buf[1]=1<<(enable-7);
breathlight_master_send(buf,2);
}else {
buf[0]=0x30;
buf[1]=0<<(enable-7);
breathlight_master_send(buf,2);
}
}
//*******************************上升时间***********************************///
static void change_risetime(int command){
char buff[8];
int i, d = 0;
buff[0] = aw2013_i2c_read_reg(0x01);
buff[1] = aw2013_i2c_read_reg(0x30);
buff[2] = aw2013_i2c_read_reg(0x31);
buff[3] = aw2013_i2c_read_reg(0x32);
buff[4] = aw2013_i2c_read_reg(0x33);
buff[5] = aw2013_i2c_read_reg(0x37);
buff[6] = aw2013_i2c_read_reg(0x3a);
buff[7] = aw2013_i2c_read_reg(0x3d);
if(buff[0] == 1){
for(i = 0; i < 3; i++){
if((buff[1] & (1 << i)) && (buff[2+i] == 0x71)){
aw2013_i2c_write_reg((0x37+d), (buff[5+i] & 0x0f) | (command << 4)); //command 0x0 ----- 0x7
d += 3;
}
}
}
}
//*******************************最大亮度保持时间***********************************///
static void change_holdtime(int command){
char buff[8];
int i, d = 0;
buff[0] = aw2013_i2c_read_reg(0x01);
buff[1] = aw2013_i2c_read_reg(0x30);
buff[2] = aw2013_i2c_read_reg(0x31);
buff[3] = aw2013_i2c_read_reg(0x32);
buff[4] = aw2013_i2c_read_reg(0x33);
buff[5] = aw2013_i2c_read_reg(0x37);
buff[6] = aw2013_i2c_read_reg(0x3a);
buff[7] = aw2013_i2c_read_reg(0x3d);
if(buff[0] == 1){
for(i = 0; i < 3; i++){
if(buff[1] & (1 << i) && (buff[2+i] == 0x71)){
aw2013_i2c_write_reg((0x37+d), (buff[5+i] & 0xf0) | command); //command 0x0 ----- 0x6
d += 3;
}
}
}
}
//*******************************下降时间***********************************///
static void change_falltime(int command){
char buff[8];
int i, d = 0;
buff[0] = aw2013_i2c_read_reg(0x01);
buff[1] = aw2013_i2c_read_reg(0x30);
buff[2] = aw2013_i2c_read_reg(0x31);
buff[3] = aw2013_i2c_read_reg(0x32);
buff[4] = aw2013_i2c_read_reg(0x33);
buff[5] = aw2013_i2c_read_reg(0x38);
buff[6] = aw2013_i2c_read_reg(0x3b);
buff[7] = aw2013_i2c_read_reg(0x3e);
if(buff[0] == 1){
for(i = 0; i < 3; i++){
if((buff[1] & (1 << i)) && (buff[2+i] == 0x71)){
aw2013_i2c_write_reg((0x38+d), (buff[5+i] & 0x0f) | (command << 4)); //command 0x0 ----- 0x7
d += 3;
}
}
}
}
//*******************************闪烁中灭灯保持时间***********************************///
static void change_offtime(int command){
char buff[8];
int i, d = 0;
buff[0] = aw2013_i2c_read_reg(0x01);
buff[1] = aw2013_i2c_read_reg(0x30);
buff[2] = aw2013_i2c_read_reg(0x31);
buff[3] = aw2013_i2c_read_reg(0x32);
buff[4] = aw2013_i2c_read_reg(0x33);
buff[5] = aw2013_i2c_read_reg(0x38);
buff[6] = aw2013_i2c_read_reg(0x3b);
buff[7] = aw2013_i2c_read_reg(0x3e);
if(buff[0] == 1){
for(i = 0; i < 3; i++){
if(buff[1] & (1 << i) && (buff[2+i] == 0x71)){
aw2013_i2c_write_reg((0x38+d), (buff[5+i] & 0xf0) | command); //command 0x0 ----- 0x7
d += 3;
}
}
}
}
//*******************************闪烁启动延迟时间***********************************///
static void change_delaytime(int command){
char buff[8];
int i, d = 0;
buff[0] = aw2013_i2c_read_reg(0x01);
buff[1] = aw2013_i2c_read_reg(0x30);
buff[2] = aw2013_i2c_read_reg(0x31);
buff[3] = aw2013_i2c_read_reg(0x32);
buff[4] = aw2013_i2c_read_reg(0x33);
buff[5] = aw2013_i2c_read_reg(0x39);
buff[6] = aw2013_i2c_read_reg(0x3c);
buff[7] = aw2013_i2c_read_reg(0x3f);
if(buff[0] == 1){
for(i = 0; i < 3; i++){
if((buff[1] & (1 << i)) && (buff[2+i] == 0x71)){
aw2013_i2c_write_reg((0x39+d), (buff[5+i] & 0x0f) | (command << 4)); //command 0x0 ----- 0x8
d += 3;
}
}
}
}
//*******************************最大亮度改变***********************************///
static void change_bright(int command){
char buff[8];
int i;
buff[0] = aw2013_i2c_read_reg(0x01);
buff[1] = aw2013_i2c_read_reg(0x30);
buff[2] = aw2013_i2c_read_reg(0x31);
buff[3] = aw2013_i2c_read_reg(0x32);
buff[4] = aw2013_i2c_read_reg(0x33);
if(buff[0] == 1){
for(i = 0; i < 3; i++){
if(buff[1] & (1 << i)){
aw2013_i2c_write_reg((0x34+i), command); //command 0x0 ----- 0x8
}
}
}
}
void Suspend_led(void)
{
//first if it's charging situation, we skip the other actions
led_off_aw2013();
}
static ssize_t aw2013_store_led(struct device* cd, struct device_attribute *attr,
const char *buf, size_t len )
{
int temp,command;
sscanf(buf, "%d", &temp);
command = temp & 0x0f;
if(command == 0){
led_close();
}
if(command > 0 && command <= 3)
{
led_light(command);
}
if(command > 3 && command <= 6){
led_blink(command);
}
if(command > 6 && command <= 9){
led_breath(command);
}
if(command == 10){
led_bright(command);
}
if(command == 11){
aw2013_breath_all(1,1,1);
}
return len;
}
................
................
static ssize_t aw2013_get_reg(struct device* cd, struct device_attribute* attr,
char *buf)
{
u8 rbuf[18];
u8 i;
rbuf[0] = aw2013_i2c_read_reg(0x00);
rbuf[1] = aw2013_i2c_read_reg(0x01);
for(i=0;i<0x10;i++) {
rbuf[i+2] = aw2013_i2c_read_reg(0x30+i);
}
return scnprintf(buf,PAGE_SIZE,"[0]%x;[1]%x;[30]%x;[31]%x;[32]%x;[33]%x;[34]%x;[35]%x;[36]%x;[37]%x;[38]%x;[39]%x;[3a]%x;[3b]%x;[3c]%x;[3d]%d;[3e]%x;[3f]%x n",
rbuf[0],rbuf[1],rbuf[2],rbuf[3],rbuf[4],rbuf[5],rbuf[6],rbuf[7],rbuf[8],rbuf[9],rbuf[10],
rbuf[11],rbuf[12],rbuf[13],rbuf[14],rbuf[15],rbuf[16],rbuf[17]);
}
static ssize_t aw2013_set_reg(struct device * cd,struct device_attribute * attr,
const char * buf,size_t len)
{
return 0;
}
static int aw2013_create_sysfs(struct i2c_client *client)
{
int err;
struct device *dev = &(client->dev);
printk(KERN_ERR "%s", __func__);
err = device_create_file(dev, &dev_attr_led);
err = device_create_file(dev, &dev_attr_reg);
err = device_create_file(dev, &dev_attr_risetime);
err = device_create_file(dev, &dev_attr_holdtime);
err = device_create_file(dev, &dev_attr_falltime);
err = device_create_file(dev, &dev_attr_offtime);
err = device_create_file(dev, &dev_attr_delaytime);
err = device_create_file(dev, &dev_attr_bright);
return err;
}
........................
static void aw2013_dispatch_work(struct work_struct *data)
{
int i;
printk(" %s n",__func__);
for(i=0;i
if(cust_aw2013_led_list.data.level_change) {
cust_aw2013_led_list.data.level_change = false;
aw2013_led_set(i,cust_aw2013_led_list.data.level);
}
if(cust_aw2013_led_list.data.blink_change) {
cust_aw2013_led_list.data.blink_change = false;
aw2013_blink_set(i, cust_aw2013_led_list.data.delay_on, cust_aw2013_led_list.data.delay_off);
}
}
return;
}
static void aw2013_blue_led_set(struct led_classdev *led_cdev, enum led_brightness level)
{
struct aw2013_led_data *led_data;
led_data = &cust_aw2013_led_list[BLUE_LED_ID].data;
printk(" %s, level=%d; new level=%d n",__func__,led_data->level, level);
if(led_data->level != level) {
led_data->level = level;
led_data->level_change = true;
}
schedule_work(&aw2013_work);
return;
}
static int aw2013_blue_blink_set(struct led_classdev *led_cdev,
unsigned long *delay_on,
unsigned long *delay_off)
{
struct aw2013_led_data *led_data;
led_data = &cust_aw2013_led_list[BLUE_LED_ID].data;
printk(" %s delay_on=%lu; delay_off = %lu; new delay_on=%lu; delay_off=%lu n",__func__,
led_data->delay_on,led_data->delay_off,*delay_on,*delay_off);
if((led_data->delay_on != *delay_on) || led_data->delay_off != *delay_off)
led_data->blink_change = true;
else
led_data->blink_change = false;
led_data->delay_off = *delay_off;
led_data->delay_on = *delay_on;
if((led_data->delay_on > 0) && (led_data->delay_off > 0))
led_data->blink = 1;
else if(!led_data->delay_on && !led_data->delay_off)
led_data->blink = 0;
schedule_work(&aw2013_work);
//aw2013_blink_set(BLUE_LED_ID, *delay_on, *delay_off );
return 0;
}
.................................
static struct cust_aw2013_led cust_aw2013_led_list[AW2013_LED_TYPE_TOTAL] = {
{"blue", aw2013_blue_led_set, aw2013_blue_blink_set, {0}},
{"green", aw2013_green_led_set, aw2013_green_blink_set, {0}},
{"red", aw2013_red_led_set, aw2013_red_blink_set, {0}},
};
static int aw2013_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret;
int i;
struct led_classdev *lcdev[AW2013_LED_TYPE_TOTAL];
aw2013_i2c_client = client;
Suspend_led();
for(i=0;i
lcdev = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
lcdev->name = cust_aw2013_led_list.name;
lcdev->brightness = LED_OFF;
lcdev->brightness_set = cust_aw2013_led_list.brightness_set;
lcdev->blink_set = cust_aw2013_led_list.blink_set;
ret = led_classdev_register(&client->dev,lcdev);
}
INIT_WORK(&aw2013_work,aw2013_dispatch_work);
aw2013_create_sysfs(client);
return 0;
}
static int aw2013_i2c_remove(struct i2c_client *client)
{
aw2013_i2c_client = NULL;
return 0;
}
static const struct i2c_device_id aw2013_i2c_id[] = {
{ "aw2013", },
{ }
};
MODULE_DEVICE_TABLE(i2c, aw2013_i2c_id);
static struct i2c_board_info __initdata aw2013_i2c_hw={ I2C_BOARD_INFO("aw2013", AW2013_I2C_ADDR)};
static const struct of_device_id of_aw2013_leds_match[] = {
{ .compatible = "aw,aw2013", },
{},
};
static struct i2c_driver aw2013_i2c_driver = {
.driver =
{
.owner = THIS_MODULE,
.name = "aw2013",
.of_match_table = of_aw2013_leds_match,
},
.probe = aw2013_i2c_probe,
.remove = aw2013_i2c_remove,
.id_table = aw2013_i2c_id,
};
static int __init aw2013_driver_init(void)
{
int ret;
i2c_register_board_info(2, &aw2013_i2c_hw, 1);
ret = i2c_add_driver(&aw2013_i2c_driver);
printk("aw2013_driver_init:end n");
return 0;
}
static void __exit aw2013_driver_exit(void)
{
i2c_del_driver(&aw2013_i2c_driver);
}
module_init(aw2013_driver_init);
module_exit(aw2013_driver_exit);
MODULE_DESCRIPTION("direct control driver");
MODULE_AUTHOR("live)");
MODULE_LICENSE("GPL");
其中用到的主要程序部分就像上面给出的,在这个程序中我们创建了几个节点进行控制,下面来看几个:
改变灯颜色的节点:
/sys/bus/i2c/devices/6-0045/led
写入的值及对应的含义如下:
0:关灯
1:红灯常量
2:蓝灯常量
3:绿灯常量
..........
改变灯亮度的节点:
/sys/bus/i2c/devices/6-0045/bright
节点值0x00---0xff,其中0xff最亮
还有其它节点及作用就不一一说明了。
这些都准备好以后,一个智能照明系统就完成了一半了,另一半就是控制端了。
|