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