brintos

brintos / linux-shallow public Read only

0
0
Text · 10.2 KiB · 96fa974 Raw
471 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * as3935.c - Support for AS3935 Franklin lightning sensor4 *5 * Copyright (C) 2014, 2017-20186 * Author: Matt Ranostay <matt.ranostay@konsulko.com>7 */8 9#include <linux/module.h>10#include <linux/mod_devicetable.h>11#include <linux/init.h>12#include <linux/interrupt.h>13#include <linux/delay.h>14#include <linux/workqueue.h>15#include <linux/devm-helpers.h>16#include <linux/mutex.h>17#include <linux/err.h>18#include <linux/irq.h>19#include <linux/spi/spi.h>20#include <linux/iio/iio.h>21#include <linux/iio/sysfs.h>22#include <linux/iio/trigger.h>23#include <linux/iio/trigger_consumer.h>24#include <linux/iio/buffer.h>25#include <linux/iio/triggered_buffer.h>26 27#define AS3935_AFE_GAIN		0x0028#define AS3935_AFE_MASK		0x3F29#define AS3935_AFE_GAIN_MAX	0x1F30#define AS3935_AFE_PWR_BIT	BIT(0)31 32#define AS3935_NFLWDTH		0x0133#define AS3935_NFLWDTH_MASK	0x7f34 35#define AS3935_INT		0x0336#define AS3935_INT_MASK		0x0f37#define AS3935_DISTURB_INT	BIT(2)38#define AS3935_EVENT_INT	BIT(3)39#define AS3935_NOISE_INT	BIT(0)40 41#define AS3935_DATA		0x0742#define AS3935_DATA_MASK	0x3F43 44#define AS3935_TUNE_CAP		0x0845#define AS3935_DEFAULTS		0x3C46#define AS3935_CALIBRATE	0x3D47 48#define AS3935_READ_DATA	BIT(14)49#define AS3935_ADDRESS(x)	((x) << 8)50 51#define MAX_PF_CAP		12052#define TUNE_CAP_DIV		853 54struct as3935_state {55	struct spi_device *spi;56	struct iio_trigger *trig;57	struct mutex lock;58	struct delayed_work work;59 60	unsigned long noise_tripped;61	u32 tune_cap;62	u32 nflwdth_reg;63	/* Ensure timestamp is naturally aligned */64	struct {65		u8 chan;66		s64 timestamp __aligned(8);67	} scan;68	u8 buf[2] __aligned(IIO_DMA_MINALIGN);69};70 71static const struct iio_chan_spec as3935_channels[] = {72	{73		.type           = IIO_PROXIMITY,74		.info_mask_separate =75			BIT(IIO_CHAN_INFO_RAW) |76			BIT(IIO_CHAN_INFO_PROCESSED) |77			BIT(IIO_CHAN_INFO_SCALE),78		.scan_index     = 0,79		.scan_type = {80			.sign           = 'u',81			.realbits       = 6,82			.storagebits    = 8,83		},84	},85	IIO_CHAN_SOFT_TIMESTAMP(1),86};87 88static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)89{90	u8 cmd;91	int ret;92 93	cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8;94	ret = spi_w8r8(st->spi, cmd);95	if (ret < 0)96		return ret;97	*val = ret;98 99	return 0;100}101 102static int as3935_write(struct as3935_state *st,103				unsigned int reg,104				unsigned int val)105{106	u8 *buf = st->buf;107 108	buf[0] = AS3935_ADDRESS(reg) >> 8;109	buf[1] = val;110 111	return spi_write(st->spi, buf, 2);112}113 114static ssize_t as3935_sensor_sensitivity_show(struct device *dev,115					struct device_attribute *attr,116					char *buf)117{118	struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));119	int val, ret;120 121	ret = as3935_read(st, AS3935_AFE_GAIN, &val);122	if (ret)123		return ret;124	val = (val & AS3935_AFE_MASK) >> 1;125 126	return sysfs_emit(buf, "%d\n", val);127}128 129static ssize_t as3935_sensor_sensitivity_store(struct device *dev,130					struct device_attribute *attr,131					const char *buf, size_t len)132{133	struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));134	unsigned long val;135	int ret;136 137	ret = kstrtoul(buf, 10, &val);138	if (ret)139		return -EINVAL;140 141	if (val > AS3935_AFE_GAIN_MAX)142		return -EINVAL;143 144	as3935_write(st, AS3935_AFE_GAIN, val << 1);145 146	return len;147}148 149static ssize_t as3935_noise_level_tripped_show(struct device *dev,150					struct device_attribute *attr,151					char *buf)152{153	struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));154	int ret;155 156	mutex_lock(&st->lock);157	ret = sysfs_emit(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ));158	mutex_unlock(&st->lock);159 160	return ret;161}162 163static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,164	as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);165 166static IIO_DEVICE_ATTR(noise_level_tripped, S_IRUGO,167	as3935_noise_level_tripped_show, NULL, 0);168 169static struct attribute *as3935_attributes[] = {170	&iio_dev_attr_sensor_sensitivity.dev_attr.attr,171	&iio_dev_attr_noise_level_tripped.dev_attr.attr,172	NULL,173};174 175static const struct attribute_group as3935_attribute_group = {176	.attrs = as3935_attributes,177};178 179static int as3935_read_raw(struct iio_dev *indio_dev,180			   struct iio_chan_spec const *chan,181			   int *val,182			   int *val2,183			   long m)184{185	struct as3935_state *st = iio_priv(indio_dev);186	int ret;187 188 189	switch (m) {190	case IIO_CHAN_INFO_PROCESSED:191	case IIO_CHAN_INFO_RAW:192		*val2 = 0;193		ret = as3935_read(st, AS3935_DATA, val);194		if (ret)195			return ret;196 197		/* storm out of range */198		if (*val == AS3935_DATA_MASK)199			return -EINVAL;200 201		if (m == IIO_CHAN_INFO_RAW)202			return IIO_VAL_INT;203 204		if (m == IIO_CHAN_INFO_PROCESSED)205			*val *= 1000;206		break;207	case IIO_CHAN_INFO_SCALE:208		*val = 1000;209		break;210	default:211		return -EINVAL;212	}213 214	return IIO_VAL_INT;215}216 217static const struct iio_info as3935_info = {218	.attrs = &as3935_attribute_group,219	.read_raw = &as3935_read_raw,220};221 222static irqreturn_t as3935_trigger_handler(int irq, void *private)223{224	struct iio_poll_func *pf = private;225	struct iio_dev *indio_dev = pf->indio_dev;226	struct as3935_state *st = iio_priv(indio_dev);227	int val, ret;228 229	ret = as3935_read(st, AS3935_DATA, &val);230	if (ret)231		goto err_read;232 233	st->scan.chan = val & AS3935_DATA_MASK;234	iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,235					   iio_get_time_ns(indio_dev));236err_read:237	iio_trigger_notify_done(indio_dev->trig);238 239	return IRQ_HANDLED;240}241 242static void as3935_event_work(struct work_struct *work)243{244	struct as3935_state *st;245	int val;246	int ret;247 248	st = container_of(work, struct as3935_state, work.work);249 250	ret = as3935_read(st, AS3935_INT, &val);251	if (ret) {252		dev_warn(&st->spi->dev, "read error\n");253		return;254	}255 256	val &= AS3935_INT_MASK;257 258	switch (val) {259	case AS3935_EVENT_INT:260		iio_trigger_poll_nested(st->trig);261		break;262	case AS3935_DISTURB_INT:263	case AS3935_NOISE_INT:264		mutex_lock(&st->lock);265		st->noise_tripped = jiffies;266		mutex_unlock(&st->lock);267		dev_warn(&st->spi->dev, "noise level is too high\n");268		break;269	}270}271 272static irqreturn_t as3935_interrupt_handler(int irq, void *private)273{274	struct iio_dev *indio_dev = private;275	struct as3935_state *st = iio_priv(indio_dev);276 277	/*278	 * Delay work for >2 milliseconds after an interrupt to allow279	 * estimated distance to recalculated.280	 */281 282	schedule_delayed_work(&st->work, msecs_to_jiffies(3));283 284	return IRQ_HANDLED;285}286 287static void calibrate_as3935(struct as3935_state *st)288{289	as3935_write(st, AS3935_DEFAULTS, 0x96);290	as3935_write(st, AS3935_CALIBRATE, 0x96);291	as3935_write(st, AS3935_TUNE_CAP,292		BIT(5) | (st->tune_cap / TUNE_CAP_DIV));293 294	mdelay(2);295	as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV));296	as3935_write(st, AS3935_NFLWDTH, st->nflwdth_reg);297}298 299static int as3935_suspend(struct device *dev)300{301	struct iio_dev *indio_dev = dev_get_drvdata(dev);302	struct as3935_state *st = iio_priv(indio_dev);303	int val, ret;304 305	mutex_lock(&st->lock);306	ret = as3935_read(st, AS3935_AFE_GAIN, &val);307	if (ret)308		goto err_suspend;309	val |= AS3935_AFE_PWR_BIT;310 311	ret = as3935_write(st, AS3935_AFE_GAIN, val);312 313err_suspend:314	mutex_unlock(&st->lock);315 316	return ret;317}318 319static int as3935_resume(struct device *dev)320{321	struct iio_dev *indio_dev = dev_get_drvdata(dev);322	struct as3935_state *st = iio_priv(indio_dev);323	int val, ret;324 325	mutex_lock(&st->lock);326	ret = as3935_read(st, AS3935_AFE_GAIN, &val);327	if (ret)328		goto err_resume;329	val &= ~AS3935_AFE_PWR_BIT;330	ret = as3935_write(st, AS3935_AFE_GAIN, val);331 332	calibrate_as3935(st);333 334err_resume:335	mutex_unlock(&st->lock);336 337	return ret;338}339 340static DEFINE_SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);341 342static int as3935_probe(struct spi_device *spi)343{344	struct device *dev = &spi->dev;345	struct iio_dev *indio_dev;346	struct iio_trigger *trig;347	struct as3935_state *st;348	int ret;349 350	/* Be sure lightning event interrupt is specified */351	if (!spi->irq) {352		dev_err(dev, "unable to get event interrupt\n");353		return -EINVAL;354	}355 356	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));357	if (!indio_dev)358		return -ENOMEM;359 360	st = iio_priv(indio_dev);361	st->spi = spi;362 363	spi_set_drvdata(spi, indio_dev);364	mutex_init(&st->lock);365 366	ret = device_property_read_u32(dev,367			"ams,tuning-capacitor-pf", &st->tune_cap);368	if (ret) {369		st->tune_cap = 0;370		dev_warn(dev, "no tuning-capacitor-pf set, defaulting to %d",371			st->tune_cap);372	}373 374	if (st->tune_cap > MAX_PF_CAP) {375		dev_err(dev, "wrong tuning-capacitor-pf setting of %d\n",376			st->tune_cap);377		return -EINVAL;378	}379 380	ret = device_property_read_u32(dev,381			"ams,nflwdth", &st->nflwdth_reg);382	if (!ret && st->nflwdth_reg > AS3935_NFLWDTH_MASK) {383		dev_err(dev, "invalid nflwdth setting of %d\n",384			st->nflwdth_reg);385		return -EINVAL;386	}387 388	indio_dev->name = spi_get_device_id(spi)->name;389	indio_dev->channels = as3935_channels;390	indio_dev->num_channels = ARRAY_SIZE(as3935_channels);391	indio_dev->modes = INDIO_DIRECT_MODE;392	indio_dev->info = &as3935_info;393 394	trig = devm_iio_trigger_alloc(dev, "%s-dev%d",395				      indio_dev->name,396				      iio_device_id(indio_dev));397 398	if (!trig)399		return -ENOMEM;400 401	st->trig = trig;402	st->noise_tripped = jiffies - HZ;403	iio_trigger_set_drvdata(trig, indio_dev);404 405	ret = devm_iio_trigger_register(dev, trig);406	if (ret) {407		dev_err(dev, "failed to register trigger\n");408		return ret;409	}410 411	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,412					      iio_pollfunc_store_time,413					      as3935_trigger_handler, NULL);414 415	if (ret) {416		dev_err(dev, "cannot setup iio trigger\n");417		return ret;418	}419 420	calibrate_as3935(st);421 422	ret = devm_delayed_work_autocancel(dev, &st->work, as3935_event_work);423	if (ret)424		return ret;425 426	ret = devm_request_irq(dev, spi->irq,427				&as3935_interrupt_handler,428				IRQF_TRIGGER_RISING,429				dev_name(dev),430				indio_dev);431 432	if (ret) {433		dev_err(dev, "unable to request irq\n");434		return ret;435	}436 437	ret = devm_iio_device_register(dev, indio_dev);438	if (ret < 0) {439		dev_err(dev, "unable to register device\n");440		return ret;441	}442	return 0;443}444 445static const struct of_device_id as3935_of_match[] = {446	{ .compatible = "ams,as3935", },447	{ /* sentinel */ },448};449MODULE_DEVICE_TABLE(of, as3935_of_match);450 451static const struct spi_device_id as3935_id[] = {452	{"as3935", 0},453	{},454};455MODULE_DEVICE_TABLE(spi, as3935_id);456 457static struct spi_driver as3935_driver = {458	.driver = {459		.name	= "as3935",460		.of_match_table = as3935_of_match,461		.pm	= pm_sleep_ptr(&as3935_pm_ops),462	},463	.probe		= as3935_probe,464	.id_table	= as3935_id,465};466module_spi_driver(as3935_driver);467 468MODULE_AUTHOR("Matt Ranostay <matt.ranostay@konsulko.com>");469MODULE_DESCRIPTION("AS3935 lightning sensor");470MODULE_LICENSE("GPL");471