linux/drivers/hwmon/ads7828.c
<<
>>
Prefs
   1/*
   2 * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles
   3 * (C) 2007 EADS Astrium
   4 *
   5 * This driver is based on the lm75 and other lm_sensors/hwmon drivers
   6 *
   7 * Written by Steve Hardy <shardy@redhat.com>
   8 *
   9 * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
  10 *
  11 * For further information, see the Documentation/hwmon/ads7828 file.
  12 *
  13 * This program is free software; you can redistribute it and/or modify
  14 * it under the terms of the GNU General Public License as published by
  15 * the Free Software Foundation; either version 2 of the License, or
  16 * (at your option) any later version.
  17 *
  18 * This program is distributed in the hope that it will be useful,
  19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21 * GNU General Public License for more details.
  22 *
  23 * You should have received a copy of the GNU General Public License
  24 * along with this program; if not, write to the Free Software
  25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 */
  27
  28#include <linux/err.h>
  29#include <linux/hwmon.h>
  30#include <linux/hwmon-sysfs.h>
  31#include <linux/i2c.h>
  32#include <linux/init.h>
  33#include <linux/module.h>
  34#include <linux/platform_data/ads7828.h>
  35#include <linux/regmap.h>
  36#include <linux/slab.h>
  37
  38/* The ADS7828 registers */
  39#define ADS7828_CMD_SD_SE       0x80    /* Single ended inputs */
  40#define ADS7828_CMD_PD1         0x04    /* Internal vref OFF && A/D ON */
  41#define ADS7828_CMD_PD3         0x0C    /* Internal vref ON && A/D ON */
  42#define ADS7828_INT_VREF_MV     2500    /* Internal vref is 2.5V, 2500mV */
  43#define ADS7828_EXT_VREF_MV_MIN 50      /* External vref min value 0.05V */
  44#define ADS7828_EXT_VREF_MV_MAX 5250    /* External vref max value 5.25V */
  45
  46/* List of supported devices */
  47enum ads7828_chips { ads7828, ads7830 };
  48
  49/* Client specific data */
  50struct ads7828_data {
  51        struct regmap *regmap;
  52        u8 cmd_byte;                    /* Command byte without channel bits */
  53        unsigned int lsb_resol;         /* Resolution of the ADC sample LSB */
  54};
  55
  56/* Command byte C2,C1,C0 - see datasheet */
  57static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
  58{
  59        return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
  60}
  61
  62/* sysfs callback function */
  63static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
  64                               char *buf)
  65{
  66        struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
  67        struct ads7828_data *data = dev_get_drvdata(dev);
  68        u8 cmd = ads7828_cmd_byte(data->cmd_byte, attr->index);
  69        unsigned int regval;
  70        int err;
  71
  72        err = regmap_read(data->regmap, cmd, &regval);
  73        if (err < 0)
  74                return err;
  75
  76        return sprintf(buf, "%d\n",
  77                       DIV_ROUND_CLOSEST(regval * data->lsb_resol, 1000));
  78}
  79
  80static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
  81static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
  82static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
  83static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
  84static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
  85static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
  86static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
  87static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
  88
  89static struct attribute *ads7828_attrs[] = {
  90        &sensor_dev_attr_in0_input.dev_attr.attr,
  91        &sensor_dev_attr_in1_input.dev_attr.attr,
  92        &sensor_dev_attr_in2_input.dev_attr.attr,
  93        &sensor_dev_attr_in3_input.dev_attr.attr,
  94        &sensor_dev_attr_in4_input.dev_attr.attr,
  95        &sensor_dev_attr_in5_input.dev_attr.attr,
  96        &sensor_dev_attr_in6_input.dev_attr.attr,
  97        &sensor_dev_attr_in7_input.dev_attr.attr,
  98        NULL
  99};
 100
 101ATTRIBUTE_GROUPS(ads7828);
 102
 103static const struct regmap_config ads2828_regmap_config = {
 104        .reg_bits = 8,
 105        .val_bits = 16,
 106};
 107
 108static const struct regmap_config ads2830_regmap_config = {
 109        .reg_bits = 8,
 110        .val_bits = 8,
 111};
 112
 113static int ads7828_probe(struct i2c_client *client,
 114                         const struct i2c_device_id *id)
 115{
 116        struct device *dev = &client->dev;
 117        struct ads7828_platform_data *pdata = dev_get_platdata(dev);
 118        struct ads7828_data *data;
 119        struct device *hwmon_dev;
 120        unsigned int vref_mv = ADS7828_INT_VREF_MV;
 121        bool diff_input = false;
 122        bool ext_vref = false;
 123        unsigned int regval;
 124
 125        data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
 126        if (!data)
 127                return -ENOMEM;
 128
 129        if (pdata) {
 130                diff_input = pdata->diff_input;
 131                ext_vref = pdata->ext_vref;
 132                if (ext_vref && pdata->vref_mv)
 133                        vref_mv = pdata->vref_mv;
 134        }
 135
 136        /* Bound Vref with min/max values */
 137        vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN,
 138                            ADS7828_EXT_VREF_MV_MAX);
 139
 140        /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
 141        if (id->driver_data == ads7828) {
 142                data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 4096);
 143                data->regmap = devm_regmap_init_i2c(client,
 144                                                    &ads2828_regmap_config);
 145        } else {
 146                data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 256);
 147                data->regmap = devm_regmap_init_i2c(client,
 148                                                    &ads2830_regmap_config);
 149        }
 150
 151        if (IS_ERR(data->regmap))
 152                return PTR_ERR(data->regmap);
 153
 154        data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
 155        if (!diff_input)
 156                data->cmd_byte |= ADS7828_CMD_SD_SE;
 157
 158        /*
 159         * Datasheet specifies internal reference voltage is disabled by
 160         * default. The internal reference voltage needs to be enabled and
 161         * voltage needs to settle before getting valid ADC data. So perform a
 162         * dummy read to enable the internal reference voltage.
 163         */
 164        if (!ext_vref)
 165                regmap_read(data->regmap, data->cmd_byte, &regval);
 166
 167        hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
 168                                                           data,
 169                                                           ads7828_groups);
 170        return PTR_ERR_OR_ZERO(hwmon_dev);
 171}
 172
 173static const struct i2c_device_id ads7828_device_ids[] = {
 174        { "ads7828", ads7828 },
 175        { "ads7830", ads7830 },
 176        { }
 177};
 178MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
 179
 180static struct i2c_driver ads7828_driver = {
 181        .driver = {
 182                .name = "ads7828",
 183        },
 184
 185        .id_table = ads7828_device_ids,
 186        .probe = ads7828_probe,
 187};
 188
 189module_i2c_driver(ads7828_driver);
 190
 191MODULE_LICENSE("GPL");
 192MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
 193MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles");
 194