Commit 674d0ed8588c11ec9f70c8427ac83a73e0d156d5
1 parent
19f053c840
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
hwmon: (atxp1) Set and use error code from vid_to_reg()
vid_to_reg() returns -1 if it encounters an error. Return -EINVAL instead. Its only caller, atxp1_storevcore(), doesn't use the return code but returns -1 instead, which is wrong anyway as it means -EPERM. Use the return value from vid_to_reg() instead to report the error. Signed-off-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Jean Delvare <khali@linux-fr.org>
Showing 2 changed files with 2 additions and 3 deletions Inline Diff
drivers/hwmon/atxp1.c
1 | /* | 1 | /* |
2 | * atxp1.c - kernel module for setting CPU VID and general purpose | 2 | * atxp1.c - kernel module for setting CPU VID and general purpose |
3 | * I/Os using the Attansic ATXP1 chip. | 3 | * I/Os using the Attansic ATXP1 chip. |
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or | 7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. | 8 | * (at your option) any later version. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, | 10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
24 | #include <linux/jiffies.h> | 24 | #include <linux/jiffies.h> |
25 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
26 | #include <linux/hwmon.h> | 26 | #include <linux/hwmon.h> |
27 | #include <linux/hwmon-vid.h> | 27 | #include <linux/hwmon-vid.h> |
28 | #include <linux/err.h> | 28 | #include <linux/err.h> |
29 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
30 | #include <linux/sysfs.h> | 30 | #include <linux/sysfs.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | 32 | ||
33 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
34 | MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); | 34 | MODULE_DESCRIPTION("System voltages control via Attansic ATXP1"); |
35 | MODULE_VERSION("0.6.3"); | 35 | MODULE_VERSION("0.6.3"); |
36 | MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); | 36 | MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>"); |
37 | 37 | ||
38 | #define ATXP1_VID 0x00 | 38 | #define ATXP1_VID 0x00 |
39 | #define ATXP1_CVID 0x01 | 39 | #define ATXP1_CVID 0x01 |
40 | #define ATXP1_GPIO1 0x06 | 40 | #define ATXP1_GPIO1 0x06 |
41 | #define ATXP1_GPIO2 0x0a | 41 | #define ATXP1_GPIO2 0x0a |
42 | #define ATXP1_VIDENA 0x20 | 42 | #define ATXP1_VIDENA 0x20 |
43 | #define ATXP1_VIDMASK 0x1f | 43 | #define ATXP1_VIDMASK 0x1f |
44 | #define ATXP1_GPIO1MASK 0x0f | 44 | #define ATXP1_GPIO1MASK 0x0f |
45 | 45 | ||
46 | static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; | 46 | static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END }; |
47 | 47 | ||
48 | static int atxp1_probe(struct i2c_client *client, | 48 | static int atxp1_probe(struct i2c_client *client, |
49 | const struct i2c_device_id *id); | 49 | const struct i2c_device_id *id); |
50 | static int atxp1_remove(struct i2c_client *client); | 50 | static int atxp1_remove(struct i2c_client *client); |
51 | static struct atxp1_data *atxp1_update_device(struct device *dev); | 51 | static struct atxp1_data *atxp1_update_device(struct device *dev); |
52 | static int atxp1_detect(struct i2c_client *client, struct i2c_board_info *info); | 52 | static int atxp1_detect(struct i2c_client *client, struct i2c_board_info *info); |
53 | 53 | ||
54 | static const struct i2c_device_id atxp1_id[] = { | 54 | static const struct i2c_device_id atxp1_id[] = { |
55 | { "atxp1", 0 }, | 55 | { "atxp1", 0 }, |
56 | { } | 56 | { } |
57 | }; | 57 | }; |
58 | MODULE_DEVICE_TABLE(i2c, atxp1_id); | 58 | MODULE_DEVICE_TABLE(i2c, atxp1_id); |
59 | 59 | ||
60 | static struct i2c_driver atxp1_driver = { | 60 | static struct i2c_driver atxp1_driver = { |
61 | .class = I2C_CLASS_HWMON, | 61 | .class = I2C_CLASS_HWMON, |
62 | .driver = { | 62 | .driver = { |
63 | .name = "atxp1", | 63 | .name = "atxp1", |
64 | }, | 64 | }, |
65 | .probe = atxp1_probe, | 65 | .probe = atxp1_probe, |
66 | .remove = atxp1_remove, | 66 | .remove = atxp1_remove, |
67 | .id_table = atxp1_id, | 67 | .id_table = atxp1_id, |
68 | .detect = atxp1_detect, | 68 | .detect = atxp1_detect, |
69 | .address_list = normal_i2c, | 69 | .address_list = normal_i2c, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | struct atxp1_data { | 72 | struct atxp1_data { |
73 | struct device *hwmon_dev; | 73 | struct device *hwmon_dev; |
74 | struct mutex update_lock; | 74 | struct mutex update_lock; |
75 | unsigned long last_updated; | 75 | unsigned long last_updated; |
76 | u8 valid; | 76 | u8 valid; |
77 | struct { | 77 | struct { |
78 | u8 vid; /* VID output register */ | 78 | u8 vid; /* VID output register */ |
79 | u8 cpu_vid; /* VID input from CPU */ | 79 | u8 cpu_vid; /* VID input from CPU */ |
80 | u8 gpio1; /* General purpose I/O register 1 */ | 80 | u8 gpio1; /* General purpose I/O register 1 */ |
81 | u8 gpio2; /* General purpose I/O register 2 */ | 81 | u8 gpio2; /* General purpose I/O register 2 */ |
82 | } reg; | 82 | } reg; |
83 | u8 vrm; /* Detected CPU VRM */ | 83 | u8 vrm; /* Detected CPU VRM */ |
84 | }; | 84 | }; |
85 | 85 | ||
86 | static struct atxp1_data *atxp1_update_device(struct device *dev) | 86 | static struct atxp1_data *atxp1_update_device(struct device *dev) |
87 | { | 87 | { |
88 | struct i2c_client *client; | 88 | struct i2c_client *client; |
89 | struct atxp1_data *data; | 89 | struct atxp1_data *data; |
90 | 90 | ||
91 | client = to_i2c_client(dev); | 91 | client = to_i2c_client(dev); |
92 | data = i2c_get_clientdata(client); | 92 | data = i2c_get_clientdata(client); |
93 | 93 | ||
94 | mutex_lock(&data->update_lock); | 94 | mutex_lock(&data->update_lock); |
95 | 95 | ||
96 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | 96 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { |
97 | 97 | ||
98 | /* Update local register data */ | 98 | /* Update local register data */ |
99 | data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); | 99 | data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID); |
100 | data->reg.cpu_vid = i2c_smbus_read_byte_data(client, | 100 | data->reg.cpu_vid = i2c_smbus_read_byte_data(client, |
101 | ATXP1_CVID); | 101 | ATXP1_CVID); |
102 | data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); | 102 | data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1); |
103 | data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); | 103 | data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2); |
104 | 104 | ||
105 | data->valid = 1; | 105 | data->valid = 1; |
106 | } | 106 | } |
107 | 107 | ||
108 | mutex_unlock(&data->update_lock); | 108 | mutex_unlock(&data->update_lock); |
109 | 109 | ||
110 | return data; | 110 | return data; |
111 | } | 111 | } |
112 | 112 | ||
113 | /* sys file functions for cpu0_vid */ | 113 | /* sys file functions for cpu0_vid */ |
114 | static ssize_t atxp1_showvcore(struct device *dev, | 114 | static ssize_t atxp1_showvcore(struct device *dev, |
115 | struct device_attribute *attr, char *buf) | 115 | struct device_attribute *attr, char *buf) |
116 | { | 116 | { |
117 | int size; | 117 | int size; |
118 | struct atxp1_data *data; | 118 | struct atxp1_data *data; |
119 | 119 | ||
120 | data = atxp1_update_device(dev); | 120 | data = atxp1_update_device(dev); |
121 | 121 | ||
122 | size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, | 122 | size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK, |
123 | data->vrm)); | 123 | data->vrm)); |
124 | 124 | ||
125 | return size; | 125 | return size; |
126 | } | 126 | } |
127 | 127 | ||
128 | static ssize_t atxp1_storevcore(struct device *dev, | 128 | static ssize_t atxp1_storevcore(struct device *dev, |
129 | struct device_attribute *attr, | 129 | struct device_attribute *attr, |
130 | const char *buf, size_t count) | 130 | const char *buf, size_t count) |
131 | { | 131 | { |
132 | struct atxp1_data *data; | 132 | struct atxp1_data *data; |
133 | struct i2c_client *client; | 133 | struct i2c_client *client; |
134 | int vid, cvid; | 134 | int vid, cvid; |
135 | unsigned long vcore; | 135 | unsigned long vcore; |
136 | int err; | 136 | int err; |
137 | 137 | ||
138 | client = to_i2c_client(dev); | 138 | client = to_i2c_client(dev); |
139 | data = atxp1_update_device(dev); | 139 | data = atxp1_update_device(dev); |
140 | 140 | ||
141 | err = kstrtoul(buf, 10, &vcore); | 141 | err = kstrtoul(buf, 10, &vcore); |
142 | if (err) | 142 | if (err) |
143 | return err; | 143 | return err; |
144 | 144 | ||
145 | vcore /= 25; | 145 | vcore /= 25; |
146 | vcore *= 25; | 146 | vcore *= 25; |
147 | 147 | ||
148 | /* Calculate VID */ | 148 | /* Calculate VID */ |
149 | vid = vid_to_reg(vcore, data->vrm); | 149 | vid = vid_to_reg(vcore, data->vrm); |
150 | |||
151 | if (vid < 0) { | 150 | if (vid < 0) { |
152 | dev_err(dev, "VID calculation failed.\n"); | 151 | dev_err(dev, "VID calculation failed.\n"); |
153 | return -1; | 152 | return vid; |
154 | } | 153 | } |
155 | 154 | ||
156 | /* | 155 | /* |
157 | * If output enabled, use control register value. | 156 | * If output enabled, use control register value. |
158 | * Otherwise original CPU VID | 157 | * Otherwise original CPU VID |
159 | */ | 158 | */ |
160 | if (data->reg.vid & ATXP1_VIDENA) | 159 | if (data->reg.vid & ATXP1_VIDENA) |
161 | cvid = data->reg.vid & ATXP1_VIDMASK; | 160 | cvid = data->reg.vid & ATXP1_VIDMASK; |
162 | else | 161 | else |
163 | cvid = data->reg.cpu_vid; | 162 | cvid = data->reg.cpu_vid; |
164 | 163 | ||
165 | /* Nothing changed, aborting */ | 164 | /* Nothing changed, aborting */ |
166 | if (vid == cvid) | 165 | if (vid == cvid) |
167 | return count; | 166 | return count; |
168 | 167 | ||
169 | dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid); | 168 | dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid); |
170 | 169 | ||
171 | /* Write every 25 mV step to increase stability */ | 170 | /* Write every 25 mV step to increase stability */ |
172 | if (cvid > vid) { | 171 | if (cvid > vid) { |
173 | for (; cvid >= vid; cvid--) | 172 | for (; cvid >= vid; cvid--) |
174 | i2c_smbus_write_byte_data(client, | 173 | i2c_smbus_write_byte_data(client, |
175 | ATXP1_VID, cvid | ATXP1_VIDENA); | 174 | ATXP1_VID, cvid | ATXP1_VIDENA); |
176 | } else { | 175 | } else { |
177 | for (; cvid <= vid; cvid++) | 176 | for (; cvid <= vid; cvid++) |
178 | i2c_smbus_write_byte_data(client, | 177 | i2c_smbus_write_byte_data(client, |
179 | ATXP1_VID, cvid | ATXP1_VIDENA); | 178 | ATXP1_VID, cvid | ATXP1_VIDENA); |
180 | } | 179 | } |
181 | 180 | ||
182 | data->valid = 0; | 181 | data->valid = 0; |
183 | 182 | ||
184 | return count; | 183 | return count; |
185 | } | 184 | } |
186 | 185 | ||
187 | /* | 186 | /* |
188 | * CPU core reference voltage | 187 | * CPU core reference voltage |
189 | * unit: millivolt | 188 | * unit: millivolt |
190 | */ | 189 | */ |
191 | static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, | 190 | static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore, |
192 | atxp1_storevcore); | 191 | atxp1_storevcore); |
193 | 192 | ||
194 | /* sys file functions for GPIO1 */ | 193 | /* sys file functions for GPIO1 */ |
195 | static ssize_t atxp1_showgpio1(struct device *dev, | 194 | static ssize_t atxp1_showgpio1(struct device *dev, |
196 | struct device_attribute *attr, char *buf) | 195 | struct device_attribute *attr, char *buf) |
197 | { | 196 | { |
198 | int size; | 197 | int size; |
199 | struct atxp1_data *data; | 198 | struct atxp1_data *data; |
200 | 199 | ||
201 | data = atxp1_update_device(dev); | 200 | data = atxp1_update_device(dev); |
202 | 201 | ||
203 | size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); | 202 | size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK); |
204 | 203 | ||
205 | return size; | 204 | return size; |
206 | } | 205 | } |
207 | 206 | ||
208 | static ssize_t atxp1_storegpio1(struct device *dev, | 207 | static ssize_t atxp1_storegpio1(struct device *dev, |
209 | struct device_attribute *attr, const char *buf, | 208 | struct device_attribute *attr, const char *buf, |
210 | size_t count) | 209 | size_t count) |
211 | { | 210 | { |
212 | struct atxp1_data *data; | 211 | struct atxp1_data *data; |
213 | struct i2c_client *client; | 212 | struct i2c_client *client; |
214 | unsigned long value; | 213 | unsigned long value; |
215 | int err; | 214 | int err; |
216 | 215 | ||
217 | client = to_i2c_client(dev); | 216 | client = to_i2c_client(dev); |
218 | data = atxp1_update_device(dev); | 217 | data = atxp1_update_device(dev); |
219 | 218 | ||
220 | err = kstrtoul(buf, 16, &value); | 219 | err = kstrtoul(buf, 16, &value); |
221 | if (err) | 220 | if (err) |
222 | return err; | 221 | return err; |
223 | 222 | ||
224 | value &= ATXP1_GPIO1MASK; | 223 | value &= ATXP1_GPIO1MASK; |
225 | 224 | ||
226 | if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { | 225 | if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) { |
227 | dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value); | 226 | dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value); |
228 | 227 | ||
229 | i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); | 228 | i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value); |
230 | 229 | ||
231 | data->valid = 0; | 230 | data->valid = 0; |
232 | } | 231 | } |
233 | 232 | ||
234 | return count; | 233 | return count; |
235 | } | 234 | } |
236 | 235 | ||
237 | /* | 236 | /* |
238 | * GPIO1 data register | 237 | * GPIO1 data register |
239 | * unit: Four bit as hex (e.g. 0x0f) | 238 | * unit: Four bit as hex (e.g. 0x0f) |
240 | */ | 239 | */ |
241 | static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); | 240 | static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1); |
242 | 241 | ||
243 | /* sys file functions for GPIO2 */ | 242 | /* sys file functions for GPIO2 */ |
244 | static ssize_t atxp1_showgpio2(struct device *dev, | 243 | static ssize_t atxp1_showgpio2(struct device *dev, |
245 | struct device_attribute *attr, char *buf) | 244 | struct device_attribute *attr, char *buf) |
246 | { | 245 | { |
247 | int size; | 246 | int size; |
248 | struct atxp1_data *data; | 247 | struct atxp1_data *data; |
249 | 248 | ||
250 | data = atxp1_update_device(dev); | 249 | data = atxp1_update_device(dev); |
251 | 250 | ||
252 | size = sprintf(buf, "0x%02x\n", data->reg.gpio2); | 251 | size = sprintf(buf, "0x%02x\n", data->reg.gpio2); |
253 | 252 | ||
254 | return size; | 253 | return size; |
255 | } | 254 | } |
256 | 255 | ||
257 | static ssize_t atxp1_storegpio2(struct device *dev, | 256 | static ssize_t atxp1_storegpio2(struct device *dev, |
258 | struct device_attribute *attr, | 257 | struct device_attribute *attr, |
259 | const char *buf, size_t count) | 258 | const char *buf, size_t count) |
260 | { | 259 | { |
261 | struct atxp1_data *data = atxp1_update_device(dev); | 260 | struct atxp1_data *data = atxp1_update_device(dev); |
262 | struct i2c_client *client = to_i2c_client(dev); | 261 | struct i2c_client *client = to_i2c_client(dev); |
263 | unsigned long value; | 262 | unsigned long value; |
264 | int err; | 263 | int err; |
265 | 264 | ||
266 | err = kstrtoul(buf, 16, &value); | 265 | err = kstrtoul(buf, 16, &value); |
267 | if (err) | 266 | if (err) |
268 | return err; | 267 | return err; |
269 | value &= 0xff; | 268 | value &= 0xff; |
270 | 269 | ||
271 | if (value != data->reg.gpio2) { | 270 | if (value != data->reg.gpio2) { |
272 | dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value); | 271 | dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value); |
273 | 272 | ||
274 | i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); | 273 | i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value); |
275 | 274 | ||
276 | data->valid = 0; | 275 | data->valid = 0; |
277 | } | 276 | } |
278 | 277 | ||
279 | return count; | 278 | return count; |
280 | } | 279 | } |
281 | 280 | ||
282 | /* | 281 | /* |
283 | * GPIO2 data register | 282 | * GPIO2 data register |
284 | * unit: Eight bit as hex (e.g. 0xff) | 283 | * unit: Eight bit as hex (e.g. 0xff) |
285 | */ | 284 | */ |
286 | static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); | 285 | static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2); |
287 | 286 | ||
288 | static struct attribute *atxp1_attributes[] = { | 287 | static struct attribute *atxp1_attributes[] = { |
289 | &dev_attr_gpio1.attr, | 288 | &dev_attr_gpio1.attr, |
290 | &dev_attr_gpio2.attr, | 289 | &dev_attr_gpio2.attr, |
291 | &dev_attr_cpu0_vid.attr, | 290 | &dev_attr_cpu0_vid.attr, |
292 | NULL | 291 | NULL |
293 | }; | 292 | }; |
294 | 293 | ||
295 | static const struct attribute_group atxp1_group = { | 294 | static const struct attribute_group atxp1_group = { |
296 | .attrs = atxp1_attributes, | 295 | .attrs = atxp1_attributes, |
297 | }; | 296 | }; |
298 | 297 | ||
299 | 298 | ||
300 | /* Return 0 if detection is successful, -ENODEV otherwise */ | 299 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
301 | static int atxp1_detect(struct i2c_client *new_client, | 300 | static int atxp1_detect(struct i2c_client *new_client, |
302 | struct i2c_board_info *info) | 301 | struct i2c_board_info *info) |
303 | { | 302 | { |
304 | struct i2c_adapter *adapter = new_client->adapter; | 303 | struct i2c_adapter *adapter = new_client->adapter; |
305 | 304 | ||
306 | u8 temp; | 305 | u8 temp; |
307 | 306 | ||
308 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 307 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
309 | return -ENODEV; | 308 | return -ENODEV; |
310 | 309 | ||
311 | /* Detect ATXP1, checking if vendor ID registers are all zero */ | 310 | /* Detect ATXP1, checking if vendor ID registers are all zero */ |
312 | if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && | 311 | if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) && |
313 | (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && | 312 | (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) && |
314 | (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && | 313 | (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) && |
315 | (i2c_smbus_read_byte_data(new_client, 0xff) == 0))) | 314 | (i2c_smbus_read_byte_data(new_client, 0xff) == 0))) |
316 | return -ENODEV; | 315 | return -ENODEV; |
317 | 316 | ||
318 | /* | 317 | /* |
319 | * No vendor ID, now checking if registers 0x10,0x11 (non-existent) | 318 | * No vendor ID, now checking if registers 0x10,0x11 (non-existent) |
320 | * showing the same as register 0x00 | 319 | * showing the same as register 0x00 |
321 | */ | 320 | */ |
322 | temp = i2c_smbus_read_byte_data(new_client, 0x00); | 321 | temp = i2c_smbus_read_byte_data(new_client, 0x00); |
323 | 322 | ||
324 | if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && | 323 | if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) && |
325 | (i2c_smbus_read_byte_data(new_client, 0x11) == temp))) | 324 | (i2c_smbus_read_byte_data(new_client, 0x11) == temp))) |
326 | return -ENODEV; | 325 | return -ENODEV; |
327 | 326 | ||
328 | /* Get VRM */ | 327 | /* Get VRM */ |
329 | temp = vid_which_vrm(); | 328 | temp = vid_which_vrm(); |
330 | 329 | ||
331 | if ((temp != 90) && (temp != 91)) { | 330 | if ((temp != 90) && (temp != 91)) { |
332 | dev_err(&adapter->dev, "atxp1: Not supporting VRM %d.%d\n", | 331 | dev_err(&adapter->dev, "atxp1: Not supporting VRM %d.%d\n", |
333 | temp / 10, temp % 10); | 332 | temp / 10, temp % 10); |
334 | return -ENODEV; | 333 | return -ENODEV; |
335 | } | 334 | } |
336 | 335 | ||
337 | strlcpy(info->type, "atxp1", I2C_NAME_SIZE); | 336 | strlcpy(info->type, "atxp1", I2C_NAME_SIZE); |
338 | 337 | ||
339 | return 0; | 338 | return 0; |
340 | } | 339 | } |
341 | 340 | ||
342 | static int atxp1_probe(struct i2c_client *new_client, | 341 | static int atxp1_probe(struct i2c_client *new_client, |
343 | const struct i2c_device_id *id) | 342 | const struct i2c_device_id *id) |
344 | { | 343 | { |
345 | struct atxp1_data *data; | 344 | struct atxp1_data *data; |
346 | int err; | 345 | int err; |
347 | 346 | ||
348 | data = devm_kzalloc(&new_client->dev, sizeof(struct atxp1_data), | 347 | data = devm_kzalloc(&new_client->dev, sizeof(struct atxp1_data), |
349 | GFP_KERNEL); | 348 | GFP_KERNEL); |
350 | if (!data) | 349 | if (!data) |
351 | return -ENOMEM; | 350 | return -ENOMEM; |
352 | 351 | ||
353 | /* Get VRM */ | 352 | /* Get VRM */ |
354 | data->vrm = vid_which_vrm(); | 353 | data->vrm = vid_which_vrm(); |
355 | 354 | ||
356 | i2c_set_clientdata(new_client, data); | 355 | i2c_set_clientdata(new_client, data); |
357 | data->valid = 0; | 356 | data->valid = 0; |
358 | 357 | ||
359 | mutex_init(&data->update_lock); | 358 | mutex_init(&data->update_lock); |
360 | 359 | ||
361 | /* Register sysfs hooks */ | 360 | /* Register sysfs hooks */ |
362 | err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group); | 361 | err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group); |
363 | if (err) | 362 | if (err) |
364 | return err; | 363 | return err; |
365 | 364 | ||
366 | data->hwmon_dev = hwmon_device_register(&new_client->dev); | 365 | data->hwmon_dev = hwmon_device_register(&new_client->dev); |
367 | if (IS_ERR(data->hwmon_dev)) { | 366 | if (IS_ERR(data->hwmon_dev)) { |
368 | err = PTR_ERR(data->hwmon_dev); | 367 | err = PTR_ERR(data->hwmon_dev); |
369 | goto exit_remove_files; | 368 | goto exit_remove_files; |
370 | } | 369 | } |
371 | 370 | ||
372 | dev_info(&new_client->dev, "Using VRM: %d.%d\n", | 371 | dev_info(&new_client->dev, "Using VRM: %d.%d\n", |
373 | data->vrm / 10, data->vrm % 10); | 372 | data->vrm / 10, data->vrm % 10); |
374 | 373 | ||
375 | return 0; | 374 | return 0; |
376 | 375 | ||
377 | exit_remove_files: | 376 | exit_remove_files: |
378 | sysfs_remove_group(&new_client->dev.kobj, &atxp1_group); | 377 | sysfs_remove_group(&new_client->dev.kobj, &atxp1_group); |
379 | return err; | 378 | return err; |
380 | }; | 379 | }; |
381 | 380 | ||
382 | static int atxp1_remove(struct i2c_client *client) | 381 | static int atxp1_remove(struct i2c_client *client) |
383 | { | 382 | { |
384 | struct atxp1_data *data = i2c_get_clientdata(client); | 383 | struct atxp1_data *data = i2c_get_clientdata(client); |
385 | 384 | ||
386 | hwmon_device_unregister(data->hwmon_dev); | 385 | hwmon_device_unregister(data->hwmon_dev); |
387 | sysfs_remove_group(&client->dev.kobj, &atxp1_group); | 386 | sysfs_remove_group(&client->dev.kobj, &atxp1_group); |
388 | 387 | ||
389 | return 0; | 388 | return 0; |
390 | }; | 389 | }; |
391 | 390 | ||
392 | module_i2c_driver(atxp1_driver); | 391 | module_i2c_driver(atxp1_driver); |
393 | 392 |
include/linux/hwmon-vid.h
1 | /* | 1 | /* |
2 | hwmon-vid.h - VID/VRM/VRD voltage conversions | 2 | hwmon-vid.h - VID/VRM/VRD voltage conversions |
3 | 3 | ||
4 | Originally part of lm_sensors | 4 | Originally part of lm_sensors |
5 | Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> | 5 | Copyright (c) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> |
6 | With assistance from Trent Piepho <xyzzy@speakeasy.org> | 6 | With assistance from Trent Piepho <xyzzy@speakeasy.org> |
7 | 7 | ||
8 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by |
10 | the Free Software Foundation; either version 2 of the License, or | 10 | the Free Software Foundation; either version 2 of the License, or |
11 | (at your option) any later version. | 11 | (at your option) any later version. |
12 | 12 | ||
13 | This program is distributed in the hope that it will be useful, | 13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. | 16 | GNU General Public License for more details. |
17 | 17 | ||
18 | You should have received a copy of the GNU General Public License | 18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software | 19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | #ifndef _LINUX_HWMON_VID_H | 23 | #ifndef _LINUX_HWMON_VID_H |
24 | #define _LINUX_HWMON_VID_H | 24 | #define _LINUX_HWMON_VID_H |
25 | 25 | ||
26 | int vid_from_reg(int val, u8 vrm); | 26 | int vid_from_reg(int val, u8 vrm); |
27 | u8 vid_which_vrm(void); | 27 | u8 vid_which_vrm(void); |
28 | 28 | ||
29 | /* vrm is the VRM/VRD document version multiplied by 10. | 29 | /* vrm is the VRM/VRD document version multiplied by 10. |
30 | val is in mV to avoid floating point in the kernel. | 30 | val is in mV to avoid floating point in the kernel. |
31 | Returned value is the 4-, 5- or 6-bit VID code. | 31 | Returned value is the 4-, 5- or 6-bit VID code. |
32 | Note that only VRM 9.x is supported for now. */ | 32 | Note that only VRM 9.x is supported for now. */ |
33 | static inline int vid_to_reg(int val, u8 vrm) | 33 | static inline int vid_to_reg(int val, u8 vrm) |
34 | { | 34 | { |
35 | switch (vrm) { | 35 | switch (vrm) { |
36 | case 91: /* VRM 9.1 */ | 36 | case 91: /* VRM 9.1 */ |
37 | case 90: /* VRM 9.0 */ | 37 | case 90: /* VRM 9.0 */ |
38 | return ((val >= 1100) && (val <= 1850) ? | 38 | return ((val >= 1100) && (val <= 1850) ? |
39 | ((18499 - val * 10) / 25 + 5) / 10 : -1); | 39 | ((18499 - val * 10) / 25 + 5) / 10 : -1); |
40 | default: | 40 | default: |
41 | return -1; | 41 | return -EINVAL; |
42 | } | 42 | } |
43 | } | 43 | } |
44 | 44 | ||
45 | #endif /* _LINUX_HWMON_VID_H */ | 45 | #endif /* _LINUX_HWMON_VID_H */ |
46 | 46 |