linux/drivers/hwmon/max197.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Maxim MAX197 A/D Converter driver
   4 *
   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 data
  41 * @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                else
 106                        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                else
 136                        value = 0;
 137        } else {
 138                if (value >= full)
 139                        value = full;
 140                else
 141                        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.attr
 231
 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                NULL
 255        },
 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 int 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        return 0;
 323}
 324
 325static const struct platform_device_id max197_device_ids[] = {
 326        { "max197", max197 },
 327        { "max199", max199 },
 328        { }
 329};
 330MODULE_DEVICE_TABLE(platform, max197_device_ids);
 331
 332static struct platform_driver max197_driver = {
 333        .driver = {
 334                .name = "max197",
 335        },
 336        .probe = max197_probe,
 337        .remove = max197_remove,
 338        .id_table = max197_device_ids,
 339};
 340module_platform_driver(max197_driver);
 341
 342MODULE_LICENSE("GPL");
 343MODULE_AUTHOR("Savoir-faire Linux Inc. <kernel@savoirfairelinux.com>");
 344MODULE_DESCRIPTION("Maxim MAX197 A/D Converter driver");
 345