]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/i2c/busses/i2c-sis630.c
72c29a650b22c44d7954e5c392bb16b8949ac5d7
[linux-2.6-omap-h63xx.git] / drivers / i2c / busses / i2c-sis630.c
1 /*
2     i2c-sis630.c - Part of lm_sensors, Linux kernel modules for hardware
3               monitoring
4
5     Copyright (c) 2002,2003 Alexander Malysh <amalysh@web.de>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23    Changes:
24    24.08.2002
25         Fixed the typo in sis630_access (Thanks to Mark M. Hoffman)
26         Changed sis630_transaction.(Thanks to Mark M. Hoffman)
27    18.09.2002
28         Added SIS730 as supported.
29    21.09.2002
30         Added high_clock module option.If this option is set
31         used Host Master Clock 56KHz (default 14KHz).For now we save old Host
32         Master Clock and after transaction completed restore (otherwise
33         it's confuse BIOS and hung Machine).
34    24.09.2002
35         Fixed typo in sis630_access
36         Fixed logical error by restoring of Host Master Clock
37    31.07.2003
38         Added block data read/write support.
39 */
40
41 /*
42    Status: beta
43
44    Supports:
45         SIS 630
46         SIS 730
47
48    Note: we assume there can only be one device, with one SMBus interface.
49 */
50
51 #include <linux/kernel.h>
52 #include <linux/module.h>
53 #include <linux/delay.h>
54 #include <linux/pci.h>
55 #include <linux/ioport.h>
56 #include <linux/init.h>
57 #include <linux/i2c.h>
58 #include <linux/acpi.h>
59 #include <asm/io.h>
60
61 /* SIS630 SMBus registers */
62 #define SMB_STS                 0x80    /* status */
63 #define SMB_EN                  0x81    /* status enable */
64 #define SMB_CNT                 0x82
65 #define SMBHOST_CNT             0x83
66 #define SMB_ADDR                0x84
67 #define SMB_CMD                 0x85
68 #define SMB_PCOUNT              0x86    /* processed count */
69 #define SMB_COUNT               0x87
70 #define SMB_BYTE                0x88    /* ~0x8F data byte field */
71 #define SMBDEV_ADDR             0x90
72 #define SMB_DB0                 0x91
73 #define SMB_DB1                 0x92
74 #define SMB_SAA                 0x93
75
76 /* register count for request_region */
77 #define SIS630_SMB_IOREGION     20
78
79 /* PCI address constants */
80 /* acpi base address register  */
81 #define SIS630_ACPI_BASE_REG    0x74
82 /* bios control register */
83 #define SIS630_BIOS_CTL_REG     0x40
84
85 /* Other settings */
86 #define MAX_TIMEOUT             500
87
88 /* SIS630 constants */
89 #define SIS630_QUICK            0x00
90 #define SIS630_BYTE             0x01
91 #define SIS630_BYTE_DATA        0x02
92 #define SIS630_WORD_DATA        0x03
93 #define SIS630_PCALL            0x04
94 #define SIS630_BLOCK_DATA       0x05
95
96 static struct pci_driver sis630_driver;
97
98 /* insmod parameters */
99 static int high_clock;
100 static int force;
101 module_param(high_clock, bool, 0);
102 MODULE_PARM_DESC(high_clock, "Set Host Master Clock to 56KHz (default 14KHz).");
103 module_param(force, bool, 0);
104 MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!");
105
106 /* acpi base address */
107 static unsigned short acpi_base;
108
109 /* supported chips */
110 static int supported[] = {
111         PCI_DEVICE_ID_SI_630,
112         PCI_DEVICE_ID_SI_730,
113         0 /* terminates the list */
114 };
115
116 static inline u8 sis630_read(u8 reg)
117 {
118         return inb(acpi_base + reg);
119 }
120
121 static inline void sis630_write(u8 reg, u8 data)
122 {
123         outb(data, acpi_base + reg);
124 }
125
126 static int sis630_transaction_start(struct i2c_adapter *adap, int size, u8 *oldclock)
127 {
128         int temp;
129
130         /* Make sure the SMBus host is ready to start transmitting. */
131         if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
132                 dev_dbg(&adap->dev, "SMBus busy (%02x).Resetting...\n",temp);
133                 /* kill smbus transaction */
134                 sis630_write(SMBHOST_CNT, 0x20);
135
136                 if ((temp = sis630_read(SMB_CNT) & 0x03) != 0x00) {
137                         dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
138                         return -EBUSY;
139                 } else {
140                         dev_dbg(&adap->dev, "Successful!\n");
141                 }
142         }
143
144         /* save old clock, so we can prevent machine for hung */
145         *oldclock = sis630_read(SMB_CNT);
146
147         dev_dbg(&adap->dev, "saved clock 0x%02x\n", *oldclock);
148
149         /* disable timeout interrupt , set Host Master Clock to 56KHz if requested */
150         if (high_clock)
151                 sis630_write(SMB_CNT, 0x20);
152         else
153                 sis630_write(SMB_CNT, (*oldclock & ~0x40));
154
155         /* clear all sticky bits */
156         temp = sis630_read(SMB_STS);
157         sis630_write(SMB_STS, temp & 0x1e);
158
159         /* start the transaction by setting bit 4 and size */
160         sis630_write(SMBHOST_CNT,0x10 | (size & 0x07));
161
162         return 0;
163 }
164
165 static int sis630_transaction_wait(struct i2c_adapter *adap, int size)
166 {
167         int temp, result = 0, timeout = 0;
168
169         /* We will always wait for a fraction of a second! */
170         do {
171                 msleep(1);
172                 temp = sis630_read(SMB_STS);
173                 /* check if block transmitted */
174                 if (size == SIS630_BLOCK_DATA && (temp & 0x10))
175                         break;
176         } while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
177
178         /* If the SMBus is still busy, we give up */
179         if (timeout >= MAX_TIMEOUT) {
180                 dev_dbg(&adap->dev, "SMBus Timeout!\n");
181                 result = -ETIMEDOUT;
182         }
183
184         if (temp & 0x02) {
185                 dev_dbg(&adap->dev, "Error: Failed bus transaction\n");
186                 result = -ENXIO;
187         }
188
189         if (temp & 0x04) {
190                 dev_err(&adap->dev, "Bus collision!\n");
191                 result = -EIO;
192                 /*
193                   TBD: Datasheet say:
194                   the software should clear this bit and restart SMBUS operation.
195                   Should we do it or user start request again?
196                 */
197         }
198
199         return result;
200 }
201
202 static void sis630_transaction_end(struct i2c_adapter *adap, u8 oldclock)
203 {
204         int temp = 0;
205
206         /* clear all status "sticky" bits */
207         sis630_write(SMB_STS, temp);
208
209         dev_dbg(&adap->dev, "SMB_CNT before clock restore 0x%02x\n", sis630_read(SMB_CNT));
210
211         /*
212          * restore old Host Master Clock if high_clock is set
213          * and oldclock was not 56KHz
214          */
215         if (high_clock && !(oldclock & 0x20))
216                 sis630_write(SMB_CNT,(sis630_read(SMB_CNT) & ~0x20));
217
218         dev_dbg(&adap->dev, "SMB_CNT after clock restore 0x%02x\n", sis630_read(SMB_CNT));
219 }
220
221 static int sis630_transaction(struct i2c_adapter *adap, int size)
222 {
223         int result = 0;
224         u8 oldclock = 0;
225
226         result = sis630_transaction_start(adap, size, &oldclock);
227         if (!result) {
228                 result = sis630_transaction_wait(adap, size);
229                 sis630_transaction_end(adap, oldclock);
230         }
231
232         return result;
233 }
234
235 static int sis630_block_data(struct i2c_adapter *adap, union i2c_smbus_data *data, int read_write)
236 {
237         int i, len = 0, rc = 0;
238         u8 oldclock = 0;
239
240         if (read_write == I2C_SMBUS_WRITE) {
241                 len = data->block[0];
242                 if (len < 0)
243                         len = 0;
244                 else if (len > 32)
245                         len = 32;
246                 sis630_write(SMB_COUNT, len);
247                 for (i=1; i <= len; i++) {
248                         dev_dbg(&adap->dev, "set data 0x%02x\n", data->block[i]);
249                         /* set data */
250                         sis630_write(SMB_BYTE+(i-1)%8, data->block[i]);
251                         if (i==8 || (len<8 && i==len)) {
252                                 dev_dbg(&adap->dev, "start trans len=%d i=%d\n",len ,i);
253                                 /* first transaction */
254                                 rc = sis630_transaction_start(adap,
255                                                 SIS630_BLOCK_DATA, &oldclock);
256                                 if (rc)
257                                         return rc;
258                         }
259                         else if ((i-1)%8 == 7 || i==len) {
260                                 dev_dbg(&adap->dev, "trans_wait len=%d i=%d\n",len,i);
261                                 if (i>8) {
262                                         dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i);
263                                         /*
264                                            If this is not first transaction,
265                                            we must clear sticky bit.
266                                            clear SMBARY_STS
267                                         */
268                                         sis630_write(SMB_STS,0x10);
269                                 }
270                                 rc = sis630_transaction_wait(adap,
271                                                 SIS630_BLOCK_DATA);
272                                 if (rc) {
273                                         dev_dbg(&adap->dev, "trans_wait failed\n");
274                                         break;
275                                 }
276                         }
277                 }
278         }
279         else {
280                 /* read request */
281                 data->block[0] = len = 0;
282                 rc = sis630_transaction_start(adap,
283                                 SIS630_BLOCK_DATA, &oldclock);
284                 if (rc)
285                         return rc;
286                 do {
287                         rc = sis630_transaction_wait(adap, SIS630_BLOCK_DATA);
288                         if (rc) {
289                                 dev_dbg(&adap->dev, "trans_wait failed\n");
290                                 break;
291                         }
292                         /* if this first transaction then read byte count */
293                         if (len == 0)
294                                 data->block[0] = sis630_read(SMB_COUNT);
295
296                         /* just to be sure */
297                         if (data->block[0] > 32)
298                                 data->block[0] = 32;
299
300                         dev_dbg(&adap->dev, "block data read len=0x%x\n", data->block[0]);
301
302                         for (i=0; i < 8 && len < data->block[0]; i++,len++) {
303                                 dev_dbg(&adap->dev, "read i=%d len=%d\n", i, len);
304                                 data->block[len+1] = sis630_read(SMB_BYTE+i);
305                         }
306
307                         dev_dbg(&adap->dev, "clear smbary_sts len=%d i=%d\n",len,i);
308
309                         /* clear SMBARY_STS */
310                         sis630_write(SMB_STS,0x10);
311                 } while(len < data->block[0]);
312         }
313
314         sis630_transaction_end(adap, oldclock);
315
316         return rc;
317 }
318
319 /* Return negative errno on error. */
320 static s32 sis630_access(struct i2c_adapter *adap, u16 addr,
321                          unsigned short flags, char read_write,
322                          u8 command, int size, union i2c_smbus_data *data)
323 {
324         int status;
325
326         switch (size) {
327                 case I2C_SMBUS_QUICK:
328                         sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
329                         size = SIS630_QUICK;
330                         break;
331                 case I2C_SMBUS_BYTE:
332                         sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
333                         if (read_write == I2C_SMBUS_WRITE)
334                                 sis630_write(SMB_CMD, command);
335                         size = SIS630_BYTE;
336                         break;
337                 case I2C_SMBUS_BYTE_DATA:
338                         sis630_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
339                         sis630_write(SMB_CMD, command);
340                         if (read_write == I2C_SMBUS_WRITE)
341                                 sis630_write(SMB_BYTE, data->byte);
342                         size = SIS630_BYTE_DATA;
343                         break;
344                 case I2C_SMBUS_PROC_CALL:
345                 case I2C_SMBUS_WORD_DATA:
346                         sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
347                         sis630_write(SMB_CMD, command);
348                         if (read_write == I2C_SMBUS_WRITE) {
349                                 sis630_write(SMB_BYTE, data->word & 0xff);
350                                 sis630_write(SMB_BYTE + 1,(data->word & 0xff00) >> 8);
351                         }
352                         size = (size == I2C_SMBUS_PROC_CALL ? SIS630_PCALL : SIS630_WORD_DATA);
353                         break;
354                 case I2C_SMBUS_BLOCK_DATA:
355                         sis630_write(SMB_ADDR,((addr & 0x7f) << 1) | (read_write & 0x01));
356                         sis630_write(SMB_CMD, command);
357                         size = SIS630_BLOCK_DATA;
358                         return sis630_block_data(adap, data, read_write);
359                 default:
360                         dev_warn(&adap->dev, "Unsupported transaction %d\n",
361                                  size);
362                         return -EOPNOTSUPP;
363         }
364
365         status = sis630_transaction(adap, size);
366         if (status)
367                 return status;
368
369         if ((size != SIS630_PCALL) &&
370                 ((read_write == I2C_SMBUS_WRITE) || (size == SIS630_QUICK))) {
371                 return 0;
372         }
373
374         switch(size) {
375                 case SIS630_BYTE:
376                 case SIS630_BYTE_DATA:
377                         data->byte = sis630_read(SMB_BYTE);
378                         break;
379                 case SIS630_PCALL:
380                 case SIS630_WORD_DATA:
381                         data->word = sis630_read(SMB_BYTE) + (sis630_read(SMB_BYTE + 1) << 8);
382                         break;
383         }
384
385         return 0;
386 }
387
388 static u32 sis630_func(struct i2c_adapter *adapter)
389 {
390         return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
391                 I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL |
392                 I2C_FUNC_SMBUS_BLOCK_DATA;
393 }
394
395 static int sis630_setup(struct pci_dev *sis630_dev)
396 {
397         unsigned char b;
398         struct pci_dev *dummy = NULL;
399         int retval = -ENODEV, i;
400
401         /* check for supported SiS devices */
402         for (i=0; supported[i] > 0 ; i++) {
403                 if ((dummy = pci_get_device(PCI_VENDOR_ID_SI, supported[i], dummy)))
404                         break; /* found */
405         }
406
407         if (dummy) {
408                 pci_dev_put(dummy);
409         }
410         else if (force) {
411                 dev_err(&sis630_dev->dev, "WARNING: Can't detect SIS630 compatible device, but "
412                         "loading because of force option enabled\n");
413         }
414         else {
415                 return -ENODEV;
416         }
417
418         /*
419            Enable ACPI first , so we can accsess reg 74-75
420            in acpi io space and read acpi base addr
421         */
422         if (pci_read_config_byte(sis630_dev, SIS630_BIOS_CTL_REG,&b)) {
423                 dev_err(&sis630_dev->dev, "Error: Can't read bios ctl reg\n");
424                 goto exit;
425         }
426         /* if ACPI already enabled , do nothing */
427         if (!(b & 0x80) &&
428             pci_write_config_byte(sis630_dev, SIS630_BIOS_CTL_REG, b | 0x80)) {
429                 dev_err(&sis630_dev->dev, "Error: Can't enable ACPI\n");
430                 goto exit;
431         }
432
433         /* Determine the ACPI base address */
434         if (pci_read_config_word(sis630_dev,SIS630_ACPI_BASE_REG,&acpi_base)) {
435                 dev_err(&sis630_dev->dev, "Error: Can't determine ACPI base address\n");
436                 goto exit;
437         }
438
439         dev_dbg(&sis630_dev->dev, "ACPI base at 0x%04x\n", acpi_base);
440
441         retval = acpi_check_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
442                                    sis630_driver.name);
443         if (retval)
444                 goto exit;
445
446         /* Everything is happy, let's grab the memory and set things up. */
447         if (!request_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION,
448                             sis630_driver.name)) {
449                 dev_err(&sis630_dev->dev, "SMBus registers 0x%04x-0x%04x already "
450                         "in use!\n", acpi_base + SMB_STS, acpi_base + SMB_SAA);
451                 goto exit;
452         }
453
454         retval = 0;
455
456 exit:
457         if (retval)
458                 acpi_base = 0;
459         return retval;
460 }
461
462
463 static const struct i2c_algorithm smbus_algorithm = {
464         .smbus_xfer     = sis630_access,
465         .functionality  = sis630_func,
466 };
467
468 static struct i2c_adapter sis630_adapter = {
469         .owner          = THIS_MODULE,
470         .id             = I2C_HW_SMBUS_SIS630,
471         .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
472         .algo           = &smbus_algorithm,
473 };
474
475 static struct pci_device_id sis630_ids[] __devinitdata = {
476         { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
477         { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
478         { 0, }
479 };
480
481 MODULE_DEVICE_TABLE (pci, sis630_ids);
482
483 static int __devinit sis630_probe(struct pci_dev *dev, const struct pci_device_id *id)
484 {
485         if (sis630_setup(dev)) {
486                 dev_err(&dev->dev, "SIS630 comp. bus not detected, module not inserted.\n");
487                 return -ENODEV;
488         }
489
490         /* set up the sysfs linkage to our parent device */
491         sis630_adapter.dev.parent = &dev->dev;
492
493         sprintf(sis630_adapter.name, "SMBus SIS630 adapter at %04x",
494                 acpi_base + SMB_STS);
495
496         return i2c_add_adapter(&sis630_adapter);
497 }
498
499 static void __devexit sis630_remove(struct pci_dev *dev)
500 {
501         if (acpi_base) {
502                 i2c_del_adapter(&sis630_adapter);
503                 release_region(acpi_base + SMB_STS, SIS630_SMB_IOREGION);
504                 acpi_base = 0;
505         }
506 }
507
508
509 static struct pci_driver sis630_driver = {
510         .name           = "sis630_smbus",
511         .id_table       = sis630_ids,
512         .probe          = sis630_probe,
513         .remove         = __devexit_p(sis630_remove),
514 };
515
516 static int __init i2c_sis630_init(void)
517 {
518         return pci_register_driver(&sis630_driver);
519 }
520
521
522 static void __exit i2c_sis630_exit(void)
523 {
524         pci_unregister_driver(&sis630_driver);
525 }
526
527
528 MODULE_LICENSE("GPL");
529 MODULE_AUTHOR("Alexander Malysh <amalysh@web.de>");
530 MODULE_DESCRIPTION("SIS630 SMBus driver");
531
532 module_init(i2c_sis630_init);
533 module_exit(i2c_sis630_exit);