linux/drivers/iio/adc/fsl-imx25-gcq.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2014-2015 Pengutronix, Markus Pargmann <mpa@pengutronix.de>
   3 *
   4 * This program is free software; you can redistribute it and/or modify it under
   5 * the terms of the GNU General Public License version 2 as published by the
   6 * Free Software Foundation.
   7 *
   8 * This is the driver for the imx25 GCQ (Generic Conversion Queue)
   9 * connected to the imx25 ADC.
  10 */
  11
  12#include <dt-bindings/iio/adc/fsl-imx25-gcq.h>
  13#include <linux/clk.h>
  14#include <linux/iio/iio.h>
  15#include <linux/interrupt.h>
  16#include <linux/mfd/imx25-tsadc.h>
  17#include <linux/module.h>
  18#include <linux/of.h>
  19#include <linux/platform_device.h>
  20#include <linux/regmap.h>
  21#include <linux/regulator/consumer.h>
  22
  23#define MX25_GCQ_TIMEOUT (msecs_to_jiffies(2000))
  24
  25static const char * const driver_name = "mx25-gcq";
  26
  27enum mx25_gcq_cfgs {
  28        MX25_CFG_XP = 0,
  29        MX25_CFG_YP,
  30        MX25_CFG_XN,
  31        MX25_CFG_YN,
  32        MX25_CFG_WIPER,
  33        MX25_CFG_INAUX0,
  34        MX25_CFG_INAUX1,
  35        MX25_CFG_INAUX2,
  36        MX25_NUM_CFGS,
  37};
  38
  39struct mx25_gcq_priv {
  40        struct regmap *regs;
  41        struct completion completed;
  42        struct clk *clk;
  43        int irq;
  44        struct regulator *vref[4];
  45        u32 channel_vref_mv[MX25_NUM_CFGS];
  46};
  47
  48#define MX25_CQG_CHAN(chan, id) {\
  49        .type = IIO_VOLTAGE,\
  50        .indexed = 1,\
  51        .channel = chan,\
  52        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
  53                              BIT(IIO_CHAN_INFO_SCALE),\
  54        .datasheet_name = id,\
  55}
  56
  57static const struct iio_chan_spec mx25_gcq_channels[MX25_NUM_CFGS] = {
  58        MX25_CQG_CHAN(MX25_CFG_XP, "xp"),
  59        MX25_CQG_CHAN(MX25_CFG_YP, "yp"),
  60        MX25_CQG_CHAN(MX25_CFG_XN, "xn"),
  61        MX25_CQG_CHAN(MX25_CFG_YN, "yn"),
  62        MX25_CQG_CHAN(MX25_CFG_WIPER, "wiper"),
  63        MX25_CQG_CHAN(MX25_CFG_INAUX0, "inaux0"),
  64        MX25_CQG_CHAN(MX25_CFG_INAUX1, "inaux1"),
  65        MX25_CQG_CHAN(MX25_CFG_INAUX2, "inaux2"),
  66};
  67
  68static const char * const mx25_gcq_refp_names[] = {
  69        [MX25_ADC_REFP_YP] = "yp",
  70        [MX25_ADC_REFP_XP] = "xp",
  71        [MX25_ADC_REFP_INT] = "int",
  72        [MX25_ADC_REFP_EXT] = "ext",
  73};
  74
  75static irqreturn_t mx25_gcq_irq(int irq, void *data)
  76{
  77        struct mx25_gcq_priv *priv = data;
  78        u32 stats;
  79
  80        regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
  81
  82        if (stats & MX25_ADCQ_SR_EOQ) {
  83                regmap_update_bits(priv->regs, MX25_ADCQ_MR,
  84                                   MX25_ADCQ_MR_EOQ_IRQ, MX25_ADCQ_MR_EOQ_IRQ);
  85                complete(&priv->completed);
  86        }
  87
  88        /* Disable conversion queue run */
  89        regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
  90
  91        /* Acknowledge all possible irqs */
  92        regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
  93                     MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR |
  94                     MX25_ADCQ_SR_EOQ | MX25_ADCQ_SR_PD);
  95
  96        return IRQ_HANDLED;
  97}
  98
  99static int mx25_gcq_get_raw_value(struct device *dev,
 100                                  struct iio_chan_spec const *chan,
 101                                  struct mx25_gcq_priv *priv,
 102                                  int *val)
 103{
 104        long timeout;
 105        u32 data;
 106
 107        /* Setup the configuration we want to use */
 108        regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
 109                     MX25_ADCQ_ITEM(0, chan->channel));
 110
 111        regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ, 0);
 112
 113        /* Trigger queue for one run */
 114        regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
 115                           MX25_ADCQ_CR_FQS);
 116
 117        timeout = wait_for_completion_interruptible_timeout(
 118                &priv->completed, MX25_GCQ_TIMEOUT);
 119        if (timeout < 0) {
 120                dev_err(dev, "ADC wait for measurement failed\n");
 121                return timeout;
 122        } else if (timeout == 0) {
 123                dev_err(dev, "ADC timed out\n");
 124                return -ETIMEDOUT;
 125        }
 126
 127        regmap_read(priv->regs, MX25_ADCQ_FIFO, &data);
 128
 129        *val = MX25_ADCQ_FIFO_DATA(data);
 130
 131        return IIO_VAL_INT;
 132}
 133
 134static int mx25_gcq_read_raw(struct iio_dev *indio_dev,
 135                             struct iio_chan_spec const *chan, int *val,
 136                             int *val2, long mask)
 137{
 138        struct mx25_gcq_priv *priv = iio_priv(indio_dev);
 139        int ret;
 140
 141        switch (mask) {
 142        case IIO_CHAN_INFO_RAW:
 143                mutex_lock(&indio_dev->mlock);
 144                ret = mx25_gcq_get_raw_value(&indio_dev->dev, chan, priv, val);
 145                mutex_unlock(&indio_dev->mlock);
 146                return ret;
 147
 148        case IIO_CHAN_INFO_SCALE:
 149                *val = priv->channel_vref_mv[chan->channel];
 150                *val2 = 12;
 151                return IIO_VAL_FRACTIONAL_LOG2;
 152
 153        default:
 154                return -EINVAL;
 155        }
 156}
 157
 158static const struct iio_info mx25_gcq_iio_info = {
 159        .read_raw = mx25_gcq_read_raw,
 160};
 161
 162static const struct regmap_config mx25_gcq_regconfig = {
 163        .max_register = 0x5c,
 164        .reg_bits = 32,
 165        .val_bits = 32,
 166        .reg_stride = 4,
 167};
 168
 169static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
 170                               struct mx25_gcq_priv *priv)
 171{
 172        struct device_node *np = pdev->dev.of_node;
 173        struct device_node *child;
 174        struct device *dev = &pdev->dev;
 175        unsigned int refp_used[4] = {};
 176        int ret, i;
 177
 178        /*
 179         * Setup all configurations registers with a default conversion
 180         * configuration for each input
 181         */
 182        for (i = 0; i < MX25_NUM_CFGS; ++i)
 183                regmap_write(priv->regs, MX25_ADCQ_CFG(i),
 184                             MX25_ADCQ_CFG_YPLL_OFF |
 185                             MX25_ADCQ_CFG_XNUR_OFF |
 186                             MX25_ADCQ_CFG_XPUL_OFF |
 187                             MX25_ADCQ_CFG_REFP_INT |
 188                             MX25_ADCQ_CFG_IN(i) |
 189                             MX25_ADCQ_CFG_REFN_NGND2);
 190
 191        /*
 192         * First get all regulators to store them in channel_vref_mv if
 193         * necessary. Later we use that information for proper IIO scale
 194         * information.
 195         */
 196        priv->vref[MX25_ADC_REFP_INT] = NULL;
 197        priv->vref[MX25_ADC_REFP_EXT] =
 198                devm_regulator_get_optional(&pdev->dev, "vref-ext");
 199        priv->vref[MX25_ADC_REFP_XP] =
 200                devm_regulator_get_optional(&pdev->dev, "vref-xp");
 201        priv->vref[MX25_ADC_REFP_YP] =
 202                devm_regulator_get_optional(&pdev->dev, "vref-yp");
 203
 204        for_each_child_of_node(np, child) {
 205                u32 reg;
 206                u32 refp = MX25_ADCQ_CFG_REFP_INT;
 207                u32 refn = MX25_ADCQ_CFG_REFN_NGND2;
 208
 209                ret = of_property_read_u32(child, "reg", &reg);
 210                if (ret) {
 211                        dev_err(dev, "Failed to get reg property\n");
 212                        return ret;
 213                }
 214
 215                if (reg >= MX25_NUM_CFGS) {
 216                        dev_err(dev,
 217                                "reg value is greater than the number of available configuration registers\n");
 218                        return -EINVAL;
 219                }
 220
 221                of_property_read_u32(child, "fsl,adc-refp", &refp);
 222                of_property_read_u32(child, "fsl,adc-refn", &refn);
 223
 224                switch (refp) {
 225                case MX25_ADC_REFP_EXT:
 226                case MX25_ADC_REFP_XP:
 227                case MX25_ADC_REFP_YP:
 228                        if (IS_ERR(priv->vref[refp])) {
 229                                dev_err(dev, "Error, trying to use external voltage reference without a vref-%s regulator.",
 230                                        mx25_gcq_refp_names[refp]);
 231                                return PTR_ERR(priv->vref[refp]);
 232                        }
 233                        priv->channel_vref_mv[reg] =
 234                                regulator_get_voltage(priv->vref[refp]);
 235                        /* Conversion from uV to mV */
 236                        priv->channel_vref_mv[reg] /= 1000;
 237                        break;
 238                case MX25_ADC_REFP_INT:
 239                        priv->channel_vref_mv[reg] = 2500;
 240                        break;
 241                default:
 242                        dev_err(dev, "Invalid positive reference %d\n", refp);
 243                        return -EINVAL;
 244                }
 245
 246                ++refp_used[refp];
 247
 248                /*
 249                 * Shift the read values to the correct positions within the
 250                 * register.
 251                 */
 252                refp = MX25_ADCQ_CFG_REFP(refp);
 253                refn = MX25_ADCQ_CFG_REFN(refn);
 254
 255                if ((refp & MX25_ADCQ_CFG_REFP_MASK) != refp) {
 256                        dev_err(dev, "Invalid fsl,adc-refp property value\n");
 257                        return -EINVAL;
 258                }
 259                if ((refn & MX25_ADCQ_CFG_REFN_MASK) != refn) {
 260                        dev_err(dev, "Invalid fsl,adc-refn property value\n");
 261                        return -EINVAL;
 262                }
 263
 264                regmap_update_bits(priv->regs, MX25_ADCQ_CFG(reg),
 265                                   MX25_ADCQ_CFG_REFP_MASK |
 266                                   MX25_ADCQ_CFG_REFN_MASK,
 267                                   refp | refn);
 268        }
 269        regmap_update_bits(priv->regs, MX25_ADCQ_CR,
 270                           MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST,
 271                           MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
 272
 273        regmap_write(priv->regs, MX25_ADCQ_CR,
 274                     MX25_ADCQ_CR_PDMSK | MX25_ADCQ_CR_QSM_FQS);
 275
 276        /* Remove unused regulators */
 277        for (i = 0; i != 4; ++i) {
 278                if (!refp_used[i]) {
 279                        if (!IS_ERR_OR_NULL(priv->vref[i]))
 280                                devm_regulator_put(priv->vref[i]);
 281                        priv->vref[i] = NULL;
 282                }
 283        }
 284
 285        return 0;
 286}
 287
 288static int mx25_gcq_probe(struct platform_device *pdev)
 289{
 290        struct iio_dev *indio_dev;
 291        struct mx25_gcq_priv *priv;
 292        struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent);
 293        struct device *dev = &pdev->dev;
 294        struct resource *res;
 295        void __iomem *mem;
 296        int ret;
 297        int i;
 298
 299        indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
 300        if (!indio_dev)
 301                return -ENOMEM;
 302
 303        priv = iio_priv(indio_dev);
 304
 305        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 306        mem = devm_ioremap_resource(dev, res);
 307        if (IS_ERR(mem))
 308                return PTR_ERR(mem);
 309
 310        priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_gcq_regconfig);
 311        if (IS_ERR(priv->regs)) {
 312                dev_err(dev, "Failed to initialize regmap\n");
 313                return PTR_ERR(priv->regs);
 314        }
 315
 316        init_completion(&priv->completed);
 317
 318        ret = mx25_gcq_setup_cfgs(pdev, priv);
 319        if (ret)
 320                return ret;
 321
 322        for (i = 0; i != 4; ++i) {
 323                if (!priv->vref[i])
 324                        continue;
 325
 326                ret = regulator_enable(priv->vref[i]);
 327                if (ret)
 328                        goto err_regulator_disable;
 329        }
 330
 331        priv->clk = tsadc->clk;
 332        ret = clk_prepare_enable(priv->clk);
 333        if (ret) {
 334                dev_err(dev, "Failed to enable clock\n");
 335                goto err_vref_disable;
 336        }
 337
 338        priv->irq = platform_get_irq(pdev, 0);
 339        if (priv->irq <= 0) {
 340                dev_err(dev, "Failed to get IRQ\n");
 341                ret = priv->irq;
 342                if (!ret)
 343                        ret = -ENXIO;
 344                goto err_clk_unprepare;
 345        }
 346
 347        ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv);
 348        if (ret) {
 349                dev_err(dev, "Failed requesting IRQ\n");
 350                goto err_clk_unprepare;
 351        }
 352
 353        indio_dev->dev.parent = &pdev->dev;
 354        indio_dev->channels = mx25_gcq_channels;
 355        indio_dev->num_channels = ARRAY_SIZE(mx25_gcq_channels);
 356        indio_dev->info = &mx25_gcq_iio_info;
 357        indio_dev->name = driver_name;
 358
 359        ret = iio_device_register(indio_dev);
 360        if (ret) {
 361                dev_err(dev, "Failed to register iio device\n");
 362                goto err_irq_free;
 363        }
 364
 365        platform_set_drvdata(pdev, indio_dev);
 366
 367        return 0;
 368
 369err_irq_free:
 370        free_irq(priv->irq, priv);
 371err_clk_unprepare:
 372        clk_disable_unprepare(priv->clk);
 373err_vref_disable:
 374        i = 4;
 375err_regulator_disable:
 376        for (; i-- > 0;) {
 377                if (priv->vref[i])
 378                        regulator_disable(priv->vref[i]);
 379        }
 380        return ret;
 381}
 382
 383static int mx25_gcq_remove(struct platform_device *pdev)
 384{
 385        struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 386        struct mx25_gcq_priv *priv = iio_priv(indio_dev);
 387        int i;
 388
 389        iio_device_unregister(indio_dev);
 390        free_irq(priv->irq, priv);
 391        clk_disable_unprepare(priv->clk);
 392        for (i = 4; i-- > 0;) {
 393                if (priv->vref[i])
 394                        regulator_disable(priv->vref[i]);
 395        }
 396
 397        return 0;
 398}
 399
 400static const struct of_device_id mx25_gcq_ids[] = {
 401        { .compatible = "fsl,imx25-gcq", },
 402        { /* Sentinel */ }
 403};
 404MODULE_DEVICE_TABLE(of, mx25_gcq_ids);
 405
 406static struct platform_driver mx25_gcq_driver = {
 407        .driver         = {
 408                .name   = "mx25-gcq",
 409                .of_match_table = mx25_gcq_ids,
 410        },
 411        .probe          = mx25_gcq_probe,
 412        .remove         = mx25_gcq_remove,
 413};
 414module_platform_driver(mx25_gcq_driver);
 415
 416MODULE_DESCRIPTION("ADC driver for Freescale mx25");
 417MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
 418MODULE_LICENSE("GPL v2");
 419