Commit | Line | Data |
---|---|---|
9c947d25 VV |
1 | /* |
2 | * nct7904.c - driver for Nuvoton NCT7904D. | |
3 | * | |
4 | * Copyright (c) 2015 Kontron | |
5 | * Author: Vadim V. Vlasov <vvlasov@dev.rtsoft.ru> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as published by | |
9 | * the Free Software Foundation; either version 2 of the License, or | |
10 | * (at your option) any later version. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | */ | |
17 | ||
18 | #include <linux/module.h> | |
19 | #include <linux/device.h> | |
20 | #include <linux/init.h> | |
21 | #include <linux/i2c.h> | |
22 | #include <linux/mutex.h> | |
23 | #include <linux/hwmon.h> | |
24 | #include <linux/hwmon-sysfs.h> | |
25 | ||
26 | #define VENDOR_ID_REG 0x7A /* Any bank */ | |
27 | #define NUVOTON_ID 0x50 | |
28 | #define CHIP_ID_REG 0x7B /* Any bank */ | |
29 | #define NCT7904_ID 0xC5 | |
30 | #define DEVICE_ID_REG 0x7C /* Any bank */ | |
31 | ||
32 | #define BANK_SEL_REG 0xFF | |
33 | #define BANK_0 0x00 | |
34 | #define BANK_1 0x01 | |
35 | #define BANK_2 0x02 | |
36 | #define BANK_3 0x03 | |
37 | #define BANK_4 0x04 | |
38 | #define BANK_MAX 0x04 | |
39 | ||
40 | #define FANIN_MAX 12 /* Counted from 1 */ | |
41 | #define VSEN_MAX 21 /* VSEN1..14, 3VDD, VBAT, V3VSB, | |
42 | LTD (not a voltage), VSEN17..19 */ | |
43 | #define FANCTL_MAX 4 /* Counted from 1 */ | |
44 | #define TCPU_MAX 8 /* Counted from 1 */ | |
45 | #define TEMP_MAX 4 /* Counted from 1 */ | |
46 | ||
47 | #define VT_ADC_CTRL0_REG 0x20 /* Bank 0 */ | |
48 | #define VT_ADC_CTRL1_REG 0x21 /* Bank 0 */ | |
49 | #define VT_ADC_CTRL2_REG 0x22 /* Bank 0 */ | |
50 | #define FANIN_CTRL0_REG 0x24 | |
51 | #define FANIN_CTRL1_REG 0x25 | |
52 | #define DTS_T_CTRL0_REG 0x26 | |
53 | #define DTS_T_CTRL1_REG 0x27 | |
54 | #define VT_ADC_MD_REG 0x2E | |
55 | ||
56 | #define VSEN1_HV_REG 0x40 /* Bank 0; 2 regs (HV/LV) per sensor */ | |
57 | #define TEMP_CH1_HV_REG 0x42 /* Bank 0; same as VSEN2_HV */ | |
58 | #define LTD_HV_REG 0x62 /* Bank 0; 2 regs in VSEN range */ | |
59 | #define FANIN1_HV_REG 0x80 /* Bank 0; 2 regs (HV/LV) per sensor */ | |
60 | #define T_CPU1_HV_REG 0xA0 /* Bank 0; 2 regs (HV/LV) per sensor */ | |
61 | ||
62 | #define PRTS_REG 0x03 /* Bank 2 */ | |
63 | #define FANCTL1_FMR_REG 0x00 /* Bank 3; 1 reg per channel */ | |
64 | #define FANCTL1_OUT_REG 0x10 /* Bank 3; 1 reg per channel */ | |
65 | ||
66 | static const unsigned short normal_i2c[] = { | |
67 | 0x2d, 0x2e, I2C_CLIENT_END | |
68 | }; | |
69 | ||
70 | struct nct7904_data { | |
71 | struct i2c_client *client; | |
72 | struct mutex bank_lock; | |
73 | int bank_sel; | |
74 | u32 fanin_mask; | |
75 | u32 vsen_mask; | |
76 | u32 tcpu_mask; | |
77 | u8 fan_mode[FANCTL_MAX]; | |
78 | }; | |
79 | ||
80 | /* Access functions */ | |
81 | static int nct7904_bank_lock(struct nct7904_data *data, unsigned bank) | |
82 | { | |
83 | int ret; | |
84 | ||
85 | mutex_lock(&data->bank_lock); | |
86 | if (data->bank_sel == bank) | |
87 | return 0; | |
88 | ret = i2c_smbus_write_byte_data(data->client, BANK_SEL_REG, bank); | |
89 | if (ret == 0) | |
90 | data->bank_sel = bank; | |
91 | else | |
92 | data->bank_sel = -1; | |
93 | return ret; | |
94 | } | |
95 | ||
96 | static inline void nct7904_bank_release(struct nct7904_data *data) | |
97 | { | |
98 | mutex_unlock(&data->bank_lock); | |
99 | } | |
100 | ||
101 | /* Read 1-byte register. Returns unsigned reg or -ERRNO on error. */ | |
102 | static int nct7904_read_reg(struct nct7904_data *data, | |
103 | unsigned bank, unsigned reg) | |
104 | { | |
105 | struct i2c_client *client = data->client; | |
106 | int ret; | |
107 | ||
108 | ret = nct7904_bank_lock(data, bank); | |
109 | if (ret == 0) | |
110 | ret = i2c_smbus_read_byte_data(client, reg); | |
111 | ||
112 | nct7904_bank_release(data); | |
113 | return ret; | |
114 | } | |
115 | ||
116 | /* | |
117 | * Read 2-byte register. Returns register in big-endian format or | |
118 | * -ERRNO on error. | |
119 | */ | |
120 | static int nct7904_read_reg16(struct nct7904_data *data, | |
121 | unsigned bank, unsigned reg) | |
122 | { | |
123 | struct i2c_client *client = data->client; | |
124 | int ret, hi; | |
125 | ||
126 | ret = nct7904_bank_lock(data, bank); | |
127 | if (ret == 0) { | |
128 | ret = i2c_smbus_read_byte_data(client, reg); | |
129 | if (ret >= 0) { | |
130 | hi = ret; | |
131 | ret = i2c_smbus_read_byte_data(client, reg + 1); | |
132 | if (ret >= 0) | |
133 | ret |= hi << 8; | |
134 | } | |
135 | } | |
136 | ||
137 | nct7904_bank_release(data); | |
138 | return ret; | |
139 | } | |
140 | ||
141 | /* Write 1-byte register. Returns 0 or -ERRNO on error. */ | |
142 | static int nct7904_write_reg(struct nct7904_data *data, | |
143 | unsigned bank, unsigned reg, u8 val) | |
144 | { | |
145 | struct i2c_client *client = data->client; | |
146 | int ret; | |
147 | ||
148 | ret = nct7904_bank_lock(data, bank); | |
149 | if (ret == 0) | |
150 | ret = i2c_smbus_write_byte_data(client, reg, val); | |
151 | ||
152 | nct7904_bank_release(data); | |
153 | return ret; | |
154 | } | |
155 | ||
156 | /* FANIN ATTR */ | |
157 | static ssize_t show_fan(struct device *dev, | |
158 | struct device_attribute *devattr, char *buf) | |
159 | { | |
160 | int index = to_sensor_dev_attr(devattr)->index; | |
161 | struct nct7904_data *data = dev_get_drvdata(dev); | |
162 | int ret; | |
163 | unsigned cnt, rpm; | |
164 | ||
165 | ret = nct7904_read_reg16(data, BANK_0, FANIN1_HV_REG + index * 2); | |
166 | if (ret < 0) | |
167 | return ret; | |
168 | cnt = ((ret & 0xff00) >> 3) | (ret & 0x1f); | |
169 | if (cnt == 0x1fff) | |
170 | rpm = 0; | |
171 | else | |
172 | rpm = 1350000 / cnt; | |
173 | return sprintf(buf, "%u\n", rpm); | |
174 | } | |
175 | ||
176 | static umode_t nct7904_fanin_is_visible(struct kobject *kobj, | |
177 | struct attribute *a, int n) | |
178 | { | |
179 | struct device *dev = container_of(kobj, struct device, kobj); | |
180 | struct nct7904_data *data = dev_get_drvdata(dev); | |
181 | ||
182 | if (data->fanin_mask & (1 << n)) | |
183 | return a->mode; | |
184 | return 0; | |
185 | } | |
186 | ||
187 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); | |
188 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); | |
189 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); | |
190 | static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); | |
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 | }; | |
220 | ||
221 | /* VSEN ATTR */ | |
222 | static ssize_t show_voltage(struct device *dev, | |
223 | struct device_attribute *devattr, char *buf) | |
224 | { | |
225 | int index = to_sensor_dev_attr(devattr)->index; | |
226 | struct nct7904_data *data = dev_get_drvdata(dev); | |
227 | int ret; | |
228 | int volt; | |
229 | ||
230 | ret = nct7904_read_reg16(data, BANK_0, VSEN1_HV_REG + index * 2); | |
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 | ||
239 | return sprintf(buf, "%d\n", volt); | |
240 | } | |
241 | ||
242 | static ssize_t show_ltemp(struct device *dev, | |
243 | struct device_attribute *devattr, char *buf) | |
244 | { | |
245 | struct nct7904_data *data = dev_get_drvdata(dev); | |
246 | int ret; | |
247 | int temp; | |
248 | ||
249 | ret = nct7904_read_reg16(data, BANK_0, LTD_HV_REG); | |
250 | if (ret < 0) | |
251 | return ret; | |
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 | ||
264 | if (data->vsen_mask & (1 << n)) | |
265 | return a->mode; | |
266 | return 0; | |
267 | } | |
268 | ||
269 | static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_voltage, NULL, 0); | |
270 | static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_voltage, NULL, 1); | |
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 | { | |
330 | int index = to_sensor_dev_attr(devattr)->index; | |
331 | struct nct7904_data *data = dev_get_drvdata(dev); | |
332 | int ret; | |
333 | int temp; | |
334 | ||
335 | ret = nct7904_read_reg16(data, BANK_0, T_CPU1_HV_REG + index * 2); | |
336 | if (ret < 0) | |
337 | return ret; | |
338 | ||
339 | temp = ((ret & 0xff00) >> 5) | (ret & 0x7); | |
340 | temp = sign_extend32(temp, 10) * 125; | |
341 | return sprintf(buf, "%d\n", temp); | |
342 | } | |
343 | ||
344 | static umode_t nct7904_tcpu_is_visible(struct kobject *kobj, | |
345 | struct attribute *a, int n) | |
346 | { | |
347 | struct device *dev = container_of(kobj, struct device, kobj); | |
348 | struct nct7904_data *data = dev_get_drvdata(dev); | |
349 | ||
350 | if (data->tcpu_mask & (1 << n)) | |
351 | return a->mode; | |
352 | return 0; | |
353 | } | |
354 | ||
355 | /* "temp1_input" reserved for local temp */ | |
356 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_tcpu, NULL, 0); | |
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 | { | |
386 | int index = to_sensor_dev_attr(devattr)->index; | |
387 | struct nct7904_data *data = dev_get_drvdata(dev); | |
388 | unsigned long val; | |
389 | int ret; | |
390 | ||
391 | if (kstrtoul(buf, 10, &val) < 0) | |
392 | return -EINVAL; | |
393 | if (val > 255) | |
394 | return -EINVAL; | |
395 | ||
396 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_OUT_REG + index, val); | |
397 | ||
398 | return ret ? ret : count; | |
399 | } | |
400 | ||
401 | static ssize_t show_pwm(struct device *dev, | |
402 | struct device_attribute *devattr, char *buf) | |
403 | { | |
404 | int index = to_sensor_dev_attr(devattr)->index; | |
405 | struct nct7904_data *data = dev_get_drvdata(dev); | |
406 | int val; | |
407 | ||
408 | val = nct7904_read_reg(data, BANK_3, FANCTL1_OUT_REG + index); | |
409 | if (val < 0) | |
410 | return val; | |
411 | ||
412 | return sprintf(buf, "%d\n", val); | |
413 | } | |
414 | ||
0d6aaffc GR |
415 | static ssize_t store_enable(struct device *dev, |
416 | struct device_attribute *devattr, | |
417 | const char *buf, size_t count) | |
9c947d25 VV |
418 | { |
419 | int index = to_sensor_dev_attr(devattr)->index; | |
420 | struct nct7904_data *data = dev_get_drvdata(dev); | |
421 | unsigned long val; | |
422 | int ret; | |
423 | ||
424 | if (kstrtoul(buf, 10, &val) < 0) | |
425 | return -EINVAL; | |
0d6aaffc | 426 | if (val < 1 || val > 2 || (val == 2 && !data->fan_mode[index])) |
9c947d25 VV |
427 | return -EINVAL; |
428 | ||
429 | ret = nct7904_write_reg(data, BANK_3, FANCTL1_FMR_REG + index, | |
0d6aaffc | 430 | val == 2 ? data->fan_mode[index] : 0); |
9c947d25 VV |
431 | |
432 | return ret ? ret : count; | |
433 | } | |
434 | ||
0d6aaffc GR |
435 | /* Return 1 for manual mode or 2 for SmartFan mode */ |
436 | static ssize_t show_enable(struct device *dev, | |
437 | struct device_attribute *devattr, char *buf) | |
9c947d25 VV |
438 | { |
439 | int index = to_sensor_dev_attr(devattr)->index; | |
440 | struct nct7904_data *data = dev_get_drvdata(dev); | |
441 | int val; | |
442 | ||
443 | val = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + index); | |
444 | if (val < 0) | |
445 | return val; | |
446 | ||
0d6aaffc | 447 | return sprintf(buf, "%d\n", val ? 2 : 1); |
9c947d25 VV |
448 | } |
449 | ||
450 | /* 2 attributes per channel: pwm and mode */ | |
0d6aaffc | 451 | static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, |
9c947d25 | 452 | show_pwm, store_pwm, 0); |
0d6aaffc GR |
453 | static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, |
454 | show_enable, store_enable, 0); | |
455 | static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, | |
9c947d25 | 456 | show_pwm, store_pwm, 1); |
0d6aaffc GR |
457 | static SENSOR_DEVICE_ATTR(pwm2_enable, S_IRUGO | S_IWUSR, |
458 | show_enable, store_enable, 1); | |
459 | static SENSOR_DEVICE_ATTR(pwm3, S_IRUGO | S_IWUSR, | |
9c947d25 | 460 | show_pwm, store_pwm, 2); |
0d6aaffc GR |
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, | |
9c947d25 | 464 | show_pwm, store_pwm, 3); |
0d6aaffc GR |
465 | static SENSOR_DEVICE_ATTR(pwm4_enable, S_IRUGO | S_IWUSR, |
466 | show_enable, store_enable, 3); | |
9c947d25 VV |
467 | |
468 | static struct attribute *nct7904_fanctl_attrs[] = { | |
0d6aaffc GR |
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, | |
9c947d25 VV |
477 | NULL |
478 | }; | |
479 | ||
480 | static const struct attribute_group nct7904_fanctl_group = { | |
481 | .attrs = nct7904_fanctl_attrs, | |
482 | }; | |
483 | ||
484 | static const struct attribute_group *nct7904_groups[] = { | |
485 | &nct7904_fanin_group, | |
486 | &nct7904_vsen_group, | |
487 | &nct7904_tcpu_group, | |
488 | &nct7904_fanctl_group, | |
489 | NULL | |
490 | }; | |
491 | ||
492 | /* Return 0 if detection is successful, -ENODEV otherwise */ | |
493 | static int nct7904_detect(struct i2c_client *client, | |
494 | struct i2c_board_info *info) | |
495 | { | |
496 | struct i2c_adapter *adapter = client->adapter; | |
497 | ||
498 | if (!i2c_check_functionality(adapter, | |
499 | I2C_FUNC_SMBUS_READ_BYTE | | |
500 | I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) | |
501 | return -ENODEV; | |
502 | ||
503 | /* Determine the chip type. */ | |
504 | if (i2c_smbus_read_byte_data(client, VENDOR_ID_REG) != NUVOTON_ID || | |
505 | i2c_smbus_read_byte_data(client, CHIP_ID_REG) != NCT7904_ID || | |
6552f327 GR |
506 | (i2c_smbus_read_byte_data(client, DEVICE_ID_REG) & 0xf0) != 0x50 || |
507 | (i2c_smbus_read_byte_data(client, BANK_SEL_REG) & 0xf8) != 0x00) | |
9c947d25 VV |
508 | return -ENODEV; |
509 | ||
510 | strlcpy(info->type, "nct7904", I2C_NAME_SIZE); | |
511 | ||
512 | return 0; | |
513 | } | |
514 | ||
515 | static int nct7904_probe(struct i2c_client *client, | |
516 | const struct i2c_device_id *id) | |
517 | { | |
518 | struct nct7904_data *data; | |
519 | struct device *hwmon_dev; | |
520 | struct device *dev = &client->dev; | |
521 | int ret, i; | |
522 | u32 mask; | |
523 | ||
524 | data = devm_kzalloc(dev, sizeof(struct nct7904_data), GFP_KERNEL); | |
525 | if (!data) | |
526 | return -ENOMEM; | |
527 | ||
528 | data->client = client; | |
529 | mutex_init(&data->bank_lock); | |
530 | data->bank_sel = -1; | |
531 | ||
532 | /* Setup sensor groups. */ | |
533 | /* FANIN attributes */ | |
534 | ret = nct7904_read_reg16(data, BANK_0, FANIN_CTRL0_REG); | |
535 | if (ret < 0) | |
536 | return ret; | |
537 | data->fanin_mask = (ret >> 8) | ((ret & 0xff) << 8); | |
538 | ||
539 | /* | |
540 | * VSEN attributes | |
541 | * | |
542 | * Note: voltage sensors overlap with external temperature | |
543 | * sensors. So, if we ever decide to support the latter | |
544 | * we will have to adjust 'vsen_mask' accordingly. | |
545 | */ | |
546 | mask = 0; | |
547 | ret = nct7904_read_reg16(data, BANK_0, VT_ADC_CTRL0_REG); | |
548 | if (ret >= 0) | |
549 | mask = (ret >> 8) | ((ret & 0xff) << 8); | |
550 | ret = nct7904_read_reg(data, BANK_0, VT_ADC_CTRL2_REG); | |
551 | if (ret >= 0) | |
552 | mask |= (ret << 16); | |
553 | data->vsen_mask = mask; | |
554 | ||
555 | /* CPU_TEMP attributes */ | |
556 | ret = nct7904_read_reg16(data, BANK_0, DTS_T_CTRL0_REG); | |
557 | if (ret < 0) | |
558 | return ret; | |
559 | data->tcpu_mask = ((ret >> 8) & 0xf) | ((ret & 0xf) << 4); | |
560 | ||
561 | for (i = 0; i < FANCTL_MAX; i++) { | |
562 | ret = nct7904_read_reg(data, BANK_3, FANCTL1_FMR_REG + i); | |
563 | if (ret < 0) | |
564 | return ret; | |
565 | data->fan_mode[i] = ret; | |
566 | } | |
567 | ||
568 | hwmon_dev = | |
569 | devm_hwmon_device_register_with_groups(dev, client->name, data, | |
570 | nct7904_groups); | |
571 | return PTR_ERR_OR_ZERO(hwmon_dev); | |
572 | } | |
573 | ||
574 | static const struct i2c_device_id nct7904_id[] = { | |
575 | {"nct7904", 0}, | |
576 | {} | |
577 | }; | |
1252be9c | 578 | MODULE_DEVICE_TABLE(i2c, nct7904_id); |
9c947d25 VV |
579 | |
580 | static struct i2c_driver nct7904_driver = { | |
581 | .class = I2C_CLASS_HWMON, | |
582 | .driver = { | |
583 | .name = "nct7904", | |
584 | }, | |
585 | .probe = nct7904_probe, | |
586 | .id_table = nct7904_id, | |
587 | .detect = nct7904_detect, | |
588 | .address_list = normal_i2c, | |
589 | }; | |
590 | ||
591 | module_i2c_driver(nct7904_driver); | |
592 | ||
593 | MODULE_AUTHOR("Vadim V. Vlasov <vvlasov@dev.rtsoft.ru>"); | |
594 | MODULE_DESCRIPTION("Hwmon driver for NUVOTON NCT7904"); | |
595 | MODULE_LICENSE("GPL"); |