18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * IIO rescale driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2018 Axentia Technologies AB 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Peter Rosin <peda@axentia.se> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/err.h> 118c2ecf20Sopenharmony_ci#include <linux/gcd.h> 128c2ecf20Sopenharmony_ci#include <linux/iio/consumer.h> 138c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 188c2ecf20Sopenharmony_ci#include <linux/property.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct rescale; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistruct rescale_cfg { 238c2ecf20Sopenharmony_ci enum iio_chan_type type; 248c2ecf20Sopenharmony_ci int (*props)(struct device *dev, struct rescale *rescale); 258c2ecf20Sopenharmony_ci}; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct rescale { 288c2ecf20Sopenharmony_ci const struct rescale_cfg *cfg; 298c2ecf20Sopenharmony_ci struct iio_channel *source; 308c2ecf20Sopenharmony_ci struct iio_chan_spec chan; 318c2ecf20Sopenharmony_ci struct iio_chan_spec_ext_info *ext_info; 328c2ecf20Sopenharmony_ci s32 numerator; 338c2ecf20Sopenharmony_ci s32 denominator; 348c2ecf20Sopenharmony_ci}; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistatic int rescale_read_raw(struct iio_dev *indio_dev, 378c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 388c2ecf20Sopenharmony_ci int *val, int *val2, long mask) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci struct rescale *rescale = iio_priv(indio_dev); 418c2ecf20Sopenharmony_ci s64 tmp; 428c2ecf20Sopenharmony_ci int ret; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci switch (mask) { 458c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 468c2ecf20Sopenharmony_ci return iio_read_channel_raw(rescale->source, val); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 498c2ecf20Sopenharmony_ci ret = iio_read_channel_scale(rescale->source, val, val2); 508c2ecf20Sopenharmony_ci switch (ret) { 518c2ecf20Sopenharmony_ci case IIO_VAL_FRACTIONAL: 528c2ecf20Sopenharmony_ci *val *= rescale->numerator; 538c2ecf20Sopenharmony_ci *val2 *= rescale->denominator; 548c2ecf20Sopenharmony_ci return ret; 558c2ecf20Sopenharmony_ci case IIO_VAL_INT: 568c2ecf20Sopenharmony_ci *val *= rescale->numerator; 578c2ecf20Sopenharmony_ci if (rescale->denominator == 1) 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci *val2 = rescale->denominator; 608c2ecf20Sopenharmony_ci return IIO_VAL_FRACTIONAL; 618c2ecf20Sopenharmony_ci case IIO_VAL_FRACTIONAL_LOG2: 628c2ecf20Sopenharmony_ci tmp = (s64)*val * 1000000000LL; 638c2ecf20Sopenharmony_ci tmp = div_s64(tmp, rescale->denominator); 648c2ecf20Sopenharmony_ci tmp *= rescale->numerator; 658c2ecf20Sopenharmony_ci tmp = div_s64(tmp, 1000000000LL); 668c2ecf20Sopenharmony_ci *val = tmp; 678c2ecf20Sopenharmony_ci return ret; 688c2ecf20Sopenharmony_ci default: 698c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci default: 728c2ecf20Sopenharmony_ci return -EINVAL; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int rescale_read_avail(struct iio_dev *indio_dev, 778c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 788c2ecf20Sopenharmony_ci const int **vals, int *type, int *length, 798c2ecf20Sopenharmony_ci long mask) 808c2ecf20Sopenharmony_ci{ 818c2ecf20Sopenharmony_ci struct rescale *rescale = iio_priv(indio_dev); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci switch (mask) { 848c2ecf20Sopenharmony_ci case IIO_CHAN_INFO_RAW: 858c2ecf20Sopenharmony_ci *type = IIO_VAL_INT; 868c2ecf20Sopenharmony_ci return iio_read_avail_channel_raw(rescale->source, 878c2ecf20Sopenharmony_ci vals, length); 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci return -EINVAL; 908c2ecf20Sopenharmony_ci } 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic const struct iio_info rescale_info = { 948c2ecf20Sopenharmony_ci .read_raw = rescale_read_raw, 958c2ecf20Sopenharmony_ci .read_avail = rescale_read_avail, 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic ssize_t rescale_read_ext_info(struct iio_dev *indio_dev, 998c2ecf20Sopenharmony_ci uintptr_t private, 1008c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1018c2ecf20Sopenharmony_ci char *buf) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci struct rescale *rescale = iio_priv(indio_dev); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return iio_read_channel_ext_info(rescale->source, 1068c2ecf20Sopenharmony_ci rescale->ext_info[private].name, 1078c2ecf20Sopenharmony_ci buf); 1088c2ecf20Sopenharmony_ci} 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic ssize_t rescale_write_ext_info(struct iio_dev *indio_dev, 1118c2ecf20Sopenharmony_ci uintptr_t private, 1128c2ecf20Sopenharmony_ci struct iio_chan_spec const *chan, 1138c2ecf20Sopenharmony_ci const char *buf, size_t len) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct rescale *rescale = iio_priv(indio_dev); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return iio_write_channel_ext_info(rescale->source, 1188c2ecf20Sopenharmony_ci rescale->ext_info[private].name, 1198c2ecf20Sopenharmony_ci buf, len); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int rescale_configure_channel(struct device *dev, 1238c2ecf20Sopenharmony_ci struct rescale *rescale) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct iio_chan_spec *chan = &rescale->chan; 1268c2ecf20Sopenharmony_ci struct iio_chan_spec const *schan = rescale->source->channel; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci chan->indexed = 1; 1298c2ecf20Sopenharmony_ci chan->output = schan->output; 1308c2ecf20Sopenharmony_ci chan->ext_info = rescale->ext_info; 1318c2ecf20Sopenharmony_ci chan->type = rescale->cfg->type; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) || 1348c2ecf20Sopenharmony_ci !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { 1358c2ecf20Sopenharmony_ci dev_err(dev, "source channel does not support raw/scale\n"); 1368c2ecf20Sopenharmony_ci return -EINVAL; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 1408c2ecf20Sopenharmony_ci BIT(IIO_CHAN_INFO_SCALE); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW)) 1438c2ecf20Sopenharmony_ci chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return 0; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int rescale_current_sense_amplifier_props(struct device *dev, 1498c2ecf20Sopenharmony_ci struct rescale *rescale) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci u32 sense; 1528c2ecf20Sopenharmony_ci u32 gain_mult = 1; 1538c2ecf20Sopenharmony_ci u32 gain_div = 1; 1548c2ecf20Sopenharmony_ci u32 factor; 1558c2ecf20Sopenharmony_ci int ret; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "sense-resistor-micro-ohms", 1588c2ecf20Sopenharmony_ci &sense); 1598c2ecf20Sopenharmony_ci if (ret) { 1608c2ecf20Sopenharmony_ci dev_err(dev, "failed to read the sense resistance: %d\n", ret); 1618c2ecf20Sopenharmony_ci return ret; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci device_property_read_u32(dev, "sense-gain-mult", &gain_mult); 1658c2ecf20Sopenharmony_ci device_property_read_u32(dev, "sense-gain-div", &gain_div); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* 1688c2ecf20Sopenharmony_ci * Calculate the scaling factor, 1 / (gain * sense), or 1698c2ecf20Sopenharmony_ci * gain_div / (gain_mult * sense), while trying to keep the 1708c2ecf20Sopenharmony_ci * numerator/denominator from overflowing. 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci factor = gcd(sense, 1000000); 1738c2ecf20Sopenharmony_ci rescale->numerator = 1000000 / factor; 1748c2ecf20Sopenharmony_ci rescale->denominator = sense / factor; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci factor = gcd(rescale->numerator, gain_mult); 1778c2ecf20Sopenharmony_ci rescale->numerator /= factor; 1788c2ecf20Sopenharmony_ci rescale->denominator *= gain_mult / factor; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci factor = gcd(rescale->denominator, gain_div); 1818c2ecf20Sopenharmony_ci rescale->numerator *= gain_div / factor; 1828c2ecf20Sopenharmony_ci rescale->denominator /= factor; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci return 0; 1858c2ecf20Sopenharmony_ci} 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_cistatic int rescale_current_sense_shunt_props(struct device *dev, 1888c2ecf20Sopenharmony_ci struct rescale *rescale) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci u32 shunt; 1918c2ecf20Sopenharmony_ci u32 factor; 1928c2ecf20Sopenharmony_ci int ret; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "shunt-resistor-micro-ohms", 1958c2ecf20Sopenharmony_ci &shunt); 1968c2ecf20Sopenharmony_ci if (ret) { 1978c2ecf20Sopenharmony_ci dev_err(dev, "failed to read the shunt resistance: %d\n", ret); 1988c2ecf20Sopenharmony_ci return ret; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci factor = gcd(shunt, 1000000); 2028c2ecf20Sopenharmony_ci rescale->numerator = 1000000 / factor; 2038c2ecf20Sopenharmony_ci rescale->denominator = shunt / factor; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic int rescale_voltage_divider_props(struct device *dev, 2098c2ecf20Sopenharmony_ci struct rescale *rescale) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci int ret; 2128c2ecf20Sopenharmony_ci u32 factor; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "output-ohms", 2158c2ecf20Sopenharmony_ci &rescale->denominator); 2168c2ecf20Sopenharmony_ci if (ret) { 2178c2ecf20Sopenharmony_ci dev_err(dev, "failed to read output-ohms: %d\n", ret); 2188c2ecf20Sopenharmony_ci return ret; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci ret = device_property_read_u32(dev, "full-ohms", 2228c2ecf20Sopenharmony_ci &rescale->numerator); 2238c2ecf20Sopenharmony_ci if (ret) { 2248c2ecf20Sopenharmony_ci dev_err(dev, "failed to read full-ohms: %d\n", ret); 2258c2ecf20Sopenharmony_ci return ret; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci factor = gcd(rescale->numerator, rescale->denominator); 2298c2ecf20Sopenharmony_ci rescale->numerator /= factor; 2308c2ecf20Sopenharmony_ci rescale->denominator /= factor; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return 0; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cienum rescale_variant { 2368c2ecf20Sopenharmony_ci CURRENT_SENSE_AMPLIFIER, 2378c2ecf20Sopenharmony_ci CURRENT_SENSE_SHUNT, 2388c2ecf20Sopenharmony_ci VOLTAGE_DIVIDER, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic const struct rescale_cfg rescale_cfg[] = { 2428c2ecf20Sopenharmony_ci [CURRENT_SENSE_AMPLIFIER] = { 2438c2ecf20Sopenharmony_ci .type = IIO_CURRENT, 2448c2ecf20Sopenharmony_ci .props = rescale_current_sense_amplifier_props, 2458c2ecf20Sopenharmony_ci }, 2468c2ecf20Sopenharmony_ci [CURRENT_SENSE_SHUNT] = { 2478c2ecf20Sopenharmony_ci .type = IIO_CURRENT, 2488c2ecf20Sopenharmony_ci .props = rescale_current_sense_shunt_props, 2498c2ecf20Sopenharmony_ci }, 2508c2ecf20Sopenharmony_ci [VOLTAGE_DIVIDER] = { 2518c2ecf20Sopenharmony_ci .type = IIO_VOLTAGE, 2528c2ecf20Sopenharmony_ci .props = rescale_voltage_divider_props, 2538c2ecf20Sopenharmony_ci }, 2548c2ecf20Sopenharmony_ci}; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_cistatic const struct of_device_id rescale_match[] = { 2578c2ecf20Sopenharmony_ci { .compatible = "current-sense-amplifier", 2588c2ecf20Sopenharmony_ci .data = &rescale_cfg[CURRENT_SENSE_AMPLIFIER], }, 2598c2ecf20Sopenharmony_ci { .compatible = "current-sense-shunt", 2608c2ecf20Sopenharmony_ci .data = &rescale_cfg[CURRENT_SENSE_SHUNT], }, 2618c2ecf20Sopenharmony_ci { .compatible = "voltage-divider", 2628c2ecf20Sopenharmony_ci .data = &rescale_cfg[VOLTAGE_DIVIDER], }, 2638c2ecf20Sopenharmony_ci { /* sentinel */ } 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rescale_match); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int rescale_probe(struct platform_device *pdev) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 2708c2ecf20Sopenharmony_ci struct iio_dev *indio_dev; 2718c2ecf20Sopenharmony_ci struct iio_channel *source; 2728c2ecf20Sopenharmony_ci struct rescale *rescale; 2738c2ecf20Sopenharmony_ci int sizeof_ext_info; 2748c2ecf20Sopenharmony_ci int sizeof_priv; 2758c2ecf20Sopenharmony_ci int i; 2768c2ecf20Sopenharmony_ci int ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci source = devm_iio_channel_get(dev, NULL); 2798c2ecf20Sopenharmony_ci if (IS_ERR(source)) 2808c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(source), 2818c2ecf20Sopenharmony_ci "failed to get source channel\n"); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci sizeof_ext_info = iio_get_channel_ext_info_count(source); 2848c2ecf20Sopenharmony_ci if (sizeof_ext_info) { 2858c2ecf20Sopenharmony_ci sizeof_ext_info += 1; /* one extra entry for the sentinel */ 2868c2ecf20Sopenharmony_ci sizeof_ext_info *= sizeof(*rescale->ext_info); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci sizeof_priv = sizeof(*rescale) + sizeof_ext_info; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci indio_dev = devm_iio_device_alloc(dev, sizeof_priv); 2928c2ecf20Sopenharmony_ci if (!indio_dev) 2938c2ecf20Sopenharmony_ci return -ENOMEM; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci rescale = iio_priv(indio_dev); 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci rescale->cfg = of_device_get_match_data(dev); 2988c2ecf20Sopenharmony_ci rescale->numerator = 1; 2998c2ecf20Sopenharmony_ci rescale->denominator = 1; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci ret = rescale->cfg->props(dev, rescale); 3028c2ecf20Sopenharmony_ci if (ret) 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (!rescale->numerator || !rescale->denominator) { 3068c2ecf20Sopenharmony_ci dev_err(dev, "invalid scaling factor.\n"); 3078c2ecf20Sopenharmony_ci return -EINVAL; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, indio_dev); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci rescale->source = source; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci indio_dev->name = dev_name(dev); 3158c2ecf20Sopenharmony_ci indio_dev->info = &rescale_info; 3168c2ecf20Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 3178c2ecf20Sopenharmony_ci indio_dev->channels = &rescale->chan; 3188c2ecf20Sopenharmony_ci indio_dev->num_channels = 1; 3198c2ecf20Sopenharmony_ci if (sizeof_ext_info) { 3208c2ecf20Sopenharmony_ci rescale->ext_info = devm_kmemdup(dev, 3218c2ecf20Sopenharmony_ci source->channel->ext_info, 3228c2ecf20Sopenharmony_ci sizeof_ext_info, GFP_KERNEL); 3238c2ecf20Sopenharmony_ci if (!rescale->ext_info) 3248c2ecf20Sopenharmony_ci return -ENOMEM; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci for (i = 0; rescale->ext_info[i].name; ++i) { 3278c2ecf20Sopenharmony_ci struct iio_chan_spec_ext_info *ext_info = 3288c2ecf20Sopenharmony_ci &rescale->ext_info[i]; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (source->channel->ext_info[i].read) 3318c2ecf20Sopenharmony_ci ext_info->read = rescale_read_ext_info; 3328c2ecf20Sopenharmony_ci if (source->channel->ext_info[i].write) 3338c2ecf20Sopenharmony_ci ext_info->write = rescale_write_ext_info; 3348c2ecf20Sopenharmony_ci ext_info->private = i; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci ret = rescale_configure_channel(dev, rescale); 3398c2ecf20Sopenharmony_ci if (ret) 3408c2ecf20Sopenharmony_ci return ret; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci return devm_iio_device_register(dev, indio_dev); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic struct platform_driver rescale_driver = { 3468c2ecf20Sopenharmony_ci .probe = rescale_probe, 3478c2ecf20Sopenharmony_ci .driver = { 3488c2ecf20Sopenharmony_ci .name = "iio-rescale", 3498c2ecf20Sopenharmony_ci .of_match_table = rescale_match, 3508c2ecf20Sopenharmony_ci }, 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_cimodule_platform_driver(rescale_driver); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("IIO rescale driver"); 3558c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); 3568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 357