linux/drivers/iio/adc/qcom-spmi-iadc.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/bitops.h>
  15#include <linux/completion.h>
  16#include <linux/delay.h>
  17#include <linux/err.h>
  18#include <linux/iio/iio.h>
  19#include <linux/interrupt.h>
  20#include <linux/kernel.h>
  21#include <linux/mutex.h>
  22#include <linux/module.h>
  23#include <linux/of.h>
  24#include <linux/of_device.h>
  25#include <linux/platform_device.h>
  26#include <linux/regmap.h>
  27#include <linux/slab.h>
  28
  29/* IADC register and bit definition */
  30#define IADC_REVISION2                          0x1
  31#define IADC_REVISION2_SUPPORTED_IADC           1
  32
  33#define IADC_PERPH_TYPE                         0x4
  34#define IADC_PERPH_TYPE_ADC                     8
  35
  36#define IADC_PERPH_SUBTYPE                      0x5
  37#define IADC_PERPH_SUBTYPE_IADC                 3
  38
  39#define IADC_STATUS1                            0x8
  40#define IADC_STATUS1_OP_MODE                    4
  41#define IADC_STATUS1_REQ_STS                    BIT(1)
  42#define IADC_STATUS1_EOC                        BIT(0)
  43#define IADC_STATUS1_REQ_STS_EOC_MASK           0x3
  44
  45#define IADC_MODE_CTL                           0x40
  46#define IADC_OP_MODE_SHIFT                      3
  47#define IADC_OP_MODE_NORMAL                     0
  48#define IADC_TRIM_EN                            BIT(0)
  49
  50#define IADC_EN_CTL1                            0x46
  51#define IADC_EN_CTL1_SET                        BIT(7)
  52
  53#define IADC_CH_SEL_CTL                         0x48
  54
  55#define IADC_DIG_PARAM                          0x50
  56#define IADC_DIG_DEC_RATIO_SEL_SHIFT            2
  57
  58#define IADC_HW_SETTLE_DELAY                    0x51
  59
  60#define IADC_CONV_REQ                           0x52
  61#define IADC_CONV_REQ_SET                       BIT(7)
  62
  63#define IADC_FAST_AVG_CTL                       0x5a
  64#define IADC_FAST_AVG_EN                        0x5b
  65#define IADC_FAST_AVG_EN_SET                    BIT(7)
  66
  67#define IADC_PERH_RESET_CTL3                    0xda
  68#define IADC_FOLLOW_WARM_RB                     BIT(2)
  69
  70#define IADC_DATA                               0x60    /* 16 bits */
  71
  72#define IADC_SEC_ACCESS                         0xd0
  73#define IADC_SEC_ACCESS_DATA                    0xa5
  74
  75#define IADC_NOMINAL_RSENSE                     0xf4
  76#define IADC_NOMINAL_RSENSE_SIGN_MASK           BIT(7)
  77
  78#define IADC_REF_GAIN_MICRO_VOLTS               17857
  79
  80#define IADC_INT_RSENSE_DEVIATION               15625   /* nano Ohms per bit */
  81
  82#define IADC_INT_RSENSE_IDEAL_VALUE             10000   /* micro Ohms */
  83#define IADC_INT_RSENSE_DEFAULT_VALUE           7800    /* micro Ohms */
  84#define IADC_INT_RSENSE_DEFAULT_GF              9000    /* micro Ohms */
  85#define IADC_INT_RSENSE_DEFAULT_SMIC            9700    /* micro Ohms */
  86
  87#define IADC_CONV_TIME_MIN_US                   2000
  88#define IADC_CONV_TIME_MAX_US                   2100
  89
  90#define IADC_DEF_PRESCALING                     0 /* 1:1 */
  91#define IADC_DEF_DECIMATION                     0 /* 512 */
  92#define IADC_DEF_HW_SETTLE_TIME                 0 /* 0 us */
  93#define IADC_DEF_AVG_SAMPLES                    0 /* 1 sample */
  94
  95/* IADC channel list */
  96#define IADC_INT_RSENSE                         0
  97#define IADC_EXT_RSENSE                         1
  98#define IADC_GAIN_17P857MV                      3
  99#define IADC_EXT_OFFSET_CSP_CSN                 5
 100#define IADC_INT_OFFSET_CSP2_CSN2               6
 101
 102/**
 103 * struct iadc_chip - IADC Current ADC device structure.
 104 * @regmap: regmap for register read/write.
 105 * @dev: This device pointer.
 106 * @base: base offset for the ADC peripheral.
 107 * @rsense: Values of the internal and external sense resister in micro Ohms.
 108 * @poll_eoc: Poll for end of conversion instead of waiting for IRQ.
 109 * @offset: Raw offset values for the internal and external channels.
 110 * @gain: Raw gain of the channels.
 111 * @lock: ADC lock for access to the peripheral.
 112 * @complete: ADC notification after end of conversion interrupt is received.
 113 */
 114struct iadc_chip {
 115        struct regmap   *regmap;
 116        struct device   *dev;
 117        u16             base;
 118        bool            poll_eoc;
 119        u32             rsense[2];
 120        u16             offset[2];
 121        u16             gain;
 122        struct mutex    lock;
 123        struct completion complete;
 124};
 125
 126static int iadc_read(struct iadc_chip *iadc, u16 offset, u8 *data)
 127{
 128        unsigned int val;
 129        int ret;
 130
 131        ret = regmap_read(iadc->regmap, iadc->base + offset, &val);
 132        if (ret < 0)
 133                return ret;
 134
 135        *data = val;
 136        return 0;
 137}
 138
 139static int iadc_write(struct iadc_chip *iadc, u16 offset, u8 data)
 140{
 141        return regmap_write(iadc->regmap, iadc->base + offset, data);
 142}
 143
 144static int iadc_reset(struct iadc_chip *iadc)
 145{
 146        u8 data;
 147        int ret;
 148
 149        ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
 150        if (ret < 0)
 151                return ret;
 152
 153        ret = iadc_read(iadc, IADC_PERH_RESET_CTL3, &data);
 154        if (ret < 0)
 155                return ret;
 156
 157        ret = iadc_write(iadc, IADC_SEC_ACCESS, IADC_SEC_ACCESS_DATA);
 158        if (ret < 0)
 159                return ret;
 160
 161        data |= IADC_FOLLOW_WARM_RB;
 162
 163        return iadc_write(iadc, IADC_PERH_RESET_CTL3, data);
 164}
 165
 166static int iadc_set_state(struct iadc_chip *iadc, bool state)
 167{
 168        return iadc_write(iadc, IADC_EN_CTL1, state ? IADC_EN_CTL1_SET : 0);
 169}
 170
 171static void iadc_status_show(struct iadc_chip *iadc)
 172{
 173        u8 mode, sta1, chan, dig, en, req;
 174        int ret;
 175
 176        ret = iadc_read(iadc, IADC_MODE_CTL, &mode);
 177        if (ret < 0)
 178                return;
 179
 180        ret = iadc_read(iadc, IADC_DIG_PARAM, &dig);
 181        if (ret < 0)
 182                return;
 183
 184        ret = iadc_read(iadc, IADC_CH_SEL_CTL, &chan);
 185        if (ret < 0)
 186                return;
 187
 188        ret = iadc_read(iadc, IADC_CONV_REQ, &req);
 189        if (ret < 0)
 190                return;
 191
 192        ret = iadc_read(iadc, IADC_STATUS1, &sta1);
 193        if (ret < 0)
 194                return;
 195
 196        ret = iadc_read(iadc, IADC_EN_CTL1, &en);
 197        if (ret < 0)
 198                return;
 199
 200        dev_err(iadc->dev,
 201                "mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n",
 202                mode, en, chan, dig, req, sta1);
 203}
 204
 205static int iadc_configure(struct iadc_chip *iadc, int channel)
 206{
 207        u8 decim, mode;
 208        int ret;
 209
 210        /* Mode selection */
 211        mode = (IADC_OP_MODE_NORMAL << IADC_OP_MODE_SHIFT) | IADC_TRIM_EN;
 212        ret = iadc_write(iadc, IADC_MODE_CTL, mode);
 213        if (ret < 0)
 214                return ret;
 215
 216        /* Channel selection */
 217        ret = iadc_write(iadc, IADC_CH_SEL_CTL, channel);
 218        if (ret < 0)
 219                return ret;
 220
 221        /* Digital parameter setup */
 222        decim = IADC_DEF_DECIMATION << IADC_DIG_DEC_RATIO_SEL_SHIFT;
 223        ret = iadc_write(iadc, IADC_DIG_PARAM, decim);
 224        if (ret < 0)
 225                return ret;
 226
 227        /* HW settle time delay */
 228        ret = iadc_write(iadc, IADC_HW_SETTLE_DELAY, IADC_DEF_HW_SETTLE_TIME);
 229        if (ret < 0)
 230                return ret;
 231
 232        ret = iadc_write(iadc, IADC_FAST_AVG_CTL, IADC_DEF_AVG_SAMPLES);
 233        if (ret < 0)
 234                return ret;
 235
 236        if (IADC_DEF_AVG_SAMPLES)
 237                ret = iadc_write(iadc, IADC_FAST_AVG_EN, IADC_FAST_AVG_EN_SET);
 238        else
 239                ret = iadc_write(iadc, IADC_FAST_AVG_EN, 0);
 240
 241        if (ret < 0)
 242                return ret;
 243
 244        if (!iadc->poll_eoc)
 245                reinit_completion(&iadc->complete);
 246
 247        ret = iadc_set_state(iadc, true);
 248        if (ret < 0)
 249                return ret;
 250
 251        /* Request conversion */
 252        return iadc_write(iadc, IADC_CONV_REQ, IADC_CONV_REQ_SET);
 253}
 254
 255static int iadc_poll_wait_eoc(struct iadc_chip *iadc, unsigned int interval_us)
 256{
 257        unsigned int count, retry;
 258        int ret;
 259        u8 sta1;
 260
 261        retry = interval_us / IADC_CONV_TIME_MIN_US;
 262
 263        for (count = 0; count < retry; count++) {
 264                ret = iadc_read(iadc, IADC_STATUS1, &sta1);
 265                if (ret < 0)
 266                        return ret;
 267
 268                sta1 &= IADC_STATUS1_REQ_STS_EOC_MASK;
 269                if (sta1 == IADC_STATUS1_EOC)
 270                        return 0;
 271
 272                usleep_range(IADC_CONV_TIME_MIN_US, IADC_CONV_TIME_MAX_US);
 273        }
 274
 275        iadc_status_show(iadc);
 276
 277        return -ETIMEDOUT;
 278}
 279
 280static int iadc_read_result(struct iadc_chip *iadc, u16 *data)
 281{
 282        return regmap_bulk_read(iadc->regmap, iadc->base + IADC_DATA, data, 2);
 283}
 284
 285static int iadc_do_conversion(struct iadc_chip *iadc, int chan, u16 *data)
 286{
 287        unsigned int wait;
 288        int ret;
 289
 290        ret = iadc_configure(iadc, chan);
 291        if (ret < 0)
 292                goto exit;
 293
 294        wait = BIT(IADC_DEF_AVG_SAMPLES) * IADC_CONV_TIME_MIN_US * 2;
 295
 296        if (iadc->poll_eoc) {
 297                ret = iadc_poll_wait_eoc(iadc, wait);
 298        } else {
 299                ret = wait_for_completion_timeout(&iadc->complete,
 300                        usecs_to_jiffies(wait));
 301                if (!ret)
 302                        ret = -ETIMEDOUT;
 303                else
 304                        /* double check conversion status */
 305                        ret = iadc_poll_wait_eoc(iadc, IADC_CONV_TIME_MIN_US);
 306        }
 307
 308        if (!ret)
 309                ret = iadc_read_result(iadc, data);
 310exit:
 311        iadc_set_state(iadc, false);
 312        if (ret < 0)
 313                dev_err(iadc->dev, "conversion failed\n");
 314
 315        return ret;
 316}
 317
 318static int iadc_read_raw(struct iio_dev *indio_dev,
 319                         struct iio_chan_spec const *chan,
 320                         int *val, int *val2, long mask)
 321{
 322        struct iadc_chip *iadc = iio_priv(indio_dev);
 323        s32 isense_ua, vsense_uv;
 324        u16 adc_raw, vsense_raw;
 325        int ret;
 326
 327        switch (mask) {
 328        case IIO_CHAN_INFO_RAW:
 329                mutex_lock(&iadc->lock);
 330                ret = iadc_do_conversion(iadc, chan->channel, &adc_raw);
 331                mutex_unlock(&iadc->lock);
 332                if (ret < 0)
 333                        return ret;
 334
 335                vsense_raw = adc_raw - iadc->offset[chan->channel];
 336
 337                vsense_uv = vsense_raw * IADC_REF_GAIN_MICRO_VOLTS;
 338                vsense_uv /= (s32)iadc->gain - iadc->offset[chan->channel];
 339
 340                isense_ua = vsense_uv / iadc->rsense[chan->channel];
 341
 342                dev_dbg(iadc->dev, "off %d gain %d adc %d %duV I %duA\n",
 343                        iadc->offset[chan->channel], iadc->gain,
 344                        adc_raw, vsense_uv, isense_ua);
 345
 346                *val = isense_ua;
 347                return IIO_VAL_INT;
 348        case IIO_CHAN_INFO_SCALE:
 349                *val = 0;
 350                *val2 = 1000;
 351                return IIO_VAL_INT_PLUS_MICRO;
 352        }
 353
 354        return -EINVAL;
 355}
 356
 357static const struct iio_info iadc_info = {
 358        .read_raw = iadc_read_raw,
 359};
 360
 361static irqreturn_t iadc_isr(int irq, void *dev_id)
 362{
 363        struct iadc_chip *iadc = dev_id;
 364
 365        complete(&iadc->complete);
 366
 367        return IRQ_HANDLED;
 368}
 369
 370static int iadc_update_offset(struct iadc_chip *iadc)
 371{
 372        int ret;
 373
 374        ret = iadc_do_conversion(iadc, IADC_GAIN_17P857MV, &iadc->gain);
 375        if (ret < 0)
 376                return ret;
 377
 378        ret = iadc_do_conversion(iadc, IADC_INT_OFFSET_CSP2_CSN2,
 379                                 &iadc->offset[IADC_INT_RSENSE]);
 380        if (ret < 0)
 381                return ret;
 382
 383        if (iadc->gain == iadc->offset[IADC_INT_RSENSE]) {
 384                dev_err(iadc->dev, "error: internal offset == gain %d\n",
 385                        iadc->gain);
 386                return -EINVAL;
 387        }
 388
 389        ret = iadc_do_conversion(iadc, IADC_EXT_OFFSET_CSP_CSN,
 390                                 &iadc->offset[IADC_EXT_RSENSE]);
 391        if (ret < 0)
 392                return ret;
 393
 394        if (iadc->gain == iadc->offset[IADC_EXT_RSENSE]) {
 395                dev_err(iadc->dev, "error: external offset == gain %d\n",
 396                        iadc->gain);
 397                return -EINVAL;
 398        }
 399
 400        return 0;
 401}
 402
 403static int iadc_version_check(struct iadc_chip *iadc)
 404{
 405        u8 val;
 406        int ret;
 407
 408        ret = iadc_read(iadc, IADC_PERPH_TYPE, &val);
 409        if (ret < 0)
 410                return ret;
 411
 412        if (val < IADC_PERPH_TYPE_ADC) {
 413                dev_err(iadc->dev, "%d is not ADC\n", val);
 414                return -EINVAL;
 415        }
 416
 417        ret = iadc_read(iadc, IADC_PERPH_SUBTYPE, &val);
 418        if (ret < 0)
 419                return ret;
 420
 421        if (val < IADC_PERPH_SUBTYPE_IADC) {
 422                dev_err(iadc->dev, "%d is not IADC\n", val);
 423                return -EINVAL;
 424        }
 425
 426        ret = iadc_read(iadc, IADC_REVISION2, &val);
 427        if (ret < 0)
 428                return ret;
 429
 430        if (val < IADC_REVISION2_SUPPORTED_IADC) {
 431                dev_err(iadc->dev, "revision %d not supported\n", val);
 432                return -EINVAL;
 433        }
 434
 435        return 0;
 436}
 437
 438static int iadc_rsense_read(struct iadc_chip *iadc, struct device_node *node)
 439{
 440        int ret, sign, int_sense;
 441        u8 deviation;
 442
 443        ret = of_property_read_u32(node, "qcom,external-resistor-micro-ohms",
 444                                   &iadc->rsense[IADC_EXT_RSENSE]);
 445        if (ret < 0)
 446                iadc->rsense[IADC_EXT_RSENSE] = IADC_INT_RSENSE_IDEAL_VALUE;
 447
 448        if (!iadc->rsense[IADC_EXT_RSENSE]) {
 449                dev_err(iadc->dev, "external resistor can't be zero Ohms");
 450                return -EINVAL;
 451        }
 452
 453        ret = iadc_read(iadc, IADC_NOMINAL_RSENSE, &deviation);
 454        if (ret < 0)
 455                return ret;
 456
 457        /*
 458         * Deviation value stored is an offset from 10 mili Ohms, bit 7 is
 459         * the sign, the remaining bits have an LSB of 15625 nano Ohms.
 460         */
 461        sign = (deviation & IADC_NOMINAL_RSENSE_SIGN_MASK) ? -1 : 1;
 462
 463        deviation &= ~IADC_NOMINAL_RSENSE_SIGN_MASK;
 464
 465        /* Scale it to nono Ohms */
 466        int_sense = IADC_INT_RSENSE_IDEAL_VALUE * 1000;
 467        int_sense += sign * deviation * IADC_INT_RSENSE_DEVIATION;
 468        int_sense /= 1000; /* micro Ohms */
 469
 470        iadc->rsense[IADC_INT_RSENSE] = int_sense;
 471        return 0;
 472}
 473
 474static const struct iio_chan_spec iadc_channels[] = {
 475        {
 476                .type = IIO_CURRENT,
 477                .datasheet_name = "INTERNAL_RSENSE",
 478                .channel = 0,
 479                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 480                                      BIT(IIO_CHAN_INFO_SCALE),
 481                .indexed = 1,
 482        },
 483        {
 484                .type = IIO_CURRENT,
 485                .datasheet_name = "EXTERNAL_RSENSE",
 486                .channel = 1,
 487                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
 488                                      BIT(IIO_CHAN_INFO_SCALE),
 489                .indexed = 1,
 490        },
 491};
 492
 493static int iadc_probe(struct platform_device *pdev)
 494{
 495        struct device_node *node = pdev->dev.of_node;
 496        struct device *dev = &pdev->dev;
 497        struct iio_dev *indio_dev;
 498        struct iadc_chip *iadc;
 499        int ret, irq_eoc;
 500        u32 res;
 501
 502        indio_dev = devm_iio_device_alloc(dev, sizeof(*iadc));
 503        if (!indio_dev)
 504                return -ENOMEM;
 505
 506        iadc = iio_priv(indio_dev);
 507        iadc->dev = dev;
 508
 509        iadc->regmap = dev_get_regmap(dev->parent, NULL);
 510        if (!iadc->regmap)
 511                return -ENODEV;
 512
 513        init_completion(&iadc->complete);
 514        mutex_init(&iadc->lock);
 515
 516        ret = of_property_read_u32(node, "reg", &res);
 517        if (ret < 0)
 518                return -ENODEV;
 519
 520        iadc->base = res;
 521
 522        ret = iadc_version_check(iadc);
 523        if (ret < 0)
 524                return -ENODEV;
 525
 526        ret = iadc_rsense_read(iadc, node);
 527        if (ret < 0)
 528                return -ENODEV;
 529
 530        dev_dbg(iadc->dev, "sense resistors %d and %d micro Ohm\n",
 531                iadc->rsense[IADC_INT_RSENSE],
 532                iadc->rsense[IADC_EXT_RSENSE]);
 533
 534        irq_eoc = platform_get_irq(pdev, 0);
 535        if (irq_eoc == -EPROBE_DEFER)
 536                return irq_eoc;
 537
 538        if (irq_eoc < 0)
 539                iadc->poll_eoc = true;
 540
 541        ret = iadc_reset(iadc);
 542        if (ret < 0) {
 543                dev_err(dev, "reset failed\n");
 544                return ret;
 545        }
 546
 547        if (!iadc->poll_eoc) {
 548                ret = devm_request_irq(dev, irq_eoc, iadc_isr, 0,
 549                                        "spmi-iadc", iadc);
 550                if (!ret)
 551                        enable_irq_wake(irq_eoc);
 552                else
 553                        return ret;
 554        } else {
 555                device_init_wakeup(iadc->dev, 1);
 556        }
 557
 558        ret = iadc_update_offset(iadc);
 559        if (ret < 0) {
 560                dev_err(dev, "failed offset calibration\n");
 561                return ret;
 562        }
 563
 564        indio_dev->dev.parent = dev;
 565        indio_dev->dev.of_node = node;
 566        indio_dev->name = pdev->name;
 567        indio_dev->modes = INDIO_DIRECT_MODE;
 568        indio_dev->info = &iadc_info;
 569        indio_dev->channels = iadc_channels;
 570        indio_dev->num_channels = ARRAY_SIZE(iadc_channels);
 571
 572        return devm_iio_device_register(dev, indio_dev);
 573}
 574
 575static const struct of_device_id iadc_match_table[] = {
 576        { .compatible = "qcom,spmi-iadc" },
 577        { }
 578};
 579
 580MODULE_DEVICE_TABLE(of, iadc_match_table);
 581
 582static struct platform_driver iadc_driver = {
 583        .driver = {
 584                   .name = "qcom-spmi-iadc",
 585                   .of_match_table = iadc_match_table,
 586        },
 587        .probe = iadc_probe,
 588};
 589
 590module_platform_driver(iadc_driver);
 591
 592MODULE_ALIAS("platform:qcom-spmi-iadc");
 593MODULE_DESCRIPTION("Qualcomm SPMI PMIC current ADC driver");
 594MODULE_LICENSE("GPL v2");
 595MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
 596