在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,就可以看到光照强度的值了.