Linux Audio

Check our new training course

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