于Dragonboard 410c的智能照明系统(二)

在上篇blog中,我们已经准备好做这个小设计的物品了,现在到了真正开始做的时候了,其主要部分就是aw2013这颗芯片的控制,通过它就可以随意的控制灯了,但是,总感觉这颗芯片用在这里明显制约了这个照明系统,因为aw2013是用来控制led灯的,所以亮度上总感觉有点不够,不过后面我们可以慢慢完善,先来看看驱动代码吧。

#include <linux/leds-aw2013.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/workqueue.h>

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=%d\n",
        __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<AW2013_I2C_MAX_LOOP; 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<AW2013_I2C_MAX_LOOP; 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=%d\n",
            __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=%d\n",
            __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<AW2013_LED_TYPE_TOTAL;i++) {
        if(cust_aw2013_led_list[i].data.level_change) {
            cust_aw2013_led_list[i].data.level_change = false;
            aw2013_led_set(i,cust_aw2013_led_list[i].data.level);
        }
        if(cust_aw2013_led_list[i].data.blink_change) {
            cust_aw2013_led_list[i].data.blink_change = false;
            aw2013_blink_set(i, cust_aw2013_led_list[i].data.delay_on, cust_aw2013_led_list[i].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<AW2013_LED_TYPE_TOTAL;i++) {
        lcdev[i] = kzalloc(sizeof(struct led_classdev), GFP_KERNEL);
        lcdev[i]->name = cust_aw2013_led_list[i].name;
        lcdev[i]->brightness = LED_OFF;
        lcdev[i]->brightness_set = cust_aw2013_led_list[i].brightness_set;
        lcdev[i]->blink_set = cust_aw2013_led_list[i].blink_set;
        ret = led_classdev_register(&client->dev,lcdev[i]);
    }
    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最亮

还有其它节点及作用就不一一说明了。

这些都准备好以后,一个智能照明系统就完成了一半了,另一半就是控制端了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值