1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * IIO DAC emulation driver using a digital potentiometer 4 * 5 * Copyright (C) 2016 Axentia Technologies AB 6 * 7 * Author: Peter Rosin <peda@axentia.se> 8 */ 9 10 /* 11 * It is assumed that the dpot is used as a voltage divider between the 12 * current dpot wiper setting and the maximum resistance of the dpot. The 13 * divided voltage is provided by a vref regulator. 14 * 15 * .------. 16 * .-----------. | | 17 * | vref |--' .---. 18 * | regulator |--. | | 19 * '-----------' | | d | 20 * | | p | 21 * | | o | wiper 22 * | | t |<---------+ 23 * | | | 24 * | '---' dac output voltage 25 * | | 26 * '------+------------+ 27 */ 28 29 #include <linux/err.h> 30 #include <linux/iio/consumer.h> 31 #include <linux/iio/iio.h> 32 #include <linux/module.h> 33 #include <linux/of.h> 34 #include <linux/platform_device.h> 35 #include <linux/regulator/consumer.h> 36 37 struct dpot_dac { 38 struct regulator *vref; 39 struct iio_channel *dpot; 40 u32 max_ohms; 41 }; 42 43 static const struct iio_chan_spec dpot_dac_iio_channel = { 44 .type = IIO_VOLTAGE, 45 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) 46 | BIT(IIO_CHAN_INFO_SCALE), 47 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), 48 .output = 1, 49 .indexed = 1, 50 }; 51 52 static int dpot_dac_read_raw(struct iio_dev *indio_dev, 53 struct iio_chan_spec const *chan, 54 int *val, int *val2, long mask) 55 { 56 struct dpot_dac *dac = iio_priv(indio_dev); 57 int ret; 58 unsigned long long tmp; 59 60 switch (mask) { 61 case IIO_CHAN_INFO_RAW: 62 return iio_read_channel_raw(dac->dpot, val); 63 64 case IIO_CHAN_INFO_SCALE: 65 ret = iio_read_channel_scale(dac->dpot, val, val2); 66 switch (ret) { 67 case IIO_VAL_FRACTIONAL_LOG2: 68 tmp = *val * 1000000000LL; 69 do_div(tmp, dac->max_ohms); 70 tmp *= regulator_get_voltage(dac->vref) / 1000; 71 do_div(tmp, 1000000000LL); 72 *val = tmp; 73 return ret; 74 case IIO_VAL_INT: 75 /* 76 * Convert integer scale to fractional scale by 77 * setting the denominator (val2) to one... 78 */ 79 *val2 = 1; 80 ret = IIO_VAL_FRACTIONAL; 81 /* ...and fall through. Say it again for GCC. */ 82 fallthrough; 83 case IIO_VAL_FRACTIONAL: 84 *val *= regulator_get_voltage(dac->vref) / 1000; 85 *val2 *= dac->max_ohms; 86 break; 87 } 88 89 return ret; 90 } 91 92 return -EINVAL; 93 } 94 95 static int dpot_dac_read_avail(struct iio_dev *indio_dev, 96 struct iio_chan_spec const *chan, 97 const int **vals, int *type, int *length, 98 long mask) 99 { 100 struct dpot_dac *dac = iio_priv(indio_dev); 101 102 switch (mask) { 103 case IIO_CHAN_INFO_RAW: 104 *type = IIO_VAL_INT; 105 return iio_read_avail_channel_raw(dac->dpot, vals, length); 106 } 107 108 return -EINVAL; 109 } 110 111 static int dpot_dac_write_raw(struct iio_dev *indio_dev, 112 struct iio_chan_spec const *chan, 113 int val, int val2, long mask) 114 { 115 struct dpot_dac *dac = iio_priv(indio_dev); 116 117 switch (mask) { 118 case IIO_CHAN_INFO_RAW: 119 return iio_write_channel_raw(dac->dpot, val); 120 } 121 122 return -EINVAL; 123 } 124 125 static const struct iio_info dpot_dac_info = { 126 .read_raw = dpot_dac_read_raw, 127 .read_avail = dpot_dac_read_avail, 128 .write_raw = dpot_dac_write_raw, 129 }; 130 131 static int dpot_dac_channel_max_ohms(struct iio_dev *indio_dev) 132 { 133 struct device *dev = &indio_dev->dev; 134 struct dpot_dac *dac = iio_priv(indio_dev); 135 unsigned long long tmp; 136 int ret; 137 int val; 138 int val2; 139 int max; 140 141 ret = iio_read_max_channel_raw(dac->dpot, &max); 142 if (ret < 0) { 143 dev_err(dev, "dpot does not indicate its raw maximum value\n"); 144 return ret; 145 } 146 147 switch (iio_read_channel_scale(dac->dpot, &val, &val2)) { 148 case IIO_VAL_INT: 149 return max * val; 150 case IIO_VAL_FRACTIONAL: 151 tmp = (unsigned long long)max * val; 152 do_div(tmp, val2); 153 return tmp; 154 case IIO_VAL_FRACTIONAL_LOG2: 155 tmp = val * 1000000000LL * max >> val2; 156 do_div(tmp, 1000000000LL); 157 return tmp; 158 default: 159 dev_err(dev, "dpot has a scale that is too weird\n"); 160 } 161 162 return -EINVAL; 163 } 164 165 static int dpot_dac_probe(struct platform_device *pdev) 166 { 167 struct device *dev = &pdev->dev; 168 struct iio_dev *indio_dev; 169 struct dpot_dac *dac; 170 enum iio_chan_type type; 171 int ret; 172 173 indio_dev = devm_iio_device_alloc(dev, sizeof(*dac)); 174 if (!indio_dev) 175 return -ENOMEM; 176 177 platform_set_drvdata(pdev, indio_dev); 178 dac = iio_priv(indio_dev); 179 180 indio_dev->name = dev_name(dev); 181 indio_dev->info = &dpot_dac_info; 182 indio_dev->modes = INDIO_DIRECT_MODE; 183 indio_dev->channels = &dpot_dac_iio_channel; 184 indio_dev->num_channels = 1; 185 186 dac->vref = devm_regulator_get(dev, "vref"); 187 if (IS_ERR(dac->vref)) { 188 if (PTR_ERR(dac->vref) != -EPROBE_DEFER) 189 dev_err(&pdev->dev, "failed to get vref regulator\n"); 190 return PTR_ERR(dac->vref); 191 } 192 193 dac->dpot = devm_iio_channel_get(dev, "dpot"); 194 if (IS_ERR(dac->dpot)) { 195 if (PTR_ERR(dac->dpot) != -EPROBE_DEFER) 196 dev_err(dev, "failed to get dpot input channel\n"); 197 return PTR_ERR(dac->dpot); 198 } 199 200 ret = iio_get_channel_type(dac->dpot, &type); 201 if (ret < 0) 202 return ret; 203 204 if (type != IIO_RESISTANCE) { 205 dev_err(dev, "dpot is of the wrong type\n"); 206 return -EINVAL; 207 } 208 209 ret = dpot_dac_channel_max_ohms(indio_dev); 210 if (ret < 0) 211 return ret; 212 dac->max_ohms = ret; 213 214 ret = regulator_enable(dac->vref); 215 if (ret) { 216 dev_err(dev, "failed to enable the vref regulator\n"); 217 return ret; 218 } 219 220 ret = iio_device_register(indio_dev); 221 if (ret) { 222 dev_err(dev, "failed to register iio device\n"); 223 goto disable_reg; 224 } 225 226 return 0; 227 228 disable_reg: 229 regulator_disable(dac->vref); 230 return ret; 231 } 232 233 static int dpot_dac_remove(struct platform_device *pdev) 234 { 235 struct iio_dev *indio_dev = platform_get_drvdata(pdev); 236 struct dpot_dac *dac = iio_priv(indio_dev); 237 238 iio_device_unregister(indio_dev); 239 regulator_disable(dac->vref); 240 241 return 0; 242 } 243 244 static const struct of_device_id dpot_dac_match[] = { 245 { .compatible = "dpot-dac" }, 246 { /* sentinel */ } 247 }; 248 MODULE_DEVICE_TABLE(of, dpot_dac_match); 249 250 static struct platform_driver dpot_dac_driver = { 251 .probe = dpot_dac_probe, 252 .remove = dpot_dac_remove, 253 .driver = { 254 .name = "iio-dpot-dac", 255 .of_match_table = dpot_dac_match, 256 }, 257 }; 258 module_platform_driver(dpot_dac_driver); 259 260 MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer"); 261 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); 262 MODULE_LICENSE("GPL v2"); 263