diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/busses/i2c-nforce2.c | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index c48140f782d0..1c63c4f2e4b6 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c | |||
@@ -98,15 +98,40 @@ struct nforce2_smbus { | |||
98 | #define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a | 98 | #define NVIDIA_SMB_PRTCL_BLOCK_DATA 0x0a |
99 | #define NVIDIA_SMB_PRTCL_PEC 0x80 | 99 | #define NVIDIA_SMB_PRTCL_PEC 0x80 |
100 | 100 | ||
101 | /* Misc definitions */ | ||
102 | #define MAX_TIMEOUT 100 | ||
103 | |||
101 | static struct pci_driver nforce2_driver; | 104 | static struct pci_driver nforce2_driver; |
102 | 105 | ||
106 | static int nforce2_check_status(struct i2c_adapter *adap) | ||
107 | { | ||
108 | struct nforce2_smbus *smbus = adap->algo_data; | ||
109 | int timeout = 0; | ||
110 | unsigned char temp; | ||
111 | |||
112 | do { | ||
113 | msleep(1); | ||
114 | temp = inb_p(NVIDIA_SMB_STS); | ||
115 | } while ((!temp) && (timeout++ < MAX_TIMEOUT)); | ||
116 | |||
117 | if (timeout >= MAX_TIMEOUT) { | ||
118 | dev_dbg(&adap->dev, "SMBus Timeout!\n"); | ||
119 | return -1; | ||
120 | } | ||
121 | if (!(temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { | ||
122 | dev_dbg(&adap->dev, "Transaction failed (0x%02x)!\n", temp); | ||
123 | return -1; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
103 | /* Return -1 on error */ | 128 | /* Return -1 on error */ |
104 | static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | 129 | static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, |
105 | unsigned short flags, char read_write, | 130 | unsigned short flags, char read_write, |
106 | u8 command, int size, union i2c_smbus_data * data) | 131 | u8 command, int size, union i2c_smbus_data * data) |
107 | { | 132 | { |
108 | struct nforce2_smbus *smbus = adap->algo_data; | 133 | struct nforce2_smbus *smbus = adap->algo_data; |
109 | unsigned char protocol, pec, temp; | 134 | unsigned char protocol, pec; |
110 | u8 len; | 135 | u8 len; |
111 | int i; | 136 | int i; |
112 | 137 | ||
@@ -170,21 +195,8 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
170 | outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); | 195 | outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR); |
171 | outb_p(protocol, NVIDIA_SMB_PRTCL); | 196 | outb_p(protocol, NVIDIA_SMB_PRTCL); |
172 | 197 | ||
173 | temp = inb_p(NVIDIA_SMB_STS); | 198 | if (nforce2_check_status(adap)) |
174 | |||
175 | if (~temp & NVIDIA_SMB_STS_DONE) { | ||
176 | udelay(500); | ||
177 | temp = inb_p(NVIDIA_SMB_STS); | ||
178 | } | ||
179 | if (~temp & NVIDIA_SMB_STS_DONE) { | ||
180 | msleep(10); | ||
181 | temp = inb_p(NVIDIA_SMB_STS); | ||
182 | } | ||
183 | |||
184 | if ((~temp & NVIDIA_SMB_STS_DONE) || (temp & NVIDIA_SMB_STS_STATUS)) { | ||
185 | dev_dbg(&adap->dev, "SMBus Timeout! (0x%02x)\n", temp); | ||
186 | return -1; | 199 | return -1; |
187 | } | ||
188 | 200 | ||
189 | if (read_write == I2C_SMBUS_WRITE) | 201 | if (read_write == I2C_SMBUS_WRITE) |
190 | return 0; | 202 | return 0; |
@@ -202,7 +214,12 @@ static s32 nforce2_access(struct i2c_adapter * adap, u16 addr, | |||
202 | 214 | ||
203 | case I2C_SMBUS_BLOCK_DATA: | 215 | case I2C_SMBUS_BLOCK_DATA: |
204 | len = inb_p(NVIDIA_SMB_BCNT); | 216 | len = inb_p(NVIDIA_SMB_BCNT); |
205 | len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); | 217 | if ((len <= 0) || (len > I2C_SMBUS_BLOCK_MAX)) { |
218 | dev_err(&adap->dev, "Transaction failed " | ||
219 | "(received block size: 0x%02x)\n", | ||
220 | len); | ||
221 | return -1; | ||
222 | } | ||
206 | for (i = 0; i < len; i++) | 223 | for (i = 0; i < len; i++) |
207 | data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); | 224 | data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i); |
208 | data->block[0] = len; | 225 | data->block[0] = len; |