基于DragonBoard 410c的环境光检测(二)

时间:2021-10-14 10:50:36

        在http://blog.csdn.net/weixin_40109283/article/details/79035119博客中,已经介绍了该系统的硬件设计现在我们来谈谈软件部分的实现步骤和方法.

首先我们得先在设备树中配置相关的硬件信息,在apq8016-sbc.dtsi文件中做如下修改:

    i2c@78b6000 { /* BLSP1 QUP2 */

        light_sensor@29 {

            compatible = "thunder,light_sensor";

            reg = <0x29>;

        };


然后编写相应的驱动程序,代码如下所示:

#include <linux/module.h>                                                                                                                                                                                   

#include <linux/delay.h>

#include <linux/i2c.h>

#include <linux/io.h>

#include <linux/platform_device.h>

#include <linux/async.h>

#include <linux/proc_fs.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/init.h>

#include <linux/slab.h>

#include <linux/mutex.h>

#include <linux/hwmon-sysfs.h>

#include <linux/err.h>

#include <linux/hwmon.h>

#include <linux/miscdevice.h>

#include <linux/poll.h>

#include <linux/gpio.h>

#include <linux/i2c/twl.h>

#include <linux/device.h>

 

#define MY_I2C_NAME     "light_sensor"

 

struct light_sensor_data {

    struct cdev dev;

    struct i2c_client *client;

    struct mutex update_lock;

};

 

static int light_sensor_get_adc_value(struct i2c_client *client, u8 cmd)

{

    int ret;

 

    ret = i2c_smbus_read_byte_data(client, cmd);

    if (ret < 0)

        return ret;

 

    return ret;

}

 

static ssize_t __light_sensor_show(struct i2c_client *client, char *buf)

{

    int ret;

    u8 ch0, ch1;

 

    ret = i2c_smbus_write_byte_data(client, 0x80, 0x03);

    if (ret < 0)

        return ret;

    ret = i2c_smbus_write_byte_data(client, 0x81, 0x01);

    if (ret < 0)

        return ret;

    msleep(10);

 

    ret = light_sensor_get_adc_value(client, 0x8c);

    if (ret < 0)

        return ret;

    ch0 = ret;

    printk(KERN_INFO "light_sensor_ch0 = %d lx\n", ch0);

 

    ret = light_sensor_get_adc_value(client, 0x8d);

    if (ret < 0)

        return ret;

    ch1 = ret;

    printk(KERN_INFO "light_sensor_ch1 = %d lx\n", ch1);

 

    /* Do the job */

    ret = ch1 * 256 + ch0;

    if (ret < 0)

        return ret;

 

    printk(KERN_INFO "light_sensor_ret = %d lx\n", ret);

 

    return sprintf(buf, "%d\n", ret);

}

 

static ssize_t light_sensor_show_lux(struct device *dev,

                            struct device_attribute *attr, char *buf)

{

    struct i2c_client *client = to_i2c_client(dev);

    int ret;

 

    ret = __light_sensor_show(client, buf);

    if (ret < 0)

        printk(KERN_INFO "light_sensor show failed\n");

 

    return ret;

}

 

static DEVICE_ATTR(light_sensor, 0666,light_sensor_show_lux, NULL);

 

static struct attribute *light_sensor_attributes[] = {

    &dev_attr_light_sensor.attr,

    NULL

};

 

static const struct attribute_group light_sensor_attr_group = {

    .attrs = light_sensor_attributes,

};

 

static int light_sensor_i2c_probe(struct i2c_client *client,

                        const struct i2c_device_id *id)

{

    int result;

    int err;

 

    struct light_sensor_data *pdata;

    struct i2c_adapter *adapter;

 

    printk(KERN_INFO "light_sensor_i2c_probe enter\n");

 

    adapter = to_i2c_adapter(client->dev.parent);

    result = i2c_check_functionality(adapter,

                    I2C_FUNC_SMBUS_BYTE |

                    I2C_FUNC_SMBUS_BYTE_DATA);

    if (!result)

        goto err_out;

 

    pdata = kzalloc(sizeof(struct light_sensor_data), GFP_KERNEL);

    if (!pdata) {

        result = -ENOMEM;

        dev_err(&client->dev, "alloc data memory error!\n");

        goto err_out;

    }

    pdata->client = client;

    i2c_set_clientdata(client, pdata);

 

    err = sysfs_create_group(&client->dev.kobj, &light_sensor_attr_group);

    if (err)

        goto err_out;   

 

err_out:

return result;   

 

err_out:

    return result;

}

 

static int light_sensor_i2c_remove(struct i2c_client *client)

{

    struct light_sensor_data *pdata =  i2c_get_clientdata(client);

    if(!pdata)

        return 0;

    sysfs_remove_group(&client->dev.kobj, &light_sensor_attr_group);

    kfree(pdata);

 

    return 0;

}

 

static const struct i2c_device_id light_sensor_i2c_id[] = {

    {MY_I2C_NAME, 0},

    { }

};

 

MODULE_DEVICE_TABLE(i2c, light_sensor_i2c_id);

 

static const struct of_device_id of_light_sensor_match[] = {

    {.compatible = "thunder,light_sensor", },

    {},

};

 

static struct i2c_driver light_sensor_i2c_driver = {

    .driver = {

        .owner = THIS_MODULE,

        .name = "light_sensor",

        .of_match_table = of_light_sensor_match,

    },

 

    .probe = light_sensor_i2c_probe,

    .remove = light_sensor_i2c_remove,

    .id_table = light_sensor_i2c_id,

};

 

module_i2c_driver(light_sensor_i2c_driver);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("heql0703@thundersoft.com");



将代码编译后烧写到DragonBoard 410c开发板后启动开发板,用adb命令进入开发板 用cat命令查看对应生成的节点light_sensor_lux,就可以看到光照强度的值了.