343 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Maxim MAX197 A/D Converter driver4 *5 * Copyright (c) 2012 Savoir-faire Linux Inc.6 * Vivien Didelot <vivien.didelot@savoirfairelinux.com>7 *8 * For further information, see the Documentation/hwmon/max197.rst file.9 */10 11#include <linux/kernel.h>12#include <linux/module.h>13#include <linux/mod_devicetable.h>14#include <linux/init.h>15#include <linux/err.h>16#include <linux/slab.h>17#include <linux/mutex.h>18#include <linux/device.h>19#include <linux/sysfs.h>20#include <linux/hwmon.h>21#include <linux/hwmon-sysfs.h>22#include <linux/platform_device.h>23#include <linux/platform_data/max197.h>24 25#define MAX199_LIMIT 4000 /* 4V */26#define MAX197_LIMIT 10000 /* 10V */27 28#define MAX197_NUM_CH 8 /* 8 Analog Input Channels */29 30/* Control byte format */31#define MAX197_BIP (1 << 3) /* Bipolarity */32#define MAX197_RNG (1 << 4) /* Full range */33 34#define MAX197_SCALE 12207 /* Scale coefficient for raw data */35 36/* List of supported chips */37enum max197_chips { max197, max199 };38 39/**40 * struct max197_data - device instance specific data41 * @pdata: Platform data.42 * @hwmon_dev: The hwmon device.43 * @lock: Read/Write mutex.44 * @limit: Max range value (10V for MAX197, 4V for MAX199).45 * @scale: Need to scale.46 * @ctrl_bytes: Channels control byte.47 */48struct max197_data {49 struct max197_platform_data *pdata;50 struct device *hwmon_dev;51 struct mutex lock;52 int limit;53 bool scale;54 u8 ctrl_bytes[MAX197_NUM_CH];55};56 57static inline void max197_set_unipolarity(struct max197_data *data, int channel)58{59 data->ctrl_bytes[channel] &= ~MAX197_BIP;60}61 62static inline void max197_set_bipolarity(struct max197_data *data, int channel)63{64 data->ctrl_bytes[channel] |= MAX197_BIP;65}66 67static inline void max197_set_half_range(struct max197_data *data, int channel)68{69 data->ctrl_bytes[channel] &= ~MAX197_RNG;70}71 72static inline void max197_set_full_range(struct max197_data *data, int channel)73{74 data->ctrl_bytes[channel] |= MAX197_RNG;75}76 77static inline bool max197_is_bipolar(struct max197_data *data, int channel)78{79 return data->ctrl_bytes[channel] & MAX197_BIP;80}81 82static inline bool max197_is_full_range(struct max197_data *data, int channel)83{84 return data->ctrl_bytes[channel] & MAX197_RNG;85}86 87/* Function called on read access on in{0,1,2,3,4,5,6,7}_{min,max} */88static ssize_t max197_show_range(struct device *dev,89 struct device_attribute *devattr, char *buf)90{91 struct max197_data *data = dev_get_drvdata(dev);92 struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);93 int channel = attr->index;94 bool is_min = attr->nr;95 int range;96 97 if (mutex_lock_interruptible(&data->lock))98 return -ERESTARTSYS;99 100 range = max197_is_full_range(data, channel) ?101 data->limit : data->limit / 2;102 if (is_min) {103 if (max197_is_bipolar(data, channel))104 range = -range;105 else106 range = 0;107 }108 109 mutex_unlock(&data->lock);110 111 return sprintf(buf, "%d\n", range);112}113 114/* Function called on write access on in{0,1,2,3,4,5,6,7}_{min,max} */115static ssize_t max197_store_range(struct device *dev,116 struct device_attribute *devattr,117 const char *buf, size_t count)118{119 struct max197_data *data = dev_get_drvdata(dev);120 struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr);121 int channel = attr->index;122 bool is_min = attr->nr;123 long value;124 int half = data->limit / 2;125 int full = data->limit;126 127 if (kstrtol(buf, 10, &value))128 return -EINVAL;129 130 if (is_min) {131 if (value <= -full)132 value = -full;133 else if (value < 0)134 value = -half;135 else136 value = 0;137 } else {138 if (value >= full)139 value = full;140 else141 value = half;142 }143 144 if (mutex_lock_interruptible(&data->lock))145 return -ERESTARTSYS;146 147 if (value == 0) {148 /* We can deduce only the polarity */149 max197_set_unipolarity(data, channel);150 } else if (value == -half) {151 max197_set_bipolarity(data, channel);152 max197_set_half_range(data, channel);153 } else if (value == -full) {154 max197_set_bipolarity(data, channel);155 max197_set_full_range(data, channel);156 } else if (value == half) {157 /* We can deduce only the range */158 max197_set_half_range(data, channel);159 } else if (value == full) {160 /* We can deduce only the range */161 max197_set_full_range(data, channel);162 }163 164 mutex_unlock(&data->lock);165 166 return count;167}168 169/* Function called on read access on in{0,1,2,3,4,5,6,7}_input */170static ssize_t max197_show_input(struct device *dev,171 struct device_attribute *devattr,172 char *buf)173{174 struct max197_data *data = dev_get_drvdata(dev);175 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);176 int channel = attr->index;177 s32 value;178 int ret;179 180 if (mutex_lock_interruptible(&data->lock))181 return -ERESTARTSYS;182 183 ret = data->pdata->convert(data->ctrl_bytes[channel]);184 if (ret < 0) {185 dev_err(dev, "conversion failed\n");186 goto unlock;187 }188 value = ret;189 190 /*191 * Coefficient to apply on raw value.192 * See Table 1. Full Scale and Zero Scale in the MAX197 datasheet.193 */194 if (data->scale) {195 value *= MAX197_SCALE;196 if (max197_is_full_range(data, channel))197 value *= 2;198 value /= 10000;199 }200 201 ret = sprintf(buf, "%d\n", value);202 203unlock:204 mutex_unlock(&data->lock);205 return ret;206}207 208static ssize_t name_show(struct device *dev, struct device_attribute *attr,209 char *buf)210{211 struct platform_device *pdev = to_platform_device(dev);212 return sprintf(buf, "%s\n", pdev->name);213}214 215#define MAX197_SENSOR_DEVICE_ATTR_CH(chan) \216 static SENSOR_DEVICE_ATTR(in##chan##_input, S_IRUGO, \217 max197_show_input, NULL, chan); \218 static SENSOR_DEVICE_ATTR_2(in##chan##_min, S_IRUGO | S_IWUSR, \219 max197_show_range, \220 max197_store_range, \221 true, chan); \222 static SENSOR_DEVICE_ATTR_2(in##chan##_max, S_IRUGO | S_IWUSR, \223 max197_show_range, \224 max197_store_range, \225 false, chan)226 227#define MAX197_SENSOR_DEV_ATTR_IN(chan) \228 &sensor_dev_attr_in##chan##_input.dev_attr.attr, \229 &sensor_dev_attr_in##chan##_max.dev_attr.attr, \230 &sensor_dev_attr_in##chan##_min.dev_attr.attr231 232static DEVICE_ATTR_RO(name);233 234MAX197_SENSOR_DEVICE_ATTR_CH(0);235MAX197_SENSOR_DEVICE_ATTR_CH(1);236MAX197_SENSOR_DEVICE_ATTR_CH(2);237MAX197_SENSOR_DEVICE_ATTR_CH(3);238MAX197_SENSOR_DEVICE_ATTR_CH(4);239MAX197_SENSOR_DEVICE_ATTR_CH(5);240MAX197_SENSOR_DEVICE_ATTR_CH(6);241MAX197_SENSOR_DEVICE_ATTR_CH(7);242 243static const struct attribute_group max197_sysfs_group = {244 .attrs = (struct attribute *[]) {245 &dev_attr_name.attr,246 MAX197_SENSOR_DEV_ATTR_IN(0),247 MAX197_SENSOR_DEV_ATTR_IN(1),248 MAX197_SENSOR_DEV_ATTR_IN(2),249 MAX197_SENSOR_DEV_ATTR_IN(3),250 MAX197_SENSOR_DEV_ATTR_IN(4),251 MAX197_SENSOR_DEV_ATTR_IN(5),252 MAX197_SENSOR_DEV_ATTR_IN(6),253 MAX197_SENSOR_DEV_ATTR_IN(7),254 NULL255 },256};257 258static int max197_probe(struct platform_device *pdev)259{260 int ch, ret;261 struct max197_data *data;262 struct max197_platform_data *pdata = dev_get_platdata(&pdev->dev);263 enum max197_chips chip = platform_get_device_id(pdev)->driver_data;264 265 if (pdata == NULL) {266 dev_err(&pdev->dev, "no platform data supplied\n");267 return -EINVAL;268 }269 270 if (pdata->convert == NULL) {271 dev_err(&pdev->dev, "no convert function supplied\n");272 return -EINVAL;273 }274 275 data = devm_kzalloc(&pdev->dev, sizeof(struct max197_data), GFP_KERNEL);276 if (!data)277 return -ENOMEM;278 279 data->pdata = pdata;280 mutex_init(&data->lock);281 282 if (chip == max197) {283 data->limit = MAX197_LIMIT;284 data->scale = true;285 } else {286 data->limit = MAX199_LIMIT;287 data->scale = false;288 }289 290 for (ch = 0; ch < MAX197_NUM_CH; ch++)291 data->ctrl_bytes[ch] = (u8) ch;292 293 platform_set_drvdata(pdev, data);294 295 ret = sysfs_create_group(&pdev->dev.kobj, &max197_sysfs_group);296 if (ret) {297 dev_err(&pdev->dev, "sysfs create group failed\n");298 return ret;299 }300 301 data->hwmon_dev = hwmon_device_register(&pdev->dev);302 if (IS_ERR(data->hwmon_dev)) {303 ret = PTR_ERR(data->hwmon_dev);304 dev_err(&pdev->dev, "hwmon device register failed\n");305 goto error;306 }307 308 return 0;309 310error:311 sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);312 return ret;313}314 315static void max197_remove(struct platform_device *pdev)316{317 struct max197_data *data = platform_get_drvdata(pdev);318 319 hwmon_device_unregister(data->hwmon_dev);320 sysfs_remove_group(&pdev->dev.kobj, &max197_sysfs_group);321}322 323static const struct platform_device_id max197_device_ids[] = {324 { "max197", max197 },325 { "max199", max199 },326 { }327};328MODULE_DEVICE_TABLE(platform, max197_device_ids);329 330static struct platform_driver max197_driver = {331 .driver = {332 .name = "max197",333 },334 .probe = max197_probe,335 .remove_new = max197_remove,336 .id_table = max197_device_ids,337};338module_platform_driver(max197_driver);339 340MODULE_LICENSE("GPL");341MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");342MODULE_DESCRIPTION("Maxim MAX197 A/D Converter driver");343