xref: /openbmc/linux/drivers/iio/proximity/as3935.c (revision f700e55e)
1d6ad8058SMatt Ranostay // SPDX-License-Identifier: GPL-2.0+
224ddb0e4SMatt Ranostay /*
324ddb0e4SMatt Ranostay  * as3935.c - Support for AS3935 Franklin lightning sensor
424ddb0e4SMatt Ranostay  *
5d6ad8058SMatt Ranostay  * Copyright (C) 2014, 2017-2018
6d6ad8058SMatt Ranostay  * Author: Matt Ranostay <matt.ranostay@konsulko.com>
724ddb0e4SMatt Ranostay  */
824ddb0e4SMatt Ranostay 
924ddb0e4SMatt Ranostay #include <linux/module.h>
1000fa493bSJonathan Cameron #include <linux/mod_devicetable.h>
1124ddb0e4SMatt Ranostay #include <linux/init.h>
1224ddb0e4SMatt Ranostay #include <linux/interrupt.h>
1324ddb0e4SMatt Ranostay #include <linux/delay.h>
1424ddb0e4SMatt Ranostay #include <linux/workqueue.h>
15261ecd47SChristophe JAILLET #include <linux/devm-helpers.h>
1624ddb0e4SMatt Ranostay #include <linux/mutex.h>
1724ddb0e4SMatt Ranostay #include <linux/err.h>
1824ddb0e4SMatt Ranostay #include <linux/irq.h>
1924ddb0e4SMatt Ranostay #include <linux/spi/spi.h>
2024ddb0e4SMatt Ranostay #include <linux/iio/iio.h>
2124ddb0e4SMatt Ranostay #include <linux/iio/sysfs.h>
2224ddb0e4SMatt Ranostay #include <linux/iio/trigger.h>
2324ddb0e4SMatt Ranostay #include <linux/iio/trigger_consumer.h>
2424ddb0e4SMatt Ranostay #include <linux/iio/buffer.h>
2524ddb0e4SMatt Ranostay #include <linux/iio/triggered_buffer.h>
2624ddb0e4SMatt Ranostay 
2724ddb0e4SMatt Ranostay #define AS3935_AFE_GAIN		0x00
2824ddb0e4SMatt Ranostay #define AS3935_AFE_MASK		0x3F
2924ddb0e4SMatt Ranostay #define AS3935_AFE_GAIN_MAX	0x1F
3024ddb0e4SMatt Ranostay #define AS3935_AFE_PWR_BIT	BIT(0)
3124ddb0e4SMatt Ranostay 
32eb35279dSMatt Ranostay #define AS3935_NFLWDTH		0x01
33eb35279dSMatt Ranostay #define AS3935_NFLWDTH_MASK	0x7f
34eb35279dSMatt Ranostay 
3524ddb0e4SMatt Ranostay #define AS3935_INT		0x03
36275292d3SMatt Ranostay #define AS3935_INT_MASK		0x0f
37eb35279dSMatt Ranostay #define AS3935_DISTURB_INT	BIT(2)
3824ddb0e4SMatt Ranostay #define AS3935_EVENT_INT	BIT(3)
39275292d3SMatt Ranostay #define AS3935_NOISE_INT	BIT(0)
4024ddb0e4SMatt Ranostay 
4124ddb0e4SMatt Ranostay #define AS3935_DATA		0x07
4224ddb0e4SMatt Ranostay #define AS3935_DATA_MASK	0x3F
4324ddb0e4SMatt Ranostay 
4424ddb0e4SMatt Ranostay #define AS3935_TUNE_CAP		0x08
45eb35279dSMatt Ranostay #define AS3935_DEFAULTS		0x3C
4624ddb0e4SMatt Ranostay #define AS3935_CALIBRATE	0x3D
4724ddb0e4SMatt Ranostay 
4824ddb0e4SMatt Ranostay #define AS3935_READ_DATA	BIT(14)
4924ddb0e4SMatt Ranostay #define AS3935_ADDRESS(x)	((x) << 8)
5024ddb0e4SMatt Ranostay 
5124ddb0e4SMatt Ranostay #define MAX_PF_CAP		120
5224ddb0e4SMatt Ranostay #define TUNE_CAP_DIV		8
5324ddb0e4SMatt Ranostay 
5424ddb0e4SMatt Ranostay struct as3935_state {
5524ddb0e4SMatt Ranostay 	struct spi_device *spi;
5624ddb0e4SMatt Ranostay 	struct iio_trigger *trig;
5724ddb0e4SMatt Ranostay 	struct mutex lock;
5824ddb0e4SMatt Ranostay 	struct delayed_work work;
5924ddb0e4SMatt Ranostay 
60eb35279dSMatt Ranostay 	unsigned long noise_tripped;
6124ddb0e4SMatt Ranostay 	u32 tune_cap;
62eb35279dSMatt Ranostay 	u32 nflwdth_reg;
6337eb8d8cSJonathan Cameron 	/* Ensure timestamp is naturally aligned */
6437eb8d8cSJonathan Cameron 	struct {
6537eb8d8cSJonathan Cameron 		u8 chan;
6637eb8d8cSJonathan Cameron 		s64 timestamp __aligned(8);
6737eb8d8cSJonathan Cameron 	} scan;
682386c0f8SJonathan Cameron 	u8 buf[2] __aligned(IIO_DMA_MINALIGN);
6924ddb0e4SMatt Ranostay };
7024ddb0e4SMatt Ranostay 
7124ddb0e4SMatt Ranostay static const struct iio_chan_spec as3935_channels[] = {
7224ddb0e4SMatt Ranostay 	{
7324ddb0e4SMatt Ranostay 		.type           = IIO_PROXIMITY,
7424ddb0e4SMatt Ranostay 		.info_mask_separate =
7524ddb0e4SMatt Ranostay 			BIT(IIO_CHAN_INFO_RAW) |
765138806fSMatt Ranostay 			BIT(IIO_CHAN_INFO_PROCESSED) |
775138806fSMatt Ranostay 			BIT(IIO_CHAN_INFO_SCALE),
7824ddb0e4SMatt Ranostay 		.scan_index     = 0,
7924ddb0e4SMatt Ranostay 		.scan_type = {
8024ddb0e4SMatt Ranostay 			.sign           = 'u',
8124ddb0e4SMatt Ranostay 			.realbits       = 6,
8224ddb0e4SMatt Ranostay 			.storagebits    = 8,
8324ddb0e4SMatt Ranostay 		},
8424ddb0e4SMatt Ranostay 	},
8524ddb0e4SMatt Ranostay 	IIO_CHAN_SOFT_TIMESTAMP(1),
8624ddb0e4SMatt Ranostay };
8724ddb0e4SMatt Ranostay 
as3935_read(struct as3935_state * st,unsigned int reg,int * val)8824ddb0e4SMatt Ranostay static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)
8924ddb0e4SMatt Ranostay {
9024ddb0e4SMatt Ranostay 	u8 cmd;
9124ddb0e4SMatt Ranostay 	int ret;
9224ddb0e4SMatt Ranostay 
9324ddb0e4SMatt Ranostay 	cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8;
9424ddb0e4SMatt Ranostay 	ret = spi_w8r8(st->spi, cmd);
9524ddb0e4SMatt Ranostay 	if (ret < 0)
9624ddb0e4SMatt Ranostay 		return ret;
9724ddb0e4SMatt Ranostay 	*val = ret;
9824ddb0e4SMatt Ranostay 
9924ddb0e4SMatt Ranostay 	return 0;
100455f0049SGeorge McCollister }
10124ddb0e4SMatt Ranostay 
as3935_write(struct as3935_state * st,unsigned int reg,unsigned int val)10224ddb0e4SMatt Ranostay static int as3935_write(struct as3935_state *st,
10324ddb0e4SMatt Ranostay 				unsigned int reg,
10424ddb0e4SMatt Ranostay 				unsigned int val)
10524ddb0e4SMatt Ranostay {
10624ddb0e4SMatt Ranostay 	u8 *buf = st->buf;
10724ddb0e4SMatt Ranostay 
10884ca8e36SMatt Ranostay 	buf[0] = AS3935_ADDRESS(reg) >> 8;
10924ddb0e4SMatt Ranostay 	buf[1] = val;
11024ddb0e4SMatt Ranostay 
11124ddb0e4SMatt Ranostay 	return spi_write(st->spi, buf, 2);
112455f0049SGeorge McCollister }
11324ddb0e4SMatt Ranostay 
as3935_sensor_sensitivity_show(struct device * dev,struct device_attribute * attr,char * buf)11424ddb0e4SMatt Ranostay static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
11524ddb0e4SMatt Ranostay 					struct device_attribute *attr,
11624ddb0e4SMatt Ranostay 					char *buf)
11724ddb0e4SMatt Ranostay {
11824ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
11924ddb0e4SMatt Ranostay 	int val, ret;
12024ddb0e4SMatt Ranostay 
12124ddb0e4SMatt Ranostay 	ret = as3935_read(st, AS3935_AFE_GAIN, &val);
12224ddb0e4SMatt Ranostay 	if (ret)
12324ddb0e4SMatt Ranostay 		return ret;
12424ddb0e4SMatt Ranostay 	val = (val & AS3935_AFE_MASK) >> 1;
12524ddb0e4SMatt Ranostay 
1262fd52124SLars-Peter Clausen 	return sysfs_emit(buf, "%d\n", val);
127455f0049SGeorge McCollister }
12824ddb0e4SMatt Ranostay 
as3935_sensor_sensitivity_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t len)12924ddb0e4SMatt Ranostay static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
13024ddb0e4SMatt Ranostay 					struct device_attribute *attr,
13124ddb0e4SMatt Ranostay 					const char *buf, size_t len)
13224ddb0e4SMatt Ranostay {
13324ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
13424ddb0e4SMatt Ranostay 	unsigned long val;
13524ddb0e4SMatt Ranostay 	int ret;
13624ddb0e4SMatt Ranostay 
13791b49aadSLars-Peter Clausen 	ret = kstrtoul(buf, 10, &val);
13824ddb0e4SMatt Ranostay 	if (ret)
13924ddb0e4SMatt Ranostay 		return -EINVAL;
14024ddb0e4SMatt Ranostay 
14124ddb0e4SMatt Ranostay 	if (val > AS3935_AFE_GAIN_MAX)
14224ddb0e4SMatt Ranostay 		return -EINVAL;
14324ddb0e4SMatt Ranostay 
14424ddb0e4SMatt Ranostay 	as3935_write(st, AS3935_AFE_GAIN, val << 1);
14524ddb0e4SMatt Ranostay 
14624ddb0e4SMatt Ranostay 	return len;
147455f0049SGeorge McCollister }
14824ddb0e4SMatt Ranostay 
as3935_noise_level_tripped_show(struct device * dev,struct device_attribute * attr,char * buf)149eb35279dSMatt Ranostay static ssize_t as3935_noise_level_tripped_show(struct device *dev,
150eb35279dSMatt Ranostay 					struct device_attribute *attr,
151eb35279dSMatt Ranostay 					char *buf)
152eb35279dSMatt Ranostay {
153eb35279dSMatt Ranostay 	struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
154eb35279dSMatt Ranostay 	int ret;
155eb35279dSMatt Ranostay 
156eb35279dSMatt Ranostay 	mutex_lock(&st->lock);
1572fd52124SLars-Peter Clausen 	ret = sysfs_emit(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ));
158eb35279dSMatt Ranostay 	mutex_unlock(&st->lock);
159eb35279dSMatt Ranostay 
160eb35279dSMatt Ranostay 	return ret;
161eb35279dSMatt Ranostay }
162eb35279dSMatt Ranostay 
16324ddb0e4SMatt Ranostay static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
16424ddb0e4SMatt Ranostay 	as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);
16524ddb0e4SMatt Ranostay 
166eb35279dSMatt Ranostay static IIO_DEVICE_ATTR(noise_level_tripped, S_IRUGO,
167eb35279dSMatt Ranostay 	as3935_noise_level_tripped_show, NULL, 0);
16824ddb0e4SMatt Ranostay 
16924ddb0e4SMatt Ranostay static struct attribute *as3935_attributes[] = {
17024ddb0e4SMatt Ranostay 	&iio_dev_attr_sensor_sensitivity.dev_attr.attr,
171eb35279dSMatt Ranostay 	&iio_dev_attr_noise_level_tripped.dev_attr.attr,
17224ddb0e4SMatt Ranostay 	NULL,
17324ddb0e4SMatt Ranostay };
17424ddb0e4SMatt Ranostay 
1757ab89e1eSsimran singhal static const struct attribute_group as3935_attribute_group = {
17624ddb0e4SMatt Ranostay 	.attrs = as3935_attributes,
17724ddb0e4SMatt Ranostay };
17824ddb0e4SMatt Ranostay 
as3935_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long m)17924ddb0e4SMatt Ranostay static int as3935_read_raw(struct iio_dev *indio_dev,
18024ddb0e4SMatt Ranostay 			   struct iio_chan_spec const *chan,
18124ddb0e4SMatt Ranostay 			   int *val,
18224ddb0e4SMatt Ranostay 			   int *val2,
18324ddb0e4SMatt Ranostay 			   long m)
18424ddb0e4SMatt Ranostay {
18524ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(indio_dev);
18624ddb0e4SMatt Ranostay 	int ret;
18724ddb0e4SMatt Ranostay 
18824ddb0e4SMatt Ranostay 
18924ddb0e4SMatt Ranostay 	switch (m) {
19024ddb0e4SMatt Ranostay 	case IIO_CHAN_INFO_PROCESSED:
19124ddb0e4SMatt Ranostay 	case IIO_CHAN_INFO_RAW:
19224ddb0e4SMatt Ranostay 		*val2 = 0;
19324ddb0e4SMatt Ranostay 		ret = as3935_read(st, AS3935_DATA, val);
19424ddb0e4SMatt Ranostay 		if (ret)
19524ddb0e4SMatt Ranostay 			return ret;
19624ddb0e4SMatt Ranostay 
19724ddb0e4SMatt Ranostay 		/* storm out of range */
19824ddb0e4SMatt Ranostay 		if (*val == AS3935_DATA_MASK)
19924ddb0e4SMatt Ranostay 			return -EINVAL;
2005138806fSMatt Ranostay 
201d532e5b2SMatt Ranostay 		if (m == IIO_CHAN_INFO_RAW)
202d532e5b2SMatt Ranostay 			return IIO_VAL_INT;
203d532e5b2SMatt Ranostay 
2045138806fSMatt Ranostay 		if (m == IIO_CHAN_INFO_PROCESSED)
20524ddb0e4SMatt Ranostay 			*val *= 1000;
20624ddb0e4SMatt Ranostay 		break;
2075138806fSMatt Ranostay 	case IIO_CHAN_INFO_SCALE:
2085138806fSMatt Ranostay 		*val = 1000;
2095138806fSMatt Ranostay 		break;
21024ddb0e4SMatt Ranostay 	default:
21124ddb0e4SMatt Ranostay 		return -EINVAL;
21224ddb0e4SMatt Ranostay 	}
21324ddb0e4SMatt Ranostay 
21424ddb0e4SMatt Ranostay 	return IIO_VAL_INT;
21524ddb0e4SMatt Ranostay }
21624ddb0e4SMatt Ranostay 
21724ddb0e4SMatt Ranostay static const struct iio_info as3935_info = {
21824ddb0e4SMatt Ranostay 	.attrs = &as3935_attribute_group,
21924ddb0e4SMatt Ranostay 	.read_raw = &as3935_read_raw,
22024ddb0e4SMatt Ranostay };
22124ddb0e4SMatt Ranostay 
as3935_trigger_handler(int irq,void * private)22224ddb0e4SMatt Ranostay static irqreturn_t as3935_trigger_handler(int irq, void *private)
22324ddb0e4SMatt Ranostay {
22424ddb0e4SMatt Ranostay 	struct iio_poll_func *pf = private;
22524ddb0e4SMatt Ranostay 	struct iio_dev *indio_dev = pf->indio_dev;
22624ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(indio_dev);
22724ddb0e4SMatt Ranostay 	int val, ret;
22824ddb0e4SMatt Ranostay 
22924ddb0e4SMatt Ranostay 	ret = as3935_read(st, AS3935_DATA, &val);
23024ddb0e4SMatt Ranostay 	if (ret)
23124ddb0e4SMatt Ranostay 		goto err_read;
23224ddb0e4SMatt Ranostay 
23337eb8d8cSJonathan Cameron 	st->scan.chan = val & AS3935_DATA_MASK;
23437eb8d8cSJonathan Cameron 	iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
2359122b54fSMatt Ranostay 					   iio_get_time_ns(indio_dev));
23624ddb0e4SMatt Ranostay err_read:
23724ddb0e4SMatt Ranostay 	iio_trigger_notify_done(indio_dev->trig);
23824ddb0e4SMatt Ranostay 
23924ddb0e4SMatt Ranostay 	return IRQ_HANDLED;
240455f0049SGeorge McCollister }
24124ddb0e4SMatt Ranostay 
as3935_event_work(struct work_struct * work)24224ddb0e4SMatt Ranostay static void as3935_event_work(struct work_struct *work)
24324ddb0e4SMatt Ranostay {
24424ddb0e4SMatt Ranostay 	struct as3935_state *st;
24524ddb0e4SMatt Ranostay 	int val;
24622ed1a1cSArnd Bergmann 	int ret;
24724ddb0e4SMatt Ranostay 
24824ddb0e4SMatt Ranostay 	st = container_of(work, struct as3935_state, work.work);
24924ddb0e4SMatt Ranostay 
25022ed1a1cSArnd Bergmann 	ret = as3935_read(st, AS3935_INT, &val);
25122ed1a1cSArnd Bergmann 	if (ret) {
25222ed1a1cSArnd Bergmann 		dev_warn(&st->spi->dev, "read error\n");
25322ed1a1cSArnd Bergmann 		return;
25422ed1a1cSArnd Bergmann 	}
25522ed1a1cSArnd Bergmann 
25624ddb0e4SMatt Ranostay 	val &= AS3935_INT_MASK;
25724ddb0e4SMatt Ranostay 
25824ddb0e4SMatt Ranostay 	switch (val) {
25924ddb0e4SMatt Ranostay 	case AS3935_EVENT_INT:
260*f700e55eSMehdi Djait 		iio_trigger_poll_nested(st->trig);
26124ddb0e4SMatt Ranostay 		break;
262eb35279dSMatt Ranostay 	case AS3935_DISTURB_INT:
26324ddb0e4SMatt Ranostay 	case AS3935_NOISE_INT:
264eb35279dSMatt Ranostay 		mutex_lock(&st->lock);
265eb35279dSMatt Ranostay 		st->noise_tripped = jiffies;
266eb35279dSMatt Ranostay 		mutex_unlock(&st->lock);
26722ed1a1cSArnd Bergmann 		dev_warn(&st->spi->dev, "noise level is too high\n");
26824ddb0e4SMatt Ranostay 		break;
26924ddb0e4SMatt Ranostay 	}
270455f0049SGeorge McCollister }
27124ddb0e4SMatt Ranostay 
as3935_interrupt_handler(int irq,void * private)27224ddb0e4SMatt Ranostay static irqreturn_t as3935_interrupt_handler(int irq, void *private)
27324ddb0e4SMatt Ranostay {
27424ddb0e4SMatt Ranostay 	struct iio_dev *indio_dev = private;
27524ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(indio_dev);
27624ddb0e4SMatt Ranostay 
27724ddb0e4SMatt Ranostay 	/*
27824ddb0e4SMatt Ranostay 	 * Delay work for >2 milliseconds after an interrupt to allow
27924ddb0e4SMatt Ranostay 	 * estimated distance to recalculated.
28024ddb0e4SMatt Ranostay 	 */
28124ddb0e4SMatt Ranostay 
28224ddb0e4SMatt Ranostay 	schedule_delayed_work(&st->work, msecs_to_jiffies(3));
28324ddb0e4SMatt Ranostay 
28424ddb0e4SMatt Ranostay 	return IRQ_HANDLED;
28524ddb0e4SMatt Ranostay }
28624ddb0e4SMatt Ranostay 
calibrate_as3935(struct as3935_state * st)28724ddb0e4SMatt Ranostay static void calibrate_as3935(struct as3935_state *st)
28824ddb0e4SMatt Ranostay {
289eb35279dSMatt Ranostay 	as3935_write(st, AS3935_DEFAULTS, 0x96);
29024ddb0e4SMatt Ranostay 	as3935_write(st, AS3935_CALIBRATE, 0x96);
29124ddb0e4SMatt Ranostay 	as3935_write(st, AS3935_TUNE_CAP,
29224ddb0e4SMatt Ranostay 		BIT(5) | (st->tune_cap / TUNE_CAP_DIV));
29324ddb0e4SMatt Ranostay 
29424ddb0e4SMatt Ranostay 	mdelay(2);
29524ddb0e4SMatt Ranostay 	as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV));
296eb35279dSMatt Ranostay 	as3935_write(st, AS3935_NFLWDTH, st->nflwdth_reg);
29724ddb0e4SMatt Ranostay }
29824ddb0e4SMatt Ranostay 
as3935_suspend(struct device * dev)2999d9f7800SLars-Peter Clausen static int as3935_suspend(struct device *dev)
30024ddb0e4SMatt Ranostay {
3019d9f7800SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
30224ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(indio_dev);
30324ddb0e4SMatt Ranostay 	int val, ret;
30424ddb0e4SMatt Ranostay 
30524ddb0e4SMatt Ranostay 	mutex_lock(&st->lock);
30624ddb0e4SMatt Ranostay 	ret = as3935_read(st, AS3935_AFE_GAIN, &val);
30724ddb0e4SMatt Ranostay 	if (ret)
30824ddb0e4SMatt Ranostay 		goto err_suspend;
30924ddb0e4SMatt Ranostay 	val |= AS3935_AFE_PWR_BIT;
31024ddb0e4SMatt Ranostay 
31124ddb0e4SMatt Ranostay 	ret = as3935_write(st, AS3935_AFE_GAIN, val);
31224ddb0e4SMatt Ranostay 
31324ddb0e4SMatt Ranostay err_suspend:
31424ddb0e4SMatt Ranostay 	mutex_unlock(&st->lock);
31524ddb0e4SMatt Ranostay 
31624ddb0e4SMatt Ranostay 	return ret;
31724ddb0e4SMatt Ranostay }
31824ddb0e4SMatt Ranostay 
as3935_resume(struct device * dev)3199d9f7800SLars-Peter Clausen static int as3935_resume(struct device *dev)
32024ddb0e4SMatt Ranostay {
3219d9f7800SLars-Peter Clausen 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
32224ddb0e4SMatt Ranostay 	struct as3935_state *st = iio_priv(indio_dev);
32324ddb0e4SMatt Ranostay 	int val, ret;
32424ddb0e4SMatt Ranostay 
32524ddb0e4SMatt Ranostay 	mutex_lock(&st->lock);
32624ddb0e4SMatt Ranostay 	ret = as3935_read(st, AS3935_AFE_GAIN, &val);
32724ddb0e4SMatt Ranostay 	if (ret)
32824ddb0e4SMatt Ranostay 		goto err_resume;
32924ddb0e4SMatt Ranostay 	val &= ~AS3935_AFE_PWR_BIT;
33024ddb0e4SMatt Ranostay 	ret = as3935_write(st, AS3935_AFE_GAIN, val);
33124ddb0e4SMatt Ranostay 
3326272c0deSMatt Ranostay 	calibrate_as3935(st);
3336272c0deSMatt Ranostay 
33424ddb0e4SMatt Ranostay err_resume:
33524ddb0e4SMatt Ranostay 	mutex_unlock(&st->lock);
33624ddb0e4SMatt Ranostay 
33724ddb0e4SMatt Ranostay 	return ret;
33824ddb0e4SMatt Ranostay }
3399d9f7800SLars-Peter Clausen 
340bff03d5cSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
34124ddb0e4SMatt Ranostay 
as3935_probe(struct spi_device * spi)34224ddb0e4SMatt Ranostay static int as3935_probe(struct spi_device *spi)
34324ddb0e4SMatt Ranostay {
344c457b7efSJonathan Cameron 	struct device *dev = &spi->dev;
34524ddb0e4SMatt Ranostay 	struct iio_dev *indio_dev;
34624ddb0e4SMatt Ranostay 	struct iio_trigger *trig;
34724ddb0e4SMatt Ranostay 	struct as3935_state *st;
34824ddb0e4SMatt Ranostay 	int ret;
34924ddb0e4SMatt Ranostay 
35024ddb0e4SMatt Ranostay 	/* Be sure lightning event interrupt is specified */
35124ddb0e4SMatt Ranostay 	if (!spi->irq) {
352c457b7efSJonathan Cameron 		dev_err(dev, "unable to get event interrupt\n");
35324ddb0e4SMatt Ranostay 		return -EINVAL;
35424ddb0e4SMatt Ranostay 	}
35524ddb0e4SMatt Ranostay 
356c457b7efSJonathan Cameron 	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
35724ddb0e4SMatt Ranostay 	if (!indio_dev)
35824ddb0e4SMatt Ranostay 		return -ENOMEM;
35924ddb0e4SMatt Ranostay 
36024ddb0e4SMatt Ranostay 	st = iio_priv(indio_dev);
36124ddb0e4SMatt Ranostay 	st->spi = spi;
36224ddb0e4SMatt Ranostay 
36324ddb0e4SMatt Ranostay 	spi_set_drvdata(spi, indio_dev);
36424ddb0e4SMatt Ranostay 	mutex_init(&st->lock);
36524ddb0e4SMatt Ranostay 
36600fa493bSJonathan Cameron 	ret = device_property_read_u32(dev,
36724ddb0e4SMatt Ranostay 			"ams,tuning-capacitor-pf", &st->tune_cap);
36824ddb0e4SMatt Ranostay 	if (ret) {
36924ddb0e4SMatt Ranostay 		st->tune_cap = 0;
370c457b7efSJonathan Cameron 		dev_warn(dev, "no tuning-capacitor-pf set, defaulting to %d",
37124ddb0e4SMatt Ranostay 			st->tune_cap);
37224ddb0e4SMatt Ranostay 	}
37324ddb0e4SMatt Ranostay 
37424ddb0e4SMatt Ranostay 	if (st->tune_cap > MAX_PF_CAP) {
375c457b7efSJonathan Cameron 		dev_err(dev, "wrong tuning-capacitor-pf setting of %d\n",
37624ddb0e4SMatt Ranostay 			st->tune_cap);
37724ddb0e4SMatt Ranostay 		return -EINVAL;
37824ddb0e4SMatt Ranostay 	}
37924ddb0e4SMatt Ranostay 
38000fa493bSJonathan Cameron 	ret = device_property_read_u32(dev,
381eb35279dSMatt Ranostay 			"ams,nflwdth", &st->nflwdth_reg);
382eb35279dSMatt Ranostay 	if (!ret && st->nflwdth_reg > AS3935_NFLWDTH_MASK) {
383c457b7efSJonathan Cameron 		dev_err(dev, "invalid nflwdth setting of %d\n",
384eb35279dSMatt Ranostay 			st->nflwdth_reg);
385eb35279dSMatt Ranostay 		return -EINVAL;
386eb35279dSMatt Ranostay 	}
387eb35279dSMatt Ranostay 
38824ddb0e4SMatt Ranostay 	indio_dev->name = spi_get_device_id(spi)->name;
38924ddb0e4SMatt Ranostay 	indio_dev->channels = as3935_channels;
39024ddb0e4SMatt Ranostay 	indio_dev->num_channels = ARRAY_SIZE(as3935_channels);
39124ddb0e4SMatt Ranostay 	indio_dev->modes = INDIO_DIRECT_MODE;
39224ddb0e4SMatt Ranostay 	indio_dev->info = &as3935_info;
39324ddb0e4SMatt Ranostay 
394c457b7efSJonathan Cameron 	trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
39515ea2878SJonathan Cameron 				      indio_dev->name,
39615ea2878SJonathan Cameron 				      iio_device_id(indio_dev));
39724ddb0e4SMatt Ranostay 
39824ddb0e4SMatt Ranostay 	if (!trig)
39924ddb0e4SMatt Ranostay 		return -ENOMEM;
40024ddb0e4SMatt Ranostay 
40124ddb0e4SMatt Ranostay 	st->trig = trig;
402eb35279dSMatt Ranostay 	st->noise_tripped = jiffies - HZ;
40324ddb0e4SMatt Ranostay 	iio_trigger_set_drvdata(trig, indio_dev);
40424ddb0e4SMatt Ranostay 
405c457b7efSJonathan Cameron 	ret = devm_iio_trigger_register(dev, trig);
40624ddb0e4SMatt Ranostay 	if (ret) {
407c457b7efSJonathan Cameron 		dev_err(dev, "failed to register trigger\n");
40824ddb0e4SMatt Ranostay 		return ret;
40924ddb0e4SMatt Ranostay 	}
41024ddb0e4SMatt Ranostay 
411c457b7efSJonathan Cameron 	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
41211362b7aSSven Van Asbroeck 					      iio_pollfunc_store_time,
41311362b7aSSven Van Asbroeck 					      as3935_trigger_handler, NULL);
41424ddb0e4SMatt Ranostay 
41524ddb0e4SMatt Ranostay 	if (ret) {
416c457b7efSJonathan Cameron 		dev_err(dev, "cannot setup iio trigger\n");
41711362b7aSSven Van Asbroeck 		return ret;
41824ddb0e4SMatt Ranostay 	}
41924ddb0e4SMatt Ranostay 
42024ddb0e4SMatt Ranostay 	calibrate_as3935(st);
42124ddb0e4SMatt Ranostay 
422261ecd47SChristophe JAILLET 	ret = devm_delayed_work_autocancel(dev, &st->work, as3935_event_work);
42311362b7aSSven Van Asbroeck 	if (ret)
42411362b7aSSven Van Asbroeck 		return ret;
42511362b7aSSven Van Asbroeck 
426c457b7efSJonathan Cameron 	ret = devm_request_irq(dev, spi->irq,
42724ddb0e4SMatt Ranostay 				&as3935_interrupt_handler,
42824ddb0e4SMatt Ranostay 				IRQF_TRIGGER_RISING,
429c457b7efSJonathan Cameron 				dev_name(dev),
43024ddb0e4SMatt Ranostay 				indio_dev);
43124ddb0e4SMatt Ranostay 
43224ddb0e4SMatt Ranostay 	if (ret) {
433c457b7efSJonathan Cameron 		dev_err(dev, "unable to request irq\n");
43424ddb0e4SMatt Ranostay 		return ret;
435455f0049SGeorge McCollister 	}
43624ddb0e4SMatt Ranostay 
437c457b7efSJonathan Cameron 	ret = devm_iio_device_register(dev, indio_dev);
43811362b7aSSven Van Asbroeck 	if (ret < 0) {
439c457b7efSJonathan Cameron 		dev_err(dev, "unable to register device\n");
44011362b7aSSven Van Asbroeck 		return ret;
44111362b7aSSven Van Asbroeck 	}
44224ddb0e4SMatt Ranostay 	return 0;
443455f0049SGeorge McCollister }
44424ddb0e4SMatt Ranostay 
4458b7c826dSJavier Martinez Canillas static const struct of_device_id as3935_of_match[] = {
4468b7c826dSJavier Martinez Canillas 	{ .compatible = "ams,as3935", },
4478b7c826dSJavier Martinez Canillas 	{ /* sentinel */ },
4488b7c826dSJavier Martinez Canillas };
4498b7c826dSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, as3935_of_match);
4508b7c826dSJavier Martinez Canillas 
45124ddb0e4SMatt Ranostay static const struct spi_device_id as3935_id[] = {
45224ddb0e4SMatt Ranostay 	{"as3935", 0},
45324ddb0e4SMatt Ranostay 	{},
45424ddb0e4SMatt Ranostay };
45524ddb0e4SMatt Ranostay MODULE_DEVICE_TABLE(spi, as3935_id);
45624ddb0e4SMatt Ranostay 
45724ddb0e4SMatt Ranostay static struct spi_driver as3935_driver = {
45824ddb0e4SMatt Ranostay 	.driver = {
45924ddb0e4SMatt Ranostay 		.name	= "as3935",
46000fa493bSJonathan Cameron 		.of_match_table = as3935_of_match,
461bff03d5cSJonathan Cameron 		.pm	= pm_sleep_ptr(&as3935_pm_ops),
46224ddb0e4SMatt Ranostay 	},
46324ddb0e4SMatt Ranostay 	.probe		= as3935_probe,
46424ddb0e4SMatt Ranostay 	.id_table	= as3935_id,
46524ddb0e4SMatt Ranostay };
46624ddb0e4SMatt Ranostay module_spi_driver(as3935_driver);
46724ddb0e4SMatt Ranostay 
468d6ad8058SMatt Ranostay MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");
46924ddb0e4SMatt Ranostay MODULE_DESCRIPTION("AS3935 lightning sensor");
47024ddb0e4SMatt Ranostay MODULE_LICENSE("GPL");
471