diff options
Diffstat (limited to 'drivers/i2c')
| -rw-r--r-- | drivers/i2c/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/i2c/algos/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/i2c/busses/Kconfig | 15 | ||||
| -rw-r--r-- | drivers/i2c/busses/Makefile | 1 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-i801.c | 343 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-intel-mid.c | 1135 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-nomadik.c | 36 | ||||
| -rw-r--r-- | drivers/i2c/busses/i2c-s3c2410.c | 10 | ||||
| -rw-r--r-- | drivers/i2c/busses/scx200_acb.c | 3 | ||||
| -rw-r--r-- | drivers/i2c/i2c-core.c | 12 | ||||
| -rw-r--r-- | drivers/i2c/i2c-mux.c | 1 | 
11 files changed, 1389 insertions, 184 deletions
| diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index b923074b2cb..30f06e956bf 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -75,8 +75,7 @@ config I2C_HELPER_AUTO  	  In doubt, say Y.  config I2C_SMBUS -	tristate -	prompt "SMBus-specific protocols" if !I2C_HELPER_AUTO +	tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO  	help  	  Say Y here if you want support for SMBus extensions to the I2C  	  specification. At the moment, the only supported extension is diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig index 3998dd620a0..f1cfe7e5508 100644 --- a/drivers/i2c/algos/Kconfig +++ b/drivers/i2c/algos/Kconfig @@ -3,7 +3,7 @@  #  menu "I2C Algorithms" -	depends on !I2C_HELPER_AUTO +	visible if !I2C_HELPER_AUTO  config I2C_ALGOBIT  	tristate "I2C bit-banging interfaces" @@ -15,15 +15,3 @@ config I2C_ALGOPCA  	tristate "I2C PCA 9564 interfaces"  endmenu - -# In automatic configuration mode, we still have to define the -# symbols to avoid unmet dependencies. - -if I2C_HELPER_AUTO -config I2C_ALGOBIT -	tristate -config I2C_ALGOPCF -	tristate -config I2C_ALGOPCA -	tristate -endif diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6539ac2907e..3a6321cb803 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -95,10 +95,11 @@ config I2C_I801  	    ESB2  	    ICH8  	    ICH9 -	    Tolapai +	    EP80579 (Tolapai)  	    ICH10 -	    3400/5 Series (PCH) +	    5/3400 Series (PCH)  	    Cougar Point (PCH) +	    Patsburg (PCH)  	  This driver can also be built as a module.  If so, the module  	  will be called i2c-i801. @@ -396,6 +397,16 @@ config I2C_IMX  	  This driver can also be built as a module.  If so, the module  	  will be called i2c-imx. +config I2C_INTEL_MID +	tristate "Intel Moorestown/Medfield Platform I2C controller" +	depends on PCI +	help +	  Say Y here if you have an Intel Moorestown/Medfield platform I2C +	  controller. + +	  This support is also available as a module. If so, the module +	  will be called i2c-intel-mid. +  config I2C_IOP3XX  	tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"  	depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 033ad413f32..84cb16ae6f9 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o  obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o  obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o  obj-$(CONFIG_I2C_IMX)		+= i2c-imx.o +obj-$(CONFIG_I2C_INTEL_MID)	+= i2c-intel-mid.o  obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o  obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o  obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c60081169cc..02835ce7ff4 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -3,6 +3,8 @@      Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker      <mdsxyz123@yahoo.com>      Copyright (C) 2007, 2008   Jean Delvare <khali@linux-fr.org> +    Copyright (C) 2010         Intel Corporation, +                               David Woodhouse <dwmw2@infradead.org>      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 @@ -38,11 +40,15 @@    82801G   (ICH7)       0x27da     32     hard     yes     yes     yes    82801H   (ICH8)       0x283e     32     hard     yes     yes     yes    82801I   (ICH9)       0x2930     32     hard     yes     yes     yes -  Tolapai               0x5032     32     hard     yes     yes     yes +  EP80579 (Tolapai)     0x5032     32     hard     yes     yes     yes    ICH10                 0x3a30     32     hard     yes     yes     yes    ICH10                 0x3a60     32     hard     yes     yes     yes -  3400/5 Series (PCH)   0x3b30     32     hard     yes     yes     yes +  5/3400 Series (PCH)   0x3b30     32     hard     yes     yes     yes    Cougar Point (PCH)    0x1c22     32     hard     yes     yes     yes +  Patsburg (PCH)        0x1d22     32     hard     yes     yes     yes +  Patsburg (PCH) IDF    0x1d70     32     hard     yes     yes     yes +  Patsburg (PCH) IDF    0x1d71     32     hard     yes     yes     yes +  Patsburg (PCH) IDF    0x1d72     32     hard     yes     yes     yes    Features supported by this driver:    Software PEC                     no @@ -50,12 +56,11 @@    Block buffer                     yes    Block process call transaction   no    I2C block read transaction       yes  (doesn't use the block buffer) +  Slave mode                       no    See the file Documentation/i2c/busses/i2c-i801 for details.  */ -/* Note: we assume there can only be one I801, with one SMBus interface */ -  #include <linux/module.h>  #include <linux/pci.h>  #include <linux/kernel.h> @@ -69,16 +74,16 @@  #include <linux/dmi.h>  /* I801 SMBus address offsets */ -#define SMBHSTSTS	(0 + i801_smba) -#define SMBHSTCNT	(2 + i801_smba) -#define SMBHSTCMD	(3 + i801_smba) -#define SMBHSTADD	(4 + i801_smba) -#define SMBHSTDAT0	(5 + i801_smba) -#define SMBHSTDAT1	(6 + i801_smba) -#define SMBBLKDAT	(7 + i801_smba) -#define SMBPEC		(8 + i801_smba)		/* ICH3 and later */ -#define SMBAUXSTS	(12 + i801_smba)	/* ICH4 and later */ -#define SMBAUXCTL	(13 + i801_smba)	/* ICH4 and later */ +#define SMBHSTSTS(p)	(0 + (p)->smba) +#define SMBHSTCNT(p)	(2 + (p)->smba) +#define SMBHSTCMD(p)	(3 + (p)->smba) +#define SMBHSTADD(p)	(4 + (p)->smba) +#define SMBHSTDAT0(p)	(5 + (p)->smba) +#define SMBHSTDAT1(p)	(6 + (p)->smba) +#define SMBBLKDAT(p)	(7 + (p)->smba) +#define SMBPEC(p)	(8 + (p)->smba)		/* ICH3 and later */ +#define SMBAUXSTS(p)	(12 + (p)->smba)	/* ICH4 and later */ +#define SMBAUXCTL(p)	(13 + (p)->smba)	/* ICH4 and later */  /* PCI Address Constants */  #define SMBBAR		4 @@ -127,16 +132,25 @@  				 SMBHSTSTS_BUS_ERR | SMBHSTSTS_DEV_ERR | \  				 SMBHSTSTS_INTR) -static unsigned long i801_smba; -static unsigned char i801_original_hstcfg; +/* Patsburg also has three 'Integrated Device Function' SMBus controllers */ +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0	0x1d70 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1	0x1d71 +#define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2	0x1d72 + +struct i801_priv { +	struct i2c_adapter adapter; +	unsigned long smba; +	unsigned char original_hstcfg; +	struct pci_dev *pci_dev; +	unsigned int features; +}; +  static struct pci_driver i801_driver; -static struct pci_dev *I801_dev;  #define FEATURE_SMBUS_PEC	(1 << 0)  #define FEATURE_BLOCK_BUFFER	(1 << 1)  #define FEATURE_BLOCK_PROC	(1 << 2)  #define FEATURE_I2C_BLOCK_READ	(1 << 3) -static unsigned int i801_features;  static const char *i801_feature_names[] = {  	"SMBus PEC", @@ -151,24 +165,24 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features");  /* Make sure the SMBus host is ready to start transmitting.     Return 0 if it is, -EBUSY if it is not. */ -static int i801_check_pre(void) +static int i801_check_pre(struct i801_priv *priv)  {  	int status; -	status = inb_p(SMBHSTSTS); +	status = inb_p(SMBHSTSTS(priv));  	if (status & SMBHSTSTS_HOST_BUSY) { -		dev_err(&I801_dev->dev, "SMBus is busy, can't use it!\n"); +		dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n");  		return -EBUSY;  	}  	status &= STATUS_FLAGS;  	if (status) { -		dev_dbg(&I801_dev->dev, "Clearing status flags (%02x)\n", +		dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n",  			status); -		outb_p(status, SMBHSTSTS); -		status = inb_p(SMBHSTSTS) & STATUS_FLAGS; +		outb_p(status, SMBHSTSTS(priv)); +		status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;  		if (status) { -			dev_err(&I801_dev->dev, +			dev_err(&priv->pci_dev->dev,  				"Failed clearing status flags (%02x)\n",  				status);  			return -EBUSY; @@ -179,48 +193,50 @@ static int i801_check_pre(void)  }  /* Convert the status register to an error code, and clear it. */ -static int i801_check_post(int status, int timeout) +static int i801_check_post(struct i801_priv *priv, int status, int timeout)  {  	int result = 0;  	/* If the SMBus is still busy, we give up */  	if (timeout) { -		dev_err(&I801_dev->dev, "Transaction timeout\n"); +		dev_err(&priv->pci_dev->dev, "Transaction timeout\n");  		/* try to stop the current command */ -		dev_dbg(&I801_dev->dev, "Terminating the current operation\n"); -		outb_p(inb_p(SMBHSTCNT) | SMBHSTCNT_KILL, SMBHSTCNT); +		dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); +		outb_p(inb_p(SMBHSTCNT(priv)) | SMBHSTCNT_KILL, +		       SMBHSTCNT(priv));  		msleep(1); -		outb_p(inb_p(SMBHSTCNT) & (~SMBHSTCNT_KILL), SMBHSTCNT); +		outb_p(inb_p(SMBHSTCNT(priv)) & (~SMBHSTCNT_KILL), +		       SMBHSTCNT(priv));  		/* Check if it worked */ -		status = inb_p(SMBHSTSTS); +		status = inb_p(SMBHSTSTS(priv));  		if ((status & SMBHSTSTS_HOST_BUSY) ||  		    !(status & SMBHSTSTS_FAILED)) -			dev_err(&I801_dev->dev, +			dev_err(&priv->pci_dev->dev,  				"Failed terminating the transaction\n"); -		outb_p(STATUS_FLAGS, SMBHSTSTS); +		outb_p(STATUS_FLAGS, SMBHSTSTS(priv));  		return -ETIMEDOUT;  	}  	if (status & SMBHSTSTS_FAILED) {  		result = -EIO; -		dev_err(&I801_dev->dev, "Transaction failed\n"); +		dev_err(&priv->pci_dev->dev, "Transaction failed\n");  	}  	if (status & SMBHSTSTS_DEV_ERR) {  		result = -ENXIO; -		dev_dbg(&I801_dev->dev, "No response\n"); +		dev_dbg(&priv->pci_dev->dev, "No response\n");  	}  	if (status & SMBHSTSTS_BUS_ERR) {  		result = -EAGAIN; -		dev_dbg(&I801_dev->dev, "Lost arbitration\n"); +		dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n");  	}  	if (result) {  		/* Clear error flags */ -		outb_p(status & STATUS_FLAGS, SMBHSTSTS); -		status = inb_p(SMBHSTSTS) & STATUS_FLAGS; +		outb_p(status & STATUS_FLAGS, SMBHSTSTS(priv)); +		status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS;  		if (status) { -			dev_warn(&I801_dev->dev, "Failed clearing status " +			dev_warn(&priv->pci_dev->dev, "Failed clearing status "  				 "flags at end of transaction (%02x)\n",  				 status);  		} @@ -229,86 +245,88 @@ static int i801_check_post(int status, int timeout)  	return result;  } -static int i801_transaction(int xact) +static int i801_transaction(struct i801_priv *priv, int xact)  {  	int status;  	int result;  	int timeout = 0; -	result = i801_check_pre(); +	result = i801_check_pre(priv);  	if (result < 0)  		return result;  	/* the current contents of SMBHSTCNT can be overwritten, since PEC,  	 * INTREN, SMBSCMD are passed in xact */ -	outb_p(xact | I801_START, SMBHSTCNT); +	outb_p(xact | I801_START, SMBHSTCNT(priv));  	/* We will always wait for a fraction of a second! */  	do {  		msleep(1); -		status = inb_p(SMBHSTSTS); +		status = inb_p(SMBHSTSTS(priv));  	} while ((status & SMBHSTSTS_HOST_BUSY) && (timeout++ < MAX_TIMEOUT)); -	result = i801_check_post(status, timeout > MAX_TIMEOUT); +	result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);  	if (result < 0)  		return result; -	outb_p(SMBHSTSTS_INTR, SMBHSTSTS); +	outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));  	return 0;  }  /* wait for INTR bit as advised by Intel */ -static void i801_wait_hwpec(void) +static void i801_wait_hwpec(struct i801_priv *priv)  {  	int timeout = 0;  	int status;  	do {  		msleep(1); -		status = inb_p(SMBHSTSTS); +		status = inb_p(SMBHSTSTS(priv));  	} while ((!(status & SMBHSTSTS_INTR))  		 && (timeout++ < MAX_TIMEOUT));  	if (timeout > MAX_TIMEOUT) -		dev_dbg(&I801_dev->dev, "PEC Timeout!\n"); +		dev_dbg(&priv->pci_dev->dev, "PEC Timeout!\n"); -	outb_p(status, SMBHSTSTS); +	outb_p(status, SMBHSTSTS(priv));  } -static int i801_block_transaction_by_block(union i2c_smbus_data *data, +static int i801_block_transaction_by_block(struct i801_priv *priv, +					   union i2c_smbus_data *data,  					   char read_write, int hwpec)  {  	int i, len;  	int status; -	inb_p(SMBHSTCNT); /* reset the data buffer index */ +	inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */  	/* Use 32-byte buffer to process this transaction */  	if (read_write == I2C_SMBUS_WRITE) {  		len = data->block[0]; -		outb_p(len, SMBHSTDAT0); +		outb_p(len, SMBHSTDAT0(priv));  		for (i = 0; i < len; i++) -			outb_p(data->block[i+1], SMBBLKDAT); +			outb_p(data->block[i+1], SMBBLKDAT(priv));  	} -	status = i801_transaction(I801_BLOCK_DATA | ENABLE_INT9 | +	status = i801_transaction(priv, I801_BLOCK_DATA | ENABLE_INT9 |  				  I801_PEC_EN * hwpec);  	if (status)  		return status;  	if (read_write == I2C_SMBUS_READ) { -		len = inb_p(SMBHSTDAT0); +		len = inb_p(SMBHSTDAT0(priv));  		if (len < 1 || len > I2C_SMBUS_BLOCK_MAX)  			return -EPROTO;  		data->block[0] = len;  		for (i = 0; i < len; i++) -			data->block[i + 1] = inb_p(SMBBLKDAT); +			data->block[i + 1] = inb_p(SMBBLKDAT(priv));  	}  	return 0;  } -static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data, +static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, +					       union i2c_smbus_data *data,  					       char read_write, int command,  					       int hwpec)  { @@ -318,15 +336,15 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,  	int result;  	int timeout; -	result = i801_check_pre(); +	result = i801_check_pre(priv);  	if (result < 0)  		return result;  	len = data->block[0];  	if (read_write == I2C_SMBUS_WRITE) { -		outb_p(len, SMBHSTDAT0); -		outb_p(data->block[1], SMBBLKDAT); +		outb_p(len, SMBHSTDAT0(priv)); +		outb_p(data->block[1], SMBBLKDAT(priv));  	}  	for (i = 1; i <= len; i++) { @@ -342,34 +360,37 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,  			else  				smbcmd = I801_BLOCK_DATA;  		} -		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT); +		outb_p(smbcmd | ENABLE_INT9, SMBHSTCNT(priv));  		if (i == 1) -			outb_p(inb(SMBHSTCNT) | I801_START, SMBHSTCNT); +			outb_p(inb(SMBHSTCNT(priv)) | I801_START, +			       SMBHSTCNT(priv));  		/* We will always wait for a fraction of a second! */  		timeout = 0;  		do {  			msleep(1); -			status = inb_p(SMBHSTSTS); +			status = inb_p(SMBHSTSTS(priv));  		} while ((!(status & SMBHSTSTS_BYTE_DONE))  			 && (timeout++ < MAX_TIMEOUT)); -		result = i801_check_post(status, timeout > MAX_TIMEOUT); +		result = i801_check_post(priv, status, timeout > MAX_TIMEOUT);  		if (result < 0)  			return result;  		if (i == 1 && read_write == I2C_SMBUS_READ  		 && command != I2C_SMBUS_I2C_BLOCK_DATA) { -			len = inb_p(SMBHSTDAT0); +			len = inb_p(SMBHSTDAT0(priv));  			if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { -				dev_err(&I801_dev->dev, +				dev_err(&priv->pci_dev->dev,  					"Illegal SMBus block read size %d\n",  					len);  				/* Recover */ -				while (inb_p(SMBHSTSTS) & SMBHSTSTS_HOST_BUSY) -					outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS); -				outb_p(SMBHSTSTS_INTR, SMBHSTSTS); +				while (inb_p(SMBHSTSTS(priv)) & +				       SMBHSTSTS_HOST_BUSY) +					outb_p(SMBHSTSTS_BYTE_DONE, +					       SMBHSTSTS(priv)); +				outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv));  				return -EPROTO;  			}  			data->block[0] = len; @@ -377,27 +398,28 @@ static int i801_block_transaction_byte_by_byte(union i2c_smbus_data *data,  		/* Retrieve/store value in SMBBLKDAT */  		if (read_write == I2C_SMBUS_READ) -			data->block[i] = inb_p(SMBBLKDAT); +			data->block[i] = inb_p(SMBBLKDAT(priv));  		if (read_write == I2C_SMBUS_WRITE && i+1 <= len) -			outb_p(data->block[i+1], SMBBLKDAT); +			outb_p(data->block[i+1], SMBBLKDAT(priv));  		/* signals SMBBLKDAT ready */ -		outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS); +		outb_p(SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR, SMBHSTSTS(priv));  	}  	return 0;  } -static int i801_set_block_buffer_mode(void) +static int i801_set_block_buffer_mode(struct i801_priv *priv)  { -	outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_E32B, SMBAUXCTL); -	if ((inb_p(SMBAUXCTL) & SMBAUXCTL_E32B) == 0) +	outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); +	if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0)  		return -EIO;  	return 0;  }  /* Block transaction function */ -static int i801_block_transaction(union i2c_smbus_data *data, char read_write, +static int i801_block_transaction(struct i801_priv *priv, +				  union i2c_smbus_data *data, char read_write,  				  int command, int hwpec)  {  	int result = 0; @@ -406,11 +428,11 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,  	if (command == I2C_SMBUS_I2C_BLOCK_DATA) {  		if (read_write == I2C_SMBUS_WRITE) {  			/* set I2C_EN bit in configuration register */ -			pci_read_config_byte(I801_dev, SMBHSTCFG, &hostc); -			pci_write_config_byte(I801_dev, SMBHSTCFG, +			pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); +			pci_write_config_byte(priv->pci_dev, SMBHSTCFG,  					      hostc | SMBHSTCFG_I2C_EN); -		} else if (!(i801_features & FEATURE_I2C_BLOCK_READ)) { -			dev_err(&I801_dev->dev, +		} else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { +			dev_err(&priv->pci_dev->dev,  				"I2C block read is unsupported!\n");  			return -EOPNOTSUPP;  		} @@ -429,22 +451,23 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,  	/* Experience has shown that the block buffer can only be used for  	   SMBus (not I2C) block transactions, even though the datasheet  	   doesn't mention this limitation. */ -	if ((i801_features & FEATURE_BLOCK_BUFFER) +	if ((priv->features & FEATURE_BLOCK_BUFFER)  	 && command != I2C_SMBUS_I2C_BLOCK_DATA -	 && i801_set_block_buffer_mode() == 0) -		result = i801_block_transaction_by_block(data, read_write, -							 hwpec); +	 && i801_set_block_buffer_mode(priv) == 0) +		result = i801_block_transaction_by_block(priv, data, +							 read_write, hwpec);  	else -		result = i801_block_transaction_byte_by_byte(data, read_write, +		result = i801_block_transaction_byte_by_byte(priv, data, +							     read_write,  							     command, hwpec);  	if (result == 0 && hwpec) -		i801_wait_hwpec(); +		i801_wait_hwpec(priv);  	if (command == I2C_SMBUS_I2C_BLOCK_DATA  	 && read_write == I2C_SMBUS_WRITE) {  		/* restore saved configuration register value */ -		pci_write_config_byte(I801_dev, SMBHSTCFG, hostc); +		pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc);  	}  	return result;  } @@ -457,81 +480,85 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,  	int hwpec;  	int block = 0;  	int ret, xact = 0; +	struct i801_priv *priv = i2c_get_adapdata(adap); -	hwpec = (i801_features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) +	hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC)  		&& size != I2C_SMBUS_QUICK  		&& size != I2C_SMBUS_I2C_BLOCK_DATA;  	switch (size) {  	case I2C_SMBUS_QUICK:  		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -		       SMBHSTADD); +		       SMBHSTADD(priv));  		xact = I801_QUICK;  		break;  	case I2C_SMBUS_BYTE:  		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -		       SMBHSTADD); +		       SMBHSTADD(priv));  		if (read_write == I2C_SMBUS_WRITE) -			outb_p(command, SMBHSTCMD); +			outb_p(command, SMBHSTCMD(priv));  		xact = I801_BYTE;  		break;  	case I2C_SMBUS_BYTE_DATA:  		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -		       SMBHSTADD); -		outb_p(command, SMBHSTCMD); +		       SMBHSTADD(priv)); +		outb_p(command, SMBHSTCMD(priv));  		if (read_write == I2C_SMBUS_WRITE) -			outb_p(data->byte, SMBHSTDAT0); +			outb_p(data->byte, SMBHSTDAT0(priv));  		xact = I801_BYTE_DATA;  		break;  	case I2C_SMBUS_WORD_DATA:  		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -		       SMBHSTADD); -		outb_p(command, SMBHSTCMD); +		       SMBHSTADD(priv)); +		outb_p(command, SMBHSTCMD(priv));  		if (read_write == I2C_SMBUS_WRITE) { -			outb_p(data->word & 0xff, SMBHSTDAT0); -			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1); +			outb_p(data->word & 0xff, SMBHSTDAT0(priv)); +			outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv));  		}  		xact = I801_WORD_DATA;  		break;  	case I2C_SMBUS_BLOCK_DATA:  		outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), -		       SMBHSTADD); -		outb_p(command, SMBHSTCMD); +		       SMBHSTADD(priv)); +		outb_p(command, SMBHSTCMD(priv));  		block = 1;  		break;  	case I2C_SMBUS_I2C_BLOCK_DATA:  		/* NB: page 240 of ICH5 datasheet shows that the R/#W  		 * bit should be cleared here, even when reading */ -		outb_p((addr & 0x7f) << 1, SMBHSTADD); +		outb_p((addr & 0x7f) << 1, SMBHSTADD(priv));  		if (read_write == I2C_SMBUS_READ) {  			/* NB: page 240 of ICH5 datasheet also shows  			 * that DATA1 is the cmd field when reading */ -			outb_p(command, SMBHSTDAT1); +			outb_p(command, SMBHSTDAT1(priv));  		} else -			outb_p(command, SMBHSTCMD); +			outb_p(command, SMBHSTCMD(priv));  		block = 1;  		break;  	default: -		dev_err(&I801_dev->dev, "Unsupported transaction %d\n", size); +		dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", +			size);  		return -EOPNOTSUPP;  	}  	if (hwpec)	/* enable/disable hardware PEC */ -		outb_p(inb_p(SMBAUXCTL) | SMBAUXCTL_CRC, SMBAUXCTL); +		outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv));  	else -		outb_p(inb_p(SMBAUXCTL) & (~SMBAUXCTL_CRC), SMBAUXCTL); +		outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), +		       SMBAUXCTL(priv));  	if (block) -		ret = i801_block_transaction(data, read_write, size, hwpec); +		ret = i801_block_transaction(priv, data, read_write, size, +					     hwpec);  	else -		ret = i801_transaction(xact | ENABLE_INT9); +		ret = i801_transaction(priv, xact | ENABLE_INT9);  	/* Some BIOSes don't like it when PEC is enabled at reboot or resume  	   time, so we forcibly disable it after every transaction. Turn off  	   E32B for the same reason. */  	if (hwpec || block) -		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), -		       SMBAUXCTL); +		outb_p(inb_p(SMBAUXCTL(priv)) & +		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));  	if (block)  		return ret; @@ -543,10 +570,11 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,  	switch (xact & 0x7f) {  	case I801_BYTE:	/* Result put in SMBHSTDAT0 */  	case I801_BYTE_DATA: -		data->byte = inb_p(SMBHSTDAT0); +		data->byte = inb_p(SMBHSTDAT0(priv));  		break;  	case I801_WORD_DATA: -		data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8); +		data->word = inb_p(SMBHSTDAT0(priv)) + +			     (inb_p(SMBHSTDAT1(priv)) << 8);  		break;  	}  	return 0; @@ -555,11 +583,13 @@ static s32 i801_access(struct i2c_adapter *adap, u16 addr,  static u32 i801_func(struct i2c_adapter *adapter)  { +	struct i801_priv *priv = i2c_get_adapdata(adapter); +  	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |  	       I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |  	       I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | -	       ((i801_features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | -	       ((i801_features & FEATURE_I2C_BLOCK_READ) ? +	       ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | +	       ((priv->features & FEATURE_I2C_BLOCK_READ) ?  		I2C_FUNC_SMBUS_READ_I2C_BLOCK : 0);  } @@ -568,12 +598,6 @@ static const struct i2c_algorithm smbus_algorithm = {  	.functionality	= i801_func,  }; -static struct i2c_adapter i801_adapter = { -	.owner		= THIS_MODULE, -	.class		= I2C_CLASS_HWMON | I2C_CLASS_SPD, -	.algo		= &smbus_algorithm, -}; -  static const struct pci_device_id i801_ids[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, @@ -587,11 +611,15 @@ static const struct pci_device_id i801_ids[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },  	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PCH_SMBUS) }, -	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CPT_SMBUS) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, +	{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) },  	{ 0, }  }; @@ -704,16 +732,25 @@ static int __devinit i801_probe(struct pci_dev *dev,  {  	unsigned char temp;  	int err, i; +	struct i801_priv *priv; + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	i2c_set_adapdata(&priv->adapter, priv); +	priv->adapter.owner = THIS_MODULE; +	priv->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; +	priv->adapter.algo = &smbus_algorithm; -	I801_dev = dev; -	i801_features = 0; +	priv->pci_dev = dev;  	switch (dev->device) {  	default: -		i801_features |= FEATURE_I2C_BLOCK_READ; +		priv->features |= FEATURE_I2C_BLOCK_READ;  		/* fall through */  	case PCI_DEVICE_ID_INTEL_82801DB_3: -		i801_features |= FEATURE_SMBUS_PEC; -		i801_features |= FEATURE_BLOCK_BUFFER; +		priv->features |= FEATURE_SMBUS_PEC; +		priv->features |= FEATURE_BLOCK_BUFFER;  		/* fall through */  	case PCI_DEVICE_ID_INTEL_82801CA_3:  	case PCI_DEVICE_ID_INTEL_82801BA_2: @@ -724,11 +761,11 @@ static int __devinit i801_probe(struct pci_dev *dev,  	/* Disable features on user request */  	for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { -		if (i801_features & disable_features & (1 << i)) +		if (priv->features & disable_features & (1 << i))  			dev_notice(&dev->dev, "%s disabled by user\n",  				   i801_feature_names[i]);  	} -	i801_features &= ~disable_features; +	priv->features &= ~disable_features;  	err = pci_enable_device(dev);  	if (err) { @@ -738,8 +775,8 @@ static int __devinit i801_probe(struct pci_dev *dev,  	}  	/* Determine the address of the SMBus area */ -	i801_smba = pci_resource_start(dev, SMBBAR); -	if (!i801_smba) { +	priv->smba = pci_resource_start(dev, SMBBAR); +	if (!priv->smba) {  		dev_err(&dev->dev, "SMBus base address uninitialized, "  			"upgrade BIOS\n");  		err = -ENODEV; @@ -755,19 +792,19 @@ static int __devinit i801_probe(struct pci_dev *dev,  	err = pci_request_region(dev, SMBBAR, i801_driver.name);  	if (err) {  		dev_err(&dev->dev, "Failed to request SMBus region " -			"0x%lx-0x%Lx\n", i801_smba, +			"0x%lx-0x%Lx\n", priv->smba,  			(unsigned long long)pci_resource_end(dev, SMBBAR));  		goto exit;  	} -	pci_read_config_byte(I801_dev, SMBHSTCFG, &temp); -	i801_original_hstcfg = temp; +	pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp); +	priv->original_hstcfg = temp;  	temp &= ~SMBHSTCFG_I2C_EN;	/* SMBus timing */  	if (!(temp & SMBHSTCFG_HST_EN)) {  		dev_info(&dev->dev, "Enabling SMBus device\n");  		temp |= SMBHSTCFG_HST_EN;  	} -	pci_write_config_byte(I801_dev, SMBHSTCFG, temp); +	pci_write_config_byte(priv->pci_dev, SMBHSTCFG, temp);  	if (temp & SMBHSTCFG_SMB_SMI_EN)  		dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); @@ -775,19 +812,19 @@ static int __devinit i801_probe(struct pci_dev *dev,  		dev_dbg(&dev->dev, "SMBus using PCI Interrupt\n");  	/* Clear special mode bits */ -	if (i801_features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) -		outb_p(inb_p(SMBAUXCTL) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), -		       SMBAUXCTL); +	if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) +		outb_p(inb_p(SMBAUXCTL(priv)) & +		       ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv));  	/* set up the sysfs linkage to our parent device */ -	i801_adapter.dev.parent = &dev->dev; +	priv->adapter.dev.parent = &dev->dev;  	/* Retry up to 3 times on lost arbitration */ -	i801_adapter.retries = 3; +	priv->adapter.retries = 3; -	snprintf(i801_adapter.name, sizeof(i801_adapter.name), -		"SMBus I801 adapter at %04lx", i801_smba); -	err = i2c_add_adapter(&i801_adapter); +	snprintf(priv->adapter.name, sizeof(priv->adapter.name), +		"SMBus I801 adapter at %04lx", priv->smba); +	err = i2c_add_adapter(&priv->adapter);  	if (err) {  		dev_err(&dev->dev, "Failed to add SMBus adapter\n");  		goto exit_release; @@ -801,27 +838,33 @@ static int __devinit i801_probe(struct pci_dev *dev,  		memset(&info, 0, sizeof(struct i2c_board_info));  		info.addr = apanel_addr;  		strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE); -		i2c_new_device(&i801_adapter, &info); +		i2c_new_device(&priv->adapter, &info);  	}  #endif  #if defined CONFIG_SENSORS_FSCHMD || defined CONFIG_SENSORS_FSCHMD_MODULE  	if (dmi_name_in_vendors("FUJITSU")) -		dmi_walk(dmi_check_onboard_devices, &i801_adapter); +		dmi_walk(dmi_check_onboard_devices, &priv->adapter);  #endif +	pci_set_drvdata(dev, priv);  	return 0;  exit_release:  	pci_release_region(dev, SMBBAR);  exit: +	kfree(priv);  	return err;  }  static void __devexit i801_remove(struct pci_dev *dev)  { -	i2c_del_adapter(&i801_adapter); -	pci_write_config_byte(I801_dev, SMBHSTCFG, i801_original_hstcfg); +	struct i801_priv *priv = pci_get_drvdata(dev); + +	i2c_del_adapter(&priv->adapter); +	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);  	pci_release_region(dev, SMBBAR); +	pci_set_drvdata(dev, NULL); +	kfree(priv);  	/*  	 * do not call pci_disable_device(dev) since it can cause hard hangs on  	 * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) @@ -831,8 +874,10 @@ static void __devexit i801_remove(struct pci_dev *dev)  #ifdef CONFIG_PM  static int i801_suspend(struct pci_dev *dev, pm_message_t mesg)  { +	struct i801_priv *priv = pci_get_drvdata(dev); +  	pci_save_state(dev); -	pci_write_config_byte(dev, SMBHSTCFG, i801_original_hstcfg); +	pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);  	pci_set_power_state(dev, pci_choose_state(dev, mesg));  	return 0;  } diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c new file mode 100644 index 00000000000..c71492782bb --- /dev/null +++ b/drivers/i2c/busses/i2c-intel-mid.c @@ -0,0 +1,1135 @@ +/* + * Support for Moorestown/Medfield I2C chip + * + * Copyright (c) 2009 Intel Corporation. + * Copyright (c) 2009 Synopsys. Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, version + * 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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., 51 + * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <linux/stat.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/pm_runtime.h> +#include <linux/io.h> + +#define DRIVER_NAME	"i2c-intel-mid" +#define VERSION		"Version 0.5ac2" +#define PLATFORM	"Moorestown/Medfield" + +/* Tables use: 0 Moorestown, 1 Medfield */ +#define NUM_PLATFORMS	2 +enum platform_enum { +	MOORESTOWN = 0, +	MEDFIELD = 1, +}; + +enum mid_i2c_status { +	STATUS_IDLE = 0, +	STATUS_READ_START, +	STATUS_READ_IN_PROGRESS, +	STATUS_READ_SUCCESS, +	STATUS_WRITE_START, +	STATUS_WRITE_SUCCESS, +	STATUS_XFER_ABORT, +	STATUS_STANDBY +}; + +/** + * struct intel_mid_i2c_private	- per device I²C context + * @adap: core i2c layer adapter information + * @dev: device reference for power management + * @base: register base + * @speed: speed mode for this port + * @complete: completion object for transaction wait + * @abort: reason for last abort + * @rx_buf: pointer into working receive buffer + * @rx_buf_len: receive buffer length + * @status: adapter state machine + * @msg: the message we are currently processing + * @platform: the MID device type we are part of + * @lock: transaction serialization + * + * We allocate one of these per device we discover, it holds the core + * i2c layer objects and the data we need to track privately. + */ +struct intel_mid_i2c_private { +	struct i2c_adapter adap; +	struct device *dev; +	void __iomem *base; +	int speed; +	struct completion complete; +	int abort; +	u8 *rx_buf; +	int rx_buf_len; +	enum mid_i2c_status status; +	struct i2c_msg *msg; +	enum platform_enum platform; +	struct mutex lock; +}; + +#define NUM_SPEEDS		3 + +#define ACTIVE			0 +#define STANDBY			1 + + +/* Control register */ +#define IC_CON			0x00 +#define SLV_DIS			(1 << 6)	/* Disable slave mode */ +#define RESTART			(1 << 5)	/* Send a Restart condition */ +#define	ADDR_10BIT		(1 << 4)	/* 10-bit addressing */ +#define	STANDARD_MODE		(1 << 1)	/* standard mode */ +#define FAST_MODE		(2 << 1)	/* fast mode */ +#define HIGH_MODE		(3 << 1)	/* high speed mode */ +#define	MASTER_EN		(1 << 0)	/* Master mode */ + +/* Target address register */ +#define IC_TAR			0x04 +#define IC_TAR_10BIT_ADDR	(1 << 12)	/* 10-bit addressing */ +#define IC_TAR_SPECIAL		(1 << 11)	/* Perform special I2C cmd */ +#define IC_TAR_GC_OR_START	(1 << 10)	/* 0: Gerneral Call Address */ +						/* 1: START BYTE */ +/* Slave Address Register */ +#define IC_SAR			0x08		/* Not used in Master mode */ + +/* High Speed Master Mode Code Address Register */ +#define IC_HS_MADDR		0x0c + +/* Rx/Tx Data Buffer and Command Register */ +#define IC_DATA_CMD		0x10 +#define IC_RD			(1 << 8)	/* 1: Read 0: Write */ + +/* Standard Speed Clock SCL High Count Register */ +#define IC_SS_SCL_HCNT		0x14 + +/* Standard Speed Clock SCL Low Count Register */ +#define IC_SS_SCL_LCNT		0x18 + +/* Fast Speed Clock SCL High Count Register */ +#define IC_FS_SCL_HCNT		0x1c + +/* Fast Spedd Clock SCL Low Count Register */ +#define IC_FS_SCL_LCNT		0x20 + +/* High Speed Clock SCL High Count Register */ +#define IC_HS_SCL_HCNT		0x24 + +/* High Speed Clock SCL Low Count Register */ +#define IC_HS_SCL_LCNT		0x28 + +/* Interrupt Status Register */ +#define IC_INTR_STAT		0x2c		/* Read only */ +#define R_GEN_CALL		(1 << 11) +#define R_START_DET		(1 << 10) +#define R_STOP_DET		(1 << 9) +#define R_ACTIVITY		(1 << 8) +#define R_RX_DONE		(1 << 7) +#define	R_TX_ABRT		(1 << 6) +#define R_RD_REQ		(1 << 5) +#define R_TX_EMPTY		(1 << 4) +#define R_TX_OVER		(1 << 3) +#define	R_RX_FULL		(1 << 2) +#define	R_RX_OVER		(1 << 1) +#define R_RX_UNDER		(1 << 0) + +/* Interrupt Mask Register */ +#define IC_INTR_MASK		0x30		/* Read and Write */ +#define M_GEN_CALL		(1 << 11) +#define M_START_DET		(1 << 10) +#define M_STOP_DET		(1 << 9) +#define M_ACTIVITY		(1 << 8) +#define M_RX_DONE		(1 << 7) +#define	M_TX_ABRT		(1 << 6) +#define M_RD_REQ		(1 << 5) +#define M_TX_EMPTY		(1 << 4) +#define M_TX_OVER		(1 << 3) +#define	M_RX_FULL		(1 << 2) +#define	M_RX_OVER		(1 << 1) +#define M_RX_UNDER		(1 << 0) + +/* Raw Interrupt Status Register */ +#define IC_RAW_INTR_STAT	0x34		/* Read Only */ +#define GEN_CALL		(1 << 11)	/* General call */ +#define START_DET		(1 << 10)	/* (RE)START occured */ +#define STOP_DET		(1 << 9)	/* STOP occured */ +#define ACTIVITY		(1 << 8)	/* Bus busy */ +#define RX_DONE			(1 << 7)	/* Not used in Master mode */ +#define	TX_ABRT			(1 << 6)	/* Transmit Abort */ +#define RD_REQ			(1 << 5)	/* Not used in Master mode */ +#define TX_EMPTY		(1 << 4)	/* TX FIFO <= threshold */ +#define TX_OVER			(1 << 3)	/* TX FIFO overflow */ +#define	RX_FULL			(1 << 2)	/* RX FIFO >= threshold */ +#define	RX_OVER			(1 << 1)	/* RX FIFO overflow */ +#define RX_UNDER		(1 << 0)	/* RX FIFO empty */ + +/* Receive FIFO Threshold Register */ +#define IC_RX_TL		0x38 + +/* Transmit FIFO Treshold Register */ +#define IC_TX_TL		0x3c + +/* Clear Combined and Individual Interrupt Register */ +#define IC_CLR_INTR		0x40 +#define CLR_INTR		(1 << 0) + +/* Clear RX_UNDER Interrupt Register */ +#define IC_CLR_RX_UNDER		0x44 +#define CLR_RX_UNDER		(1 << 0) + +/* Clear RX_OVER Interrupt Register */ +#define IC_CLR_RX_OVER		0x48 +#define CLR_RX_OVER		(1 << 0) + +/* Clear TX_OVER Interrupt Register */ +#define IC_CLR_TX_OVER		0x4c +#define CLR_TX_OVER		(1 << 0) + +#define IC_CLR_RD_REQ		0x50 + +/* Clear TX_ABRT Interrupt Register */ +#define IC_CLR_TX_ABRT		0x54 +#define CLR_TX_ABRT		(1 << 0) +#define IC_CLR_RX_DONE		0x58 + +/* Clear ACTIVITY Interrupt Register */ +#define IC_CLR_ACTIVITY		0x5c +#define CLR_ACTIVITY		(1 << 0) + +/* Clear STOP_DET Interrupt Register */ +#define IC_CLR_STOP_DET		0x60 +#define CLR_STOP_DET		(1 << 0) + +/* Clear START_DET Interrupt Register */ +#define IC_CLR_START_DET	0x64 +#define CLR_START_DET		(1 << 0) + +/* Clear GEN_CALL Interrupt Register */ +#define IC_CLR_GEN_CALL		0x68 +#define CLR_GEN_CALL		(1 << 0) + +/* Enable Register */ +#define IC_ENABLE		0x6c +#define ENABLE			(1 << 0) + +/* Status Register */ +#define IC_STATUS		0x70		/* Read Only */ +#define STAT_SLV_ACTIVITY	(1 << 6)	/* Slave not in idle */ +#define STAT_MST_ACTIVITY	(1 << 5)	/* Master not in idle */ +#define STAT_RFF		(1 << 4)	/* RX FIFO Full */ +#define STAT_RFNE		(1 << 3)	/* RX FIFO Not Empty */ +#define STAT_TFE		(1 << 2)	/* TX FIFO Empty */ +#define STAT_TFNF		(1 << 1)	/* TX FIFO Not Full */ +#define STAT_ACTIVITY		(1 << 0)	/* Activity Status */ + +/* Transmit FIFO Level Register */ +#define IC_TXFLR		0x74		/* Read Only */ +#define TXFLR			(1 << 0)	/* TX FIFO level */ + +/* Receive FIFO Level Register */ +#define IC_RXFLR		0x78		/* Read Only */ +#define RXFLR			(1 << 0)	/* RX FIFO level */ + +/* Transmit Abort Source Register */ +#define IC_TX_ABRT_SOURCE	0x80 +#define ABRT_SLVRD_INTX		(1 << 15) +#define ABRT_SLV_ARBLOST	(1 << 14) +#define ABRT_SLVFLUSH_TXFIFO	(1 << 13) +#define	ARB_LOST		(1 << 12) +#define ABRT_MASTER_DIS		(1 << 11) +#define ABRT_10B_RD_NORSTRT	(1 << 10) +#define ABRT_SBYTE_NORSTRT	(1 << 9) +#define ABRT_HS_NORSTRT		(1 << 8) +#define ABRT_SBYTE_ACKDET	(1 << 7) +#define ABRT_HS_ACKDET		(1 << 6) +#define ABRT_GCALL_READ		(1 << 5) +#define ABRT_GCALL_NOACK	(1 << 4) +#define ABRT_TXDATA_NOACK	(1 << 3) +#define ABRT_10ADDR2_NOACK	(1 << 2) +#define ABRT_10ADDR1_NOACK	(1 << 1) +#define ABRT_7B_ADDR_NOACK	(1 << 0) + +/* Enable Status Register */ +#define IC_ENABLE_STATUS	0x9c +#define IC_EN			(1 << 0)	/* I2C in an enabled state */ + +/* Component Parameter Register 1*/ +#define IC_COMP_PARAM_1		0xf4 +#define APB_DATA_WIDTH		(0x3 << 0) + +/* added by xiaolin --begin */ +#define SS_MIN_SCL_HIGH         4000 +#define SS_MIN_SCL_LOW          4700 +#define FS_MIN_SCL_HIGH         600 +#define FS_MIN_SCL_LOW          1300 +#define HS_MIN_SCL_HIGH_100PF   60 +#define HS_MIN_SCL_LOW_100PF    120 + +#define STANDARD		0 +#define FAST			1 +#define HIGH			2 + +#define NUM_SPEEDS		3 + +static int speed_mode[6] = { +	FAST, +	FAST, +	FAST, +	STANDARD, +	FAST, +	FAST +}; + +static int ctl_num = 6; +module_param_array(speed_mode, int, &ctl_num, S_IRUGO); +MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)"); + +/** + * intel_mid_i2c_disable - Disable I2C controller + * @adap: struct pointer to i2c_adapter + * + * Return Value: + * 0		success + * -EBUSY	if device is busy + * -ETIMEDOUT	if i2c cannot be disabled within the given time + * + * I2C bus state should be checked prior to disabling the hardware. If bus is + * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable + * I2C controller. + */ +static int intel_mid_i2c_disable(struct i2c_adapter *adap) +{ +	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); +	int err = 0; +	int count = 0; +	int ret1, ret2; +	static const u16 delay[NUM_SPEEDS] = {100, 25, 3}; + +	/* Set IC_ENABLE to 0 */ +	writel(0, i2c->base + IC_ENABLE); + +	/* Check if device is busy */ +	dev_dbg(&adap->dev, "mrst i2c disable\n"); +	while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1) +		|| (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) { +		udelay(delay[i2c->speed]); +		writel(0, i2c->base + IC_ENABLE); +		dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n", +			count, i2c->speed); +		if (count++ > 10) { +			err = -ETIMEDOUT; +			break; +		} +	} + +	/* Clear all interrupts */ +	readl(i2c->base + IC_CLR_INTR); +	readl(i2c->base + IC_CLR_STOP_DET); +	readl(i2c->base + IC_CLR_START_DET); +	readl(i2c->base + IC_CLR_ACTIVITY); +	readl(i2c->base + IC_CLR_TX_ABRT); +	readl(i2c->base + IC_CLR_RX_OVER); +	readl(i2c->base + IC_CLR_RX_UNDER); +	readl(i2c->base + IC_CLR_TX_OVER); +	readl(i2c->base + IC_CLR_RX_DONE); +	readl(i2c->base + IC_CLR_GEN_CALL); + +	/* Disable all interupts */ +	writel(0x0000, i2c->base + IC_INTR_MASK); + +	return err; +} + +/** + * intel_mid_i2c_hwinit - Initialize the I2C hardware registers + * @dev: pci device struct pointer + * + * This function will be called in intel_mid_i2c_probe() before device + * registration. + * + * Return Values: + * 0		success + * -EBUSY	i2c cannot be disabled + * -ETIMEDOUT	i2c cannot be disabled + * -EFAULT	If APB data width is not 32-bit wide + * + * I2C should be disabled prior to other register operation. If failed, an + * errno is returned. Mask and Clear all interrpts, this should be done at + * first.  Set common registers which will not be modified during normal + * transfers, including: controll register, FIFO threshold and clock freq. + * Check APB data width at last. + */ +static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c) +{ +	int err; + +	static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = { +		{ 0x75,  0x15, 0x07 }, +		{ 0x04c,  0x10, 0x06 } +	}; +	static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = { +		{ 0x7C,  0x21, 0x0E }, +		{ 0x053, 0x19, 0x0F } +	}; + +	/* Disable i2c first */ +	err = intel_mid_i2c_disable(&i2c->adap); +	if (err) +		return err; + +	/* +	 * Setup clock frequency and speed mode +	 * Enable restart condition, +	 * enable master FSM, disable slave FSM, +	 * use target address when initiating transfer +	 */ + +	writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN, +		i2c->base + IC_CON); +	writel(hcnt[i2c->platform][i2c->speed], +		i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3))); +	writel(lcnt[i2c->platform][i2c->speed], +		i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3))); + +	/* Set tranmit & receive FIFO threshold to zero */ +	writel(0x0, i2c->base + IC_RX_TL); +	writel(0x0, i2c->base + IC_TX_TL); + +	return 0; +} + +/** + * intel_mid_i2c_func - Return the supported three I2C operations. + * @adapter: i2c_adapter struct pointer + */ +static u32 intel_mid_i2c_func(struct i2c_adapter *adapter) +{ +	return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; +} + +/** + * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages + * are equal. + * @p1: first i2c_msg + * @p2: second i2c_msg + * + * Return Values: + * 0	 if addresses are equal + * 1	 if not equal + * + * Within a single transfer, the I2C client may need to send its address more + * than once. So a check if the addresses match is needed. + */ +static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1, +				       const struct i2c_msg *p2) +{ +	if (p1->addr != p2->addr) +		return 1; +	if ((p1->flags ^ p2->flags) & I2C_M_TEN) +		return 1; +	return 0; +} + +/** + * intel_mid_i2c_abort - To handle transfer abortions and print error messages. + * @adap: i2c_adapter struct pointer + * + * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be + * distingushed. At present, no circumstances have been found out that + * multiple errors would be occured simutaneously, so we simply use the + * register value directly. + * + * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need + * a few extra steps) + */ +static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c) +{ +	/* Read about source register */ +	int abort = i2c->abort; +	struct i2c_adapter *adap = &i2c->adap; + +	/* Single transfer error check: +	 * According to databook, TX/RX FIFOs would be flushed when +	 * the abort interrupt occured. +	 */ +	if (abort & ABRT_MASTER_DIS) +		dev_err(&adap->dev, +		"initiate master operation with master mode disabled.\n"); +	if (abort & ABRT_10B_RD_NORSTRT) +		dev_err(&adap->dev, +	"RESTART disabled and master sent READ cmd in 10-bit addressing.\n"); + +	if (abort & ABRT_SBYTE_NORSTRT) { +		dev_err(&adap->dev, +		"RESTART disabled and user is trying to send START byte.\n"); +		writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE); +		writel(RESTART, i2c->base + IC_CON); +		writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR); +	} + +	if (abort & ABRT_SBYTE_ACKDET) +		dev_err(&adap->dev, +			"START byte was not acknowledged.\n"); +	if (abort & ABRT_TXDATA_NOACK) +		dev_dbg(&adap->dev, +			"No acknowledgement received from slave.\n"); +	if (abort & ABRT_10ADDR2_NOACK) +		dev_dbg(&adap->dev, +	"The 2nd address byte of the 10-bit address was not acknowledged.\n"); +	if (abort & ABRT_10ADDR1_NOACK) +		dev_dbg(&adap->dev, +	"The 1st address byte of 10-bit address was not acknowledged.\n"); +	if (abort & ABRT_7B_ADDR_NOACK) +		dev_dbg(&adap->dev, +			"I2C slave device not acknowledged.\n"); + +	/* Clear TX_ABRT bit */ +	readl(i2c->base + IC_CLR_TX_ABRT); +	i2c->status = STATUS_XFER_ABORT; +} + +/** + * xfer_read - Internal function to implement master read transfer. + * @adap: i2c_adapter struct pointer + * @buf: buffer in i2c_msg + * @length: number of bytes to be read + * + * Return Values: + * 0		if the read transfer succeeds + * -ETIMEDOUT	if cannot read the "raw" interrupt register + * -EINVAL	if a transfer abort occurred + * + * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to + * data transfer. The actual "read" operation will be performed if an RX_FULL + * interrupt occurred. + * + * Note there may be two interrupt signals captured, one should read + * IC_RAW_INTR_STAT to separate between errors and actual data. + */ +static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +{ +	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); +	int i = length; +	int err; + +	if (length >= 256) { +		dev_err(&adap->dev, +			"I2C FIFO cannot support larger than 256 bytes\n"); +		return -EMSGSIZE; +	} + +	INIT_COMPLETION(i2c->complete); + +	readl(i2c->base + IC_CLR_INTR); +	writel(0x0044, i2c->base + IC_INTR_MASK); + +	i2c->status = STATUS_READ_START; + +	while (i--) +		writel(IC_RD, i2c->base + IC_DATA_CMD); + +	i2c->status = STATUS_READ_START; +	err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ); +	if (!err) { +		dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n"); +		intel_mid_i2c_hwinit(i2c); +		return -ETIMEDOUT; +	} +	if (i2c->status == STATUS_READ_SUCCESS) +		return 0; +	else +		return -EIO; +} + +/** + * xfer_write - Internal function to implement master write transfer. + * @adap: i2c_adapter struct pointer + * @buf: buffer in i2c_msg + * @length: number of bytes to be read + * + * Return Values: + * 0	if the read transfer succeeds + * -ETIMEDOUT	if we cannot read the "raw" interrupt register + * -EINVAL	if a transfer abort occured + * + * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to + * data transfer. The actual "write" operation will be performed when the + * RX_FULL interrupt signal occurs. + * + * Note there may be two interrupt signals captured, one should read + * IC_RAW_INTR_STAT to separate between errors and actual data. + */ +static int xfer_write(struct i2c_adapter *adap, +		      unsigned char *buf, int length) +{ +	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); +	int i, err; + +	if (length >= 256) { +		dev_err(&adap->dev, +			"I2C FIFO cannot support larger than 256 bytes\n"); +		return -EMSGSIZE; +	} + +	INIT_COMPLETION(i2c->complete); + +	readl(i2c->base + IC_CLR_INTR); +	writel(0x0050, i2c->base + IC_INTR_MASK); + +	i2c->status = STATUS_WRITE_START; +	for (i = 0; i < length; i++) +		writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD); + +	i2c->status = STATUS_WRITE_START; +	err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ); +	if (!err) { +		dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n"); +		intel_mid_i2c_hwinit(i2c); +		return -ETIMEDOUT; +	} else { +		if (i2c->status == STATUS_WRITE_SUCCESS) +			return 0; +		else +			return -EIO; +	} +} + +static int intel_mid_i2c_setup(struct i2c_adapter *adap,  struct i2c_msg *pmsg) +{ +	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); +	int err; +	u32 reg; +	u32 bit_mask; +	u32 mode; + +	/* Disable device first */ +	err = intel_mid_i2c_disable(adap); +	if (err) { +		dev_err(&adap->dev, +			"Cannot disable i2c controller, timeout\n"); +		return err; +	} + +	mode = (1 + i2c->speed) << 1; +	/* set the speed mode */ +	reg = readl(i2c->base + IC_CON); +	if ((reg & 0x06) != mode) { +		dev_dbg(&adap->dev, "set mode %d\n", i2c->speed); +		writel((reg & ~0x6) | mode, i2c->base + IC_CON); +	} + +	reg = readl(i2c->base + IC_CON); +	/* use 7-bit addressing */ +	if (pmsg->flags & I2C_M_TEN) { +		if ((reg & ADDR_10BIT) != ADDR_10BIT) { +			dev_dbg(&adap->dev, "set i2c 10 bit address mode\n"); +			writel(reg | ADDR_10BIT, i2c->base + IC_CON); +		} +	} else { +		if ((reg & ADDR_10BIT) != 0x0) { +			dev_dbg(&adap->dev, "set i2c 7 bit address mode\n"); +			writel(reg & ~ADDR_10BIT, i2c->base + IC_CON); +		} +	} +	/* enable restart conditions */ +	reg = readl(i2c->base + IC_CON); +	if ((reg & RESTART) != RESTART) { +		dev_dbg(&adap->dev, "enable restart conditions\n"); +		writel(reg | RESTART, i2c->base + IC_CON); +	} + +	/* enable master FSM */ +	reg = readl(i2c->base + IC_CON); +	dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg); +	writel(reg | MASTER_EN, i2c->base + IC_CON); +	if ((reg & SLV_DIS) != SLV_DIS) { +		dev_dbg(&adap->dev, "enable master FSM\n"); +		writel(reg | SLV_DIS, i2c->base + IC_CON); +		dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg); +	} + +	/* use target address when initiating transfer */ +	reg = readl(i2c->base + IC_TAR); +	bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START; + +	if ((reg & bit_mask) != 0x0) { +		dev_dbg(&adap->dev, +	 "WR: use target address when intiating transfer, i2c_tx_target\n"); +		writel(reg & ~bit_mask, i2c->base + IC_TAR); +	} + +	/* set target address to the I2C slave address */ +	dev_dbg(&adap->dev, +		"set target address to the I2C slave address, addr is %x\n", +			pmsg->addr); +	writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0), +		i2c->base + IC_TAR); + +	/* Enable I2C controller */ +	writel(ENABLE, i2c->base + IC_ENABLE); + +	return 0; +} + +/** + * intel_mid_i2c_xfer - Main master transfer routine. + * @adap: i2c_adapter struct pointer + * @pmsg: i2c_msg struct pointer + * @num: number of i2c_msg + * + * Return Values: + * +		number of messages transfered + * -ETIMEDOUT	If cannot disable I2C controller or read IC_STATUS + * -EINVAL	If the address in i2c_msg is invalid + * + * This function will be registered in i2c-core and exposed to external + * I2C clients. + * 1. Disable I2C controller + * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT + * 3. Check if address in i2c_msg is valid + * 4. Enable I2C controller + * 5. Perform real transfer (call xfer_read or xfer_write) + * 6. Wait until the current transfer is finished (check bus state) + * 7. Mask and clear all interrupts + */ +static int intel_mid_i2c_xfer(struct i2c_adapter *adap, +			 struct i2c_msg *pmsg, +			 int num) +{ +	struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); +	int i, err = 0; + +	/* if number of messages equal 0*/ +	if (num == 0) +		return 0; + +	pm_runtime_get(i2c->dev); + +	mutex_lock(&i2c->lock); +	dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num); +	dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr); + + +	if (i2c->status != STATUS_IDLE) { +		dev_err(&adap->dev, "Adapter %d in transfer/standby\n", +								adap->nr); +		mutex_unlock(&i2c->lock); +		pm_runtime_put(i2c->dev); +		return -1; +	} + + +	for (i = 1; i < num; i++) { +		/* Message address equal? */ +		if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) { +			dev_err(&adap->dev, "Invalid address in msg[%d]\n", i); +			mutex_unlock(&i2c->lock); +			pm_runtime_put(i2c->dev); +			return -EINVAL; +		} +	} + +	if (intel_mid_i2c_setup(adap, pmsg)) { +		mutex_unlock(&i2c->lock); +		pm_runtime_put(i2c->dev); +		return -EINVAL; +	} + +	for (i = 0; i < num; i++) { +		i2c->msg = pmsg; +		i2c->status = STATUS_IDLE; +		/* Read or Write */ +		if (pmsg->flags & I2C_M_RD) { +			dev_dbg(&adap->dev, "I2C_M_RD\n"); +			err = xfer_read(adap, pmsg->buf, pmsg->len); +		} else { +			dev_dbg(&adap->dev, "I2C_M_WR\n"); +			err = xfer_write(adap, pmsg->buf, pmsg->len); +		} +		if (err < 0) +			break; +		dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i); +		pmsg++;		/* next message */ +	} + +	/* Mask interrupts */ +	writel(0x0000, i2c->base + IC_INTR_MASK); +	/* Clear all interrupts */ +	readl(i2c->base + IC_CLR_INTR); + +	i2c->status = STATUS_IDLE; +	mutex_unlock(&i2c->lock); +	pm_runtime_put(i2c->dev); + +	return err; +} + +static int intel_mid_i2c_runtime_suspend(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev); +	struct i2c_adapter *adap = to_i2c_adapter(dev); +	int err; + +	if (i2c->status != STATUS_IDLE) +		return -1; + +	intel_mid_i2c_disable(adap); + +	err = pci_save_state(pdev); +	if (err) { +		dev_err(dev, "pci_save_state failed\n"); +		return err; +	} + +	err = pci_set_power_state(pdev, PCI_D3hot); +	if (err) { +		dev_err(dev, "pci_set_power_state failed\n"); +		return err; +	} +	i2c->status = STATUS_STANDBY; + +	return 0; +} + +static int intel_mid_i2c_runtime_resume(struct device *dev) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev); +	int err; + +	if (i2c->status != STATUS_STANDBY) +		return 0; + +	pci_set_power_state(pdev, PCI_D0); +	pci_restore_state(pdev); +	err = pci_enable_device(pdev); +	if (err) { +		dev_err(dev, "pci_enable_device failed\n"); +		return err; +	} + +	i2c->status = STATUS_IDLE; + +	intel_mid_i2c_hwinit(i2c); +	return err; +} + +static void i2c_isr_read(struct intel_mid_i2c_private *i2c) +{ +	struct i2c_msg *msg = i2c->msg; +	int rx_num; +	u32 len; +	u8 *buf; + +	if (!(msg->flags & I2C_M_RD)) +		return; + +	if (i2c->status != STATUS_READ_IN_PROGRESS) { +		len = msg->len; +		buf = msg->buf; +	} else { +		len = i2c->rx_buf_len; +		buf = i2c->rx_buf; +	} + +	rx_num = readl(i2c->base + IC_RXFLR); + +	for (; len > 0 && rx_num > 0; len--, rx_num--) +		*buf++ = readl(i2c->base + IC_DATA_CMD); + +	if (len > 0) { +		i2c->status = STATUS_READ_IN_PROGRESS; +		i2c->rx_buf_len = len; +		i2c->rx_buf = buf; +	} else +		i2c->status = STATUS_READ_SUCCESS; + +	return; +} + +static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev) +{ +	struct intel_mid_i2c_private *i2c = dev; +	u32 stat = readl(i2c->base + IC_INTR_STAT); + +	if (!stat) +		return IRQ_NONE; + +	dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat); +	stat &= 0x54; + +	if (i2c->status != STATUS_WRITE_START && +	    i2c->status != STATUS_READ_START && +	    i2c->status != STATUS_READ_IN_PROGRESS) +		goto err; + +	if (stat & TX_ABRT) +		i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE); + +	readl(i2c->base + IC_CLR_INTR); + +	if (stat & TX_ABRT) { +		intel_mid_i2c_abort(i2c); +		goto exit; +	} + +	if (stat & RX_FULL) { +		i2c_isr_read(i2c); +		goto exit; +	} + +	if (stat & TX_EMPTY) { +		if (readl(i2c->base + IC_STATUS) & 0x4) +			i2c->status = STATUS_WRITE_SUCCESS; +	} + +exit: +	if (i2c->status == STATUS_READ_SUCCESS || +	    i2c->status == STATUS_WRITE_SUCCESS || +	    i2c->status == STATUS_XFER_ABORT) { +		/* Clear all interrupts */ +		readl(i2c->base + IC_CLR_INTR); +		/* Mask interrupts */ +		writel(0, i2c->base + IC_INTR_MASK); +		complete(&i2c->complete); +	} +err: +	return IRQ_HANDLED; +} + +static struct i2c_algorithm intel_mid_i2c_algorithm = { +	.master_xfer	= intel_mid_i2c_xfer, +	.functionality	= intel_mid_i2c_func, +}; + + +static const struct dev_pm_ops intel_mid_i2c_pm_ops = { +	.runtime_suspend = intel_mid_i2c_runtime_suspend, +	.runtime_resume = intel_mid_i2c_runtime_resume, +}; + +/** + * intel_mid_i2c_probe - I2C controller initialization routine + * @dev: pci device + * @id: device id + * + * Return Values: + * 0		success + * -ENODEV	If cannot allocate pci resource + * -ENOMEM	If the register base remapping failed, or + *		if kzalloc failed + * + * Initialization steps: + * 1. Request for PCI resource + * 2. Remap the start address of PCI resource to register base + * 3. Request for device memory region + * 4. Fill in the struct members of intel_mid_i2c_private + * 5. Call intel_mid_i2c_hwinit() for hardware initialization + * 6. Register I2C adapter in i2c-core + */ +static int __devinit intel_mid_i2c_probe(struct pci_dev *dev, +				    const struct pci_device_id *id) +{ +	struct intel_mid_i2c_private *mrst; +	unsigned long start, len; +	int err, busnum; +	void __iomem *base = NULL; + +	dev_dbg(&dev->dev, "Get into probe function for I2C\n"); +	err = pci_enable_device(dev); +	if (err) { +		dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n", +			err); +		goto exit; +	} + +	/* Determine the address of the I2C area */ +	start = pci_resource_start(dev, 0); +	len = pci_resource_len(dev, 0); +	if (!start || len == 0) { +		dev_err(&dev->dev, "base address not set\n"); +		err = -ENODEV; +		goto exit; +	} +	dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n", +		PLATFORM, start, len); + +	err = pci_request_region(dev, 0, DRIVER_NAME); +	if (err) { +		dev_err(&dev->dev, "failed to request I2C region " +			"0x%lx-0x%lx\n", start, +			(unsigned long)pci_resource_end(dev, 0)); +		goto exit; +	} + +	base = ioremap_nocache(start, len); +	if (!base) { +		dev_err(&dev->dev, "I/O memory remapping failed\n"); +		err = -ENOMEM; +		goto fail0; +	} + +	/* Allocate the per-device data structure, intel_mid_i2c_private */ +	mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL); +	if (mrst == NULL) { +		dev_err(&dev->dev, "can't allocate interface\n"); +		err = -ENOMEM; +		goto fail1; +	} + +	/* Initialize struct members */ +	snprintf(mrst->adap.name, sizeof(mrst->adap.name), +		"Intel MID I2C at %lx", start); +	mrst->adap.owner = THIS_MODULE; +	mrst->adap.algo = &intel_mid_i2c_algorithm; +	mrst->adap.dev.parent = &dev->dev; +	mrst->dev = &dev->dev; +	mrst->base = base; +	mrst->speed = STANDARD; +	mrst->abort = 0; +	mrst->rx_buf_len = 0; +	mrst->status = STATUS_IDLE; + +	pci_set_drvdata(dev, mrst); +	i2c_set_adapdata(&mrst->adap, mrst); + +	mrst->adap.nr = busnum = id->driver_data; +	if (dev->device <= 0x0804) +		mrst->platform = MOORESTOWN; +	else +		mrst->platform = MEDFIELD; + +	dev_dbg(&dev->dev, "I2C%d\n", busnum); + +	if (ctl_num > busnum) { +		if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS) +			dev_warn(&dev->dev, "invalid speed %d ignored.\n", +							speed_mode[busnum]); +		else +			mrst->speed = speed_mode[busnum]; +	} + +	/* Initialize i2c controller */ +	err = intel_mid_i2c_hwinit(mrst); +	if (err < 0) { +		dev_err(&dev->dev, "I2C interface initialization failed\n"); +		goto fail2; +	} + +	mutex_init(&mrst->lock); +	init_completion(&mrst->complete); + +	/* Clear all interrupts */ +	readl(mrst->base + IC_CLR_INTR); +	writel(0x0000, mrst->base + IC_INTR_MASK); + +	err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED, +					mrst->adap.name, mrst); +	if (err) { +		dev_err(&dev->dev, "Failed to request IRQ for I2C controller: " +			"%s", mrst->adap.name); +		goto fail2; +	} + +	/* Adapter registration */ +	err = i2c_add_numbered_adapter(&mrst->adap); +	if (err) { +		dev_err(&dev->dev, "Adapter %s registration failed\n", +			mrst->adap.name); +		goto fail3; +	} + +	dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n", +		(mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield", +		busnum); + +	pm_runtime_enable(&dev->dev); +	return 0; + +fail3: +	free_irq(dev->irq, mrst); +fail2: +	pci_set_drvdata(dev, NULL); +	kfree(mrst); +fail1: +	iounmap(base); +fail0: +	pci_release_region(dev, 0); +exit: +	return err; +} + +static void __devexit intel_mid_i2c_remove(struct pci_dev *dev) +{ +	struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev); +	intel_mid_i2c_disable(&mrst->adap); +	if (i2c_del_adapter(&mrst->adap)) +		dev_err(&dev->dev, "Failed to delete i2c adapter"); + +	free_irq(dev->irq, mrst); +	pci_set_drvdata(dev, NULL); +	iounmap(mrst->base); +	kfree(mrst); +	pci_release_region(dev, 0); +} + +static struct pci_device_id intel_mid_i2c_ids[] = { +	/* Moorestown */ +	{ PCI_VDEVICE(INTEL, 0x0802), 0 }, +	{ PCI_VDEVICE(INTEL, 0x0803), 1 }, +	{ PCI_VDEVICE(INTEL, 0x0804), 2 }, +	/* Medfield */ +	{ PCI_VDEVICE(INTEL, 0x0817), 3,}, +	{ PCI_VDEVICE(INTEL, 0x0818), 4 }, +	{ PCI_VDEVICE(INTEL, 0x0819), 5 }, +	{ PCI_VDEVICE(INTEL, 0x082C), 0 }, +	{ PCI_VDEVICE(INTEL, 0x082D), 1 }, +	{ PCI_VDEVICE(INTEL, 0x082E), 2 }, +	{ 0,} +}; +MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids); + +static struct pci_driver intel_mid_i2c_driver = { +	.name		= DRIVER_NAME, +	.id_table	= intel_mid_i2c_ids, +	.probe		= intel_mid_i2c_probe, +	.remove		= __devexit_p(intel_mid_i2c_remove), +}; + +static int __init intel_mid_i2c_init(void) +{ +	return pci_register_driver(&intel_mid_i2c_driver); +} + +static void __exit intel_mid_i2c_exit(void) +{ +	pci_unregister_driver(&intel_mid_i2c_driver); +} + +module_init(intel_mid_i2c_init); +module_exit(intel_mid_i2c_exit); + +MODULE_AUTHOR("Ba Zheng <zheng.ba@intel.com>"); +MODULE_DESCRIPTION("I2C driver for Moorestown Platform"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(VERSION); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 73de8ade10b..c9fffd0389f 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1,5 +1,5 @@  /* - * Copyright (C) 2009 ST-Ericsson + * Copyright (C) 2009 ST-Ericsson SA   * Copyright (C) 2009 STMicroelectronics   *   * I2C master mode controller driver, used in Nomadik 8815 @@ -103,6 +103,9 @@  /* maximum threshold value */  #define MAX_I2C_FIFO_THRESHOLD	15 +/* per-transfer delay, required for the hardware to stabilize */ +#define I2C_DELAY		150 +  enum i2c_status {  	I2C_NOP,  	I2C_ON_GOING, @@ -118,7 +121,7 @@ enum i2c_operation {  };  /* controller response timeout in ms */ -#define I2C_TIMEOUT_MS	500 +#define I2C_TIMEOUT_MS	2000  /**   * struct i2c_nmk_client - client specific data @@ -250,6 +253,8 @@ static int init_hw(struct nmk_i2c_dev *dev)  {  	int stat; +	clk_enable(dev->clk); +  	stat = flush_i2c_fifo(dev);  	if (stat)  		return stat; @@ -263,6 +268,9 @@ static int init_hw(struct nmk_i2c_dev *dev)  	dev->cli.operation = I2C_NO_OPERATION; +	clk_disable(dev->clk); + +	udelay(I2C_DELAY);  	return 0;  } @@ -431,7 +439,6 @@ static int read_i2c(struct nmk_i2c_dev *dev)  		(void) init_hw(dev);  		status = -ETIMEDOUT;  	} -  	return status;  } @@ -502,9 +509,9 @@ static int write_i2c(struct nmk_i2c_dev *dev)  /**   * nmk_i2c_xfer() - I2C transfer function used by kernel framework - * @i2c_adap 	- Adapter pointer to the controller - * @msgs[] - Pointer to data to be written. - * @num_msgs - Number of messages to be executed + * @i2c_adap: Adapter pointer to the controller + * @msgs: Pointer to data to be written. + * @num_msgs: Number of messages to be executed   *   * This is the function called by the generic kernel i2c_transfer()   * or i2c_smbus...() API calls. Note that this code is protected by the @@ -559,6 +566,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,  	if (status)  		return status; +	clk_enable(dev->clk); +  	/* setup the i2c controller */  	setup_i2c_controller(dev); @@ -591,10 +600,13 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,  			dev_err(&dev->pdev->dev, "%s\n",  				cause >= ARRAY_SIZE(abort_causes)  				? "unknown reason" : abort_causes[cause]); +			clk_disable(dev->clk);  			return status;  		} -		mdelay(1); +		udelay(I2C_DELAY);  	} +	clk_disable(dev->clk); +  	/* return the no. messages processed */  	if (status)  		return status; @@ -605,6 +617,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,  /**   * disable_interrupts() - disable the interrupts   * @dev: private data of controller + * @irq: interrupt number   */  static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq)  { @@ -794,10 +807,7 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)  static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)  { -	return I2C_FUNC_I2C -		| I2C_FUNC_SMBUS_BYTE_DATA -		| I2C_FUNC_SMBUS_WORD_DATA -		| I2C_FUNC_SMBUS_I2C_BLOCK; +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;  }  static const struct i2c_algorithm nmk_i2c_algo = { @@ -857,8 +867,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)  		goto err_no_clk;  	} -	clk_enable(dev->clk); -  	adap = &dev->adap;  	adap->dev.parent = &pdev->dev;  	adap->owner	= THIS_MODULE; @@ -895,7 +903,6 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev)  	return 0;   err_init_hw: -	clk_disable(dev->clk);   err_add_adap:  	clk_put(dev->clk);   err_no_clk: @@ -928,7 +935,6 @@ static int __devexit nmk_i2c_remove(struct platform_device *pdev)  	iounmap(dev->virtbase);  	if (res)  		release_mem_region(res->start, resource_size(res)); -	clk_disable(dev->clk);  	clk_put(dev->clk);  	platform_set_drvdata(pdev, NULL);  	kfree(dev); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 6a292ea5e35..6c00c107ebf 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -554,18 +554,23 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,  	int retry;  	int ret; +	clk_enable(i2c->clk); +  	for (retry = 0; retry < adap->retries; retry++) {  		ret = s3c24xx_i2c_doxfer(i2c, msgs, num); -		if (ret != -EAGAIN) +		if (ret != -EAGAIN) { +			clk_disable(i2c->clk);  			return ret; +		}  		dev_dbg(i2c->dev, "Retrying transmission (%d)\n", retry);  		udelay(100);  	} +	clk_disable(i2c->clk);  	return -EREMOTEIO;  } @@ -910,6 +915,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, i2c);  	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); +	clk_disable(i2c->clk);  	return 0;   err_cpufreq: @@ -977,7 +983,9 @@ static int s3c24xx_i2c_resume(struct device *dev)  	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);  	i2c->suspended = 0; +	clk_enable(i2c->clk);  	s3c24xx_i2c_init(i2c); +	clk_disable(i2c->clk);  	return 0;  } diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 4cb4bb00995..53fab518b3d 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -560,7 +560,8 @@ static const struct pci_device_id scx200_pci[] __initconst = {  	{ PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_ISA),  	  .driver_data = 1 },  	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA), -	  .driver_data = 2 } +	  .driver_data = 2 }, +	{ 0, }  };  static struct { diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index d231f683f57..6b4cc567645 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -848,6 +848,18 @@ static int i2c_register_adapter(struct i2c_adapter *adap)  		goto out_list;  	} +	/* Sanity checks */ +	if (unlikely(adap->name[0] == '\0')) { +		pr_err("i2c-core: Attempt to register an adapter with " +		       "no name!\n"); +		return -EINVAL; +	} +	if (unlikely(!adap->algo)) { +		pr_err("i2c-core: Attempt to register adapter '%s' with " +		       "no algo!\n", adap->name); +		return -EINVAL; +	} +  	rt_mutex_init(&adap->bus_lock);  	mutex_init(&adap->userspace_clients_lock);  	INIT_LIST_HEAD(&adap->userspace_clients); diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index d32a4843fc3..d7a4833be41 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -120,7 +120,6 @@ struct i2c_adapter *i2c_add_mux_adapter(struct i2c_adapter *parent,  	snprintf(priv->adap.name, sizeof(priv->adap.name),  		 "i2c-%d-mux (chan_id %d)", i2c_adapter_id(parent), chan_id);  	priv->adap.owner = THIS_MODULE; -	priv->adap.id = parent->id;  	priv->adap.algo = &priv->algo;  	priv->adap.algo_data = priv;  	priv->adap.dev.parent = &parent->dev; | 
