Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/i2c/busses/i2c-sis630.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us