linux/drivers/hwmon/pcf8591.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
   4 * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
   5 * the help of Jean Delvare <jdelvare@suse.de>
   6 */
   7
   8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9
  10#include <linux/module.h>
  11#include <linux/init.h>
  12#include <linux/slab.h>
  13#include <linux/i2c.h>
  14#include <linux/mutex.h>
  15#include <linux/err.h>
  16#include <linux/hwmon.h>
  17
  18/* Insmod parameters */
  19
  20static int input_mode;
  21module_param(input_mode, int, 0);
  22MODULE_PARM_DESC(input_mode,
  23        "Analog input mode:\n"
  24        " 0 = four single ended inputs\n"
  25        " 1 = three differential inputs\n"
  26        " 2 = single ended and differential mixed\n"
  27        " 3 = two differential inputs\n");
  28
  29/*
  30 * The PCF8591 control byte
  31 *      7    6    5    4    3    2    1    0
  32 *   |  0 |AOEF|   AIP   |  0 |AINC|  AICH   |
  33 */
  34
  35/* Analog Output Enable Flag (analog output active if 1) */
  36#define PCF8591_CONTROL_AOEF            0x40
  37
  38/*
  39 * Analog Input Programming
  40 * 0x00 = four single ended inputs
  41 * 0x10 = three differential inputs
  42 * 0x20 = single ended and differential mixed
  43 * 0x30 = two differential inputs
  44 */
  45#define PCF8591_CONTROL_AIP_MASK        0x30
  46
  47/* Autoincrement Flag (switch on if 1) */
  48#define PCF8591_CONTROL_AINC            0x04
  49
  50/*
  51 * Channel selection
  52 * 0x00 = channel 0
  53 * 0x01 = channel 1
  54 * 0x02 = channel 2
  55 * 0x03 = channel 3
  56 */
  57#define PCF8591_CONTROL_AICH_MASK       0x03
  58
  59/* Initial values */
  60#define PCF8591_INIT_CONTROL    ((input_mode << 4) | PCF8591_CONTROL_AOEF)
  61#define PCF8591_INIT_AOUT       0       /* DAC out = 0 */
  62
  63/* Conversions */
  64#define REG_TO_SIGNED(reg)      (((reg) & 0x80) ? ((reg) - 256) : (reg))
  65
  66struct pcf8591_data {
  67        struct device *hwmon_dev;
  68        struct mutex update_lock;
  69
  70        u8 control;
  71        u8 aout;
  72};
  73
  74static void pcf8591_init_client(struct i2c_client *client);
  75static int pcf8591_read_channel(struct device *dev, int channel);
  76
  77/* following are the sysfs callback functions */
  78#define show_in_channel(channel)                                        \
  79static ssize_t show_in##channel##_input(struct device *dev,             \
  80                                        struct device_attribute *attr,  \
  81                                        char *buf)                      \
  82{                                                                       \
  83        return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\
  84}                                                                       \
  85static DEVICE_ATTR(in##channel##_input, S_IRUGO,                        \
  86                   show_in##channel##_input, NULL);
  87
  88show_in_channel(0);
  89show_in_channel(1);
  90show_in_channel(2);
  91show_in_channel(3);
  92
  93static ssize_t out0_output_show(struct device *dev,
  94                                struct device_attribute *attr, char *buf)
  95{
  96        struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
  97        return sprintf(buf, "%d\n", data->aout * 10);
  98}
  99
 100static ssize_t out0_output_store(struct device *dev,
 101                                 struct device_attribute *attr,
 102                                 const char *buf, size_t count)
 103{
 104        unsigned long val;
 105        struct i2c_client *client = to_i2c_client(dev);
 106        struct pcf8591_data *data = i2c_get_clientdata(client);
 107        int err;
 108
 109        err = kstrtoul(buf, 10, &val);
 110        if (err)
 111                return err;
 112
 113        val /= 10;
 114        if (val > 255)
 115                return -EINVAL;
 116
 117        data->aout = val;
 118        i2c_smbus_write_byte_data(client, data->control, data->aout);
 119        return count;
 120}
 121
 122static DEVICE_ATTR_RW(out0_output);
 123
 124static ssize_t out0_enable_show(struct device *dev,
 125                                struct device_attribute *attr, char *buf)
 126{
 127        struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev));
 128        return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF)));
 129}
 130
 131static ssize_t out0_enable_store(struct device *dev,
 132                                 struct device_attribute *attr,
 133                                 const char *buf, size_t count)
 134{
 135        struct i2c_client *client = to_i2c_client(dev);
 136        struct pcf8591_data *data = i2c_get_clientdata(client);
 137        unsigned long val;
 138        int err;
 139
 140        err = kstrtoul(buf, 10, &val);
 141        if (err)
 142                return err;
 143
 144        mutex_lock(&data->update_lock);
 145        if (val)
 146                data->control |= PCF8591_CONTROL_AOEF;
 147        else
 148                data->control &= ~PCF8591_CONTROL_AOEF;
 149        i2c_smbus_write_byte(client, data->control);
 150        mutex_unlock(&data->update_lock);
 151        return count;
 152}
 153
 154static DEVICE_ATTR_RW(out0_enable);
 155
 156static struct attribute *pcf8591_attributes[] = {
 157        &dev_attr_out0_enable.attr,
 158        &dev_attr_out0_output.attr,
 159        &dev_attr_in0_input.attr,
 160        &dev_attr_in1_input.attr,
 161        NULL
 162};
 163
 164static const struct attribute_group pcf8591_attr_group = {
 165        .attrs = pcf8591_attributes,
 166};
 167
 168static struct attribute *pcf8591_attributes_opt[] = {
 169        &dev_attr_in2_input.attr,
 170        &dev_attr_in3_input.attr,
 171        NULL
 172};
 173
 174static const struct attribute_group pcf8591_attr_group_opt = {
 175        .attrs = pcf8591_attributes_opt,
 176};
 177
 178/*
 179 * Real code
 180 */
 181
 182static int pcf8591_probe(struct i2c_client *client)
 183{
 184        struct pcf8591_data *data;
 185        int err;
 186
 187        data = devm_kzalloc(&client->dev, sizeof(struct pcf8591_data),
 188                            GFP_KERNEL);
 189        if (!data)
 190                return -ENOMEM;
 191
 192        i2c_set_clientdata(client, data);
 193        mutex_init(&data->update_lock);
 194
 195        /* Initialize the PCF8591 chip */
 196        pcf8591_init_client(client);
 197
 198        /* Register sysfs hooks */
 199        err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group);
 200        if (err)
 201                return err;
 202
 203        /* Register input2 if not in "two differential inputs" mode */
 204        if (input_mode != 3) {
 205                err = device_create_file(&client->dev, &dev_attr_in2_input);
 206                if (err)
 207                        goto exit_sysfs_remove;
 208        }
 209
 210        /* Register input3 only in "four single ended inputs" mode */
 211        if (input_mode == 0) {
 212                err = device_create_file(&client->dev, &dev_attr_in3_input);
 213                if (err)
 214                        goto exit_sysfs_remove;
 215        }
 216
 217        data->hwmon_dev = hwmon_device_register(&client->dev);
 218        if (IS_ERR(data->hwmon_dev)) {
 219                err = PTR_ERR(data->hwmon_dev);
 220                goto exit_sysfs_remove;
 221        }
 222
 223        return 0;
 224
 225exit_sysfs_remove:
 226        sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
 227        sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
 228        return err;
 229}
 230
 231static int pcf8591_remove(struct i2c_client *client)
 232{
 233        struct pcf8591_data *data = i2c_get_clientdata(client);
 234
 235        hwmon_device_unregister(data->hwmon_dev);
 236        sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
 237        sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
 238        return 0;
 239}
 240
 241/* Called when we have found a new PCF8591. */
 242static void pcf8591_init_client(struct i2c_client *client)
 243{
 244        struct pcf8591_data *data = i2c_get_clientdata(client);
 245        data->control = PCF8591_INIT_CONTROL;
 246        data->aout = PCF8591_INIT_AOUT;
 247
 248        i2c_smbus_write_byte_data(client, data->control, data->aout);
 249
 250        /*
 251         * The first byte transmitted contains the conversion code of the
 252         * previous read cycle. FLUSH IT!
 253         */
 254        i2c_smbus_read_byte(client);
 255}
 256
 257static int pcf8591_read_channel(struct device *dev, int channel)
 258{
 259        u8 value;
 260        struct i2c_client *client = to_i2c_client(dev);
 261        struct pcf8591_data *data = i2c_get_clientdata(client);
 262
 263        mutex_lock(&data->update_lock);
 264
 265        if ((data->control & PCF8591_CONTROL_AICH_MASK) != channel) {
 266                data->control = (data->control & ~PCF8591_CONTROL_AICH_MASK)
 267                              | channel;
 268                i2c_smbus_write_byte(client, data->control);
 269
 270                /*
 271                 * The first byte transmitted contains the conversion code of
 272                 * the previous read cycle. FLUSH IT!
 273                 */
 274                i2c_smbus_read_byte(client);
 275        }
 276        value = i2c_smbus_read_byte(client);
 277
 278        mutex_unlock(&data->update_lock);
 279
 280        if ((channel == 2 && input_mode == 2) ||
 281            (channel != 3 && (input_mode == 1 || input_mode == 3)))
 282                return 10 * REG_TO_SIGNED(value);
 283        else
 284                return 10 * value;
 285}
 286
 287static const struct i2c_device_id pcf8591_id[] = {
 288        { "pcf8591", 0 },
 289        { }
 290};
 291MODULE_DEVICE_TABLE(i2c, pcf8591_id);
 292
 293static struct i2c_driver pcf8591_driver = {
 294        .driver = {
 295                .name   = "pcf8591",
 296        },
 297        .probe_new      = pcf8591_probe,
 298        .remove         = pcf8591_remove,
 299        .id_table       = pcf8591_id,
 300};
 301
 302static int __init pcf8591_init(void)
 303{
 304        if (input_mode < 0 || input_mode > 3) {
 305                pr_warn("invalid input_mode (%d)\n", input_mode);
 306                input_mode = 0;
 307        }
 308        return i2c_add_driver(&pcf8591_driver);
 309}
 310
 311static void __exit pcf8591_exit(void)
 312{
 313        i2c_del_driver(&pcf8591_driver);
 314}
 315
 316MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");
 317MODULE_DESCRIPTION("PCF8591 driver");
 318MODULE_LICENSE("GPL");
 319
 320module_init(pcf8591_init);
 321module_exit(pcf8591_exit);
 322