Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
420 | giacomo | 1 | /* |
2 | i2c-sensor.c - Part of lm_sensors, Linux kernel modules for hardware |
||
3 | monitoring |
||
4 | Copyright (c) 1998 - 2001 Frodo Looijaard <frodol@dds.nl> and |
||
5 | Mark D. Studebaker <mdsxyz123@yahoo.com> |
||
6 | |||
7 | This program is free software; you can redistribute it and/or modify |
||
8 | it under the terms of the GNU General Public License as published by |
||
9 | the Free Software Foundation; either version 2 of the License, or |
||
10 | (at your option) any later version. |
||
11 | |||
12 | This program is distributed in the hope that it will be useful, |
||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program; if not, write to the Free Software |
||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
||
20 | */ |
||
21 | |||
22 | /* #define DEBUG 1 */ |
||
23 | |||
24 | #include <linux/module.h> |
||
25 | #include <linux/kernel.h> |
||
26 | #include <linux/slab.h> |
||
27 | #include <linux/ctype.h> |
||
28 | #include <linux/sysctl.h> |
||
29 | #include <linux/init.h> |
||
30 | #include <linux/ioport.h> |
||
31 | #include <linux/i2c.h> |
||
32 | #include <linux/i2c-sensor.h> |
||
33 | #include <asm/uaccess.h> |
||
34 | |||
35 | |||
36 | /* Very inefficient for ISA detects, and won't work for 10-bit addresses! */ |
||
37 | int i2c_detect(struct i2c_adapter *adapter, |
||
38 | struct i2c_address_data *address_data, |
||
39 | int (*found_proc) (struct i2c_adapter *, int, int)) |
||
40 | { |
||
41 | int addr, i, found, j, err; |
||
42 | struct i2c_force_data *this_force; |
||
43 | int is_isa = i2c_is_isa_adapter(adapter); |
||
44 | int adapter_id = |
||
45 | is_isa ? ANY_I2C_ISA_BUS : i2c_adapter_id(adapter); |
||
46 | |||
47 | /* Forget it if we can't probe using SMBUS_QUICK */ |
||
48 | if ((!is_isa) && |
||
49 | !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_QUICK)) |
||
50 | return -1; |
||
51 | |||
52 | for (addr = 0x00; addr <= (is_isa ? 0xffff : 0x7f); addr++) { |
||
53 | if (!is_isa && i2c_check_addr(adapter, addr)) |
||
54 | continue; |
||
55 | |||
56 | /* If it is in one of the force entries, we don't do any |
||
57 | detection at all */ |
||
58 | found = 0; |
||
59 | for (i = 0; !found && (this_force = address_data->forces + i, this_force->force); i++) { |
||
60 | for (j = 0; !found && (this_force->force[j] != I2C_CLIENT_END); j += 2) { |
||
61 | if ( ((adapter_id == this_force->force[j]) || |
||
62 | ((this_force->force[j] == ANY_I2C_BUS) && !is_isa)) && |
||
63 | (addr == this_force->force[j + 1]) ) { |
||
64 | dev_dbg(&adapter->dev, "found force parameter for adapter %d, addr %04x\n", adapter_id, addr); |
||
65 | if ((err = found_proc(adapter, addr, this_force->kind))) |
||
66 | return err; |
||
67 | found = 1; |
||
68 | } |
||
69 | } |
||
70 | } |
||
71 | if (found) |
||
72 | continue; |
||
73 | |||
74 | /* If this address is in one of the ignores, we can forget about it |
||
75 | right now */ |
||
76 | for (i = 0; !found && (address_data->ignore[i] != I2C_CLIENT_END); i += 2) { |
||
77 | if ( ((adapter_id == address_data->ignore[i]) || |
||
78 | ((address_data->ignore[i] == ANY_I2C_BUS) && |
||
79 | !is_isa)) && |
||
80 | (addr == address_data->ignore[i + 1])) { |
||
81 | dev_dbg(&adapter->dev, "found ignore parameter for adapter %d, addr %04x\n", adapter_id, addr); |
||
82 | found = 1; |
||
83 | } |
||
84 | } |
||
85 | for (i = 0; !found && (address_data->ignore_range[i] != I2C_CLIENT_END); i += 3) { |
||
86 | if ( ((adapter_id == address_data->ignore_range[i]) || |
||
87 | ((address_data-> ignore_range[i] == ANY_I2C_BUS) & |
||
88 | !is_isa)) && |
||
89 | (addr >= address_data->ignore_range[i + 1]) && |
||
90 | (addr <= address_data->ignore_range[i + 2])) { |
||
91 | dev_dbg(&adapter->dev, "found ignore_range parameter for adapter %d, addr %04x\n", adapter_id, addr); |
||
92 | found = 1; |
||
93 | } |
||
94 | } |
||
95 | if (found) |
||
96 | continue; |
||
97 | |||
98 | /* Now, we will do a detection, but only if it is in the normal or |
||
99 | probe entries */ |
||
100 | if (is_isa) { |
||
101 | for (i = 0; !found && (address_data->normal_isa[i] != I2C_CLIENT_ISA_END); i += 1) { |
||
102 | if (addr == address_data->normal_isa[i]) { |
||
103 | dev_dbg(&adapter->dev, "found normal isa entry for adapter %d, addr %04x\n", adapter_id, addr); |
||
104 | found = 1; |
||
105 | } |
||
106 | } |
||
107 | for (i = 0; !found && (address_data->normal_isa_range[i] != I2C_CLIENT_ISA_END); i += 3) { |
||
108 | if ((addr >= address_data->normal_isa_range[i]) && |
||
109 | (addr <= address_data->normal_isa_range[i + 1]) && |
||
110 | ((addr - address_data->normal_isa_range[i]) % address_data->normal_isa_range[i + 2] == 0)) { |
||
111 | dev_dbg(&adapter->dev, "found normal isa_range entry for adapter %d, addr %04x", adapter_id, addr); |
||
112 | found = 1; |
||
113 | } |
||
114 | } |
||
115 | } else { |
||
116 | for (i = 0; !found && (address_data->normal_i2c[i] != I2C_CLIENT_END); i += 1) { |
||
117 | if (addr == address_data->normal_i2c[i]) { |
||
118 | found = 1; |
||
119 | dev_dbg(&adapter->dev, "found normal i2c entry for adapter %d, addr %02x", adapter_id, addr); |
||
120 | } |
||
121 | } |
||
122 | for (i = 0; !found && (address_data->normal_i2c_range[i] != I2C_CLIENT_END); i += 2) { |
||
123 | if ((addr >= address_data->normal_i2c_range[i]) && |
||
124 | (addr <= address_data->normal_i2c_range[i + 1])) { |
||
125 | dev_dbg(&adapter->dev, "found normal i2c_range entry for adapter %d, addr %04x\n", adapter_id, addr); |
||
126 | found = 1; |
||
127 | } |
||
128 | } |
||
129 | } |
||
130 | |||
131 | for (i = 0; |
||
132 | !found && (address_data->probe[i] != I2C_CLIENT_END); |
||
133 | i += 2) { |
||
134 | if (((adapter_id == address_data->probe[i]) || |
||
135 | ((address_data-> |
||
136 | probe[i] == ANY_I2C_BUS) && !is_isa)) |
||
137 | && (addr == address_data->probe[i + 1])) { |
||
138 | dev_dbg(&adapter->dev, "found probe parameter for adapter %d, addr %04x\n", adapter_id, addr); |
||
139 | found = 1; |
||
140 | } |
||
141 | } |
||
142 | for (i = 0; !found && (address_data->probe_range[i] != I2C_CLIENT_END); i += 3) { |
||
143 | if ( ((adapter_id == address_data->probe_range[i]) || |
||
144 | ((address_data->probe_range[i] == ANY_I2C_BUS) && !is_isa)) && |
||
145 | (addr >= address_data->probe_range[i + 1]) && |
||
146 | (addr <= address_data->probe_range[i + 2])) { |
||
147 | found = 1; |
||
148 | dev_dbg(&adapter->dev, "found probe_range parameter for adapter %d, addr %04x\n", adapter_id, addr); |
||
149 | } |
||
150 | } |
||
151 | if (!found) |
||
152 | continue; |
||
153 | |||
154 | /* OK, so we really should examine this address. First check |
||
155 | whether there is some client here at all! */ |
||
156 | if (is_isa || |
||
157 | (i2c_smbus_xfer (adapter, addr, 0, 0, 0, I2C_SMBUS_QUICK, NULL) >= 0)) |
||
158 | if ((err = found_proc(adapter, addr, -1))) |
||
159 | return err; |
||
160 | } |
||
161 | return 0; |
||
162 | } |
||
163 | |||
164 | EXPORT_SYMBOL(i2c_detect); |
||
165 | |||
166 | MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"); |
||
167 | MODULE_DESCRIPTION("i2c-sensor driver"); |
||
168 | MODULE_LICENSE("GPL"); |