diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/hwmon/pcf8591.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/hwmon/pcf8591.c')
-rw-r--r-- | drivers/hwmon/pcf8591.c | 154 |
1 files changed, 64 insertions, 90 deletions
diff --git a/drivers/hwmon/pcf8591.c b/drivers/hwmon/pcf8591.c index 825883d2900..731b09af76b 100644 --- a/drivers/hwmon/pcf8591.c +++ b/drivers/hwmon/pcf8591.c | |||
@@ -1,22 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> | 2 | Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net> |
3 | * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with | 3 | Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with |
4 | * the help of Jean Delvare <khali@linux-fr.org> | 4 | the help of Jean Delvare <khali@linux-fr.org> |
5 | * | 5 | |
6 | * This program is free software; you can redistribute it and/or modify | 6 | This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by | 7 | it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or | 8 | the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. | 9 | (at your option) any later version. |
10 | * | 10 | |
11 | * This program is distributed in the hope that it will be useful, | 11 | This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. | 14 | GNU General Public License for more details. |
15 | * | 15 | |
16 | * You should have received a copy of the GNU General Public License | 16 | You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software | 17 | along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 21 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
22 | 22 | ||
@@ -39,34 +39,28 @@ MODULE_PARM_DESC(input_mode, | |||
39 | " 2 = single ended and differential mixed\n" | 39 | " 2 = single ended and differential mixed\n" |
40 | " 3 = two differential inputs\n"); | 40 | " 3 = two differential inputs\n"); |
41 | 41 | ||
42 | /* | 42 | /* The PCF8591 control byte |
43 | * The PCF8591 control byte | 43 | 7 6 5 4 3 2 1 0 |
44 | * 7 6 5 4 3 2 1 0 | 44 | | 0 |AOEF| AIP | 0 |AINC| AICH | */ |
45 | * | 0 |AOEF| AIP | 0 |AINC| AICH | | ||
46 | */ | ||
47 | 45 | ||
48 | /* Analog Output Enable Flag (analog output active if 1) */ | 46 | /* Analog Output Enable Flag (analog output active if 1) */ |
49 | #define PCF8591_CONTROL_AOEF 0x40 | 47 | #define PCF8591_CONTROL_AOEF 0x40 |
50 | 48 | ||
51 | /* | 49 | /* Analog Input Programming |
52 | * Analog Input Programming | 50 | 0x00 = four single ended inputs |
53 | * 0x00 = four single ended inputs | 51 | 0x10 = three differential inputs |
54 | * 0x10 = three differential inputs | 52 | 0x20 = single ended and differential mixed |
55 | * 0x20 = single ended and differential mixed | 53 | 0x30 = two differential inputs */ |
56 | * 0x30 = two differential inputs | ||
57 | */ | ||
58 | #define PCF8591_CONTROL_AIP_MASK 0x30 | 54 | #define PCF8591_CONTROL_AIP_MASK 0x30 |
59 | 55 | ||
60 | /* Autoincrement Flag (switch on if 1) */ | 56 | /* Autoincrement Flag (switch on if 1) */ |
61 | #define PCF8591_CONTROL_AINC 0x04 | 57 | #define PCF8591_CONTROL_AINC 0x04 |
62 | 58 | ||
63 | /* | 59 | /* Channel selection |
64 | * Channel selection | 60 | 0x00 = channel 0 |
65 | * 0x00 = channel 0 | 61 | 0x01 = channel 1 |
66 | * 0x01 = channel 1 | 62 | 0x02 = channel 2 |
67 | * 0x02 = channel 2 | 63 | 0x03 = channel 3 */ |
68 | * 0x03 = channel 3 | ||
69 | */ | ||
70 | #define PCF8591_CONTROL_AICH_MASK 0x03 | 64 | #define PCF8591_CONTROL_AICH_MASK 0x03 |
71 | 65 | ||
72 | /* Initial values */ | 66 | /* Initial values */ |
@@ -74,7 +68,7 @@ MODULE_PARM_DESC(input_mode, | |||
74 | #define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ | 68 | #define PCF8591_INIT_AOUT 0 /* DAC out = 0 */ |
75 | 69 | ||
76 | /* Conversions */ | 70 | /* Conversions */ |
77 | #define REG_TO_SIGNED(reg) (((reg) & 0x80) ? ((reg) - 256) : (reg)) | 71 | #define REG_TO_SIGNED(reg) (((reg) & 0x80)?((reg) - 256):(reg)) |
78 | 72 | ||
79 | struct pcf8591_data { | 73 | struct pcf8591_data { |
80 | struct device *hwmon_dev; | 74 | struct device *hwmon_dev; |
@@ -89,9 +83,7 @@ static int pcf8591_read_channel(struct device *dev, int channel); | |||
89 | 83 | ||
90 | /* following are the sysfs callback functions */ | 84 | /* following are the sysfs callback functions */ |
91 | #define show_in_channel(channel) \ | 85 | #define show_in_channel(channel) \ |
92 | static ssize_t show_in##channel##_input(struct device *dev, \ | 86 | static ssize_t show_in##channel##_input(struct device *dev, struct device_attribute *attr, char *buf) \ |
93 | struct device_attribute *attr, \ | ||
94 | char *buf) \ | ||
95 | { \ | 87 | { \ |
96 | return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ | 88 | return sprintf(buf, "%d\n", pcf8591_read_channel(dev, channel));\ |
97 | } \ | 89 | } \ |
@@ -103,57 +95,39 @@ show_in_channel(1); | |||
103 | show_in_channel(2); | 95 | show_in_channel(2); |
104 | show_in_channel(3); | 96 | show_in_channel(3); |
105 | 97 | ||
106 | static ssize_t show_out0_ouput(struct device *dev, | 98 | static ssize_t show_out0_ouput(struct device *dev, struct device_attribute *attr, char *buf) |
107 | struct device_attribute *attr, char *buf) | ||
108 | { | 99 | { |
109 | struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); | 100 | struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); |
110 | return sprintf(buf, "%d\n", data->aout * 10); | 101 | return sprintf(buf, "%d\n", data->aout * 10); |
111 | } | 102 | } |
112 | 103 | ||
113 | static ssize_t set_out0_output(struct device *dev, | 104 | static ssize_t set_out0_output(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
114 | struct device_attribute *attr, | ||
115 | const char *buf, size_t count) | ||
116 | { | 105 | { |
117 | unsigned long val; | 106 | unsigned int value; |
118 | struct i2c_client *client = to_i2c_client(dev); | 107 | struct i2c_client *client = to_i2c_client(dev); |
119 | struct pcf8591_data *data = i2c_get_clientdata(client); | 108 | struct pcf8591_data *data = i2c_get_clientdata(client); |
120 | int err; | 109 | if ((value = (simple_strtoul(buf, NULL, 10) + 5) / 10) <= 255) { |
121 | 110 | data->aout = value; | |
122 | err = kstrtoul(buf, 10, &val); | 111 | i2c_smbus_write_byte_data(client, data->control, data->aout); |
123 | if (err) | 112 | return count; |
124 | return err; | 113 | } |
125 | 114 | return -EINVAL; | |
126 | val /= 10; | ||
127 | if (val > 255) | ||
128 | return -EINVAL; | ||
129 | |||
130 | data->aout = val; | ||
131 | i2c_smbus_write_byte_data(client, data->control, data->aout); | ||
132 | return count; | ||
133 | } | 115 | } |
134 | 116 | ||
135 | static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, | 117 | static DEVICE_ATTR(out0_output, S_IWUSR | S_IRUGO, |
136 | show_out0_ouput, set_out0_output); | 118 | show_out0_ouput, set_out0_output); |
137 | 119 | ||
138 | static ssize_t show_out0_enable(struct device *dev, | 120 | static ssize_t show_out0_enable(struct device *dev, struct device_attribute *attr, char *buf) |
139 | struct device_attribute *attr, char *buf) | ||
140 | { | 121 | { |
141 | struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); | 122 | struct pcf8591_data *data = i2c_get_clientdata(to_i2c_client(dev)); |
142 | return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); | 123 | return sprintf(buf, "%u\n", !(!(data->control & PCF8591_CONTROL_AOEF))); |
143 | } | 124 | } |
144 | 125 | ||
145 | static ssize_t set_out0_enable(struct device *dev, | 126 | static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) |
146 | struct device_attribute *attr, | ||
147 | const char *buf, size_t count) | ||
148 | { | 127 | { |
149 | struct i2c_client *client = to_i2c_client(dev); | 128 | struct i2c_client *client = to_i2c_client(dev); |
150 | struct pcf8591_data *data = i2c_get_clientdata(client); | 129 | struct pcf8591_data *data = i2c_get_clientdata(client); |
151 | unsigned long val; | 130 | unsigned long val = simple_strtoul(buf, NULL, 10); |
152 | int err; | ||
153 | |||
154 | err = kstrtoul(buf, 10, &val); | ||
155 | if (err) | ||
156 | return err; | ||
157 | 131 | ||
158 | mutex_lock(&data->update_lock); | 132 | mutex_lock(&data->update_lock); |
159 | if (val) | 133 | if (val) |
@@ -200,10 +174,10 @@ static int pcf8591_probe(struct i2c_client *client, | |||
200 | struct pcf8591_data *data; | 174 | struct pcf8591_data *data; |
201 | int err; | 175 | int err; |
202 | 176 | ||
203 | data = devm_kzalloc(&client->dev, sizeof(struct pcf8591_data), | 177 | if (!(data = kzalloc(sizeof(struct pcf8591_data), GFP_KERNEL))) { |
204 | GFP_KERNEL); | 178 | err = -ENOMEM; |
205 | if (!data) | 179 | goto exit; |
206 | return -ENOMEM; | 180 | } |
207 | 181 | ||
208 | i2c_set_clientdata(client, data); | 182 | i2c_set_clientdata(client, data); |
209 | mutex_init(&data->update_lock); | 183 | mutex_init(&data->update_lock); |
@@ -214,19 +188,19 @@ static int pcf8591_probe(struct i2c_client *client, | |||
214 | /* Register sysfs hooks */ | 188 | /* Register sysfs hooks */ |
215 | err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group); | 189 | err = sysfs_create_group(&client->dev.kobj, &pcf8591_attr_group); |
216 | if (err) | 190 | if (err) |
217 | return err; | 191 | goto exit_kfree; |
218 | 192 | ||
219 | /* Register input2 if not in "two differential inputs" mode */ | 193 | /* Register input2 if not in "two differential inputs" mode */ |
220 | if (input_mode != 3) { | 194 | if (input_mode != 3) { |
221 | err = device_create_file(&client->dev, &dev_attr_in2_input); | 195 | if ((err = device_create_file(&client->dev, |
222 | if (err) | 196 | &dev_attr_in2_input))) |
223 | goto exit_sysfs_remove; | 197 | goto exit_sysfs_remove; |
224 | } | 198 | } |
225 | 199 | ||
226 | /* Register input3 only in "four single ended inputs" mode */ | 200 | /* Register input3 only in "four single ended inputs" mode */ |
227 | if (input_mode == 0) { | 201 | if (input_mode == 0) { |
228 | err = device_create_file(&client->dev, &dev_attr_in3_input); | 202 | if ((err = device_create_file(&client->dev, |
229 | if (err) | 203 | &dev_attr_in3_input))) |
230 | goto exit_sysfs_remove; | 204 | goto exit_sysfs_remove; |
231 | } | 205 | } |
232 | 206 | ||
@@ -241,6 +215,9 @@ static int pcf8591_probe(struct i2c_client *client, | |||
241 | exit_sysfs_remove: | 215 | exit_sysfs_remove: |
242 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); | 216 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); |
243 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); | 217 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); |
218 | exit_kfree: | ||
219 | kfree(data); | ||
220 | exit: | ||
244 | return err; | 221 | return err; |
245 | } | 222 | } |
246 | 223 | ||
@@ -251,6 +228,7 @@ static int pcf8591_remove(struct i2c_client *client) | |||
251 | hwmon_device_unregister(data->hwmon_dev); | 228 | hwmon_device_unregister(data->hwmon_dev); |
252 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); | 229 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt); |
253 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); | 230 | sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group); |
231 | kfree(i2c_get_clientdata(client)); | ||
254 | return 0; | 232 | return 0; |
255 | } | 233 | } |
256 | 234 | ||
@@ -263,10 +241,8 @@ static void pcf8591_init_client(struct i2c_client *client) | |||
263 | 241 | ||
264 | i2c_smbus_write_byte_data(client, data->control, data->aout); | 242 | i2c_smbus_write_byte_data(client, data->control, data->aout); |
265 | 243 | ||
266 | /* | 244 | /* The first byte transmitted contains the conversion code of the |
267 | * The first byte transmitted contains the conversion code of the | 245 | previous read cycle. FLUSH IT! */ |
268 | * previous read cycle. FLUSH IT! | ||
269 | */ | ||
270 | i2c_smbus_read_byte(client); | 246 | i2c_smbus_read_byte(client); |
271 | } | 247 | } |
272 | 248 | ||
@@ -283,10 +259,8 @@ static int pcf8591_read_channel(struct device *dev, int channel) | |||
283 | | channel; | 259 | | channel; |
284 | i2c_smbus_write_byte(client, data->control); | 260 | i2c_smbus_write_byte(client, data->control); |
285 | 261 | ||
286 | /* | 262 | /* The first byte transmitted contains the conversion code of |
287 | * The first byte transmitted contains the conversion code of | 263 | the previous read cycle. FLUSH IT! */ |
288 | * the previous read cycle. FLUSH IT! | ||
289 | */ | ||
290 | i2c_smbus_read_byte(client); | 264 | i2c_smbus_read_byte(client); |
291 | } | 265 | } |
292 | value = i2c_smbus_read_byte(client); | 266 | value = i2c_smbus_read_byte(client); |
@@ -295,9 +269,9 @@ static int pcf8591_read_channel(struct device *dev, int channel) | |||
295 | 269 | ||
296 | if ((channel == 2 && input_mode == 2) || | 270 | if ((channel == 2 && input_mode == 2) || |
297 | (channel != 3 && (input_mode == 1 || input_mode == 3))) | 271 | (channel != 3 && (input_mode == 1 || input_mode == 3))) |
298 | return 10 * REG_TO_SIGNED(value); | 272 | return (10 * REG_TO_SIGNED(value)); |
299 | else | 273 | else |
300 | return 10 * value; | 274 | return (10 * value); |
301 | } | 275 | } |
302 | 276 | ||
303 | static const struct i2c_device_id pcf8591_id[] = { | 277 | static const struct i2c_device_id pcf8591_id[] = { |