1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49#include <linux/module.h>
50#include <linux/pci.h>
51#include <linux/kernel.h>
52#include <linux/stddef.h>
53#include <linux/ioport.h>
54#include <linux/delay.h>
55#include <linux/i2c.h>
56#include <linux/acpi.h>
57#include <linux/io.h>
58
59
60#define SMBHSTSTS (0 + ali15x3_smba)
61#define SMBHSTCNT (1 + ali15x3_smba)
62#define SMBHSTSTART (2 + ali15x3_smba)
63#define SMBHSTCMD (7 + ali15x3_smba)
64#define SMBHSTADD (3 + ali15x3_smba)
65#define SMBHSTDAT0 (4 + ali15x3_smba)
66#define SMBHSTDAT1 (5 + ali15x3_smba)
67#define SMBBLKDAT (6 + ali15x3_smba)
68
69
70#define SMBCOM 0x004
71#define SMBBA 0x014
72#define SMBATPC 0x05B
73#define SMBHSTCFG 0x0E0
74#define SMBSLVC 0x0E1
75#define SMBCLK 0x0E2
76#define SMBREV 0x008
77
78
79#define MAX_TIMEOUT 200
80#define ALI15X3_SMB_IOSIZE 32
81
82
83
84
85
86#define ALI15X3_SMB_DEFAULTBASE 0xE800
87
88
89#define ALI15X3_LOCK 0x06
90
91
92#define ALI15X3_ABORT 0x02
93#define ALI15X3_T_OUT 0x04
94#define ALI15X3_QUICK 0x00
95#define ALI15X3_BYTE 0x10
96#define ALI15X3_BYTE_DATA 0x20
97#define ALI15X3_WORD_DATA 0x30
98#define ALI15X3_BLOCK_DATA 0x40
99#define ALI15X3_BLOCK_CLR 0x80
100
101
102#define ALI15X3_STS_IDLE 0x04
103#define ALI15X3_STS_BUSY 0x08
104#define ALI15X3_STS_DONE 0x10
105#define ALI15X3_STS_DEV 0x20
106#define ALI15X3_STS_COLL 0x40
107#define ALI15X3_STS_TERM 0x80
108#define ALI15X3_STS_ERR 0xE0
109
110
111
112
113static u16 force_addr;
114module_param_hw(force_addr, ushort, ioport, 0);
115MODULE_PARM_DESC(force_addr,
116 "Initialize the base address of the i2c controller");
117
118static struct pci_driver ali15x3_driver;
119static unsigned short ali15x3_smba;
120
121static int ali15x3_setup(struct pci_dev *ALI15X3_dev)
122{
123 u16 a;
124 unsigned char temp;
125
126
127
128
129
130
131
132
133
134
135
136
137 pci_read_config_byte(ALI15X3_dev, SMBATPC, &temp);
138 if (temp & ALI15X3_LOCK) {
139 temp &= ~ALI15X3_LOCK;
140 pci_write_config_byte(ALI15X3_dev, SMBATPC, temp);
141 }
142
143
144 pci_read_config_word(ALI15X3_dev, SMBBA, &ali15x3_smba);
145 ali15x3_smba &= (0xffff & ~(ALI15X3_SMB_IOSIZE - 1));
146 if (ali15x3_smba == 0 && force_addr == 0) {
147 dev_err(&ALI15X3_dev->dev, "ALI15X3_smb region uninitialized "
148 "- upgrade BIOS or use force_addr=0xaddr\n");
149 return -ENODEV;
150 }
151
152 if(force_addr)
153 ali15x3_smba = force_addr & ~(ALI15X3_SMB_IOSIZE - 1);
154
155 if (acpi_check_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
156 ali15x3_driver.name))
157 return -EBUSY;
158
159 if (!request_region(ali15x3_smba, ALI15X3_SMB_IOSIZE,
160 ali15x3_driver.name)) {
161 dev_err(&ALI15X3_dev->dev,
162 "ALI15X3_smb region 0x%x already in use!\n",
163 ali15x3_smba);
164 return -ENODEV;
165 }
166
167 if(force_addr) {
168 dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n",
169 ali15x3_smba);
170 if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev,
171 SMBBA,
172 ali15x3_smba))
173 goto error;
174 if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev,
175 SMBBA, &a))
176 goto error;
177 if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) {
178
179 dev_err(&ALI15X3_dev->dev,
180 "force address failed - not supported?\n");
181 goto error;
182 }
183 }
184
185 pci_read_config_byte(ALI15X3_dev, SMBCOM, &temp);
186 if ((temp & 1) == 0) {
187 dev_info(&ALI15X3_dev->dev, "enabling SMBus device\n");
188 pci_write_config_byte(ALI15X3_dev, SMBCOM, temp | 0x01);
189 }
190
191
192 pci_read_config_byte(ALI15X3_dev, SMBHSTCFG, &temp);
193 if ((temp & 1) == 0) {
194 dev_info(&ALI15X3_dev->dev, "enabling SMBus controller\n");
195 pci_write_config_byte(ALI15X3_dev, SMBHSTCFG, temp | 0x01);
196 }
197
198
199 pci_write_config_byte(ALI15X3_dev, SMBCLK, 0x20);
200
201
202
203
204
205
206
207
208 pci_read_config_byte(ALI15X3_dev, SMBREV, &temp);
209 dev_dbg(&ALI15X3_dev->dev, "SMBREV = 0x%X\n", temp);
210 dev_dbg(&ALI15X3_dev->dev, "iALI15X3_smba = 0x%X\n", ali15x3_smba);
211
212 return 0;
213error:
214 release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
215 return -ENODEV;
216}
217
218
219static int ali15x3_transaction(struct i2c_adapter *adap)
220{
221 int temp;
222 int result = 0;
223 int timeout = 0;
224
225 dev_dbg(&adap->dev, "Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, "
226 "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
227 inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
228 inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
229
230
231 temp = inb_p(SMBHSTSTS);
232
233
234
235 if (temp & ALI15X3_STS_BUSY) {
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 dev_info(&adap->dev, "Resetting entire SMB Bus to "
258 "clear busy condition (%02x)\n", temp);
259 outb_p(ALI15X3_T_OUT, SMBHSTCNT);
260 temp = inb_p(SMBHSTSTS);
261 }
262
263
264 if (temp & (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
265
266 outb_p(0xFF, SMBHSTSTS);
267 if ((temp = inb_p(SMBHSTSTS)) &
268 (ALI15X3_STS_ERR | ALI15X3_STS_BUSY)) {
269
270
271
272 dev_err(&adap->dev, "SMBus reset failed! (0x%02x) - "
273 "controller or device on bus is probably hung\n",
274 temp);
275 return -EBUSY;
276 }
277 } else {
278
279 if (temp & ALI15X3_STS_DONE) {
280 outb_p(temp, SMBHSTSTS);
281 }
282 }
283
284
285 outb_p(0xFF, SMBHSTSTART);
286
287
288 timeout = 0;
289 do {
290 msleep(1);
291 temp = inb_p(SMBHSTSTS);
292 } while ((!(temp & (ALI15X3_STS_ERR | ALI15X3_STS_DONE)))
293 && (timeout++ < MAX_TIMEOUT));
294
295
296 if (timeout > MAX_TIMEOUT) {
297 result = -ETIMEDOUT;
298 dev_err(&adap->dev, "SMBus Timeout!\n");
299 }
300
301 if (temp & ALI15X3_STS_TERM) {
302 result = -EIO;
303 dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
304 }
305
306
307
308
309
310
311
312 if (temp & ALI15X3_STS_COLL) {
313 result = -ENXIO;
314 dev_dbg(&adap->dev,
315 "Error: no response or bus collision ADD=%02x\n",
316 inb_p(SMBHSTADD));
317 }
318
319
320 if (temp & ALI15X3_STS_DEV) {
321 result = -EIO;
322 dev_err(&adap->dev, "Error: device error\n");
323 }
324 dev_dbg(&adap->dev, "Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, "
325 "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb_p(SMBHSTSTS),
326 inb_p(SMBHSTCNT), inb_p(SMBHSTCMD), inb_p(SMBHSTADD),
327 inb_p(SMBHSTDAT0), inb_p(SMBHSTDAT1));
328 return result;
329}
330
331
332static s32 ali15x3_access(struct i2c_adapter * adap, u16 addr,
333 unsigned short flags, char read_write, u8 command,
334 int size, union i2c_smbus_data * data)
335{
336 int i, len;
337 int temp;
338 int timeout;
339
340
341 outb_p(0xFF, SMBHSTSTS);
342
343 temp = inb_p(SMBHSTSTS);
344 for (timeout = 0;
345 (timeout < MAX_TIMEOUT) && !(temp & ALI15X3_STS_IDLE);
346 timeout++) {
347 msleep(1);
348 temp = inb_p(SMBHSTSTS);
349 }
350 if (timeout >= MAX_TIMEOUT) {
351 dev_err(&adap->dev, "Idle wait Timeout! STS=0x%02x\n", temp);
352 }
353
354 switch (size) {
355 case I2C_SMBUS_QUICK:
356 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
357 SMBHSTADD);
358 size = ALI15X3_QUICK;
359 break;
360 case I2C_SMBUS_BYTE:
361 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
362 SMBHSTADD);
363 if (read_write == I2C_SMBUS_WRITE)
364 outb_p(command, SMBHSTCMD);
365 size = ALI15X3_BYTE;
366 break;
367 case I2C_SMBUS_BYTE_DATA:
368 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
369 SMBHSTADD);
370 outb_p(command, SMBHSTCMD);
371 if (read_write == I2C_SMBUS_WRITE)
372 outb_p(data->byte, SMBHSTDAT0);
373 size = ALI15X3_BYTE_DATA;
374 break;
375 case I2C_SMBUS_WORD_DATA:
376 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
377 SMBHSTADD);
378 outb_p(command, SMBHSTCMD);
379 if (read_write == I2C_SMBUS_WRITE) {
380 outb_p(data->word & 0xff, SMBHSTDAT0);
381 outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
382 }
383 size = ALI15X3_WORD_DATA;
384 break;
385 case I2C_SMBUS_BLOCK_DATA:
386 outb_p(((addr & 0x7f) << 1) | (read_write & 0x01),
387 SMBHSTADD);
388 outb_p(command, SMBHSTCMD);
389 if (read_write == I2C_SMBUS_WRITE) {
390 len = data->block[0];
391 if (len < 0) {
392 len = 0;
393 data->block[0] = len;
394 }
395 if (len > 32) {
396 len = 32;
397 data->block[0] = len;
398 }
399 outb_p(len, SMBHSTDAT0);
400
401 outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
402 for (i = 1; i <= len; i++)
403 outb_p(data->block[i], SMBBLKDAT);
404 }
405 size = ALI15X3_BLOCK_DATA;
406 break;
407 default:
408 dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
409 return -EOPNOTSUPP;
410 }
411
412 outb_p(size, SMBHSTCNT);
413
414 temp = ali15x3_transaction(adap);
415 if (temp)
416 return temp;
417
418 if ((read_write == I2C_SMBUS_WRITE) || (size == ALI15X3_QUICK))
419 return 0;
420
421
422 switch (size) {
423 case ALI15X3_BYTE:
424 data->byte = inb_p(SMBHSTDAT0);
425 break;
426 case ALI15X3_BYTE_DATA:
427 data->byte = inb_p(SMBHSTDAT0);
428 break;
429 case ALI15X3_WORD_DATA:
430 data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
431 break;
432 case ALI15X3_BLOCK_DATA:
433 len = inb_p(SMBHSTDAT0);
434 if (len > 32)
435 len = 32;
436 data->block[0] = len;
437
438 outb_p(inb_p(SMBHSTCNT) | ALI15X3_BLOCK_CLR, SMBHSTCNT);
439 for (i = 1; i <= data->block[0]; i++) {
440 data->block[i] = inb_p(SMBBLKDAT);
441 dev_dbg(&adap->dev, "Blk: len=%d, i=%d, data=%02x\n",
442 len, i, data->block[i]);
443 }
444 break;
445 }
446 return 0;
447}
448
449static u32 ali15x3_func(struct i2c_adapter *adapter)
450{
451 return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
452 I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
453 I2C_FUNC_SMBUS_BLOCK_DATA;
454}
455
456static const struct i2c_algorithm smbus_algorithm = {
457 .smbus_xfer = ali15x3_access,
458 .functionality = ali15x3_func,
459};
460
461static struct i2c_adapter ali15x3_adapter = {
462 .owner = THIS_MODULE,
463 .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
464 .algo = &smbus_algorithm,
465};
466
467static const struct pci_device_id ali15x3_ids[] = {
468 { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
469 { 0, }
470};
471
472MODULE_DEVICE_TABLE (pci, ali15x3_ids);
473
474static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id)
475{
476 if (ali15x3_setup(dev)) {
477 dev_err(&dev->dev,
478 "ALI15X3 not detected, module not inserted.\n");
479 return -ENODEV;
480 }
481
482
483 ali15x3_adapter.dev.parent = &dev->dev;
484
485 snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name),
486 "SMBus ALI15X3 adapter at %04x", ali15x3_smba);
487 return i2c_add_adapter(&ali15x3_adapter);
488}
489
490static void ali15x3_remove(struct pci_dev *dev)
491{
492 i2c_del_adapter(&ali15x3_adapter);
493 release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE);
494}
495
496static struct pci_driver ali15x3_driver = {
497 .name = "ali15x3_smbus",
498 .id_table = ali15x3_ids,
499 .probe = ali15x3_probe,
500 .remove = ali15x3_remove,
501};
502
503module_pci_driver(ali15x3_driver);
504
505MODULE_AUTHOR ("Frodo Looijaard <frodol@dds.nl>, "
506 "Philip Edelbrock <phil@netroedge.com>, "
507 "and Mark D. Studebaker <mdsxyz123@yahoo.com>");
508MODULE_DESCRIPTION("ALI15X3 SMBus driver");
509MODULE_LICENSE("GPL");
510