瑞芯微Rockchip开发者社区
直播中

徐伟

7年用户 921经验值
私信 关注
[问答]

AW9523B I2C总线LED驱动函数该怎样去编写呢

AW9523B分为几种工作模式呢?
AW9523B I2C总线LED驱动函数该怎样去编写呢?

回帖(1)

黄晔华

2022-2-18 09:53:54
本来想做的是Android APP方向的工作,结果稀里糊涂的就干起了驱动。长话短说,作为人生中的第一个驱动,当灯终于亮起来的时候,还是蛮感动的,菜鸟真的很感动的说。
AW9523B分为2种工作模式,分别为GPIO模式和LED模式,由于刚开始的时候并不熟悉驱动编写,也根本没有仔细看数据手册的习惯(计算机专业的通病吗?),所以开始的道路真是曲折的不行。后来在带头大哥的英明指导下,终于发现了这茬,通过配置12H和13H寄存器 可以将P0_1-7和P1_1-7的工作模式切换,默认都是GPIO模式,若想将某个IO口配为LED模式,则将改为写0;
开始的时候由于不知道有LED模式这种东西的存在,傻乎乎的就开搞了,虽然结果不咋地,但是好歹是亮起来了。
首先,从probe函数开始:


static int  led_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    struct led_data *led;
    int err;


    led = kzalloc(sizeof(struct led_data), GFP_KERNEL);
    if (!led) {
        printk("[led]:alloc data failed.n");
        err = -ENOMEM;
        goto exit_alloc_data_failed;
    }


    printk(" ++++value=%x ++++n   ",client->addr);
    INIT_WORK(&led->work, led_work_func);
    INIT_DELAYED_WORK(&led->delaywork, led_delaywork_func);


    schedule_work(&led->work);
    led->client = client;
    i2c_set_clientdata(client, led);


    this_client = client;


    err = led_init_client(client);
    if (err < 0) {
        printk(KERN_ERR
                    "led_probe: led_init_client failedn");
        goto exit_request_gpio_irq_failed;
    }


    iomux_set(GPIO1_A6);
    mdelay(100);
    gpio_request(RK30_PIN1_PA6, "i2c_led-start");
    mdelay(50);
    gpio_direction_output(RK30_PIN1_PA6, 1);


    printk("============in func:%s, LINE:%d ==============n", __func__, __LINE__);
    light_red_on();
    //  led_start(client, LED_RATE_32);


    led_device.parent = &client->dev;
    err = misc_register(&led_device);
    if (err < 0) {
        printk(KERN_ERR
                    "led_probe: led_device register failedn");
        return 0;
    }


    err = i2c0_led_sysfs_init();
    if (err < 0) {
        printk(KERN_ERR
                    "led_probe: i2c0_led sysfs init failedn");
        goto exit_i2c0_led_sysfs_init_failed;
    }


    printk(KERN_INFO "led probe okn");
    return 0;


exit_i2c0_led_sysfs_init_failed:
    misc_deregister(&led_device);
exit_request_gpio_irq_failed:
    kfree(led);
exit_alloc_data_failed:
    ;
    return err;
}


其实回过头再看,探测函数是非常的简单啊,无非就是申请内存,定义工作队列以及定义sys文件系统。
然后就是很重要的I2C读写函数了:


static int led_rx_data(struct i2c_client *client, char *rxData, int length)
{
    int ret = 0;
    char reg = rxData[0];
    ret = i2c_master_reg8_recv(client, reg, rxData, length, LED_SPEED);
    printk("led_rx_data++++++++++++++++++++++n");
    return (ret > 0)? 0 : ret;
}


static int led_tx8_data(struct i2c_client *client, char *txData, int length)
{
    int ret = 0;
    char reg = txData[0];
    printk("led_tx8_data++++++++++++++++++++++n");
    ret = i2c_master_reg8_send(client, reg, &txData[1], length-1, LED_SPEED);
    printk("led_tx8_data++++++++++++++++++++++n");
    return (ret > 0)? 0 : ret;
}


创建sys节点:


static int i2c0_led_sysfs_init(void)
{
    int ret ;


    android_i2c0_led_kobj = kobject_create_and_add("android_i2c0_led", NULL);
    if (android_i2c0_led_kobj == NULL) {
        printk(KERN_ERR
                    "i2c0_led_sysfs_init:"
                    "subsystem_register failedn");
        ret = -ENOMEM;
        goto err;
    }


    ret = sysfs_create_file(android_i2c0_led_kobj, &dev_attr_i2c0_led.attr);
    if (ret) {
        printk(KERN_ERR
                    "i2c0_led_sysfs_init:"
                    "sysfs_create_group failedn");
        goto err4;
    }
    printk("i2c_led_sysfs_init ++++++++++++++++n");
    return 0 ;
err4:
    kobject_del(android_i2c0_led_kobj);
err:
    return ret ;
}


由于硬件工程师将18个灯分别挂到四条I2C总线上,所以本菜鸟很聪明的写了四个I2C设备驱动,简单粗暴。开始的时候怎么都亮不了,硬件工程师检测I2C也是有供电的,后来自己瞎琢磨半天,才发现原来 是由于复位脚没有拉高,所以I2C设备根本都没有工作起来,不管咋说,瞎整瞎整总算是也把灯给点亮了,算是涨姿势了,哈哈。
明天尝试下LED模式下的LED驱动编写,加油。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分