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