diff options
author | Amaury Decrême <amaury.decreme@gmail.com> | 2013-01-28 16:21:05 -0500 |
---|---|---|
committer | Wolfram Sang <wolfram@the-dreams.de> | 2013-02-11 09:59:38 -0500 |
commit | 974d6a3797001c88e59ccb78567c6d71ac526c43 (patch) | |
tree | 5a0a99f5526f12f5b6e0db1803f2abbd4e43dae8 /drivers/i2c | |
parent | b08369a174a183e88baa98ab5e3566a617a3a7f8 (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/Kconfig | 4 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-sis630.c | 88 |
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 | ||
199 | config I2C_SIS630 | 199 | config 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; | |||
96 | static bool high_clock; | 109 | static bool high_clock; |
97 | static bool force; | 110 | static bool force; |
98 | module_param(high_clock, bool, 0); | 111 | module_param(high_clock, bool, 0); |
99 | MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz)."); | 112 | MODULE_PARM_DESC(high_clock, |
113 | "Set Host Master Clock to 56KHz (default 14KHz) (SIS630/730 only)."); | ||
100 | module_param(force, bool, 0); | 114 | module_param(force, bool, 0); |
101 | MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); | 115 | MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); |
102 | 116 | ||
103 | /* acpi base address */ | 117 | /* SMBus base adress */ |
104 | static unsigned short acpi_base; | 118 | static unsigned short smbus_base; |
105 | 119 | ||
106 | /* supported chips */ | 120 | /* supported chips */ |
107 | static int supported[] = { | 121 | static 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 | ||
113 | static inline u8 sis630_read(u8 reg) | 128 | static inline u8 sis630_read(u8 reg) |
114 | { | 129 | { |
115 | return inb(acpi_base + reg); | 130 | return inb(smbus_base + reg); |
116 | } | 131 | } |
117 | 132 | ||
118 | static inline void sis630_write(u8 reg, u8 data) | 133 | static 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 | ||
123 | static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock) | 138 | static 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 | ||
457 | exit: | 483 | exit: |
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 | ||
475 | static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = { | 502 | static 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 | ||
499 | static void sis630_remove(struct pci_dev *dev) | 527 | static 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 | ||