aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorAmaury Decrême <amaury.decreme@gmail.com>2013-01-28 16:21:05 -0500
committerWolfram Sang <wolfram@the-dreams.de>2013-02-11 09:59:38 -0500
commit974d6a3797001c88e59ccb78567c6d71ac526c43 (patch)
tree5a0a99f5526f12f5b6e0db1803f2abbd4e43dae8 /drivers/i2c
parentb08369a174a183e88baa98ab5e3566a617a3a7f8 (diff)
i2c: sis630: Add SIS964 support
Signed-off-by: Amaury Decrême <amaury.decreme@gmail.com> Reviewed-by: Jean Delvare <khali@linux-fr.org> Signed-off-by: Wolfram Sang <wolfram@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig4
-rw-r--r--drivers/i2c/busses/i2c-sis630.c88
2 files changed, 60 insertions, 32 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 87df863ba110..74e18bc0bf62 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -197,11 +197,11 @@ config I2C_SIS5595
197 will be called i2c-sis5595. 197 will be called i2c-sis5595.
198 198
199config I2C_SIS630 199config I2C_SIS630
200 tristate "SiS 630/730" 200 tristate "SiS 630/730/964"
201 depends on PCI 201 depends on PCI
202 help 202 help
203 If you say yes to this option, support will be included for the 203 If you say yes to this option, support will be included for the
204 SiS630 and SiS730 SMBus (a subset of I2C) interface. 204 SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface.
205 205
206 This driver can also be built as a module. If so, the module 206 This driver can also be built as a module. If so, the module
207 will be called i2c-sis630. 207 will be called i2c-sis630.
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index de6dddb9f865..df8e20ab3a09 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -41,6 +41,20 @@
41 Supports: 41 Supports:
42 SIS 630 42 SIS 630
43 SIS 730 43 SIS 730
44 SIS 964
45
46 Notable differences between chips:
47 +------------------------+--------------------+-------------------+
48 | | SIS630/730 | SIS964 |
49 +------------------------+--------------------+-------------------+
50 | Clock | 14kHz/56kHz | 55.56kHz/27.78kHz |
51 | SMBus registers offset | 0x80 | 0xE0 |
52 | SMB_CNT | Bit 1 = Slave Busy | Bit 1 = Bus probe |
53 | (not used yet) | Bit 3 is reserved | Bit 3 = Last byte |
54 | SMB_PCOUNT | Offset + 0x06 | Offset + 0x14 |
55 | SMB_COUNT | 4:0 bits | 5:0 bits |
56 +------------------------+--------------------+-------------------+
57 (Other differences don't affect the functions provided by the driver)
44 58
45 Note: we assume there can only be one device, with one SMBus interface. 59 Note: we assume there can only be one device, with one SMBus interface.
46*/ 60*/
@@ -55,22 +69,21 @@
55#include <linux/acpi.h> 69#include <linux/acpi.h>
56#include <linux/io.h> 70#include <linux/io.h>
57 71
58/* SIS630 SMBus registers */ 72/* SIS964 id is defined here as we are the only file using it */
59#define SMB_STS 0x80 /* status */ 73#define PCI_DEVICE_ID_SI_964 0x0964
60#define SMB_EN 0x81 /* status enable */ 74
61#define SMB_CNT 0x82 75/* SIS630/730/964 SMBus registers */
62#define SMBHOST_CNT 0x83 76#define SMB_STS 0x00 /* status */
63#define SMB_ADDR 0x84 77#define SMB_CNT 0x02 /* control */
64#define SMB_CMD 0x85 78#define SMBHOST_CNT 0x03 /* host control */
65#define SMB_PCOUNT 0x86 /* processed count */ 79#define SMB_ADDR 0x04 /* address */
66#define SMB_COUNT 0x87 80#define SMB_CMD 0x05 /* command */
67#define SMB_BYTE 0x88 /* ~0x8F data byte field */ 81#define SMB_COUNT 0x07 /* byte count */
68#define SMBDEV_ADDR 0x90 82#define SMB_BYTE 0x08 /* ~0x8F data byte field */
69#define SMB_DB0 0x91 83
70#define SMB_DB1 0x92 84/* register count for request_region
71#define SMB_SAA 0x93 85 * As we don't use SMB_PCOUNT, 20 is ok for SiS630 and SiS964
72 86 */
73/* register count for request_region */
74#define SIS630_SMB_IOREGION 20 87#define SIS630_SMB_IOREGION 20
75 88
76/* PCI address constants */ 89/* PCI address constants */
@@ -96,28 +109,30 @@ static struct pci_driver sis630_driver;
96static bool high_clock; 109static bool high_clock;
97static bool force; 110static bool force;
98module_param(high_clock, bool, 0); 111module_param(high_clock, bool, 0);
99MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); 112MODULE_PARM_DESC(high_clock,
113 "Set Host Master Clock to 56KHz (default 14KHz) (SIS630/730 only).");
100module_param(force, bool, 0); 114module_param(force, bool, 0);
101MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); 115MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
102 116
103/* acpi base address */ 117/* SMBus base adress */
104static unsigned short acpi_base; 118static unsigned short smbus_base;
105 119
106/* supported chips */ 120/* supported chips */
107static int supported[] = { 121static int supported[] = {
108 PCI_DEVICE_ID_SI_630, 122 PCI_DEVICE_ID_SI_630,
109 PCI_DEVICE_ID_SI_730, 123 PCI_DEVICE_ID_SI_730,
124 PCI_DEVICE_ID_SI_760,
110 0 /* terminates the list */ 125 0 /* terminates the list */
111}; 126};
112 127
113static inline u8 sis630_read(u8 reg) 128static inline u8 sis630_read(u8 reg)
114{ 129{
115 return inb(acpi_base + reg); 130 return inb(smbus_base + reg);
116} 131}
117 132
118static inline void sis630_write(u8 reg, u8 data) 133static inline void sis630_write(u8 reg, u8 data)
119{ 134{
120 outb(data, acpi_base + reg); 135 outb(data, smbus_base + reg);
121} 136}
122 137
123static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock) 138static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock)
@@ -394,6 +409,8 @@ static int sis630_setup(struct pci_dev *sis630_dev)
394 unsigned char b; 409 unsigned char b;
395 struct pci_dev *dummy = NULL; 410 struct pci_dev *dummy = NULL;
396 int retval, i; 411 int retval, i;
412 /* acpi base address */
413 unsigned short acpi_base;
397 414
398 /* check for supported SiS devices */ 415 /* check for supported SiS devices */
399 for (i=0; supported[i] > 0 ; i++) { 416 for (i=0; supported[i] > 0 ; i++) {
@@ -438,16 +455,25 @@ static int sis630_setup(struct pci_dev *sis630_dev)
438 455
439 dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base); 456 dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);
440 457
441 retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, 458 if (supported[i] == PCI_DEVICE_ID_SI_760)
459 smbus_base = acpi_base + 0xE0;
460 else
461 smbus_base = acpi_base + 0x80;
462
463 dev_dbg(&sis630_dev->dev, "SMBus base at 0x%04hx\n", smbus_base);
464
465 retval = acpi_check_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
442 sis630_driver.name); 466 sis630_driver.name);
443 if (retval) 467 if (retval)
444 goto exit; 468 goto exit;
445 469
446 /* Everything is happy, let's grab the memory and set things up. */ 470 /* Everything is happy, let's grab the memory and set things up. */
447 if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION, 471 if (!request_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION,
448 sis630_driver.name)) { 472 sis630_driver.name)) {
449 dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already " 473 dev_err(&sis630_dev->dev,
450 "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA); 474 "I/O Region 0x%04hx-0x%04hx for SMBus already in use.\n",
475 smbus_base + SMB_STS,
476 smbus_base + SMB_STS + SIS630_SMB_IOREGION - 1);
451 retval = -EBUSY; 477 retval = -EBUSY;
452 goto exit; 478 goto exit;
453 } 479 }
@@ -456,7 +482,7 @@ static int sis630_setup(struct pci_dev *sis630_dev)
456 482
457exit: 483exit:
458 if (retval) 484 if (retval)
459 acpi_base = 0; 485 smbus_base = 0;
460 return retval; 486 return retval;
461} 487}
462 488
@@ -470,11 +496,13 @@ static struct i2c_adapter sis630_adapter = {
470 .owner = THIS_MODULE, 496 .owner = THIS_MODULE,
471 .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, 497 .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
472 .algo = &smbus_algorithm, 498 .algo = &smbus_algorithm,
499 .retries = 3
473}; 500};
474 501
475static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { 502static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
476 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 503 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
477 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, 504 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
505 { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },
478 { 0, } 506 { 0, }
479}; 507};
480 508
@@ -491,17 +519,17 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
491 sis630_adapter.dev.parent = &dev->dev; 519 sis630_adapter.dev.parent = &dev->dev;
492 520
493 snprintf(sis630_adapter.name, sizeof(sis630_adapter.name), 521 snprintf(sis630_adapter.name, sizeof(sis630_adapter.name),
494 "SMBus SIS630 adapter at %04x", acpi_base + SMB_STS); 522 "SMBus SIS630 adapter at %04hx", smbus_base + SMB_STS);
495 523
496 return i2c_add_adapter(&sis630_adapter); 524 return i2c_add_adapter(&sis630_adapter);
497} 525}
498 526
499static void sis630_remove(struct pci_dev *dev) 527static void sis630_remove(struct pci_dev *dev)
500{ 528{
501 if (acpi_base) { 529 if (smbus_base) {
502 i2c_del_adapter(&sis630_adapter); 530 i2c_del_adapter(&sis630_adapter);
503 release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION); 531 release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION);
504 acpi_base = 0; 532 smbus_base = 0;
505 } 533 }
506} 534}
507 535