diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-07 19:29:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-07 19:29:27 -0500 |
commit | b4669d66fb1488fd9cebe0b8da447cfeb86109ba (patch) | |
tree | 2beaba0e7d8acac9703667aff5f9bc9f4d4357d6 | |
parent | b43d4ddaec2b33fd6eaf0bed970c86ab08a52aaf (diff) | |
parent | c5e3fbf22ccba0879b174fab7ec0e322b1266c2c (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/i2c-2.6
-rw-r--r-- | Documentation/feature-removal-schedule.txt | 9 | ||||
-rw-r--r-- | Documentation/hwmon/f71805f | 105 | ||||
-rw-r--r-- | Documentation/hwmon/it87 | 2 | ||||
-rw-r--r-- | Documentation/hwmon/sysfs-interface | 18 | ||||
-rw-r--r-- | Documentation/i2c/busses/i2c-sis96x (renamed from Documentation/i2c/busses/i2c-sis69x) | 4 | ||||
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | drivers/hwmon/Kconfig | 10 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/f71805f.c | 908 | ||||
-rw-r--r-- | drivers/hwmon/it87.c | 8 | ||||
-rw-r--r-- | drivers/hwmon/lm77.c | 8 | ||||
-rw-r--r-- | drivers/hwmon/w83792d.c | 31 | ||||
-rw-r--r-- | drivers/i2c/algos/i2c-algo-sibyte.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/Kconfig | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 2 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-parport-light.c | 9 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-parport.c | 7 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-pxa.c | 2 | ||||
-rw-r--r-- | drivers/i2c/i2c-core.c | 15 | ||||
-rw-r--r-- | include/linux/i2c.h | 3 |
20 files changed, 1111 insertions, 40 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 4d4897c8ef96..b730d765b525 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
@@ -162,3 +162,12 @@ What: pci_module_init(driver) | |||
162 | When: January 2007 | 162 | When: January 2007 |
163 | Why: Is replaced by pci_register_driver(pci_driver). | 163 | Why: Is replaced by pci_register_driver(pci_driver). |
164 | Who: Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@suse.de> | 164 | Who: Richard Knutsson <ricknu-0@student.ltu.se> and Greg Kroah-Hartman <gregkh@suse.de> |
165 | |||
166 | --------------------------- | ||
167 | |||
168 | What: I2C interface of the it87 driver | ||
169 | When: January 2007 | ||
170 | Why: The ISA interface is faster and should be always available. The I2C | ||
171 | probing is also known to cause trouble in at least one case (see | ||
172 | bug #5889.) | ||
173 | Who: Jean Delvare <khali@linux-fr.org> | ||
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f new file mode 100644 index 000000000000..28c5b7d1eb90 --- /dev/null +++ b/Documentation/hwmon/f71805f | |||
@@ -0,0 +1,105 @@ | |||
1 | Kernel driver f71805f | ||
2 | ===================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Fintek F71805F/FG | ||
6 | Prefix: 'f71805f' | ||
7 | Addresses scanned: none, address read from Super I/O config space | ||
8 | Datasheet: Provided by Fintek on request | ||
9 | |||
10 | Author: Jean Delvare <khali@linux-fr.org> | ||
11 | |||
12 | Thanks to Denis Kieft from Barracuda Networks for the donation of a | ||
13 | test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and | ||
14 | for providing initial documentation. | ||
15 | |||
16 | Thanks to Kris Chen from Fintek for answering technical questions and | ||
17 | providing additional documentation. | ||
18 | |||
19 | Thanks to Chris Lin from Jetway for providing wiring schematics and | ||
20 | anwsering technical questions. | ||
21 | |||
22 | |||
23 | Description | ||
24 | ----------- | ||
25 | |||
26 | The Fintek F71805F/FG Super I/O chip includes complete hardware monitoring | ||
27 | capabilities. It can monitor up to 9 voltages (counting its own power | ||
28 | source), 3 fans and 3 temperature sensors. | ||
29 | |||
30 | This chip also has fan controlling features, using either DC or PWM, in | ||
31 | three different modes (one manual, two automatic). The driver doesn't | ||
32 | support these features yet. | ||
33 | |||
34 | The driver assumes that no more than one chip is present, which seems | ||
35 | reasonable. | ||
36 | |||
37 | |||
38 | Voltage Monitoring | ||
39 | ------------------ | ||
40 | |||
41 | Voltages are sampled by an 8-bit ADC with a LSB of 8 mV. The supported | ||
42 | range is thus from 0 to 2.040 V. Voltage values outside of this range | ||
43 | need external resistors. An exception is in0, which is used to monitor | ||
44 | the chip's own power source (+3.3V), and is divided internally by a | ||
45 | factor 2. | ||
46 | |||
47 | The two LSB of the voltage limit registers are not used (always 0), so | ||
48 | you can only set the limits in steps of 32 mV (before scaling). | ||
49 | |||
50 | The wirings and resistor values suggested by Fintek are as follow: | ||
51 | |||
52 | pin expected | ||
53 | name use R1 R2 divider raw val. | ||
54 | |||
55 | in0 VCC VCC3.3V int. int. 2.00 1.65 V | ||
56 | in1 VIN1 VTT1.2V 10K - 1.00 1.20 V | ||
57 | in2 VIN2 VRAM 100K 100K 2.00 ~1.25 V (1) | ||
58 | in3 VIN3 VCHIPSET 47K 100K 1.47 2.24 V (2) | ||
59 | in4 VIN4 VCC5V 200K 47K 5.25 0.95 V | ||
60 | in5 VIN5 +12V 200K 20K 11.00 1.05 V | ||
61 | in6 VIN6 VCC1.5V 10K - 1.00 1.50 V | ||
62 | in7 VIN7 VCORE 10K - 1.00 ~1.40 V (1) | ||
63 | in8 VIN8 VSB5V 200K 47K 1.00 0.95 V | ||
64 | |||
65 | (1) Depends on your hardware setup. | ||
66 | (2) Obviously not correct, swapping R1 and R2 would make more sense. | ||
67 | |||
68 | These values can be used as hints at best, as motherboard manufacturers | ||
69 | are free to use a completely different setup. As a matter of fact, the | ||
70 | Jetway K8M8MS uses a significantly different setup. You will have to | ||
71 | find out documentation about your own motherboard, and edit sensors.conf | ||
72 | accordingly. | ||
73 | |||
74 | Each voltage measured has associated low and high limits, each of which | ||
75 | triggers an alarm when crossed. | ||
76 | |||
77 | |||
78 | Fan Monitoring | ||
79 | -------------- | ||
80 | |||
81 | Fan rotation speeds are reported as 12-bit values from a gated clock | ||
82 | signal. Speeds down to 366 RPM can be measured. There is no theoretical | ||
83 | high limit, but values over 6000 RPM seem to cause problem. The effective | ||
84 | resolution is much lower than you would expect, the step between different | ||
85 | register values being 10 rather than 1. | ||
86 | |||
87 | The chip assumes 2 pulse-per-revolution fans. | ||
88 | |||
89 | An alarm is triggered if the rotation speed drops below a programmable | ||
90 | limit or is too low to be measured. | ||
91 | |||
92 | |||
93 | Temperature Monitoring | ||
94 | ---------------------- | ||
95 | |||
96 | Temperatures are reported in degrees Celsius. Each temperature measured | ||
97 | has a high limit, those crossing triggers an alarm. There is an associated | ||
98 | hysteresis value, below which the temperature has to drop before the | ||
99 | alarm is cleared. | ||
100 | |||
101 | All temperature channels are external, there is no embedded temperature | ||
102 | sensor. Each channel can be used for connecting either a thermal diode | ||
103 | or a thermistor. The driver reports the currently selected mode, but | ||
104 | doesn't allow changing it. In theory, the BIOS should have configured | ||
105 | everything properly. | ||
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87 index 7f42e441c645..9555be1ed999 100644 --- a/Documentation/hwmon/it87 +++ b/Documentation/hwmon/it87 | |||
@@ -9,7 +9,7 @@ Supported chips: | |||
9 | http://www.ite.com.tw/ | 9 | http://www.ite.com.tw/ |
10 | * IT8712F | 10 | * IT8712F |
11 | Prefix: 'it8712' | 11 | Prefix: 'it8712' |
12 | Addresses scanned: I2C 0x28 - 0x2f | 12 | Addresses scanned: I2C 0x2d |
13 | from Super I/O config space (8 I/O ports) | 13 | from Super I/O config space (8 I/O ports) |
14 | Datasheet: Publicly available at the ITE website | 14 | Datasheet: Publicly available at the ITE website |
15 | http://www.ite.com.tw/ | 15 | http://www.ite.com.tw/ |
diff --git a/Documentation/hwmon/sysfs-interface b/Documentation/hwmon/sysfs-interface index 764cdc5480e7..a0d0ab24288e 100644 --- a/Documentation/hwmon/sysfs-interface +++ b/Documentation/hwmon/sysfs-interface | |||
@@ -179,11 +179,12 @@ temp[1-*]_auto_point[1-*]_temp_hyst | |||
179 | **************** | 179 | **************** |
180 | 180 | ||
181 | temp[1-3]_type Sensor type selection. | 181 | temp[1-3]_type Sensor type selection. |
182 | Integers 1, 2, 3 or thermistor Beta value (3435) | 182 | Integers 1 to 4 or thermistor Beta value (typically 3435) |
183 | Read/Write. | 183 | Read/Write. |
184 | 1: PII/Celeron Diode | 184 | 1: PII/Celeron Diode |
185 | 2: 3904 transistor | 185 | 2: 3904 transistor |
186 | 3: thermal diode | 186 | 3: thermal diode |
187 | 4: thermistor (default/unknown Beta) | ||
187 | Not all types are supported by all chips | 188 | Not all types are supported by all chips |
188 | 189 | ||
189 | temp[1-4]_max Temperature max value. | 190 | temp[1-4]_max Temperature max value. |
@@ -261,6 +262,21 @@ alarms Alarm bitmask. | |||
261 | of individual bits. | 262 | of individual bits. |
262 | Bits are defined in kernel/include/sensors.h. | 263 | Bits are defined in kernel/include/sensors.h. |
263 | 264 | ||
265 | alarms_in Alarm bitmask relative to in (voltage) channels | ||
266 | Read only | ||
267 | A '1' bit means an alarm, LSB corresponds to in0 and so on | ||
268 | Prefered to 'alarms' for newer chips | ||
269 | |||
270 | alarms_fan Alarm bitmask relative to fan channels | ||
271 | Read only | ||
272 | A '1' bit means an alarm, LSB corresponds to fan1 and so on | ||
273 | Prefered to 'alarms' for newer chips | ||
274 | |||
275 | alarms_temp Alarm bitmask relative to temp (temperature) channels | ||
276 | Read only | ||
277 | A '1' bit means an alarm, LSB corresponds to temp1 and so on | ||
278 | Prefered to 'alarms' for newer chips | ||
279 | |||
264 | beep_enable Beep/interrupt enable | 280 | beep_enable Beep/interrupt enable |
265 | 0 to disable. | 281 | 0 to disable. |
266 | 1 to enable. | 282 | 1 to enable. |
diff --git a/Documentation/i2c/busses/i2c-sis69x b/Documentation/i2c/busses/i2c-sis96x index b88953dfd580..00a009b977e9 100644 --- a/Documentation/i2c/busses/i2c-sis69x +++ b/Documentation/i2c/busses/i2c-sis96x | |||
@@ -7,7 +7,7 @@ Supported adapters: | |||
7 | Any combination of these host bridges: | 7 | Any combination of these host bridges: |
8 | 645, 645DX (aka 646), 648, 650, 651, 655, 735, 745, 746 | 8 | 645, 645DX (aka 646), 648, 650, 651, 655, 735, 745, 746 |
9 | and these south bridges: | 9 | and these south bridges: |
10 | 961, 962, 963(L) | 10 | 961, 962, 963(L) |
11 | 11 | ||
12 | Author: Mark M. Hoffman <mhoffman@lightlink.com> | 12 | Author: Mark M. Hoffman <mhoffman@lightlink.com> |
13 | 13 | ||
@@ -29,7 +29,7 @@ The command "lspci" as root should produce something like these lines: | |||
29 | 29 | ||
30 | or perhaps this... | 30 | or perhaps this... |
31 | 31 | ||
32 | 00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 | 32 | 00:00.0 Host bridge: Silicon Integrated Systems [SiS]: Unknown device 0645 |
33 | 00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961 | 33 | 00:02.0 ISA bridge: Silicon Integrated Systems [SiS]: Unknown device 0961 |
34 | 00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 | 34 | 00:02.1 SMBus: Silicon Integrated Systems [SiS]: Unknown device 0016 |
35 | 35 | ||
diff --git a/MAINTAINERS b/MAINTAINERS index a05aefdea602..b22db521cec1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -931,6 +931,12 @@ M: sct@redhat.com, akpm@osdl.org, adilger@clusterfs.com | |||
931 | L: ext3-users@redhat.com | 931 | L: ext3-users@redhat.com |
932 | S: Maintained | 932 | S: Maintained |
933 | 933 | ||
934 | F71805F HARDWARE MONITORING DRIVER | ||
935 | P: Jean Delvare | ||
936 | M: khali@linux-fr.org | ||
937 | L: lm-sensors@lm-sensors.org | ||
938 | S: Maintained | ||
939 | |||
934 | FARSYNC SYNCHRONOUS DRIVER | 940 | FARSYNC SYNCHRONOUS DRIVER |
935 | P: Kevin Curtis | 941 | P: Kevin Curtis |
936 | M: kevin.curtis@farsite.co.uk | 942 | M: kevin.curtis@farsite.co.uk |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index c58295914365..7230d4e08196 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -113,6 +113,16 @@ config SENSORS_DS1621 | |||
113 | This driver can also be built as a module. If so, the module | 113 | This driver can also be built as a module. If so, the module |
114 | will be called ds1621. | 114 | will be called ds1621. |
115 | 115 | ||
116 | config SENSORS_F71805F | ||
117 | tristate "Fintek F71805F/FG" | ||
118 | depends on HWMON && EXPERIMENTAL | ||
119 | help | ||
120 | If you say yes here you get support for hardware monitoring | ||
121 | features of the Fintek F71805F/FG chips. | ||
122 | |||
123 | This driver can also be built as a module. If so, the module | ||
124 | will be called f71805f. | ||
125 | |||
116 | config SENSORS_FSCHER | 126 | config SENSORS_FSCHER |
117 | tristate "FSC Hermes" | 127 | tristate "FSC Hermes" |
118 | depends on HWMON && I2C && EXPERIMENTAL | 128 | depends on HWMON && I2C && EXPERIMENTAL |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 06d4a1d14105..fbdb8d911a72 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -18,6 +18,7 @@ obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o | |||
18 | obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o | 18 | obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o |
19 | obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o | 19 | obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o |
20 | obj-$(CONFIG_SENSORS_DS1621) += ds1621.o | 20 | obj-$(CONFIG_SENSORS_DS1621) += ds1621.o |
21 | obj-$(CONFIG_SENSORS_F71805F) += f71805f.o | ||
21 | obj-$(CONFIG_SENSORS_FSCHER) += fscher.o | 22 | obj-$(CONFIG_SENSORS_FSCHER) += fscher.o |
22 | obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o | 23 | obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o |
23 | obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o | 24 | obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o |
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c new file mode 100644 index 000000000000..e029e0a94ecc --- /dev/null +++ b/drivers/hwmon/f71805f.c | |||
@@ -0,0 +1,908 @@ | |||
1 | /* | ||
2 | * f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated | ||
3 | * hardware monitoring features | ||
4 | * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> | ||
5 | * | ||
6 | * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates | ||
7 | * complete hardware monitoring features: voltage, fan and temperature | ||
8 | * sensors, and manual and automatic fan speed control. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/hwmon.h> | ||
31 | #include <linux/hwmon-sysfs.h> | ||
32 | #include <linux/err.h> | ||
33 | #include <asm/io.h> | ||
34 | |||
35 | static struct platform_device *pdev; | ||
36 | |||
37 | #define DRVNAME "f71805f" | ||
38 | |||
39 | /* | ||
40 | * Super-I/O constants and functions | ||
41 | */ | ||
42 | |||
43 | #define F71805F_LD_HWM 0x04 | ||
44 | |||
45 | #define SIO_REG_LDSEL 0x07 /* Logical device select */ | ||
46 | #define SIO_REG_DEVID 0x20 /* Device ID (2 bytes) */ | ||
47 | #define SIO_REG_DEVREV 0x22 /* Device revision */ | ||
48 | #define SIO_REG_MANID 0x23 /* Fintek ID (2 bytes) */ | ||
49 | #define SIO_REG_ENABLE 0x30 /* Logical device enable */ | ||
50 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ | ||
51 | |||
52 | #define SIO_FINTEK_ID 0x1934 | ||
53 | #define SIO_F71805F_ID 0x0406 | ||
54 | |||
55 | static inline int | ||
56 | superio_inb(int base, int reg) | ||
57 | { | ||
58 | outb(reg, base); | ||
59 | return inb(base + 1); | ||
60 | } | ||
61 | |||
62 | static int | ||
63 | superio_inw(int base, int reg) | ||
64 | { | ||
65 | int val; | ||
66 | outb(reg++, base); | ||
67 | val = inb(base + 1) << 8; | ||
68 | outb(reg, base); | ||
69 | val |= inb(base + 1); | ||
70 | return val; | ||
71 | } | ||
72 | |||
73 | static inline void | ||
74 | superio_select(int base, int ld) | ||
75 | { | ||
76 | outb(SIO_REG_LDSEL, base); | ||
77 | outb(ld, base + 1); | ||
78 | } | ||
79 | |||
80 | static inline void | ||
81 | superio_enter(int base) | ||
82 | { | ||
83 | outb(0x87, base); | ||
84 | outb(0x87, base); | ||
85 | } | ||
86 | |||
87 | static inline void | ||
88 | superio_exit(int base) | ||
89 | { | ||
90 | outb(0xaa, base); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * ISA constants | ||
95 | */ | ||
96 | |||
97 | #define REGION_LENGTH 2 | ||
98 | #define ADDR_REG_OFFSET 0 | ||
99 | #define DATA_REG_OFFSET 1 | ||
100 | |||
101 | static struct resource f71805f_resource __initdata = { | ||
102 | .flags = IORESOURCE_IO, | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * Registers | ||
107 | */ | ||
108 | |||
109 | /* in nr from 0 to 8 (8-bit values) */ | ||
110 | #define F71805F_REG_IN(nr) (0x10 + (nr)) | ||
111 | #define F71805F_REG_IN_HIGH(nr) (0x40 + 2 * (nr)) | ||
112 | #define F71805F_REG_IN_LOW(nr) (0x41 + 2 * (nr)) | ||
113 | /* fan nr from 0 to 2 (12-bit values, two registers) */ | ||
114 | #define F71805F_REG_FAN(nr) (0x20 + 2 * (nr)) | ||
115 | #define F71805F_REG_FAN_LOW(nr) (0x28 + 2 * (nr)) | ||
116 | #define F71805F_REG_FAN_CTRL(nr) (0x60 + 16 * (nr)) | ||
117 | /* temp nr from 0 to 2 (8-bit values) */ | ||
118 | #define F71805F_REG_TEMP(nr) (0x1B + (nr)) | ||
119 | #define F71805F_REG_TEMP_HIGH(nr) (0x54 + 2 * (nr)) | ||
120 | #define F71805F_REG_TEMP_HYST(nr) (0x55 + 2 * (nr)) | ||
121 | #define F71805F_REG_TEMP_MODE 0x01 | ||
122 | |||
123 | #define F71805F_REG_START 0x00 | ||
124 | /* status nr from 0 to 2 */ | ||
125 | #define F71805F_REG_STATUS(nr) (0x36 + (nr)) | ||
126 | |||
127 | /* | ||
128 | * Data structures and manipulation thereof | ||
129 | */ | ||
130 | |||
131 | struct f71805f_data { | ||
132 | unsigned short addr; | ||
133 | const char *name; | ||
134 | struct semaphore lock; | ||
135 | struct class_device *class_dev; | ||
136 | |||
137 | struct semaphore update_lock; | ||
138 | char valid; /* !=0 if following fields are valid */ | ||
139 | unsigned long last_updated; /* In jiffies */ | ||
140 | unsigned long last_limits; /* In jiffies */ | ||
141 | |||
142 | /* Register values */ | ||
143 | u8 in[9]; | ||
144 | u8 in_high[9]; | ||
145 | u8 in_low[9]; | ||
146 | u16 fan[3]; | ||
147 | u16 fan_low[3]; | ||
148 | u8 fan_enabled; /* Read once at init time */ | ||
149 | u8 temp[3]; | ||
150 | u8 temp_high[3]; | ||
151 | u8 temp_hyst[3]; | ||
152 | u8 temp_mode; | ||
153 | u8 alarms[3]; | ||
154 | }; | ||
155 | |||
156 | static inline long in_from_reg(u8 reg) | ||
157 | { | ||
158 | return (reg * 8); | ||
159 | } | ||
160 | |||
161 | /* The 2 least significant bits are not used */ | ||
162 | static inline u8 in_to_reg(long val) | ||
163 | { | ||
164 | if (val <= 0) | ||
165 | return 0; | ||
166 | if (val >= 2016) | ||
167 | return 0xfc; | ||
168 | return (((val + 16) / 32) << 2); | ||
169 | } | ||
170 | |||
171 | /* in0 is downscaled by a factor 2 internally */ | ||
172 | static inline long in0_from_reg(u8 reg) | ||
173 | { | ||
174 | return (reg * 16); | ||
175 | } | ||
176 | |||
177 | static inline u8 in0_to_reg(long val) | ||
178 | { | ||
179 | if (val <= 0) | ||
180 | return 0; | ||
181 | if (val >= 4032) | ||
182 | return 0xfc; | ||
183 | return (((val + 32) / 64) << 2); | ||
184 | } | ||
185 | |||
186 | /* The 4 most significant bits are not used */ | ||
187 | static inline long fan_from_reg(u16 reg) | ||
188 | { | ||
189 | reg &= 0xfff; | ||
190 | if (!reg || reg == 0xfff) | ||
191 | return 0; | ||
192 | return (1500000 / reg); | ||
193 | } | ||
194 | |||
195 | static inline u16 fan_to_reg(long rpm) | ||
196 | { | ||
197 | /* If the low limit is set below what the chip can measure, | ||
198 | store the largest possible 12-bit value in the registers, | ||
199 | so that no alarm will ever trigger. */ | ||
200 | if (rpm < 367) | ||
201 | return 0xfff; | ||
202 | return (1500000 / rpm); | ||
203 | } | ||
204 | |||
205 | static inline long temp_from_reg(u8 reg) | ||
206 | { | ||
207 | return (reg * 1000); | ||
208 | } | ||
209 | |||
210 | static inline u8 temp_to_reg(long val) | ||
211 | { | ||
212 | if (val < 0) | ||
213 | val = 0; | ||
214 | else if (val > 1000 * 0xff) | ||
215 | val = 0xff; | ||
216 | return ((val + 500) / 1000); | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Device I/O access | ||
221 | */ | ||
222 | |||
223 | static u8 f71805f_read8(struct f71805f_data *data, u8 reg) | ||
224 | { | ||
225 | u8 val; | ||
226 | |||
227 | down(&data->lock); | ||
228 | outb(reg, data->addr + ADDR_REG_OFFSET); | ||
229 | val = inb(data->addr + DATA_REG_OFFSET); | ||
230 | up(&data->lock); | ||
231 | |||
232 | return val; | ||
233 | } | ||
234 | |||
235 | static void f71805f_write8(struct f71805f_data *data, u8 reg, u8 val) | ||
236 | { | ||
237 | down(&data->lock); | ||
238 | outb(reg, data->addr + ADDR_REG_OFFSET); | ||
239 | outb(val, data->addr + DATA_REG_OFFSET); | ||
240 | up(&data->lock); | ||
241 | } | ||
242 | |||
243 | /* It is important to read the MSB first, because doing so latches the | ||
244 | value of the LSB, so we are sure both bytes belong to the same value. */ | ||
245 | static u16 f71805f_read16(struct f71805f_data *data, u8 reg) | ||
246 | { | ||
247 | u16 val; | ||
248 | |||
249 | down(&data->lock); | ||
250 | outb(reg, data->addr + ADDR_REG_OFFSET); | ||
251 | val = inb(data->addr + DATA_REG_OFFSET) << 8; | ||
252 | outb(++reg, data->addr + ADDR_REG_OFFSET); | ||
253 | val |= inb(data->addr + DATA_REG_OFFSET); | ||
254 | up(&data->lock); | ||
255 | |||
256 | return val; | ||
257 | } | ||
258 | |||
259 | static void f71805f_write16(struct f71805f_data *data, u8 reg, u16 val) | ||
260 | { | ||
261 | down(&data->lock); | ||
262 | outb(reg, data->addr + ADDR_REG_OFFSET); | ||
263 | outb(val >> 8, data->addr + DATA_REG_OFFSET); | ||
264 | outb(++reg, data->addr + ADDR_REG_OFFSET); | ||
265 | outb(val & 0xff, data->addr + DATA_REG_OFFSET); | ||
266 | up(&data->lock); | ||
267 | } | ||
268 | |||
269 | static struct f71805f_data *f71805f_update_device(struct device *dev) | ||
270 | { | ||
271 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
272 | int nr; | ||
273 | |||
274 | down(&data->update_lock); | ||
275 | |||
276 | /* Limit registers cache is refreshed after 60 seconds */ | ||
277 | if (time_after(jiffies, data->last_updated + 60 * HZ) | ||
278 | || !data->valid) { | ||
279 | for (nr = 0; nr < 9; nr++) { | ||
280 | data->in_high[nr] = f71805f_read8(data, | ||
281 | F71805F_REG_IN_HIGH(nr)); | ||
282 | data->in_low[nr] = f71805f_read8(data, | ||
283 | F71805F_REG_IN_LOW(nr)); | ||
284 | } | ||
285 | for (nr = 0; nr < 3; nr++) { | ||
286 | if (data->fan_enabled & (1 << nr)) | ||
287 | data->fan_low[nr] = f71805f_read16(data, | ||
288 | F71805F_REG_FAN_LOW(nr)); | ||
289 | } | ||
290 | for (nr = 0; nr < 3; nr++) { | ||
291 | data->temp_high[nr] = f71805f_read8(data, | ||
292 | F71805F_REG_TEMP_HIGH(nr)); | ||
293 | data->temp_hyst[nr] = f71805f_read8(data, | ||
294 | F71805F_REG_TEMP_HYST(nr)); | ||
295 | } | ||
296 | data->temp_mode = f71805f_read8(data, F71805F_REG_TEMP_MODE); | ||
297 | |||
298 | data->last_limits = jiffies; | ||
299 | } | ||
300 | |||
301 | /* Measurement registers cache is refreshed after 1 second */ | ||
302 | if (time_after(jiffies, data->last_updated + HZ) | ||
303 | || !data->valid) { | ||
304 | for (nr = 0; nr < 9; nr++) { | ||
305 | data->in[nr] = f71805f_read8(data, | ||
306 | F71805F_REG_IN(nr)); | ||
307 | } | ||
308 | for (nr = 0; nr < 3; nr++) { | ||
309 | if (data->fan_enabled & (1 << nr)) | ||
310 | data->fan[nr] = f71805f_read16(data, | ||
311 | F71805F_REG_FAN(nr)); | ||
312 | } | ||
313 | for (nr = 0; nr < 3; nr++) { | ||
314 | data->temp[nr] = f71805f_read8(data, | ||
315 | F71805F_REG_TEMP(nr)); | ||
316 | } | ||
317 | for (nr = 0; nr < 3; nr++) { | ||
318 | data->alarms[nr] = f71805f_read8(data, | ||
319 | F71805F_REG_STATUS(nr)); | ||
320 | } | ||
321 | |||
322 | data->last_updated = jiffies; | ||
323 | data->valid = 1; | ||
324 | } | ||
325 | |||
326 | up(&data->update_lock); | ||
327 | |||
328 | return data; | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Sysfs interface | ||
333 | */ | ||
334 | |||
335 | static ssize_t show_in0(struct device *dev, struct device_attribute *devattr, | ||
336 | char *buf) | ||
337 | { | ||
338 | struct f71805f_data *data = f71805f_update_device(dev); | ||
339 | |||
340 | return sprintf(buf, "%ld\n", in0_from_reg(data->in[0])); | ||
341 | } | ||
342 | |||
343 | static ssize_t show_in0_max(struct device *dev, struct device_attribute | ||
344 | *devattr, char *buf) | ||
345 | { | ||
346 | struct f71805f_data *data = f71805f_update_device(dev); | ||
347 | |||
348 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_high[0])); | ||
349 | } | ||
350 | |||
351 | static ssize_t show_in0_min(struct device *dev, struct device_attribute | ||
352 | *devattr, char *buf) | ||
353 | { | ||
354 | struct f71805f_data *data = f71805f_update_device(dev); | ||
355 | |||
356 | return sprintf(buf, "%ld\n", in0_from_reg(data->in_low[0])); | ||
357 | } | ||
358 | |||
359 | static ssize_t set_in0_max(struct device *dev, struct device_attribute | ||
360 | *devattr, const char *buf, size_t count) | ||
361 | { | ||
362 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
363 | long val = simple_strtol(buf, NULL, 10); | ||
364 | |||
365 | down(&data->update_lock); | ||
366 | data->in_high[0] = in0_to_reg(val); | ||
367 | f71805f_write8(data, F71805F_REG_IN_HIGH(0), data->in_high[0]); | ||
368 | up(&data->update_lock); | ||
369 | |||
370 | return count; | ||
371 | } | ||
372 | |||
373 | static ssize_t set_in0_min(struct device *dev, struct device_attribute | ||
374 | *devattr, const char *buf, size_t count) | ||
375 | { | ||
376 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
377 | long val = simple_strtol(buf, NULL, 10); | ||
378 | |||
379 | down(&data->update_lock); | ||
380 | data->in_low[0] = in0_to_reg(val); | ||
381 | f71805f_write8(data, F71805F_REG_IN_LOW(0), data->in_low[0]); | ||
382 | up(&data->update_lock); | ||
383 | |||
384 | return count; | ||
385 | } | ||
386 | |||
387 | static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL); | ||
388 | static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max); | ||
389 | static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min); | ||
390 | |||
391 | static ssize_t show_in(struct device *dev, struct device_attribute *devattr, | ||
392 | char *buf) | ||
393 | { | ||
394 | struct f71805f_data *data = f71805f_update_device(dev); | ||
395 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
396 | int nr = attr->index; | ||
397 | |||
398 | return sprintf(buf, "%ld\n", in_from_reg(data->in[nr])); | ||
399 | } | ||
400 | |||
401 | static ssize_t show_in_max(struct device *dev, struct device_attribute | ||
402 | *devattr, char *buf) | ||
403 | { | ||
404 | struct f71805f_data *data = f71805f_update_device(dev); | ||
405 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
406 | int nr = attr->index; | ||
407 | |||
408 | return sprintf(buf, "%ld\n", in_from_reg(data->in_high[nr])); | ||
409 | } | ||
410 | |||
411 | static ssize_t show_in_min(struct device *dev, struct device_attribute | ||
412 | *devattr, char *buf) | ||
413 | { | ||
414 | struct f71805f_data *data = f71805f_update_device(dev); | ||
415 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
416 | int nr = attr->index; | ||
417 | |||
418 | return sprintf(buf, "%ld\n", in_from_reg(data->in_low[nr])); | ||
419 | } | ||
420 | |||
421 | static ssize_t set_in_max(struct device *dev, struct device_attribute | ||
422 | *devattr, const char *buf, size_t count) | ||
423 | { | ||
424 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
425 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
426 | int nr = attr->index; | ||
427 | long val = simple_strtol(buf, NULL, 10); | ||
428 | |||
429 | down(&data->update_lock); | ||
430 | data->in_high[nr] = in_to_reg(val); | ||
431 | f71805f_write8(data, F71805F_REG_IN_HIGH(nr), data->in_high[nr]); | ||
432 | up(&data->update_lock); | ||
433 | |||
434 | return count; | ||
435 | } | ||
436 | |||
437 | static ssize_t set_in_min(struct device *dev, struct device_attribute | ||
438 | *devattr, const char *buf, size_t count) | ||
439 | { | ||
440 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
441 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
442 | int nr = attr->index; | ||
443 | long val = simple_strtol(buf, NULL, 10); | ||
444 | |||
445 | down(&data->update_lock); | ||
446 | data->in_low[nr] = in_to_reg(val); | ||
447 | f71805f_write8(data, F71805F_REG_IN_LOW(nr), data->in_low[nr]); | ||
448 | up(&data->update_lock); | ||
449 | |||
450 | return count; | ||
451 | } | ||
452 | |||
453 | #define sysfs_in(offset) \ | ||
454 | static SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ | ||
455 | show_in, NULL, offset); \ | ||
456 | static SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ | ||
457 | show_in_max, set_in_max, offset); \ | ||
458 | static SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ | ||
459 | show_in_min, set_in_min, offset) | ||
460 | |||
461 | sysfs_in(1); | ||
462 | sysfs_in(2); | ||
463 | sysfs_in(3); | ||
464 | sysfs_in(4); | ||
465 | sysfs_in(5); | ||
466 | sysfs_in(6); | ||
467 | sysfs_in(7); | ||
468 | sysfs_in(8); | ||
469 | |||
470 | static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, | ||
471 | char *buf) | ||
472 | { | ||
473 | struct f71805f_data *data = f71805f_update_device(dev); | ||
474 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
475 | int nr = attr->index; | ||
476 | |||
477 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan[nr])); | ||
478 | } | ||
479 | |||
480 | static ssize_t show_fan_min(struct device *dev, struct device_attribute | ||
481 | *devattr, char *buf) | ||
482 | { | ||
483 | struct f71805f_data *data = f71805f_update_device(dev); | ||
484 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
485 | int nr = attr->index; | ||
486 | |||
487 | return sprintf(buf, "%ld\n", fan_from_reg(data->fan_low[nr])); | ||
488 | } | ||
489 | |||
490 | static ssize_t set_fan_min(struct device *dev, struct device_attribute | ||
491 | *devattr, const char *buf, size_t count) | ||
492 | { | ||
493 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
494 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
495 | int nr = attr->index; | ||
496 | long val = simple_strtol(buf, NULL, 10); | ||
497 | |||
498 | down(&data->update_lock); | ||
499 | data->fan_low[nr] = fan_to_reg(val); | ||
500 | f71805f_write16(data, F71805F_REG_FAN_LOW(nr), data->fan_low[nr]); | ||
501 | up(&data->update_lock); | ||
502 | |||
503 | return count; | ||
504 | } | ||
505 | |||
506 | #define sysfs_fan(offset) \ | ||
507 | static SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ | ||
508 | show_fan, NULL, offset - 1); \ | ||
509 | static SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ | ||
510 | show_fan_min, set_fan_min, offset - 1) | ||
511 | |||
512 | sysfs_fan(1); | ||
513 | sysfs_fan(2); | ||
514 | sysfs_fan(3); | ||
515 | |||
516 | static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | ||
517 | char *buf) | ||
518 | { | ||
519 | struct f71805f_data *data = f71805f_update_device(dev); | ||
520 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
521 | int nr = attr->index; | ||
522 | |||
523 | return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr])); | ||
524 | } | ||
525 | |||
526 | static ssize_t show_temp_max(struct device *dev, struct device_attribute | ||
527 | *devattr, char *buf) | ||
528 | { | ||
529 | struct f71805f_data *data = f71805f_update_device(dev); | ||
530 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
531 | int nr = attr->index; | ||
532 | |||
533 | return sprintf(buf, "%ld\n", temp_from_reg(data->temp_high[nr])); | ||
534 | } | ||
535 | |||
536 | static ssize_t show_temp_hyst(struct device *dev, struct device_attribute | ||
537 | *devattr, char *buf) | ||
538 | { | ||
539 | struct f71805f_data *data = f71805f_update_device(dev); | ||
540 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
541 | int nr = attr->index; | ||
542 | |||
543 | return sprintf(buf, "%ld\n", temp_from_reg(data->temp_hyst[nr])); | ||
544 | } | ||
545 | |||
546 | static ssize_t show_temp_type(struct device *dev, struct device_attribute | ||
547 | *devattr, char *buf) | ||
548 | { | ||
549 | struct f71805f_data *data = f71805f_update_device(dev); | ||
550 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
551 | int nr = attr->index; | ||
552 | |||
553 | /* 3 is diode, 4 is thermistor */ | ||
554 | return sprintf(buf, "%u\n", (data->temp_mode & (1 << nr)) ? 3 : 4); | ||
555 | } | ||
556 | |||
557 | static ssize_t set_temp_max(struct device *dev, struct device_attribute | ||
558 | *devattr, const char *buf, size_t count) | ||
559 | { | ||
560 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
561 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
562 | int nr = attr->index; | ||
563 | long val = simple_strtol(buf, NULL, 10); | ||
564 | |||
565 | down(&data->update_lock); | ||
566 | data->temp_high[nr] = temp_to_reg(val); | ||
567 | f71805f_write8(data, F71805F_REG_TEMP_HIGH(nr), data->temp_high[nr]); | ||
568 | up(&data->update_lock); | ||
569 | |||
570 | return count; | ||
571 | } | ||
572 | |||
573 | static ssize_t set_temp_hyst(struct device *dev, struct device_attribute | ||
574 | *devattr, const char *buf, size_t count) | ||
575 | { | ||
576 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
577 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
578 | int nr = attr->index; | ||
579 | long val = simple_strtol(buf, NULL, 10); | ||
580 | |||
581 | down(&data->update_lock); | ||
582 | data->temp_hyst[nr] = temp_to_reg(val); | ||
583 | f71805f_write8(data, F71805F_REG_TEMP_HYST(nr), data->temp_hyst[nr]); | ||
584 | up(&data->update_lock); | ||
585 | |||
586 | return count; | ||
587 | } | ||
588 | |||
589 | #define sysfs_temp(offset) \ | ||
590 | static SENSOR_DEVICE_ATTR(temp##offset##_input, S_IRUGO, \ | ||
591 | show_temp, NULL, offset - 1); \ | ||
592 | static SENSOR_DEVICE_ATTR(temp##offset##_max, S_IRUGO | S_IWUSR, \ | ||
593 | show_temp_max, set_temp_max, offset - 1); \ | ||
594 | static SENSOR_DEVICE_ATTR(temp##offset##_max_hyst, S_IRUGO | S_IWUSR, \ | ||
595 | show_temp_hyst, set_temp_hyst, offset - 1); \ | ||
596 | static SENSOR_DEVICE_ATTR(temp##offset##_type, S_IRUGO, \ | ||
597 | show_temp_type, NULL, offset - 1) | ||
598 | |||
599 | sysfs_temp(1); | ||
600 | sysfs_temp(2); | ||
601 | sysfs_temp(3); | ||
602 | |||
603 | static ssize_t show_alarms_in(struct device *dev, struct device_attribute | ||
604 | *devattr, char *buf) | ||
605 | { | ||
606 | struct f71805f_data *data = f71805f_update_device(dev); | ||
607 | |||
608 | return sprintf(buf, "%d\n", data->alarms[0] | | ||
609 | ((data->alarms[1] & 0x01) << 8)); | ||
610 | } | ||
611 | |||
612 | static ssize_t show_alarms_fan(struct device *dev, struct device_attribute | ||
613 | *devattr, char *buf) | ||
614 | { | ||
615 | struct f71805f_data *data = f71805f_update_device(dev); | ||
616 | |||
617 | return sprintf(buf, "%d\n", data->alarms[2] & 0x07); | ||
618 | } | ||
619 | |||
620 | static ssize_t show_alarms_temp(struct device *dev, struct device_attribute | ||
621 | *devattr, char *buf) | ||
622 | { | ||
623 | struct f71805f_data *data = f71805f_update_device(dev); | ||
624 | |||
625 | return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07); | ||
626 | } | ||
627 | |||
628 | static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL); | ||
629 | static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL); | ||
630 | static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL); | ||
631 | |||
632 | static ssize_t show_name(struct device *dev, struct device_attribute | ||
633 | *devattr, char *buf) | ||
634 | { | ||
635 | struct f71805f_data *data = dev_get_drvdata(dev); | ||
636 | |||
637 | return sprintf(buf, "%s\n", data->name); | ||
638 | } | ||
639 | |||
640 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
641 | |||
642 | /* | ||
643 | * Device registration and initialization | ||
644 | */ | ||
645 | |||
646 | static void __devinit f71805f_init_device(struct f71805f_data *data) | ||
647 | { | ||
648 | u8 reg; | ||
649 | int i; | ||
650 | |||
651 | reg = f71805f_read8(data, F71805F_REG_START); | ||
652 | if ((reg & 0x41) != 0x01) { | ||
653 | printk(KERN_DEBUG DRVNAME ": Starting monitoring " | ||
654 | "operations\n"); | ||
655 | f71805f_write8(data, F71805F_REG_START, (reg | 0x01) & ~0x40); | ||
656 | } | ||
657 | |||
658 | /* Fan monitoring can be disabled. If it is, we won't be polling | ||
659 | the register values, and won't create the related sysfs files. */ | ||
660 | for (i = 0; i < 3; i++) { | ||
661 | reg = f71805f_read8(data, F71805F_REG_FAN_CTRL(i)); | ||
662 | if (!(reg & 0x80)) | ||
663 | data->fan_enabled |= (1 << i); | ||
664 | } | ||
665 | } | ||
666 | |||
667 | static int __devinit f71805f_probe(struct platform_device *pdev) | ||
668 | { | ||
669 | struct f71805f_data *data; | ||
670 | struct resource *res; | ||
671 | int err; | ||
672 | |||
673 | if (!(data = kzalloc(sizeof(struct f71805f_data), GFP_KERNEL))) { | ||
674 | err = -ENOMEM; | ||
675 | printk(KERN_ERR DRVNAME ": Out of memory\n"); | ||
676 | goto exit; | ||
677 | } | ||
678 | |||
679 | res = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
680 | data->addr = res->start; | ||
681 | init_MUTEX(&data->lock); | ||
682 | data->name = "f71805f"; | ||
683 | init_MUTEX(&data->update_lock); | ||
684 | |||
685 | platform_set_drvdata(pdev, data); | ||
686 | |||
687 | data->class_dev = hwmon_device_register(&pdev->dev); | ||
688 | if (IS_ERR(data->class_dev)) { | ||
689 | err = PTR_ERR(data->class_dev); | ||
690 | dev_err(&pdev->dev, "Class registration failed (%d)\n", err); | ||
691 | goto exit_free; | ||
692 | } | ||
693 | |||
694 | /* Initialize the F71805F chip */ | ||
695 | f71805f_init_device(data); | ||
696 | |||
697 | /* Register sysfs interface files */ | ||
698 | device_create_file(&pdev->dev, &dev_attr_in0_input); | ||
699 | device_create_file(&pdev->dev, &dev_attr_in0_max); | ||
700 | device_create_file(&pdev->dev, &dev_attr_in0_min); | ||
701 | device_create_file(&pdev->dev, &sensor_dev_attr_in1_input.dev_attr); | ||
702 | device_create_file(&pdev->dev, &sensor_dev_attr_in2_input.dev_attr); | ||
703 | device_create_file(&pdev->dev, &sensor_dev_attr_in3_input.dev_attr); | ||
704 | device_create_file(&pdev->dev, &sensor_dev_attr_in4_input.dev_attr); | ||
705 | device_create_file(&pdev->dev, &sensor_dev_attr_in5_input.dev_attr); | ||
706 | device_create_file(&pdev->dev, &sensor_dev_attr_in6_input.dev_attr); | ||
707 | device_create_file(&pdev->dev, &sensor_dev_attr_in7_input.dev_attr); | ||
708 | device_create_file(&pdev->dev, &sensor_dev_attr_in8_input.dev_attr); | ||
709 | device_create_file(&pdev->dev, &sensor_dev_attr_in1_max.dev_attr); | ||
710 | device_create_file(&pdev->dev, &sensor_dev_attr_in2_max.dev_attr); | ||
711 | device_create_file(&pdev->dev, &sensor_dev_attr_in3_max.dev_attr); | ||
712 | device_create_file(&pdev->dev, &sensor_dev_attr_in4_max.dev_attr); | ||
713 | device_create_file(&pdev->dev, &sensor_dev_attr_in5_max.dev_attr); | ||
714 | device_create_file(&pdev->dev, &sensor_dev_attr_in6_max.dev_attr); | ||
715 | device_create_file(&pdev->dev, &sensor_dev_attr_in7_max.dev_attr); | ||
716 | device_create_file(&pdev->dev, &sensor_dev_attr_in8_max.dev_attr); | ||
717 | device_create_file(&pdev->dev, &sensor_dev_attr_in1_min.dev_attr); | ||
718 | device_create_file(&pdev->dev, &sensor_dev_attr_in2_min.dev_attr); | ||
719 | device_create_file(&pdev->dev, &sensor_dev_attr_in3_min.dev_attr); | ||
720 | device_create_file(&pdev->dev, &sensor_dev_attr_in4_min.dev_attr); | ||
721 | device_create_file(&pdev->dev, &sensor_dev_attr_in5_min.dev_attr); | ||
722 | device_create_file(&pdev->dev, &sensor_dev_attr_in6_min.dev_attr); | ||
723 | device_create_file(&pdev->dev, &sensor_dev_attr_in7_min.dev_attr); | ||
724 | device_create_file(&pdev->dev, &sensor_dev_attr_in8_min.dev_attr); | ||
725 | if (data->fan_enabled & (1 << 0)) { | ||
726 | device_create_file(&pdev->dev, | ||
727 | &sensor_dev_attr_fan1_input.dev_attr); | ||
728 | device_create_file(&pdev->dev, | ||
729 | &sensor_dev_attr_fan1_min.dev_attr); | ||
730 | } | ||
731 | if (data->fan_enabled & (1 << 1)) { | ||
732 | device_create_file(&pdev->dev, | ||
733 | &sensor_dev_attr_fan2_input.dev_attr); | ||
734 | device_create_file(&pdev->dev, | ||
735 | &sensor_dev_attr_fan2_min.dev_attr); | ||
736 | } | ||
737 | if (data->fan_enabled & (1 << 2)) { | ||
738 | device_create_file(&pdev->dev, | ||
739 | &sensor_dev_attr_fan3_input.dev_attr); | ||
740 | device_create_file(&pdev->dev, | ||
741 | &sensor_dev_attr_fan3_min.dev_attr); | ||
742 | } | ||
743 | device_create_file(&pdev->dev, | ||
744 | &sensor_dev_attr_temp1_input.dev_attr); | ||
745 | device_create_file(&pdev->dev, | ||
746 | &sensor_dev_attr_temp2_input.dev_attr); | ||
747 | device_create_file(&pdev->dev, | ||
748 | &sensor_dev_attr_temp3_input.dev_attr); | ||
749 | device_create_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr); | ||
750 | device_create_file(&pdev->dev, &sensor_dev_attr_temp2_max.dev_attr); | ||
751 | device_create_file(&pdev->dev, &sensor_dev_attr_temp3_max.dev_attr); | ||
752 | device_create_file(&pdev->dev, | ||
753 | &sensor_dev_attr_temp1_max_hyst.dev_attr); | ||
754 | device_create_file(&pdev->dev, | ||
755 | &sensor_dev_attr_temp2_max_hyst.dev_attr); | ||
756 | device_create_file(&pdev->dev, | ||
757 | &sensor_dev_attr_temp3_max_hyst.dev_attr); | ||
758 | device_create_file(&pdev->dev, &sensor_dev_attr_temp1_type.dev_attr); | ||
759 | device_create_file(&pdev->dev, &sensor_dev_attr_temp2_type.dev_attr); | ||
760 | device_create_file(&pdev->dev, &sensor_dev_attr_temp3_type.dev_attr); | ||
761 | device_create_file(&pdev->dev, &dev_attr_alarms_in); | ||
762 | device_create_file(&pdev->dev, &dev_attr_alarms_fan); | ||
763 | device_create_file(&pdev->dev, &dev_attr_alarms_temp); | ||
764 | device_create_file(&pdev->dev, &dev_attr_name); | ||
765 | |||
766 | return 0; | ||
767 | |||
768 | exit_free: | ||
769 | kfree(data); | ||
770 | exit: | ||
771 | return err; | ||
772 | } | ||
773 | |||
774 | static int __devexit f71805f_remove(struct platform_device *pdev) | ||
775 | { | ||
776 | struct f71805f_data *data = platform_get_drvdata(pdev); | ||
777 | |||
778 | platform_set_drvdata(pdev, NULL); | ||
779 | hwmon_device_unregister(data->class_dev); | ||
780 | kfree(data); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | static struct platform_driver f71805f_driver = { | ||
786 | .driver = { | ||
787 | .owner = THIS_MODULE, | ||
788 | .name = DRVNAME, | ||
789 | }, | ||
790 | .probe = f71805f_probe, | ||
791 | .remove = __devexit_p(f71805f_remove), | ||
792 | }; | ||
793 | |||
794 | static int __init f71805f_device_add(unsigned short address) | ||
795 | { | ||
796 | int err; | ||
797 | |||
798 | pdev = platform_device_alloc(DRVNAME, address); | ||
799 | if (!pdev) { | ||
800 | err = -ENOMEM; | ||
801 | printk(KERN_ERR DRVNAME ": Device allocation failed\n"); | ||
802 | goto exit; | ||
803 | } | ||
804 | |||
805 | f71805f_resource.start = address; | ||
806 | f71805f_resource.end = address + REGION_LENGTH - 1; | ||
807 | f71805f_resource.name = pdev->name; | ||
808 | err = platform_device_add_resources(pdev, &f71805f_resource, 1); | ||
809 | if (err) { | ||
810 | printk(KERN_ERR DRVNAME ": Device resource addition failed " | ||
811 | "(%d)\n", err); | ||
812 | goto exit_device_put; | ||
813 | } | ||
814 | |||
815 | err = platform_device_add(pdev); | ||
816 | if (err) { | ||
817 | printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n", | ||
818 | err); | ||
819 | goto exit_device_put; | ||
820 | } | ||
821 | |||
822 | return 0; | ||
823 | |||
824 | exit_device_put: | ||
825 | platform_device_put(pdev); | ||
826 | exit: | ||
827 | return err; | ||
828 | } | ||
829 | |||
830 | static int __init f71805f_find(int sioaddr, unsigned short *address) | ||
831 | { | ||
832 | int err = -ENODEV; | ||
833 | u16 devid; | ||
834 | |||
835 | superio_enter(sioaddr); | ||
836 | |||
837 | devid = superio_inw(sioaddr, SIO_REG_MANID); | ||
838 | if (devid != SIO_FINTEK_ID) | ||
839 | goto exit; | ||
840 | |||
841 | devid = superio_inw(sioaddr, SIO_REG_DEVID); | ||
842 | if (devid != SIO_F71805F_ID) { | ||
843 | printk(KERN_INFO DRVNAME ": Unsupported Fintek device, " | ||
844 | "skipping\n"); | ||
845 | goto exit; | ||
846 | } | ||
847 | |||
848 | superio_select(sioaddr, F71805F_LD_HWM); | ||
849 | if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { | ||
850 | printk(KERN_WARNING DRVNAME ": Device not activated, " | ||
851 | "skipping\n"); | ||
852 | goto exit; | ||
853 | } | ||
854 | |||
855 | *address = superio_inw(sioaddr, SIO_REG_ADDR); | ||
856 | if (*address == 0) { | ||
857 | printk(KERN_WARNING DRVNAME ": Base address not set, " | ||
858 | "skipping\n"); | ||
859 | goto exit; | ||
860 | } | ||
861 | |||
862 | err = 0; | ||
863 | printk(KERN_INFO DRVNAME ": Found F71805F chip at %#x, revision %u\n", | ||
864 | *address, superio_inb(sioaddr, SIO_REG_DEVREV)); | ||
865 | |||
866 | exit: | ||
867 | superio_exit(sioaddr); | ||
868 | return err; | ||
869 | } | ||
870 | |||
871 | static int __init f71805f_init(void) | ||
872 | { | ||
873 | int err; | ||
874 | unsigned short address; | ||
875 | |||
876 | if (f71805f_find(0x2e, &address) | ||
877 | && f71805f_find(0x4e, &address)) | ||
878 | return -ENODEV; | ||
879 | |||
880 | err = platform_driver_register(&f71805f_driver); | ||
881 | if (err) | ||
882 | goto exit; | ||
883 | |||
884 | /* Sets global pdev as a side effect */ | ||
885 | err = f71805f_device_add(address); | ||
886 | if (err) | ||
887 | goto exit_driver; | ||
888 | |||
889 | return 0; | ||
890 | |||
891 | exit_driver: | ||
892 | platform_driver_unregister(&f71805f_driver); | ||
893 | exit: | ||
894 | return err; | ||
895 | } | ||
896 | |||
897 | static void __exit f71805f_exit(void) | ||
898 | { | ||
899 | platform_device_unregister(pdev); | ||
900 | platform_driver_unregister(&f71805f_driver); | ||
901 | } | ||
902 | |||
903 | MODULE_AUTHOR("Jean Delvare <khali@linux-fr>"); | ||
904 | MODULE_LICENSE("GPL"); | ||
905 | MODULE_DESCRIPTION("F71805F hardware monitoring driver"); | ||
906 | |||
907 | module_init(f71805f_init); | ||
908 | module_exit(f71805f_exit); | ||
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c index 0da7c9c508c3..e87d52c59940 100644 --- a/drivers/hwmon/it87.c +++ b/drivers/hwmon/it87.c | |||
@@ -45,8 +45,7 @@ | |||
45 | 45 | ||
46 | 46 | ||
47 | /* Addresses to scan */ | 47 | /* Addresses to scan */ |
48 | static unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, | 48 | static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END }; |
49 | 0x2e, 0x2f, I2C_CLIENT_END }; | ||
50 | static unsigned short isa_address; | 49 | static unsigned short isa_address; |
51 | 50 | ||
52 | /* Insmod parameters */ | 51 | /* Insmod parameters */ |
@@ -830,6 +829,11 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind) | |||
830 | if ((err = i2c_attach_client(new_client))) | 829 | if ((err = i2c_attach_client(new_client))) |
831 | goto ERROR2; | 830 | goto ERROR2; |
832 | 831 | ||
832 | if (!is_isa) | ||
833 | dev_info(&new_client->dev, "The I2C interface to IT87xxF " | ||
834 | "hardware monitoring chips is deprecated. Please " | ||
835 | "report if you still rely on it.\n"); | ||
836 | |||
833 | /* Check PWM configuration */ | 837 | /* Check PWM configuration */ |
834 | enable_pwm_interface = it87_check_pwm(new_client); | 838 | enable_pwm_interface = it87_check_pwm(new_client); |
835 | 839 | ||
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c index a2f420d01fb7..df9e02aaa70a 100644 --- a/drivers/hwmon/lm77.c +++ b/drivers/hwmon/lm77.c | |||
@@ -87,15 +87,15 @@ static struct i2c_driver lm77_driver = { | |||
87 | 87 | ||
88 | /* In the temperature registers, the low 3 bits are not part of the | 88 | /* In the temperature registers, the low 3 bits are not part of the |
89 | temperature values; they are the status bits. */ | 89 | temperature values; they are the status bits. */ |
90 | static inline u16 LM77_TEMP_TO_REG(int temp) | 90 | static inline s16 LM77_TEMP_TO_REG(int temp) |
91 | { | 91 | { |
92 | int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); | 92 | int ntemp = SENSORS_LIMIT(temp, LM77_TEMP_MIN, LM77_TEMP_MAX); |
93 | return (u16)((ntemp / 500) * 8); | 93 | return (ntemp / 500) * 8; |
94 | } | 94 | } |
95 | 95 | ||
96 | static inline int LM77_TEMP_FROM_REG(u16 reg) | 96 | static inline int LM77_TEMP_FROM_REG(s16 reg) |
97 | { | 97 | { |
98 | return ((int)reg / 8) * 500; | 98 | return (reg / 8) * 500; |
99 | } | 99 | } |
100 | 100 | ||
101 | /* sysfs stuff */ | 101 | /* sysfs stuff */ |
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c index b176bf0c4c7b..a2f6bb676235 100644 --- a/drivers/hwmon/w83792d.c +++ b/drivers/hwmon/w83792d.c | |||
@@ -303,10 +303,6 @@ struct w83792d_data { | |||
303 | static int w83792d_attach_adapter(struct i2c_adapter *adapter); | 303 | static int w83792d_attach_adapter(struct i2c_adapter *adapter); |
304 | static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind); | 304 | static int w83792d_detect(struct i2c_adapter *adapter, int address, int kind); |
305 | static int w83792d_detach_client(struct i2c_client *client); | 305 | static int w83792d_detach_client(struct i2c_client *client); |
306 | |||
307 | static int w83792d_read_value(struct i2c_client *client, u8 register); | ||
308 | static int w83792d_write_value(struct i2c_client *client, u8 register, | ||
309 | u8 value); | ||
310 | static struct w83792d_data *w83792d_update_device(struct device *dev); | 306 | static struct w83792d_data *w83792d_update_device(struct device *dev); |
311 | 307 | ||
312 | #ifdef DEBUG | 308 | #ifdef DEBUG |
@@ -329,6 +325,20 @@ static inline long in_count_from_reg(int nr, struct w83792d_data *data) | |||
329 | return ((data->in[nr] << 2) | ((data->low_bits >> (2 * nr)) & 0x03)); | 325 | return ((data->in[nr] << 2) | ((data->low_bits >> (2 * nr)) & 0x03)); |
330 | } | 326 | } |
331 | 327 | ||
328 | /* The SMBus locks itself. The Winbond W83792D chip has a bank register, | ||
329 | but the driver only accesses registers in bank 0, so we don't have | ||
330 | to switch banks and lock access between switches. */ | ||
331 | static inline int w83792d_read_value(struct i2c_client *client, u8 reg) | ||
332 | { | ||
333 | return i2c_smbus_read_byte_data(client, reg); | ||
334 | } | ||
335 | |||
336 | static inline int | ||
337 | w83792d_write_value(struct i2c_client *client, u8 reg, u8 value) | ||
338 | { | ||
339 | return i2c_smbus_write_byte_data(client, reg, value); | ||
340 | } | ||
341 | |||
332 | /* following are the sysfs callback functions */ | 342 | /* following are the sysfs callback functions */ |
333 | static ssize_t show_in(struct device *dev, struct device_attribute *attr, | 343 | static ssize_t show_in(struct device *dev, struct device_attribute *attr, |
334 | char *buf) | 344 | char *buf) |
@@ -1386,19 +1396,6 @@ w83792d_detach_client(struct i2c_client *client) | |||
1386 | return 0; | 1396 | return 0; |
1387 | } | 1397 | } |
1388 | 1398 | ||
1389 | /* The SMBus locks itself. The Winbond W83792D chip has a bank register, | ||
1390 | but the driver only accesses registers in bank 0, so we don't have | ||
1391 | to switch banks and lock access between switches. */ | ||
1392 | static int w83792d_read_value(struct i2c_client *client, u8 reg) | ||
1393 | { | ||
1394 | return i2c_smbus_read_byte_data(client, reg); | ||
1395 | } | ||
1396 | |||
1397 | static int w83792d_write_value(struct i2c_client *client, u8 reg, u8 value) | ||
1398 | { | ||
1399 | return i2c_smbus_write_byte_data(client, reg, value); | ||
1400 | } | ||
1401 | |||
1402 | static void | 1399 | static void |
1403 | w83792d_init_client(struct i2c_client *client) | 1400 | w83792d_init_client(struct i2c_client *client) |
1404 | { | 1401 | { |
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c index 938848ae162d..3df3f09995c2 100644 --- a/drivers/i2c/algos/i2c-algo-sibyte.c +++ b/drivers/i2c/algos/i2c-algo-sibyte.c | |||
@@ -202,7 +202,7 @@ EXPORT_SYMBOL(i2c_sibyte_del_bus); | |||
202 | #ifdef MODULE | 202 | #ifdef MODULE |
203 | MODULE_AUTHOR("Kip Walker, Broadcom Corp."); | 203 | MODULE_AUTHOR("Kip Walker, Broadcom Corp."); |
204 | MODULE_DESCRIPTION("SiByte I2C-Bus algorithm"); | 204 | MODULE_DESCRIPTION("SiByte I2C-Bus algorithm"); |
205 | MODULE_PARM(bit_scan, "i"); | 205 | module_param(bit_scan, int, 0); |
206 | MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); | 206 | MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus"); |
207 | MODULE_LICENSE("GPL"); | 207 | MODULE_LICENSE("GPL"); |
208 | 208 | ||
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 08d5b8fed2dc..ff92735c7c85 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -124,6 +124,7 @@ config I2C_I801 | |||
124 | ICH6 | 124 | ICH6 |
125 | ICH7 | 125 | ICH7 |
126 | ESB2 | 126 | ESB2 |
127 | ICH8 | ||
127 | 128 | ||
128 | This driver can also be built as a module. If so, the module | 129 | This driver can also be built as a module. If so, the module |
129 | will be called i2c-i801. | 130 | will be called i2c-i801. |
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 1c752ddc10e2..8e0f3158215f 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c | |||
@@ -32,6 +32,7 @@ | |||
32 | ICH6 266A | 32 | ICH6 266A |
33 | ICH7 27DA | 33 | ICH7 27DA |
34 | ESB2 269B | 34 | ESB2 269B |
35 | ICH8 283E | ||
35 | This driver supports several versions of Intel's I/O Controller Hubs (ICH). | 36 | This driver supports several versions of Intel's I/O Controller Hubs (ICH). |
36 | For SMBus support, they are similar to the PIIX4 and are part | 37 | For SMBus support, they are similar to the PIIX4 and are part |
37 | of Intel's '810' and other chipsets. | 38 | of Intel's '810' and other chipsets. |
@@ -527,6 +528,7 @@ static struct pci_device_id i801_ids[] = { | |||
527 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, | 528 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, |
528 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, | 529 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, |
529 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, | 530 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, |
531 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, | ||
530 | { 0, } | 532 | { 0, } |
531 | }; | 533 | }; |
532 | 534 | ||
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c index 3e5eba9fcacb..c63025a4c861 100644 --- a/drivers/i2c/busses/i2c-parport-light.c +++ b/drivers/i2c/busses/i2c-parport-light.c | |||
@@ -121,14 +121,11 @@ static struct i2c_adapter parport_adapter = { | |||
121 | 121 | ||
122 | static int __init i2c_parport_init(void) | 122 | static int __init i2c_parport_init(void) |
123 | { | 123 | { |
124 | int type_count; | 124 | if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { |
125 | |||
126 | type_count = sizeof(adapter_parm)/sizeof(struct adapter_parm); | ||
127 | if (type < 0 || type >= type_count) { | ||
128 | printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); | 125 | printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); |
129 | type = 0; | 126 | type = 0; |
130 | } | 127 | } |
131 | 128 | ||
132 | if (base == 0) { | 129 | if (base == 0) { |
133 | printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE); | 130 | printk(KERN_INFO "i2c-parport: using default base 0x%x\n", DEFAULT_BASE); |
134 | base = DEFAULT_BASE; | 131 | base = DEFAULT_BASE; |
@@ -152,7 +149,7 @@ static int __init i2c_parport_init(void) | |||
152 | release_region(base, 3); | 149 | release_region(base, 3); |
153 | return -ENODEV; | 150 | return -ENODEV; |
154 | } | 151 | } |
155 | 152 | ||
156 | return 0; | 153 | return 0; |
157 | } | 154 | } |
158 | 155 | ||
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 2854d858fc9b..7e2e8cd1c14a 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c | |||
@@ -241,14 +241,11 @@ static struct parport_driver i2c_parport_driver = { | |||
241 | 241 | ||
242 | static int __init i2c_parport_init(void) | 242 | static int __init i2c_parport_init(void) |
243 | { | 243 | { |
244 | int type_count; | 244 | if (type < 0 || type >= ARRAY_SIZE(adapter_parm)) { |
245 | |||
246 | type_count = sizeof(adapter_parm)/sizeof(struct adapter_parm); | ||
247 | if (type < 0 || type >= type_count) { | ||
248 | printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); | 245 | printk(KERN_WARNING "i2c-parport: invalid type (%d)\n", type); |
249 | type = 0; | 246 | type = 0; |
250 | } | 247 | } |
251 | 248 | ||
252 | return parport_register_driver(&i2c_parport_driver); | 249 | return parport_register_driver(&i2c_parport_driver); |
253 | } | 250 | } |
254 | 251 | ||
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 86e2234faf80..7579f4b256a8 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c | |||
@@ -861,7 +861,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *r | |||
861 | decode_ISR(isr); | 861 | decode_ISR(isr); |
862 | } | 862 | } |
863 | 863 | ||
864 | if (i2c->irqlogidx < sizeof(i2c->isrlog)/sizeof(u32)) | 864 | if (i2c->irqlogidx < ARRAY_SIZE(i2c->isrlog)) |
865 | i2c->isrlog[i2c->irqlogidx++] = isr; | 865 | i2c->isrlog[i2c->irqlogidx++] = isr; |
866 | 866 | ||
867 | show_state(i2c); | 867 | show_state(i2c); |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0ce58b506046..1a2c9ab5d9e3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -946,6 +946,20 @@ s32 i2c_smbus_read_i2c_block_data(struct i2c_client *client, u8 command, u8 *val | |||
946 | } | 946 | } |
947 | } | 947 | } |
948 | 948 | ||
949 | s32 i2c_smbus_write_i2c_block_data(struct i2c_client *client, u8 command, | ||
950 | u8 length, u8 *values) | ||
951 | { | ||
952 | union i2c_smbus_data data; | ||
953 | |||
954 | if (length > I2C_SMBUS_BLOCK_MAX) | ||
955 | length = I2C_SMBUS_BLOCK_MAX; | ||
956 | data.block[0] = length; | ||
957 | memcpy(data.block + 1, values, length); | ||
958 | return i2c_smbus_xfer(client->adapter, client->addr, client->flags, | ||
959 | I2C_SMBUS_WRITE, command, | ||
960 | I2C_SMBUS_I2C_BLOCK_DATA, &data); | ||
961 | } | ||
962 | |||
949 | /* Simulate a SMBus command using the i2c protocol | 963 | /* Simulate a SMBus command using the i2c protocol |
950 | No checking of parameters is done! */ | 964 | No checking of parameters is done! */ |
951 | static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, | 965 | static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr, |
@@ -1150,6 +1164,7 @@ EXPORT_SYMBOL(i2c_smbus_read_word_data); | |||
1150 | EXPORT_SYMBOL(i2c_smbus_write_word_data); | 1164 | EXPORT_SYMBOL(i2c_smbus_write_word_data); |
1151 | EXPORT_SYMBOL(i2c_smbus_write_block_data); | 1165 | EXPORT_SYMBOL(i2c_smbus_write_block_data); |
1152 | EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); | 1166 | EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data); |
1167 | EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data); | ||
1153 | 1168 | ||
1154 | MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); | 1169 | MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); |
1155 | MODULE_DESCRIPTION("I2C-Bus main module"); | 1170 | MODULE_DESCRIPTION("I2C-Bus main module"); |
diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 7863a59bd598..63f1d63cc1d8 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h | |||
@@ -100,6 +100,9 @@ extern s32 i2c_smbus_write_block_data(struct i2c_client * client, | |||
100 | /* Returns the number of read bytes */ | 100 | /* Returns the number of read bytes */ |
101 | extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, | 101 | extern s32 i2c_smbus_read_i2c_block_data(struct i2c_client * client, |
102 | u8 command, u8 *values); | 102 | u8 command, u8 *values); |
103 | extern s32 i2c_smbus_write_i2c_block_data(struct i2c_client * client, | ||
104 | u8 command, u8 length, | ||
105 | u8 *values); | ||
103 | 106 | ||
104 | /* | 107 | /* |
105 | * A driver is capable of handling one or more physical devices present on | 108 | * A driver is capable of handling one or more physical devices present on |