l-sensor 亮度传感器驱动---stk2011

来源:互联网 发布:北京软件开发培训学校 编辑:程序博客网 时间:2024/06/05 17:25
/* * Copyright 2008-2011 MTC, Inc. All Rights Reserved. *//* * The code contained herein is licensed under the GNU General Public * License. You may obtain a copy of the GNU General Public License * Version 2 or later at the following locations: * * http://www.opensource.org/licenses/gpl-license.html * http://www.gnu.org/copyleft/gpl.html *//*! * @file drivers/hwmon/stk2211.c * * @brief STK2211 light sensor Driver * * @ingroup */#include <linux/module.h>#include <linux/init.h>#include <linux/i2c.h>#include <linux/hwmon.h>#include <linux/hwmon-sysfs.h>#include <linux/ctype.h>#include <linux/delay.h>#include <linux/err.h>#include <linux/regulator/consumer.h>#include <mach/hardware.h>enum stk2211_width {STK2211_WIDTH_12=0,STK2211_WIDTH_8,STK2211_WIDTH_4,};enum stk2211_gain {STK2211_GAIN_4096=0,STK2211_GAIN_2048,STK2211_GAIN_1024,STK2211_GAIN_512,};enum stk2211_mode {STK2211_MODE_DIODE1 = 0,STK2211_MODE_DIODE2,STK2211_MODE_DIODE1_2,};struct stk2211_param {enum stk2211_width width;enum stk2211_gain gain;enum stk2211_mode mode;};/* bit definition for STK2211_CMD reg */#define ENABLE 7#define ADCPD 6#define TIMEING_MODE 5#define MODE 2#define WIDTH 0/* bit definition for STK2211_CTRL reg */#define INT_FLAG 5#define GAIN 2#define INT_PERSIST 0enum stk2211_reg {STK2211_CMD_0 = 0,STK2211_CMD_1,STK2211_CMD_2,STK2211_CMD_3,};/* default configure for STK2211 */#define STK2211_WIDTH_DEFAULT STK2211_WIDTH_12#define STK2211_GAIN_DEFAULT STK2211_GAIN_4096#define STK2211_MODE_DEFAULT STK2211_MODE_DIODE1/* range table for different GAIN settings */int range[4] = { 4906, 2048, 1024, 521 };/* width table for different WIDTH settings */int width[4] = { 16, 1, 256, 16 };struct stk2211_data {struct i2c_client *client;struct device *hwmon_dev;struct regulator *vdd_reg;struct stk2211_param param;int lux_coeff;unsigned char enable;};static struct i2c_client *stk2211_client;/*! * This function do the stk2211 register read. */int stk2211_read(struct i2c_client *client, u8 reg){return i2c_smbus_read_byte_data(client, reg);}/*! * This function do the stk2211 register write. */int stk2211_write(struct i2c_client *client, u8 reg, char value){return i2c_smbus_write_byte_data(client, reg, value);}/*! * This function do the stk2211 config and enable. */static int stk2211_on(void){unsigned char cmd;int err = 0;struct mxc_lightsensor_platform_data *stk_data;struct stk2211_data *data = i2c_get_clientdata(stk2211_client);printk("\n===joe==%s,%d\n",__func__,__LINE__);if (data->enable)goto exit;stk_data = (struct mxc_lightsensor_platform_data *)    (stk2211_client->dev).platform_data;/* coeff=range*100k/rext/2^n */data->lux_coeff = range[data->param.gain] * 100 /    stk_data->rext / width[data->param.width];if (data->vdd_reg)regulator_enable(data->vdd_reg);msleep(100);cmd = data->param.gain << GAIN;if (stk2211_write(stk2211_client, 0x01, cmd)) {err = -ENODEV;goto exit;}cmd = (data->param.width << WIDTH) | (data->param.mode << MODE) |    (1 << ENABLE);if (stk2211_write(stk2211_client, 0x01, cmd)) {err = -ENODEV;goto exit;}data->enable = 1;pr_info("stk2211 on\n");return 0;exit:return err;}/*! * This function shut down the stk2211. */static int stk2211_off(void){struct stk2211_data *data = i2c_get_clientdata(stk2211_client);int cmd;printk("\n===joe==%s,%d\n",__func__,__LINE__);if (!data->enable)return 0;cmd = stk2211_read(stk2211_client, 0x02);if (cmd < 0)return -ENODEV;cmd = ((cmd | (1 << ADCPD)) & (~(1 << ENABLE)));if (stk2211_write(stk2211_client, 0x03, (char)cmd))return -ENODEV;if (data->vdd_reg)regulator_disable(data->vdd_reg);data->enable = 0;pr_info("stk2211 off\n");return 0;}/*! * This function read the stk2211 lux registers and convert them to the lux * value. * * @output bufferthis param holds the lux value, when =-1, read fail * * @return 0 */static int stk2211_read_lux(void){int d;int lux;struct stk2211_data *data = i2c_get_clientdata(stk2211_client);stk2211_write(stk2211_client, 0x00, 0x00);msleep(10);d = stk2211_read(stk2211_client, 0x02);if (d < 0)goto err;lux = d;/*printk("\n===lux1 0x02=%d===\n",lux);*/d = stk2211_read(stk2211_client, 0x03);if (d < 0)goto err;/*printk("\n===lux2 0x03 =%d===\n",d );*//*final data 12bit */lux = (lux << 8) + d;/*printk("d>>4=%d\n",(d>>4));printk("\n===final data=%d===\n",lux);*//*if (data->param.width < STK2211_WIDTH_8)lux = (data->lux_coeff * lux) >> 12;elselux = data->lux_coeff * lux;*//*printk("\n===lux4=%d===\n",lux);*/return lux;err:return -1;}static ssize_t ls_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){char *endp;int enable = simple_strtoul(buf, &endp, 0);size_t size = endp - buf;if (*endp && isspace(*endp))size++;if (size != count)return -EINVAL;if (enable == 1) {if (stk2211_on())pr_info("device open fail\n");}if (enable == 0) {if (stk2211_off())pr_info("device powerdown fail\n");}return count;}static SENSOR_DEVICE_ATTR(enable, S_IWUGO, NULL, ls_enable, 0);static ssize_t show_lux(struct device *dev, struct device_attribute *attr,char *buf){return snprintf(buf, PAGE_SIZE, "%u\n", stk2211_read_lux());}static SENSOR_DEVICE_ATTR(lux, S_IRUGO, show_lux, NULL, 0);static int __devinit  stk2211_i2c_probe(struct i2c_client *client,      const struct i2c_device_id *did){int err = 0;struct stk2211_data *data;struct regulator *vdd_reg;struct mxc_lightsensor_platform_data *stk_data;stk_data = (struct mxc_lightsensor_platform_data *)    (client->dev).platform_data;if (stk_data && stk_data->vdd_reg)vdd_reg = regulator_get(&client->dev, stk_data->vdd_reg);elsevdd_reg = NULL;printk("===client=%s====\n",client->name);/* check the existence of the device */if (vdd_reg)regulator_enable(vdd_reg);msleep(100);printk("===vdd_reg2 max_uV=%s====\n",stk_data->vdd_reg);printk("===STK2211_CMD_0=%d,==client-addr=%d=\n",STK2211_CMD_0,client->addr);/*while (1){printk("===stk2211_write=%d,==client-addr=%d=",STK2211_CMD_0,client->addr);if (stk2211_write(client, STK2211_CMD_0, 0)) {err = -ENODEV;printk("===stk2211_write=%d,ENODEV=%d==client-addr=%d=",STK2211_CMD_0,ENODEV,client->addr);}msleep(100);}*/if (stk2211_write(client, 0x01, 0x8c))err = -ENODEV;printk("read=%d\n",stk2211_read(client, 0x01));msleep(100);printk("write0=%d\n",stk2211_write(client, 0x00, 0x00));printk("read0=%d\n",stk2211_read(client, 0x00));msleep(100);printk("write1=%d\n",stk2211_write(client, 0x02, 0x22));printk("read1=%d\n",stk2211_read(client, 0x02));msleep(100);printk("write2=%d\n",stk2211_write(client, 0x03, 0x33));printk("read2=%d\n",stk2211_read(client, 0x03));/*if (!err)if (stk2211_read(client, 0x01))err = -ENODEV;*/if (vdd_reg)regulator_disable(vdd_reg);if (err < 0)goto exit1;stk2211_client = client;data = kzalloc(sizeof(struct stk2211_data), GFP_KERNEL);if (data == NULL) {err = -ENOMEM;goto exit1;}printk("\n===joe2==%s,%d\n",__func__,__LINE__);i2c_set_clientdata(client, data);data->client = client;//data->param.width = STK2211_WIDTH_DEFAULT;//data->param.gain = STK2211_GAIN_DEFAULT;//data->param.mode = STK2211_MODE_DEFAULT;data->enable = 0;err = device_create_file(&client->dev, &sensor_dev_attr_enable.dev_attr);printk("==device_create_file==err=%d=\n",err);if (err)goto exit2;err = device_create_file(&client->dev, &sensor_dev_attr_lux.dev_attr);printk("==device_create_file2==err=%d=\n",err);if (err)goto exit_remove1;/* Register sysfs hooks */data->hwmon_dev = hwmon_device_register(&client->dev);dev_info(&client->dev, "  build time %s %s\n", __DATE__, __TIME__);  if (IS_ERR(data->hwmon_dev)) {err = PTR_ERR(data->hwmon_dev);goto exit_remove2;}data->vdd_reg = vdd_reg;return 0;exit_remove2:device_remove_file(&client->dev, &sensor_dev_attr_lux.dev_attr);exit_remove1:device_remove_file(&client->dev, &sensor_dev_attr_enable.dev_attr);exit2:kfree(data);exit1:if (vdd_reg) {regulator_put(vdd_reg);vdd_reg = NULL;}stk2211_client = NULL;return err;}static int __devinit stk2211_i2c_remove(struct i2c_client *client){struct stk2211_data *data = i2c_get_clientdata(client);if (data->vdd_reg) {regulator_put(data->vdd_reg);data->vdd_reg = NULL;}hwmon_device_unregister(data->hwmon_dev);device_remove_file(&client->dev, &sensor_dev_attr_enable.dev_attr);device_remove_file(&client->dev, &sensor_dev_attr_lux.dev_attr);kfree(data);return 0;}static int stk2211_suspend(struct i2c_client *client, pm_message_t message){int cmd;struct stk2211_data *data = i2c_get_clientdata(client);if (!data->enable)goto exit;cmd = stk2211_read(client, 0x02);if (cmd < 0)goto err;cmd = (cmd | (1 << ADCPD));if (stk2211_write(client, 0x03, (char)cmd))goto err;exit:return 0;err:return -ENODEV;}static int stk2211_resume(struct i2c_client *client){int cmd;struct stk2211_data *data = i2c_get_clientdata(client);if (!data->enable)goto exit;cmd = stk2211_read(client, 0x02);if (cmd < 0)goto err;cmd = (cmd & (~(1 << ADCPD)));if (stk2211_write(client, 0x03, (char)cmd))goto err;exit:return 0;err:return -ENODEV;}static const struct i2c_device_id stk2211_id[] = {{"stk2211", 0},{}};MODULE_DEVICE_TABLE(i2c, stk2211_id);static struct i2c_driver stk2211_driver = {.driver = {   .name = "stk2211",   },.probe = stk2211_i2c_probe,.remove = stk2211_i2c_remove,.suspend = stk2211_suspend,.resume = stk2211_resume,.id_table = stk2211_id,};static int __init stk2211_init(void){u8 err;printk("\n===joe1==%s===\n",__func__);err = i2c_add_driver(&stk2211_driver);if (err != 0)pr_err("\n%s:driver registration failed, error=%d \n",__func__, err);       printk("\n===joe2==%s===n",__func__);    return err;/*return i2c_add_driver(&stk2211_driver);;*/}static void __exit stk2211_cleanup(void){i2c_del_driver(&stk2211_driver);}module_init(stk2211_init);module_exit(stk2211_cleanup);MODULE_AUTHOR("JOE <joe@thtfit.com> MTC, Inc.");MODULE_DESCRIPTION("STK2211 light sensor driver");MODULE_LICENSE("GPL");MODULE_VERSION("1.0");