0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029 #include <linux/err.h>
0030 #include <linux/iio/consumer.h>
0031 #include <linux/iio/iio.h>
0032 #include <linux/module.h>
0033 #include <linux/mod_devicetable.h>
0034 #include <linux/platform_device.h>
0035 #include <linux/regulator/consumer.h>
0036
0037 struct dpot_dac {
0038 struct regulator *vref;
0039 struct iio_channel *dpot;
0040 u32 max_ohms;
0041 };
0042
0043 static const struct iio_chan_spec dpot_dac_iio_channel = {
0044 .type = IIO_VOLTAGE,
0045 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW)
0046 | BIT(IIO_CHAN_INFO_SCALE),
0047 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW),
0048 .output = 1,
0049 .indexed = 1,
0050 };
0051
0052 static int dpot_dac_read_raw(struct iio_dev *indio_dev,
0053 struct iio_chan_spec const *chan,
0054 int *val, int *val2, long mask)
0055 {
0056 struct dpot_dac *dac = iio_priv(indio_dev);
0057 int ret;
0058 unsigned long long tmp;
0059
0060 switch (mask) {
0061 case IIO_CHAN_INFO_RAW:
0062 return iio_read_channel_raw(dac->dpot, val);
0063
0064 case IIO_CHAN_INFO_SCALE:
0065 ret = iio_read_channel_scale(dac->dpot, val, val2);
0066 switch (ret) {
0067 case IIO_VAL_FRACTIONAL_LOG2:
0068 tmp = *val * 1000000000LL;
0069 do_div(tmp, dac->max_ohms);
0070 tmp *= regulator_get_voltage(dac->vref) / 1000;
0071 do_div(tmp, 1000000000LL);
0072 *val = tmp;
0073 return ret;
0074 case IIO_VAL_INT:
0075
0076
0077
0078
0079 *val2 = 1;
0080 ret = IIO_VAL_FRACTIONAL;
0081
0082 fallthrough;
0083 case IIO_VAL_FRACTIONAL:
0084 *val *= regulator_get_voltage(dac->vref) / 1000;
0085 *val2 *= dac->max_ohms;
0086 break;
0087 }
0088
0089 return ret;
0090 }
0091
0092 return -EINVAL;
0093 }
0094
0095 static int dpot_dac_read_avail(struct iio_dev *indio_dev,
0096 struct iio_chan_spec const *chan,
0097 const int **vals, int *type, int *length,
0098 long mask)
0099 {
0100 struct dpot_dac *dac = iio_priv(indio_dev);
0101
0102 switch (mask) {
0103 case IIO_CHAN_INFO_RAW:
0104 *type = IIO_VAL_INT;
0105 return iio_read_avail_channel_raw(dac->dpot, vals, length);
0106 }
0107
0108 return -EINVAL;
0109 }
0110
0111 static int dpot_dac_write_raw(struct iio_dev *indio_dev,
0112 struct iio_chan_spec const *chan,
0113 int val, int val2, long mask)
0114 {
0115 struct dpot_dac *dac = iio_priv(indio_dev);
0116
0117 switch (mask) {
0118 case IIO_CHAN_INFO_RAW:
0119 return iio_write_channel_raw(dac->dpot, val);
0120 }
0121
0122 return -EINVAL;
0123 }
0124
0125 static const struct iio_info dpot_dac_info = {
0126 .read_raw = dpot_dac_read_raw,
0127 .read_avail = dpot_dac_read_avail,
0128 .write_raw = dpot_dac_write_raw,
0129 };
0130
0131 static int dpot_dac_channel_max_ohms(struct iio_dev *indio_dev)
0132 {
0133 struct device *dev = &indio_dev->dev;
0134 struct dpot_dac *dac = iio_priv(indio_dev);
0135 unsigned long long tmp;
0136 int ret;
0137 int val;
0138 int val2;
0139 int max;
0140
0141 ret = iio_read_max_channel_raw(dac->dpot, &max);
0142 if (ret < 0) {
0143 dev_err(dev, "dpot does not indicate its raw maximum value\n");
0144 return ret;
0145 }
0146
0147 switch (iio_read_channel_scale(dac->dpot, &val, &val2)) {
0148 case IIO_VAL_INT:
0149 return max * val;
0150 case IIO_VAL_FRACTIONAL:
0151 tmp = (unsigned long long)max * val;
0152 do_div(tmp, val2);
0153 return tmp;
0154 case IIO_VAL_FRACTIONAL_LOG2:
0155 tmp = val * 1000000000LL * max >> val2;
0156 do_div(tmp, 1000000000LL);
0157 return tmp;
0158 default:
0159 dev_err(dev, "dpot has a scale that is too weird\n");
0160 }
0161
0162 return -EINVAL;
0163 }
0164
0165 static int dpot_dac_probe(struct platform_device *pdev)
0166 {
0167 struct device *dev = &pdev->dev;
0168 struct iio_dev *indio_dev;
0169 struct dpot_dac *dac;
0170 enum iio_chan_type type;
0171 int ret;
0172
0173 indio_dev = devm_iio_device_alloc(dev, sizeof(*dac));
0174 if (!indio_dev)
0175 return -ENOMEM;
0176
0177 platform_set_drvdata(pdev, indio_dev);
0178 dac = iio_priv(indio_dev);
0179
0180 indio_dev->name = dev_name(dev);
0181 indio_dev->info = &dpot_dac_info;
0182 indio_dev->modes = INDIO_DIRECT_MODE;
0183 indio_dev->channels = &dpot_dac_iio_channel;
0184 indio_dev->num_channels = 1;
0185
0186 dac->vref = devm_regulator_get(dev, "vref");
0187 if (IS_ERR(dac->vref))
0188 return dev_err_probe(&pdev->dev, PTR_ERR(dac->vref),
0189 "failed to get vref regulator\n");
0190
0191 dac->dpot = devm_iio_channel_get(dev, "dpot");
0192 if (IS_ERR(dac->dpot))
0193 return dev_err_probe(&pdev->dev, PTR_ERR(dac->dpot),
0194 "failed to get dpot input channel\n");
0195
0196 ret = iio_get_channel_type(dac->dpot, &type);
0197 if (ret < 0)
0198 return ret;
0199
0200 if (type != IIO_RESISTANCE) {
0201 dev_err(dev, "dpot is of the wrong type\n");
0202 return -EINVAL;
0203 }
0204
0205 ret = dpot_dac_channel_max_ohms(indio_dev);
0206 if (ret < 0)
0207 return ret;
0208 dac->max_ohms = ret;
0209
0210 ret = regulator_enable(dac->vref);
0211 if (ret) {
0212 dev_err(dev, "failed to enable the vref regulator\n");
0213 return ret;
0214 }
0215
0216 ret = iio_device_register(indio_dev);
0217 if (ret) {
0218 dev_err(dev, "failed to register iio device\n");
0219 goto disable_reg;
0220 }
0221
0222 return 0;
0223
0224 disable_reg:
0225 regulator_disable(dac->vref);
0226 return ret;
0227 }
0228
0229 static int dpot_dac_remove(struct platform_device *pdev)
0230 {
0231 struct iio_dev *indio_dev = platform_get_drvdata(pdev);
0232 struct dpot_dac *dac = iio_priv(indio_dev);
0233
0234 iio_device_unregister(indio_dev);
0235 regulator_disable(dac->vref);
0236
0237 return 0;
0238 }
0239
0240 static const struct of_device_id dpot_dac_match[] = {
0241 { .compatible = "dpot-dac" },
0242 { }
0243 };
0244 MODULE_DEVICE_TABLE(of, dpot_dac_match);
0245
0246 static struct platform_driver dpot_dac_driver = {
0247 .probe = dpot_dac_probe,
0248 .remove = dpot_dac_remove,
0249 .driver = {
0250 .name = "iio-dpot-dac",
0251 .of_match_table = dpot_dac_match,
0252 },
0253 };
0254 module_platform_driver(dpot_dac_driver);
0255
0256 MODULE_DESCRIPTION("DAC emulation driver using a digital potentiometer");
0257 MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
0258 MODULE_LICENSE("GPL v2");