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