cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

isl29020.c (5081B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * isl29020.c - Intersil  ALS Driver
      4 *
      5 * Copyright (C) 2008 Intel Corp
      6 *
      7 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      8 *
      9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     10 *
     11 * Data sheet at: http://www.intersil.com/data/fn/fn6505.pdf
     12 */
     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	else
     96		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	else
    122		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	NULL
    135};
    136
    137static const struct attribute_group m_als_gr = {
    138	.name = "isl29020",
    139	.attrs = mid_att_als
    140};
    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					const struct i2c_device_id *id)
    156{
    157	int res;
    158
    159	res = als_set_default_config(client);
    160	if (res <  0)
    161		return res;
    162
    163	res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
    164	if (res) {
    165		dev_err(&client->dev, "isl29020: device create file failed\n");
    166		return res;
    167	}
    168	dev_info(&client->dev, "%s isl29020: ALS chip found\n", client->name);
    169	als_set_power_state(client, 0);
    170	pm_runtime_enable(&client->dev);
    171	return res;
    172}
    173
    174static int isl29020_remove(struct i2c_client *client)
    175{
    176	pm_runtime_disable(&client->dev);
    177	sysfs_remove_group(&client->dev.kobj, &m_als_gr);
    178	return 0;
    179}
    180
    181static const struct i2c_device_id isl29020_id[] = {
    182	{ "isl29020", 0 },
    183	{ }
    184};
    185
    186MODULE_DEVICE_TABLE(i2c, isl29020_id);
    187
    188#ifdef CONFIG_PM
    189
    190static int isl29020_runtime_suspend(struct device *dev)
    191{
    192	struct i2c_client *client = to_i2c_client(dev);
    193	als_set_power_state(client, 0);
    194	return 0;
    195}
    196
    197static int isl29020_runtime_resume(struct device *dev)
    198{
    199	struct i2c_client *client = to_i2c_client(dev);
    200	als_set_power_state(client, 1);
    201	return 0;
    202}
    203
    204static const struct dev_pm_ops isl29020_pm_ops = {
    205	.runtime_suspend = isl29020_runtime_suspend,
    206	.runtime_resume = isl29020_runtime_resume,
    207};
    208
    209#define ISL29020_PM_OPS (&isl29020_pm_ops)
    210#else	/* CONFIG_PM */
    211#define ISL29020_PM_OPS NULL
    212#endif	/* CONFIG_PM */
    213
    214static struct i2c_driver isl29020_driver = {
    215	.driver = {
    216		.name = "isl29020",
    217		.pm = ISL29020_PM_OPS,
    218	},
    219	.probe = isl29020_probe,
    220	.remove = isl29020_remove,
    221	.id_table = isl29020_id,
    222};
    223
    224module_i2c_driver(isl29020_driver);
    225
    226MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>");
    227MODULE_DESCRIPTION("Intersil isl29020 ALS Driver");
    228MODULE_LICENSE("GPL v2");