cachepc-linux

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

lm3533-als.c (22045B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * lm3533-als.c -- LM3533 Ambient Light Sensor driver
      4 *
      5 * Copyright (C) 2011-2012 Texas Instruments
      6 *
      7 * Author: Johan Hovold <jhovold@gmail.com>
      8 */
      9
     10#include <linux/atomic.h>
     11#include <linux/fs.h>
     12#include <linux/interrupt.h>
     13#include <linux/io.h>
     14#include <linux/iio/events.h>
     15#include <linux/iio/iio.h>
     16#include <linux/module.h>
     17#include <linux/mutex.h>
     18#include <linux/mfd/core.h>
     19#include <linux/platform_device.h>
     20#include <linux/slab.h>
     21#include <linux/uaccess.h>
     22
     23#include <linux/mfd/lm3533.h>
     24
     25
     26#define LM3533_ALS_RESISTOR_MIN			1
     27#define LM3533_ALS_RESISTOR_MAX			127
     28#define LM3533_ALS_CHANNEL_CURRENT_MAX		2
     29#define LM3533_ALS_THRESH_MAX			3
     30#define LM3533_ALS_ZONE_MAX			4
     31
     32#define LM3533_REG_ALS_RESISTOR_SELECT		0x30
     33#define LM3533_REG_ALS_CONF			0x31
     34#define LM3533_REG_ALS_ZONE_INFO		0x34
     35#define LM3533_REG_ALS_READ_ADC_RAW		0x37
     36#define LM3533_REG_ALS_READ_ADC_AVERAGE		0x38
     37#define LM3533_REG_ALS_BOUNDARY_BASE		0x50
     38#define LM3533_REG_ALS_TARGET_BASE		0x60
     39
     40#define LM3533_ALS_ENABLE_MASK			0x01
     41#define LM3533_ALS_INPUT_MODE_MASK		0x02
     42#define LM3533_ALS_INT_ENABLE_MASK		0x01
     43
     44#define LM3533_ALS_ZONE_SHIFT			2
     45#define LM3533_ALS_ZONE_MASK			0x1c
     46
     47#define LM3533_ALS_FLAG_INT_ENABLED		1
     48
     49
     50struct lm3533_als {
     51	struct lm3533 *lm3533;
     52	struct platform_device *pdev;
     53
     54	unsigned long flags;
     55	int irq;
     56
     57	atomic_t zone;
     58	struct mutex thresh_mutex;
     59};
     60
     61
     62static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average,
     63								int *adc)
     64{
     65	struct lm3533_als *als = iio_priv(indio_dev);
     66	u8 reg;
     67	u8 val;
     68	int ret;
     69
     70	if (average)
     71		reg = LM3533_REG_ALS_READ_ADC_AVERAGE;
     72	else
     73		reg = LM3533_REG_ALS_READ_ADC_RAW;
     74
     75	ret = lm3533_read(als->lm3533, reg, &val);
     76	if (ret) {
     77		dev_err(&indio_dev->dev, "failed to read adc\n");
     78		return ret;
     79	}
     80
     81	*adc = val;
     82
     83	return 0;
     84}
     85
     86static int _lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
     87{
     88	struct lm3533_als *als = iio_priv(indio_dev);
     89	u8 val;
     90	int ret;
     91
     92	ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
     93	if (ret) {
     94		dev_err(&indio_dev->dev, "failed to read zone\n");
     95		return ret;
     96	}
     97
     98	val = (val & LM3533_ALS_ZONE_MASK) >> LM3533_ALS_ZONE_SHIFT;
     99	*zone = min_t(u8, val, LM3533_ALS_ZONE_MAX);
    100
    101	return 0;
    102}
    103
    104static int lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
    105{
    106	struct lm3533_als *als = iio_priv(indio_dev);
    107	int ret;
    108
    109	if (test_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags)) {
    110		*zone = atomic_read(&als->zone);
    111	} else {
    112		ret = _lm3533_als_get_zone(indio_dev, zone);
    113		if (ret)
    114			return ret;
    115	}
    116
    117	return 0;
    118}
    119
    120/*
    121 * channel	output channel 0..2
    122 * zone		zone 0..4
    123 */
    124static inline u8 lm3533_als_get_target_reg(unsigned channel, unsigned zone)
    125{
    126	return LM3533_REG_ALS_TARGET_BASE + 5 * channel + zone;
    127}
    128
    129static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel,
    130							unsigned zone, u8 *val)
    131{
    132	struct lm3533_als *als = iio_priv(indio_dev);
    133	u8 reg;
    134	int ret;
    135
    136	if (channel > LM3533_ALS_CHANNEL_CURRENT_MAX)
    137		return -EINVAL;
    138
    139	if (zone > LM3533_ALS_ZONE_MAX)
    140		return -EINVAL;
    141
    142	reg = lm3533_als_get_target_reg(channel, zone);
    143	ret = lm3533_read(als->lm3533, reg, val);
    144	if (ret)
    145		dev_err(&indio_dev->dev, "failed to get target current\n");
    146
    147	return ret;
    148}
    149
    150static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel,
    151							unsigned zone, u8 val)
    152{
    153	struct lm3533_als *als = iio_priv(indio_dev);
    154	u8 reg;
    155	int ret;
    156
    157	if (channel > LM3533_ALS_CHANNEL_CURRENT_MAX)
    158		return -EINVAL;
    159
    160	if (zone > LM3533_ALS_ZONE_MAX)
    161		return -EINVAL;
    162
    163	reg = lm3533_als_get_target_reg(channel, zone);
    164	ret = lm3533_write(als->lm3533, reg, val);
    165	if (ret)
    166		dev_err(&indio_dev->dev, "failed to set target current\n");
    167
    168	return ret;
    169}
    170
    171static int lm3533_als_get_current(struct iio_dev *indio_dev, unsigned channel,
    172								int *val)
    173{
    174	u8 zone;
    175	u8 target;
    176	int ret;
    177
    178	ret = lm3533_als_get_zone(indio_dev, &zone);
    179	if (ret)
    180		return ret;
    181
    182	ret = lm3533_als_get_target(indio_dev, channel, zone, &target);
    183	if (ret)
    184		return ret;
    185
    186	*val = target;
    187
    188	return 0;
    189}
    190
    191static int lm3533_als_read_raw(struct iio_dev *indio_dev,
    192				struct iio_chan_spec const *chan,
    193				int *val, int *val2, long mask)
    194{
    195	int ret;
    196
    197	switch (mask) {
    198	case IIO_CHAN_INFO_RAW:
    199		switch (chan->type) {
    200		case IIO_LIGHT:
    201			ret = lm3533_als_get_adc(indio_dev, false, val);
    202			break;
    203		case IIO_CURRENT:
    204			ret = lm3533_als_get_current(indio_dev, chan->channel,
    205									val);
    206			break;
    207		default:
    208			return -EINVAL;
    209		}
    210		break;
    211	case IIO_CHAN_INFO_AVERAGE_RAW:
    212		ret = lm3533_als_get_adc(indio_dev, true, val);
    213		break;
    214	default:
    215		return -EINVAL;
    216	}
    217
    218	if (ret)
    219		return ret;
    220
    221	return IIO_VAL_INT;
    222}
    223
    224#define CHANNEL_CURRENT(_channel)					\
    225	{								\
    226		.type		= IIO_CURRENT,				\
    227		.channel	= _channel,				\
    228		.indexed	= true,					\
    229		.output		= true,					\
    230		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
    231	}
    232
    233static const struct iio_chan_spec lm3533_als_channels[] = {
    234	{
    235		.type		= IIO_LIGHT,
    236		.channel	= 0,
    237		.indexed	= true,
    238		.info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
    239				   BIT(IIO_CHAN_INFO_RAW),
    240	},
    241	CHANNEL_CURRENT(0),
    242	CHANNEL_CURRENT(1),
    243	CHANNEL_CURRENT(2),
    244};
    245
    246static irqreturn_t lm3533_als_isr(int irq, void *dev_id)
    247{
    248
    249	struct iio_dev *indio_dev = dev_id;
    250	struct lm3533_als *als = iio_priv(indio_dev);
    251	u8 zone;
    252	int ret;
    253
    254	/* Clear interrupt by reading the ALS zone register. */
    255	ret = _lm3533_als_get_zone(indio_dev, &zone);
    256	if (ret)
    257		goto out;
    258
    259	atomic_set(&als->zone, zone);
    260
    261	iio_push_event(indio_dev,
    262		       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
    263					    0,
    264					    IIO_EV_TYPE_THRESH,
    265					    IIO_EV_DIR_EITHER),
    266		       iio_get_time_ns(indio_dev));
    267out:
    268	return IRQ_HANDLED;
    269}
    270
    271static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable)
    272{
    273	struct lm3533_als *als = iio_priv(indio_dev);
    274	u8 mask = LM3533_ALS_INT_ENABLE_MASK;
    275	u8 val;
    276	int ret;
    277
    278	if (enable)
    279		val = mask;
    280	else
    281		val = 0;
    282
    283	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, val, mask);
    284	if (ret) {
    285		dev_err(&indio_dev->dev, "failed to set int mode %d\n",
    286								enable);
    287		return ret;
    288	}
    289
    290	return 0;
    291}
    292
    293static int lm3533_als_get_int_mode(struct iio_dev *indio_dev, int *enable)
    294{
    295	struct lm3533_als *als = iio_priv(indio_dev);
    296	u8 mask = LM3533_ALS_INT_ENABLE_MASK;
    297	u8 val;
    298	int ret;
    299
    300	ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
    301	if (ret) {
    302		dev_err(&indio_dev->dev, "failed to get int mode\n");
    303		return ret;
    304	}
    305
    306	*enable = !!(val & mask);
    307
    308	return 0;
    309}
    310
    311static inline u8 lm3533_als_get_threshold_reg(unsigned nr, bool raising)
    312{
    313	u8 offset = !raising;
    314
    315	return LM3533_REG_ALS_BOUNDARY_BASE + 2 * nr + offset;
    316}
    317
    318static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr,
    319							bool raising, u8 *val)
    320{
    321	struct lm3533_als *als = iio_priv(indio_dev);
    322	u8 reg;
    323	int ret;
    324
    325	if (nr > LM3533_ALS_THRESH_MAX)
    326		return -EINVAL;
    327
    328	reg = lm3533_als_get_threshold_reg(nr, raising);
    329	ret = lm3533_read(als->lm3533, reg, val);
    330	if (ret)
    331		dev_err(&indio_dev->dev, "failed to get threshold\n");
    332
    333	return ret;
    334}
    335
    336static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr,
    337							bool raising, u8 val)
    338{
    339	struct lm3533_als *als = iio_priv(indio_dev);
    340	u8 val2;
    341	u8 reg, reg2;
    342	int ret;
    343
    344	if (nr > LM3533_ALS_THRESH_MAX)
    345		return -EINVAL;
    346
    347	reg = lm3533_als_get_threshold_reg(nr, raising);
    348	reg2 = lm3533_als_get_threshold_reg(nr, !raising);
    349
    350	mutex_lock(&als->thresh_mutex);
    351	ret = lm3533_read(als->lm3533, reg2, &val2);
    352	if (ret) {
    353		dev_err(&indio_dev->dev, "failed to get threshold\n");
    354		goto out;
    355	}
    356	/*
    357	 * This device does not allow negative hysteresis (in fact, it uses
    358	 * whichever value is smaller as the lower bound) so we need to make
    359	 * sure that thresh_falling <= thresh_raising.
    360	 */
    361	if ((raising && (val < val2)) || (!raising && (val > val2))) {
    362		ret = -EINVAL;
    363		goto out;
    364	}
    365
    366	ret = lm3533_write(als->lm3533, reg, val);
    367	if (ret) {
    368		dev_err(&indio_dev->dev, "failed to set threshold\n");
    369		goto out;
    370	}
    371out:
    372	mutex_unlock(&als->thresh_mutex);
    373
    374	return ret;
    375}
    376
    377static int lm3533_als_get_hysteresis(struct iio_dev *indio_dev, unsigned nr,
    378								u8 *val)
    379{
    380	struct lm3533_als *als = iio_priv(indio_dev);
    381	u8 falling;
    382	u8 raising;
    383	int ret;
    384
    385	if (nr > LM3533_ALS_THRESH_MAX)
    386		return -EINVAL;
    387
    388	mutex_lock(&als->thresh_mutex);
    389	ret = lm3533_als_get_threshold(indio_dev, nr, false, &falling);
    390	if (ret)
    391		goto out;
    392	ret = lm3533_als_get_threshold(indio_dev, nr, true, &raising);
    393	if (ret)
    394		goto out;
    395
    396	*val = raising - falling;
    397out:
    398	mutex_unlock(&als->thresh_mutex);
    399
    400	return ret;
    401}
    402
    403static ssize_t show_thresh_either_en(struct device *dev,
    404					struct device_attribute *attr,
    405					char *buf)
    406{
    407	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
    408	struct lm3533_als *als = iio_priv(indio_dev);
    409	int enable;
    410	int ret;
    411
    412	if (als->irq) {
    413		ret = lm3533_als_get_int_mode(indio_dev, &enable);
    414		if (ret)
    415			return ret;
    416	} else {
    417		enable = 0;
    418	}
    419
    420	return sysfs_emit(buf, "%u\n", enable);
    421}
    422
    423static ssize_t store_thresh_either_en(struct device *dev,
    424					struct device_attribute *attr,
    425					const char *buf, size_t len)
    426{
    427	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
    428	struct lm3533_als *als = iio_priv(indio_dev);
    429	unsigned long enable;
    430	bool int_enabled;
    431	u8 zone;
    432	int ret;
    433
    434	if (!als->irq)
    435		return -EBUSY;
    436
    437	if (kstrtoul(buf, 0, &enable))
    438		return -EINVAL;
    439
    440	int_enabled = test_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
    441
    442	if (enable && !int_enabled) {
    443		ret = lm3533_als_get_zone(indio_dev, &zone);
    444		if (ret)
    445			return ret;
    446
    447		atomic_set(&als->zone, zone);
    448
    449		set_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
    450	}
    451
    452	ret = lm3533_als_set_int_mode(indio_dev, enable);
    453	if (ret) {
    454		if (!int_enabled)
    455			clear_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
    456
    457		return ret;
    458	}
    459
    460	if (!enable)
    461		clear_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
    462
    463	return len;
    464}
    465
    466static ssize_t show_zone(struct device *dev,
    467				struct device_attribute *attr, char *buf)
    468{
    469	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
    470	u8 zone;
    471	int ret;
    472
    473	ret = lm3533_als_get_zone(indio_dev, &zone);
    474	if (ret)
    475		return ret;
    476
    477	return sysfs_emit(buf, "%u\n", zone);
    478}
    479
    480enum lm3533_als_attribute_type {
    481	LM3533_ATTR_TYPE_HYSTERESIS,
    482	LM3533_ATTR_TYPE_TARGET,
    483	LM3533_ATTR_TYPE_THRESH_FALLING,
    484	LM3533_ATTR_TYPE_THRESH_RAISING,
    485};
    486
    487struct lm3533_als_attribute {
    488	struct device_attribute dev_attr;
    489	enum lm3533_als_attribute_type type;
    490	u8 val1;
    491	u8 val2;
    492};
    493
    494static inline struct lm3533_als_attribute *
    495to_lm3533_als_attr(struct device_attribute *attr)
    496{
    497	return container_of(attr, struct lm3533_als_attribute, dev_attr);
    498}
    499
    500static ssize_t show_als_attr(struct device *dev,
    501					struct device_attribute *attr,
    502					char *buf)
    503{
    504	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
    505	struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
    506	u8 val;
    507	int ret;
    508
    509	switch (als_attr->type) {
    510	case LM3533_ATTR_TYPE_HYSTERESIS:
    511		ret = lm3533_als_get_hysteresis(indio_dev, als_attr->val1,
    512									&val);
    513		break;
    514	case LM3533_ATTR_TYPE_TARGET:
    515		ret = lm3533_als_get_target(indio_dev, als_attr->val1,
    516							als_attr->val2, &val);
    517		break;
    518	case LM3533_ATTR_TYPE_THRESH_FALLING:
    519		ret = lm3533_als_get_threshold(indio_dev, als_attr->val1,
    520								false, &val);
    521		break;
    522	case LM3533_ATTR_TYPE_THRESH_RAISING:
    523		ret = lm3533_als_get_threshold(indio_dev, als_attr->val1,
    524								true, &val);
    525		break;
    526	default:
    527		ret = -ENXIO;
    528	}
    529
    530	if (ret)
    531		return ret;
    532
    533	return sysfs_emit(buf, "%u\n", val);
    534}
    535
    536static ssize_t store_als_attr(struct device *dev,
    537					struct device_attribute *attr,
    538					const char *buf, size_t len)
    539{
    540	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
    541	struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
    542	u8 val;
    543	int ret;
    544
    545	if (kstrtou8(buf, 0, &val))
    546		return -EINVAL;
    547
    548	switch (als_attr->type) {
    549	case LM3533_ATTR_TYPE_TARGET:
    550		ret = lm3533_als_set_target(indio_dev, als_attr->val1,
    551							als_attr->val2, val);
    552		break;
    553	case LM3533_ATTR_TYPE_THRESH_FALLING:
    554		ret = lm3533_als_set_threshold(indio_dev, als_attr->val1,
    555								false, val);
    556		break;
    557	case LM3533_ATTR_TYPE_THRESH_RAISING:
    558		ret = lm3533_als_set_threshold(indio_dev, als_attr->val1,
    559								true, val);
    560		break;
    561	default:
    562		ret = -ENXIO;
    563	}
    564
    565	if (ret)
    566		return ret;
    567
    568	return len;
    569}
    570
    571#define ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2)	\
    572	{ .dev_attr	= __ATTR(_name, _mode, _show, _store),		\
    573	  .type		= _type,					\
    574	  .val1		= _val1,					\
    575	  .val2		= _val2 }
    576
    577#define LM3533_ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2) \
    578	struct lm3533_als_attribute lm3533_als_attr_##_name =		  \
    579		ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2)
    580
    581#define ALS_TARGET_ATTR_RW(_channel, _zone)				\
    582	LM3533_ALS_ATTR(out_current##_channel##_current##_zone##_raw,	\
    583				S_IRUGO | S_IWUSR,			\
    584				show_als_attr, store_als_attr,		\
    585				LM3533_ATTR_TYPE_TARGET, _channel, _zone)
    586/*
    587 * ALS output current values (ALS mapper targets)
    588 *
    589 * out_current[0-2]_current[0-4]_raw		0-255
    590 */
    591static ALS_TARGET_ATTR_RW(0, 0);
    592static ALS_TARGET_ATTR_RW(0, 1);
    593static ALS_TARGET_ATTR_RW(0, 2);
    594static ALS_TARGET_ATTR_RW(0, 3);
    595static ALS_TARGET_ATTR_RW(0, 4);
    596
    597static ALS_TARGET_ATTR_RW(1, 0);
    598static ALS_TARGET_ATTR_RW(1, 1);
    599static ALS_TARGET_ATTR_RW(1, 2);
    600static ALS_TARGET_ATTR_RW(1, 3);
    601static ALS_TARGET_ATTR_RW(1, 4);
    602
    603static ALS_TARGET_ATTR_RW(2, 0);
    604static ALS_TARGET_ATTR_RW(2, 1);
    605static ALS_TARGET_ATTR_RW(2, 2);
    606static ALS_TARGET_ATTR_RW(2, 3);
    607static ALS_TARGET_ATTR_RW(2, 4);
    608
    609#define ALS_THRESH_FALLING_ATTR_RW(_nr)					\
    610	LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_falling_value,	\
    611			S_IRUGO | S_IWUSR,				\
    612			show_als_attr, store_als_attr,		\
    613			LM3533_ATTR_TYPE_THRESH_FALLING, _nr, 0)
    614
    615#define ALS_THRESH_RAISING_ATTR_RW(_nr)					\
    616	LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_raising_value,	\
    617			S_IRUGO | S_IWUSR,				\
    618			show_als_attr, store_als_attr,			\
    619			LM3533_ATTR_TYPE_THRESH_RAISING, _nr, 0)
    620/*
    621 * ALS Zone thresholds (boundaries)
    622 *
    623 * in_illuminance0_thresh[0-3]_falling_value	0-255
    624 * in_illuminance0_thresh[0-3]_raising_value	0-255
    625 */
    626static ALS_THRESH_FALLING_ATTR_RW(0);
    627static ALS_THRESH_FALLING_ATTR_RW(1);
    628static ALS_THRESH_FALLING_ATTR_RW(2);
    629static ALS_THRESH_FALLING_ATTR_RW(3);
    630
    631static ALS_THRESH_RAISING_ATTR_RW(0);
    632static ALS_THRESH_RAISING_ATTR_RW(1);
    633static ALS_THRESH_RAISING_ATTR_RW(2);
    634static ALS_THRESH_RAISING_ATTR_RW(3);
    635
    636#define ALS_HYSTERESIS_ATTR_RO(_nr)					\
    637	LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_hysteresis,	\
    638			S_IRUGO, show_als_attr, NULL,			\
    639			LM3533_ATTR_TYPE_HYSTERESIS, _nr, 0)
    640/*
    641 * ALS Zone threshold hysteresis
    642 *
    643 * threshY_hysteresis = threshY_raising - threshY_falling
    644 *
    645 * in_illuminance0_thresh[0-3]_hysteresis	0-255
    646 * in_illuminance0_thresh[0-3]_hysteresis	0-255
    647 */
    648static ALS_HYSTERESIS_ATTR_RO(0);
    649static ALS_HYSTERESIS_ATTR_RO(1);
    650static ALS_HYSTERESIS_ATTR_RO(2);
    651static ALS_HYSTERESIS_ATTR_RO(3);
    652
    653#define ILLUMINANCE_ATTR_RO(_name) \
    654	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO, show_##_name, NULL)
    655#define ILLUMINANCE_ATTR_RW(_name) \
    656	DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR, \
    657						show_##_name, store_##_name)
    658/*
    659 * ALS Zone threshold-event enable
    660 *
    661 * in_illuminance0_thresh_either_en		0,1
    662 */
    663static ILLUMINANCE_ATTR_RW(thresh_either_en);
    664
    665/*
    666 * ALS Current Zone
    667 *
    668 * in_illuminance0_zone		0-4
    669 */
    670static ILLUMINANCE_ATTR_RO(zone);
    671
    672static struct attribute *lm3533_als_event_attributes[] = {
    673	&dev_attr_in_illuminance0_thresh_either_en.attr,
    674	&lm3533_als_attr_in_illuminance0_thresh0_falling_value.dev_attr.attr,
    675	&lm3533_als_attr_in_illuminance0_thresh0_hysteresis.dev_attr.attr,
    676	&lm3533_als_attr_in_illuminance0_thresh0_raising_value.dev_attr.attr,
    677	&lm3533_als_attr_in_illuminance0_thresh1_falling_value.dev_attr.attr,
    678	&lm3533_als_attr_in_illuminance0_thresh1_hysteresis.dev_attr.attr,
    679	&lm3533_als_attr_in_illuminance0_thresh1_raising_value.dev_attr.attr,
    680	&lm3533_als_attr_in_illuminance0_thresh2_falling_value.dev_attr.attr,
    681	&lm3533_als_attr_in_illuminance0_thresh2_hysteresis.dev_attr.attr,
    682	&lm3533_als_attr_in_illuminance0_thresh2_raising_value.dev_attr.attr,
    683	&lm3533_als_attr_in_illuminance0_thresh3_falling_value.dev_attr.attr,
    684	&lm3533_als_attr_in_illuminance0_thresh3_hysteresis.dev_attr.attr,
    685	&lm3533_als_attr_in_illuminance0_thresh3_raising_value.dev_attr.attr,
    686	NULL
    687};
    688
    689static const struct attribute_group lm3533_als_event_attribute_group = {
    690	.attrs = lm3533_als_event_attributes
    691};
    692
    693static struct attribute *lm3533_als_attributes[] = {
    694	&dev_attr_in_illuminance0_zone.attr,
    695	&lm3533_als_attr_out_current0_current0_raw.dev_attr.attr,
    696	&lm3533_als_attr_out_current0_current1_raw.dev_attr.attr,
    697	&lm3533_als_attr_out_current0_current2_raw.dev_attr.attr,
    698	&lm3533_als_attr_out_current0_current3_raw.dev_attr.attr,
    699	&lm3533_als_attr_out_current0_current4_raw.dev_attr.attr,
    700	&lm3533_als_attr_out_current1_current0_raw.dev_attr.attr,
    701	&lm3533_als_attr_out_current1_current1_raw.dev_attr.attr,
    702	&lm3533_als_attr_out_current1_current2_raw.dev_attr.attr,
    703	&lm3533_als_attr_out_current1_current3_raw.dev_attr.attr,
    704	&lm3533_als_attr_out_current1_current4_raw.dev_attr.attr,
    705	&lm3533_als_attr_out_current2_current0_raw.dev_attr.attr,
    706	&lm3533_als_attr_out_current2_current1_raw.dev_attr.attr,
    707	&lm3533_als_attr_out_current2_current2_raw.dev_attr.attr,
    708	&lm3533_als_attr_out_current2_current3_raw.dev_attr.attr,
    709	&lm3533_als_attr_out_current2_current4_raw.dev_attr.attr,
    710	NULL
    711};
    712
    713static const struct attribute_group lm3533_als_attribute_group = {
    714	.attrs = lm3533_als_attributes
    715};
    716
    717static int lm3533_als_set_input_mode(struct lm3533_als *als, bool pwm_mode)
    718{
    719	u8 mask = LM3533_ALS_INPUT_MODE_MASK;
    720	u8 val;
    721	int ret;
    722
    723	if (pwm_mode)
    724		val = mask;	/* pwm input */
    725	else
    726		val = 0;	/* analog input */
    727
    728	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, val, mask);
    729	if (ret) {
    730		dev_err(&als->pdev->dev, "failed to set input mode %d\n",
    731								pwm_mode);
    732		return ret;
    733	}
    734
    735	return 0;
    736}
    737
    738static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
    739{
    740	int ret;
    741
    742	if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) {
    743		dev_err(&als->pdev->dev, "invalid resistor value\n");
    744		return -EINVAL;
    745	}
    746
    747	ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
    748	if (ret) {
    749		dev_err(&als->pdev->dev, "failed to set resistor\n");
    750		return ret;
    751	}
    752
    753	return 0;
    754}
    755
    756static int lm3533_als_setup(struct lm3533_als *als,
    757			    struct lm3533_als_platform_data *pdata)
    758{
    759	int ret;
    760
    761	ret = lm3533_als_set_input_mode(als, pdata->pwm_mode);
    762	if (ret)
    763		return ret;
    764
    765	/* ALS input is always high impedance in PWM-mode. */
    766	if (!pdata->pwm_mode) {
    767		ret = lm3533_als_set_resistor(als, pdata->r_select);
    768		if (ret)
    769			return ret;
    770	}
    771
    772	return 0;
    773}
    774
    775static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
    776{
    777	u8 mask = LM3533_ALS_INT_ENABLE_MASK;
    778	int ret;
    779
    780	/* Make sure interrupts are disabled. */
    781	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, 0, mask);
    782	if (ret) {
    783		dev_err(&als->pdev->dev, "failed to disable interrupts\n");
    784		return ret;
    785	}
    786
    787	ret = request_threaded_irq(als->irq, NULL, lm3533_als_isr,
    788					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
    789					dev_name(&als->pdev->dev), dev);
    790	if (ret) {
    791		dev_err(&als->pdev->dev, "failed to request irq %d\n",
    792								als->irq);
    793		return ret;
    794	}
    795
    796	return 0;
    797}
    798
    799static int lm3533_als_enable(struct lm3533_als *als)
    800{
    801	u8 mask = LM3533_ALS_ENABLE_MASK;
    802	int ret;
    803
    804	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, mask, mask);
    805	if (ret)
    806		dev_err(&als->pdev->dev, "failed to enable ALS\n");
    807
    808	return ret;
    809}
    810
    811static int lm3533_als_disable(struct lm3533_als *als)
    812{
    813	u8 mask = LM3533_ALS_ENABLE_MASK;
    814	int ret;
    815
    816	ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, 0, mask);
    817	if (ret)
    818		dev_err(&als->pdev->dev, "failed to disable ALS\n");
    819
    820	return ret;
    821}
    822
    823static const struct iio_info lm3533_als_info = {
    824	.attrs		= &lm3533_als_attribute_group,
    825	.event_attrs	= &lm3533_als_event_attribute_group,
    826	.read_raw	= &lm3533_als_read_raw,
    827};
    828
    829static int lm3533_als_probe(struct platform_device *pdev)
    830{
    831	struct lm3533 *lm3533;
    832	struct lm3533_als_platform_data *pdata;
    833	struct lm3533_als *als;
    834	struct iio_dev *indio_dev;
    835	int ret;
    836
    837	lm3533 = dev_get_drvdata(pdev->dev.parent);
    838	if (!lm3533)
    839		return -EINVAL;
    840
    841	pdata = pdev->dev.platform_data;
    842	if (!pdata) {
    843		dev_err(&pdev->dev, "no platform data\n");
    844		return -EINVAL;
    845	}
    846
    847	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*als));
    848	if (!indio_dev)
    849		return -ENOMEM;
    850
    851	indio_dev->info = &lm3533_als_info;
    852	indio_dev->channels = lm3533_als_channels;
    853	indio_dev->num_channels = ARRAY_SIZE(lm3533_als_channels);
    854	indio_dev->name = dev_name(&pdev->dev);
    855	iio_device_set_parent(indio_dev, pdev->dev.parent);
    856	indio_dev->modes = INDIO_DIRECT_MODE;
    857
    858	als = iio_priv(indio_dev);
    859	als->lm3533 = lm3533;
    860	als->pdev = pdev;
    861	als->irq = lm3533->irq;
    862	atomic_set(&als->zone, 0);
    863	mutex_init(&als->thresh_mutex);
    864
    865	platform_set_drvdata(pdev, indio_dev);
    866
    867	if (als->irq) {
    868		ret = lm3533_als_setup_irq(als, indio_dev);
    869		if (ret)
    870			return ret;
    871	}
    872
    873	ret = lm3533_als_setup(als, pdata);
    874	if (ret)
    875		goto err_free_irq;
    876
    877	ret = lm3533_als_enable(als);
    878	if (ret)
    879		goto err_free_irq;
    880
    881	ret = iio_device_register(indio_dev);
    882	if (ret) {
    883		dev_err(&pdev->dev, "failed to register ALS\n");
    884		goto err_disable;
    885	}
    886
    887	return 0;
    888
    889err_disable:
    890	lm3533_als_disable(als);
    891err_free_irq:
    892	if (als->irq)
    893		free_irq(als->irq, indio_dev);
    894
    895	return ret;
    896}
    897
    898static int lm3533_als_remove(struct platform_device *pdev)
    899{
    900	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
    901	struct lm3533_als *als = iio_priv(indio_dev);
    902
    903	lm3533_als_set_int_mode(indio_dev, false);
    904	iio_device_unregister(indio_dev);
    905	lm3533_als_disable(als);
    906	if (als->irq)
    907		free_irq(als->irq, indio_dev);
    908
    909	return 0;
    910}
    911
    912static struct platform_driver lm3533_als_driver = {
    913	.driver	= {
    914		.name	= "lm3533-als",
    915	},
    916	.probe		= lm3533_als_probe,
    917	.remove		= lm3533_als_remove,
    918};
    919module_platform_driver(lm3533_als_driver);
    920
    921MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
    922MODULE_DESCRIPTION("LM3533 Ambient Light Sensor driver");
    923MODULE_LICENSE("GPL");
    924MODULE_ALIAS("platform:lm3533-als");