1940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein/* 2940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * A iio driver for the light sensor ISL 29018. 3940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * 4940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * IIO driver for monitoring ambient light intensity in luxi, proximity 5940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * sensing and infrared sensing. 6940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * 7940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * Copyright (c) 2010, NVIDIA Corporation. 8940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * 9940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * This program is free software; you can redistribute it and/or modify 10940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * it under the terms of the GNU General Public License as published by 11940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * the Free Software Foundation; either version 2 of the License, or 12940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * (at your option) any later version. 13940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * 14940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * This program is distributed in the hope that it will be useful, but WITHOUT 15940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 16940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 17940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * more details. 18940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * 19940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * You should have received a copy of the GNU General Public License along 20940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * with this program; if not, write to the Free Software Foundation, Inc., 21940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein */ 23940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 24940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include <linux/module.h> 25940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include <linux/i2c.h> 26940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include <linux/err.h> 27940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include <linux/mutex.h> 28940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include <linux/delay.h> 29940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include <linux/slab.h> 30940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#include "../iio.h" 319dd1cb303c18f4508abc69f5b40f423ff36a9626Jonathan Cameron#include "../sysfs.h" 32940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define CONVERSION_TIME_MS 100 33940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 34940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define ISL29018_REG_ADD_COMMAND1 0x00 35940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMMAND1_OPMODE_SHIFT 5 36940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT) 37940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMMAND1_OPMODE_POWER_DOWN 0 38940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMMAND1_OPMODE_ALS_ONCE 1 39940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMMAND1_OPMODE_IR_ONCE 2 40940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMMAND1_OPMODE_PROX_ONCE 3 41940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 42940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define ISL29018_REG_ADD_COMMANDII 0x01 43940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMANDII_RESOLUTION_SHIFT 2 44940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT) 45940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 46940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMANDII_RANGE_SHIFT 0 47940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT) 48940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 49940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMANDII_SCHEME_SHIFT 7 50940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define COMMANDII_SCHEME_MASK (0x1 << COMMANDII_SCHEME_SHIFT) 51940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 52940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define ISL29018_REG_ADD_DATA_LSB 0x02 53940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define ISL29018_REG_ADD_DATA_MSB 0x03 5425d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron#define ISL29018_MAX_REGS (ISL29018_REG_ADD_DATA_MSB+1) 55940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 56176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler#define ISL29018_REG_TEST 0x08 57176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler#define ISL29018_TEST_SHIFT 0 58176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler#define ISL29018_TEST_MASK (0xFF << ISL29018_TEST_SHIFT) 59176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler 60940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstruct isl29018_chip { 61940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct i2c_client *client; 62940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct mutex lock; 636d1ad0f8aa9d3caf6e3f26ad39b43c687abd9c82Bryan Freed unsigned int lux_scale; 64940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned int range; 65940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned int adc_bit; 66940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int prox_scheme; 67940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein u8 reg_cache[ISL29018_MAX_REGS]; 68940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein}; 69940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 70940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_write_data(struct i2c_client *client, u8 reg, 71940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein u8 val, u8 mask, u8 shift) 72940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 7325d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron u8 regval = val; 7425d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron int ret; 75152d52cf7ec18e655a2d5bb6a79d42e6e09d92d7Bryan Freed struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); 76940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 7725d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron /* don't cache or mask REG_TEST */ 7825d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron if (reg < ISL29018_MAX_REGS) { 7925d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron regval = chip->reg_cache[reg]; 8025d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron regval &= ~mask; 8125d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron regval |= val << shift; 8225d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron } 83940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 84940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ret = i2c_smbus_write_byte_data(client, reg, regval); 85940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (ret) { 86940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "Write to device fails status %x\n", ret); 8725d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron } else { 8825d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron /* don't update cache on err */ 8925d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron if (reg < ISL29018_MAX_REGS) 9025d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron chip->reg_cache[reg] = regval; 91940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 92940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 9325d7315a19bae4c880ca25b75fe8c632b79a21b7Jonathan Cameron return ret; 94940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 95940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 96940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_set_range(struct i2c_client *client, unsigned long range, 97940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned int *new_range) 98940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 99940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; 100940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int i; 101940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 102940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) { 103940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (range <= supp_ranges[i]) { 104940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein *new_range = (unsigned int)supp_ranges[i]; 105940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein break; 106940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 107940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 108940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 109940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (i >= ARRAY_SIZE(supp_ranges)) 110940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 111940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 112940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, 113940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); 114940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 115940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 116940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_set_resolution(struct i2c_client *client, 117940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned long adcbit, unsigned int *conf_adc_bit) 118940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 119940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein static const unsigned long supp_adcbit[] = {16, 12, 8, 4}; 120940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int i; 121940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 122940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein for (i = 0; i < ARRAY_SIZE(supp_adcbit); ++i) { 123940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (adcbit >= supp_adcbit[i]) { 124940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein *conf_adc_bit = (unsigned int)supp_adcbit[i]; 125940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein break; 126940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 127940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 128940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 129940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (i >= ARRAY_SIZE(supp_adcbit)) 130940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 131940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 132940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, 133940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein i, COMMANDII_RESOLUTION_MASK, 134940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein COMMANDII_RESOLUTION_SHIFT); 135940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 136940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 137940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_read_sensor_input(struct i2c_client *client, int mode) 138940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 139940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int status; 140940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int lsb; 141940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int msb; 142940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 143940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein /* Set mode */ 144940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 145940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); 146940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (status) { 147940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "Error in setting operating mode\n"); 148940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return status; 149940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 150940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein msleep(CONVERSION_TIME_MS); 151940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); 152940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (lsb < 0) { 153940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "Error in reading LSB DATA\n"); 154940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return lsb; 155940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 156940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 157940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); 158940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (msb < 0) { 159940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "Error in reading MSB DATA\n"); 160940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return msb; 161940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 162940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); 163940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 164940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return (msb << 8) | lsb; 165940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 166940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 167940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_read_lux(struct i2c_client *client, int *lux) 168940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 169940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int lux_data; 170152d52cf7ec18e655a2d5bb6a79d42e6e09d92d7Bryan Freed struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); 171940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 172940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein lux_data = isl29018_read_sensor_input(client, 173940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein COMMMAND1_OPMODE_ALS_ONCE); 174940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 175940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (lux_data < 0) 176940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return lux_data; 177940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 1786d1ad0f8aa9d3caf6e3f26ad39b43c687abd9c82Bryan Freed *lux = (lux_data * chip->range * chip->lux_scale) >> chip->adc_bit; 179940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 180940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 181940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 182940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 183940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_read_ir(struct i2c_client *client, int *ir) 184940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 185940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int ir_data; 186940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 187940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE); 188940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 189940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (ir_data < 0) 190940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return ir_data; 191940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 192940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein *ir = ir_data; 193940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 194940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 195940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 196940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 197940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, 198940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int *near_ir) 199940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 200940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int status; 201940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int prox_data = -1; 202940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int ir_data = -1; 203940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 204940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein /* Do proximity sensing with required scheme */ 205940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, 206940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT); 207940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (status) { 208940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "Error in setting operating mode\n"); 209940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return status; 210940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 211940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 212940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein prox_data = isl29018_read_sensor_input(client, 213940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein COMMMAND1_OPMODE_PROX_ONCE); 214940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (prox_data < 0) 215940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return prox_data; 216940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 217940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (scheme == 1) { 218940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein *near_ir = prox_data; 219940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 220940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 221940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 222940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ir_data = isl29018_read_sensor_input(client, 223940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein COMMMAND1_OPMODE_IR_ONCE); 224940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 225940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (ir_data < 0) 226940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return ir_data; 227940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 228940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (prox_data >= ir_data) 229940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein *near_ir = prox_data - ir_data; 230940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein else 231940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein *near_ir = 0; 232940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 233940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 234940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 235940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 236940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein/* Sysfs interface */ 237940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein/* range */ 238940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic ssize_t show_range(struct device *dev, 239940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct device_attribute *attr, char *buf) 240940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 241940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct iio_dev *indio_dev = dev_get_drvdata(dev); 242927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct isl29018_chip *chip = iio_priv(indio_dev); 243940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 244940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return sprintf(buf, "%u\n", chip->range); 245940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 246940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 247940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic ssize_t store_range(struct device *dev, 248940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct device_attribute *attr, const char *buf, size_t count) 249940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 250940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct iio_dev *indio_dev = dev_get_drvdata(dev); 251927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct isl29018_chip *chip = iio_priv(indio_dev); 252940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct i2c_client *client = chip->client; 253940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int status; 254940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned long lval; 255940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned int new_range; 256940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 257940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (strict_strtoul(buf, 10, &lval)) 258940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 259940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 260940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (!(lval == 1000UL || lval == 4000UL || 261940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein lval == 16000UL || lval == 64000UL)) { 262940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(dev, "The range is not supported\n"); 263940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 264940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 265940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 266940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_lock(&chip->lock); 267940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein status = isl29018_set_range(client, lval, &new_range); 268940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (status < 0) { 269940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_unlock(&chip->lock); 270940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(dev, "Error in setting max range\n"); 271940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return status; 272940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 273940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein chip->range = new_range; 274940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_unlock(&chip->lock); 275940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 276940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return count; 277940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 278940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 279940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein/* resolution */ 280940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic ssize_t show_resolution(struct device *dev, 281940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct device_attribute *attr, char *buf) 282940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 283940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct iio_dev *indio_dev = dev_get_drvdata(dev); 284927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct isl29018_chip *chip = iio_priv(indio_dev); 285940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 286940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return sprintf(buf, "%u\n", chip->adc_bit); 287940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 288940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 289940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic ssize_t store_resolution(struct device *dev, 290940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct device_attribute *attr, const char *buf, size_t count) 291940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 292940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct iio_dev *indio_dev = dev_get_drvdata(dev); 293927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct isl29018_chip *chip = iio_priv(indio_dev); 294940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct i2c_client *client = chip->client; 295940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int status; 296940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned long lval; 297940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned int new_adc_bit; 298940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 299940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (strict_strtoul(buf, 10, &lval)) 300940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 301940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) { 302940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(dev, "The resolution is not supported\n"); 303940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 304940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 305940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 306940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_lock(&chip->lock); 307940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein status = isl29018_set_resolution(client, lval, &new_adc_bit); 308940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (status < 0) { 309940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_unlock(&chip->lock); 310940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(dev, "Error in setting resolution\n"); 311940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return status; 312940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 313940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein chip->adc_bit = new_adc_bit; 314940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_unlock(&chip->lock); 315940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 316940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return count; 317940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 318940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 319940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein/* proximity scheme */ 320940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic ssize_t show_prox_infrared_supression(struct device *dev, 321940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct device_attribute *attr, char *buf) 322940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 323940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct iio_dev *indio_dev = dev_get_drvdata(dev); 324927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct isl29018_chip *chip = iio_priv(indio_dev); 325940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 326940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein /* return the "proximity scheme" i.e. if the chip does on chip 327940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein infrared supression (1 means perform on chip supression) */ 328940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return sprintf(buf, "%d\n", chip->prox_scheme); 329940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 330940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 331940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic ssize_t store_prox_infrared_supression(struct device *dev, 332940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct device_attribute *attr, const char *buf, size_t count) 333940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 334940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct iio_dev *indio_dev = dev_get_drvdata(dev); 335927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct isl29018_chip *chip = iio_priv(indio_dev); 336940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned long lval; 337940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 338940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (strict_strtoul(buf, 10, &lval)) 339940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 340940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (!(lval == 0UL || lval == 1UL)) { 341940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(dev, "The mode is not supported\n"); 342940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return -EINVAL; 343940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 344940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 345940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein /* get the "proximity scheme" i.e. if the chip does on chip 346940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein infrared supression (1 means perform on chip supression) */ 347940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_lock(&chip->lock); 348940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein chip->prox_scheme = (int)lval; 349940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_unlock(&chip->lock); 350940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 351940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return count; 352940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 353940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 35401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed/* Channel IO */ 35501e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freedstatic int isl29018_write_raw(struct iio_dev *indio_dev, 35601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed struct iio_chan_spec const *chan, 35701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed int val, 35801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed int val2, 35901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed long mask) 360940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 36101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed struct isl29018_chip *chip = iio_priv(indio_dev); 36201e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed int ret = -EINVAL; 363940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 36401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed mutex_lock(&chip->lock); 365c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) { 36601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed chip->lux_scale = val; 36701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed ret = 0; 36801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed } 36901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed mutex_unlock(&chip->lock); 37001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed 37101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed return 0; 372940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 373940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 37401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freedstatic int isl29018_read_raw(struct iio_dev *indio_dev, 37501e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed struct iio_chan_spec const *chan, 37601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed int *val, 37701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed int *val2, 37801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed long mask) 379940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 38001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed int ret = -EINVAL; 38101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed struct isl29018_chip *chip = iio_priv(indio_dev); 38201e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed struct i2c_client *client = chip->client; 38301e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed 38401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed mutex_lock(&chip->lock); 38501e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed switch (mask) { 38601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed case 0: 38701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed switch (chan->type) { 38801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed case IIO_LIGHT: 38901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed ret = isl29018_read_lux(client, val); 39001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 39101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed case IIO_INTENSITY: 39201e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed ret = isl29018_read_ir(client, val); 39301e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 39401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed case IIO_PROXIMITY: 39501e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed ret = isl29018_read_proximity_ir(client, 39601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed chip->prox_scheme, val); 39701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 39801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed default: 39901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 40001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed } 40101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed if (!ret) 40201e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed ret = IIO_VAL_INT; 40301e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 404c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron case IIO_CHAN_INFO_CALIBSCALE: 40501e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed if (chan->type == IIO_LIGHT) { 40601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed *val = chip->lux_scale; 40701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed ret = IIO_VAL_INT; 40801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed } 40901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 41001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed default: 41101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed break; 41201e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed } 41301e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed mutex_unlock(&chip->lock); 41401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed return ret; 415940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 416940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 41701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freedstatic const struct iio_chan_spec isl29018_channels[] = { 41801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed { 41901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .type = IIO_LIGHT, 42001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .indexed = 1, 42101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .channel = 0, 4224a70513074091e814fd5444c75f572691b7ba588Jonathan Cameron .processed_val = IIO_PROCESSED, 423c8a9f8056f40f6201b84fdddb49a1c62630902c5Jonathan Cameron .info_mask = IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT, 42401e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed }, { 42501e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .type = IIO_INTENSITY, 42601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .modified = 1, 42701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .channel2 = IIO_MOD_LIGHT_IR, 42801e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed }, { 42901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed /* Unindexed in current ABI. But perhaps it should be. */ 43001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .type = IIO_PROXIMITY, 43101e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed } 43201e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed}; 43301e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed 434940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0); 435940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic IIO_CONST_ATTR(range_available, "1000 4000 16000 64000"); 436940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic IIO_CONST_ATTR(adc_resolution_available, "4 8 12 16"); 437940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic IIO_DEVICE_ATTR(adc_resolution, S_IRUGO | S_IWUSR, 438940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein show_resolution, store_resolution, 0); 439940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_supression, 440940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein S_IRUGO | S_IWUSR, 441940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein show_prox_infrared_supression, 442940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein store_prox_infrared_supression, 0); 443940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 444940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) 445940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein#define ISL29018_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) 446940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic struct attribute *isl29018_attributes[] = { 447940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ISL29018_DEV_ATTR(range), 448940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ISL29018_CONST_ATTR(range_available), 449940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ISL29018_DEV_ATTR(adc_resolution), 450940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ISL29018_CONST_ATTR(adc_resolution_available), 451940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_supression), 452940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein NULL 453940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein}; 454940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 455940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic const struct attribute_group isl29108_group = { 456940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .attrs = isl29018_attributes, 457940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein}; 458940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 459940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int isl29018_chip_init(struct i2c_client *client) 460940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 461152d52cf7ec18e655a2d5bb6a79d42e6e09d92d7Bryan Freed struct isl29018_chip *chip = iio_priv(i2c_get_clientdata(client)); 462940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int status; 463940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int new_adc_bit; 464940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein unsigned int new_range; 465940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 466940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); 467940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 468176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler /* Code added per Intersil Application Note 1534: 469176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * When VDD sinks to approximately 1.8V or below, some of 470176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * the part's registers may change their state. When VDD 471176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * recovers to 2.25V (or greater), the part may thus be in an 472176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * unknown mode of operation. The user can return the part to 473176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * a known mode of operation either by (a) setting VDD = 0V for 474176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * 1 second or more and then powering back up with a slew rate 475176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * of 0.5V/ms or greater, or (b) via I2C disable all ALS/PROX 476176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * conversions, clear the test registers, and then rewrite all 477176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * registers to the desired values. 478176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * ... 479176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * FOR ISL29011, ISL29018, ISL29021, ISL29023 480176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * 1. Write 0x00 to register 0x08 (TEST) 481176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * 2. Write 0x00 to register 0x00 (CMD1) 482176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * 3. Rewrite all registers to the desired values 483176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * 484176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * ISL29018 Data Sheet (FN6619.1, Feb 11, 2010) essentially says 485176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * the same thing EXCEPT the data sheet asks for a 1ms delay after 486176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * writing the CMD1 register. 487176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler */ 488176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler status = isl29018_write_data(client, ISL29018_REG_TEST, 0, 489176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler ISL29018_TEST_MASK, ISL29018_TEST_SHIFT); 490176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler if (status < 0) { 491176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler dev_err(&client->dev, "Failed to clear isl29018 TEST reg." 492176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler "(%d)\n", status); 493176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler return status; 494176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler } 495176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler 496176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler /* See Intersil AN1534 comments above. 497176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * "Operating Mode" (COMMAND1) register is reprogrammed when 498176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler * data is read from the device. 499176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler */ 500176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, 0, 501176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler 0xff, 0); 502176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler if (status < 0) { 503176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler dev_err(&client->dev, "Failed to clear isl29018 CMD1 reg." 504176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler "(%d)\n", status); 505176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler return status; 506176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler } 507176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler 508176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler msleep(1); /* per data sheet, page 10 */ 509176f9f29cec95f88cfa01a8e40741d1fc532add2Grant Grundler 510940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein /* set defaults */ 511940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein status = isl29018_set_range(client, chip->range, &new_range); 512940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (status < 0) { 513940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "Init of isl29018 fails\n"); 514940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return status; 515940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 516940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 517940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein status = isl29018_set_resolution(client, chip->adc_bit, 518940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein &new_adc_bit); 519940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 520940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 521940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 522940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 5236fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameronstatic const struct iio_info isl29108_info = { 5246fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .attrs = &isl29108_group, 5256fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron .driver_module = THIS_MODULE, 52601e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .read_raw = &isl29018_read_raw, 52701e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed .write_raw = &isl29018_write_raw, 5286fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron}; 5296fe8135fccd66aedcc55ded70824342587fd2499Jonathan Cameron 530940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int __devinit isl29018_probe(struct i2c_client *client, 531940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein const struct i2c_device_id *id) 532940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 533940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein struct isl29018_chip *chip; 534927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct iio_dev *indio_dev; 535940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein int err; 536940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 537927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron indio_dev = iio_allocate_device(sizeof(*chip)); 538927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron if (indio_dev == NULL) { 539927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron dev_err(&client->dev, "iio allocation fails\n"); 540940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein err = -ENOMEM; 541940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein goto exit; 542940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 543927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron chip = iio_priv(indio_dev); 544940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 545927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron i2c_set_clientdata(client, indio_dev); 546940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein chip->client = client; 547940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 548940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein mutex_init(&chip->lock); 549940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 5506d1ad0f8aa9d3caf6e3f26ad39b43c687abd9c82Bryan Freed chip->lux_scale = 1; 551940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein chip->range = 1000; 552940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein chip->adc_bit = 16; 553940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 554940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein err = isl29018_chip_init(client); 555940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (err) 556927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron goto exit_iio_free; 557940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 558927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron indio_dev->info = &isl29108_info; 55901e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed indio_dev->channels = isl29018_channels; 56001e57c5742fcd4d08eddab59ef1c3b3e1f60610cBryan Freed indio_dev->num_channels = ARRAY_SIZE(isl29018_channels); 561927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron indio_dev->name = id->name; 562927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron indio_dev->dev.parent = &client->dev; 563927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron indio_dev->modes = INDIO_DIRECT_MODE; 564927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron err = iio_device_register(indio_dev); 565940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein if (err) { 566940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_err(&client->dev, "iio registration fails\n"); 567940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein goto exit_iio_free; 568940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein } 569940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 570940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 571940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinexit_iio_free: 572927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron iio_free_device(indio_dev); 573940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinexit: 574940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return err; 575940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 576940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 577940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic int __devexit isl29018_remove(struct i2c_client *client) 578940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein{ 579927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron struct iio_dev *indio_dev = i2c_get_clientdata(client); 580940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 581940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein dev_dbg(&client->dev, "%s()\n", __func__); 582927afbec71d62dd766d134b61f71d22b91b20713Jonathan Cameron iio_device_unregister(indio_dev); 583d2fffd6c2fd60fe9ab63ef30758d9d43a5057549Jonathan Cameron iio_free_device(indio_dev); 584940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 585940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein return 0; 586940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein} 587940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 588940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic const struct i2c_device_id isl29018_id[] = { 589940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein {"isl29018", 0}, 590940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein {} 591940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein}; 592940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 593940428742ed208836feb715fffd7cbc006fec3cbRhyland KleinMODULE_DEVICE_TABLE(i2c, isl29018_id); 594940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 5954ee195241a3d9384ad222da7c593f7565a7cf518Olof Johanssonstatic const struct of_device_id isl29018_of_match[] = { 5964ee195241a3d9384ad222da7c593f7565a7cf518Olof Johansson { .compatible = "invn,isl29018", }, 5974ee195241a3d9384ad222da7c593f7565a7cf518Olof Johansson { }, 5984ee195241a3d9384ad222da7c593f7565a7cf518Olof Johansson}; 5994ee195241a3d9384ad222da7c593f7565a7cf518Olof JohanssonMODULE_DEVICE_TABLE(of, isl29018_of_match); 6004ee195241a3d9384ad222da7c593f7565a7cf518Olof Johansson 601940428742ed208836feb715fffd7cbc006fec3cbRhyland Kleinstatic struct i2c_driver isl29018_driver = { 602940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .class = I2C_CLASS_HWMON, 603940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .driver = { 604940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .name = "isl29018", 605940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .owner = THIS_MODULE, 6064ee195241a3d9384ad222da7c593f7565a7cf518Olof Johansson .of_match_table = isl29018_of_match, 607940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein }, 608940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .probe = isl29018_probe, 609940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .remove = __devexit_p(isl29018_remove), 610940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein .id_table = isl29018_id, 611940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein}; 6126e5af184f810f6150e07339bd23a09c498739c82Lars-Peter Clausenmodule_i2c_driver(isl29018_driver); 613940428742ed208836feb715fffd7cbc006fec3cbRhyland Klein 614940428742ed208836feb715fffd7cbc006fec3cbRhyland KleinMODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); 615940428742ed208836feb715fffd7cbc006fec3cbRhyland KleinMODULE_LICENSE("GPL"); 616