linux/drivers/iio/adc/rn5t618-adc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * ADC driver for the RICOH RN5T618 power management chip family
   4 *
   5 * Copyright (C) 2019 Andreas Kemnade
   6 */
   7
   8#include <linux/kernel.h>
   9#include <linux/device.h>
  10#include <linux/errno.h>
  11#include <linux/interrupt.h>
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/mfd/rn5t618.h>
  15#include <linux/platform_device.h>
  16#include <linux/completion.h>
  17#include <linux/regmap.h>
  18#include <linux/iio/iio.h>
  19#include <linux/slab.h>
  20
  21#define RN5T618_ADC_CONVERSION_TIMEOUT   (msecs_to_jiffies(500))
  22#define RN5T618_REFERENCE_VOLT 2500
  23
  24/* mask for selecting channels for single conversion */
  25#define RN5T618_ADCCNT3_CHANNEL_MASK 0x7
  26/* average 4-time conversion mode */
  27#define RN5T618_ADCCNT3_AVG BIT(3)
  28/* set for starting a single conversion, gets cleared by hw when done */
  29#define RN5T618_ADCCNT3_GODONE BIT(4)
  30/* automatic conversion, period is in ADCCNT2, selected channels are
  31 * in ADCCNT1
  32 */
  33#define RN5T618_ADCCNT3_AUTO BIT(5)
  34#define RN5T618_ADCEND_IRQ BIT(0)
  35
  36struct rn5t618_adc_data {
  37        struct device *dev;
  38        struct rn5t618 *rn5t618;
  39        struct completion conv_completion;
  40        int irq;
  41};
  42
  43struct rn5t618_channel_ratios {
  44        u16 numerator;
  45        u16 denominator;
  46};
  47
  48enum rn5t618_channels {
  49        LIMMON = 0,
  50        VBAT,
  51        VADP,
  52        VUSB,
  53        VSYS,
  54        VTHM,
  55        AIN1,
  56        AIN0
  57};
  58
  59static const struct rn5t618_channel_ratios rn5t618_ratios[8] = {
  60        [LIMMON] = {50, 32}, /* measured across 20mOhm, amplified by 32 */
  61        [VBAT] = {2, 1},
  62        [VADP] = {3, 1},
  63        [VUSB] = {3, 1},
  64        [VSYS] = {3, 1},
  65        [VTHM] = {1, 1},
  66        [AIN1] = {1, 1},
  67        [AIN0] = {1, 1},
  68};
  69
  70static int rn5t618_read_adc_reg(struct rn5t618 *rn5t618, int reg, u16 *val)
  71{
  72        u8 data[2];
  73        int ret;
  74
  75        ret = regmap_bulk_read(rn5t618->regmap, reg, data, sizeof(data));
  76        if (ret < 0)
  77                return ret;
  78
  79        *val = (data[0] << 4) | (data[1] & 0xF);
  80
  81        return 0;
  82}
  83
  84static irqreturn_t rn5t618_adc_irq(int irq, void *data)
  85{
  86        struct rn5t618_adc_data *adc = data;
  87        unsigned int r = 0;
  88        int ret;
  89
  90        /* clear low & high threshold irqs */
  91        regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC1, 0);
  92        regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC2, 0);
  93
  94        ret = regmap_read(adc->rn5t618->regmap, RN5T618_IR_ADC3, &r);
  95        if (ret < 0)
  96                dev_err(adc->dev, "failed to read IRQ status: %d\n", ret);
  97
  98        regmap_write(adc->rn5t618->regmap, RN5T618_IR_ADC3, 0);
  99
 100        if (r & RN5T618_ADCEND_IRQ)
 101                complete(&adc->conv_completion);
 102
 103        return IRQ_HANDLED;
 104}
 105
 106static int rn5t618_adc_read(struct iio_dev *iio_dev,
 107                            const struct iio_chan_spec *chan,
 108                            int *val, int *val2, long mask)
 109{
 110        struct rn5t618_adc_data *adc = iio_priv(iio_dev);
 111        u16 raw;
 112        int ret;
 113
 114        if (mask == IIO_CHAN_INFO_SCALE) {
 115                *val = RN5T618_REFERENCE_VOLT *
 116                       rn5t618_ratios[chan->channel].numerator;
 117                *val2 = rn5t618_ratios[chan->channel].denominator * 4095;
 118
 119                return IIO_VAL_FRACTIONAL;
 120        }
 121
 122        /* select channel */
 123        ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
 124                                 RN5T618_ADCCNT3_CHANNEL_MASK,
 125                                 chan->channel);
 126        if (ret < 0)
 127                return ret;
 128
 129        ret = regmap_write(adc->rn5t618->regmap, RN5T618_EN_ADCIR3,
 130                           RN5T618_ADCEND_IRQ);
 131        if (ret < 0)
 132                return ret;
 133
 134        ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
 135                                 RN5T618_ADCCNT3_AVG,
 136                                 mask == IIO_CHAN_INFO_AVERAGE_RAW ?
 137                                 RN5T618_ADCCNT3_AVG : 0);
 138        if (ret < 0)
 139                return ret;
 140
 141        init_completion(&adc->conv_completion);
 142        /* single conversion */
 143        ret = regmap_update_bits(adc->rn5t618->regmap, RN5T618_ADCCNT3,
 144                                 RN5T618_ADCCNT3_GODONE,
 145                                 RN5T618_ADCCNT3_GODONE);
 146        if (ret < 0)
 147                return ret;
 148
 149        ret = wait_for_completion_timeout(&adc->conv_completion,
 150                                          RN5T618_ADC_CONVERSION_TIMEOUT);
 151        if (ret == 0) {
 152                dev_warn(adc->dev, "timeout waiting for adc result\n");
 153                return -ETIMEDOUT;
 154        }
 155
 156        ret = rn5t618_read_adc_reg(adc->rn5t618,
 157                                   RN5T618_ILIMDATAH + 2 * chan->channel,
 158                                   &raw);
 159        if (ret < 0)
 160                return ret;
 161
 162        *val = raw;
 163
 164        return IIO_VAL_INT;
 165}
 166
 167static const struct iio_info rn5t618_adc_iio_info = {
 168        .read_raw = &rn5t618_adc_read,
 169};
 170
 171#define RN5T618_ADC_CHANNEL(_channel, _type, _name) { \
 172        .type = _type, \
 173        .channel = _channel, \
 174        .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
 175                              BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
 176                              BIT(IIO_CHAN_INFO_SCALE), \
 177        .datasheet_name = _name, \
 178        .indexed = 1. \
 179}
 180
 181static const struct iio_chan_spec rn5t618_adc_iio_channels[] = {
 182        RN5T618_ADC_CHANNEL(LIMMON, IIO_CURRENT, "LIMMON"),
 183        RN5T618_ADC_CHANNEL(VBAT, IIO_VOLTAGE, "VBAT"),
 184        RN5T618_ADC_CHANNEL(VADP, IIO_VOLTAGE, "VADP"),
 185        RN5T618_ADC_CHANNEL(VUSB, IIO_VOLTAGE, "VUSB"),
 186        RN5T618_ADC_CHANNEL(VSYS, IIO_VOLTAGE, "VSYS"),
 187        RN5T618_ADC_CHANNEL(VTHM, IIO_VOLTAGE, "VTHM"),
 188        RN5T618_ADC_CHANNEL(AIN1, IIO_VOLTAGE, "AIN1"),
 189        RN5T618_ADC_CHANNEL(AIN0, IIO_VOLTAGE, "AIN0")
 190};
 191
 192static int rn5t618_adc_probe(struct platform_device *pdev)
 193{
 194        int ret;
 195        struct iio_dev *iio_dev;
 196        struct rn5t618_adc_data *adc;
 197        struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
 198
 199        iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc));
 200        if (!iio_dev) {
 201                dev_err(&pdev->dev, "failed allocating iio device\n");
 202                return -ENOMEM;
 203        }
 204
 205        adc = iio_priv(iio_dev);
 206        adc->dev = &pdev->dev;
 207        adc->rn5t618 = rn5t618;
 208
 209        if (rn5t618->irq_data)
 210                adc->irq = regmap_irq_get_virq(rn5t618->irq_data,
 211                                               RN5T618_IRQ_ADC);
 212
 213        if (adc->irq <= 0) {
 214                dev_err(&pdev->dev, "get virq failed\n");
 215                return -EINVAL;
 216        }
 217
 218        init_completion(&adc->conv_completion);
 219
 220        iio_dev->name = dev_name(&pdev->dev);
 221        iio_dev->info = &rn5t618_adc_iio_info;
 222        iio_dev->modes = INDIO_DIRECT_MODE;
 223        iio_dev->channels = rn5t618_adc_iio_channels;
 224        iio_dev->num_channels = ARRAY_SIZE(rn5t618_adc_iio_channels);
 225
 226        /* stop any auto-conversion */
 227        ret = regmap_write(rn5t618->regmap, RN5T618_ADCCNT3, 0);
 228        if (ret < 0)
 229                return ret;
 230
 231        platform_set_drvdata(pdev, iio_dev);
 232
 233        ret = devm_request_threaded_irq(adc->dev, adc->irq, NULL,
 234                                        rn5t618_adc_irq,
 235                                        IRQF_ONESHOT, dev_name(adc->dev),
 236                                        adc);
 237        if (ret < 0) {
 238                dev_err(adc->dev, "request irq %d failed: %d\n", adc->irq, ret);
 239                return ret;
 240        }
 241
 242        return devm_iio_device_register(adc->dev, iio_dev);
 243}
 244
 245static struct platform_driver rn5t618_adc_driver = {
 246        .driver = {
 247                .name   = "rn5t618-adc",
 248        },
 249        .probe = rn5t618_adc_probe,
 250};
 251
 252module_platform_driver(rn5t618_adc_driver);
 253MODULE_ALIAS("platform:rn5t618-adc");
 254MODULE_DESCRIPTION("RICOH RN5T618 ADC driver");
 255MODULE_LICENSE("GPL");
 256