mirror of
https://github.com/lm-sensors/lm-sensors.git
synced 2026-11-13 17:00:15 +00:00
Patch from
Vojtech Pavlik <vojtech@suse.cz> Implemented/fixed PEC and process calls, and block reads/writes in the driver. ARP now works with smbus-arp.c. Removed attempt at 2.2 support. Module doesn't work w/ 2.2 kernels. Added check in Module.mk so it won't compile unless CONFIG_X86_64. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@1656 7894878c-1315-0410-8ee3-d5d059ff63e0
This commit is contained in:
1 parent
1b74956ae0
commit
39d845c73b
3 files changed
+101
-56
No files matched your search
+15
-7
@@ -1,15 +1,16 @@
|
||||
Kernel driver `i2c-adm8111.o'
|
||||
|
||||
Status: Untested.
|
||||
Status: Slightly tested.
|
||||
|
||||
Supported adapters:
|
||||
* AMD-8111 SMBus 2.0 PCI interface
|
||||
* Possibly any other interface that implements the ACPI 2.0 EC interface
|
||||
Datasheets: Publicly available at AMD and ACPI websites
|
||||
|
||||
Datasheets:
|
||||
AMD datasheet not yet available, but almost everything can be found in
|
||||
publically available ACPI 2.0 specification, which the adapter follows.
|
||||
|
||||
Author: Vojtech Pavlik <vojtech@suse.cz>
|
||||
|
||||
|
||||
Module Parameters
|
||||
-----------------
|
||||
|
||||
@@ -30,15 +31,22 @@ in your 'lspci -v', then this driver is for your chipset.
|
||||
Process Call Support
|
||||
--------------------
|
||||
|
||||
The chip supports it, but it's not implemented in the driver at the moment.
|
||||
Supported.
|
||||
|
||||
SMBus 2.0 Support
|
||||
-----------------
|
||||
|
||||
The chip supports SMBus 2.0, however the only extension the driver
|
||||
supports is PEC. Slave mode or host notification are not implemented.
|
||||
Supported. Both PEC and block process call support is implemented.
|
||||
Slave mode or host notification are not yet implemented.
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Note that for the 8111, there are two SMBus adapters. The SMBus 2.0 adapter is
|
||||
supported by this driver, and the SMBus 1.0 adapter is supported
|
||||
by the i2c-amd756 driver.
|
||||
|
||||
The 8111 used with the AMD Hammer. While the module should work either with
|
||||
CONFIG_X86 or CONFIG_X86_64, it will only be compiled with CONFIG_X86_64
|
||||
(as it was the easiest way to prevent compilation in 2.2 kernels).
|
||||
If you would like to compile it for CONFIG_X86, modify kernel/busses/Module.mk.
|
||||
@@ -40,9 +40,12 @@ endif
|
||||
ifneq ($(shell if grep -q '^CONFIG_I2C_AMD756=y' $(LINUX)/.config; then echo 1; fi),1)
|
||||
KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-amd756.o
|
||||
endif
|
||||
# Should also work for CONFIG_X86 but this is the easiest way to prevent compilation in 2.2 kernels...
|
||||
ifeq ($(shell if grep -q '^CONFIG_X86_64=' $(LINUX)/.config; then echo 1; fi),1)
|
||||
ifneq ($(shell if grep -q '^CONFIG_I2C_AMD8111=y' $(LINUX)/.config; then echo 1; fi),1)
|
||||
KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-amd8111.o
|
||||
endif
|
||||
endif
|
||||
ifneq ($(shell if grep -q '^CONFIG_I2C_HYDRA=y' $(LINUX)/.config; then echo 1; fi),1)
|
||||
KERNELBUSSESTARGETS += $(MODULE_DIR)/i2c-hydra.o
|
||||
endif
|
||||
|
||||
+83
-49
@@ -80,7 +80,7 @@ unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
|
||||
udelay(1);
|
||||
|
||||
if (!timeout) {
|
||||
printk(KERN_WARNING "i2c-amd811.c: Timeout while waiting for IBF to clear\n");
|
||||
printk(KERN_WARNING "i2c-amd8111.c: Timeout while waiting for IBF to clear\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -166,6 +166,8 @@ unsigned int amd_ec_write(struct amd_smbus *smbus, unsigned char address, unsign
|
||||
#define AMD_SMB_STATUS_BUSY 0x1A
|
||||
#define AMD_SMB_STATUS_PEC 0x1F
|
||||
|
||||
#define AMD_SMB_PRTCL_WRITE 0x00
|
||||
#define AMD_SMB_PRTCL_READ 0x01
|
||||
#define AMD_SMB_PRTCL_QUICK 0x02
|
||||
#define AMD_SMB_PRTCL_BYTE 0x04
|
||||
#define AMD_SMB_PRTCL_BYTE_DATA 0x06
|
||||
@@ -181,59 +183,89 @@ s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
||||
char read_write, u8 command, int size, union i2c_smbus_data * data)
|
||||
{
|
||||
struct amd_smbus *smbus = adap->algo_data;
|
||||
unsigned char protocol = read_write; /* 1 = read, 0 = write */
|
||||
unsigned char temp[2];
|
||||
int i, timeout = 5000;
|
||||
unsigned char protocol, len, pec, temp[2];
|
||||
int i;
|
||||
|
||||
protocol = (read_write == I2C_SMBUS_READ) ? AMD_SMB_PRTCL_READ : AMD_SMB_PRTCL_WRITE;
|
||||
pec = (flags & I2C_CLIENT_PEC) ? AMD_SMB_PRTCL_PEC : 0;
|
||||
|
||||
switch (size) {
|
||||
|
||||
case I2C_SMBUS_QUICK:
|
||||
protocol |= AMD_SMB_PRTCL_QUICK;
|
||||
read_write = I2C_SMBUS_WRITE;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE:
|
||||
if (!read_write)
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
|
||||
protocol |= AMD_SMB_PRTCL_BYTE;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BYTE_DATA:
|
||||
amd_ec_write(smbus, AMD_SMB_CMD, command);
|
||||
if (!read_write)
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
|
||||
protocol |= AMD_SMB_PRTCL_BYTE_DATA;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA_PEC:
|
||||
protocol |= AMD_SMB_PRTCL_PEC;
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
amd_ec_write(smbus, AMD_SMB_CMD, command);
|
||||
if (!read_write) {
|
||||
amd_ec_write(smbus, AMD_SMB_DATA, data->byte);
|
||||
amd_ec_write(smbus, AMD_SMB_DATA + 1, data->byte >> 8);
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
amd_ec_write(smbus, AMD_SMB_DATA, data->word);
|
||||
amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
|
||||
}
|
||||
protocol |= AMD_SMB_PRTCL_WORD_DATA;
|
||||
protocol |= AMD_SMB_PRTCL_WORD_DATA | pec;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_BLOCK_DATA_PEC:
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
protocol |= AMD_SMB_PRTCL_PEC;
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
amd_ec_write(smbus, AMD_SMB_CMD, command);
|
||||
if (!read_write)
|
||||
for (i = 0; i < data->block[0]; i++)
|
||||
if (read_write == I2C_SMBUS_WRITE) {
|
||||
len = min_t(u8, data->block[0], 32);
|
||||
amd_ec_write(smbus, AMD_SMB_BCNT, len);
|
||||
for (i = 0; i < len; i++)
|
||||
amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
|
||||
switch (size) {
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
protocol |= AMD_SMB_PRTCL_BLOCK_DATA;
|
||||
break;
|
||||
case I2C_SMBUS_BLOCK_DATA_PEC:
|
||||
protocol |= AMD_SMB_PRTCL_BLOCK_DATA | AMD_SMB_PRTCL_PEC;
|
||||
break;
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
|
||||
break;
|
||||
}
|
||||
protocol |= AMD_SMB_PRTCL_BLOCK_DATA | pec;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
len = min_t(u8, data->block[0], 32);
|
||||
amd_ec_write(smbus, AMD_SMB_CMD, command);
|
||||
amd_ec_write(smbus, AMD_SMB_BCNT, len);
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
for (i = 0; i < len; i++)
|
||||
amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
|
||||
protocol |= AMD_SMB_PRTCL_I2C_BLOCK_DATA;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_PROC_CALL_PEC:
|
||||
protocol |= AMD_SMB_PRTCL_PEC;
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
amd_ec_write(smbus, AMD_SMB_CMD, command);
|
||||
amd_ec_write(smbus, AMD_SMB_DATA, data->word);
|
||||
amd_ec_write(smbus, AMD_SMB_DATA + 1, data->word >> 8);
|
||||
protocol = AMD_SMB_PRTCL_PROC_CALL | pec;
|
||||
read_write = I2C_SMBUS_READ;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
|
||||
protocol |= AMD_SMB_PRTCL_PEC;
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
protocol |= pec;
|
||||
len = min_t(u8, data->block[0], 31);
|
||||
amd_ec_write(smbus, AMD_SMB_CMD, command);
|
||||
amd_ec_write(smbus, AMD_SMB_BCNT, len);
|
||||
for (i = 0; i < len; i++)
|
||||
amd_ec_write(smbus, AMD_SMB_DATA + i, data->block[i + 1]);
|
||||
protocol = AMD_SMB_PRTCL_BLOCK_PROC_CALL | pec;
|
||||
read_write = I2C_SMBUS_READ;
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_PROC_CALL: /* We don't support proc_call yet */
|
||||
default:
|
||||
printk(KERN_WARNING "i2c-amd8111.c: Unsupported transaction %d\n", size);
|
||||
return -1;
|
||||
@@ -244,21 +276,21 @@ s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
||||
|
||||
amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
|
||||
|
||||
while (timeout && ~temp[0] & AMD_SMB_STS_DONE) {
|
||||
if (~temp[0] & AMD_SMB_STS_DONE) {
|
||||
udelay(500);
|
||||
amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
|
||||
udelay(10);
|
||||
timeout--;
|
||||
}
|
||||
|
||||
if (!timeout)
|
||||
return -1;
|
||||
|
||||
if (~temp[0] & AMD_SMB_STS_DONE) {
|
||||
printk(KERN_WARNING "i2c-amd8111.c: Transaction completed with error %#x\n", temp[0]);
|
||||
return -1;
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule_timeout(HZ/100);
|
||||
amd_ec_read(smbus, AMD_SMB_STS, temp + 0);
|
||||
}
|
||||
|
||||
if (!read_write) /* We're done, no values to return; */
|
||||
if ((~temp[0] & AMD_SMB_STS_DONE) || (temp[0] & AMD_SMB_STS_STATUS))
|
||||
return -1;
|
||||
|
||||
if (read_write == I2C_SMBUS_WRITE)
|
||||
return 0;
|
||||
|
||||
switch (size) {
|
||||
@@ -269,6 +301,9 @@ s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
||||
break;
|
||||
|
||||
case I2C_SMBUS_WORD_DATA:
|
||||
case I2C_SMBUS_WORD_DATA_PEC:
|
||||
case I2C_SMBUS_PROC_CALL:
|
||||
case I2C_SMBUS_PROC_CALL_PEC:
|
||||
amd_ec_read(smbus, AMD_SMB_DATA, temp + 0);
|
||||
amd_ec_read(smbus, AMD_SMB_DATA + 1, temp + 1);
|
||||
data->word = (temp[1] << 8) | temp[0];
|
||||
@@ -276,9 +311,14 @@ s32 amd8111_access(struct i2c_adapter * adap, u16 addr, unsigned short flags,
|
||||
|
||||
case I2C_SMBUS_BLOCK_DATA:
|
||||
case I2C_SMBUS_BLOCK_DATA_PEC:
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL:
|
||||
case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
|
||||
amd_ec_read(smbus, AMD_SMB_BCNT, &len);
|
||||
len = min_t(u8, len, 32);
|
||||
case I2C_SMBUS_I2C_BLOCK_DATA:
|
||||
for (i = 0; i < data->block[0]; i++)
|
||||
for (i = 0; i < len; i++)
|
||||
amd_ec_read(smbus, AMD_SMB_DATA + i, data->block + i + 1);
|
||||
data->block[0] = len;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -297,10 +337,12 @@ void amd8111_dec(struct i2c_adapter *adapter)
|
||||
|
||||
u32 amd8111_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA_PEC | I2C_FUNC_SMBUS_HWPEC_CALC;
|
||||
return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_WORD_DATA_PEC |
|
||||
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA_PEC |
|
||||
I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_PROC_CALL_PEC |
|
||||
I2C_FUNC_SMBUS_BLOCK_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_PROC_CALL_PEC |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
@@ -326,18 +368,10 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_
|
||||
smbus->base = pci_resource_start(dev, 0);
|
||||
smbus->size = pci_resource_len(dev, 0);
|
||||
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,14)
|
||||
if (!request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0")) {
|
||||
kfree(smbus);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if (check_region(smbus->base, smbus->size) < 0) {
|
||||
kfree(smbus);
|
||||
return -1;
|
||||
}
|
||||
request_region(smbus->base, smbus->size, "amd8111 SMBus 2.0");
|
||||
#endif
|
||||
|
||||
sprintf(smbus->adapter.name, "SMBus2 AMD8111 adapter at %04x", smbus->base);
|
||||
smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111;
|
||||
@@ -346,8 +380,6 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_
|
||||
smbus->adapter.inc_use = amd8111_inc;
|
||||
smbus->adapter.dec_use = amd8111_dec;
|
||||
|
||||
pci_write_config_dword(dev, AMD_PCI_MISC, 0);
|
||||
|
||||
if (i2c_add_adapter(&smbus->adapter)) {
|
||||
printk(KERN_WARNING "i2c-amd8111.c: Failed to register adapter.\n");
|
||||
release_region(smbus->base, smbus->size);
|
||||
@@ -355,6 +387,8 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_
|
||||
return -1;
|
||||
}
|
||||
|
||||
pci_write_config_dword(smbus->dev, AMD_PCI_MISC, 0);
|
||||
|
||||
printk(KERN_INFO "i2c-amd8111.c: AMD8111 SMBus 2.0 adapter at pci%s\n", dev->slot_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user