linux/drivers/staging/iio/adc/lpc32xx_adc.c
<<
>>
Prefs
   1/*
   2 *  lpc32xx_adc.c - Support for ADC in LPC32XX
   3 *
   4 *  3-channel, 10-bit ADC
   5 *
   6 *  Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.de>
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *  GNU General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License
  19 *  along with this program; if not, write to the Free Software
  20 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21 */
  22
  23#include <linux/module.h>
  24#include <linux/platform_device.h>
  25#include <linux/interrupt.h>
  26#include <linux/device.h>
  27#include <linux/kernel.h>
  28#include <linux/slab.h>
  29#include <linux/io.h>
  30#include <linux/clk.h>
  31#include <linux/err.h>
  32#include <linux/completion.h>
  33#include <linux/of.h>
  34
  35#include <linux/iio/iio.h>
  36#include <linux/iio/sysfs.h>
  37
  38/*
  39 * LPC32XX registers definitions
  40 */
  41#define LPC32XX_ADC_SELECT(x)   ((x) + 0x04)
  42#define LPC32XX_ADC_CTRL(x)     ((x) + 0x08)
  43#define LPC32XX_ADC_VALUE(x)    ((x) + 0x48)
  44
  45/* Bit definitions for LPC32XX_ADC_SELECT: */
  46#define AD_REFm         0x00000200 /* constant, always write this value! */
  47#define AD_REFp         0x00000080 /* constant, always write this value! */
  48#define AD_IN           0x00000010 /* multiple of this is the */
  49                                   /* channel number: 0, 1, 2 */
  50#define AD_INTERNAL     0x00000004 /* constant, always write this value! */
  51
  52/* Bit definitions for LPC32XX_ADC_CTRL: */
  53#define AD_STROBE       0x00000002
  54#define AD_PDN_CTRL     0x00000004
  55
  56/* Bit definitions for LPC32XX_ADC_VALUE: */
  57#define ADC_VALUE_MASK  0x000003FF
  58
  59#define MOD_NAME "lpc32xx-adc"
  60
  61struct lpc32xx_adc_info {
  62        void __iomem *adc_base;
  63        struct clk *clk;
  64        struct completion completion;
  65
  66        u32 value;
  67};
  68
  69static int lpc32xx_read_raw(struct iio_dev *indio_dev,
  70                                struct iio_chan_spec const *chan,
  71                                int *val,
  72                                int *val2,
  73                                long mask)
  74{
  75        struct lpc32xx_adc_info *info = iio_priv(indio_dev);
  76
  77        if (mask == IIO_CHAN_INFO_RAW) {
  78                mutex_lock(&indio_dev->mlock);
  79                clk_enable(info->clk);
  80                /* Measurement setup */
  81                __raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm,
  82                        LPC32XX_ADC_SELECT(info->adc_base));
  83                /* Trigger conversion */
  84                __raw_writel(AD_PDN_CTRL | AD_STROBE,
  85                        LPC32XX_ADC_CTRL(info->adc_base));
  86                wait_for_completion(&info->completion); /* set by ISR */
  87                clk_disable(info->clk);
  88                *val = info->value;
  89                mutex_unlock(&indio_dev->mlock);
  90
  91                return IIO_VAL_INT;
  92        }
  93
  94        return -EINVAL;
  95}
  96
  97static const struct iio_info lpc32xx_adc_iio_info = {
  98        .read_raw = &lpc32xx_read_raw,
  99        .driver_module = THIS_MODULE,
 100};
 101
 102#define LPC32XX_ADC_CHANNEL(_index) {                   \
 103        .type = IIO_VOLTAGE,                            \
 104        .indexed = 1,                                   \
 105        .channel = _index,                              \
 106        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
 107        .address = AD_IN * _index,                      \
 108        .scan_index = _index,                           \
 109}
 110
 111static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
 112        LPC32XX_ADC_CHANNEL(0),
 113        LPC32XX_ADC_CHANNEL(1),
 114        LPC32XX_ADC_CHANNEL(2),
 115};
 116
 117static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
 118{
 119        struct lpc32xx_adc_info *info = (struct lpc32xx_adc_info *) dev_id;
 120
 121        /* Read value and clear irq */
 122        info->value = __raw_readl(LPC32XX_ADC_VALUE(info->adc_base)) &
 123                                ADC_VALUE_MASK;
 124        complete(&info->completion);
 125
 126        return IRQ_HANDLED;
 127}
 128
 129static int lpc32xx_adc_probe(struct platform_device *pdev)
 130{
 131        struct lpc32xx_adc_info *info = NULL;
 132        struct resource *res;
 133        int retval = -ENODEV;
 134        struct iio_dev *iodev = NULL;
 135        int irq;
 136
 137        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 138        if (!res) {
 139                dev_err(&pdev->dev, "failed to get platform I/O memory\n");
 140                retval = -EBUSY;
 141                goto errout1;
 142        }
 143
 144        iodev = iio_device_alloc(sizeof(struct lpc32xx_adc_info));
 145        if (!iodev) {
 146                dev_err(&pdev->dev, "failed allocating iio device\n");
 147                retval = -ENOMEM;
 148                goto errout1;
 149        }
 150
 151        info = iio_priv(iodev);
 152
 153        info->adc_base = ioremap(res->start, resource_size(res));
 154        if (!info->adc_base) {
 155                dev_err(&pdev->dev, "failed mapping memory\n");
 156                retval = -EBUSY;
 157                goto errout2;
 158        }
 159
 160        info->clk = clk_get(&pdev->dev, NULL);
 161        if (IS_ERR(info->clk)) {
 162                dev_err(&pdev->dev, "failed getting clock\n");
 163                goto errout3;
 164        }
 165
 166        irq = platform_get_irq(pdev, 0);
 167        if ((irq < 0) || (irq >= NR_IRQS)) {
 168                dev_err(&pdev->dev, "failed getting interrupt resource\n");
 169                retval = -EINVAL;
 170                goto errout4;
 171        }
 172
 173        retval = request_irq(irq, lpc32xx_adc_isr, 0, MOD_NAME, info);
 174        if (retval < 0) {
 175                dev_err(&pdev->dev, "failed requesting interrupt\n");
 176                goto errout4;
 177        }
 178
 179        platform_set_drvdata(pdev, iodev);
 180
 181        init_completion(&info->completion);
 182
 183        iodev->name = MOD_NAME;
 184        iodev->dev.parent = &pdev->dev;
 185        iodev->info = &lpc32xx_adc_iio_info;
 186        iodev->modes = INDIO_DIRECT_MODE;
 187        iodev->channels = lpc32xx_adc_iio_channels;
 188        iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
 189
 190        retval = iio_device_register(iodev);
 191        if (retval)
 192                goto errout5;
 193
 194        dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq);
 195
 196        return 0;
 197
 198errout5:
 199        free_irq(irq, info);
 200errout4:
 201        clk_put(info->clk);
 202errout3:
 203        iounmap(info->adc_base);
 204errout2:
 205        iio_device_free(iodev);
 206errout1:
 207        return retval;
 208}
 209
 210static int lpc32xx_adc_remove(struct platform_device *pdev)
 211{
 212        struct iio_dev *iodev = platform_get_drvdata(pdev);
 213        struct lpc32xx_adc_info *info = iio_priv(iodev);
 214        int irq = platform_get_irq(pdev, 0);
 215
 216        iio_device_unregister(iodev);
 217        free_irq(irq, info);
 218        platform_set_drvdata(pdev, NULL);
 219        clk_put(info->clk);
 220        iounmap(info->adc_base);
 221        iio_device_free(iodev);
 222
 223        return 0;
 224}
 225
 226#ifdef CONFIG_OF
 227static const struct of_device_id lpc32xx_adc_match[] = {
 228        { .compatible = "nxp,lpc3220-adc" },
 229        {},
 230};
 231MODULE_DEVICE_TABLE(of, lpc32xx_adc_match);
 232#endif
 233
 234static struct platform_driver lpc32xx_adc_driver = {
 235        .probe          = lpc32xx_adc_probe,
 236        .remove         = lpc32xx_adc_remove,
 237        .driver         = {
 238                .name   = MOD_NAME,
 239                .owner  = THIS_MODULE,
 240                .of_match_table = of_match_ptr(lpc32xx_adc_match),
 241        },
 242};
 243
 244module_platform_driver(lpc32xx_adc_driver);
 245
 246MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
 247MODULE_DESCRIPTION("LPC32XX ADC driver");
 248MODULE_LICENSE("GPL");
 249