diff options
Diffstat (limited to 'drivers/i2c/chips/eeprom.c')
-rw-r--r-- | drivers/i2c/chips/eeprom.c | 81 |
1 files changed, 40 insertions, 41 deletions
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c index 7dee001e5133..373ea8d8fe8f 100644 --- a/drivers/i2c/chips/eeprom.c +++ b/drivers/i2c/chips/eeprom.c | |||
@@ -1,15 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | eeprom.c - Part of lm_sensors, Linux kernel modules for hardware | ||
3 | monitoring | ||
4 | Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and | 2 | Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and |
5 | Philip Edelbrock <phil@netroedge.com> | 3 | Philip Edelbrock <phil@netroedge.com> |
6 | Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> | 4 | Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com> |
7 | Copyright (C) 2003 IBM Corp. | 5 | Copyright (C) 2003 IBM Corp. |
8 | 6 | Copyright (C) 2004 Jean Delvare <khali@linux-fr.org> | |
9 | 2004-01-16 Jean Delvare <khali@linux-fr.org> | ||
10 | Divide the eeprom in 32-byte (arbitrary) slices. This significantly | ||
11 | speeds sensors up, as well as various scripts using the eeprom | ||
12 | module. | ||
13 | 7 | ||
14 | This program is free software; you can redistribute it and/or modify | 8 | This program is free software; you can redistribute it and/or modify |
15 | it under the terms of the GNU General Public License as published by | 9 | it under the terms of the GNU General Public License as published by |
@@ -78,7 +72,7 @@ static struct i2c_driver eeprom_driver = { | |||
78 | static void eeprom_update_client(struct i2c_client *client, u8 slice) | 72 | static void eeprom_update_client(struct i2c_client *client, u8 slice) |
79 | { | 73 | { |
80 | struct eeprom_data *data = i2c_get_clientdata(client); | 74 | struct eeprom_data *data = i2c_get_clientdata(client); |
81 | int i, j; | 75 | int i; |
82 | 76 | ||
83 | mutex_lock(&data->update_lock); | 77 | mutex_lock(&data->update_lock); |
84 | 78 | ||
@@ -93,15 +87,12 @@ static void eeprom_update_client(struct i2c_client *client, u8 slice) | |||
93 | != 32) | 87 | != 32) |
94 | goto exit; | 88 | goto exit; |
95 | } else { | 89 | } else { |
96 | if (i2c_smbus_write_byte(client, slice << 5)) { | 90 | for (i = slice << 5; i < (slice + 1) << 5; i += 2) { |
97 | dev_dbg(&client->dev, "eeprom read start has failed!\n"); | 91 | int word = i2c_smbus_read_word_data(client, i); |
98 | goto exit; | 92 | if (word < 0) |
99 | } | ||
100 | for (i = slice << 5; i < (slice + 1) << 5; i++) { | ||
101 | j = i2c_smbus_read_byte(client); | ||
102 | if (j < 0) | ||
103 | goto exit; | 93 | goto exit; |
104 | data->data[i] = (u8) j; | 94 | data->data[i] = word & 0xff; |
95 | data->data[i + 1] = word >> 8; | ||
105 | } | 96 | } |
106 | } | 97 | } |
107 | data->last_updated[slice] = jiffies; | 98 | data->last_updated[slice] = jiffies; |
@@ -159,24 +150,33 @@ static struct bin_attribute eeprom_attr = { | |||
159 | 150 | ||
160 | static int eeprom_attach_adapter(struct i2c_adapter *adapter) | 151 | static int eeprom_attach_adapter(struct i2c_adapter *adapter) |
161 | { | 152 | { |
153 | if (!(adapter->class & (I2C_CLASS_DDC | I2C_CLASS_SPD))) | ||
154 | return 0; | ||
162 | return i2c_probe(adapter, &addr_data, eeprom_detect); | 155 | return i2c_probe(adapter, &addr_data, eeprom_detect); |
163 | } | 156 | } |
164 | 157 | ||
165 | /* This function is called by i2c_probe */ | 158 | /* This function is called by i2c_probe */ |
166 | static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) | 159 | static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) |
167 | { | 160 | { |
168 | struct i2c_client *new_client; | 161 | struct i2c_client *client; |
169 | struct eeprom_data *data; | 162 | struct eeprom_data *data; |
170 | int err = 0; | 163 | int err = 0; |
171 | 164 | ||
172 | /* There are three ways we can read the EEPROM data: | 165 | /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all |
166 | addresses 0x50-0x57, but we only care about 0x50. So decline | ||
167 | attaching to addresses >= 0x51 on DDC buses */ | ||
168 | if (!(adapter->class & I2C_CLASS_SPD) && address >= 0x51) | ||
169 | goto exit; | ||
170 | |||
171 | /* There are four ways we can read the EEPROM data: | ||
173 | (1) I2C block reads (faster, but unsupported by most adapters) | 172 | (1) I2C block reads (faster, but unsupported by most adapters) |
174 | (2) Consecutive byte reads (100% overhead) | 173 | (2) Word reads (128% overhead) |
175 | (3) Regular byte data reads (200% overhead) | 174 | (3) Consecutive byte reads (88% overhead, unsafe) |
176 | The third method is not implemented by this driver because all | 175 | (4) Regular byte data reads (265% overhead) |
177 | known adapters support at least the second. */ | 176 | The third and fourth methods are not implemented by this driver |
178 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA | 177 | because all known adapters support one of the first two. */ |
179 | | I2C_FUNC_SMBUS_BYTE)) | 178 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA) |
179 | && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) | ||
180 | goto exit; | 180 | goto exit; |
181 | 181 | ||
182 | if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { | 182 | if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) { |
@@ -184,50 +184,49 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind) | |||
184 | goto exit; | 184 | goto exit; |
185 | } | 185 | } |
186 | 186 | ||
187 | new_client = &data->client; | 187 | client = &data->client; |
188 | memset(data->data, 0xff, EEPROM_SIZE); | 188 | memset(data->data, 0xff, EEPROM_SIZE); |
189 | i2c_set_clientdata(new_client, data); | 189 | i2c_set_clientdata(client, data); |
190 | new_client->addr = address; | 190 | client->addr = address; |
191 | new_client->adapter = adapter; | 191 | client->adapter = adapter; |
192 | new_client->driver = &eeprom_driver; | 192 | client->driver = &eeprom_driver; |
193 | new_client->flags = 0; | ||
194 | 193 | ||
195 | /* Fill in the remaining client fields */ | 194 | /* Fill in the remaining client fields */ |
196 | strlcpy(new_client->name, "eeprom", I2C_NAME_SIZE); | 195 | strlcpy(client->name, "eeprom", I2C_NAME_SIZE); |
197 | data->valid = 0; | ||
198 | mutex_init(&data->update_lock); | 196 | mutex_init(&data->update_lock); |
199 | data->nature = UNKNOWN; | 197 | data->nature = UNKNOWN; |
200 | 198 | ||
201 | /* Tell the I2C layer a new client has arrived */ | 199 | /* Tell the I2C layer a new client has arrived */ |
202 | if ((err = i2c_attach_client(new_client))) | 200 | if ((err = i2c_attach_client(client))) |
203 | goto exit_kfree; | 201 | goto exit_kfree; |
204 | 202 | ||
205 | /* Detect the Vaio nature of EEPROMs. | 203 | /* Detect the Vaio nature of EEPROMs. |
206 | We use the "PCG-" or "VGN-" prefix as the signature. */ | 204 | We use the "PCG-" or "VGN-" prefix as the signature. */ |
207 | if (address == 0x57) { | 205 | if (address == 0x57 |
206 | && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) { | ||
208 | char name[4]; | 207 | char name[4]; |
209 | 208 | ||
210 | name[0] = i2c_smbus_read_byte_data(new_client, 0x80); | 209 | name[0] = i2c_smbus_read_byte_data(client, 0x80); |
211 | name[1] = i2c_smbus_read_byte(new_client); | 210 | name[1] = i2c_smbus_read_byte_data(client, 0x81); |
212 | name[2] = i2c_smbus_read_byte(new_client); | 211 | name[2] = i2c_smbus_read_byte_data(client, 0x82); |
213 | name[3] = i2c_smbus_read_byte(new_client); | 212 | name[3] = i2c_smbus_read_byte_data(client, 0x83); |
214 | 213 | ||
215 | if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { | 214 | if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) { |
216 | dev_info(&new_client->dev, "Vaio EEPROM detected, " | 215 | dev_info(&client->dev, "Vaio EEPROM detected, " |
217 | "enabling privacy protection\n"); | 216 | "enabling privacy protection\n"); |
218 | data->nature = VAIO; | 217 | data->nature = VAIO; |
219 | } | 218 | } |
220 | } | 219 | } |
221 | 220 | ||
222 | /* create the sysfs eeprom file */ | 221 | /* create the sysfs eeprom file */ |
223 | err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr); | 222 | err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr); |
224 | if (err) | 223 | if (err) |
225 | goto exit_detach; | 224 | goto exit_detach; |
226 | 225 | ||
227 | return 0; | 226 | return 0; |
228 | 227 | ||
229 | exit_detach: | 228 | exit_detach: |
230 | i2c_detach_client(new_client); | 229 | i2c_detach_client(client); |
231 | exit_kfree: | 230 | exit_kfree: |
232 | kfree(data); | 231 | kfree(data); |
233 | exit: | 232 | exit: |