RK3188&AW9523B I2C接口LED驱动(1)

本来想做的是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 failed\n");
        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 failed\n");
        return 0;
    }

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

    printk(KERN_INFO "led probe ok\n");
    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 failed\n");
        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 failed\n");
        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驱动编写,加油。
虽然不知道以后会不会做驱动方面的工作,但是现在既然有这个机会,就要好好珍惜,哈哈。

你可能感兴趣的:(Android驱动)