diff options
46 files changed, 2087 insertions, 588 deletions
diff --git a/Documentation/devicetree/bindings/i2c/atmel-i2c.txt b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt new file mode 100644 index 00000000000..b689a0d9441 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/atmel-i2c.txt @@ -0,0 +1,30 @@ +I2C for Atmel platforms + +Required properties : +- compatible : Must be "atmel,at91rm9200-i2c", "atmel,at91sam9261-i2c", +     "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c" +     or "atmel,at91sam9x5-i2c" +- reg: physical base address of the controller and length of memory mapped +     region. +- interrupts: interrupt number to the cpu. +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties: +- Child nodes conforming to i2c bus binding + +Examples : + +i2c0: i2c@fff84000 { +	compatible = "atmel,at91sam9g20-i2c"; +	reg = <0xfff84000 0x100>; +	interrupts = <12 4 6>; +	#address-cells = <1>; +	#size-cells = <0>; + +	24c512@50 { +		compatible = "24c512"; +		reg = <0x50>; +		pagesize = <128>; +	} +} diff --git a/Documentation/devicetree/bindings/i2c/davinci.txt b/Documentation/devicetree/bindings/i2c/davinci.txt new file mode 100644 index 00000000000..2dc935b4113 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/davinci.txt @@ -0,0 +1,28 @@ +* Texas Instruments Davinci I2C + +This file provides information, what the device node for the +davinci i2c interface contain. + +Required properties: +- compatible: "ti,davinci-i2c"; +- reg : Offset and length of the register set for the device + +Recommended properties : +- interrupts : standard interrupt property. +- clock-frequency : desired I2C bus clock frequency in Hz. + +Example (enbw_cmc board): +	i2c@1c22000 { +		compatible = "ti,davinci-i2c"; +		reg = <0x22000 0x1000>; +		clock-frequency = <100000>; +		interrupts = <15>; +		interrupt-parent = <&intc>; +		#address-cells = <1>; +		#size-cells = <0>; + +		dtt@48 { +			compatible = "national,lm75"; +			reg = <0x48>; +		}; +	}; diff --git a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt index 30ac3a0557f..7a3fe9e5f4c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mxs.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mxs.txt @@ -6,6 +6,7 @@ Required properties:  - interrupts: Should contain ERROR and DMA interrupts  - clock-frequency: Desired I2C bus clock frequency in Hz.                     Only 100000Hz and 400000Hz modes are supported. +- fsl,i2c-dma-channel: APBX DMA channel for the I2C  Examples: @@ -16,4 +17,5 @@ i2c0: i2c@80058000 {  	reg = <0x80058000 2000>;  	interrupts = <111 68>;  	clock-frequency = <100000>; +	fsl,i2c-dma-channel = <6>;  }; diff --git a/Documentation/devicetree/bindings/i2c/nomadik.txt b/Documentation/devicetree/bindings/i2c/nomadik.txt new file mode 100644 index 00000000000..72065b0ff68 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nomadik.txt @@ -0,0 +1,23 @@ +I2C for Nomadik based systems + +Required (non-standard) properties: + - Nil + +Recommended (non-standard) properties: + - clock-frequency : Maximum bus clock frequency for the device + +Optional (non-standard) properties: + - Nil + +Example : + +i2c@80004000 { +        compatible = "stericsson,db8500-i2c", "st,nomadik-i2c"; +        reg = <0x80004000 0x1000>; +        interrupts = <0 21 0x4>; +        #address-cells = <1>; +        #size-cells = <0>; +        v-i2c-supply = <&db8500_vape_reg>; + +        clock-frequency = <400000>; +}; diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 7c95f76398d..d410581a5a8 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -28,6 +28,7 @@  		gpio2 = &pioC;  		tcb0 = &tcb0;  		tcb1 = &tcb1; +		i2c0 = &i2c0;  	};  	cpus {  		cpu@0 { @@ -202,6 +203,15 @@  				status = "disabled";  			}; +			i2c0: i2c@fffac000 { +				compatible = "atmel,at91sam9260-i2c"; +				reg = <0xfffac000 0x100>; +				interrupts = <11 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; +  			adc0: adc@fffe0000 {  				compatible = "atmel,at91sam9260-adc";  				reg = <0xfffe0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index 195019b7ca0..3e6e5c1abbf 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -24,6 +24,7 @@  		gpio3 = &pioD;  		gpio4 = &pioE;  		tcb0 = &tcb0; +		i2c0 = &i2c0;  	};  	cpus {  		cpu@0 { @@ -185,6 +186,15 @@  				interrupts = <24 4 2>;  				status = "disabled";  			}; + +			i2c0: i2c@fff88000 { +				compatible = "atmel,at91sam9263-i2c"; +				reg = <0xfff88000 0x100>; +				interrupts = <13 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			};  		};  		nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9g20.dtsi b/arch/arm/boot/dts/at91sam9g20.dtsi index 2a1d1ca8bd8..75ce6e76001 100644 --- a/arch/arm/boot/dts/at91sam9g20.dtsi +++ b/arch/arm/boot/dts/at91sam9g20.dtsi @@ -18,6 +18,10 @@  	ahb {  		apb { +			i2c0: i2c@fffac000 { +				compatible = "atmel,at91sam9g20-i2c"; +			}; +  			adc0: adc@fffe0000 {  				atmel,adc-startup-time = <40>;  			}; diff --git a/arch/arm/boot/dts/at91sam9g25ek.dts b/arch/arm/boot/dts/at91sam9g25ek.dts index 96514c134e5..877c08f0676 100644 --- a/arch/arm/boot/dts/at91sam9g25ek.dts +++ b/arch/arm/boot/dts/at91sam9g25ek.dts @@ -32,6 +32,18 @@  				phy-mode = "rmii";  				status = "okay";  			}; + +			i2c0: i2c@f8010000 { +				status = "okay"; +			}; + +			i2c1: i2c@f8014000 { +				status = "okay"; +			}; + +			i2c2: i2c@f8018000 { +				status = "okay"; +			};  		};  		usb0: ohci@00600000 { diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 63751b1e744..3add030d61f 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -29,6 +29,8 @@  		gpio4 = &pioE;  		tcb0 = &tcb0;  		tcb1 = &tcb1; +		i2c0 = &i2c0; +		i2c1 = &i2c1;  	};  	cpus {  		cpu@0 { @@ -206,6 +208,24 @@  				status = "disabled";  			}; +			i2c0: i2c@fff84000 { +				compatible = "atmel,at91sam9g10-i2c"; +				reg = <0xfff84000 0x100>; +				interrupts = <12 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; + +			i2c1: i2c@fff88000 { +				compatible = "atmel,at91sam9g10-i2c"; +				reg = <0xfff88000 0x100>; +				interrupts = <13 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; +  			adc0: adc@fffb0000 {  				compatible = "atmel,at91sam9260-adc";  				reg = <0xfffb0000 0x100>; diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index a3633bd1311..15e1dd43f62 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -46,6 +46,14 @@  				phy-mode = "rmii";  				status = "okay";  			}; + +			i2c0: i2c@fff84000 { +				status = "okay"; +			}; + +			i2c1: i2c@fff88000 { +				status = "okay"; +			};  		};  		nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index ef9336ae961..82508d68aa7 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -26,6 +26,8 @@  		gpio3 = &pioD;  		tcb0 = &tcb0;  		tcb1 = &tcb1; +		i2c0 = &i2c0; +		i2c1 = &i2c1;  	};  	cpus {  		cpu@0 { @@ -182,6 +184,24 @@  				atmel,use-dma-tx;  				status = "disabled";  			}; + +			i2c0: i2c@f8010000 { +				compatible = "atmel,at91sam9x5-i2c"; +				reg = <0xf8010000 0x100>; +				interrupts = <9 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; + +			i2c1: i2c@f8014000 { +				compatible = "atmel,at91sam9x5-i2c"; +				reg = <0xf8014000 0x100>; +				interrupts = <10 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			};  		};  		nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index f4e43e38f3a..912b2c283d6 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -37,6 +37,14 @@  			dbgu: serial@fffff200 {  				status = "okay";  			}; + +			i2c0: i2c@f8010000 { +				status = "okay"; +			}; + +			i2c1: i2c@f8014000 { +				status = "okay"; +			};  		};  		nand0: nand@40000000 { diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 8a387a8d61b..03fc136421c 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -27,6 +27,9 @@  		gpio3 = &pioD;  		tcb0 = &tcb0;  		tcb1 = &tcb1; +		i2c0 = &i2c0; +		i2c1 = &i2c1; +		i2c2 = &i2c2;  	};  	cpus {  		cpu@0 { @@ -196,6 +199,33 @@  				status = "disabled";  			}; +			i2c0: i2c@f8010000 { +				compatible = "atmel,at91sam9x5-i2c"; +				reg = <0xf8010000 0x100>; +				interrupts = <9 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; + +			i2c1: i2c@f8014000 { +				compatible = "atmel,at91sam9x5-i2c"; +				reg = <0xf8014000 0x100>; +				interrupts = <10 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; + +			i2c2: i2c@f8018000 { +				compatible = "atmel,at91sam9x5-i2c"; +				reg = <0xf8018000 0x100>; +				interrupts = <11 4 6>; +				#address-cells = <1>; +				#size-cells = <0>; +				status = "disabled"; +			}; +  			adc0: adc@f804c000 {  				compatible = "atmel,at91sam9260-adc";  				reg = <0xf804c000 0x100>; diff --git a/arch/arm/boot/dts/imx28.dtsi b/arch/arm/boot/dts/imx28.dtsi index 59fbfba23df..e16d6315548 100644 --- a/arch/arm/boot/dts/imx28.dtsi +++ b/arch/arm/boot/dts/imx28.dtsi @@ -764,6 +764,7 @@  				reg = <0x80058000 0x2000>;  				interrupts = <111 68>;  				clock-frequency = <100000>; +				fsl,i2c-dma-channel = <6>;  				status = "disabled";  			}; @@ -774,6 +775,7 @@  				reg = <0x8005a000 0x2000>;  				interrupts = <110 69>;  				clock-frequency = <100000>; +				fsl,i2c-dma-channel = <7>;  				status = "disabled";  			}; diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index 6f50c672227..b4f0565aff6 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c @@ -187,6 +187,7 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200", &twi_clk),  	/* fake hclk clock */  	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),  	CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index 9ac427a702d..a563189cdfc 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c @@ -511,7 +511,7 @@ static struct resource twi_resources[] = {  };  static struct platform_device at91rm9200_twi_device = { -	.name		= "at91_i2c", +	.name		= "i2c-at91rm9200",  	.id		= -1,  	.resource	= twi_resources,  	.num_resources	= ARRAY_SIZE(twi_resources), diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c index 30c7f26a466..ad29f93f20c 100644 --- a/arch/arm/mach-at91/at91sam9260.c +++ b/arch/arm/mach-at91/at91sam9260.c @@ -211,6 +211,8 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),  	CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20", &twi_clk),  	/* more usart lookup table for DT entries */  	CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),  	CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk), @@ -219,6 +221,7 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),  	CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),  	CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk), +	CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),  	/* more tc lookup table for DT entries */  	CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),  	CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk), diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index af50ff3281c..a76b8684f52 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c @@ -421,7 +421,6 @@ static struct resource twi_resources[] = {  };  static struct platform_device at91sam9260_twi_device = { -	.name		= "at91_i2c",  	.id		= -1,  	.resource	= twi_resources,  	.num_resources	= ARRAY_SIZE(twi_resources), @@ -429,6 +428,13 @@ static struct platform_device at91sam9260_twi_device = {  void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)  { +	/* IP version is not the same on 9260 and g20 */ +	if (cpu_is_at91sam9g20()) { +		at91sam9260_twi_device.name = "i2c-at91sam9g20"; +	} else { +		at91sam9260_twi_device.name = "i2c-at91sam9260"; +	} +  	/* pins used for TWI interface */  	at91_set_A_periph(AT91_PIN_PA23, 0);		/* TWD */  	at91_set_multi_drive(AT91_PIN_PA23, 1); diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c index f40762c5fed..8d999eb1a13 100644 --- a/arch/arm/mach-at91/at91sam9261.c +++ b/arch/arm/mach-at91/at91sam9261.c @@ -178,6 +178,8 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk),  	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261", &twi_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10", &twi_clk),  	CLKDEV_CON_ID("pioA", &pioA_clk),  	CLKDEV_CON_ID("pioB", &pioB_clk),  	CLKDEV_CON_ID("pioC", &pioC_clk), diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 11e9fa835cd..9752f17efba 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c @@ -317,7 +317,6 @@ static struct resource twi_resources[] = {  };  static struct platform_device at91sam9261_twi_device = { -	.name		= "at91_i2c",  	.id		= -1,  	.resource	= twi_resources,  	.num_resources	= ARRAY_SIZE(twi_resources), @@ -325,12 +324,19 @@ static struct platform_device at91sam9261_twi_device = {  void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)  { +	/* IP version is not the same on 9261 and g10 */ +	if (cpu_is_at91sam9g10()) { +		at91sam9261_twi_device.name = "i2c-at91sam9g10"; +		/* I2C PIO must not be configured as open-drain on this chip */ +	} else { +		at91sam9261_twi_device.name = "i2c-at91sam9261"; +		at91_set_multi_drive(AT91_PIN_PA7, 1); +		at91_set_multi_drive(AT91_PIN_PA8, 1); +	} +  	/* pins used for TWI interface */  	at91_set_A_periph(AT91_PIN_PA7, 0);		/* TWD */ -	at91_set_multi_drive(AT91_PIN_PA7, 1); -  	at91_set_A_periph(AT91_PIN_PA8, 0);		/* TWCK */ -	at91_set_multi_drive(AT91_PIN_PA8, 1);  	i2c_register_board_info(0, devices, nr_devices);  	platform_device_register(&at91sam9261_twi_device); diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c index 144ef5de51b..6a01d0360df 100644 --- a/arch/arm/mach-at91/at91sam9263.c +++ b/arch/arm/mach-at91/at91sam9263.c @@ -193,6 +193,7 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),  	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),  	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260", &twi_clk),  	/* fake hclk clock */  	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),  	CLKDEV_CON_ID("pioA", &pioA_clk), @@ -210,6 +211,7 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),  	CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),  	CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk), +	CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),  };  static struct clk_lookup usart_clocks_lookups[] = { diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index 7c0898fe20f..8dde220b42b 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c @@ -599,7 +599,7 @@ static struct resource twi_resources[] = {  };  static struct platform_device at91sam9263_twi_device = { -	.name		= "at91_i2c", +	.name		= "i2c-at91sam9260",  	.id		= -1,  	.resource	= twi_resources,  	.num_resources	= ARRAY_SIZE(twi_resources), diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index ef6cedd52e3..84af1b506d9 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c @@ -237,6 +237,8 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),  	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),  	CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk),  	CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk), @@ -254,6 +256,8 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),  	CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),  	CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk), +	CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk), +	CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),  	/* fake hclk clock */  	CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),  	CLKDEV_CON_ID("pioA", &pioA_clk), diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index e4c3b370920..b1596072dcc 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c @@ -653,7 +653,7 @@ static struct resource twi0_resources[] = {  };  static struct platform_device at91sam9g45_twi0_device = { -	.name		= "at91_i2c", +	.name		= "i2c-at91sam9g10",  	.id		= 0,  	.resource	= twi0_resources,  	.num_resources	= ARRAY_SIZE(twi0_resources), @@ -673,7 +673,7 @@ static struct resource twi1_resources[] = {  };  static struct platform_device at91sam9g45_twi1_device = { -	.name		= "at91_i2c", +	.name		= "i2c-at91sam9g10",  	.id		= 1,  	.resource	= twi1_resources,  	.num_resources	= ARRAY_SIZE(twi1_resources), @@ -686,18 +686,12 @@ void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, in  	/* pins used for TWI interface */  	if (i2c_id == 0) {  		at91_set_A_periph(AT91_PIN_PA20, 0);		/* TWD */ -		at91_set_multi_drive(AT91_PIN_PA20, 1); -  		at91_set_A_periph(AT91_PIN_PA21, 0);		/* TWCK */ -		at91_set_multi_drive(AT91_PIN_PA21, 1);  		platform_device_register(&at91sam9g45_twi0_device);  	} else {  		at91_set_A_periph(AT91_PIN_PB10, 0);		/* TWD */ -		at91_set_multi_drive(AT91_PIN_PB10, 1); -  		at91_set_A_periph(AT91_PIN_PB11, 0);		/* TWCK */ -		at91_set_multi_drive(AT91_PIN_PB11, 1);  		platform_device_register(&at91sam9g45_twi1_device);  	} diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c index 08494664ab7..732d3d3f4ec 100644 --- a/arch/arm/mach-at91/at91sam9n12.c +++ b/arch/arm/mach-at91/at91sam9n12.c @@ -169,6 +169,8 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),  	CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),  	CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk), +	CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk), +	CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),  	CLKDEV_CON_ID("pioA", &pioAB_clk),  	CLKDEV_CON_ID("pioB", &pioAB_clk),  	CLKDEV_CON_ID("pioC", &pioCD_clk), diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 72ce50a50de..72e90841222 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c @@ -186,6 +186,8 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk),  	CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk), +	CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),  	CLKDEV_CON_ID("pioA", &pioA_clk),  	CLKDEV_CON_ID("pioB", &pioB_clk),  	CLKDEV_CON_ID("pioC", &pioC_clk), diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index deafea0e493..d6ca0543ce8 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c @@ -346,7 +346,7 @@ static struct resource twi_resources[] = {  };  static struct platform_device at91sam9rl_twi_device = { -	.name		= "at91_i2c", +	.name		= "i2c-at91sam9g20",  	.id		= -1,  	.resource	= twi_resources,  	.num_resources	= ARRAY_SIZE(twi_resources), diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c index 477cf9d0667..e5035380dcb 100644 --- a/arch/arm/mach-at91/at91sam9x5.c +++ b/arch/arm/mach-at91/at91sam9x5.c @@ -231,6 +231,9 @@ static struct clk_lookup periph_clocks_lookups[] = {  	CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),  	CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),  	CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk), +	CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk), +	CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk), +	CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),  	CLKDEV_CON_ID("pioA", &pioAB_clk),  	CLKDEV_CON_ID("pioB", &pioAB_clk),  	CLKDEV_CON_ID("pioC", &pioCD_clk), diff --git a/arch/arm/mach-at91/include/mach/at91_twi.h b/arch/arm/mach-at91/include/mach/at91_twi.h deleted file mode 100644 index bb2880f6ba3..00000000000 --- a/arch/arm/mach-at91/include/mach/at91_twi.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * arch/arm/mach-at91/include/mach/at91_twi.h - * - * Copyright (C) 2005 Ivan Kokshaysky - * Copyright (C) SAN People - * - * Two-wire Interface (TWI) registers. - * Based on AT91RM9200 datasheet revision E. - * - * 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. - */ - -#ifndef AT91_TWI_H -#define AT91_TWI_H - -#define	AT91_TWI_CR		0x00		/* Control Register */ -#define		AT91_TWI_START		(1 <<  0)	/* Send a Start Condition */ -#define		AT91_TWI_STOP		(1 <<  1)	/* Send a Stop Condition */ -#define		AT91_TWI_MSEN		(1 <<  2)	/* Master Transfer Enable */ -#define		AT91_TWI_MSDIS		(1 <<  3)	/* Master Transfer Disable */ -#define		AT91_TWI_SVEN		(1 <<  4)	/* Slave Transfer Enable [SAM9260 only] */ -#define		AT91_TWI_SVDIS		(1 <<  5)	/* Slave Transfer Disable [SAM9260 only] */ -#define		AT91_TWI_SWRST		(1 <<  7)	/* Software Reset */ - -#define	AT91_TWI_MMR		0x04		/* Master Mode Register */ -#define		AT91_TWI_IADRSZ		(3    <<  8)	/* Internal Device Address Size */ -#define			AT91_TWI_IADRSZ_NO		(0 << 8) -#define			AT91_TWI_IADRSZ_1		(1 << 8) -#define			AT91_TWI_IADRSZ_2		(2 << 8) -#define			AT91_TWI_IADRSZ_3		(3 << 8) -#define		AT91_TWI_MREAD		(1    << 12)	/* Master Read Direction */ -#define		AT91_TWI_DADR		(0x7f << 16)	/* Device Address */ - -#define	AT91_TWI_SMR		0x08		/* Slave Mode Register [SAM9260 only] */ -#define		AT91_TWI_SADR		(0x7f << 16)	/* Slave Address */ - -#define	AT91_TWI_IADR		0x0c		/* Internal Address Register */ - -#define	AT91_TWI_CWGR		0x10		/* Clock Waveform Generator Register */ -#define		AT91_TWI_CLDIV		(0xff <<  0)	/* Clock Low Divisor */ -#define		AT91_TWI_CHDIV		(0xff <<  8)	/* Clock High Divisor */ -#define		AT91_TWI_CKDIV		(7    << 16)	/* Clock Divider */ - -#define	AT91_TWI_SR		0x20		/* Status Register */ -#define		AT91_TWI_TXCOMP		(1 <<  0)	/* Transmission Complete */ -#define		AT91_TWI_RXRDY		(1 <<  1)	/* Receive Holding Register Ready */ -#define		AT91_TWI_TXRDY		(1 <<  2)	/* Transmit Holding Register Ready */ -#define		AT91_TWI_SVREAD		(1 <<  3)	/* Slave Read [SAM9260 only] */ -#define		AT91_TWI_SVACC		(1 <<  4)	/* Slave Access [SAM9260 only] */ -#define		AT91_TWI_GACC		(1 <<  5)	/* General Call Access [SAM9260 only] */ -#define		AT91_TWI_OVRE		(1 <<  6)	/* Overrun Error [AT91RM9200 only] */ -#define		AT91_TWI_UNRE		(1 <<  7)	/* Underrun Error [AT91RM9200 only] */ -#define		AT91_TWI_NACK		(1 <<  8)	/* Not Acknowledged */ -#define		AT91_TWI_ARBLST		(1 <<  9)	/* Arbitration Lost [SAM9260 only] */ -#define		AT91_TWI_SCLWS		(1 << 10)	/* Clock Wait State [SAM9260 only] */ -#define		AT91_TWI_EOSACC		(1 << 11)	/* End of Slave Address [SAM9260 only] */ - -#define	AT91_TWI_IER		0x24		/* Interrupt Enable Register */ -#define	AT91_TWI_IDR		0x28		/* Interrupt Disable Register */ -#define	AT91_TWI_IMR		0x2c		/* Interrupt Mask Register */ -#define	AT91_TWI_RHR		0x30		/* Receive Holding Register */ -#define	AT91_TWI_THR		0x34		/* Transmit Holding Register */ - -#endif - diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c index 6013831a043..a5683a84c6e 100644 --- a/arch/arm/plat-omap/i2c.c +++ b/arch/arm/plat-omap/i2c.c @@ -26,14 +26,12 @@  #include <linux/kernel.h>  #include <linux/platform_device.h>  #include <linux/i2c.h> -#include <linux/i2c-omap.h>  #include <linux/slab.h>  #include <linux/err.h>  #include <linux/clk.h>  #include <mach/irqs.h>  #include <plat/i2c.h> -#include <plat/omap-pm.h>  #include <plat/omap_device.h>  #define OMAP_I2C_SIZE		0x3f @@ -129,16 +127,6 @@ static inline int omap1_i2c_add_bus(int bus_id)  #ifdef CONFIG_ARCH_OMAP2PLUS -/* - * XXX This function is a temporary compatibility wrapper - only - * needed until the I2C driver can be converted to call - * omap_pm_set_max_dev_wakeup_lat() and handle a return code. - */ -static void omap_pm_set_max_mpu_wakeup_lat_compat(struct device *dev, long t) -{ -	omap_pm_set_max_mpu_wakeup_lat(dev, t); -} -  static inline int omap2_i2c_add_bus(int bus_id)  {  	int l; @@ -170,15 +158,6 @@ static inline int omap2_i2c_add_bus(int bus_id)  	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 -	 * ensure quick enough wakeup from idle, when transfer -	 * completes. -	 * Only omap3 has support for constraints -	 */ -	if (cpu_is_omap34xx()) -		pdata->set_mpu_wkup_lat = omap_pm_set_max_mpu_wakeup_lat_compat;  	pdev = omap_device_build(name, bus_id, oh, pdata,  			sizeof(struct omap_i2c_bus_platform_data),  			NULL, 0, 0); diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 6f5f98d69af..f892a424009 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -46,14 +46,19 @@ static int i2c_debug;  #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val)  #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON)  #define pca_wait(adap) adap->wait_for_completion(adap->data) -#define pca_reset(adap) adap->reset_chip(adap->data) -static void pca9665_reset(void *pd) +static void pca_reset(struct i2c_algo_pca_data *adap)  { -	struct i2c_algo_pca_data *adap = pd; -	pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); -	pca_outw(adap, I2C_PCA_IND, 0xA5); -	pca_outw(adap, I2C_PCA_IND, 0x5A); +	if (adap->chip == I2C_PCA_CHIP_9665) { +		/* Ignore the reset function from the module, +		 * we can use the parallel bus reset. +		 */ +		pca_outw(adap, I2C_PCA_INDPTR, I2C_PCA_IPRESET); +		pca_outw(adap, I2C_PCA_IND, 0xA5); +		pca_outw(adap, I2C_PCA_IND, 0x5A); +	} else { +		adap->reset_chip(adap->data); +	}  }  /* @@ -378,11 +383,12 @@ static unsigned int pca_probe_chip(struct i2c_adapter *adap)  	pca_outw(pca_data, I2C_PCA_INDPTR, I2C_PCA_IADR);  	if (pca_inw(pca_data, I2C_PCA_IND) == 0xAA) {  		printk(KERN_INFO "%s: PCA9665 detected.\n", adap->name); -		return I2C_PCA_CHIP_9665; +		pca_data->chip = I2C_PCA_CHIP_9665;  	} else {  		printk(KERN_INFO "%s: PCA9564 detected.\n", adap->name); -		return I2C_PCA_CHIP_9564; +		pca_data->chip = I2C_PCA_CHIP_9564;  	} +	return pca_data->chip;  }  static int pca_init(struct i2c_adapter *adap) @@ -456,11 +462,6 @@ static int pca_init(struct i2c_adapter *adap)  		 */  		int raise_fall_time; -		/* Ignore the reset function from the module, -		 * we can use the parallel bus reset -		 */ -		pca_data->reset_chip = pca9665_reset; -  		if (pca_data->i2c_clock > 1265800) {  			printk(KERN_WARNING "%s: I2C clock speed too high."  				" Using 1265.8kHz.\n", adap->name); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index ff01c389e2d..65dd599a026 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -294,18 +294,21 @@ comment "I2C system bus drivers (mostly embedded / system-on-chip)"  config I2C_AT91  	tristate "Atmel AT91 I2C Two-Wire interface (TWI)" -	depends on ARCH_AT91 && EXPERIMENTAL && BROKEN +	depends on ARCH_AT91 && EXPERIMENTAL  	help  	  This supports the use of the I2C interface on Atmel AT91  	  processors. -	  This driver is BROKEN because the controller which it uses -	  will easily trigger RX overrun and TX underrun errors.  Using -	  low I2C clock rates may partially work around those issues -	  on some systems.  Another serious problem is that there is no -	  documented way to issue repeated START conditions, as needed +	  A serious problem is that there is no documented way to issue +	  repeated START conditions for more than two messages, as needed  	  to support combined I2C messages.  Use the i2c-gpio driver -	  unless your system can cope with those limitations. +	  unless your system can cope with this limitation. + +	  Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices +	  don't have clock stretching in transmission mode. For that reason, +	  you can encounter underrun issues causing premature stop sendings if +	  the latency to fill the transmission register is too long. If you +	  are facing this situation, use the i2c-gpio driver.  config I2C_AU1550  	tristate "Au1550/Au1200/Au1300 SMBus interface" @@ -718,6 +721,16 @@ config I2C_XLR  	  This driver can also be built as a module.  If so, the module  	  will be called i2c-xlr. +config I2C_RCAR +	tristate "Renesas R-Car I2C Controller" +	depends on ARCH_SHMOBILE && I2C +	help +	  If you say yes to this option, support will be included for the +	  R-Car I2C controller. + +	  This driver can also be built as a module.  If so, the module +	  will be called i2c-rcar. +  comment "External I2C/SMBus adapter drivers"  config I2C_DIOLAN_U2C diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37c4182cc98..2d33d62952c 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_I2C_VERSATILE)	+= i2c-versatile.o  obj-$(CONFIG_I2C_OCTEON)	+= i2c-octeon.o  obj-$(CONFIG_I2C_XILINX)	+= i2c-xiic.o  obj-$(CONFIG_I2C_XLR)		+= i2c-xlr.o +obj-$(CONFIG_I2C_RCAR)		+= i2c-rcar.o  # External I2C/SMBus adapter drivers  obj-$(CONFIG_I2C_DIOLAN_U2C)	+= i2c-diolan-u2c.o diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index e24484beef0..aa59a254be2 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -1,315 +1,554 @@  /* -    i2c Support for Atmel's AT91 Two-Wire Interface (TWI) - -    Copyright (C) 2004 Rick Bronson -    Converted to 2.6 by Andrew Victor <andrew@sanpeople.com> - -    Borrowed heavily from original work by: -    Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> - -    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. -*/ + *  i2c Support for Atmel's AT91 Two-Wire Interface (TWI) + * + *  Copyright (C) 2011 Weinmann Medical GmbH + *  Author: Nikolaus Voss <n.voss@weinmann.de> + * + *  Evolved from original work by: + *  Copyright (C) 2004 Rick Bronson + *  Converted to 2.6 by Andrew Victor <andrew@sanpeople.com> + * + *  Borrowed heavily from original work by: + *  Copyright (C) 2000 Philip Edelbrock <phil@stimpy.netroedge.com> + * + *  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. + */ -#include <linux/module.h> -#include <linux/kernel.h> +#include <linux/clk.h> +#include <linux/completion.h>  #include <linux/err.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/delay.h>  #include <linux/i2c.h> -#include <linux/init.h> -#include <linux/clk.h> -#include <linux/platform_device.h> +#include <linux/interrupt.h>  #include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_i2c.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#define TWI_CLK_HZ		100000			/* max 400 Kbits/s */ +#define AT91_I2C_TIMEOUT	msecs_to_jiffies(100)	/* transfer timeout */ + +/* AT91 TWI register definitions */ +#define	AT91_TWI_CR		0x0000	/* Control Register */ +#define	AT91_TWI_START		0x0001	/* Send a Start Condition */ +#define	AT91_TWI_STOP		0x0002	/* Send a Stop Condition */ +#define	AT91_TWI_MSEN		0x0004	/* Master Transfer Enable */ +#define	AT91_TWI_SVDIS		0x0020	/* Slave Transfer Disable */ +#define	AT91_TWI_SWRST		0x0080	/* Software Reset */ + +#define	AT91_TWI_MMR		0x0004	/* Master Mode Register */ +#define	AT91_TWI_IADRSZ_1	0x0100	/* Internal Device Address Size */ +#define	AT91_TWI_MREAD		0x1000	/* Master Read Direction */ -#include <mach/at91_twi.h> -#include <mach/board.h> -#include <mach/cpu.h> +#define	AT91_TWI_IADR		0x000c	/* Internal Address Register */ -#define TWI_CLOCK		100000		/* Hz. max 400 Kbits/sec */ +#define	AT91_TWI_CWGR		0x0010	/* Clock Waveform Generator Reg */ +#define	AT91_TWI_SR		0x0020	/* Status Register */ +#define	AT91_TWI_TXCOMP		0x0001	/* Transmission Complete */ +#define	AT91_TWI_RXRDY		0x0002	/* Receive Holding Register Ready */ +#define	AT91_TWI_TXRDY		0x0004	/* Transmit Holding Register Ready */ + +#define	AT91_TWI_OVRE		0x0040	/* Overrun Error */ +#define	AT91_TWI_UNRE		0x0080	/* Underrun Error */ +#define	AT91_TWI_NACK		0x0100	/* Not Acknowledged */ + +#define	AT91_TWI_IER		0x0024	/* Interrupt Enable Register */ +#define	AT91_TWI_IDR		0x0028	/* Interrupt Disable Register */ +#define	AT91_TWI_IMR		0x002c	/* Interrupt Mask Register */ +#define	AT91_TWI_RHR		0x0030	/* Receive Holding Register */ +#define	AT91_TWI_THR		0x0034	/* Transmit Holding Register */ + +struct at91_twi_pdata { +	unsigned	clk_max_div; +	unsigned	clk_offset; +	bool		has_unre_flag; +}; -static struct clk *twi_clk; -static void __iomem *twi_base; +struct at91_twi_dev { +	struct device		*dev; +	void __iomem		*base; +	struct completion	cmd_complete; +	struct clk		*clk; +	u8			*buf; +	size_t			buf_len; +	struct i2c_msg		*msg; +	int			irq; +	unsigned		transfer_status; +	struct i2c_adapter	adapter; +	unsigned		twi_cwgr_reg; +	struct at91_twi_pdata	*pdata; +}; + +static unsigned at91_twi_read(struct at91_twi_dev *dev, unsigned reg) +{ +	return readl_relaxed(dev->base + reg); +} + +static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val) +{ +	writel_relaxed(val, dev->base + reg); +} -#define at91_twi_read(reg)		__raw_readl(twi_base + (reg)) -#define at91_twi_write(reg, val)	__raw_writel((val), twi_base + (reg)) +static void at91_disable_twi_interrupts(struct at91_twi_dev *dev) +{ +	at91_twi_write(dev, AT91_TWI_IDR, +		       AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY); +} +static void at91_init_twi_bus(struct at91_twi_dev *dev) +{ +	at91_disable_twi_interrupts(dev); +	at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SWRST); +	at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_MSEN); +	at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_SVDIS); +	at91_twi_write(dev, AT91_TWI_CWGR, dev->twi_cwgr_reg); +}  /* - * Initialize the TWI hardware registers. + * Calculate symmetric clock as stated in datasheet: + * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset))   */ -static void __devinit at91_twi_hwinit(void) +static void __devinit at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk)  { -	unsigned long cdiv, ckdiv; +	int ckdiv, cdiv, div; +	struct at91_twi_pdata *pdata = dev->pdata; +	int offset = pdata->clk_offset; +	int max_ckdiv = pdata->clk_max_div; -	at91_twi_write(AT91_TWI_IDR, 0xffffffff);	/* Disable all interrupts */ -	at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST);	/* Reset peripheral */ -	at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);	/* Set Master mode */ +	div = max(0, (int)DIV_ROUND_UP(clk_get_rate(dev->clk), +				       2 * twi_clk) - offset); +	ckdiv = fls(div >> 8); +	cdiv = div >> ckdiv; -	/* Calcuate clock dividers */ -	cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3; -	cdiv = cdiv + 1;	/* round up */ -	ckdiv = 0; -	while (cdiv > 255) { -		ckdiv++; -		cdiv = cdiv >> 1; +	if (ckdiv > max_ckdiv) { +		dev_warn(dev->dev, "%d exceeds ckdiv max value which is %d.\n", +			 ckdiv, max_ckdiv); +		ckdiv = max_ckdiv; +		cdiv = 255;  	} -	if (cpu_is_at91rm9200()) {			/* AT91RM9200 Errata #22 */ -		if (ckdiv > 5) { -			printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n"); -			ckdiv = 5; -		} -	} +	dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv; +	dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); +} -	at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv); +static void at91_twi_write_next_byte(struct at91_twi_dev *dev) +{ +	if (dev->buf_len <= 0) +		return; + +	at91_twi_write(dev, AT91_TWI_THR, *dev->buf); + +	/* send stop when last byte has been written */ +	if (--dev->buf_len == 0) +		at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + +	dev_dbg(dev->dev, "wrote 0x%x, to go %d\n", *dev->buf, dev->buf_len); + +	++dev->buf;  } -/* - * Poll the i2c status register until the specified bit is set. - * Returns 0 if timed out (100 msec). - */ -static short at91_poll_status(unsigned long bit) +static void at91_twi_read_next_byte(struct at91_twi_dev *dev)  { -	int loop_cntr = 10000; +	if (dev->buf_len <= 0) +		return; + +	*dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; +	--dev->buf_len; -	do { -		udelay(10); -	} while (!(at91_twi_read(AT91_TWI_SR) & bit) && (--loop_cntr > 0)); +	/* handle I2C_SMBUS_BLOCK_DATA */ +	if (unlikely(dev->msg->flags & I2C_M_RECV_LEN)) { +		dev->msg->flags &= ~I2C_M_RECV_LEN; +		dev->buf_len += *dev->buf; +		dev->msg->len = dev->buf_len + 1; +		dev_dbg(dev->dev, "received block length %d\n", dev->buf_len); +	} + +	/* send stop if second but last byte has been read */ +	if (dev->buf_len == 1) +		at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); -	return (loop_cntr > 0); +	dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); + +	++dev->buf;  } -static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) +static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)  { -	/* Send Start */ -	at91_twi_write(AT91_TWI_CR, AT91_TWI_START); +	struct at91_twi_dev *dev = dev_id; +	const unsigned status = at91_twi_read(dev, AT91_TWI_SR); +	const unsigned irqstatus = status & at91_twi_read(dev, AT91_TWI_IMR); -	/* Read data */ -	while (length--) { -		if (!length)	/* need to send Stop before reading last byte */ -			at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); -		if (!at91_poll_status(AT91_TWI_RXRDY)) { -			dev_dbg(&adap->dev, "RXRDY timeout\n"); -			return -ETIMEDOUT; -		} -		*buf++ = (at91_twi_read(AT91_TWI_RHR) & 0xff); +	if (!irqstatus) +		return IRQ_NONE; +	else if (irqstatus & AT91_TWI_RXRDY) +		at91_twi_read_next_byte(dev); +	else if (irqstatus & AT91_TWI_TXRDY) +		at91_twi_write_next_byte(dev); + +	/* catch error flags */ +	dev->transfer_status |= status; + +	if (irqstatus & AT91_TWI_TXCOMP) { +		at91_disable_twi_interrupts(dev); +		complete(&dev->cmd_complete);  	} -	return 0; +	return IRQ_HANDLED;  } -static int xfer_write(struct i2c_adapter *adap, unsigned char *buf, int length) +static int at91_do_twi_transfer(struct at91_twi_dev *dev)  { -	/* Load first byte into transmitter */ -	at91_twi_write(AT91_TWI_THR, *buf++); +	int ret; +	bool has_unre_flag = dev->pdata->has_unre_flag; -	/* Send Start */ -	at91_twi_write(AT91_TWI_CR, AT91_TWI_START); +	dev_dbg(dev->dev, "transfer: %s %d bytes.\n", +		(dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); -	do { -		if (!at91_poll_status(AT91_TWI_TXRDY)) { -			dev_dbg(&adap->dev, "TXRDY timeout\n"); -			return -ETIMEDOUT; -		} +	INIT_COMPLETION(dev->cmd_complete); +	dev->transfer_status = 0; +	if (dev->msg->flags & I2C_M_RD) { +		unsigned start_flags = AT91_TWI_START; -		length--;	/* byte was transmitted */ +		if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { +			dev_err(dev->dev, "RXRDY still set!"); +			at91_twi_read(dev, AT91_TWI_RHR); +		} -		if (length > 0)		/* more data to send? */ -			at91_twi_write(AT91_TWI_THR, *buf++); -	} while (length); +		/* if only one byte is to be read, immediately stop transfer */ +		if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) +			start_flags |= AT91_TWI_STOP; +		at91_twi_write(dev, AT91_TWI_CR, start_flags); +		at91_twi_write(dev, AT91_TWI_IER, +			       AT91_TWI_TXCOMP | AT91_TWI_RXRDY); +	} else { +		at91_twi_write_next_byte(dev); +		at91_twi_write(dev, AT91_TWI_IER, +			       AT91_TWI_TXCOMP | AT91_TWI_TXRDY); +	} -	/* Send Stop */ -	at91_twi_write(AT91_TWI_CR, AT91_TWI_STOP); +	ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, +							dev->adapter.timeout); +	if (ret == 0) { +		dev_err(dev->dev, "controller timed out\n"); +		at91_init_twi_bus(dev); +		return -ETIMEDOUT; +	} +	if (dev->transfer_status & AT91_TWI_NACK) { +		dev_dbg(dev->dev, "received nack\n"); +		return -EREMOTEIO; +	} +	if (dev->transfer_status & AT91_TWI_OVRE) { +		dev_err(dev->dev, "overrun while reading\n"); +		return -EIO; +	} +	if (has_unre_flag && dev->transfer_status & AT91_TWI_UNRE) { +		dev_err(dev->dev, "underrun while writing\n"); +		return -EIO; +	} +	dev_dbg(dev->dev, "transfer complete\n");  	return 0;  } -/* - * Generic i2c master transfer entrypoint. - * - * Note: We do not use Atmel's feature of storing the "internal device address". - * Instead the "internal device address" has to be written using a separate - * i2c message. - * http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-September/024411.html - */ -static int at91_xfer(struct i2c_adapter *adap, struct i2c_msg *pmsg, int num) +static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)  { -	int i, ret; +	struct at91_twi_dev *dev = i2c_get_adapdata(adap); +	int ret; +	unsigned int_addr_flag = 0; +	struct i2c_msg *m_start = msg;  	dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); -	for (i = 0; i < num; i++) { -		dev_dbg(&adap->dev, " #%d: %sing %d byte%s %s 0x%02x\n", i, -			pmsg->flags & I2C_M_RD ? "read" : "writ", -			pmsg->len, pmsg->len > 1 ? "s" : "", -			pmsg->flags & I2C_M_RD ? "from" : "to",	pmsg->addr); +	/* +	 * The hardware can handle at most two messages concatenated by a +	 * repeated start via it's internal address feature. +	 */ +	if (num > 2) { +		dev_err(dev->dev, +			"cannot handle more than two concatenated messages.\n"); +		return 0; +	} else if (num == 2) { +		int internal_address = 0; +		int i; -		at91_twi_write(AT91_TWI_MMR, (pmsg->addr << 16) -			| ((pmsg->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); - -		if (pmsg->len && pmsg->buf) {	/* sanity check */ -			if (pmsg->flags & I2C_M_RD) -				ret = xfer_read(adap, pmsg->buf, pmsg->len); -			else -				ret = xfer_write(adap, pmsg->buf, pmsg->len); +		if (msg->flags & I2C_M_RD) { +			dev_err(dev->dev, "first transfer must be write.\n"); +			return -EINVAL; +		} +		if (msg->len > 3) { +			dev_err(dev->dev, "first message size must be <= 3.\n"); +			return -EINVAL; +		} -			if (ret) -				return ret; +		/* 1st msg is put into the internal address, start with 2nd */ +		m_start = &msg[1]; +		for (i = 0; i < msg->len; ++i) { +			const unsigned addr = msg->buf[msg->len - 1 - i]; -			/* Wait until transfer is finished */ -			if (!at91_poll_status(AT91_TWI_TXCOMP)) { -				dev_dbg(&adap->dev, "TXCOMP timeout\n"); -				return -ETIMEDOUT; -			} +			internal_address |= addr << (8 * i); +			int_addr_flag += AT91_TWI_IADRSZ_1;  		} -		dev_dbg(&adap->dev, "transfer complete\n"); -		pmsg++;		/* next message */ +		at91_twi_write(dev, AT91_TWI_IADR, internal_address);  	} -	return i; + +	at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag +		       | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + +	dev->buf_len = m_start->len; +	dev->buf = m_start->buf; +	dev->msg = m_start; + +	ret = at91_do_twi_transfer(dev); + +	return (ret < 0) ? ret : num;  } -/* - * Return list of supported functionality. - */ -static u32 at91_func(struct i2c_adapter *adapter) +static u32 at91_twi_func(struct i2c_adapter *adapter)  { -	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL +		| I2C_FUNC_SMBUS_READ_BLOCK_DATA;  } -static struct i2c_algorithm at91_algorithm = { -	.master_xfer	= at91_xfer, -	.functionality	= at91_func, +static struct i2c_algorithm at91_twi_algorithm = { +	.master_xfer	= at91_twi_xfer, +	.functionality	= at91_twi_func,  }; -/* - * Main initialization routine. - */ -static int __devinit at91_i2c_probe(struct platform_device *pdev) +static struct at91_twi_pdata at91rm9200_config = { +	.clk_max_div = 5, +	.clk_offset = 3, +	.has_unre_flag = true, +}; + +static struct at91_twi_pdata at91sam9261_config = { +	.clk_max_div = 5, +	.clk_offset = 4, +	.has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9260_config = { +	.clk_max_div = 7, +	.clk_offset = 4, +	.has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9g20_config = { +	.clk_max_div = 7, +	.clk_offset = 4, +	.has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9g10_config = { +	.clk_max_div = 7, +	.clk_offset = 4, +	.has_unre_flag = false, +}; + +static struct at91_twi_pdata at91sam9x5_config = { +	.clk_max_div = 7, +	.clk_offset = 4, +	.has_unre_flag = false, +}; + +static const struct platform_device_id at91_twi_devtypes[] = { +	{ +		.name = "i2c-at91rm9200", +		.driver_data = (unsigned long) &at91rm9200_config, +	}, { +		.name = "i2c-at91sam9261", +		.driver_data = (unsigned long) &at91sam9261_config, +	}, { +		.name = "i2c-at91sam9260", +		.driver_data = (unsigned long) &at91sam9260_config, +	}, { +		.name = "i2c-at91sam9g20", +		.driver_data = (unsigned long) &at91sam9g20_config, +	}, { +		.name = "i2c-at91sam9g10", +		.driver_data = (unsigned long) &at91sam9g10_config, +	}, { +		/* sentinel */ +	} +}; + +#if defined(CONFIG_OF) +static const struct of_device_id atmel_twi_dt_ids[] = { +	{ +		.compatible = "atmel,at91sam9260-i2c", +		.data = &at91sam9260_config, +	} , { +		.compatible = "atmel,at91sam9g20-i2c", +		.data = &at91sam9g20_config, +	} , { +		.compatible = "atmel,at91sam9g10-i2c", +		.data = &at91sam9g10_config, +	}, { +		.compatible = "atmel,at91sam9x5-i2c", +		.data = &at91sam9x5_config, +	}, { +		/* sentinel */ +	} +}; +MODULE_DEVICE_TABLE(of, atmel_twi_dt_ids); +#else +#define atmel_twi_dt_ids NULL +#endif + +static struct at91_twi_pdata * __devinit at91_twi_get_driver_data( +					struct platform_device *pdev) +{ +	if (pdev->dev.of_node) { +		const struct of_device_id *match; +		match = of_match_node(atmel_twi_dt_ids, pdev->dev.of_node); +		if (!match) +			return NULL; +		return match->data; +	} +	return (struct at91_twi_pdata *) platform_get_device_id(pdev)->driver_data; +} + +static int __devinit at91_twi_probe(struct platform_device *pdev)  { -	struct i2c_adapter *adapter; -	struct resource *res; +	struct at91_twi_dev *dev; +	struct resource *mem;  	int rc; -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENXIO; +	dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); +	if (!dev) +		return -ENOMEM; +	init_completion(&dev->cmd_complete); +	dev->dev = &pdev->dev; + +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!mem) +		return -ENODEV; -	if (!request_mem_region(res->start, resource_size(res), "at91_i2c")) +	dev->pdata = at91_twi_get_driver_data(pdev); +	if (!dev->pdata) +		return -ENODEV; + +	dev->base = devm_request_and_ioremap(&pdev->dev, mem); +	if (!dev->base)  		return -EBUSY; -	twi_base = ioremap(res->start, resource_size(res)); -	if (!twi_base) { -		rc = -ENOMEM; -		goto fail0; -	} +	dev->irq = platform_get_irq(pdev, 0); +	if (dev->irq < 0) +		return dev->irq; -	twi_clk = clk_get(NULL, "twi_clk"); -	if (IS_ERR(twi_clk)) { -		dev_err(&pdev->dev, "no clock defined\n"); -		rc = -ENODEV; -		goto fail1; +	rc = devm_request_irq(&pdev->dev, dev->irq, atmel_twi_interrupt, 0, +			 dev_name(dev->dev), dev); +	if (rc) { +		dev_err(dev->dev, "Cannot get irq %d: %d\n", dev->irq, rc); +		return rc;  	} -	adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); -	if (adapter == NULL) { -		dev_err(&pdev->dev, "can't allocate inteface!\n"); -		rc = -ENOMEM; -		goto fail2; +	platform_set_drvdata(pdev, dev); + +	dev->clk = devm_clk_get(dev->dev, NULL); +	if (IS_ERR(dev->clk)) { +		dev_err(dev->dev, "no clock defined\n"); +		return -ENODEV;  	} -	snprintf(adapter->name, sizeof(adapter->name), "AT91"); -	adapter->algo = &at91_algorithm; -	adapter->class = I2C_CLASS_HWMON; -	adapter->dev.parent = &pdev->dev; -	/* adapter->id == 0 ... only one TWI controller for now */ +	clk_prepare_enable(dev->clk); -	platform_set_drvdata(pdev, adapter); +	at91_calc_twi_clock(dev, TWI_CLK_HZ); +	at91_init_twi_bus(dev); -	clk_enable(twi_clk);		/* enable peripheral clock */ -	at91_twi_hwinit();		/* initialize TWI controller */ +	snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); +	i2c_set_adapdata(&dev->adapter, dev); +	dev->adapter.owner = THIS_MODULE; +	dev->adapter.class = I2C_CLASS_HWMON; +	dev->adapter.algo = &at91_twi_algorithm; +	dev->adapter.dev.parent = dev->dev; +	dev->adapter.nr = pdev->id; +	dev->adapter.timeout = AT91_I2C_TIMEOUT; +	dev->adapter.dev.of_node = pdev->dev.of_node; -	rc = i2c_add_numbered_adapter(adapter); +	rc = i2c_add_numbered_adapter(&dev->adapter);  	if (rc) { -		dev_err(&pdev->dev, "Adapter %s registration failed\n", -				adapter->name); -		goto fail3; +		dev_err(dev->dev, "Adapter %s registration failed\n", +			dev->adapter.name); +		clk_disable_unprepare(dev->clk); +		return rc;  	} -	dev_info(&pdev->dev, "AT91 i2c bus driver.\n"); -	return 0; - -fail3: -	platform_set_drvdata(pdev, NULL); -	kfree(adapter); -	clk_disable(twi_clk); -fail2: -	clk_put(twi_clk); -fail1: -	iounmap(twi_base); -fail0: -	release_mem_region(res->start, resource_size(res)); +	of_i2c_register_devices(&dev->adapter); -	return rc; +	dev_info(dev->dev, "AT91 i2c bus driver.\n"); +	return 0;  } -static int __devexit at91_i2c_remove(struct platform_device *pdev) +static int __devexit at91_twi_remove(struct platform_device *pdev)  { -	struct i2c_adapter *adapter = platform_get_drvdata(pdev); -	struct resource *res; +	struct at91_twi_dev *dev = platform_get_drvdata(pdev);  	int rc; -	rc = i2c_del_adapter(adapter); -	platform_set_drvdata(pdev, NULL); - -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	iounmap(twi_base); -	release_mem_region(res->start, resource_size(res)); - -	clk_disable(twi_clk);		/* disable peripheral clock */ -	clk_put(twi_clk); +	rc = i2c_del_adapter(&dev->adapter); +	clk_disable_unprepare(dev->clk);  	return rc;  }  #ifdef CONFIG_PM -/* NOTE: could save a few mA by keeping clock off outside of at91_xfer... */ - -static int at91_i2c_suspend(struct device *dev) +static int at91_twi_runtime_suspend(struct device *dev)  { -	clk_disable(twi_clk); +	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); + +	clk_disable(twi_dev->clk); +  	return 0;  } -static int at91_i2c_resume(struct device *dev) +static int at91_twi_runtime_resume(struct device *dev)  { -	return clk_enable(twi_clk); +	struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); + +	return clk_enable(twi_dev->clk);  } -static SIMPLE_DEV_PM_OPS(at91_i2c_pm, at91_i2c_suspend, at91_i2c_resume); -#define AT91_I2C_PM	(&at91_i2c_pm) +static const struct dev_pm_ops at91_twi_pm = { +	.runtime_suspend	= at91_twi_runtime_suspend, +	.runtime_resume		= at91_twi_runtime_resume, +}; +#define at91_twi_pm_ops (&at91_twi_pm)  #else -#define AT91_I2C_PM	NULL +#define at91_twi_pm_ops NULL  #endif -static struct platform_driver at91_i2c_driver = { -	.probe		= at91_i2c_probe, -	.remove		= __devexit_p(at91_i2c_remove), +static struct platform_driver at91_twi_driver = { +	.probe		= at91_twi_probe, +	.remove		= __devexit_p(at91_twi_remove), +	.id_table	= at91_twi_devtypes,  	.driver		= {  		.name	= "at91_i2c",  		.owner	= THIS_MODULE, -		.pm	= AT91_I2C_PM, +		.of_match_table = atmel_twi_dt_ids, +		.pm	= at91_twi_pm_ops,  	},  }; -module_platform_driver(at91_i2c_driver); +static int __init at91_twi_init(void) +{ +	return platform_driver_register(&at91_twi_driver); +} + +static void __exit at91_twi_exit(void) +{ +	platform_driver_unregister(&at91_twi_driver); +} + +subsys_initcall(at91_twi_init); +module_exit(at91_twi_exit); -MODULE_AUTHOR("Rick Bronson"); +MODULE_AUTHOR("Nikolaus Voss <n.voss@weinmann.de>");  MODULE_DESCRIPTION("I2C (TWI) driver for Atmel AT91");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:at91_i2c"); diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index 79a2542d8c4..6a0a5531944 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -38,6 +38,8 @@  #include <linux/slab.h>  #include <linux/cpufreq.h>  #include <linux/gpio.h> +#include <linux/of_i2c.h> +#include <linux/of_device.h>  #include <mach/hardware.h>  #include <linux/platform_data/i2c-davinci.h> @@ -114,6 +116,7 @@ struct davinci_i2c_dev {  	struct completion	xfr_complete;  	struct notifier_block	freq_transition;  #endif +	struct davinci_i2c_platform_data *pdata;  };  /* default platform data to use if not supplied in the platform_device */ @@ -155,7 +158,7 @@ static void generic_i2c_clock_pulse(unsigned int scl_pin)  static void i2c_recover_bus(struct davinci_i2c_dev *dev)  {  	u32 flag = 0; -	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; +	struct davinci_i2c_platform_data *pdata = dev->pdata;  	dev_err(dev->dev, "initiating i2c bus recovery\n");  	/* Send NACK to the slave */ @@ -163,8 +166,7 @@ static void i2c_recover_bus(struct davinci_i2c_dev *dev)  	flag |=  DAVINCI_I2C_MDR_NACK;  	/* write the data into mode register */  	davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag); -	if (pdata) -		generic_i2c_clock_pulse(pdata->scl_pin); +	generic_i2c_clock_pulse(pdata->scl_pin);  	/* Send STOP */  	flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);  	flag |= DAVINCI_I2C_MDR_STP; @@ -187,7 +189,7 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,  static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)  { -	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; +	struct davinci_i2c_platform_data *pdata = dev->pdata;  	u16 psc;  	u32 clk;  	u32 d; @@ -235,10 +237,7 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev)   */  static int i2c_davinci_init(struct davinci_i2c_dev *dev)  { -	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; - -	if (!pdata) -		pdata = &davinci_i2c_platform_data_default; +	struct davinci_i2c_platform_data *pdata = dev->pdata;  	/* put I2C into reset */  	davinci_i2c_reset_ctrl(dev, 0); @@ -260,6 +259,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)  	dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n",  		pdata->bus_freq, pdata->bus_delay); +  	/* Take the I2C module out of reset: */  	davinci_i2c_reset_ctrl(dev, 1); @@ -308,13 +308,11 @@ static int  i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)  {  	struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); -	struct davinci_i2c_platform_data *pdata = dev->dev->platform_data; +	struct davinci_i2c_platform_data *pdata = dev->pdata;  	u32 flag;  	u16 w;  	int r; -	if (!pdata) -		pdata = &davinci_i2c_platform_data_default;  	/* Introduce a delay, required for some boards (e.g Davinci EVM) */  	if (pdata->bus_delay)  		udelay(pdata->bus_delay); @@ -635,6 +633,12 @@ static struct i2c_algorithm i2c_davinci_algo = {  	.functionality	= i2c_davinci_func,  }; +static const struct of_device_id davinci_i2c_of_match[] = { +	{.compatible = "ti,davinci-i2c", }, +	{}, +}; +MODULE_DEVICE_TABLE(of, davinci_i2c_of_match); +  static int davinci_i2c_probe(struct platform_device *pdev)  {  	struct davinci_i2c_dev *dev; @@ -674,14 +678,33 @@ static int davinci_i2c_probe(struct platform_device *pdev)  #endif  	dev->dev = get_device(&pdev->dev);  	dev->irq = irq->start; +	dev->pdata = dev->dev->platform_data;  	platform_set_drvdata(pdev, dev); +	if (!dev->pdata && pdev->dev.of_node) { +		u32 prop; + +		dev->pdata = devm_kzalloc(&pdev->dev, +			sizeof(struct davinci_i2c_platform_data), GFP_KERNEL); +		if (!dev->pdata) { +			r = -ENOMEM; +			goto err_free_mem; +		} +		memcpy(dev->pdata, &davinci_i2c_platform_data_default, +			sizeof(struct davinci_i2c_platform_data)); +		if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", +			&prop)) +			dev->pdata->bus_freq = prop / 1000; +	} else if (!dev->pdata) { +		dev->pdata = &davinci_i2c_platform_data_default; +	} +  	dev->clk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(dev->clk)) {  		r = -ENODEV;  		goto err_free_mem;  	} -	clk_enable(dev->clk); +	clk_prepare_enable(dev->clk);  	dev->base = ioremap(mem->start, resource_size(mem));  	if (!dev->base) { @@ -711,6 +734,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)  	adap->algo = &i2c_davinci_algo;  	adap->dev.parent = &pdev->dev;  	adap->timeout = DAVINCI_I2C_TIMEOUT; +	adap->dev.of_node = pdev->dev.of_node;  	adap->nr = pdev->id;  	r = i2c_add_numbered_adapter(adap); @@ -718,6 +742,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "failure adding adapter\n");  		goto err_free_irq;  	} +	of_i2c_register_devices(adap);  	return 0; @@ -726,7 +751,7 @@ err_free_irq:  err_unuse_clocks:  	iounmap(dev->base);  err_mem_ioremap: -	clk_disable(dev->clk); +	clk_disable_unprepare(dev->clk);  	clk_put(dev->clk);  	dev->clk = NULL;  err_free_mem: @@ -750,7 +775,7 @@ static int davinci_i2c_remove(struct platform_device *pdev)  	i2c_del_adapter(&dev->adapter);  	put_device(&pdev->dev); -	clk_disable(dev->clk); +	clk_disable_unprepare(dev->clk);  	clk_put(dev->clk);  	dev->clk = NULL; @@ -772,7 +797,7 @@ static int davinci_i2c_suspend(struct device *dev)  	/* put I2C into reset */  	davinci_i2c_reset_ctrl(i2c_dev, 0); -	clk_disable(i2c_dev->clk); +	clk_disable_unprepare(i2c_dev->clk);  	return 0;  } @@ -782,7 +807,7 @@ static int davinci_i2c_resume(struct device *dev)  	struct platform_device *pdev = to_platform_device(dev);  	struct davinci_i2c_dev *i2c_dev = platform_get_drvdata(pdev); -	clk_enable(i2c_dev->clk); +	clk_prepare_enable(i2c_dev->clk);  	/* take I2C out of reset */  	davinci_i2c_reset_ctrl(i2c_dev, 1); @@ -809,6 +834,7 @@ static struct platform_driver davinci_i2c_driver = {  		.name	= "i2c_davinci",  		.owner	= THIS_MODULE,  		.pm	= davinci_i2c_pm_ops, +		.of_match_table = of_match_ptr(davinci_i2c_of_match),  	},  }; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index b7907ba7448..2ef162d148c 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -272,9 +272,9 @@ static void __init i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx,  	/* dev_dbg() can't be used, because adapter is not yet registered */  #ifdef CONFIG_I2C_DEBUG_BUS -	printk(KERN_DEBUG "I2C: <%s> I2C_CLK=%d, REQ DIV=%d\n", +	dev_dbg(&i2c_imx->adapter.dev, "<%s> I2C_CLK=%d, REQ DIV=%d\n",  		__func__, i2c_clk_rate, div); -	printk(KERN_DEBUG "I2C: <%s> IFDR[IC]=0x%x, REAL DIV=%d\n", +	dev_dbg(&i2c_imx->adapter.dev, "<%s> IFDR[IC]=0x%x, REAL DIV=%d\n",  		__func__, i2c_clk_div[i][1], i2c_clk_div[i][0]);  #endif  } @@ -564,7 +564,7 @@ static int __init i2c_imx_probe(struct platform_device *pdev)  		resource_size(res), res->start);  	dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n",  		i2c_imx->adapter.name); -	dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); +	dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");  	return 0;   /* Return OK */  } diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 57f7703ce2e..ca86430cb4a 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -576,7 +576,23 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)  			    mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);  		}  	} -	mpc_i2c_stop(i2c); +	mpc_i2c_stop(i2c); /* Initiate STOP */ +	orig_jiffies = jiffies; +	/* Wait until STOP is seen, allow up to 1 s */ +	while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) { +		if (time_after(jiffies, orig_jiffies + HZ)) { +			u8 status = readb(i2c->base + MPC_I2C_SR); + +			dev_dbg(i2c->dev, "timeout\n"); +			if ((status & (CSR_MCF | CSR_MBB | CSR_RXAK)) != 0) { +				writeb(status & ~CSR_MAL, +				       i2c->base + MPC_I2C_SR); +				mpc_i2c_fixup(i2c); +			} +			return -EIO; +		} +		cond_resched(); +	}  	return (ret < 0) ? ret : num;  } diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 51f05b8520e..1f58197062c 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -7,8 +7,6 @@   *   * Copyright (C) 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.   * - * TODO: add dma-support if platform-support for it is available - *   * 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 @@ -31,9 +29,16 @@  #include <linux/of.h>  #include <linux/of_device.h>  #include <linux/of_i2c.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> +#include <linux/fsl/mxs-dma.h>  #define DRIVER_NAME "mxs-i2c" +static bool use_pioqueue; +module_param(use_pioqueue, bool, 0); +MODULE_PARM_DESC(use_pioqueue, "Use PIOQUEUE mode for transfer instead of DMA"); +  #define MXS_I2C_CTRL0		(0x00)  #define MXS_I2C_CTRL0_SET	(0x04) @@ -146,6 +151,16 @@ struct mxs_i2c_dev {  	u32 cmd_err;  	struct i2c_adapter adapter;  	const struct mxs_i2c_speed_config *speed; + +	/* DMA support components */ +	bool				dma_mode; +	int				dma_channel; +	struct dma_chan         	*dmach; +	struct mxs_dma_data		dma_data; +	uint32_t			pio_data[2]; +	uint32_t			addr_data; +	struct scatterlist		sg_io[2]; +	bool				dma_read;  };  static void mxs_i2c_reset(struct mxs_i2c_dev *i2c) @@ -157,7 +172,11 @@ static void mxs_i2c_reset(struct mxs_i2c_dev *i2c)  	writel(i2c->speed->timing2, i2c->regs + MXS_I2C_TIMING2);  	writel(MXS_I2C_IRQ_MASK << 8, i2c->regs + MXS_I2C_CTRL1_SET); -	writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, +	if (i2c->dma_mode) +		writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE, +			i2c->regs + MXS_I2C_QUEUECTRL_CLR); +	else +		writel(MXS_I2C_QUEUECTRL_PIO_QUEUE_MODE,  			i2c->regs + MXS_I2C_QUEUECTRL_SET);  } @@ -248,6 +267,150 @@ static int mxs_i2c_finish_read(struct mxs_i2c_dev *i2c, u8 *buf, int len)  	return 0;  } +static void mxs_i2c_dma_finish(struct mxs_i2c_dev *i2c) +{ +	if (i2c->dma_read) { +		dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); +		dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); +	} else { +		dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); +	} +} + +static void mxs_i2c_dma_irq_callback(void *param) +{ +	struct mxs_i2c_dev *i2c = param; + +	complete(&i2c->cmd_complete); +	mxs_i2c_dma_finish(i2c); +} + +static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, +			struct i2c_msg *msg, uint32_t flags) +{ +	struct dma_async_tx_descriptor *desc; +	struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); + +	if (msg->flags & I2C_M_RD) { +		i2c->dma_read = 1; +		i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_READ; + +		/* +		 * SELECT command. +		 */ + +		/* Queue the PIO register write transfer. */ +		i2c->pio_data[0] = MXS_CMD_I2C_SELECT; +		desc = dmaengine_prep_slave_sg(i2c->dmach, +					(struct scatterlist *)&i2c->pio_data[0], +					1, DMA_TRANS_NONE, 0); +		if (!desc) { +			dev_err(i2c->dev, +				"Failed to get PIO reg. write descriptor.\n"); +			goto select_init_pio_fail; +		} + +		/* Queue the DMA data transfer. */ +		sg_init_one(&i2c->sg_io[0], &i2c->addr_data, 1); +		dma_map_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); +		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[0], 1, +					DMA_MEM_TO_DEV, +					DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { +			dev_err(i2c->dev, +				"Failed to get DMA data write descriptor.\n"); +			goto select_init_dma_fail; +		} + +		/* +		 * READ command. +		 */ + +		/* Queue the PIO register write transfer. */ +		i2c->pio_data[1] = flags | MXS_CMD_I2C_READ | +				MXS_I2C_CTRL0_XFER_COUNT(msg->len); +		desc = dmaengine_prep_slave_sg(i2c->dmach, +					(struct scatterlist *)&i2c->pio_data[1], +					1, DMA_TRANS_NONE, DMA_PREP_INTERRUPT); +		if (!desc) { +			dev_err(i2c->dev, +				"Failed to get PIO reg. write descriptor.\n"); +			goto select_init_dma_fail; +		} + +		/* Queue the DMA data transfer. */ +		sg_init_one(&i2c->sg_io[1], msg->buf, msg->len); +		dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); +		desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1, +					DMA_DEV_TO_MEM, +					DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { +			dev_err(i2c->dev, +				"Failed to get DMA data write descriptor.\n"); +			goto read_init_dma_fail; +		} +	} else { +		i2c->dma_read = 0; +		i2c->addr_data = (msg->addr << 1) | I2C_SMBUS_WRITE; + +		/* +		 * WRITE command. +		 */ + +		/* Queue the PIO register write transfer. */ +		i2c->pio_data[0] = flags | MXS_CMD_I2C_WRITE | +				MXS_I2C_CTRL0_XFER_COUNT(msg->len + 1); +		desc = dmaengine_prep_slave_sg(i2c->dmach, +					(struct scatterlist *)&i2c->pio_data[0], +					1, DMA_TRANS_NONE, 0); +		if (!desc) { +			dev_err(i2c->dev, +				"Failed to get PIO reg. write descriptor.\n"); +			goto write_init_pio_fail; +		} + +		/* Queue the DMA data transfer. */ +		sg_init_table(i2c->sg_io, 2); +		sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1); +		sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len); +		dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); +		desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2, +					DMA_MEM_TO_DEV, +					DMA_PREP_INTERRUPT | DMA_CTRL_ACK); +		if (!desc) { +			dev_err(i2c->dev, +				"Failed to get DMA data write descriptor.\n"); +			goto write_init_dma_fail; +		} +	} + +	/* +	 * The last descriptor must have this callback, +	 * to finish the DMA transaction. +	 */ +	desc->callback = mxs_i2c_dma_irq_callback; +	desc->callback_param = i2c; + +	/* Start the transfer. */ +	dmaengine_submit(desc); +	dma_async_issue_pending(i2c->dmach); +	return 0; + +/* Read failpath. */ +read_init_dma_fail: +	dma_unmap_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); +select_init_dma_fail: +	dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); +select_init_pio_fail: +	return -EINVAL; + +/* Write failpath. */ +write_init_dma_fail: +	dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); +write_init_pio_fail: +	return -EINVAL; +} +  /*   * Low level master read/write transaction.   */ @@ -258,6 +421,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,  	int ret;  	int flags; +	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; +  	dev_dbg(i2c->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",  		msg->addr, msg->len, msg->flags, stop); @@ -267,23 +432,29 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,  	init_completion(&i2c->cmd_complete);  	i2c->cmd_err = 0; -	flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0; - -	if (msg->flags & I2C_M_RD) -		mxs_i2c_pioq_setup_read(i2c, msg->addr, msg->len, flags); -	else -		mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, msg->len, -					flags); +	if (i2c->dma_mode) { +		ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); +		if (ret) +			return ret; +	} else { +		if (msg->flags & I2C_M_RD) { +			mxs_i2c_pioq_setup_read(i2c, msg->addr, +						msg->len, flags); +		} else { +			mxs_i2c_pioq_setup_write(i2c, msg->addr, msg->buf, +						msg->len, flags); +		} -	writel(MXS_I2C_QUEUECTRL_QUEUE_RUN, +		writel(MXS_I2C_QUEUECTRL_QUEUE_RUN,  			i2c->regs + MXS_I2C_QUEUECTRL_SET); +	}  	ret = wait_for_completion_timeout(&i2c->cmd_complete,  						msecs_to_jiffies(1000));  	if (ret == 0)  		goto timeout; -	if ((!i2c->cmd_err) && (msg->flags & I2C_M_RD)) { +	if (!i2c->dma_mode && !i2c->cmd_err && (msg->flags & I2C_M_RD)) {  		ret = mxs_i2c_finish_read(i2c, msg->buf, msg->len);  		if (ret)  			goto timeout; @@ -301,6 +472,8 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,  timeout:  	dev_dbg(i2c->dev, "Timeout!\n"); +	if (i2c->dma_mode) +		mxs_i2c_dma_finish(i2c);  	mxs_i2c_reset(i2c);  	return -ETIMEDOUT;  } @@ -342,11 +515,13 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id)  		/* MXS_I2C_CTRL1_OVERSIZE_XFER_TERM_IRQ is only for slaves */  		i2c->cmd_err = -EIO; -	is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & -		MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; +	if (!i2c->dma_mode) { +		is_last_cmd = (readl(i2c->regs + MXS_I2C_QUEUESTAT) & +			MXS_I2C_QUEUESTAT_WRITE_QUEUE_CNT_MASK) == 0; -	if (is_last_cmd || i2c->cmd_err) -		complete(&i2c->cmd_complete); +		if (is_last_cmd || i2c->cmd_err) +			complete(&i2c->cmd_complete); +	}  	writel(stat, i2c->regs + MXS_I2C_CTRL1_CLR); @@ -358,6 +533,21 @@ static const struct i2c_algorithm mxs_i2c_algo = {  	.functionality = mxs_i2c_func,  }; +static bool mxs_i2c_dma_filter(struct dma_chan *chan, void *param) +{ +	struct mxs_i2c_dev *i2c = param; + +	if (!mxs_dma_is_apbx(chan)) +		return false; + +	if (chan->chan_id != i2c->dma_channel) +		return false; + +	chan->private = &i2c->dma_data; + +	return true; +} +  static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)  {  	uint32_t speed; @@ -365,6 +555,26 @@ static int mxs_i2c_get_ofdata(struct mxs_i2c_dev *i2c)  	struct device_node *node = dev->of_node;  	int ret; +	/* +	 * The MXS I2C DMA mode is prefered and enabled by default. +	 * The PIO mode is still supported, but should be used only +	 * for debuging purposes etc. +	 */ +	i2c->dma_mode = !use_pioqueue; +	if (!i2c->dma_mode) +		dev_info(dev, "Using PIOQUEUE mode for I2C transfers!\n"); + +	/* +	 * TODO: This is a temporary solution and should be changed +	 * to use generic DMA binding later when the helpers get in. +	 */ +	ret = of_property_read_u32(node, "fsl,i2c-dma-channel", +				   &i2c->dma_channel); +	if (ret) { +		dev_warn(dev, "Failed to get DMA channel, using PIOQUEUE!\n"); +		i2c->dma_mode = 0; +	} +  	ret = of_property_read_u32(node, "clock-frequency", &speed);  	if (ret)  		dev_warn(dev, "No I2C speed selected, using 100kHz\n"); @@ -384,7 +594,8 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)  	struct pinctrl *pinctrl;  	struct resource *res;  	resource_size_t res_size; -	int err, irq; +	int err, irq, dmairq; +	dma_cap_mask_t mask;  	pinctrl = devm_pinctrl_get_select_default(dev);  	if (IS_ERR(pinctrl)) @@ -395,7 +606,10 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)  		return -ENOMEM;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) +	irq = platform_get_irq(pdev, 0); +	dmairq = platform_get_irq(pdev, 1); + +	if (!res || irq < 0 || dmairq < 0)  		return -ENOENT;  	res_size = resource_size(res); @@ -406,10 +620,6 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)  	if (!i2c->regs)  		return -EBUSY; -	irq = platform_get_irq(pdev, 0); -	if (irq < 0) -		return irq; -  	err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);  	if (err)  		return err; @@ -423,6 +633,18 @@ static int __devinit mxs_i2c_probe(struct platform_device *pdev)  			return err;  	} +	/* Setup the DMA */ +	if (i2c->dma_mode) { +		dma_cap_zero(mask); +		dma_cap_set(DMA_SLAVE, mask); +		i2c->dma_data.chan_irq = dmairq; +		i2c->dmach = dma_request_channel(mask, mxs_i2c_dma_filter, i2c); +		if (!i2c->dmach) { +			dev_err(dev, "Failed to request dma\n"); +			return -ENODEV; +		} +	} +  	platform_set_drvdata(pdev, i2c);  	/* Do reset to enforce correct startup after pinmuxing */ @@ -458,6 +680,9 @@ static int __devexit mxs_i2c_remove(struct platform_device *pdev)  	if (ret)  		return -EBUSY; +	if (i2c->dmach) +		dma_release_channel(i2c->dmach); +  	writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET);  	platform_set_drvdata(pdev, NULL); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 61b00edacb0..698d7acb0f0 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -22,9 +22,10 @@  #include <linux/err.h>  #include <linux/clk.h>  #include <linux/io.h> -#include <linux/regulator/consumer.h>  #include <linux/pm_runtime.h>  #include <linux/platform_data/i2c-nomadik.h> +#include <linux/of.h> +#include <linux/of_i2c.h>  #define DRIVER_NAME "nmk-i2c" @@ -146,7 +147,6 @@ struct i2c_nmk_client {   * @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 { @@ -160,7 +160,6 @@ struct nmk_i2c_dev {  	int				stop;  	struct completion		xfer_complete;  	int				result; -	struct regulator		*regulator;  	bool				busy;  }; @@ -643,8 +642,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,  	dev->busy = true; -	if (dev->regulator) -		regulator_enable(dev->regulator);  	pm_runtime_get_sync(&dev->adev->dev);  	clk_enable(dev->clk); @@ -676,8 +673,6 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,  out:  	clk_disable(dev->clk);  	pm_runtime_put_sync(&dev->adev->dev); -	if (dev->regulator) -		regulator_disable(dev->regulator);  	dev->busy = false; @@ -920,18 +915,42 @@ static struct nmk_i2c_controller u8500_i2c = {  	.sm             = I2C_FREQ_MODE_FAST,  }; +static void nmk_i2c_of_probe(struct device_node *np, +			struct nmk_i2c_controller *pdata) +{ +	of_property_read_u32(np, "clock-frequency", &pdata->clk_freq); + +	/* This driver only supports 'standard' and 'fast' modes of operation. */ +	if (pdata->clk_freq <= 100000) +		pdata->sm = I2C_FREQ_MODE_STANDARD; +	else +		pdata->sm = I2C_FREQ_MODE_FAST; +} +  static atomic_t adapter_id = ATOMIC_INIT(0);  static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)  {  	int ret = 0;  	struct nmk_i2c_controller *pdata = adev->dev.platform_data; +	struct device_node *np = adev->dev.of_node;  	struct nmk_i2c_dev	*dev;  	struct i2c_adapter *adap; -	if (!pdata) -		/* No i2c configuration found, using the default. */ -		pdata = &u8500_i2c; +	if (!pdata) { +		if (np) { +			pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL); +			if (!pdata) { +				ret = -ENOMEM; +				goto err_no_mem; +			} +			/* Provide the default configuration as a base. */ +			memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller)); +			nmk_i2c_of_probe(np, pdata); +		} else +			/* No i2c configuration found, using the default. */ +			pdata = &u8500_i2c; +	}  	dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);  	if (!dev) { @@ -957,12 +976,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)  		goto err_irq;  	} -	dev->regulator = regulator_get(&adev->dev, "v-i2c"); -	if (IS_ERR(dev->regulator)) { -		dev_warn(&adev->dev, "could not get i2c regulator\n"); -		dev->regulator = NULL; -	} -  	pm_suspend_ignore_children(&adev->dev, true);  	dev->clk = clk_get(&adev->dev, NULL); @@ -973,6 +986,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)  	}  	adap = &dev->adap; +	adap->dev.of_node = np;  	adap->dev.parent = &adev->dev;  	adap->owner	= THIS_MODULE;  	adap->class	= I2C_CLASS_HWMON | I2C_CLASS_SPD; @@ -1002,6 +1016,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)  		goto err_add_adap;  	} +	of_i2c_register_devices(adap); +  	pm_runtime_put(&adev->dev);  	return 0; @@ -1009,8 +1025,6 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)   err_add_adap:  	clk_put(dev->clk);   err_no_clk: -	if (dev->regulator) -		regulator_put(dev->regulator);  	free_irq(dev->irq, dev);   err_irq:  	iounmap(dev->virtbase); @@ -1038,8 +1052,6 @@ static int nmk_i2c_remove(struct amba_device *adev)  	if (res)  		release_mem_region(res->start, resource_size(res));  	clk_put(dev->clk); -	if (dev->regulator) -		regulator_put(dev->regulator);  	pm_runtime_disable(&adev->dev);  	amba_set_drvdata(adev, NULL);  	kfree(dev); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index a0e49f6aaf9..db31eaed6ea 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -43,6 +43,7 @@  #include <linux/slab.h>  #include <linux/i2c-omap.h>  #include <linux/pm_runtime.h> +#include <linux/pm_qos.h>  /* I2C controller revisions */  #define OMAP_I2C_OMAP1_REV_2		0x20 @@ -55,6 +56,9 @@  /* timeout waiting for the controller to respond */  #define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000)) +/* timeout for pm runtime autosuspend */ +#define OMAP_I2C_PM_TIMEOUT		1000	/* ms */ +  /* For OMAP3 I2C_IV has changed to I2C_WE (wakeup enable) */  enum {  	OMAP_I2C_REV_REG = 0, @@ -176,15 +180,15 @@ enum {  #define I2C_OMAP_ERRATA_I462		(1 << 1)  struct omap_i2c_dev { +	spinlock_t		lock;		/* IRQ synchronization */  	struct device		*dev;  	void __iomem		*base;		/* virtual */  	int			irq;  	int			reg_shift;      /* bit shift for I2C register addresses */  	struct completion	cmd_complete;  	struct resource		*ioarea; -	u32			latency;	/* maximum mpu wkup latency */ -	void			(*set_mpu_wkup_lat)(struct device *dev, -						    long latency); +	u32			latency;	/* maximum MPU wkup latency */ +	struct pm_qos_request	pm_qos_request;  	u32			speed;		/* Speed of bus in kHz */  	u32			dtrev;		/* extra revision from DT */  	u32			flags; @@ -193,12 +197,14 @@ struct omap_i2c_dev {  	u8			*regs;  	size_t			buf_len;  	struct i2c_adapter	adapter; +	u8			threshold;  	u8			fifo_size;	/* use as flag and value  						 * fifo_size==0 implies no fifo  						 * if set, should be trsh+1  						 */  	u8			rev;  	unsigned		b_hw:1;		/* bad h/w fixes */ +	unsigned		receiver:1;	/* true when we're in receiver mode */  	u16			iestate;	/* Saved interrupt register */  	u16			pscstate;  	u16			scllstate; @@ -417,13 +423,6 @@ static int omap_i2c_init(struct omap_i2c_dev *dev)  	omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, scll);  	omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, sclh); -	if (dev->fifo_size) { -		/* Note: setup required fifo size - 1. RTRSH and XTRSH */ -		buf = (dev->fifo_size - 1) << 8 | OMAP_I2C_BUF_RXFIF_CLR | -			(dev->fifo_size - 1) | OMAP_I2C_BUF_TXFIF_CLR; -		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); -	} -  	/* Take the I2C module out of reset: */  	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN); @@ -461,6 +460,43 @@ static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)  	return 0;  } +static void omap_i2c_resize_fifo(struct omap_i2c_dev *dev, u8 size, bool is_rx) +{ +	u16		buf; + +	if (dev->flags & OMAP_I2C_FLAG_NO_FIFO) +		return; + +	/* +	 * Set up notification threshold based on message size. We're doing +	 * this to try and avoid draining feature as much as possible. Whenever +	 * we have big messages to transfer (bigger than our total fifo size) +	 * then we might use draining feature to transfer the remaining bytes. +	 */ + +	dev->threshold = clamp(size, (u8) 1, dev->fifo_size); + +	buf = omap_i2c_read_reg(dev, OMAP_I2C_BUF_REG); + +	if (is_rx) { +		/* Clear RX Threshold */ +		buf &= ~(0x3f << 8); +		buf |= ((dev->threshold - 1) << 8) | OMAP_I2C_BUF_RXFIF_CLR; +	} else { +		/* Clear TX Threshold */ +		buf &= ~0x3f; +		buf |= (dev->threshold - 1) | OMAP_I2C_BUF_TXFIF_CLR; +	} + +	omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, buf); + +	if (dev->rev < OMAP_I2C_REV_ON_3630_4430) +		dev->b_hw = 1; /* Enable hardware fixes */ + +	/* calculate wakeup latency constraint for MPU */ +	dev->latency = (1000000 * dev->threshold) / (1000 * dev->speed / 8); +} +  /*   * Low level master read/write transaction.   */ @@ -477,6 +513,9 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap,  	if (msg->len == 0)  		return -EINVAL; +	dev->receiver = !!(msg->flags & I2C_M_RD); +	omap_i2c_resize_fifo(dev, msg->len, dev->receiver); +  	omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);  	/* REVISIT: Could the STB bit of I2C_CON be used with probing? */ @@ -590,8 +629,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)  	if (r < 0)  		goto out; -	if (dev->set_mpu_wkup_lat != NULL) -		dev->set_mpu_wkup_lat(dev->dev, dev->latency); +	/* +	 * When waiting for completion of a i2c transfer, we need to +	 * set a wake up latency constraint for the MPU. This is to +	 * ensure quick enough wakeup from idle, when transfer +	 * completes. +	 */ +	if (dev->latency) +		pm_qos_add_request(&dev->pm_qos_request, +				   PM_QOS_CPU_DMA_LATENCY, +				   dev->latency);  	for (i = 0; i < num; i++) {  		r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1))); @@ -599,15 +646,16 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)  			break;  	} -	if (dev->set_mpu_wkup_lat != NULL) -		dev->set_mpu_wkup_lat(dev->dev, -1); +	if (dev->latency) +		pm_qos_remove_request(&dev->pm_qos_request);  	if (r == 0)  		r = num;  	omap_i2c_wait_for_bb(dev);  out: -	pm_runtime_put(dev->dev); +	pm_runtime_mark_last_busy(dev->dev); +	pm_runtime_put_autosuspend(dev->dev);  	return r;  } @@ -725,186 +773,252 @@ omap_i2c_omap1_isr(int this_irq, void *dev_id)   * data to DATA_REG. Otherwise some data bytes can be lost while transferring   * them from the memory to the I2C interface.   */ -static int errata_omap3_i462(struct omap_i2c_dev *dev, u16 *stat, int *err) +static int errata_omap3_i462(struct omap_i2c_dev *dev)  {  	unsigned long timeout = 10000; +	u16 stat; -	while (--timeout && !(*stat & OMAP_I2C_STAT_XUDF)) { -		if (*stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { -			omap_i2c_ack_stat(dev, *stat & (OMAP_I2C_STAT_XRDY | +	do { +		stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); +		if (stat & OMAP_I2C_STAT_XUDF) +			break; + +		if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) { +			omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_XRDY |  							OMAP_I2C_STAT_XDR)); -			return -ETIMEDOUT; +			if (stat & OMAP_I2C_STAT_NACK) { +				dev->cmd_err |= OMAP_I2C_STAT_NACK; +				omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); +			} + +			if (stat & OMAP_I2C_STAT_AL) { +				dev_err(dev->dev, "Arbitration lost\n"); +				dev->cmd_err |= OMAP_I2C_STAT_AL; +				omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); +			} + +			return -EIO;  		}  		cpu_relax(); -		*stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); -	} +	} while (--timeout);  	if (!timeout) {  		dev_err(dev->dev, "timeout waiting on XUDF bit\n");  		return 0;  	} -	*err |= OMAP_I2C_STAT_XUDF;  	return 0;  } +static void omap_i2c_receive_data(struct omap_i2c_dev *dev, u8 num_bytes, +		bool is_rdr) +{ +	u16		w; + +	while (num_bytes--) { +		w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); +		*dev->buf++ = w; +		dev->buf_len--; + +		/* +		 * Data reg in 2430, omap3 and +		 * omap4 is 8 bit wide +		 */ +		if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { +			*dev->buf++ = w >> 8; +			dev->buf_len--; +		} +	} +} + +static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, +		bool is_xdr) +{ +	u16		w; + +	while (num_bytes--) { +		w = *dev->buf++; +		dev->buf_len--; + +		/* +		 * Data reg in 2430, omap3 and +		 * omap4 is 8 bit wide +		 */ +		if (dev->flags & OMAP_I2C_FLAG_16BIT_DATA_REG) { +			w |= *dev->buf++ << 8; +			dev->buf_len--; +		} + +		if (dev->errata & I2C_OMAP_ERRATA_I462) { +			int ret; + +			ret = errata_omap3_i462(dev); +			if (ret < 0) +				return ret; +		} + +		omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); +	} + +	return 0; +} + +static irqreturn_t +omap_i2c_isr(int irq, void *dev_id) +{ +	struct omap_i2c_dev *dev = dev_id; +	irqreturn_t ret = IRQ_HANDLED; +	u16 mask; +	u16 stat; + +	spin_lock(&dev->lock); +	mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); +	stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); + +	if (stat & mask) +		ret = IRQ_WAKE_THREAD; + +	spin_unlock(&dev->lock); + +	return ret; +} +  static irqreturn_t -omap_i2c_isr(int this_irq, void *dev_id) +omap_i2c_isr_thread(int this_irq, void *dev_id)  {  	struct omap_i2c_dev *dev = dev_id; +	unsigned long flags;  	u16 bits; -	u16 stat, w; -	int err, count = 0; +	u16 stat; +	int err = 0, count = 0; -	if (pm_runtime_suspended(dev->dev)) -		return IRQ_NONE; +	spin_lock_irqsave(&dev->lock, flags); +	do { +		bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); +		stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); +		stat &= bits; + +		/* If we're in receiver mode, ignore XDR/XRDY */ +		if (dev->receiver) +			stat &= ~(OMAP_I2C_STAT_XDR | OMAP_I2C_STAT_XRDY); +		else +			stat &= ~(OMAP_I2C_STAT_RDR | OMAP_I2C_STAT_RRDY); + +		if (!stat) { +			/* my work here is done */ +			goto out; +		} -	bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); -	while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {  		dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);  		if (count++ == 100) {  			dev_warn(dev->dev, "Too much work in one IRQ\n");  			break;  		} -		err = 0; -complete: -		/* -		 * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be -		 * acked after the data operation is complete. -		 * Ref: TRM SWPU114Q Figure 18-31 -		 */ -		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat & -				~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | -				OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); - -		if (stat & OMAP_I2C_STAT_NACK) +		if (stat & OMAP_I2C_STAT_NACK) {  			err |= OMAP_I2C_STAT_NACK; +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); +			break; +		}  		if (stat & OMAP_I2C_STAT_AL) {  			dev_err(dev->dev, "Arbitration lost\n");  			err |= OMAP_I2C_STAT_AL; +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); +			break;  		} +  		/*  		 * ProDB0017052: Clear ARDY bit twice  		 */  		if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |  					OMAP_I2C_STAT_AL)) { -			omap_i2c_ack_stat(dev, stat & -				(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR | -				OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR | -				OMAP_I2C_STAT_ARDY)); -			omap_i2c_complete_cmd(dev, err); -			return IRQ_HANDLED; +			omap_i2c_ack_stat(dev, (OMAP_I2C_STAT_RRDY | +						OMAP_I2C_STAT_RDR | +						OMAP_I2C_STAT_XRDY | +						OMAP_I2C_STAT_XDR | +						OMAP_I2C_STAT_ARDY)); +			break;  		} -		if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) { + +		if (stat & OMAP_I2C_STAT_RDR) {  			u8 num_bytes = 1; +			if (dev->fifo_size) +				num_bytes = dev->buf_len; + +			omap_i2c_receive_data(dev, num_bytes, true); +  			if (dev->errata & I2C_OMAP_ERRATA_I207)  				i2c_omap_errata_i207(dev, stat); -			if (dev->fifo_size) { -				if (stat & OMAP_I2C_STAT_RRDY) -					num_bytes = dev->fifo_size; -				else    /* read RXSTAT on RDR interrupt */ -					num_bytes = (omap_i2c_read_reg(dev, -							OMAP_I2C_BUFSTAT_REG) -							>> 8) & 0x3F; -			} -			while (num_bytes) { -				num_bytes--; -				w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG); -				if (dev->buf_len) { -					*dev->buf++ = w; -					dev->buf_len--; -					/* -					 * Data reg in 2430, omap3 and -					 * omap4 is 8 bit wide -					 */ -					if (dev->flags & -						 OMAP_I2C_FLAG_16BIT_DATA_REG) { -						if (dev->buf_len) { -							*dev->buf++ = w >> 8; -							dev->buf_len--; -						} -					} -				} else { -					if (stat & OMAP_I2C_STAT_RRDY) -						dev_err(dev->dev, -							"RRDY IRQ while no data" -								" requested\n"); -					if (stat & OMAP_I2C_STAT_RDR) -						dev_err(dev->dev, -							"RDR IRQ while no data" -								" requested\n"); -					break; -				} -			} -			omap_i2c_ack_stat(dev, -				stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)); +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); +			break; +		} + +		if (stat & OMAP_I2C_STAT_RRDY) { +			u8 num_bytes = 1; + +			if (dev->threshold) +				num_bytes = dev->threshold; + +			omap_i2c_receive_data(dev, num_bytes, false); +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);  			continue;  		} -		if (stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)) { + +		if (stat & OMAP_I2C_STAT_XDR) {  			u8 num_bytes = 1; -			if (dev->fifo_size) { -				if (stat & OMAP_I2C_STAT_XRDY) -					num_bytes = dev->fifo_size; -				else    /* read TXSTAT on XDR interrupt */ -					num_bytes = omap_i2c_read_reg(dev, -							OMAP_I2C_BUFSTAT_REG) -							& 0x3F; -			} -			while (num_bytes) { -				num_bytes--; -				w = 0; -				if (dev->buf_len) { -					w = *dev->buf++; -					dev->buf_len--; -					/* -					 * Data reg in 2430, omap3 and -					 * omap4 is 8 bit wide -					 */ -					if (dev->flags & -						 OMAP_I2C_FLAG_16BIT_DATA_REG) { -						if (dev->buf_len) { -							w |= *dev->buf++ << 8; -							dev->buf_len--; -						} -					} -				} else { -					if (stat & OMAP_I2C_STAT_XRDY) -						dev_err(dev->dev, -							"XRDY IRQ while no " -							"data to send\n"); -					if (stat & OMAP_I2C_STAT_XDR) -						dev_err(dev->dev, -							"XDR IRQ while no " -							"data to send\n"); -					break; -				} +			int ret; -				if ((dev->errata & I2C_OMAP_ERRATA_I462) && -				    errata_omap3_i462(dev, &stat, &err)) -					goto complete; +			if (dev->fifo_size) +				num_bytes = dev->buf_len; -				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w); -			} -			omap_i2c_ack_stat(dev, -				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR)); +			ret = omap_i2c_transmit_data(dev, num_bytes, true); +			if (ret < 0) +				break; + +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XDR); +			break; +		} + +		if (stat & OMAP_I2C_STAT_XRDY) { +			u8 num_bytes = 1; +			int ret; + +			if (dev->threshold) +				num_bytes = dev->threshold; + +			ret = omap_i2c_transmit_data(dev, num_bytes, false); +			if (ret < 0) +				break; + +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);  			continue;  		} +  		if (stat & OMAP_I2C_STAT_ROVR) {  			dev_err(dev->dev, "Receive overrun\n"); -			dev->cmd_err |= OMAP_I2C_STAT_ROVR; +			err |= OMAP_I2C_STAT_ROVR; +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_ROVR); +			break;  		} +  		if (stat & OMAP_I2C_STAT_XUDF) {  			dev_err(dev->dev, "Transmit underflow\n"); -			dev->cmd_err |= OMAP_I2C_STAT_XUDF; +			err |= OMAP_I2C_STAT_XUDF; +			omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XUDF); +			break;  		} -	} +	} while (stat); + +	omap_i2c_complete_cmd(dev, err); + +out: +	spin_unlock_irqrestore(&dev->lock, flags); -	return count ? IRQ_HANDLED : IRQ_NONE; +	return IRQ_HANDLED;  }  static const struct i2c_algorithm omap_i2c_algo = { @@ -943,12 +1057,12 @@ omap_i2c_probe(struct platform_device *pdev)  {  	struct omap_i2c_dev	*dev;  	struct i2c_adapter	*adap; -	struct resource		*mem, *irq, *ioarea; +	struct resource		*mem;  	const struct omap_i2c_bus_platform_data *pdata =  		pdev->dev.platform_data;  	struct device_node	*node = pdev->dev.of_node;  	const struct of_device_id *match; -	irq_handler_t isr; +	int irq;  	int r;  	/* NOTE: driver uses the static register mapping */ @@ -957,23 +1071,23 @@ omap_i2c_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "no mem resource?\n");  		return -ENODEV;  	} -	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); -	if (!irq) { + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) {  		dev_err(&pdev->dev, "no irq resource?\n"); -		return -ENODEV; +		return irq;  	} -	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 = devm_kzalloc(&pdev->dev, sizeof(struct omap_i2c_dev), GFP_KERNEL); +	if (!dev) { +		dev_err(&pdev->dev, "Menory allocation failed\n"); +		return -ENOMEM;  	} -	dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL); -	if (!dev) { -		r = -ENOMEM; -		goto err_release_region; +	dev->base = devm_request_and_ioremap(&pdev->dev, mem); +	if (!dev->base) { +		dev_err(&pdev->dev, "I2C region already claimed\n"); +		return -ENOMEM;  	}  	match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); @@ -990,17 +1104,13 @@ omap_i2c_probe(struct platform_device *pdev)  	} else if (pdata != NULL) {  		dev->speed = pdata->clkrate;  		dev->flags = pdata->flags; -		dev->set_mpu_wkup_lat = pdata->set_mpu_wkup_lat;  		dev->dtrev = pdata->rev;  	}  	dev->dev = &pdev->dev; -	dev->irq = irq->start; -	dev->base = ioremap(mem->start, resource_size(mem)); -	if (!dev->base) { -		r = -ENOMEM; -		goto err_free_mem; -	} +	dev->irq = irq; + +	spin_lock_init(&dev->lock);  	platform_set_drvdata(pdev, dev);  	init_completion(&dev->cmd_complete); @@ -1013,6 +1123,9 @@ omap_i2c_probe(struct platform_device *pdev)  		dev->regs = (u8 *)reg_map_ip_v1;  	pm_runtime_enable(dev->dev); +	pm_runtime_set_autosuspend_delay(dev->dev, OMAP_I2C_PM_TIMEOUT); +	pm_runtime_use_autosuspend(dev->dev); +  	r = pm_runtime_get_sync(dev->dev);  	if (IS_ERR_VALUE(r))  		goto err_free_mem; @@ -1042,32 +1155,31 @@ omap_i2c_probe(struct platform_device *pdev)  		dev->fifo_size = (dev->fifo_size / 2); -		if (dev->rev >= OMAP_I2C_REV_ON_3630_4430) -			dev->b_hw = 0; /* Disable hardware fixes */ -		else +		if (dev->rev < OMAP_I2C_REV_ON_3630_4430)  			dev->b_hw = 1; /* Enable hardware fixes */  		/* calculate wakeup latency constraint for MPU */ -		if (dev->set_mpu_wkup_lat != NULL) -			dev->latency = (1000000 * dev->fifo_size) / -				       (1000 * dev->speed / 8); +		dev->latency = (1000000 * dev->fifo_size) / +			       (1000 * dev->speed / 8);  	}  	/* reset ASAP, clearing any IRQs */  	omap_i2c_init(dev); -	isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : -								   omap_i2c_isr; -	r = request_irq(dev->irq, isr, IRQF_NO_SUSPEND, pdev->name, dev); +	if (dev->rev < OMAP_I2C_OMAP1_REV_2) +		r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr, +				IRQF_NO_SUSPEND, pdev->name, dev); +	else +		r = devm_request_threaded_irq(&pdev->dev, dev->irq, +				omap_i2c_isr, omap_i2c_isr_thread, +				IRQF_NO_SUSPEND | IRQF_ONESHOT, +				pdev->name, dev);  	if (r) {  		dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);  		goto err_unuse_clocks;  	} -	dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", pdev->id, -		 dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); -  	adap = &dev->adapter;  	i2c_set_adapdata(adap, dev);  	adap->owner = THIS_MODULE; @@ -1082,27 +1194,25 @@ omap_i2c_probe(struct platform_device *pdev)  	r = i2c_add_numbered_adapter(adap);  	if (r) {  		dev_err(dev->dev, "failure adding adapter\n"); -		goto err_free_irq; +		goto err_unuse_clocks;  	} +	dev_info(dev->dev, "bus %d rev%d.%d.%d at %d kHz\n", adap->nr, +		 dev->dtrev, dev->rev >> 4, dev->rev & 0xf, dev->speed); +  	of_i2c_register_devices(adap); -	pm_runtime_put(dev->dev); +	pm_runtime_mark_last_busy(dev->dev); +	pm_runtime_put_autosuspend(dev->dev);  	return 0; -err_free_irq: -	free_irq(dev->irq, dev);  err_unuse_clocks:  	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);  	pm_runtime_put(dev->dev); -	iounmap(dev->base);  	pm_runtime_disable(&pdev->dev);  err_free_mem:  	platform_set_drvdata(pdev, NULL); -	kfree(dev); -err_release_region: -	release_mem_region(mem->start, resource_size(mem));  	return r;  } @@ -1110,12 +1220,10 @@ err_release_region:  static int __devexit omap_i2c_remove(struct platform_device *pdev)  {  	struct omap_i2c_dev	*dev = platform_get_drvdata(pdev); -	struct resource		*mem;  	int ret;  	platform_set_drvdata(pdev, NULL); -	free_irq(dev->irq, dev);  	i2c_del_adapter(&dev->adapter);  	ret = pm_runtime_get_sync(&pdev->dev);  	if (IS_ERR_VALUE(ret)) @@ -1124,10 +1232,6 @@ static int __devexit omap_i2c_remove(struct platform_device *pdev)  	omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);  	pm_runtime_put(&pdev->dev);  	pm_runtime_disable(&pdev->dev); -	iounmap(dev->base); -	kfree(dev); -	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	release_mem_region(mem->start, resource_size(mem));  	return 0;  } diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c new file mode 100644 index 00000000000..f9399d163af --- /dev/null +++ b/drivers/i2c/busses/i2c-rcar.c @@ -0,0 +1,709 @@ +/* + *  drivers/i2c/busses/i2c-rcar.c + * + * Copyright (C) 2012 Renesas Solutions Corp. + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This file is based on the drivers/i2c/busses/i2c-sh7760.c + * (c) 2005-2008 MSC Vertriebsges.m.b.H, Manuel Lauss <mlau@msc-ge.com> + * + * This file used out-of-tree driver i2c-rcar.c + * Copyright (C) 2011-2012 Renesas Electronics 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 + * + * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/i2c/i2c-rcar.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +/* register offsets */ +#define ICSCR	0x00	/* slave ctrl */ +#define ICMCR	0x04	/* master ctrl */ +#define ICSSR	0x08	/* slave status */ +#define ICMSR	0x0C	/* master status */ +#define ICSIER	0x10	/* slave irq enable */ +#define ICMIER	0x14	/* master irq enable */ +#define ICCCR	0x18	/* clock dividers */ +#define ICSAR	0x1C	/* slave address */ +#define ICMAR	0x20	/* master address */ +#define ICRXTX	0x24	/* data port */ + +/* ICMCR */ +#define MDBS	(1 << 7)	/* non-fifo mode switch */ +#define FSCL	(1 << 6)	/* override SCL pin */ +#define FSDA	(1 << 5)	/* override SDA pin */ +#define OBPC	(1 << 4)	/* override pins */ +#define MIE	(1 << 3)	/* master if enable */ +#define TSBE	(1 << 2) +#define FSB	(1 << 1)	/* force stop bit */ +#define ESG	(1 << 0)	/* en startbit gen */ + +/* ICMSR */ +#define MNR	(1 << 6)	/* nack received */ +#define MAL	(1 << 5)	/* arbitration lost */ +#define MST	(1 << 4)	/* sent a stop */ +#define MDE	(1 << 3) +#define MDT	(1 << 2) +#define MDR	(1 << 1) +#define MAT	(1 << 0)	/* slave addr xfer done */ + +/* ICMIE */ +#define MNRE	(1 << 6)	/* nack irq en */ +#define MALE	(1 << 5)	/* arblos irq en */ +#define MSTE	(1 << 4)	/* stop irq en */ +#define MDEE	(1 << 3) +#define MDTE	(1 << 2) +#define MDRE	(1 << 1) +#define MATE	(1 << 0)	/* address sent irq en */ + + +enum { +	RCAR_BUS_PHASE_ADDR, +	RCAR_BUS_PHASE_DATA, +	RCAR_BUS_PHASE_STOP, +}; + +enum { +	RCAR_IRQ_CLOSE, +	RCAR_IRQ_OPEN_FOR_SEND, +	RCAR_IRQ_OPEN_FOR_RECV, +	RCAR_IRQ_OPEN_FOR_STOP, +}; + +/* + * flags + */ +#define ID_LAST_MSG	(1 << 0) +#define ID_IOERROR	(1 << 1) +#define ID_DONE		(1 << 2) +#define ID_ARBLOST	(1 << 3) +#define ID_NACK		(1 << 4) + +struct rcar_i2c_priv { +	void __iomem *io; +	struct i2c_adapter adap; +	struct i2c_msg	*msg; + +	spinlock_t lock; +	wait_queue_head_t wait; + +	int pos; +	int irq; +	u32 icccr; +	u32 flags; +}; + +#define rcar_i2c_priv_to_dev(p)		((p)->adap.dev.parent) +#define rcar_i2c_is_recv(p)		((p)->msg->flags & I2C_M_RD) + +#define rcar_i2c_flags_set(p, f)	((p)->flags |= (f)) +#define rcar_i2c_flags_has(p, f)	((p)->flags & (f)) + +#define LOOP_TIMEOUT	1024 + +/* + *		basic functions + */ +static void rcar_i2c_write(struct rcar_i2c_priv *priv, int reg, u32 val) +{ +	writel(val, priv->io + reg); +} + +static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) +{ +	return readl(priv->io + reg); +} + +static void rcar_i2c_init(struct rcar_i2c_priv *priv) +{ +	/* +	 * reset slave mode. +	 * slave mode is not used on this driver +	 */ +	rcar_i2c_write(priv, ICSIER, 0); +	rcar_i2c_write(priv, ICSAR, 0); +	rcar_i2c_write(priv, ICSCR, 0); +	rcar_i2c_write(priv, ICSSR, 0); + +	/* reset master mode */ +	rcar_i2c_write(priv, ICMIER, 0); +	rcar_i2c_write(priv, ICMCR, 0); +	rcar_i2c_write(priv, ICMSR, 0); +	rcar_i2c_write(priv, ICMAR, 0); +} + +static void rcar_i2c_irq_mask(struct rcar_i2c_priv *priv, int open) +{ +	u32 val = MNRE | MALE | MSTE | MATE; /* default */ + +	switch (open) { +	case RCAR_IRQ_OPEN_FOR_SEND: +		val |= MDEE; /* default + send */ +		break; +	case RCAR_IRQ_OPEN_FOR_RECV: +		val |= MDRE; /* default + read */ +		break; +	case RCAR_IRQ_OPEN_FOR_STOP: +		val = MSTE; /* stop irq only */ +		break; +	case RCAR_IRQ_CLOSE: +	default: +		val = 0; /* all close */ +		break; +	} +	rcar_i2c_write(priv, ICMIER, val); +} + +static void rcar_i2c_set_addr(struct rcar_i2c_priv *priv, u32 recv) +{ +	rcar_i2c_write(priv, ICMAR, (priv->msg->addr << 1) | recv); +} + +/* + *		bus control functions + */ +static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) +{ +	int i; + +	for (i = 0; i < LOOP_TIMEOUT; i++) { +		/* make sure that bus is not busy */ +		if (!(rcar_i2c_read(priv, ICMCR) & FSDA)) +			return 0; +		udelay(1); +	} + +	return -EBUSY; +} + +static void rcar_i2c_bus_phase(struct rcar_i2c_priv *priv, int phase) +{ +	switch (phase) { +	case RCAR_BUS_PHASE_ADDR: +		rcar_i2c_write(priv, ICMCR, MDBS | MIE | ESG); +		break; +	case RCAR_BUS_PHASE_DATA: +		rcar_i2c_write(priv, ICMCR, MDBS | MIE); +		break; +	case RCAR_BUS_PHASE_STOP: +		rcar_i2c_write(priv, ICMCR, MDBS | MIE | FSB); +		break; +	} +} + +/* + *		clock function + */ +static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv, +				    u32 bus_speed, +				    struct device *dev) +{ +	struct clk *clkp = clk_get(NULL, "peripheral_clk"); +	u32 scgd, cdf; +	u32 round, ick; +	u32 scl; + +	if (!clkp) { +		dev_err(dev, "there is no peripheral_clk\n"); +		return -EIO; +	} + +	/* +	 * calculate SCL clock +	 * see +	 *	ICCCR +	 * +	 * ick	= clkp / (1 + CDF) +	 * SCL	= ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick]) +	 * +	 * ick  : I2C internal clock < 20 MHz +	 * ticf : I2C SCL falling time  =  35 ns here +	 * tr   : I2C SCL rising  time  = 200 ns here +	 * intd : LSI internal delay    =  50 ns here +	 * clkp : peripheral_clk +	 * F[]  : integer up-valuation +	 */ +	for (cdf = 0; cdf < 4; cdf++) { +		ick = clk_get_rate(clkp) / (1 + cdf); +		if (ick < 20000000) +			goto ick_find; +	} +	dev_err(dev, "there is no best CDF\n"); +	return -EIO; + +ick_find: +	/* +	 * it is impossible to calculate large scale +	 * number on u32. separate it +	 * +	 * F[(ticf + tr + intd) * ick] +	 *  = F[(35 + 200 + 50)ns * ick] +	 *  = F[285 * ick / 1000000000] +	 *  = F[(ick / 1000000) * 285 / 1000] +	 */ +	round = (ick + 500000) / 1000000 * 285; +	round = (round + 500) / 1000; + +	/* +	 * SCL	= ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick]) +	 * +	 * Calculation result (= SCL) should be less than +	 * bus_speed for hardware safety +	 */ +	for (scgd = 0; scgd < 0x40; scgd++) { +		scl = ick / (20 + (scgd * 8) + round); +		if (scl <= bus_speed) +			goto scgd_find; +	} +	dev_err(dev, "it is impossible to calculate best SCL\n"); +	return -EIO; + +scgd_find: +	dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n", +		scl, bus_speed, clk_get_rate(clkp), round, cdf, scgd); + +	/* +	 * keep icccr value +	 */ +	priv->icccr = (scgd << 2 | cdf); + +	return 0; +} + +static void rcar_i2c_clock_start(struct rcar_i2c_priv *priv) +{ +	rcar_i2c_write(priv, ICCCR, priv->icccr); +} + +/* + *		status functions + */ +static u32 rcar_i2c_status_get(struct rcar_i2c_priv *priv) +{ +	return rcar_i2c_read(priv, ICMSR); +} + +#define rcar_i2c_status_clear(priv) rcar_i2c_status_bit_clear(priv, 0xffffffff) +static void rcar_i2c_status_bit_clear(struct rcar_i2c_priv *priv, u32 bit) +{ +	rcar_i2c_write(priv, ICMSR, ~bit); +} + +/* + *		recv/send functions + */ +static int rcar_i2c_recv(struct rcar_i2c_priv *priv) +{ +	rcar_i2c_set_addr(priv, 1); +	rcar_i2c_status_clear(priv); +	rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); +	rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_RECV); + +	return 0; +} + +static int rcar_i2c_send(struct rcar_i2c_priv *priv) +{ +	int ret; + +	/* +	 * It should check bus status when send case +	 */ +	ret = rcar_i2c_bus_barrier(priv); +	if (ret < 0) +		return ret; + +	rcar_i2c_set_addr(priv, 0); +	rcar_i2c_status_clear(priv); +	rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_ADDR); +	rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_SEND); + +	return 0; +} + +#define rcar_i2c_send_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDE)) +#define rcar_i2c_recv_restart(priv) rcar_i2c_status_bit_clear(priv, (MAT | MDR)) + +/* + *		interrupt functions + */ +static int rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) +{ +	struct i2c_msg *msg = priv->msg; + +	/* +	 * FIXME +	 * sometimes, unknown interrupt happened. +	 * Do nothing +	 */ +	if (!(msr & MDE)) +		return 0; + +	/* +	 * If address transfer phase finished, +	 * goto data phase. +	 */ +	if (msr & MAT) +		rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + +	if (priv->pos < msg->len) { +		/* +		 * Prepare next data to ICRXTX register. +		 * This data will go to _SHIFT_ register. +		 * +		 *    * +		 * [ICRXTX] -> [SHIFT] -> [I2C bus] +		 */ +		rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]); +		priv->pos++; + +	} else { +		/* +		 * The last data was pushed to ICRXTX on _PREV_ empty irq. +		 * It is on _SHIFT_ register, and will sent to I2C bus. +		 * +		 *		  * +		 * [ICRXTX] -> [SHIFT] -> [I2C bus] +		 */ + +		if (priv->flags & ID_LAST_MSG) +			/* +			 * If current msg is the _LAST_ msg, +			 * prepare stop condition here. +			 * ID_DONE will be set on STOP irq. +			 */ +			rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); +		else +			/* +			 * If current msg is _NOT_ last msg, +			 * it doesn't call stop phase. +			 * thus, there is no STOP irq. +			 * return ID_DONE here. +			 */ +			return ID_DONE; +	} + +	rcar_i2c_send_restart(priv); + +	return 0; +} + +static int rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) +{ +	struct i2c_msg *msg = priv->msg; + +	/* +	 * FIXME +	 * sometimes, unknown interrupt happened. +	 * Do nothing +	 */ +	if (!(msr & MDR)) +		return 0; + +	if (msr & MAT) { +		/* +		 * Address transfer phase finished, +		 * but, there is no data at this point. +		 * Do nothing. +		 */ +	} else if (priv->pos < msg->len) { +		/* +		 * get received data +		 */ +		msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX); +		priv->pos++; +	} + +	/* +	 * If next received data is the _LAST_, +	 * go to STOP phase, +	 * otherwise, go to DATA phase. +	 */ +	if (priv->pos + 1 >= msg->len) +		rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); +	else +		rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_DATA); + +	rcar_i2c_recv_restart(priv); + +	return 0; +} + +static irqreturn_t rcar_i2c_irq(int irq, void *ptr) +{ +	struct rcar_i2c_priv *priv = ptr; +	struct device *dev = rcar_i2c_priv_to_dev(priv); +	u32 msr; + +	/*-------------- spin lock -----------------*/ +	spin_lock(&priv->lock); + +	msr = rcar_i2c_status_get(priv); + +	/* +	 * Arbitration lost +	 */ +	if (msr & MAL) { +		/* +		 * CAUTION +		 * +		 * When arbitration lost, device become _slave_ mode. +		 */ +		dev_dbg(dev, "Arbitration Lost\n"); +		rcar_i2c_flags_set(priv, (ID_DONE | ID_ARBLOST)); +		goto out; +	} + +	/* +	 * Stop +	 */ +	if (msr & MST) { +		dev_dbg(dev, "Stop\n"); +		rcar_i2c_flags_set(priv, ID_DONE); +		goto out; +	} + +	/* +	 * Nack +	 */ +	if (msr & MNR) { +		dev_dbg(dev, "Nack\n"); + +		/* go to stop phase */ +		rcar_i2c_bus_phase(priv, RCAR_BUS_PHASE_STOP); +		rcar_i2c_irq_mask(priv, RCAR_IRQ_OPEN_FOR_STOP); +		rcar_i2c_flags_set(priv, ID_NACK); +		goto out; +	} + +	/* +	 * recv/send +	 */ +	if (rcar_i2c_is_recv(priv)) +		rcar_i2c_flags_set(priv, rcar_i2c_irq_recv(priv, msr)); +	else +		rcar_i2c_flags_set(priv, rcar_i2c_irq_send(priv, msr)); + +out: +	if (rcar_i2c_flags_has(priv, ID_DONE)) { +		rcar_i2c_irq_mask(priv, RCAR_IRQ_CLOSE); +		rcar_i2c_status_clear(priv); +		wake_up(&priv->wait); +	} + +	spin_unlock(&priv->lock); +	/*-------------- spin unlock -----------------*/ + +	return IRQ_HANDLED; +} + +static int rcar_i2c_master_xfer(struct i2c_adapter *adap, +				struct i2c_msg *msgs, +				int num) +{ +	struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); +	struct device *dev = rcar_i2c_priv_to_dev(priv); +	unsigned long flags; +	int i, ret, timeout; + +	pm_runtime_get_sync(dev); + +	/*-------------- spin lock -----------------*/ +	spin_lock_irqsave(&priv->lock, flags); + +	rcar_i2c_init(priv); +	rcar_i2c_clock_start(priv); + +	spin_unlock_irqrestore(&priv->lock, flags); +	/*-------------- spin unlock -----------------*/ + +	ret = -EINVAL; +	for (i = 0; i < num; i++) { +		/*-------------- spin lock -----------------*/ +		spin_lock_irqsave(&priv->lock, flags); + +		/* init each data */ +		priv->msg	= &msgs[i]; +		priv->pos	= 0; +		priv->flags	= 0; +		if (priv->msg == &msgs[num - 1]) +			rcar_i2c_flags_set(priv, ID_LAST_MSG); + +		/* start send/recv */ +		if (rcar_i2c_is_recv(priv)) +			ret = rcar_i2c_recv(priv); +		else +			ret = rcar_i2c_send(priv); + +		spin_unlock_irqrestore(&priv->lock, flags); +		/*-------------- spin unlock -----------------*/ + +		if (ret < 0) +			break; + +		/* +		 * wait result +		 */ +		timeout = wait_event_timeout(priv->wait, +					     rcar_i2c_flags_has(priv, ID_DONE), +					     5 * HZ); +		if (!timeout) { +			ret = -ETIMEDOUT; +			break; +		} + +		/* +		 * error handling +		 */ +		if (rcar_i2c_flags_has(priv, ID_NACK)) { +			ret = -EREMOTEIO; +			break; +		} + +		if (rcar_i2c_flags_has(priv, ID_ARBLOST)) { +			ret = -EAGAIN; +			break; +		} + +		if (rcar_i2c_flags_has(priv, ID_IOERROR)) { +			ret = -EIO; +			break; +		} + +		ret = i + 1; /* The number of transfer */ +	} + +	pm_runtime_put(dev); + +	if (ret < 0) +		dev_err(dev, "error %d : %x\n", ret, priv->flags); + +	return ret; +} + +static u32 rcar_i2c_func(struct i2c_adapter *adap) +{ +	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm rcar_i2c_algo = { +	.master_xfer	= rcar_i2c_master_xfer, +	.functionality	= rcar_i2c_func, +}; + +static int __devinit rcar_i2c_probe(struct platform_device *pdev) +{ +	struct i2c_rcar_platform_data *pdata = pdev->dev.platform_data; +	struct rcar_i2c_priv *priv; +	struct i2c_adapter *adap; +	struct resource *res; +	struct device *dev = &pdev->dev; +	u32 bus_speed; +	int ret; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		dev_err(dev, "no mmio resources\n"); +		return -ENODEV; +	} + +	priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); +	if (!priv) { +		dev_err(dev, "no mem for private data\n"); +		return -ENOMEM; +	} + +	bus_speed = 100000; /* default 100 kHz */ +	if (pdata && pdata->bus_speed) +		bus_speed = pdata->bus_speed; +	ret = rcar_i2c_clock_calculate(priv, bus_speed, dev); +	if (ret < 0) +		return ret; + +	priv->io = devm_ioremap(dev, res->start, resource_size(res)); +	if (!priv->io) { +		dev_err(dev, "cannot ioremap\n"); +		return -ENODEV; +	} + +	priv->irq = platform_get_irq(pdev, 0); +	init_waitqueue_head(&priv->wait); +	spin_lock_init(&priv->lock); + +	adap			= &priv->adap; +	adap->nr		= pdev->id; +	adap->algo		= &rcar_i2c_algo; +	adap->class		= I2C_CLASS_HWMON | I2C_CLASS_SPD; +	adap->retries		= 3; +	adap->dev.parent	= dev; +	i2c_set_adapdata(adap, priv); +	strlcpy(adap->name, pdev->name, sizeof(adap->name)); + +	ret = devm_request_irq(dev, priv->irq, rcar_i2c_irq, 0, +			       dev_name(dev), priv); +	if (ret < 0) { +		dev_err(dev, "cannot get irq %d\n", priv->irq); +		return ret; +	} + +	ret = i2c_add_numbered_adapter(adap); +	if (ret < 0) { +		dev_err(dev, "reg adap failed: %d\n", ret); +		return ret; +	} + +	pm_runtime_enable(dev); +	platform_set_drvdata(pdev, priv); + +	dev_info(dev, "probed\n"); + +	return 0; +} + +static int __devexit rcar_i2c_remove(struct platform_device *pdev) +{ +	struct rcar_i2c_priv *priv = platform_get_drvdata(pdev); +	struct device *dev = &pdev->dev; + +	i2c_del_adapter(&priv->adap); +	pm_runtime_disable(dev); + +	return 0; +} + +static struct platform_driver rcar_i2c_drv = { +	.driver	= { +		.name	= "i2c-rcar", +		.owner	= THIS_MODULE, +	}, +	.probe		= rcar_i2c_probe, +	.remove		= __devexit_p(rcar_i2c_remove), +}; + +module_platform_driver(rcar_i2c_drv); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Renesas R-Car I2C bus driver"); +MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4d07dea9bca..3e0335f1fc6 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -601,14 +601,14 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,  	int ret;  	pm_runtime_get_sync(&adap->dev); -	clk_enable(i2c->clk); +	clk_prepare_enable(i2c->clk);  	for (retry = 0; retry < adap->retries; retry++) {  		ret = s3c24xx_i2c_doxfer(i2c, msgs, num);  		if (ret != -EAGAIN) { -			clk_disable(i2c->clk); +			clk_disable_unprepare(i2c->clk);  			pm_runtime_put(&adap->dev);  			return ret;  		} @@ -618,7 +618,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,  		udelay(100);  	} -	clk_disable(i2c->clk); +	clk_disable_unprepare(i2c->clk);  	pm_runtime_put(&adap->dev);  	return -EREMOTEIO;  } @@ -977,7 +977,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)  	dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); -	clk_enable(i2c->clk); +	clk_prepare_enable(i2c->clk);  	/* map the registers */ @@ -1065,7 +1065,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)  	pm_runtime_enable(&i2c->adap.dev);  	dev_info(&pdev->dev, "%s: S3C I2C adapter\n", dev_name(&i2c->adap.dev)); -	clk_disable(i2c->clk); +	clk_disable_unprepare(i2c->clk);  	return 0;   err_cpufreq: @@ -1082,7 +1082,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)  	kfree(i2c->ioarea);   err_clk: -	clk_disable(i2c->clk); +	clk_disable_unprepare(i2c->clk);  	clk_put(i2c->clk);   err_noclk: @@ -1106,7 +1106,7 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)  	i2c_del_adapter(&i2c->adap);  	free_irq(i2c->irq, i2c); -	clk_disable(i2c->clk); +	clk_disable_unprepare(i2c->clk);  	clk_put(i2c->clk);  	iounmap(i2c->regs); @@ -1135,9 +1135,9 @@ static int s3c24xx_i2c_resume(struct device *dev)  	struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);  	i2c->suspended = 0; -	clk_enable(i2c->clk); +	clk_prepare_enable(i2c->clk);  	s3c24xx_i2c_init(i2c); -	clk_disable(i2c->clk); +	clk_disable_unprepare(i2c->clk);  	return 0;  } diff --git a/include/linux/i2c-algo-pca.h b/include/linux/i2c-algo-pca.h index 1364d62e2fb..a3c3ecd59f0 100644 --- a/include/linux/i2c-algo-pca.h +++ b/include/linux/i2c-algo-pca.h @@ -62,6 +62,7 @@ struct i2c_algo_pca_data {  	 * 330000, 288000, 217000, 146000, 88000, 59000, 44000, 36000  	 * For PCA9665, use the frequency you want here. */  	unsigned int			i2c_clock; +	unsigned int			chip;  };  int i2c_pca_add_bus(struct i2c_adapter *); diff --git a/include/linux/i2c-omap.h b/include/linux/i2c-omap.h index 92a0dc75bc7..df804ba73e0 100644 --- a/include/linux/i2c-omap.h +++ b/include/linux/i2c-omap.h @@ -34,7 +34,6 @@ struct omap_i2c_bus_platform_data {  	u32		clkrate;  	u32		rev;  	u32		flags; -	void		(*set_mpu_wkup_lat)(struct device *dev, long set);  };  #endif diff --git a/include/linux/i2c/i2c-rcar.h b/include/linux/i2c/i2c-rcar.h new file mode 100644 index 00000000000..496f5c2b23c --- /dev/null +++ b/include/linux/i2c/i2c-rcar.h @@ -0,0 +1,10 @@ +#ifndef __I2C_R_CAR_H__ +#define __I2C_R_CAR_H__ + +#include <linux/platform_device.h> + +struct i2c_rcar_platform_data { +	u32 bus_speed; +}; + +#endif /* __I2C_R_CAR_H__ */ diff --git a/include/linux/platform_data/i2c-nomadik.h b/include/linux/platform_data/i2c-nomadik.h index c2303c3e480..3a8be9cdc95 100644 --- a/include/linux/platform_data/i2c-nomadik.h +++ b/include/linux/platform_data/i2c-nomadik.h @@ -28,7 +28,7 @@ enum i2c_freq_mode {   * @sm:		speed mode   */  struct nmk_i2c_controller { -	unsigned long	clk_freq; +	u32             clk_freq;  	unsigned short	slsu;  	unsigned char	tft;  	unsigned char	rft;  |