aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/ads7828.c
diff options
context:
space:
mode:
authorVivien Didelot <vivien.didelot@savoirfairelinux.com>2012-10-03 16:54:07 -0400
committerGuenter Roeck <linux@roeck-us.net>2012-12-05 13:55:54 -0500
commit46d784629202c5da9be8d727988e7083fb455bf8 (patch)
treeabff9c58c8e94c4b9433145f67f5da33f1bbd62b /drivers/hwmon/ads7828.c
parent22e32f4f57778ebc6e17812fa3008361c05d64f9 (diff)
hwmon: (ads7828) driver cleanup
As there is no reliable way to identify the chip, it is preferable to remove the detect callback, to avoid misdetection. Module parameters are not worth it here, so let's get rid of them and add an ads7828_platform_data structure instead. Clean the code by removing unused macros, fixing coding style issues, avoiding function prototypes and using convenient macros such as module_i2c_driver(). Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Diffstat (limited to 'drivers/hwmon/ads7828.c')
-rw-r--r--drivers/hwmon/ads7828.c228
1 files changed, 86 insertions, 142 deletions
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index 1f9e8af0f322..42914fc1436d 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -6,7 +6,7 @@
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 * For further information, see the Documentation/hwmon/ads7828 file.
10 * 10 *
11 * This program is free software; you can redistribute it and/or modify 11 * 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 12 * it under the terms of the GNU General Public License as published by
@@ -23,63 +23,44 @@
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 */ 24 */
25 25
26#include <linux/module.h> 26#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> 27#include <linux/hwmon.h>
32#include <linux/hwmon-sysfs.h> 28#include <linux/hwmon-sysfs.h>
33#include <linux/err.h> 29#include <linux/i2c.h>
30#include <linux/init.h>
31#include <linux/jiffies.h>
32#include <linux/module.h>
34#include <linux/mutex.h> 33#include <linux/mutex.h>
34#include <linux/platform_data/ads7828.h>
35#include <linux/slab.h>
35 36
36/* The ADS7828 registers */ 37/* The ADS7828 registers */
37#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */ 38#define ADS7828_NCH 8 /* 8 channels supported */
38#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */ 39#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
39#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */ 40#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */
40#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */ 41#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */
41#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */ 42#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
42#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */ 43#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 */ 44#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 */ 45
45 46/* Client specific data */
46/* Addresses to scan */
47static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b,
48 I2C_CLIENT_END };
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 { 47struct ads7828_data {
64 struct device *hwmon_dev; 48 struct device *hwmon_dev;
65 struct mutex update_lock; /* mutex protect updates */ 49 struct mutex update_lock; /* Mutex protecting updates */
66 char valid; /* !=0 if following fields are valid */ 50 unsigned long last_updated; /* Last updated time (in jiffies) */
67 unsigned long last_updated; /* In jiffies */ 51 u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
68 u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */ 52 bool valid; /* Validity flag */
53 bool diff_input; /* Differential input */
54 bool ext_vref; /* External voltage reference */
55 unsigned int vref_mv; /* voltage reference value */
56 u8 cmd_byte; /* Command byte without channel bits */
57 unsigned int lsb_resol; /* Resolution of the ADC sample LSB */
69}; 58};
70 59
71/* Function declaration - necessary due to function dependencies */ 60/* Command byte C2,C1,C0 - see datasheet */
72static int ads7828_detect(struct i2c_client *client, 61static 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{ 62{
79 /* cmd byte C2,C1,C0 - see datasheet */ 63 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} 64}
84 65
85/* Update data for the device (all 8 channels) */ 66/* Update data for the device (all 8 channels) */
@@ -96,12 +77,12 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
96 dev_dbg(&client->dev, "Starting ads7828 update\n"); 77 dev_dbg(&client->dev, "Starting ads7828 update\n");
97 78
98 for (ch = 0; ch < ADS7828_NCH; ch++) { 79 for (ch = 0; ch < ADS7828_NCH; ch++) {
99 u8 cmd = channel_cmd_byte(ch); 80 u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch);
100 data->adc_input[ch] = 81 data->adc_input[ch] =
101 i2c_smbus_read_word_swapped(client, cmd); 82 i2c_smbus_read_word_swapped(client, cmd);
102 } 83 }
103 data->last_updated = jiffies; 84 data->last_updated = jiffies;
104 data->valid = 1; 85 data->valid = true;
105 } 86 }
106 87
107 mutex_unlock(&data->update_lock); 88 mutex_unlock(&data->update_lock);
@@ -110,28 +91,25 @@ static struct ads7828_data *ads7828_update_device(struct device *dev)
110} 91}
111 92
112/* sysfs callback function */ 93/* sysfs callback function */
113static ssize_t show_in(struct device *dev, struct device_attribute *da, 94static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
114 char *buf) 95 char *buf)
115{ 96{
116 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 97 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
117 struct ads7828_data *data = ads7828_update_device(dev); 98 struct ads7828_data *data = ads7828_update_device(dev);
118 /* Print value (in mV as specified in sysfs-interface documentation) */ 99 unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
119 return sprintf(buf, "%d\n", (data->adc_input[attr->index] * 100 data->lsb_resol, 1000);
120 ads7828_lsb_resol)/1000);
121}
122 101
123#define in_reg(offset)\ 102 return sprintf(buf, "%d\n", value);
124static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ 103}
125 NULL, offset)
126 104
127in_reg(0); 105static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
128in_reg(1); 106static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
129in_reg(2); 107static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
130in_reg(3); 108static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
131in_reg(4); 109static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
132in_reg(5); 110static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
133in_reg(6); 111static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
134in_reg(7); 112static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
135 113
136static struct attribute *ads7828_attributes[] = { 114static struct attribute *ads7828_attributes[] = {
137 &sensor_dev_attr_in0_input.dev_attr.attr, 115 &sensor_dev_attr_in0_input.dev_attr.attr,
@@ -152,60 +130,9 @@ static const struct attribute_group ads7828_group = {
152static int ads7828_remove(struct i2c_client *client) 130static int ads7828_remove(struct i2c_client *client)
153{ 131{
154 struct ads7828_data *data = i2c_get_clientdata(client); 132 struct ads7828_data *data = i2c_get_clientdata(client);
133
155 hwmon_device_unregister(data->hwmon_dev); 134 hwmon_device_unregister(data->hwmon_dev);
156 sysfs_remove_group(&client->dev.kobj, &ads7828_group); 135 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 136
210 return 0; 137 return 0;
211} 138}
@@ -213,6 +140,7 @@ static int ads7828_detect(struct i2c_client *client,
213static int ads7828_probe(struct i2c_client *client, 140static int ads7828_probe(struct i2c_client *client,
214 const struct i2c_device_id *id) 141 const struct i2c_device_id *id)
215{ 142{
143 struct ads7828_platform_data *pdata = client->dev.platform_data;
216 struct ads7828_data *data; 144 struct ads7828_data *data;
217 int err; 145 int err;
218 146
@@ -221,10 +149,30 @@ static int ads7828_probe(struct i2c_client *client,
221 if (!data) 149 if (!data)
222 return -ENOMEM; 150 return -ENOMEM;
223 151
152 if (pdata) {
153 data->diff_input = pdata->diff_input;
154 data->ext_vref = pdata->ext_vref;
155 if (data->ext_vref)
156 data->vref_mv = pdata->vref_mv;
157 }
158
159 /* Bound Vref with min/max values if it was provided */
160 if (data->vref_mv)
161 data->vref_mv = SENSORS_LIMIT(data->vref_mv,
162 ADS7828_EXT_VREF_MV_MIN,
163 ADS7828_EXT_VREF_MV_MAX);
164 else
165 data->vref_mv = ADS7828_INT_VREF_MV;
166
167 data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096);
168
169 data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
170 if (!data->diff_input)
171 data->cmd_byte |= ADS7828_CMD_SD_SE;
172
224 i2c_set_clientdata(client, data); 173 i2c_set_clientdata(client, data);
225 mutex_init(&data->update_lock); 174 mutex_init(&data->update_lock);
226 175
227 /* Register sysfs hooks */
228 err = sysfs_create_group(&client->dev.kobj, &ads7828_group); 176 err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
229 if (err) 177 if (err)
230 return err; 178 return err;
@@ -232,38 +180,34 @@ static int ads7828_probe(struct i2c_client *client,
232 data->hwmon_dev = hwmon_device_register(&client->dev); 180 data->hwmon_dev = hwmon_device_register(&client->dev);
233 if (IS_ERR(data->hwmon_dev)) { 181 if (IS_ERR(data->hwmon_dev)) {
234 err = PTR_ERR(data->hwmon_dev); 182 err = PTR_ERR(data->hwmon_dev);
235 goto exit_remove; 183 goto error;
236 } 184 }
237 185
238 return 0; 186 return 0;
239 187
240exit_remove: 188error:
241 sysfs_remove_group(&client->dev.kobj, &ads7828_group); 189 sysfs_remove_group(&client->dev.kobj, &ads7828_group);
242 return err; 190 return err;
243} 191}
244 192
245static int __init sensors_ads7828_init(void) 193static const struct i2c_device_id ads7828_device_ids[] = {
246{ 194 { "ads7828", 0 },
247 /* Initialize the command byte according to module parameters */ 195 { }
248 ads7828_cmd_byte = se_input ? 196};
249 ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF; 197MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
250 ads7828_cmd_byte |= int_vref ?
251 ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
252 198
253 /* Calculate the LSB resolution */ 199static struct i2c_driver ads7828_driver = {
254 ads7828_lsb_resol = (vref_mv*1000)/4096; 200 .driver = {
201 .name = "ads7828",
202 },
255 203
256 return i2c_add_driver(&ads7828_driver); 204 .id_table = ads7828_device_ids,
257} 205 .probe = ads7828_probe,
206 .remove = ads7828_remove,
207};
258 208
259static void __exit sensors_ads7828_exit(void) 209module_i2c_driver(ads7828_driver);
260{
261 i2c_del_driver(&ads7828_driver);
262}
263 210
264MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
265MODULE_DESCRIPTION("ADS7828 driver");
266MODULE_LICENSE("GPL"); 211MODULE_LICENSE("GPL");
267 212MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
268module_init(sensors_ads7828_init); 213MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter");
269module_exit(sensors_ads7828_exit);