Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
new file mode 100644
index 0000000..6d13127
--- /dev/null
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -0,0 +1,410 @@
+/*
+    SMBus driver for nVidia nForce2 MCP
+
+    Added nForce3 Pro 150  Thomas Leibold <thomas@plx.com>,
+	Ported to 2.5 Patrick Dreker <patrick@dreker.de>,
+    Copyright (c) 2003  Hans-Frieder Vogt <hfvogt@arcor.de>,
+    Based on
+    SMBus 2.0 driver for AMD-8111 IO-Hub
+    Copyright (c) 2002 Vojtech Pavlik
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    SUPPORTED DEVICES		PCI ID
+    nForce2 MCP			0064
+    nForce2 Ultra 400 MCP	0084
+    nForce3 Pro150 MCP		00D4
+    nForce3 250Gb MCP		00E4
+    nForce4 MCP			0052
+
+    This driver supports the 2 SMBuses that are included in the MCP of the
+    nForce2/3/4 chipsets.
+*/
+
+/* Note: we assume there can only be one nForce2, with two SMBus interfaces */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Hans-Frieder Vogt <hfvogt@arcor.de>");
+MODULE_DESCRIPTION("nForce2 SMBus driver");
+
+
+struct nforce2_smbus {
+	struct pci_dev *dev;
+	struct i2c_adapter adapter;
+	int base;
+	int size;
+};
+
+
+/*
+ * nVidia nForce2 SMBus control register definitions
+ */
+#define NFORCE_PCI_SMB1	0x50
+#define NFORCE_PCI_SMB2	0x54
+
+
+/*
+ * ACPI 2.0 chapter 13 SMBus 2.0 EC register model
+ */
+#define NVIDIA_SMB_PRTCL	(smbus->base + 0x00)	/* protocol, PEC */
+#define NVIDIA_SMB_STS		(smbus->base + 0x01)	/* status */
+#define NVIDIA_SMB_ADDR		(smbus->base + 0x02)	/* address */
+#define NVIDIA_SMB_CMD		(smbus->base + 0x03)	/* command */
+#define NVIDIA_SMB_DATA		(smbus->base + 0x04)	/* 32 data registers */
+#define NVIDIA_SMB_BCNT		(smbus->base + 0x24)	/* number of data bytes */
+#define NVIDIA_SMB_ALRM_A	(smbus->base + 0x25)	/* alarm address */
+#define NVIDIA_SMB_ALRM_D	(smbus->base + 0x26)	/* 2 bytes alarm data */
+
+#define NVIDIA_SMB_STS_DONE	0x80
+#define NVIDIA_SMB_STS_ALRM	0x40
+#define NVIDIA_SMB_STS_RES	0x20
+#define NVIDIA_SMB_STS_STATUS	0x1f
+
+#define NVIDIA_SMB_PRTCL_WRITE			0x00
+#define NVIDIA_SMB_PRTCL_READ			0x01
+#define NVIDIA_SMB_PRTCL_QUICK			0x02
+#define NVIDIA_SMB_PRTCL_BYTE			0x04
+#define NVIDIA_SMB_PRTCL_BYTE_DATA		0x06
+#define NVIDIA_SMB_PRTCL_WORD_DATA		0x08
+#define NVIDIA_SMB_PRTCL_BLOCK_DATA		0x0a
+#define NVIDIA_SMB_PRTCL_PROC_CALL		0x0c
+#define NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL	0x0d
+#define NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA		0x4a
+#define NVIDIA_SMB_PRTCL_PEC			0x80
+
+
+/* Other settings */
+#define MAX_TIMEOUT 256
+
+
+
+static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
+		       unsigned short flags, char read_write,
+		       u8 command, int size, union i2c_smbus_data *data);
+static u32 nforce2_func(struct i2c_adapter *adapter);
+
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name = "Non-I2C SMBus adapter",
+	.id = I2C_ALGO_SMBUS,
+	.smbus_xfer = nforce2_access,
+	.functionality = nforce2_func,
+};
+
+static struct i2c_adapter nforce2_adapter = {
+	.owner          = THIS_MODULE,
+	.class          = I2C_CLASS_HWMON,
+	.algo           = &smbus_algorithm,
+	.name   	= "unset",
+};
+
+/* Return -1 on error. See smbus.h for more information */
+static s32 nforce2_access(struct i2c_adapter * adap, u16 addr,
+		unsigned short flags, char read_write,
+		u8 command, int size, union i2c_smbus_data * data)
+{
+	struct nforce2_smbus *smbus = adap->algo_data;
+	unsigned char protocol, pec, temp;
+	unsigned char len = 0; /* to keep the compiler quiet */
+	int timeout = 0;
+	int i;
+
+	protocol = (read_write == I2C_SMBUS_READ) ? NVIDIA_SMB_PRTCL_READ :
+		NVIDIA_SMB_PRTCL_WRITE;
+	pec = (flags & I2C_CLIENT_PEC) ? NVIDIA_SMB_PRTCL_PEC : 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_QUICK:
+			protocol |= NVIDIA_SMB_PRTCL_QUICK;
+			read_write = I2C_SMBUS_WRITE;
+			break;
+
+		case I2C_SMBUS_BYTE:
+			if (read_write == I2C_SMBUS_WRITE)
+				outb_p(command, NVIDIA_SMB_CMD);
+			protocol |= NVIDIA_SMB_PRTCL_BYTE;
+			break;
+
+		case I2C_SMBUS_BYTE_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE)
+				outb_p(data->byte, NVIDIA_SMB_DATA);
+			protocol |= NVIDIA_SMB_PRTCL_BYTE_DATA;
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE) {
+				 outb_p(data->word, NVIDIA_SMB_DATA);
+				 outb_p(data->word >> 8, NVIDIA_SMB_DATA+1);
+			}
+			protocol |= NVIDIA_SMB_PRTCL_WORD_DATA | pec;
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+			outb_p(command, NVIDIA_SMB_CMD);
+			if (read_write == I2C_SMBUS_WRITE) {
+				len = min_t(u8, data->block[0], 32);
+				outb_p(len, NVIDIA_SMB_BCNT);
+				for (i = 0; i < len; i++)
+					outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
+			}
+			protocol |= NVIDIA_SMB_PRTCL_BLOCK_DATA | pec;
+			break;
+
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			len = min_t(u8, data->block[0], 32);
+			outb_p(command, NVIDIA_SMB_CMD);
+			outb_p(len, NVIDIA_SMB_BCNT);
+			if (read_write == I2C_SMBUS_WRITE)
+				for (i = 0; i < len; i++)
+					outb_p(data->block[i + 1], NVIDIA_SMB_DATA+i);
+			protocol |= NVIDIA_SMB_PRTCL_I2C_BLOCK_DATA;
+			break;
+
+		case I2C_SMBUS_PROC_CALL:
+			dev_err(&adap->dev, "I2C_SMBUS_PROC_CALL not supported!\n");
+			return -1;
+			/*
+			outb_p(command, NVIDIA_SMB_CMD);
+			outb_p(data->word, NVIDIA_SMB_DATA);
+			outb_p(data->word >> 8, NVIDIA_SMB_DATA + 1);
+			protocol = NVIDIA_SMB_PRTCL_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+			 */
+
+		case I2C_SMBUS_BLOCK_PROC_CALL:
+			dev_err(&adap->dev, "I2C_SMBUS_BLOCK_PROC_CALL not supported!\n");
+			return -1;
+			/*
+			protocol |= pec;
+			len = min_t(u8, data->block[0], 31);
+			outb_p(command, NVIDIA_SMB_CMD);
+			outb_p(len, NVIDIA_SMB_BCNT);
+			for (i = 0; i < len; i++)
+				outb_p(data->block[i + 1], NVIDIA_SMB_DATA + i);
+			protocol = NVIDIA_SMB_PRTCL_BLOCK_PROC_CALL | pec;
+			read_write = I2C_SMBUS_READ;
+			break;
+			*/
+
+		case I2C_SMBUS_WORD_DATA_PEC:
+		case I2C_SMBUS_BLOCK_DATA_PEC:
+		case I2C_SMBUS_PROC_CALL_PEC:
+		case I2C_SMBUS_BLOCK_PROC_CALL_PEC:
+			dev_err(&adap->dev, "Unexpected software PEC transaction %d\n.", size);
+			return -1;
+
+		default:
+			dev_err(&adap->dev, "Unsupported transaction %d\n", size);
+			return -1;
+	}
+
+	outb_p((addr & 0x7f) << 1, NVIDIA_SMB_ADDR);
+	outb_p(protocol, NVIDIA_SMB_PRTCL);
+
+	temp = inb_p(NVIDIA_SMB_STS);
+
+#if 0
+	do {
+		i2c_do_pause(1);
+		temp = inb_p(NVIDIA_SMB_STS);
+	} while (((temp & NVIDIA_SMB_STS_DONE) == 0) && (timeout++ < MAX_TIMEOUT));
+#endif
+	if (~temp & NVIDIA_SMB_STS_DONE) {
+		udelay(500);
+		temp = inb_p(NVIDIA_SMB_STS);
+	}
+	if (~temp & NVIDIA_SMB_STS_DONE) {
+		msleep(10);
+		temp = inb_p(NVIDIA_SMB_STS);
+	}
+
+	if ((timeout >= MAX_TIMEOUT) || (~temp & NVIDIA_SMB_STS_DONE)
+		|| (temp & NVIDIA_SMB_STS_STATUS))
+		return -1;
+
+	if (read_write == I2C_SMBUS_WRITE)
+		return 0;
+
+	switch (size) {
+
+		case I2C_SMBUS_BYTE:
+		case I2C_SMBUS_BYTE_DATA:
+			data->byte = inb_p(NVIDIA_SMB_DATA);
+			break;
+
+		case I2C_SMBUS_WORD_DATA:
+		/* case I2C_SMBUS_PROC_CALL: not supported */
+			data->word = inb_p(NVIDIA_SMB_DATA) | (inb_p(NVIDIA_SMB_DATA+1) << 8);
+			break;
+
+		case I2C_SMBUS_BLOCK_DATA:
+		/* case I2C_SMBUS_BLOCK_PROC_CALL: not supported */
+			len = inb_p(NVIDIA_SMB_BCNT);
+			len = min_t(u8, len, 32);
+		case I2C_SMBUS_I2C_BLOCK_DATA:
+			for (i = 0; i < len; i++)
+				data->block[i+1] = inb_p(NVIDIA_SMB_DATA + i);
+			data->block[0] = len;
+			break;
+	}
+
+	return 0;
+}
+
+
+static u32 nforce2_func(struct i2c_adapter *adapter)
+{
+	/* other functionality might be possible, but is not tested */
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA /* |
+	    I2C_FUNC_SMBUS_BLOCK_DATA */;
+}
+
+
+static struct pci_device_id nforce2_ids[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS) },
+	{ 0 }
+};
+
+
+MODULE_DEVICE_TABLE (pci, nforce2_ids);
+
+
+static int __devinit nforce2_probe_smb (struct pci_dev *dev, int reg,
+	struct nforce2_smbus *smbus, char *name)
+{
+	u16 iobase;
+	int error;
+
+	if (pci_read_config_word(dev, reg, &iobase) != PCIBIOS_SUCCESSFUL) {
+		dev_err(&smbus->adapter.dev, "Error reading PCI config for %s\n", name);
+		return -1;
+	}
+	smbus->dev  = dev;
+	smbus->base = iobase & 0xfffc;
+	smbus->size = 8;
+
+	if (!request_region(smbus->base, smbus->size, "nForce2 SMBus")) {
+		dev_err(&smbus->adapter.dev, "Error requesting region %02x .. %02X for %s\n",
+			smbus->base, smbus->base+smbus->size-1, name);
+		return -1;
+	}
+	smbus->adapter = nforce2_adapter;
+	smbus->adapter.algo_data = smbus;
+	smbus->adapter.dev.parent = &dev->dev;
+	snprintf(smbus->adapter.name, I2C_NAME_SIZE,
+		"SMBus nForce2 adapter at %04x", smbus->base);
+
+	error = i2c_add_adapter(&smbus->adapter);
+	if (error) {
+		dev_err(&smbus->adapter.dev, "Failed to register adapter.\n");
+		release_region(smbus->base, smbus->size);
+		return -1;
+	}
+	dev_info(&smbus->adapter.dev, "nForce2 SMBus adapter at %#x\n", smbus->base);
+	return 0;
+}
+
+
+static int __devinit nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+	struct nforce2_smbus *smbuses;
+	int res1, res2;
+
+	/* we support 2 SMBus adapters */
+	if (!(smbuses = (void *)kmalloc(2*sizeof(struct nforce2_smbus),
+				       	GFP_KERNEL)))
+		return -ENOMEM;
+	memset (smbuses, 0, 2*sizeof(struct nforce2_smbus));
+	pci_set_drvdata(dev, smbuses);
+
+	/* SMBus adapter 1 */
+	res1 = nforce2_probe_smb (dev, NFORCE_PCI_SMB1, &smbuses[0], "SMB1");
+	if (res1 < 0) {
+		dev_err(&dev->dev, "Error probing SMB1.\n");
+		smbuses[0].base = 0;	/* to have a check value */
+	}
+	res2 = nforce2_probe_smb (dev, NFORCE_PCI_SMB2, &smbuses[1], "SMB2");
+	if (res2 < 0) {
+		dev_err(&dev->dev, "Error probing SMB2.\n");
+		smbuses[1].base = 0;	/* to have a check value */
+	}
+	if ((res1 < 0) && (res2 < 0)) {
+		/* we did not find even one of the SMBuses, so we give up */
+		kfree(smbuses);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
+static void __devexit nforce2_remove(struct pci_dev *dev)
+{
+	struct nforce2_smbus *smbuses = (void*) pci_get_drvdata(dev);
+
+	if (smbuses[0].base) {
+		i2c_del_adapter(&smbuses[0].adapter);
+		release_region(smbuses[0].base, smbuses[0].size);
+	}
+	if (smbuses[1].base) {
+		i2c_del_adapter(&smbuses[1].adapter);
+		release_region(smbuses[1].base, smbuses[1].size);
+	}
+	kfree(smbuses);
+}
+
+static struct pci_driver nforce2_driver = {
+	.name		= "nForce2_smbus",
+	.id_table	= nforce2_ids,
+	.probe		= nforce2_probe,
+	.remove		= __devexit_p(nforce2_remove),
+};
+
+static int __init nforce2_init(void)
+{
+	return pci_register_driver(&nforce2_driver);
+}
+
+static void __exit nforce2_exit(void)
+{
+	pci_unregister_driver(&nforce2_driver);
+}
+
+module_init(nforce2_init);
+module_exit(nforce2_exit);
+