diff options
author | Jean Delvare <khali@linux-fr.org> | 2005-09-22 15:58:41 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-10-28 17:02:08 -0400 |
commit | f118301416953d677de738100c33eb8cfb7adecb (patch) | |
tree | 145997f9c2159d1657dcaca8c56ee93341d8b5f9 /drivers/i2c | |
parent | 5f49ef8e8cefe0a95948b4270db28507c1c287d4 (diff) |
[PATCH] i2c-viapro: Implement I2C Block transactions
Implement the I2C block transactions on VIA chips which support them:
VT82C686B, VT8233, VT8233A, VT8235 and VT8237R. This speeds up EEPROM
accesses by a factor 10 or so.
I would like to thank Antonino A. Daplas, Hinko Kocevar, Salah Coronya
and Andreas Henriksson for their help in testing this new feature.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Documentation/i2c/busses/i2c-viapro | 7 +++++-
drivers/i2c/busses/i2c-viapro.c | 39 +++++++++++++++++++++++++++++++++---
2 files changed, 42 insertions(+), 4 deletions(-)
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-viapro.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 262755e1ae02..b420e752b1dc 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c | |||
@@ -4,6 +4,7 @@ | |||
4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, | 4 | Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>, |
5 | Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>, | 5 | Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>, |
6 | Mark D. Studebaker <mdsxyz123@yahoo.com> | 6 | Mark D. Studebaker <mdsxyz123@yahoo.com> |
7 | Copyright (C) 2005 Jean Delvare <khali@linux-fr.org> | ||
7 | 8 | ||
8 | This program is free software; you can redistribute it and/or modify | 9 | This program is free software; you can redistribute it and/or modify |
9 | it under the terms of the GNU General Public License as published by | 10 | it under the terms of the GNU General Public License as published by |
@@ -88,6 +89,7 @@ static unsigned short smb_cf_hstcfg = 0xD2; | |||
88 | #define VT596_BYTE_DATA 0x08 | 89 | #define VT596_BYTE_DATA 0x08 |
89 | #define VT596_WORD_DATA 0x0C | 90 | #define VT596_WORD_DATA 0x0C |
90 | #define VT596_BLOCK_DATA 0x14 | 91 | #define VT596_BLOCK_DATA 0x14 |
92 | #define VT596_I2C_BLOCK_DATA 0x34 | ||
91 | 93 | ||
92 | 94 | ||
93 | /* If force is set to anything different from 0, we forcibly enable the | 95 | /* If force is set to anything different from 0, we forcibly enable the |
@@ -107,6 +109,9 @@ MODULE_PARM_DESC(force_addr, | |||
107 | 109 | ||
108 | static struct i2c_adapter vt596_adapter; | 110 | static struct i2c_adapter vt596_adapter; |
109 | 111 | ||
112 | #define FEATURE_I2CBLOCK (1<<0) | ||
113 | static unsigned int vt596_features; | ||
114 | |||
110 | /* Another internally used function */ | 115 | /* Another internally used function */ |
111 | static int vt596_transaction(void) | 116 | static int vt596_transaction(void) |
112 | { | 117 | { |
@@ -225,6 +230,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, | |||
225 | } | 230 | } |
226 | size = VT596_WORD_DATA; | 231 | size = VT596_WORD_DATA; |
227 | break; | 232 | break; |
233 | case I2C_SMBUS_I2C_BLOCK_DATA: | ||
234 | if (!(vt596_features & FEATURE_I2CBLOCK)) | ||
235 | return -1; | ||
236 | if (read_write == I2C_SMBUS_READ) | ||
237 | outb_p(I2C_SMBUS_BLOCK_MAX, SMBHSTDAT0); | ||
238 | /* Fall through */ | ||
228 | case I2C_SMBUS_BLOCK_DATA: | 239 | case I2C_SMBUS_BLOCK_DATA: |
229 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), | 240 | outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), |
230 | SMBHSTADD); | 241 | SMBHSTADD); |
@@ -240,11 +251,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, | |||
240 | for (i = 1; i <= len; i++) | 251 | for (i = 1; i <= len; i++) |
241 | outb_p(data->block[i], SMBBLKDAT); | 252 | outb_p(data->block[i], SMBBLKDAT); |
242 | } | 253 | } |
243 | size = VT596_BLOCK_DATA; | 254 | size = (size == I2C_SMBUS_I2C_BLOCK_DATA) ? |
255 | VT596_I2C_BLOCK_DATA : VT596_BLOCK_DATA; | ||
244 | break; | 256 | break; |
245 | } | 257 | } |
246 | 258 | ||
247 | outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); | 259 | outb_p((size & 0x3C) + (ENABLE_INT9 & 1), SMBHSTCNT); |
248 | 260 | ||
249 | if (vt596_transaction()) /* Error in transaction */ | 261 | if (vt596_transaction()) /* Error in transaction */ |
250 | return -1; | 262 | return -1; |
@@ -266,6 +278,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, | |||
266 | case VT596_WORD_DATA: | 278 | case VT596_WORD_DATA: |
267 | data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); | 279 | data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); |
268 | break; | 280 | break; |
281 | case VT596_I2C_BLOCK_DATA: | ||
269 | case VT596_BLOCK_DATA: | 282 | case VT596_BLOCK_DATA: |
270 | data->block[0] = inb_p(SMBHSTDAT0); | 283 | data->block[0] = inb_p(SMBHSTDAT0); |
271 | if (data->block[0] > I2C_SMBUS_BLOCK_MAX) | 284 | if (data->block[0] > I2C_SMBUS_BLOCK_MAX) |
@@ -280,9 +293,13 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr, | |||
280 | 293 | ||
281 | static u32 vt596_func(struct i2c_adapter *adapter) | 294 | static u32 vt596_func(struct i2c_adapter *adapter) |
282 | { | 295 | { |
283 | return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | | 296 | u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | |
284 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | | 297 | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | |
285 | I2C_FUNC_SMBUS_BLOCK_DATA; | 298 | I2C_FUNC_SMBUS_BLOCK_DATA; |
299 | |||
300 | if (vt596_features & FEATURE_I2CBLOCK) | ||
301 | func |= I2C_FUNC_SMBUS_I2C_BLOCK; | ||
302 | return func; | ||
286 | } | 303 | } |
287 | 304 | ||
288 | static struct i2c_algorithm smbus_algorithm = { | 305 | static struct i2c_algorithm smbus_algorithm = { |
@@ -379,6 +396,22 @@ found: | |||
379 | dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); | 396 | dev_dbg(&pdev->dev, "SMBREV = 0x%X\n", temp); |
380 | dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); | 397 | dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba); |
381 | 398 | ||
399 | switch (pdev->device) { | ||
400 | case PCI_DEVICE_ID_VIA_8237: | ||
401 | case PCI_DEVICE_ID_VIA_8235: | ||
402 | case PCI_DEVICE_ID_VIA_8233A: | ||
403 | case PCI_DEVICE_ID_VIA_8233_0: | ||
404 | vt596_features |= FEATURE_I2CBLOCK; | ||
405 | break; | ||
406 | case PCI_DEVICE_ID_VIA_82C686_4: | ||
407 | /* The VT82C686B (rev 0x40) does support I2C block | ||
408 | transactions, but the VT82C686A (rev 0x30) doesn't */ | ||
409 | if (!pci_read_config_byte(pdev, PCI_REVISION_ID, &temp) | ||
410 | && temp >= 0x40) | ||
411 | vt596_features |= FEATURE_I2CBLOCK; | ||
412 | break; | ||
413 | } | ||
414 | |||
382 | vt596_adapter.dev.parent = &pdev->dev; | 415 | vt596_adapter.dev.parent = &pdev->dev; |
383 | snprintf(vt596_adapter.name, I2C_NAME_SIZE, | 416 | snprintf(vt596_adapter.name, I2C_NAME_SIZE, |
384 | "SMBus Via Pro adapter at %04x", vt596_smba); | 417 | "SMBus Via Pro adapter at %04x", vt596_smba); |