linux/drivers/iio/proximity/as3935.c
<<
>>
Prefs
   1/*
   2 * as3935.c - Support for AS3935 Franklin lightning sensor
   3 *
   4 * Copyright (C) 2014 Matt Ranostay <mranostay@gmail.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * (at your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 * GNU General Public License for more details.
  15 *
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/init.h>
  20#include <linux/interrupt.h>
  21#include <linux/delay.h>
  22#include <linux/workqueue.h>
  23#include <linux/mutex.h>
  24#include <linux/err.h>
  25#include <linux/irq.h>
  26#include <linux/gpio.h>
  27#include <linux/spi/spi.h>
  28#include <linux/iio/iio.h>
  29#include <linux/iio/sysfs.h>
  30#include <linux/iio/trigger.h>
  31#include <linux/iio/trigger_consumer.h>
  32#include <linux/iio/buffer.h>
  33#include <linux/iio/triggered_buffer.h>
  34#include <linux/of_gpio.h>
  35
  36
  37#define AS3935_AFE_GAIN         0x00
  38#define AS3935_AFE_MASK         0x3F
  39#define AS3935_AFE_GAIN_MAX     0x1F
  40#define AS3935_AFE_PWR_BIT      BIT(0)
  41
  42#define AS3935_NFLWDTH          0x01
  43#define AS3935_NFLWDTH_MASK     0x7f
  44
  45#define AS3935_INT              0x03
  46#define AS3935_INT_MASK         0x0f
  47#define AS3935_DISTURB_INT      BIT(2)
  48#define AS3935_EVENT_INT        BIT(3)
  49#define AS3935_NOISE_INT        BIT(0)
  50
  51#define AS3935_DATA             0x07
  52#define AS3935_DATA_MASK        0x3F
  53
  54#define AS3935_TUNE_CAP         0x08
  55#define AS3935_DEFAULTS         0x3C
  56#define AS3935_CALIBRATE        0x3D
  57
  58#define AS3935_READ_DATA        BIT(14)
  59#define AS3935_ADDRESS(x)       ((x) << 8)
  60
  61#define MAX_PF_CAP              120
  62#define TUNE_CAP_DIV            8
  63
  64struct as3935_state {
  65        struct spi_device *spi;
  66        struct iio_trigger *trig;
  67        struct mutex lock;
  68        struct delayed_work work;
  69
  70        unsigned long noise_tripped;
  71        u32 tune_cap;
  72        u32 nflwdth_reg;
  73        u8 buffer[16]; /* 8-bit data + 56-bit padding + 64-bit timestamp */
  74        u8 buf[2] ____cacheline_aligned;
  75};
  76
  77static const struct iio_chan_spec as3935_channels[] = {
  78        {
  79                .type           = IIO_PROXIMITY,
  80                .info_mask_separate =
  81                        BIT(IIO_CHAN_INFO_RAW) |
  82                        BIT(IIO_CHAN_INFO_PROCESSED) |
  83                        BIT(IIO_CHAN_INFO_SCALE),
  84                .scan_index     = 0,
  85                .scan_type = {
  86                        .sign           = 'u',
  87                        .realbits       = 6,
  88                        .storagebits    = 8,
  89                },
  90        },
  91        IIO_CHAN_SOFT_TIMESTAMP(1),
  92};
  93
  94static int as3935_read(struct as3935_state *st, unsigned int reg, int *val)
  95{
  96        u8 cmd;
  97        int ret;
  98
  99        cmd = (AS3935_READ_DATA | AS3935_ADDRESS(reg)) >> 8;
 100        ret = spi_w8r8(st->spi, cmd);
 101        if (ret < 0)
 102                return ret;
 103        *val = ret;
 104
 105        return 0;
 106}
 107
 108static int as3935_write(struct as3935_state *st,
 109                                unsigned int reg,
 110                                unsigned int val)
 111{
 112        u8 *buf = st->buf;
 113
 114        buf[0] = AS3935_ADDRESS(reg) >> 8;
 115        buf[1] = val;
 116
 117        return spi_write(st->spi, buf, 2);
 118}
 119
 120static ssize_t as3935_sensor_sensitivity_show(struct device *dev,
 121                                        struct device_attribute *attr,
 122                                        char *buf)
 123{
 124        struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
 125        int val, ret;
 126
 127        ret = as3935_read(st, AS3935_AFE_GAIN, &val);
 128        if (ret)
 129                return ret;
 130        val = (val & AS3935_AFE_MASK) >> 1;
 131
 132        return sprintf(buf, "%d\n", val);
 133}
 134
 135static ssize_t as3935_sensor_sensitivity_store(struct device *dev,
 136                                        struct device_attribute *attr,
 137                                        const char *buf, size_t len)
 138{
 139        struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
 140        unsigned long val;
 141        int ret;
 142
 143        ret = kstrtoul((const char *) buf, 10, &val);
 144        if (ret)
 145                return -EINVAL;
 146
 147        if (val > AS3935_AFE_GAIN_MAX)
 148                return -EINVAL;
 149
 150        as3935_write(st, AS3935_AFE_GAIN, val << 1);
 151
 152        return len;
 153}
 154
 155static ssize_t as3935_noise_level_tripped_show(struct device *dev,
 156                                        struct device_attribute *attr,
 157                                        char *buf)
 158{
 159        struct as3935_state *st = iio_priv(dev_to_iio_dev(dev));
 160        int ret;
 161
 162        mutex_lock(&st->lock);
 163        ret = sprintf(buf, "%d\n", !time_after(jiffies, st->noise_tripped + HZ));
 164        mutex_unlock(&st->lock);
 165
 166        return ret;
 167}
 168
 169static IIO_DEVICE_ATTR(sensor_sensitivity, S_IRUGO | S_IWUSR,
 170        as3935_sensor_sensitivity_show, as3935_sensor_sensitivity_store, 0);
 171
 172static IIO_DEVICE_ATTR(noise_level_tripped, S_IRUGO,
 173        as3935_noise_level_tripped_show, NULL, 0);
 174
 175static struct attribute *as3935_attributes[] = {
 176        &iio_dev_attr_sensor_sensitivity.dev_attr.attr,
 177        &iio_dev_attr_noise_level_tripped.dev_attr.attr,
 178        NULL,
 179};
 180
 181static const struct attribute_group as3935_attribute_group = {
 182        .attrs = as3935_attributes,
 183};
 184
 185static int as3935_read_raw(struct iio_dev *indio_dev,
 186                           struct iio_chan_spec const *chan,
 187                           int *val,
 188                           int *val2,
 189                           long m)
 190{
 191        struct as3935_state *st = iio_priv(indio_dev);
 192        int ret;
 193
 194
 195        switch (m) {
 196        case IIO_CHAN_INFO_PROCESSED:
 197        case IIO_CHAN_INFO_RAW:
 198                *val2 = 0;
 199                ret = as3935_read(st, AS3935_DATA, val);
 200                if (ret)
 201                        return ret;
 202
 203                /* storm out of range */
 204                if (*val == AS3935_DATA_MASK)
 205                        return -EINVAL;
 206
 207                if (m == IIO_CHAN_INFO_RAW)
 208                        return IIO_VAL_INT;
 209
 210                if (m == IIO_CHAN_INFO_PROCESSED)
 211                        *val *= 1000;
 212                break;
 213        case IIO_CHAN_INFO_SCALE:
 214                *val = 1000;
 215                break;
 216        default:
 217                return -EINVAL;
 218        }
 219
 220        return IIO_VAL_INT;
 221}
 222
 223static const struct iio_info as3935_info = {
 224        .driver_module = THIS_MODULE,
 225        .attrs = &as3935_attribute_group,
 226        .read_raw = &as3935_read_raw,
 227};
 228
 229static irqreturn_t as3935_trigger_handler(int irq, void *private)
 230{
 231        struct iio_poll_func *pf = private;
 232        struct iio_dev *indio_dev = pf->indio_dev;
 233        struct as3935_state *st = iio_priv(indio_dev);
 234        int val, ret;
 235
 236        ret = as3935_read(st, AS3935_DATA, &val);
 237        if (ret)
 238                goto err_read;
 239
 240        st->buffer[0] = val & AS3935_DATA_MASK;
 241        iio_push_to_buffers_with_timestamp(indio_dev, &st->buffer,
 242                                           iio_get_time_ns(indio_dev));
 243err_read:
 244        iio_trigger_notify_done(indio_dev->trig);
 245
 246        return IRQ_HANDLED;
 247}
 248
 249static const struct iio_trigger_ops iio_interrupt_trigger_ops = {
 250        .owner = THIS_MODULE,
 251};
 252
 253static void as3935_event_work(struct work_struct *work)
 254{
 255        struct as3935_state *st;
 256        int val;
 257        int ret;
 258
 259        st = container_of(work, struct as3935_state, work.work);
 260
 261        ret = as3935_read(st, AS3935_INT, &val);
 262        if (ret) {
 263                dev_warn(&st->spi->dev, "read error\n");
 264                return;
 265        }
 266
 267        val &= AS3935_INT_MASK;
 268
 269        switch (val) {
 270        case AS3935_EVENT_INT:
 271                iio_trigger_poll_chained(st->trig);
 272                break;
 273        case AS3935_DISTURB_INT:
 274        case AS3935_NOISE_INT:
 275                mutex_lock(&st->lock);
 276                st->noise_tripped = jiffies;
 277                mutex_unlock(&st->lock);
 278                dev_warn(&st->spi->dev, "noise level is too high\n");
 279                break;
 280        }
 281}
 282
 283static irqreturn_t as3935_interrupt_handler(int irq, void *private)
 284{
 285        struct iio_dev *indio_dev = private;
 286        struct as3935_state *st = iio_priv(indio_dev);
 287
 288        /*
 289         * Delay work for >2 milliseconds after an interrupt to allow
 290         * estimated distance to recalculated.
 291         */
 292
 293        schedule_delayed_work(&st->work, msecs_to_jiffies(3));
 294
 295        return IRQ_HANDLED;
 296}
 297
 298static void calibrate_as3935(struct as3935_state *st)
 299{
 300        as3935_write(st, AS3935_DEFAULTS, 0x96);
 301        as3935_write(st, AS3935_CALIBRATE, 0x96);
 302        as3935_write(st, AS3935_TUNE_CAP,
 303                BIT(5) | (st->tune_cap / TUNE_CAP_DIV));
 304
 305        mdelay(2);
 306        as3935_write(st, AS3935_TUNE_CAP, (st->tune_cap / TUNE_CAP_DIV));
 307        as3935_write(st, AS3935_NFLWDTH, st->nflwdth_reg);
 308}
 309
 310#ifdef CONFIG_PM_SLEEP
 311static int as3935_suspend(struct device *dev)
 312{
 313        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 314        struct as3935_state *st = iio_priv(indio_dev);
 315        int val, ret;
 316
 317        mutex_lock(&st->lock);
 318        ret = as3935_read(st, AS3935_AFE_GAIN, &val);
 319        if (ret)
 320                goto err_suspend;
 321        val |= AS3935_AFE_PWR_BIT;
 322
 323        ret = as3935_write(st, AS3935_AFE_GAIN, val);
 324
 325err_suspend:
 326        mutex_unlock(&st->lock);
 327
 328        return ret;
 329}
 330
 331static int as3935_resume(struct device *dev)
 332{
 333        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 334        struct as3935_state *st = iio_priv(indio_dev);
 335        int val, ret;
 336
 337        mutex_lock(&st->lock);
 338        ret = as3935_read(st, AS3935_AFE_GAIN, &val);
 339        if (ret)
 340                goto err_resume;
 341        val &= ~AS3935_AFE_PWR_BIT;
 342        ret = as3935_write(st, AS3935_AFE_GAIN, val);
 343
 344        calibrate_as3935(st);
 345
 346err_resume:
 347        mutex_unlock(&st->lock);
 348
 349        return ret;
 350}
 351
 352static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
 353#define AS3935_PM_OPS (&as3935_pm_ops)
 354
 355#else
 356#define AS3935_PM_OPS NULL
 357#endif
 358
 359static int as3935_probe(struct spi_device *spi)
 360{
 361        struct iio_dev *indio_dev;
 362        struct iio_trigger *trig;
 363        struct as3935_state *st;
 364        struct device_node *np = spi->dev.of_node;
 365        int ret;
 366
 367        /* Be sure lightning event interrupt is specified */
 368        if (!spi->irq) {
 369                dev_err(&spi->dev, "unable to get event interrupt\n");
 370                return -EINVAL;
 371        }
 372
 373        indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
 374        if (!indio_dev)
 375                return -ENOMEM;
 376
 377        st = iio_priv(indio_dev);
 378        st->spi = spi;
 379
 380        spi_set_drvdata(spi, indio_dev);
 381        mutex_init(&st->lock);
 382        INIT_DELAYED_WORK(&st->work, as3935_event_work);
 383
 384        ret = of_property_read_u32(np,
 385                        "ams,tuning-capacitor-pf", &st->tune_cap);
 386        if (ret) {
 387                st->tune_cap = 0;
 388                dev_warn(&spi->dev,
 389                        "no tuning-capacitor-pf set, defaulting to %d",
 390                        st->tune_cap);
 391        }
 392
 393        if (st->tune_cap > MAX_PF_CAP) {
 394                dev_err(&spi->dev,
 395                        "wrong tuning-capacitor-pf setting of %d\n",
 396                        st->tune_cap);
 397                return -EINVAL;
 398        }
 399
 400        ret = of_property_read_u32(np,
 401                        "ams,nflwdth", &st->nflwdth_reg);
 402        if (!ret && st->nflwdth_reg > AS3935_NFLWDTH_MASK) {
 403                dev_err(&spi->dev,
 404                        "invalid nflwdth setting of %d\n",
 405                        st->nflwdth_reg);
 406                return -EINVAL;
 407        }
 408
 409        indio_dev->dev.parent = &spi->dev;
 410        indio_dev->name = spi_get_device_id(spi)->name;
 411        indio_dev->channels = as3935_channels;
 412        indio_dev->num_channels = ARRAY_SIZE(as3935_channels);
 413        indio_dev->modes = INDIO_DIRECT_MODE;
 414        indio_dev->info = &as3935_info;
 415
 416        trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
 417                                      indio_dev->name, indio_dev->id);
 418
 419        if (!trig)
 420                return -ENOMEM;
 421
 422        st->trig = trig;
 423        st->noise_tripped = jiffies - HZ;
 424        trig->dev.parent = indio_dev->dev.parent;
 425        iio_trigger_set_drvdata(trig, indio_dev);
 426        trig->ops = &iio_interrupt_trigger_ops;
 427
 428        ret = iio_trigger_register(trig);
 429        if (ret) {
 430                dev_err(&spi->dev, "failed to register trigger\n");
 431                return ret;
 432        }
 433
 434        ret = iio_triggered_buffer_setup(indio_dev, iio_pollfunc_store_time,
 435                &as3935_trigger_handler, NULL);
 436
 437        if (ret) {
 438                dev_err(&spi->dev, "cannot setup iio trigger\n");
 439                goto unregister_trigger;
 440        }
 441
 442        calibrate_as3935(st);
 443
 444        ret = devm_request_irq(&spi->dev, spi->irq,
 445                                &as3935_interrupt_handler,
 446                                IRQF_TRIGGER_RISING,
 447                                dev_name(&spi->dev),
 448                                indio_dev);
 449
 450        if (ret) {
 451                dev_err(&spi->dev, "unable to request irq\n");
 452                goto unregister_buffer;
 453        }
 454
 455        ret = iio_device_register(indio_dev);
 456        if (ret < 0) {
 457                dev_err(&spi->dev, "unable to register device\n");
 458                goto unregister_buffer;
 459        }
 460        return 0;
 461
 462unregister_buffer:
 463        iio_triggered_buffer_cleanup(indio_dev);
 464
 465unregister_trigger:
 466        iio_trigger_unregister(st->trig);
 467
 468        return ret;
 469}
 470
 471static int as3935_remove(struct spi_device *spi)
 472{
 473        struct iio_dev *indio_dev = spi_get_drvdata(spi);
 474        struct as3935_state *st = iio_priv(indio_dev);
 475
 476        iio_device_unregister(indio_dev);
 477        iio_triggered_buffer_cleanup(indio_dev);
 478        iio_trigger_unregister(st->trig);
 479
 480        return 0;
 481}
 482
 483static const struct of_device_id as3935_of_match[] = {
 484        { .compatible = "ams,as3935", },
 485        { /* sentinel */ },
 486};
 487MODULE_DEVICE_TABLE(of, as3935_of_match);
 488
 489static const struct spi_device_id as3935_id[] = {
 490        {"as3935", 0},
 491        {},
 492};
 493MODULE_DEVICE_TABLE(spi, as3935_id);
 494
 495static struct spi_driver as3935_driver = {
 496        .driver = {
 497                .name   = "as3935",
 498                .of_match_table = of_match_ptr(as3935_of_match),
 499                .pm     = AS3935_PM_OPS,
 500        },
 501        .probe          = as3935_probe,
 502        .remove         = as3935_remove,
 503        .id_table       = as3935_id,
 504};
 505module_spi_driver(as3935_driver);
 506
 507MODULE_AUTHOR("Matt Ranostay <mranostay@gmail.com>");
 508MODULE_DESCRIPTION("AS3935 lightning sensor");
 509MODULE_LICENSE("GPL");
 510