aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/ads7828.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hwmon/ads7828.c')
-rw-r--r--drivers/hwmon/ads7828.c247
1 files changed, 102 insertions, 145 deletions
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 1f9e8af0f322..409b5c16defb 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -1,12 +1,14 @@
1/* 1/*
2 * ads7828.c - lm_sensors driver for ads7828 12-bit 8-channel ADC 2 * ads7828.c - driver for TI ADS7828 8-channel A/D converter and compatibles
3 * (C) 2007 EADS Astrium 3 * (C) 2007 EADS Astrium
4 * 4 *
5 * This driver is based on the lm75 and other lm_sensors/hwmon drivers 5 * This driver is based on the lm75 and other lm_sensors/hwmon drivers
6 * 6 *
7 * Written by Steve Hardy <shardy@redhat.com> 7 * Written by Steve Hardy <shardy@redhat.com>
8 * 8 *
9 * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads7828.pdf 9 * ADS7830 support, by Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
10 *
11 * For further information, see the Documentation/hwmon/ads7828 file.
10 * 12 *
11 * This program is free software; you can redistribute it and/or modify 13 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
@@ -23,63 +25,48 @@
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */ 26 */
25 27
26#include <linux/module.h> 28#include <linux/err.h>
27#include <linux/init.h>
28#include <linux/slab.h>
29#include <linux/jiffies.h>
30#include <linux/i2c.h>
31#include <linux/hwmon.h> 29#include <linux/hwmon.h>
32#include <linux/hwmon-sysfs.h> 30#include <linux/hwmon-sysfs.h>
33#include <linux/err.h> 31#include <linux/i2c.h>
32#include <linux/init.h>
33#include <linux/jiffies.h>
34#include <linux/module.h>
34#include <linux/mutex.h> 35#include <linux/mutex.h>
36#include <linux/platform_data/ads7828.h>
37#include <linux/slab.h>
35 38
36/* The ADS7828 registers */ 39/* The ADS7828 registers */
37#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */ 40#define ADS7828_NCH 8 /* 8 channels supported */
38#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ 41#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
39#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */ 42#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */
40#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */ 43#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */
41#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */ 44#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
42#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */ 45#define ADS7828_EXT_VREF_MV_MIN 50 /* External vref min value 0.05V */
43#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */ 46#define ADS7828_EXT_VREF_MV_MAX 5250 /* External vref max value 5.25V */
44#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */ 47
45 48/* List of supported devices */
46/* Addresses to scan */ 49enum ads7828_chips { ads7828, ads7830 };
47static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, 50
48 I2C_CLIENT_END }; 51/* Client specific data */
49
50/* Module parameters */
51static bool se_input = 1; /* Default is SE, 0 == diff */
52static bool int_vref = 1; /* Default is internal ref ON */
53static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */
54module_param(se_input, bool, S_IRUGO);
55module_param(int_vref, bool, S_IRUGO);
56module_param(vref_mv, int, S_IRUGO);
57
58/* Global Variables */
59static u8 ads7828_cmd_byte; /* cmd byte without channel bits */
60static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */
61
62/* Each client has this additional data */
63struct ads7828_data { 52struct ads7828_data {
64 struct device *hwmon_dev; 53 struct device *hwmon_dev;
65 struct mutex update_lock; /* mutex protect updates */ 54 struct mutex update_lock; /* Mutex protecting updates */
66 char valid; /* !=0 if following fields are valid */ 55 unsigned long last_updated; /* Last updated time (in jiffies) */
67 unsigned long last_updated; /* In jiffies */ 56 u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
68 u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */ 57 bool valid; /* Validity flag */
58 bool diff_input; /* Differential input */
59 bool ext_vref; /* External voltage reference */
60 unsigned int vref_mv; /* voltage reference value */
61 u8 cmd_byte; /* Command byte without channel bits */
62 unsigned int lsb_resol; /* Resolution of the ADC sample LSB */
63 s32 (*read_channel)(const struct i2c_client *client, u8 command);
69}; 64};
70 65
71/* Function declaration - necessary due to function dependencies */ 66/* Command byte C2,C1,C0 - see datasheet */
72static int ads7828_detect(struct i2c_client *client, 67static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
73 struct i2c_board_info *info);
74static int ads7828_probe(struct i2c_client *client,
75 const struct i2c_device_id *id);
76
77static inline u8 channel_cmd_byte(int ch)
78{ 68{
79 /* cmd byte C2,C1,C0 - see datasheet */ 69 return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
80 u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
81 cmd |= ads7828_cmd_byte;
82 return cmd;
83} 70}
84 71
85/* Update data for the device (all 8 channels) */ 72/* Update data for the device (all 8 channels) */
@@ -96,12 +83,11 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
96 dev_dbg(&client->dev, "Starting ads7828 update\n"); 83 dev_dbg(&client->dev, "Starting ads7828 update\n");
97 84
98 for (ch = 0; ch < ADS7828_NCH; ch++) { 85 for (ch = 0; ch < ADS7828_NCH; ch++) {
99 u8 cmd = channel_cmd_byte(ch); 86 u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch);
100 data->adc_input[ch] = 87 data->adc_input[ch] = data->read_channel(client, cmd);
101 i2c_smbus_read_word_swapped(client, cmd);
102 } 88 }
103 data->last_updated = jiffies; 89 data->last_updated = jiffies;
104 data->valid = 1; 90 data->valid = true;
105 } 91 }
106 92
107 mutex_unlock(&data->update_lock); 93 mutex_unlock(&data->update_lock);
@@ -110,28 +96,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
110} 96}
111 97
112/* sysfs callback function */ 98/* sysfs callback function */
113static ssize_t show_in(struct device *dev, struct device_attribute *da, 99static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
114 char *buf) 100 char *buf)
115{ 101{
116 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 102 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
117 struct ads7828_data *data = ads7828_update_device(dev); 103 struct ads7828_data *data = ads7828_update_device(dev);
118 /* Print value (in mV as specified in sysfs-interface documentation) */ 104 unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
119 return sprintf(buf, "%d\n", (data->adc_input[attr->index] * 105 data->lsb_resol, 1000);
120 ads7828_lsb_resol)/1000);
121}
122 106
123#define in_reg(offset)\ 107 return sprintf(buf, "%d\n", value);
124static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ 108}
125 NULL, offset)
126 109
127in_reg(0); 110static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
128in_reg(1); 111static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
129in_reg(2); 112static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
130in_reg(3); 113static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
131in_reg(4); 114static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
132in_reg(5); 115static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
133in_reg(6); 116static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
134in_reg(7); 117static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
135 118
136static struct attribute *ads7828_attributes[] = { 119static struct attribute *ads7828_attributes[] = {
137 &sensor_dev_attr_in0_input.dev_attr.attr, 120 &sensor_dev_attr_in0_input.dev_attr.attr,
@@ -152,60 +135,9 @@ static const struct attribute_group ads7828_group = {
152static int ads7828_remove(struct i2c_client *client) 135static int ads7828_remove(struct i2c_client *client)
153{ 136{
154 struct ads7828_data *data = i2c_get_clientdata(client); 137 struct ads7828_data *data = i2c_get_clientdata(client);
138
155 hwmon_device_unregister(data->hwmon_dev); 139 hwmon_device_unregister(data->hwmon_dev);
156 sysfs_remove_group(&client->dev.kobj, &ads7828_group); 140 sysfs_remove_group(&client->dev.kobj, &ads7828_group);
157 return 0;
158}
159
160static const struct i2c_device_id ads7828_id[] = {
161 { "ads7828", 0 },
162 { }
163};
164MODULE_DEVICE_TABLE(i2c, ads7828_id);
165
166/* This is the driver that will be inserted */
167static struct i2c_driver ads7828_driver = {
168 .class = I2C_CLASS_HWMON,
169 .driver = {
170 .name = "ads7828",
171 },
172 .probe = ads7828_probe,
173 .remove = ads7828_remove,
174 .id_table = ads7828_id,
175 .detect = ads7828_detect,
176 .address_list = normal_i2c,
177};
178
179/* Return 0 if detection is successful, -ENODEV otherwise */
180static int ads7828_detect(struct i2c_client *client,
181 struct i2c_board_info *info)
182{
183 struct i2c_adapter *adapter = client->adapter;
184 int ch;
185
186 /* Check we have a valid client */
187 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA))
188 return -ENODEV;
189
190 /*
191 * Now, we do the remaining detection. There is no identification
192 * dedicated register so attempt to sanity check using knowledge of
193 * the chip
194 * - Read from the 8 channel addresses
195 * - Check the top 4 bits of each result are not set (12 data bits)
196 */
197 for (ch = 0; ch < ADS7828_NCH; ch++) {
198 u16 in_data;
199 u8 cmd = channel_cmd_byte(ch);
200 in_data = i2c_smbus_read_word_swapped(client, cmd);
201 if (in_data & 0xF000) {
202 pr_debug("%s : Doesn't look like an ads7828 device\n",
203 __func__);
204 return -ENODEV;
205 }
206 }
207
208 strlcpy(info->type, "ads7828", I2C_NAME_SIZE);
209 141
210 return 0; 142 return 0;
211} 143}
@@ -213,6 +145,7 @@ static int ads7828_detect(struct i2c_client *client,
213static int ads7828_probe(struct i2c_client *client, 145static int ads7828_probe(struct i2c_client *client,
214 const struct i2c_device_id *id) 146 const struct i2c_device_id *id)
215{ 147{
148 struct ads7828_platform_data *pdata = client->dev.platform_data;
216 struct ads7828_data *data; 149 struct ads7828_data *data;
217 int err; 150 int err;
218 151
@@ -221,10 +154,37 @@ static int ads7828_probe(struct i2c_client *client,
221 if (!data) 154 if (!data)
222 return -ENOMEM; 155 return -ENOMEM;
223 156
157 if (pdata) {
158 data->diff_input = pdata->diff_input;
159 data->ext_vref = pdata->ext_vref;
160 if (data->ext_vref)
161 data->vref_mv = pdata->vref_mv;
162 }
163
164 /* Bound Vref with min/max values if it was provided */
165 if (data->vref_mv)
166 data->vref_mv = SENSORS_LIMIT(data->vref_mv,
167 ADS7828_EXT_VREF_MV_MIN,
168 ADS7828_EXT_VREF_MV_MAX);
169 else
170 data->vref_mv = ADS7828_INT_VREF_MV;
171
172 /* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
173 if (id->driver_data == ads7828) {
174 data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096);
175 data->read_channel = i2c_smbus_read_word_swapped;
176 } else {
177 data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256);
178 data->read_channel = i2c_smbus_read_byte_data;
179 }
180
181 data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
182 if (!data->diff_input)
183 data->cmd_byte |= ADS7828_CMD_SD_SE;
184
224 i2c_set_clientdata(client, data); 185 i2c_set_clientdata(client, data);
225 mutex_init(&data->update_lock); 186 mutex_init(&data->update_lock);
226 187
227 /* Register sysfs hooks */
228 err = sysfs_create_group(&client->dev.kobj, &ads7828_group); 188 err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
229 if (err) 189 if (err)
230 return err; 190 return err;
@@ -232,38 +192,35 @@ static int ads7828_probe(struct i2c_client *client,
232 data->hwmon_dev = hwmon_device_register(&client->dev); 192 data->hwmon_dev = hwmon_device_register(&client->dev);
233 if (IS_ERR(data->hwmon_dev)) { 193 if (IS_ERR(data->hwmon_dev)) {
234 err = PTR_ERR(data->hwmon_dev); 194 err = PTR_ERR(data->hwmon_dev);
235 goto exit_remove; 195 goto error;
236 } 196 }
237 197
238 return 0; 198 return 0;
239 199
240exit_remove: 200error:
241 sysfs_remove_group(&client->dev.kobj, &ads7828_group); 201 sysfs_remove_group(&client->dev.kobj, &ads7828_group);
242 return err; 202 return err;
243} 203}
244 204
245static int __init sensors_ads7828_init(void) 205static const struct i2c_device_id ads7828_device_ids[] = {
246{ 206 { "ads7828", ads7828 },
247 /* Initialize the command byte according to module parameters */ 207 { "ads7830", ads7830 },
248 ads7828_cmd_byte = se_input ? 208 { }
249 ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF; 209};
250 ads7828_cmd_byte |= int_vref ? 210MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
251 ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
252 211
253 /* Calculate the LSB resolution */ 212static struct i2c_driver ads7828_driver = {
254 ads7828_lsb_resol = (vref_mv*1000)/4096; 213 .driver = {
214 .name = "ads7828",
215 },
255 216
256 return i2c_add_driver(&ads7828_driver); 217 .id_table = ads7828_device_ids,
257} 218 .probe = ads7828_probe,
219 .remove = ads7828_remove,
220};
258 221
259static void __exit sensors_ads7828_exit(void) 222module_i2c_driver(ads7828_driver);
260{
261 i2c_del_driver(&ads7828_driver);
262}
263 223
264MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
265MODULE_DESCRIPTION("ADS7828 driver");
266MODULE_LICENSE("GPL"); 224MODULE_LICENSE("GPL");
267 225MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
268module_init(sensors_ads7828_init); 226MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter and compatibles");
269module_exit(sensors_ads7828_exit);