diff options
author | Vivien Didelot <vivien.didelot@savoirfairelinux.com> | 2012-10-03 16:54:07 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2012-12-05 13:55:54 -0500 |
commit | 46d784629202c5da9be8d727988e7083fb455bf8 (patch) | |
tree | abff9c58c8e94c4b9433145f67f5da33f1bbd62b /drivers/hwmon/ads7828.c | |
parent | 22e32f4f57778ebc6e17812fa3008361c05d64f9 (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.c | 228 |
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 */ | ||
47 | static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, | ||
48 | I2C_CLIENT_END }; | ||
49 | |||
50 | /* Module parameters */ | ||
51 | static bool se_input = 1; /* Default is SE, 0 == diff */ | ||
52 | static bool int_vref = 1; /* Default is internal ref ON */ | ||
53 | static int vref_mv = ADS7828_INT_VREF_MV; /* set if vref != 2.5V */ | ||
54 | module_param(se_input, bool, S_IRUGO); | ||
55 | module_param(int_vref, bool, S_IRUGO); | ||
56 | module_param(vref_mv, int, S_IRUGO); | ||
57 | |||
58 | /* Global Variables */ | ||
59 | static u8 ads7828_cmd_byte; /* cmd byte without channel bits */ | ||
60 | static unsigned int ads7828_lsb_resol; /* resolution of the ADC sample lsb */ | ||
61 | |||
62 | /* Each client has this additional data */ | ||
63 | struct ads7828_data { | 47 | struct 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 */ |
72 | static int ads7828_detect(struct i2c_client *client, | 61 | static inline u8 ads7828_cmd_byte(u8 cmd, int ch) |
73 | struct i2c_board_info *info); | ||
74 | static int ads7828_probe(struct i2c_client *client, | ||
75 | const struct i2c_device_id *id); | ||
76 | |||
77 | static 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 */ |
113 | static ssize_t show_in(struct device *dev, struct device_attribute *da, | 94 | static 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); |
124 | static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\ | 103 | } |
125 | NULL, offset) | ||
126 | 104 | ||
127 | in_reg(0); | 105 | static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0); |
128 | in_reg(1); | 106 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1); |
129 | in_reg(2); | 107 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2); |
130 | in_reg(3); | 108 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3); |
131 | in_reg(4); | 109 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4); |
132 | in_reg(5); | 110 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5); |
133 | in_reg(6); | 111 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6); |
134 | in_reg(7); | 112 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7); |
135 | 113 | ||
136 | static struct attribute *ads7828_attributes[] = { | 114 | static 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 = { | |||
152 | static int ads7828_remove(struct i2c_client *client) | 130 | static 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 | |||
160 | static const struct i2c_device_id ads7828_id[] = { | ||
161 | { "ads7828", 0 }, | ||
162 | { } | ||
163 | }; | ||
164 | MODULE_DEVICE_TABLE(i2c, ads7828_id); | ||
165 | |||
166 | /* This is the driver that will be inserted */ | ||
167 | static 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 */ | ||
180 | static 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, | |||
213 | static int ads7828_probe(struct i2c_client *client, | 140 | static 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 | ||
240 | exit_remove: | 188 | error: |
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 | ||
245 | static int __init sensors_ads7828_init(void) | 193 | static 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; | 197 | MODULE_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 */ | 199 | static 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 | ||
259 | static void __exit sensors_ads7828_exit(void) | 209 | module_i2c_driver(ads7828_driver); |
260 | { | ||
261 | i2c_del_driver(&ads7828_driver); | ||
262 | } | ||
263 | 210 | ||
264 | MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); | ||
265 | MODULE_DESCRIPTION("ADS7828 driver"); | ||
266 | MODULE_LICENSE("GPL"); | 211 | MODULE_LICENSE("GPL"); |
267 | 212 | MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>"); | |
268 | module_init(sensors_ads7828_init); | 213 | MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter"); |
269 | module_exit(sensors_ads7828_exit); | ||