brintos

brintos / linux-shallow public Read only

0
0
Text · 4.9 KiB · 1643ba2 Raw
227 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * isl29020.c - Intersil  ALS Driver4 *5 * Copyright (C) 2008 Intel Corp6 *7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~8 *9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~10 *11 * Data sheet at: http://www.intersil.com/data/fn/fn6505.pdf12 */13 14#include <linux/module.h>15#include <linux/slab.h>16#include <linux/i2c.h>17#include <linux/err.h>18#include <linux/delay.h>19#include <linux/sysfs.h>20#include <linux/pm_runtime.h>21 22static DEFINE_MUTEX(mutex);23 24static ssize_t als_sensing_range_show(struct device *dev,25			struct device_attribute *attr,  char *buf)26{27	struct i2c_client *client = to_i2c_client(dev);28	int  val;29 30	val = i2c_smbus_read_byte_data(client, 0x00);31 32	if (val < 0)33		return val;34	return sprintf(buf, "%d000\n", 1 << (2 * (val & 3)));35 36}37 38static ssize_t als_lux_input_data_show(struct device *dev,39			struct device_attribute *attr, char *buf)40{41	struct i2c_client *client = to_i2c_client(dev);42	int ret_val, val;43	unsigned long int lux;44	int temp;45 46	pm_runtime_get_sync(dev);47	msleep(100);48 49	mutex_lock(&mutex);50	temp = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */51	if (temp < 0) {52		pm_runtime_put_sync(dev);53		mutex_unlock(&mutex);54		return temp;55	}56 57	ret_val = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */58	mutex_unlock(&mutex);59 60	if (ret_val < 0) {61		pm_runtime_put_sync(dev);62		return ret_val;63	}64 65	ret_val |= temp << 8;66	val = i2c_smbus_read_byte_data(client, 0x00);67	pm_runtime_put_sync(dev);68	if (val < 0)69		return val;70	lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / 65536;71	return sprintf(buf, "%ld\n", lux);72}73 74static ssize_t als_sensing_range_store(struct device *dev,75		struct device_attribute *attr, const  char *buf, size_t count)76{77	struct i2c_client *client = to_i2c_client(dev);78	int ret_val;79	unsigned long val;80 81	ret_val = kstrtoul(buf, 10, &val);82	if (ret_val)83		return ret_val;84 85	if (val < 1 || val > 64000)86		return -EINVAL;87 88	/* Pick the smallest sensor range that will meet our requirements */89	if (val <= 1000)90		val = 1;91	else if (val <= 4000)92		val = 2;93	else if (val <= 16000)94		val = 3;95	else96		val = 4;97 98	ret_val = i2c_smbus_read_byte_data(client, 0x00);99	if (ret_val < 0)100		return ret_val;101 102	ret_val &= 0xFC; /*reset the bit before setting them */103	ret_val |= val - 1;104	ret_val = i2c_smbus_write_byte_data(client, 0x00, ret_val);105 106	if (ret_val < 0)107		return ret_val;108	return count;109}110 111static void als_set_power_state(struct i2c_client *client, int enable)112{113	int ret_val;114 115	ret_val = i2c_smbus_read_byte_data(client, 0x00);116	if (ret_val < 0)117		return;118 119	if (enable)120		ret_val |= 0x80;121	else122		ret_val &= 0x7F;123 124	i2c_smbus_write_byte_data(client, 0x00, ret_val);125}126 127static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR,128	als_sensing_range_show, als_sensing_range_store);129static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux_input_data_show, NULL);130 131static struct attribute *mid_att_als[] = {132	&dev_attr_lux0_sensor_range.attr,133	&dev_attr_lux0_input.attr,134	NULL135};136 137static const struct attribute_group m_als_gr = {138	.name = "isl29020",139	.attrs = mid_att_als140};141 142static int als_set_default_config(struct i2c_client *client)143{144	int retval;145 146	retval = i2c_smbus_write_byte_data(client, 0x00, 0xc0);147	if (retval < 0) {148		dev_err(&client->dev, "default write failed.");149		return retval;150	}151	return 0;152}153 154static int  isl29020_probe(struct i2c_client *client)155{156	int res;157 158	res = als_set_default_config(client);159	if (res <  0)160		return res;161 162	res = sysfs_create_group(&client->dev.kobj, &m_als_gr);163	if (res) {164		dev_err(&client->dev, "isl29020: device create file failed\n");165		return res;166	}167	dev_info(&client->dev, "%s isl29020: ALS chip found\n", client->name);168	als_set_power_state(client, 0);169	pm_runtime_enable(&client->dev);170	return res;171}172 173static void isl29020_remove(struct i2c_client *client)174{175	pm_runtime_disable(&client->dev);176	sysfs_remove_group(&client->dev.kobj, &m_als_gr);177}178 179static const struct i2c_device_id isl29020_id[] = {180	{ "isl29020" },181	{ }182};183 184MODULE_DEVICE_TABLE(i2c, isl29020_id);185 186#ifdef CONFIG_PM187 188static int isl29020_runtime_suspend(struct device *dev)189{190	struct i2c_client *client = to_i2c_client(dev);191	als_set_power_state(client, 0);192	return 0;193}194 195static int isl29020_runtime_resume(struct device *dev)196{197	struct i2c_client *client = to_i2c_client(dev);198	als_set_power_state(client, 1);199	return 0;200}201 202static const struct dev_pm_ops isl29020_pm_ops = {203	.runtime_suspend = isl29020_runtime_suspend,204	.runtime_resume = isl29020_runtime_resume,205};206 207#define ISL29020_PM_OPS (&isl29020_pm_ops)208#else	/* CONFIG_PM */209#define ISL29020_PM_OPS NULL210#endif	/* CONFIG_PM */211 212static struct i2c_driver isl29020_driver = {213	.driver = {214		.name = "isl29020",215		.pm = ISL29020_PM_OPS,216	},217	.probe = isl29020_probe,218	.remove = isl29020_remove,219	.id_table = isl29020_id,220};221 222module_i2c_driver(isl29020_driver);223 224MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>");225MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");226MODULE_LICENSE("GPL v2");227