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