Merge branch 'for-linus/i2c-3.2' of git://git.fluff.org/bjdooks/linux
* 'for-linus/i2c-3.2' of git://git.fluff.org/bjdooks/linux: (47 commits) i2c-s3c2410: Add device tree support i2c-s3c2410: Keep a copy of platform data and use it i2c-nomadik: cosmetic coding style corrections i2c-au1550: dev_pm_ops conversion i2c-au1550: increase timeout waiting for master done i2c-au1550: remove unused ack_timeout i2c-au1550: remove usage of volatile keyword i2c-tegra: __iomem annotation fix i2c-eg20t: Add initialize processing in case i2c-error occurs i2c-eg20t: Fix flag setting issue i2c-eg20t: add stop sequence in case wait-event timeout occurs i2c-eg20t: Separate error processing i2c-eg20t: Fix 10bit access issue i2c-eg20t: Modify returned value s32 to long i2c-eg20t: Fix bus-idle waiting issue i2c-designware: Fix PCI core warning on suspend/resume i2c-designware: Add runtime power management support i2c-designware: Add support for Designware core behind PCI devices. i2c-designware: Push all register reads/writes into the core code. i2c-designware: Support multiple cores using same ISR ...
This commit is contained in:
		
						commit
						b4beb4bf99
					
				
							
								
								
									
										25
									
								
								Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								Documentation/devicetree/bindings/i2c/fsl-imx-i2c.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | ||||
| * Freescale Inter IC (I2C) and High Speed Inter IC (HS-I2C) for i.MX | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible : Should be "fsl,<chip>-i2c" | ||||
| - reg : Should contain I2C/HS-I2C registers location and length | ||||
| - interrupts : Should contain I2C/HS-I2C interrupt | ||||
| 
 | ||||
| Optional properties: | ||||
| - clock-frequency : Constains desired I2C/HS-I2C bus clock frequency in Hz. | ||||
|   The absence of the propoerty indicates the default frequency 100 kHz. | ||||
| 
 | ||||
| Examples: | ||||
| 
 | ||||
| i2c@83fc4000 { /* I2C2 on i.MX51 */ | ||||
| 	compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; | ||||
| 	reg = <0x83fc4000 0x4000>; | ||||
| 	interrupts = <63>; | ||||
| }; | ||||
| 
 | ||||
| i2c@70038000 { /* HS-I2C on i.MX51 */ | ||||
| 	compatible = "fsl,imx51-i2c", "fsl,imx1-i2c"; | ||||
| 	reg = <0x70038000 0x4000>; | ||||
| 	interrupts = <64>; | ||||
| 	clock-frequency = <400000>; | ||||
| }; | ||||
							
								
								
									
										39
									
								
								Documentation/devicetree/bindings/i2c/samsung-i2c.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								Documentation/devicetree/bindings/i2c/samsung-i2c.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | ||||
| * Samsung's I2C controller | ||||
| 
 | ||||
| The Samsung's I2C controller is used to interface with I2C devices. | ||||
| 
 | ||||
| Required properties: | ||||
|   - compatible: value should be either of the following. | ||||
|       (a) "samsung, s3c2410-i2c", for i2c compatible with s3c2410 i2c. | ||||
|       (b) "samsung, s3c2440-i2c", for i2c compatible with s3c2440 i2c. | ||||
|   - reg: physical base address of the controller and length of memory mapped | ||||
|     region. | ||||
|   - interrupts: interrupt number to the cpu. | ||||
|   - samsung,i2c-sda-delay: Delay (in ns) applied to data line (SDA) edges. | ||||
|   - gpios: The order of the gpios should be the following: <SDA, SCL>. | ||||
|     The gpio specifier depends on the gpio controller. | ||||
| 
 | ||||
| Optional properties: | ||||
|   - samsung,i2c-slave-addr: Slave address in multi-master enviroment. If not | ||||
|     specified, default value is 0. | ||||
|   - samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not | ||||
|     specified, the default value in Hz is 100000. | ||||
| 
 | ||||
| Example: | ||||
| 
 | ||||
| 	i2c@13870000 { | ||||
| 		compatible = "samsung,s3c2440-i2c"; | ||||
| 		reg = <0x13870000 0x100>; | ||||
| 		interrupts = <345>; | ||||
| 		samsung,i2c-sda-delay = <100>; | ||||
| 		samsung,i2c-max-bus-freq = <100000>; | ||||
| 		gpios = <&gpd1 2 0 /* SDA */ | ||||
| 			 &gpd1 3 0 /* SCL */>; | ||||
| 		#address-cells = <1>; | ||||
| 		#size-cells = <0>; | ||||
| 
 | ||||
| 		wm8994@1a { | ||||
| 			compatible = "wlf,wm8994"; | ||||
| 			reg = <0x1a>; | ||||
| 		}; | ||||
| 	}; | ||||
| @ -11,14 +11,10 @@ | ||||
| 
 | ||||
| /**
 | ||||
|  * struct imxi2c_platform_data - structure of platform data for MXC I2C driver | ||||
|  * @init:	Initialise gpio's and other board specific things | ||||
|  * @exit:	Free everything initialised by @init | ||||
|  * @bitrate:	Bus speed measured in Hz | ||||
|  * | ||||
|  **/ | ||||
| struct imxi2c_platform_data { | ||||
| 	int (*init)(struct device *dev); | ||||
| 	void (*exit)(struct device *dev); | ||||
| 	int bitrate; | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -108,6 +108,22 @@ static inline int omap1_i2c_add_bus(int bus_id) | ||||
| 	res[1].start = INT_I2C; | ||||
| 	pdata = &i2c_pdata[bus_id - 1]; | ||||
| 
 | ||||
| 	/* all OMAP1 have IP version 1 register set */ | ||||
| 	pdata->rev = OMAP_I2C_IP_VERSION_1; | ||||
| 
 | ||||
| 	/* all OMAP1 I2C are implemented like this */ | ||||
| 	pdata->flags = OMAP_I2C_FLAG_NO_FIFO | | ||||
| 		       OMAP_I2C_FLAG_SIMPLE_CLOCK | | ||||
| 		       OMAP_I2C_FLAG_16BIT_DATA_REG | | ||||
| 		       OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK; | ||||
| 
 | ||||
| 	/* how the cpu bus is wired up differs for 7xx only */ | ||||
| 
 | ||||
| 	if (cpu_is_omap7xx()) | ||||
| 		pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_1; | ||||
| 	else | ||||
| 		pdata->flags |= OMAP_I2C_FLAG_BUS_SHIFT_2; | ||||
| 
 | ||||
| 	return platform_device_register(pdev); | ||||
| } | ||||
| 
 | ||||
| @ -138,6 +154,7 @@ static inline int omap2_i2c_add_bus(int bus_id) | ||||
| 	struct omap_device *od; | ||||
| 	char oh_name[MAX_OMAP_I2C_HWMOD_NAME_LEN]; | ||||
| 	struct omap_i2c_bus_platform_data *pdata; | ||||
| 	struct omap_i2c_dev_attr *dev_attr; | ||||
| 
 | ||||
| 	omap2_i2c_mux_pins(bus_id); | ||||
| 
 | ||||
| @ -151,6 +168,16 @@ static inline int omap2_i2c_add_bus(int bus_id) | ||||
| 	} | ||||
| 
 | ||||
| 	pdata = &i2c_pdata[bus_id - 1]; | ||||
| 	/*
 | ||||
| 	 * pass the hwmod class's CPU-specific knowledge of I2C IP revision in | ||||
| 	 * use, and functionality implementation flags, up to the OMAP I2C | ||||
| 	 * driver via platform data | ||||
| 	 */ | ||||
| 	pdata->rev = oh->class->rev; | ||||
| 
 | ||||
| 	dev_attr = (struct omap_i2c_dev_attr *)oh->dev_attr; | ||||
| 	pdata->flags = dev_attr->flags; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * When waiting for completion of a i2c transfer, we need to | ||||
| 	 * set a wake up latency constraint for the MPU. This is to | ||||
|  | ||||
| @ -394,19 +394,6 @@ typedef struct	psc_spi { | ||||
| #define PSC_SPITXRX_LC		(1 << 29) | ||||
| #define PSC_SPITXRX_SR		(1 << 28) | ||||
| 
 | ||||
| /* PSC in SMBus (I2C) Mode. */ | ||||
| typedef struct	psc_smb { | ||||
| 	u32	psc_sel; | ||||
| 	u32	psc_ctrl; | ||||
| 	u32	psc_smbcfg; | ||||
| 	u32	psc_smbmsk; | ||||
| 	u32	psc_smbpcr; | ||||
| 	u32	psc_smbstat; | ||||
| 	u32	psc_smbevnt; | ||||
| 	u32	psc_smbtxrx; | ||||
| 	u32	psc_smbtmr; | ||||
| } psc_smb_t; | ||||
| 
 | ||||
| /* SMBus Config Register. */ | ||||
| #define PSC_SMBCFG_RT_MASK	(3 << 30) | ||||
| #define PSC_SMBCFG_RT_FIFO1	(0 << 30) | ||||
|  | ||||
| @ -350,15 +350,25 @@ config I2C_DAVINCI | ||||
| 	  devices such as DaVinci NIC. | ||||
| 	  For details please see http://www.ti.com/davinci | ||||
| 
 | ||||
| config I2C_DESIGNWARE | ||||
| 	tristate "Synopsys DesignWare" | ||||
| config I2C_DESIGNWARE_PLATFORM | ||||
| 	tristate "Synopsys DesignWare Platfrom" | ||||
| 	depends on HAVE_CLK | ||||
| 	help | ||||
| 	  If you say yes to this option, support will be included for the | ||||
| 	  Synopsys DesignWare I2C adapter. Only master mode is supported. | ||||
| 
 | ||||
| 	  This driver can also be built as a module.  If so, the module | ||||
| 	  will be called i2c-designware. | ||||
| 	  will be called i2c-designware-platform. | ||||
| 
 | ||||
| config I2C_DESIGNWARE_PCI | ||||
| 	tristate "Synopsys DesignWare PCI" | ||||
| 	depends on PCI | ||||
| 	help | ||||
| 	  If you say yes to this option, support will be included for the | ||||
| 	  Synopsys DesignWare I2C adapter. Only master mode is supported. | ||||
| 
 | ||||
| 	  This driver can also be built as a module.  If so, the module | ||||
| 	  will be called i2c-designware-pci. | ||||
| 
 | ||||
| config I2C_GPIO | ||||
| 	tristate "GPIO-based bitbanging I2C" | ||||
|  | ||||
| @ -33,7 +33,10 @@ obj-$(CONFIG_I2C_AU1550)	+= i2c-au1550.o | ||||
| obj-$(CONFIG_I2C_BLACKFIN_TWI)	+= i2c-bfin-twi.o | ||||
| obj-$(CONFIG_I2C_CPM)		+= i2c-cpm.o | ||||
| obj-$(CONFIG_I2C_DAVINCI)	+= i2c-davinci.o | ||||
| obj-$(CONFIG_I2C_DESIGNWARE)	+= i2c-designware.o | ||||
| obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM)	+= i2c-designware-platform.o | ||||
| i2c-designware-platform-objs := i2c-designware-platdrv.o i2c-designware-core.o | ||||
| obj-$(CONFIG_I2C_DESIGNWARE_PCI)	+= i2c-designware-pci.o | ||||
| i2c-designware-pci-objs := i2c-designware-pcidrv.o i2c-designware-core.o | ||||
| obj-$(CONFIG_I2C_GPIO)		+= i2c-gpio.o | ||||
| obj-$(CONFIG_I2C_HIGHLANDER)	+= i2c-highlander.o | ||||
| obj-$(CONFIG_I2C_IBM_IIC)	+= i2c-ibm_iic.o | ||||
|  | ||||
| @ -39,29 +39,41 @@ | ||||
| #include <asm/mach-au1x00/au1xxx.h> | ||||
| #include <asm/mach-au1x00/au1xxx_psc.h> | ||||
| 
 | ||||
| #define PSC_SEL		0x00 | ||||
| #define PSC_CTRL	0x04 | ||||
| #define PSC_SMBCFG	0x08 | ||||
| #define PSC_SMBMSK	0x0C | ||||
| #define PSC_SMBPCR	0x10 | ||||
| #define PSC_SMBSTAT	0x14 | ||||
| #define PSC_SMBEVNT	0x18 | ||||
| #define PSC_SMBTXRX	0x1C | ||||
| #define PSC_SMBTMR	0x20 | ||||
| 
 | ||||
| struct i2c_au1550_data { | ||||
| 	u32	psc_base; | ||||
| 	void __iomem *psc_base; | ||||
| 	int	xfer_timeout; | ||||
| 	int	ack_timeout; | ||||
| 	struct i2c_adapter adap; | ||||
| 	struct resource *ioarea; | ||||
| }; | ||||
| 
 | ||||
| static int | ||||
| wait_xfer_done(struct i2c_au1550_data *adap) | ||||
| static inline void WR(struct i2c_au1550_data *a, int r, unsigned long v) | ||||
| { | ||||
| 	u32	stat; | ||||
| 	int	i; | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	__raw_writel(v, a->psc_base + r); | ||||
| 	wmb(); | ||||
| } | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| static inline unsigned long RD(struct i2c_au1550_data *a, int r) | ||||
| { | ||||
| 	return __raw_readl(a->psc_base + r); | ||||
| } | ||||
| 
 | ||||
| 	/* Wait for Tx Buffer Empty
 | ||||
| 	*/ | ||||
| static int wait_xfer_done(struct i2c_au1550_data *adap) | ||||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	/* Wait for Tx Buffer Empty */ | ||||
| 	for (i = 0; i < adap->xfer_timeout; i++) { | ||||
| 		stat = sp->psc_smbstat; | ||||
| 		au_sync(); | ||||
| 		if ((stat & PSC_SMBSTAT_TE) != 0) | ||||
| 		if (RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_TE) | ||||
| 			return 0; | ||||
| 
 | ||||
| 		udelay(1); | ||||
| @ -70,41 +82,27 @@ wait_xfer_done(struct i2c_au1550_data *adap) | ||||
| 	return -ETIMEDOUT; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| wait_ack(struct i2c_au1550_data *adap) | ||||
| static int wait_ack(struct i2c_au1550_data *adap) | ||||
| { | ||||
| 	u32	stat; | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	unsigned long stat; | ||||
| 
 | ||||
| 	if (wait_xfer_done(adap)) | ||||
| 		return -ETIMEDOUT; | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| 
 | ||||
| 	stat = sp->psc_smbevnt; | ||||
| 	au_sync(); | ||||
| 
 | ||||
| 	stat = RD(adap, PSC_SMBEVNT); | ||||
| 	if ((stat & (PSC_SMBEVNT_DN | PSC_SMBEVNT_AN | PSC_SMBEVNT_AL)) != 0) | ||||
| 		return -ETIMEDOUT; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| wait_master_done(struct i2c_au1550_data *adap) | ||||
| static int wait_master_done(struct i2c_au1550_data *adap) | ||||
| { | ||||
| 	u32	stat; | ||||
| 	int	i; | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	int i; | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| 
 | ||||
| 	/* Wait for Master Done.
 | ||||
| 	*/ | ||||
| 	for (i = 0; i < adap->xfer_timeout; i++) { | ||||
| 		stat = sp->psc_smbevnt; | ||||
| 		au_sync(); | ||||
| 		if ((stat & PSC_SMBEVNT_MD) != 0) | ||||
| 	/* Wait for Master Done. */ | ||||
| 	for (i = 0; i < 2 * adap->xfer_timeout; i++) { | ||||
| 		if ((RD(adap, PSC_SMBEVNT) & PSC_SMBEVNT_MD) != 0) | ||||
| 			return 0; | ||||
| 		udelay(1); | ||||
| 	} | ||||
| @ -115,29 +113,20 @@ wait_master_done(struct i2c_au1550_data *adap) | ||||
| static int | ||||
| do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q) | ||||
| { | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	u32			stat; | ||||
| 	unsigned long stat; | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| 
 | ||||
| 	/* Reset the FIFOs, clear events.
 | ||||
| 	*/ | ||||
| 	stat = sp->psc_smbstat; | ||||
| 	sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR; | ||||
| 	au_sync(); | ||||
| 	/* Reset the FIFOs, clear events. */ | ||||
| 	stat = RD(adap, PSC_SMBSTAT); | ||||
| 	WR(adap, PSC_SMBEVNT, PSC_SMBEVNT_ALLCLR); | ||||
| 
 | ||||
| 	if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) { | ||||
| 		sp->psc_smbpcr = PSC_SMBPCR_DC; | ||||
| 		au_sync(); | ||||
| 		do { | ||||
| 			stat = sp->psc_smbpcr; | ||||
| 			au_sync(); | ||||
| 		} while ((stat & PSC_SMBPCR_DC) != 0); | ||||
| 		WR(adap, PSC_SMBPCR, PSC_SMBPCR_DC); | ||||
| 		while ((RD(adap, PSC_SMBPCR) & PSC_SMBPCR_DC) != 0) | ||||
| 			cpu_relax(); | ||||
| 		udelay(50); | ||||
| 	} | ||||
| 
 | ||||
| 	/* Write out the i2c chip address and specify operation
 | ||||
| 	*/ | ||||
| 	/* Write out the i2c chip address and specify operation */ | ||||
| 	addr <<= 1; | ||||
| 	if (rd) | ||||
| 		addr |= 1; | ||||
| @ -146,56 +135,42 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q) | ||||
| 	if (q) | ||||
| 		addr |= PSC_SMBTXRX_STP; | ||||
| 
 | ||||
| 	/* Put byte into fifo, start up master.
 | ||||
| 	*/ | ||||
| 	sp->psc_smbtxrx = addr; | ||||
| 	au_sync(); | ||||
| 	sp->psc_smbpcr = PSC_SMBPCR_MS; | ||||
| 	au_sync(); | ||||
| 	/* Put byte into fifo, start up master. */ | ||||
| 	WR(adap, PSC_SMBTXRX, addr); | ||||
| 	WR(adap, PSC_SMBPCR, PSC_SMBPCR_MS); | ||||
| 	if (wait_ack(adap)) | ||||
| 		return -EIO; | ||||
| 	return (q) ? wait_master_done(adap) : 0; | ||||
| } | ||||
| 
 | ||||
| static u32 | ||||
| wait_for_rx_byte(struct i2c_au1550_data *adap, u32 *ret_data) | ||||
| static int wait_for_rx_byte(struct i2c_au1550_data *adap, unsigned char *out) | ||||
| { | ||||
| 	int	j; | ||||
| 	u32	data, stat; | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	int j; | ||||
| 
 | ||||
| 	if (wait_xfer_done(adap)) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| 
 | ||||
| 	j =  adap->xfer_timeout * 100; | ||||
| 	do { | ||||
| 		j--; | ||||
| 		if (j <= 0) | ||||
| 			return -EIO; | ||||
| 
 | ||||
| 		stat = sp->psc_smbstat; | ||||
| 		au_sync(); | ||||
| 		if ((stat & PSC_SMBSTAT_RE) == 0) | ||||
| 		if ((RD(adap, PSC_SMBSTAT) & PSC_SMBSTAT_RE) == 0) | ||||
| 			j = 0; | ||||
| 		else | ||||
| 			udelay(1); | ||||
| 	} while (j > 0); | ||||
| 	data = sp->psc_smbtxrx; | ||||
| 	au_sync(); | ||||
| 	*ret_data = data; | ||||
| 
 | ||||
| 	*out = RD(adap, PSC_SMBTXRX); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| i2c_read(struct i2c_au1550_data *adap, unsigned char *buf, | ||||
| static int i2c_read(struct i2c_au1550_data *adap, unsigned char *buf, | ||||
| 		    unsigned int len) | ||||
| { | ||||
| 	int	i; | ||||
| 	u32	data; | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	int i; | ||||
| 
 | ||||
| 	if (len == 0) | ||||
| 		return 0; | ||||
| @ -204,62 +179,46 @@ i2c_read(struct i2c_au1550_data *adap, unsigned char *buf, | ||||
| 	 * zero bytes for timing, waiting for bytes to appear in the | ||||
| 	 * receive fifo, then reading the bytes. | ||||
| 	 */ | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| 
 | ||||
| 	i = 0; | ||||
| 	while (i < (len-1)) { | ||||
| 		sp->psc_smbtxrx = 0; | ||||
| 		au_sync(); | ||||
| 		if (wait_for_rx_byte(adap, &data)) | ||||
| 	while (i < (len - 1)) { | ||||
| 		WR(adap, PSC_SMBTXRX, 0); | ||||
| 		if (wait_for_rx_byte(adap, &buf[i])) | ||||
| 			return -EIO; | ||||
| 
 | ||||
| 		buf[i] = data; | ||||
| 		i++; | ||||
| 	} | ||||
| 
 | ||||
| 	/* The last byte has to indicate transfer done.
 | ||||
| 	*/ | ||||
| 	sp->psc_smbtxrx = PSC_SMBTXRX_STP; | ||||
| 	au_sync(); | ||||
| 	/* The last byte has to indicate transfer done. */ | ||||
| 	WR(adap, PSC_SMBTXRX, PSC_SMBTXRX_STP); | ||||
| 	if (wait_master_done(adap)) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	data = sp->psc_smbtxrx; | ||||
| 	au_sync(); | ||||
| 	buf[i] = data; | ||||
| 	buf[i] = (unsigned char)(RD(adap, PSC_SMBTXRX) & 0xff); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| i2c_write(struct i2c_au1550_data *adap, unsigned char *buf, | ||||
| static int i2c_write(struct i2c_au1550_data *adap, unsigned char *buf, | ||||
| 		     unsigned int len) | ||||
| { | ||||
| 	int	i; | ||||
| 	u32	data; | ||||
| 	volatile psc_smb_t	*sp; | ||||
| 	int i; | ||||
| 	unsigned long data; | ||||
| 
 | ||||
| 	if (len == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	sp = (volatile psc_smb_t *)(adap->psc_base); | ||||
| 
 | ||||
| 	i = 0; | ||||
| 	while (i < (len-1)) { | ||||
| 		data = buf[i]; | ||||
| 		sp->psc_smbtxrx = data; | ||||
| 		au_sync(); | ||||
| 		WR(adap, PSC_SMBTXRX, data); | ||||
| 		if (wait_ack(adap)) | ||||
| 			return -EIO; | ||||
| 		i++; | ||||
| 	} | ||||
| 
 | ||||
| 	/* The last byte has to indicate transfer done.
 | ||||
| 	*/ | ||||
| 	/* The last byte has to indicate transfer done. */ | ||||
| 	data = buf[i]; | ||||
| 	data |= PSC_SMBTXRX_STP; | ||||
| 	sp->psc_smbtxrx = data; | ||||
| 	au_sync(); | ||||
| 	WR(adap, PSC_SMBTXRX, data); | ||||
| 	if (wait_master_done(adap)) | ||||
| 		return -EIO; | ||||
| 	return 0; | ||||
| @ -269,12 +228,10 @@ static int | ||||
| au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | ||||
| { | ||||
| 	struct i2c_au1550_data *adap = i2c_adap->algo_data; | ||||
| 	volatile psc_smb_t *sp = (volatile psc_smb_t *)adap->psc_base; | ||||
| 	struct i2c_msg *p; | ||||
| 	int i, err = 0; | ||||
| 
 | ||||
| 	sp->psc_ctrl = PSC_CTRL_ENABLE; | ||||
| 	au_sync(); | ||||
| 	WR(adap, PSC_CTRL, PSC_CTRL_ENABLE); | ||||
| 
 | ||||
| 	for (i = 0; !err && i < num; i++) { | ||||
| 		p = &msgs[i]; | ||||
| @ -293,14 +250,12 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) | ||||
| 	if (err == 0) | ||||
| 		err = num; | ||||
| 
 | ||||
| 	sp->psc_ctrl = PSC_CTRL_SUSPEND; | ||||
| 	au_sync(); | ||||
| 	WR(adap, PSC_CTRL, PSC_CTRL_SUSPEND); | ||||
| 
 | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static u32 | ||||
| au1550_func(struct i2c_adapter *adap) | ||||
| static u32 au1550_func(struct i2c_adapter *adap) | ||||
| { | ||||
| 	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; | ||||
| } | ||||
| @ -312,57 +267,45 @@ static const struct i2c_algorithm au1550_algo = { | ||||
| 
 | ||||
| static void i2c_au1550_setup(struct i2c_au1550_data *priv) | ||||
| { | ||||
| 	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||||
| 	u32 stat; | ||||
| 	unsigned long cfg; | ||||
| 
 | ||||
| 	sp->psc_ctrl = PSC_CTRL_DISABLE; | ||||
| 	au_sync(); | ||||
| 	sp->psc_sel = PSC_SEL_PS_SMBUSMODE; | ||||
| 	sp->psc_smbcfg = 0; | ||||
| 	au_sync(); | ||||
| 	sp->psc_ctrl = PSC_CTRL_ENABLE; | ||||
| 	au_sync(); | ||||
| 	do { | ||||
| 		stat = sp->psc_smbstat; | ||||
| 		au_sync(); | ||||
| 	} while ((stat & PSC_SMBSTAT_SR) == 0); | ||||
| 	WR(priv, PSC_CTRL, PSC_CTRL_DISABLE); | ||||
| 	WR(priv, PSC_SEL, PSC_SEL_PS_SMBUSMODE); | ||||
| 	WR(priv, PSC_SMBCFG, 0); | ||||
| 	WR(priv, PSC_CTRL, PSC_CTRL_ENABLE); | ||||
| 	while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0) | ||||
| 		cpu_relax(); | ||||
| 
 | ||||
| 	sp->psc_smbcfg = (PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | | ||||
| 				PSC_SMBCFG_DD_DISABLE); | ||||
| 	cfg = PSC_SMBCFG_RT_FIFO8 | PSC_SMBCFG_TT_FIFO8 | PSC_SMBCFG_DD_DISABLE; | ||||
| 	WR(priv, PSC_SMBCFG, cfg); | ||||
| 
 | ||||
| 	/* Divide by 8 to get a 6.25 MHz clock.  The later protocol
 | ||||
| 	 * timings are based on this clock. | ||||
| 	 */ | ||||
| 	sp->psc_smbcfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8); | ||||
| 	sp->psc_smbmsk = PSC_SMBMSK_ALLMASK; | ||||
| 	au_sync(); | ||||
| 	cfg |= PSC_SMBCFG_SET_DIV(PSC_SMBCFG_DIV8); | ||||
| 	WR(priv, PSC_SMBCFG, cfg); | ||||
| 	WR(priv, PSC_SMBMSK, PSC_SMBMSK_ALLMASK); | ||||
| 
 | ||||
| 	/* Set the protocol timer values.  See Table 71 in the
 | ||||
| 	 * Au1550 Data Book for standard timing values. | ||||
| 	 */ | ||||
| 	sp->psc_smbtmr = PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \ | ||||
| 	WR(priv, PSC_SMBTMR, PSC_SMBTMR_SET_TH(0) | PSC_SMBTMR_SET_PS(15) | \ | ||||
| 		PSC_SMBTMR_SET_PU(15) | PSC_SMBTMR_SET_SH(15) | \ | ||||
| 		PSC_SMBTMR_SET_SU(15) | PSC_SMBTMR_SET_CL(15) | \ | ||||
| 		PSC_SMBTMR_SET_CH(15); | ||||
| 	au_sync(); | ||||
| 		PSC_SMBTMR_SET_CH(15)); | ||||
| 
 | ||||
| 	sp->psc_smbcfg |= PSC_SMBCFG_DE_ENABLE; | ||||
| 	do { | ||||
| 		stat = sp->psc_smbstat; | ||||
| 		au_sync(); | ||||
| 	} while ((stat & PSC_SMBSTAT_SR) == 0); | ||||
| 	cfg |= PSC_SMBCFG_DE_ENABLE; | ||||
| 	WR(priv, PSC_SMBCFG, cfg); | ||||
| 	while ((RD(priv, PSC_SMBSTAT) & PSC_SMBSTAT_SR) == 0) | ||||
| 		cpu_relax(); | ||||
| 
 | ||||
| 	sp->psc_ctrl = PSC_CTRL_SUSPEND; | ||||
| 	au_sync(); | ||||
| 	WR(priv, PSC_CTRL, PSC_CTRL_SUSPEND); | ||||
| } | ||||
| 
 | ||||
| static void i2c_au1550_disable(struct i2c_au1550_data *priv) | ||||
| { | ||||
| 	volatile psc_smb_t *sp = (volatile psc_smb_t *)priv->psc_base; | ||||
| 
 | ||||
| 	sp->psc_smbcfg = 0; | ||||
| 	sp->psc_ctrl = PSC_CTRL_DISABLE; | ||||
| 	au_sync(); | ||||
| 	WR(priv, PSC_SMBCFG, 0); | ||||
| 	WR(priv, PSC_CTRL, PSC_CTRL_DISABLE); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -396,9 +339,12 @@ i2c_au1550_probe(struct platform_device *pdev) | ||||
| 		goto out_mem; | ||||
| 	} | ||||
| 
 | ||||
| 	priv->psc_base = CKSEG1ADDR(r->start); | ||||
| 	priv->psc_base = ioremap(r->start, resource_size(r)); | ||||
| 	if (!priv->psc_base) { | ||||
| 		ret = -EIO; | ||||
| 		goto out_map; | ||||
| 	} | ||||
| 	priv->xfer_timeout = 200; | ||||
| 	priv->ack_timeout = 200; | ||||
| 
 | ||||
| 	priv->adap.nr = pdev->id; | ||||
| 	priv->adap.algo = &au1550_algo; | ||||
| @ -406,8 +352,7 @@ i2c_au1550_probe(struct platform_device *pdev) | ||||
| 	priv->adap.dev.parent = &pdev->dev; | ||||
| 	strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); | ||||
| 
 | ||||
| 	/* Now, set up the PSC for SMBus PIO mode.
 | ||||
| 	*/ | ||||
| 	/* Now, set up the PSC for SMBus PIO mode. */ | ||||
| 	i2c_au1550_setup(priv); | ||||
| 
 | ||||
| 	ret = i2c_add_numbered_adapter(&priv->adap); | ||||
| @ -417,7 +362,8 @@ i2c_au1550_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	i2c_au1550_disable(priv); | ||||
| 
 | ||||
| 	iounmap(priv->psc_base); | ||||
| out_map: | ||||
| 	release_resource(priv->ioarea); | ||||
| 	kfree(priv->ioarea); | ||||
| out_mem: | ||||
| @ -426,14 +372,14 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static int __devexit | ||||
| i2c_au1550_remove(struct platform_device *pdev) | ||||
| static int __devexit i2c_au1550_remove(struct platform_device *pdev) | ||||
| { | ||||
| 	struct i2c_au1550_data *priv = platform_get_drvdata(pdev); | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| 	i2c_del_adapter(&priv->adap); | ||||
| 	i2c_au1550_disable(priv); | ||||
| 	iounmap(priv->psc_base); | ||||
| 	release_resource(priv->ioarea); | ||||
| 	kfree(priv->ioarea); | ||||
| 	kfree(priv); | ||||
| @ -441,49 +387,51 @@ i2c_au1550_remove(struct platform_device *pdev) | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM | ||||
| static int | ||||
| i2c_au1550_suspend(struct platform_device *pdev, pm_message_t state) | ||||
| static int i2c_au1550_suspend(struct device *dev) | ||||
| { | ||||
| 	struct i2c_au1550_data *priv = platform_get_drvdata(pdev); | ||||
| 	struct i2c_au1550_data *priv = dev_get_drvdata(dev); | ||||
| 
 | ||||
| 	i2c_au1550_disable(priv); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int | ||||
| i2c_au1550_resume(struct platform_device *pdev) | ||||
| static int i2c_au1550_resume(struct device *dev) | ||||
| { | ||||
| 	struct i2c_au1550_data *priv = platform_get_drvdata(pdev); | ||||
| 	struct i2c_au1550_data *priv = dev_get_drvdata(dev); | ||||
| 
 | ||||
| 	i2c_au1550_setup(priv); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct dev_pm_ops i2c_au1550_pmops = { | ||||
| 	.suspend	= i2c_au1550_suspend, | ||||
| 	.resume		= i2c_au1550_resume, | ||||
| }; | ||||
| 
 | ||||
| #define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops) | ||||
| 
 | ||||
| #else | ||||
| #define i2c_au1550_suspend	NULL | ||||
| #define i2c_au1550_resume	NULL | ||||
| #define AU1XPSC_SMBUS_PMOPS NULL | ||||
| #endif | ||||
| 
 | ||||
| static struct platform_driver au1xpsc_smbus_driver = { | ||||
| 	.driver = { | ||||
| 		.name	= "au1xpsc_smbus", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 		.pm	= AU1XPSC_SMBUS_PMOPS, | ||||
| 	}, | ||||
| 	.probe		= i2c_au1550_probe, | ||||
| 	.remove		= __devexit_p(i2c_au1550_remove), | ||||
| 	.suspend	= i2c_au1550_suspend, | ||||
| 	.resume		= i2c_au1550_resume, | ||||
| }; | ||||
| 
 | ||||
| static int __init | ||||
| i2c_au1550_init(void) | ||||
| static int __init i2c_au1550_init(void) | ||||
| { | ||||
| 	return platform_driver_register(&au1xpsc_smbus_driver); | ||||
| } | ||||
| 
 | ||||
| static void __exit | ||||
| i2c_au1550_exit(void) | ||||
| static void __exit i2c_au1550_exit(void) | ||||
| { | ||||
| 	platform_driver_unregister(&au1xpsc_smbus_driver); | ||||
| } | ||||
|  | ||||
| @ -631,7 +631,7 @@ static int i2c_bfin_twi_resume(struct platform_device *pdev) | ||||
| 	struct bfin_twi_iface *iface = platform_get_drvdata(pdev); | ||||
| 
 | ||||
| 	int rc = request_irq(iface->irq, bfin_twi_interrupt_entry, | ||||
| 		IRQF_DISABLED, pdev->name, iface); | ||||
| 		0, pdev->name, iface); | ||||
| 	if (rc) { | ||||
| 		dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); | ||||
| 		return -ENODEV; | ||||
| @ -702,7 +702,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	rc = request_irq(iface->irq, bfin_twi_interrupt_entry, | ||||
| 		IRQF_DISABLED, pdev->name, iface); | ||||
| 		0, pdev->name, iface); | ||||
| 	if (rc) { | ||||
| 		dev_err(&pdev->dev, "Can't get IRQ %d !\n", iface->irq); | ||||
| 		rc = -ENODEV; | ||||
|  | ||||
| @ -25,18 +25,15 @@ | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  */ | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include <linux/delay.h> | ||||
| #include "i2c-designware-core.h" | ||||
| 
 | ||||
| /*
 | ||||
|  * Registers offset | ||||
| @ -68,15 +65,10 @@ | ||||
| #define DW_IC_STATUS		0x70 | ||||
| #define DW_IC_TXFLR		0x74 | ||||
| #define DW_IC_RXFLR		0x78 | ||||
| #define DW_IC_COMP_PARAM_1	0xf4 | ||||
| #define DW_IC_TX_ABRT_SOURCE	0x80 | ||||
| 
 | ||||
| #define DW_IC_CON_MASTER		0x1 | ||||
| #define DW_IC_CON_SPEED_STD		0x2 | ||||
| #define DW_IC_CON_SPEED_FAST		0x4 | ||||
| #define DW_IC_CON_10BITADDR_MASTER	0x10 | ||||
| #define DW_IC_CON_RESTART_EN		0x20 | ||||
| #define DW_IC_CON_SLAVE_DISABLE		0x40 | ||||
| #define DW_IC_COMP_PARAM_1	0xf4 | ||||
| #define DW_IC_COMP_TYPE		0xfc | ||||
| #define DW_IC_COMP_TYPE_VALUE	0x44570140 | ||||
| 
 | ||||
| #define DW_IC_INTR_RX_UNDER	0x001 | ||||
| #define DW_IC_INTR_RX_OVER	0x002 | ||||
| @ -170,55 +162,23 @@ static char *abort_sources[] = { | ||||
| 		"lost arbitration", | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct dw_i2c_dev - private i2c-designware data | ||||
|  * @dev: driver model device node | ||||
|  * @base: IO registers pointer | ||||
|  * @cmd_complete: tx completion indicator | ||||
|  * @lock: protect this struct and IO registers | ||||
|  * @clk: input reference clock | ||||
|  * @cmd_err: run time hadware error code | ||||
|  * @msgs: points to an array of messages currently being transferred | ||||
|  * @msgs_num: the number of elements in msgs | ||||
|  * @msg_write_idx: the element index of the current tx message in the msgs | ||||
|  *	array | ||||
|  * @tx_buf_len: the length of the current tx buffer | ||||
|  * @tx_buf: the current tx buffer | ||||
|  * @msg_read_idx: the element index of the current rx message in the msgs | ||||
|  *	array | ||||
|  * @rx_buf_len: the length of the current rx buffer | ||||
|  * @rx_buf: the current rx buffer | ||||
|  * @msg_err: error status of the current transfer | ||||
|  * @status: i2c master status, one of STATUS_* | ||||
|  * @abort_source: copy of the TX_ABRT_SOURCE register | ||||
|  * @irq: interrupt number for the i2c master | ||||
|  * @adapter: i2c subsystem adapter node | ||||
|  * @tx_fifo_depth: depth of the hardware tx fifo | ||||
|  * @rx_fifo_depth: depth of the hardware rx fifo | ||||
|  */ | ||||
| struct dw_i2c_dev { | ||||
| 	struct device		*dev; | ||||
| 	void __iomem		*base; | ||||
| 	struct completion	cmd_complete; | ||||
| 	struct mutex		lock; | ||||
| 	struct clk		*clk; | ||||
| 	int			cmd_err; | ||||
| 	struct i2c_msg		*msgs; | ||||
| 	int			msgs_num; | ||||
| 	int			msg_write_idx; | ||||
| 	u32			tx_buf_len; | ||||
| 	u8			*tx_buf; | ||||
| 	int			msg_read_idx; | ||||
| 	u32			rx_buf_len; | ||||
| 	u8			*rx_buf; | ||||
| 	int			msg_err; | ||||
| 	unsigned int		status; | ||||
| 	u32			abort_source; | ||||
| 	int			irq; | ||||
| 	struct i2c_adapter	adapter; | ||||
| 	unsigned int		tx_fifo_depth; | ||||
| 	unsigned int		rx_fifo_depth; | ||||
| }; | ||||
| u32 dw_readl(struct dw_i2c_dev *dev, int offset) | ||||
| { | ||||
| 	u32 value = readl(dev->base + offset); | ||||
| 
 | ||||
| 	if (dev->swab) | ||||
| 		return swab32(value); | ||||
| 	else | ||||
| 		return value; | ||||
| } | ||||
| 
 | ||||
| void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset) | ||||
| { | ||||
| 	if (dev->swab) | ||||
| 		b = swab32(b); | ||||
| 
 | ||||
| 	writel(b, dev->base + offset); | ||||
| } | ||||
| 
 | ||||
| static u32 | ||||
| i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) | ||||
| @ -283,13 +243,29 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) | ||||
|  * This function is called during I2C init function, and in case of timeout at | ||||
|  * run time. | ||||
|  */ | ||||
| static void i2c_dw_init(struct dw_i2c_dev *dev) | ||||
| int i2c_dw_init(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	u32 input_clock_khz = clk_get_rate(dev->clk) / 1000; | ||||
| 	u32 ic_con, hcnt, lcnt; | ||||
| 	u32 input_clock_khz; | ||||
| 	u32 hcnt, lcnt; | ||||
| 	u32 reg; | ||||
| 
 | ||||
| 	input_clock_khz = dev->get_clk_rate_khz(dev); | ||||
| 
 | ||||
| 	/* Configure register endianess access */ | ||||
| 	reg = dw_readl(dev, DW_IC_COMP_TYPE); | ||||
| 	if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { | ||||
| 		dev->swab = 1; | ||||
| 		reg = DW_IC_COMP_TYPE_VALUE; | ||||
| 	} | ||||
| 
 | ||||
| 	if (reg != DW_IC_COMP_TYPE_VALUE) { | ||||
| 		dev_err(dev->dev, "Unknown Synopsys component type: " | ||||
| 			"0x%08x\n", reg); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Disable the adapter */ | ||||
| 	writel(0, dev->base + DW_IC_ENABLE); | ||||
| 	dw_writel(dev, 0, DW_IC_ENABLE); | ||||
| 
 | ||||
| 	/* set standard and fast speed deviders for high/low periods */ | ||||
| 
 | ||||
| @ -303,8 +279,8 @@ static void i2c_dw_init(struct dw_i2c_dev *dev) | ||||
| 				47,	/* tLOW = 4.7 us */ | ||||
| 				3,	/* tf = 0.3 us */ | ||||
| 				0);	/* No offset */ | ||||
| 	writel(hcnt, dev->base + DW_IC_SS_SCL_HCNT); | ||||
| 	writel(lcnt, dev->base + DW_IC_SS_SCL_LCNT); | ||||
| 	dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT); | ||||
| 	dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); | ||||
| 	dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); | ||||
| 
 | ||||
| 	/* Fast-mode */ | ||||
| @ -317,18 +293,17 @@ static void i2c_dw_init(struct dw_i2c_dev *dev) | ||||
| 				13,	/* tLOW = 1.3 us */ | ||||
| 				3,	/* tf = 0.3 us */ | ||||
| 				0);	/* No offset */ | ||||
| 	writel(hcnt, dev->base + DW_IC_FS_SCL_HCNT); | ||||
| 	writel(lcnt, dev->base + DW_IC_FS_SCL_LCNT); | ||||
| 	dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT); | ||||
| 	dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); | ||||
| 	dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); | ||||
| 
 | ||||
| 	/* Configure Tx/Rx FIFO threshold levels */ | ||||
| 	writel(dev->tx_fifo_depth - 1, dev->base + DW_IC_TX_TL); | ||||
| 	writel(0, dev->base + DW_IC_RX_TL); | ||||
| 	dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); | ||||
| 	dw_writel(dev, 0, DW_IC_RX_TL); | ||||
| 
 | ||||
| 	/* configure the i2c master */ | ||||
| 	ic_con = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | | ||||
| 		DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; | ||||
| 	writel(ic_con, dev->base + DW_IC_CON); | ||||
| 	dw_writel(dev, dev->master_cfg , DW_IC_CON); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -338,7 +313,7 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	int timeout = TIMEOUT; | ||||
| 
 | ||||
| 	while (readl(dev->base + DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { | ||||
| 	while (dw_readl(dev, DW_IC_STATUS) & DW_IC_STATUS_ACTIVITY) { | ||||
| 		if (timeout <= 0) { | ||||
| 			dev_warn(dev->dev, "timeout waiting for bus ready\n"); | ||||
| 			return -ETIMEDOUT; | ||||
| @ -356,24 +331,24 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) | ||||
| 	u32 ic_con; | ||||
| 
 | ||||
| 	/* Disable the adapter */ | ||||
| 	writel(0, dev->base + DW_IC_ENABLE); | ||||
| 	dw_writel(dev, 0, DW_IC_ENABLE); | ||||
| 
 | ||||
| 	/* set the slave (target) address */ | ||||
| 	writel(msgs[dev->msg_write_idx].addr, dev->base + DW_IC_TAR); | ||||
| 	dw_writel(dev, msgs[dev->msg_write_idx].addr, DW_IC_TAR); | ||||
| 
 | ||||
| 	/* if the slave address is ten bit address, enable 10BITADDR */ | ||||
| 	ic_con = readl(dev->base + DW_IC_CON); | ||||
| 	ic_con = dw_readl(dev, DW_IC_CON); | ||||
| 	if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) | ||||
| 		ic_con |= DW_IC_CON_10BITADDR_MASTER; | ||||
| 	else | ||||
| 		ic_con &= ~DW_IC_CON_10BITADDR_MASTER; | ||||
| 	writel(ic_con, dev->base + DW_IC_CON); | ||||
| 	dw_writel(dev, ic_con, DW_IC_CON); | ||||
| 
 | ||||
| 	/* Enable the adapter */ | ||||
| 	writel(1, dev->base + DW_IC_ENABLE); | ||||
| 	dw_writel(dev, 1, DW_IC_ENABLE); | ||||
| 
 | ||||
| 	/* Enable interrupts */ | ||||
| 	writel(DW_IC_INTR_DEFAULT_MASK, dev->base + DW_IC_INTR_MASK); | ||||
| 	dw_writel(dev, DW_IC_INTR_DEFAULT_MASK, DW_IC_INTR_MASK); | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
| @ -382,7 +357,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) | ||||
|  * messages into the tx buffer.  Even if the size of i2c_msg data is | ||||
|  * longer than the size of the tx buffer, it handles everything. | ||||
|  */ | ||||
| static void | ||||
| void | ||||
| i2c_dw_xfer_msg(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	struct i2c_msg *msgs = dev->msgs; | ||||
| @ -420,15 +395,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) | ||||
| 			buf_len = msgs[dev->msg_write_idx].len; | ||||
| 		} | ||||
| 
 | ||||
| 		tx_limit = dev->tx_fifo_depth - readl(dev->base + DW_IC_TXFLR); | ||||
| 		rx_limit = dev->rx_fifo_depth - readl(dev->base + DW_IC_RXFLR); | ||||
| 		tx_limit = dev->tx_fifo_depth - dw_readl(dev, DW_IC_TXFLR); | ||||
| 		rx_limit = dev->rx_fifo_depth - dw_readl(dev, DW_IC_RXFLR); | ||||
| 
 | ||||
| 		while (buf_len > 0 && tx_limit > 0 && rx_limit > 0) { | ||||
| 			if (msgs[dev->msg_write_idx].flags & I2C_M_RD) { | ||||
| 				writel(0x100, dev->base + DW_IC_DATA_CMD); | ||||
| 				dw_writel(dev, 0x100, DW_IC_DATA_CMD); | ||||
| 				rx_limit--; | ||||
| 			} else | ||||
| 				writel(*buf++, dev->base + DW_IC_DATA_CMD); | ||||
| 				dw_writel(dev, *buf++, DW_IC_DATA_CMD); | ||||
| 			tx_limit--; buf_len--; | ||||
| 		} | ||||
| 
 | ||||
| @ -453,7 +428,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) | ||||
| 	if (dev->msg_err) | ||||
| 		intr_mask = 0; | ||||
| 
 | ||||
| 	writel(intr_mask, dev->base + DW_IC_INTR_MASK); | ||||
| 	dw_writel(dev, intr_mask,  DW_IC_INTR_MASK); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
| @ -477,10 +452,10 @@ i2c_dw_read(struct dw_i2c_dev *dev) | ||||
| 			buf = dev->rx_buf; | ||||
| 		} | ||||
| 
 | ||||
| 		rx_valid = readl(dev->base + DW_IC_RXFLR); | ||||
| 		rx_valid = dw_readl(dev, DW_IC_RXFLR); | ||||
| 
 | ||||
| 		for (; len > 0 && rx_valid > 0; len--, rx_valid--) | ||||
| 			*buf++ = readl(dev->base + DW_IC_DATA_CMD); | ||||
| 			*buf++ = dw_readl(dev, DW_IC_DATA_CMD); | ||||
| 
 | ||||
| 		if (len > 0) { | ||||
| 			dev->status |= STATUS_READ_IN_PROGRESS; | ||||
| @ -518,7 +493,7 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) | ||||
| /*
 | ||||
|  * Prepare controller for a transaction and call i2c_dw_xfer_msg | ||||
|  */ | ||||
| static int | ||||
| int | ||||
| i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev = i2c_get_adapdata(adap); | ||||
| @ -527,6 +502,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||||
| 	dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); | ||||
| 
 | ||||
| 	mutex_lock(&dev->lock); | ||||
| 	pm_runtime_get_sync(dev->dev); | ||||
| 
 | ||||
| 	INIT_COMPLETION(dev->cmd_complete); | ||||
| 	dev->msgs = msgs; | ||||
| @ -563,7 +539,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||||
| 	/* no error */ | ||||
| 	if (likely(!dev->cmd_err)) { | ||||
| 		/* Disable the adapter */ | ||||
| 		writel(0, dev->base + DW_IC_ENABLE); | ||||
| 		dw_writel(dev, 0, DW_IC_ENABLE); | ||||
| 		ret = num; | ||||
| 		goto done; | ||||
| 	} | ||||
| @ -576,19 +552,16 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||||
| 	ret = -EIO; | ||||
| 
 | ||||
| done: | ||||
| 	pm_runtime_put(dev->dev); | ||||
| 	mutex_unlock(&dev->lock); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static u32 i2c_dw_func(struct i2c_adapter *adap) | ||||
| u32 i2c_dw_func(struct i2c_adapter *adap) | ||||
| { | ||||
| 	return	I2C_FUNC_I2C | | ||||
| 		I2C_FUNC_10BIT_ADDR | | ||||
| 		I2C_FUNC_SMBUS_BYTE | | ||||
| 		I2C_FUNC_SMBUS_BYTE_DATA | | ||||
| 		I2C_FUNC_SMBUS_WORD_DATA | | ||||
| 		I2C_FUNC_SMBUS_I2C_BLOCK; | ||||
| 	struct dw_i2c_dev *dev = i2c_get_adapdata(adap); | ||||
| 	return dev->functionality; | ||||
| } | ||||
| 
 | ||||
| static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) | ||||
| @ -601,47 +574,47 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) | ||||
| 	 * in the IC_RAW_INTR_STAT register. | ||||
| 	 * | ||||
| 	 * That is, | ||||
| 	 *   stat = readl(IC_INTR_STAT); | ||||
| 	 *   stat = dw_readl(IC_INTR_STAT); | ||||
| 	 * equals to, | ||||
| 	 *   stat = readl(IC_RAW_INTR_STAT) & readl(IC_INTR_MASK); | ||||
| 	 *   stat = dw_readl(IC_RAW_INTR_STAT) & dw_readl(IC_INTR_MASK); | ||||
| 	 * | ||||
| 	 * The raw version might be useful for debugging purposes. | ||||
| 	 */ | ||||
| 	stat = readl(dev->base + DW_IC_INTR_STAT); | ||||
| 	stat = dw_readl(dev, DW_IC_INTR_STAT); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Do not use the IC_CLR_INTR register to clear interrupts, or | ||||
| 	 * you'll miss some interrupts, triggered during the period from | ||||
| 	 * readl(IC_INTR_STAT) to readl(IC_CLR_INTR). | ||||
| 	 * dw_readl(IC_INTR_STAT) to dw_readl(IC_CLR_INTR). | ||||
| 	 * | ||||
| 	 * Instead, use the separately-prepared IC_CLR_* registers. | ||||
| 	 */ | ||||
| 	if (stat & DW_IC_INTR_RX_UNDER) | ||||
| 		readl(dev->base + DW_IC_CLR_RX_UNDER); | ||||
| 		dw_readl(dev, DW_IC_CLR_RX_UNDER); | ||||
| 	if (stat & DW_IC_INTR_RX_OVER) | ||||
| 		readl(dev->base + DW_IC_CLR_RX_OVER); | ||||
| 		dw_readl(dev, DW_IC_CLR_RX_OVER); | ||||
| 	if (stat & DW_IC_INTR_TX_OVER) | ||||
| 		readl(dev->base + DW_IC_CLR_TX_OVER); | ||||
| 		dw_readl(dev, DW_IC_CLR_TX_OVER); | ||||
| 	if (stat & DW_IC_INTR_RD_REQ) | ||||
| 		readl(dev->base + DW_IC_CLR_RD_REQ); | ||||
| 		dw_readl(dev, DW_IC_CLR_RD_REQ); | ||||
| 	if (stat & DW_IC_INTR_TX_ABRT) { | ||||
| 		/*
 | ||||
| 		 * The IC_TX_ABRT_SOURCE register is cleared whenever | ||||
| 		 * the IC_CLR_TX_ABRT is read.  Preserve it beforehand. | ||||
| 		 */ | ||||
| 		dev->abort_source = readl(dev->base + DW_IC_TX_ABRT_SOURCE); | ||||
| 		readl(dev->base + DW_IC_CLR_TX_ABRT); | ||||
| 		dev->abort_source = dw_readl(dev, DW_IC_TX_ABRT_SOURCE); | ||||
| 		dw_readl(dev, DW_IC_CLR_TX_ABRT); | ||||
| 	} | ||||
| 	if (stat & DW_IC_INTR_RX_DONE) | ||||
| 		readl(dev->base + DW_IC_CLR_RX_DONE); | ||||
| 		dw_readl(dev, DW_IC_CLR_RX_DONE); | ||||
| 	if (stat & DW_IC_INTR_ACTIVITY) | ||||
| 		readl(dev->base + DW_IC_CLR_ACTIVITY); | ||||
| 		dw_readl(dev, DW_IC_CLR_ACTIVITY); | ||||
| 	if (stat & DW_IC_INTR_STOP_DET) | ||||
| 		readl(dev->base + DW_IC_CLR_STOP_DET); | ||||
| 		dw_readl(dev, DW_IC_CLR_STOP_DET); | ||||
| 	if (stat & DW_IC_INTR_START_DET) | ||||
| 		readl(dev->base + DW_IC_CLR_START_DET); | ||||
| 		dw_readl(dev, DW_IC_CLR_START_DET); | ||||
| 	if (stat & DW_IC_INTR_GEN_CALL) | ||||
| 		readl(dev->base + DW_IC_CLR_GEN_CALL); | ||||
| 		dw_readl(dev, DW_IC_CLR_GEN_CALL); | ||||
| 
 | ||||
| 	return stat; | ||||
| } | ||||
| @ -650,13 +623,19 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) | ||||
|  * Interrupt service routine. This gets called whenever an I2C interrupt | ||||
|  * occurs. | ||||
|  */ | ||||
| static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) | ||||
| irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev = dev_id; | ||||
| 	u32 stat; | ||||
| 	u32 stat, enabled; | ||||
| 
 | ||||
| 	enabled = dw_readl(dev, DW_IC_ENABLE); | ||||
| 	stat = dw_readl(dev, DW_IC_RAW_INTR_STAT); | ||||
| 	dev_dbg(dev->dev, "%s:  %s enabled= 0x%x stat=0x%x\n", __func__, | ||||
| 		dev->adapter.name, enabled, stat); | ||||
| 	if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) | ||||
| 		return IRQ_NONE; | ||||
| 
 | ||||
| 	stat = i2c_dw_read_clear_intrbits(dev); | ||||
| 	dev_dbg(dev->dev, "%s: stat=0x%x\n", __func__, stat); | ||||
| 
 | ||||
| 	if (stat & DW_IC_INTR_TX_ABRT) { | ||||
| 		dev->cmd_err |= DW_IC_ERR_TX_ABRT; | ||||
| @ -666,7 +645,7 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) | ||||
| 		 * Anytime TX_ABRT is set, the contents of the tx/rx | ||||
| 		 * buffers are flushed.  Make sure to skip them. | ||||
| 		 */ | ||||
| 		writel(0, dev->base + DW_IC_INTR_MASK); | ||||
| 		dw_writel(dev, 0, DW_IC_INTR_MASK); | ||||
| 		goto tx_aborted; | ||||
| 	} | ||||
| 
 | ||||
| @ -689,159 +668,38 @@ tx_aborted: | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| 
 | ||||
| static struct i2c_algorithm i2c_dw_algo = { | ||||
| 	.master_xfer	= i2c_dw_xfer, | ||||
| 	.functionality	= i2c_dw_func, | ||||
| }; | ||||
| 
 | ||||
| static int __devinit dw_i2c_probe(struct platform_device *pdev) | ||||
| void i2c_dw_enable(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev; | ||||
| 	struct i2c_adapter *adap; | ||||
| 	struct resource *mem, *ioarea; | ||||
| 	int irq, r; | ||||
| 
 | ||||
| 	/* NOTE: driver uses the static register mapping */ | ||||
| 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	if (!mem) { | ||||
| 		dev_err(&pdev->dev, "no mem resource?\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	irq = platform_get_irq(pdev, 0); | ||||
| 	if (irq < 0) { | ||||
| 		dev_err(&pdev->dev, "no irq resource?\n"); | ||||
| 		return irq; /* -ENXIO */ | ||||
| 	} | ||||
| 
 | ||||
| 	ioarea = request_mem_region(mem->start, resource_size(mem), | ||||
| 			pdev->name); | ||||
| 	if (!ioarea) { | ||||
| 		dev_err(&pdev->dev, "I2C region already claimed\n"); | ||||
| 		return -EBUSY; | ||||
| 	} | ||||
| 
 | ||||
| 	dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); | ||||
| 	if (!dev) { | ||||
| 		r = -ENOMEM; | ||||
| 		goto err_release_region; | ||||
| 	} | ||||
| 
 | ||||
| 	init_completion(&dev->cmd_complete); | ||||
| 	mutex_init(&dev->lock); | ||||
| 	dev->dev = get_device(&pdev->dev); | ||||
| 	dev->irq = irq; | ||||
| 	platform_set_drvdata(pdev, dev); | ||||
| 
 | ||||
| 	dev->clk = clk_get(&pdev->dev, NULL); | ||||
| 	if (IS_ERR(dev->clk)) { | ||||
| 		r = -ENODEV; | ||||
| 		goto err_free_mem; | ||||
| 	} | ||||
| 	clk_enable(dev->clk); | ||||
| 
 | ||||
| 	dev->base = ioremap(mem->start, resource_size(mem)); | ||||
| 	if (dev->base == NULL) { | ||||
| 		dev_err(&pdev->dev, "failure mapping io resources\n"); | ||||
| 		r = -EBUSY; | ||||
| 		goto err_unuse_clocks; | ||||
| 	} | ||||
| 	{ | ||||
| 		u32 param1 = readl(dev->base + DW_IC_COMP_PARAM_1); | ||||
| 
 | ||||
| 		dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; | ||||
| 		dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1; | ||||
| 	} | ||||
| 	i2c_dw_init(dev); | ||||
| 
 | ||||
| 	writel(0, dev->base + DW_IC_INTR_MASK); /* disable IRQ */ | ||||
| 	r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); | ||||
| 		goto err_iounmap; | ||||
| 	} | ||||
| 
 | ||||
| 	adap = &dev->adapter; | ||||
| 	i2c_set_adapdata(adap, dev); | ||||
| 	adap->owner = THIS_MODULE; | ||||
| 	adap->class = I2C_CLASS_HWMON; | ||||
| 	strlcpy(adap->name, "Synopsys DesignWare I2C adapter", | ||||
| 			sizeof(adap->name)); | ||||
| 	adap->algo = &i2c_dw_algo; | ||||
| 	adap->dev.parent = &pdev->dev; | ||||
| 
 | ||||
| 	adap->nr = pdev->id; | ||||
| 	r = i2c_add_numbered_adapter(adap); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failure adding adapter\n"); | ||||
| 		goto err_free_irq; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_free_irq: | ||||
| 	free_irq(dev->irq, dev); | ||||
| err_iounmap: | ||||
| 	iounmap(dev->base); | ||||
| err_unuse_clocks: | ||||
| 	clk_disable(dev->clk); | ||||
| 	clk_put(dev->clk); | ||||
| 	dev->clk = NULL; | ||||
| err_free_mem: | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| 	put_device(&pdev->dev); | ||||
| 	kfree(dev); | ||||
| err_release_region: | ||||
| 	release_mem_region(mem->start, resource_size(mem)); | ||||
| 
 | ||||
| 	return r; | ||||
|        /* Enable the adapter */ | ||||
| 	dw_writel(dev, 1, DW_IC_ENABLE); | ||||
| } | ||||
| 
 | ||||
| static int __devexit dw_i2c_remove(struct platform_device *pdev) | ||||
| u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev = platform_get_drvdata(pdev); | ||||
| 	struct resource *mem; | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| 	i2c_del_adapter(&dev->adapter); | ||||
| 	put_device(&pdev->dev); | ||||
| 
 | ||||
| 	clk_disable(dev->clk); | ||||
| 	clk_put(dev->clk); | ||||
| 	dev->clk = NULL; | ||||
| 
 | ||||
| 	writel(0, dev->base + DW_IC_ENABLE); | ||||
| 	free_irq(dev->irq, dev); | ||||
| 	kfree(dev); | ||||
| 
 | ||||
| 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	release_mem_region(mem->start, resource_size(mem)); | ||||
| 	return 0; | ||||
| 	return dw_readl(dev, DW_IC_ENABLE); | ||||
| } | ||||
| 
 | ||||
| /* work with hotplug and coldplug */ | ||||
| MODULE_ALIAS("platform:i2c_designware"); | ||||
| 
 | ||||
| static struct platform_driver dw_i2c_driver = { | ||||
| 	.remove		= __devexit_p(dw_i2c_remove), | ||||
| 	.driver		= { | ||||
| 		.name	= "i2c_designware", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int __init dw_i2c_init_driver(void) | ||||
| void i2c_dw_disable(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); | ||||
| } | ||||
| module_init(dw_i2c_init_driver); | ||||
| 	/* Disable controller */ | ||||
| 	dw_writel(dev, 0, DW_IC_ENABLE); | ||||
| 
 | ||||
| static void __exit dw_i2c_exit_driver(void) | ||||
| 	/* Disable all interupts */ | ||||
| 	dw_writel(dev, 0, DW_IC_INTR_MASK); | ||||
| 	dw_readl(dev, DW_IC_CLR_INTR); | ||||
| } | ||||
| 
 | ||||
| void i2c_dw_clear_int(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	platform_driver_unregister(&dw_i2c_driver); | ||||
| 	dw_readl(dev, DW_IC_CLR_INTR); | ||||
| } | ||||
| module_exit(dw_i2c_exit_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); | ||||
| MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| void i2c_dw_disable_int(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	dw_writel(dev, 0, DW_IC_INTR_MASK); | ||||
| } | ||||
| 
 | ||||
| u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	return dw_readl(dev, DW_IC_COMP_PARAM_1); | ||||
| } | ||||
							
								
								
									
										105
									
								
								drivers/i2c/busses/i2c-designware-core.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								drivers/i2c/busses/i2c-designware-core.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,105 @@ | ||||
| /*
 | ||||
|  * Synopsys DesignWare I2C adapter driver (master only). | ||||
|  * | ||||
|  * Based on the TI DAVINCI I2C adapter driver. | ||||
|  * | ||||
|  * Copyright (C) 2006 Texas Instruments. | ||||
|  * Copyright (C) 2007 MontaVista Software Inc. | ||||
|  * Copyright (C) 2009 Provigent Ltd. | ||||
|  * | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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. | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| 
 | ||||
| #define DW_IC_CON_MASTER		0x1 | ||||
| #define DW_IC_CON_SPEED_STD		0x2 | ||||
| #define DW_IC_CON_SPEED_FAST		0x4 | ||||
| #define DW_IC_CON_10BITADDR_MASTER	0x10 | ||||
| #define DW_IC_CON_RESTART_EN		0x20 | ||||
| #define DW_IC_CON_SLAVE_DISABLE		0x40 | ||||
| 
 | ||||
| 
 | ||||
| /**
 | ||||
|  * struct dw_i2c_dev - private i2c-designware data | ||||
|  * @dev: driver model device node | ||||
|  * @base: IO registers pointer | ||||
|  * @cmd_complete: tx completion indicator | ||||
|  * @lock: protect this struct and IO registers | ||||
|  * @clk: input reference clock | ||||
|  * @cmd_err: run time hadware error code | ||||
|  * @msgs: points to an array of messages currently being transfered | ||||
|  * @msgs_num: the number of elements in msgs | ||||
|  * @msg_write_idx: the element index of the current tx message in the msgs | ||||
|  *	array | ||||
|  * @tx_buf_len: the length of the current tx buffer | ||||
|  * @tx_buf: the current tx buffer | ||||
|  * @msg_read_idx: the element index of the current rx message in the msgs | ||||
|  *	array | ||||
|  * @rx_buf_len: the length of the current rx buffer | ||||
|  * @rx_buf: the current rx buffer | ||||
|  * @msg_err: error status of the current transfer | ||||
|  * @status: i2c master status, one of STATUS_* | ||||
|  * @abort_source: copy of the TX_ABRT_SOURCE register | ||||
|  * @irq: interrupt number for the i2c master | ||||
|  * @adapter: i2c subsystem adapter node | ||||
|  * @tx_fifo_depth: depth of the hardware tx fifo | ||||
|  * @rx_fifo_depth: depth of the hardware rx fifo | ||||
|  */ | ||||
| struct dw_i2c_dev { | ||||
| 	struct device		*dev; | ||||
| 	void __iomem		*base; | ||||
| 	struct completion	cmd_complete; | ||||
| 	struct mutex		lock; | ||||
| 	struct clk		*clk; | ||||
| 	u32			(*get_clk_rate_khz) (struct dw_i2c_dev *dev); | ||||
| 	struct dw_pci_controller *controller; | ||||
| 	int			cmd_err; | ||||
| 	struct i2c_msg		*msgs; | ||||
| 	int			msgs_num; | ||||
| 	int			msg_write_idx; | ||||
| 	u32			tx_buf_len; | ||||
| 	u8			*tx_buf; | ||||
| 	int			msg_read_idx; | ||||
| 	u32			rx_buf_len; | ||||
| 	u8			*rx_buf; | ||||
| 	int			msg_err; | ||||
| 	unsigned int		status; | ||||
| 	u32			abort_source; | ||||
| 	int			irq; | ||||
| 	int			swab; | ||||
| 	struct i2c_adapter	adapter; | ||||
| 	u32			functionality; | ||||
| 	u32			master_cfg; | ||||
| 	unsigned int		tx_fifo_depth; | ||||
| 	unsigned int		rx_fifo_depth; | ||||
| }; | ||||
| 
 | ||||
| extern u32 dw_readl(struct dw_i2c_dev *dev, int offset); | ||||
| extern void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset); | ||||
| extern int i2c_dw_init(struct dw_i2c_dev *dev); | ||||
| extern int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], | ||||
| 		int num); | ||||
| extern u32 i2c_dw_func(struct i2c_adapter *adap); | ||||
| extern irqreturn_t i2c_dw_isr(int this_irq, void *dev_id); | ||||
| extern void i2c_dw_enable(struct dw_i2c_dev *dev); | ||||
| extern u32 i2c_dw_is_enabled(struct dw_i2c_dev *dev); | ||||
| extern void i2c_dw_disable(struct dw_i2c_dev *dev); | ||||
| extern void i2c_dw_clear_int(struct dw_i2c_dev *dev); | ||||
| extern void i2c_dw_disable_int(struct dw_i2c_dev *dev); | ||||
| extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev); | ||||
							
								
								
									
										392
									
								
								drivers/i2c/busses/i2c-designware-pcidrv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								drivers/i2c/busses/i2c-designware-pcidrv.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,392 @@ | ||||
| /*
 | ||||
|  * Synopsys DesignWare I2C adapter driver (master only). | ||||
|  * | ||||
|  * Based on the TI DAVINCI I2C adapter driver. | ||||
|  * | ||||
|  * Copyright (C) 2006 Texas Instruments. | ||||
|  * Copyright (C) 2007 MontaVista Software Inc. | ||||
|  * Copyright (C) 2009 Provigent Ltd. | ||||
|  * Copyright (C) 2011 Intel corporation. | ||||
|  * | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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. | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/pci.h> | ||||
| #include <linux/pm_runtime.h> | ||||
| #include "i2c-designware-core.h" | ||||
| 
 | ||||
| #define DRIVER_NAME "i2c-designware-pci" | ||||
| 
 | ||||
| enum dw_pci_ctl_id_t { | ||||
| 	moorestown_0, | ||||
| 	moorestown_1, | ||||
| 	moorestown_2, | ||||
| 
 | ||||
| 	medfield_0, | ||||
| 	medfield_1, | ||||
| 	medfield_2, | ||||
| 	medfield_3, | ||||
| 	medfield_4, | ||||
| 	medfield_5, | ||||
| }; | ||||
| 
 | ||||
| struct dw_pci_controller { | ||||
| 	u32 bus_num; | ||||
| 	u32 bus_cfg; | ||||
| 	u32 tx_fifo_depth; | ||||
| 	u32 rx_fifo_depth; | ||||
| 	u32 clk_khz; | ||||
| }; | ||||
| 
 | ||||
| #define INTEL_MID_STD_CFG  (DW_IC_CON_MASTER |			\ | ||||
| 				DW_IC_CON_SLAVE_DISABLE |	\ | ||||
| 				DW_IC_CON_RESTART_EN) | ||||
| 
 | ||||
| static struct  dw_pci_controller  dw_pci_controllers[] = { | ||||
| 	[moorestown_0] = { | ||||
| 		.bus_num     = 0, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[moorestown_1] = { | ||||
| 		.bus_num     = 1, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[moorestown_2] = { | ||||
| 		.bus_num     = 2, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[medfield_0] = { | ||||
| 		.bus_num     = 0, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[medfield_1] = { | ||||
| 		.bus_num     = 1, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[medfield_2] = { | ||||
| 		.bus_num     = 2, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[medfield_3] = { | ||||
| 		.bus_num     = 3, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_STD, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[medfield_4] = { | ||||
| 		.bus_num     = 4, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| 	[medfield_5] = { | ||||
| 		.bus_num     = 5, | ||||
| 		.bus_cfg   = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, | ||||
| 		.tx_fifo_depth = 32, | ||||
| 		.rx_fifo_depth = 32, | ||||
| 		.clk_khz      = 25000, | ||||
| 	}, | ||||
| }; | ||||
| static struct i2c_algorithm i2c_dw_algo = { | ||||
| 	.master_xfer	= i2c_dw_xfer, | ||||
| 	.functionality	= i2c_dw_func, | ||||
| }; | ||||
| 
 | ||||
| static int i2c_dw_pci_suspend(struct device *dev) | ||||
| { | ||||
| 	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||||
| 	struct dw_i2c_dev *i2c = pci_get_drvdata(pdev); | ||||
| 	int err; | ||||
| 
 | ||||
| 
 | ||||
| 	i2c_dw_disable(i2c); | ||||
| 
 | ||||
| 	err = pci_save_state(pdev); | ||||
| 	if (err) { | ||||
| 		dev_err(&pdev->dev, "pci_save_state failed\n"); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	err = pci_set_power_state(pdev, PCI_D3hot); | ||||
| 	if (err) { | ||||
| 		dev_err(&pdev->dev, "pci_set_power_state failed\n"); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int i2c_dw_pci_resume(struct device *dev) | ||||
| { | ||||
| 	struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); | ||||
| 	struct dw_i2c_dev *i2c = pci_get_drvdata(pdev); | ||||
| 	int err; | ||||
| 	u32 enabled; | ||||
| 
 | ||||
| 	enabled = i2c_dw_is_enabled(i2c); | ||||
| 	if (enabled) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	err = pci_set_power_state(pdev, PCI_D0); | ||||
| 	if (err) { | ||||
| 		dev_err(&pdev->dev, "pci_set_power_state() failed\n"); | ||||
| 		return err; | ||||
| 	} | ||||
| 
 | ||||
| 	pci_restore_state(pdev); | ||||
| 
 | ||||
| 	i2c_dw_init(i2c); | ||||
| 	i2c_dw_enable(i2c); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int i2c_dw_pci_runtime_idle(struct device *dev) | ||||
| { | ||||
| 	int err = pm_schedule_suspend(dev, 500); | ||||
| 	dev_dbg(dev, "runtime_idle called\n"); | ||||
| 
 | ||||
| 	if (err != 0) | ||||
| 		return 0; | ||||
| 	return -EBUSY; | ||||
| } | ||||
| 
 | ||||
| static const struct dev_pm_ops i2c_dw_pm_ops = { | ||||
| 	.resume         = i2c_dw_pci_resume, | ||||
| 	.suspend        = i2c_dw_pci_suspend, | ||||
| 	SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume, | ||||
| 			   i2c_dw_pci_runtime_idle) | ||||
| }; | ||||
| 
 | ||||
| static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	return dev->controller->clk_khz; | ||||
| } | ||||
| 
 | ||||
| static int __devinit i2c_dw_pci_probe(struct pci_dev *pdev, | ||||
| const struct pci_device_id *id) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev; | ||||
| 	struct i2c_adapter *adap; | ||||
| 	unsigned long start, len; | ||||
| 	void __iomem *base; | ||||
| 	int r; | ||||
| 	struct  dw_pci_controller *controller; | ||||
| 
 | ||||
| 	if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { | ||||
| 		printk(KERN_ERR "dw_i2c_pci_probe: invalid driver data %ld\n", | ||||
| 			id->driver_data); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	controller = &dw_pci_controllers[id->driver_data]; | ||||
| 
 | ||||
| 	r = pci_enable_device(pdev); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n", | ||||
| 			r); | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Determine the address of the I2C area */ | ||||
| 	start = pci_resource_start(pdev, 0); | ||||
| 	len = pci_resource_len(pdev, 0); | ||||
| 	if (!start || len == 0) { | ||||
| 		dev_err(&pdev->dev, "base address not set\n"); | ||||
| 		r = -ENODEV; | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	r = pci_request_region(pdev, 0, DRIVER_NAME); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failed to request I2C region " | ||||
| 			"0x%lx-0x%lx\n", start, | ||||
| 			(unsigned long)pci_resource_end(pdev, 0)); | ||||
| 		goto exit; | ||||
| 	} | ||||
| 
 | ||||
| 	base = ioremap_nocache(start, len); | ||||
| 	if (!base) { | ||||
| 		dev_err(&pdev->dev, "I/O memory remapping failed\n"); | ||||
| 		r = -ENOMEM; | ||||
| 		goto err_release_region; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); | ||||
| 	if (!dev) { | ||||
| 		r = -ENOMEM; | ||||
| 		goto err_release_region; | ||||
| 	} | ||||
| 
 | ||||
| 	init_completion(&dev->cmd_complete); | ||||
| 	mutex_init(&dev->lock); | ||||
| 	dev->clk = NULL; | ||||
| 	dev->controller = controller; | ||||
| 	dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; | ||||
| 	dev->base = base; | ||||
| 	dev->dev = get_device(&pdev->dev); | ||||
| 	dev->functionality = | ||||
| 		I2C_FUNC_I2C | | ||||
| 		I2C_FUNC_SMBUS_BYTE | | ||||
| 		I2C_FUNC_SMBUS_BYTE_DATA | | ||||
| 		I2C_FUNC_SMBUS_WORD_DATA | | ||||
| 		I2C_FUNC_SMBUS_I2C_BLOCK; | ||||
| 	dev->master_cfg =  controller->bus_cfg; | ||||
| 
 | ||||
| 	pci_set_drvdata(pdev, dev); | ||||
| 
 | ||||
| 	dev->tx_fifo_depth = controller->tx_fifo_depth; | ||||
| 	dev->rx_fifo_depth = controller->rx_fifo_depth; | ||||
| 	r = i2c_dw_init(dev); | ||||
| 	if (r) | ||||
| 		goto err_iounmap; | ||||
| 
 | ||||
| 	adap = &dev->adapter; | ||||
| 	i2c_set_adapdata(adap, dev); | ||||
| 	adap->owner = THIS_MODULE; | ||||
| 	adap->class = 0; | ||||
| 	adap->algo = &i2c_dw_algo; | ||||
| 	adap->dev.parent = &pdev->dev; | ||||
| 	adap->nr = controller->bus_num; | ||||
| 	snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d", | ||||
| 		adap->nr); | ||||
| 
 | ||||
| 	r = request_irq(pdev->irq, i2c_dw_isr, IRQF_SHARED, adap->name, dev); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); | ||||
| 		goto err_iounmap; | ||||
| 	} | ||||
| 
 | ||||
| 	i2c_dw_disable_int(dev); | ||||
| 	i2c_dw_clear_int(dev); | ||||
| 	r = i2c_add_numbered_adapter(adap); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failure adding adapter\n"); | ||||
| 		goto err_free_irq; | ||||
| 	} | ||||
| 
 | ||||
| 	pm_runtime_put_noidle(&pdev->dev); | ||||
| 	pm_runtime_allow(&pdev->dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_free_irq: | ||||
| 	free_irq(pdev->irq, dev); | ||||
| err_iounmap: | ||||
| 	iounmap(dev->base); | ||||
| 	pci_set_drvdata(pdev, NULL); | ||||
| 	put_device(&pdev->dev); | ||||
| 	kfree(dev); | ||||
| err_release_region: | ||||
| 	pci_release_region(pdev, 0); | ||||
| exit: | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static void __devexit i2c_dw_pci_remove(struct pci_dev *pdev) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev = pci_get_drvdata(pdev); | ||||
| 
 | ||||
| 	i2c_dw_disable(dev); | ||||
| 	pm_runtime_forbid(&pdev->dev); | ||||
| 	pm_runtime_get_noresume(&pdev->dev); | ||||
| 
 | ||||
| 	pci_set_drvdata(pdev, NULL); | ||||
| 	i2c_del_adapter(&dev->adapter); | ||||
| 	put_device(&pdev->dev); | ||||
| 
 | ||||
| 	free_irq(dev->irq, dev); | ||||
| 	kfree(dev); | ||||
| 	pci_release_region(pdev, 0); | ||||
| } | ||||
| 
 | ||||
| /* work with hotplug and coldplug */ | ||||
| MODULE_ALIAS("i2c_designware-pci"); | ||||
| 
 | ||||
| DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = { | ||||
| 	/* Moorestown */ | ||||
| 	{ PCI_VDEVICE(INTEL, 0x0802), moorestown_0 }, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x0803), moorestown_1 }, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x0804), moorestown_2 }, | ||||
| 	/* Medfield */ | ||||
| 	{ PCI_VDEVICE(INTEL, 0x0817), medfield_3,}, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 }, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 }, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 }, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x082D), medfield_1 }, | ||||
| 	{ PCI_VDEVICE(INTEL, 0x082E), medfield_2 }, | ||||
| 	{ 0,} | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); | ||||
| 
 | ||||
| static struct pci_driver dw_i2c_driver = { | ||||
| 	.name		= DRIVER_NAME, | ||||
| 	.id_table	= i2_designware_pci_ids, | ||||
| 	.probe		= i2c_dw_pci_probe, | ||||
| 	.remove		= __devexit_p(i2c_dw_pci_remove), | ||||
| 	.driver         = { | ||||
| 		.pm     = &i2c_dw_pm_ops, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int __init dw_i2c_init_driver(void) | ||||
| { | ||||
| 	return  pci_register_driver(&dw_i2c_driver); | ||||
| } | ||||
| module_init(dw_i2c_init_driver); | ||||
| 
 | ||||
| static void __exit dw_i2c_exit_driver(void) | ||||
| { | ||||
| 	pci_unregister_driver(&dw_i2c_driver); | ||||
| } | ||||
| module_exit(dw_i2c_exit_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); | ||||
| MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); | ||||
| MODULE_LICENSE("GPL"); | ||||
							
								
								
									
										215
									
								
								drivers/i2c/busses/i2c-designware-platdrv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								drivers/i2c/busses/i2c-designware-platdrv.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,215 @@ | ||||
| /*
 | ||||
|  * Synopsys DesignWare I2C adapter driver (master only). | ||||
|  * | ||||
|  * Based on the TI DAVINCI I2C adapter driver. | ||||
|  * | ||||
|  * Copyright (C) 2006 Texas Instruments. | ||||
|  * Copyright (C) 2007 MontaVista Software Inc. | ||||
|  * Copyright (C) 2009 Provigent Ltd. | ||||
|  * | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  * 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. | ||||
|  * ---------------------------------------------------------------------------- | ||||
|  * | ||||
|  */ | ||||
| #include <linux/kernel.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/errno.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/interrupt.h> | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/slab.h> | ||||
| #include "i2c-designware-core.h" | ||||
| 
 | ||||
| static struct i2c_algorithm i2c_dw_algo = { | ||||
| 	.master_xfer	= i2c_dw_xfer, | ||||
| 	.functionality	= i2c_dw_func, | ||||
| }; | ||||
| static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) | ||||
| { | ||||
| 	return clk_get_rate(dev->clk)/1000; | ||||
| } | ||||
| 
 | ||||
| static int __devinit dw_i2c_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev; | ||||
| 	struct i2c_adapter *adap; | ||||
| 	struct resource *mem, *ioarea; | ||||
| 	int irq, r; | ||||
| 
 | ||||
| 	/* NOTE: driver uses the static register mapping */ | ||||
| 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	if (!mem) { | ||||
| 		dev_err(&pdev->dev, "no mem resource?\n"); | ||||
| 		return -EINVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	irq = platform_get_irq(pdev, 0); | ||||
| 	if (irq < 0) { | ||||
| 		dev_err(&pdev->dev, "no irq resource?\n"); | ||||
| 		return irq; /* -ENXIO */ | ||||
| 	} | ||||
| 
 | ||||
| 	ioarea = request_mem_region(mem->start, resource_size(mem), | ||||
| 			pdev->name); | ||||
| 	if (!ioarea) { | ||||
| 		dev_err(&pdev->dev, "I2C region already claimed\n"); | ||||
| 		return -EBUSY; | ||||
| 	} | ||||
| 
 | ||||
| 	dev = kzalloc(sizeof(struct dw_i2c_dev), GFP_KERNEL); | ||||
| 	if (!dev) { | ||||
| 		r = -ENOMEM; | ||||
| 		goto err_release_region; | ||||
| 	} | ||||
| 
 | ||||
| 	init_completion(&dev->cmd_complete); | ||||
| 	mutex_init(&dev->lock); | ||||
| 	dev->dev = get_device(&pdev->dev); | ||||
| 	dev->irq = irq; | ||||
| 	platform_set_drvdata(pdev, dev); | ||||
| 
 | ||||
| 	dev->clk = clk_get(&pdev->dev, NULL); | ||||
| 	dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; | ||||
| 
 | ||||
| 	if (IS_ERR(dev->clk)) { | ||||
| 		r = -ENODEV; | ||||
| 		goto err_free_mem; | ||||
| 	} | ||||
| 	clk_enable(dev->clk); | ||||
| 
 | ||||
| 	dev->functionality = | ||||
| 		I2C_FUNC_I2C | | ||||
| 		I2C_FUNC_10BIT_ADDR | | ||||
| 		I2C_FUNC_SMBUS_BYTE | | ||||
| 		I2C_FUNC_SMBUS_BYTE_DATA | | ||||
| 		I2C_FUNC_SMBUS_WORD_DATA | | ||||
| 		I2C_FUNC_SMBUS_I2C_BLOCK; | ||||
| 	dev->master_cfg =  DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | | ||||
| 		DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; | ||||
| 
 | ||||
| 	dev->base = ioremap(mem->start, resource_size(mem)); | ||||
| 	if (dev->base == NULL) { | ||||
| 		dev_err(&pdev->dev, "failure mapping io resources\n"); | ||||
| 		r = -EBUSY; | ||||
| 		goto err_unuse_clocks; | ||||
| 	} | ||||
| 	{ | ||||
| 		u32 param1 = i2c_dw_read_comp_param(dev); | ||||
| 
 | ||||
| 		dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; | ||||
| 		dev->rx_fifo_depth = ((param1 >> 8)  & 0xff) + 1; | ||||
| 	} | ||||
| 	r = i2c_dw_init(dev); | ||||
| 	if (r) | ||||
| 		goto err_iounmap; | ||||
| 
 | ||||
| 	i2c_dw_disable_int(dev); | ||||
| 	r = request_irq(dev->irq, i2c_dw_isr, IRQF_DISABLED, pdev->name, dev); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failure requesting irq %i\n", dev->irq); | ||||
| 		goto err_iounmap; | ||||
| 	} | ||||
| 
 | ||||
| 	adap = &dev->adapter; | ||||
| 	i2c_set_adapdata(adap, dev); | ||||
| 	adap->owner = THIS_MODULE; | ||||
| 	adap->class = I2C_CLASS_HWMON; | ||||
| 	strlcpy(adap->name, "Synopsys DesignWare I2C adapter", | ||||
| 			sizeof(adap->name)); | ||||
| 	adap->algo = &i2c_dw_algo; | ||||
| 	adap->dev.parent = &pdev->dev; | ||||
| 
 | ||||
| 	adap->nr = pdev->id; | ||||
| 	r = i2c_add_numbered_adapter(adap); | ||||
| 	if (r) { | ||||
| 		dev_err(&pdev->dev, "failure adding adapter\n"); | ||||
| 		goto err_free_irq; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 
 | ||||
| err_free_irq: | ||||
| 	free_irq(dev->irq, dev); | ||||
| err_iounmap: | ||||
| 	iounmap(dev->base); | ||||
| err_unuse_clocks: | ||||
| 	clk_disable(dev->clk); | ||||
| 	clk_put(dev->clk); | ||||
| 	dev->clk = NULL; | ||||
| err_free_mem: | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| 	put_device(&pdev->dev); | ||||
| 	kfree(dev); | ||||
| err_release_region: | ||||
| 	release_mem_region(mem->start, resource_size(mem)); | ||||
| 
 | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| static int __devexit dw_i2c_remove(struct platform_device *pdev) | ||||
| { | ||||
| 	struct dw_i2c_dev *dev = platform_get_drvdata(pdev); | ||||
| 	struct resource *mem; | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| 	i2c_del_adapter(&dev->adapter); | ||||
| 	put_device(&pdev->dev); | ||||
| 
 | ||||
| 	clk_disable(dev->clk); | ||||
| 	clk_put(dev->clk); | ||||
| 	dev->clk = NULL; | ||||
| 
 | ||||
| 	i2c_dw_disable(dev); | ||||
| 	free_irq(dev->irq, dev); | ||||
| 	kfree(dev); | ||||
| 
 | ||||
| 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||||
| 	release_mem_region(mem->start, resource_size(mem)); | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* work with hotplug and coldplug */ | ||||
| MODULE_ALIAS("platform:i2c_designware"); | ||||
| 
 | ||||
| static struct platform_driver dw_i2c_driver = { | ||||
| 	.remove		= __devexit_p(dw_i2c_remove), | ||||
| 	.driver		= { | ||||
| 		.name	= "i2c_designware", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static int __init dw_i2c_init_driver(void) | ||||
| { | ||||
| 	return platform_driver_probe(&dw_i2c_driver, dw_i2c_probe); | ||||
| } | ||||
| module_init(dw_i2c_init_driver); | ||||
| 
 | ||||
| static void __exit dw_i2c_exit_driver(void) | ||||
| { | ||||
| 	platform_driver_unregister(&dw_i2c_driver); | ||||
| } | ||||
| module_exit(dw_i2c_exit_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); | ||||
| MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); | ||||
| MODULE_LICENSE("GPL"); | ||||
| @ -64,6 +64,7 @@ | ||||
| #define TEN_BIT_ADDR_DEFAULT	0xF000 | ||||
| #define TEN_BIT_ADDR_MASK	0xF0 | ||||
| #define PCH_START		0x0020 | ||||
| #define PCH_RESTART		0x0004 | ||||
| #define PCH_ESR_START		0x0001 | ||||
| #define PCH_BUFF_START		0x1 | ||||
| #define PCH_REPSTART		0x0004 | ||||
| @ -273,23 +274,24 @@ static s32 pch_i2c_wait_for_bus_idle(struct i2c_algo_pch_data *adap, | ||||
| 				     s32 timeout) | ||||
| { | ||||
| 	void __iomem *p = adap->pch_base_address; | ||||
| 	ktime_t ns_val; | ||||
| 
 | ||||
| 	if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* MAX timeout value is timeout*1000*1000nsec */ | ||||
| 	ktime_t ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000); | ||||
| 	ns_val = ktime_add_ns(ktime_get(), timeout*1000*1000); | ||||
| 	do { | ||||
| 		if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) | ||||
| 			break; | ||||
| 		msleep(20); | ||||
| 		if ((ioread32(p + PCH_I2CSR) & I2CMBB_BIT) == 0) | ||||
| 			return 0; | ||||
| 	} while (ktime_lt(ktime_get(), ns_val)); | ||||
| 
 | ||||
| 	pch_dbg(adap, "I2CSR = %x\n", ioread32(p + PCH_I2CSR)); | ||||
| 	pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME); | ||||
| 	pch_i2c_init(adap); | ||||
| 
 | ||||
| 	if (timeout == 0) { | ||||
| 		pch_err(adap, "%s: Timeout Error.return%d\n", __func__, -ETIME); | ||||
| 		return -ETIME; | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| 	return -ETIME; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
| @ -311,21 +313,19 @@ static void pch_i2c_start(struct i2c_algo_pch_data *adap) | ||||
|  */ | ||||
| static s32 pch_i2c_wait_for_xfer_complete(struct i2c_algo_pch_data *adap) | ||||
| { | ||||
| 	s32 ret; | ||||
| 	long ret; | ||||
| 	ret = wait_event_timeout(pch_event, | ||||
| 			(adap->pch_event_flag != 0), msecs_to_jiffies(50)); | ||||
| 	if (ret < 0) { | ||||
| 		pch_err(adap, "timeout: %x\n", adap->pch_event_flag); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ret == 0) { | ||||
| 		pch_err(adap, "timeout: %x\n", adap->pch_event_flag); | ||||
| 		adap->pch_event_flag = 0; | ||||
| 		return -ETIMEDOUT; | ||||
| 	} | ||||
| 
 | ||||
| 	if (adap->pch_event_flag & I2C_ERROR_MASK) { | ||||
| 		pch_err(adap, "error bits set: %x\n", adap->pch_event_flag); | ||||
| 		adap->pch_event_flag = 0; | ||||
| 		return -EIO; | ||||
| 	} | ||||
| 
 | ||||
| @ -394,6 +394,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, | ||||
| 	u32 addr_2_msb; | ||||
| 	u32 addr_8_lsb; | ||||
| 	s32 wrcount; | ||||
| 	s32 rtn; | ||||
| 	void __iomem *p = adap->pch_base_address; | ||||
| 
 | ||||
| 	length = msgs->len; | ||||
| @ -412,15 +413,29 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, | ||||
| 	} | ||||
| 
 | ||||
| 	if (msgs->flags & I2C_M_TEN) { | ||||
| 		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); | ||||
| 		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06; | ||||
| 		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); | ||||
| 		if (first) | ||||
| 			pch_i2c_start(adap); | ||||
| 		if (pch_i2c_wait_for_xfer_complete(adap) == 0 && | ||||
| 		    pch_i2c_getack(adap) == 0) { | ||||
| 
 | ||||
| 		rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 		if (rtn == 0) { | ||||
| 			if (pch_i2c_getack(adap)) { | ||||
| 				pch_dbg(adap, "Receive NACK for slave address" | ||||
| 					"setting\n"); | ||||
| 				return -EIO; | ||||
| 			} | ||||
| 			addr_8_lsb = (addr & I2C_ADDR_MSK); | ||||
| 			iowrite32(addr_8_lsb, p + PCH_I2CDR); | ||||
| 		} else { | ||||
| 		} else if (rtn == -EIO) { /* Arbitration Lost */ | ||||
| 			pch_err(adap, "Lost Arbitration\n"); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMAL_BIT); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMIF_BIT); | ||||
| 			pch_i2c_init(adap); | ||||
| 			return -EAGAIN; | ||||
| 		} else { /* wait-event timeout */ | ||||
| 			pch_i2c_stop(adap); | ||||
| 			return -ETIME; | ||||
| 		} | ||||
| @ -431,31 +446,52 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, | ||||
| 			pch_i2c_start(adap); | ||||
| 	} | ||||
| 
 | ||||
| 	if ((pch_i2c_wait_for_xfer_complete(adap) == 0) && | ||||
| 	    (pch_i2c_getack(adap) == 0)) { | ||||
| 		for (wrcount = 0; wrcount < length; ++wrcount) { | ||||
| 			/* write buffer value to I2C data register */ | ||||
| 			iowrite32(buf[wrcount], p + PCH_I2CDR); | ||||
| 			pch_dbg(adap, "writing %x to Data register\n", | ||||
| 				buf[wrcount]); | ||||
| 
 | ||||
| 			if (pch_i2c_wait_for_xfer_complete(adap) != 0) | ||||
| 				return -ETIME; | ||||
| 
 | ||||
| 			if (pch_i2c_getack(adap)) | ||||
| 				return -EIO; | ||||
| 	rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 	if (rtn == 0) { | ||||
| 		if (pch_i2c_getack(adap)) { | ||||
| 			pch_dbg(adap, "Receive NACK for slave address" | ||||
| 				"setting\n"); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 
 | ||||
| 		/* check if this is the last message */ | ||||
| 		if (last) | ||||
| 			pch_i2c_stop(adap); | ||||
| 		else | ||||
| 			pch_i2c_repstart(adap); | ||||
| 	} else { | ||||
| 	} else if (rtn == -EIO) { /* Arbitration Lost */ | ||||
| 		pch_err(adap, "Lost Arbitration\n"); | ||||
| 		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT); | ||||
| 		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); | ||||
| 		pch_i2c_init(adap); | ||||
| 		return -EAGAIN; | ||||
| 	} else { /* wait-event timeout */ | ||||
| 		pch_i2c_stop(adap); | ||||
| 		return -EIO; | ||||
| 		return -ETIME; | ||||
| 	} | ||||
| 
 | ||||
| 	for (wrcount = 0; wrcount < length; ++wrcount) { | ||||
| 		/* write buffer value to I2C data register */ | ||||
| 		iowrite32(buf[wrcount], p + PCH_I2CDR); | ||||
| 		pch_dbg(adap, "writing %x to Data register\n", buf[wrcount]); | ||||
| 
 | ||||
| 		rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 		if (rtn == 0) { | ||||
| 			if (pch_i2c_getack(adap)) { | ||||
| 				pch_dbg(adap, "Receive NACK for slave address" | ||||
| 					"setting\n"); | ||||
| 				return -EIO; | ||||
| 			} | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMCF_BIT); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMIF_BIT); | ||||
| 		} else { /* wait-event timeout */ | ||||
| 			pch_i2c_stop(adap); | ||||
| 			return -ETIME; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* check if this is the last message */ | ||||
| 	if (last) | ||||
| 		pch_i2c_stop(adap); | ||||
| 	else | ||||
| 		pch_i2c_repstart(adap); | ||||
| 
 | ||||
| 	pch_dbg(adap, "return=%d\n", wrcount); | ||||
| 
 | ||||
| 	return wrcount; | ||||
| @ -483,6 +519,19 @@ static void pch_i2c_sendnack(struct i2c_algo_pch_data *adap) | ||||
| 	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_ACK); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * pch_i2c_restart() - Generate I2C restart condition in normal mode. | ||||
|  * @adap:	Pointer to struct i2c_algo_pch_data. | ||||
|  * | ||||
|  * Generate I2C restart condition in normal mode by setting I2CCTL.I2CRSTA. | ||||
|  */ | ||||
| static void pch_i2c_restart(struct i2c_algo_pch_data *adap) | ||||
| { | ||||
| 	void __iomem *p = adap->pch_base_address; | ||||
| 	pch_dbg(adap, "I2CCTL = %x\n", ioread32(p + PCH_I2CCTL)); | ||||
| 	pch_setbit(adap->pch_base_address, PCH_I2CCTL, PCH_RESTART); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * pch_i2c_readbytes() - read data  from I2C bus in normal mode. | ||||
|  * @i2c_adap:	Pointer to the struct i2c_adapter. | ||||
| @ -500,7 +549,9 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | ||||
| 	u32 length; | ||||
| 	u32 addr; | ||||
| 	u32 addr_2_msb; | ||||
| 	u32 addr_8_lsb; | ||||
| 	void __iomem *p = adap->pch_base_address; | ||||
| 	s32 rtn; | ||||
| 
 | ||||
| 	length = msgs->len; | ||||
| 	buf = msgs->buf; | ||||
| @ -515,9 +566,55 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | ||||
| 	} | ||||
| 
 | ||||
| 	if (msgs->flags & I2C_M_TEN) { | ||||
| 		addr_2_msb = (((addr & I2C_MSB_2B_MSK) >> 7) | (I2C_RD)); | ||||
| 		addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); | ||||
| 		iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); | ||||
| 		if (first) | ||||
| 			pch_i2c_start(adap); | ||||
| 
 | ||||
| 		rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 		if (rtn == 0) { | ||||
| 			if (pch_i2c_getack(adap)) { | ||||
| 				pch_dbg(adap, "Receive NACK for slave address" | ||||
| 					"setting\n"); | ||||
| 				return -EIO; | ||||
| 			} | ||||
| 			addr_8_lsb = (addr & I2C_ADDR_MSK); | ||||
| 			iowrite32(addr_8_lsb, p + PCH_I2CDR); | ||||
| 		} else if (rtn == -EIO) { /* Arbitration Lost */ | ||||
| 			pch_err(adap, "Lost Arbitration\n"); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMAL_BIT); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMIF_BIT); | ||||
| 			pch_i2c_init(adap); | ||||
| 			return -EAGAIN; | ||||
| 		} else { /* wait-event timeout */ | ||||
| 			pch_i2c_stop(adap); | ||||
| 			return -ETIME; | ||||
| 		} | ||||
| 		pch_i2c_restart(adap); | ||||
| 		rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 		if (rtn == 0) { | ||||
| 			if (pch_i2c_getack(adap)) { | ||||
| 				pch_dbg(adap, "Receive NACK for slave address" | ||||
| 					"setting\n"); | ||||
| 				return -EIO; | ||||
| 			} | ||||
| 			addr_2_msb |= I2C_RD; | ||||
| 			iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, | ||||
| 				  p + PCH_I2CDR); | ||||
| 		} else if (rtn == -EIO) { /* Arbitration Lost */ | ||||
| 			pch_err(adap, "Lost Arbitration\n"); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMAL_BIT); | ||||
| 			pch_clrbit(adap->pch_base_address, PCH_I2CSR, | ||||
| 				   I2CMIF_BIT); | ||||
| 			pch_i2c_init(adap); | ||||
| 			return -EAGAIN; | ||||
| 		} else { /* wait-event timeout */ | ||||
| 			pch_i2c_stop(adap); | ||||
| 			return -ETIME; | ||||
| 		} | ||||
| 	} else { | ||||
| 		/* 7 address bits + R/W bit */ | ||||
| 		addr = (((addr) << 1) | (I2C_RD)); | ||||
| @ -528,56 +625,81 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, | ||||
| 	if (first) | ||||
| 		pch_i2c_start(adap); | ||||
| 
 | ||||
| 	if ((pch_i2c_wait_for_xfer_complete(adap) == 0) && | ||||
| 	    (pch_i2c_getack(adap) == 0)) { | ||||
| 		pch_dbg(adap, "return %d\n", 0); | ||||
| 	rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 	if (rtn == 0) { | ||||
| 		if (pch_i2c_getack(adap)) { | ||||
| 			pch_dbg(adap, "Receive NACK for slave address" | ||||
| 				"setting\n"); | ||||
| 			return -EIO; | ||||
| 		} | ||||
| 	} else if (rtn == -EIO) { /* Arbitration Lost */ | ||||
| 		pch_err(adap, "Lost Arbitration\n"); | ||||
| 		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMAL_BIT); | ||||
| 		pch_clrbit(adap->pch_base_address, PCH_I2CSR, I2CMIF_BIT); | ||||
| 		pch_i2c_init(adap); | ||||
| 		return -EAGAIN; | ||||
| 	} else { /* wait-event timeout */ | ||||
| 		pch_i2c_stop(adap); | ||||
| 		return -ETIME; | ||||
| 	} | ||||
| 
 | ||||
| 		if (length == 0) { | ||||
| 			pch_i2c_stop(adap); | ||||
| 			ioread32(p + PCH_I2CDR); /* Dummy read needs */ | ||||
| 	if (length == 0) { | ||||
| 		pch_i2c_stop(adap); | ||||
| 		ioread32(p + PCH_I2CDR); /* Dummy read needs */ | ||||
| 
 | ||||
| 			count = length; | ||||
| 		} else { | ||||
| 			int read_index; | ||||
| 			int loop; | ||||
| 			pch_i2c_sendack(adap); | ||||
| 
 | ||||
| 			/* Dummy read */ | ||||
| 			for (loop = 1, read_index = 0; loop < length; loop++) { | ||||
| 				buf[read_index] = ioread32(p + PCH_I2CDR); | ||||
| 
 | ||||
| 				if (loop != 1) | ||||
| 					read_index++; | ||||
| 
 | ||||
| 				if (pch_i2c_wait_for_xfer_complete(adap) != 0) { | ||||
| 					pch_i2c_stop(adap); | ||||
| 					return -ETIME; | ||||
| 				} | ||||
| 			}	/* end for */ | ||||
| 
 | ||||
| 			pch_i2c_sendnack(adap); | ||||
| 		count = length; | ||||
| 	} else { | ||||
| 		int read_index; | ||||
| 		int loop; | ||||
| 		pch_i2c_sendack(adap); | ||||
| 
 | ||||
| 		/* Dummy read */ | ||||
| 		for (loop = 1, read_index = 0; loop < length; loop++) { | ||||
| 			buf[read_index] = ioread32(p + PCH_I2CDR); | ||||
| 
 | ||||
| 			if (length != 1) | ||||
| 			if (loop != 1) | ||||
| 				read_index++; | ||||
| 
 | ||||
| 			if (pch_i2c_wait_for_xfer_complete(adap) == 0) { | ||||
| 				if (last) | ||||
| 					pch_i2c_stop(adap); | ||||
| 				else | ||||
| 					pch_i2c_repstart(adap); | ||||
| 
 | ||||
| 				buf[read_index++] = ioread32(p + PCH_I2CDR); | ||||
| 				count = read_index; | ||||
| 			} else { | ||||
| 				count = -ETIME; | ||||
| 			rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 			if (rtn == 0) { | ||||
| 				if (pch_i2c_getack(adap)) { | ||||
| 					pch_dbg(adap, "Receive NACK for slave" | ||||
| 						"address setting\n"); | ||||
| 					return -EIO; | ||||
| 				} | ||||
| 			} else { /* wait-event timeout */ | ||||
| 				pch_i2c_stop(adap); | ||||
| 				return -ETIME; | ||||
| 			} | ||||
| 
 | ||||
| 		}	/* end for */ | ||||
| 
 | ||||
| 		pch_i2c_sendnack(adap); | ||||
| 
 | ||||
| 		buf[read_index] = ioread32(p + PCH_I2CDR); /* Read final - 1 */ | ||||
| 
 | ||||
| 		if (length != 1) | ||||
| 			read_index++; | ||||
| 
 | ||||
| 		rtn = pch_i2c_wait_for_xfer_complete(adap); | ||||
| 		if (rtn == 0) { | ||||
| 			if (pch_i2c_getack(adap)) { | ||||
| 				pch_dbg(adap, "Receive NACK for slave" | ||||
| 					"address setting\n"); | ||||
| 				return -EIO; | ||||
| 			} | ||||
| 		} else { /* wait-event timeout */ | ||||
| 			pch_i2c_stop(adap); | ||||
| 			return -ETIME; | ||||
| 		} | ||||
| 	} else { | ||||
| 		count = -ETIME; | ||||
| 		pch_i2c_stop(adap); | ||||
| 
 | ||||
| 		if (last) | ||||
| 			pch_i2c_stop(adap); | ||||
| 		else | ||||
| 			pch_i2c_repstart(adap); | ||||
| 
 | ||||
| 		buf[read_index++] = ioread32(p + PCH_I2CDR); /* Read Final */ | ||||
| 		count = read_index; | ||||
| 	} | ||||
| 
 | ||||
| 	return count; | ||||
|  | ||||
| @ -387,7 +387,7 @@ static int __devinit highlander_i2c_probe(struct platform_device *pdev) | ||||
| 		dev->irq = 0; | ||||
| 
 | ||||
| 	if (dev->irq) { | ||||
| 		ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED, | ||||
| 		ret = request_irq(dev->irq, highlander_i2c_irq, 0, | ||||
| 				  pdev->name, dev); | ||||
| 		if (unlikely(ret)) | ||||
| 			goto err_unmap; | ||||
|  | ||||
| @ -48,6 +48,9 @@ | ||||
| #include <linux/platform_device.h> | ||||
| #include <linux/clk.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/of_i2c.h> | ||||
| 
 | ||||
| #include <mach/irqs.h> | ||||
| #include <mach/hardware.h> | ||||
| @ -125,6 +128,11 @@ struct imx_i2c_struct { | ||||
| 	unsigned int		ifdr; /* IMX_I2C_IFDR */ | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id i2c_imx_dt_ids[] = { | ||||
| 	{ .compatible = "fsl,imx1-i2c", }, | ||||
| 	{ /* sentinel */ } | ||||
| }; | ||||
| 
 | ||||
| /** Functions for IMX I2C adapter driver ***************************************
 | ||||
| *******************************************************************************/ | ||||
| 
 | ||||
| @ -466,10 +474,10 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct imx_i2c_struct *i2c_imx; | ||||
| 	struct resource *res; | ||||
| 	struct imxi2c_platform_data *pdata; | ||||
| 	struct imxi2c_platform_data *pdata = pdev->dev.platform_data; | ||||
| 	void __iomem *base; | ||||
| 	resource_size_t res_size; | ||||
| 	int irq; | ||||
| 	int irq, bitrate; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	dev_dbg(&pdev->dev, "<%s>\n", __func__); | ||||
| @ -485,19 +493,11 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | ||||
| 		return -ENOENT; | ||||
| 	} | ||||
| 
 | ||||
| 	pdata = pdev->dev.platform_data; | ||||
| 
 | ||||
| 	if (pdata && pdata->init) { | ||||
| 		ret = pdata->init(&pdev->dev); | ||||
| 		if (ret) | ||||
| 			return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	res_size = resource_size(res); | ||||
| 
 | ||||
| 	if (!request_mem_region(res->start, res_size, DRIVER_NAME)) { | ||||
| 		ret = -EBUSY; | ||||
| 		goto fail0; | ||||
| 		dev_err(&pdev->dev, "request_mem_region failed\n"); | ||||
| 		return -EBUSY; | ||||
| 	} | ||||
| 
 | ||||
| 	base = ioremap(res->start, res_size); | ||||
| @ -520,6 +520,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | ||||
| 	i2c_imx->adapter.algo		= &i2c_imx_algo; | ||||
| 	i2c_imx->adapter.dev.parent	= &pdev->dev; | ||||
| 	i2c_imx->adapter.nr 		= pdev->id; | ||||
| 	i2c_imx->adapter.dev.of_node	= pdev->dev.of_node; | ||||
| 	i2c_imx->irq			= irq; | ||||
| 	i2c_imx->base			= base; | ||||
| 	i2c_imx->res			= res; | ||||
| @ -546,10 +547,12 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | ||||
| 	i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); | ||||
| 
 | ||||
| 	/* Set up clock divider */ | ||||
| 	if (pdata && pdata->bitrate) | ||||
| 		i2c_imx_set_clk(i2c_imx, pdata->bitrate); | ||||
| 	else | ||||
| 		i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE); | ||||
| 	bitrate = IMX_I2C_BIT_RATE; | ||||
| 	ret = of_property_read_u32(pdev->dev.of_node, | ||||
| 				   "clock-frequency", &bitrate); | ||||
| 	if (ret < 0 && pdata && pdata->bitrate) | ||||
| 		bitrate = pdata->bitrate; | ||||
| 	i2c_imx_set_clk(i2c_imx, bitrate); | ||||
| 
 | ||||
| 	/* Set up chip registers to defaults */ | ||||
| 	writeb(0, i2c_imx->base + IMX_I2C_I2CR); | ||||
| @ -562,6 +565,8 @@ static int __init i2c_imx_probe(struct platform_device *pdev) | ||||
| 		goto fail5; | ||||
| 	} | ||||
| 
 | ||||
| 	of_i2c_register_devices(&i2c_imx->adapter); | ||||
| 
 | ||||
| 	/* Set up platform driver data */ | ||||
| 	platform_set_drvdata(pdev, i2c_imx); | ||||
| 
 | ||||
| @ -586,16 +591,12 @@ fail2: | ||||
| 	iounmap(base); | ||||
| fail1: | ||||
| 	release_mem_region(res->start, resource_size(res)); | ||||
| fail0: | ||||
| 	if (pdata && pdata->exit) | ||||
| 		pdata->exit(&pdev->dev); | ||||
| 	return ret; /* Return error number */ | ||||
| } | ||||
| 
 | ||||
| static int __exit i2c_imx_remove(struct platform_device *pdev) | ||||
| { | ||||
| 	struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev); | ||||
| 	struct imxi2c_platform_data *pdata = pdev->dev.platform_data; | ||||
| 
 | ||||
| 	/* remove adapter */ | ||||
| 	dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); | ||||
| @ -611,10 +612,6 @@ static int __exit i2c_imx_remove(struct platform_device *pdev) | ||||
| 	writeb(0, i2c_imx->base + IMX_I2C_I2CR); | ||||
| 	writeb(0, i2c_imx->base + IMX_I2C_I2SR); | ||||
| 
 | ||||
| 	/* Shut down hardware */ | ||||
| 	if (pdata && pdata->exit) | ||||
| 		pdata->exit(&pdev->dev); | ||||
| 
 | ||||
| 	clk_put(i2c_imx->clk); | ||||
| 
 | ||||
| 	iounmap(i2c_imx->base); | ||||
| @ -628,6 +625,7 @@ static struct platform_driver i2c_imx_driver = { | ||||
| 	.driver	= { | ||||
| 		.name	= DRIVER_NAME, | ||||
| 		.owner	= THIS_MODULE, | ||||
| 		.of_match_table = i2c_imx_dt_ids, | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -63,11 +63,11 @@ | ||||
| /* Master controller (MCR) register */ | ||||
| #define I2C_MCR_OP		(0x1 << 0)	/* Operation */ | ||||
| #define I2C_MCR_A7		(0x7f << 1)	/* 7-bit address */ | ||||
| #define I2C_MCR_EA10		(0x7 << 8) 	/* 10-bit Extended address */ | ||||
| #define I2C_MCR_EA10		(0x7 << 8)	/* 10-bit Extended address */ | ||||
| #define I2C_MCR_SB		(0x1 << 11)	/* Extended address */ | ||||
| #define I2C_MCR_AM		(0x3 << 12)	/* Address type */ | ||||
| #define I2C_MCR_STOP		(0x1 << 14) 	/* Stop condition */ | ||||
| #define I2C_MCR_LENGTH		(0x7ff << 15) 	/* Transaction length */ | ||||
| #define I2C_MCR_STOP		(0x1 << 14)	/* Stop condition */ | ||||
| #define I2C_MCR_LENGTH		(0x7ff << 15)	/* Transaction length */ | ||||
| 
 | ||||
| /* Status register (SR) */ | ||||
| #define I2C_SR_OP		(0x3 << 0)	/* Operation */ | ||||
| @ -77,7 +77,7 @@ | ||||
| #define I2C_SR_LENGTH		(0x7ff << 9)	/* Transfer length */ | ||||
| 
 | ||||
| /* Interrupt mask set/clear (IMSCR) bits */ | ||||
| #define I2C_IT_TXFE 		(0x1 << 0) | ||||
| #define I2C_IT_TXFE		(0x1 << 0) | ||||
| #define I2C_IT_TXFNE		(0x1 << 1) | ||||
| #define I2C_IT_TXFF		(0x1 << 2) | ||||
| #define I2C_IT_TXFOVR		(0x1 << 3) | ||||
| @ -135,31 +135,31 @@ struct i2c_nmk_client { | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct nmk_i2c_dev - private data structure of the controller | ||||
|  * @pdev: parent platform device | ||||
|  * @adap: corresponding I2C adapter | ||||
|  * @irq: interrupt line for the controller | ||||
|  * @virtbase: virtual io memory area | ||||
|  * @clk: hardware i2c block clock | ||||
|  * @cfg: machine provided controller configuration | ||||
|  * @cli: holder of client specific data | ||||
|  * @stop: stop condition | ||||
|  * @xfer_complete: acknowledge completion for a I2C message | ||||
|  * @result: controller propogated result | ||||
|  * @regulator: pointer to i2c regulator | ||||
|  * @busy: Busy doing transfer | ||||
|  * struct nmk_i2c_dev - private data structure of the controller. | ||||
|  * @pdev: parent platform device. | ||||
|  * @adap: corresponding I2C adapter. | ||||
|  * @irq: interrupt line for the controller. | ||||
|  * @virtbase: virtual io memory area. | ||||
|  * @clk: hardware i2c block clock. | ||||
|  * @cfg: machine provided controller configuration. | ||||
|  * @cli: holder of client specific data. | ||||
|  * @stop: stop condition. | ||||
|  * @xfer_complete: acknowledge completion for a I2C message. | ||||
|  * @result: controller propogated result. | ||||
|  * @regulator: pointer to i2c regulator. | ||||
|  * @busy: Busy doing transfer. | ||||
|  */ | ||||
| struct nmk_i2c_dev { | ||||
| 	struct platform_device		*pdev; | ||||
| 	struct i2c_adapter 		adap; | ||||
| 	int 				irq; | ||||
| 	struct i2c_adapter		adap; | ||||
| 	int				irq; | ||||
| 	void __iomem			*virtbase; | ||||
| 	struct clk			*clk; | ||||
| 	struct nmk_i2c_controller	cfg; | ||||
| 	struct i2c_nmk_client		cli; | ||||
| 	int 				stop; | ||||
| 	int				stop; | ||||
| 	struct completion		xfer_complete; | ||||
| 	int 				result; | ||||
| 	int				result; | ||||
| 	struct regulator		*regulator; | ||||
| 	bool				busy; | ||||
| }; | ||||
| @ -217,8 +217,9 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	dev_err(&dev->pdev->dev, "flushing operation timed out " | ||||
| 		"giving up after %d attempts", LOOP_ATTEMPTS); | ||||
| 	dev_err(&dev->pdev->dev, | ||||
| 		"flushing operation timed out giving up after %d attempts", | ||||
| 		LOOP_ATTEMPTS); | ||||
| 
 | ||||
| 	return -ETIMEDOUT; | ||||
| } | ||||
| @ -270,7 +271,7 @@ exit: | ||||
| } | ||||
| 
 | ||||
| /* enable peripheral, master mode operation */ | ||||
| #define DEFAULT_I2C_REG_CR 	((1 << 1) | I2C_CR_PE) | ||||
| #define DEFAULT_I2C_REG_CR	((1 << 1) | I2C_CR_PE) | ||||
| 
 | ||||
| /**
 | ||||
|  * load_i2c_mcr_reg() - load the MCR register | ||||
| @ -363,8 +364,8 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) | ||||
| 	 * and high speed (up to 3.4 Mb/s) | ||||
| 	 */ | ||||
| 	if (dev->cfg.sm > I2C_FREQ_MODE_FAST) { | ||||
| 		dev_err(&dev->pdev->dev, "do not support this mode " | ||||
| 			"defaulting to std. mode\n"); | ||||
| 		dev_err(&dev->pdev->dev, | ||||
| 			"do not support this mode defaulting to std. mode\n"); | ||||
| 		brcr2 = i2c_clk/(100000 * 2) & 0xffff; | ||||
| 		writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); | ||||
| 		writel(I2C_FREQ_MODE_STANDARD << 4, | ||||
| @ -423,7 +424,7 @@ static int read_i2c(struct nmk_i2c_dev *dev) | ||||
| 
 | ||||
| 	if (timeout < 0) { | ||||
| 		dev_err(&dev->pdev->dev, | ||||
| 			"wait_for_completion_timeout" | ||||
| 			"wait_for_completion_timeout " | ||||
| 			"returned %d waiting for event\n", timeout); | ||||
| 		status = timeout; | ||||
| 	} | ||||
| @ -556,8 +557,8 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) | ||||
| 		if (((i2c_sr >> 2) & 0x3) == 0x3) { | ||||
| 			/* get the abort cause */ | ||||
| 			cause =	(i2c_sr >> 4) & 0x7; | ||||
| 			dev_err(&dev->pdev->dev, "%s\n", cause | ||||
| 				>= ARRAY_SIZE(abort_causes) ? | ||||
| 			dev_err(&dev->pdev->dev, "%s\n", | ||||
| 				cause >= ARRAY_SIZE(abort_causes) ? | ||||
| 				"unknown reason" : | ||||
| 				abort_causes[cause]); | ||||
| 		} | ||||
| @ -582,13 +583,13 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) | ||||
|  * | ||||
|  * NOTE: | ||||
|  * READ TRANSFER : We impose a restriction of the first message to be the | ||||
|  * 		index message for any read transaction. | ||||
|  * 		- a no index is coded as '0', | ||||
|  * 		- 2byte big endian index is coded as '3' | ||||
|  * 		!!! msg[0].buf holds the actual index. | ||||
|  * 		This is compatible with generic messages of smbus emulator | ||||
|  * 		that send a one byte index. | ||||
|  * 		eg. a I2C transation to read 2 bytes from index 0 | ||||
|  *		index message for any read transaction. | ||||
|  *		- a no index is coded as '0', | ||||
|  *		- 2byte big endian index is coded as '3' | ||||
|  *		!!! msg[0].buf holds the actual index. | ||||
|  *		This is compatible with generic messages of smbus emulator | ||||
|  *		that send a one byte index. | ||||
|  *		eg. a I2C transation to read 2 bytes from index 0 | ||||
|  *			idx = 0; | ||||
|  *			msg[0].addr = client->addr; | ||||
|  *			msg[0].flags = 0x0; | ||||
| @ -644,8 +645,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, | ||||
| 
 | ||||
| 		for (i = 0; i < num_msgs; i++) { | ||||
| 			if (unlikely(msgs[i].flags & I2C_M_TEN)) { | ||||
| 				dev_err(&dev->pdev->dev, "10 bit addressing" | ||||
| 						"not supported\n"); | ||||
| 				dev_err(&dev->pdev->dev, | ||||
| 					"10 bit addressing not supported\n"); | ||||
| 
 | ||||
| 				status = -EINVAL; | ||||
| 				goto out; | ||||
| @ -789,8 +790,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) | ||||
| 
 | ||||
| 		if (dev->cli.count) { | ||||
| 			dev->result = -EIO; | ||||
| 			dev_err(&dev->pdev->dev, "%lu bytes still remain to be" | ||||
| 					"xfered\n", dev->cli.count); | ||||
| 			dev_err(&dev->pdev->dev, | ||||
| 				"%lu bytes still remain to be xfered\n", | ||||
| 				dev->cli.count); | ||||
| 			(void) init_hw(dev); | ||||
| 		} | ||||
| 		complete(&dev->xfer_complete); | ||||
| @ -923,7 +925,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	if (request_mem_region(res->start, resource_size(res), | ||||
| 		DRIVER_NAME "I/O region") == 	NULL)	{ | ||||
| 		DRIVER_NAME "I/O region") == NULL) { | ||||
| 		ret = -EBUSY; | ||||
| 		goto err_no_region; | ||||
| 	} | ||||
| @ -935,7 +937,7 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	dev->irq = platform_get_irq(pdev, 0); | ||||
| 	ret = request_irq(dev->irq, i2c_irq_handler, IRQF_DISABLED, | ||||
| 	ret = request_irq(dev->irq, i2c_irq_handler, 0, | ||||
| 				DRIVER_NAME, dev); | ||||
| 	if (ret) { | ||||
| 		dev_err(&pdev->dev, "cannot claim the irq %d\n", dev->irq); | ||||
| @ -980,8 +982,9 @@ static int __devinit nmk_i2c_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	i2c_set_adapdata(adap, dev); | ||||
| 
 | ||||
| 	dev_info(&pdev->dev, "initialize %s on virtual " | ||||
| 		"base %p\n", adap->name, dev->virtbase); | ||||
| 	dev_info(&pdev->dev, | ||||
| 		 "initialize %s on virtual base %p\n", | ||||
| 		 adap->name, dev->virtbase); | ||||
| 
 | ||||
| 	ret = i2c_add_numbered_adapter(adap); | ||||
| 	if (ret) { | ||||
|  | ||||
| @ -610,7 +610,7 @@ static int __devinit nuc900_i2c_probe(struct platform_device *pdev) | ||||
| 		goto err_iomap; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_DISABLED | IRQF_SHARED, | ||||
| 	ret = request_irq(i2c->irq, nuc900_i2c_irq, IRQF_SHARED, | ||||
| 			  dev_name(&pdev->dev), i2c); | ||||
| 
 | ||||
| 	if (ret != 0) { | ||||
|  | ||||
| @ -42,12 +42,12 @@ | ||||
| #include <linux/pm_runtime.h> | ||||
| 
 | ||||
| /* I2C controller revisions */ | ||||
| #define OMAP_I2C_REV_2			0x20 | ||||
| #define OMAP_I2C_OMAP1_REV_2		0x20 | ||||
| 
 | ||||
| /* I2C controller revisions present on specific hardware */ | ||||
| #define OMAP_I2C_REV_ON_2430		0x36 | ||||
| #define OMAP_I2C_REV_ON_3430		0x3C | ||||
| #define OMAP_I2C_REV_ON_4430		0x40 | ||||
| #define OMAP_I2C_REV_ON_3530_4430	0x40 | ||||
| 
 | ||||
| /* timeout waiting for the controller to respond */ | ||||
| #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) | ||||
| @ -72,11 +72,12 @@ enum { | ||||
| 	OMAP_I2C_SCLH_REG, | ||||
| 	OMAP_I2C_SYSTEST_REG, | ||||
| 	OMAP_I2C_BUFSTAT_REG, | ||||
| 	OMAP_I2C_REVNB_LO, | ||||
| 	OMAP_I2C_REVNB_HI, | ||||
| 	OMAP_I2C_IRQSTATUS_RAW, | ||||
| 	OMAP_I2C_IRQENABLE_SET, | ||||
| 	OMAP_I2C_IRQENABLE_CLR, | ||||
| 	/* only on OMAP4430 */ | ||||
| 	OMAP_I2C_IP_V2_REVNB_LO, | ||||
| 	OMAP_I2C_IP_V2_REVNB_HI, | ||||
| 	OMAP_I2C_IP_V2_IRQSTATUS_RAW, | ||||
| 	OMAP_I2C_IP_V2_IRQENABLE_SET, | ||||
| 	OMAP_I2C_IP_V2_IRQENABLE_CLR, | ||||
| }; | ||||
| 
 | ||||
| /* I2C Interrupt Enable Register (OMAP_I2C_IE): */ | ||||
| @ -193,7 +194,6 @@ struct omap_i2c_dev { | ||||
| 						 */ | ||||
| 	u8			rev; | ||||
| 	unsigned		b_hw:1;		/* bad h/w fixes */ | ||||
| 	unsigned		idle:1; | ||||
| 	u16			iestate;	/* Saved interrupt register */ | ||||
| 	u16			pscstate; | ||||
| 	u16			scllstate; | ||||
| @ -204,7 +204,7 @@ struct omap_i2c_dev { | ||||
| 	u16			errata; | ||||
| }; | ||||
| 
 | ||||
| static const u8 reg_map[] = { | ||||
| static const u8 reg_map_ip_v1[] = { | ||||
| 	[OMAP_I2C_REV_REG] = 0x00, | ||||
| 	[OMAP_I2C_IE_REG] = 0x01, | ||||
| 	[OMAP_I2C_STAT_REG] = 0x02, | ||||
| @ -225,7 +225,7 @@ static const u8 reg_map[] = { | ||||
| 	[OMAP_I2C_BUFSTAT_REG] = 0x10, | ||||
| }; | ||||
| 
 | ||||
| static const u8 omap4_reg_map[] = { | ||||
| static const u8 reg_map_ip_v2[] = { | ||||
| 	[OMAP_I2C_REV_REG] = 0x04, | ||||
| 	[OMAP_I2C_IE_REG] = 0x2c, | ||||
| 	[OMAP_I2C_STAT_REG] = 0x28, | ||||
| @ -244,11 +244,11 @@ static const u8 omap4_reg_map[] = { | ||||
| 	[OMAP_I2C_SCLH_REG] = 0xb8, | ||||
| 	[OMAP_I2C_SYSTEST_REG] = 0xbC, | ||||
| 	[OMAP_I2C_BUFSTAT_REG] = 0xc0, | ||||
| 	[OMAP_I2C_REVNB_LO] = 0x00, | ||||
| 	[OMAP_I2C_REVNB_HI] = 0x04, | ||||
| 	[OMAP_I2C_IRQSTATUS_RAW] = 0x24, | ||||
| 	[OMAP_I2C_IRQENABLE_SET] = 0x2c, | ||||
| 	[OMAP_I2C_IRQENABLE_CLR] = 0x30, | ||||
| 	[OMAP_I2C_IP_V2_REVNB_LO] = 0x00, | ||||
| 	[OMAP_I2C_IP_V2_REVNB_HI] = 0x04, | ||||
| 	[OMAP_I2C_IP_V2_IRQSTATUS_RAW] = 0x24, | ||||
| 	[OMAP_I2C_IP_V2_IRQENABLE_SET] = 0x2c, | ||||
| 	[OMAP_I2C_IP_V2_IRQENABLE_CLR] = 0x30, | ||||
| }; | ||||
| 
 | ||||
| static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev, | ||||
| @ -266,17 +266,11 @@ static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg) | ||||
| 
 | ||||
| static void omap_i2c_unidle(struct omap_i2c_dev *dev) | ||||
| { | ||||
| 	struct platform_device *pdev; | ||||
| 	struct omap_i2c_bus_platform_data *pdata; | ||||
| 
 | ||||
| 	WARN_ON(!dev->idle); | ||||
| 	pdata = dev->dev->platform_data; | ||||
| 
 | ||||
| 	pdev = to_platform_device(dev->dev); | ||||
| 	pdata = pdev->dev.platform_data; | ||||
| 
 | ||||
| 	pm_runtime_get_sync(&pdev->dev); | ||||
| 
 | ||||
| 	if (cpu_is_omap34xx()) { | ||||
| 	if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate); | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate); | ||||
| @ -286,7 +280,6 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev) | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); | ||||
| 	} | ||||
| 	dev->idle = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Don't write to this register if the IE state is 0 as it can | ||||
| @ -298,32 +291,25 @@ static void omap_i2c_unidle(struct omap_i2c_dev *dev) | ||||
| 
 | ||||
| static void omap_i2c_idle(struct omap_i2c_dev *dev) | ||||
| { | ||||
| 	struct platform_device *pdev; | ||||
| 	struct omap_i2c_bus_platform_data *pdata; | ||||
| 	u16 iv; | ||||
| 
 | ||||
| 	WARN_ON(dev->idle); | ||||
| 
 | ||||
| 	pdev = to_platform_device(dev->dev); | ||||
| 	pdata = pdev->dev.platform_data; | ||||
| 	pdata = dev->dev->platform_data; | ||||
| 
 | ||||
| 	dev->iestate = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); | ||||
| 	if (dev->rev >= OMAP_I2C_REV_ON_4430) | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_IRQENABLE_CLR, 1); | ||||
| 	if (pdata->rev == OMAP_I2C_IP_VERSION_2) | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, 1); | ||||
| 	else | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, 0); | ||||
| 
 | ||||
| 	if (dev->rev < OMAP_I2C_REV_2) { | ||||
| 	if (dev->rev < OMAP_I2C_OMAP1_REV_2) { | ||||
| 		iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); /* Read clears */ | ||||
| 	} else { | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, dev->iestate); | ||||
| 
 | ||||
| 		/* Flush posted write before the dev->idle store occurs */ | ||||
| 		/* Flush posted write */ | ||||
| 		omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); | ||||
| 	} | ||||
| 	dev->idle = 1; | ||||
| 
 | ||||
| 	pm_runtime_put_sync(&pdev->dev); | ||||
| } | ||||
| 
 | ||||
| static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| @ -334,8 +320,11 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| 	unsigned long timeout; | ||||
| 	unsigned long internal_clk = 0; | ||||
| 	struct clk *fclk; | ||||
| 	struct omap_i2c_bus_platform_data *pdata; | ||||
| 
 | ||||
| 	if (dev->rev >= OMAP_I2C_REV_2) { | ||||
| 	pdata = dev->dev->platform_data; | ||||
| 
 | ||||
| 	if (dev->rev >= OMAP_I2C_OMAP1_REV_2) { | ||||
| 		/* Disable I2C controller before soft reset */ | ||||
| 		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, | ||||
| 			omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) & | ||||
| @ -378,12 +367,13 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| 			 * REVISIT: Some wkup sources might not be needed. | ||||
| 			 */ | ||||
| 			dev->westate = OMAP_I2C_WE_ALL; | ||||
| 			omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate); | ||||
| 			omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, | ||||
| 							dev->westate); | ||||
| 		} | ||||
| 	} | ||||
| 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); | ||||
| 
 | ||||
| 	if (cpu_class_is_omap1()) { | ||||
| 	if (pdata->flags & OMAP_I2C_FLAG_ALWAYS_ARMXOR_CLK) { | ||||
| 		/*
 | ||||
| 		 * The I2C functional clock is the armxor_ck, so there's | ||||
| 		 * no need to get "armxor_ck" separately.  Now, if OMAP2420 | ||||
| @ -407,7 +397,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| 			psc = fclk_rate / 12000000; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!(cpu_class_is_omap1() || cpu_is_omap2420())) { | ||||
| 	if (!(pdata->flags & OMAP_I2C_FLAG_SIMPLE_CLOCK)) { | ||||
| 
 | ||||
| 		/*
 | ||||
| 		 * HSI2C controller internal clk rate should be 19.2 Mhz for | ||||
| @ -415,7 +405,8 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| 		 * to get longer filter period for better noise suppression. | ||||
| 		 * The filter is iclk (fclk for HS) period. | ||||
| 		 */ | ||||
| 		if (dev->speed > 400 || cpu_is_omap2430()) | ||||
| 		if (dev->speed > 400 || | ||||
| 			       pdata->flags & OMAP_I2C_FLAG_FORCE_19200_INT_CLK) | ||||
| 			internal_clk = 19200; | ||||
| 		else if (dev->speed > 100) | ||||
| 			internal_clk = 9600; | ||||
| @ -484,7 +475,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| 
 | ||||
| 	dev->errata = 0; | ||||
| 
 | ||||
| 	if (cpu_is_omap2430() || cpu_is_omap34xx()) | ||||
| 	if (pdata->flags & OMAP_I2C_FLAG_APPLY_ERRATA_I207) | ||||
| 		dev->errata |= I2C_OMAP_ERRATA_I207; | ||||
| 
 | ||||
| 	/* Enable interrupts */ | ||||
| @ -493,7 +484,7 @@ static int omap_i2c_init(struct omap_i2c_dev *dev) | ||||
| 			OMAP_I2C_IE_AL)  | ((dev->fifo_size) ? | ||||
| 				(OMAP_I2C_IE_RDR | OMAP_I2C_IE_XDR) : 0); | ||||
| 	omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate); | ||||
| 	if (cpu_is_omap34xx()) { | ||||
| 	if (pdata->flags & OMAP_I2C_FLAG_RESET_REGS_POSTIDLE) { | ||||
| 		dev->pscstate = psc; | ||||
| 		dev->scllstate = scll; | ||||
| 		dev->sclhstate = sclh; | ||||
| @ -642,7 +633,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||||
| 	int i; | ||||
| 	int r; | ||||
| 
 | ||||
| 	omap_i2c_unidle(dev); | ||||
| 	pm_runtime_get_sync(dev->dev); | ||||
| 
 | ||||
| 	r = omap_i2c_wait_for_bb(dev); | ||||
| 	if (r < 0) | ||||
| @ -665,7 +656,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) | ||||
| 
 | ||||
| 	omap_i2c_wait_for_bb(dev); | ||||
| out: | ||||
| 	omap_i2c_idle(dev); | ||||
| 	pm_runtime_put(dev->dev); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| @ -720,12 +711,12 @@ static inline void i2c_omap_errata_i207(struct omap_i2c_dev *dev, u16 stat) | ||||
| #ifdef CONFIG_ARCH_OMAP15XX | ||||
| 
 | ||||
| static irqreturn_t | ||||
| omap_i2c_rev1_isr(int this_irq, void *dev_id) | ||||
| omap_i2c_omap1_isr(int this_irq, void *dev_id) | ||||
| { | ||||
| 	struct omap_i2c_dev *dev = dev_id; | ||||
| 	u16 iv, w; | ||||
| 
 | ||||
| 	if (dev->idle) | ||||
| 	if (pm_runtime_suspended(dev->dev)) | ||||
| 		return IRQ_NONE; | ||||
| 
 | ||||
| 	iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG); | ||||
| @ -774,7 +765,7 @@ omap_i2c_rev1_isr(int this_irq, void *dev_id) | ||||
| 	return IRQ_HANDLED; | ||||
| } | ||||
| #else | ||||
| #define omap_i2c_rev1_isr		NULL | ||||
| #define omap_i2c_omap1_isr		NULL | ||||
| #endif | ||||
| 
 | ||||
| /*
 | ||||
| @ -813,8 +804,11 @@ omap_i2c_isr(int this_irq, void *dev_id) | ||||
| 	u16 bits; | ||||
| 	u16 stat, w; | ||||
| 	int err, count = 0; | ||||
| 	struct omap_i2c_bus_platform_data *pdata; | ||||
| 
 | ||||
| 	if (dev->idle) | ||||
| 	pdata = dev->dev->platform_data; | ||||
| 
 | ||||
| 	if (pm_runtime_suspended(dev->dev)) | ||||
| 		return IRQ_NONE; | ||||
| 
 | ||||
| 	bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); | ||||
| @ -881,8 +875,8 @@ complete: | ||||
| 					 * Data reg in 2430, omap3 and | ||||
| 					 * omap4 is 8 bit wide | ||||
| 					 */ | ||||
| 					if (cpu_class_is_omap1() || | ||||
| 							cpu_is_omap2420()) { | ||||
| 					if (pdata->flags & | ||||
| 						 OMAP_I2C_FLAG_16BIT_DATA_REG) { | ||||
| 						if (dev->buf_len) { | ||||
| 							*dev->buf++ = w >> 8; | ||||
| 							dev->buf_len--; | ||||
| @ -924,8 +918,8 @@ complete: | ||||
| 					 * Data reg in 2430, omap3 and | ||||
| 					 * omap4 is 8 bit wide | ||||
| 					 */ | ||||
| 					if (cpu_class_is_omap1() || | ||||
| 							cpu_is_omap2420()) { | ||||
| 					if (pdata->flags & | ||||
| 						 OMAP_I2C_FLAG_16BIT_DATA_REG) { | ||||
| 						if (dev->buf_len) { | ||||
| 							w |= *dev->buf++ << 8; | ||||
| 							dev->buf_len--; | ||||
| @ -1016,7 +1010,6 @@ omap_i2c_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	dev->speed = speed; | ||||
| 	dev->idle = 1; | ||||
| 	dev->dev = &pdev->dev; | ||||
| 	dev->irq = irq->start; | ||||
| 	dev->base = ioremap(mem->start, resource_size(mem)); | ||||
| @ -1027,27 +1020,22 @@ omap_i2c_probe(struct platform_device *pdev) | ||||
| 
 | ||||
| 	platform_set_drvdata(pdev, dev); | ||||
| 
 | ||||
| 	if (cpu_is_omap7xx()) | ||||
| 		dev->reg_shift = 1; | ||||
| 	else if (cpu_is_omap44xx()) | ||||
| 		dev->reg_shift = 0; | ||||
| 	else | ||||
| 		dev->reg_shift = 2; | ||||
| 	dev->reg_shift = (pdata->flags >> OMAP_I2C_FLAG_BUS_SHIFT__SHIFT) & 3; | ||||
| 
 | ||||
| 	if (cpu_is_omap44xx()) | ||||
| 		dev->regs = (u8 *) omap4_reg_map; | ||||
| 	if (pdata->rev == OMAP_I2C_IP_VERSION_2) | ||||
| 		dev->regs = (u8 *)reg_map_ip_v2; | ||||
| 	else | ||||
| 		dev->regs = (u8 *) reg_map; | ||||
| 		dev->regs = (u8 *)reg_map_ip_v1; | ||||
| 
 | ||||
| 	pm_runtime_enable(&pdev->dev); | ||||
| 	omap_i2c_unidle(dev); | ||||
| 	pm_runtime_enable(dev->dev); | ||||
| 	pm_runtime_get_sync(dev->dev); | ||||
| 
 | ||||
| 	dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff; | ||||
| 
 | ||||
| 	if (dev->rev <= OMAP_I2C_REV_ON_3430) | ||||
| 		dev->errata |= I2C_OMAP3_1P153; | ||||
| 
 | ||||
| 	if (!(cpu_class_is_omap1() || cpu_is_omap2420())) { | ||||
| 	if (!(pdata->flags & OMAP_I2C_FLAG_NO_FIFO)) { | ||||
| 		u16 s; | ||||
| 
 | ||||
| 		/* Set up the fifo size - Get total size */ | ||||
| @ -1059,7 +1047,7 @@ omap_i2c_probe(struct platform_device *pdev) | ||||
| 		 * size. This is to ensure that we can handle the status on int | ||||
| 		 * call back latencies. | ||||
| 		 */ | ||||
| 		if (dev->rev >= OMAP_I2C_REV_ON_4430) { | ||||
| 		if (dev->rev >= OMAP_I2C_REV_ON_3530_4430) { | ||||
| 			dev->fifo_size = 0; | ||||
| 			dev->b_hw = 0; /* Disable hardware fixes */ | ||||
| 		} else { | ||||
| @ -1075,7 +1063,8 @@ omap_i2c_probe(struct platform_device *pdev) | ||||
| 	/* reset ASAP, clearing any IRQs */ | ||||
| 	omap_i2c_init(dev); | ||||
| 
 | ||||
| 	isr = (dev->rev < OMAP_I2C_REV_2) ? omap_i2c_rev1_isr : omap_i2c_isr; | ||||
| 	isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : | ||||
| 								   omap_i2c_isr; | ||||
| 	r = request_irq(dev->irq, isr, 0, pdev->name, dev); | ||||
| 
 | ||||
| 	if (r) { | ||||
| @ -1083,10 +1072,10 @@ omap_i2c_probe(struct platform_device *pdev) | ||||
| 		goto err_unuse_clocks; | ||||
| 	} | ||||
| 
 | ||||
| 	dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n", | ||||
| 		 pdev->id, dev->rev >> 4, dev->rev & 0xf, dev->speed); | ||||
| 	dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, | ||||
| 		 pdata->rev, dev->rev >> 4, dev->rev & 0xf, dev->speed); | ||||
| 
 | ||||
| 	omap_i2c_idle(dev); | ||||
| 	pm_runtime_put(dev->dev); | ||||
| 
 | ||||
| 	adap = &dev->adapter; | ||||
| 	i2c_set_adapdata(adap, dev); | ||||
| @ -1110,7 +1099,7 @@ err_free_irq: | ||||
| 	free_irq(dev->irq, dev); | ||||
| err_unuse_clocks: | ||||
| 	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0); | ||||
| 	omap_i2c_idle(dev); | ||||
| 	pm_runtime_put(dev->dev); | ||||
| 	iounmap(dev->base); | ||||
| err_free_mem: | ||||
| 	platform_set_drvdata(pdev, NULL); | ||||
| @ -1139,12 +1128,43 @@ omap_i2c_remove(struct platform_device *pdev) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_PM_RUNTIME | ||||
| static int omap_i2c_runtime_suspend(struct device *dev) | ||||
| { | ||||
| 	struct platform_device *pdev = to_platform_device(dev); | ||||
| 	struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); | ||||
| 
 | ||||
| 	omap_i2c_idle(_dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int omap_i2c_runtime_resume(struct device *dev) | ||||
| { | ||||
| 	struct platform_device *pdev = to_platform_device(dev); | ||||
| 	struct omap_i2c_dev *_dev = platform_get_drvdata(pdev); | ||||
| 
 | ||||
| 	omap_i2c_unidle(_dev); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static struct dev_pm_ops omap_i2c_pm_ops = { | ||||
| 	.runtime_suspend = omap_i2c_runtime_suspend, | ||||
| 	.runtime_resume = omap_i2c_runtime_resume, | ||||
| }; | ||||
| #define OMAP_I2C_PM_OPS (&omap_i2c_pm_ops) | ||||
| #else | ||||
| #define OMAP_I2C_PM_OPS NULL | ||||
| #endif | ||||
| 
 | ||||
| static struct platform_driver omap_i2c_driver = { | ||||
| 	.probe		= omap_i2c_probe, | ||||
| 	.remove		= omap_i2c_remove, | ||||
| 	.driver		= { | ||||
| 		.name	= "omap_i2c", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 		.pm	= OMAP_I2C_PM_OPS, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -306,7 +306,7 @@ static int __devinit pmcmsptwi_probe(struct platform_device *pldev) | ||||
| 	pmcmsptwi_data.irq = platform_get_irq(pldev, 0); | ||||
| 	if (pmcmsptwi_data.irq) { | ||||
| 		rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt, | ||||
| 			IRQF_SHARED | IRQF_DISABLED | IRQF_SAMPLE_RANDOM, | ||||
| 			IRQF_SHARED | IRQF_SAMPLE_RANDOM, | ||||
| 			pldev->name, &pmcmsptwi_data); | ||||
| 		if (rc == 0) { | ||||
| 			/*
 | ||||
|  | ||||
| @ -35,6 +35,8 @@ | ||||
| #include <linux/cpufreq.h> | ||||
| #include <linux/slab.h> | ||||
| #include <linux/io.h> | ||||
| #include <linux/of_i2c.h> | ||||
| #include <linux/of_gpio.h> | ||||
| 
 | ||||
| #include <asm/irq.h> | ||||
| 
 | ||||
| @ -78,6 +80,8 @@ struct s3c24xx_i2c { | ||||
| 	struct resource		*ioarea; | ||||
| 	struct i2c_adapter	adap; | ||||
| 
 | ||||
| 	struct s3c2410_platform_i2c	*pdata; | ||||
| 	int			gpios[2]; | ||||
| #ifdef CONFIG_CPU_FREQ | ||||
| 	struct notifier_block	freq_transition; | ||||
| #endif | ||||
| @ -95,6 +99,12 @@ static inline int s3c24xx_i2c_is2440(struct s3c24xx_i2c *i2c) | ||||
| 	struct platform_device *pdev = to_platform_device(i2c->dev); | ||||
| 	enum s3c24xx_i2c_type type; | ||||
| 
 | ||||
| #ifdef CONFIG_OF | ||||
| 	if (i2c->dev->of_node) | ||||
| 		return of_device_is_compatible(i2c->dev->of_node, | ||||
| 				"samsung,s3c2440-i2c"); | ||||
| #endif | ||||
| 
 | ||||
| 	type = platform_get_device_id(pdev)->driver_data; | ||||
| 	return type == TYPE_S3C2440; | ||||
| } | ||||
| @ -625,7 +635,7 @@ static int s3c24xx_i2c_calcdivisor(unsigned long clkin, unsigned int wanted, | ||||
| 
 | ||||
| static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) | ||||
| { | ||||
| 	struct s3c2410_platform_i2c *pdata = i2c->dev->platform_data; | ||||
| 	struct s3c2410_platform_i2c *pdata = i2c->pdata; | ||||
| 	unsigned long clkin = clk_get_rate(i2c->clk); | ||||
| 	unsigned int divs, div1; | ||||
| 	unsigned long target_frequency; | ||||
| @ -741,6 +751,49 @@ static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #ifdef CONFIG_OF | ||||
| static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) | ||||
| { | ||||
| 	int idx, gpio, ret; | ||||
| 
 | ||||
| 	for (idx = 0; idx < 2; idx++) { | ||||
| 		gpio = of_get_gpio(i2c->dev->of_node, idx); | ||||
| 		if (!gpio_is_valid(gpio)) { | ||||
| 			dev_err(i2c->dev, "invalid gpio[%d]: %d\n", idx, gpio); | ||||
| 			goto free_gpio; | ||||
| 		} | ||||
| 
 | ||||
| 		ret = gpio_request(gpio, "i2c-bus"); | ||||
| 		if (ret) { | ||||
| 			dev_err(i2c->dev, "gpio [%d] request failed\n", gpio); | ||||
| 			goto free_gpio; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| 
 | ||||
| free_gpio: | ||||
| 	while (--idx >= 0) | ||||
| 		gpio_free(i2c->gpios[idx]); | ||||
| 	return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) | ||||
| { | ||||
| 	unsigned int idx; | ||||
| 	for (idx = 0; idx < 2; idx++) | ||||
| 		gpio_free(i2c->gpios[idx]); | ||||
| } | ||||
| #else | ||||
| static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) | ||||
| { | ||||
| 	return -EINVAL; | ||||
| } | ||||
| 
 | ||||
| static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c) | ||||
| { | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* s3c24xx_i2c_init
 | ||||
|  * | ||||
|  * initialise the controller, set the IO lines and frequency | ||||
| @ -754,12 +807,15 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | ||||
| 
 | ||||
| 	/* get the plafrom data */ | ||||
| 
 | ||||
| 	pdata = i2c->dev->platform_data; | ||||
| 	pdata = i2c->pdata; | ||||
| 
 | ||||
| 	/* inititalise the gpio */ | ||||
| 
 | ||||
| 	if (pdata->cfg_gpio) | ||||
| 		pdata->cfg_gpio(to_platform_device(i2c->dev)); | ||||
| 	else | ||||
| 		if (s3c24xx_i2c_parse_dt_gpio(i2c)) | ||||
| 			return -EINVAL; | ||||
| 
 | ||||
| 	/* write slave address */ | ||||
| 
 | ||||
| @ -785,6 +841,34 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| #ifdef CONFIG_OF | ||||
| /* s3c24xx_i2c_parse_dt
 | ||||
|  * | ||||
|  * Parse the device tree node and retreive the platform data. | ||||
| */ | ||||
| 
 | ||||
| static void | ||||
| s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) | ||||
| { | ||||
| 	struct s3c2410_platform_i2c *pdata = i2c->pdata; | ||||
| 
 | ||||
| 	if (!np) | ||||
| 		return; | ||||
| 
 | ||||
| 	pdata->bus_num = -1; /* i2c bus number is dynamically assigned */ | ||||
| 	of_property_read_u32(np, "samsung,i2c-sda-delay", &pdata->sda_delay); | ||||
| 	of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr); | ||||
| 	of_property_read_u32(np, "samsung,i2c-max-bus-freq", | ||||
| 				(u32 *)&pdata->frequency); | ||||
| } | ||||
| #else | ||||
| static void | ||||
| s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c) | ||||
| { | ||||
| 	return; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| /* s3c24xx_i2c_probe
 | ||||
|  * | ||||
|  * called by the bus driver when a suitable device is found | ||||
| @ -793,14 +877,16 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c) | ||||
| static int s3c24xx_i2c_probe(struct platform_device *pdev) | ||||
| { | ||||
| 	struct s3c24xx_i2c *i2c; | ||||
| 	struct s3c2410_platform_i2c *pdata; | ||||
| 	struct s3c2410_platform_i2c *pdata = NULL; | ||||
| 	struct resource *res; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	pdata = pdev->dev.platform_data; | ||||
| 	if (!pdata) { | ||||
| 		dev_err(&pdev->dev, "no platform data\n"); | ||||
| 		return -EINVAL; | ||||
| 	if (!pdev->dev.of_node) { | ||||
| 		pdata = pdev->dev.platform_data; | ||||
| 		if (!pdata) { | ||||
| 			dev_err(&pdev->dev, "no platform data\n"); | ||||
| 			return -EINVAL; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	i2c = kzalloc(sizeof(struct s3c24xx_i2c), GFP_KERNEL); | ||||
| @ -809,6 +895,17 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	i2c->pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | ||||
| 	if (!i2c->pdata) { | ||||
| 		ret = -ENOMEM; | ||||
| 		goto err_noclk; | ||||
| 	} | ||||
| 
 | ||||
| 	if (pdata) | ||||
| 		memcpy(i2c->pdata, pdata, sizeof(*pdata)); | ||||
| 	else | ||||
| 		s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c); | ||||
| 
 | ||||
| 	strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); | ||||
| 	i2c->adap.owner   = THIS_MODULE; | ||||
| 	i2c->adap.algo    = &s3c24xx_i2c_algorithm; | ||||
| @ -883,7 +980,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | ||||
| 		goto err_iomap; | ||||
| 	} | ||||
| 
 | ||||
| 	ret = request_irq(i2c->irq, s3c24xx_i2c_irq, IRQF_DISABLED, | ||||
| 	ret = request_irq(i2c->irq, s3c24xx_i2c_irq, 0, | ||||
| 			  dev_name(&pdev->dev), i2c); | ||||
| 
 | ||||
| 	if (ret != 0) { | ||||
| @ -903,7 +1000,8 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | ||||
| 	 * being bus 0. | ||||
| 	 */ | ||||
| 
 | ||||
| 	i2c->adap.nr = pdata->bus_num; | ||||
| 	i2c->adap.nr = i2c->pdata->bus_num; | ||||
| 	i2c->adap.dev.of_node = pdev->dev.of_node; | ||||
| 
 | ||||
| 	ret = i2c_add_numbered_adapter(&i2c->adap); | ||||
| 	if (ret < 0) { | ||||
| @ -911,6 +1009,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) | ||||
| 		goto err_cpufreq; | ||||
| 	} | ||||
| 
 | ||||
| 	of_i2c_register_devices(&i2c->adap); | ||||
| 	platform_set_drvdata(pdev, i2c); | ||||
| 
 | ||||
| 	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); | ||||
| @ -959,6 +1058,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) | ||||
| 	iounmap(i2c->regs); | ||||
| 
 | ||||
| 	release_resource(i2c->ioarea); | ||||
| 	s3c24xx_i2c_dt_gpio_free(i2c); | ||||
| 	kfree(i2c->ioarea); | ||||
| 	kfree(i2c); | ||||
| 
 | ||||
| @ -1012,6 +1112,17 @@ static struct platform_device_id s3c24xx_driver_ids[] = { | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); | ||||
| 
 | ||||
| #ifdef CONFIG_OF | ||||
| static const struct of_device_id s3c24xx_i2c_match[] = { | ||||
| 	{ .compatible = "samsung,s3c2410-i2c" }, | ||||
| 	{ .compatible = "samsung,s3c2440-i2c" }, | ||||
| 	{}, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match); | ||||
| #else | ||||
| #define s3c24xx_i2c_match NULL | ||||
| #endif | ||||
| 
 | ||||
| static struct platform_driver s3c24xx_i2c_driver = { | ||||
| 	.probe		= s3c24xx_i2c_probe, | ||||
| 	.remove		= s3c24xx_i2c_remove, | ||||
| @ -1020,6 +1131,7 @@ static struct platform_driver s3c24xx_i2c_driver = { | ||||
| 		.owner	= THIS_MODULE, | ||||
| 		.name	= "s3c-i2c", | ||||
| 		.pm	= S3C24XX_DEV_PM_OPS, | ||||
| 		.of_match_table = s3c24xx_i2c_match, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
|  | ||||
| @ -502,7 +502,7 @@ static int __devinit sh7760_i2c_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 	OUT32(id, I2CCCR, ret); | ||||
| 
 | ||||
| 	if (request_irq(id->irq, sh7760_i2c_irq, IRQF_DISABLED, | ||||
| 	if (request_irq(id->irq, sh7760_i2c_irq, 0, | ||||
| 			SH7760_I2C_DEVNAME, id)) { | ||||
| 		dev_err(&pdev->dev, "cannot get irq %d\n", id->irq); | ||||
| 		ret = -EBUSY; | ||||
|  | ||||
| @ -543,7 +543,7 @@ static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, int hook) | ||||
| 
 | ||||
| 	while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { | ||||
| 		for (n = res->start; hook && n <= res->end; n++) { | ||||
| 			if (request_irq(n, sh_mobile_i2c_isr, IRQF_DISABLED, | ||||
| 			if (request_irq(n, sh_mobile_i2c_isr, 0, | ||||
| 					dev_name(&dev->dev), dev)) { | ||||
| 				for (n--; n >= res->start; n--) | ||||
| 					free_irq(n, dev); | ||||
|  | ||||
| @ -916,7 +916,7 @@ stu300_probe(struct platform_device *pdev) | ||||
| 	} | ||||
| 
 | ||||
| 	dev->irq = platform_get_irq(pdev, 0); | ||||
| 	if (request_irq(dev->irq, stu300_irh, IRQF_DISABLED, | ||||
| 	if (request_irq(dev->irq, stu300_irh, 0, | ||||
| 			NAME, dev)) { | ||||
| 		ret = -EIO; | ||||
| 		goto err_no_irq; | ||||
|  | ||||
| @ -566,7 +566,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) | ||||
| 	struct clk *clk; | ||||
| 	struct clk *i2c_clk; | ||||
| 	const unsigned int *prop; | ||||
| 	void *base; | ||||
| 	void __iomem *base; | ||||
| 	int irq; | ||||
| 	int ret = 0; | ||||
| 
 | ||||
|  | ||||
| @ -32,10 +32,9 @@ | ||||
| 
 | ||||
| struct omap_i2c_bus_platform_data { | ||||
| 	u32		clkrate; | ||||
| 	u32		rev; | ||||
| 	u32		flags; | ||||
| 	void		(*set_mpu_wkup_lat)(struct device *dev, long set); | ||||
| 	int		(*device_enable) (struct platform_device *pdev); | ||||
| 	int		(*device_shutdown) (struct platform_device *pdev); | ||||
| 	int		(*device_idle) (struct platform_device *pdev); | ||||
| }; | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user