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