Commit 46d784629202c5da9be8d727988e7083fb455bf8

Authored by Vivien Didelot
Committed by Guenter Roeck
1 parent 22e32f4f57

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>

Showing 3 changed files with 140 additions and 152 deletions Side-by-side Diff

Documentation/hwmon/ads7828
... ... @@ -4,23 +4,34 @@
4 4 Supported chips:
5 5 * Texas Instruments/Burr-Brown ADS7828
6 6 Prefix: 'ads7828'
7   - Addresses scanned: I2C 0x48, 0x49, 0x4a, 0x4b
8   - Datasheet: Publicly available at the Texas Instruments website :
  7 + Datasheet: Publicly available at the Texas Instruments website:
9 8 http://focus.ti.com/lit/ds/symlink/ads7828.pdf
10 9  
11 10 Authors:
12 11 Steve Hardy <shardy@redhat.com>
  12 + Vivien Didelot <vivien.didelot@savoirfairelinux.com>
13 13  
14   -Module Parameters
15   ------------------
  14 +Platform data
  15 +-------------
16 16  
17   -* se_input: bool (default Y)
18   - Single ended operation - set to N for differential mode
19   -* int_vref: bool (default Y)
20   - Operate with the internal 2.5V reference - set to N for external reference
21   -* vref_mv: int (default 2500)
22   - If using an external reference, set this to the reference voltage in mV
  17 +The ads7828 driver accepts an optional ads7828_platform_data structure (defined
  18 +in include/linux/platform_data/ads7828.h). The structure fields are:
23 19  
  20 +* diff_input: (bool) Differential operation
  21 + set to true for differential mode, false for default single ended mode.
  22 +
  23 +* ext_vref: (bool) External reference
  24 + set to true if it operates with an external reference, false for default
  25 + internal reference.
  26 +
  27 +* vref_mv: (unsigned int) Voltage reference
  28 + if using an external reference, set this to the reference voltage in mV,
  29 + otherwise it will default to the internal value (2500mV). This value will be
  30 + bounded with limits accepted by the chip, described in the datasheet.
  31 +
  32 + If no structure is provided, the configuration defaults to single ended
  33 + operation and internal voltage reference (2.5V).
  34 +
24 35 Description
25 36 -----------
26 37  
... ... @@ -34,4 +45,8 @@
34 45 The chip also has the facility to use an external voltage reference. This
35 46 may be required if your hardware supplies the ADS7828 from a 5V supply, see
36 47 the datasheet for more details.
  48 +
  49 +There is no reliable way to identify this chip, so the driver will not scan
  50 +some addresses to try to auto-detect it. That means that you will have to
  51 +statically declare the device in the platform support code.
drivers/hwmon/ads7828.c
... ... @@ -6,7 +6,7 @@
6 6 *
7 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 11 * This program is free software; you can redistribute it and/or modify
12 12 * it under the terms of the GNU General Public License as published by
13 13  
14 14  
15 15  
16 16  
17 17  
18 18  
19 19  
... ... @@ -23,63 +23,44 @@
23 23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 24 */
25 25  
26   -#include <linux/module.h>
27   -#include <linux/init.h>
28   -#include <linux/slab.h>
29   -#include <linux/jiffies.h>
30   -#include <linux/i2c.h>
  26 +#include <linux/err.h>
31 27 #include <linux/hwmon.h>
32 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 33 #include <linux/mutex.h>
  34 +#include <linux/platform_data/ads7828.h>
  35 +#include <linux/slab.h>
35 36  
36 37 /* The ADS7828 registers */
37   -#define ADS7828_NCH 8 /* 8 channels of 12-bit A-D supported */
38   -#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
39   -#define ADS7828_CMD_SD_DIFF 0x00 /* Differential inputs */
40   -#define ADS7828_CMD_PD0 0x0 /* Power Down between A-D conversions */
41   -#define ADS7828_CMD_PD1 0x04 /* Internal ref OFF && A-D ON */
42   -#define ADS7828_CMD_PD2 0x08 /* Internal ref ON && A-D OFF */
43   -#define ADS7828_CMD_PD3 0x0C /* Internal ref ON && A-D ON */
44   -#define ADS7828_INT_VREF_MV 2500 /* Internal vref is 2.5V, 2500mV */
  38 +#define ADS7828_NCH 8 /* 8 channels supported */
  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 45  
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 */
  46 +/* Client specific data */
63 47 struct ads7828_data {
64 48 struct device *hwmon_dev;
65   - struct mutex update_lock; /* mutex protect updates */
66   - char valid; /* !=0 if following fields are valid */
67   - unsigned long last_updated; /* In jiffies */
68   - u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 12-bit samples */
  49 + struct mutex update_lock; /* Mutex protecting updates */
  50 + unsigned long last_updated; /* Last updated time (in jiffies) */
  51 + u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH 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 */
72   -static int ads7828_detect(struct i2c_client *client,
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)
  60 +/* Command byte C2,C1,C0 - see datasheet */
  61 +static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
78 62 {
79   - /* cmd byte C2,C1,C0 - see datasheet */
80   - u8 cmd = (((ch>>1) | (ch&0x01)<<2)<<4);
81   - cmd |= ads7828_cmd_byte;
82   - return cmd;
  63 + return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
83 64 }
84 65  
85 66 /* Update data for the device (all 8 channels) */
86 67  
... ... @@ -96,12 +77,12 @@
96 77 dev_dbg(&client->dev, "Starting ads7828 update\n");
97 78  
98 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 81 data->adc_input[ch] =
101 82 i2c_smbus_read_word_swapped(client, cmd);
102 83 }
103 84 data->last_updated = jiffies;
104   - data->valid = 1;
  85 + data->valid = true;
105 86 }
106 87  
107 88 mutex_unlock(&data->update_lock);
108 89  
109 90  
110 91  
... ... @@ -110,29 +91,26 @@
110 91 }
111 92  
112 93 /* sysfs callback function */
113   -static ssize_t show_in(struct device *dev, struct device_attribute *da,
114   - char *buf)
  94 +static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
  95 + char *buf)
115 96 {
116 97 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
117 98 struct ads7828_data *data = ads7828_update_device(dev);
118   - /* Print value (in mV as specified in sysfs-interface documentation) */
119   - return sprintf(buf, "%d\n", (data->adc_input[attr->index] *
120   - ads7828_lsb_resol)/1000);
  99 + unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
  100 + data->lsb_resol, 1000);
  101 +
  102 + return sprintf(buf, "%d\n", value);
121 103 }
122 104  
123   -#define in_reg(offset)\
124   -static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, show_in,\
125   - NULL, offset)
  105 +static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
  106 +static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, ads7828_show_in, NULL, 1);
  107 +static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, ads7828_show_in, NULL, 2);
  108 +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, ads7828_show_in, NULL, 3);
  109 +static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, ads7828_show_in, NULL, 4);
  110 +static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, ads7828_show_in, NULL, 5);
  111 +static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, ads7828_show_in, NULL, 6);
  112 +static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, ads7828_show_in, NULL, 7);
126 113  
127   -in_reg(0);
128   -in_reg(1);
129   -in_reg(2);
130   -in_reg(3);
131   -in_reg(4);
132   -in_reg(5);
133   -in_reg(6);
134   -in_reg(7);
135   -
136 114 static struct attribute *ads7828_attributes[] = {
137 115 &sensor_dev_attr_in0_input.dev_attr.attr,
138 116 &sensor_dev_attr_in1_input.dev_attr.attr,
139 117  
140 118  
141 119  
... ... @@ -152,67 +130,17 @@
152 130 static int ads7828_remove(struct i2c_client *client)
153 131 {
154 132 struct ads7828_data *data = i2c_get_clientdata(client);
  133 +
155 134 hwmon_device_unregister(data->hwmon_dev);
156 135 sysfs_remove_group(&client->dev.kobj, &ads7828_group);
157   - return 0;
158   -}
159 136  
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   -
210 137 return 0;
211 138 }
212 139  
213 140 static int ads7828_probe(struct i2c_client *client,
214 141 const struct i2c_device_id *id)
215 142 {
  143 + struct ads7828_platform_data *pdata = client->dev.platform_data;
216 144 struct ads7828_data *data;
217 145 int err;
218 146  
219 147  
... ... @@ -221,10 +149,30 @@
221 149 if (!data)
222 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 173 i2c_set_clientdata(client, data);
225 174 mutex_init(&data->update_lock);
226 175  
227   - /* Register sysfs hooks */
228 176 err = sysfs_create_group(&client->dev.kobj, &ads7828_group);
229 177 if (err)
230 178 return err;
231 179  
232 180  
233 181  
234 182  
235 183  
236 184  
237 185  
... ... @@ -232,39 +180,35 @@
232 180 data->hwmon_dev = hwmon_device_register(&client->dev);
233 181 if (IS_ERR(data->hwmon_dev)) {
234 182 err = PTR_ERR(data->hwmon_dev);
235   - goto exit_remove;
  183 + goto error;
236 184 }
237 185  
238 186 return 0;
239 187  
240   -exit_remove:
  188 +error:
241 189 sysfs_remove_group(&client->dev.kobj, &ads7828_group);
242 190 return err;
243 191 }
244 192  
245   -static int __init sensors_ads7828_init(void)
246   -{
247   - /* Initialize the command byte according to module parameters */
248   - ads7828_cmd_byte = se_input ?
249   - ADS7828_CMD_SD_SE : ADS7828_CMD_SD_DIFF;
250   - ads7828_cmd_byte |= int_vref ?
251   - ADS7828_CMD_PD3 : ADS7828_CMD_PD1;
  193 +static const struct i2c_device_id ads7828_device_ids[] = {
  194 + { "ads7828", 0 },
  195 + { }
  196 +};
  197 +MODULE_DEVICE_TABLE(i2c, ads7828_device_ids);
252 198  
253   - /* Calculate the LSB resolution */
254   - ads7828_lsb_resol = (vref_mv*1000)/4096;
  199 +static struct i2c_driver ads7828_driver = {
  200 + .driver = {
  201 + .name = "ads7828",
  202 + },
255 203  
256   - return i2c_add_driver(&ads7828_driver);
257   -}
  204 + .id_table = ads7828_device_ids,
  205 + .probe = ads7828_probe,
  206 + .remove = ads7828_remove,
  207 +};
258 208  
259   -static void __exit sensors_ads7828_exit(void)
260   -{
261   - i2c_del_driver(&ads7828_driver);
262   -}
  209 +module_i2c_driver(ads7828_driver);
263 210  
264   -MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
265   -MODULE_DESCRIPTION("ADS7828 driver");
266 211 MODULE_LICENSE("GPL");
267   -
268   -module_init(sensors_ads7828_init);
269   -module_exit(sensors_ads7828_exit);
  212 +MODULE_AUTHOR("Steve Hardy <shardy@redhat.com>");
  213 +MODULE_DESCRIPTION("Driver for TI ADS7828 A/D converter");
include/linux/platform_data/ads7828.h
  1 +/*
  2 + * TI ADS7828 A/D Converter platform data definition
  3 + *
  4 + * Copyright (c) 2012 Savoir-faire Linux Inc.
  5 + * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  6 + *
  7 + * For further information, see the Documentation/hwmon/ads7828 file.
  8 + *
  9 + * This program is free software; you can redistribute it and/or modify
  10 + * it under the terms of the GNU General Public License version 2 as
  11 + * published by the Free Software Foundation.
  12 + */
  13 +
  14 +#ifndef _PDATA_ADS7828_H
  15 +#define _PDATA_ADS7828_H
  16 +
  17 +/**
  18 + * struct ads7828_platform_data - optional ADS7828 connectivity info
  19 + * @diff_input: Differential input mode.
  20 + * @ext_vref: Use an external voltage reference.
  21 + * @vref_mv: Voltage reference value, if external.
  22 + */
  23 +struct ads7828_platform_data {
  24 + bool diff_input;
  25 + bool ext_vref;
  26 + unsigned int vref_mv;
  27 +};
  28 +
  29 +#endif /* _PDATA_ADS7828_H */