root/drivers/iio/adc/mcp3911.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mcp3911_read
  2. mcp3911_write
  3. mcp3911_update
  4. mcp3911_read_raw
  5. mcp3911_write_raw
  6. mcp3911_config
  7. mcp3911_probe
  8. mcp3911_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Driver for Microchip MCP3911, Two-channel Analog Front End
   4  *
   5  * Copyright (C) 2018 Marcus Folkesson <marcus.folkesson@gmail.com>
   6  * Copyright (C) 2018 Kent Gustavsson <kent@minoris.se>
   7  */
   8 #include <linux/clk.h>
   9 #include <linux/delay.h>
  10 #include <linux/err.h>
  11 #include <linux/iio/iio.h>
  12 #include <linux/module.h>
  13 #include <linux/regulator/consumer.h>
  14 #include <linux/spi/spi.h>
  15 
  16 #define MCP3911_REG_CHANNEL0            0x00
  17 #define MCP3911_REG_CHANNEL1            0x03
  18 #define MCP3911_REG_MOD                 0x06
  19 #define MCP3911_REG_PHASE               0x07
  20 #define MCP3911_REG_GAIN                0x09
  21 
  22 #define MCP3911_REG_STATUSCOM           0x0a
  23 #define MCP3911_STATUSCOM_CH1_24WIDTH   BIT(4)
  24 #define MCP3911_STATUSCOM_CH0_24WIDTH   BIT(3)
  25 #define MCP3911_STATUSCOM_EN_OFFCAL     BIT(2)
  26 #define MCP3911_STATUSCOM_EN_GAINCAL    BIT(1)
  27 
  28 #define MCP3911_REG_CONFIG              0x0c
  29 #define MCP3911_CONFIG_CLKEXT           BIT(1)
  30 #define MCP3911_CONFIG_VREFEXT          BIT(2)
  31 
  32 #define MCP3911_REG_OFFCAL_CH0          0x0e
  33 #define MCP3911_REG_GAINCAL_CH0         0x11
  34 #define MCP3911_REG_OFFCAL_CH1          0x14
  35 #define MCP3911_REG_GAINCAL_CH1         0x17
  36 #define MCP3911_REG_VREFCAL             0x1a
  37 
  38 #define MCP3911_CHANNEL(x)              (MCP3911_REG_CHANNEL0 + x * 3)
  39 #define MCP3911_OFFCAL(x)               (MCP3911_REG_OFFCAL_CH0 + x * 6)
  40 
  41 /* Internal voltage reference in uV */
  42 #define MCP3911_INT_VREF_UV             1200000
  43 
  44 #define MCP3911_REG_READ(reg, id)       ((((reg) << 1) | ((id) << 5) | (1 << 0)) & 0xff)
  45 #define MCP3911_REG_WRITE(reg, id)      ((((reg) << 1) | ((id) << 5) | (0 << 0)) & 0xff)
  46 
  47 #define MCP3911_NUM_CHANNELS            2
  48 
  49 struct mcp3911 {
  50         struct spi_device *spi;
  51         struct mutex lock;
  52         struct regulator *vref;
  53         struct clk *clki;
  54         u32 dev_addr;
  55 };
  56 
  57 static int mcp3911_read(struct mcp3911 *adc, u8 reg, u32 *val, u8 len)
  58 {
  59         int ret;
  60 
  61         reg = MCP3911_REG_READ(reg, adc->dev_addr);
  62         ret = spi_write_then_read(adc->spi, &reg, 1, val, len);
  63         if (ret < 0)
  64                 return ret;
  65 
  66         be32_to_cpus(val);
  67         *val >>= ((4 - len) * 8);
  68         dev_dbg(&adc->spi->dev, "reading 0x%x from register 0x%x\n", *val,
  69                 reg >> 1);
  70         return ret;
  71 }
  72 
  73 static int mcp3911_write(struct mcp3911 *adc, u8 reg, u32 val, u8 len)
  74 {
  75         dev_dbg(&adc->spi->dev, "writing 0x%x to register 0x%x\n", val, reg);
  76 
  77         val <<= (3 - len) * 8;
  78         cpu_to_be32s(&val);
  79         val |= MCP3911_REG_WRITE(reg, adc->dev_addr);
  80 
  81         return spi_write(adc->spi, &val, len + 1);
  82 }
  83 
  84 static int mcp3911_update(struct mcp3911 *adc, u8 reg, u32 mask,
  85                 u32 val, u8 len)
  86 {
  87         u32 tmp;
  88         int ret;
  89 
  90         ret = mcp3911_read(adc, reg, &tmp, len);
  91         if (ret)
  92                 return ret;
  93 
  94         val &= mask;
  95         val |= tmp & ~mask;
  96         return mcp3911_write(adc, reg, val, len);
  97 }
  98 
  99 static int mcp3911_read_raw(struct iio_dev *indio_dev,
 100                             struct iio_chan_spec const *channel, int *val,
 101                             int *val2, long mask)
 102 {
 103         struct mcp3911 *adc = iio_priv(indio_dev);
 104         int ret = -EINVAL;
 105 
 106         mutex_lock(&adc->lock);
 107         switch (mask) {
 108         case IIO_CHAN_INFO_RAW:
 109                 ret = mcp3911_read(adc,
 110                                    MCP3911_CHANNEL(channel->channel), val, 3);
 111                 if (ret)
 112                         goto out;
 113 
 114                 ret = IIO_VAL_INT;
 115                 break;
 116 
 117         case IIO_CHAN_INFO_OFFSET:
 118                 ret = mcp3911_read(adc,
 119                                    MCP3911_OFFCAL(channel->channel), val, 3);
 120                 if (ret)
 121                         goto out;
 122 
 123                 ret = IIO_VAL_INT;
 124                 break;
 125 
 126         case IIO_CHAN_INFO_SCALE:
 127                 if (adc->vref) {
 128                         ret = regulator_get_voltage(adc->vref);
 129                         if (ret < 0) {
 130                                 dev_err(indio_dev->dev.parent,
 131                                         "failed to get vref voltage: %d\n",
 132                                        ret);
 133                                 goto out;
 134                         }
 135 
 136                         *val = ret / 1000;
 137                 } else {
 138                         *val = MCP3911_INT_VREF_UV;
 139                 }
 140 
 141                 *val2 = 24;
 142                 ret = IIO_VAL_FRACTIONAL_LOG2;
 143                 break;
 144         }
 145 
 146 out:
 147         mutex_unlock(&adc->lock);
 148         return ret;
 149 }
 150 
 151 static int mcp3911_write_raw(struct iio_dev *indio_dev,
 152                             struct iio_chan_spec const *channel, int val,
 153                             int val2, long mask)
 154 {
 155         struct mcp3911 *adc = iio_priv(indio_dev);
 156         int ret = -EINVAL;
 157 
 158         mutex_lock(&adc->lock);
 159         switch (mask) {
 160         case IIO_CHAN_INFO_OFFSET:
 161                 if (val2 != 0) {
 162                         ret = -EINVAL;
 163                         goto out;
 164                 }
 165 
 166                 /* Write offset */
 167                 ret = mcp3911_write(adc, MCP3911_OFFCAL(channel->channel), val,
 168                                     3);
 169                 if (ret)
 170                         goto out;
 171 
 172                 /* Enable offset*/
 173                 ret = mcp3911_update(adc, MCP3911_REG_STATUSCOM,
 174                                 MCP3911_STATUSCOM_EN_OFFCAL,
 175                                 MCP3911_STATUSCOM_EN_OFFCAL, 2);
 176                 break;
 177         }
 178 
 179 out:
 180         mutex_unlock(&adc->lock);
 181         return ret;
 182 }
 183 
 184 #define MCP3911_CHAN(idx) {                                     \
 185                 .type = IIO_VOLTAGE,                            \
 186                 .indexed = 1,                                   \
 187                 .channel = idx,                                 \
 188                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
 189                         BIT(IIO_CHAN_INFO_OFFSET) |             \
 190                         BIT(IIO_CHAN_INFO_SCALE),               \
 191 }
 192 
 193 static const struct iio_chan_spec mcp3911_channels[] = {
 194         MCP3911_CHAN(0),
 195         MCP3911_CHAN(1),
 196 };
 197 
 198 static const struct iio_info mcp3911_info = {
 199         .read_raw = mcp3911_read_raw,
 200         .write_raw = mcp3911_write_raw,
 201 };
 202 
 203 static int mcp3911_config(struct mcp3911 *adc, struct device_node *of_node)
 204 {
 205         u32 configreg;
 206         int ret;
 207 
 208         of_property_read_u32(of_node, "device-addr", &adc->dev_addr);
 209         if (adc->dev_addr > 3) {
 210                 dev_err(&adc->spi->dev,
 211                         "invalid device address (%i). Must be in range 0-3.\n",
 212                         adc->dev_addr);
 213                 return -EINVAL;
 214         }
 215         dev_dbg(&adc->spi->dev, "use device address %i\n", adc->dev_addr);
 216 
 217         ret = mcp3911_read(adc, MCP3911_REG_CONFIG, &configreg, 2);
 218         if (ret)
 219                 return ret;
 220 
 221         if (adc->vref) {
 222                 dev_dbg(&adc->spi->dev, "use external voltage reference\n");
 223                 configreg |= MCP3911_CONFIG_VREFEXT;
 224         } else {
 225                 dev_dbg(&adc->spi->dev,
 226                         "use internal voltage reference (1.2V)\n");
 227                 configreg &= ~MCP3911_CONFIG_VREFEXT;
 228         }
 229 
 230         if (adc->clki) {
 231                 dev_dbg(&adc->spi->dev, "use external clock as clocksource\n");
 232                 configreg |= MCP3911_CONFIG_CLKEXT;
 233         } else {
 234                 dev_dbg(&adc->spi->dev,
 235                         "use crystal oscillator as clocksource\n");
 236                 configreg &= ~MCP3911_CONFIG_CLKEXT;
 237         }
 238 
 239         return  mcp3911_write(adc, MCP3911_REG_CONFIG, configreg, 2);
 240 }
 241 
 242 static int mcp3911_probe(struct spi_device *spi)
 243 {
 244         struct iio_dev *indio_dev;
 245         struct mcp3911 *adc;
 246         int ret;
 247 
 248         indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*adc));
 249         if (!indio_dev)
 250                 return -ENOMEM;
 251 
 252         adc = iio_priv(indio_dev);
 253         adc->spi = spi;
 254 
 255         adc->vref = devm_regulator_get_optional(&adc->spi->dev, "vref");
 256         if (IS_ERR(adc->vref)) {
 257                 if (PTR_ERR(adc->vref) == -ENODEV) {
 258                         adc->vref = NULL;
 259                 } else {
 260                         dev_err(&adc->spi->dev,
 261                                 "failed to get regulator (%ld)\n",
 262                                 PTR_ERR(adc->vref));
 263                         return PTR_ERR(adc->vref);
 264                 }
 265 
 266         } else {
 267                 ret = regulator_enable(adc->vref);
 268                 if (ret)
 269                         return ret;
 270         }
 271 
 272         adc->clki = devm_clk_get(&adc->spi->dev, NULL);
 273         if (IS_ERR(adc->clki)) {
 274                 if (PTR_ERR(adc->clki) == -ENOENT) {
 275                         adc->clki = NULL;
 276                 } else {
 277                         dev_err(&adc->spi->dev,
 278                                 "failed to get adc clk (%ld)\n",
 279                                 PTR_ERR(adc->clki));
 280                         ret = PTR_ERR(adc->clki);
 281                         goto reg_disable;
 282                 }
 283         } else {
 284                 ret = clk_prepare_enable(adc->clki);
 285                 if (ret < 0) {
 286                         dev_err(&adc->spi->dev,
 287                                 "Failed to enable clki: %d\n", ret);
 288                         goto reg_disable;
 289                 }
 290         }
 291 
 292         ret = mcp3911_config(adc, spi->dev.of_node);
 293         if (ret)
 294                 goto clk_disable;
 295 
 296         indio_dev->dev.parent = &spi->dev;
 297         indio_dev->dev.of_node = spi->dev.of_node;
 298         indio_dev->name = spi_get_device_id(spi)->name;
 299         indio_dev->modes = INDIO_DIRECT_MODE;
 300         indio_dev->info = &mcp3911_info;
 301         spi_set_drvdata(spi, indio_dev);
 302 
 303         indio_dev->channels = mcp3911_channels;
 304         indio_dev->num_channels = ARRAY_SIZE(mcp3911_channels);
 305 
 306         mutex_init(&adc->lock);
 307 
 308         ret = iio_device_register(indio_dev);
 309         if (ret)
 310                 goto clk_disable;
 311 
 312         return ret;
 313 
 314 clk_disable:
 315         clk_disable_unprepare(adc->clki);
 316 reg_disable:
 317         if (adc->vref)
 318                 regulator_disable(adc->vref);
 319 
 320         return ret;
 321 }
 322 
 323 static int mcp3911_remove(struct spi_device *spi)
 324 {
 325         struct iio_dev *indio_dev = spi_get_drvdata(spi);
 326         struct mcp3911 *adc = iio_priv(indio_dev);
 327 
 328         iio_device_unregister(indio_dev);
 329 
 330         clk_disable_unprepare(adc->clki);
 331         if (adc->vref)
 332                 regulator_disable(adc->vref);
 333 
 334         return 0;
 335 }
 336 
 337 static const struct of_device_id mcp3911_dt_ids[] = {
 338         { .compatible = "microchip,mcp3911" },
 339         { }
 340 };
 341 MODULE_DEVICE_TABLE(of, mcp3911_dt_ids);
 342 
 343 static const struct spi_device_id mcp3911_id[] = {
 344         { "mcp3911", 0 },
 345         { }
 346 };
 347 MODULE_DEVICE_TABLE(spi, mcp3911_id);
 348 
 349 static struct spi_driver mcp3911_driver = {
 350         .driver = {
 351                 .name = "mcp3911",
 352                 .of_match_table = mcp3911_dt_ids,
 353         },
 354         .probe = mcp3911_probe,
 355         .remove = mcp3911_remove,
 356         .id_table = mcp3911_id,
 357 };
 358 module_spi_driver(mcp3911_driver);
 359 
 360 MODULE_AUTHOR("Marcus Folkesson <marcus.folkesson@gmail.com>");
 361 MODULE_AUTHOR("Kent Gustavsson <kent@minoris.se>");
 362 MODULE_DESCRIPTION("Microchip Technology MCP3911");
 363 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */