16d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan/*
26d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * IIO driver for the light sensor ISL29028.
36d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * ISL29028 is Concurrent Ambient Light and Proximity Sensor
46d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan *
56d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
66d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan *
76d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * This program is free software; you can redistribute it and/or modify it
86d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * under the terms and conditions of the GNU General Public License,
96d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * version 2, as published by the Free Software Foundation.
106d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan *
116d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * This program is distributed in the hope it will be useful, but WITHOUT
126d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
136d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
146d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * more details.
156d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan *
166d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * You should have received a copy of the GNU General Public License
176d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan * along with this program.  If not, see <http://www.gnu.org/licenses/>.
186d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan */
196d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
206d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/module.h>
216d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/i2c.h>
226d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/err.h>
236d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/mutex.h>
246d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/delay.h>
256d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/slab.h>
266d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#include <linux/regmap.h>
2706458e277eac2b8761b0a04d3c808d57be281a2eJonathan Cameron#include <linux/iio/iio.h>
2806458e277eac2b8761b0a04d3c808d57be281a2eJonathan Cameron#include <linux/iio/sysfs.h>
296d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
306d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONVERSION_TIME_MS		100
316d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
326d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_CONFIGURE		0x01
336d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
346d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_IR_MODE_ALS	0
356d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_IR_MODE_IR	BIT(0)
366d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_IR_MODE_MASK	BIT(0)
376d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
386d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_RANGE_LOW_LUX	0
396d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_RANGE_HIGH_LUX	BIT(1)
406d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_RANGE_MASK	BIT(1)
416d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
426d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_DIS		0
436d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_EN		BIT(2)
446d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_ALS_EN_MASK		BIT(2)
456d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
466d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_PROX_DRIVE		BIT(3)
476d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
486d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_PROX_SLP_SH		4
496d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_PROX_SLP_MASK		(7 << CONFIGURE_PROX_SLP_SH)
506d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
516d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_PROX_EN		BIT(7)
526d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define CONFIGURE_PROX_EN_MASK		BIT(7)
536d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
546d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_INTERRUPT		0x02
556d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
566d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_PROX_DATA		0x08
576d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_ALSIR_L		0x09
586d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_ALSIR_U		0x0A
596d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
606d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_TEST1_MODE		0x0E
616d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_REG_TEST2_MODE		0x0F
626d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
636d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_NUM_REGS		(ISL29028_REG_TEST2_MODE + 1)
646d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
656d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganenum als_ir_mode {
666d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	MODE_NONE = 0,
676d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	MODE_ALS,
686d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	MODE_IR
696d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
706d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
716d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstruct isl29028_chip {
726d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct device		*dev;
736d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct mutex		lock;
746d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct regmap		*regmap;
756d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
766d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	unsigned int		prox_sampling;
776d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	bool			enable_prox;
786d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
796d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int			lux_scale;
806d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int			als_ir_mode;
816d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
826d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
836d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_set_proxim_sampling(struct isl29028_chip *chip,
846d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			unsigned int sampling)
856d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
866d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	static unsigned int prox_period[] = {800, 400, 200, 100, 75, 50, 12, 0};
876d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int sel;
886d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	unsigned int period = DIV_ROUND_UP(1000, sampling);
896d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
906d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	for (sel = 0; sel < ARRAY_SIZE(prox_period); ++sel) {
916d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (period >= prox_period[sel])
926d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
936d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
946d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
956d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_PROX_SLP_MASK, sel << CONFIGURE_PROX_SLP_SH);
966d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
976d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
986d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_enable_proximity(struct isl29028_chip *chip, bool enable)
996d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
1006d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
1016d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int val = 0;
1026d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1036d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (enable)
1046d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		val = CONFIGURE_PROX_EN;
1056d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1066d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_PROX_EN_MASK, val);
1076d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0)
1086d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
1096d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1106d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	/* Wait for conversion to be complete for first sample */
1116d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mdelay(DIV_ROUND_UP(1000, chip->prox_sampling));
1126d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
1136d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
1146d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1156d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_set_als_scale(struct isl29028_chip *chip, int lux_scale)
1166d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
1176d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int val = (lux_scale == 2000) ? CONFIGURE_ALS_RANGE_HIGH_LUX :
1186d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan					CONFIGURE_ALS_RANGE_LOW_LUX;
1196d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1206d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1216d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		CONFIGURE_ALS_RANGE_MASK, val);
1226d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
1236d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1246d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_set_als_ir_mode(struct isl29028_chip *chip,
1256d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	enum als_ir_mode mode)
1266d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
1276d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret = 0;
1286d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1296d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	switch (mode) {
1306d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case MODE_ALS:
1316d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1326d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_ALS);
1336d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0)
1346d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			return ret;
1356d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1366d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1376d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_ALS_RANGE_MASK, CONFIGURE_ALS_RANGE_HIGH_LUX);
1386d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
1396d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1406d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case MODE_IR:
1416d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1426d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_ALS_IR_MODE_MASK, CONFIGURE_ALS_IR_MODE_IR);
1436d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
1446d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1456d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case MODE_NONE:
1466d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1476d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_DIS);
1486d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
1496d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1506d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0)
1516d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
1526d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1536d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	/* Enable the ALS/IR */
1546d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_update_bits(chip->regmap, ISL29028_REG_CONFIGURE,
1556d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			CONFIGURE_ALS_EN_MASK, CONFIGURE_ALS_EN);
1566d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0)
1576d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
1586d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1596d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	/* Need to wait for conversion time if ALS/IR mode enabled */
1606d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mdelay(CONVERSION_TIME_MS);
1616d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
1626d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
1636d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1646d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_read_als_ir(struct isl29028_chip *chip, int *als_ir)
1656d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
1666d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	unsigned int lsb;
1676d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	unsigned int msb;
1686d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
1696d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1706d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_L, &lsb);
1716d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
1726d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev,
1736d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			"Error in reading register ALSIR_L err %d\n", ret);
1746d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
1756d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
1766d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1776d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_read(chip->regmap, ISL29028_REG_ALSIR_U, &msb);
1786d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
1796d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev,
1806d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			"Error in reading register ALSIR_U err %d\n", ret);
1816d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
1826d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
1836d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1846d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	*als_ir = ((msb & 0xF) << 8) | (lsb & 0xFF);
1856d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
1866d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
1876d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1886d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_read_proxim(struct isl29028_chip *chip, int *prox)
1896d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
1906d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	unsigned int data;
1916d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
1926d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
1936d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_read(chip->regmap, ISL29028_REG_PROX_DATA, &data);
1946d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
1956d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "Error in reading register %d, error %d\n",
1966d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				ISL29028_REG_PROX_DATA, ret);
1976d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
1986d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
1996d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	*prox = data;
2006d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
2016d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
2026d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2036d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_proxim_get(struct isl29028_chip *chip, int *prox_data)
2046d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
2056d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
2066d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2076d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (!chip->enable_prox) {
2086d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = isl29028_enable_proximity(chip, true);
2096d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0)
2106d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			return ret;
2116d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		chip->enable_prox = true;
2126d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
2136d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return isl29028_read_proxim(chip, prox_data);
2146d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
2156d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2166d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_als_get(struct isl29028_chip *chip, int *als_data)
2176d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
2186d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
2196d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int als_ir_data;
2206d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2216d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (chip->als_ir_mode != MODE_ALS) {
2226d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = isl29028_set_als_ir_mode(chip, MODE_ALS);
2236d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0) {
2246d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
2256d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"Error in enabling ALS mode err %d\n", ret);
2266d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			return ret;
2276d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
2286d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		chip->als_ir_mode = MODE_ALS;
2296d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
2306d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2316d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = isl29028_read_als_ir(chip, &als_ir_data);
2326d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0)
2336d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
2346d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2356d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	/*
2366d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	 * convert als data count to lux.
2376d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	 * if lux_scale = 125,  lux = count * 0.031
2386d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	 * if lux_scale = 2000, lux = count * 0.49
2396d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	 */
2406d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (chip->lux_scale == 125)
2416d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		als_ir_data = (als_ir_data * 31) / 1000;
2426d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	else
2436d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		als_ir_data = (als_ir_data * 49) / 100;
2446d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2456d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	*als_data = als_ir_data;
2466d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
2476d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
2486d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2496d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_ir_get(struct isl29028_chip *chip, int *ir_data)
2506d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
2516d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
2526d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2536d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (chip->als_ir_mode != MODE_IR) {
2546d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = isl29028_set_als_ir_mode(chip, MODE_IR);
2556d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0) {
2566d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
2576d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"Error in enabling IR mode err %d\n", ret);
2586d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			return ret;
2596d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
2606d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		chip->als_ir_mode = MODE_IR;
2616d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
2626d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return isl29028_read_als_ir(chip, ir_data);
2636d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
2646d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2656d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan/* Channel IO */
2666d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_write_raw(struct iio_dev *indio_dev,
2676d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	     struct iio_chan_spec const *chan, int val, int val2, long mask)
2686d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
2696d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct isl29028_chip *chip = iio_priv(indio_dev);
2706d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret = -EINVAL;
2716d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2726d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mutex_lock(&chip->lock);
2736d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	switch (chan->type) {
2746d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case IIO_PROXIMITY:
275892cb6dc9fbbfa7281f3aa53aa6599618aec7cb1Laxman Dewangan		if (mask != IIO_CHAN_INFO_SAMP_FREQ) {
2766d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
2776d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"proximity: mask value 0x%08lx not supported\n",
2786d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				mask);
2796d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
2806d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
2816d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (val < 1 || val > 100) {
2826d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
2836d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"Samp_freq %d is not in range[1:100]\n", val);
2846d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
2856d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
2866d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = isl29028_set_proxim_sampling(chip, val);
2876d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0) {
2886d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
2896d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"Setting proximity samp_freq fail, err %d\n",
2906d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				ret);
2916d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
2926d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
2936d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		chip->prox_sampling = val;
2946d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
2956d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
2966d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case IIO_LIGHT:
297892cb6dc9fbbfa7281f3aa53aa6599618aec7cb1Laxman Dewangan		if (mask != IIO_CHAN_INFO_SCALE) {
2986d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
2996d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"light: mask value 0x%08lx not supported\n",
3006d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				mask);
3016d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3026d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
3036d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if ((val != 125) && (val != 2000)) {
3046d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
3056d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"lux scale %d is invalid [125, 2000]\n", val);
3066d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3076d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
3086d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = isl29028_set_als_scale(chip, val);
3096d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0) {
3106d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			dev_err(chip->dev,
3116d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"Setting lux scale fail with error %d\n", ret);
3126d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3136d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
3146d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		chip->lux_scale = val;
3156d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
3166d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3176d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	default:
3186d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "Unsupported channel type\n");
3196d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
3206d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
3216d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mutex_unlock(&chip->lock);
3226d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return ret;
3236d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
3246d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3256d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_read_raw(struct iio_dev *indio_dev,
3266d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	     struct iio_chan_spec const *chan, int *val, int *val2, long mask)
3276d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
3286d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct isl29028_chip *chip = iio_priv(indio_dev);
3296d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret = -EINVAL;
3306d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3316d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mutex_lock(&chip->lock);
3326d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	switch (mask) {
333a8c0ed756574ba5a484cd8238892f88501ff400dJonathan Cameron	case IIO_CHAN_INFO_RAW:
334a8c0ed756574ba5a484cd8238892f88501ff400dJonathan Cameron	case IIO_CHAN_INFO_PROCESSED:
3356d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		switch (chan->type) {
3366d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		case IIO_LIGHT:
3376d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			ret = isl29028_als_get(chip, val);
3386d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3396d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		case IIO_INTENSITY:
3406d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			ret = isl29028_ir_get(chip, val);
3416d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3426d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		case IIO_PROXIMITY:
3436d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			ret = isl29028_proxim_get(chip, val);
3446d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3456d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		default:
3466d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3476d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		}
3486d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (ret < 0)
3496d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3506d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = IIO_VAL_INT;
3516d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
3526d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
353892cb6dc9fbbfa7281f3aa53aa6599618aec7cb1Laxman Dewangan	case IIO_CHAN_INFO_SAMP_FREQ:
3546d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (chan->type != IIO_PROXIMITY)
3556d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3566d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		*val = chip->prox_sampling;
3576d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = IIO_VAL_INT;
3586d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
3596d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
360892cb6dc9fbbfa7281f3aa53aa6599618aec7cb1Laxman Dewangan	case IIO_CHAN_INFO_SCALE:
3616d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		if (chan->type != IIO_LIGHT)
3626d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			break;
3636d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		*val = chip->lux_scale;
3646d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = IIO_VAL_INT;
3656d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
3666d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3676d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	default:
3686d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "mask value 0x%08lx not supported\n", mask);
3696d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		break;
3706d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
3716d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mutex_unlock(&chip->lock);
3726d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return ret;
3736d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
3746d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3756d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic IIO_CONST_ATTR(in_proximity_sampling_frequency_available,
3766d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan				"1, 3, 5, 10, 13, 20, 83, 100");
3776d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic IIO_CONST_ATTR(in_illuminance_scale_available, "125, 2000");
3786d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3796d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr)
3806d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan#define ISL29028_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr)
3816d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic struct attribute *isl29028_attributes[] = {
3826d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ISL29028_CONST_ATTR(in_proximity_sampling_frequency_available),
3836d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ISL29028_CONST_ATTR(in_illuminance_scale_available),
3846d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	NULL,
3856d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
3866d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3876d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic const struct attribute_group isl29108_group = {
3886d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.attrs = isl29028_attributes,
3896d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
3906d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
3916d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic const struct iio_chan_spec isl29028_channels[] = {
3926d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	{
3936d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		.type = IIO_LIGHT,
39493a9fdff2106f34747ec934812c89fa8b28b419fJonathan Cameron		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
39593a9fdff2106f34747ec934812c89fa8b28b419fJonathan Cameron		BIT(IIO_CHAN_INFO_SCALE),
3966d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}, {
3976d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		.type = IIO_INTENSITY,
39893a9fdff2106f34747ec934812c89fa8b28b419fJonathan Cameron		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
3996d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}, {
4006d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		.type = IIO_PROXIMITY,
40193a9fdff2106f34747ec934812c89fa8b28b419fJonathan Cameron		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
40293a9fdff2106f34747ec934812c89fa8b28b419fJonathan Cameron		BIT(IIO_CHAN_INFO_SAMP_FREQ),
4036d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4046d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
4056d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4066d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic const struct iio_info isl29028_info = {
4076d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.attrs = &isl29108_group,
4086d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.driver_module = THIS_MODULE,
4096d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.read_raw = &isl29028_read_raw,
4106d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.write_raw = &isl29028_write_raw,
4116d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
4126d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4136d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic int isl29028_chip_init(struct isl29028_chip *chip)
4146d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
4156d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
4166d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4176d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip->enable_prox  = false;
4186d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip->prox_sampling = 20;
4196d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip->lux_scale = 2000;
4206d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip->als_ir_mode = MODE_NONE;
4216d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4226d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_write(chip->regmap, ISL29028_REG_TEST1_MODE, 0x0);
4236d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
4246d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
4256d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			__func__, ISL29028_REG_TEST1_MODE, ret);
4266d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
4276d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4286d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_write(chip->regmap, ISL29028_REG_TEST2_MODE, 0x0);
4296d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
4306d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
4316d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			__func__, ISL29028_REG_TEST2_MODE, ret);
4326d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
4336d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4346d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4356d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = regmap_write(chip->regmap, ISL29028_REG_CONFIGURE, 0x0);
4366d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
4376d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "%s(): write to reg %d failed, err = %d\n",
4386d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			__func__, ISL29028_REG_CONFIGURE, ret);
4396d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
4406d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4416d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4426d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = isl29028_set_proxim_sampling(chip, chip->prox_sampling);
4436d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
4446d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "%s(): setting the proximity, err = %d\n",
4456d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			__func__, ret);
4466d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return ret;
4476d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4486d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4496d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = isl29028_set_als_scale(chip, chip->lux_scale);
4506d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0)
4516d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "%s(): setting als scale failed, err = %d\n",
4526d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			__func__, ret);
4536d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return ret;
4546d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
4556d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4566d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic bool is_volatile_reg(struct device *dev, unsigned int reg)
4576d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
4586d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	switch (reg) {
4596d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case ISL29028_REG_INTERRUPT:
4606d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case ISL29028_REG_PROX_DATA:
4616d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case ISL29028_REG_ALSIR_L:
4626d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	case ISL29028_REG_ALSIR_U:
4636d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return true;
4646d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	default:
4656d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return false;
4666d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4676d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
4686d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4696d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic const struct regmap_config isl29028_regmap_config = {
4706d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.reg_bits = 8,
4716d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.val_bits = 8,
4726d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.volatile_reg = is_volatile_reg,
4736d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.max_register = ISL29028_NUM_REGS - 1,
4746d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.num_reg_defaults_raw = ISL29028_NUM_REGS,
4756d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.cache_type = REGCACHE_RBTREE,
4766d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
4776d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4784ae1c61ff2ba4fea4e4c1a045cb1f34520608789Bill Pembertonstatic int isl29028_probe(struct i2c_client *client,
4796d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	const struct i2c_device_id *id)
4806d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
4816d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct isl29028_chip *chip;
4826d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct iio_dev *indio_dev;
4836d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	int ret;
4846d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
48580cab1da704e3f27fb4a631f95369fc31323e91cSachin Kamat	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
4866d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (!indio_dev) {
4876d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(&client->dev, "iio allocation fails\n");
4886d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		return -ENOMEM;
4896d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
4906d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4916d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip = iio_priv(indio_dev);
4926d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4936d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	i2c_set_clientdata(client, indio_dev);
4946d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip->dev = &client->dev;
4956d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	mutex_init(&chip->lock);
4966d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
4976d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	chip->regmap = devm_regmap_init_i2c(client, &isl29028_regmap_config);
4986d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (IS_ERR(chip->regmap)) {
4996d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		ret = PTR_ERR(chip->regmap);
5006d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "regmap initialization failed: %d\n", ret);
50180cab1da704e3f27fb4a631f95369fc31323e91cSachin Kamat		return ret;
5026d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
5036d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5046d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = isl29028_chip_init(chip);
5056d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
5066d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "chip initialization failed: %d\n", ret);
50780cab1da704e3f27fb4a631f95369fc31323e91cSachin Kamat		return ret;
5086d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
5096d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5106d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	indio_dev->info = &isl29028_info;
5116d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	indio_dev->channels = isl29028_channels;
5126d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	indio_dev->num_channels = ARRAY_SIZE(isl29028_channels);
5136d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	indio_dev->name = id->name;
5146d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	indio_dev->dev.parent = &client->dev;
5156d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	indio_dev->modes = INDIO_DIRECT_MODE;
5166d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	ret = iio_device_register(indio_dev);
5176d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	if (ret < 0) {
5186d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		dev_err(chip->dev, "iio registration fails with error %d\n",
5196d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan			ret);
52080cab1da704e3f27fb4a631f95369fc31323e91cSachin Kamat		return ret;
5216d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	}
5226d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
5236d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
5246d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
525447d4f29ee3fa62f13c65688bb7b74d5a9a0d767Bill Pembertonstatic int isl29028_remove(struct i2c_client *client)
5266d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan{
5276d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	struct iio_dev *indio_dev = i2c_get_clientdata(client);
5286d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5296d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	iio_device_unregister(indio_dev);
5306d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	return 0;
5316d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan}
5326d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5336d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic const struct i2c_device_id isl29028_id[] = {
5346d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	{"isl29028", 0},
5356d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	{}
5366d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
5376d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman DewanganMODULE_DEVICE_TABLE(i2c, isl29028_id);
5386d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5396d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic const struct of_device_id isl29028_of_match[] = {
540610202ddc6951453034475fdcf5c9caf14f050deLaxman Dewangan	{ .compatible = "isil,isl29028", },
5416d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	{ },
5426d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
5436d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman DewanganMODULE_DEVICE_TABLE(of, isl29028_of_match);
5446d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5456d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganstatic struct i2c_driver isl29028_driver = {
5466d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.class	= I2C_CLASS_HWMON,
5476d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.driver  = {
5486d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		.name = "isl29028",
5496d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		.owner = THIS_MODULE,
5506d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan		.of_match_table = isl29028_of_match,
5516d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	},
5526d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.probe	 = isl29028_probe,
553e543acf07db78cfc135e45c4ce0ed26ccf774c37Bill Pemberton	.remove  = isl29028_remove,
5546d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan	.id_table = isl29028_id,
5556d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan};
5566d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5576d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewanganmodule_i2c_driver(isl29028_driver);
5586d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman Dewangan
5596d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman DewanganMODULE_DESCRIPTION("ISL29028 Ambient Light and Proximity Sensor driver");
5606d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman DewanganMODULE_LICENSE("GPL v2");
5616d59ba2f9676210b4631e9c447ab1c9faf0a9577Laxman DewanganMODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
562