48 #include <linux/kernel.h>
49 #include <linux/module.h>
51 #include <linux/pci.h>
54 #include <linux/i2c.h>
62 #define SMBHOST_CNT 0x83
65 #define SMB_PCOUNT 0x86
66 #define SMB_COUNT 0x87
68 #define SMBDEV_ADDR 0x90
74 #define SIS630_SMB_IOREGION 20
78 #define SIS630_ACPI_BASE_REG 0x74
80 #define SIS630_BIOS_CTL_REG 0x40
83 #define MAX_TIMEOUT 500
86 #define SIS630_QUICK 0x00
87 #define SIS630_BYTE 0x01
88 #define SIS630_BYTE_DATA 0x02
89 #define SIS630_WORD_DATA 0x03
90 #define SIS630_PCALL 0x04
91 #define SIS630_BLOCK_DATA 0x05
96 static bool high_clock;
99 MODULE_PARM_DESC(high_clock,
"Set Host Master Clock to 56KHz (default 14KHz).");
104 static unsigned short acpi_base;
107 static int supported[] = {
113 static inline u8 sis630_read(
u8 reg)
115 return inb(acpi_base + reg);
120 outb(data, acpi_base + reg);
123 static int sis630_transaction_start(
struct i2c_adapter *adap,
int size,
u8 *oldclock)
128 if ((temp = sis630_read(
SMB_CNT) & 0x03) != 0x00) {
129 dev_dbg(&adap->
dev,
"SMBus busy (%02x).Resetting...\n",temp);
133 if ((temp = sis630_read(
SMB_CNT) & 0x03) != 0x00) {
134 dev_dbg(&adap->
dev,
"Failed! (%02x)\n", temp);
142 *oldclock = sis630_read(
SMB_CNT);
144 dev_dbg(&adap->
dev,
"saved clock 0x%02x\n", *oldclock);
150 sis630_write(
SMB_CNT, (*oldclock & ~0x40));
154 sis630_write(
SMB_STS, temp & 0x1e);
162 static int sis630_transaction_wait(
struct i2c_adapter *adap,
int size)
173 }
while (!(temp & 0x0e) && (timeout++ <
MAX_TIMEOUT));
182 dev_dbg(&adap->
dev,
"Error: Failed bus transaction\n");
199 static void sis630_transaction_end(
struct i2c_adapter *adap,
u8 oldclock)
206 dev_dbg(&adap->
dev,
"SMB_CNT before clock restore 0x%02x\n", sis630_read(
SMB_CNT));
212 if (high_clock && !(oldclock & 0x20))
215 dev_dbg(&adap->
dev,
"SMB_CNT after clock restore 0x%02x\n", sis630_read(
SMB_CNT));
218 static int sis630_transaction(
struct i2c_adapter *adap,
int size)
223 result = sis630_transaction_start(adap, size, &oldclock);
225 result = sis630_transaction_wait(adap, size);
226 sis630_transaction_end(adap, oldclock);
238 len = data->
block[0];
244 for (i=1; i <= len; i++) {
248 if (i==8 || (len<8 && i==len)) {
249 dev_dbg(&adap->
dev,
"start trans len=%d i=%d\n",len ,i);
251 rc = sis630_transaction_start(adap,
256 else if ((i-1)%8 == 7 || i==len) {
257 dev_dbg(&adap->
dev,
"trans_wait len=%d i=%d\n",len,i);
259 dev_dbg(&adap->
dev,
"clear smbary_sts len=%d i=%d\n",len,i);
267 rc = sis630_transaction_wait(adap,
278 data->
block[0] = len = 0;
279 rc = sis630_transaction_start(adap,
294 if (data->
block[0] > 32)
299 for (i=0; i < 8 && len < data->
block[0]; i++,len++) {
300 dev_dbg(&adap->
dev,
"read i=%d len=%d\n", i, len);
304 dev_dbg(&adap->
dev,
"clear smbary_sts len=%d i=%d\n",len,i);
308 }
while(len < data->
block[0]);
311 sis630_transaction_end(adap, oldclock);
318 unsigned short flags,
char read_write,
325 sis630_write(
SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
329 sis630_write(
SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
331 sis630_write(
SMB_CMD, command);
335 sis630_write(
SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
336 sis630_write(
SMB_CMD, command);
343 sis630_write(
SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
344 sis630_write(
SMB_CMD, command);
352 sis630_write(
SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
353 sis630_write(
SMB_CMD, command);
355 return sis630_block_data(adap, data, read_write);
357 dev_warn(&adap->
dev,
"Unsupported transaction %d\n",
362 status = sis630_transaction(adap, size);
399 for (i=0; supported[
i] > 0 ; i++) {
408 dev_err(&sis630_dev->
dev,
"WARNING: Can't detect SIS630 compatible device, but "
409 "loading because of force option enabled\n");
420 dev_err(&sis630_dev->
dev,
"Error: Can't read bios ctl reg\n");
427 dev_err(&sis630_dev->
dev,
"Error: Can't enable ACPI\n");
434 dev_err(&sis630_dev->
dev,
"Error: Can't determine ACPI base address\n");
439 dev_dbg(&sis630_dev->
dev,
"ACPI base at 0x%04x\n", acpi_base);
448 sis630_driver.name)) {
449 dev_err(&sis630_dev->
dev,
"SMBus registers 0x%04x-0x%04x already "
465 .smbus_xfer = sis630_access,
466 .functionality = sis630_func,
472 .algo = &smbus_algorithm,
485 if (sis630_setup(dev)) {
486 dev_err(&dev->
dev,
"SIS630 comp. bus not detected, module not inserted.\n");
491 sis630_adapter.
dev.parent = &dev->
dev;
494 "SMBus SIS630 adapter at %04x", acpi_base +
SMB_STS);
510 .name =
"sis630_smbus",
511 .id_table = sis630_ids,
512 .probe = sis630_probe,