diff options
-rw-r--r-- | Documentation/hwmon/nct6775 | 81 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 13 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/nct6775.c | 1021 |
4 files changed, 1116 insertions, 0 deletions
diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775 new file mode 100644 index 000000000000..ccfd5cc21006 --- /dev/null +++ b/Documentation/hwmon/nct6775 | |||
@@ -0,0 +1,81 @@ | |||
1 | Note | ||
2 | ==== | ||
3 | |||
4 | This driver supersedes the NCT6775F and NCT6776F support in the W83627EHF | ||
5 | driver. | ||
6 | |||
7 | Kernel driver NCT6775 | ||
8 | ===================== | ||
9 | |||
10 | Supported chips: | ||
11 | * Nuvoton NCT6775F/W83667HG-I | ||
12 | Prefix: 'nct6775' | ||
13 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
14 | Datasheet: Available from Nuvoton upon request | ||
15 | * Nuvoton NCT6776F | ||
16 | Prefix: 'nct6776' | ||
17 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
18 | Datasheet: Available from Nuvoton upon request | ||
19 | * Nuvoton NCT6779D | ||
20 | Prefix: 'nct6779' | ||
21 | Addresses scanned: ISA address retrieved from Super I/O registers | ||
22 | Datasheet: Available from Nuvoton upon request | ||
23 | |||
24 | Authors: | ||
25 | Guenter Roeck <linux@roeck-us.net> | ||
26 | |||
27 | Description | ||
28 | ----------- | ||
29 | |||
30 | This driver implements support for the Nuvoton NCT6775F, NCT6776F, and NCT6779D | ||
31 | super I/O chips. | ||
32 | |||
33 | The chips support up to 25 temperature monitoring sources. Up to 6 of those are | ||
34 | direct temperature sensor inputs, the others are special sources such as PECI, | ||
35 | PCH, and SMBUS. Depending on the chip type, 2 to 6 of the temperature sources | ||
36 | can be monitored and compared against minimum, maximum, and critical | ||
37 | temperatures. The driver reports up to 10 of the temperatures to the user. | ||
38 | There are 4 to 5 fan rotation speed sensors, 8 to 15 analog voltage sensors, | ||
39 | one VID, alarms with beep warnings (control unimplemented), and some automatic | ||
40 | fan regulation strategies (plus manual fan control mode). | ||
41 | |||
42 | The temperature sensor sources on all chips are configurable. The configured | ||
43 | source for each of the temperature sensors is provided in tempX_label. | ||
44 | |||
45 | Temperatures are measured in degrees Celsius and measurement resolution is | ||
46 | either 1 degC or 0.5 degC, depending on the temperature source and | ||
47 | configuration. An alarm is triggered when the temperature gets higher than | ||
48 | the high limit; it stays on until the temperature falls below the hysteresis | ||
49 | value. Alarms are only supported for temp1 to temp6, depending on the chip type. | ||
50 | |||
51 | Fan rotation speeds are reported in RPM (rotations per minute). An alarm is | ||
52 | triggered if the rotation speed has dropped below a programmable limit. On | ||
53 | NCT6775F, fan readings can be divided by a programmable divider (1, 2, 4, 8, | ||
54 | 16, 32, 64 or 128) to give the readings more range or accuracy; the other chips | ||
55 | do not have a fan speed divider. The driver sets the most suitable fan divisor | ||
56 | itself; specifically, it doubles the divider value each time a fan speed reading | ||
57 | returns an invalid value. Some fans might not be present because they share pins | ||
58 | with other functions. | ||
59 | |||
60 | Voltage sensors (also known as IN sensors) report their values in millivolts. | ||
61 | An alarm is triggered if the voltage has crossed a programmable minimum | ||
62 | or maximum limit. | ||
63 | |||
64 | The driver supports automatic fan control mode known as Thermal Cruise. | ||
65 | In this mode, the chip attempts to keep the measured temperature in a | ||
66 | predefined temperature range. If the temperature goes out of range, fan | ||
67 | is driven slower/faster to reach the predefined range again. | ||
68 | |||
69 | The mode works for fan1-fan5. | ||
70 | |||
71 | Usage Notes | ||
72 | ----------- | ||
73 | |||
74 | On various ASUS boards with NCT6776F, it appears that CPUTIN is not really | ||
75 | connected to anything and floats, or that it is connected to some non-standard | ||
76 | temperature measurement device. As a result, the temperature reported on CPUTIN | ||
77 | will not reflect a usable value. It often reports unreasonably high | ||
78 | temperatures, and in some cases the reported temperature declines if the actual | ||
79 | temperature increases (similar to the raw PECI temperature value - see PECI | ||
80 | specification for details). CPUTIN should therefore be be ignored on ASUS | ||
81 | boards. The CPU temperature on ASUS boards is reported from PECI 0. | ||
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index 47d2176957a0..a0f1d6a406eb 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -897,6 +897,19 @@ config SENSORS_MCP3021 | |||
897 | This driver can also be built as a module. If so, the module | 897 | This driver can also be built as a module. If so, the module |
898 | will be called mcp3021. | 898 | will be called mcp3021. |
899 | 899 | ||
900 | config SENSORS_NCT6775 | ||
901 | tristate "Nuvoton NCT6775F, NCT6776F, NCT6779D" | ||
902 | depends on !PPC | ||
903 | select HWMON_VID | ||
904 | help | ||
905 | If you say yes here you get support for the hardware monitoring | ||
906 | functionality of the Nuvoton NCT6775F, NCT6776F, and NCT6779D | ||
907 | Super-I/O chips. This driver replaces the w83627ehf driver for | ||
908 | NCT6775F and NCT6776F. | ||
909 | |||
910 | This driver can also be built as a module. If so, the module | ||
911 | will be called nct6775. | ||
912 | |||
900 | config SENSORS_NTC_THERMISTOR | 913 | config SENSORS_NTC_THERMISTOR |
901 | tristate "NTC thermistor support" | 914 | tristate "NTC thermistor support" |
902 | depends on (!OF && !IIO) || (OF && IIO) | 915 | depends on (!OF && !IIO) || (OF && IIO) |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 5d36a57c055b..82975724d3af 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -105,6 +105,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o | |||
105 | obj-$(CONFIG_SENSORS_MAX6697) += max6697.o | 105 | obj-$(CONFIG_SENSORS_MAX6697) += max6697.o |
106 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o | 106 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o |
107 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o | 107 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o |
108 | obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o | ||
108 | obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o | 109 | obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o |
109 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | 110 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o |
110 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o | 111 | obj-$(CONFIG_SENSORS_PC87427) += pc87427.o |
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c new file mode 100644 index 000000000000..f75cd8231534 --- /dev/null +++ b/drivers/hwmon/nct6775.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* | ||
2 | * nct6775 - Driver for the hardware monitoring functionality of | ||
3 | * Nuvoton NCT677x Super-I/O chips | ||
4 | * | ||
5 | * Copyright (C) 2012 Guenter Roeck <linux@roeck-us.net> | ||
6 | * | ||
7 | * Derived from w83627ehf driver | ||
8 | * Copyright (C) 2005-2012 Jean Delvare <khali@linux-fr.org> | ||
9 | * Copyright (C) 2006 Yuan Mu (Winbond), | ||
10 | * Rudolf Marek <r.marek@assembler.cz> | ||
11 | * David Hubbard <david.c.hubbard@gmail.com> | ||
12 | * Daniel J Blueman <daniel.blueman@gmail.com> | ||
13 | * Copyright (C) 2010 Sheng-Yuan Huang (Nuvoton) (PS00) | ||
14 | * | ||
15 | * Shamelessly ripped from the w83627hf driver | ||
16 | * Copyright (C) 2003 Mark Studebaker | ||
17 | * | ||
18 | * This program is free software; you can redistribute it and/or modify | ||
19 | * it under the terms of the GNU General Public License as published by | ||
20 | * the Free Software Foundation; either version 2 of the License, or | ||
21 | * (at your option) any later version. | ||
22 | * | ||
23 | * This program is distributed in the hope that it will be useful, | ||
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
26 | * GNU General Public License for more details. | ||
27 | * | ||
28 | * You should have received a copy of the GNU General Public License | ||
29 | * along with this program; if not, write to the Free Software | ||
30 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
31 | * | ||
32 | * | ||
33 | * Supports the following chips: | ||
34 | * | ||
35 | * Chip #vin #fan #pwm #temp chip IDs man ID | ||
36 | * nct6775f 9 4 3 6+3 0xb470 0xc1 0x5ca3 | ||
37 | * nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3 | ||
38 | * nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3 | ||
39 | * | ||
40 | * #temp lists the number of monitored temperature sources (first value) plus | ||
41 | * the number of directly connectable temperature sensors (second value). | ||
42 | */ | ||
43 | |||
44 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
45 | |||
46 | #include <linux/module.h> | ||
47 | #include <linux/init.h> | ||
48 | #include <linux/slab.h> | ||
49 | #include <linux/jiffies.h> | ||
50 | #include <linux/platform_device.h> | ||
51 | #include <linux/hwmon.h> | ||
52 | #include <linux/hwmon-sysfs.h> | ||
53 | #include <linux/hwmon-vid.h> | ||
54 | #include <linux/err.h> | ||
55 | #include <linux/mutex.h> | ||
56 | #include <linux/acpi.h> | ||
57 | #include <linux/io.h> | ||
58 | #include "lm75.h" | ||
59 | |||
60 | enum kinds { nct6775, nct6776, nct6779 }; | ||
61 | |||
62 | /* used to set data->name = nct6775_device_names[data->sio_kind] */ | ||
63 | static const char * const nct6775_device_names[] = { | ||
64 | "nct6775", | ||
65 | "nct6776", | ||
66 | "nct6779", | ||
67 | }; | ||
68 | |||
69 | static unsigned short force_id; | ||
70 | module_param(force_id, ushort, 0); | ||
71 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); | ||
72 | |||
73 | #define DRVNAME "nct6775" | ||
74 | |||
75 | /* | ||
76 | * Super-I/O constants and functions | ||
77 | */ | ||
78 | |||
79 | #define NCT6775_LD_HWM 0x0b | ||
80 | #define NCT6775_LD_VID 0x0d | ||
81 | |||
82 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ | ||
83 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | ||
84 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ | ||
85 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ | ||
86 | |||
87 | #define SIO_NCT6775_ID 0xb470 | ||
88 | #define SIO_NCT6776_ID 0xc330 | ||
89 | #define SIO_NCT6779_ID 0xc560 | ||
90 | #define SIO_ID_MASK 0xFFF0 | ||
91 | |||
92 | static inline void | ||
93 | superio_outb(int ioreg, int reg, int val) | ||
94 | { | ||
95 | outb(reg, ioreg); | ||
96 | outb(val, ioreg + 1); | ||
97 | } | ||
98 | |||
99 | static inline int | ||
100 | superio_inb(int ioreg, int reg) | ||
101 | { | ||
102 | outb(reg, ioreg); | ||
103 | return inb(ioreg + 1); | ||
104 | } | ||
105 | |||
106 | static inline void | ||
107 | superio_select(int ioreg, int ld) | ||
108 | { | ||
109 | outb(SIO_REG_LDSEL, ioreg); | ||
110 | outb(ld, ioreg + 1); | ||
111 | } | ||
112 | |||
113 | static inline int | ||
114 | superio_enter(int ioreg) | ||
115 | { | ||
116 | /* | ||
117 | * Try to reserve <ioreg> and <ioreg + 1> for exclusive access. | ||
118 | */ | ||
119 | if (!request_muxed_region(ioreg, 2, DRVNAME)) | ||
120 | return -EBUSY; | ||
121 | |||
122 | outb(0x87, ioreg); | ||
123 | outb(0x87, ioreg); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static inline void | ||
129 | superio_exit(int ioreg) | ||
130 | { | ||
131 | outb(0xaa, ioreg); | ||
132 | outb(0x02, ioreg); | ||
133 | outb(0x02, ioreg + 1); | ||
134 | release_region(ioreg, 2); | ||
135 | } | ||
136 | |||
137 | /* | ||
138 | * ISA constants | ||
139 | */ | ||
140 | |||
141 | #define IOREGION_ALIGNMENT (~7) | ||
142 | #define IOREGION_OFFSET 5 | ||
143 | #define IOREGION_LENGTH 2 | ||
144 | #define ADDR_REG_OFFSET 0 | ||
145 | #define DATA_REG_OFFSET 1 | ||
146 | |||
147 | #define NCT6775_REG_BANK 0x4E | ||
148 | #define NCT6775_REG_CONFIG 0x40 | ||
149 | |||
150 | /* | ||
151 | * Not currently used: | ||
152 | * REG_MAN_ID has the value 0x5ca3 for all supported chips. | ||
153 | * REG_CHIP_ID == 0x88/0xa1/0xc1 depending on chip model. | ||
154 | * REG_MAN_ID is at port 0x4f | ||
155 | * REG_CHIP_ID is at port 0x58 | ||
156 | */ | ||
157 | |||
158 | #define NUM_REG_ALARM 4 /* Max number of alarm registers */ | ||
159 | |||
160 | /* Common and NCT6775 specific data */ | ||
161 | |||
162 | /* Voltage min/max registers for nr=7..14 are in bank 5 */ | ||
163 | |||
164 | static const u16 NCT6775_REG_IN_MAX[] = { | ||
165 | 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x554, 0x556, 0x558, 0x55a, | ||
166 | 0x55c, 0x55e, 0x560, 0x562 }; | ||
167 | static const u16 NCT6775_REG_IN_MIN[] = { | ||
168 | 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x555, 0x557, 0x559, 0x55b, | ||
169 | 0x55d, 0x55f, 0x561, 0x563 }; | ||
170 | static const u16 NCT6775_REG_IN[] = { | ||
171 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x550, 0x551, 0x552 | ||
172 | }; | ||
173 | |||
174 | #define NCT6775_REG_VBAT 0x5D | ||
175 | |||
176 | static const u16 NCT6775_REG_ALARM[NUM_REG_ALARM] = { 0x459, 0x45A, 0x45B }; | ||
177 | |||
178 | /* 0..15 voltages, 16..23 fans, 24..31 temperatures */ | ||
179 | |||
180 | static const s8 NCT6775_ALARM_BITS[] = { | ||
181 | 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ | ||
182 | 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */ | ||
183 | -1, /* unused */ | ||
184 | 6, 7, 11, 10, 23, /* fan1..fan5 */ | ||
185 | -1, -1, -1, /* unused */ | ||
186 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | ||
187 | 12, -1 }; /* intrusion0, intrusion1 */ | ||
188 | |||
189 | /* NCT6776 specific data */ | ||
190 | |||
191 | static const s8 NCT6776_ALARM_BITS[] = { | ||
192 | 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ | ||
193 | 17, -1, -1, -1, -1, -1, -1, /* in8..in14 */ | ||
194 | -1, /* unused */ | ||
195 | 6, 7, 11, 10, 23, /* fan1..fan5 */ | ||
196 | -1, -1, -1, /* unused */ | ||
197 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | ||
198 | 12, 9 }; /* intrusion0, intrusion1 */ | ||
199 | |||
200 | /* NCT6779 specific data */ | ||
201 | |||
202 | static const u16 NCT6779_REG_IN[] = { | ||
203 | 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487, | ||
204 | 0x488, 0x489, 0x48a, 0x48b, 0x48c, 0x48d, 0x48e }; | ||
205 | |||
206 | static const u16 NCT6779_REG_ALARM[NUM_REG_ALARM] = { | ||
207 | 0x459, 0x45A, 0x45B, 0x568 }; | ||
208 | |||
209 | static const s8 NCT6779_ALARM_BITS[] = { | ||
210 | 0, 1, 2, 3, 8, 21, 20, 16, /* in0.. in7 */ | ||
211 | 17, 24, 25, 26, 27, 28, 29, /* in8..in14 */ | ||
212 | -1, /* unused */ | ||
213 | 6, 7, 11, 10, 23, /* fan1..fan5 */ | ||
214 | -1, -1, -1, /* unused */ | ||
215 | 4, 5, 13, -1, -1, -1, /* temp1..temp6 */ | ||
216 | 12, 9 }; /* intrusion0, intrusion1 */ | ||
217 | |||
218 | /* | ||
219 | * Conversions | ||
220 | */ | ||
221 | |||
222 | /* | ||
223 | * Some of the voltage inputs have internal scaling, the tables below | ||
224 | * contain 8 (the ADC LSB in mV) * scaling factor * 100 | ||
225 | */ | ||
226 | static const u16 scale_in[15] = { | ||
227 | 800, 800, 1600, 1600, 800, 800, 800, 1600, 1600, 800, 800, 800, 800, | ||
228 | 800, 800 | ||
229 | }; | ||
230 | |||
231 | static inline long in_from_reg(u8 reg, u8 nr) | ||
232 | { | ||
233 | return DIV_ROUND_CLOSEST(reg * scale_in[nr], 100); | ||
234 | } | ||
235 | |||
236 | static inline u8 in_to_reg(u32 val, u8 nr) | ||
237 | { | ||
238 | return clamp_val(DIV_ROUND_CLOSEST(val * 100, scale_in[nr]), 0, 255); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * Data structures and manipulation thereof | ||
243 | */ | ||
244 | |||
245 | struct nct6775_data { | ||
246 | int addr; /* IO base of hw monitor block */ | ||
247 | enum kinds kind; | ||
248 | const char *name; | ||
249 | |||
250 | struct device *hwmon_dev; | ||
251 | struct mutex lock; | ||
252 | |||
253 | u16 REG_CONFIG; | ||
254 | u16 REG_VBAT; | ||
255 | |||
256 | const s8 *ALARM_BITS; | ||
257 | |||
258 | const u16 *REG_VIN; | ||
259 | const u16 *REG_IN_MINMAX[2]; | ||
260 | |||
261 | const u16 *REG_ALARM; | ||
262 | |||
263 | struct mutex update_lock; | ||
264 | bool valid; /* true if following fields are valid */ | ||
265 | unsigned long last_updated; /* In jiffies */ | ||
266 | |||
267 | /* Register values */ | ||
268 | u8 bank; /* current register bank */ | ||
269 | u8 in_num; /* number of in inputs we have */ | ||
270 | u8 in[15][3]; /* [0]=in, [1]=in_max, [2]=in_min */ | ||
271 | |||
272 | u64 alarms; | ||
273 | |||
274 | u8 vid; | ||
275 | u8 vrm; | ||
276 | |||
277 | u16 have_in; | ||
278 | }; | ||
279 | |||
280 | struct nct6775_sio_data { | ||
281 | int sioreg; | ||
282 | enum kinds kind; | ||
283 | }; | ||
284 | |||
285 | static bool is_word_sized(struct nct6775_data *data, u16 reg) | ||
286 | { | ||
287 | switch (data->kind) { | ||
288 | case nct6775: | ||
289 | return (((reg & 0xff00) == 0x100 || | ||
290 | (reg & 0xff00) == 0x200) && | ||
291 | ((reg & 0x00ff) == 0x50 || | ||
292 | (reg & 0x00ff) == 0x53 || | ||
293 | (reg & 0x00ff) == 0x55)) || | ||
294 | (reg & 0xfff0) == 0x630 || | ||
295 | reg == 0x640 || reg == 0x642 || | ||
296 | reg == 0x662 || | ||
297 | ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) || | ||
298 | reg == 0x73 || reg == 0x75 || reg == 0x77; | ||
299 | case nct6776: | ||
300 | return (((reg & 0xff00) == 0x100 || | ||
301 | (reg & 0xff00) == 0x200) && | ||
302 | ((reg & 0x00ff) == 0x50 || | ||
303 | (reg & 0x00ff) == 0x53 || | ||
304 | (reg & 0x00ff) == 0x55)) || | ||
305 | (reg & 0xfff0) == 0x630 || | ||
306 | reg == 0x402 || | ||
307 | reg == 0x640 || reg == 0x642 || | ||
308 | ((reg & 0xfff0) == 0x650 && (reg & 0x000f) >= 0x06) || | ||
309 | reg == 0x73 || reg == 0x75 || reg == 0x77; | ||
310 | case nct6779: | ||
311 | return reg == 0x150 || reg == 0x153 || reg == 0x155 || | ||
312 | ((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x09) || | ||
313 | reg == 0x402 || | ||
314 | reg == 0x63a || reg == 0x63c || reg == 0x63e || | ||
315 | reg == 0x640 || reg == 0x642 || | ||
316 | reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 || | ||
317 | reg == 0x7b; | ||
318 | } | ||
319 | return false; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * On older chips, only registers 0x50-0x5f are banked. | ||
324 | * On more recent chips, all registers are banked. | ||
325 | * Assume that is the case and set the bank number for each access. | ||
326 | * Cache the bank number so it only needs to be set if it changes. | ||
327 | */ | ||
328 | static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg) | ||
329 | { | ||
330 | u8 bank = reg >> 8; | ||
331 | if (data->bank != bank) { | ||
332 | outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET); | ||
333 | outb_p(bank, data->addr + DATA_REG_OFFSET); | ||
334 | data->bank = bank; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | static u16 nct6775_read_value(struct nct6775_data *data, u16 reg) | ||
339 | { | ||
340 | int res, word_sized = is_word_sized(data, reg); | ||
341 | |||
342 | mutex_lock(&data->lock); | ||
343 | |||
344 | nct6775_set_bank(data, reg); | ||
345 | outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); | ||
346 | res = inb_p(data->addr + DATA_REG_OFFSET); | ||
347 | if (word_sized) { | ||
348 | outb_p((reg & 0xff) + 1, | ||
349 | data->addr + ADDR_REG_OFFSET); | ||
350 | res = (res << 8) + inb_p(data->addr + DATA_REG_OFFSET); | ||
351 | } | ||
352 | |||
353 | mutex_unlock(&data->lock); | ||
354 | return res; | ||
355 | } | ||
356 | |||
357 | static int nct6775_write_value(struct nct6775_data *data, u16 reg, u16 value) | ||
358 | { | ||
359 | int word_sized = is_word_sized(data, reg); | ||
360 | |||
361 | mutex_lock(&data->lock); | ||
362 | |||
363 | nct6775_set_bank(data, reg); | ||
364 | outb_p(reg & 0xff, data->addr + ADDR_REG_OFFSET); | ||
365 | if (word_sized) { | ||
366 | outb_p(value >> 8, data->addr + DATA_REG_OFFSET); | ||
367 | outb_p((reg & 0xff) + 1, | ||
368 | data->addr + ADDR_REG_OFFSET); | ||
369 | } | ||
370 | outb_p(value & 0xff, data->addr + DATA_REG_OFFSET); | ||
371 | |||
372 | mutex_unlock(&data->lock); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static struct nct6775_data *nct6775_update_device(struct device *dev) | ||
377 | { | ||
378 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
379 | int i; | ||
380 | |||
381 | mutex_lock(&data->update_lock); | ||
382 | |||
383 | if (time_after(jiffies, data->last_updated + HZ + HZ/2) | ||
384 | || !data->valid) { | ||
385 | /* Measured voltages and limits */ | ||
386 | for (i = 0; i < data->in_num; i++) { | ||
387 | if (!(data->have_in & (1 << i))) | ||
388 | continue; | ||
389 | |||
390 | data->in[i][0] = nct6775_read_value(data, | ||
391 | data->REG_VIN[i]); | ||
392 | data->in[i][1] = nct6775_read_value(data, | ||
393 | data->REG_IN_MINMAX[0][i]); | ||
394 | data->in[i][2] = nct6775_read_value(data, | ||
395 | data->REG_IN_MINMAX[1][i]); | ||
396 | } | ||
397 | |||
398 | data->alarms = 0; | ||
399 | for (i = 0; i < NUM_REG_ALARM; i++) { | ||
400 | u8 alarm; | ||
401 | if (!data->REG_ALARM[i]) | ||
402 | continue; | ||
403 | alarm = nct6775_read_value(data, data->REG_ALARM[i]); | ||
404 | data->alarms |= ((u64)alarm) << (i << 3); | ||
405 | } | ||
406 | |||
407 | data->last_updated = jiffies; | ||
408 | data->valid = true; | ||
409 | } | ||
410 | |||
411 | mutex_unlock(&data->update_lock); | ||
412 | return data; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | * Sysfs callback functions | ||
417 | */ | ||
418 | static ssize_t | ||
419 | show_in_reg(struct device *dev, struct device_attribute *attr, char *buf) | ||
420 | { | ||
421 | struct nct6775_data *data = nct6775_update_device(dev); | ||
422 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
423 | int nr = sattr->nr; | ||
424 | int index = sattr->index; | ||
425 | return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr)); | ||
426 | } | ||
427 | |||
428 | static ssize_t | ||
429 | store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf, | ||
430 | size_t count) | ||
431 | { | ||
432 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
433 | struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr); | ||
434 | int nr = sattr->nr; | ||
435 | int index = sattr->index; | ||
436 | unsigned long val; | ||
437 | int err = kstrtoul(buf, 10, &val); | ||
438 | if (err < 0) | ||
439 | return err; | ||
440 | mutex_lock(&data->update_lock); | ||
441 | data->in[nr][index] = in_to_reg(val, nr); | ||
442 | nct6775_write_value(data, data->REG_IN_MINMAX[index-1][nr], | ||
443 | data->in[nr][index]); | ||
444 | mutex_unlock(&data->update_lock); | ||
445 | return count; | ||
446 | } | ||
447 | |||
448 | static ssize_t | ||
449 | show_alarm(struct device *dev, struct device_attribute *attr, char *buf) | ||
450 | { | ||
451 | struct nct6775_data *data = nct6775_update_device(dev); | ||
452 | struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); | ||
453 | int nr = data->ALARM_BITS[sattr->index]; | ||
454 | return sprintf(buf, "%u\n", | ||
455 | (unsigned int)((data->alarms >> nr) & 0x01)); | ||
456 | } | ||
457 | |||
458 | static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in_reg, NULL, 0, 0); | ||
459 | static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in_reg, NULL, 1, 0); | ||
460 | static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in_reg, NULL, 2, 0); | ||
461 | static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in_reg, NULL, 3, 0); | ||
462 | static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in_reg, NULL, 4, 0); | ||
463 | static SENSOR_DEVICE_ATTR_2(in5_input, S_IRUGO, show_in_reg, NULL, 5, 0); | ||
464 | static SENSOR_DEVICE_ATTR_2(in6_input, S_IRUGO, show_in_reg, NULL, 6, 0); | ||
465 | static SENSOR_DEVICE_ATTR_2(in7_input, S_IRUGO, show_in_reg, NULL, 7, 0); | ||
466 | static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in_reg, NULL, 8, 0); | ||
467 | static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in_reg, NULL, 9, 0); | ||
468 | static SENSOR_DEVICE_ATTR_2(in10_input, S_IRUGO, show_in_reg, NULL, 10, 0); | ||
469 | static SENSOR_DEVICE_ATTR_2(in11_input, S_IRUGO, show_in_reg, NULL, 11, 0); | ||
470 | static SENSOR_DEVICE_ATTR_2(in12_input, S_IRUGO, show_in_reg, NULL, 12, 0); | ||
471 | static SENSOR_DEVICE_ATTR_2(in13_input, S_IRUGO, show_in_reg, NULL, 13, 0); | ||
472 | static SENSOR_DEVICE_ATTR_2(in14_input, S_IRUGO, show_in_reg, NULL, 14, 0); | ||
473 | |||
474 | static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); | ||
475 | static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); | ||
476 | static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); | ||
477 | static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); | ||
478 | static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4); | ||
479 | static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5); | ||
480 | static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6); | ||
481 | static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7); | ||
482 | static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8); | ||
483 | static SENSOR_DEVICE_ATTR(in9_alarm, S_IRUGO, show_alarm, NULL, 9); | ||
484 | static SENSOR_DEVICE_ATTR(in10_alarm, S_IRUGO, show_alarm, NULL, 10); | ||
485 | static SENSOR_DEVICE_ATTR(in11_alarm, S_IRUGO, show_alarm, NULL, 11); | ||
486 | static SENSOR_DEVICE_ATTR(in12_alarm, S_IRUGO, show_alarm, NULL, 12); | ||
487 | static SENSOR_DEVICE_ATTR(in13_alarm, S_IRUGO, show_alarm, NULL, 13); | ||
488 | static SENSOR_DEVICE_ATTR(in14_alarm, S_IRUGO, show_alarm, NULL, 14); | ||
489 | |||
490 | static SENSOR_DEVICE_ATTR_2(in0_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
491 | store_in_reg, 0, 1); | ||
492 | static SENSOR_DEVICE_ATTR_2(in1_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
493 | store_in_reg, 1, 1); | ||
494 | static SENSOR_DEVICE_ATTR_2(in2_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
495 | store_in_reg, 2, 1); | ||
496 | static SENSOR_DEVICE_ATTR_2(in3_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
497 | store_in_reg, 3, 1); | ||
498 | static SENSOR_DEVICE_ATTR_2(in4_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
499 | store_in_reg, 4, 1); | ||
500 | static SENSOR_DEVICE_ATTR_2(in5_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
501 | store_in_reg, 5, 1); | ||
502 | static SENSOR_DEVICE_ATTR_2(in6_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
503 | store_in_reg, 6, 1); | ||
504 | static SENSOR_DEVICE_ATTR_2(in7_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
505 | store_in_reg, 7, 1); | ||
506 | static SENSOR_DEVICE_ATTR_2(in8_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
507 | store_in_reg, 8, 1); | ||
508 | static SENSOR_DEVICE_ATTR_2(in9_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
509 | store_in_reg, 9, 1); | ||
510 | static SENSOR_DEVICE_ATTR_2(in10_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
511 | store_in_reg, 10, 1); | ||
512 | static SENSOR_DEVICE_ATTR_2(in11_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
513 | store_in_reg, 11, 1); | ||
514 | static SENSOR_DEVICE_ATTR_2(in12_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
515 | store_in_reg, 12, 1); | ||
516 | static SENSOR_DEVICE_ATTR_2(in13_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
517 | store_in_reg, 13, 1); | ||
518 | static SENSOR_DEVICE_ATTR_2(in14_min, S_IWUSR | S_IRUGO, show_in_reg, | ||
519 | store_in_reg, 14, 1); | ||
520 | |||
521 | static SENSOR_DEVICE_ATTR_2(in0_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
522 | store_in_reg, 0, 2); | ||
523 | static SENSOR_DEVICE_ATTR_2(in1_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
524 | store_in_reg, 1, 2); | ||
525 | static SENSOR_DEVICE_ATTR_2(in2_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
526 | store_in_reg, 2, 2); | ||
527 | static SENSOR_DEVICE_ATTR_2(in3_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
528 | store_in_reg, 3, 2); | ||
529 | static SENSOR_DEVICE_ATTR_2(in4_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
530 | store_in_reg, 4, 2); | ||
531 | static SENSOR_DEVICE_ATTR_2(in5_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
532 | store_in_reg, 5, 2); | ||
533 | static SENSOR_DEVICE_ATTR_2(in6_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
534 | store_in_reg, 6, 2); | ||
535 | static SENSOR_DEVICE_ATTR_2(in7_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
536 | store_in_reg, 7, 2); | ||
537 | static SENSOR_DEVICE_ATTR_2(in8_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
538 | store_in_reg, 8, 2); | ||
539 | static SENSOR_DEVICE_ATTR_2(in9_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
540 | store_in_reg, 9, 2); | ||
541 | static SENSOR_DEVICE_ATTR_2(in10_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
542 | store_in_reg, 10, 2); | ||
543 | static SENSOR_DEVICE_ATTR_2(in11_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
544 | store_in_reg, 11, 2); | ||
545 | static SENSOR_DEVICE_ATTR_2(in12_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
546 | store_in_reg, 12, 2); | ||
547 | static SENSOR_DEVICE_ATTR_2(in13_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
548 | store_in_reg, 13, 2); | ||
549 | static SENSOR_DEVICE_ATTR_2(in14_max, S_IWUSR | S_IRUGO, show_in_reg, | ||
550 | store_in_reg, 14, 2); | ||
551 | |||
552 | static struct attribute *nct6775_attributes_in[15][5] = { | ||
553 | { | ||
554 | &sensor_dev_attr_in0_input.dev_attr.attr, | ||
555 | &sensor_dev_attr_in0_min.dev_attr.attr, | ||
556 | &sensor_dev_attr_in0_max.dev_attr.attr, | ||
557 | &sensor_dev_attr_in0_alarm.dev_attr.attr, | ||
558 | NULL | ||
559 | }, | ||
560 | { | ||
561 | &sensor_dev_attr_in1_input.dev_attr.attr, | ||
562 | &sensor_dev_attr_in1_min.dev_attr.attr, | ||
563 | &sensor_dev_attr_in1_max.dev_attr.attr, | ||
564 | &sensor_dev_attr_in1_alarm.dev_attr.attr, | ||
565 | NULL | ||
566 | }, | ||
567 | { | ||
568 | &sensor_dev_attr_in2_input.dev_attr.attr, | ||
569 | &sensor_dev_attr_in2_min.dev_attr.attr, | ||
570 | &sensor_dev_attr_in2_max.dev_attr.attr, | ||
571 | &sensor_dev_attr_in2_alarm.dev_attr.attr, | ||
572 | NULL | ||
573 | }, | ||
574 | { | ||
575 | &sensor_dev_attr_in3_input.dev_attr.attr, | ||
576 | &sensor_dev_attr_in3_min.dev_attr.attr, | ||
577 | &sensor_dev_attr_in3_max.dev_attr.attr, | ||
578 | &sensor_dev_attr_in3_alarm.dev_attr.attr, | ||
579 | NULL | ||
580 | }, | ||
581 | { | ||
582 | &sensor_dev_attr_in4_input.dev_attr.attr, | ||
583 | &sensor_dev_attr_in4_min.dev_attr.attr, | ||
584 | &sensor_dev_attr_in4_max.dev_attr.attr, | ||
585 | &sensor_dev_attr_in4_alarm.dev_attr.attr, | ||
586 | NULL | ||
587 | }, | ||
588 | { | ||
589 | &sensor_dev_attr_in5_input.dev_attr.attr, | ||
590 | &sensor_dev_attr_in5_min.dev_attr.attr, | ||
591 | &sensor_dev_attr_in5_max.dev_attr.attr, | ||
592 | &sensor_dev_attr_in5_alarm.dev_attr.attr, | ||
593 | NULL | ||
594 | }, | ||
595 | { | ||
596 | &sensor_dev_attr_in6_input.dev_attr.attr, | ||
597 | &sensor_dev_attr_in6_min.dev_attr.attr, | ||
598 | &sensor_dev_attr_in6_max.dev_attr.attr, | ||
599 | &sensor_dev_attr_in6_alarm.dev_attr.attr, | ||
600 | NULL | ||
601 | }, | ||
602 | { | ||
603 | &sensor_dev_attr_in7_input.dev_attr.attr, | ||
604 | &sensor_dev_attr_in7_min.dev_attr.attr, | ||
605 | &sensor_dev_attr_in7_max.dev_attr.attr, | ||
606 | &sensor_dev_attr_in7_alarm.dev_attr.attr, | ||
607 | NULL | ||
608 | }, | ||
609 | { | ||
610 | &sensor_dev_attr_in8_input.dev_attr.attr, | ||
611 | &sensor_dev_attr_in8_min.dev_attr.attr, | ||
612 | &sensor_dev_attr_in8_max.dev_attr.attr, | ||
613 | &sensor_dev_attr_in8_alarm.dev_attr.attr, | ||
614 | NULL | ||
615 | }, | ||
616 | { | ||
617 | &sensor_dev_attr_in9_input.dev_attr.attr, | ||
618 | &sensor_dev_attr_in9_min.dev_attr.attr, | ||
619 | &sensor_dev_attr_in9_max.dev_attr.attr, | ||
620 | &sensor_dev_attr_in9_alarm.dev_attr.attr, | ||
621 | NULL | ||
622 | }, | ||
623 | { | ||
624 | &sensor_dev_attr_in10_input.dev_attr.attr, | ||
625 | &sensor_dev_attr_in10_min.dev_attr.attr, | ||
626 | &sensor_dev_attr_in10_max.dev_attr.attr, | ||
627 | &sensor_dev_attr_in10_alarm.dev_attr.attr, | ||
628 | NULL | ||
629 | }, | ||
630 | { | ||
631 | &sensor_dev_attr_in11_input.dev_attr.attr, | ||
632 | &sensor_dev_attr_in11_min.dev_attr.attr, | ||
633 | &sensor_dev_attr_in11_max.dev_attr.attr, | ||
634 | &sensor_dev_attr_in11_alarm.dev_attr.attr, | ||
635 | NULL | ||
636 | }, | ||
637 | { | ||
638 | &sensor_dev_attr_in12_input.dev_attr.attr, | ||
639 | &sensor_dev_attr_in12_min.dev_attr.attr, | ||
640 | &sensor_dev_attr_in12_max.dev_attr.attr, | ||
641 | &sensor_dev_attr_in12_alarm.dev_attr.attr, | ||
642 | NULL | ||
643 | }, | ||
644 | { | ||
645 | &sensor_dev_attr_in13_input.dev_attr.attr, | ||
646 | &sensor_dev_attr_in13_min.dev_attr.attr, | ||
647 | &sensor_dev_attr_in13_max.dev_attr.attr, | ||
648 | &sensor_dev_attr_in13_alarm.dev_attr.attr, | ||
649 | NULL | ||
650 | }, | ||
651 | { | ||
652 | &sensor_dev_attr_in14_input.dev_attr.attr, | ||
653 | &sensor_dev_attr_in14_min.dev_attr.attr, | ||
654 | &sensor_dev_attr_in14_max.dev_attr.attr, | ||
655 | &sensor_dev_attr_in14_alarm.dev_attr.attr, | ||
656 | NULL | ||
657 | }, | ||
658 | }; | ||
659 | |||
660 | static const struct attribute_group nct6775_group_in[15] = { | ||
661 | { .attrs = nct6775_attributes_in[0] }, | ||
662 | { .attrs = nct6775_attributes_in[1] }, | ||
663 | { .attrs = nct6775_attributes_in[2] }, | ||
664 | { .attrs = nct6775_attributes_in[3] }, | ||
665 | { .attrs = nct6775_attributes_in[4] }, | ||
666 | { .attrs = nct6775_attributes_in[5] }, | ||
667 | { .attrs = nct6775_attributes_in[6] }, | ||
668 | { .attrs = nct6775_attributes_in[7] }, | ||
669 | { .attrs = nct6775_attributes_in[8] }, | ||
670 | { .attrs = nct6775_attributes_in[9] }, | ||
671 | { .attrs = nct6775_attributes_in[10] }, | ||
672 | { .attrs = nct6775_attributes_in[11] }, | ||
673 | { .attrs = nct6775_attributes_in[12] }, | ||
674 | { .attrs = nct6775_attributes_in[13] }, | ||
675 | { .attrs = nct6775_attributes_in[14] }, | ||
676 | }; | ||
677 | |||
678 | static ssize_t | ||
679 | show_name(struct device *dev, struct device_attribute *attr, char *buf) | ||
680 | { | ||
681 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
682 | |||
683 | return sprintf(buf, "%s\n", data->name); | ||
684 | } | ||
685 | |||
686 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
687 | |||
688 | static ssize_t | ||
689 | show_vid(struct device *dev, struct device_attribute *attr, char *buf) | ||
690 | { | ||
691 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
692 | return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm)); | ||
693 | } | ||
694 | |||
695 | static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); | ||
696 | |||
697 | /* | ||
698 | * Driver and device management | ||
699 | */ | ||
700 | |||
701 | static void nct6775_device_remove_files(struct device *dev) | ||
702 | { | ||
703 | /* | ||
704 | * some entries in the following arrays may not have been used in | ||
705 | * device_create_file(), but device_remove_file() will ignore them | ||
706 | */ | ||
707 | int i; | ||
708 | struct nct6775_data *data = dev_get_drvdata(dev); | ||
709 | |||
710 | for (i = 0; i < data->in_num; i++) | ||
711 | sysfs_remove_group(&dev->kobj, &nct6775_group_in[i]); | ||
712 | |||
713 | device_remove_file(dev, &dev_attr_name); | ||
714 | device_remove_file(dev, &dev_attr_cpu0_vid); | ||
715 | } | ||
716 | |||
717 | /* Get the monitoring functions started */ | ||
718 | static inline void nct6775_init_device(struct nct6775_data *data) | ||
719 | { | ||
720 | u8 tmp; | ||
721 | |||
722 | /* Start monitoring if needed */ | ||
723 | if (data->REG_CONFIG) { | ||
724 | tmp = nct6775_read_value(data, data->REG_CONFIG); | ||
725 | if (!(tmp & 0x01)) | ||
726 | nct6775_write_value(data, data->REG_CONFIG, tmp | 0x01); | ||
727 | } | ||
728 | |||
729 | /* Enable VBAT monitoring if needed */ | ||
730 | tmp = nct6775_read_value(data, data->REG_VBAT); | ||
731 | if (!(tmp & 0x01)) | ||
732 | nct6775_write_value(data, data->REG_VBAT, tmp | 0x01); | ||
733 | } | ||
734 | |||
735 | static int nct6775_probe(struct platform_device *pdev) | ||
736 | { | ||
737 | struct device *dev = &pdev->dev; | ||
738 | struct nct6775_sio_data *sio_data = dev->platform_data; | ||
739 | struct nct6775_data *data; | ||
740 | struct resource *res; | ||
741 | int i, err = 0; | ||
742 | |||
743 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
744 | if (!devm_request_region(&pdev->dev, res->start, IOREGION_LENGTH, | ||
745 | DRVNAME)) | ||
746 | return -EBUSY; | ||
747 | |||
748 | data = devm_kzalloc(&pdev->dev, sizeof(struct nct6775_data), | ||
749 | GFP_KERNEL); | ||
750 | if (!data) | ||
751 | return -ENOMEM; | ||
752 | |||
753 | data->kind = sio_data->kind; | ||
754 | data->addr = res->start; | ||
755 | mutex_init(&data->lock); | ||
756 | mutex_init(&data->update_lock); | ||
757 | data->name = nct6775_device_names[data->kind]; | ||
758 | data->bank = 0xff; /* Force initial bank selection */ | ||
759 | platform_set_drvdata(pdev, data); | ||
760 | |||
761 | switch (data->kind) { | ||
762 | case nct6775: | ||
763 | data->in_num = 9; | ||
764 | |||
765 | data->ALARM_BITS = NCT6775_ALARM_BITS; | ||
766 | |||
767 | data->REG_CONFIG = NCT6775_REG_CONFIG; | ||
768 | data->REG_VBAT = NCT6775_REG_VBAT; | ||
769 | data->REG_VIN = NCT6775_REG_IN; | ||
770 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | ||
771 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | ||
772 | data->REG_ALARM = NCT6775_REG_ALARM; | ||
773 | break; | ||
774 | case nct6776: | ||
775 | data->in_num = 9; | ||
776 | |||
777 | data->ALARM_BITS = NCT6776_ALARM_BITS; | ||
778 | |||
779 | data->REG_CONFIG = NCT6775_REG_CONFIG; | ||
780 | data->REG_VBAT = NCT6775_REG_VBAT; | ||
781 | data->REG_VIN = NCT6775_REG_IN; | ||
782 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | ||
783 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | ||
784 | data->REG_ALARM = NCT6775_REG_ALARM; | ||
785 | break; | ||
786 | case nct6779: | ||
787 | data->in_num = 15; | ||
788 | |||
789 | data->ALARM_BITS = NCT6779_ALARM_BITS; | ||
790 | |||
791 | data->REG_CONFIG = NCT6775_REG_CONFIG; | ||
792 | data->REG_VBAT = NCT6775_REG_VBAT; | ||
793 | data->REG_VIN = NCT6779_REG_IN; | ||
794 | data->REG_IN_MINMAX[0] = NCT6775_REG_IN_MIN; | ||
795 | data->REG_IN_MINMAX[1] = NCT6775_REG_IN_MAX; | ||
796 | data->REG_ALARM = NCT6779_REG_ALARM; | ||
797 | break; | ||
798 | default: | ||
799 | return -ENODEV; | ||
800 | } | ||
801 | data->have_in = (1 << data->in_num) - 1; | ||
802 | |||
803 | /* Initialize the chip */ | ||
804 | nct6775_init_device(data); | ||
805 | |||
806 | data->vrm = vid_which_vrm(); | ||
807 | err = superio_enter(sio_data->sioreg); | ||
808 | if (err) | ||
809 | return err; | ||
810 | |||
811 | /* | ||
812 | * Read VID value | ||
813 | * We can get the VID input values directly at logical device D 0xe3. | ||
814 | */ | ||
815 | superio_select(sio_data->sioreg, NCT6775_LD_VID); | ||
816 | data->vid = superio_inb(sio_data->sioreg, 0xe3); | ||
817 | superio_exit(sio_data->sioreg); | ||
818 | |||
819 | err = device_create_file(dev, &dev_attr_cpu0_vid); | ||
820 | if (err) | ||
821 | return err; | ||
822 | |||
823 | for (i = 0; i < data->in_num; i++) { | ||
824 | if (!(data->have_in & (1 << i))) | ||
825 | continue; | ||
826 | err = sysfs_create_group(&dev->kobj, &nct6775_group_in[i]); | ||
827 | if (err) | ||
828 | goto exit_remove; | ||
829 | } | ||
830 | |||
831 | err = device_create_file(dev, &dev_attr_name); | ||
832 | if (err) | ||
833 | goto exit_remove; | ||
834 | |||
835 | data->hwmon_dev = hwmon_device_register(dev); | ||
836 | if (IS_ERR(data->hwmon_dev)) { | ||
837 | err = PTR_ERR(data->hwmon_dev); | ||
838 | goto exit_remove; | ||
839 | } | ||
840 | |||
841 | return 0; | ||
842 | |||
843 | exit_remove: | ||
844 | nct6775_device_remove_files(dev); | ||
845 | return err; | ||
846 | } | ||
847 | |||
848 | static int nct6775_remove(struct platform_device *pdev) | ||
849 | { | ||
850 | struct nct6775_data *data = platform_get_drvdata(pdev); | ||
851 | |||
852 | hwmon_device_unregister(data->hwmon_dev); | ||
853 | nct6775_device_remove_files(&pdev->dev); | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static struct platform_driver nct6775_driver = { | ||
859 | .driver = { | ||
860 | .owner = THIS_MODULE, | ||
861 | .name = DRVNAME, | ||
862 | }, | ||
863 | .probe = nct6775_probe, | ||
864 | .remove = nct6775_remove, | ||
865 | }; | ||
866 | |||
867 | /* nct6775_find() looks for a '627 in the Super-I/O config space */ | ||
868 | static int __init nct6775_find(int sioaddr, unsigned short *addr, | ||
869 | struct nct6775_sio_data *sio_data) | ||
870 | { | ||
871 | static const char sio_name_NCT6775[] __initconst = "NCT6775F"; | ||
872 | static const char sio_name_NCT6776[] __initconst = "NCT6776F"; | ||
873 | static const char sio_name_NCT6779[] __initconst = "NCT6779D"; | ||
874 | |||
875 | u16 val; | ||
876 | const char *sio_name; | ||
877 | int err; | ||
878 | |||
879 | err = superio_enter(sioaddr); | ||
880 | if (err) | ||
881 | return err; | ||
882 | |||
883 | if (force_id) | ||
884 | val = force_id; | ||
885 | else | ||
886 | val = (superio_inb(sioaddr, SIO_REG_DEVID) << 8) | ||
887 | | superio_inb(sioaddr, SIO_REG_DEVID + 1); | ||
888 | switch (val & SIO_ID_MASK) { | ||
889 | case SIO_NCT6775_ID: | ||
890 | sio_data->kind = nct6775; | ||
891 | sio_name = sio_name_NCT6775; | ||
892 | break; | ||
893 | case SIO_NCT6776_ID: | ||
894 | sio_data->kind = nct6776; | ||
895 | sio_name = sio_name_NCT6776; | ||
896 | break; | ||
897 | case SIO_NCT6779_ID: | ||
898 | sio_data->kind = nct6779; | ||
899 | sio_name = sio_name_NCT6779; | ||
900 | break; | ||
901 | default: | ||
902 | if (val != 0xffff) | ||
903 | pr_debug("unsupported chip ID: 0x%04x\n", val); | ||
904 | superio_exit(sioaddr); | ||
905 | return -ENODEV; | ||
906 | } | ||
907 | |||
908 | /* We have a known chip, find the HWM I/O address */ | ||
909 | superio_select(sioaddr, NCT6775_LD_HWM); | ||
910 | val = (superio_inb(sioaddr, SIO_REG_ADDR) << 8) | ||
911 | | superio_inb(sioaddr, SIO_REG_ADDR + 1); | ||
912 | *addr = val & IOREGION_ALIGNMENT; | ||
913 | if (*addr == 0) { | ||
914 | pr_err("Refusing to enable a Super-I/O device with a base I/O port 0\n"); | ||
915 | superio_exit(sioaddr); | ||
916 | return -ENODEV; | ||
917 | } | ||
918 | |||
919 | /* Activate logical device if needed */ | ||
920 | val = superio_inb(sioaddr, SIO_REG_ENABLE); | ||
921 | if (!(val & 0x01)) { | ||
922 | pr_warn("Forcibly enabling Super-I/O. Sensor is probably unusable.\n"); | ||
923 | superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01); | ||
924 | } | ||
925 | |||
926 | superio_exit(sioaddr); | ||
927 | pr_info("Found %s chip at %#x\n", sio_name, *addr); | ||
928 | sio_data->sioreg = sioaddr; | ||
929 | |||
930 | return 0; | ||
931 | } | ||
932 | |||
933 | /* | ||
934 | * when Super-I/O functions move to a separate file, the Super-I/O | ||
935 | * bus will manage the lifetime of the device and this module will only keep | ||
936 | * track of the nct6775 driver. But since we platform_device_alloc(), we | ||
937 | * must keep track of the device | ||
938 | */ | ||
939 | static struct platform_device *pdev; | ||
940 | |||
941 | static int __init sensors_nct6775_init(void) | ||
942 | { | ||
943 | int err; | ||
944 | unsigned short address; | ||
945 | struct resource res; | ||
946 | struct nct6775_sio_data sio_data; | ||
947 | |||
948 | /* | ||
949 | * initialize sio_data->kind and sio_data->sioreg. | ||
950 | * | ||
951 | * when Super-I/O functions move to a separate file, the Super-I/O | ||
952 | * driver will probe 0x2e and 0x4e and auto-detect the presence of a | ||
953 | * nct6775 hardware monitor, and call probe() | ||
954 | */ | ||
955 | if (nct6775_find(0x2e, &address, &sio_data) && | ||
956 | nct6775_find(0x4e, &address, &sio_data)) | ||
957 | return -ENODEV; | ||
958 | |||
959 | err = platform_driver_register(&nct6775_driver); | ||
960 | if (err) | ||
961 | goto exit; | ||
962 | |||
963 | pdev = platform_device_alloc(DRVNAME, address); | ||
964 | if (!pdev) { | ||
965 | err = -ENOMEM; | ||
966 | pr_err("Device allocation failed\n"); | ||
967 | goto exit_unregister; | ||
968 | } | ||
969 | |||
970 | err = platform_device_add_data(pdev, &sio_data, | ||
971 | sizeof(struct nct6775_sio_data)); | ||
972 | if (err) { | ||
973 | pr_err("Platform data allocation failed\n"); | ||
974 | goto exit_device_put; | ||
975 | } | ||
976 | |||
977 | memset(&res, 0, sizeof(res)); | ||
978 | res.name = DRVNAME; | ||
979 | res.start = address + IOREGION_OFFSET; | ||
980 | res.end = address + IOREGION_OFFSET + IOREGION_LENGTH - 1; | ||
981 | res.flags = IORESOURCE_IO; | ||
982 | |||
983 | err = acpi_check_resource_conflict(&res); | ||
984 | if (err) | ||
985 | goto exit_device_put; | ||
986 | |||
987 | err = platform_device_add_resources(pdev, &res, 1); | ||
988 | if (err) { | ||
989 | pr_err("Device resource addition failed (%d)\n", err); | ||
990 | goto exit_device_put; | ||
991 | } | ||
992 | |||
993 | /* platform_device_add calls probe() */ | ||
994 | err = platform_device_add(pdev); | ||
995 | if (err) { | ||
996 | pr_err("Device addition failed (%d)\n", err); | ||
997 | goto exit_device_put; | ||
998 | } | ||
999 | |||
1000 | return 0; | ||
1001 | |||
1002 | exit_device_put: | ||
1003 | platform_device_put(pdev); | ||
1004 | exit_unregister: | ||
1005 | platform_driver_unregister(&nct6775_driver); | ||
1006 | exit: | ||
1007 | return err; | ||
1008 | } | ||
1009 | |||
1010 | static void __exit sensors_nct6775_exit(void) | ||
1011 | { | ||
1012 | platform_device_unregister(pdev); | ||
1013 | platform_driver_unregister(&nct6775_driver); | ||
1014 | } | ||
1015 | |||
1016 | MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>"); | ||
1017 | MODULE_DESCRIPTION("NCT6775F/NCT6776F/NCT6779D driver"); | ||
1018 | MODULE_LICENSE("GPL"); | ||
1019 | |||
1020 | module_init(sensors_nct6775_init); | ||
1021 | module_exit(sensors_nct6775_exit); | ||