250 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ltc2497-core.c - Common code for Analog Devices/Linear Technology4 * LTC2496 and LTC2497 ADCs5 *6 * Copyright (C) 2017 Analog Devices Inc.7 */8 9#include <linux/delay.h>10#include <linux/iio/iio.h>11#include <linux/iio/driver.h>12#include <linux/module.h>13#include <linux/mutex.h>14#include <linux/regulator/consumer.h>15 16#include "ltc2497.h"17 18#define LTC2497_SGL BIT(4)19#define LTC2497_DIFF 020#define LTC2497_SIGN BIT(3)21 22static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata)23{24 s64 time_elapsed;25 26 time_elapsed = ktime_ms_delta(ktime_get(), ddata->time_prev);27 28 if (time_elapsed < LTC2497_CONVERSION_TIME_MS) {29 /* delay if conversion time not passed30 * since last read or write31 */32 if (msleep_interruptible(33 LTC2497_CONVERSION_TIME_MS - time_elapsed))34 return -ERESTARTSYS;35 36 return 0;37 }38 39 if (time_elapsed - LTC2497_CONVERSION_TIME_MS <= 0) {40 /* We're in automatic mode -41 * so the last reading is still not outdated42 */43 return 0;44 }45 46 return 1;47}48 49static int ltc2497core_read(struct ltc2497core_driverdata *ddata, u8 address, int *val)50{51 int ret;52 53 ret = ltc2497core_wait_conv(ddata);54 if (ret < 0)55 return ret;56 57 if (ret || ddata->addr_prev != address) {58 ret = ddata->result_and_measure(ddata, address, NULL);59 if (ret < 0)60 return ret;61 ddata->addr_prev = address;62 63 if (msleep_interruptible(LTC2497_CONVERSION_TIME_MS))64 return -ERESTARTSYS;65 }66 67 ret = ddata->result_and_measure(ddata, address, val);68 if (ret < 0)69 return ret;70 71 ddata->time_prev = ktime_get();72 73 return ret;74}75 76static int ltc2497core_read_raw(struct iio_dev *indio_dev,77 struct iio_chan_spec const *chan,78 int *val, int *val2, long mask)79{80 struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);81 int ret;82 83 switch (mask) {84 case IIO_CHAN_INFO_RAW:85 mutex_lock(&ddata->lock);86 ret = ltc2497core_read(ddata, chan->address, val);87 mutex_unlock(&ddata->lock);88 if (ret < 0)89 return ret;90 91 return IIO_VAL_INT;92 93 case IIO_CHAN_INFO_SCALE:94 ret = regulator_get_voltage(ddata->ref);95 if (ret < 0)96 return ret;97 98 *val = ret / 1000;99 *val2 = ddata->chip_info->resolution + 1;100 101 return IIO_VAL_FRACTIONAL_LOG2;102 103 default:104 return -EINVAL;105 }106}107 108#define LTC2497_CHAN(_chan, _addr, _ds_name) { \109 .type = IIO_VOLTAGE, \110 .indexed = 1, \111 .channel = (_chan), \112 .address = (_addr | (_chan / 2) | ((_chan & 1) ? LTC2497_SIGN : 0)), \113 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \114 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \115 .datasheet_name = (_ds_name), \116}117 118#define LTC2497_CHAN_DIFF(_chan, _addr) { \119 .type = IIO_VOLTAGE, \120 .indexed = 1, \121 .channel = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 1 : 0), \122 .channel2 = (_chan) * 2 + ((_addr) & LTC2497_SIGN ? 0 : 1),\123 .address = (_addr | _chan), \124 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \125 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \126 .differential = 1, \127}128 129static const struct iio_chan_spec ltc2497core_channel[] = {130 LTC2497_CHAN(0, LTC2497_SGL, "CH0"),131 LTC2497_CHAN(1, LTC2497_SGL, "CH1"),132 LTC2497_CHAN(2, LTC2497_SGL, "CH2"),133 LTC2497_CHAN(3, LTC2497_SGL, "CH3"),134 LTC2497_CHAN(4, LTC2497_SGL, "CH4"),135 LTC2497_CHAN(5, LTC2497_SGL, "CH5"),136 LTC2497_CHAN(6, LTC2497_SGL, "CH6"),137 LTC2497_CHAN(7, LTC2497_SGL, "CH7"),138 LTC2497_CHAN(8, LTC2497_SGL, "CH8"),139 LTC2497_CHAN(9, LTC2497_SGL, "CH9"),140 LTC2497_CHAN(10, LTC2497_SGL, "CH10"),141 LTC2497_CHAN(11, LTC2497_SGL, "CH11"),142 LTC2497_CHAN(12, LTC2497_SGL, "CH12"),143 LTC2497_CHAN(13, LTC2497_SGL, "CH13"),144 LTC2497_CHAN(14, LTC2497_SGL, "CH14"),145 LTC2497_CHAN(15, LTC2497_SGL, "CH15"),146 LTC2497_CHAN_DIFF(0, LTC2497_DIFF),147 LTC2497_CHAN_DIFF(1, LTC2497_DIFF),148 LTC2497_CHAN_DIFF(2, LTC2497_DIFF),149 LTC2497_CHAN_DIFF(3, LTC2497_DIFF),150 LTC2497_CHAN_DIFF(4, LTC2497_DIFF),151 LTC2497_CHAN_DIFF(5, LTC2497_DIFF),152 LTC2497_CHAN_DIFF(6, LTC2497_DIFF),153 LTC2497_CHAN_DIFF(7, LTC2497_DIFF),154 LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN),155 LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN),156 LTC2497_CHAN_DIFF(2, LTC2497_DIFF | LTC2497_SIGN),157 LTC2497_CHAN_DIFF(3, LTC2497_DIFF | LTC2497_SIGN),158 LTC2497_CHAN_DIFF(4, LTC2497_DIFF | LTC2497_SIGN),159 LTC2497_CHAN_DIFF(5, LTC2497_DIFF | LTC2497_SIGN),160 LTC2497_CHAN_DIFF(6, LTC2497_DIFF | LTC2497_SIGN),161 LTC2497_CHAN_DIFF(7, LTC2497_DIFF | LTC2497_SIGN),162};163 164static const struct iio_info ltc2497core_info = {165 .read_raw = ltc2497core_read_raw,166};167 168int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)169{170 struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);171 int ret;172 173 /*174 * Keep using dev_name() for the iio_dev's name on some of the parts,175 * since updating it would result in a ABI breakage.176 */177 if (ddata->chip_info->name)178 indio_dev->name = ddata->chip_info->name;179 else180 indio_dev->name = dev_name(dev);181 182 indio_dev->info = <c2497core_info;183 indio_dev->modes = INDIO_DIRECT_MODE;184 indio_dev->channels = ltc2497core_channel;185 indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);186 187 ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);188 if (ret < 0)189 return ret;190 191 ddata->ref = devm_regulator_get(dev, "vref");192 if (IS_ERR(ddata->ref))193 return dev_err_probe(dev, PTR_ERR(ddata->ref),194 "Failed to get vref regulator\n");195 196 ret = regulator_enable(ddata->ref);197 if (ret < 0) {198 dev_err(dev, "Failed to enable vref regulator: %pe\n",199 ERR_PTR(ret));200 return ret;201 }202 203 if (dev->platform_data) {204 struct iio_map *plat_data;205 206 plat_data = (struct iio_map *)dev->platform_data;207 208 ret = iio_map_array_register(indio_dev, plat_data);209 if (ret) {210 dev_err(&indio_dev->dev, "iio map err: %d\n", ret);211 goto err_regulator_disable;212 }213 }214 215 ddata->addr_prev = LTC2497_CONFIG_DEFAULT;216 ddata->time_prev = ktime_get();217 218 mutex_init(&ddata->lock);219 220 ret = iio_device_register(indio_dev);221 if (ret < 0)222 goto err_array_unregister;223 224 return 0;225 226err_array_unregister:227 iio_map_array_unregister(indio_dev);228 229err_regulator_disable:230 regulator_disable(ddata->ref);231 232 return ret;233}234EXPORT_SYMBOL_NS(ltc2497core_probe, LTC2497);235 236void ltc2497core_remove(struct iio_dev *indio_dev)237{238 struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);239 240 iio_device_unregister(indio_dev);241 242 iio_map_array_unregister(indio_dev);243 244 regulator_disable(ddata->ref);245}246EXPORT_SYMBOL_NS(ltc2497core_remove, LTC2497);247 248MODULE_DESCRIPTION("common code for LTC2496/LTC2497 drivers");249MODULE_LICENSE("GPL v2");250