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