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

/*
 * 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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

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 0

enum 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 buffer	this 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;
	else
		lux = 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);
	else
		vdd_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  MTC, Inc.");
MODULE_DESCRIPTION("STK2211 light sensor driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("1.0");


 

你可能感兴趣的:(android)