linux/drivers/iio/adc/men_z188_adc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * MEN 16z188 Analog to Digial Converter
   4 *
   5 * Copyright (C) 2014 MEN Mikroelektronik GmbH (www.men.de)
   6 * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <linux/mcb.h>
  12#include <linux/io.h>
  13#include <linux/iio/iio.h>
  14
  15#define Z188_ADC_MAX_CHAN       8
  16#define Z188_ADC_GAIN           0x0700000
  17#define Z188_MODE_VOLTAGE       BIT(27)
  18#define Z188_CFG_AUTO           0x1
  19#define Z188_CTRL_REG           0x40
  20
  21#define ADC_DATA(x) (((x) >> 2) & 0x7ffffc)
  22#define ADC_OVR(x) ((x) & 0x1)
  23
  24struct z188_adc {
  25        struct resource *mem;
  26        void __iomem *base;
  27};
  28
  29#define Z188_ADC_CHANNEL(idx) {                                 \
  30                .type = IIO_VOLTAGE,                            \
  31                .indexed = 1,                                   \
  32                .channel = (idx),                               \
  33                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),   \
  34}
  35
  36static const struct iio_chan_spec z188_adc_iio_channels[] = {
  37        Z188_ADC_CHANNEL(0),
  38        Z188_ADC_CHANNEL(1),
  39        Z188_ADC_CHANNEL(2),
  40        Z188_ADC_CHANNEL(3),
  41        Z188_ADC_CHANNEL(4),
  42        Z188_ADC_CHANNEL(5),
  43        Z188_ADC_CHANNEL(6),
  44        Z188_ADC_CHANNEL(7),
  45};
  46
  47static int z188_iio_read_raw(struct iio_dev *iio_dev,
  48                        struct iio_chan_spec const *chan,
  49                        int *val,
  50                        int *val2,
  51                        long info)
  52{
  53        struct z188_adc *adc = iio_priv(iio_dev);
  54        int ret;
  55        u16 tmp;
  56
  57        switch (info) {
  58        case IIO_CHAN_INFO_RAW:
  59                tmp = readw(adc->base + chan->channel * 4);
  60
  61                if (ADC_OVR(tmp)) {
  62                        dev_info(&iio_dev->dev,
  63                                "Oversampling error on ADC channel %d\n",
  64                                chan->channel);
  65                        return -EIO;
  66                }
  67                *val = ADC_DATA(tmp);
  68                ret = IIO_VAL_INT;
  69                break;
  70        default:
  71                ret = -EINVAL;
  72                break;
  73        }
  74
  75        return ret;
  76}
  77
  78static const struct iio_info z188_adc_info = {
  79        .read_raw = &z188_iio_read_raw,
  80};
  81
  82static void men_z188_config_channels(void __iomem *addr)
  83{
  84        int i;
  85        u32 cfg;
  86        u32 ctl;
  87
  88        ctl = readl(addr + Z188_CTRL_REG);
  89        ctl |= Z188_CFG_AUTO;
  90        writel(ctl, addr + Z188_CTRL_REG);
  91
  92        for (i = 0; i < Z188_ADC_MAX_CHAN; i++) {
  93                cfg = readl(addr + i);
  94                cfg &= ~Z188_ADC_GAIN;
  95                cfg |= Z188_MODE_VOLTAGE;
  96                writel(cfg, addr + i);
  97        }
  98}
  99
 100static int men_z188_probe(struct mcb_device *dev,
 101                        const struct mcb_device_id *id)
 102{
 103        struct z188_adc *adc;
 104        struct iio_dev *indio_dev;
 105        struct resource *mem;
 106
 107        indio_dev = devm_iio_device_alloc(&dev->dev, sizeof(struct z188_adc));
 108        if (!indio_dev)
 109                return -ENOMEM;
 110
 111        adc = iio_priv(indio_dev);
 112        indio_dev->name = "z188-adc";
 113        indio_dev->info = &z188_adc_info;
 114        indio_dev->modes = INDIO_DIRECT_MODE;
 115        indio_dev->channels = z188_adc_iio_channels;
 116        indio_dev->num_channels = ARRAY_SIZE(z188_adc_iio_channels);
 117
 118        mem = mcb_request_mem(dev, "z188-adc");
 119        if (IS_ERR(mem))
 120                return PTR_ERR(mem);
 121
 122        adc->base = ioremap(mem->start, resource_size(mem));
 123        if (adc->base == NULL)
 124                goto err;
 125
 126        men_z188_config_channels(adc->base);
 127
 128        adc->mem = mem;
 129        mcb_set_drvdata(dev, indio_dev);
 130
 131        return iio_device_register(indio_dev);
 132
 133err:
 134        mcb_release_mem(mem);
 135        return -ENXIO;
 136}
 137
 138static void men_z188_remove(struct mcb_device *dev)
 139{
 140        struct iio_dev *indio_dev  = mcb_get_drvdata(dev);
 141        struct z188_adc *adc = iio_priv(indio_dev);
 142
 143        iio_device_unregister(indio_dev);
 144        iounmap(adc->base);
 145        mcb_release_mem(adc->mem);
 146}
 147
 148static const struct mcb_device_id men_z188_ids[] = {
 149        { .device = 0xbc },
 150        { }
 151};
 152MODULE_DEVICE_TABLE(mcb, men_z188_ids);
 153
 154static struct mcb_driver men_z188_driver = {
 155        .driver = {
 156                .name = "z188-adc",
 157                .owner = THIS_MODULE,
 158        },
 159        .probe = men_z188_probe,
 160        .remove = men_z188_remove,
 161        .id_table = men_z188_ids,
 162};
 163module_mcb_driver(men_z188_driver);
 164
 165MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
 166MODULE_LICENSE("GPL");
 167MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
 168MODULE_ALIAS("mcb:16z188");
 169MODULE_IMPORT_NS(MCB);
 170