linux/drivers/iio/adc/hi8435.c
<<
>>
Prefs
   1/*
   2 * Holt Integrated Circuits HI-8435 threshold detector driver
   3 *
   4 * Copyright (C) 2015 Zodiac Inflight Innovations
   5 * Copyright (C) 2015 Cogent Embedded, Inc.
   6 *
   7 * This program is free software; you can redistribute  it and/or modify it
   8 * under  the terms of  the GNU General  Public License as published by the
   9 * Free Software Foundation;  either version 2 of the  License, or (at your
  10 * option) any later version.
  11 */
  12
  13#include <linux/delay.h>
  14#include <linux/iio/events.h>
  15#include <linux/iio/iio.h>
  16#include <linux/iio/sysfs.h>
  17#include <linux/iio/trigger.h>
  18#include <linux/iio/trigger_consumer.h>
  19#include <linux/iio/triggered_event.h>
  20#include <linux/interrupt.h>
  21#include <linux/module.h>
  22#include <linux/of.h>
  23#include <linux/of_device.h>
  24#include <linux/of_gpio.h>
  25#include <linux/spi/spi.h>
  26#include <linux/gpio/consumer.h>
  27
  28#define DRV_NAME "hi8435"
  29
  30/* Register offsets for HI-8435 */
  31#define HI8435_CTRL_REG         0x02
  32#define HI8435_PSEN_REG         0x04
  33#define HI8435_TMDATA_REG       0x1E
  34#define HI8435_GOCENHYS_REG     0x3A
  35#define HI8435_SOCENHYS_REG     0x3C
  36#define HI8435_SO7_0_REG        0x10
  37#define HI8435_SO15_8_REG       0x12
  38#define HI8435_SO23_16_REG      0x14
  39#define HI8435_SO31_24_REG      0x16
  40#define HI8435_SO31_0_REG       0x78
  41
  42#define HI8435_WRITE_OPCODE     0x00
  43#define HI8435_READ_OPCODE      0x80
  44
  45/* CTRL register bits */
  46#define HI8435_CTRL_TEST        0x01
  47#define HI8435_CTRL_SRST        0x02
  48
  49struct hi8435_priv {
  50        struct spi_device *spi;
  51        struct mutex lock;
  52
  53        unsigned long event_scan_mask; /* soft mask/unmask channels events */
  54        unsigned int event_prev_val;
  55
  56        unsigned threshold_lo[2]; /* GND-Open and Supply-Open thresholds */
  57        unsigned threshold_hi[2]; /* GND-Open and Supply-Open thresholds */
  58        u8 reg_buffer[3] ____cacheline_aligned;
  59};
  60
  61static int hi8435_readb(struct hi8435_priv *priv, u8 reg, u8 *val)
  62{
  63        reg |= HI8435_READ_OPCODE;
  64        return spi_write_then_read(priv->spi, &reg, 1, val, 1);
  65}
  66
  67static int hi8435_readw(struct hi8435_priv *priv, u8 reg, u16 *val)
  68{
  69        int ret;
  70        __be16 be_val;
  71
  72        reg |= HI8435_READ_OPCODE;
  73        ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 2);
  74        *val = be16_to_cpu(be_val);
  75
  76        return ret;
  77}
  78
  79static int hi8435_readl(struct hi8435_priv *priv, u8 reg, u32 *val)
  80{
  81        int ret;
  82        __be32 be_val;
  83
  84        reg |= HI8435_READ_OPCODE;
  85        ret = spi_write_then_read(priv->spi, &reg, 1, &be_val, 4);
  86        *val = be32_to_cpu(be_val);
  87
  88        return ret;
  89}
  90
  91static int hi8435_writeb(struct hi8435_priv *priv, u8 reg, u8 val)
  92{
  93        priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
  94        priv->reg_buffer[1] = val;
  95
  96        return spi_write(priv->spi, priv->reg_buffer, 2);
  97}
  98
  99static int hi8435_writew(struct hi8435_priv *priv, u8 reg, u16 val)
 100{
 101        priv->reg_buffer[0] = reg | HI8435_WRITE_OPCODE;
 102        priv->reg_buffer[1] = (val >> 8) & 0xff;
 103        priv->reg_buffer[2] = val & 0xff;
 104
 105        return spi_write(priv->spi, priv->reg_buffer, 3);
 106}
 107
 108static int hi8435_read_raw(struct iio_dev *idev,
 109                           const struct iio_chan_spec *chan,
 110                           int *val, int *val2, long mask)
 111{
 112        struct hi8435_priv *priv = iio_priv(idev);
 113        u32 tmp;
 114        int ret;
 115
 116        switch (mask) {
 117        case IIO_CHAN_INFO_RAW:
 118                ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
 119                if (ret < 0)
 120                        return ret;
 121                *val = !!(tmp & BIT(chan->channel));
 122                return IIO_VAL_INT;
 123        default:
 124                return -EINVAL;
 125        }
 126}
 127
 128static int hi8435_read_event_config(struct iio_dev *idev,
 129                                    const struct iio_chan_spec *chan,
 130                                    enum iio_event_type type,
 131                                    enum iio_event_direction dir)
 132{
 133        struct hi8435_priv *priv = iio_priv(idev);
 134
 135        return !!(priv->event_scan_mask & BIT(chan->channel));
 136}
 137
 138static int hi8435_write_event_config(struct iio_dev *idev,
 139                                     const struct iio_chan_spec *chan,
 140                                     enum iio_event_type type,
 141                                     enum iio_event_direction dir, int state)
 142{
 143        struct hi8435_priv *priv = iio_priv(idev);
 144        int ret;
 145        u32 tmp;
 146
 147        if (state) {
 148                ret = hi8435_readl(priv, HI8435_SO31_0_REG, &tmp);
 149                if (ret < 0)
 150                        return ret;
 151                if (tmp & BIT(chan->channel))
 152                        priv->event_prev_val |= BIT(chan->channel);
 153                else
 154                        priv->event_prev_val &= ~BIT(chan->channel);
 155
 156                priv->event_scan_mask |= BIT(chan->channel);
 157        } else
 158                priv->event_scan_mask &= ~BIT(chan->channel);
 159
 160        return 0;
 161}
 162
 163static int hi8435_read_event_value(struct iio_dev *idev,
 164                                   const struct iio_chan_spec *chan,
 165                                   enum iio_event_type type,
 166                                   enum iio_event_direction dir,
 167                                   enum iio_event_info info,
 168                                   int *val, int *val2)
 169{
 170        struct hi8435_priv *priv = iio_priv(idev);
 171        int ret;
 172        u8 mode, psen;
 173        u16 reg;
 174
 175        ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
 176        if (ret < 0)
 177                return ret;
 178
 179        /* Supply-Open or GND-Open sensing mode */
 180        mode = !!(psen & BIT(chan->channel / 8));
 181
 182        ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
 183                                 HI8435_GOCENHYS_REG, &reg);
 184        if (ret < 0)
 185                return ret;
 186
 187        if (dir == IIO_EV_DIR_FALLING)
 188                *val = ((reg & 0xff) - (reg >> 8)) / 2;
 189        else if (dir == IIO_EV_DIR_RISING)
 190                *val = ((reg & 0xff) + (reg >> 8)) / 2;
 191
 192        return IIO_VAL_INT;
 193}
 194
 195static int hi8435_write_event_value(struct iio_dev *idev,
 196                                    const struct iio_chan_spec *chan,
 197                                    enum iio_event_type type,
 198                                    enum iio_event_direction dir,
 199                                    enum iio_event_info info,
 200                                    int val, int val2)
 201{
 202        struct hi8435_priv *priv = iio_priv(idev);
 203        int ret;
 204        u8 mode, psen;
 205        u16 reg;
 206
 207        ret = hi8435_readb(priv, HI8435_PSEN_REG, &psen);
 208        if (ret < 0)
 209                return ret;
 210
 211        /* Supply-Open or GND-Open sensing mode */
 212        mode = !!(psen & BIT(chan->channel / 8));
 213
 214        ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
 215                                 HI8435_GOCENHYS_REG, &reg);
 216        if (ret < 0)
 217                return ret;
 218
 219        if (dir == IIO_EV_DIR_FALLING) {
 220                /* falling threshold range 2..21V, hysteresis minimum 2V */
 221                if (val < 2 || val > 21 || (val + 2) > priv->threshold_hi[mode])
 222                        return -EINVAL;
 223
 224                if (val == priv->threshold_lo[mode])
 225                        return 0;
 226
 227                priv->threshold_lo[mode] = val;
 228
 229                /* hysteresis must not be odd */
 230                if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
 231                        priv->threshold_hi[mode]--;
 232        } else if (dir == IIO_EV_DIR_RISING) {
 233                /* rising threshold range 3..22V, hysteresis minimum 2V */
 234                if (val < 3 || val > 22 || val < (priv->threshold_lo[mode] + 2))
 235                        return -EINVAL;
 236
 237                if (val == priv->threshold_hi[mode])
 238                        return 0;
 239
 240                priv->threshold_hi[mode] = val;
 241
 242                /* hysteresis must not be odd */
 243                if ((priv->threshold_hi[mode] - priv->threshold_lo[mode]) % 2)
 244                        priv->threshold_lo[mode]++;
 245        }
 246
 247        /* program thresholds */
 248        mutex_lock(&priv->lock);
 249
 250        ret = hi8435_readw(priv, mode ? HI8435_SOCENHYS_REG :
 251                                 HI8435_GOCENHYS_REG, &reg);
 252        if (ret < 0) {
 253                mutex_unlock(&priv->lock);
 254                return ret;
 255        }
 256
 257        /* hysteresis */
 258        reg = priv->threshold_hi[mode] - priv->threshold_lo[mode];
 259        reg <<= 8;
 260        /* threshold center */
 261        reg |= (priv->threshold_hi[mode] + priv->threshold_lo[mode]);
 262
 263        ret = hi8435_writew(priv, mode ? HI8435_SOCENHYS_REG :
 264                                  HI8435_GOCENHYS_REG, reg);
 265
 266        mutex_unlock(&priv->lock);
 267
 268        return ret;
 269}
 270
 271static int hi8435_debugfs_reg_access(struct iio_dev *idev,
 272                                     unsigned reg, unsigned writeval,
 273                                     unsigned *readval)
 274{
 275        struct hi8435_priv *priv = iio_priv(idev);
 276        int ret;
 277        u8 val;
 278
 279        if (readval != NULL) {
 280                ret = hi8435_readb(priv, reg, &val);
 281                *readval = val;
 282        } else {
 283                val = (u8)writeval;
 284                ret = hi8435_writeb(priv, reg, val);
 285        }
 286
 287        return ret;
 288}
 289
 290static const struct iio_event_spec hi8435_events[] = {
 291        {
 292                .type = IIO_EV_TYPE_THRESH,
 293                .dir = IIO_EV_DIR_RISING,
 294                .mask_separate = BIT(IIO_EV_INFO_VALUE),
 295        }, {
 296                .type = IIO_EV_TYPE_THRESH,
 297                .dir = IIO_EV_DIR_FALLING,
 298                .mask_separate = BIT(IIO_EV_INFO_VALUE),
 299        }, {
 300                .type = IIO_EV_TYPE_THRESH,
 301                .dir = IIO_EV_DIR_EITHER,
 302                .mask_separate = BIT(IIO_EV_INFO_ENABLE),
 303        },
 304};
 305
 306static int hi8435_get_sensing_mode(struct iio_dev *idev,
 307                                   const struct iio_chan_spec *chan)
 308{
 309        struct hi8435_priv *priv = iio_priv(idev);
 310        int ret;
 311        u8 reg;
 312
 313        ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
 314        if (ret < 0)
 315                return ret;
 316
 317        return !!(reg & BIT(chan->channel / 8));
 318}
 319
 320static int hi8435_set_sensing_mode(struct iio_dev *idev,
 321                                   const struct iio_chan_spec *chan,
 322                                   unsigned int mode)
 323{
 324        struct hi8435_priv *priv = iio_priv(idev);
 325        int ret;
 326        u8 reg;
 327
 328        mutex_lock(&priv->lock);
 329
 330        ret = hi8435_readb(priv, HI8435_PSEN_REG, &reg);
 331        if (ret < 0) {
 332                mutex_unlock(&priv->lock);
 333                return ret;
 334        }
 335
 336        reg &= ~BIT(chan->channel / 8);
 337        if (mode)
 338                reg |= BIT(chan->channel / 8);
 339
 340        ret = hi8435_writeb(priv, HI8435_PSEN_REG, reg);
 341
 342        mutex_unlock(&priv->lock);
 343
 344        return ret;
 345}
 346
 347static const char * const hi8435_sensing_modes[] = { "GND-Open",
 348                                                     "Supply-Open" };
 349
 350static const struct iio_enum hi8435_sensing_mode = {
 351        .items = hi8435_sensing_modes,
 352        .num_items = ARRAY_SIZE(hi8435_sensing_modes),
 353        .get = hi8435_get_sensing_mode,
 354        .set = hi8435_set_sensing_mode,
 355};
 356
 357static const struct iio_chan_spec_ext_info hi8435_ext_info[] = {
 358        IIO_ENUM("sensing_mode", IIO_SEPARATE, &hi8435_sensing_mode),
 359        IIO_ENUM_AVAILABLE("sensing_mode", &hi8435_sensing_mode),
 360        {},
 361};
 362
 363#define HI8435_VOLTAGE_CHANNEL(num)                     \
 364{                                                       \
 365        .type = IIO_VOLTAGE,                            \
 366        .indexed = 1,                                   \
 367        .channel = num,                                 \
 368        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
 369        .event_spec = hi8435_events,                    \
 370        .num_event_specs = ARRAY_SIZE(hi8435_events),   \
 371        .ext_info = hi8435_ext_info,                    \
 372}
 373
 374static const struct iio_chan_spec hi8435_channels[] = {
 375        HI8435_VOLTAGE_CHANNEL(0),
 376        HI8435_VOLTAGE_CHANNEL(1),
 377        HI8435_VOLTAGE_CHANNEL(2),
 378        HI8435_VOLTAGE_CHANNEL(3),
 379        HI8435_VOLTAGE_CHANNEL(4),
 380        HI8435_VOLTAGE_CHANNEL(5),
 381        HI8435_VOLTAGE_CHANNEL(6),
 382        HI8435_VOLTAGE_CHANNEL(7),
 383        HI8435_VOLTAGE_CHANNEL(8),
 384        HI8435_VOLTAGE_CHANNEL(9),
 385        HI8435_VOLTAGE_CHANNEL(10),
 386        HI8435_VOLTAGE_CHANNEL(11),
 387        HI8435_VOLTAGE_CHANNEL(12),
 388        HI8435_VOLTAGE_CHANNEL(13),
 389        HI8435_VOLTAGE_CHANNEL(14),
 390        HI8435_VOLTAGE_CHANNEL(15),
 391        HI8435_VOLTAGE_CHANNEL(16),
 392        HI8435_VOLTAGE_CHANNEL(17),
 393        HI8435_VOLTAGE_CHANNEL(18),
 394        HI8435_VOLTAGE_CHANNEL(19),
 395        HI8435_VOLTAGE_CHANNEL(20),
 396        HI8435_VOLTAGE_CHANNEL(21),
 397        HI8435_VOLTAGE_CHANNEL(22),
 398        HI8435_VOLTAGE_CHANNEL(23),
 399        HI8435_VOLTAGE_CHANNEL(24),
 400        HI8435_VOLTAGE_CHANNEL(25),
 401        HI8435_VOLTAGE_CHANNEL(26),
 402        HI8435_VOLTAGE_CHANNEL(27),
 403        HI8435_VOLTAGE_CHANNEL(28),
 404        HI8435_VOLTAGE_CHANNEL(29),
 405        HI8435_VOLTAGE_CHANNEL(30),
 406        HI8435_VOLTAGE_CHANNEL(31),
 407        IIO_CHAN_SOFT_TIMESTAMP(32),
 408};
 409
 410static const struct iio_info hi8435_info = {
 411        .read_raw = hi8435_read_raw,
 412        .read_event_config = hi8435_read_event_config,
 413        .write_event_config = hi8435_write_event_config,
 414        .read_event_value = hi8435_read_event_value,
 415        .write_event_value = hi8435_write_event_value,
 416        .debugfs_reg_access = hi8435_debugfs_reg_access,
 417};
 418
 419static void hi8435_iio_push_event(struct iio_dev *idev, unsigned int val)
 420{
 421        struct hi8435_priv *priv = iio_priv(idev);
 422        enum iio_event_direction dir;
 423        unsigned int i;
 424        unsigned int status = priv->event_prev_val ^ val;
 425
 426        if (!status)
 427                return;
 428
 429        for_each_set_bit(i, &priv->event_scan_mask, 32) {
 430                if (status & BIT(i)) {
 431                        dir = val & BIT(i) ? IIO_EV_DIR_RISING :
 432                                             IIO_EV_DIR_FALLING;
 433                        iio_push_event(idev,
 434                                       IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
 435                                                    IIO_EV_TYPE_THRESH, dir),
 436                                       iio_get_time_ns(idev));
 437                }
 438        }
 439
 440        priv->event_prev_val = val;
 441}
 442
 443static irqreturn_t hi8435_trigger_handler(int irq, void *private)
 444{
 445        struct iio_poll_func *pf = private;
 446        struct iio_dev *idev = pf->indio_dev;
 447        struct hi8435_priv *priv = iio_priv(idev);
 448        u32 val;
 449        int ret;
 450
 451        ret = hi8435_readl(priv, HI8435_SO31_0_REG, &val);
 452        if (ret < 0)
 453                goto err_read;
 454
 455        hi8435_iio_push_event(idev, val);
 456
 457err_read:
 458        iio_trigger_notify_done(idev->trig);
 459
 460        return IRQ_HANDLED;
 461}
 462
 463static int hi8435_probe(struct spi_device *spi)
 464{
 465        struct iio_dev *idev;
 466        struct hi8435_priv *priv;
 467        struct gpio_desc *reset_gpio;
 468        int ret;
 469
 470        idev = devm_iio_device_alloc(&spi->dev, sizeof(*priv));
 471        if (!idev)
 472                return -ENOMEM;
 473
 474        priv = iio_priv(idev);
 475        priv->spi = spi;
 476
 477        reset_gpio = devm_gpiod_get(&spi->dev, NULL, GPIOD_OUT_LOW);
 478        if (IS_ERR(reset_gpio)) {
 479                /* chip s/w reset if h/w reset failed */
 480                hi8435_writeb(priv, HI8435_CTRL_REG, HI8435_CTRL_SRST);
 481                hi8435_writeb(priv, HI8435_CTRL_REG, 0);
 482        } else {
 483                udelay(5);
 484                gpiod_set_value(reset_gpio, 1);
 485        }
 486
 487        spi_set_drvdata(spi, idev);
 488        mutex_init(&priv->lock);
 489
 490        idev->dev.parent        = &spi->dev;
 491        idev->dev.of_node       = spi->dev.of_node;
 492        idev->name              = spi_get_device_id(spi)->name;
 493        idev->modes             = INDIO_DIRECT_MODE;
 494        idev->info              = &hi8435_info;
 495        idev->channels          = hi8435_channels;
 496        idev->num_channels      = ARRAY_SIZE(hi8435_channels);
 497
 498        /* unmask all events */
 499        priv->event_scan_mask = ~(0);
 500        /*
 501         * There is a restriction in the chip - the hysteresis can not be odd.
 502         * If the hysteresis is set to odd value then chip gets into lock state
 503         * and not functional anymore.
 504         * After chip reset the thresholds are in undefined state, so we need to
 505         * initialize thresholds to some initial values and then prevent
 506         * userspace setting odd hysteresis.
 507         *
 508         * Set threshold low voltage to 2V, threshold high voltage to 4V
 509         * for both GND-Open and Supply-Open sensing modes.
 510         */
 511        priv->threshold_lo[0] = priv->threshold_lo[1] = 2;
 512        priv->threshold_hi[0] = priv->threshold_hi[1] = 4;
 513        hi8435_writew(priv, HI8435_GOCENHYS_REG, 0x206);
 514        hi8435_writew(priv, HI8435_SOCENHYS_REG, 0x206);
 515
 516        ret = iio_triggered_event_setup(idev, NULL, hi8435_trigger_handler);
 517        if (ret)
 518                return ret;
 519
 520        ret = iio_device_register(idev);
 521        if (ret < 0) {
 522                dev_err(&spi->dev, "unable to register device\n");
 523                goto unregister_triggered_event;
 524        }
 525
 526        return 0;
 527
 528unregister_triggered_event:
 529        iio_triggered_event_cleanup(idev);
 530        return ret;
 531}
 532
 533static int hi8435_remove(struct spi_device *spi)
 534{
 535        struct iio_dev *idev = spi_get_drvdata(spi);
 536
 537        iio_device_unregister(idev);
 538        iio_triggered_event_cleanup(idev);
 539
 540        return 0;
 541}
 542
 543static const struct of_device_id hi8435_dt_ids[] = {
 544        { .compatible = "holt,hi8435" },
 545        {},
 546};
 547MODULE_DEVICE_TABLE(of, hi8435_dt_ids);
 548
 549static const struct spi_device_id hi8435_id[] = {
 550        { "hi8435", 0},
 551        { }
 552};
 553MODULE_DEVICE_TABLE(spi, hi8435_id);
 554
 555static struct spi_driver hi8435_driver = {
 556        .driver = {
 557                .name           = DRV_NAME,
 558                .of_match_table = of_match_ptr(hi8435_dt_ids),
 559        },
 560        .probe          = hi8435_probe,
 561        .remove         = hi8435_remove,
 562        .id_table       = hi8435_id,
 563};
 564module_spi_driver(hi8435_driver);
 565
 566MODULE_LICENSE("GPL");
 567MODULE_AUTHOR("Vladimir Barinov");
 568MODULE_DESCRIPTION("HI-8435 threshold detector");
 569