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