diff options
author | Guenter Roeck <linux@roeck-us.net> | 2016-06-26 15:22:03 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2016-09-09 00:34:18 -0400 |
commit | d65a5102a99f5b2f95956b9deff66052b563c996 (patch) | |
tree | c7c46a80e58681c3c48154dec42025fddd5e443f | |
parent | a584287cd26cefba42d72b0cb7050e01b3aa77b8 (diff) |
hwmon: (nct7904) Convert to use new hwmon registration API
Simplify code and reduce code size by using the new hwmon
registration API.
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | drivers/hwmon/nct7904.c | 555 |
1 files changed, 270 insertions, 285 deletions
diff --git a/drivers/hwmon/nct7904.c b/drivers/hwmon/nct7904.c index 08ff89d222e5..95a68ab175c7 100644 --- a/drivers/hwmon/nct7904.c +++ b/drivers/hwmon/nct7904.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/i2c.h> | 21 | #include <linux/i2c.h> |
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/hwmon.h> | 23 | #include <linux/hwmon.h> |
24 | #include <linux/hwmon-sysfs.h> | ||
25 | 24 | ||
26 | #define VENDOR_ID_REG 0x7A /* Any bank */ | 25 | #define VENDOR_ID_REG 0x7A /* Any bank */ |
27 | #define NUVOTON_ID 0x50 | 26 | #define NUVOTON_ID 0x50 |
@@ -153,341 +152,230 @@ static int nct7904_write_reg(struct nct7904_data *data, | |||
153 | return ret; | 152 | return ret; |
154 | } | 153 | } |
155 | 154 | ||
156 | /* FANIN ATTR */ | 155 | static int nct7904_read_fan(struct device *dev, u32 attr, int channel, |
157 | static ssize_t show_fan(struct device *dev, | 156 | long *val) |
158 | struct device_attribute *devattr, char *buf) | ||
159 | { | 157 | { |
160 | int index = to_sensor_dev_attr(devattr)->index; | ||
161 | struct nct7904_data *data = dev_get_drvdata(dev); | 158 | struct nct7904_data *data = dev_get_drvdata(dev); |
159 | unsigned int cnt, rpm; | ||
162 | int ret; | 160 | int ret; |
163 | unsigned cnt, rpm; | ||
164 | 161 | ||
165 | ret = nct7904_read_reg16(data, BANK_0, FANIN1_HV_REG + index * 2); | 162 | switch(attr) { |
166 | if (ret < 0) | 163 | case hwmon_fan_input: |
167 | return ret; | 164 | ret = nct7904_read_reg16(data, BANK_0, |
168 | cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); | 165 | FANIN1_HV_REG + channel * 2); |
169 | if (cnt == 0x1fff) | 166 | if (ret < 0) |
170 | rpm = 0; | 167 | return ret; |
171 | else | 168 | cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); |
172 | rpm = 1350000 / cnt; | 169 | if (cnt == 0x1fff) |
173 | return sprintf(buf, "%u\n", rpm); | 170 | rpm = 0; |
171 | else | ||
172 | rpm = 1350000 / cnt; | ||
173 | *val = rpm; | ||
174 | return 0; | ||
175 | default: | ||
176 | return -EOPNOTSUPP; | ||
177 | } | ||
174 | } | 178 | } |
175 | 179 | ||
176 | static umode_t nct7904_fanin_is_visible(struct kobject *kobj, | 180 | static umode_t nct7904_fan_is_visible(const void *_data, u32 attr, int channel) |
177 | struct attribute *a, int n) | ||
178 | { | 181 | { |
179 | struct device *dev = container_of(kobj, struct device, kobj); | 182 | const struct nct7904_data *data = _data; |
180 | struct nct7904_data *data = dev_get_drvdata(dev); | ||
181 | 183 | ||
182 | if (data->fanin_mask & (1 << n)) | 184 | if (attr == hwmon_fan_input && data->fanin_mask & (1 << channel)) |
183 | return a->mode; | 185 | return S_IRUGO; |
184 | return 0; | 186 | return 0; |
185 | } | 187 | } |
186 | 188 | ||
187 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | 189 | static u8 nct7904_chan_to_index[] = { |
188 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); | 190 | 0, /* Not used */ |
189 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); | 191 | 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
190 | static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); | 192 | 18, 19, 20, 16 |
191 | static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 4); | ||
192 | static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 5); | ||
193 | static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 6); | ||
194 | static SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan, NULL, 7); | ||
195 | static SENSOR_DEVICE_ATTR(fan9_input, S_IRUGO, show_fan, NULL, 8); | ||
196 | static SENSOR_DEVICE_ATTR(fan10_input, S_IRUGO, show_fan, NULL, 9); | ||
197 | static SENSOR_DEVICE_ATTR(fan11_input, S_IRUGO, show_fan, NULL, 10); | ||
198 | static SENSOR_DEVICE_ATTR(fan12_input, S_IRUGO, show_fan, NULL, 11); | ||
199 | |||
200 | static struct attribute *nct7904_fanin_attrs[] = { | ||
201 | &sensor_dev_attr_fan1_input.dev_attr.attr, | ||
202 | &sensor_dev_attr_fan2_input.dev_attr.attr, | ||
203 | &sensor_dev_attr_fan3_input.dev_attr.attr, | ||
204 | &sensor_dev_attr_fan4_input.dev_attr.attr, | ||
205 | &sensor_dev_attr_fan5_input.dev_attr.attr, | ||
206 | &sensor_dev_attr_fan6_input.dev_attr.attr, | ||
207 | &sensor_dev_attr_fan7_input.dev_attr.attr, | ||
208 | &sensor_dev_attr_fan8_input.dev_attr.attr, | ||
209 | &sensor_dev_attr_fan9_input.dev_attr.attr, | ||
210 | &sensor_dev_attr_fan10_input.dev_attr.attr, | ||
211 | &sensor_dev_attr_fan11_input.dev_attr.attr, | ||
212 | &sensor_dev_attr_fan12_input.dev_attr.attr, | ||
213 | NULL | ||
214 | }; | ||
215 | |||
216 | static const struct attribute_group nct7904_fanin_group = { | ||
217 | .attrs = nct7904_fanin_attrs, | ||
218 | .is_visible = nct7904_fanin_is_visible, | ||
219 | }; | 193 | }; |
220 | 194 | ||
221 | /* VSEN ATTR */ | 195 | static int nct7904_read_in(struct device *dev, u32 attr, int channel, |
222 | static ssize_t show_voltage(struct device *dev, | 196 | long *val) |
223 | struct device_attribute *devattr, char *buf) | ||
224 | { | 197 | { |
225 | int index = to_sensor_dev_attr(devattr)->index; | ||
226 | struct nct7904_data *data = dev_get_drvdata(dev); | 198 | struct nct7904_data *data = dev_get_drvdata(dev); |
227 | int ret; | 199 | int ret, volt, index; |
228 | int volt; | ||
229 | 200 | ||
230 | ret = nct7904_read_reg16(data, BANK_0, VSEN1_HV_REG + index * 2); | 201 | index = nct7904_chan_to_index[channel]; |
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | volt = ((ret & 0xff00) >> 5) | (ret & 0x7); | ||
234 | if (index < 14) | ||
235 | volt *= 2; /* 0.002V scale */ | ||
236 | else | ||
237 | volt *= 6; /* 0.006V scale */ | ||
238 | 202 | ||
239 | return sprintf(buf, "%d\n", volt); | 203 | switch(attr) { |
204 | case hwmon_in_input: | ||
205 | ret = nct7904_read_reg16(data, BANK_0, | ||
206 | VSEN1_HV_REG + index * 2); | ||
207 | if (ret < 0) | ||
208 | return ret; | ||
209 | volt = ((ret & 0xff00) >> 5) | (ret & 0x7); | ||
210 | if (index < 14) | ||
211 | volt *= 2; /* 0.002V scale */ | ||
212 | else | ||
213 | volt *= 6; /* 0.006V scale */ | ||
214 | *val = volt; | ||
215 | return 0; | ||
216 | default: | ||
217 | return -EOPNOTSUPP; | ||
218 | } | ||
240 | } | 219 | } |
241 | 220 | ||
242 | static ssize_t show_ltemp(struct device *dev, | 221 | static umode_t nct7904_in_is_visible(const void *_data, u32 attr, int channel) |
243 | struct device_attribute *devattr, char *buf) | ||
244 | { | 222 | { |
245 | struct nct7904_data *data = dev_get_drvdata(dev); | 223 | const struct nct7904_data *data = _data; |
246 | int ret; | 224 | int index = nct7904_chan_to_index[channel]; |
247 | int temp; | ||
248 | 225 | ||
249 | ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG); | 226 | if (channel > 0 && attr == hwmon_in_input && |
250 | if (ret < 0) | 227 | (data->vsen_mask & BIT(index))) |
251 | return ret; | 228 | return S_IRUGO; |
252 | temp = ((ret & 0xff00) >> 5) | (ret & 0x7); | ||
253 | temp = sign_extend32(temp, 10) * 125; | ||
254 | |||
255 | return sprintf(buf, "%d\n", temp); | ||
256 | } | ||
257 | |||
258 | static umode_t nct7904_vsen_is_visible(struct kobject *kobj, | ||
259 | struct attribute *a, int n) | ||
260 | { | ||
261 | struct device *dev = container_of(kobj, struct device, kobj); | ||
262 | struct nct7904_data *data = dev_get_drvdata(dev); | ||
263 | 229 | ||
264 | if (data->vsen_mask & (1 << n)) | ||
265 | return a->mode; | ||
266 | return 0; | 230 | return 0; |
267 | } | 231 | } |
268 | 232 | ||
269 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0); | 233 | static int nct7904_read_temp(struct device *dev, u32 attr, int channel, |
270 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 1); | 234 | long *val) |
271 | static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_voltage, NULL, 2); | ||
272 | static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_voltage, NULL, 3); | ||
273 | static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_voltage, NULL, 4); | ||
274 | static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_voltage, NULL, 5); | ||
275 | static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_voltage, NULL, 6); | ||
276 | static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_voltage, NULL, 7); | ||
277 | static SENSOR_DEVICE_ATTR(in9_input, S_IRUGO, show_voltage, NULL, 8); | ||
278 | static SENSOR_DEVICE_ATTR(in10_input, S_IRUGO, show_voltage, NULL, 9); | ||
279 | static SENSOR_DEVICE_ATTR(in11_input, S_IRUGO, show_voltage, NULL, 10); | ||
280 | static SENSOR_DEVICE_ATTR(in12_input, S_IRUGO, show_voltage, NULL, 11); | ||
281 | static SENSOR_DEVICE_ATTR(in13_input, S_IRUGO, show_voltage, NULL, 12); | ||
282 | static SENSOR_DEVICE_ATTR(in14_input, S_IRUGO, show_voltage, NULL, 13); | ||
283 | /* | ||
284 | * Next 3 voltage sensors have specific names in the Nuvoton doc | ||
285 | * (3VDD, VBAT, 3VSB) but we use vacant numbers for them. | ||
286 | */ | ||
287 | static SENSOR_DEVICE_ATTR(in15_input, S_IRUGO, show_voltage, NULL, 14); | ||
288 | static SENSOR_DEVICE_ATTR(in16_input, S_IRUGO, show_voltage, NULL, 15); | ||
289 | static SENSOR_DEVICE_ATTR(in20_input, S_IRUGO, show_voltage, NULL, 16); | ||
290 | /* This is not a voltage, but a local temperature sensor. */ | ||
291 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_ltemp, NULL, 0); | ||
292 | static SENSOR_DEVICE_ATTR(in17_input, S_IRUGO, show_voltage, NULL, 18); | ||
293 | static SENSOR_DEVICE_ATTR(in18_input, S_IRUGO, show_voltage, NULL, 19); | ||
294 | static SENSOR_DEVICE_ATTR(in19_input, S_IRUGO, show_voltage, NULL, 20); | ||
295 | |||
296 | static struct attribute *nct7904_vsen_attrs[] = { | ||
297 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
298 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
299 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
300 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
301 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
302 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
303 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
304 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
305 | &sensor_dev_attr_in9_input.dev_attr.attr, | ||
306 | &sensor_dev_attr_in10_input.dev_attr.attr, | ||
307 | &sensor_dev_attr_in11_input.dev_attr.attr, | ||
308 | &sensor_dev_attr_in12_input.dev_attr.attr, | ||
309 | &sensor_dev_attr_in13_input.dev_attr.attr, | ||
310 | &sensor_dev_attr_in14_input.dev_attr.attr, | ||
311 | &sensor_dev_attr_in15_input.dev_attr.attr, | ||
312 | &sensor_dev_attr_in16_input.dev_attr.attr, | ||
313 | &sensor_dev_attr_in20_input.dev_attr.attr, | ||
314 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
315 | &sensor_dev_attr_in17_input.dev_attr.attr, | ||
316 | &sensor_dev_attr_in18_input.dev_attr.attr, | ||
317 | &sensor_dev_attr_in19_input.dev_attr.attr, | ||
318 | NULL | ||
319 | }; | ||
320 | |||
321 | static const struct attribute_group nct7904_vsen_group = { | ||
322 | .attrs = nct7904_vsen_attrs, | ||
323 | .is_visible = nct7904_vsen_is_visible, | ||
324 | }; | ||
325 | |||
326 | /* CPU_TEMP ATTR */ | ||
327 | static ssize_t show_tcpu(struct device *dev, | ||
328 | struct device_attribute *devattr, char *buf) | ||
329 | { | 235 | { |
330 | int index = to_sensor_dev_attr(devattr)->index; | ||
331 | struct nct7904_data *data = dev_get_drvdata(dev); | 236 | struct nct7904_data *data = dev_get_drvdata(dev); |
332 | int ret; | 237 | int ret, temp; |
333 | int temp; | 238 | |
334 | 239 | switch(attr) { | |
335 | ret = nct7904_read_reg16(data, BANK_0, T_CPU1_HV_REG + index * 2); | 240 | case hwmon_temp_input: |
336 | if (ret < 0) | 241 | if (channel == 0) |
337 | return ret; | 242 | ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG); |
338 | 243 | else | |
339 | temp = ((ret & 0xff00) >> 5) | (ret & 0x7); | 244 | ret = nct7904_read_reg16(data, BANK_0, |
340 | temp = sign_extend32(temp, 10) * 125; | 245 | T_CPU1_HV_REG + (channel - 1) * 2); |
341 | return sprintf(buf, "%d\n", temp); | 246 | if (ret < 0) |
247 | return ret; | ||
248 | temp = ((ret & 0xff00) >> 5) | (ret & 0x7); | ||
249 | *val = sign_extend32(temp, 10) * 125; | ||
250 | return 0; | ||
251 | default: | ||
252 | return -EOPNOTSUPP; | ||
253 | } | ||
342 | } | 254 | } |
343 | 255 | ||
344 | static umode_t nct7904_tcpu_is_visible(struct kobject *kobj, | 256 | static umode_t nct7904_temp_is_visible(const void *_data, u32 attr, int channel) |
345 | struct attribute *a, int n) | ||
346 | { | 257 | { |
347 | struct device *dev = container_of(kobj, struct device, kobj); | 258 | const struct nct7904_data *data = _data; |
348 | struct nct7904_data *data = dev_get_drvdata(dev); | 259 | |
260 | if (attr == hwmon_temp_input) { | ||
261 | if (channel == 0) { | ||
262 | if (data->vsen_mask & BIT(17)) | ||
263 | return S_IRUGO; | ||
264 | } else { | ||
265 | if (data->tcpu_mask & BIT(channel - 1)) | ||
266 | return S_IRUGO; | ||
267 | } | ||
268 | } | ||
349 | 269 | ||
350 | if (data->tcpu_mask & (1 << n)) | ||
351 | return a->mode; | ||
352 | return 0; | 270 | return 0; |
353 | } | 271 | } |
354 | 272 | ||
355 | /* "temp1_input" reserved for local temp */ | 273 | static int nct7904_read_pwm(struct device *dev, u32 attr, int channel, |
356 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_tcpu, NULL, 0); | 274 | long *val) |
357 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_tcpu, NULL, 1); | ||
358 | static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_tcpu, NULL, 2); | ||
359 | static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_tcpu, NULL, 3); | ||
360 | static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_tcpu, NULL, 4); | ||
361 | static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_tcpu, NULL, 5); | ||
362 | static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_tcpu, NULL, 6); | ||
363 | static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_tcpu, NULL, 7); | ||
364 | |||
365 | static struct attribute *nct7904_tcpu_attrs[] = { | ||
366 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
367 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
368 | &sensor_dev_attr_temp4_input.dev_attr.attr, | ||
369 | &sensor_dev_attr_temp5_input.dev_attr.attr, | ||
370 | &sensor_dev_attr_temp6_input.dev_attr.attr, | ||
371 | &sensor_dev_attr_temp7_input.dev_attr.attr, | ||
372 | &sensor_dev_attr_temp8_input.dev_attr.attr, | ||
373 | &sensor_dev_attr_temp9_input.dev_attr.attr, | ||
374 | NULL | ||
375 | }; | ||
376 | |||
377 | static const struct attribute_group nct7904_tcpu_group = { | ||
378 | .attrs = nct7904_tcpu_attrs, | ||
379 | .is_visible = nct7904_tcpu_is_visible, | ||
380 | }; | ||
381 | |||
382 | /* PWM ATTR */ | ||
383 | static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, | ||
384 | const char *buf, size_t count) | ||
385 | { | 275 | { |
386 | int index = to_sensor_dev_attr(devattr)->index; | ||
387 | struct nct7904_data *data = dev_get_drvdata(dev); | 276 | struct nct7904_data *data = dev_get_drvdata(dev); |
388 | unsigned long val; | ||
389 | int ret; | 277 | int ret; |
390 | 278 | ||
391 | if (kstrtoul(buf, 10, &val) < 0) | 279 | switch(attr) { |
392 | return -EINVAL; | 280 | case hwmon_pwm_input: |
393 | if (val > 255) | 281 | ret = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + channel); |
394 | return -EINVAL; | 282 | if (ret < 0) |
395 | 283 | return ret; | |
396 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + index, val); | 284 | *val = ret; |
285 | return 0; | ||
286 | case hwmon_pwm_enable: | ||
287 | ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + channel); | ||
288 | if (ret < 0) | ||
289 | return ret; | ||
397 | 290 | ||
398 | return ret ? ret : count; | 291 | *val = ret ? 2 : 1; |
292 | return 0; | ||
293 | default: | ||
294 | return -EOPNOTSUPP; | ||
295 | } | ||
399 | } | 296 | } |
400 | 297 | ||
401 | static ssize_t show_pwm(struct device *dev, | 298 | static int nct7904_write_pwm(struct device *dev, u32 attr, int channel, |
402 | struct device_attribute *devattr, char *buf) | 299 | long val) |
403 | { | 300 | { |
404 | int index = to_sensor_dev_attr(devattr)->index; | ||
405 | struct nct7904_data *data = dev_get_drvdata(dev); | 301 | struct nct7904_data *data = dev_get_drvdata(dev); |
406 | int val; | 302 | int ret; |
407 | |||
408 | val = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + index); | ||
409 | if (val < 0) | ||
410 | return val; | ||
411 | 303 | ||
412 | return sprintf(buf, "%d\n", val); | 304 | switch(attr) { |
305 | case hwmon_pwm_input: | ||
306 | if (val < 0 || val > 255) | ||
307 | return -EINVAL; | ||
308 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + channel, | ||
309 | val); | ||
310 | return ret; | ||
311 | case hwmon_pwm_enable: | ||
312 | if (val < 1 || val > 2 || | ||
313 | (val == 2 && !data->fan_mode[channel])) | ||
314 | return -EINVAL; | ||
315 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + channel, | ||
316 | val == 2 ? data->fan_mode[channel] : 0); | ||
317 | return ret; | ||
318 | default: | ||
319 | return -EOPNOTSUPP; | ||
320 | } | ||
413 | } | 321 | } |
414 | 322 | ||
415 | static ssize_t store_enable(struct device *dev, | 323 | static umode_t nct7904_pwm_is_visible(const void *_data, u32 attr, int channel) |
416 | struct device_attribute *devattr, | ||
417 | const char *buf, size_t count) | ||
418 | { | 324 | { |
419 | int index = to_sensor_dev_attr(devattr)->index; | 325 | switch(attr) { |
420 | struct nct7904_data *data = dev_get_drvdata(dev); | 326 | case hwmon_pwm_input: |
421 | unsigned long val; | 327 | case hwmon_pwm_enable: |
422 | int ret; | 328 | return S_IRUGO | S_IWUSR; |
423 | 329 | default: | |
424 | if (kstrtoul(buf, 10, &val) < 0) | 330 | return 0; |
425 | return -EINVAL; | 331 | } |
426 | if (val < 1 || val > 2 || (val == 2 && !data->fan_mode[index])) | ||
427 | return -EINVAL; | ||
428 | |||
429 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + index, | ||
430 | val == 2 ? data->fan_mode[index] : 0); | ||
431 | |||
432 | return ret ? ret : count; | ||
433 | } | 332 | } |
434 | 333 | ||
435 | /* Return 1 for manual mode or 2 for SmartFan mode */ | 334 | static int nct7904_read(struct device *dev, enum hwmon_sensor_types type, |
436 | static ssize_t show_enable(struct device *dev, | 335 | u32 attr, int channel, long *val) |
437 | struct device_attribute *devattr, char *buf) | ||
438 | { | 336 | { |
439 | int index = to_sensor_dev_attr(devattr)->index; | 337 | switch (type) { |
440 | struct nct7904_data *data = dev_get_drvdata(dev); | 338 | case hwmon_in: |
441 | int val; | 339 | return nct7904_read_in(dev, attr, channel, val); |
442 | 340 | case hwmon_fan: | |
443 | val = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + index); | 341 | return nct7904_read_fan(dev, attr, channel, val); |
444 | if (val < 0) | 342 | case hwmon_pwm: |
445 | return val; | 343 | return nct7904_read_pwm(dev, attr, channel, val); |
446 | 344 | case hwmon_temp: | |
447 | return sprintf(buf, "%d\n", val ? 2 : 1); | 345 | return nct7904_read_temp(dev, attr, channel, val); |
346 | default: | ||
347 | return -EOPNOTSUPP; | ||
348 | } | ||
448 | } | 349 | } |
449 | 350 | ||
450 | /* 2 attributes per channel: pwm and mode */ | 351 | static int nct7904_write(struct device *dev, enum hwmon_sensor_types type, |
451 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, | 352 | u32 attr, int channel, long val) |
452 | show_pwm, store_pwm, 0); | 353 | { |
453 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, | 354 | switch (type) { |
454 | show_enable, store_enable, 0); | 355 | case hwmon_pwm: |
455 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, | 356 | return nct7904_write_pwm(dev, attr, channel, val); |
456 | show_pwm, store_pwm, 1); | 357 | default: |
457 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, | 358 | return -EOPNOTSUPP; |
458 | show_enable, store_enable, 1); | 359 | } |
459 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, | 360 | } |
460 | show_pwm, store_pwm, 2); | ||
461 | static SENSOR_DEVICE_ATTR(pwm3_enable, S_IRUGO | S_IWUSR, | ||
462 | show_enable, store_enable, 2); | ||
463 | static SENSOR_DEVICE_ATTR(pwm4, S_IRUGO | S_IWUSR, | ||
464 | show_pwm, store_pwm, 3); | ||
465 | static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR, | ||
466 | show_enable, store_enable, 3); | ||
467 | |||
468 | static struct attribute *nct7904_fanctl_attrs[] = { | ||
469 | &sensor_dev_attr_pwm1.dev_attr.attr, | ||
470 | &sensor_dev_attr_pwm1_enable.dev_attr.attr, | ||
471 | &sensor_dev_attr_pwm2.dev_attr.attr, | ||
472 | &sensor_dev_attr_pwm2_enable.dev_attr.attr, | ||
473 | &sensor_dev_attr_pwm3.dev_attr.attr, | ||
474 | &sensor_dev_attr_pwm3_enable.dev_attr.attr, | ||
475 | &sensor_dev_attr_pwm4.dev_attr.attr, | ||
476 | &sensor_dev_attr_pwm4_enable.dev_attr.attr, | ||
477 | NULL | ||
478 | }; | ||
479 | |||
480 | static const struct attribute_group nct7904_fanctl_group = { | ||
481 | .attrs = nct7904_fanctl_attrs, | ||
482 | }; | ||
483 | 361 | ||
484 | static const struct attribute_group *nct7904_groups[] = { | 362 | static umode_t nct7904_is_visible(const void *data, |
485 | &nct7904_fanin_group, | 363 | enum hwmon_sensor_types type, |
486 | &nct7904_vsen_group, | 364 | u32 attr, int channel) |
487 | &nct7904_tcpu_group, | 365 | { |
488 | &nct7904_fanctl_group, | 366 | switch (type) { |
489 | NULL | 367 | case hwmon_in: |
490 | }; | 368 | return nct7904_in_is_visible(data, attr, channel); |
369 | case hwmon_fan: | ||
370 | return nct7904_fan_is_visible(data, attr, channel); | ||
371 | case hwmon_pwm: | ||
372 | return nct7904_pwm_is_visible(data, attr, channel); | ||
373 | case hwmon_temp: | ||
374 | return nct7904_temp_is_visible(data, attr, channel); | ||
375 | default: | ||
376 | return 0; | ||
377 | } | ||
378 | } | ||
491 | 379 | ||
492 | /* Return 0 if detection is successful, -ENODEV otherwise */ | 380 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
493 | static int nct7904_detect(struct i2c_client *client, | 381 | static int nct7904_detect(struct i2c_client *client, |
@@ -512,6 +400,103 @@ static int nct7904_detect(struct i2c_client *client, | |||
512 | return 0; | 400 | return 0; |
513 | } | 401 | } |
514 | 402 | ||
403 | static const u32 nct7904_in_config[] = { | ||
404 | HWMON_I_INPUT, /* dummy, skipped in is_visible */ | ||
405 | HWMON_I_INPUT, | ||
406 | HWMON_I_INPUT, | ||
407 | HWMON_I_INPUT, | ||
408 | HWMON_I_INPUT, | ||
409 | HWMON_I_INPUT, | ||
410 | HWMON_I_INPUT, | ||
411 | HWMON_I_INPUT, | ||
412 | HWMON_I_INPUT, | ||
413 | HWMON_I_INPUT, | ||
414 | HWMON_I_INPUT, | ||
415 | HWMON_I_INPUT, | ||
416 | HWMON_I_INPUT, | ||
417 | HWMON_I_INPUT, | ||
418 | HWMON_I_INPUT, | ||
419 | HWMON_I_INPUT, | ||
420 | HWMON_I_INPUT, | ||
421 | HWMON_I_INPUT, | ||
422 | HWMON_I_INPUT, | ||
423 | HWMON_I_INPUT, | ||
424 | HWMON_I_INPUT, | ||
425 | 0 | ||
426 | }; | ||
427 | |||
428 | static const struct hwmon_channel_info nct7904_in = { | ||
429 | .type = hwmon_in, | ||
430 | .config = nct7904_in_config, | ||
431 | }; | ||
432 | |||
433 | static const u32 nct7904_fan_config[] = { | ||
434 | HWMON_F_INPUT, | ||
435 | HWMON_F_INPUT, | ||
436 | HWMON_F_INPUT, | ||
437 | HWMON_F_INPUT, | ||
438 | HWMON_F_INPUT, | ||
439 | HWMON_F_INPUT, | ||
440 | HWMON_F_INPUT, | ||
441 | HWMON_F_INPUT, | ||
442 | 0 | ||
443 | }; | ||
444 | |||
445 | static const struct hwmon_channel_info nct7904_fan = { | ||
446 | .type = hwmon_fan, | ||
447 | .config = nct7904_fan_config, | ||
448 | }; | ||
449 | |||
450 | static const u32 nct7904_pwm_config[] = { | ||
451 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, | ||
452 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, | ||
453 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, | ||
454 | HWMON_PWM_INPUT | HWMON_PWM_ENABLE, | ||
455 | 0 | ||
456 | }; | ||
457 | |||
458 | static const struct hwmon_channel_info nct7904_pwm = { | ||
459 | .type = hwmon_pwm, | ||
460 | .config = nct7904_pwm_config, | ||
461 | }; | ||
462 | |||
463 | static const u32 nct7904_temp_config[] = { | ||
464 | HWMON_T_INPUT, | ||
465 | HWMON_T_INPUT, | ||
466 | HWMON_T_INPUT, | ||
467 | HWMON_T_INPUT, | ||
468 | HWMON_T_INPUT, | ||
469 | HWMON_T_INPUT, | ||
470 | HWMON_T_INPUT, | ||
471 | HWMON_T_INPUT, | ||
472 | HWMON_T_INPUT, | ||
473 | 0 | ||
474 | }; | ||
475 | |||
476 | static const struct hwmon_channel_info nct7904_temp = { | ||
477 | .type = hwmon_temp, | ||
478 | .config = nct7904_temp_config, | ||
479 | }; | ||
480 | |||
481 | static const struct hwmon_channel_info *nct7904_info[] = { | ||
482 | &nct7904_in, | ||
483 | &nct7904_fan, | ||
484 | &nct7904_pwm, | ||
485 | &nct7904_temp, | ||
486 | NULL | ||
487 | }; | ||
488 | |||
489 | static const struct hwmon_ops nct7904_hwmon_ops = { | ||
490 | .is_visible = nct7904_is_visible, | ||
491 | .read = nct7904_read, | ||
492 | .write = nct7904_write, | ||
493 | }; | ||
494 | |||
495 | static const struct hwmon_chip_info nct7904_chip_info = { | ||
496 | .ops = &nct7904_hwmon_ops, | ||
497 | .info = nct7904_info, | ||
498 | }; | ||
499 | |||
515 | static int nct7904_probe(struct i2c_client *client, | 500 | static int nct7904_probe(struct i2c_client *client, |
516 | const struct i2c_device_id *id) | 501 | const struct i2c_device_id *id) |
517 | { | 502 | { |
@@ -566,8 +551,8 @@ static int nct7904_probe(struct i2c_client *client, | |||
566 | } | 551 | } |
567 | 552 | ||
568 | hwmon_dev = | 553 | hwmon_dev = |
569 | devm_hwmon_device_register_with_groups(dev, client->name, data, | 554 | devm_hwmon_device_register_with_info(dev, client->name, data, |
570 | nct7904_groups); | 555 | &nct7904_chip_info, NULL); |
571 | return PTR_ERR_OR_ZERO(hwmon_dev); | 556 | return PTR_ERR_OR_ZERO(hwmon_dev); |
572 | } | 557 | } |
573 | 558 | ||