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