From 92d9b6c5d01e1a5eb7a27feb554f546db7cb7de6 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 17 Jun 2015 10:59:04 +0200 Subject: [PATCH 001/381] ARM: at91/dt: trivial: fix USB udc compatible string To please checkpatch and the tiresome reader, add the "atmel," prefix to the USB udc compatible string. Signed-off-by: Nicolas Ferre Cc: #4.0+ Signed-off-by: Kevin Hilman --- Documentation/devicetree/bindings/usb/atmel-usb.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/usb/atmel-usb.txt b/Documentation/devicetree/bindings/usb/atmel-usb.txt index 1be8d7a26c15ff..5883b73ea1b560 100644 --- a/Documentation/devicetree/bindings/usb/atmel-usb.txt +++ b/Documentation/devicetree/bindings/usb/atmel-usb.txt @@ -79,9 +79,9 @@ Atmel High-Speed USB device controller Required properties: - compatible: Should be one of the following - "at91sam9rl-udc" - "at91sam9g45-udc" - "sama5d3-udc" + "atmel,at91sam9rl-udc" + "atmel,at91sam9g45-udc" + "atmel,sama5d3-udc" - reg: Address and length of the register set for the device - interrupts: Should contain usba interrupt - clocks: Should reference the peripheral and host clocks From cd5b5718047b650df0c4aa0f643ce0a1ccc01f40 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 17 Jun 2015 10:59:05 +0200 Subject: [PATCH 002/381] ARM: at91/dt: update udc compatible strings at91sam9g45, at91sam9x5 and sama5 SoCs should not use "atmel,at91sam9rl-udc" for their USB device compatible property since this compatible is attached to a specific hardware bug fix. Signed-off-by: Boris Brezillon Acked-by: Alexandre Belloni Tested-by: Bo Shen Acked-by: Nicolas Ferre Cc: #4.0+ Signed-off-by: Kevin Hilman --- arch/arm/boot/dts/at91sam9g45.dtsi | 2 +- arch/arm/boot/dts/at91sam9x5.dtsi | 2 +- arch/arm/boot/dts/sama5d3.dtsi | 2 +- arch/arm/boot/dts/sama5d4.dtsi | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index d260ba779ae53c..18177f5a746420 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -1148,7 +1148,7 @@ usb2: gadget@fff78000 { #address-cells = <1>; #size-cells = <0>; - compatible = "atmel,at91sam9rl-udc"; + compatible = "atmel,at91sam9g45-udc"; reg = <0x00600000 0x80000 0xfff78000 0x400>; interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 7521bdf17ef25a..b6c8df8d380ea4 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -1108,7 +1108,7 @@ usb2: gadget@f803c000 { #address-cells = <1>; #size-cells = <0>; - compatible = "atmel,at91sam9rl-udc"; + compatible = "atmel,at91sam9g45-udc"; reg = <0x00500000 0x80000 0xf803c000 0x400>; interrupts = <23 IRQ_TYPE_LEVEL_HIGH 0>; diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 5ab7548e04e1f4..9e2444b07bceee 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -1321,7 +1321,7 @@ usb0: gadget@00500000 { #address-cells = <1>; #size-cells = <0>; - compatible = "atmel,at91sam9rl-udc"; + compatible = "atmel,sama5d3-udc"; reg = <0x00500000 0x100000 0xf8030000 0x4000>; interrupts = <33 IRQ_TYPE_LEVEL_HIGH 2>; diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index bafdb3af19aa18..6a1762288c3432 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -127,7 +127,7 @@ usb0: gadget@00400000 { #address-cells = <1>; #size-cells = <0>; - compatible = "atmel,at91sam9rl-udc"; + compatible = "atmel,sama5d3-udc"; reg = <0x00400000 0x100000 0xfc02c000 0x4000>; interrupts = <47 IRQ_TYPE_LEVEL_HIGH 2>; From 568895dd0ccfdb6fd643fd3a3b03e7638e5619a9 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Mon, 8 Jun 2015 15:55:48 +0200 Subject: [PATCH 003/381] ARM: at91/dt: sama5d4: fix dma conf for aes, sha and tdes nodes The xdmac channel configuration is done in one cell not two. This error prevents from probing devices correctly. Signed-off-by: Ludovic Desroches Fixes: 83906783b766 ("ARM: at91/dt: sama5d4: add aes, sha and tdes nodes") Cc: stable@vger.kernel.org # 4.1 Acked-by: Nicolas Ferre Signed-off-by: Kevin Hilman --- arch/arm/boot/dts/sama5d4.dtsi | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 6a1762288c3432..3ee22ee13c5a89 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1240,10 +1240,10 @@ compatible = "atmel,at91sam9g46-aes"; reg = <0xfc044000 0x100>; interrupts = <12 IRQ_TYPE_LEVEL_HIGH 0>; - dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(41)>, - <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(40)>; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(41))>, + <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(40))>; dma-names = "tx", "rx"; clocks = <&aes_clk>; clock-names = "aes_clk"; @@ -1254,10 +1254,10 @@ compatible = "atmel,at91sam9g46-tdes"; reg = <0xfc04c000 0x100>; interrupts = <14 IRQ_TYPE_LEVEL_HIGH 0>; - dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(42)>, - <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(43)>; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(42))>, + <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(43))>; dma-names = "tx", "rx"; clocks = <&tdes_clk>; clock-names = "tdes_clk"; @@ -1268,8 +1268,8 @@ compatible = "atmel,at91sam9g46-sha"; reg = <0xfc050000 0x100>; interrupts = <15 IRQ_TYPE_LEVEL_HIGH 0>; - dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(44)>; + dmas = <&dma0 (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(44))>; dma-names = "tx"; clocks = <&sha_clk>; clock-names = "sha_clk"; From 06ef74004fd13cb4061e140c8c1dd60bad99285a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 30 Jul 2015 19:12:12 +0200 Subject: [PATCH 004/381] ARM: at91/soc: add basic support for new sama5d2 SoC Add Kconfig entries, header file changes and addition to the documentation. The early debug infrastructure is also added for easy development. Signed-off-by: Ludovic Desroches Signed-off-by: Nicolas Ferre Acked-by: Alexandre Belloni Signed-off-by: Olof Johansson --- Documentation/arm/Atmel/README | 5 +++++ Documentation/devicetree/bindings/arm/atmel-at91.txt | 2 ++ arch/arm/Kconfig.debug | 6 ++++++ arch/arm/include/debug/at91.S | 5 ++++- arch/arm/mach-at91/Kconfig | 12 ++++++++++++ arch/arm/mach-at91/sama5.c | 3 +++ arch/arm/mach-at91/soc.h | 3 +++ 7 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/arm/Atmel/README b/Documentation/arm/Atmel/README index c53a19b4aab2e2..0931cf7e2e56cb 100644 --- a/Documentation/arm/Atmel/README +++ b/Documentation/arm/Atmel/README @@ -90,6 +90,11 @@ the Atmel website: http://www.atmel.com. + Datasheet http://www.atmel.com/Images/Atmel-11238-32-bit-Cortex-A5-Microcontroller-SAMA5D4_Datasheet.pdf + - sama5d2 family + - sama5d27 + + Datasheet + Coming soon + Linux kernel information ------------------------ diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 424ac8cbfa0828..7f04b8ae4ca97e 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -27,6 +27,8 @@ compatible: must be one of: o "atmel,at91sam9xe" * "atmel,sama5" for SoCs using a Cortex-A5, shall be extended with the specific SoC family: + o "atmel,sama5d2" shall be extended with the specific SoC compatible: + - "atmel,sama5d27" o "atmel,sama5d3" shall be extended with the specific SoC compatible: - "atmel,sama5d31" - "atmel,sama5d33" diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug index 0c12ffb155a23c..5a65f30bcd30a5 100644 --- a/arch/arm/Kconfig.debug +++ b/arch/arm/Kconfig.debug @@ -140,6 +140,12 @@ choice depends on ARCH_AT91 depends on SOC_SAMA5 + config AT91_DEBUG_LL_DBGU3 + bool "Kernel low-level debugging on sama5d2" + select DEBUG_AT91_UART + depends on ARCH_AT91 + depends on SOC_SAMA5 + config DEBUG_BCM2835 bool "Kernel low-level debugging on BCM2835 PL011 UART" depends on ARCH_BCM2835 diff --git a/arch/arm/include/debug/at91.S b/arch/arm/include/debug/at91.S index c3c45e628e33bb..2556a8801c8cb9 100644 --- a/arch/arm/include/debug/at91.S +++ b/arch/arm/include/debug/at91.S @@ -13,9 +13,12 @@ #define AT91_DBGU 0xfffff200 /* AT91_BASE_DBGU0 */ #elif defined(CONFIG_AT91_DEBUG_LL_DBGU1) #define AT91_DBGU 0xffffee00 /* AT91_BASE_DBGU1 */ -#else +#elif defined(CONFIG_AT91_DEBUG_LL_DBGU2) /* On sama5d4, use USART3 as low level serial console */ #define AT91_DBGU 0xfc00c000 /* SAMA5D4_BASE_USART3 */ +#else +/* On sama5d2, use UART1 as low level serial console */ +#define AT91_DBGU 0xf8020000 #endif #ifdef CONFIG_MMU diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index fd95f34945f482..89a755b90db224 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -8,6 +8,18 @@ menuconfig ARCH_AT91 select SOC_BUS if ARCH_AT91 +config SOC_SAMA5D2 + bool "SAMA5D2 family" if ARCH_MULTI_V7 + select SOC_SAMA5 + select CACHE_L2X0 + select HAVE_FB_ATMEL + select HAVE_AT91_UTMI + select HAVE_AT91_USB_CLK + select HAVE_AT91_H32MX + select HAVE_AT91_GENERATED_CLK + help + Select this if ou are using one of Atmel's SAMA5D2 family SoC. + config SOC_SAMA5D3 bool "SAMA5D3 family" if ARCH_MULTI_V7 select SOC_SAMA5 diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index 41d829d8e7d510..90c3c3051ae752 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c @@ -18,6 +18,8 @@ #include "soc.h" static const struct at91_soc sama5_socs[] = { + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27_EXID_MATCH, + "sama5d27", "sama5d2"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, "sama5d31", "sama5d3"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, @@ -64,6 +66,7 @@ DT_MACHINE_START(sama5_dt, "Atmel SAMA5") MACHINE_END static const char *sama5_alt_dt_board_compat[] __initconst = { + "atmel,sama5d2", "atmel,sama5d4", NULL }; diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h index be23c400596b4e..8ede0ef86172a6 100644 --- a/arch/arm/mach-at91/soc.h +++ b/arch/arm/mach-at91/soc.h @@ -62,6 +62,9 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9XE256_CIDR_MATCH 0x329a93a0 #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0 +#define SAMA5D2_CIDR_MATCH 0x0a5c08c0 +#define SAMA5D27_EXID_MATCH 0x00000021 + #define SAMA5D3_CIDR_MATCH 0x0a5c07c0 #define SAMA5D31_EXID_MATCH 0x00444300 #define SAMA5D33_EXID_MATCH 0x00414300 From 2875a34ac9dab29862042dfe51d7b302296b2252 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 22 Jun 2015 09:45:47 +0200 Subject: [PATCH 005/381] ARM: at91/dt: sama5d4: fix external trigger property The property is actually atmel,adc-use-external-triggers. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d4.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 3ee22ee13c5a89..3e27e8a282839a 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1207,7 +1207,7 @@ clock-names = "adc_clk", "adc_op_clk"; atmel,adc-channels-used = <0x01f>; atmel,adc-startup-time = <40>; - atmel,adc-use-external; + atmel,adc-use-external-triggers; atmel,adc-vref = <3000>; atmel,adc-res = <8 10>; atmel,adc-sample-hold-time = <11>; From fb3aba19ea007afd8d7131db285c3000bca7b11b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 22 Jun 2015 09:45:48 +0200 Subject: [PATCH 006/381] ARM: at91/dt: sama5d4: move ADC pinctrl to board device trees The ADC pinctrl is board specific, move it to the board device trees. Signed-off-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d4_xplained.dts | 9 +++++++++ arch/arm/boot/dts/at91-sama5d4ek.dts | 9 +++++++++ arch/arm/boot/dts/sama5d4.dtsi | 9 --------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index 22ad7c95910363..07f46963335bb6 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -131,6 +131,15 @@ }; adc0: adc@fc034000 { + pinctrl-names = "default"; + pinctrl-0 = < + /* external trigger conflicts with USBA_VBUS */ + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + >; atmel,adc-vref = <3300>; status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index d782f2926b7392..49a59c7e4a5d1e 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -100,6 +100,15 @@ }; adc0: adc@fc034000 { + pinctrl-names = "default"; + pinctrl-0 = < + /* external trigger conflicts with USBA_VBUS */ + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + >; /* The vref depends on JP22 of EK. If connect 1-2 then use 3.3V. connect 2-3 use 3.0V */ atmel,adc-vref = <3300>; /*atmel,adc-ts-wires = <4>;*/ /* Set up ADC touch screen */ diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 3e27e8a282839a..261b6acb765563 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1193,15 +1193,6 @@ compatible = "atmel,at91sam9x5-adc"; reg = <0xfc034000 0x100>; interrupts = <44 IRQ_TYPE_LEVEL_HIGH 5>; - pinctrl-names = "default"; - pinctrl-0 = < - /* external trigger is conflict with USBA_VBUS */ - &pinctrl_adc0_ad0 - &pinctrl_adc0_ad1 - &pinctrl_adc0_ad2 - &pinctrl_adc0_ad3 - &pinctrl_adc0_ad4 - >; clocks = <&adc_clk>, <&adc_op_clk>; clock-names = "adc_clk", "adc_op_clk"; From 6b94e7f1b5a82bf68a15c7bfe8bfb603af6f2a51 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 16 Jun 2015 18:08:34 +0800 Subject: [PATCH 007/381] ARM: at91/dt: add isi & ov2640 dt nodes for at91sam9m10g45ek board First we group the isi data pins, and for now we only use 0~7 data pins with HSYNC and VSYNC. Also add the link for atmel-isi and ov2640 sensor node. Signed-off-by: Josh Wu [nicolas.ferre@atmel.com: move the pinctrl properties in board .dts file] Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9g45.dtsi | 48 ++++++++++++++++---------- arch/arm/boot/dts/at91sam9m10g45ek.dts | 47 +++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 18177f5a746420..4268341b0ebba2 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -498,23 +498,31 @@ }; isi { - pinctrl_isi: isi-0 { - atmel,pins = ; + pinctrl_isi_data_0_7: isi-0-data-0-7 { + atmel,pins = + ; /* HSYNC */ + }; + + pinctrl_isi_data_8_9: isi-0-data-8-9 { + atmel,pins = + ; /* D9 */ + }; + + pinctrl_isi_data_10_11: isi-0-data-10-11 { + atmel,pins = + ; /* D11 */ }; }; @@ -1067,9 +1075,11 @@ interrupts = <26 IRQ_TYPE_LEVEL_HIGH 5>; clocks = <&isi_clk>; clock-names = "isi_clk"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_isi>; status = "disabled"; + port { + #address-cells = <1>; + #size-cells = <0>; + }; }; pwm0: pwm@fffb8000 { diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index 1375d33626031d..d1ae60a855d492 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -63,6 +63,25 @@ i2c0: i2c@fff84000 { status = "okay"; + ov2640: camera@30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck1_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioD 12 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioD 13 GPIO_ACTIVE_HIGH>; + clocks = <&pck1>; + clock-names = "xvclk"; + assigned-clocks = <&pck1>; + assigned-clock-rates = <25000000>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isi_0>; + bus-width = <8>; + }; + }; + }; }; i2c1: i2c@fff88000 { @@ -101,6 +120,22 @@ }; pinctrl@fffff200 { + camera_sensor { + pinctrl_pck1_as_isi_mck: pck1_as_isi_mck-0 { + atmel,pins = + ; + }; + + pinctrl_sensor_reset: sensor_reset-0 { + atmel,pins = + ; + }; + + pinctrl_sensor_power: sensor_power-0 { + atmel,pins = + ; + }; + }; mmc0 { pinctrl_board_mmc0: mmc0-board { atmel,pins = @@ -155,6 +190,18 @@ status = "okay"; }; + isi@fffb4000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_isi_data_0_7>; + status = "okay"; + port { + isi_0: endpoint { + remote-endpoint = <&ov2640_0>; + bus-width = <8>; + }; + }; + }; + pwm0: pwm@fffb8000 { status = "okay"; From 6c03ea8840fff4d4f7c345b8a549f21e16259be9 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 20 Jul 2015 17:32:06 +0800 Subject: [PATCH 008/381] ARM: at91/dt: sama5: update rstc to correct compatible string They'll use "atmel,sama5d3-rstc" for reset function. Signed-off-by: Josh Wu Acked-by: Alexandre Belloni [nicolas.ferre@atmel.com: add the old compatible string as a fallback] Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d3.dtsi | 2 +- arch/arm/boot/dts/sama5d4.dtsi | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 9e2444b07bceee..81ced62cedafdd 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -1259,7 +1259,7 @@ }; rstc@fffffe00 { - compatible = "atmel,at91sam9g45-rstc"; + compatible = "atmel,sama5d3-rstc", "atmel,at91sam9g45-rstc"; reg = <0xfffffe00 0x10>; }; diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 261b6acb765563..1fa8b3611a03db 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1268,7 +1268,7 @@ }; rstc@fc068600 { - compatible = "atmel,at91sam9g45-rstc"; + compatible = "atmel,sama5d3-rstc", "atmel,at91sam9g45-rstc"; reg = <0xfc068600 0x10>; }; From cd17a9e4a6b641827ad30ecb378d2738f38a4dd9 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 18 Jun 2015 14:48:28 +0200 Subject: [PATCH 009/381] ARM: at91/dt: add basic dtsi for sama5d2 SoC Only the basic support for this new Atmel Cortex-A5 SoC. A subset of the peripherals is setup to allow booting. IRQ, clocks, USB, crypto, timers, rtc, ethernet, spi/i2c and uart/usart peripheral nodes are added. Signed-off-by: Ludovic Desroches Acked-by: Alexandre Belloni Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 925 +++++++++++++++++++++++++++++++++ 1 file changed, 925 insertions(+) create mode 100644 arch/arm/boot/dts/sama5d2.dtsi diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi new file mode 100644 index 00000000000000..f39258fa381597 --- /dev/null +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -0,0 +1,925 @@ +/* + * sama5d2.dtsi - Device Tree Include file for SAMA5D2 family SoC + * + * Copyright (C) 2015 Atmel, + * 2015 Ludovic Desroches + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "skeleton.dtsi" +#include +#include +#include + +/ { + model = "Atmel SAMA5D2 family SoC"; + compatible = "atmel,sama5d2"; + interrupt-parent = <&aic>; + + aliases { + serial0 = &uart1; + serial1 = &uart3; + tcb0 = &tcb0; + tcb1 = &tcb1; + }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a5"; + reg = <0>; + next-level-cache = <&L2>; + }; + }; + + memory { + reg = <0x20000000 0x20000000>; + }; + + clocks { + slow_xtal: slow_xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + main_xtal: main_xtal { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <0>; + }; + + adc_op_clk: adc_op_clk{ + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <1000000>; + }; + }; + + ns_sram: sram@00200000 { + compatible = "mmio-sram"; + reg = <0x00200000 0x20000>; + }; + + ahb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + usb0: gadget@00300000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "atmel,sama5d3-udc"; + reg = <0x00300000 0x100000 + 0xfc02c000 0x400>; + interrupts = <42 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&udphs_clk>, <&utmi>; + clock-names = "pclk", "hclk"; + status = "disabled"; + + ep0 { + reg = <0>; + atmel,fifo-size = <64>; + atmel,nb-banks = <1>; + }; + + ep1 { + reg = <1>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep2 { + reg = <2>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <3>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep3 { + reg = <3>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep4 { + reg = <4>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep5 { + reg = <5>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep6 { + reg = <6>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep7 { + reg = <7>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-dma; + atmel,can-isoc; + }; + + ep8 { + reg = <8>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep9 { + reg = <9>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep10 { + reg = <10>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep11 { + reg = <11>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep12 { + reg = <12>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep13 { + reg = <13>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep14 { + reg = <14>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + + ep15 { + reg = <15>; + atmel,fifo-size = <1024>; + atmel,nb-banks = <2>; + atmel,can-isoc; + }; + }; + + usb1: ohci@00400000 { + compatible = "atmel,at91rm9200-ohci", "usb-ohci"; + reg = <0x00400000 0x100000>; + interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&uhphs_clk>, <&uhphs_clk>, <&uhpck>; + clock-names = "ohci_clk", "hclk", "uhpck"; + status = "disabled"; + }; + + usb2: ehci@00500000 { + compatible = "atmel,at91sam9g45-ehci", "usb-ehci"; + reg = <0x00500000 0x100000>; + interrupts = <41 IRQ_TYPE_LEVEL_HIGH 2>; + clocks = <&utmi>, <&uhphs_clk>; + clock-names = "usb_clk", "ehci_clk"; + status = "disabled"; + }; + + L2: cache-controller@00a00000 { + compatible = "arm,pl310-cache"; + reg = <0x00a00000 0x1000>; + interrupts = <63 IRQ_TYPE_LEVEL_HIGH 4>; + cache-unified; + cache-level = <2>; + }; + + apb { + compatible = "simple-bus"; + #address-cells = <1>; + #size-cells = <1>; + ranges; + + ramc0: ramc@f000c000 { + compatible = "atmel,sama5d3-ddramc"; + reg = <0xf000c000 0x200>; + clocks = <&ddrck>, <&mpddr_clk>; + clock-names = "ddrck", "mpddr"; + }; + + dma0: dma-controller@f0010000 { + compatible = "atmel,sama5d4-dma"; + reg = <0xf0010000 0x1000>; + interrupts = <6 IRQ_TYPE_LEVEL_HIGH 0>; + #dma-cells = <1>; + clocks = <&dma0_clk>; + clock-names = "dma_clk"; + }; + + pmc: pmc@f0014000 { + compatible = "atmel,sama5d2-pmc"; + reg = <0xf0014000 0x160>; + interrupts = <74 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #address-cells = <1>; + #size-cells = <0>; + #interrupt-cells = <1>; + + main_rc_osc: main_rc_osc { + compatible = "atmel,at91sam9x5-clk-main-rc-osc"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clock-frequency = <12000000>; + clock-accuracy = <100000000>; + }; + + main_osc: main_osc { + compatible = "atmel,at91rm9200-clk-main-osc"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clocks = <&main_xtal>; + }; + + main: mainck { + compatible = "atmel,at91sam9x5-clk-main"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clocks = <&main_rc_osc &main_osc>; + }; + + plla: pllack { + compatible = "atmel,sama5d3-clk-pll"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clocks = <&main>; + reg = <0>; + atmel,clk-input-range = <12000000 12000000>; + #atmel,pll-clk-output-range-cells = <4>; + atmel,pll-clk-output-ranges = <600000000 1200000000 0 0>; + }; + + plladiv: plladivck { + compatible = "atmel,at91sam9x5-clk-plldiv"; + #clock-cells = <0>; + clocks = <&plla>; + }; + + utmi: utmick { + compatible = "atmel,at91sam9x5-clk-utmi"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clocks = <&main>; + }; + + mck: masterck { + compatible = "atmel,at91sam9x5-clk-master"; + #clock-cells = <0>; + interrupt-parent = <&pmc>; + interrupts = ; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>; + atmel,clk-output-range = <124000000 166000000>; + atmel,clk-divisors = <1 2 4 3>; + }; + + h32ck: h32mxck { + #clock-cells = <0>; + compatible = "atmel,sama5d4-clk-h32mx"; + clocks = <&mck>; + }; + + usb: usbck { + compatible = "atmel,at91sam9x5-clk-usb"; + #clock-cells = <0>; + clocks = <&plladiv>, <&utmi>; + }; + + prog: progck { + compatible = "atmel,at91sam9x5-clk-programmable"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + + prog0: prog0 { + #clock-cells = <0>; + reg = <0>; + interrupts = ; + }; + + prog1: prog1 { + #clock-cells = <0>; + reg = <1>; + interrupts = ; + }; + + prog2: prog2 { + #clock-cells = <0>; + reg = <2>; + interrupts = ; + }; + }; + + systemck { + compatible = "atmel,at91rm9200-clk-system"; + #address-cells = <1>; + #size-cells = <0>; + + ddrck: ddrck { + #clock-cells = <0>; + reg = <2>; + clocks = <&mck>; + }; + + lcdck: lcdck { + #clock-cells = <0>; + reg = <3>; + clocks = <&mck>; + }; + + uhpck: uhpck { + #clock-cells = <0>; + reg = <6>; + clocks = <&usb>; + }; + + udpck: udpck { + #clock-cells = <0>; + reg = <7>; + clocks = <&usb>; + }; + + pck0: pck0 { + #clock-cells = <0>; + reg = <8>; + clocks = <&prog0>; + }; + + pck1: pck1 { + #clock-cells = <0>; + reg = <9>; + clocks = <&prog1>; + }; + + pck2: pck2 { + #clock-cells = <0>; + reg = <10>; + clocks = <&prog2>; + }; + + iscck: iscck { + #clock-cells = <0>; + reg = <18>; + clocks = <&mck>; + }; + }; + + periph32ck { + compatible = "atmel,at91sam9x5-clk-peripheral"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&h32ck>; + + macb0_clk: macb0_clk { + #clock-cells = <0>; + reg = <5>; + atmel,clk-output-range = <0 83000000>; + }; + + tdes_clk: tdes_clk { + #clock-cells = <0>; + reg = <11>; + atmel,clk-output-range = <0 83000000>; + }; + + matrix1_clk: matrix1_clk { + #clock-cells = <0>; + reg = <14>; + }; + + hsmc_clk: hsmc_clk { + #clock-cells = <0>; + reg = <17>; + }; + + pioA_clk: pioA_clk { + #clock-cells = <0>; + reg = <18>; + atmel,clk-output-range = <0 83000000>; + }; + + flx0_clk: flx0_clk { + #clock-cells = <0>; + reg = <19>; + atmel,clk-output-range = <0 83000000>; + }; + + flx1_clk: flx1_clk { + #clock-cells = <0>; + reg = <20>; + atmel,clk-output-range = <0 83000000>; + }; + + flx2_clk: flx2_clk { + #clock-cells = <0>; + reg = <21>; + atmel,clk-output-range = <0 83000000>; + }; + + flx3_clk: flx3_clk { + #clock-cells = <0>; + reg = <22>; + atmel,clk-output-range = <0 83000000>; + }; + + flx4_clk: flx4_clk { + #clock-cells = <0>; + reg = <23>; + atmel,clk-output-range = <0 83000000>; + }; + + uart0_clk: uart0_clk { + #clock-cells = <0>; + reg = <24>; + atmel,clk-output-range = <0 83000000>; + }; + + uart1_clk: uart1_clk { + #clock-cells = <0>; + reg = <25>; + atmel,clk-output-range = <0 83000000>; + }; + + uart2_clk: uart2_clk { + #clock-cells = <0>; + reg = <26>; + atmel,clk-output-range = <0 83000000>; + }; + + uart3_clk: uart3_clk { + #clock-cells = <0>; + reg = <27>; + atmel,clk-output-range = <0 83000000>; + }; + + uart4_clk: uart4_clk { + #clock-cells = <0>; + reg = <28>; + atmel,clk-output-range = <0 83000000>; + }; + + twi0_clk: twi0_clk { + reg = <29>; + #clock-cells = <0>; + atmel,clk-output-range = <0 83000000>; + }; + + twi1_clk: twi1_clk { + #clock-cells = <0>; + reg = <30>; + atmel,clk-output-range = <0 83000000>; + }; + + spi0_clk: spi0_clk { + #clock-cells = <0>; + reg = <33>; + atmel,clk-output-range = <0 83000000>; + }; + + spi1_clk: spi1_clk { + #clock-cells = <0>; + reg = <34>; + atmel,clk-output-range = <0 83000000>; + }; + + tcb0_clk: tcb0_clk { + #clock-cells = <0>; + reg = <35>; + atmel,clk-output-range = <0 83000000>; + }; + + tcb1_clk: tcb1_clk { + #clock-cells = <0>; + reg = <36>; + atmel,clk-output-range = <0 83000000>; + }; + + pwm_clk: pwm_clk { + #clock-cells = <0>; + reg = <38>; + atmel,clk-output-range = <0 83000000>; + }; + + adc_clk: adc_clk { + #clock-cells = <0>; + reg = <40>; + atmel,clk-output-range = <0 83000000>; + }; + + uhphs_clk: uhphs_clk { + #clock-cells = <0>; + reg = <41>; + atmel,clk-output-range = <0 83000000>; + }; + + udphs_clk: udphs_clk { + #clock-cells = <0>; + reg = <42>; + atmel,clk-output-range = <0 83000000>; + }; + + ssc0_clk: ssc0_clk { + #clock-cells = <0>; + reg = <43>; + atmel,clk-output-range = <0 83000000>; + }; + + ssc1_clk: ssc1_clk { + #clock-cells = <0>; + reg = <44>; + atmel,clk-output-range = <0 83000000>; + }; + + trng_clk: trng_clk { + #clock-cells = <0>; + reg = <47>; + atmel,clk-output-range = <0 83000000>; + }; + + classd_clk: classd_clk { + #clock-cells = <0>; + reg = <59>; + atmel,clk-output-range = <0 83000000>; + }; + }; + + periph64ck { + compatible = "atmel,at91sam9x5-clk-peripheral"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mck>; + + dma0_clk: dma0_clk { + #clock-cells = <0>; + reg = <6>; + }; + + dma1_clk: dma1_clk { + #clock-cells = <0>; + reg = <7>; + }; + + aes_clk: aes_clk { + #clock-cells = <0>; + reg = <9>; + }; + + aesb_clk: aesb_clk { + #clock-cells = <0>; + reg = <10>; + }; + + sha_clk: sha_clk { + #clock-cells = <0>; + reg = <12>; + }; + + mpddr_clk: mpddr_clk { + #clock-cells = <0>; + reg = <13>; + }; + + matrix0_clk: matrix0_clk { + #clock-cells = <0>; + reg = <15>; + }; + + sdmmc0_hclk: sdmmc0_hclk { + #clock-cells = <0>; + reg = <31>; + }; + + sdmmc1_hclk: sdmmc1_hclk { + #clock-cells = <0>; + reg = <32>; + }; + + lcdc_clk: lcdc_clk { + #clock-cells = <0>; + reg = <45>; + }; + + isc_clk: isc_clk { + #clock-cells = <0>; + reg = <46>; + }; + + qspi0_clk: qspi0_clk { + #clock-cells = <0>; + reg = <52>; + }; + + qspi1_clk: qspi1_clk { + #clock-cells = <0>; + reg = <53>; + }; + }; + }; + + sha@f0028000 { + compatible = "atmel,at91sam9g46-sha"; + reg = <0xf0028000 0x100>; + interrupts = <12 IRQ_TYPE_LEVEL_HIGH 0>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(30))>; + dma-names = "tx"; + clocks = <&sha_clk>; + clock-names = "sha_clk"; + status = "disabled"; + }; + + aes@f002c000 { + compatible = "atmel,at91sam9g46-aes"; + reg = <0xf002c000 0x100>; + interrupts = <9 IRQ_TYPE_LEVEL_HIGH 0>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(26))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(27))>; + dma-names = "tx", "rx"; + clocks = <&aes_clk>; + clock-names = "aes_clk"; + status = "disabled"; + }; + + spi0: spi@f8000000 { + compatible = "atmel,at91rm9200-spi"; + reg = <0xf8000000 0x100>; + interrupts = <33 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(6))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(7))>; + dma-names = "tx", "rx"; + clocks = <&spi0_clk>; + clock-names = "spi_clk"; + atmel,fifo-size = <16>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + macb0: ethernet@f8008000 { + compatible = "atmel,sama5d2-gem"; + reg = <0xf8008000 0x1000>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH 3 /* Queue 0 */ + 66 IRQ_TYPE_LEVEL_HIGH 3 /* Queue 1 */ + 67 IRQ_TYPE_LEVEL_HIGH 3>; /* Queue 2 */ + #address-cells = <1>; + #size-cells = <0>; + clocks = <&macb0_clk>, <&macb0_clk>; + clock-names = "hclk", "pclk"; + status = "disabled"; + }; + + tcb0: timer@f800c000 { + compatible = "atmel,at91sam9x5-tcb"; + reg = <0xf800c000 0x100>; + interrupts = <35 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tcb0_clk>; + clock-names = "t0_clk"; + }; + + tcb1: timer@f8010000 { + compatible = "atmel,at91sam9x5-tcb"; + reg = <0xf8010000 0x100>; + interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&tcb1_clk>; + clock-names = "t0_clk"; + }; + + uart0: serial@f801c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf801c000 0x100>; + interrupts = <24 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&uart0_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + uart1: serial@f8020000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8020000 0x100>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&uart1_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + uart2: serial@f8024000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8024000 0x100>; + interrupts = <26 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&uart2_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + i2c0: i2c@f8028000 { + compatible = "atmel,sama5d2-i2c"; + reg = <0xf8028000 0x100>; + interrupts = <29 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(0))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(1))>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&twi0_clk>; + status = "disabled"; + }; + + pit: timer@f8048030 { + compatible = "atmel,at91sam9260-pit"; + reg = <0xf8048030 0x10>; + interrupts = <3 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&h32ck>; + }; + + sckc@f8048050 { + compatible = "atmel,at91sam9x5-sckc"; + reg = <0xf8048050 0x4>; + + slow_rc_osc: slow_rc_osc { + compatible = "atmel,at91sam9x5-clk-slow-rc-osc"; + #clock-cells = <0>; + clock-frequency = <32768>; + clock-accuracy = <250000000>; + atmel,startup-time-usec = <75>; + }; + + slow_osc: slow_osc { + compatible = "atmel,at91sam9x5-clk-slow-osc"; + #clock-cells = <0>; + clocks = <&slow_xtal>; + atmel,startup-time-usec = <1200000>; + }; + + clk32k: slowck { + compatible = "atmel,at91sam9x5-clk-slow"; + #clock-cells = <0>; + clocks = <&slow_rc_osc &slow_osc>; + }; + }; + + rtc@f80480b0 { + compatible = "atmel,at91rm9200-rtc"; + reg = <0xf80480b0 0x30>; + interrupts = <74 IRQ_TYPE_LEVEL_HIGH 7>; + }; + + spi1: spi@fc000000 { + compatible = "atmel,at91rm9200-spi"; + reg = <0xfc000000 0x100>; + interrupts = <34 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(8))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(9))>; + dma-names = "tx", "rx"; + clocks = <&spi1_clk>; + clock-names = "spi_clk"; + atmel,fifo-size = <16>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + uart3: serial@fc008000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfc008000 0x100>; + interrupts = <27 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&uart3_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + uart4: serial@fc00c000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xfc00c000 0x100>; + interrupts = <28 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&uart4_clk>; + clock-names = "usart"; + status = "disabled"; + }; + + aic: interrupt-controller@fc020000 { + #interrupt-cells = <3>; + compatible = "atmel,sama5d2-aic"; + interrupt-controller; + reg = <0xfc020000 0x200>; + atmel,external-irqs = <49>; + }; + + i2c1: i2c@fc028000 { + compatible = "atmel,sama5d2-i2c"; + reg = <0xfc028000 0x100>; + interrupts = <30 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(2))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(3))>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&twi1_clk>; + status = "disabled"; + }; + }; + }; +}; From 196bfcd9c8279ca3e38c301442a1f46aa1ee44f6 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 18 Jun 2015 14:55:03 +0200 Subject: [PATCH 010/381] ARM: at91/dt: add minimal sama5d2 Xplained board Add minimal support for the new sama5d2 Xplained board. Only USB, spi/i2c, ethernet and uart/usart peripherals added. With this DTS file you can boot the board and begin to play with it. Rootfs on NFS and sd card have successfully been tested. Signed-off-by: Nicolas Ferre Acked-by: Alexandre Belloni --- arch/arm/boot/dts/Makefile | 1 + arch/arm/boot/dts/at91-sama5d2_xplained.dts | 134 ++++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 arch/arm/boot/dts/at91-sama5d2_xplained.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 6f0ed4ce64ad82..a2c3853a26bc40 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -41,6 +41,7 @@ dtb-$(CONFIG_SOC_SAM_V4_V5) += \ at91sam9x35ek.dtb dtb-$(CONFIG_SOC_SAM_V7) += \ at91-kizbox2.dtb \ + at91-sama5d2_xplained.dtb \ at91-sama5d3_xplained.dtb \ sama5d31ek.dtb \ sama5d33ek.dtb \ diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts new file mode 100644 index 00000000000000..e8d63afdb135f1 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -0,0 +1,134 @@ +/* + * at91-sama5d2_xplained.dts - Device Tree file for SAMA5D2 Xplained board + * + * Copyright (C) 2015 Atmel, + * 2015 Nicolas Ferre + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; +#include "sama5d2.dtsi" + +/ { + model = "Atmel SAMA5D2 Xplained"; + compatible = "atmel,sama5d2-xplained", "atmel,sama5d2", "atmel,sama5"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x80000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + usb0: gadget@00300000 { + status = "okay"; + }; + + usb1: ohci@00400000 { + num-ports = <3>; + status = "okay"; + }; + + usb2: ehci@00500000 { + status = "okay"; + }; + + apb { + spi0: spi@f8000000 { + status = "okay"; + + m25p80@0 { + compatible = "atmel,at25df321a"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; + + macb0: ethernet@f8008000 { + phy-mode = "rmii"; + status = "okay"; + }; + + uart1: serial@f8020000 { + status = "okay"; + }; + + i2c0: i2c@f8028000 { + dmas = <0>, <0>; + status = "okay"; + }; + + uart3: serial@fc008000 { + status = "okay"; + }; + + i2c1: i2c@fc028000 { + dmas = <0>, <0>; + status = "okay"; + + at24@54 { + compatible = "atmel,24c02"; + reg = <0x54>; + pagesize = <16>; + }; + }; + }; + }; +}; From db7fe1c2cf989791f710fa86ddc308f71be976a8 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Thu, 30 Jul 2015 19:18:19 +0200 Subject: [PATCH 011/381] ARM: at91: at91_dt_defconfig: enable ISI and ov2640 support Add Atmel-isi and ov2640 driver in defconfig Signed-off-by: Josh Wu [nicolas.ferre@atmel.com: make SOC_CAMERA_OV2640 selected as a module] Signed-off-by: Nicolas Ferre Signed-off-by: Olof Johansson --- arch/arm/configs/at91_dt_defconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 94b5dcabdeccdd..c7abc0d77da774 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -133,6 +133,12 @@ CONFIG_AT91SAM9X_WATCHDOG=y CONFIG_SSB=m CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_VIDEO_ATMEL_ISI=y +CONFIG_SOC_CAMERA_OV2640=m CONFIG_FB=y CONFIG_FB_ATMEL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y From 1701aa6f8c812a9d7be96efeb34c026595521b2a Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 31 Jul 2015 19:26:36 +0200 Subject: [PATCH 012/381] ARM: at91/defconfig: at91_dt: enable DRM hlcdc support This patch adds drm atmel lcdc, simple panel and backlight options. Signed-off-by: Josh Wu Signed-off-by: Alexandre Belloni Signed-off-by: Olof Johansson --- arch/arm/configs/at91_dt_defconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index c7abc0d77da774..0a21ab1b1a635e 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -131,6 +131,7 @@ CONFIG_POWER_RESET=y CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y CONFIG_SSB=m +CONFIG_MFD_ATMEL_HLCDC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y CONFIG_MEDIA_SUPPORT=y @@ -139,6 +140,9 @@ CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SOC_CAMERA=y CONFIG_VIDEO_ATMEL_ISI=y CONFIG_SOC_CAMERA_OV2640=m +CONFIG_DRM=y +CONFIG_DRM_ATMEL_HLCDC=y +CONFIG_DRM_PANEL_SIMPLE=y CONFIG_FB=y CONFIG_FB_ATMEL=y CONFIG_BACKLIGHT_LCD_SUPPORT=y @@ -146,6 +150,7 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y CONFIG_BACKLIGHT_CLASS_DEVICE=y CONFIG_BACKLIGHT_ATMEL_LCDC=y # CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y CONFIG_LOGO=y @@ -192,6 +197,7 @@ CONFIG_IIO=y CONFIG_AT91_ADC=y CONFIG_PWM=y CONFIG_PWM_ATMEL=y +CONFIG_PWM_ATMEL_HLCDC_PWM=y CONFIG_PWM_ATMEL_TCB=y CONFIG_EXT4_FS=y CONFIG_FANOTIFY=y From 17bb48a282ebaac7c5672764498d4306682f122e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Jul 2015 19:30:07 +0200 Subject: [PATCH 013/381] ARM: at91/defconfig: at91_dt: remove ARM_AT91_ETHER CONFIG_ARM_AT91_ETHER doesn't exist anymore, both drivers have been merged in the macb driver. Signed-off-by: Alexandre Belloni Signed-off-by: Olof Johansson --- arch/arm/configs/at91_dt_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 0a21ab1b1a635e..090c5b25dbed59 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -73,7 +73,6 @@ CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y -CONFIG_ARM_AT91_ETHER=y CONFIG_MACB=y # CONFIG_NET_VENDOR_BROADCOM is not set CONFIG_DM9000=y From 72f976649e9bc9cce8eaa26dd393bd9c7d9fbd40 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 30 Jul 2015 01:02:36 +0200 Subject: [PATCH 014/381] Documentation: dt: atmel-at91: add clocks to system timer, rstc and shdwc The system timer (at91rm9200), the reset controller and the shutdown controller need an input clock. This is the slow clock and they will not function without it. Also fix the shutdown controller example. Acked-By: Sebastian Reichel Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 7f04b8ae4ca97e..6c10e3f56a2d40 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -52,6 +52,7 @@ System Timer (ST) required properties: - reg: Should contain registers location and length - interrupts: Should contain interrupt for the ST which is the IRQ line shared across all System Controller members. +- clocks: phandle to input clock. Its subnodes can be: - watchdog: compatible should be "atmel,at91rm9200-wdt" @@ -91,12 +92,14 @@ RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". can be "at91sam9260" or "at91sam9g45" - reg: Should contain registers location and length +- clocks: phandle to input clock. Example: rstc@fffffd00 { compatible = "atmel,at91sam9260-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; }; RAMC SDRAM/DDR Controller required properties: @@ -119,6 +122,7 @@ required properties: - compatible: Should be "atmel,-shdwc". can be "at91sam9260", "at91sam9rl" or "at91sam9x5". - reg: Should contain registers location and length +- clocks: phandle to input clock. optional properties: - atmel,wakeup-mode: String, operation mode of the wakeup mode. @@ -137,9 +141,10 @@ optional at91sam9x5 properties: Example: - rstc@fffffd00 { - compatible = "atmel,at91sam9260-rstc"; - reg = <0xfffffd00 0x10>; + shdwc@fffffd10 { + compatible = "atmel,at91sam9260-shdwc"; + reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; }; Special Function Registers (SFR) From 64bfc10b327451019f2662c6424f2eca6ca06102 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Jul 2015 02:11:14 +0200 Subject: [PATCH 015/381] Documentation: dt: atmel-at91: add slow clock to tcb The timer counters need the slow clock. It is required as they will not function without it. Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/arm/atmel-at91.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 6c10e3f56a2d40..929a7d477bd27d 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -64,7 +64,7 @@ TC/TCLIB Timer required properties: Note that you can specify several interrupt cells if the TC block has one interrupt per channel. - clock-names: tuple listing input clock names. - Required elements: "t0_clk" + Required elements: "t0_clk", "slow_clk" Optional elements: "t1_clk", "t2_clk" - clocks: phandles to input clocks. From 9b8ce57744d12211ac05578a0a09bb7bef9c9ccd Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 30 Jul 2015 00:43:07 +0200 Subject: [PATCH 016/381] Documentation: watchdog: at91sam9_wdt: add clocks property The watchdog has an input clock, the slow clock. It is required as it will not function without it. Reviewed-by: Guenter Roeck Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/watchdog/atmel-wdt.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt index a4d869744f5958..86fa6de1019bdb 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt @@ -6,6 +6,7 @@ Required properties: - compatible: must be "atmel,at91sam9260-wdt". - reg: physical base address of the controller and length of memory mapped region. +- clocks: phandle to input clock. Optional properties: - timeout-sec: contains the watchdog timeout in seconds. @@ -39,6 +40,7 @@ Example: compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; timeout-sec = <15>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; From 63be1434351d7251dee6e68c5dcaaea3a7a19b3f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 30 Jul 2015 00:49:44 +0200 Subject: [PATCH 017/381] Documentation: dt: rtc: at91rm9200: add clocks property The RTC needs an input clock, it is the slow clock. It is required as it will not function without it. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt index 34c1505774bfc4..5d3791e789c6ba 100644 --- a/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt +++ b/Documentation/devicetree/bindings/rtc/atmel,at91rm9200-rtc.txt @@ -5,6 +5,7 @@ Required properties: - reg: physical base address of the controller and length of memory mapped region. - interrupts: rtc alarm/event interrupt +- clocks: phandle to input clock. Example: @@ -12,4 +13,5 @@ rtc@fffffe00 { compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffe00 0x100>; interrupts = <1 4 7>; + clocks = <&clk32k>; }; From 7182496a325617419067935408e355fd5ad7ccf3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:09:52 +0200 Subject: [PATCH 018/381] ARM: at91/dt: at91rm9200: use slow clock where necessary The system timer, the RTC and the timer counters need the slow clock, add it. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91rm9200.dtsi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91rm9200.dtsi b/arch/arm/boot/dts/at91rm9200.dtsi index e3cfb9972f5452..60edd8baebb81a 100644 --- a/arch/arm/boot/dts/at91rm9200.dtsi +++ b/arch/arm/boot/dts/at91rm9200.dtsi @@ -359,6 +359,7 @@ compatible = "atmel,at91rm9200-st", "syscon", "simple-mfd"; reg = <0xfffffd00 0x100>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&slow_xtal>; watchdog { compatible = "atmel,at91rm9200-wdt"; @@ -369,6 +370,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffe00 0x40>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&slow_xtal>; status = "disabled"; }; @@ -378,8 +380,8 @@ interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0 18 IRQ_TYPE_LEVEL_HIGH 0 19 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>, <&slow_xtal>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; tcb1: timer@fffa4000 { @@ -388,8 +390,8 @@ interrupts = <20 IRQ_TYPE_LEVEL_HIGH 0 21 IRQ_TYPE_LEVEL_HIGH 0 22 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tc3_clk>, <&tc4_clk>, <&tc5_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tc3_clk>, <&tc4_clk>, <&tc5_clk>, <&slow_xtal>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; i2c0: i2c@fffb8000 { From c8be50ea99dc1900b67e0aaa9219005fb54ca299 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:09:53 +0200 Subject: [PATCH 019/381] ARM: at91/dt: at91sam9260: use slow clock where necessary The watchdog, the reset controller, the real-time timer, the shutdown controller, the timer counters need the slow clock, add it where necessary. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9260.dtsi | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index 4bc34754910280..be9c027ddd979c 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -359,11 +359,13 @@ rstc@fffffd00 { compatible = "atmel,at91sam9260-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; }; shdwc@fffffd10 { compatible = "atmel,at91sam9260-shdwc"; reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; }; pit: timer@fffffd30 { @@ -379,8 +381,8 @@ interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0 18 IRQ_TYPE_LEVEL_HIGH 0 19 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>, <&clk32k>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; tcb1: timer@fffdc000 { @@ -389,8 +391,8 @@ interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0 27 IRQ_TYPE_LEVEL_HIGH 0 28 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tc3_clk>, <&tc4_clk>, <&tc5_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tc3_clk>, <&tc4_clk>, <&tc5_clk>, <&clk32k>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; pinctrl@fffff400 { @@ -973,6 +975,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; atmel,dbg-halt; From 74402a4a3d1806b778c95b00634ca67b5ffaa2ca Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:09:54 +0200 Subject: [PATCH 020/381] ARM: at91/dt: at91sam9261: use slow clock where necessary The watchdog, the reset controller, the real-time timer, the shutdown controller and the timer counter need the slow clock, add it where necessary. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9261.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9261.dtsi b/arch/arm/boot/dts/at91sam9261.dtsi index b2c44a07a3d0ee..ce1e3e94a40c20 100644 --- a/arch/arm/boot/dts/at91sam9261.dtsi +++ b/arch/arm/boot/dts/at91sam9261.dtsi @@ -119,8 +119,8 @@ interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>, <18 IRQ_TYPE_LEVEL_HIGH 0>, <19 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>, <&slow_xtal>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; usb1: gadget@fffa4000 { @@ -820,11 +820,13 @@ rstc@fffffd00 { compatible = "atmel,at91sam9260-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&slow_xtal>; }; shdwc@fffffd10 { compatible = "atmel,at91sam9260-shdwc"; reg = <0xfffffd10 0x10>; + clocks = <&slow_xtal>; }; pit: timer@fffffd30 { @@ -846,6 +848,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&slow_xtal>; status = "disabled"; }; From 484fa002f4669ba5c3f30559f62e15a6bcdb32ef Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:03 +0200 Subject: [PATCH 021/381] ARM: at91/dt: at91sam9263: use slow clock where necessary The watchdog, the reset controller, the two real-time timers, the shutdown controller and the timer counter need the slow clock, add it where necessary. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9263.dtsi | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi index e36d966ef5e886..f1f5fa3a9e6e27 100644 --- a/arch/arm/boot/dts/at91sam9263.dtsi +++ b/arch/arm/boot/dts/at91sam9263.dtsi @@ -377,18 +377,20 @@ compatible = "atmel,at91rm9200-tcb"; reg = <0xfff7c000 0x100>; interrupts = <19 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb_clk>; - clock-names = "t0_clk"; + clocks = <&tcb_clk>, <&slow_xtal>; + clock-names = "t0_clk", "slow_clk"; }; rstc@fffffd00 { compatible = "atmel,at91sam9260-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&slow_xtal>; }; shdwc@fffffd10 { compatible = "atmel,at91sam9260-shdwc"; reg = <0xfffffd10 0x10>; + clocks = <&slow_xtal>; }; pinctrl@fffff200 { @@ -902,6 +904,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&slow_xtal>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; atmel,dbg-halt; From 490902246aea699b1f9e207392032853d2ddf74f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:04 +0200 Subject: [PATCH 022/381] ARM: at91/dt: at91sam9g45: use slow clock where necessary The watchdog, the reset controller, the RTC, the real-time timer, the shutdown controller and the timer counters need the slow clock, add it where necessary. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9g45.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9g45.dtsi b/arch/arm/boot/dts/at91sam9g45.dtsi index 4268341b0ebba2..18b8b9e2970430 100644 --- a/arch/arm/boot/dts/at91sam9g45.dtsi +++ b/arch/arm/boot/dts/at91sam9g45.dtsi @@ -387,6 +387,7 @@ rstc@fffffd00 { compatible = "atmel,at91sam9g45-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; }; pit: timer@fffffd30 { @@ -400,22 +401,23 @@ shdwc@fffffd10 { compatible = "atmel,at91sam9rl-shdwc"; reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; }; tcb0: timer@fff7c000 { compatible = "atmel,at91rm9200-tcb"; reg = <0xfff7c000 0x100>; interrupts = <18 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; tcb1: timer@fffd4000 { compatible = "atmel,at91rm9200-tcb"; reg = <0xfffd4000 0x100>; interrupts = <18 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tcb0_clk>, <&tcb0_clk>, <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; dma: dma-controller@ffffec00 { @@ -1123,6 +1125,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; atmel,dbg-halt; @@ -1257,6 +1260,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffdb0 0x30>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; status = "disabled"; }; From 42f58b973a62bcdafda803b617fcb4427001eb46 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:05 +0200 Subject: [PATCH 023/381] ARM: at91/dt: at91sam9n12: use slow clock where necessary The watchdog, the reset controller, the RTC, the shutdown controller, the timer counters and the LCD PWM need the slow clock, add it where necessary. The LCD PWM will be handled later. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9n12.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index 5c2a8c8c8bd485..345186f91422d2 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -376,6 +376,7 @@ rstc@fffffe00 { compatible = "atmel,at91sam9g45-rstc"; reg = <0xfffffe00 0x10>; + clocks = <&clk32k>; }; pit: timer@fffffe30 { @@ -388,6 +389,7 @@ shdwc@fffffe10 { compatible = "atmel,at91sam9x5-shdwc"; reg = <0xfffffe10 0x10>; + clocks = <&clk32k>; }; sckc@fffffe50 { @@ -431,16 +433,16 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8008000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb_clk>; - clock-names = "t0_clk"; + clocks = <&tcb_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; tcb1: timer@f800c000 { compatible = "atmel,at91sam9x5-tcb"; reg = <0xf800c000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb_clk>; - clock-names = "t0_clk"; + clocks = <&tcb_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; dma: dma-controller@ffffec00 { @@ -891,6 +893,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; atmel,dbg-halt; @@ -901,6 +904,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffeb0 0x40>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; status = "disabled"; }; From 564788ce0d1b9270fa76b04ebc49e611ed62795e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:05 +0200 Subject: [PATCH 024/381] ARM: at91/dt: at91sam9rl: use slow clock where necessary The watchdog, the reset controller, the RTC, the real-time timer, the shutdown controller and the timer counter need the slow clock, add it where necessary. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9rl.dtsi | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9rl.dtsi b/arch/arm/boot/dts/at91sam9rl.dtsi index c9920c64791cf6..a0b90aedd3b829 100644 --- a/arch/arm/boot/dts/at91sam9rl.dtsi +++ b/arch/arm/boot/dts/at91sam9rl.dtsi @@ -121,8 +121,8 @@ interrupts = <16 IRQ_TYPE_LEVEL_HIGH 0>, <17 IRQ_TYPE_LEVEL_HIGH 0>, <18 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>; - clock-names = "t0_clk", "t1_clk", "t2_clk"; + clocks = <&tc0_clk>, <&tc1_clk>, <&tc2_clk>, <&clk32k>; + clock-names = "t0_clk", "t1_clk", "t2_clk", "slow_clk"; }; mmc0: mmc@fffa4000 { @@ -1018,11 +1018,13 @@ rstc@fffffd00 { compatible = "atmel,at91sam9260-rstc"; reg = <0xfffffd00 0x10>; + clocks = <&clk32k>; }; shdwc@fffffd10 { compatible = "atmel,at91sam9260-shdwc"; reg = <0xfffffd10 0x10>; + clocks = <&clk32k>; }; pit: timer@fffffd30 { @@ -1036,6 +1038,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; status = "disabled"; }; @@ -1083,6 +1086,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffe00 0x40>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; status = "disabled"; }; From 7a096cda4c311b7cf7825abd79b094b5107c9c3e Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:06 +0200 Subject: [PATCH 025/381] ARM: at91/dt: at91sam9x5: use slow clock where necessary The watchdog, the reset controller, the RTC, the shutdown controller, the timer counters and the LCD PWM need the slow clock, add it where necessary, The LCD PWM will be handled later. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9x5.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index b6c8df8d380ea4..747d8f070a5c26 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -376,11 +376,13 @@ rstc@fffffe00 { compatible = "atmel,at91sam9g45-rstc"; reg = <0xfffffe00 0x10>; + clocks = <&clk32k>; }; shdwc@fffffe10 { compatible = "atmel,at91sam9x5-shdwc"; reg = <0xfffffe10 0x10>; + clocks = <&clk32k>; }; pit: timer@fffffe30 { @@ -418,16 +420,16 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8008000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>; - clock-names = "t0_clk"; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; tcb1: timer@f800c000 { compatible = "atmel,at91sam9x5-tcb"; reg = <0xf800c000 0x100>; interrupts = <17 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>; - clock-names = "t0_clk"; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; dma0: dma-controller@ffffec00 { @@ -1173,6 +1175,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; atmel,dbg-halt; @@ -1183,6 +1186,7 @@ compatible = "atmel,at91sam9x5-rtc"; reg = <0xfffffeb0 0x40>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; status = "disabled"; }; From 09fc16539c33152fed1d49da5234eeb479e075cc Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:06 +0200 Subject: [PATCH 026/381] ARM: at91/dt: sama5d3: use slow clock where necessary The watchdog, the reset controller, the RTC, the shutdown controller, the timer counters and the LCD PWM need the slow clock, add it where necessary. [boris.brezillon@free-electrons.com: add tcb clocks] Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/sama5d3.dtsi | 8 ++++++-- arch/arm/boot/dts/sama5d3_tcb1.dtsi | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 81ced62cedafdd..7fa276515f11b6 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -145,8 +145,8 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf0010000 0x100>; interrupts = <26 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>; - clock-names = "t0_clk"; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; i2c0: i2c@f0014000 { @@ -1261,11 +1261,13 @@ rstc@fffffe00 { compatible = "atmel,sama5d3-rstc", "atmel,at91sam9g45-rstc"; reg = <0xfffffe00 0x10>; + clocks = <&clk32k>; }; shutdown-controller@fffffe10 { compatible = "atmel,at91sam9x5-shdwc"; reg = <0xfffffe10 0x10>; + clocks = <&clk32k>; }; pit: timer@fffffe30 { @@ -1279,6 +1281,7 @@ compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffe40 0x10>; interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; atmel,dbg-halt; @@ -1315,6 +1318,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xfffffeb0 0x30>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; }; }; diff --git a/arch/arm/boot/dts/sama5d3_tcb1.dtsi b/arch/arm/boot/dts/sama5d3_tcb1.dtsi index f7fa58fe09f155..801f9745e82f1c 100644 --- a/arch/arm/boot/dts/sama5d3_tcb1.dtsi +++ b/arch/arm/boot/dts/sama5d3_tcb1.dtsi @@ -31,8 +31,8 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8014000 0x100>; interrupts = <27 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb1_clk>; - clock-names = "t0_clk"; + clocks = <&tcb1_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; }; }; From d3778026dc2dbda5db99f136d6112cd7cd2b3774 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 14:10:07 +0200 Subject: [PATCH 027/381] ARM: at91/dt: sama5d4: use slow clock where necessary The watchdog, the reset controller, the RTC, the shutdown controller, the timer counters and the LCD PWM need the slow clock, add it where necessary. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/sama5d4.dtsi | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 1fa8b3611a03db..8d1de29e8da107 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -957,8 +957,8 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf801c000 0x100>; interrupts = <40 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>; - clock-names = "t0_clk"; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; macb0: ethernet@f8020000 { @@ -1185,8 +1185,8 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xfc020000 0x100>; interrupts = <41 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb1_clk>; - clock-names = "t0_clk"; + clocks = <&tcb1_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; adc0: adc@fc034000 { @@ -1270,11 +1270,13 @@ rstc@fc068600 { compatible = "atmel,sama5d3-rstc", "atmel,at91sam9g45-rstc"; reg = <0xfc068600 0x10>; + clocks = <&clk32k>; }; shdwc@fc068610 { compatible = "atmel,at91sam9x5-shdwc"; reg = <0xfc068610 0x10>; + clocks = <&clk32k>; }; pit: timer@fc068630 { @@ -1287,6 +1289,7 @@ watchdog@fc068640 { compatible = "atmel,at91sam9260-wdt"; reg = <0xfc068640 0x10>; + clocks = <&clk32k>; status = "disabled"; }; @@ -1320,6 +1323,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xfc0686b0 0x30>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; }; dbgu: serial@fc069000 { From 0887bd50e8bf6a08fde955c521b3d8a1d17c4a3d Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 31 Jul 2014 09:35:31 +0200 Subject: [PATCH 028/381] ARM: at91/dt: define hlcdc node in at91sam9x5_lcd.dtsi Define at91sam9x5 hlcdc node for the SoCs with an LCD controller. Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9x5_lcd.dtsi | 139 ++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9x5_lcd.dtsi b/arch/arm/boot/dts/at91sam9x5_lcd.dtsi index 485302e8233d4d..1629db9dd56365 100644 --- a/arch/arm/boot/dts/at91sam9x5_lcd.dtsi +++ b/arch/arm/boot/dts/at91sam9x5_lcd.dtsi @@ -13,6 +13,137 @@ / { ahb { apb { + hlcdc: hlcdc@f8038000 { + compatible = "atmel,at91sam9x5-hlcdc"; + reg = <0xf8038000 0x4000>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + status = "disabled"; + + hlcdc-display-controller { + compatible = "atmel,hlcdc-display-controller"; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; + + pinctrl@fffff400 { + lcd { + pinctrl_lcd_base: lcd-base-0 { + atmel,pins = + ; /* LCDPCK */ + }; + + pinctrl_lcd_pwm: lcd-pwm-0 { + atmel,pins = ; /* LCDPWM */ + }; + + pinctrl_lcd_rgb444: lcd-rgb-0 { + atmel,pins = + ; /* LCDD11 pin */ + }; + + pinctrl_lcd_rgb565: lcd-rgb-1 { + atmel,pins = + ; /* LCDD15 pin */ + }; + + pinctrl_lcd_rgb666: lcd-rgb-2 { + atmel,pins = + ; /* LCDD17 pin */ + }; + + pinctrl_lcd_rgb888: lcd-rgb-3 { + atmel,pins = + ; /* LCDD23 pin */ + }; + }; + }; + pmc: pmc@fffffc00 { periphck { lcdc_clk: lcdc_clk { @@ -20,6 +151,14 @@ reg = <25>; }; }; + + systemck { + lcdck: lcdck { + #clock-cells = <0>; + reg = <3>; + clocks = <&mck>; + }; + }; }; }; }; From 04d703ba8d2adfcc100961cf415a16fe4e98972c Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 31 Jul 2014 09:36:10 +0200 Subject: [PATCH 029/381] ARM: at91/dt: include lcd dtsi in at91sam9x5 dtsis Actually make use of at91sam9x5_lcd.dtsi in the relevant SoC dtsis. Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9g15.dtsi | 1 + arch/arm/boot/dts/at91sam9g35.dtsi | 1 + arch/arm/boot/dts/at91sam9x35.dtsi | 1 + 3 files changed, 3 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9g15.dtsi b/arch/arm/boot/dts/at91sam9g15.dtsi index cfd7044616d793..27de7dc0f0e09f 100644 --- a/arch/arm/boot/dts/at91sam9g15.dtsi +++ b/arch/arm/boot/dts/at91sam9g15.dtsi @@ -7,6 +7,7 @@ */ #include "at91sam9x5.dtsi" +#include "at91sam9x5_lcd.dtsi" / { model = "Atmel AT91SAM9G15 SoC"; diff --git a/arch/arm/boot/dts/at91sam9g35.dtsi b/arch/arm/boot/dts/at91sam9g35.dtsi index e35c2fcf82985f..ff4115886f9781 100644 --- a/arch/arm/boot/dts/at91sam9g35.dtsi +++ b/arch/arm/boot/dts/at91sam9g35.dtsi @@ -7,6 +7,7 @@ */ #include "at91sam9x5.dtsi" +#include "at91sam9x5_lcd.dtsi" #include "at91sam9x5_macb0.dtsi" / { diff --git a/arch/arm/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi index 499cdc81f4c07c..d9054e8167b7c1 100644 --- a/arch/arm/boot/dts/at91sam9x35.dtsi +++ b/arch/arm/boot/dts/at91sam9x35.dtsi @@ -7,6 +7,7 @@ */ #include "at91sam9x5.dtsi" +#include "at91sam9x5_lcd.dtsi" #include "at91sam9x5_macb0.dtsi" #include "at91sam9x5_can.dtsi" From 76248d2c6763c77a04e4612e3863946e387f0485 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 31 Jul 2014 09:34:54 +0200 Subject: [PATCH 030/381] ARM: at91/dt: add at91sam9x5-ek Display Module dtsi All the at91sam9x5-ek share the share display module, add a dtsi to describe it. Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9x5dm.dtsi | 74 +++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 arch/arm/boot/dts/at91sam9x5dm.dtsi diff --git a/arch/arm/boot/dts/at91sam9x5dm.dtsi b/arch/arm/boot/dts/at91sam9x5dm.dtsi new file mode 100644 index 00000000000000..31676f1b6e31ab --- /dev/null +++ b/arch/arm/boot/dts/at91sam9x5dm.dtsi @@ -0,0 +1,74 @@ +/* + * at91sam9x5dm.dtsi - Device Tree file for SAM9x5 display module + * + * Copyright (C) 2014 Atmel, + * 2014 Free Electrons + * + * Author: Boris Brezillon + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + hlcdc: hlcdc@f8038000 { + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "disabled"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "disabled"; + }; + + panel: panel { + compatible = "foxlink,fl500wvr00-a0t", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "disabled"; + }; +}; From 066e00c2cbd53d04ed1fe3b137280cbe441ee322 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 31 Jul 2014 09:37:06 +0200 Subject: [PATCH 031/381] ARM: at91/dt: enable lcd support for at91sam9x5 SoCs Use the at91sam9x5 display module dtsi in the relevant board dts. Signed-off-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9g15ek.dts | 25 +++++++++++++++++++++++++ arch/arm/boot/dts/at91sam9g35ek.dts | 21 +++++++++++++++++++++ arch/arm/boot/dts/at91sam9x35ek.dts | 20 ++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9g15ek.dts b/arch/arm/boot/dts/at91sam9g15ek.dts index 26b0444b0f96dc..d1d2b400f1c64b 100644 --- a/arch/arm/boot/dts/at91sam9g15ek.dts +++ b/arch/arm/boot/dts/at91sam9g15ek.dts @@ -8,9 +8,34 @@ */ /dts-v1/; #include "at91sam9g15.dtsi" +#include "at91sam9x5dm.dtsi" #include "at91sam9x5ek.dtsi" / { model = "Atmel AT91SAM9G15-EK"; compatible = "atmel,at91sam9g15ek", "atmel,at91sam9x5ek", "atmel,at91sam9x5", "atmel,at91sam9"; + + ahb { + apb { + hlcdc: hlcdc@f8038000 { + status = "okay"; + }; + }; + }; + + backlight: backlight { + status = "okay"; + }; + + bl_reg: backlight_regulator { + status = "okay"; + }; + + panel: panel { + status = "okay"; + }; + + panel_reg: panel_regulator { + status = "okay"; + }; }; diff --git a/arch/arm/boot/dts/at91sam9g35ek.dts b/arch/arm/boot/dts/at91sam9g35ek.dts index 641a9bf89ed189..23ec8b13f30a0a 100644 --- a/arch/arm/boot/dts/at91sam9g35ek.dts +++ b/arch/arm/boot/dts/at91sam9g35ek.dts @@ -8,6 +8,7 @@ */ /dts-v1/; #include "at91sam9g35.dtsi" +#include "at91sam9x5dm.dtsi" #include "at91sam9x5ek.dtsi" / { @@ -20,6 +21,26 @@ phy-mode = "rmii"; status = "okay"; }; + + hlcdc: hlcdc@f8038000 { + status = "okay"; + }; }; }; + + backlight: backlight { + status = "okay"; + }; + + bl_reg: backlight_regulator { + status = "okay"; + }; + + panel: panel { + status = "okay"; + }; + + panel_reg: panel_regulator { + status = "okay"; + }; }; diff --git a/arch/arm/boot/dts/at91sam9x35ek.dts b/arch/arm/boot/dts/at91sam9x35ek.dts index 343d32818ca311..fcb67180ea26fd 100644 --- a/arch/arm/boot/dts/at91sam9x35ek.dts +++ b/arch/arm/boot/dts/at91sam9x35ek.dts @@ -8,6 +8,7 @@ */ /dts-v1/; #include "at91sam9x35.dtsi" +#include "at91sam9x5dm.dtsi" #include "at91sam9x5ek.dtsi" / { @@ -20,6 +21,25 @@ phy-mode = "rmii"; status = "okay"; }; + hlcdc: hlcdc@f8038000 { + status = "okay"; + }; }; }; + + backlight: backlight { + status = "okay"; + }; + + bl_reg: backlight_regulator { + status = "okay"; + }; + + panel: panel { + status = "okay"; + }; + + panel_reg: panel_regulator { + status = "okay"; + }; }; From 5e5a72c9e7cd2ea1cd978129f109d3c752215136 Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Wed, 25 Mar 2015 18:41:31 +0800 Subject: [PATCH 032/381] ARM: at91/dt: add drm support for at91sam9n12ek Add drm support for at91sam9n12ek board. Signed-off-by: Bo Shen Signed-off-by: Josh Wu Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9n12.dtsi | 71 +++++++++++++++++++++++++++++ arch/arm/boot/dts/at91sam9n12ek.dts | 61 +++++++++++++++++++++++++ 2 files changed, 132 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9n12.dtsi b/arch/arm/boot/dts/at91sam9n12.dtsi index 345186f91422d2..32bc9a189db0fc 100644 --- a/arch/arm/boot/dts/at91sam9n12.dtsi +++ b/arch/arm/boot/dts/at91sam9n12.dtsi @@ -445,6 +445,34 @@ clock-names = "t0_clk", "slow_clk"; }; + hlcdc: hlcdc@f8038000 { + compatible = "atmel,at91sam9n12-hlcdc"; + reg = <0xf8038000 0x2000>; + interrupts = <25 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk", "sys_clk", "slow_clk"; + status = "disabled"; + + hlcdc-display-controller { + compatible = "atmel,hlcdc-display-controller"; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + #pwm-cells = <3>; + }; + }; + dma: dma-controller@ffffec00 { compatible = "atmel,at91sam9g45-dma"; reg = <0xffffec00 0x200>; @@ -477,6 +505,49 @@ }; }; + lcd { + pinctrl_lcd_base: lcd-base-0 { + atmel,pins = + ; /* LCDPCK */ + }; + + pinctrl_lcd_pwm: lcd-pwm-0 { + atmel,pins = ; /* LCDPWM */ + }; + + pinctrl_lcd_rgb888: lcd-rgb-3 { + atmel,pins = + ; /* LCDD23 pin */ + }; + }; + usart0 { pinctrl_usart0: usart0-0 { atmel,pins = diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index eab17fcace6d9b..efa75064d38a62 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -128,6 +128,22 @@ }; }; + hlcdc: hlcdc@f8038000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + usb1: gadget@f803c000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_usb1_vbus_sense>; @@ -161,6 +177,23 @@ }; }; + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + leds { compatible = "gpio-leds"; @@ -194,6 +227,34 @@ }; }; + panel: panel { + compatible = "qd,qd43003c0-40", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; + sound { compatible = "atmel,asoc-wm8904"; pinctrl-names = "default"; From 2325f27840e954de259eeb98fe90b56d8d0994f9 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Jul 2015 23:17:10 +0200 Subject: [PATCH 033/381] ARM: at91/dt: at91sam9x5dm: add support for the touschscreen The display module on the at91sam9x5-ek has a resistive touchscreen, add it. Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9x5dm.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9x5dm.dtsi b/arch/arm/boot/dts/at91sam9x5dm.dtsi index 31676f1b6e31ab..3e6b4a04218652 100644 --- a/arch/arm/boot/dts/at91sam9x5dm.dtsi +++ b/arch/arm/boot/dts/at91sam9x5dm.dtsi @@ -25,6 +25,12 @@ }; }; }; + + adc0: adc@f804c000 { + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; + status = "okay"; + }; }; }; From 5e181e821f74cd542a74f6e1032ac9a155d63d3f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 25 Mar 2015 17:31:09 +0100 Subject: [PATCH 034/381] ARM: at91/dt: at91sam9x5dm: add QT1070 touch button controller The display module for at91sam9x5-ek has a few touch buttons, add support for those. Signed-off-by: Nicolas Ferre Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/at91sam9x5dm.dtsi | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9x5dm.dtsi b/arch/arm/boot/dts/at91sam9x5dm.dtsi index 3e6b4a04218652..34c089fe0bc0c9 100644 --- a/arch/arm/boot/dts/at91sam9x5dm.dtsi +++ b/arch/arm/boot/dts/at91sam9x5dm.dtsi @@ -12,6 +12,18 @@ / { ahb { apb { + i2c0: i2c@f8010000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioA>; + interrupts = <7 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + }; + hlcdc: hlcdc@f8038000 { hlcdc-display-controller { pinctrl-names = "default"; @@ -31,6 +43,15 @@ atmel,adc-ts-pressure-threshold = <10000>; status = "okay"; }; + + pinctrl@fffff400 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + }; + }; }; }; From d68e86c945a62542b718d88af6d02a1994b876e6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 7 Aug 2015 12:54:10 +0200 Subject: [PATCH 035/381] ARM: at91/dt: sama5d2: use slow clock where necessary The watchdog, the reset controller, the RTC, the shutdown controller, the timer counters and the LCD PWM need the slow clock, add it to the currently defined nodes. Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/sama5d2.dtsi | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index f39258fa381597..034cd48ae28b49 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -764,16 +764,16 @@ compatible = "atmel,at91sam9x5-tcb"; reg = <0xf800c000 0x100>; interrupts = <35 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb0_clk>; - clock-names = "t0_clk"; + clocks = <&tcb0_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; tcb1: timer@f8010000 { compatible = "atmel,at91sam9x5-tcb"; reg = <0xf8010000 0x100>; interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>; - clocks = <&tcb1_clk>; - clock-names = "t0_clk"; + clocks = <&tcb1_clk>, <&clk32k>; + clock-names = "t0_clk", "slow_clk"; }; uart0: serial@f801c000 { @@ -857,6 +857,7 @@ compatible = "atmel,at91rm9200-rtc"; reg = <0xf80480b0 0x30>; interrupts = <74 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; }; spi1: spi@fc000000 { From d3b1707ae404cb26fa82a80c493dcc9658794d3e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Mon, 27 Apr 2015 21:52:38 +0900 Subject: [PATCH 036/381] clk: at91: Constify irq_domain_ops The irq_domain_ops are not modified by the driver and the irqdomain core code accepts pointer to a const data. Signed-off-by: Krzysztof Kozlowski Acked-by: Boris Brezillon Signed-off-by: Stephen Boyd --- drivers/clk/at91/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 3f27d21fb7297e..39be2be82b0a04 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -153,7 +153,7 @@ static int pmc_irq_domain_xlate(struct irq_domain *d, return 0; } -static struct irq_domain_ops pmc_irq_ops = { +static const struct irq_domain_ops pmc_irq_ops = { .map = pmc_irq_map, .xlate = pmc_irq_domain_xlate, }; From 203f314f80234d59c3f7e1291d9251d2a50b32cd Mon Sep 17 00:00:00 2001 From: David Dueck Date: Fri, 26 Jun 2015 15:30:22 +0200 Subject: [PATCH 037/381] clk: at91: do not leak resources Do not leak memory and free irqs in case of an error. Acked-by: Boris Brezillon Signed-off-by: David Dueck Signed-off-by: Stephen Boyd --- drivers/clk/at91/clk-h32mx.c | 4 +++- drivers/clk/at91/clk-main.c | 4 +++- drivers/clk/at91/clk-master.c | 8 ++++++-- drivers/clk/at91/clk-pll.c | 8 ++++++-- drivers/clk/at91/clk-system.c | 8 ++++++-- drivers/clk/at91/clk-utmi.c | 8 ++++++-- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c index 152dcb3f7b5f50..61566bcefa5339 100644 --- a/drivers/clk/at91/clk-h32mx.c +++ b/drivers/clk/at91/clk-h32mx.c @@ -116,8 +116,10 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, h32mxclk->pmc = pmc; clk = clk_register(NULL, &h32mxclk->hw); - if (!clk) + if (!clk) { + kfree(h32mxclk); return; + } of_clk_add_provider(np, of_clk_src_simple_get, clk); } diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c index 59fa3cc96c9eb3..696719eb873c76 100644 --- a/drivers/clk/at91/clk-main.c +++ b/drivers/clk/at91/clk-main.c @@ -171,8 +171,10 @@ at91_clk_register_main_osc(struct at91_pmc *pmc, irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); ret = request_irq(osc->irq, clk_main_osc_irq_handler, IRQF_TRIGGER_HIGH, name, osc); - if (ret) + if (ret) { + kfree(osc); return ERR_PTR(ret); + } if (bypass) pmc_write(pmc, AT91_CKGR_MOR, diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index c1af80bcdf2082..d7d6c5941832a5 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -165,12 +165,16 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq, irq_set_status_flags(master->irq, IRQ_NOAUTOEN); ret = request_irq(master->irq, clk_master_irq_handler, IRQF_TRIGGER_HIGH, "clk-master", master); - if (ret) + if (ret) { + kfree(master); return ERR_PTR(ret); + } clk = clk_register(NULL, &master->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(master->irq, master); kfree(master); + } return clk; } diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c index cbbe40377ad622..18b60f4895a684 100644 --- a/drivers/clk/at91/clk-pll.c +++ b/drivers/clk/at91/clk-pll.c @@ -346,12 +346,16 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name, irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, id ? "clk-pllb" : "clk-plla", pll); - if (ret) + if (ret) { + kfree(pll); return ERR_PTR(ret); + } clk = clk_register(NULL, &pll->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(pll->irq, pll); kfree(pll); + } return clk; } diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c index a76d03fd577be0..58008b3e8bc175 100644 --- a/drivers/clk/at91/clk-system.c +++ b/drivers/clk/at91/clk-system.c @@ -130,13 +130,17 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name, irq_set_status_flags(sys->irq, IRQ_NOAUTOEN); ret = request_irq(sys->irq, clk_system_irq_handler, IRQF_TRIGGER_HIGH, name, sys); - if (ret) + if (ret) { + kfree(sys); return ERR_PTR(ret); + } } clk = clk_register(NULL, &sys->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(sys->irq, sys); kfree(sys); + } return clk; } diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index ae3263bc147650..30dd697b1668be 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -118,12 +118,16 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq, irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); ret = request_irq(utmi->irq, clk_utmi_irq_handler, IRQF_TRIGGER_HIGH, "clk-utmi", utmi); - if (ret) + if (ret) { + kfree(utmi); return ERR_PTR(ret); + } clk = clk_register(NULL, &utmi->hw); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + free_irq(utmi->irq, utmi); kfree(utmi); + } return clk; } From a9e4b18cc86822cfd6e4f9281d81e9aba32ab8e8 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 17 Jun 2015 14:40:38 +0200 Subject: [PATCH 038/381] clk: at91: cleanup PMC header file for PCR register fields Add _MASK and _OFFSET values and cleanup register fields layout. Signed-off-by: Nicolas Ferre Signed-off-by: Boris Brezillon --- drivers/clk/at91/clk-peripheral.c | 8 ++++---- include/linux/clk/at91_pmc.h | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index df2c1afa52b4ac..e56c4646939607 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -165,7 +165,7 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) if (periph->id < PERIPHERAL_ID_MIN) return 0; - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID) | + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK) | AT91_PMC_PCR_CMD | AT91_PMC_PCR_DIV(periph->div) | AT91_PMC_PCR_EN); @@ -180,7 +180,7 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) if (periph->id < PERIPHERAL_ID_MIN) return; - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID) | + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK) | AT91_PMC_PCR_CMD); } @@ -194,7 +194,7 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) return 1; pmc_lock(pmc); - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID)); + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_EN); pmc_unlock(pmc); @@ -213,7 +213,7 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw, return parent_rate; pmc_lock(pmc); - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID)); + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); tmp = pmc_read(pmc, AT91_PMC_PCR); pmc_unlock(pmc); diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 7669f7618f397b..dfc59e2b64fb42 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -182,13 +182,11 @@ extern void __iomem *at91_pmc_base; #define AT91_PMC_PCSR1 0x108 /* Peripheral Clock Enable Register 1 */ #define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ -#define AT91_PMC_PCR_PID (0x3f << 0) /* Peripheral ID */ -#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ -#define AT91_PMC_PCR_DIV(n) ((n) << 16) /* Divisor Value */ -#define AT91_PMC_PCR_DIV0 0x0 /* Peripheral clock is MCK */ -#define AT91_PMC_PCR_DIV2 0x1 /* Peripheral clock is MCK/2 */ -#define AT91_PMC_PCR_DIV4 0x2 /* Peripheral clock is MCK/4 */ -#define AT91_PMC_PCR_DIV8 0x3 /* Peripheral clock is MCK/8 */ -#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ +#define AT91_PMC_PCR_PID_MASK 0x3f +#define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ +#define AT91_PMC_PCR_DIV_OFFSET 16 +#define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET) +#define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */ +#define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ #endif From 6bec589eca30d7e172dffcaea4e59760d585cfe3 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 17 Jun 2015 14:40:39 +0200 Subject: [PATCH 039/381] clk: at91: modify PMC peripheral clock to deal with newer register layout As some more information is added to the PCR register, we'd better use a copy of its content and modify just the peripheral-related bits. Implement a read-modify-write for the enable() and disable() callbacks. Signed-off-by: Nicolas Ferre Signed-off-by: Boris Brezillon --- drivers/clk/at91/clk-peripheral.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c index e56c4646939607..6f0ba99522a0a0 100644 --- a/drivers/clk/at91/clk-peripheral.c +++ b/drivers/clk/at91/clk-peripheral.c @@ -161,14 +161,18 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw) { struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); struct at91_pmc *pmc = periph->pmc; + u32 tmp; if (periph->id < PERIPHERAL_ID_MIN) return 0; - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK) | - AT91_PMC_PCR_CMD | - AT91_PMC_PCR_DIV(periph->div) | - AT91_PMC_PCR_EN); + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); + tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_DIV_MASK; + pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_DIV(periph->div) + | AT91_PMC_PCR_CMD + | AT91_PMC_PCR_EN); + pmc_unlock(pmc); return 0; } @@ -176,12 +180,16 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw) { struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(hw); struct at91_pmc *pmc = periph->pmc; + u32 tmp; if (periph->id < PERIPHERAL_ID_MIN) return; - pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK) | - AT91_PMC_PCR_CMD); + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (periph->id & AT91_PMC_PCR_PID_MASK)); + tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_EN; + pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); + pmc_unlock(pmc); } static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw) From e6918a58f76c2bdfeb4b52dc0167ea094f38083c Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 18 Jun 2015 14:43:29 +0200 Subject: [PATCH 040/381] clk: at91: add PMC sama5d2 support Add support for the new sama5d2 SoC and adapt capabilities. Signed-off-by: Nicolas Ferre Signed-off-by: Boris Brezillon --- drivers/clk/at91/pmc.c | 15 +++++++++++++++ include/dt-bindings/clock/at91.h | 1 + include/linux/clk/at91_pmc.h | 1 + 3 files changed, 17 insertions(+) diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index 3f27d21fb7297e..c1f006245756dd 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -207,6 +207,14 @@ static const struct at91_pmc_caps at91sam9x5_caps = { AT91_PMC_MOSCRCS | AT91_PMC_CFDEV, }; +static const struct at91_pmc_caps sama5d2_caps = { + .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | + AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | + AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY | + AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS | + AT91_PMC_CFDEV | AT91_PMC_GCKRDY, +}; + static const struct at91_pmc_caps sama5d3_caps = { .available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY | AT91_PMC_LOCKU | AT91_PMC_PCK0RDY | @@ -437,6 +445,13 @@ static void __init of_at91sam9x5_pmc_setup(struct device_node *np) CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc", of_at91sam9x5_pmc_setup); +static void __init of_sama5d2_pmc_setup(struct device_node *np) +{ + of_at91_pmc_setup(np, &sama5d2_caps); +} +CLK_OF_DECLARE(sama5d2_clk_pmc, "atmel,sama5d2-pmc", + of_sama5d2_pmc_setup); + static void __init of_sama5d3_pmc_setup(struct device_node *np) { of_at91_pmc_setup(np, &sama5d3_caps); diff --git a/include/dt-bindings/clock/at91.h b/include/dt-bindings/clock/at91.h index 0b4cb999a3f7a2..ab3ee241d10c50 100644 --- a/include/dt-bindings/clock/at91.h +++ b/include/dt-bindings/clock/at91.h @@ -18,5 +18,6 @@ #define AT91_PMC_MOSCSELS 16 /* Main Oscillator Selection */ #define AT91_PMC_MOSCRCS 17 /* Main On-Chip RC */ #define AT91_PMC_CFDEV 18 /* Clock Failure Detector Event */ +#define AT91_PMC_GCKRDY 24 /* Generated Clocks */ #endif diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index dfc59e2b64fb42..dc2a0fa62eaa7e 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -164,6 +164,7 @@ extern void __iomem *at91_pmc_base; #define AT91_PMC_MOSCSELS (1 << 16) /* Main Oscillator Selection [some SAM9] */ #define AT91_PMC_MOSCRCS (1 << 17) /* Main On-Chip RC [some SAM9] */ #define AT91_PMC_CFDEV (1 << 18) /* Clock Failure Detector Event [some SAM9] */ +#define AT91_PMC_GCKRDY (1 << 24) /* Generated Clocks */ #define AT91_PMC_IMR 0x6c /* Interrupt Mask Register */ #define AT91_PMC_PLLICPR 0x80 /* PLL Charge Pump Current Register */ From e7898c63e9fcd3f66dc2ede814ef8c6d66bc3837 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 31 Jul 2015 11:43:12 +0200 Subject: [PATCH 041/381] clk: at91: add generated clock driver Add a new type of clocks that can be provided to a peripheral. In addition to the peripheral clock, this new clock that can use several input clocks as parents can generate divided rates. This would allow a peripheral to have finer grained clocks for generating a baud rate, clocking an asynchronous part or having more options in frequency. Signed-off-by: Nicolas Ferre Signed-off-by: Boris Brezillon --- .../devicetree/bindings/clock/at91-clock.txt | 35 ++ arch/arm/mach-at91/Kconfig | 3 + drivers/clk/at91/Makefile | 1 + drivers/clk/at91/clk-generated.c | 306 ++++++++++++++++++ drivers/clk/at91/pmc.c | 6 + drivers/clk/at91/pmc.h | 3 + include/linux/clk/at91_pmc.h | 7 + 7 files changed, 361 insertions(+) create mode 100644 drivers/clk/at91/clk-generated.c diff --git a/Documentation/devicetree/bindings/clock/at91-clock.txt b/Documentation/devicetree/bindings/clock/at91-clock.txt index 5ba6450693b981..181bc8ac4e3a50 100644 --- a/Documentation/devicetree/bindings/clock/at91-clock.txt +++ b/Documentation/devicetree/bindings/clock/at91-clock.txt @@ -77,6 +77,9 @@ Required properties: "atmel,sama5d4-clk-h32mx": at91 h32mx clock + "atmel,sama5d2-clk-generated": + at91 generated clock + Required properties for SCKC node: - reg : defines the IO memory reserved for the SCKC. - #size-cells : shall be 0 (reg is used to encode clk id). @@ -461,3 +464,35 @@ For example: compatible = "atmel,sama5d4-clk-h32mx"; clocks = <&mck>; }; + +Required properties for generated clocks: +- #size-cells : shall be 0 (reg is used to encode clk id). +- #address-cells : shall be 1 (reg is used to encode clk id). +- clocks : shall be the generated clock source phandles. + e.g. clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; +- name: device tree node describing a specific generated clock. + * #clock-cells : from common clock binding; shall be set to 0. + * reg: peripheral id. See Atmel's datasheets to get a full + list of peripheral ids. + * atmel,clk-output-range : minimum and maximum clock frequency + (two u32 fields). + +For example: + gck { + compatible = "atmel,sama5d2-clk-generated"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; + + tcb0_gclk: tcb0_gclk { + #clock-cells = <0>; + reg = <35>; + atmel,clk-output-range = <0 83000000>; + }; + + pwm_gclk: pwm_gclk { + #clock-cells = <0>; + reg = <38>; + atmel,clk-output-range = <0 83000000>; + }; + }; diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index fd95f34945f482..e8273e79f6babe 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -90,6 +90,9 @@ config HAVE_AT91_SMD config HAVE_AT91_H32MX bool +config HAVE_AT91_GENERATED_CLK + bool + config SOC_SAM_V4_V5 bool diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 89a48a7bd5df45..13e67bd35cff3c 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -10,3 +10,4 @@ obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o +obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c new file mode 100644 index 00000000000000..631123ca6f854c --- /dev/null +++ b/drivers/clk/at91/clk-generated.c @@ -0,0 +1,306 @@ +/* + * Copyright (C) 2015 Atmel Corporation, + * Nicolas Ferre + * + * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON. + * + * 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 +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define PERIPHERAL_MAX 64 +#define PERIPHERAL_ID_MIN 2 + +#define GENERATED_SOURCE_MAX 6 +#define GENERATED_MAX_DIV 255 + +struct clk_generated { + struct clk_hw hw; + struct at91_pmc *pmc; + struct clk_range range; + u32 id; + u32 gckdiv; + u8 parent_id; +}; + +#define to_clk_generated(hw) \ + container_of(hw, struct clk_generated, hw) + +static int clk_generated_enable(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + struct at91_pmc *pmc = gck->pmc; + u32 tmp; + + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", + __func__, gck->gckdiv, gck->parent_id); + + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); + tmp = pmc_read(pmc, AT91_PMC_PCR) & + ~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK); + pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id) + | AT91_PMC_PCR_CMD + | AT91_PMC_PCR_GCKDIV(gck->gckdiv) + | AT91_PMC_PCR_GCKEN); + pmc_unlock(pmc); + return 0; +} + +static void clk_generated_disable(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + struct at91_pmc *pmc = gck->pmc; + u32 tmp; + + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); + tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN; + pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); + pmc_unlock(pmc); +} + +static int clk_generated_is_enabled(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + struct at91_pmc *pmc = gck->pmc; + int ret; + + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); + ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN); + pmc_unlock(pmc); + + return ret; +} + +static unsigned long +clk_generated_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_generated *gck = to_clk_generated(hw); + + return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1); +} + +static int clk_generated_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct clk_generated *gck = to_clk_generated(hw); + struct clk *parent = NULL; + long best_rate = -EINVAL; + unsigned long tmp_rate, min_rate; + int best_diff = -1; + int tmp_diff; + int i; + + for (i = 0; i < __clk_get_num_parents(hw->clk); i++) { + u32 div; + unsigned long parent_rate; + + parent = clk_get_parent_by_index(hw->clk, i); + if (!parent) + continue; + + parent_rate = __clk_get_rate(parent); + min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1); + if (!parent_rate || + (gck->range.max && min_rate > gck->range.max)) + continue; + + for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { + tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); + tmp_diff = abs(req->rate - tmp_rate); + + if (best_diff < 0 || best_diff > tmp_diff) { + best_rate = tmp_rate; + best_diff = tmp_diff; + req->best_parent_rate = parent_rate; + req->best_parent_hw = __clk_get_hw(parent); + } + + if (!best_diff || tmp_rate < req->rate) + break; + } + + if (!best_diff) + break; + } + + pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", + __func__, best_rate, + __clk_get_name((req->best_parent_hw)->clk), + req->best_parent_rate); + + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + return 0; +} + +/* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */ +static int clk_generated_set_parent(struct clk_hw *hw, u8 index) +{ + struct clk_generated *gck = to_clk_generated(hw); + + if (index >= __clk_get_num_parents(hw->clk)) + return -EINVAL; + + gck->parent_id = index; + return 0; +} + +static u8 clk_generated_get_parent(struct clk_hw *hw) +{ + struct clk_generated *gck = to_clk_generated(hw); + + return gck->parent_id; +} + +/* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */ +static int clk_generated_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct clk_generated *gck = to_clk_generated(hw); + u32 div; + + if (!rate) + return -EINVAL; + + if (gck->range.max && rate > gck->range.max) + return -EINVAL; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if (div > GENERATED_MAX_DIV + 1 || !div) + return -EINVAL; + + gck->gckdiv = div - 1; + return 0; +} + +static const struct clk_ops generated_ops = { + .enable = clk_generated_enable, + .disable = clk_generated_disable, + .is_enabled = clk_generated_is_enabled, + .recalc_rate = clk_generated_recalc_rate, + .determine_rate = clk_generated_determine_rate, + .get_parent = clk_generated_get_parent, + .set_parent = clk_generated_set_parent, + .set_rate = clk_generated_set_rate, +}; + +/** + * clk_generated_startup - Initialize a given clock to its default parent and + * divisor parameter. + * + * @gck: Generated clock to set the startup parameters for. + * + * Take parameters from the hardware and update local clock configuration + * accordingly. + */ +static void clk_generated_startup(struct clk_generated *gck) +{ + struct at91_pmc *pmc = gck->pmc; + u32 tmp; + + pmc_lock(pmc); + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); + tmp = pmc_read(pmc, AT91_PMC_PCR); + pmc_unlock(pmc); + + gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) + >> AT91_PMC_PCR_GCKCSS_OFFSET; + gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK) + >> AT91_PMC_PCR_GCKDIV_OFFSET; +} + +static struct clk * __init +at91_clk_register_generated(struct at91_pmc *pmc, const char *name, + const char **parent_names, u8 num_parents, + u8 id, const struct clk_range *range) +{ + struct clk_generated *gck; + struct clk *clk = NULL; + struct clk_init_data init; + + gck = kzalloc(sizeof(*gck), GFP_KERNEL); + if (!gck) + return ERR_PTR(-ENOMEM); + + init.name = name; + init.ops = &generated_ops; + init.parent_names = parent_names; + init.num_parents = num_parents; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + gck->id = id; + gck->hw.init = &init; + gck->pmc = pmc; + gck->range = *range; + + clk = clk_register(NULL, &gck->hw); + if (IS_ERR(clk)) + kfree(gck); + else + clk_generated_startup(gck); + + return clk; +} + +void __init of_sama5d2_clk_generated_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + int num; + u32 id; + const char *name; + struct clk *clk; + int num_parents; + const char *parent_names[GENERATED_SOURCE_MAX]; + struct device_node *gcknp; + struct clk_range range = CLK_RANGE(0, 0); + + num_parents = of_clk_get_parent_count(np); + if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) + return; + + of_clk_parent_fill(np, parent_names, num_parents); + + num = of_get_child_count(np); + if (!num || num > PERIPHERAL_MAX) + return; + + for_each_child_of_node(np, gcknp) { + if (of_property_read_u32(gcknp, "reg", &id)) + continue; + + if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) + continue; + + if (of_property_read_string(np, "clock-output-names", &name)) + name = gcknp->name; + + of_at91_get_clk_range(gcknp, "atmel,clk-output-range", + &range); + + clk = at91_clk_register_generated(pmc, name, parent_names, + num_parents, id, &range); + if (IS_ERR(clk)) + continue; + + of_clk_add_provider(gcknp, of_clk_src_simple_get, clk); + } +} diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index c1f006245756dd..af468e154ee529 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -377,6 +377,12 @@ static const struct of_device_id pmc_clk_ids[] __initconst = { .compatible = "atmel,sama5d4-clk-h32mx", .data = of_sama5d4_clk_h32mx_setup, }, +#endif +#if defined(CONFIG_HAVE_AT91_GENERATED_CLK) + { + .compatible = "atmel,sama5d2-clk-generated", + .data = of_sama5d2_clk_generated_setup, + }, #endif { /*sentinel*/ } }; diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index eb8e5dc9076d46..f6a17f94a44dc6 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -126,4 +126,7 @@ extern void __init of_sama5d4_clk_h32mx_setup(struct device_node *np, struct at91_pmc *pmc); #endif +void of_sama5d2_clk_generated_setup(struct device_node *np, + struct at91_pmc *pmc); + #endif /* __PMC_H_ */ diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index dc2a0fa62eaa7e..1e6932222e110d 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -184,10 +184,17 @@ extern void __iomem *at91_pmc_base; #define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ #define AT91_PMC_PCR_PID_MASK 0x3f +#define AT91_PMC_PCR_GCKCSS_OFFSET 8 +#define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) +#define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ #define AT91_PMC_PCR_DIV_OFFSET 16 #define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET) #define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */ +#define AT91_PMC_PCR_GCKDIV_OFFSET 20 +#define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) +#define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ #define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ +#define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ #endif From d29a9ecf19730436f76f3f0e747381dd24e69c3d Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 1 Sep 2015 15:34:03 +0200 Subject: [PATCH 042/381] clk: at91: generated clocks: backport to 4.1 Signed-off-by: Nicolas Ferre --- drivers/clk/at91/clk-generated.c | 45 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c index 631123ca6f854c..cff71dc903c2ee 100644 --- a/drivers/clk/at91/clk-generated.c +++ b/drivers/clk/at91/clk-generated.c @@ -95,13 +95,17 @@ clk_generated_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1); } -static int clk_generated_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) +static long clk_generated_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_hw) { struct clk_generated *gck = to_clk_generated(hw); struct clk *parent = NULL; long best_rate = -EINVAL; - unsigned long tmp_rate, min_rate; + unsigned long tmp_rate, minimum_rate; int best_diff = -1; int tmp_diff; int i; @@ -115,23 +119,24 @@ static int clk_generated_determine_rate(struct clk_hw *hw, continue; parent_rate = __clk_get_rate(parent); - min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1); + minimum_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1); if (!parent_rate || - (gck->range.max && min_rate > gck->range.max)) + (gck->range.max && minimum_rate > gck->range.max)) continue; for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { + tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); - tmp_diff = abs(req->rate - tmp_rate); + tmp_diff = abs(rate - tmp_rate); if (best_diff < 0 || best_diff > tmp_diff) { best_rate = tmp_rate; best_diff = tmp_diff; - req->best_parent_rate = parent_rate; - req->best_parent_hw = __clk_get_hw(parent); + *best_parent_rate = parent_rate; + *best_parent_hw = __clk_get_hw(parent); } - if (!best_diff || tmp_rate < req->rate) + if (!best_diff || tmp_rate < rate) break; } @@ -139,16 +144,11 @@ static int clk_generated_determine_rate(struct clk_hw *hw, break; } - pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", - __func__, best_rate, - __clk_get_name((req->best_parent_hw)->clk), - req->best_parent_rate); - - if (best_rate < 0) - return best_rate; + pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n" , + __FUNCTION__ , best_rate, + __clk_get_name((*best_parent_hw)->clk), *best_parent_rate); - req->rate = best_rate; - return 0; + return best_rate; } /* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */ @@ -264,6 +264,7 @@ at91_clk_register_generated(struct at91_pmc *pmc, const char *name, void __init of_sama5d2_clk_generated_setup(struct device_node *np, struct at91_pmc *pmc) { + int i; int num; u32 id; const char *name; @@ -273,11 +274,15 @@ void __init of_sama5d2_clk_generated_setup(struct device_node *np, struct device_node *gcknp; struct clk_range range = CLK_RANGE(0, 0); - num_parents = of_clk_get_parent_count(np); + num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) return; - of_clk_parent_fill(np, parent_names, num_parents); + for (i = 0; i < num_parents; ++i) { + parent_names[i] = of_clk_get_parent_name(np, i); + if (!parent_names[i]) + return; + } num = of_get_child_count(np); if (!num || num > PERIPHERAL_MAX) From 6a70b35ba935db6d877b9883cba1ef7871f3ac34 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 18 Jun 2015 15:07:35 +0200 Subject: [PATCH 043/381] irqchip: atmel-aic5: Add sama5d2 support Add sama5d2 support to irq-atmel-aic5. Signed-off-by: Nicolas Ferre Cc: Boris BREZILLON Cc: Alexandre Belloni Cc: Ludovic Desroches Cc: Jason Cooper Cc: Link: http://lkml.kernel.org/r/1434632855-27272-1-git-send-email-nicolas.ferre@atmel.com Signed-off-by: Thomas Gleixner --- .../bindings/interrupt-controller/atmel,aic.txt | 2 +- drivers/irqchip/irq-atmel-aic5.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt index f292917fa00d8b..0e9f09a6a2fe48 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt +++ b/Documentation/devicetree/bindings/interrupt-controller/atmel,aic.txt @@ -2,7 +2,7 @@ Required properties: - compatible: Should be "atmel,-aic" - can be "at91rm9200", "sama5d3" or "sama5d4" + can be "at91rm9200", "sama5d2", "sama5d3" or "sama5d4" - interrupt-controller: Identifies the node as an interrupt controller. - interrupt-parent: For single AIC system, it is an empty property. - #interrupt-cells: The number of cells to define the interrupts. It should be 3. diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index a2e8c3f876cbd2..459bf4429d3657 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -339,6 +339,15 @@ static int __init aic5_of_init(struct device_node *node, return 0; } +#define NR_SAMA5D2_IRQS 77 + +static int __init sama5d2_aic5_of_init(struct device_node *node, + struct device_node *parent) +{ + return aic5_of_init(node, parent, NR_SAMA5D2_IRQS); +} +IRQCHIP_DECLARE(sama5d2_aic5, "atmel,sama5d2-aic", sama5d2_aic5_of_init); + #define NR_SAMA5D3_IRQS 48 static int __init sama5d3_aic5_of_init(struct device_node *node, From bada9f94956379eb9e77130fbde864d718c3bec3 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 24 Jul 2015 15:24:45 -0400 Subject: [PATCH 044/381] irqchip: Appropriate __init annotation for const data Init data marked const should be annotated with __initconst for correctness and not __initdata. And for those already __initconst, they should be qualified as const at the compiler level too. This also fixes LTO builds that otherwise fail with section mismatch errors. Signed-off-by: Nicolas Pitre Cc: Jason Cooper Link: http://lkml.kernel.org/r/alpine.LFD.2.20.1507241511551.1806@knanqh.ubzr Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-atmel-aic.c | 2 +- drivers/irqchip/irq-atmel-aic5.c | 2 +- drivers/irqchip/irq-bcm2835.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c index dae3604b32a900..602f40a14c6fb6 100644 --- a/drivers/irqchip/irq-atmel-aic.c +++ b/drivers/irqchip/irq-atmel-aic.c @@ -225,7 +225,7 @@ static void __init at91sam9g45_aic_irq_fixup(struct device_node *root) aic_common_rtt_irq_fixup(root); } -static const struct of_device_id __initdata aic_irq_fixups[] = { +static const struct of_device_id aic_irq_fixups[] __initconst = { { .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup }, { .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup }, { .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup }, diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 459bf4429d3657..2b4ec729b0721f 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -290,7 +290,7 @@ static void __init sama5d3_aic_irq_fixup(struct device_node *root) aic_common_rtc_irq_fixup(root); } -static const struct of_device_id __initdata aic5_irq_fixups[] = { +static const struct of_device_id aic5_irq_fixups[] __initconst = { { .compatible = "atmel,sama5d3", .data = sama5d3_aic_irq_fixup }, { .compatible = "atmel,sama5d4", .data = sama5d3_aic_irq_fixup }, { /* sentinel */ }, diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c index 5916d6cdafa1c9..f751a02265b84d 100644 --- a/drivers/irqchip/irq-bcm2835.c +++ b/drivers/irqchip/irq-bcm2835.c @@ -76,10 +76,10 @@ #define NR_BANKS 3 #define IRQS_PER_BANK 32 -static int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; -static int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; -static int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; -static int bank_irqs[] __initconst = { 8, 32, 32 }; +static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; +static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; +static const int reg_disable[] __initconst = { 0x24, 0x1c, 0x20 }; +static const int bank_irqs[] __initconst = { 8, 32, 32 }; static const int shortcuts[] = { 7, 9, 10, 18, 19, /* Bank 1 */ From 25c33890e7f9b5d24b4a7a1a6f196b049589a5ae Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 4 Aug 2015 11:59:42 +0200 Subject: [PATCH 045/381] clockevents/drivers/timer-atmel-pit: Fix typo in structure initialization Reported-by: Peter Mamonov Signed-off-by: Daniel Lezcano --- drivers/clocksource/timer-atmel-pit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c index c0304ff608b064..9d80632f971bf3 100644 --- a/drivers/clocksource/timer-atmel-pit.c +++ b/drivers/clocksource/timer-atmel-pit.c @@ -208,8 +208,8 @@ static void __init at91sam926x_pit_common_init(struct pit_data *data) data->clksrc.mask = CLOCKSOURCE_MASK(bits); data->clksrc.name = "pit"; data->clksrc.rating = 175; - data->clksrc.read = read_pit_clk, - data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS, + data->clksrc.read = read_pit_clk; + data->clksrc.flags = CLOCK_SOURCE_IS_CONTINUOUS; clocksource_register_hz(&data->clksrc, pit_rate); /* Set up irq handler */ From a0607968ff4c40488a2d713d6788321e829c2234 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 30 Jun 2015 14:36:57 +0200 Subject: [PATCH 046/381] dmaengine: at_xdmac: fix transfer data width in at_xdmac_prep_slave_sg() commit 1c8a38b1268aebc1a903b21b11575077e02d2cf7 upstream. This patch adds the missing update of the transfer data width in at_xdmac_prep_slave_sg(). Indeed, for each item in the scatter-gather list, we check whether the transfer length is aligned with the data width provided by dmaengine_slave_config(). If so, we directly use this data width for the current part of the transfer we are preparing. Otherwise, the data width is reduced to 8 bits (1 byte). Of course, the actual number of register accesses must also be updated to match the new data width. So one chunk was missing in the original patch (see Fixes tag below): the number of register accesses was correctly set to (len >> fixed_dwidth) in mbr_ubc but the real data width was not updated in mbr_cfg. Since mbr_cfg may change for each part of the scatter-gather transfer this also explains why the original patch used the Descriptor View 2 instead of the Descriptor View 1. Let's take the example of a DMA transfer to write 8bit data into an Atmel USART with FIFOs. When FIFOs are enabled in the USART, its Transmit Holding Register (THR) works in multidata mode, that is to say that up to 4 8bit data can be written into the THR in a single 32bit access and it is still possible to write only one data with a 8bit access. To take advantage of this new feature, the DMA driver was modified to allow multiple dwidths when doing slave transfers. For instance, when the total length is 22 bytes, the USART driver splits the transfer into 2 parts: First part: 20 bytes transferred through 5 32bit writes into THR Second part: 2 bytes transferred though 2 8bit writes into THR For the second part, the data width was first set to 4_BYTES by the USART driver thanks to dmaengine_slave_config() then at_xdmac_prep_slave_sg() reduces this data width to 1_BYTE because the 2 byte length is not aligned with the original 4_BYTES data width. Since the data width is modified, the actual number of writes into THR must be set accordingly. Signed-off-by: Cyrille Pitchen Fixes: 6d3a7d9e3ada ("dmaengine: at_xdmac: allow muliple dwidths when doing slave transfers") Cc: stable@vger.kernel.org #4.0 and later Acked-by: Nicolas Ferre Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul Signed-off-by: Greg Kroah-Hartman --- drivers/dma/at_xdmac.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 7992164ea9ec28..c89a7abb523fa4 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -648,16 +648,17 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc->lld.mbr_sa = mem; desc->lld.mbr_da = atchan->sconfig.dst_addr; } - desc->lld.mbr_cfg = atchan->cfg; - dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg); + dwidth = at_xdmac_get_dwidth(atchan->cfg); fixed_dwidth = IS_ALIGNED(len, 1 << dwidth) - ? at_xdmac_get_dwidth(desc->lld.mbr_cfg) + ? dwidth : AT_XDMAC_CC_DWIDTH_BYTE; desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2 /* next descriptor view */ | AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */ | AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */ | (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */ | (len >> fixed_dwidth); /* microblock length */ + desc->lld.mbr_cfg = (atchan->cfg & ~AT_XDMAC_CC_DWIDTH_MASK) | + AT_XDMAC_CC_DWIDTH(fixed_dwidth); dev_dbg(chan2dev(chan), "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n", __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc); From 26d86d977cebb8ee9c4164b9642965e2d34cbd6e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 7 May 2015 17:38:07 +0200 Subject: [PATCH 047/381] dmaengine: Support different source and destination stride In interleaved mode, we can expect to have different source and destination strides. Add support for such case to dmaengine. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index ad419757241ffc..5d63acb09813b8 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -122,10 +122,18 @@ enum dma_transfer_direction { * chunk and before first src/dst address for next chunk. * Ignored for dst(assumed 0), if dst_inc is true and dst_sgl is false. * Ignored for src(assumed 0), if src_inc is true and src_sgl is false. + * @dst_icg: Number of bytes to jump after last dst address of this + * chunk and before the first dst address for next chunk. + * Ignored if dst_inc is true and dst_sgl is false. + * @src_icg: Number of bytes to jump after last src address of this + * chunk and before the first src address for next chunk. + * Ignored if src_inc is true and src_sgl is false. */ struct data_chunk { size_t size; size_t icg; + size_t dst_icg; + size_t src_icg; }; /** From 718b4e5c17717a878f3def56e29a2bcc6d2abc49 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 7 May 2015 17:38:08 +0200 Subject: [PATCH 048/381] dmaengine: xdmac: Handle descriptor's view 3 registers The XDMAC DMA controller uses a concept of views to be able to handle descriptors of different sizes. So far, only the views 1 and 2 were handled by the driver. Unfortunately, we need some of the configuration fields found in the view 3 in order to support memset and interleaved transfers. Add the definition for the view 3 registers, and the needed code to handle view 3 descriptors. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index c89a7abb523fa4..d058be82fa3b65 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -235,6 +235,10 @@ struct at_xdmac_lld { dma_addr_t mbr_sa; /* Source Address Member */ dma_addr_t mbr_da; /* Destination Address Member */ u32 mbr_cfg; /* Configuration Register */ + u32 mbr_bc; /* Block Control Register */ + u32 mbr_ds; /* Data Stride Register */ + u32 mbr_sus; /* Source Microblock Stride Register */ + u32 mbr_dus; /* Destination Microblock Stride Register */ }; @@ -358,6 +362,8 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan, if (at_xdmac_chan_is_cyclic(atchan)) { reg = AT_XDMAC_CNDC_NDVIEW_NDV1; at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg); + } else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3) { + reg = AT_XDMAC_CNDC_NDVIEW_NDV3; } else { /* * No need to write AT_XDMAC_CC reg, it will be done when the From ba1f628a1764c761bca986beac11cf8a0e672b0e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 7 May 2015 17:38:09 +0200 Subject: [PATCH 049/381] dmaengine: xdmac: Add function to align width The code has some logic to compute the burst width according to the alignment of the address we're using. Move that in a function of its own to reduce code duplication. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 63 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index d058be82fa3b65..05a1c474609c96 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -790,6 +790,35 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, return &first->tx_dma_desc; } +static inline u32 at_xdmac_align_width(struct dma_chan *chan, dma_addr_t addr) +{ + u32 width; + + /* + * Check address alignment to select the greater data width we + * can use. + * + * Some XDMAC implementations don't provide dword transfer, in + * this case selecting dword has the same behavior as + * selecting word transfers. + */ + if (!(addr & 7)) { + width = AT_XDMAC_CC_DWIDTH_DWORD; + dev_dbg(chan2dev(chan), "%s: dwidth: double word\n", __func__); + } else if (!(addr & 3)) { + width = AT_XDMAC_CC_DWIDTH_WORD; + dev_dbg(chan2dev(chan), "%s: dwidth: word\n", __func__); + } else if (!(addr & 1)) { + width = AT_XDMAC_CC_DWIDTH_HALFWORD; + dev_dbg(chan2dev(chan), "%s: dwidth: half word\n", __func__); + } else { + width = AT_XDMAC_CC_DWIDTH_BYTE; + dev_dbg(chan2dev(chan), "%s: dwidth: byte\n", __func__); + } + + return width; +} + static struct dma_async_tx_descriptor * at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) @@ -821,24 +850,7 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, if (unlikely(!len)) return NULL; - /* - * Check address alignment to select the greater data width we can use. - * Some XDMAC implementations don't provide dword transfer, in this - * case selecting dword has the same behavior as selecting word transfers. - */ - if (!((src_addr | dst_addr) & 7)) { - dwidth = AT_XDMAC_CC_DWIDTH_DWORD; - dev_dbg(chan2dev(chan), "%s: dwidth: double word\n", __func__); - } else if (!((src_addr | dst_addr) & 3)) { - dwidth = AT_XDMAC_CC_DWIDTH_WORD; - dev_dbg(chan2dev(chan), "%s: dwidth: word\n", __func__); - } else if (!((src_addr | dst_addr) & 1)) { - dwidth = AT_XDMAC_CC_DWIDTH_HALFWORD; - dev_dbg(chan2dev(chan), "%s: dwidth: half word\n", __func__); - } else { - dwidth = AT_XDMAC_CC_DWIDTH_BYTE; - dev_dbg(chan2dev(chan), "%s: dwidth: byte\n", __func__); - } + dwidth = at_xdmac_align_width(chan, src_addr | dst_addr); /* Prepare descriptors. */ while (remaining_size) { @@ -868,19 +880,8 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, dev_dbg(chan2dev(chan), "%s: xfer_size=%zu\n", __func__, xfer_size); /* Check remaining length and change data width if needed. */ - if (!((src_addr | dst_addr | xfer_size) & 7)) { - dwidth = AT_XDMAC_CC_DWIDTH_DWORD; - dev_dbg(chan2dev(chan), "%s: dwidth: double word\n", __func__); - } else if (!((src_addr | dst_addr | xfer_size) & 3)) { - dwidth = AT_XDMAC_CC_DWIDTH_WORD; - dev_dbg(chan2dev(chan), "%s: dwidth: word\n", __func__); - } else if (!((src_addr | dst_addr | xfer_size) & 1)) { - dwidth = AT_XDMAC_CC_DWIDTH_HALFWORD; - dev_dbg(chan2dev(chan), "%s: dwidth: half word\n", __func__); - } else if ((src_addr | dst_addr | xfer_size) & 1) { - dwidth = AT_XDMAC_CC_DWIDTH_BYTE; - dev_dbg(chan2dev(chan), "%s: dwidth: byte\n", __func__); - } + dwidth = at_xdmac_align_width(chan, + src_addr | dst_addr | xfer_size); chan_cc |= AT_XDMAC_CC_DWIDTH(dwidth); ublen = xfer_size >> dwidth; From 01f8a7d29da6f769732aa8d0a50aa0583f7a4e78 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 7 May 2015 17:38:10 +0200 Subject: [PATCH 050/381] dmaengine: xdmac: Rework the chaining logic So far, we were setting the NDE bit in our descriptors through some logic to try to see if we were the last descriptor in the chain. However, that was turning out to be rather complex to get right, while this information is also available when we actually chain a new descriptor after an already existing one. Simplify this by never setting NDE unless when we actually chain a descriptor. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 41 ++++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 05a1c474609c96..0f7641731442ad 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -471,6 +471,20 @@ static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan) return desc; } +static void at_xdmac_queue_desc(struct dma_chan *chan, + struct at_xdmac_desc *prev, + struct at_xdmac_desc *desc) +{ + if (!prev || !desc) + return; + + prev->lld.mbr_nda = desc->tx_dma_desc.phys; + prev->lld.mbr_ubc |= AT_XDMAC_MBR_UBC_NDE; + + dev_dbg(chan2dev(chan), "%s: chain lld: prev=0x%p, mbr_nda=%pad\n", + __func__, prev, &prev->lld.mbr_nda); +} + static struct dma_chan *at_xdmac_xlate(struct of_phandle_args *dma_spec, struct of_dma *of_dma) { @@ -661,7 +675,6 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2 /* next descriptor view */ | AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */ | AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */ - | (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */ | (len >> fixed_dwidth); /* microblock length */ desc->lld.mbr_cfg = (atchan->cfg & ~AT_XDMAC_CC_DWIDTH_MASK) | AT_XDMAC_CC_DWIDTH(fixed_dwidth); @@ -670,12 +683,8 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc); /* Chain lld. */ - if (prev) { - prev->lld.mbr_nda = desc->tx_dma_desc.phys; - dev_dbg(chan2dev(chan), - "%s: chain lld: prev=0x%p, mbr_nda=%pad\n", - __func__, prev, &prev->lld.mbr_nda); - } + if (prev) + at_xdmac_queue_desc(chan, prev, desc); prev = desc; if (!first) @@ -755,7 +764,6 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1 | AT_XDMAC_MBR_UBC_NDEN | AT_XDMAC_MBR_UBC_NSEN - | AT_XDMAC_MBR_UBC_NDE | period_len >> at_xdmac_get_dwidth(desc->lld.mbr_cfg); dev_dbg(chan2dev(chan), @@ -763,12 +771,8 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc); /* Chain lld. */ - if (prev) { - prev->lld.mbr_nda = desc->tx_dma_desc.phys; - dev_dbg(chan2dev(chan), - "%s: chain lld: prev=0x%p, mbr_nda=%pad\n", - __func__, prev, &prev->lld.mbr_nda); - } + if (prev) + at_xdmac_queue_desc(chan, prev, desc); prev = desc; if (!first) @@ -892,7 +896,6 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2 | AT_XDMAC_MBR_UBC_NDEN | AT_XDMAC_MBR_UBC_NSEN - | (remaining_size ? AT_XDMAC_MBR_UBC_NDE : 0) | ublen; desc->lld.mbr_cfg = chan_cc; @@ -901,12 +904,8 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc, desc->lld.mbr_cfg); /* Chain lld. */ - if (prev) { - prev->lld.mbr_nda = desc->tx_dma_desc.phys; - dev_dbg(chan2dev(chan), - "%s: chain lld: prev=0x%p, mbr_nda=0x%08x\n", - __func__, prev, prev->lld.mbr_nda); - } + if (prev) + at_xdmac_queue_desc(chan, prev, desc); prev = desc; if (!first) From b38bc7e81ddd620d2ef0bed134edc1d94100cb0d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 7 May 2015 17:38:11 +0200 Subject: [PATCH 051/381] dmaengine: xdmac: Add interleaved transfer support The XDMAC supports interleaved tranfers through its flexible descriptor configuration. Add support for that kind of transfers to the dmaengine driver. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 233 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 0f7641731442ad..b44d2e8a819f01 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -485,6 +485,19 @@ static void at_xdmac_queue_desc(struct dma_chan *chan, __func__, prev, &prev->lld.mbr_nda); } +static inline void at_xdmac_increment_block_count(struct dma_chan *chan, + struct at_xdmac_desc *desc) +{ + if (!desc) + return; + + desc->lld.mbr_bc++; + + dev_dbg(chan2dev(chan), + "%s: incrementing the block count of the desc 0x%p\n", + __func__, desc); +} + static struct dma_chan *at_xdmac_xlate(struct of_phandle_args *dma_spec, struct of_dma *of_dma) { @@ -823,6 +836,224 @@ static inline u32 at_xdmac_align_width(struct dma_chan *chan, dma_addr_t addr) return width; } +static struct at_xdmac_desc * +at_xdmac_interleaved_queue_desc(struct dma_chan *chan, + struct at_xdmac_chan *atchan, + struct at_xdmac_desc *prev, + dma_addr_t src, dma_addr_t dst, + struct dma_interleaved_template *xt, + struct data_chunk *chunk) +{ + struct at_xdmac_desc *desc; + u32 dwidth; + unsigned long flags; + size_t ublen; + /* + * WARNING: The channel configuration is set here since there is no + * dmaengine_slave_config call in this case. Moreover we don't know the + * direction, it involves we can't dynamically set the source and dest + * interface so we have to use the same one. Only interface 0 allows EBI + * access. Hopefully we can access DDR through both ports (at least on + * SAMA5D4x), so we can use the same interface for source and dest, + * that solves the fact we don't know the direction. + */ + u32 chan_cc = AT_XDMAC_CC_DIF(0) + | AT_XDMAC_CC_SIF(0) + | AT_XDMAC_CC_MBSIZE_SIXTEEN + | AT_XDMAC_CC_TYPE_MEM_TRAN; + + dwidth = at_xdmac_align_width(chan, src | dst | chunk->size); + if (chunk->size >= (AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth)) { + dev_dbg(chan2dev(chan), + "%s: chunk too big (%d, max size %lu)...\n", + __func__, chunk->size, + AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth); + return NULL; + } + + if (prev) + dev_dbg(chan2dev(chan), + "Adding items at the end of desc 0x%p\n", prev); + + if (xt->src_inc) { + if (xt->src_sgl) + chan_cc |= AT_XDMAC_CC_SAM_UBS_DS_AM; + else + chan_cc |= AT_XDMAC_CC_SAM_INCREMENTED_AM; + } + + if (xt->dst_inc) { + if (xt->dst_sgl) + chan_cc |= AT_XDMAC_CC_DAM_UBS_DS_AM; + else + chan_cc |= AT_XDMAC_CC_DAM_INCREMENTED_AM; + } + + spin_lock_irqsave(&atchan->lock, flags); + desc = at_xdmac_get_desc(atchan); + spin_unlock_irqrestore(&atchan->lock, flags); + if (!desc) { + dev_err(chan2dev(chan), "can't get descriptor\n"); + return NULL; + } + + chan_cc |= AT_XDMAC_CC_DWIDTH(dwidth); + + ublen = chunk->size >> dwidth; + + desc->lld.mbr_sa = src; + desc->lld.mbr_da = dst; + + if (xt->src_inc && xt->src_sgl) { + if (chunk->src_icg) + desc->lld.mbr_sus = chunk->src_icg; + else + desc->lld.mbr_sus = chunk->icg; + } + + if (xt->dst_inc && xt->dst_sgl) { + if (chunk->dst_icg) + desc->lld.mbr_dus = chunk->dst_icg; + else + desc->lld.mbr_dus = chunk->icg; + } + + desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV3 + | AT_XDMAC_MBR_UBC_NDEN + | AT_XDMAC_MBR_UBC_NSEN + | ublen; + desc->lld.mbr_cfg = chan_cc; + + dev_dbg(chan2dev(chan), + "%s: lld: mbr_sa=0x%08x, mbr_da=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", + __func__, desc->lld.mbr_sa, desc->lld.mbr_da, + desc->lld.mbr_ubc, desc->lld.mbr_cfg); + + /* Chain lld. */ + if (prev) + at_xdmac_queue_desc(chan, prev, desc); + + return desc; +} + +static size_t at_xdmac_get_icg(bool inc, bool sgl, size_t icg, size_t dir_icg) +{ + if (inc) { + if (dir_icg) + return dir_icg; + else if (sgl) + return icg; + } + + return 0; +} + +static size_t at_xdmac_get_dst_icg(struct dma_interleaved_template *xt, + struct data_chunk *chunk) +{ + return at_xdmac_get_icg(xt->dst_inc, xt->dst_sgl, + chunk->icg, chunk->dst_icg); +} + +static size_t at_xdmac_get_src_icg(struct dma_interleaved_template *xt, + struct data_chunk *chunk) +{ + return at_xdmac_get_icg(xt->src_inc, xt->src_sgl, + chunk->icg, chunk->src_icg); +} + +static struct dma_async_tx_descriptor * +at_xdmac_prep_interleaved(struct dma_chan *chan, + struct dma_interleaved_template *xt, + unsigned long flags) +{ + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *prev = NULL, *first = NULL; + struct data_chunk *chunk, *prev_chunk = NULL; + dma_addr_t dst_addr, src_addr; + size_t dst_skip, src_skip, len = 0; + size_t prev_dst_icg = 0, prev_src_icg = 0; + int i; + + if (!xt || (xt->numf != 1) || (xt->dir != DMA_MEM_TO_MEM)) + return NULL; + + dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", + __func__, xt->src_start, xt->dst_start, xt->numf, + xt->frame_size, flags); + + src_addr = xt->src_start; + dst_addr = xt->dst_start; + + for (i = 0; i < xt->frame_size; i++) { + struct at_xdmac_desc *desc; + size_t src_icg, dst_icg; + + chunk = xt->sgl + i; + + dst_icg = at_xdmac_get_dst_icg(xt, chunk); + src_icg = at_xdmac_get_src_icg(xt, chunk); + + src_skip = chunk->size + src_icg; + dst_skip = chunk->size + dst_icg; + + dev_dbg(chan2dev(chan), + "%s: chunk size=%d, src icg=%d, dst icg=%d\n", + __func__, chunk->size, src_icg, dst_icg); + + /* + * Handle the case where we just have the same + * transfer to setup, we can just increase the + * block number and reuse the same descriptor. + */ + if (prev_chunk && prev && + (prev_chunk->size == chunk->size) && + (prev_src_icg == src_icg) && + (prev_dst_icg == dst_icg)) { + dev_dbg(chan2dev(chan), + "%s: same configuration that the previous chunk, merging the descriptors...\n", + __func__); + at_xdmac_increment_block_count(chan, prev); + continue; + } + + desc = at_xdmac_interleaved_queue_desc(chan, atchan, + prev, + src_addr, dst_addr, + xt, chunk); + if (!desc) { + list_splice_init(&first->descs_list, + &atchan->free_descs_list); + return NULL; + } + + if (!first) + first = desc; + + dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n", + __func__, desc, first); + list_add_tail(&desc->desc_node, &first->descs_list); + + if (xt->src_sgl) + src_addr += src_skip; + + if (xt->dst_sgl) + dst_addr += dst_skip; + + len += chunk->size; + prev_chunk = chunk; + prev_dst_icg = dst_icg; + prev_src_icg = src_icg; + prev = desc; + } + + first->tx_dma_desc.cookie = -EBUSY; + first->tx_dma_desc.flags = flags; + first->xfer_size = len; + + return &first->tx_dma_desc; +} + static struct dma_async_tx_descriptor * at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len, unsigned long flags) @@ -1452,6 +1683,7 @@ static int at_xdmac_probe(struct platform_device *pdev) } dma_cap_set(DMA_CYCLIC, atxdmac->dma.cap_mask); + dma_cap_set(DMA_INTERLEAVE, atxdmac->dma.cap_mask); dma_cap_set(DMA_MEMCPY, atxdmac->dma.cap_mask); dma_cap_set(DMA_SLAVE, atxdmac->dma.cap_mask); /* @@ -1465,6 +1697,7 @@ static int at_xdmac_probe(struct platform_device *pdev) atxdmac->dma.device_tx_status = at_xdmac_tx_status; atxdmac->dma.device_issue_pending = at_xdmac_issue_pending; atxdmac->dma.device_prep_dma_cyclic = at_xdmac_prep_dma_cyclic; + atxdmac->dma.device_prep_interleaved_dma = at_xdmac_prep_interleaved; atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy; atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg; atxdmac->dma.device_config = at_xdmac_device_config; From 6bd44291a58fb05c9c8361157ee016bc8a404b83 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 27 May 2015 16:01:52 +0200 Subject: [PATCH 052/381] dmaengine: Move icg helpers to global header Now that we can have ICGs set for both the source and destination (using the icg field of struct data_chunk) or for only the source or the destination (using the dst_icg or src_icg respectively), and that these fields can be ignored depending on other parameters (src_inc, src_sgl, etc.), the logic to get the actual ICG value can be quite tricky. The XDMAC driver was already implementing it, but since we will need it in other drivers, we can move it to the main header file. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 46 ++++----------------------------------- include/linux/dmaengine.h | 27 +++++++++++++++++++++++ 2 files changed, 31 insertions(+), 42 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b44d2e8a819f01..ce171828401dd6 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -903,20 +903,8 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, desc->lld.mbr_sa = src; desc->lld.mbr_da = dst; - - if (xt->src_inc && xt->src_sgl) { - if (chunk->src_icg) - desc->lld.mbr_sus = chunk->src_icg; - else - desc->lld.mbr_sus = chunk->icg; - } - - if (xt->dst_inc && xt->dst_sgl) { - if (chunk->dst_icg) - desc->lld.mbr_dus = chunk->dst_icg; - else - desc->lld.mbr_dus = chunk->icg; - } + desc->lld.mbr_sus = dmaengine_get_src_icg(xt, chunk); + desc->lld.mbr_dus = dmaengine_get_dst_icg(xt, chunk); desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV3 | AT_XDMAC_MBR_UBC_NDEN @@ -936,32 +924,6 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, return desc; } -static size_t at_xdmac_get_icg(bool inc, bool sgl, size_t icg, size_t dir_icg) -{ - if (inc) { - if (dir_icg) - return dir_icg; - else if (sgl) - return icg; - } - - return 0; -} - -static size_t at_xdmac_get_dst_icg(struct dma_interleaved_template *xt, - struct data_chunk *chunk) -{ - return at_xdmac_get_icg(xt->dst_inc, xt->dst_sgl, - chunk->icg, chunk->dst_icg); -} - -static size_t at_xdmac_get_src_icg(struct dma_interleaved_template *xt, - struct data_chunk *chunk) -{ - return at_xdmac_get_icg(xt->src_inc, xt->src_sgl, - chunk->icg, chunk->src_icg); -} - static struct dma_async_tx_descriptor * at_xdmac_prep_interleaved(struct dma_chan *chan, struct dma_interleaved_template *xt, @@ -991,8 +953,8 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, chunk = xt->sgl + i; - dst_icg = at_xdmac_get_dst_icg(xt, chunk); - src_icg = at_xdmac_get_src_icg(xt, chunk); + dst_icg = dmaengine_get_dst_icg(xt, chunk); + src_icg = dmaengine_get_src_icg(xt, chunk); src_skip = chunk->size + src_icg; dst_skip = chunk->size + dst_icg; diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 5d63acb09813b8..6a281395f46506 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -882,6 +882,33 @@ static inline int dma_maxpq(struct dma_device *dma, enum dma_ctrl_flags flags) BUG(); } +static inline size_t dmaengine_get_icg(bool inc, bool sgl, size_t icg, + size_t dir_icg) +{ + if (inc) { + if (dir_icg) + return dir_icg; + else if (sgl) + return icg; + } + + return 0; +} + +static inline size_t dmaengine_get_dst_icg(struct dma_interleaved_template *xt, + struct data_chunk *chunk) +{ + return dmaengine_get_icg(xt->dst_inc, xt->dst_sgl, + chunk->icg, chunk->dst_icg); +} + +static inline size_t dmaengine_get_src_icg(struct dma_interleaved_template *xt, + struct data_chunk *chunk) +{ + return dmaengine_get_icg(xt->src_inc, xt->src_sgl, + chunk->icg, chunk->src_icg); +} + /* --- public DMA engine API --- */ #ifdef CONFIG_DMA_ENGINE From 61f68066da5e8b1b1ce219ff895671c338568881 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 27 May 2015 16:01:53 +0200 Subject: [PATCH 053/381] dmaengine: hdmac: Implement interleaved transfers The AT91 HDMAC controller supports interleaved transfers through what's called the Picture-in-Picture mode, which allows to transfer a squared portion of a framebuffer. This means that this interleaved transfer only supports interleaved transfers which have a transfer size and ICGs that are fixed across all the chunks. While this is a quite drastic restriction of the interleaved transfers compared to what the dmaengine API allows, this is still useful, and our driver will only reject transfers that do not conform to this. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 106 ++++++++++++++++++++++++++++++++++++ drivers/dma/at_hdmac_regs.h | 5 ++ 2 files changed, 111 insertions(+) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 57b2141ddddc1a..59892126d1758f 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -247,6 +247,10 @@ static void atc_dostart(struct at_dma_chan *atchan, struct at_desc *first) channel_writel(atchan, CTRLA, 0); channel_writel(atchan, CTRLB, 0); channel_writel(atchan, DSCR, first->txd.phys); + channel_writel(atchan, SPIP, ATC_SPIP_HOLE(first->src_hole) | + ATC_SPIP_BOUNDARY(first->boundary)); + channel_writel(atchan, DPIP, ATC_DPIP_HOLE(first->dst_hole) | + ATC_DPIP_BOUNDARY(first->boundary)); dma_writel(atdma, CHER, atchan->mask); vdbg_dump_regs(atchan); @@ -634,6 +638,104 @@ static dma_cookie_t atc_tx_submit(struct dma_async_tx_descriptor *tx) return cookie; } +/** + * atc_prep_dma_interleaved - prepare memory to memory interleaved operation + * @chan: the channel to prepare operation on + * @xt: Interleaved transfer template + * @flags: tx descriptor status flags + */ +static struct dma_async_tx_descriptor * +atc_prep_dma_interleaved(struct dma_chan *chan, + struct dma_interleaved_template *xt, + unsigned long flags) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct data_chunk *first = xt->sgl; + struct at_desc *desc = NULL; + size_t xfer_count; + unsigned int dwidth; + u32 ctrla; + u32 ctrlb; + size_t len = 0; + int i; + + dev_info(chan2dev(chan), + "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", + __func__, xt->src_start, xt->dst_start, xt->numf, + xt->frame_size, flags); + + if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) + return NULL; + + /* + * The controller can only "skip" X bytes every Y bytes, so we + * need to make sure we are given a template that fit that + * description, ie a template with chunks that always have the + * same size, with the same ICGs. + */ + for (i = 0; i < xt->frame_size; i++) { + struct data_chunk *chunk = xt->sgl + i; + + if ((chunk->size != xt->sgl->size) || + (dmaengine_get_dst_icg(xt, chunk) != dmaengine_get_dst_icg(xt, first)) || + (dmaengine_get_src_icg(xt, chunk) != dmaengine_get_src_icg(xt, first))) { + dev_err(chan2dev(chan), + "%s: the controller can transfer only identical chunks\n", + __func__); + return NULL; + } + + len += chunk->size; + } + + dwidth = atc_get_xfer_width(xt->src_start, + xt->dst_start, len); + + xfer_count = len >> dwidth; + if (xfer_count > ATC_BTSIZE_MAX) { + dev_err(chan2dev(chan), "%s: buffer is too big\n", __func__); + return NULL; + } + + ctrla = ATC_SRC_WIDTH(dwidth) | + ATC_DST_WIDTH(dwidth); + + ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN + | ATC_SRC_ADDR_MODE_INCR + | ATC_DST_ADDR_MODE_INCR + | ATC_SRC_PIP + | ATC_DST_PIP + | ATC_FC_MEM2MEM; + + /* create the transfer */ + desc = atc_desc_get(atchan); + if (!desc) { + dev_err(chan2dev(chan), + "%s: couldn't allocate our descriptor\n", __func__); + return NULL; + } + + desc->lli.saddr = xt->src_start; + desc->lli.daddr = xt->dst_start; + desc->lli.ctrla = ctrla | xfer_count; + desc->lli.ctrlb = ctrlb; + + desc->boundary = first->size >> dwidth; + desc->dst_hole = (dmaengine_get_dst_icg(xt, first) >> dwidth) + 1; + desc->src_hole = (dmaengine_get_src_icg(xt, first) >> dwidth) + 1; + + desc->txd.cookie = -EBUSY; + desc->total_len = desc->len = len; + desc->tx_width = dwidth; + + /* set end-of-link to the last link descriptor of list*/ + set_desc_eol(desc); + + desc->txd.flags = flags; /* client is in control of this ack */ + + return &desc->txd; +} + /** * atc_prep_dma_memcpy - prepare a memcpy operation * @chan: the channel to prepare operation on @@ -1609,6 +1711,7 @@ static int __init at_dma_probe(struct platform_device *pdev) /* setup platform data for each SoC */ dma_cap_set(DMA_MEMCPY, at91sam9rl_config.cap_mask); dma_cap_set(DMA_SG, at91sam9rl_config.cap_mask); + dma_cap_set(DMA_INTERLEAVE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_MEMCPY, at91sam9g45_config.cap_mask); dma_cap_set(DMA_SLAVE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_SG, at91sam9g45_config.cap_mask); @@ -1713,6 +1816,9 @@ static int __init at_dma_probe(struct platform_device *pdev) atdma->dma_common.dev = &pdev->dev; /* set prep routines based on capability */ + if (dma_has_cap(DMA_INTERLEAVE, atdma->dma_common.cap_mask)) + atdma->dma_common.device_prep_interleaved_dma = atc_prep_dma_interleaved; + if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 2727ca56057258..bc8d5ebedd192f 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -196,6 +196,11 @@ struct at_desc { size_t len; u32 tx_width; size_t total_len; + + /* Interleaved data */ + size_t boundary; + size_t dst_hole; + size_t src_hole; }; static inline struct at_desc * From 1a117ac5e93ea78461ab32f6ffa49b377ccfcfdb Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 May 2015 13:46:15 +0200 Subject: [PATCH 054/381] dmaengine: Revert "drivers/dma: remove unused support for MEMSET operations" This reverts commit 48a9db462d99494583dad829969616ac90a8df4e. Some platforms actually need support for the memset operations. Bring it back. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 2 ++ include/linux/dmaengine.h | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index 3ddfd1f6c23c0f..a6e12fc61783ac 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -836,6 +836,8 @@ int dma_async_device_register(struct dma_device *device) !device->device_prep_dma_pq); BUG_ON(dma_has_cap(DMA_PQ_VAL, device->cap_mask) && !device->device_prep_dma_pq_val); + BUG_ON(dma_has_cap(DMA_MEMSET, device->cap_mask) && + !device->device_prep_dma_memset); BUG_ON(dma_has_cap(DMA_INTERRUPT, device->cap_mask) && !device->device_prep_dma_interrupt); BUG_ON(dma_has_cap(DMA_SG, device->cap_mask) && diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 6a281395f46506..21ece7643519dc 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -65,6 +65,7 @@ enum dma_transaction_type { DMA_PQ, DMA_XOR_VAL, DMA_PQ_VAL, + DMA_MEMSET, DMA_INTERRUPT, DMA_SG, DMA_PRIVATE, @@ -578,6 +579,7 @@ struct dma_tx_state { * @copy_align: alignment shift for memcpy operations * @xor_align: alignment shift for xor operations * @pq_align: alignment shift for pq operations + * @fill_align: alignment shift for memset operations * @dev_id: unique device ID * @dev: struct device reference for dma mapping api * @src_addr_widths: bit mask of src addr widths the device supports @@ -596,6 +598,7 @@ struct dma_tx_state { * @device_prep_dma_xor_val: prepares a xor validation operation * @device_prep_dma_pq: prepares a pq operation * @device_prep_dma_pq_val: prepares a pqzero_sum operation + * @device_prep_dma_memset: prepares a memset operation * @device_prep_dma_interrupt: prepares an end of chain interrupt operation * @device_prep_slave_sg: prepares a slave dma operation * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio. @@ -628,6 +631,7 @@ struct dma_device { u8 copy_align; u8 xor_align; u8 pq_align; + u8 fill_align; #define DMA_HAS_PQ_CONTINUE (1 << 15) int dev_id; @@ -658,6 +662,9 @@ struct dma_device { struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, unsigned int src_cnt, const unsigned char *scf, size_t len, enum sum_check_flags *pqres, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_dma_memset)( + struct dma_chan *chan, dma_addr_t dest, int value, size_t len, + unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan, unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_sg)( @@ -753,6 +760,17 @@ static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma( return chan->device->device_prep_interleaved_dma(chan, xt, flags); } +static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memset( + struct dma_chan *chan, dma_addr_t dest, int value, size_t len, + unsigned long flags) +{ + if (!chan || !chan->device) + return NULL; + + return chan->device->device_prep_dma_memset(chan, dest, value, + len, flags); +} + static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_sg( struct dma_chan *chan, struct scatterlist *dst_sg, unsigned int dst_nents, @@ -828,6 +846,12 @@ static inline bool is_dma_pq_aligned(struct dma_device *dev, size_t off1, return dmaengine_check_align(dev->pq_align, off1, off2, len); } +static inline bool is_dma_fill_aligned(struct dma_device *dev, size_t off1, + size_t off2, size_t len) +{ + return dmaengine_check_align(dev->fill_align, off1, off2, len); +} + static inline void dma_set_maxpq(struct dma_device *dma, int maxpq, int has_pq_continue) { From a849e45e68857982cb2bfecceb64ee912d4c7ae4 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 18 May 2015 13:46:16 +0200 Subject: [PATCH 055/381] dmaengine: xdmac: Add memset support The XDMAC supports memset transfers, both over contiguous areas, and over discontiguous areas through a LLI. The current memset operation only supports contiguous memset for now, add some support for it. Scatter-gathered memset will come eventually. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index ce171828401dd6..931b2183e2a7fa 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1115,6 +1115,93 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, return &first->tx_dma_desc; } +static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, + struct at_xdmac_chan *atchan, + dma_addr_t dst_addr, + size_t len, + int value) +{ + struct at_xdmac_desc *desc; + unsigned long flags; + size_t ublen; + u32 dwidth; + /* + * WARNING: The channel configuration is set here since there is no + * dmaengine_slave_config call in this case. Moreover we don't know the + * direction, it involves we can't dynamically set the source and dest + * interface so we have to use the same one. Only interface 0 allows EBI + * access. Hopefully we can access DDR through both ports (at least on + * SAMA5D4x), so we can use the same interface for source and dest, + * that solves the fact we don't know the direction. + */ + u32 chan_cc = AT_XDMAC_CC_DAM_INCREMENTED_AM + | AT_XDMAC_CC_SAM_INCREMENTED_AM + | AT_XDMAC_CC_DIF(0) + | AT_XDMAC_CC_SIF(0) + | AT_XDMAC_CC_MBSIZE_SIXTEEN + | AT_XDMAC_CC_MEMSET_HW_MODE + | AT_XDMAC_CC_TYPE_MEM_TRAN; + + dwidth = at_xdmac_align_width(chan, dst_addr); + + if (len >= (AT_XDMAC_MBR_UBC_UBLEN_MAX << dwidth)) { + dev_err(chan2dev(chan), + "%s: Transfer too large, aborting...\n", + __func__); + return NULL; + } + + spin_lock_irqsave(&atchan->lock, flags); + desc = at_xdmac_get_desc(atchan); + spin_unlock_irqrestore(&atchan->lock, flags); + if (!desc) { + dev_err(chan2dev(chan), "can't get descriptor\n"); + return NULL; + } + + chan_cc |= AT_XDMAC_CC_DWIDTH(dwidth); + + ublen = len >> dwidth; + + desc->lld.mbr_da = dst_addr; + desc->lld.mbr_ds = value; + desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV3 + | AT_XDMAC_MBR_UBC_NDEN + | AT_XDMAC_MBR_UBC_NSEN + | ublen; + desc->lld.mbr_cfg = chan_cc; + + dev_dbg(chan2dev(chan), + "%s: lld: mbr_da=0x%08x, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", + __func__, desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc, + desc->lld.mbr_cfg); + + return desc; +} + +struct dma_async_tx_descriptor * +at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, + size_t len, unsigned long flags) +{ + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *desc; + + dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, dest, len, value, flags); + + if (unlikely(!len)) + return NULL; + + desc = at_xdmac_memset_create_desc(chan, atchan, dest, len, value); + list_add_tail(&desc->desc_node, &desc->descs_list); + + desc->tx_dma_desc.cookie = -EBUSY; + desc->tx_dma_desc.flags = flags; + desc->xfer_size = len; + + return &desc->tx_dma_desc; +} + static enum dma_status at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) @@ -1647,6 +1734,7 @@ static int at_xdmac_probe(struct platform_device *pdev) dma_cap_set(DMA_CYCLIC, atxdmac->dma.cap_mask); dma_cap_set(DMA_INTERLEAVE, atxdmac->dma.cap_mask); dma_cap_set(DMA_MEMCPY, atxdmac->dma.cap_mask); + dma_cap_set(DMA_MEMSET, atxdmac->dma.cap_mask); dma_cap_set(DMA_SLAVE, atxdmac->dma.cap_mask); /* * Without DMA_PRIVATE the driver is not able to allocate more than @@ -1661,6 +1749,7 @@ static int at_xdmac_probe(struct platform_device *pdev) atxdmac->dma.device_prep_dma_cyclic = at_xdmac_prep_dma_cyclic; atxdmac->dma.device_prep_interleaved_dma = at_xdmac_prep_interleaved; atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy; + atxdmac->dma.device_prep_dma_memset = at_xdmac_prep_dma_memset; atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg; atxdmac->dma.device_config = at_xdmac_device_config; atxdmac->dma.device_pause = at_xdmac_device_pause; From 94f2a594c866cd026c9995c5b11c94bbd23c1810 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 8 Jun 2015 10:33:16 +0200 Subject: [PATCH 056/381] dmaengine: at_xdmac: fix indentation Fix indentation. Signed-off-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 931b2183e2a7fa..a7bd50e375673b 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -624,12 +624,12 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags, void *context) { - struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); - struct at_xdmac_desc *first = NULL, *prev = NULL; - struct scatterlist *sg; - int i; - unsigned int xfer_size = 0; - unsigned long irqflags; + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *first = NULL, *prev = NULL; + struct scatterlist *sg; + int i; + unsigned int xfer_size = 0; + unsigned long irqflags; struct dma_async_tx_descriptor *ret = NULL; if (!sgl) From f73f46dfb5b9fabf50f33b66de44abb3224554ad Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 26 Jun 2015 16:04:48 +0530 Subject: [PATCH 057/381] dmaengine: Use Pointer xt after NULL check. Removing static analysis error:- Possible null pointer dereference: xt Because currently xt is dereferenced before NULL check, Thus Use it after NULL Check. Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Acked-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 59892126d1758f..d313acbb50e00b 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -659,14 +659,14 @@ atc_prep_dma_interleaved(struct dma_chan *chan, size_t len = 0; int i; + if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) + return NULL; + dev_info(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", __func__, xt->src_start, xt->dst_start, xt->numf, xt->frame_size, flags); - if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) - return NULL; - /* * The controller can only "skip" X bytes every Y bytes, so we * need to make sure we are given a template that fit that From d11863a4c7556445fdf57f24d67d93aa700e3e6e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 17 Jun 2015 16:22:26 +0200 Subject: [PATCH 058/381] dmaengine: at_xdmac: fix bug about channel configuration When using descriptor view 2 or higher, we don't write the configuration into AT_XDMAC_CC register because this configuration will be fetch from the descriptor. Unfortunately, the PROT bit is not updated with this method, we have to do it manually before enabling the channel. Signed-off-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index a7bd50e375673b..d51ef6d3b3b345 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -359,18 +359,19 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan, * descriptor view 2 since some fields of the configuration register * depend on transfer size and src/dest addresses. */ - if (at_xdmac_chan_is_cyclic(atchan)) { + if (at_xdmac_chan_is_cyclic(atchan)) reg = AT_XDMAC_CNDC_NDVIEW_NDV1; - at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg); - } else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3) { + else if (first->lld.mbr_ubc & AT_XDMAC_MBR_UBC_NDV3) reg = AT_XDMAC_CNDC_NDVIEW_NDV3; - } else { - /* - * No need to write AT_XDMAC_CC reg, it will be done when the - * descriptor is fecthed. - */ + else reg = AT_XDMAC_CNDC_NDVIEW_NDV2; - } + /* + * Even if the register will be updated from the configuration in the + * descriptor when using view 2 or higher, the PROT bit won't be set + * properly. This bit can be modified only by using the channel + * configuration register. + */ + at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg); reg |= AT_XDMAC_CNDC_NDDUP | AT_XDMAC_CNDC_NDSUP From 45266ef3caac8658eacb5895baf14c54bc1ae556 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 18 Jun 2015 13:25:41 +0200 Subject: [PATCH 059/381] dmaengine: at_hdmac: fix residue computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As claimed by the programmer datasheet and confirmed by the IP designer, the Block Transfer Size (BTSIZE) bitfield of the Channel x Control A Register (CTRLAx) always refers to a number of Source Width (SRC_WIDTH) transfers. Both the SRC_WIDTH and BTSIZE bitfields can be extacted from the CTRLAx register to compute the DMA residue. So the 'tx_width' field is useless and can be removed from the struct at_desc. Before this patch, atc_prep_slave_sg() was not consistent: BTSIZE was correctly initialized according to the SRC_WIDTH but 'tx_width' was always set to reg_width, which was incorrect for MEM_TO_DEV transfers. It led to bad DMA residue when 'tx_width' != SRC_WIDTH. Also the 'tx_width' field was mostly set only in the first and last descriptors. Depending on the kind of DMA transfer, this field remained uninitialized for intermediate descriptors. The accurate DMA residue was computed only when the currently processed descriptor was the first or the last of the chain. This algorithm was a little bit odd. An accurate DMA residue can always be computed using the SRC_WIDTH and BTSIZE bitfields in the CTRLAx register. Finally, the test to check whether the currently processed descriptor is the last of the chain was wrong: for cyclic transfer, last_desc->lli.dscr is NOT equal to zero, since set_desc_eol() is never called, but logically equal to first_desc->txd.phys. This bug has a side effect on the drivers/tty/serial/atmel_serial.c driver, which uses cyclic DMA transfer to receive data. Since the DMA residue was wrong each time the DMA transfer reaches the second (and last) period of the transfer, no more data were received by the USART driver till the cyclic DMA transfer loops back to the first period. Signed-off-by: Cyrille Pitchen Acked-by: Torsten Fleischer Tested-by: Jirí Prchal Acked-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 132 ++++++++++++++++++++++++------------ drivers/dma/at_hdmac_regs.h | 3 +- 2 files changed, 88 insertions(+), 47 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index d313acbb50e00b..1459c9f3165f12 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -48,6 +48,8 @@ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) +#define ATC_MAX_DSCR_TRIALS 10 + /* * Initial number of descriptors to allocate for each channel. This could * be increased during dma usage. @@ -285,28 +287,19 @@ static struct at_desc *atc_get_desc_by_cookie(struct at_dma_chan *atchan, * * @current_len: the number of bytes left before reading CTRLA * @ctrla: the value of CTRLA - * @desc: the descriptor containing the transfer width */ -static inline int atc_calc_bytes_left(int current_len, u32 ctrla, - struct at_desc *desc) +static inline int atc_calc_bytes_left(int current_len, u32 ctrla) { - return current_len - ((ctrla & ATC_BTSIZE_MAX) << desc->tx_width); -} + u32 btsize = (ctrla & ATC_BTSIZE_MAX); + u32 src_width = ATC_REG_TO_SRC_WIDTH(ctrla); -/** - * atc_calc_bytes_left_from_reg - calculates the number of bytes left according - * to the current value of CTRLA. - * - * @current_len: the number of bytes left before reading CTRLA - * @atchan: the channel to read CTRLA for - * @desc: the descriptor containing the transfer width - */ -static inline int atc_calc_bytes_left_from_reg(int current_len, - struct at_dma_chan *atchan, struct at_desc *desc) -{ - u32 ctrla = channel_readl(atchan, CTRLA); - - return atc_calc_bytes_left(current_len, ctrla, desc); + /* + * According to the datasheet, when reading the Control A Register + * (ctrla), the Buffer Transfer Size (btsize) bitfield refers to the + * number of transfers completed on the Source Interface. + * So btsize is always a number of source width transfers. + */ + return current_len - (btsize << src_width); } /** @@ -320,7 +313,7 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie) struct at_desc *desc_first = atc_first_active(atchan); struct at_desc *desc; int ret; - u32 ctrla, dscr; + u32 ctrla, dscr, trials; /* * If the cookie doesn't match to the currently running transfer then @@ -346,15 +339,82 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie) * the channel's DSCR register and compare it against the value * of the hardware linked list structure of each child * descriptor. + * + * The CTRLA register provides us with the amount of data + * already read from the source for the current child + * descriptor. So we can compute a more accurate residue by also + * removing the number of bytes corresponding to this amount of + * data. + * + * However, the DSCR and CTRLA registers cannot be read both + * atomically. Hence a race condition may occur: the first read + * register may refer to one child descriptor whereas the second + * read may refer to a later child descriptor in the list + * because of the DMA transfer progression inbetween the two + * reads. + * + * One solution could have been to pause the DMA transfer, read + * the DSCR and CTRLA then resume the DMA transfer. Nonetheless, + * this approach presents some drawbacks: + * - If the DMA transfer is paused, RX overruns or TX underruns + * are more likey to occur depending on the system latency. + * Taking the USART driver as an example, it uses a cyclic DMA + * transfer to read data from the Receive Holding Register + * (RHR) to avoid RX overruns since the RHR is not protected + * by any FIFO on most Atmel SoCs. So pausing the DMA transfer + * to compute the residue would break the USART driver design. + * - The atc_pause() function masks interrupts but we'd rather + * avoid to do so for system latency purpose. + * + * Then we'd rather use another solution: the DSCR is read a + * first time, the CTRLA is read in turn, next the DSCR is read + * a second time. If the two consecutive read values of the DSCR + * are the same then we assume both refers to the very same + * child descriptor as well as the CTRLA value read inbetween + * does. For cyclic tranfers, the assumption is that a full loop + * is "not so fast". + * If the two DSCR values are different, we read again the CTRLA + * then the DSCR till two consecutive read values from DSCR are + * equal or till the maxium trials is reach. + * This algorithm is very unlikely not to find a stable value for + * DSCR. */ - ctrla = channel_readl(atchan, CTRLA); - rmb(); /* ensure CTRLA is read before DSCR */ dscr = channel_readl(atchan, DSCR); + rmb(); /* ensure DSCR is read before CTRLA */ + ctrla = channel_readl(atchan, CTRLA); + for (trials = 0; trials < ATC_MAX_DSCR_TRIALS; ++trials) { + u32 new_dscr; + + rmb(); /* ensure DSCR is read after CTRLA */ + new_dscr = channel_readl(atchan, DSCR); + + /* + * If the DSCR register value has not changed inside the + * DMA controller since the previous read, we assume + * that both the dscr and ctrla values refers to the + * very same descriptor. + */ + if (likely(new_dscr == dscr)) + break; + + /* + * DSCR has changed inside the DMA controller, so the + * previouly read value of CTRLA may refer to an already + * processed descriptor hence could be outdated. + * We need to update ctrla to match the current + * descriptor. + */ + dscr = new_dscr; + rmb(); /* ensure DSCR is read before CTRLA */ + ctrla = channel_readl(atchan, CTRLA); + } + if (unlikely(trials >= ATC_MAX_DSCR_TRIALS)) + return -ETIMEDOUT; /* for the first descriptor we can be more accurate */ if (desc_first->lli.dscr == dscr) - return atc_calc_bytes_left(ret, ctrla, desc_first); + return atc_calc_bytes_left(ret, ctrla); ret -= desc_first->len; list_for_each_entry(desc, &desc_first->tx_list, desc_node) { @@ -365,16 +425,14 @@ static int atc_get_bytes_left(struct dma_chan *chan, dma_cookie_t cookie) } /* - * For the last descriptor in the chain we can calculate + * For the current descriptor in the chain we can calculate * the remaining bytes using the channel's register. - * Note that the transfer width of the first and last - * descriptor may differ. */ - if (!desc->lli.dscr) - ret = atc_calc_bytes_left_from_reg(ret, atchan, desc); + ret = atc_calc_bytes_left(ret, ctrla); } else { /* single transfer */ - ret = atc_calc_bytes_left_from_reg(ret, atchan, desc_first); + ctrla = channel_readl(atchan, CTRLA); + ret = atc_calc_bytes_left(ret, ctrla); } return ret; @@ -726,7 +784,6 @@ atc_prep_dma_interleaved(struct dma_chan *chan, desc->txd.cookie = -EBUSY; desc->total_len = desc->len = len; - desc->tx_width = dwidth; /* set end-of-link to the last link descriptor of list*/ set_desc_eol(desc); @@ -804,10 +861,6 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, first->txd.cookie = -EBUSY; first->total_len = len; - /* set transfer width for the calculation of the residue */ - first->tx_width = src_width; - prev->tx_width = src_width; - /* set end-of-link to the last link descriptor of list*/ set_desc_eol(desc); @@ -956,10 +1009,6 @@ atc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, first->txd.cookie = -EBUSY; first->total_len = total_len; - /* set transfer width for the calculation of the residue */ - first->tx_width = reg_width; - prev->tx_width = reg_width; - /* first link descriptor of list is responsible of flags */ first->txd.flags = flags; /* client is in control of this ack */ @@ -1077,12 +1126,6 @@ atc_prep_dma_sg(struct dma_chan *chan, desc->txd.cookie = 0; desc->len = len; - /* - * Although we only need the transfer width for the first and - * the last descriptor, its easier to set it to all descriptors. - */ - desc->tx_width = src_width; - atc_desc_chain(&first, &prev, desc); /* update the lengths and addresses for the next loop cycle */ @@ -1256,7 +1299,6 @@ atc_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, /* First descriptor of the chain embedds additional information */ first->txd.cookie = -EBUSY; first->total_len = buf_len; - first->tx_width = reg_width; return &first->txd; diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index bc8d5ebedd192f..7f5a08230f76de 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -112,6 +112,7 @@ #define ATC_SRC_WIDTH_BYTE (0x0 << 24) #define ATC_SRC_WIDTH_HALFWORD (0x1 << 24) #define ATC_SRC_WIDTH_WORD (0x2 << 24) +#define ATC_REG_TO_SRC_WIDTH(r) (((r) >> 24) & 0x3) #define ATC_DST_WIDTH_MASK (0x3 << 28) /* Destination Single Transfer Size */ #define ATC_DST_WIDTH(x) ((x) << 28) #define ATC_DST_WIDTH_BYTE (0x0 << 28) @@ -182,7 +183,6 @@ struct at_lli { * @txd: support for the async_tx api * @desc_node: node on the channed descriptors list * @len: descriptor byte count - * @tx_width: transfer width * @total_len: total transaction byte count */ struct at_desc { @@ -194,7 +194,6 @@ struct at_desc { struct dma_async_tx_descriptor txd; struct list_head desc_node; size_t len; - u32 tx_width; size_t total_len; /* Interleaved data */ From d6239d685413c6c7a82fd8615c23cb65b0d6f6b3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jul 2015 10:41:32 +0200 Subject: [PATCH 060/381] dmaengine: Add an enum for the dmaengine alignment constraints Most drivers need to set constraints on the buffer alignment for async tx operations. However, even though it is documented, some drivers either use a defined constant that is not matching what the alignment variable expects (like DMA_BUSWIDTH_* constants) or fill the alignment in bytes instead of power of two. Add a new enum for these alignments that matches what the framework expects, and convert the drivers to it. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/coh901318.c | 2 +- drivers/dma/dma-jz4780.c | 2 +- drivers/dma/edma.c | 2 +- drivers/dma/imx-dma.c | 2 +- drivers/dma/k3dma.c | 3 +-- drivers/dma/mic_x100_dma.h | 2 +- drivers/dma/mmp_pdma.c | 3 +-- drivers/dma/mmp_tdma.c | 3 +-- drivers/dma/ste_dma40.c | 2 +- drivers/dma/sun6i-dma.c | 2 +- drivers/dma/xgene-dma.c | 5 ++--- include/linux/dmaengine.h | 25 ++++++++++++++++++++----- 12 files changed, 32 insertions(+), 21 deletions(-) diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c index fd22dd36985f2b..c340ca9bd2b5dc 100644 --- a/drivers/dma/coh901318.c +++ b/drivers/dma/coh901318.c @@ -2730,7 +2730,7 @@ static int __init coh901318_probe(struct platform_device *pdev) * This controller can only access address at even 32bit boundaries, * i.e. 2^2 */ - base->dma_memcpy.copy_align = 2; + base->dma_memcpy.copy_align = DMAENGINE_ALIGN_4_BYTES; err = dma_async_device_register(&base->dma_memcpy); if (err) diff --git a/drivers/dma/dma-jz4780.c b/drivers/dma/dma-jz4780.c index 26d2f0e09ea3da..c29569ac9e4f98 100644 --- a/drivers/dma/dma-jz4780.c +++ b/drivers/dma/dma-jz4780.c @@ -775,7 +775,7 @@ static int jz4780_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_CYCLIC, dd->cap_mask); dd->dev = dev; - dd->copy_align = 2; /* 2^2 = 4 byte alignment */ + dd->copy_align = DMAENGINE_ALIGN_4_BYTES; dd->device_alloc_chan_resources = jz4780_dma_alloc_chan_resources; dd->device_free_chan_resources = jz4780_dma_free_chan_resources; dd->device_prep_slave_sg = jz4780_dma_prep_slave_sg; diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index bf09db7ca9ee9c..be3c823a1ecf7e 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -1005,7 +1005,7 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma, * code using dma memcpy must make sure alignment of * length is at dma->copy_align boundary. */ - dma->copy_align = DMA_SLAVE_BUSWIDTH_4_BYTES; + dma->copy_align = DMAENGINE_ALIGN_4_BYTES; INIT_LIST_HEAD(&dma->channels); } diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index eed405976ea920..da8f3b9f60a48d 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1183,7 +1183,7 @@ static int __init imxdma_probe(struct platform_device *pdev) platform_set_drvdata(pdev, imxdma); - imxdma->dma_device.copy_align = 2; /* 2^2 = 4 bytes alignment */ + imxdma->dma_device.copy_align = DMAENGINE_ALIGN_4_BYTES; imxdma->dma_device.dev->dma_parms = &imxdma->dma_parms; dma_set_max_seg_size(imxdma->dma_device.dev, 0xffffff); diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index 647e362f01fd17..1ba2fd73852d27 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -24,7 +24,6 @@ #include "virt-dma.h" #define DRIVER_NAME "k3-dma" -#define DMA_ALIGN 3 #define DMA_MAX_SIZE 0x1ffc #define INT_STAT 0x00 @@ -732,7 +731,7 @@ static int k3_dma_probe(struct platform_device *op) d->slave.device_pause = k3_dma_transfer_pause; d->slave.device_resume = k3_dma_transfer_resume; d->slave.device_terminate_all = k3_dma_terminate_all; - d->slave.copy_align = DMA_ALIGN; + d->slave.copy_align = DMAENGINE_ALIGN_8_BYTES; /* init virtual channel */ d->chans = devm_kzalloc(&op->dev, diff --git a/drivers/dma/mic_x100_dma.h b/drivers/dma/mic_x100_dma.h index f663b0bdd11d8d..d89982034e68c5 100644 --- a/drivers/dma/mic_x100_dma.h +++ b/drivers/dma/mic_x100_dma.h @@ -39,7 +39,7 @@ */ #define MIC_DMA_MAX_NUM_CHAN 8 #define MIC_DMA_NUM_CHAN 4 -#define MIC_DMA_ALIGN_SHIFT 6 +#define MIC_DMA_ALIGN_SHIFT DMAENGINE_ALIGN_64_BYTES #define MIC_DMA_ALIGN_BYTES (1 << MIC_DMA_ALIGN_SHIFT) #define MIC_DMA_DESC_RX_SIZE (128 * 1024 - 4) diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c index 462a0229a74309..e39457f13d4dd4 100644 --- a/drivers/dma/mmp_pdma.c +++ b/drivers/dma/mmp_pdma.c @@ -72,7 +72,6 @@ #define DCMD_WIDTH4 (3 << 14) /* 4 byte width (Word) */ #define DCMD_LENGTH 0x01fff /* length mask (max = 8K - 1) */ -#define PDMA_ALIGNMENT 3 #define PDMA_MAX_DESC_BYTES DCMD_LENGTH struct mmp_pdma_desc_hw { @@ -1071,7 +1070,7 @@ static int mmp_pdma_probe(struct platform_device *op) pdev->device.device_issue_pending = mmp_pdma_issue_pending; pdev->device.device_config = mmp_pdma_config; pdev->device.device_terminate_all = mmp_pdma_terminate_all; - pdev->device.copy_align = PDMA_ALIGNMENT; + pdev->device.copy_align = DMAENGINE_ALIGN_8_BYTES; pdev->device.src_addr_widths = widths; pdev->device.dst_addr_widths = widths; pdev->device.directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM); diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c index 449e785def17d2..44beaff3487d45 100644 --- a/drivers/dma/mmp_tdma.c +++ b/drivers/dma/mmp_tdma.c @@ -100,7 +100,6 @@ enum mmp_tdma_type { PXA910_SQU, }; -#define TDMA_ALIGNMENT 3 #define TDMA_MAX_XFER_BYTES SZ_64K struct mmp_tdma_chan { @@ -695,7 +694,7 @@ static int mmp_tdma_probe(struct platform_device *pdev) tdev->device.device_pause = mmp_tdma_pause_chan; tdev->device.device_resume = mmp_tdma_resume_chan; tdev->device.device_terminate_all = mmp_tdma_terminate_all; - tdev->device.copy_align = TDMA_ALIGNMENT; + tdev->device.copy_align = DMAENGINE_ALIGN_8_BYTES; dma_set_mask(&pdev->dev, DMA_BIT_MASK(64)); platform_set_drvdata(pdev, tdev); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 3c10f034d4b935..750d1b3136847f 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -2853,7 +2853,7 @@ static void d40_ops_init(struct d40_base *base, struct dma_device *dev) * This controller can only access address at even * 32bit boundaries, i.e. 2^2 */ - dev->copy_align = 2; + dev->copy_align = DMAENGINE_ALIGN_4_BYTES; } if (dma_has_cap(DMA_SG, dev->cap_mask)) diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 11e536586812fa..8cadc2dda067ac 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -957,7 +957,7 @@ static int sun6i_dma_probe(struct platform_device *pdev) sdc->slave.device_issue_pending = sun6i_dma_issue_pending; sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg; sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy; - sdc->slave.copy_align = 4; + sdc->slave.copy_align = DMAENGINE_ALIGN_4_BYTES; sdc->slave.device_config = sun6i_dma_config; sdc->slave.device_pause = sun6i_dma_pause; sdc->slave.device_resume = sun6i_dma_resume; diff --git a/drivers/dma/xgene-dma.c b/drivers/dma/xgene-dma.c index f52e37502254d4..040bd52476cfeb 100755 --- a/drivers/dma/xgene-dma.c +++ b/drivers/dma/xgene-dma.c @@ -181,7 +181,6 @@ #define XGENE_DMA_PQ_CHANNEL 1 #define XGENE_DMA_MAX_BYTE_CNT 0x4000 /* 16 KB */ #define XGENE_DMA_MAX_64B_DESC_BYTE_CNT 0x14000 /* 80 KB */ -#define XGENE_DMA_XOR_ALIGNMENT 6 /* 64 Bytes */ #define XGENE_DMA_MAX_XOR_SRC 5 #define XGENE_DMA_16K_BUFFER_LEN_CODE 0x0 #define XGENE_DMA_INVALID_LEN_CODE 0x7800 @@ -1781,13 +1780,13 @@ static void xgene_dma_set_caps(struct xgene_dma_chan *chan, if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { dma_dev->device_prep_dma_xor = xgene_dma_prep_xor; dma_dev->max_xor = XGENE_DMA_MAX_XOR_SRC; - dma_dev->xor_align = XGENE_DMA_XOR_ALIGNMENT; + dma_dev->xor_align = DMAENGINE_ALIGN_64_BYTES; } if (dma_has_cap(DMA_PQ, dma_dev->cap_mask)) { dma_dev->device_prep_dma_pq = xgene_dma_prep_pq; dma_dev->max_pq = XGENE_DMA_MAX_XOR_SRC; - dma_dev->pq_align = XGENE_DMA_XOR_ALIGNMENT; + dma_dev->pq_align = DMAENGINE_ALIGN_64_BYTES; } } diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 21ece7643519dc..34f187cd1ceb1f 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -567,6 +567,20 @@ struct dma_tx_state { u32 residue; }; +/** + * enum dmaengine_alignment - defines alignment of the DMA async tx + * buffers + */ +enum dmaengine_alignment { + DMAENGINE_ALIGN_1_BYTE = 0, + DMAENGINE_ALIGN_2_BYTES = 1, + DMAENGINE_ALIGN_4_BYTES = 2, + DMAENGINE_ALIGN_8_BYTES = 3, + DMAENGINE_ALIGN_16_BYTES = 4, + DMAENGINE_ALIGN_32_BYTES = 5, + DMAENGINE_ALIGN_64_BYTES = 6, +}; + /** * struct dma_device - info on the entity supplying DMA services * @chancnt: how many DMA channels are supported @@ -628,10 +642,10 @@ struct dma_device { dma_cap_mask_t cap_mask; unsigned short max_xor; unsigned short max_pq; - u8 copy_align; - u8 xor_align; - u8 pq_align; - u8 fill_align; + enum dmaengine_alignment copy_align; + enum dmaengine_alignment xor_align; + enum dmaengine_alignment pq_align; + enum dmaengine_alignment fill_align; #define DMA_HAS_PQ_CONTINUE (1 << 15) int dev_id; @@ -816,7 +830,8 @@ static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc return desc->tx_submit(desc); } -static inline bool dmaengine_check_align(u8 align, size_t off1, size_t off2, size_t len) +static inline bool dmaengine_check_align(enum dmaengine_alignment align, + size_t off1, size_t off2, size_t len) { size_t mask; From 96866bd8b5249eef0816c74e70442b3a56009c99 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 6 Jul 2015 12:19:23 +0200 Subject: [PATCH 061/381] dmaengine: Add scatter-gathered memset The current API allows the driver to accelerate memset by using the DMA controller. However, it does so over a contiguous memory area, which might proves inefficient when you have to do it over a non-contiguous yet repititive pattern, since you have to create a number of descriptors and then submit each other. Add a memset operation going over a scatter list to handle such cases in a single call. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- include/linux/dmaengine.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 34f187cd1ceb1f..db761ee2db60ee 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -66,6 +66,7 @@ enum dma_transaction_type { DMA_XOR_VAL, DMA_PQ_VAL, DMA_MEMSET, + DMA_MEMSET_SG, DMA_INTERRUPT, DMA_SG, DMA_PRIVATE, @@ -613,6 +614,7 @@ enum dmaengine_alignment { * @device_prep_dma_pq: prepares a pq operation * @device_prep_dma_pq_val: prepares a pqzero_sum operation * @device_prep_dma_memset: prepares a memset operation + * @device_prep_dma_memset_sg: prepares a memset operation over a scatter list * @device_prep_dma_interrupt: prepares an end of chain interrupt operation * @device_prep_slave_sg: prepares a slave dma operation * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio. @@ -679,6 +681,9 @@ struct dma_device { struct dma_async_tx_descriptor *(*device_prep_dma_memset)( struct dma_chan *chan, dma_addr_t dest, int value, size_t len, unsigned long flags); + struct dma_async_tx_descriptor *(*device_prep_dma_memset_sg)( + struct dma_chan *chan, struct scatterlist *sg, + unsigned int nents, int value, unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( struct dma_chan *chan, unsigned long flags); struct dma_async_tx_descriptor *(*device_prep_dma_sg)( From 9eec356f45c6d1a8da7c58183737edf644b0f858 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 6 Jul 2015 12:19:24 +0200 Subject: [PATCH 062/381] dmaengine: xdmac: Add scatter gathered memset support The XDMAC also supports memset operations over discontiguous areas. Add the necessary logic to support this. Signed-off-by: Maxime Ripard Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 166 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 165 insertions(+), 1 deletion(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index d51ef6d3b3b345..ac30102bda919d 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1135,7 +1135,7 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, * SAMA5D4x), so we can use the same interface for source and dest, * that solves the fact we don't know the direction. */ - u32 chan_cc = AT_XDMAC_CC_DAM_INCREMENTED_AM + u32 chan_cc = AT_XDMAC_CC_DAM_UBS_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0) @@ -1203,6 +1203,168 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, return &desc->tx_dma_desc; } +static struct dma_async_tx_descriptor * +at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, int value, + unsigned long flags) +{ + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *desc, *pdesc = NULL, + *ppdesc = NULL, *first = NULL; + struct scatterlist *sg, *psg = NULL, *ppsg = NULL; + size_t stride = 0, pstride = 0, len = 0; + int i; + + if (!sgl) + return NULL; + + dev_dbg(chan2dev(chan), "%s: sg_len=%d, value=0x%x, flags=0x%lx\n", + __func__, sg_len, value, flags); + + /* Prepare descriptors. */ + for_each_sg(sgl, sg, sg_len, i) { + dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, sg_dma_address(sg), sg_dma_len(sg), + value, flags); + desc = at_xdmac_memset_create_desc(chan, atchan, + sg_dma_address(sg), + sg_dma_len(sg), + value); + if (!desc && first) + list_splice_init(&first->descs_list, + &atchan->free_descs_list); + + if (!first) + first = desc; + + /* Update our strides */ + pstride = stride; + if (psg) + stride = sg_dma_address(sg) - + (sg_dma_address(psg) + sg_dma_len(psg)); + + /* + * The scatterlist API gives us only the address and + * length of each elements. + * + * Unfortunately, we don't have the stride, which we + * will need to compute. + * + * That make us end up in a situation like this one: + * len stride len stride len + * +-------+ +-------+ +-------+ + * | N-2 | | N-1 | | N | + * +-------+ +-------+ +-------+ + * + * We need all these three elements (N-2, N-1 and N) + * to actually take the decision on whether we need to + * queue N-1 or reuse N-2. + * + * We will only consider N if it is the last element. + */ + if (ppdesc && pdesc) { + if ((stride == pstride) && + (sg_dma_len(ppsg) == sg_dma_len(psg))) { + dev_dbg(chan2dev(chan), + "%s: desc 0x%p can be merged with desc 0x%p\n", + __func__, pdesc, ppdesc); + + /* + * Increment the block count of the + * N-2 descriptor + */ + at_xdmac_increment_block_count(chan, ppdesc); + ppdesc->lld.mbr_dus = stride; + + /* + * Put back the N-1 descriptor in the + * free descriptor list + */ + list_add_tail(&pdesc->desc_node, + &atchan->free_descs_list); + + /* + * Make our N-1 descriptor pointer + * point to the N-2 since they were + * actually merged. + */ + pdesc = ppdesc; + + /* + * Rule out the case where we don't have + * pstride computed yet (our second sg + * element) + * + * We also want to catch the case where there + * would be a negative stride, + */ + } else if (pstride || + sg_dma_address(sg) < sg_dma_address(psg)) { + /* + * Queue the N-1 descriptor after the + * N-2 + */ + at_xdmac_queue_desc(chan, ppdesc, pdesc); + + /* + * Add the N-1 descriptor to the list + * of the descriptors used for this + * transfer + */ + list_add_tail(&desc->desc_node, + &first->descs_list); + dev_dbg(chan2dev(chan), + "%s: add desc 0x%p to descs_list 0x%p\n", + __func__, desc, first); + } + } + + /* + * If we are the last element, just see if we have the + * same size than the previous element. + * + * If so, we can merge it with the previous descriptor + * since we don't care about the stride anymore. + */ + if ((i == (sg_len - 1)) && + sg_dma_len(ppsg) == sg_dma_len(psg)) { + dev_dbg(chan2dev(chan), + "%s: desc 0x%p can be merged with desc 0x%p\n", + __func__, desc, pdesc); + + /* + * Increment the block count of the N-1 + * descriptor + */ + at_xdmac_increment_block_count(chan, pdesc); + pdesc->lld.mbr_dus = stride; + + /* + * Put back the N descriptor in the free + * descriptor list + */ + list_add_tail(&desc->desc_node, + &atchan->free_descs_list); + } + + /* Update our descriptors */ + ppdesc = pdesc; + pdesc = desc; + + /* Update our scatter pointers */ + ppsg = psg; + psg = sg; + + len += sg_dma_len(sg); + } + + first->tx_dma_desc.cookie = -EBUSY; + first->tx_dma_desc.flags = flags; + first->xfer_size = len; + + return &first->tx_dma_desc; +} + static enum dma_status at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *txstate) @@ -1736,6 +1898,7 @@ static int at_xdmac_probe(struct platform_device *pdev) dma_cap_set(DMA_INTERLEAVE, atxdmac->dma.cap_mask); dma_cap_set(DMA_MEMCPY, atxdmac->dma.cap_mask); dma_cap_set(DMA_MEMSET, atxdmac->dma.cap_mask); + dma_cap_set(DMA_MEMSET_SG, atxdmac->dma.cap_mask); dma_cap_set(DMA_SLAVE, atxdmac->dma.cap_mask); /* * Without DMA_PRIVATE the driver is not able to allocate more than @@ -1751,6 +1914,7 @@ static int at_xdmac_probe(struct platform_device *pdev) atxdmac->dma.device_prep_interleaved_dma = at_xdmac_prep_interleaved; atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy; atxdmac->dma.device_prep_dma_memset = at_xdmac_prep_dma_memset; + atxdmac->dma.device_prep_dma_memset_sg = at_xdmac_prep_dma_memset_sg; atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg; atxdmac->dma.device_config = at_xdmac_device_config; atxdmac->dma.device_pause = at_xdmac_device_pause; From e1594bef9ceffed5b46249d707e1a4e9ae5a8999 Mon Sep 17 00:00:00 2001 From: Robert Baldyga Date: Fri, 7 Aug 2015 12:26:47 +0200 Subject: [PATCH 063/381] dmaengine: fix balance of privatecnt inc/dec operations This patch increments privatecnt value and set DMA_PRIVATE in device caps in dma_request_slave_channel() function. This is needed to keep privatecnt increment/decrement balance. As function dma_release_channel() decrements privatecnt counter, we need to increment it when channel is requested. Otherwise privatecnt drops into negatives after few dma_release_channel() calls. Reported-by: Krzysztof Kozlowski Signed-off-by: Robert Baldyga Signed-off-by: Vinod Koul --- drivers/dma/dmaengine.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index a6e12fc61783ac..d174d95f3ca1fc 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -682,6 +682,10 @@ struct dma_chan *dma_request_slave_channel(struct device *dev, struct dma_chan *ch = dma_request_slave_channel_reason(dev, name); if (IS_ERR(ch)) return NULL; + + dma_cap_set(DMA_PRIVATE, ch->device->cap_mask); + ch->device->privatecnt++; + return ch; } EXPORT_SYMBOL_GPL(dma_request_slave_channel); From be6b64e9cba28783d9eca279ba49df5999926ff9 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 22 Jul 2015 16:12:29 +0200 Subject: [PATCH 064/381] dmaengine: at_xdmac: fix bug in prep_dma_cyclic In cyclic mode, the round chaining has been broken by the introduction of at_xdmac_queue_desc(): AT_XDMAC_MBR_UBC_NDE is set for all descriptors excepted for the last one. at_xdmac_queue_desc() has to be called one more time to chain the last and the first descriptors. Signed-off-by: Ludovic Desroches Fixes: 0d0ee751f7f7 ("dmaengine: xdmac: Rework the chaining logic") Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index ac30102bda919d..a165b4bfd3300e 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -797,10 +797,7 @@ at_xdmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, list_add_tail(&desc->desc_node, &first->descs_list); } - prev->lld.mbr_nda = first->tx_dma_desc.phys; - dev_dbg(chan2dev(chan), - "%s: chain lld: prev=0x%p, mbr_nda=%pad\n", - __func__, prev, &prev->lld.mbr_nda); + at_xdmac_queue_desc(chan, prev, first); first->tx_dma_desc.flags = flags; first->xfer_size = buf_len; first->direction = direction; From 15f88459c0f1cb3176eedaea3c06f0022ba3101e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 24 Aug 2015 11:21:15 +0200 Subject: [PATCH 065/381] dmaengine: hdmac: Add memset capabilities Just like for the XDMAC, the SoCs that embed the HDMAC don't have any kind of GPU, and need to accelerate a few framebuffer-related operations through their DMA controller. However, unlike the XDMAC, the HDMAC doesn't have the memset capability built-in. That can be easily emulated though, by doing a transfer with a fixed address on the variable that holds the value we want to set. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 121 +++++++++++++++++++++++++++++++++++- drivers/dma/at_hdmac_regs.h | 6 ++ 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 1459c9f3165f12..58d406230d899f 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -448,6 +448,7 @@ static void atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) { struct dma_async_tx_descriptor *txd = &desc->txd; + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); dev_vdbg(chan2dev(&atchan->chan_common), "descriptor %u complete\n", txd->cookie); @@ -456,6 +457,13 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) if (!atc_chan_is_cyclic(atchan)) dma_cookie_complete(txd); + /* If the transfer was a memset, free our temporary buffer */ + if (desc->memset) { + dma_pool_free(atdma->memset_pool, desc->memset_vaddr, + desc->memset_paddr); + desc->memset = false; + } + /* move children to free_list */ list_splice_init(&desc->tx_list, &atchan->free_list); /* move myself to free_list */ @@ -873,6 +881,93 @@ atc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, return NULL; } +/** + * atc_prep_dma_memset - prepare a memcpy operation + * @chan: the channel to prepare operation on + * @dest: operation virtual destination address + * @value: value to set memory buffer to + * @len: operation length + * @flags: tx descriptor status flags + */ +static struct dma_async_tx_descriptor * +atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, + size_t len, unsigned long flags) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); + struct at_desc *desc = NULL; + size_t xfer_count; + u32 ctrla; + u32 ctrlb; + + dev_vdbg(chan2dev(chan), "%s: d0x%x v0x%x l0x%zx f0x%lx\n", __func__, + dest, value, len, flags); + + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); + return NULL; + } + + if (!is_dma_fill_aligned(chan->device, dest, 0, len)) { + dev_dbg(chan2dev(chan), "%s: buffer is not aligned\n", + __func__); + return NULL; + } + + xfer_count = len >> 2; + if (xfer_count > ATC_BTSIZE_MAX) { + dev_err(chan2dev(chan), "%s: buffer is too big\n", + __func__); + return NULL; + } + + ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN + | ATC_SRC_ADDR_MODE_FIXED + | ATC_DST_ADDR_MODE_INCR + | ATC_FC_MEM2MEM; + + ctrla = ATC_SRC_WIDTH(2) | + ATC_DST_WIDTH(2); + + desc = atc_desc_get(atchan); + if (!desc) { + dev_err(chan2dev(chan), "%s: can't get a descriptor\n", + __func__); + return NULL; + } + + desc->memset_vaddr = dma_pool_alloc(atdma->memset_pool, GFP_ATOMIC, + &desc->memset_paddr); + if (!desc->memset_vaddr) { + dev_err(chan2dev(chan), "%s: couldn't allocate buffer\n", + __func__); + goto err_put_desc; + } + + *desc->memset_vaddr = value; + desc->memset = true; + + desc->lli.saddr = desc->memset_paddr; + desc->lli.daddr = dest; + desc->lli.ctrla = ctrla | xfer_count; + desc->lli.ctrlb = ctrlb; + + desc->txd.cookie = -EBUSY; + desc->len = len; + desc->total_len = len; + + /* set end-of-link on the descriptor */ + set_desc_eol(desc); + + desc->txd.flags = flags; + + return &desc->txd; + +err_put_desc: + atc_desc_put(atchan, desc); + return NULL; +} + /** * atc_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction @@ -1755,6 +1850,8 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_SG, at91sam9rl_config.cap_mask); dma_cap_set(DMA_INTERLEAVE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_MEMCPY, at91sam9g45_config.cap_mask); + dma_cap_set(DMA_MEMSET, at91sam9g45_config.cap_mask); + dma_cap_set(DMA_PRIVATE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_SLAVE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_SG, at91sam9g45_config.cap_mask); @@ -1818,7 +1915,16 @@ static int __init at_dma_probe(struct platform_device *pdev) if (!atdma->dma_desc_pool) { dev_err(&pdev->dev, "No memory for descriptors dma pool\n"); err = -ENOMEM; - goto err_pool_create; + goto err_desc_pool_create; + } + + /* create a pool of consistent memory blocks for memset blocks */ + atdma->memset_pool = dma_pool_create("at_hdmac_memset_pool", + &pdev->dev, sizeof(int), 4, 0); + if (!atdma->memset_pool) { + dev_err(&pdev->dev, "No memory for memset dma pool\n"); + err = -ENOMEM; + goto err_memset_pool_create; } /* clear any pending interrupt */ @@ -1864,6 +1970,11 @@ static int __init at_dma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; + if (dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask)) { + atdma->dma_common.device_prep_dma_memset = atc_prep_dma_memset; + atdma->dma_common.fill_align = DMAENGINE_ALIGN_4_BYTES; + } + if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; /* controller can do slave DMA: can trigger cyclic transfers */ @@ -1884,8 +1995,9 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_writel(atdma, EN, AT_DMA_ENABLE); - dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s%s), %d channels\n", + dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s%s%s), %d channels\n", dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "", + dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask) ? "set " : "", dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "", dma_has_cap(DMA_SG, atdma->dma_common.cap_mask) ? "sg-cpy " : "", plat_dat->nr_channels); @@ -1910,8 +2022,10 @@ static int __init at_dma_probe(struct platform_device *pdev) err_of_dma_controller_register: dma_async_device_unregister(&atdma->dma_common); + dma_pool_destroy(atdma->memset_pool); +err_memset_pool_create: dma_pool_destroy(atdma->dma_desc_pool); -err_pool_create: +err_desc_pool_create: free_irq(platform_get_irq(pdev, 0), atdma); err_irq: clk_disable_unprepare(atdma->clk); @@ -1936,6 +2050,7 @@ static int at_dma_remove(struct platform_device *pdev) at_dma_off(atdma); dma_async_device_unregister(&atdma->dma_common); + dma_pool_destroy(atdma->memset_pool); dma_pool_destroy(atdma->dma_desc_pool); free_irq(platform_get_irq(pdev, 0), atdma); diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index 7f5a08230f76de..c3bebbe899ac0b 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -200,6 +200,11 @@ struct at_desc { size_t boundary; size_t dst_hole; size_t src_hole; + + /* Memset temporary buffer */ + bool memset; + dma_addr_t memset_paddr; + int *memset_vaddr; }; static inline struct at_desc * @@ -330,6 +335,7 @@ struct at_dma { u8 all_chan_mask; struct dma_pool *dma_desc_pool; + struct dma_pool *memset_pool; /* AT THE END channels table */ struct at_dma_chan chan[0]; }; From e71a0a97eba33d70fb86961386882fbea4b97f0b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 11 May 2015 13:00:31 +0200 Subject: [PATCH 066/381] tty/serial: at91: RS485 mode: 0 is valid for delay_rts_after_send MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 8687634b7908c42eb700e0469e110e02833611d1 upstream. In RS485 mode, we may want to set the delay_rts_after_send value to 0. In the datasheet, the 0 value is said to "disable" the Transmitter Timeguard but this is exactly the expected behavior if we want no delay... Moreover, if the value was set to non-zero value by device-tree or earlier ioctl command, it was impossible to change it back to zero. Reported-by: Sami Pietikäinen Signed-off-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 27dade29646b7c..5ca1dfb0561cd4 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -315,8 +315,7 @@ static int atmel_config_rs485(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - if ((rs485conf->delay_rts_after_send) > 0) - UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); + UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -354,8 +353,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) /* override mode to RS485 if needed, otherwise keep the current mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - if ((port->rs485.delay_rts_after_send) > 0) - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } @@ -2061,8 +2059,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, /* mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - if ((port->rs485.delay_rts_after_send) > 0) - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ From 9f076b9ee948881d5456d817e36d75a66aca2ba8 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Thu, 9 Apr 2015 10:48:15 +0800 Subject: [PATCH 067/381] tty/serial: at91: handle IRQ status more safely Handle the changed flag of IRQ status in interruption instead of handling it in tasklet due to the tasklet may be scheduled more than once in one interruption. Otherwise, the changed status may be processed more than once which will lead to unexpected result. And seriously, kernel will crash. Signed-off-by: Leilei Zhao Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 5ca1dfb0561cd4..2a8f528153e7cf 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -165,6 +165,7 @@ struct atmel_uart_port { struct tasklet_struct tasklet; unsigned int irq_status; unsigned int irq_status_prev; + unsigned int status_change; struct circ_buf rx_ring; @@ -1175,6 +1176,9 @@ atmel_handle_status(struct uart_port *port, unsigned int pending, if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) { atmel_port->irq_status = status; + atmel_port->status_change = atmel_port->irq_status ^ + atmel_port->irq_status_prev; + atmel_port->irq_status_prev = status; tasklet_schedule(&atmel_port->tasklet); } } @@ -1521,17 +1525,14 @@ static void atmel_tasklet_func(unsigned long data) { struct uart_port *port = (struct uart_port *)data; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - unsigned int status; - unsigned int status_change; + unsigned int status = atmel_port->irq_status; + unsigned int status_change = atmel_port->status_change; /* The interrupt handler does not take the lock */ spin_lock(&port->lock); atmel_port->schedule_tx(port); - status = atmel_port->irq_status; - status_change = status ^ atmel_port->irq_status_prev; - if (status_change & (ATMEL_US_RI | ATMEL_US_DSR | ATMEL_US_DCD | ATMEL_US_CTS)) { /* TODO: All reads to CSR will clear these interrupts! */ @@ -1546,7 +1547,7 @@ static void atmel_tasklet_func(unsigned long data) wake_up_interruptible(&port->state->port.delta_msr_wait); - atmel_port->irq_status_prev = status; + atmel_port->status_change = 0; } atmel_port->schedule_rx(port); From e0d38ac837e8df6e7eae27e255222af472e64180 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:10 +0200 Subject: [PATCH 068/381] tty/serial: at91: fix some macro definitions to fit coding style This patch updates macro definitions in atmel_serial.h to fit the 80 column rule. Please note that some deprecated comments such as "[AT91SAM9261 only]" are removed as the corresponding bits also exist in some later chips. Signed-off-by: Cyrille Pitchen Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- include/linux/atmel_serial.h | 204 +++++++++++++++++------------------ 1 file changed, 102 insertions(+), 102 deletions(-) diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h index 00beddf6be2035..c384c21d65f044 100644 --- a/include/linux/atmel_serial.h +++ b/include/linux/atmel_serial.h @@ -16,115 +16,115 @@ #ifndef ATMEL_SERIAL_H #define ATMEL_SERIAL_H -#define ATMEL_US_CR 0x00 /* Control Register */ -#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */ -#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */ -#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */ -#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */ -#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */ -#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */ -#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */ -#define ATMEL_US_STTBRK (1 << 9) /* Start Break */ -#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */ -#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */ -#define ATMEL_US_SENDA (1 << 12) /* Send Address */ -#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */ -#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */ -#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */ -#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable [AT91RM9200 only] */ -#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable [AT91RM9200 only] */ -#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */ -#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */ +#define ATMEL_US_CR 0x00 /* Control Register */ +#define ATMEL_US_RSTRX BIT(2) /* Reset Receiver */ +#define ATMEL_US_RSTTX BIT(3) /* Reset Transmitter */ +#define ATMEL_US_RXEN BIT(4) /* Receiver Enable */ +#define ATMEL_US_RXDIS BIT(5) /* Receiver Disable */ +#define ATMEL_US_TXEN BIT(6) /* Transmitter Enable */ +#define ATMEL_US_TXDIS BIT(7) /* Transmitter Disable */ +#define ATMEL_US_RSTSTA BIT(8) /* Reset Status Bits */ +#define ATMEL_US_STTBRK BIT(9) /* Start Break */ +#define ATMEL_US_STPBRK BIT(10) /* Stop Break */ +#define ATMEL_US_STTTO BIT(11) /* Start Time-out */ +#define ATMEL_US_SENDA BIT(12) /* Send Address */ +#define ATMEL_US_RSTIT BIT(13) /* Reset Iterations */ +#define ATMEL_US_RSTNACK BIT(14) /* Reset Non Acknowledge */ +#define ATMEL_US_RETTO BIT(15) /* Rearm Time-out */ +#define ATMEL_US_DTREN BIT(16) /* Data Terminal Ready Enable */ +#define ATMEL_US_DTRDIS BIT(17) /* Data Terminal Ready Disable */ +#define ATMEL_US_RTSEN BIT(18) /* Request To Send Enable */ +#define ATMEL_US_RTSDIS BIT(19) /* Request To Send Disable */ -#define ATMEL_US_MR 0x04 /* Mode Register */ -#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */ -#define ATMEL_US_USMODE_NORMAL 0 -#define ATMEL_US_USMODE_RS485 1 -#define ATMEL_US_USMODE_HWHS 2 -#define ATMEL_US_USMODE_MODEM 3 -#define ATMEL_US_USMODE_ISO7816_T0 4 -#define ATMEL_US_USMODE_ISO7816_T1 6 -#define ATMEL_US_USMODE_IRDA 8 -#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */ -#define ATMEL_US_USCLKS_MCK (0 << 4) -#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) -#define ATMEL_US_USCLKS_SCK (3 << 4) -#define ATMEL_US_CHRL (3 << 6) /* Character Length */ -#define ATMEL_US_CHRL_5 (0 << 6) -#define ATMEL_US_CHRL_6 (1 << 6) -#define ATMEL_US_CHRL_7 (2 << 6) -#define ATMEL_US_CHRL_8 (3 << 6) -#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */ -#define ATMEL_US_PAR (7 << 9) /* Parity Type */ -#define ATMEL_US_PAR_EVEN (0 << 9) -#define ATMEL_US_PAR_ODD (1 << 9) -#define ATMEL_US_PAR_SPACE (2 << 9) -#define ATMEL_US_PAR_MARK (3 << 9) -#define ATMEL_US_PAR_NONE (4 << 9) -#define ATMEL_US_PAR_MULTI_DROP (6 << 9) -#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */ -#define ATMEL_US_NBSTOP_1 (0 << 12) -#define ATMEL_US_NBSTOP_1_5 (1 << 12) -#define ATMEL_US_NBSTOP_2 (2 << 12) -#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */ -#define ATMEL_US_CHMODE_NORMAL (0 << 14) -#define ATMEL_US_CHMODE_ECHO (1 << 14) -#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) -#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) -#define ATMEL_US_MSBF (1 << 16) /* Bit Order */ -#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */ -#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */ -#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */ -#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */ -#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */ -#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */ -#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */ +#define ATMEL_US_MR 0x04 /* Mode Register */ +#define ATMEL_US_USMODE GENMASK(3, 0) /* Mode of the USART */ +#define ATMEL_US_USMODE_NORMAL 0 +#define ATMEL_US_USMODE_RS485 1 +#define ATMEL_US_USMODE_HWHS 2 +#define ATMEL_US_USMODE_MODEM 3 +#define ATMEL_US_USMODE_ISO7816_T0 4 +#define ATMEL_US_USMODE_ISO7816_T1 6 +#define ATMEL_US_USMODE_IRDA 8 +#define ATMEL_US_USCLKS GENMASK(5, 4) /* Clock Selection */ +#define ATMEL_US_USCLKS_MCK (0 << 4) +#define ATMEL_US_USCLKS_MCK_DIV8 (1 << 4) +#define ATMEL_US_USCLKS_SCK (3 << 4) +#define ATMEL_US_CHRL GENMASK(7, 6) /* Character Length */ +#define ATMEL_US_CHRL_5 (0 << 6) +#define ATMEL_US_CHRL_6 (1 << 6) +#define ATMEL_US_CHRL_7 (2 << 6) +#define ATMEL_US_CHRL_8 (3 << 6) +#define ATMEL_US_SYNC BIT(8) /* Synchronous Mode Select */ +#define ATMEL_US_PAR GENMASK(11, 9) /* Parity Type */ +#define ATMEL_US_PAR_EVEN (0 << 9) +#define ATMEL_US_PAR_ODD (1 << 9) +#define ATMEL_US_PAR_SPACE (2 << 9) +#define ATMEL_US_PAR_MARK (3 << 9) +#define ATMEL_US_PAR_NONE (4 << 9) +#define ATMEL_US_PAR_MULTI_DROP (6 << 9) +#define ATMEL_US_NBSTOP GENMASK(13, 12) /* Number of Stop Bits */ +#define ATMEL_US_NBSTOP_1 (0 << 12) +#define ATMEL_US_NBSTOP_1_5 (1 << 12) +#define ATMEL_US_NBSTOP_2 (2 << 12) +#define ATMEL_US_CHMODE GENMASK(15, 14) /* Channel Mode */ +#define ATMEL_US_CHMODE_NORMAL (0 << 14) +#define ATMEL_US_CHMODE_ECHO (1 << 14) +#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14) +#define ATMEL_US_CHMODE_REM_LOOP (3 << 14) +#define ATMEL_US_MSBF BIT(16) /* Bit Order */ +#define ATMEL_US_MODE9 BIT(17) /* 9-bit Character Length */ +#define ATMEL_US_CLKO BIT(18) /* Clock Output Select */ +#define ATMEL_US_OVER BIT(19) /* Oversampling Mode */ +#define ATMEL_US_INACK BIT(20) /* Inhibit Non Acknowledge */ +#define ATMEL_US_DSNACK BIT(21) /* Disable Successive NACK */ +#define ATMEL_US_MAX_ITER GENMASK(26, 24) /* Max Iterations */ +#define ATMEL_US_FILTER BIT(28) /* Infrared Receive Line Filter */ -#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ -#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */ -#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */ -#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */ -#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */ -#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */ -#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */ -#define ATMEL_US_FRAME (1 << 6) /* Framing Error */ -#define ATMEL_US_PARE (1 << 7) /* Parity Error */ -#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */ -#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */ -#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */ -#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */ -#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */ -#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */ -#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change [AT91RM9200 only] */ -#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change [AT91RM9200 only] */ -#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change [AT91RM9200 only] */ -#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */ -#define ATMEL_US_RI (1 << 20) /* RI */ -#define ATMEL_US_DSR (1 << 21) /* DSR */ -#define ATMEL_US_DCD (1 << 22) /* DCD */ -#define ATMEL_US_CTS (1 << 23) /* CTS */ +#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */ +#define ATMEL_US_RXRDY BIT(0) /* Receiver Ready */ +#define ATMEL_US_TXRDY BIT(1) /* Transmitter Ready */ +#define ATMEL_US_RXBRK BIT(2) /* Break Received / End of Break */ +#define ATMEL_US_ENDRX BIT(3) /* End of Receiver Transfer */ +#define ATMEL_US_ENDTX BIT(4) /* End of Transmitter Transfer */ +#define ATMEL_US_OVRE BIT(5) /* Overrun Error */ +#define ATMEL_US_FRAME BIT(6) /* Framing Error */ +#define ATMEL_US_PARE BIT(7) /* Parity Error */ +#define ATMEL_US_TIMEOUT BIT(8) /* Receiver Time-out */ +#define ATMEL_US_TXEMPTY BIT(9) /* Transmitter Empty */ +#define ATMEL_US_ITERATION BIT(10) /* Max number of Repetitions Reached */ +#define ATMEL_US_TXBUFE BIT(11) /* Transmission Buffer Empty */ +#define ATMEL_US_RXBUFF BIT(12) /* Reception Buffer Full */ +#define ATMEL_US_NACK BIT(13) /* Non Acknowledge */ +#define ATMEL_US_RIIC BIT(16) /* Ring Indicator Input Change */ +#define ATMEL_US_DSRIC BIT(17) /* Data Set Ready Input Change */ +#define ATMEL_US_DCDIC BIT(18) /* Data Carrier Detect Input Change */ +#define ATMEL_US_CTSIC BIT(19) /* Clear to Send Input Change */ +#define ATMEL_US_RI BIT(20) /* RI */ +#define ATMEL_US_DSR BIT(21) /* DSR */ +#define ATMEL_US_DCD BIT(22) /* DCD */ +#define ATMEL_US_CTS BIT(23) /* CTS */ -#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */ -#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */ -#define ATMEL_US_CSR 0x14 /* Channel Status Register */ -#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ -#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ -#define ATMEL_US_SYNH (1 << 15) /* Transmit/Receive Sync [AT91SAM9261 only] */ +#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */ +#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */ +#define ATMEL_US_CSR 0x14 /* Channel Status Register */ +#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */ +#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */ +#define ATMEL_US_SYNH BIT(15) /* Transmit/Receive Sync */ -#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ -#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */ +#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */ +#define ATMEL_US_CD GENMASK(15, 0) /* Clock Divider */ -#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ -#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */ +#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */ +#define ATMEL_US_TO GENMASK(15, 0) /* Time-out Value */ -#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ -#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */ +#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */ +#define ATMEL_US_TG GENMASK(7, 0) /* Timeguard Value */ -#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */ -#define ATMEL_US_NER 0x44 /* Number of Errors Register */ -#define ATMEL_US_IF 0x4c /* IrDA Filter Register */ +#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */ +#define ATMEL_US_NER 0x44 /* Number of Errors Register */ +#define ATMEL_US_IF 0x4c /* IrDA Filter Register */ -#define ATMEL_US_NAME 0xf0 /* Ip Name */ -#define ATMEL_US_VERSION 0xfc /* Ip Version */ +#define ATMEL_US_NAME 0xf0 /* Ip Name */ +#define ATMEL_US_VERSION 0xfc /* Ip Version */ #endif From 1c2fd895e9e6dada5ef597579f1a1fff5f153179 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:11 +0200 Subject: [PATCH 069/381] tty/serial: at91: remove bunch of macros to access UART registers This patch replaces the UART_PUT_*, resp. UART_GET_*, macros by atmel_uart_writel(), resp. atmel_uart_readl(), inline function calls. Signed-off-by: Cyrille Pitchen Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 313 +++++++++++++++--------------- 1 file changed, 159 insertions(+), 154 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 2a8f528153e7cf..e7c337de31d19e 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -88,37 +88,6 @@ static void atmel_stop_rx(struct uart_port *port); #define ATMEL_ISR_PASS_LIMIT 256 -/* UART registers. CR is write-only, hence no GET macro */ -#define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) -#define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) -#define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) -#define UART_PUT_IER(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IER) -#define UART_PUT_IDR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_IDR) -#define UART_GET_IMR(port) __raw_readl((port)->membase + ATMEL_US_IMR) -#define UART_GET_CSR(port) __raw_readl((port)->membase + ATMEL_US_CSR) -#define UART_GET_CHAR(port) __raw_readl((port)->membase + ATMEL_US_RHR) -#define UART_PUT_CHAR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_THR) -#define UART_GET_BRGR(port) __raw_readl((port)->membase + ATMEL_US_BRGR) -#define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) -#define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) -#define UART_PUT_TTGR(port, v) __raw_writel(v, (port)->membase + ATMEL_US_TTGR) -#define UART_GET_IP_NAME(port) __raw_readl((port)->membase + ATMEL_US_NAME) -#define UART_GET_IP_VERSION(port) __raw_readl((port)->membase + ATMEL_US_VERSION) - - /* PDC registers */ -#define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) -#define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) - -#define UART_PUT_RPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RPR) -#define UART_GET_RPR(port) __raw_readl((port)->membase + ATMEL_PDC_RPR) -#define UART_PUT_RCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RCR) -#define UART_PUT_RNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNPR) -#define UART_PUT_RNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_RNCR) - -#define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) -#define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) -#define UART_GET_TCR(port) __raw_readl((port)->membase + ATMEL_PDC_TCR) - struct atmel_dma_buffer { unsigned char *buf; dma_addr_t dma_addr; @@ -212,6 +181,16 @@ to_atmel_uart_port(struct uart_port *uart) return container_of(uart, struct atmel_uart_port, uart); } +static inline u32 atmel_uart_readl(struct uart_port *port, u32 reg) +{ + return __raw_readl(port->membase + reg); +} + +static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) +{ + __raw_writel(value, port->membase + reg); +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -257,7 +236,7 @@ static unsigned int atmel_get_lines_status(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, ret = 0; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); mctrl_gpio_get(atmel_port->gpios, &ret); @@ -304,9 +283,9 @@ static int atmel_config_rs485(struct uart_port *port, unsigned int mode; /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - mode = UART_GET_MR(port); + mode = atmel_uart_readl(port, ATMEL_US_MR); /* Resetting serial mode to RS232 (0x0) */ mode &= ~ATMEL_US_USMODE; @@ -316,7 +295,8 @@ static int atmel_config_rs485(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { dev_dbg(port->dev, "Setting UART to RS485\n"); atmel_port->tx_done_mask = ATMEL_US_TXEMPTY; - UART_PUT_TTGR(port, rs485conf->delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + rs485conf->delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else { dev_dbg(port->dev, "Setting UART to RS232\n"); @@ -326,10 +306,10 @@ static int atmel_config_rs485(struct uart_port *port, else atmel_port->tx_done_mask = ATMEL_US_TXRDY; } - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); return 0; } @@ -339,7 +319,9 @@ static int atmel_config_rs485(struct uart_port *port, */ static u_int atmel_tx_empty(struct uart_port *port) { - return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0; + return (atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXEMPTY) ? + TIOCSER_TEMT : + 0; } /* @@ -348,13 +330,14 @@ static u_int atmel_tx_empty(struct uart_port *port) static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) { unsigned int control = 0; - unsigned int mode = UART_GET_MR(port); + unsigned int mode = atmel_uart_readl(port, ATMEL_US_MR); unsigned int rts_paused, rts_ready; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); /* override mode to RS485 if needed, otherwise keep the current mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + port->rs485.delay_rts_after_send); mode &= ~ATMEL_US_USMODE; mode |= ATMEL_US_USMODE_RS485; } @@ -384,7 +367,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) else control |= ATMEL_US_DTRDIS; - UART_PUT_CR(port, control); + atmel_uart_writel(port, ATMEL_US_CR, control); mctrl_gpio_set(atmel_port->gpios, mctrl); @@ -395,7 +378,7 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) else mode |= ATMEL_US_CHMODE_NORMAL; - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); } /* @@ -406,7 +389,7 @@ static u_int atmel_get_mctrl(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int ret = 0, status; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); /* * The control signals are active low. @@ -432,10 +415,10 @@ static void atmel_stop_tx(struct uart_port *port) if (atmel_use_pdc_tx(port)) { /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); } /* Disable interrupts */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) @@ -450,7 +433,7 @@ static void atmel_start_tx(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_use_pdc_tx(port)) { - if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + if (atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN) /* The transmitter is already running. Yes, we really need this.*/ return; @@ -460,10 +443,10 @@ static void atmel_start_tx(struct uart_port *port) atmel_stop_rx(port); /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); } /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } /* @@ -471,17 +454,19 @@ static void atmel_start_tx(struct uart_port *port) */ static void atmel_start_rx(struct uart_port *port) { - UART_PUT_CR(port, ATMEL_US_RSTSTA); /* reset status and receiver */ + /* reset status and receiver */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); - UART_PUT_CR(port, ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXEN); if (atmel_use_pdc_rx(port)) { /* enable PDC controller */ - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else { - UART_PUT_IER(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); } } @@ -490,15 +475,16 @@ static void atmel_start_rx(struct uart_port *port) */ static void atmel_stop_rx(struct uart_port *port) { - UART_PUT_CR(port, ATMEL_US_RXDIS); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RXDIS); if (atmel_use_pdc_rx(port)) { /* disable PDC receive */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); - UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | - port->read_status_mask); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT | + port->read_status_mask); } else { - UART_PUT_IDR(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXRDY); } } @@ -538,7 +524,7 @@ static void atmel_enable_ms(struct uart_port *port) else ier |= ATMEL_US_DCDIC; - UART_PUT_IER(port, ier); + atmel_uart_writel(port, ATMEL_US_IER, ier); } /* @@ -577,7 +563,7 @@ static void atmel_disable_ms(struct uart_port *port) else idr |= ATMEL_US_DCDIC; - UART_PUT_IDR(port, idr); + atmel_uart_writel(port, ATMEL_US_IDR, idr); } /* @@ -586,9 +572,11 @@ static void atmel_disable_ms(struct uart_port *port) static void atmel_break_ctl(struct uart_port *port, int break_state) { if (break_state != 0) - UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */ + /* start break */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTBRK); else - UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */ + /* stop break */ + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STPBRK); } /* @@ -622,7 +610,7 @@ atmel_buffer_rx_char(struct uart_port *port, unsigned int status, static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) { /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK) { /* ignore side-effect */ @@ -645,9 +633,9 @@ static void atmel_rx_chars(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); unsigned int status, ch; - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = UART_GET_CHAR(port); + ch = atmel_uart_readl(port, ATMEL_US_RHR); /* * note that the error handling code is @@ -658,12 +646,13 @@ static void atmel_rx_chars(struct uart_port *port) || atmel_port->break_active)) { /* clear error */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); if (status & ATMEL_US_RXBRK && !atmel_port->break_active) { atmel_port->break_active = 1; - UART_PUT_IER(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_RXBRK); } else { /* * This is either the end-of-break @@ -672,14 +661,15 @@ static void atmel_rx_chars(struct uart_port *port) * being set. In both cases, the next * RXBRK will indicate start-of-break. */ - UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_RXBRK); status &= ~ATMEL_US_RXBRK; atmel_port->break_active = 0; } } atmel_buffer_rx_char(port, status, ch); - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); } tasklet_schedule(&atmel_port->tasklet); @@ -694,16 +684,18 @@ static void atmel_tx_chars(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (port->x_char && UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, port->x_char); + if (port->x_char && + (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { + atmel_uart_writel(port, ATMEL_US_THR, port->x_char); port->icount.tx++; port->x_char = 0; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; - while (UART_GET_CSR(port) & atmel_port->tx_done_mask) { - UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + while (atmel_uart_readl(port, ATMEL_US_CSR) & + atmel_port->tx_done_mask) { + atmel_uart_writel(port, ATMEL_US_THR, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -715,7 +707,8 @@ static void atmel_tx_chars(struct uart_port *port) if (!uart_circ_empty(xmit)) /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } static void atmel_complete_tx_dma(void *arg) @@ -935,14 +928,14 @@ static void atmel_rx_from_dma(struct uart_port *port) /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); dmastat = dmaengine_tx_status(chan, atmel_port->cookie_rx, &state); /* Restart a new tasklet if DMA status is error */ if (dmastat == DMA_ERROR) { dev_dbg(port->dev, "Get residue error, restart tasklet\n"); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); tasklet_schedule(&atmel_port->tasklet); return; } @@ -1008,7 +1001,7 @@ static void atmel_rx_from_dma(struct uart_port *port) tty_flip_buffer_push(tport); spin_lock(&port->lock); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_TIMEOUT); } static int atmel_prepare_rx_dma(struct uart_port *port) @@ -1118,8 +1111,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) * the moment. */ if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { - UART_PUT_IDR(port, (ATMEL_US_ENDRX - | ATMEL_US_TIMEOUT)); + atmel_uart_writel(port, ATMEL_US_IDR, + (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)); tasklet_schedule(&atmel_port->tasklet); } @@ -1130,7 +1123,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) if (atmel_use_dma_rx(port)) { if (pending & ATMEL_US_TIMEOUT) { - UART_PUT_IDR(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_TIMEOUT); tasklet_schedule(&atmel_port->tasklet); } } @@ -1143,8 +1137,8 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending) * End of break detected. If it came along with a * character, atmel_rx_chars will handle it. */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_IDR, ATMEL_US_RXBRK); atmel_port->break_active = 0; } } @@ -1159,7 +1153,8 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) if (pending & atmel_port->tx_done_mask) { /* Either PDC or interrupt transmission */ - UART_PUT_IDR(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IDR, + atmel_port->tx_done_mask); tasklet_schedule(&atmel_port->tasklet); } } @@ -1197,7 +1192,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) do { status = atmel_get_lines_status(port); - mask = UART_GET_IMR(port); + mask = atmel_uart_readl(port, ATMEL_US_IMR); pending = status & mask; if (!gpio_handled) { /* @@ -1223,7 +1218,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) if (atmel_port->suspended) { atmel_port->pending |= pending; atmel_port->pending_status = status; - UART_PUT_IDR(port, mask); + atmel_uart_writel(port, ATMEL_US_IDR, mask); pm_system_wakeup(); break; } @@ -1260,7 +1255,7 @@ static void atmel_tx_pdc(struct uart_port *port) int count; /* nothing left to transmit? */ - if (UART_GET_TCR(port)) + if (atmel_uart_readl(port, ATMEL_PDC_TCR)) return; xmit->tail += pdc->ofs; @@ -1272,7 +1267,7 @@ static void atmel_tx_pdc(struct uart_port *port) /* more to transmit - setup next transfer */ /* disable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) { dma_sync_single_for_device(port->dev, @@ -1283,12 +1278,14 @@ static void atmel_tx_pdc(struct uart_port *port) count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); pdc->ofs = count; - UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); - UART_PUT_TCR(port, count); + atmel_uart_writel(port, ATMEL_PDC_TPR, + pdc->dma_addr + xmit->tail); + atmel_uart_writel(port, ATMEL_PDC_TCR, count); /* re-enable PDC transmit */ - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); /* Enable interrupts */ - UART_PUT_IER(port, atmel_port->tx_done_mask); + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } else { if ((port->rs485.flags & SER_RS485_ENABLED) && !(port->rs485.flags & SER_RS485_RX_DURING_TX)) { @@ -1414,10 +1411,10 @@ static void atmel_rx_from_pdc(struct uart_port *port) do { /* Reset the UART timeout early so that we don't miss one */ - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); pdc = &atmel_port->pdc_rx[rx_idx]; - head = UART_GET_RPR(port) - pdc->dma_addr; + head = atmel_uart_readl(port, ATMEL_PDC_RPR) - pdc->dma_addr; tail = pdc->ofs; /* If the PDC has switched buffers, RPR won't contain @@ -1460,8 +1457,8 @@ static void atmel_rx_from_pdc(struct uart_port *port) */ if (head >= pdc->dma_size) { pdc->ofs = 0; - UART_PUT_RNPR(port, pdc->dma_addr); - UART_PUT_RNCR(port, pdc->dma_size); + atmel_uart_writel(port, ATMEL_PDC_RNPR, pdc->dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RNCR, pdc->dma_size); rx_idx = !rx_idx; atmel_port->pdc_rx_idx = rx_idx; @@ -1476,7 +1473,8 @@ static void atmel_rx_from_pdc(struct uart_port *port) tty_flip_buffer_push(tport); spin_lock(&port->lock); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } static int atmel_prepare_rx_pdc(struct uart_port *port) @@ -1509,11 +1507,12 @@ static int atmel_prepare_rx_pdc(struct uart_port *port) atmel_port->pdc_rx_idx = 0; - UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); - UART_PUT_RCR(port, PDC_BUFFER_SIZE); + atmel_uart_writel(port, ATMEL_PDC_RPR, atmel_port->pdc_rx[0].dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RCR, PDC_BUFFER_SIZE); - UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); - UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + atmel_uart_writel(port, ATMEL_PDC_RNPR, + atmel_port->pdc_rx[1].dma_addr); + atmel_uart_writel(port, ATMEL_PDC_RNCR, PDC_BUFFER_SIZE); return 0; } @@ -1667,7 +1666,7 @@ static void atmel_set_ops(struct uart_port *port) static void atmel_get_ip_name(struct uart_port *port) { struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - int name = UART_GET_IP_NAME(port); + int name = atmel_uart_readl(port, ATMEL_US_NAME); u32 version; int usart, uart; /* usart and uart ascii */ @@ -1684,7 +1683,7 @@ static void atmel_get_ip_name(struct uart_port *port) atmel_port->is_usart = false; } else { /* fallback for older SoCs: use version field */ - version = UART_GET_IP_VERSION(port); + version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { case 0x302: case 0x10213: @@ -1756,7 +1755,7 @@ static int atmel_startup(struct uart_port *port) * request_irq() is called we could get stuck trying to * handle an unexpected interrupt */ - UART_PUT_IDR(port, -1); + atmel_uart_writel(port, ATMEL_US_IDR, -1); atmel_port->ms_irq_enabled = false; /* @@ -1804,9 +1803,9 @@ static int atmel_startup(struct uart_port *port) /* * Finally, enable the serial port */ - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); /* enable xmit & rcvr */ - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); setup_timer(&atmel_port->uart_timer, atmel_uart_timer_callback, @@ -1819,13 +1818,14 @@ static int atmel_startup(struct uart_port *port) jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); } /* enable PDC controller */ - UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); } else if (atmel_use_dma_rx(port)) { /* set UART timeout */ if (!atmel_port->is_usart) { @@ -1833,14 +1833,15 @@ static int atmel_startup(struct uart_port *port) jiffies + uart_poll_timeout(port)); /* set USART timeout */ } else { - UART_PUT_RTOR(port, PDC_RX_TIMEOUT); - UART_PUT_CR(port, ATMEL_US_STTTO); + atmel_uart_writel(port, ATMEL_US_RTOR, PDC_RX_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_STTTO); - UART_PUT_IER(port, ATMEL_US_TIMEOUT); + atmel_uart_writel(port, ATMEL_US_IER, + ATMEL_US_TIMEOUT); } } else { /* enable receive only */ - UART_PUT_IER(port, ATMEL_US_RXRDY); + atmel_uart_writel(port, ATMEL_US_IER, ATMEL_US_RXRDY); } return 0; @@ -1860,7 +1861,7 @@ static void atmel_flush_buffer(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_use_pdc_tx(port)) { - UART_PUT_TCR(port, 0); + atmel_uart_writel(port, ATMEL_PDC_TCR, 0); atmel_port->pdc_tx.ofs = 0; } } @@ -1892,8 +1893,8 @@ static void atmel_shutdown(struct uart_port *port) atmel_stop_rx(port); atmel_stop_tx(port); - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, -1); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* @@ -1938,12 +1939,12 @@ static void atmel_serial_pm(struct uart_port *port, unsigned int state, clk_prepare_enable(atmel_port->clk); /* re-enable interrupts if we disabled some on suspend */ - UART_PUT_IER(port, atmel_port->backup_imr); + atmel_uart_writel(port, ATMEL_US_IER, atmel_port->backup_imr); break; case 3: /* Back up the interrupt mask and disable all interrupts */ - atmel_port->backup_imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); + atmel_port->backup_imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* * Disable the peripheral clock for this serial port. @@ -1966,7 +1967,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, unsigned int old_mode, mode, imr, quot, baud; /* save the current mode register */ - mode = old_mode = UART_GET_MR(port); + mode = old_mode = atmel_uart_readl(port, ATMEL_US_MR); /* reset the mode, clock divisor, parity, stop bits and data size */ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | @@ -2025,7 +2026,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, if (atmel_use_pdc_rx(port)) /* need to enable error interrupts */ - UART_PUT_IER(port, port->read_status_mask); + atmel_uart_writel(port, ATMEL_US_IER, port->read_status_mask); /* * Characters to ignore @@ -2052,15 +2053,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, * transmitter is empty if requested by the caller, so there's * no need to wait for it here. */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, -1); + imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, -1); /* disable receiver and transmitter */ - UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXDIS | ATMEL_US_RXDIS); /* mode */ if (port->rs485.flags & SER_RS485_ENABLED) { - UART_PUT_TTGR(port, port->rs485.delay_rts_after_send); + atmel_uart_writel(port, ATMEL_US_TTGR, + port->rs485.delay_rts_after_send); mode |= ATMEL_US_USMODE_RS485; } else if (termios->c_cflag & CRTSCTS) { /* RS232 with hardware handshake (RTS/CTS) */ @@ -2071,7 +2073,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, } /* set the mode, clock divisor, parity, stop bits and data size */ - UART_PUT_MR(port, mode); + atmel_uart_writel(port, ATMEL_US_MR, mode); /* * when switching the mode, set the RTS line state according to the @@ -2088,16 +2090,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, rts_state = ATMEL_US_RTSEN; } - UART_PUT_CR(port, rts_state); + atmel_uart_writel(port, ATMEL_US_CR, rts_state); } /* set the baud rate */ - UART_PUT_BRGR(port, quot); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_BRGR, quot); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); /* restore interrupts */ - UART_PUT_IER(port, imr); + atmel_uart_writel(port, ATMEL_US_IER, imr); /* CTS flow-control and modem-status interrupts */ if (UART_ENABLE_MS(port, termios->c_cflag)) @@ -2208,18 +2210,18 @@ static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser) #ifdef CONFIG_CONSOLE_POLL static int atmel_poll_get_char(struct uart_port *port) { - while (!(UART_GET_CSR(port) & ATMEL_US_RXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return UART_GET_CHAR(port); + return atmel_uart_readl(port, ATMEL_US_RHR); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - UART_PUT_CHAR(port, ch); + atmel_uart_writel(port, ATMEL_US_THR, ch); } #endif @@ -2324,9 +2326,9 @@ struct platform_device *atmel_default_console_device; /* the serial console devi #ifdef CONFIG_SERIAL_ATMEL_CONSOLE static void atmel_console_putchar(struct uart_port *port, int ch) { - while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - UART_PUT_CHAR(port, ch); + atmel_uart_writel(port, ATMEL_US_THR, ch); } /* @@ -2342,12 +2344,13 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) /* * First, save IMR and then disable interrupts */ - imr = UART_GET_IMR(port); - UART_PUT_IDR(port, ATMEL_US_RXRDY | atmel_port->tx_done_mask); + imr = atmel_uart_readl(port, ATMEL_US_IMR); + atmel_uart_writel(port, ATMEL_US_IDR, + ATMEL_US_RXRDY | atmel_port->tx_done_mask); /* Store PDC transmit status and disable it */ - pdc_tx = UART_GET_PTSR(port) & ATMEL_PDC_TXTEN; - UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + pdc_tx = atmel_uart_readl(port, ATMEL_PDC_PTSR) & ATMEL_PDC_TXTEN; + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS); uart_console_write(port, s, count, atmel_console_putchar); @@ -2356,15 +2359,15 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) * and restore IMR */ do { - status = UART_GET_CSR(port); + status = atmel_uart_readl(port, ATMEL_US_CSR); } while (!(status & ATMEL_US_TXRDY)); /* Restore PDC transmit status */ if (pdc_tx) - UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + atmel_uart_writel(port, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); /* set interrupts back the way they were */ - UART_PUT_IER(port, imr); + atmel_uart_writel(port, ATMEL_US_IER, imr); } /* @@ -2380,17 +2383,17 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, * If the baud rate generator isn't running, the port wasn't * initialized by the boot loader. */ - quot = UART_GET_BRGR(port) & ATMEL_US_CD; + quot = atmel_uart_readl(port, ATMEL_US_BRGR) & ATMEL_US_CD; if (!quot) return; - mr = UART_GET_MR(port) & ATMEL_US_CHRL; + mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_CHRL; if (mr == ATMEL_US_CHRL_8) *bits = 8; else *bits = 7; - mr = UART_GET_MR(port) & ATMEL_US_PAR; + mr = atmel_uart_readl(port, ATMEL_US_MR) & ATMEL_US_PAR; if (mr == ATMEL_US_PAR_EVEN) *parity = 'e'; else if (mr == ATMEL_US_PAR_ODD) @@ -2423,9 +2426,9 @@ static int __init atmel_console_setup(struct console *co, char *options) if (ret) return ret; - UART_PUT_IDR(port, -1); - UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); + atmel_uart_writel(port, ATMEL_US_IDR, -1); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); + atmel_uart_writel(port, ATMEL_US_CR, ATMEL_US_TXEN | ATMEL_US_RXEN); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -2532,7 +2535,8 @@ static int atmel_serial_suspend(struct platform_device *pdev, if (atmel_is_console_port(port) && console_suspend_enabled) { /* Drain the TX shifter */ - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) + while (!(atmel_uart_readl(port, ATMEL_US_CSR) & + ATMEL_US_TXEMPTY)) cpu_relax(); } @@ -2684,8 +2688,9 @@ static int atmel_serial_probe(struct platform_device *pdev) clk_prepare_enable(port->clk); if (rs485_enabled) { - UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL); - UART_PUT_CR(&port->uart, ATMEL_US_RTSEN); + atmel_uart_writel(&port->uart, ATMEL_US_MR, + ATMEL_US_USMODE_NORMAL); + atmel_uart_writel(&port->uart, ATMEL_US_CR, ATMEL_US_RTSEN); } /* From e2c2a91abd6804c29cf25414488758c9cd13a84d Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:12 +0200 Subject: [PATCH 070/381] tty/serial: at91: add support to FIFOs Depending on the hardware, TX and RX FIFOs may be available. The RX FIFO can avoid receive overruns, especially when DMA transfers are not used to read data from the Receive Holding Register. For heavy system load, The CPU is likely not be able to fetch data fast enough from the RHR. In addition, the RX FIFO can supersede the DMA/PDC to control the RTS line when the Hardware Handshaking mode is enabled. Two thresholds are to be set for that purpose: - When the number of data in the RX FIFO crosses and becomes lower than or equal to the low threshold, the RTS line is set to low level: the remote peer is requested to send data. - When the number of data in the RX FIFO crosses and becomes greater than or equal to the high threshold, the RTS line is set to high level: the remote peer should stop sending new data. - low threshold <= high threshold Once these two thresholds are set properly, this new feature is enabled by setting the FIFO RTS Control bit of the FIFO Mode Register. FIFOs also introduce a new multiple data mode: the USART works either in multiple data mode or in single data (legacy) mode. If MODE9 bit is set into the Mode Register or if USMODE is set to either LIN_MASTER, LIN_SLAVE or LON_MODE, FIFOs operate in single data mode. Otherwise, they operate in multiple data mode. In this new multiple data mode, accesses to the Receive Holding Register or Transmit Holding Register slightly change. Since this driver implements neither the 9bit data feature (MODE9 bit set into the Mode Register) nor LIN modes, the USART works in multiple data mode whenever FIFOs are available and enabled. We also assume that data are 8bit wide. In single data mode, 32bit access CAN be used to read a single data from RHR or write a single data into THR. However in multiple data mode, a 32bit access to RHR now allows us to read four consecutive data from RX FIFO. Also a 32bit access to THR now allows to write four consecutive data into TX FIFO. So we MUST use 8bit access whenever only one data have to be read/written at a time. Signed-off-by: Cyrille Pitchen Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 100 ++++++++++++++++++++++++++++-- include/linux/atmel_serial.h | 36 +++++++++++ 2 files changed, 130 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e7c337de31d19e..87de21f0c7a3fa 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -56,6 +56,15 @@ /* Revisit: We should calculate this based on the actual port settings */ #define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ +/* The minium number of data FIFOs should be able to contain */ +#define ATMEL_MIN_FIFO_SIZE 8 +/* + * These two offsets are substracted from the RX FIFO size to define the RTS + * high and low thresholds + */ +#define ATMEL_RTS_HIGH_OFFSET 16 +#define ATMEL_RTS_LOW_OFFSET 20 + #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif @@ -141,6 +150,9 @@ struct atmel_uart_port { struct mctrl_gpios *gpios; int gpio_irq[UART_GPIO_MAX]; unsigned int tx_done_mask; + u32 fifo_size; + u32 rts_high; + u32 rts_low; bool ms_irq_enabled; bool is_usart; /* usart or uart */ struct timer_list uart_timer; /* uart timer */ @@ -191,6 +203,16 @@ static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) __raw_writel(value, port->membase + reg); } +static inline u8 atmel_uart_readb(struct uart_port *port, u32 reg) +{ + return __raw_readb(port->membase + reg); +} + +static inline void atmel_uart_writeb(struct uart_port *port, u32 reg, u8 value) +{ + __raw_writeb(value, port->membase + reg); +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -635,7 +657,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = atmel_uart_readl(port, ATMEL_US_RHR); + ch = atmel_uart_readb(port, ATMEL_US_RHR); /* * note that the error handling code is @@ -686,7 +708,7 @@ static void atmel_tx_chars(struct uart_port *port) if (port->x_char && (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { - atmel_uart_writel(port, ATMEL_US_THR, port->x_char); + atmel_uart_writeb(port, ATMEL_US_THR, port->x_char); port->icount.tx++; port->x_char = 0; } @@ -695,7 +717,7 @@ static void atmel_tx_chars(struct uart_port *port) while (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask) { - atmel_uart_writel(port, ATMEL_US_THR, xmit->buf[xmit->tail]); + atmel_uart_writeb(port, ATMEL_US_THR, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -1796,6 +1818,29 @@ static int atmel_startup(struct uart_port *port) atmel_set_ops(port); } + /* + * Enable FIFO when available + */ + if (atmel_port->fifo_size) { + unsigned int txrdym = ATMEL_US_ONE_DATA; + unsigned int rxrdym = ATMEL_US_ONE_DATA; + unsigned int fmr; + + atmel_uart_writel(port, ATMEL_US_CR, + ATMEL_US_FIFOEN | + ATMEL_US_RXFCLR | + ATMEL_US_TXFLCLR); + + fmr = ATMEL_US_TXRDYM(txrdym) | ATMEL_US_RXRDYM(rxrdym); + if (atmel_port->rts_high && + atmel_port->rts_low) + fmr |= ATMEL_US_FRTSC | + ATMEL_US_RXFTHRES(atmel_port->rts_high) | + ATMEL_US_RXFTHRES2(atmel_port->rts_low); + + atmel_uart_writel(port, ATMEL_US_FMR, fmr); + } + /* Save current CSR for comparison in atmel_tasklet_func() */ atmel_port->irq_status_prev = atmel_get_lines_status(port); atmel_port->irq_status = atmel_port->irq_status_prev; @@ -2213,7 +2258,7 @@ static int atmel_poll_get_char(struct uart_port *port) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return atmel_uart_readl(port, ATMEL_US_RHR); + return atmel_uart_readb(port, ATMEL_US_RHR); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) @@ -2221,7 +2266,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writel(port, ATMEL_US_THR, ch); + atmel_uart_writeb(port, ATMEL_US_THR, ch); } #endif @@ -2328,7 +2373,7 @@ static void atmel_console_putchar(struct uart_port *port, int ch) { while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writel(port, ATMEL_US_THR, ch); + atmel_uart_writeb(port, ATMEL_US_THR, ch); } /* @@ -2603,6 +2648,48 @@ static int atmel_init_gpios(struct atmel_uart_port *p, struct device *dev) return 0; } +static void atmel_serial_probe_fifos(struct atmel_uart_port *port, + struct platform_device *pdev) +{ + port->fifo_size = 0; + port->rts_low = 0; + port->rts_high = 0; + + if (of_property_read_u32(pdev->dev.of_node, + "atmel,fifo-size", + &port->fifo_size)) + return; + + if (!port->fifo_size) + return; + + if (port->fifo_size < ATMEL_MIN_FIFO_SIZE) { + port->fifo_size = 0; + dev_err(&pdev->dev, "Invalid FIFO size\n"); + return; + } + + /* + * 0 <= rts_low <= rts_high <= fifo_size + * Once their CTS line asserted by the remote peer, some x86 UARTs tend + * to flush their internal TX FIFO, commonly up to 16 data, before + * actually stopping to send new data. So we try to set the RTS High + * Threshold to a reasonably high value respecting this 16 data + * empirical rule when possible. + */ + port->rts_high = max_t(int, port->fifo_size >> 1, + port->fifo_size - ATMEL_RTS_HIGH_OFFSET); + port->rts_low = max_t(int, port->fifo_size >> 2, + port->fifo_size - ATMEL_RTS_LOW_OFFSET); + + dev_info(&pdev->dev, "Using FIFO (%u data)\n", + port->fifo_size); + dev_dbg(&pdev->dev, "RTS High Threshold : %2u data\n", + port->rts_high); + dev_dbg(&pdev->dev, "RTS Low Threshold : %2u data\n", + port->rts_low); +} + static int atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; @@ -2639,6 +2726,7 @@ static int atmel_serial_probe(struct platform_device *pdev) port = &atmel_ports[ret]; port->backup_imr = 0; port->uart.line = ret; + atmel_serial_probe_fifos(port, pdev); spin_lock_init(&port->lock_suspended); diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h index c384c21d65f044..ee696d7e8a43e4 100644 --- a/include/linux/atmel_serial.h +++ b/include/linux/atmel_serial.h @@ -35,6 +35,11 @@ #define ATMEL_US_DTRDIS BIT(17) /* Data Terminal Ready Disable */ #define ATMEL_US_RTSEN BIT(18) /* Request To Send Enable */ #define ATMEL_US_RTSDIS BIT(19) /* Request To Send Disable */ +#define ATMEL_US_TXFCLR BIT(24) /* Transmit FIFO Clear */ +#define ATMEL_US_RXFCLR BIT(25) /* Receive FIFO Clear */ +#define ATMEL_US_TXFLCLR BIT(26) /* Transmit FIFO Lock Clear */ +#define ATMEL_US_FIFOEN BIT(30) /* FIFO enable */ +#define ATMEL_US_FIFODIS BIT(31) /* FIFO disable */ #define ATMEL_US_MR 0x04 /* Mode Register */ #define ATMEL_US_USMODE GENMASK(3, 0) /* Mode of the USART */ @@ -124,6 +129,37 @@ #define ATMEL_US_NER 0x44 /* Number of Errors Register */ #define ATMEL_US_IF 0x4c /* IrDA Filter Register */ +#define ATMEL_US_CMPR 0x90 /* Comparaison Register */ +#define ATMEL_US_FMR 0xa0 /* FIFO Mode Register */ +#define ATMEL_US_TXRDYM(data) (((data) & 0x3) << 0) /* TX Ready Mode */ +#define ATMEL_US_RXRDYM(data) (((data) & 0x3) << 4) /* RX Ready Mode */ +#define ATMEL_US_ONE_DATA 0x0 +#define ATMEL_US_TWO_DATA 0x1 +#define ATMEL_US_FOUR_DATA 0x2 +#define ATMEL_US_FRTSC BIT(7) /* FIFO RTS pin Control */ +#define ATMEL_US_TXFTHRES(thr) (((thr) & 0x3f) << 8) /* TX FIFO Threshold */ +#define ATMEL_US_RXFTHRES(thr) (((thr) & 0x3f) << 16) /* RX FIFO Threshold */ +#define ATMEL_US_RXFTHRES2(thr) (((thr) & 0x3f) << 24) /* RX FIFO Threshold2 */ + +#define ATMEL_US_FLR 0xa4 /* FIFO Level Register */ +#define ATMEL_US_TXFL(reg) (((reg) >> 0) & 0x3f) /* TX FIFO Level */ +#define ATMEL_US_RXFL(reg) (((reg) >> 16) & 0x3f) /* RX FIFO Level */ + +#define ATMEL_US_FIER 0xa8 /* FIFO Interrupt Enable Register */ +#define ATMEL_US_FIDR 0xac /* FIFO Interrupt Disable Register */ +#define ATMEL_US_FIMR 0xb0 /* FIFO Interrupt Mask Register */ +#define ATMEL_US_FESR 0xb4 /* FIFO Event Status Register */ +#define ATMEL_US_TXFEF BIT(0) /* Transmit FIFO Empty Flag */ +#define ATMEL_US_TXFFF BIT(1) /* Transmit FIFO Full Flag */ +#define ATMEL_US_TXFTHF BIT(2) /* Transmit FIFO Threshold Flag */ +#define ATMEL_US_RXFEF BIT(3) /* Receive FIFO Empty Flag */ +#define ATMEL_US_RXFFF BIT(4) /* Receive FIFO Full Flag */ +#define ATMEL_US_RXFTHF BIT(5) /* Receive FIFO Threshold Flag */ +#define ATMEL_US_TXFPTEF BIT(6) /* Transmit FIFO Pointer Error Flag */ +#define ATMEL_US_RXFPTEF BIT(7) /* Receive FIFO Pointer Error Flag */ +#define ATMEL_US_TXFLOCK BIT(8) /* Transmit FIFO Lock (FESR only) */ +#define ATMEL_US_RXFTHF2 BIT(9) /* Receive FIFO Threshold Flag 2 */ + #define ATMEL_US_NAME 0xf0 /* Ip Name */ #define ATMEL_US_VERSION 0xfc /* Ip Version */ From 36d57dde2a94ad1597c263fb76ee5fa1807be8c7 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 2 Jul 2015 15:18:13 +0200 Subject: [PATCH 071/381] tty/serial: at91: use 32bit writes into TX FIFO when DMA is enabled For now this improvement is only used with TX DMA transfers. The data width must be set properly when configuring the DMA controller. Also the FIFO configuration must be set to match the DMA transfer data width: TXRDYM (Transmitter Ready Mode) and RXRDYM (Receiver Ready Mode) must be set into the FIFO Mode Register. These values are used by the USART to trigger the DMA controller. In single data mode they are not used and should be reset to 0. So the TXRDYM bits are changed to FOUR_DATA; then USART triggers the DMA controller when at least 4 data can be written into the TX FIFO througth the THR. On the other hand the RXRDYM bits are left unchanged to ONE_DATA. Atmel eXtended DMA controller allows us to set a different data width for each part of a scatter-gather transfer. So when calling dmaengine_slave_config() to configure the TX path, we just need to set dst_addr_width to the maximum data width. Then DMA writes into THR are split into up to two parts. The first part carries the first data to be sent and has a length equal to the greatest multiple of 4 (bytes) lower than or equal to the total length of the TX DMA transfer. The second part carries the trailing data (up to 3 bytes). The first part is written by the DMA into THR using 32 bit accesses, whereas 8bit accesses are used for the second part. Signed-off-by: Cyrille Pitchen Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 66 ++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 87de21f0c7a3fa..e91b3b2f059050 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -144,6 +144,7 @@ struct atmel_uart_port { unsigned int irq_status; unsigned int irq_status_prev; unsigned int status_change; + unsigned int tx_len; struct circ_buf rx_ring; @@ -745,10 +746,10 @@ static void atmel_complete_tx_dma(void *arg) if (chan) dmaengine_terminate_all(chan); - xmit->tail += sg_dma_len(&atmel_port->sg_tx); + xmit->tail += atmel_port->tx_len; xmit->tail &= UART_XMIT_SIZE - 1; - port->icount.tx += sg_dma_len(&atmel_port->sg_tx); + port->icount.tx += atmel_port->tx_len; spin_lock_irq(&atmel_port->lock_tx); async_tx_ack(atmel_port->desc_tx); @@ -796,7 +797,9 @@ static void atmel_tx_dma(struct uart_port *port) struct circ_buf *xmit = &port->state->xmit; struct dma_chan *chan = atmel_port->chan_tx; struct dma_async_tx_descriptor *desc; - struct scatterlist *sg = &atmel_port->sg_tx; + struct scatterlist sgl[2], *sg, *sg_tx = &atmel_port->sg_tx; + unsigned int tx_len, part1_len, part2_len, sg_len; + dma_addr_t phys_addr; /* Make sure we have an idle channel */ if (atmel_port->desc_tx != NULL) @@ -812,18 +815,46 @@ static void atmel_tx_dma(struct uart_port *port) * Take the port lock to get a * consistent xmit buffer state. */ - sg->offset = xmit->tail & (UART_XMIT_SIZE - 1); - sg_dma_address(sg) = (sg_dma_address(sg) & - ~(UART_XMIT_SIZE - 1)) - + sg->offset; - sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head, - xmit->tail, - UART_XMIT_SIZE); - BUG_ON(!sg_dma_len(sg)); + tx_len = CIRC_CNT_TO_END(xmit->head, + xmit->tail, + UART_XMIT_SIZE); + + if (atmel_port->fifo_size) { + /* multi data mode */ + part1_len = (tx_len & ~0x3); /* DWORD access */ + part2_len = (tx_len & 0x3); /* BYTE access */ + } else { + /* single data (legacy) mode */ + part1_len = 0; + part2_len = tx_len; /* BYTE access only */ + } + + sg_init_table(sgl, 2); + sg_len = 0; + phys_addr = sg_dma_address(sg_tx) + xmit->tail; + if (part1_len) { + sg = &sgl[sg_len++]; + sg_dma_address(sg) = phys_addr; + sg_dma_len(sg) = part1_len; + + phys_addr += part1_len; + } + + if (part2_len) { + sg = &sgl[sg_len++]; + sg_dma_address(sg) = phys_addr; + sg_dma_len(sg) = part2_len; + } + + /* + * save tx_len so atmel_complete_tx_dma() will increase + * xmit->tail correctly + */ + atmel_port->tx_len = tx_len; desc = dmaengine_prep_slave_sg(chan, - sg, - 1, + sgl, + sg_len, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -832,7 +863,7 @@ static void atmel_tx_dma(struct uart_port *port) return; } - dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE); + dma_sync_sg_for_device(port->dev, sg_tx, 1, DMA_TO_DEVICE); atmel_port->desc_tx = desc; desc->callback = atmel_complete_tx_dma; @@ -892,7 +923,9 @@ static int atmel_prepare_tx_dma(struct uart_port *port) /* Configure the slave DMA */ memset(&config, 0, sizeof(config)); config.direction = DMA_MEM_TO_DEV; - config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + config.dst_addr_width = (atmel_port->fifo_size) ? + DMA_SLAVE_BUSWIDTH_4_BYTES : + DMA_SLAVE_BUSWIDTH_1_BYTE; config.dst_addr = port->mapbase + ATMEL_US_THR; config.dst_maxburst = 1; @@ -1831,6 +1864,9 @@ static int atmel_startup(struct uart_port *port) ATMEL_US_RXFCLR | ATMEL_US_TXFLCLR); + if (atmel_use_dma_tx(port)) + txrdym = ATMEL_US_FOUR_DATA; + fmr = ATMEL_US_TXRDYM(txrdym) | ATMEL_US_RXRDYM(rxrdym); if (atmel_port->rts_high && atmel_port->rts_low) From 5374901b16836c866a3a2f8a941df049822e18eb Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 30 Jul 2015 16:33:38 +0200 Subject: [PATCH 072/381] tty/serial: at91: fix I/O accesses on RHR and THR for AVR32 This patch fixes I/O accesses on the Receiver Holding Register and on the Transmitter Holding Register. Indeed AVR32 can only perform 32bit I/O accesses on registers: using 8bit I/O accesses would read or write garbage data. Fixes: commit b5199d468177 ("tty/serial: at91: add support to FIFOs") Signed-off-by: Cyrille Pitchen Tested-by: Andy Shevchenko Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/atmel_serial.c | 37 ++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e91b3b2f059050..5ca5cf3e9359cf 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -204,16 +204,33 @@ static inline void atmel_uart_writel(struct uart_port *port, u32 reg, u32 value) __raw_writel(value, port->membase + reg); } -static inline u8 atmel_uart_readb(struct uart_port *port, u32 reg) +#ifdef CONFIG_AVR32 + +/* AVR32 cannot handle 8 or 16bit I/O accesses but only 32bit I/O accesses */ +static inline u8 atmel_uart_read_char(struct uart_port *port) +{ + return __raw_readl(port->membase + ATMEL_US_RHR); +} + +static inline void atmel_uart_write_char(struct uart_port *port, u8 value) { - return __raw_readb(port->membase + reg); + __raw_writel(value, port->membase + ATMEL_US_THR); } -static inline void atmel_uart_writeb(struct uart_port *port, u32 reg, u8 value) +#else + +static inline u8 atmel_uart_read_char(struct uart_port *port) { - __raw_writeb(value, port->membase + reg); + return __raw_readb(port->membase + ATMEL_US_RHR); } +static inline void atmel_uart_write_char(struct uart_port *port, u8 value) +{ + __raw_writeb(value, port->membase + ATMEL_US_THR); +} + +#endif + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -658,7 +675,7 @@ static void atmel_rx_chars(struct uart_port *port) status = atmel_uart_readl(port, ATMEL_US_CSR); while (status & ATMEL_US_RXRDY) { - ch = atmel_uart_readb(port, ATMEL_US_RHR); + ch = atmel_uart_read_char(port); /* * note that the error handling code is @@ -709,7 +726,7 @@ static void atmel_tx_chars(struct uart_port *port) if (port->x_char && (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask)) { - atmel_uart_writeb(port, ATMEL_US_THR, port->x_char); + atmel_uart_write_char(port, port->x_char); port->icount.tx++; port->x_char = 0; } @@ -718,7 +735,7 @@ static void atmel_tx_chars(struct uart_port *port) while (atmel_uart_readl(port, ATMEL_US_CSR) & atmel_port->tx_done_mask) { - atmel_uart_writeb(port, ATMEL_US_THR, xmit->buf[xmit->tail]); + atmel_uart_write_char(port, xmit->buf[xmit->tail]); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) @@ -2294,7 +2311,7 @@ static int atmel_poll_get_char(struct uart_port *port) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_RXRDY)) cpu_relax(); - return atmel_uart_readb(port, ATMEL_US_RHR); + return atmel_uart_read_char(port); } static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) @@ -2302,7 +2319,7 @@ static void atmel_poll_put_char(struct uart_port *port, unsigned char ch) while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writeb(port, ATMEL_US_THR, ch); + atmel_uart_write_char(port, ch); } #endif @@ -2409,7 +2426,7 @@ static void atmel_console_putchar(struct uart_port *port, int ch) { while (!(atmel_uart_readl(port, ATMEL_US_CSR) & ATMEL_US_TXRDY)) cpu_relax(); - atmel_uart_writeb(port, ATMEL_US_THR, ch); + atmel_uart_write_char(port, ch); } /* From 8e9f810d9b94f556da1a2b766e329be3d99c1d7a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 1 Jun 2015 16:47:45 +0200 Subject: [PATCH 073/381] tty/serial: at91: change uart/usart choice selection Signed-off-by: Nicolas Ferre --- drivers/tty/serial/atmel_serial.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 5ca5cf3e9359cf..497cd2ed8349ad 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1740,20 +1740,19 @@ static void atmel_get_ip_name(struct uart_port *port) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int name = atmel_uart_readl(port, ATMEL_US_NAME); u32 version; - int usart, uart; - /* usart and uart ascii */ - usart = 0x55534152; - uart = 0x44424755; atmel_port->is_usart = false; - if (name == usart) { + switch (name) { + case 0x55534152: dev_dbg(port->dev, "This is usart\n"); atmel_port->is_usart = true; - } else if (name == uart) { + break; + case 0x44424755: dev_dbg(port->dev, "This is uart\n"); atmel_port->is_usart = false; - } else { + break; + default: /* fallback for older SoCs: use version field */ version = atmel_uart_readl(port, ATMEL_US_VERSION); switch (version) { @@ -1770,6 +1769,7 @@ static void atmel_get_ip_name(struct uart_port *port) default: dev_err(port->dev, "Not supported ip name nor version, set to uart\n"); } + break; } } From bf8d42d33aabea8afcc977a73efd1ab921c92a8b Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 1 Jun 2015 16:49:57 +0200 Subject: [PATCH 074/381] tty/serial: at91: add new UART New UART have the same behavior for timeout management. This is the only difference that this code tries to identify: treat new UART as USART in this selection code. Signed-off-by: Nicolas Ferre --- drivers/tty/serial/atmel_serial.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 497cd2ed8349ad..5d51f397376856 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1744,7 +1744,8 @@ static void atmel_get_ip_name(struct uart_port *port) atmel_port->is_usart = false; switch (name) { - case 0x55534152: + case 0x55534152: /* USART */ + case 0x55415254: /* new UART with "timeout" feature: considered as usart */ dev_dbg(port->dev, "This is usart\n"); atmel_port->is_usart = true; break; From 03abfaa10dc87eea0cfcb06ea7781320ab0c26ae Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Fri, 12 Jun 2015 11:45:02 +0200 Subject: [PATCH 075/381] mmc: sdhci: fix low memory corruption commit 62a7f368ffbc13d9aedfdd7aeae711b177db69ac upstream. When dma mapping (dma_map_sg) fails in sdhci_pre_dma_transfer, -EINVAL is returned. There are 3 callers of sdhci_pre_dma_transfer: * sdhci_pre_req and sdhci_adma_table_pre: handle negative return * sdhci_prepare_data: handles 0 (error) and "else" (good) only sdhci_prepare_data is therefore broken. When it receives -EINVAL from sdhci_pre_dma_transfer, it assumes 1 sg mapping was mapped. Later, this non-existent mapping with address 0 is kmap'ped and written to: Corrupted low memory at ffff880000001000 (1000 phys) = 22b7d67df2f6d1cf Corrupted low memory at ffff880000001008 (1008 phys) = 63848a5216b7dd95 Corrupted low memory at ffff880000001010 (1010 phys) = 330eb7ddef39e427 Corrupted low memory at ffff880000001018 (1018 phys) = 8017ac7295039bda Corrupted low memory at ffff880000001020 (1020 phys) = 8ce039eac119074f ... So teach sdhci_prepare_data to understand negative return values from sdhci_pre_dma_transfer and disable DMA in that case, as well as for zero. It was introduced in 348487cb28e66b032bae1b38424d81bf5b444408 (mmc: sdhci: use pipeline mmc requests to improve performance). The commit seems to be suspicious also by assigning host->sg_count both in sdhci_pre_dma_transfer and sdhci_adma_table_pre. Signed-off-by: Jiri Slaby Fixes: 348487cb28e6 Cc: Ulf Hansson Cc: Haibo Chen Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c80287a027356e..9231cdfe27575c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -848,7 +848,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) int sg_cnt; sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); - if (sg_cnt == 0) { + if (sg_cnt <= 0) { /* * This only happens when someone fed * us an invalid request. From c5e4278669ce17d95d9e82203419f26b3f6fe6f4 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 16 Jul 2015 15:50:45 +0200 Subject: [PATCH 076/381] mmc: block: Add missing mmc_blk_put() in power_ro_lock_show() commit 9098f84cced870f54d8c410dd2444cfa61467fa0 upstream. Enclosing mmc_blk_put() is missing in power_ro_lock_show() sysfs handler, let's add it. Fixes: add710eaa886 ("mmc: boot partition ro lock support") Signed-off-by: Tomas Winkler Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/card/block.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 60f7141a6b02e6..e4a52ce9242fec 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -208,6 +208,8 @@ static ssize_t power_ro_lock_show(struct device *dev, ret = snprintf(buf, PAGE_SIZE, "%d\n", locked); + mmc_blk_put(md); + return ret; } From edf238344fa9ca4dcfba98d242bea1e9bf5f3ef8 Mon Sep 17 00:00:00 2001 From: Ding Wang Date: Mon, 18 May 2015 20:14:15 +0800 Subject: [PATCH 077/381] mmc: card: Fixup request missing in mmc_blk_issue_rw_rq commit 29535f7b797df35cc9b6b3bca635591cdd3dd2a8 upstream. The current handler of MMC_BLK_CMD_ERR in mmc_blk_issue_rw_rq function may cause new coming request permanent missing when the ongoing request (previoulsy started) complete end. The problem scenario is as follows: (1) Request A is ongoing; (2) Request B arrived, and finally mmc_blk_issue_rw_rq() is called; (3) Request A encounters the MMC_BLK_CMD_ERR error; (4) In the error handling of MMC_BLK_CMD_ERR, suppose mmc_blk_cmd_err() end request A completed and return zero. Continue the error handling, suppose mmc_blk_reset() reset device success; (5) Continue the execution, while loop completed because variable ret is zero now; (6) Finally, mmc_blk_issue_rw_rq() return without processing request B. The process related to the missing request may wait that IO request complete forever, possibly crashing the application or hanging the system. Fix this issue by starting new request when reset success. Signed-off-by: Ding Wang Fixes: 67716327eec7 ("mmc: block: add eMMC hardware reset support") Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/card/block.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index e4a52ce9242fec..31d2627d9d4d6a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -1912,9 +1912,11 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc) break; case MMC_BLK_CMD_ERR: ret = mmc_blk_cmd_err(md, card, brq, req, ret); - if (!mmc_blk_reset(md, card->host, type)) - break; - goto cmd_abort; + if (mmc_blk_reset(md, card->host, type)) + goto cmd_abort; + if (!ret) + goto start_new_req; + break; case MMC_BLK_RETRY: if (retry++ < 5) break; From 5c814773ee5796a92f62850873adad72ac73eead Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Fri, 5 Jun 2015 11:40:08 +0200 Subject: [PATCH 078/381] mmc: sdhci: Restore behavior while creating OCR mask commit 5fd26c7ecb32082745b0bd33c8e35badd1cb5a91 upstream. Commit 3a48edc4bd68 ("mmc: sdhci: Use mmc core regulator infrastucture") changed the behavior for how to assign the ocr_avail mask for the mmc host. More precisely it started to mask the bits instead of assigning them. Restore the behavior, but also make it clear that an OCR mask created from an external regulator overrides the other ones. The OCR mask is determined by one of the following with this priority: 1. Supported ranges of external regulator if one supplies VDD 2. Host OCR mask if set by the driver (based on DT properties) 3. The capabilities reported by the controller itself Fixes: 3a48edc4bd68 ("mmc: sdhci: Use mmc core regulator infrastucture") Cc: Tim Kryger Reported-by: Yangbo Lu Signed-off-by: Ulf Hansson Reviewed-by: Tim Kryger Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 9231cdfe27575c..d3dbb28057e9b1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3315,13 +3315,14 @@ int sdhci_add_host(struct sdhci_host *host) SDHCI_MAX_CURRENT_MULTIPLIER; } - /* If OCR set by external regulators, use it instead */ + /* If OCR set by host, use it instead. */ + if (host->ocr_mask) + ocr_avail = host->ocr_mask; + + /* If OCR set by external regulators, give it highest prio. */ if (mmc->ocr_avail) ocr_avail = mmc->ocr_avail; - if (host->ocr_mask) - ocr_avail &= host->ocr_mask; - mmc->ocr_avail = ocr_avail; mmc->ocr_avail_sdio = ocr_avail; if (host->ocr_avail_sdio) From 84554a5939d17d0f97a23dcdd6d47fff0aca6bc3 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 22 Jun 2015 11:41:23 +0800 Subject: [PATCH 079/381] mmc: sdhci check parameters before call dma_free_coherent commit 7ac020366b0a436d726408841160b5dc32c19214 upstream. We should not call dma_free_coherent if host->adma_table is NULL, otherwise may trigger panic. Fixes: d1e49f77d7c7 ("mmc: sdhci: convert ADMA descriptors to a...") Signed-off-by: Peng Fan Acked-by: Adrian Hunter Signed-off-by: Ulf Hansson Signed-off-by: Greg Kroah-Hartman --- drivers/mmc/host/sdhci.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index d3dbb28057e9b1..bec8a307f8cd36 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3037,8 +3037,11 @@ int sdhci_add_host(struct sdhci_host *host) GFP_KERNEL); host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL); if (!host->adma_table || !host->align_buffer) { - dma_free_coherent(mmc_dev(mmc), host->adma_table_sz, - host->adma_table, host->adma_addr); + if (host->adma_table) + dma_free_coherent(mmc_dev(mmc), + host->adma_table_sz, + host->adma_table, + host->adma_addr); kfree(host->align_buffer); pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n", mmc_hostname(mmc)); From 480e26f07e9dca166a34572948a8cb778b76b10d Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 29 Jul 2015 16:22:46 +0200 Subject: [PATCH 080/381] mmc: sdhci: switch from programmable clock mode to divided one if needed In programmable mode, if the clock frequency is too high, the divider can be too small to meet the clock frequency requirement especially to init the SD card. In this case, switch to the divided clock mode. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index bec8a307f8cd36..b53518451ee24e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1166,6 +1166,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) int real_div = div, clk_mul = 1; u16 clk = 0; unsigned long timeout; + bool switch_base_clk = false; host->mmc->actual_clock = 0; @@ -1203,15 +1204,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) <= clock) break; } - /* - * Set Programmable Clock Mode in the Clock - * Control register. - */ - clk = SDHCI_PROG_CLOCK_MODE; - real_div = div; - clk_mul = host->clk_mul; - div--; - } else { + if ((host->max_clk * host->clk_mul / div) <= clock) { + /* + * Set Programmable Clock Mode in the Clock + * Control register. + */ + clk = SDHCI_PROG_CLOCK_MODE; + real_div = div; + clk_mul = host->clk_mul; + div--; + } else { + /* + * Divisor can be too small to reach clock + * speed requirement. Then use the base clock. + */ + switch_base_clk = true; + } + } + + if (!host->clk_mul || switch_base_clk) { /* Version 3.00 divisors must be a multiple of 2. */ if (host->max_clk <= clock) div = 1; From 35bbb6acd62875c59db2004debb957f4df589ed0 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 29 Jul 2015 16:22:47 +0200 Subject: [PATCH 081/381] mmc: sdhci-of-at91: introduce driver for the Atmel SDMMC Introduce driver for he Atmel SDMMC available on sama5d2. It is a sdhci compliant controller. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/sdhci-atmel.txt | 21 ++ drivers/mmc/host/Kconfig | 8 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-of-at91.c | 192 ++++++++++++++++++ 4 files changed, 222 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-atmel.txt create mode 100644 drivers/mmc/host/sdhci-of-at91.c diff --git a/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt b/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt new file mode 100644 index 00000000000000..1b662d7171a0f0 --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt @@ -0,0 +1,21 @@ +* Atmel SDHCI controller + +This file documents the differences between the core properties in +Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the +sdhci-of-at91 driver. + +Required properties: +- compatible: Must be "atmel,sama5d2-sdhci". +- clocks: Phandlers to the clocks. +- clock-names: Must be "hclock", "multclk", "baseclk"; + + +Example: + +sdmmc0: sdio-host@a0000000 { + compatible = "atmel,sama5d2-sdhci"; + reg = <0xa0000000 0x300>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>; + clock-names = "hclock", "multclk", "baseclk"; +}; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index b1f837e749fe83..f5301de4a9cd65 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -129,6 +129,14 @@ config MMC_SDHCI_OF_ARASAN If unsure, say N. +config MMC_SDHCI_OF_AT91 + tristate "SDHCI OF support for the Atmel SDMMC controller" + depends on MMC_SDHCI_PLTFM + depends on OF + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Atmel SDMMC driver + config MMC_SDHCI_OF_ESDHC tristate "SDHCI OF support for the Freescale eSDHC controller" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index e3ab5b968651f5..975df423e2c1b7 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o +obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c new file mode 100644 index 00000000000000..7a9f4b19f98959 --- /dev/null +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -0,0 +1,192 @@ +/* + * Atmel SDMMC controller driver. + * + * Copyright (C) 2015 Atmel, + * 2015 Ludovic Desroches + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +#define SDMMC_CACR 0x230 +#define SDMMC_CACR_CAPWREN BIT(0) +#define SDMMC_CACR_KEY (0x46 << 8) + +struct sdhci_at91_priv { + struct clk *hclock; + struct clk *gck; + struct clk *mainck; +}; + +static const struct sdhci_ops sdhci_at91_sama5d2_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data soc_data_sama5d2 = { + .ops = &sdhci_at91_sama5d2_ops, +}; + +static const struct of_device_id sdhci_at91_dt_match[] = { + { .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 }, + {} +}; + +static int sdhci_at91_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct sdhci_pltfm_data *soc_data; + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_at91_priv *priv; + unsigned int caps0, caps1; + unsigned int clk_base, clk_mul; + unsigned int gck_rate, real_gck_rate; + int ret; + + match = of_match_device(sdhci_at91_dt_match, &pdev->dev); + if (!match) + return -EINVAL; + soc_data = match->data; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate private data\n"); + return -ENOMEM; + } + + priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); + if (IS_ERR(priv->mainck)) { + dev_err(&pdev->dev, "failed to get baseclk\n"); + return PTR_ERR(priv->mainck); + } + + priv->hclock = devm_clk_get(&pdev->dev, "hclock"); + if (IS_ERR(priv->hclock)) { + dev_err(&pdev->dev, "failed to get hclock\n"); + return PTR_ERR(priv->hclock); + } + + priv->gck = devm_clk_get(&pdev->dev, "multclk"); + if (IS_ERR(priv->gck)) { + dev_err(&pdev->dev, "failed to get multclk\n"); + return PTR_ERR(priv->gck); + } + + host = sdhci_pltfm_init(pdev, soc_data, 0); + if (IS_ERR(host)) + return PTR_ERR(host); + + /* + * The mult clock is provided by as a generated clock by the PMC + * controller. In order to set the rate of gck, we have to get the + * base clock rate and the clock mult from capabilities. + */ + clk_prepare_enable(priv->hclock); + caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES); + caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1); + clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; + clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; + gck_rate = clk_base * 1000000 * (clk_mul + 1); + ret = clk_set_rate(priv->gck, gck_rate); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set gck"); + goto hclock_disable_unprepare; + return -EINVAL; + } + /* + * We need to check if we have the requested rate for gck because in + * some cases this rate could be not supported. If it happens, the rate + * is the closest one gck can provide. We have to update the value + * of clk mul. + */ + real_gck_rate = clk_get_rate(priv->gck); + if (real_gck_rate != gck_rate) { + clk_mul = real_gck_rate / (clk_base * 1000000) - 1; + caps1 &= (~SDHCI_CLOCK_MUL_MASK); + caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK); + /* Set capabilities in r/w mode. */ + writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR); + writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1); + /* Set capabilities in ro mode. */ + writel(0, host->ioaddr + SDMMC_CACR); + dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n", + clk_mul, real_gck_rate); + } + + clk_prepare_enable(priv->mainck); + clk_prepare_enable(priv->gck); + + pltfm_host = sdhci_priv(host); + pltfm_host->priv = priv; + + ret = mmc_of_parse(host->mmc); + if (ret) + goto clocks_disable_unprepare; + + sdhci_get_of_property(pdev); + + ret = sdhci_add_host(host); + if (ret) + goto clocks_disable_unprepare; + + return 0; + +clocks_disable_unprepare: + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->mainck); +hclock_disable_unprepare: + clk_disable_unprepare(priv->hclock); + sdhci_pltfm_free(pdev); + return ret; +} + +static int sdhci_at91_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + + sdhci_pltfm_unregister(pdev); + + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->hclock); + clk_disable_unprepare(priv->mainck); + + return 0; +} + +static struct platform_driver sdhci_at91_driver = { + .driver = { + .name = "sdhci-at91", + .owner = THIS_MODULE, + .of_match_table = sdhci_at91_dt_match, + .pm = SDHCI_PLTFM_PMOPS, + }, + .probe = sdhci_at91_probe, + .remove = sdhci_at91_remove, +}; + +module_platform_driver(sdhci_at91_driver); + +MODULE_DESCRIPTION("SDHCI driver for at91"); +MODULE_AUTHOR("Ludovic Desroches "); +MODULE_LICENSE("GPL v2"); From 721e3925eff0d5ddf238b5d3f0c2192baa0150cc Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 29 Jul 2015 16:22:48 +0200 Subject: [PATCH 082/381] MAINTAINERS: add entry for Atmel sdhci-of-at91 driver Add an entry for Atmel SDMMC device. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d8afd29536786b..c418509dfa1fce 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1829,6 +1829,12 @@ L: linux-mtd@lists.infradead.org S: Supported F: drivers/mtd/nand/atmel_nand* +ATMEL SDMMC DRIVER +M: Ludovic Desroches +L: linux-mmc@vger.kernel.org +S: Supported +F: drivers/mmc/host/sdhci-of-at91.c + ATMEL SPI DRIVER M: Nicolas Ferre S: Supported From b065fa133b491cd0de6ed9123dbee3147c91accf Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 25 Aug 2015 16:13:29 +0200 Subject: [PATCH 083/381] mmc: sdhci-of-at91: fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: ludovic.desroches@atmel.com Signed-off-by: Fengguang Wu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 7a9f4b19f98959..d1556643a41d32 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -177,7 +177,6 @@ static int sdhci_at91_remove(struct platform_device *pdev) static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", - .owner = THIS_MODULE, .of_match_table = sdhci_at91_dt_match, .pm = SDHCI_PLTFM_PMOPS, }, From d24ff53f39a71fb775b4149b43419fbe9cff0c77 Mon Sep 17 00:00:00 2001 From: Holger Busse Date: Wed, 26 Aug 2015 10:45:45 +0200 Subject: [PATCH 084/381] ARM: at91/dt: corrections to i2c1 declaration to sama5d4 Correcting the dma declaration for i2c1 dma. Signed-off-by: Holger Busse Signed-off-by: Nicolas Ferre Fixes: 4cc7cdf35c5f ("ARM: at91/dt: add i2c1 declaration to sama5d4") Cc: stable@vger.kernel.org # v4.1+ --- arch/arm/boot/dts/sama5d4.dtsi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 8d1de29e8da107..fb92481e60d467 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -939,11 +939,11 @@ reg = <0xf8018000 0x4000>; interrupts = <33 IRQ_TYPE_LEVEL_HIGH 6>; dmas = <&dma1 - (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(4)>, + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(4))>, <&dma1 - (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) - AT91_XDMAC_DT_PERID(5)>; + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(5))>; dma-names = "tx", "rx"; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c1>; From 69e1a5ae63a52c83182cd25c345ff4f093a0cf91 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 2 Apr 2015 11:55:49 +0200 Subject: [PATCH 085/381] pinctrl: at91: Add set_multiple GPIO chip feature This adds the callback for set_multiple. As this controller has a separate set and clear register, we can't write directly to PIO_ODSR as this would required a cached variable and would race with at91_gpio_set. So build masks for the PIO_SODR and PIO_CODR registers and write them together. Signed-off-by: Alexander Stein Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 2f797cb7e20501..d80ade23fd1bb4 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1326,6 +1326,21 @@ static void at91_gpio_set(struct gpio_chip *chip, unsigned offset, writel_relaxed(mask, pio + (val ? PIO_SODR : PIO_CODR)); } +static void at91_gpio_set_multiple(struct gpio_chip *chip, + unsigned long *mask, unsigned long *bits) +{ + struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip); + void __iomem *pio = at91_gpio->regbase; + +#define BITS_MASK(bits) (((bits) == 32) ? ~0U : (BIT(bits) - 1)) + /* Mask additionally to ngpio as not all GPIO controllers have 32 pins */ + uint32_t set_mask = (*mask & *bits) & BITS_MASK(chip->ngpio); + uint32_t clear_mask = (*mask & ~(*bits)) & BITS_MASK(chip->ngpio); + + writel_relaxed(set_mask, pio + PIO_SODR); + writel_relaxed(clear_mask, pio + PIO_CODR); +} + static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int val) { @@ -1685,6 +1700,7 @@ static struct gpio_chip at91_gpio_template = { .get = at91_gpio_get, .direction_output = at91_gpio_direction_output, .set = at91_gpio_set, + .set_multiple = at91_gpio_set_multiple, .dbg_show = at91_gpio_dbg_show, .can_sleep = false, .ngpio = MAX_NB_GPIO_PER_BANK, From 97ab2afcf62a2bfdce29bb7872c60a44bd5568c8 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 8 Jun 2015 17:16:37 +0200 Subject: [PATCH 086/381] pinctrl: don't print unavailable function groups There is no reason to try to print groups associated to a function if get_function_groups returns an error. Moreover, it can lead to a NULL pointer dereference error. Signed-off-by: Ludovic Desroches Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index b874458dcb8854..fd944e387d5630 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -544,9 +544,12 @@ static int pinmux_functions_show(struct seq_file *s, void *what) ret = pmxops->get_function_groups(pctldev, func_selector, &groups, &num_groups); - if (ret) + if (ret) { seq_printf(s, "function %s: COULD NOT GET GROUPS\n", func); + func_selector++; + continue; + } seq_printf(s, "function: %s, groups = [ ", func); for (i = 0; i < num_groups; i++) From c5ec511141e7751dacb4c589a94e79fe310bc265 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Jul 2015 11:17:59 +0100 Subject: [PATCH 087/381] pinctrl: pinconf: Fix display of configs The function pinconf_dbg_config_print() only prints the configuration of the 1st pin config in an array of pin configurations. Fix this so that all pin configurations in the array are displayed. There are a few places in the code where the pin configs are displayed and so add a helper function to display the pin configs to simplify the code. Signed-off-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 64 +++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 1fc09dc2019905..0b0334b2691752 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -202,18 +202,34 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) #ifdef CONFIG_DEBUG_FS -void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, + unsigned long *configs, unsigned num_configs) { - struct pinctrl_dev *pctldev; const struct pinconf_ops *confops; int i; - pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (pctldev) confops = pctldev->desc->confops; else confops = NULL; + for (i = 0; i < num_configs; i++) { + seq_puts(s, "config "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + configs[i]); + else + seq_printf(s, "%08lx", configs[i]); + seq_puts(s, "\n"); + } +} + +void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +{ + struct pinctrl_dev *pctldev; + + pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); + switch (map->type) { case PIN_MAP_TYPE_CONFIGS_PIN: seq_printf(s, "pin "); @@ -227,15 +243,8 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) seq_printf(s, "%s\n", map->data.configs.group_or_pin); - for (i = 0; i < map->data.configs.num_configs; i++) { - seq_printf(s, "config "); - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, - map->data.configs.configs[i]); - else - seq_printf(s, "%08lx", map->data.configs.configs[i]); - seq_printf(s, "\n"); - } + pinconf_show_config(s, pctldev, map->data.configs.configs, + map->data.configs.num_configs); } void pinconf_show_setting(struct seq_file *s, @@ -243,9 +252,7 @@ void pinconf_show_setting(struct seq_file *s, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const struct pinconf_ops *confops = pctldev->desc->confops; struct pin_desc *desc; - int i; switch (setting->type) { case PIN_MAP_TYPE_CONFIGS_PIN: @@ -269,17 +276,8 @@ void pinconf_show_setting(struct seq_file *s, * FIXME: We should really get the pin controler to dump the config * values, so they can be decoded to something meaningful. */ - for (i = 0; i < setting->data.configs.num_configs; i++) { - seq_printf(s, " "); - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, - setting->data.configs.configs[i]); - else - seq_printf(s, "%08lx", - setting->data.configs.configs[i]); - } - - seq_printf(s, "\n"); + pinconf_show_config(s, pctldev, setting->data.configs.configs, + setting->data.configs.num_configs); } static void pinconf_dump_pin(struct pinctrl_dev *pctldev, @@ -412,10 +410,8 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) const struct pinctrl_map *map; const struct pinctrl_map *found = NULL; struct pinctrl_dev *pctldev; - const struct pinconf_ops *confops = NULL; struct dbg_cfg *dbg = &pinconf_dbg_conf; int i, j; - unsigned long config; mutex_lock(&pinctrl_maps_mutex); @@ -449,16 +445,10 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) } pctldev = get_pinctrl_dev_from_devname(found->ctrl_dev_name); - config = *found->data.configs.configs; - seq_printf(s, "Dev %s has config of %s in state %s: 0x%08lX\n", - dbg->dev_name, dbg->pin_name, - dbg->state_name, config); - - if (pctldev) - confops = pctldev->desc->confops; - - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, config); + seq_printf(s, "Dev %s has config of %s in state %s:\n", + dbg->dev_name, dbg->pin_name, dbg->state_name); + pinconf_show_config(s, pctldev, found->data.configs.configs, + found->data.configs.num_configs); exit: mutex_unlock(&pinctrl_maps_mutex); From 29b504c76a9c0bb5bb7a2ff7f3b606c50a593146 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 31 Jul 2015 14:48:56 +0200 Subject: [PATCH 088/381] gpio: don't override irq_*_resources() callbacks If the driver has specified its own irq_{request/release}_resources() functions, don't override them. The gpio-etraxfs driver will use this. Signed-off-by: Rabin Vincent [Added a small comment blurb] Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6bc612b8a49fcf..3da123cd55fdf9 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -625,8 +625,16 @@ int gpiochip_irqchip_add(struct gpio_chip *gpiochip, gpiochip->irqchip = NULL; return -EINVAL; } - irqchip->irq_request_resources = gpiochip_irq_reqres; - irqchip->irq_release_resources = gpiochip_irq_relres; + + /* + * It is possible for a driver to override this, but only if the + * alternative functions are both implemented. + */ + if (!irqchip->irq_request_resources && + !irqchip->irq_release_resources) { + irqchip->irq_request_resources = gpiochip_irq_reqres; + irqchip->irq_release_resources = gpiochip_irq_relres; + } /* * Prepare the mapping since the irqchip shall be orthogonal to From c107687e299ce2a201a2fa6de4d66b8f11df29d6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Aug 2015 15:32:16 +0200 Subject: [PATCH 089/381] pinctrl: at91: Use generic irq_{request,release}_resources() The at91-specific irq_{request,release}_resources() callbacks are identical to the generic ones, modulo the bug fix in 5b76e79c77264899 ("gpiolib: irqchip: prevent driver unloading if gpio is used as irq only"). Until commit 8b67a1f0ad1f260f ("gpio: don't override irq_*_resources() callbacks"), the buggy at91-specific callbacks were never used, though. Hence drop the at91-specific ones in favor of the generic ones. Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index d80ade23fd1bb4..0b2fb68261e043 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1488,28 +1488,6 @@ static void gpio_irq_ack(struct irq_data *d) /* the interrupt is already cleared before by reading ISR */ } -static int gpio_irq_request_res(struct irq_data *d) -{ - struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); - unsigned pin = d->hwirq; - int ret; - - ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin); - if (ret) - dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n", - d->hwirq); - - return ret; -} - -static void gpio_irq_release_res(struct irq_data *d) -{ - struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); - unsigned pin = d->hwirq; - - gpiochip_unlock_as_irq(&at91_gpio->chip, pin); -} - #ifdef CONFIG_PM static u32 wakeups[MAX_GPIO_BANKS]; @@ -1585,8 +1563,6 @@ void at91_pinctrl_gpio_resume(void) static struct irq_chip gpio_irqchip = { .name = "GPIO", .irq_ack = gpio_irq_ack, - .irq_request_resources = gpio_irq_request_res, - .irq_release_resources = gpio_irq_release_res, .irq_disable = gpio_irq_mask, .irq_mask = gpio_irq_mask, .irq_unmask = gpio_irq_unmask, From d9e3a2617a6173ba540e35aa04d647b87f64462e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 1 Apr 2015 10:06:46 +0200 Subject: [PATCH 090/381] pinctrl: change function behavior for per pin muxing controllers When having a controller which allows per pin muxing, declaring with which groups a function can be used is a useless constraint since groups are something virtual. Signed-off-by: Ludovic Desroches --- drivers/pinctrl/pinmux.c | 58 +++++++++++++++++++--------------- include/linux/pinctrl/pinmux.h | 3 ++ 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index fd944e387d5630..216f2c6b08fca5 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -40,7 +40,7 @@ int pinmux_check_ops(struct pinctrl_dev *pctldev) if (!ops || !ops->get_functions_count || !ops->get_function_name || - !ops->get_function_groups || + (!ops->get_function_groups & !ops->mux_per_pin) || !ops->set_mux) { dev_err(pctldev->dev, "pinmux ops lacks necessary functions\n"); return -EINVAL; @@ -338,36 +338,42 @@ int pinmux_map_to_setting(struct pinctrl_map const *map, } setting->data.mux.func = ret; - ret = pmxops->get_function_groups(pctldev, setting->data.mux.func, - &groups, &num_groups); - if (ret < 0) { - dev_err(pctldev->dev, "can't query groups for function %s\n", - map->data.mux.function); - return ret; - } - if (!num_groups) { - dev_err(pctldev->dev, - "function %s can't be selected on any group\n", - map->data.mux.function); - return -EINVAL; - } - if (map->data.mux.group) { - bool found = false; - group = map->data.mux.group; - for (i = 0; i < num_groups; i++) { - if (!strcmp(group, groups[i])) { - found = true; - break; - } + if (!pmxops->mux_per_pin) { + ret = pmxops->get_function_groups(pctldev, + setting->data.mux.func, + &groups, &num_groups); + if (ret < 0) { + dev_err(pctldev->dev, + "can't query groups for function %s\n", + map->data.mux.function); + return ret; } - if (!found) { + if (!num_groups) { dev_err(pctldev->dev, - "invalid group \"%s\" for function \"%s\"\n", - group, map->data.mux.function); + "function %s can't be selected on any group\n", + map->data.mux.function); return -EINVAL; } + if (map->data.mux.group) { + bool found = false; + group = map->data.mux.group; + for (i = 0; i < num_groups; i++) { + if (!strcmp(group, groups[i])) { + found = true; + break; + } + } + if (!found) { + dev_err(pctldev->dev, + "invalid group \"%s\" for function \"%s\"\n", + group, map->data.mux.function); + return -EINVAL; + } + } else { + group = groups[0]; + } } else { - group = groups[0]; + group = map->data.mux.group; } ret = pinctrl_get_group_selector(pctldev, group); diff --git a/include/linux/pinctrl/pinmux.h b/include/linux/pinctrl/pinmux.h index 511bda9ed4bf0d..51b84ebb50e0e6 100644 --- a/include/linux/pinctrl/pinmux.h +++ b/include/linux/pinctrl/pinmux.h @@ -23,6 +23,8 @@ struct pinctrl_dev; /** * struct pinmux_ops - pinmux operations, to be implemented by pin controller * drivers that support pinmuxing + * @mux_per_pin: in case of per pin muxing, it removes the need to declare + * with which groups a function can be used. * @request: called by the core to see if a certain pin can be made * available for muxing. This is called by the core to acquire the pins * before selecting any actual mux setting across a function. The driver @@ -58,6 +60,7 @@ struct pinctrl_dev; * to the GPIO controllers that need pin muxing. */ struct pinmux_ops { + bool mux_per_pin; int (*request) (struct pinctrl_dev *pctldev, unsigned offset); int (*free) (struct pinctrl_dev *pctldev, unsigned offset); int (*get_functions_count) (struct pinctrl_dev *pctldev); From 5df5c530ceb25e6bb000f06b8dcddd82cd1f8671 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 30 Apr 2015 17:01:32 +0200 Subject: [PATCH 091/381] pinctrl: introduce complex pin description Using a string to describe a pin in the device tree can be not enough. Some controllers may need extra information to fully describe a pin. It concerns mainly controllers which have a per pin muxing approach which don't fit well the notions of groups and functions. Instead of using a pin name, a 32 bit value is used. The 16 least significant bits are used for the pin number. Other 16 bits can be used to store extra parameters. Signed-off-by: Ludovic Desroches --- drivers/pinctrl/pinconf-generic.c | 44 ++++++++++++++++++++++++------- include/linux/pinctrl/pinctrl.h | 6 +++++ 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index e63ad9fbd388a7..46048cba5137ac 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -278,17 +278,25 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, unsigned *reserved_maps, unsigned *num_maps, enum pinctrl_map_type type) { - int ret; + int ret, i = 0; const char *function; struct device *dev = pctldev->dev; unsigned long *configs = NULL; unsigned num_configs = 0; - unsigned reserve, strings_count; + unsigned reserve, items_count, pin_id; struct property *prop; const char *group; const char *subnode_target_type = "pins"; - - ret = of_property_count_strings(np, "pins"); + const char **items_name = NULL; + struct pinctrl_desc *pctldesc = pctldev->desc; + const __be32 *cur; + u32 val; + bool pins_prop = true; + + if (pctldesc->complex_pin_desc) + ret = of_property_count_u32_elems(np, "pins"); + else + ret = of_property_count_strings(np, "pins"); if (ret < 0) { ret = of_property_count_strings(np, "groups"); if (ret < 0) @@ -297,11 +305,12 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (type == PIN_MAP_TYPE_INVALID) type = PIN_MAP_TYPE_CONFIGS_GROUP; subnode_target_type = "groups"; + pins_prop = false; } else { if (type == PIN_MAP_TYPE_INVALID) type = PIN_MAP_TYPE_CONFIGS_PIN; } - strings_count = ret; + items_count = ret; ret = of_property_read_string(np, "function", &function); if (ret < 0) { @@ -326,17 +335,31 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (num_configs) reserve++; - reserve *= strings_count; + reserve *= items_count; ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, reserve); if (ret < 0) goto exit; - of_property_for_each_string(np, subnode_target_type, prop, group) { + items_name = kmalloc_array(items_count, sizeof(char *), GFP_KERNEL); + if (!items_name) + goto exit; + if (pctldesc->complex_pin_desc && pins_prop) { + of_property_for_each_u32(np, subnode_target_type, prop, cur, val) { + pin_id = val & PINCTRL_PIN_MASK; + items_name[i++] = pctldesc->pins[pin_id].name; + } + } else { + of_property_for_each_string(np, subnode_target_type, prop, group) { + items_name[i++] = group; + } + } + + for (i = 0; i < items_count; i++) { if (function) { ret = pinctrl_utils_add_map_mux(pctldev, map, - reserved_maps, num_maps, group, + reserved_maps, num_maps, items_name[i], function); if (ret < 0) goto exit; @@ -344,8 +367,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, if (num_configs) { ret = pinctrl_utils_add_map_configs(pctldev, map, - reserved_maps, num_maps, group, configs, - num_configs, type); + reserved_maps, num_maps, items_name[i], + configs, num_configs, type); if (ret < 0) goto exit; } @@ -353,6 +376,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, ret = 0; exit: + kfree(items_name); kfree(configs); return ret; } diff --git a/include/linux/pinctrl/pinctrl.h b/include/linux/pinctrl/pinctrl.h index 66e4697516dea2..116c0595c8fd34 100644 --- a/include/linux/pinctrl/pinctrl.h +++ b/include/linux/pinctrl/pinctrl.h @@ -45,6 +45,8 @@ struct pinctrl_pin_desc { #define PINCTRL_PIN(a, b) { .number = a, .name = b } #define PINCTRL_PIN_ANON(a) { .number = a } +#define PINCTRL_PIN_MASK 0xffff + /** * struct pinctrl_gpio_range - each pin controller can provide subranges of * the GPIO number space to be handled by the controller @@ -112,6 +114,9 @@ struct pinctrl_ops { * this pin controller * @npins: number of descriptors in the array, usually just ARRAY_SIZE() * of the pins field above + * @complex_pin_desc: some pin controllers need more information than the pin + * name. In this case, pins property uses u32 instead of string. In this + * value there is the pin number plus optional parameters. * @pctlops: pin control operation vtable, to support global concepts like * grouping of pins, this is optional. * @pmxops: pinmux operations vtable, if you support pinmuxing in your driver @@ -129,6 +134,7 @@ struct pinctrl_desc { const char *name; struct pinctrl_pin_desc const *pins; unsigned int npins; + bool complex_pin_desc; const struct pinctrl_ops *pctlops; const struct pinmux_ops *pmxops; const struct pinconf_ops *confops; From f2450b35984e6d466e9e21dbe6a763b40059beee Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 17 Apr 2015 16:29:48 +0200 Subject: [PATCH 092/381] ARM: at91/dt: sama5d2 pinmux Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/sama5d2-pinfunc.h | 760 ++++++++++++++++++++++++++++ 1 file changed, 760 insertions(+) create mode 100644 arch/arm/boot/dts/sama5d2-pinfunc.h diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h new file mode 100644 index 00000000000000..afdd71df207790 --- /dev/null +++ b/arch/arm/boot/dts/sama5d2-pinfunc.h @@ -0,0 +1,760 @@ +#define PINMUX_PIN(no, ioset) \ +( ((no) & 0xffff) | (((ioset) & 0xff) << 16) ) + +#define PIN_PA0 0 +#define PIN_PA0__SDMMC0_CK PINMUX_PIN(PIN_PA0, 1) +#define PIN_PA0__QSPI0_SCK PINMUX_PIN(PIN_PA0, 1) +#define PIN_PA0__D0 PINMUX_PIN(PIN_PA0, 2) +#define PIN_PA1 1 +#define PIN_PA1__SDMMC0_CMD PINMUX_PIN(PIN_PA1, 1) +#define PIN_PA1__QSPI0_CS PINMUX_PIN(PIN_PA1, 1) +#define PIN_PA1__D1 PINMUX_PIN(PIN_PA1, 2) +#define PIN_PA2 2 +#define PIN_PA2__SDMMC0_DAT0 PINMUX_PIN(PIN_PA2, 1) +#define PIN_PA2__QSPI0_IO0 PINMUX_PIN(PIN_PA2, 1) +#define PIN_PA2__D2 PINMUX_PIN(PIN_PA2, 2) +#define PIN_PA3 3 +#define PIN_PA3__SDMMC0_DAT1 PINMUX_PIN(PIN_PA3, 1) +#define PIN_PA3__QSPI0_IO1 PINMUX_PIN(PIN_PA3, 1) +#define PIN_PA3__D3 PINMUX_PIN(PIN_PA3, 2) +#define PIN_PA4 4 +#define PIN_PA4__SDMMC0_DAT2 PINMUX_PIN(PIN_PA4, 1) +#define PIN_PA4__QSPI0_IO2 PINMUX_PIN(PIN_PA4, 1) +#define PIN_PA4__D4 PINMUX_PIN(PIN_PA4, 2) +#define PIN_PA5 5 +#define PIN_PA5__SDMMC0_DAT3 PINMUX_PIN(PIN_PA5, 1) +#define PIN_PA5__QSPI0_IO3 PINMUX_PIN(PIN_PA5, 1) +#define PIN_PA5__D5 PINMUX_PIN(PIN_PA5, 2) +#define PIN_PA6 6 +#define PIN_PA6__SDMMC0_DAT4 PINMUX_PIN(PIN_PA6, 1) +#define PIN_PA6__QSPI1_SCK PINMUX_PIN(PIN_PA6, 1) +#define PIN_PA6__TIOA5 PINMUX_PIN(PIN_PA6, 1) +#define PIN_PA6__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA6, 1) +#define PIN_PA6__D6 PINMUX_PIN(PIN_PA6, 2) +#define PIN_PA7 7 +#define PIN_PA7__SDMMC0_DAT5 PINMUX_PIN(PIN_PA7, 1) +#define PIN_PA7__QSPI1_IO0 PINMUX_PIN(PIN_PA7, 1) +#define PIN_PA7__TIOB5 PINMUX_PIN(PIN_PA7, 1) +#define PIN_PA7__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA7, 1) +#define PIN_PA7__D7 PINMUX_PIN(PIN_PA7, 2) +#define PIN_PA8 8 +#define PIN_PA8__SDMMC0_DAT6 PINMUX_PIN(PIN_PA8, 1) +#define PIN_PA8__QSPI1_IO1 PINMUX_PIN(PIN_PA8, 1) +#define PIN_PA8__TCLK5 PINMUX_PIN(PIN_PA8, 1) +#define PIN_PA8__FLEXCOM2_IO2 PINMUX_PIN(PIN_PA8, 1) +#define PIN_PA8__NWE_NANDWE PINMUX_PIN(PIN_PA8, 2) +#define PIN_PA9 9 +#define PIN_PA9__SDMMC0_DAT7 PINMUX_PIN(PIN_PA9, 1) +#define PIN_PA9__QSPI1_IO2 PINMUX_PIN(PIN_PA9, 1) +#define PIN_PA9__TIOA4 PINMUX_PIN(PIN_PA9, 1) +#define PIN_PA9__FLEXCOM2_IO3 PINMUX_PIN(PIN_PA9, 1) +#define PIN_PA9__NCS3 PINMUX_PIN(PIN_PA9, 2) +#define PIN_PA10 10 +#define PIN_PA10__SDMMC0_RSTN PINMUX_PIN(PIN_PA10, 1) +#define PIN_PA10__QSPI1_IO3 PINMUX_PIN(PIN_PA10, 1) +#define PIN_PA10__TIOB4 PINMUX_PIN(PIN_PA10, 1) +#define PIN_PA10__FLEXCOM2_IO4 PINMUX_PIN(PIN_PA10, 1) +#define PIN_PA10__A21_NANDALE PINMUX_PIN(PIN_PA10, 2) +#define PIN_PA11 11 +#define PIN_PA11__SDMMC0_VDDSEL PINMUX_PIN(PIN_PA11, 1) +#define PIN_PA11__QSPI1_CS PINMUX_PIN(PIN_PA11, 1) +#define PIN_PA11__TCLK4 PINMUX_PIN(PIN_PA11, 1) +#define PIN_PA11__A22_NANDCLE PINMUX_PIN(PIN_PA11, 2) +#define PIN_PA12 12 +#define PIN_PA12__SDMMC0_WP PINMUX_PIN(PIN_PA12, 1) +#define PIN_PA12__IRQ PINMUX_PIN(PIN_PA12, 1) +#define PIN_PA12__NRD_NANDOE PINMUX_PIN(PIN_PA12, 2) +#define PIN_PA13 13 +#define PIN_PA13__SDMMC0_CD PINMUX_PIN(PIN_PA13, 1) +#define PIN_PA13__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA13, 1) +#define PIN_PA13__D8 PINMUX_PIN(PIN_PA13, 2) +#define PIN_PA14 14 +#define PIN_PA14__SPI0_SPCK PINMUX_PIN(PIN_PA14, 1) +#define PIN_PA14__TK1 PINMUX_PIN(PIN_PA14, 1) +#define PIN_PA14__QSPI0_SCK PINMUX_PIN(PIN_PA14, 2) +#define PIN_PA14__I2SMCK1 PINMUX_PIN(PIN_PA14, 2) +#define PIN_PA14__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA14, 1) +#define PIN_PA14__D9 PINMUX_PIN(PIN_PA14, 2) +#define PIN_PA15 14 +#define PIN_PA15__SPI0_MOSI PINMUX_PIN(PIN_PA15, 1) +#define PIN_PA15__TF1 PINMUX_PIN(PIN_PA15, 1) +#define PIN_PA15__QSPI0_CS PINMUX_PIN(PIN_PA15, 2) +#define PIN_PA15__I2SCK1 PINMUX_PIN(PIN_PA15, 2) +#define PIN_PA15__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA15, 1) +#define PIN_PA15__D10 PINMUX_PIN(PIN_PA15, 2) +#define PIN_PA16 16 +#define PIN_PA16__SPI0_MISO PINMUX_PIN(PIN_PA16, 1) +#define PIN_PA16__TD1 PINMUX_PIN(PIN_PA16, 1) +#define PIN_PA16__QSPI0_IO0 PINMUX_PIN(PIN_PA16, 2) +#define PIN_PA16__I2SWS1 PINMUX_PIN(PIN_PA16, 2) +#define PIN_PA16__FLEXCOM3_IO3 PINMUX_PIN(PIN_PA16, 1) +#define PIN_PA16__D11 PINMUX_PIN(PIN_PA16, 2) +#define PIN_PA17 17 +#define PIN_PA17__SPI0_NPCS0 PINMUX_PIN(PIN_PA17, 1) +#define PIN_PA17__RD1 PINMUX_PIN(PIN_PA17, 1) +#define PIN_PA17__QSPI0_IO1 PINMUX_PIN(PIN_PA17, 2) +#define PIN_PA17__I2SDI1 PINMUX_PIN(PIN_PA17, 2) +#define PIN_PA17__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA17, 1) +#define PIN_PA17__D12 PINMUX_PIN(PIN_PA17, 2) +#define PIN_PA18 18 +#define PIN_PA18__SPI0_NPCS1 PINMUX_PIN(PIN_PA18, 1) +#define PIN_PA18__RK1 PINMUX_PIN(PIN_PA18, 1) +#define PIN_PA18__QSPI0_IO2 PINMUX_PIN(PIN_PA18, 2) +#define PIN_PA18__I2SDO1 PINMUX_PIN(PIN_PA18, 2) +#define PIN_PA18__SDMMC1_DAT0 PINMUX_PIN(PIN_PA18, 1) +#define PIN_PA18__D13 PINMUX_PIN(PIN_PA18, 2) +#define PIN_PA19 19 +#define PIN_PA19__SPI0_NPCS2 PINMUX_PIN(PIN_PA19, 1) +#define PIN_PA19__RF1 PINMUX_PIN(PIN_PA19, 1) +#define PIN_PA19__QSPI0_IO3 PINMUX_PIN(PIN_PA19, 2) +#define PIN_PA19__TIOA0 PINMUX_PIN(PIN_PA19, 1) +#define PIN_PA19__SDMMC1_DAT1 PINMUX_PIN(PIN_PA19, 1) +#define PIN_PA19__D14 PINMUX_PIN(PIN_PA19, 2) +#define PIN_PA20 20 +#define PIN_PA20__SPI0_NPCS3 PINMUX_PIN(PIN_PA20, 1) +#define PIN_PA20__TIOB0 PINMUX_PIN(PIN_PA20, 1) +#define PIN_PA20__SDMMC1_DAT2 PINMUX_PIN(PIN_PA20, 1) +#define PIN_PA20__D15 PINMUX_PIN(PIN_PA20, 2) +#define PIN_PA21 21 +#define PIN_PA21__IRQ PINMUX_PIN(PIN_PA21, 2) +#define PIN_PA21__PCK2 PINMUX_PIN(PIN_PA21, 3) +#define PIN_PA21__TCLK0 PINMUX_PIN(PIN_PA21, 1) +#define PIN_PA21__SDMMC1_DAT3 PINMUX_PIN(PIN_PA21, 1) +#define PIN_PA21__NANDRDY PINMUX_PIN(PIN_PA21, 2) +#define PIN_PA22 22 +#define PIN_PA22__FLEXCOM1_IO2 PINMUX_PIN(PIN_PA22, 1) +#define PIN_PA22__D0 PINMUX_PIN(PIN_PA22, 1) +#define PIN_PA22__TCK PINMUX_PIN(PIN_PA22, 4) +#define PIN_PA22__SPI1_SPCK PINMUX_PIN(PIN_PA22, 2) +#define PIN_PA22__SDMMC1_CK PINMUX_PIN(PIN_PA22, 1) +#define PIN_PA22__QSPI0_SCK PINMUX_PIN(PIN_PA22, 3) +#define PIN_PA23 23 +#define PIN_PA23__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA23, 1) +#define PIN_PA23__D1 PINMUX_PIN(PIN_PA23, 1) +#define PIN_PA23__TDI PINMUX_PIN(PIN_PA23, 4) +#define PIN_PA23__SPI1_MOSI PINMUX_PIN(PIN_PA23, 2) +#define PIN_PA23__QSPI0_CS PINMUX_PIN(PIN_PA23, 3) +#define PIN_PA24 24 +#define PIN_PA24__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA24, 1) +#define PIN_PA24__D2 PINMUX_PIN(PIN_PA24, 1) +#define PIN_PA24__TDO PINMUX_PIN(PIN_PA24, 4) +#define PIN_PA24__SPI1_MISO PINMUX_PIN(PIN_PA24, 2) +#define PIN_PA24__QSPI0_IO0 PINMUX_PIN(PIN_PA24, 3) +#define PIN_PA25 25 +#define PIN_PA25__FLEXCOM1_IO3 PINMUX_PIN(PIN_PA25, 1) +#define PIN_PA25__D3 PINMUX_PIN(PIN_PA25, 1) +#define PIN_PA25__TMS PINMUX_PIN(PIN_PA25, 4) +#define PIN_PA25__SPI1_NPCS0 PINMUX_PIN(PIN_PA25, 2) +#define PIN_PA25__QSPI0_IO1 PINMUX_PIN(PIN_PA25, 3) +#define PIN_PA26 26 +#define PIN_PA26__FLEXCOM1_IO4 PINMUX_PIN(PIN_PA26, 1) +#define PIN_PA26__D4 PINMUX_PIN(PIN_PA26, 1) +#define PIN_PA26__NTRST PINMUX_PIN(PIN_PA26, 4) +#define PIN_PA26__SPI1_NPCS1 PINMUX_PIN(PIN_PA26, 2) +#define PIN_PA26__QSPI0_IO2 PINMUX_PIN(PIN_PA26, 3) +#define PIN_PA27 27 +#define PIN_PA27__TIOA1 PINMUX_PIN(PIN_PA27, 2) +#define PIN_PA27__D5 PINMUX_PIN(PIN_PA27, 1) +#define PIN_PA27__SPI0_NPCS2 PINMUX_PIN(PIN_PA27, 2) +#define PIN_PA27__SPI1_NPCS2 PINMUX_PIN(PIN_PA27, 2) +#define PIN_PA27__SDMMC1_RSTN PINMUX_PIN(PIN_PA27, 1) +#define PIN_PA27__QSPI0_IO3 PINMUX_PIN(PIN_PA27, 3) +#define PIN_PA28 28 +#define PIN_PA28__TIOB1 PINMUX_PIN(PIN_PA28, 2) +#define PIN_PA28__D6 PINMUX_PIN(PIN_PA28, 1) +#define PIN_PA28__SPI0_NPCS3 PINMUX_PIN(PIN_PA28, 2) +#define PIN_PA28__SPI1_NPCS3 PINMUX_PIN(PIN_PA28, 2) +#define PIN_PA28__SDMMC1_CMD PINMUX_PIN(PIN_PA28, 1) +#define PIN_PA28__CLASSD_L0 PINMUX_PIN(PIN_PA28, 1) +#define PIN_PA29 29 +#define PIN_PA29__TCLK1 PINMUX_PIN(PIN_PA29, 2) +#define PIN_PA29__D7 PINMUX_PIN(PIN_PA29, 1) +#define PIN_PA29__SPI0_NPCS1 PINMUX_PIN(PIN_PA29, 2) +#define PIN_PA29__SDMMC1_WP PINMUX_PIN(PIN_PA29, 1) +#define PIN_PA29__CLASSD_L1 PINMUX_PIN(PIN_PA29, 1) +#define PIN_PA30 30 +#define PIN_PA30__NWE_NANDWE PINMUX_PIN(PIN_PA30, 1) +#define PIN_PA30__SPI0_NPCS0 PINMUX_PIN(PIN_PA30, 2) +#define PIN_PA30__PWMH0 PINMUX_PIN(PIN_PA30, 1) +#define PIN_PA30__SDMMC1_CD PINMUX_PIN(PIN_PA30, 1) +#define PIN_PA30__CLASSD_L2 PINMUX_PIN(PIN_PA30, 1) +#define PIN_PA31 31 +#define PIN_PA31__NCS3 PINMUX_PIN(PIN_PA31, 1) +#define PIN_PA31__SPI0_MISO PINMUX_PIN(PIN_PA31, 2) +#define PIN_PA31__PWML0 PINMUX_PIN(PIN_PA31, 1) +#define PIN_PA31__CLASSD_L3 PINMUX_PIN(PIN_PA31, 1) +#define PIN_PB0 32 +#define PIN_PB0__A21_NANDALE PINMUX_PIN(PIN_PB0, 1) +#define PIN_PB0__SPI0_MOSI PINMUX_PIN(PIN_PB0, 2) +#define PIN_PB0__PWMH1 PINMUX_PIN(PIN_PB0, 1) +#define PIN_PB0__PTC_PORT0 PINMUX_PIN(PIN_PB0, 1) +#define PIN_PB1 33 +#define PIN_PB1__A22_NANDCLE PINMUX_PIN(PIN_PB1, 1) +#define PIN_PB1__SPI0_SPCK PINMUX_PIN(PIN_PB1, 2) +#define PIN_PB1__PWML1 PINMUX_PIN(PIN_PB1, 1) +#define PIN_PB1__PTC_PORT1 PINMUX_PIN(PIN_PB1, 1) +#define PIN_PB1__CLASSD_R0 PINMUX_PIN(PIN_PB1, 1) +#define PIN_PB2 34 +#define PIN_PB2__NRD_NANDOE PINMUX_PIN(PIN_PB2, 1) +#define PIN_PB2__PWMFI0 PINMUX_PIN(PIN_PB2, 1) +#define PIN_PB2__PTC_PORT2 PINMUX_PIN(PIN_PB2, 1) +#define PIN_PB2__CLASSD_R1 PINMUX_PIN(PIN_PB2, 1) +#define PIN_PB3 35 +#define PIN_PB3__URXD4 PINMUX_PIN(PIN_PB3, 1) +#define PIN_PB3__D8 PINMUX_PIN(PIN_PB3, 1) +#define PIN_PB3__IRQ PINMUX_PIN(PIN_PB3, 3) +#define PIN_PB3__PWMEXTRG0 PINMUX_PIN(PIN_PB3, 1) +#define PIN_PB3__PTC_PORT3 PINMUX_PIN(PIN_PB3, 1) +#define PIN_PB3__CLASSD_R2 PINMUX_PIN(PIN_PB3, 1) +#define PIN_PB4 36 +#define PIN_PB4__UTXD4 PINMUX_PIN(PIN_PB4, 1) +#define PIN_PB4__D9 PINMUX_PIN(PIN_PB4, 1) +#define PIN_PB4__FIQ PINMUX_PIN(PIN_PB4, 4) +#define PIN_PB4__PTC_PORT4 PINMUX_PIN(PIN_PB4, 1) +#define PIN_PB4__CLASSD_R3 PINMUX_PIN(PIN_PB4, 1) +#define PIN_PB5 37 +#define PIN_PB5__TCLK2 PINMUX_PIN(PIN_PB5, 1) +#define PIN_PB5__D10 PINMUX_PIN(PIN_PB5, 1) +#define PIN_PB5__PWMH2 PINMUX_PIN(PIN_PB5, 1) +#define PIN_PB5__QSPI1_SCK PINMUX_PIN(PIN_PB5, 2) +#define PIN_PB5__PTC_PORT5 PINMUX_PIN(PIN_PB5, 1) +#define PIN_PB5__GTSUCOMP PINMUX_PIN(PIN_PB5, 3) +#define PIN_PB6 38 +#define PIN_PB6__TIOA2 PINMUX_PIN(PIN_PB6, 1) +#define PIN_PB6__D11 PINMUX_PIN(PIN_PB6, 1) +#define PIN_PB6__PWML2 PINMUX_PIN(PIN_PB6, 1) +#define PIN_PB6__QSPI1_CS PINMUX_PIN(PIN_PB6, 2) +#define PIN_PB6__PTC_PORT6 PINMUX_PIN(PIN_PB6, 1) +#define PIN_PB6__GTXER PINMUX_PIN(PIN_PB6, 3) +#define PIN_PB7 39 +#define PIN_PB7__TIOB2 PINMUX_PIN(PIN_PB7, 1) +#define PIN_PB7__D12 PINMUX_PIN(PIN_PB7, 1) +#define PIN_PB7__PWMH3 PINMUX_PIN(PIN_PB7, 1) +#define PIN_PB7__QSPI1_IO0 PINMUX_PIN(PIN_PB7, 2) +#define PIN_PB7__PTC_PORT7 PINMUX_PIN(PIN_PB7, 1) +#define PIN_PB7__GRXCK PINMUX_PIN(PIN_PB7, 3) +#define PIN_PB8 40 +#define PIN_PB8__TCLK3 PINMUX_PIN(PIN_PB8, 1) +#define PIN_PB8__D13 PINMUX_PIN(PIN_PB8, 1) +#define PIN_PB8__PWML3 PINMUX_PIN(PIN_PB8, 1) +#define PIN_PB8__QSPI1_IO1 PINMUX_PIN(PIN_PB8, 2) +#define PIN_PB8__GTSUCOMP PINMUX_PIN(PIN_PB8, 3) +#define PIN_PB9 41 +#define PIN_PB9__TIOA3 PINMUX_PIN(PIN_PB9, 1) +#define PIN_PB9__D14 PINMUX_PIN(PIN_PB9, 1) +#define PIN_PB9__PWMFI1 PINMUX_PIN(PIN_PB9, 1) +#define PIN_PB9__QSPI1_IO2 PINMUX_PIN(PIN_PB9, 2) +#define PIN_PB9__GCOL PINMUX_PIN(PIN_PB9, 3) +#define PIN_PB10 42 +#define PIN_PB10__TIOB3 PINMUX_PIN(PIN_PB10, 1) +#define PIN_PB10__D15 PINMUX_PIN(PIN_PB10, 1) +#define PIN_PB10__PWMEXTRG1 PINMUX_PIN(PIN_PB10, 1) +#define PIN_PB10__QSPI1_IO3 PINMUX_PIN(PIN_PB10, 2) +#define PIN_PB10__GRX2 PINMUX_PIN(PIN_PB10, 3) +#define PIN_PB11 43 +#define PIN_PB11__LCDDAT0 PINMUX_PIN(PIN_PB11, 1) +#define PIN_PB11__A0_NBS0 PINMUX_PIN(PIN_PB11, 1) +#define PIN_PB11__URXD3 PINMUX_PIN(PIN_PB11, 3) +#define PIN_PB11__PDMIC_DAT0 PINMUX_PIN(PIN_PB11, 2) +#define PIN_PB11__GRX3 PINMUX_PIN(PIN_PB11, 3) +#define PIN_PB12 44 +#define PIN_PB12__LCDDAT1 PINMUX_PIN(PIN_PB12, 1) +#define PIN_PB12__A1 PINMUX_PIN(PIN_PB12, 1) +#define PIN_PB12__UTXD3 PINMUX_PIN(PIN_PB12, 3) +#define PIN_PB12__PDMIC_CLK0 PINMUX_PIN(PIN_PB12, 2) +#define PIN_PB12__GTX2 PINMUX_PIN(PIN_PB12, 3) +#define PIN_PB13 45 +#define PIN_PB13__LCDDAT2 PINMUX_PIN(PIN_PB13, 1) +#define PIN_PB13__A2 PINMUX_PIN(PIN_PB13, 1) +#define PIN_PB13__PCK1 PINMUX_PIN(PIN_PB13, 3) +#define PIN_PB13__GTX3 PINMUX_PIN(PIN_PB13, 3) +#define PIN_PB14 46 +#define PIN_PB14__LCDDAT3 PINMUX_PIN(PIN_PB14, 1) +#define PIN_PB14__A3 PINMUX_PIN(PIN_PB14, 1) +#define PIN_PB14__TK1 PINMUX_PIN(PIN_PB14, 2) +#define PIN_PB14__I2SMCK1 PINMUX_PIN(PIN_PB14, 1) +#define PIN_PB14__QSPI1_SCK PINMUX_PIN(PIN_PB14, 3) +#define PIN_PB14__GTXCK PINMUX_PIN(PIN_PB14, 3) +#define PIN_PB15 47 +#define PIN_PB15__LCDDAT4 PINMUX_PIN(PIN_PB15, 1) +#define PIN_PB15__A4 PINMUX_PIN(PIN_PB15, 1) +#define PIN_PB15__TF1 PINMUX_PIN(PIN_PB15, 2) +#define PIN_PB15__I2SCK1 PINMUX_PIN(PIN_PB15, 1) +#define PIN_PB15__QSPI1_CS PINMUX_PIN(PIN_PB15, 3) +#define PIN_PB15__GTXEN PINMUX_PIN(PIN_PB15, 3) +#define PIN_PB16 48 +#define PIN_PB16__LCDDAT5 PINMUX_PIN(PIN_PB16, 1) +#define PIN_PB16__A5 PINMUX_PIN(PIN_PB16, 1) +#define PIN_PB16__TD1 PINMUX_PIN(PIN_PB16, 2) +#define PIN_PB16__I2SWS1 PINMUX_PIN(PIN_PB16, 1) +#define PIN_PB16__QSPI1_IO0 PINMUX_PIN(PIN_PB16, 3) +#define PIN_PB16__GRXDV PINMUX_PIN(PIN_PB16, 3) +#define PIN_PB17 49 +#define PIN_PB17__LCDDAT6 PINMUX_PIN(PIN_PB17, 1) +#define PIN_PB17__A6 PINMUX_PIN(PIN_PB17, 1) +#define PIN_PB17__RD1 PINMUX_PIN(PIN_PB17, 2) +#define PIN_PB17__I2SDI1 PINMUX_PIN(PIN_PB17, 1) +#define PIN_PB17__QSPI1_IO1 PINMUX_PIN(PIN_PB17, 3) +#define PIN_PB17__GRXER PINMUX_PIN(PIN_PB17, 3) +#define PIN_PB18 50 +#define PIN_PB18__LCDDAT7 PINMUX_PIN(PIN_PB18, 1) +#define PIN_PB18__A7 PINMUX_PIN(PIN_PB18, 1) +#define PIN_PB18__RK1 PINMUX_PIN(PIN_PB18, 2) +#define PIN_PB18__I2SDO1 PINMUX_PIN(PIN_PB18, 1) +#define PIN_PB18__QSPI1_IO2 PINMUX_PIN(PIN_PB18, 3) +#define PIN_PB18__GRX0 PINMUX_PIN(PIN_PB18, 3) +#define PIN_PB19 51 +#define PIN_PB19__LCDDAT8 PINMUX_PIN(PIN_PB19, 1) +#define PIN_PB19__A8 PINMUX_PIN(PIN_PB19, 1) +#define PIN_PB19__RF1 PINMUX_PIN(PIN_PB19, 2) +#define PIN_PB19__TIOA3 PINMUX_PIN(PIN_PB19, 2) +#define PIN_PB19__QSPI1_IO3 PINMUX_PIN(PIN_PB19, 3) +#define PIN_PB19__GRX1 PINMUX_PIN(PIN_PB19, 3) +#define PIN_PB20 52 +#define PIN_PB20__LCDDAT9 PINMUX_PIN(PIN_PB20, 1) +#define PIN_PB20__A9 PINMUX_PIN(PIN_PB20, 1) +#define PIN_PB20__TK0 PINMUX_PIN(PIN_PB20, 1) +#define PIN_PB20__TIOB3 PINMUX_PIN(PIN_PB20, 2) +#define PIN_PB20__PCK1 PINMUX_PIN(PIN_PB20, 4) +#define PIN_PB20__GTX0 PINMUX_PIN(PIN_PB20, 3) +#define PIN_PB21 53 +#define PIN_PB21__LCDDAT10 PINMUX_PIN(PIN_PB21, 1) +#define PIN_PB21__A10 PINMUX_PIN(PIN_PB21, 1) +#define PIN_PB21__TF0 PINMUX_PIN(PIN_PB21, 1) +#define PIN_PB21__TCLK3 PINMUX_PIN(PIN_PB21, 2) +#define PIN_PB21__FLEXCOM3_IO2 PINMUX_PIN(PIN_PB21, 3) +#define PIN_PB21__GTX1 PINMUX_PIN(PIN_PB21, 3) +#define PIN_PB22 54 +#define PIN_PB22__LCDDAT11 PINMUX_PIN(PIN_PB22, 1) +#define PIN_PB22__A11 PINMUX_PIN(PIN_PB22, 1) +#define PIN_PB22__TDO PINMUX_PIN(PIN_PB22, 1) +#define PIN_PB22__TIOA2 PINMUX_PIN(PIN_PB22, 2) +#define PIN_PB22__FLEXCOM3_IO1 PINMUX_PIN(PIN_PB22, 3) +#define PIN_PB22__GMDC PINMUX_PIN(PIN_PB22, 3) +#define PIN_PB23 55 +#define PIN_PB23__LCDDAT12 PINMUX_PIN(PIN_PB23, 1) +#define PIN_PB23__A12 PINMUX_PIN(PIN_PB23, 1) +#define PIN_PB23__RD0 PINMUX_PIN(PIN_PB23, 1) +#define PIN_PB23__TIOB2 PINMUX_PIN(PIN_PB23, 2) +#define PIN_PB23__FLEXCOM3_IO0 PINMUX_PIN(PIN_PB23, 3) +#define PIN_PB23__GMDIO PINMUX_PIN(PIN_PB23, 3) +#define PIN_PB24 56 +#define PIN_PB24__LCDDAT13 PINMUX_PIN(PIN_PB24, 1) +#define PIN_PB24__A13 PINMUX_PIN(PIN_PB24, 1) +#define PIN_PB24__RK0 PINMUX_PIN(PIN_PB24, 1) +#define PIN_PB24__TCLK2 PINMUX_PIN(PIN_PB24, 2) +#define PIN_PB24__FLEXCOM3_IO3 PINMUX_PIN(PIN_PB24, 3) +#define PIN_PB24__ISI_D10 PINMUX_PIN(PIN_PB24, 3) +#define PIN_PB25 57 +#define PIN_PB25__LCDDAT14 PINMUX_PIN(PIN_PB25, 1) +#define PIN_PB25__A14 PINMUX_PIN(PIN_PB25, 1) +#define PIN_PB25__RF0 PINMUX_PIN(PIN_PB25, 1) +#define PIN_PB25__FLEXCOM3_IO4 PINMUX_PIN(PIN_PB25, 3) +#define PIN_PB25__ISI_D11 PINMUX_PIN(PIN_PB25, 3) +#define PIN_PB26 58 +#define PIN_PB26__LCDDAT15 PINMUX_PIN(PIN_PB26, 1) +#define PIN_PB26__A15 PINMUX_PIN(PIN_PB26, 1) +#define PIN_PB26__URXD0 PINMUX_PIN(PIN_PB26, 1) +#define PIN_PB26__PDMIC_DAT0 PINMUX_PIN(PIN_PB26, 1) +#define PIN_PB26__ISI_D0 PINMUX_PIN(PIN_PB26, 3) +#define PIN_PB27 59 +#define PIN_PB27__LCDDAT16 PINMUX_PIN(PIN_PB27, 1) +#define PIN_PB27__A16 PINMUX_PIN(PIN_PB27, 1) +#define PIN_PB27__UTXD0 PINMUX_PIN(PIN_PB27, 1) +#define PIN_PB27__PDMIC_CLK0 PINMUX_PIN(PIN_PB27, 1) +#define PIN_PB27__ISI_D1 PINMUX_PIN(PIN_PB27, 3) +#define PIN_PB28 60 +#define PIN_PB28__LCDDAT17 PINMUX_PIN(PIN_PB28, 1) +#define PIN_PB28__A17 PINMUX_PIN(PIN_PB28, 1) +#define PIN_PB28__FLEXCOM0_IO0 PINMUX_PIN(PIN_PB28, 1) +#define PIN_PB28__TIOA5 PINMUX_PIN(PIN_PB28, 2) +#define PIN_PB28__ISI_D2 PINMUX_PIN(PIN_PB28, 3) +#define PIN_PB29 61 +#define PIN_PB29__LCDDAT18 PINMUX_PIN(PIN_PB29, 1) +#define PIN_PB29__A18 PINMUX_PIN(PIN_PB29, 1) +#define PIN_PB29__FLEXCOM0_IO1 PINMUX_PIN(PIN_PB29, 1) +#define PIN_PB29__TIOB5 PINMUX_PIN(PIN_PB29, 2) +#define PIN_PB29__ISI_D3 PINMUX_PIN(PIN_PB29, 3) +#define PIN_PB30 62 +#define PIN_PB30__LCDDAT19 PINMUX_PIN(PIN_PB30, 1) +#define PIN_PB30__A19 PINMUX_PIN(PIN_PB30, 1) +#define PIN_PB30__FLEXCOM0_IO2 PINMUX_PIN(PIN_PB30, 1) +#define PIN_PB30__TCLK5 PINMUX_PIN(PIN_PB30, 2) +#define PIN_PB30__ISI_D4 PINMUX_PIN(PIN_PB30, 3) +#define PIN_PB31 63 +#define PIN_PB31__LCDDAT20 PINMUX_PIN(PIN_PB31, 1) +#define PIN_PB31__A20 PINMUX_PIN(PIN_PB31, 1) +#define PIN_PB31__FLEXCOM0_IO3 PINMUX_PIN(PIN_PB31, 1) +#define PIN_PB31__TWD0 PINMUX_PIN(PIN_PB31, 1) +#define PIN_PB31__ISI_D5 PINMUX_PIN(PIN_PB31, 3) +#define PIN_PC0 64 +#define PIN_PC0__LCDDAT21 PINMUX_PIN(PIN_PC0, 1) +#define PIN_PC0__A23 PINMUX_PIN(PIN_PC0, 1) +#define PIN_PC0__FLEXCOM0_IO4 PINMUX_PIN(PIN_PC0, 1) +#define PIN_PC0__TWCK0 PINMUX_PIN(PIN_PC0, 1) +#define PIN_PC0__ISI_D6 PINMUX_PIN(PIN_PC0, 3) +#define PIN_PC1 65 +#define PIN_PC1__LCDDAT22 PINMUX_PIN(PIN_PC1, 1) +#define PIN_PC1__A24 PINMUX_PIN(PIN_PC1, 1) +#define PIN_PC1__CANTX0 PINMUX_PIN(PIN_PC1, 1) +#define PIN_PC1__SPI1_SPCK PINMUX_PIN(PIN_PC1, 1) +#define PIN_PC1__I2SCK0 PINMUX_PIN(PIN_PC1, 1) +#define PIN_PC1__ISI_D7 PINMUX_PIN(PIN_PC1, 3) +#define PIN_PC2 66 +#define PIN_PC2__LCDDAT23 PINMUX_PIN(PIN_PC2, 1) +#define PIN_PC2__A25 PINMUX_PIN(PIN_PC2, 1) +#define PIN_PC2__CANRX0 PINMUX_PIN(PIN_PC2, 1) +#define PIN_PC2__SPI1_MOSI PINMUX_PIN(PIN_PC2, 1) +#define PIN_PC2__I2SMCK0 PINMUX_PIN(PIN_PC2, 1) +#define PIN_PC2__ISI_D8 PINMUX_PIN(PIN_PC2, 3) +#define PIN_PC3 67 +#define PIN_PC3__LCDPWM PINMUX_PIN(PIN_PC3, 1) +#define PIN_PC3__NWAIT PINMUX_PIN(PIN_PC3, 1) +#define PIN_PC3__TIOA1 PINMUX_PIN(PIN_PC3, 1) +#define PIN_PC3__SPI1_MISO PINMUX_PIN(PIN_PC3, 1) +#define PIN_PC3__I2SWS0 PINMUX_PIN(PIN_PC3, 1) +#define PIN_PC3__ISI_D9 PINMUX_PIN(PIN_PC3, 3) +#define PIN_PC4 68 +#define PIN_PC4__LCDDISP PINMUX_PIN(PIN_PC4, 1) +#define PIN_PC4__NWR1_NBS1 PINMUX_PIN(PIN_PC4, 1) +#define PIN_PC4__TIOB1 PINMUX_PIN(PIN_PC4, 1) +#define PIN_PC4__SPI1_NPCS0 PINMUX_PIN(PIN_PC4, 1) +#define PIN_PC4__I2SDI0 PINMUX_PIN(PIN_PC4, 1) +#define PIN_PC4__ISI_PCK PINMUX_PIN(PIN_PC4, 3) +#define PIN_PC5 69 +#define PIN_PC5__LCDVSYNC PINMUX_PIN(PIN_PC5, 1) +#define PIN_PC5__NCS0 PINMUX_PIN(PIN_PC5, 1) +#define PIN_PC5__TCLK1 PINMUX_PIN(PIN_PC5, 1) +#define PIN_PC5__SPI1_NPCS1 PINMUX_PIN(PIN_PC5, 1) +#define PIN_PC5__I2SDO0 PINMUX_PIN(PIN_PC5, 1) +#define PIN_PC5__ISI_VSYNC PINMUX_PIN(PIN_PC5, 3) +#define PIN_PC6 70 +#define PIN_PC6__LCDHSYNC PINMUX_PIN(PIN_PC6, 1) +#define PIN_PC6__NCS1 PINMUX_PIN(PIN_PC6, 1) +#define PIN_PC6__TWD1 PINMUX_PIN(PIN_PC6, 1) +#define PIN_PC6__SPI1_NPCS2 PINMUX_PIN(PIN_PC6, 1) +#define PIN_PC6__ISI_HSYNC PINMUX_PIN(PIN_PC6, 3) +#define PIN_PC7 71 +#define PIN_PC7__LCDPCK PINMUX_PIN(PIN_PC7, 1) +#define PIN_PC7__NCS2 PINMUX_PIN(PIN_PC7, 1) +#define PIN_PC7__TWCK1 PINMUX_PIN(PIN_PC7, 1) +#define PIN_PC7__SPI1_NPCS3 PINMUX_PIN(PIN_PC7, 1) +#define PIN_PC7__URXD1 PINMUX_PIN(PIN_PC7, 2) +#define PIN_PC7__ISI_MCK PINMUX_PIN(PIN_PC7, 3) +#define PIN_PC8 72 +#define PIN_PC8__LCDDEN PINMUX_PIN(PIN_PC8, 1) +#define PIN_PC8__NANDRDY PINMUX_PIN(PIN_PC8, 1) +#define PIN_PC8__FIQ PINMUX_PIN(PIN_PC8, 1) +#define PIN_PC8__PCK0 PINMUX_PIN(PIN_PC8, 3) +#define PIN_PC8__UTXD1 PINMUX_PIN(PIN_PC8, 2) +#define PIN_PC8__ISI_FIELD PINMUX_PIN(PIN_PC8, 3) +#define PIN_PC9 73 +#define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 3) +#define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 1) +#define PIN_PC9__ISI_D0 PINMUX_PIN(PIN_PC9, 1) +#define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 2) +#define PIN_PC10 74 +#define PIN_PC10__LCDDAT2 PINMUX_PIN(PIN_PC10, 2) +#define PIN_PC10__GTXCK PINMUX_PIN(PIN_PC10, 1) +#define PIN_PC10__ISI_D1 PINMUX_PIN(PIN_PC10, 1) +#define PIN_PC10__TIOB4 PINMUX_PIN(PIN_PC10, 2) +#define PIN_PC10__CANTX0 PINMUX_PIN(PIN_PC10, 2) +#define PIN_PC11 75 +#define PIN_PC11__LCDDAT3 PINMUX_PIN(PIN_PC11, 2) +#define PIN_PC11__GTXEN PINMUX_PIN(PIN_PC11, 1) +#define PIN_PC11__ISI_D2 PINMUX_PIN(PIN_PC11, 1) +#define PIN_PC11__TCLK4 PINMUX_PIN(PIN_PC11, 2) +#define PIN_PC11__CANRX0 PINMUX_PIN(PIN_PC11, 2) +#define PIN_PC11__A0_NBS0 PINMUX_PIN(PIN_PC11, 2) +#define PIN_PC12 76 +#define PIN_PC12__LCDDAT4 PINMUX_PIN(PIN_PC12, 2) +#define PIN_PC12__GRXDV PINMUX_PIN(PIN_PC12, 1) +#define PIN_PC12__ISI_D3 PINMUX_PIN(PIN_PC12, 1) +#define PIN_PC12__URXD3 PINMUX_PIN(PIN_PC12, 1) +#define PIN_PC12__TK0 PINMUX_PIN(PIN_PC12, 2) +#define PIN_PC12__A1 PINMUX_PIN(PIN_PC12, 2) +#define PIN_PC13 77 +#define PIN_PC13__LCDDAT5 PINMUX_PIN(PIN_PC13, 2) +#define PIN_PC13__GRXER PINMUX_PIN(PIN_PC13, 1) +#define PIN_PC13__ISI_D4 PINMUX_PIN(PIN_PC13, 1) +#define PIN_PC13__UTXD3 PINMUX_PIN(PIN_PC13, 1) +#define PIN_PC13__TF0 PINMUX_PIN(PIN_PC13, 2) +#define PIN_PC13__A2 PINMUX_PIN(PIN_PC13, 2) +#define PIN_PC14 78 +#define PIN_PC14__LCDDAT6 PINMUX_PIN(PIN_PC14, 2) +#define PIN_PC14__GRX0 PINMUX_PIN(PIN_PC14, 1) +#define PIN_PC14__ISI_D5 PINMUX_PIN(PIN_PC14, 1) +#define PIN_PC14__TDO PINMUX_PIN(PIN_PC14, 2) +#define PIN_PC14__A3 PINMUX_PIN(PIN_PC14, 2) +#define PIN_PC15 79 +#define PIN_PC15__LCDDAT7 PINMUX_PIN(PIN_PC15, 2) +#define PIN_PC15__GRX1 PINMUX_PIN(PIN_PC15, 1) +#define PIN_PC15__ISI_D6 PINMUX_PIN(PIN_PC15, 1) +#define PIN_PC15__RD0 PINMUX_PIN(PIN_PC15, 2) +#define PIN_PC15__A4 PINMUX_PIN(PIN_PC15, 2) +#define PIN_PC16 80 +#define PIN_PC16__LCDDAT10 PINMUX_PIN(PIN_PC16, 2) +#define PIN_PC16__GTX0 PINMUX_PIN(PIN_PC16, 1) +#define PIN_PC16__ISI_D7 PINMUX_PIN(PIN_PC16, 1) +#define PIN_PC16__RK0 PINMUX_PIN(PIN_PC16, 2) +#define PIN_PC16__A5 PINMUX_PIN(PIN_PC16, 2) +#define PIN_PC17 81 +#define PIN_PC17__LCDDAT11 PINMUX_PIN(PIN_PC17, 2) +#define PIN_PC17__GTX1 PINMUX_PIN(PIN_PC17, 1) +#define PIN_PC17__ISI_D8 PINMUX_PIN(PIN_PC17, 1) +#define PIN_PC17__TF0 PINMUX_PIN(PIN_PC17, 2) +#define PIN_PC17__A6 PINMUX_PIN(PIN_PC17, 2) +#define PIN_PC18 82 +#define PIN_PC18__LCDDAT12 PINMUX_PIN(PIN_PC18, 2) +#define PIN_PC18__GMDC PINMUX_PIN(PIN_PC18, 1) +#define PIN_PC18__ISI_D9 PINMUX_PIN(PIN_PC18, 1) +#define PIN_PC18__FLEXCOM3_IO2 PINMUX_PIN(PIN_PC18, 2) +#define PIN_PC18__A7 PINMUX_PIN(PIN_PC18, 2) +#define PIN_PC19 83 +#define PIN_PC19__LCDDAT13 PINMUX_PIN(PIN_PC19, 2) +#define PIN_PC19__GMDIO PINMUX_PIN(PIN_PC19, 1) +#define PIN_PC19__ISI_D10 PINMUX_PIN(PIN_PC19, 1) +#define PIN_PC19__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC19, 2) +#define PIN_PC19__A8 PINMUX_PIN(PIN_PC19, 2) +#define PIN_PC20 84 +#define PIN_PC20__LCDDAT14 PINMUX_PIN(PIN_PC20, 2) +#define PIN_PC20__GRXCK PINMUX_PIN(PIN_PC20, 1) +#define PIN_PC20__ISI_D11 PINMUX_PIN(PIN_PC20, 1) +#define PIN_PC20__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC20, 2) +#define PIN_PC20__A9 PINMUX_PIN(PIN_PC20, 2) +#define PIN_PC21 85 +#define PIN_PC21__LCDDAT15 PINMUX_PIN(PIN_PC21, 2) +#define PIN_PC21__GTXER PINMUX_PIN(PIN_PC21, 1) +#define PIN_PC21__ISI_PCK PINMUX_PIN(PIN_PC21, 1) +#define PIN_PC21__FLEXCOM3_IO3 PINMUX_PIN(PIN_PC21, 2) +#define PIN_PC21__A10 PINMUX_PIN(PIN_PC21, 2) +#define PIN_PC22 86 +#define PIN_PC22__LCDDAT18 PINMUX_PIN(PIN_PC22, 2) +#define PIN_PC22__GCRS PINMUX_PIN(PIN_PC22, 1) +#define PIN_PC22__ISI_VSYNC PINMUX_PIN(PIN_PC22, 1) +#define PIN_PC22__FLEXCOM3_IO4 PINMUX_PIN(PIN_PC22, 2) +#define PIN_PC22__A11 PINMUX_PIN(PIN_PC22, 2) +#define PIN_PC23 87 +#define PIN_PC23__LCDDAT19 PINMUX_PIN(PIN_PC23, 2) +#define PIN_PC23__GCOL PINMUX_PIN(PIN_PC23, 1) +#define PIN_PC23__ISI_HSYNC PINMUX_PIN(PIN_PC23, 1) +#define PIN_PC23__A12 PINMUX_PIN(PIN_PC23, 2) +#define PIN_PC24 88 +#define PIN_PC24__LCDDAT20 PINMUX_PIN(PIN_PC24, 2) +#define PIN_PC24__GRX2 PINMUX_PIN(PIN_PC24, 1) +#define PIN_PC24__ISI_MCK PINMUX_PIN(PIN_PC24, 1) +#define PIN_PC24__A13 PINMUX_PIN(PIN_PC24, 2) +#define PIN_PC25 89 +#define PIN_PC25__LCDDAT21 PINMUX_PIN(PIN_PC25, 2) +#define PIN_PC25__GRX3 PINMUX_PIN(PIN_PC25, 1) +#define PIN_PC25__ISI_FIELD PINMUX_PIN(PIN_PC25, 1) +#define PIN_PC25__A14 PINMUX_PIN(PIN_PC25, 2) +#define PIN_PC26 90 +#define PIN_PC26__LCDDAT22 PINMUX_PIN(PIN_PC26, 2) +#define PIN_PC26__GTX2 PINMUX_PIN(PIN_PC26, 1) +#define PIN_PC26__CANTX1 PINMUX_PIN(PIN_PC26, 1) +#define PIN_PC26__A15 PINMUX_PIN(PIN_PC26, 2) +#define PIN_PC27 91 +#define PIN_PC27__LCDDAT23 PINMUX_PIN(PIN_PC27, 2) +#define PIN_PC27__GTX3 PINMUX_PIN(PIN_PC27, 1) +#define PIN_PC27__PCK1 PINMUX_PIN(PIN_PC27, 2) +#define PIN_PC27__CANRX1 PINMUX_PIN(PIN_PC27, 1) +#define PIN_PC27__TWD0 PINMUX_PIN(PIN_PC27, 2) +#define PIN_PC27__A16 PINMUX_PIN(PIN_PC27, 2) +#define PIN_PC28 92 +#define PIN_PC28__LCDPWM PINMUX_PIN(PIN_PC28, 2) +#define PIN_PC28__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC28, 1) +#define PIN_PC28__PCK2 PINMUX_PIN(PIN_PC28, 2) +#define PIN_PC28__TWCK0 PINMUX_PIN(PIN_PC28, 2) +#define PIN_PC28__A17 PINMUX_PIN(PIN_PC28, 2) +#define PIN_PC29 93 +#define PIN_PC29__LCDDISP PINMUX_PIN(PIN_PC29, 2) +#define PIN_PC29__FLEXCOM4_IO1 PINMUX_PIN(PIN_PC29, 1) +#define PIN_PC29__A18 PINMUX_PIN(PIN_PC29, 2) +#define PIN_PC30 94 +#define PIN_PC30__LCDVSYNC PINMUX_PIN(PIN_PC30, 2) +#define PIN_PC30__FLEXCOM4_IO2 PINMUX_PIN(PIN_PC30, 1) +#define PIN_PC30__A19 PINMUX_PIN(PIN_PC30, 2) +#define PIN_PC31 95 +#define PIN_PC31__LCDHSYNC PINMUX_PIN(PIN_PC31, 2) +#define PIN_PC31__FLEXCOM4_IO3 PINMUX_PIN(PIN_PC31, 1) +#define PIN_PC31__URXD3 PINMUX_PIN(PIN_PC31, 2) +#define PIN_PC31__A20 PINMUX_PIN(PIN_PC31, 2) +#define PIN_PD0 96 +#define PIN_PD0__LCDPCK PINMUX_PIN(PIN_PD0, 2) +#define PIN_PD0__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD0, 1) +#define PIN_PD0__UTXD3 PINMUX_PIN(PIN_PD0, 2) +#define PIN_PD0__GTSUCOMP PINMUX_PIN(PIN_PD0, 2) +#define PIN_PD0__A23 PINMUX_PIN(PIN_PD0, 2) +#define PIN_PD1 97 +#define PIN_PD1__LCDDEN PINMUX_PIN(PIN_PD1, 2) +#define PIN_PD1__GRXCK PINMUX_PIN(PIN_PD1, 2) +#define PIN_PD1__A24 PINMUX_PIN(PIN_PD1, 2) +#define PIN_PD2 98 +#define PIN_PD2__URXD1 PINMUX_PIN(PIN_PD2, 1) +#define PIN_PD2__UTXD3 PINMUX_PIN(PIN_PD2, 2) +#define PIN_PD2__GTXER PINMUX_PIN(PIN_PD2, 2) +#define PIN_PD2__A25 PINMUX_PIN(PIN_PD2, 2) +#define PIN_PD3 99 +#define PIN_PD3__UTXD1 PINMUX_PIN(PIN_PD3, 1) +#define PIN_PD3__FIQ PINMUX_PIN(PIN_PD3, 2) +#define PIN_PD3__GCRS PINMUX_PIN(PIN_PD3, 2) +#define PIN_PD3__ISI_D11 PINMUX_PIN(PIN_PD3, 2) +#define PIN_PD3__NWAIT PINMUX_PIN(PIN_PD3, 2) +#define PIN_PD4 100 +#define PIN_PD4__TWD1 PINMUX_PIN(PIN_PD4, 2) +#define PIN_PD4__URXD2 PINMUX_PIN(PIN_PD4, 1) +#define PIN_PD4__GCOL PINMUX_PIN(PIN_PD4, 2) +#define PIN_PD4__ISI_D10 PINMUX_PIN(PIN_PD4, 2) +#define PIN_PD4__NCS0 PINMUX_PIN(PIN_PD4, 2) +#define PIN_PD5 101 +#define PIN_PD5__TWCK1 PINMUX_PIN(PIN_PD5, 2) +#define PIN_PD5__UTXD2 PINMUX_PIN(PIN_PD5, 1) +#define PIN_PD5__GRX2 PINMUX_PIN(PIN_PD5, 2) +#define PIN_PD5__ISI_D9 PINMUX_PIN(PIN_PD5, 2) +#define PIN_PD5__NCS1 PINMUX_PIN(PIN_PD5, 2) +#define PIN_PD6 102 +#define PIN_PD6__TCK PINMUX_PIN(PIN_PD6, 2) +#define PIN_PD6__PCK1 PINMUX_PIN(PIN_PD6, 1) +#define PIN_PD6__GRX3 PINMUX_PIN(PIN_PD6, 2) +#define PIN_PD6__ISI_D8 PINMUX_PIN(PIN_PD6, 2) +#define PIN_PD6__NCS2 PINMUX_PIN(PIN_PD6, 2) +#define PIN_PD7 103 +#define PIN_PD7__TDI PINMUX_PIN(PIN_PD7, 2) +#define PIN_PD7__UTMI_RXVAL PINMUX_PIN(PIN_PD7, 1) +#define PIN_PD7__GTX2 PINMUX_PIN(PIN_PD7, 2) +#define PIN_PD7__ISI_D0 PINMUX_PIN(PIN_PD7, 2) +#define PIN_PD7__NWR1_NBS1 PINMUX_PIN(PIN_PD7, 2) +#define PIN_PD8 104 +#define PIN_PD8__TDO PINMUX_PIN(PIN_PD8, 2) +#define PIN_PD8__UTMI_RXERR PINMUX_PIN(PIN_PD8, 1) +#define PIN_PD8__GTX3 PINMUX_PIN(PIN_PD8, 2) +#define PIN_PD8__ISI_D1 PINMUX_PIN(PIN_PD8, 2) +#define PIN_PD8__NANDRDY PINMUX_PIN(PIN_PD8, 2) +#define PIN_PD9 105 +#define PIN_PD9__TMS PINMUX_PIN(PIN_PD9, 2) +#define PIN_PD9__UTMI_RXACT PINMUX_PIN(PIN_PD9, 1) +#define PIN_PD9__GTXCK PINMUX_PIN(PIN_PD9, 2) +#define PIN_PD9__ISI_D2 PINMUX_PIN(PIN_PD9, 2) +#define PIN_PD10 106 +#define PIN_PD10__NTRST PINMUX_PIN(PIN_PD10, 2) +#define PIN_PD10__UTMI_HDIS PINMUX_PIN(PIN_PD10, 1) +#define PIN_PD10__GTXEN PINMUX_PIN(PIN_PD10, 2) +#define PIN_PD10__ISI_D3 PINMUX_PIN(PIN_PD10, 2) +#define PIN_PD11 107 +#define PIN_PD11__TIOA1 PINMUX_PIN(PIN_PD11, 3) +#define PIN_PD11__PCK2 PINMUX_PIN(PIN_PD11, 2) +#define PIN_PD11__UTMI_LS0 PINMUX_PIN(PIN_PD11, 1) +#define PIN_PD11__GRXDV PINMUX_PIN(PIN_PD11, 2) +#define PIN_PD11__ISI_D4 PINMUX_PIN(PIN_PD11, 2) +#define PIN_PD11__ISI_MCK PINMUX_PIN(PIN_PD11, 4) +#define PIN_PD12 108 +#define PIN_PD12__TIOB1 PINMUX_PIN(PIN_PD12, 3) +#define PIN_PD12__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD12, 2) +#define PIN_PD12__UTMI_LS1 PINMUX_PIN(PIN_PD12, 1) +#define PIN_PD12__GRXER PINMUX_PIN(PIN_PD12, 2) +#define PIN_PD12__ISI_D5 PINMUX_PIN(PIN_PD12, 2) +#define PIN_PD12__ISI_D4 PINMUX_PIN(PIN_PD12, 4) +#define PIN_PD13 109 +#define PIN_PD13__TCLK1 PINMUX_PIN(PIN_PD13, 3) +#define PIN_PD13__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD13, 2) +#define PIN_PD13__UTMI_CDRPCSEL0 PINMUX_PIN(PIN_PD13, 1) +#define PIN_PD13__GRX0 PINMUX_PIN(PIN_PD13, 2) +#define PIN_PD13__ISI_D6 PINMUX_PIN(PIN_PD13, 2) +#define PIN_PD13__ISI_D5 PINMUX_PIN(PIN_PD13, 4) +#define PIN_PD14 110 +#define PIN_PD14__TCK PINMUX_PIN(PIN_PD14, 1) +#define PIN_PD14__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD14, 2) +#define PIN_PD14__UTMI_CDRPCSEL1 PINMUX_PIN(PIN_PD14, 1) +#define PIN_PD14__GRX1 PINMUX_PIN(PIN_PD14, 2) +#define PIN_PD14__ISI_D7 PINMUX_PIN(PIN_PD14, 2) +#define PIN_PD14__ISI_D6 PINMUX_PIN(PIN_PD14, 4) +#define PIN_PD15 111 +#define PIN_PD15__TDI PINMUX_PIN(PIN_PD15, 1) +#define PIN_PD15__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD15, 2) +#define PIN_PD15__UTMI_CDRCPDIVEN PINMUX_PIN(PIN_PD15, 1) +#define PIN_PD15__GTX0 PINMUX_PIN(PIN_PD15, 2) +#define PIN_PD15__ISI_PCK PINMUX_PIN(PIN_PD15, 2) +#define PIN_PD15__ISI_D7 PINMUX_PIN(PIN_PD15, 4) +#define PIN_PD16 112 +#define PIN_PD16__TDO PINMUX_PIN(PIN_PD16, 1) +#define PIN_PD16__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD16, 2) +#define PIN_PD16__UTMI_CDRBISTEN PINMUX_PIN(PIN_PD16, 1) +#define PIN_PD16__GTX1 PINMUX_PIN(PIN_PD16, 2) +#define PIN_PD16__ISI_VSYNC PINMUX_PIN(PIN_PD16, 2) +#define PIN_PD16__ISI_D8 PINMUX_PIN(PIN_PD16, 4) +#define PIN_PD17 113 +#define PIN_PD17__TMS PINMUX_PIN(PIN_PD17, 1) +#define PIN_PD17__UTMI_CDRCPSELDIV PINMUX_PIN(PIN_PD17, 1) +#define PIN_PD17__GMDC PINMUX_PIN(PIN_PD17, 2) +#define PIN_PD17__ISI_HSYNC PINMUX_PIN(PIN_PD17, 2) +#define PIN_PD17__ISI_D9 PINMUX_PIN(PIN_PD17, 4) +#define PIN_PD18 114 +#define PIN_PD18__NTRST PINMUX_PIN(PIN_PD18, 1) +#define PIN_PD18__GMDIO PINMUX_PIN(PIN_PD18, 2) +#define PIN_PD18__ISI_FIELD PINMUX_PIN(PIN_PD18, 2) +#define PIN_PD18__ISI_D10 PINMUX_PIN(PIN_PD18, 4) +#define PIN_PD19 115 +#define PIN_PD19__PCK0 PINMUX_PIN(PIN_PD19, 1) +#define PIN_PD19__TWD1 PINMUX_PIN(PIN_PD19, 3) +#define PIN_PD19__URXD2 PINMUX_PIN(PIN_PD19, 3) +#define PIN_PD19__I2SCK0 PINMUX_PIN(PIN_PD19, 2) +#define PIN_PD19__ISI_D11 PINMUX_PIN(PIN_PD19, 4) +#define PIN_PD20 116 +#define PIN_PD20__TIOA2 PINMUX_PIN(PIN_PD20, 3) +#define PIN_PD20__TWCK1 PINMUX_PIN(PIN_PD20, 3) +#define PIN_PD20__UTXD2 PINMUX_PIN(PIN_PD20, 3) +#define PIN_PD20__I2SMCK0 PINMUX_PIN(PIN_PD20, 2) +#define PIN_PD20__ISI_PCK PINMUX_PIN(PIN_PD20, 4) +#define PIN_PD21 117 +#define PIN_PD21__TIOB2 PINMUX_PIN(PIN_PD21, 3) +#define PIN_PD21__TWD0 PINMUX_PIN(PIN_PD21, 4) +#define PIN_PD21__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD21, 3) +#define PIN_PD21__I2SWS0 PINMUX_PIN(PIN_PD21, 2) +#define PIN_PD21__ISI_VSYNC PINMUX_PIN(PIN_PD21, 4) +#define PIN_PD22 118 +#define PIN_PD22__TCLK2 PINMUX_PIN(PIN_PD22, 3) +#define PIN_PD22__TWCK0 PINMUX_PIN(PIN_PD22, 4) +#define PIN_PD22__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD22, 3) +#define PIN_PD22__I2SDI0 PINMUX_PIN(PIN_PD22, 2) +#define PIN_PD22__ISI_HSYNC PINMUX_PIN(PIN_PD22, 4) +#define PIN_PD23 119 +#define PIN_PD23__URXD2 PINMUX_PIN(PIN_PD23, 2) +#define PIN_PD23__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD23, 3) +#define PIN_PD23__I2SDO0 PINMUX_PIN(PIN_PD23, 2) +#define PIN_PD23__ISI_FIELD PINMUX_PIN(PIN_PD23, 4) +#define PIN_PD24 120 +#define PIN_PD24__UTXD2 PINMUX_PIN(PIN_PD23, 2) +#define PIN_PD24__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD23, 3) +#define PIN_PD25 121 +#define PIN_PD25__SPI1_SPCK PINMUX_PIN(PIN_PD25, 3) +#define PIN_PD25__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD25, 3) +#define PIN_PD26 122 +#define PIN_PD26__SPI1_MISO PINMUX_PIN(PIN_PD26, 3) +#define PIN_PD26__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD26, 2) +#define PIN_PD27 123 +#define PIN_PD27__SPI1_MISO PINMUX_PIN(PIN_PD27, 3) +#define PIN_PD27__TCK PINMUX_PIN(PIN_PD27, 3) +#define PIN_PD27__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD27, 2) +#define PIN_PD28 124 +#define PIN_PD28__SPI1_NPCS0 PINMUX_PIN(PIN_PD28, 3) +#define PIN_PD28__TCI PINMUX_PIN(PIN_PD28, 3) +#define PIN_PD28__FLEXCOM2_IO2 PINMUX_PIN(PIN_PD28, 2) +#define PIN_PD29 125 +#define PIN_PD29__SPI1_NPCS1 PINMUX_PIN(PIN_PD29, 3) +#define PIN_PD29__TDO PINMUX_PIN(PIN_PD29, 3) +#define PIN_PD29__FLEXCOM2_IO3 PINMUX_PIN(PIN_PD29, 2) +#define PIN_PD29__TIOA3 PINMUX_PIN(PIN_PD29, 3) +#define PIN_PD29__TWD0 PINMUX_PIN(PIN_PD29, 3) +#define PIN_PD30 126 +#define PIN_PD30__SPI1_NPCS2 PINMUX_PIN(PIN_PD30, 3) +#define PIN_PD30__TMS PINMUX_PIN(PIN_PD30, 3) +#define PIN_PD30__FLEXCOM2_IO4 PINMUX_PIN(PIN_PD30, 2) +#define PIN_PD30__TIOB3 PINMUX_PIN(PIN_PD30, 3) +#define PIN_PD30__TWCK0 PINMUX_PIN(PIN_PD30, 3) +#define PIN_PD31 127 +#define PIN_PD31__ADTRG PINMUX_PIN(PIN_PD31, 1) +#define PIN_PD31__NTRST PINMUX_PIN(PIN_PD31, 3) +#define PIN_PD31__IRQ PINMUX_PIN(PIN_PD31, 4) +#define PIN_PD31__TCLK3 PINMUX_PIN(PIN_PD31, 3) +#define PIN_PD31__PCK0 PINMUX_PIN(PIN_PD31, 2) From 0a97479939aaf021660c72916f18f9f457ad836e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 28 Apr 2015 14:38:23 +0200 Subject: [PATCH 093/381] [WIP] pinctrl: at91: introduce driver for PIO4 controller Signed-off-by: Ludovic Desroches Conflicts: drivers/pinctrl/Kconfig drivers/pinctrl/Makefile --- drivers/pinctrl/Kconfig | 10 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-at91-pio4.c | 602 ++++++++++++++++++++++++++++ 3 files changed, 613 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-at91-pio4.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index aeb5729fbda619..dcde1036181623 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -67,6 +67,16 @@ config PINCTRL_AT91 help Say Y here to enable the at91 pinctrl driver +config PINCTRL_AT91PIO4 + bool "AT91 PIO4 pinctrl driver" + depends on OF + depends on ARCH_AT91 + select PINMUX + select PINCONF + select GENERIC_PINCONF + help + Say Y here to enable the at91-pio4 pinctrl driver + config PINCTRL_AMD bool "AMD GPIO pin control" depends on GPIOLIB diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 6eadf04a33b3e5..a685d8698df332 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o +obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MESON) += meson/ diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c new file mode 100644 index 00000000000000..b9db58516bf2ff --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -0,0 +1,602 @@ +/* + * Driver for the Atmel PIO4 controller + * + * Copyright (C) 2015 Atmel Corporation + * + * Author: Ludovic Desroches + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "pinctrl-utils.h" + + +#define ATMEL_PIO4_BANK_OFFSET 0x0040 +#define ATMEL_PIO4_MSKR 0x0000 +#define ATMEL_PIO4_CFGR 0x0004 +#define ATMEL_PIO4_CFGR_FUNC_MASK (0x7) +#define ATMEL_PIO4_DIR_MASK (0x1 << 8) +#define ATMEL_PIO4_PUEN_MASK (0x1 << 9) +#define ATMEL_PIO4_PDEN_MASK (0x1 << 10) +#define ATMEL_PIO4_IFEN_MASK (0x1 << 12) +#define ATMEL_PIO4_IFSCEN_MASK (0x1 << 13) +#define ATMEL_PIO4_OPD_MASK (0x1 << 14) +#define ATMEL_PIO4_SCHMITT_MASK (0x1 << 15) +#define ATMEL_PIO4_PDSR 0x0008 +#define ATMEL_PIO4_LOCKSR 0x000C +#define ATMEL_PIO4_SODR 0x0010 +#define ATMEL_PIO4_CODR 0x0014 +#define ATMEL_PIO4_ODSR 0x0018 +#define ATMEL_PIO4_IER 0x0020 +#define ATMEL_PIO4_IDR 0x0024 +#define ATMEL_PIO4_IMR 0x0028 +#define ATMEL_PIO4_ISR 0x002C +#define ATMEL_PIO4_IOFR 0x003C + +#define ATMEL_GET_IOSET(pin) ((pin >> 16) & 0xff) + + +struct atmel_pinctrl { + struct pinctrl_dev *pctrl; + struct regmap *regmap_base; + unsigned int nbanks; + unsigned int npins_per_bank; + struct atmel_group *groups; + unsigned int ngroups; + const char* const *funcs; + unsigned int nfuncs; + struct pinctrl_desc *pctrl_desc; +}; + +struct atmel_pinctrl_data { + const struct pinctrl_ops *pctlops; + const struct pinmux_ops *pmxops; + const struct pinconf_ops *confops; + bool complex_pin_desc; + unsigned nbanks; + struct atmel_pinctrl *atmel_pinctrl; +}; + +struct atmel_group { + const char *name; + u32 *pins; + unsigned npins; +}; + +static int atmel_pio4_pin_config_read(struct pinctrl_dev *pctldev, + unsigned pin_id, u32 *res) +{ + struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned bank, pin; + u32 mask; + + bank = pin_id / pctrl->npins_per_bank; + pin = pin_id % pctrl->npins_per_bank; + mask = 1 << pin; + dev_vdbg(pctldev->dev, "%s: bank %u, pin %u\n", __func__, bank, pin); + + regmap_write(pctrl->regmap_base, + bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_MSKR, + mask); + + return regmap_read(pctrl->regmap_base, + bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_CFGR, + res); +} + +static void atmel_pio4_pin_config_write(struct pinctrl_dev *pctldev, + unsigned pin_id, u32 conf) +{ + struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned bank, pin; + u32 mask; + + bank = pin_id / pctrl->npins_per_bank; + pin = pin_id % pctrl->npins_per_bank; + mask = 1 << pin; + dev_vdbg(pctldev->dev, "%s: bank %u, pin %u\n", __func__, bank, pin); + + regmap_write(pctrl->regmap_base, + bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_MSKR, + mask); + + regmap_write(pctrl->regmap_base, + bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_CFGR, + conf); +} + +/* ----- pinctrl part ----- */ + +static int atmel_pctl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct atmel_pinctrl *atmel_pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return atmel_pinctrl->ngroups; +} + +static const char *atmel_pctl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct atmel_pinctrl *atmel_pinctrl = pinctrl_dev_get_drvdata(pctldev); + + return atmel_pinctrl->groups[selector].name; +} + +static int atmel_pctl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, + unsigned *num_pins) +{ + struct atmel_pinctrl *atmel_pinctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = atmel_pinctrl->groups[selector].pins; + *num_pins = atmel_pinctrl->groups[selector].npins; + + return 0; +} + +static const struct pinctrl_ops atmel_pctlops = { + .get_groups_count = atmel_pctl_get_groups_count, + .get_group_name = atmel_pctl_get_group_name, + .get_group_pins = atmel_pctl_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + + +/* ----- pinmux part ----- */ + +static int atmel_pmux_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->nfuncs; +} + +static const char *atmel_pmux_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->funcs[selector]; +} + +static int atmel_pmux_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + return -EINVAL; +} + +static int atmel_pio4_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int ret, i; + u32 conf; + unsigned *pin; + + dev_dbg(pctldev->dev, "enable function %s group %s\n", + pctrl->funcs[function], pctrl->groups[group].name); + + /* + * Unfortunately, we can't set the function for several pins in one + * operation. Inside a group, pins can have different configurations. + */ + pin = pctrl->groups[group].pins; + for (i = 0 ; i < pctrl->groups[group].npins ; i++) { + ret = atmel_pio4_pin_config_read(pctldev, pin[i], &conf); + conf &= (~ATMEL_PIO4_CFGR_FUNC_MASK); + conf |= (function & ATMEL_PIO4_CFGR_FUNC_MASK); + dev_dbg(pctldev->dev, "pin: %u, conf: 0x%08x\n", pin[i], conf); + atmel_pio4_pin_config_write(pctldev, pin[i], conf); + } + + return 0; +} + +static const struct pinmux_ops atmel_pio4_pmxops = { + .mux_per_pin = true, + .get_functions_count = atmel_pmux_get_functions_count, + .get_function_name = atmel_pmux_get_function_name, + .get_function_groups = atmel_pmux_get_function_groups, + .set_mux = atmel_pio4_set_mux, + /* TODO */ + .gpio_request_enable = NULL, + .gpio_disable_free = NULL, + .gpio_set_direction = NULL, +}; + + +/* ----- pinconf part ----- */ + +static int atmel_pio4_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *config) +{ + unsigned int arg = 0; + unsigned int param = pinconf_to_config_param(*config); + u32 res; + int ret; + + ret = atmel_pio4_pin_config_read(pctldev, pin, &res); + if (ret) + return -EIO; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + if (!(res & ATMEL_PIO4_PUEN_MASK)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if ((res & ATMEL_PIO4_PUEN_MASK) + || (!(res & ATMEL_PIO4_PDEN_MASK))) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_DISABLE: + if ((res & ATMEL_PIO4_PUEN_MASK) + || ((res & ATMEL_PIO4_PDEN_MASK))) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (!(res & ATMEL_PIO4_OPD_MASK)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (!(res & ATMEL_PIO4_SCHMITT_MASK)) + return -EINVAL; + arg = 1; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int atmel_pio4_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin_id, + unsigned long *configs, + unsigned num_configs) +{ + struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + int i, ret; + u32 mask, conf = 0; + unsigned bank, pin; + + ret = atmel_pio4_pin_config_read(pctldev, pin_id, &conf); + if (ret) + return -EIO; + + for (i = 0; i < num_configs; i++) { + unsigned int param = pinconf_to_config_param(configs[i]); + unsigned int arg = pinconf_to_config_argument(configs[i]); + + dev_dbg(pctldev->dev, "%s: pin=%u, config=0x%lx\n", + __func__, pin_id, configs[i]); + + switch(param) { + case PIN_CONFIG_BIAS_DISABLE: + conf &= (~ATMEL_PIO4_PUEN_MASK); + conf &= (~ATMEL_PIO4_PDEN_MASK); + break; + case PIN_CONFIG_BIAS_PULL_UP: + conf |= ATMEL_PIO4_PUEN_MASK; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + conf |= ATMEL_PIO4_PDEN_MASK; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (arg == 0) + conf &= (~ATMEL_PIO4_OPD_MASK); + else + conf |= ATMEL_PIO4_OPD_MASK; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (arg == 0) + conf |= ATMEL_PIO4_SCHMITT_MASK; + else + conf &= (~ATMEL_PIO4_SCHMITT_MASK); + break; + case PIN_CONFIG_OUTPUT: + conf |= ATMEL_PIO4_DIR_MASK; + bank = pin_id / pctrl->npins_per_bank; + pin = pin_id % pctrl->npins_per_bank; + mask = 1 << pin; + + if (arg == 0) + regmap_write(pctrl->regmap_base, + bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_CODR, + mask); + else + regmap_write(pctrl->regmap_base, + bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_SODR, + mask); + break; + default: + dev_warn(pctldev->dev, + "unsupported configuration parameter: %u\n", + param); + continue; + } + } + + atmel_pio4_pin_config_write(pctldev, pin_id, conf); + + return 0; +} + +static void atmel_pio4_pin_config_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + /* TODO */ + + return; +} + +static const struct pinconf_ops atmel_pio4_confops = { + .is_generic = true, + .pin_config_get = atmel_pio4_pin_config_get, + .pin_config_set = atmel_pio4_pin_config_set, + .pin_config_dbg_show = atmel_pio4_pin_config_dbg_show, +}; + +static struct pinctrl_desc atmel_pinctrl_desc = { + .name = "atmel_pinctrl", + .owner = THIS_MODULE, +}; + +static const char * const atmel_pio4_functions[] = { + "GPIO", "A", "B", "C", "D", "E", "F", "G" +}; + +/* + * Set only values which are specific to PIO4. nbanks is related to the device + * so take this information from atmel_pinctrl_data. Groups will be parsed + * from the device tree. + */ +struct atmel_pinctrl atmel_pio4_pinctrl = { + .npins_per_bank = 32, + .funcs = atmel_pio4_functions, + .nfuncs = ARRAY_SIZE(atmel_pio4_functions), +}; + +static const struct atmel_pinctrl_data atmel_sama5d2_pctrl_data = { + .pctlops = &atmel_pctlops, + .pmxops = &atmel_pio4_pmxops, + .confops = &atmel_pio4_confops, + .complex_pin_desc = true, + .nbanks = 4, + .atmel_pinctrl = &atmel_pio4_pinctrl, +}; + +static const struct of_device_id atmel_pinctrl_of_match[] = { + { + .compatible = "atmel,sama5d2-pinctrl", + .data = &atmel_sama5d2_pctrl_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_pinctrl_of_match); + +/* + * Groups are used to check if all the pins used are from the same ioset and + * for readability. The controller has no knowledge about groups, they are a + * virtual concept. Groups are defined in a subnode called group_defs. + */ +static int atmel_pinctrl_parse_groups(struct platform_device *pdev, + struct atmel_pinctrl *atmel_pinctrl) +{ + struct device_node *np = pdev->dev.of_node, *groups_np, *group_np; + struct atmel_group *group; + int ret, i, ioset; + u32 pin; + + groups_np = of_find_node_by_name(np, "group_defs"); + if (!groups_np) { + dev_err(&pdev->dev, "group_defs node not found\n"); + return -EINVAL; + } + + atmel_pinctrl->ngroups = of_get_child_count(groups_np); + if (!atmel_pinctrl->ngroups) + return -EINVAL; + + dev_dbg(&pdev->dev, "%u group(s)\n", atmel_pinctrl->ngroups); + + atmel_pinctrl->groups = devm_kzalloc(&pdev->dev, + sizeof(*atmel_pinctrl->groups) * atmel_pinctrl->ngroups, + GFP_KERNEL); + if (!atmel_pinctrl->groups) + return -ENOMEM; + + group = atmel_pinctrl->groups; + for_each_child_of_node(groups_np, group_np) { + ioset = -1; + group->name = group_np->name; + dev_dbg(&pdev->dev, "%s:\n", group->name); + group->npins = of_property_count_u32_elems(group_np, "pins"); + if (!group->npins) { + dev_err(&pdev->dev, "no pins for group %s\n", group->name); + return -EINVAL; + } + group->pins = devm_kzalloc(&pdev->dev, + sizeof(*group->pins) * group->npins, + GFP_KERNEL); + if (!group->pins) { + dev_err(&pdev->dev, + "can't allocate pin table for group %s\n", + group->name); + return -ENOMEM; + } + for (i = 0; i < group->npins; i++) { + ret = of_property_read_u32_index(group_np, "pins", i, &pin); + if (ret) { + dev_err(&pdev->dev, + "can't get pins for group %s\n", + group->name); + return ret; + } + group->pins[i] = pin & PINCTRL_PIN_MASK; + dev_dbg(&pdev->dev, "%u\n", group->pins[i]); + /* + * All the pins of a group should have the same ioset + * because validation has been done in this way. It + * means you can have an unexpected behaviour if you + * mix signals from several iosets. + */ + if (ioset < 0) + ioset = ATMEL_GET_IOSET(pin); + if (ATMEL_GET_IOSET(pin) != ioset) + dev_warn(&pdev->dev, + "/!\\ pins from group %s are not using the same ioset /!\\\n", + group->name); + } + group++; + } + + return 0; +} + +static struct atmel_pinctrl *atmel_pinctrl_get_data(struct platform_device *pdev) { + struct atmel_pinctrl *atmel_pinctrl; + const struct of_device_id *match; + const struct atmel_pinctrl_data *data; + + atmel_pinctrl = devm_kzalloc(&pdev->dev, sizeof(*atmel_pinctrl), + GFP_KERNEL); + if (!atmel_pinctrl) { + dev_err(&pdev->dev, "can't allocate atmel_pinctrl structure\n"); + return ERR_PTR(-ENOMEM); + } + + match = of_match_node(atmel_pinctrl_of_match, pdev->dev.of_node); + if (!match) { + dev_err(&pdev->dev, "unknow compatible string\n"); + return ERR_PTR(-ENODEV); + } + + data = match->data; + atmel_pinctrl = data->atmel_pinctrl; + atmel_pinctrl->nbanks = data->nbanks; + atmel_pinctrl_desc.pctlops = data->pctlops; + atmel_pinctrl_desc.pmxops = data->pmxops; + atmel_pinctrl_desc.confops = data->confops; + atmel_pinctrl_desc.complex_pin_desc = data->complex_pin_desc; + atmel_pinctrl_desc.npins = data->nbanks * atmel_pinctrl->npins_per_bank; + dev_dbg(&pdev->dev, "%u pins: %u banks, %u pins per bank\n", + atmel_pinctrl_desc.npins, atmel_pinctrl->nbanks, + atmel_pinctrl->npins_per_bank); + + return atmel_pinctrl; +} + +static int atmel_pinctrl_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node, *regmap_np; + struct atmel_pinctrl *atmel_pinctrl; + struct pinctrl_pin_desc *pin_desc; + int ret, i; + + atmel_pinctrl = atmel_pinctrl_get_data(pdev); + if (!atmel_pinctrl) + return PTR_ERR(atmel_pinctrl); + + pin_desc = devm_kzalloc(&pdev->dev, + sizeof(*atmel_pinctrl_desc.pins) * atmel_pinctrl_desc.npins, + GFP_KERNEL); + if (!pin_desc) { + dev_err(&pdev->dev, "can't allocate pins structure\n"); + return -ENOMEM; + } + + /* Pin naming convention is P(bank_name)(bank_pin_number). */ + for (i = 0 ; i < atmel_pinctrl_desc.npins; i++) { + pin_desc[i].number = i; + pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d", + (i / atmel_pinctrl->npins_per_bank) + 'A', + i % atmel_pinctrl->npins_per_bank); + } + atmel_pinctrl_desc.pins = pin_desc; + + ret = atmel_pinctrl_parse_groups(pdev, atmel_pinctrl); + if (ret) + return ret; + + /* Some registers are shared with the gpio controller driver. */ + regmap_np = of_parse_phandle(np, "atmel,pio_reg", 0); + if (regmap_np) { + atmel_pinctrl->regmap_base = syscon_node_to_regmap(regmap_np); + if (IS_ERR(atmel_pinctrl->regmap_base)) { + dev_err(&pdev->dev, "can't get regmap\n"); + return PTR_ERR(atmel_pinctrl->regmap_base); + } + } else { + dev_err(&pdev->dev, "atmel,pio_reg property is missing\n"); + return -EINVAL; + } + + atmel_pinctrl->pctrl = pinctrl_register(&atmel_pinctrl_desc, &pdev->dev, atmel_pinctrl); + if (!atmel_pinctrl->pctrl) { + dev_err(&pdev->dev, "pinctrl registration failed\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, atmel_pinctrl); + + dev_info(&pdev->dev, "atmel pinctrl initialized\n"); + + return 0; +} + +int atmel_pinctrl_remove(struct platform_device *pdev) +{ + struct atmel_pinctrl *atmel_pinctrl = platform_get_drvdata(pdev); + + pinctrl_unregister(atmel_pinctrl->pctrl); + + return 0; +} + +static struct platform_driver atmel_pinctrl_driver = { + .driver = { + .name = "pinctrl-at91-pio4", + .of_match_table = atmel_pinctrl_of_match, + }, + .probe = atmel_pinctrl_probe, + .remove = atmel_pinctrl_remove, +}; + +module_platform_driver(atmel_pinctrl_driver); + +MODULE_AUTHOR(Ludovic Desroches ); +MODULE_DESCRIPTION("Atmel PIO4 pinctrl driver"); +MODULE_LICENSE("GPL v2"); From 4d06e6291d7361ab0cdde7696fb7ffbc04c2ae2d Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 4 Jun 2015 18:16:47 +0200 Subject: [PATCH 094/381] ARM: at91/dt: sama5d2: add pinctrl definition Both pinctrl with new pio4 driver and associated syscon declaration. Signed-off-by: Nicolas Ferre Conflicts: arch/arm/boot/dts/sama5d2.dtsi --- arch/arm/boot/dts/sama5d2.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 034cd48ae28b49..d6b4e70d35453b 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -921,6 +921,18 @@ clocks = <&twi1_clk>; status = "disabled"; }; + + pio_reg: syscon@fc038000 { + compatible = "atmel,sama5d2-pio_reg", "syscon"; + reg = <0xfc038000 0x600>; + }; + + pinctrl@fc038000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,sama5d2-pinctrl", "simple-bus"; + atmel,pio_reg = <&pio_reg 0x0>; + }; }; }; }; From 0b6fe605259b94abdbb3971437938eb3fddd5037 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 4 Jun 2015 18:18:47 +0200 Subject: [PATCH 095/381] ARM: at91/dt: sama5d2 xplained: add uart1 pinmux pinfunc.h header added and uart1 group + mux definition added. Then the pinctrl configuration is selected in the uart1 node. Signed-off-by: Nicolas Ferre Conflicts: arch/arm/boot/dts/at91-sama5d2_xplained.dts --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index e8d63afdb135f1..460bac717a0ee0 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -44,6 +44,7 @@ */ /dts-v1/; #include "sama5d2.dtsi" +#include "sama5d2-pinfunc.h" / { model = "Atmel SAMA5D2 Xplained"; @@ -107,6 +108,8 @@ }; uart1: serial@f8020000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1_default>; status = "okay"; }; @@ -129,6 +132,22 @@ pagesize = <16>; }; }; + + pinctrl@fc038000 { + group_defs { + uart1_0 { + pins = , + ; + }; + }; + + pinctrl_uart1_default: uart1_default { + mux { + function = "A"; + groups = "uart1_0"; + }; + }; + }; }; }; }; From fcfd13773f3d5805a3019be6b4089222a5a408d7 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 17 Jun 2015 15:53:53 +0200 Subject: [PATCH 096/381] ARM: at91/dt: sama5d2: add generated clock definition Basic generated clock definition for tcb and pwm. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 36 ++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 034cd48ae28b49..472ba835b0604c 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -697,6 +697,42 @@ reg = <53>; }; }; + + gck { + compatible = "atmel,sama5d2-clk-generated"; + #address-cells = <1>; + #size-cells = <0>; + interrupt-parent = <&pmc>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + + sdmmc0_gclk: sdmmc0_gclk { + #clock-cells = <0>; + reg = <31>; + }; + + sdmmc1_gclk: sdmmc1_gclk { + #clock-cells = <0>; + reg = <32>; + }; + + tcb0_gclk: tcb0_gclk { + #clock-cells = <0>; + reg = <35>; + atmel,clk-output-range = <0 83000000>; + }; + + tcb1_gclk: tcb1_gclk { + #clock-cells = <0>; + reg = <36>; + atmel,clk-output-range = <0 83000000>; + }; + + pwm_gclk: pwm_gclk { + #clock-cells = <0>; + reg = <38>; + atmel,clk-output-range = <0 83000000>; + }; + }; }; sha@f0028000 { From eed0d184a26108d88ad156f3b539edbcba28673a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 4 Jun 2015 18:16:47 +0200 Subject: [PATCH 097/381] ARM: at91/dt: sama5d2: add pinctrl definition Both pinctrl with new pio4 driver and associated syscon declaration. Signed-off-by: Nicolas Ferre Conflicts: arch/arm/boot/dts/sama5d2.dtsi --- arch/arm/boot/dts/sama5d2.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 472ba835b0604c..8a7b8a0cd3fd08 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -957,6 +957,18 @@ clocks = <&twi1_clk>; status = "disabled"; }; + + pio_reg: syscon@fc038000 { + compatible = "atmel,sama5d2-pio_reg", "syscon"; + reg = <0xfc038000 0x600>; + }; + + pinctrl@fc038000 { + #address-cells = <1>; + #size-cells = <1>; + compatible = "atmel,sama5d2-pinctrl", "simple-bus"; + atmel,pio_reg = <&pio_reg 0x0>; + }; }; }; }; From 736fbda3a0cff1d0c16ec577a7386b62148de5bd Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 4 Jun 2015 18:18:47 +0200 Subject: [PATCH 098/381] ARM: at91/dt: sama5d2 xplained: add uart1 pinmux pinfunc.h header added and uart1 group + mux definition added. Then the pinctrl configuration is selected in the uart1 node. Signed-off-by: Nicolas Ferre Conflicts: arch/arm/boot/dts/at91-sama5d2_xplained.dts --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index e8d63afdb135f1..460bac717a0ee0 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -44,6 +44,7 @@ */ /dts-v1/; #include "sama5d2.dtsi" +#include "sama5d2-pinfunc.h" / { model = "Atmel SAMA5D2 Xplained"; @@ -107,6 +108,8 @@ }; uart1: serial@f8020000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1_default>; status = "okay"; }; @@ -129,6 +132,22 @@ pagesize = <16>; }; }; + + pinctrl@fc038000 { + group_defs { + uart1_0 { + pins = , + ; + }; + }; + + pinctrl_uart1_default: uart1_default { + mux { + function = "A"; + groups = "uart1_0"; + }; + }; + }; }; }; }; From 47796ecc2645b0ca174b341ae4fbd9e86314cd48 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 3 Jun 2015 18:59:04 +0200 Subject: [PATCH 099/381] ARM: at91/dt: sama5d2: add uart3 + pinctrl Signed-off-by: Nicolas Ferre Conflicts: arch/arm/boot/dts/at91-sama5d2_xplained.dts arch/arm/boot/dts/sama5d2.dtsi --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 460bac717a0ee0..972b684645c639 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -119,6 +119,8 @@ }; uart3: serial@fc008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3_default>; status = "okay"; }; @@ -139,6 +141,11 @@ pins = , ; }; + + uart3_0 { + pins = , + ; + }; }; pinctrl_uart1_default: uart1_default { @@ -147,6 +154,13 @@ groups = "uart1_0"; }; }; + + pinctrl_uart3_default: uart3_default { + mux { + function = "C"; + groups = "uart3_0"; + }; + }; }; }; }; From eb74d3584c4b3035508e4f9e720fb56886ebf743 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 5 Jun 2015 15:19:32 +0200 Subject: [PATCH 100/381] ARM: at91/dt: sama5d2 xplained: add uart1 and uart3 pin conf Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 972b684645c639..41dd0059cf141b 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -153,6 +153,11 @@ function = "A"; groups = "uart1_0"; }; + + conf { + group = "uart1_0"; + bias-disable; + }; }; pinctrl_uart3_default: uart3_default { @@ -160,6 +165,11 @@ function = "C"; groups = "uart3_0"; }; + + conf { + group = "uart3_0"; + bias-disable; + }; }; }; }; From a96849c2e1509177882a9c1c378bc66fd13d6fd6 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 5 Jun 2015 11:25:55 +0200 Subject: [PATCH 101/381] ARM: at91/dt: sama5d2: add sdmmc0, sdmmc1 dt nodes Signed-off-by: Ludovic Desroches Conflicts: arch/arm/boot/dts/sama5d2.dtsi --- arch/arm/boot/dts/sama5d2.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 8a7b8a0cd3fd08..3590ebea158ab1 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -263,6 +263,24 @@ cache-level = <2>; }; + sdmmc0: sdio-host@a0000000 { + compatible = "atmel,sama5d2-sdhci"; + reg = <0xa0000000 0x300>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>; + clock-names = "hclock", "multclk", "baseclk"; + status = "disabled"; + }; + + sdmmc1: sdio-host@b0000000 { + compatible = "atmel,sama5d2-sdhci"; + reg = <0xb0000000 0x300>; + interrupts = <32 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&sdmmc1_hclk>, <&sdmmc1_gclk>, <&main>; + clock-names = "hclock", "multclk", "baseclk"; + status = "disabled"; + }; + apb { compatible = "simple-bus"; #address-cells = <1>; From 605d40c1829943d440c4823fa0e0b849dfc4c49e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 5 Jun 2015 11:31:34 +0200 Subject: [PATCH 102/381] ARM: at91/dt: at91-sama5d2_xplained: enable sdmmc1 Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 41dd0059cf141b..9755cc583d0d9c 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -91,6 +91,13 @@ status = "okay"; }; + sdmmc1: sdio-host@b0000000 { + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc1_default>; + status = "okay"; + }; + apb { spi0: spi@f8000000 { status = "okay"; @@ -137,6 +144,16 @@ pinctrl@fc038000 { group_defs { + sdmmc1_0 { + pins = , + , + , + , + , + , + ; + }; + uart1_0 { pins = , ; @@ -148,6 +165,28 @@ }; }; + pinctrl_sdmmc1_default: sdmmc1_default { + mux { + function = "E"; + groups = "sdmmc1_0"; + }; + + conf-cmd_data { + pins = , + , + , + , + ; + bias-pull-up; + }; + + conf-ck_cd { + pins = , + ; + bias-disable; + }; + }; + pinctrl_uart1_default: uart1_default { mux { function = "A"; From 3e1ac4d715fcac2ac1f61dd33870b61ecbf1ba86 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 23 Jun 2015 15:04:52 +0200 Subject: [PATCH 103/381] ARM: at91/dt: sama5d2 Xplained: add sdmmc0 node Add sdmmc0 node. Don't use card detect signal since it is inverted on the board. We should have cd = 0 if the card is present. Hopefully, not muxing the card detect signal will set it to 0 by default. Be careful, there will be a metal fix setting it to 1 by default. Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 52 +++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 9755cc583d0d9c..efded66d89e7de 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -91,6 +91,14 @@ status = "okay"; }; + sdmmc0: sdio-host@a0000000 { + bus-width = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc0_default>; + non-removable; + status = "okay"; + }; + sdmmc1: sdio-host@b0000000 { bus-width = <4>; pinctrl-names = "default"; @@ -144,6 +152,22 @@ pinctrl@fc038000 { group_defs { + sdmmc0_0 { + pins = , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + sdmmc1_0 { pins = , , @@ -165,6 +189,34 @@ }; }; + pinctrl_sdmmc0_default: sdmmc0_default { + mux { + function = "A"; + groups = "sdmmc0_0"; + }; + + conf-data { + pins = , + , + , + , + , + , + , + ; + bias-pull-up; + }; + + conf-cmd_ck_cd_rstn_vddsel { + pins = , + , + , + , + ; + bias-disable; + }; + }; + pinctrl_sdmmc1_default: sdmmc1_default { mux { function = "E"; From bd1fed8f85d4f3fd266c609774ae92a1f23e1151 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 4 Sep 2015 12:03:40 +0200 Subject: [PATCH 104/381] ARM: at91/defconfig: add sama5d2 special defconfig Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5d2_defconfig | 246 +++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 arch/arm/configs/sama5d2_defconfig diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig new file mode 100644 index 00000000000000..9962aa142a3d5c --- /dev/null +++ b/arch/arm/configs/sama5d2_defconfig @@ -0,0 +1,246 @@ +# CONFIG_SWAP is not set +CONFIG_SYSVIPC=y +CONFIG_IRQ_DOMAIN_DEBUG=y +CONFIG_LOG_BUF_SHIFT=16 +CONFIG_BLK_DEV_INITRD=y +CONFIG_RD_LZMA=y +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_JUMP_LABEL=y +CONFIG_MODULES=y +CONFIG_MODULE_FORCE_LOAD=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +# CONFIG_BLK_DEV_BSG is not set +# CONFIG_IOSCHED_DEADLINE is not set +# CONFIG_IOSCHED_CFQ is not set +CONFIG_ARCH_AT91=y +CONFIG_SOC_SAMA5D2=y +CONFIG_SOC_SAMA5D3=y +CONFIG_SOC_SAMA5D4=y +# CONFIG_KUSER_HELPERS is not set +CONFIG_AEABI=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y +CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_ATAGS is not set +CONFIG_ZBOOT_ROM_TEXT=0x0 +CONFIG_ZBOOT_ROM_BSS=0x0 +CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" +CONFIG_KEXEC=y +CONFIG_VFP=y +CONFIG_NEON=y +CONFIG_KERNEL_MODE_NEON=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SUSPEND is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_INET_DIAG is not set +# CONFIG_IPV6 is not set +CONFIG_CAN=y +CONFIG_CAN_AT91=y +CONFIG_CFG80211=y +CONFIG_MAC80211=y +CONFIG_MAC80211_LEDS=y +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_STANDALONE is not set +# CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_DMA_CMA=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_NAND=y +CONFIG_MTD_NAND_ATMEL=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_COUNT=4 +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_ATMEL_TCLIB=y +CONFIG_ATMEL_SSC=y +CONFIG_SRAM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_93CX6=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +# CONFIG_SCSI_LOWLEVEL is not set +CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ARC is not set +CONFIG_MACB=y +# CONFIG_NET_VENDOR_BROADCOM is not set +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_INTEL is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_MICREL_PHY=y +CONFIG_RT2X00=y +CONFIG_RT2800USB=y +# CONFIG_RT2800USB_RT35XX is not set +CONFIG_RT2800USB_RT53XX=y +# CONFIG_RTL_CARDS is not set +# CONFIG_INPUT_MOUSEDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_KEYBOARD_ATKBD is not set +CONFIG_KEYBOARD_QT1070=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ATMEL_MXT=y +# CONFIG_SERIO is not set +CONFIG_LEGACY_PTY_COUNT=4 +CONFIG_SERIAL_ATMEL=y +CONFIG_SERIAL_ATMEL_CONSOLE=y +CONFIG_HW_RANDOM=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_AT91=y +CONFIG_I2C_GPIO=y +CONFIG_SPI=y +CONFIG_SPI_ATMEL=y +CONFIG_SPI_GPIO=y +CONFIG_PINCTRL_AT91PIO4=y +CONFIG_SPI_SPIDEV=m +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_SYSCON=y +CONFIG_POWER_SUPPLY=y +CONFIG_POWER_RESET=y +# CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_AT91SAM9X_WATCHDOG=y +CONFIG_SAMA5D4_WATCHDOG=y +CONFIG_SSB=m +CONFIG_MFD_ATMEL_FLEXCOM=y +CONFIG_MFD_ATMEL_HLCDC=y +CONFIG_MFD_SYSCON=y +CONFIG_REGULATOR=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y +CONFIG_REGULATOR_ACT8865=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SOC_CAMERA=y +CONFIG_VIDEO_ATMEL_ISI=y +CONFIG_SOC_CAMERA_OV2640=y +CONFIG_SOC_CAMERA_OV5642=y +CONFIG_SOC_CAMERA_OV6650=y +CONFIG_SOC_CAMERA_OV772X=y +CONFIG_SOC_CAMERA_OV9640=y +CONFIG_SOC_CAMERA_OV9740=y +CONFIG_DRM=y +CONFIG_DRM_I2C_SIL902X=y +CONFIG_DRM_ATMEL_HLCDC=y +CONFIG_DRM_PANEL_SIMPLE=y +CONFIG_BACKLIGHT_LCD_SUPPORT=y +CONFIG_LCD_CLASS_DEVICE=y +CONFIG_BACKLIGHT_CLASS_DEVICE=y +# CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y +CONFIG_LOGO=y +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_SOC=y +CONFIG_SND_ATMEL_SOC=y +CONFIG_SND_ATMEL_SOC_WM8904=y +CONFIG_SND_ATMEL_SOC_CLASSD=y +# CONFIG_HID_GENERIC is not set +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_ACM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_SERIAL=y +CONFIG_USB_SERIAL_GENERIC=y +CONFIG_USB_SERIAL_FTDI_SIO=y +CONFIG_USB_SERIAL_PL2303=y +CONFIG_USB_GADGET=y +CONFIG_USB_ATMEL_USBA=m +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m +CONFIG_MMC=y +# CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_AT91=y +CONFIG_MMC_ATMELMCI=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_PWM=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y +CONFIG_LEDS_TRIGGER_GPIO=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_AT91RM9200=y +CONFIG_DMADEVICES=y +CONFIG_AT_XDMAC=y +CONFIG_DMATEST=m +# CONFIG_IOMMU_SUPPORT is not set +CONFIG_IIO=y +CONFIG_AT91_ADC=y +CONFIG_PWM=y +CONFIG_PWM_ATMEL=y +CONFIG_PWM_ATMEL_HLCDC_PWM=y +CONFIG_PWM_ATMEL_TCB=y +CONFIG_RESET_CONTROLLER=y +CONFIG_EXT4_FS=y +CONFIG_FANOTIFY=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_UBIFS_FS=y +CONFIG_UBIFS_FS_ADVANCED_COMPR=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_CODEPAGE_850=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_STRIP_ASM_SYMS=y +CONFIG_DEBUG_FS=y +CONFIG_DEBUG_MEMORY_INIT=y +# CONFIG_SCHED_DEBUG is not set +# CONFIG_FTRACE is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_LL=y +CONFIG_AT91_DEBUG_LL_DBGU3=y +CONFIG_EARLY_PRINTK=y +# CONFIG_CRYPTO_ANSI_CPRNG is not set +CONFIG_CRYPTO_DRBG_MENU=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_DEV_ATMEL_AES=y +CONFIG_CRYPTO_DEV_ATMEL_TDES=y +CONFIG_CRYPTO_DEV_ATMEL_SHA=y +CONFIG_CRC_ITU_T=m From 0b8ce04e5ab45f396638e66c8e831968a6b81eba Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Tue, 21 Apr 2015 13:16:37 -0700 Subject: [PATCH 105/381] video: fbdev: atmel_lcdfb: use ioremap_wc() for framebuffer The driver doesn't use mtrr_add() or arch_phys_wc_add() but since we know the framebuffer is isolated already on an ioremap() we can take advantage of write combining for performance where possible. In this case there are a few motivations for this: a) Take advantage of PAT when available b) Help with the goal of eventually using _PAGE_CACHE_UC over _PAGE_CACHE_UC_MINUS on x86 on ioremap_nocache() (see commit de33c442e titled "x86 PAT: fix performance drop for glx, use UC minus for ioremap(), ioremap_nocache() and pci_mmap_page_range()") Cc: Nicolas Ferre Cc: Suresh Siddha Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Juergen Gross Cc: Daniel Vetter Cc: Andy Lutomirski Cc: Dave Airlie Cc: Antonino Daplas Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: linux-fbdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Luis R. Rodriguez Acked-by: Nicolas Ferre Reviewed-by: Dave Airlie Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/atmel_lcdfb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 94a8d04e60f946..abadc490fa1f58 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -1266,7 +1266,8 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) goto stop_clk; } - info->screen_base = ioremap(info->fix.smem_start, info->fix.smem_len); + info->screen_base = ioremap_wc(info->fix.smem_start, + info->fix.smem_len); if (!info->screen_base) { ret = -ENOMEM; goto release_intmem; From 77f756bcd229d8f26ca7002bf9e2f24c796b24e5 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 20 Aug 2015 13:46:10 +0300 Subject: [PATCH 106/381] video: fbdev: atmel: fix warning for const return value A const on a return value is meaningless and generates a warning on some versions of gcc: drivers/video/fbdev/atmel_lcdfb.c:1003: warning: type qualifiers ignored on function return type The function in question is only used inside the .c file, so the author of the code most likely means "static" instead of "const". Change the const to static. Reported-by: Fengguang Wu Cc: Nicolas Ferre Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/atmel_lcdfb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index abadc490fa1f58..016cae1425a4ea 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -999,7 +999,7 @@ static const char *atmel_lcdfb_wiring_modes[] = { [ATMEL_LCDC_WIRING_RGB] = "RGB", }; -const int atmel_lcdfb_get_of_wiring_modes(struct device_node *np) +static int atmel_lcdfb_get_of_wiring_modes(struct device_node *np) { const char *mode; int err, i; From 57dee3004e7fe0e859ac41c6615bbdabf00c9f8a Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 16 Jul 2015 20:55:34 +0200 Subject: [PATCH 107/381] drm: atmel-hlcdc: fix vblank initial state drm_vblank_on() now warns on nested use or if vblank is not properly initialized. This patch fixes Atmel HLCDC vblank initial state. Signed-off-by: Boris Brezillon Reported-by: Sylvain Rochet --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 1 + drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index f69b92535505b5..5ae5c69231280a 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -355,6 +355,7 @@ int atmel_hlcdc_crtc_create(struct drm_device *dev) planes->overlays[i]->base.possible_crtcs = 1 << crtc->id; drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs); + drm_crtc_vblank_reset(&crtc->base); dc->crtc = &crtc->base; diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 60b0c13d7ff5cc..6fad1f9648f388 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -313,20 +313,20 @@ static int atmel_hlcdc_dc_load(struct drm_device *dev) pm_runtime_enable(dev->dev); - ret = atmel_hlcdc_dc_modeset_init(dev); + ret = drm_vblank_init(dev, 1); if (ret < 0) { - dev_err(dev->dev, "failed to initialize mode setting\n"); + dev_err(dev->dev, "failed to initialize vblank\n"); goto err_periph_clk_disable; } - drm_mode_config_reset(dev); - - ret = drm_vblank_init(dev, 1); + ret = atmel_hlcdc_dc_modeset_init(dev); if (ret < 0) { - dev_err(dev->dev, "failed to initialize vblank\n"); + dev_err(dev->dev, "failed to initialize mode setting\n"); goto err_periph_clk_disable; } + drm_mode_config_reset(dev); + pm_runtime_get_sync(dev->dev); ret = drm_irq_install(dev, dc->hlcdc->irq); pm_runtime_put_sync(dev->dev); From d11283c48a26ea394c718c278cf9065640f56353 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 14 Aug 2015 13:58:20 +0200 Subject: [PATCH 108/381] drm/atmel-hlcdc: Compile suspend/resume for PM_SLEEP only If PM is enabled but PM_SLEEP is disabled, the suspend/resume functions are still unused and produce a compiler warning. Signed-off-by: Thierry Reding Signed-off-by: Boris Brezillon Cc: # 4.1+ --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 6fad1f9648f388..ef6182bc8e5eef 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -559,7 +559,7 @@ static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int atmel_hlcdc_dc_drm_suspend(struct device *dev) { struct drm_device *drm_dev = dev_get_drvdata(dev); From bfe835a6faa19eb9a2512c5fad9872b3df971b15 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 20 Apr 2015 13:43:26 +0200 Subject: [PATCH 109/381] drm: atmel-hlcdc: add PRIME support Signed-off-by: Boris Brezillon --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index ef6182bc8e5eef..be5b56c612a0c0 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -485,7 +485,8 @@ static const struct file_operations fops = { }; static struct drm_driver atmel_hlcdc_dc_driver = { - .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET, + .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | + DRIVER_MODESET | DRIVER_PRIME, .preclose = atmel_hlcdc_dc_preclose, .lastclose = atmel_hlcdc_dc_lastclose, .irq_handler = atmel_hlcdc_dc_irq_handler, @@ -497,6 +498,15 @@ static struct drm_driver atmel_hlcdc_dc_driver = { .disable_vblank = atmel_hlcdc_dc_disable_vblank, .gem_free_object = drm_gem_cma_free_object, .gem_vm_ops = &drm_gem_cma_vm_ops, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + .gem_prime_import = drm_gem_prime_import, + .gem_prime_export = drm_gem_prime_export, + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table, + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table, + .gem_prime_vmap = drm_gem_cma_prime_vmap, + .gem_prime_vunmap = drm_gem_cma_prime_vunmap, + .gem_prime_mmap = drm_gem_cma_prime_mmap, .dumb_create = drm_gem_cma_dumb_create, .dumb_map_offset = drm_gem_cma_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, From 9a11fabf476d665c5417d742374ad41583bff933 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Jul 2015 15:10:26 +0200 Subject: [PATCH 110/381] drm: atmel-hlcdc: add the missing DRM_ATOMIC flag The atmel-hlcdc driver already supports atomic operations, add the missing DRM_ATOMIC flag to expose the atomic features to userspace. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index be5b56c612a0c0..92f6a075879725 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -486,7 +486,8 @@ static const struct file_operations fops = { static struct drm_driver atmel_hlcdc_dc_driver = { .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | - DRIVER_MODESET | DRIVER_PRIME, + DRIVER_MODESET | DRIVER_PRIME | + DRIVER_ATOMIC, .preclose = atmel_hlcdc_dc_preclose, .lastclose = atmel_hlcdc_dc_lastclose, .irq_handler = atmel_hlcdc_dc_irq_handler, From 353699d8c4a4c3cace710d728022a3cbb7d5272e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 6 Jan 2015 11:18:09 +0100 Subject: [PATCH 111/381] drm: atmel-hlcdc: add RGB565 and RGB444 output support The HLCDC IP supports RGB565 and RGB444 output formats. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c index 9c451300531068..067e4c144bd608 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c @@ -126,12 +126,16 @@ atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder, if (info->num_bus_formats) { switch (info->bus_formats[0]) { + case MEDIA_BUS_FMT_RGB565_1X16: + cfg |= ATMEL_HLCDC_CONNECTOR_RGB565 << 8; + break; case MEDIA_BUS_FMT_RGB666_1X18: cfg |= ATMEL_HLCDC_CONNECTOR_RGB666 << 8; break; case MEDIA_BUS_FMT_RGB888_1X24: cfg |= ATMEL_HLCDC_CONNECTOR_RGB888 << 8; break; + case MEDIA_BUS_FMT_RGB444_1X12: default: break; } From 8de2f76053526e47e24483deba16a122725012cb Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 7 Jan 2015 09:30:20 +0100 Subject: [PATCH 112/381] drm: atmel-hlcdc: add support for at91sam9x5 SoCs Describe capabilities of the HLCDC IP found on at91sam9x5 SoCs and add a new entry to the atmel_hlcdc_of_match table. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 88 ++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 92f6a075879725..3319e16ef302aa 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -29,6 +29,90 @@ #define ATMEL_HLCDC_LAYER_IRQS_OFFSET 8 +static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { + { + .name = "base", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x40, + .id = 0, + .type = ATMEL_HLCDC_BASE_LAYER, + .nconfigs = 5, + .layout = { + .xstride = { 2 }, + .default_color = 3, + .general_config = 4, + .disc_pos = 5, + .disc_size = 6, + }, + }, + { + .name = "overlay1", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x100, + .id = 1, + .type = ATMEL_HLCDC_OVERLAY_LAYER, + .nconfigs = 10, + .layout = { + .pos = 2, + .size = 3, + .xstride = { 4 }, + .pstride = { 5 }, + .default_color = 6, + .chroma_key = 7, + .chroma_key_mask = 8, + .general_config = 9, + }, + }, + { + .name = "high-end-overlay", + .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats, + .regs_offset = 0x280, + .id = 2, + .type = ATMEL_HLCDC_OVERLAY_LAYER, + .nconfigs = 17, + .layout = { + .pos = 2, + .size = 3, + .memsize = 4, + .xstride = { 5, 7 }, + .pstride = { 6, 8 }, + .default_color = 9, + .chroma_key = 10, + .chroma_key_mask = 11, + .general_config = 12, + .csc = 14, + }, + }, + { + .name = "cursor", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x340, + .id = 3, + .type = ATMEL_HLCDC_CURSOR_LAYER, + .nconfigs = 10, + .max_width = 128, + .max_height = 128, + .layout = { + .pos = 2, + .size = 3, + .xstride = { 4 }, + .default_color = 6, + .chroma_key = 7, + .chroma_key_mask = 8, + .general_config = 9, + }, + }, +}; + +static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9x5 = { + .min_width = 0, + .min_height = 0, + .max_width = 800, + .max_height = 600, + .nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9x5_layers), + .layers = atmel_hlcdc_at91sam9x5_layers, +}; + static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = { { .name = "base", @@ -133,6 +217,10 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = { }; static const struct of_device_id atmel_hlcdc_of_match[] = { + { + .compatible = "atmel,at91sam9x5-hlcdc", + .data = &atmel_hlcdc_dc_at91sam9x5, + }, { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_dc_sama5d3, From 5e482d5a7e6a2496b68994516f6c8f58222ac403 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 7 Jan 2015 10:12:41 +0100 Subject: [PATCH 113/381] drm: atmel-hlcdc: add support for at91sam9n12 SoC Describe capabilities of the HLCDC IP found on at91sam9n12 SoC and add a new entry to the atmel_hlcdc_of_match table. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 3319e16ef302aa..07c037d6bd879f 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -29,6 +29,31 @@ #define ATMEL_HLCDC_LAYER_IRQS_OFFSET 8 +static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9n12_layers[] = { + { + .name = "base", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x40, + .id = 0, + .type = ATMEL_HLCDC_BASE_LAYER, + .nconfigs = 5, + .layout = { + .xstride = { 2 }, + .default_color = 3, + .general_config = 4, + }, + }, +}; + +static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9n12 = { + .min_width = 0, + .min_height = 0, + .max_width = 1280, + .max_height = 860, + .nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9n12_layers), + .layers = atmel_hlcdc_at91sam9n12_layers, +}; + static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = { { .name = "base", @@ -217,6 +242,10 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = { }; static const struct of_device_id atmel_hlcdc_of_match[] = { + { + .compatible = "atmel,at91sam9n12-hlcdc", + .data = &atmel_hlcdc_dc_at91sam9n12, + }, { .compatible = "atmel,at91sam9x5-hlcdc", .data = &atmel_hlcdc_dc_at91sam9x5, From 4ae25ac6cc9dce8df5b068e42e69c09df8d2fb64 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 7 Jan 2015 10:25:41 +0100 Subject: [PATCH 114/381] drm: atmel-hlcdc: add support for sama5d4 SoCs Describe capabilities of the HLCDC IP found on sama5d4 SoCs and add a new entry to the atmel_hlcdc_of_match table. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 86 ++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 07c037d6bd879f..8bc62ec407f9a9 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -241,6 +241,88 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = { .layers = atmel_hlcdc_sama5d3_layers, }; +static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = { + { + .name = "base", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x40, + .id = 0, + .type = ATMEL_HLCDC_BASE_LAYER, + .nconfigs = 7, + .layout = { + .xstride = { 2 }, + .default_color = 3, + .general_config = 4, + .disc_pos = 5, + .disc_size = 6, + }, + }, + { + .name = "overlay1", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x140, + .id = 1, + .type = ATMEL_HLCDC_OVERLAY_LAYER, + .nconfigs = 10, + .layout = { + .pos = 2, + .size = 3, + .xstride = { 4 }, + .pstride = { 5 }, + .default_color = 6, + .chroma_key = 7, + .chroma_key_mask = 8, + .general_config = 9, + }, + }, + { + .name = "overlay2", + .formats = &atmel_hlcdc_plane_rgb_formats, + .regs_offset = 0x240, + .id = 2, + .type = ATMEL_HLCDC_OVERLAY_LAYER, + .nconfigs = 10, + .layout = { + .pos = 2, + .size = 3, + .xstride = { 4 }, + .pstride = { 5 }, + .default_color = 6, + .chroma_key = 7, + .chroma_key_mask = 8, + .general_config = 9, + }, + }, + { + .name = "high-end-overlay", + .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats, + .regs_offset = 0x340, + .id = 3, + .type = ATMEL_HLCDC_OVERLAY_LAYER, + .nconfigs = 42, + .layout = { + .pos = 2, + .size = 3, + .memsize = 4, + .xstride = { 5, 7 }, + .pstride = { 6, 8 }, + .default_color = 9, + .chroma_key = 10, + .chroma_key_mask = 11, + .general_config = 12, + .csc = 14, + }, + }, +}; + +static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d4 = { + .min_width = 0, + .min_height = 0, + .max_width = 2048, + .max_height = 2048, + .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d4_layers), + .layers = atmel_hlcdc_sama5d4_layers, +}; static const struct of_device_id atmel_hlcdc_of_match[] = { { .compatible = "atmel,at91sam9n12-hlcdc", @@ -254,6 +336,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_dc_sama5d3, }, + { + .compatible = "atmel,sama5d4-hlcdc", + .data = &atmel_hlcdc_dc_sama5d4, + }, { /* sentinel */ }, }; From 2bc2f85fba12f95f5ecf6c9e08186e4d537c9149 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 31 Jul 2015 18:45:54 +0200 Subject: [PATCH 115/381] mfd: atmel-hlcdc: Add support for new SoCs Add the compatible strings for the at91sam9x5, at91sam9n12, sama5d4 and sama5d2 SoCs. Update the documentation accordingly. Signed-off-by: Boris Brezillon Signed-off-by: Nicolas Ferre Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt | 4 ++++ drivers/mfd/atmel-hlcdc.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt index f64de95a8e8b78..ad5d90482a0e07 100644 --- a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt +++ b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt @@ -2,7 +2,11 @@ Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver Required properties: - compatible: value should be one of the following: + "atmel,at91sam9n12-hlcdc" + "atmel,at91sam9x5-hlcdc" + "atmel,sama5d2-hlcdc" "atmel,sama5d3-hlcdc" + "atmel,sama5d4-hlcdc" - reg: base address and size of the HLCDC device registers. - clock-names: the name of the 3 clocks requested by the HLCDC device. Should contain "periph_clk", "sys_clk" and "slow_clk". diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c index cfd58f4cc5c349..e4c95ed16066c2 100644 --- a/drivers/mfd/atmel-hlcdc.c +++ b/drivers/mfd/atmel-hlcdc.c @@ -102,7 +102,11 @@ static int atmel_hlcdc_remove(struct platform_device *pdev) } static const struct of_device_id atmel_hlcdc_match[] = { + { .compatible = "atmel,at91sam9n12-hlcdc" }, + { .compatible = "atmel,at91sam9x5-hlcdc" }, + { .compatible = "atmel,sama5d2-hlcdc" }, { .compatible = "atmel,sama5d3-hlcdc" }, + { .compatible = "atmel,sama5d4-hlcdc" }, { /* sentinel */ }, }; From b4e857d626f110f826251742a1a7cd530c31a5e1 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 7 Jul 2015 19:16:43 +0200 Subject: [PATCH 116/381] mfd: atmel-hlcdc: Implement config synchronization Some HLCDC registers cannot be written until the hardware has finished applying the previous configuration request. If they are written while an action is still in progress, the new configuration might be silently ignored, resulting in unpredictable behavior. Hide the config synchronization stuff in a regmap implementation and use this implementation instead of the generic mmio one. Signed-off-by: Boris Brezillon Acked-by: Nicolas Ferre Signed-off-by: Lee Jones --- drivers/mfd/atmel-hlcdc.c | 51 ++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c index e4c95ed16066c2..3fff6b5d042683 100644 --- a/drivers/mfd/atmel-hlcdc.c +++ b/drivers/mfd/atmel-hlcdc.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -26,6 +27,10 @@ #define ATMEL_HLCDC_REG_MAX (0x4000 - 0x4) +struct atmel_hlcdc_regmap { + void __iomem *regs; +}; + static const struct mfd_cell atmel_hlcdc_cells[] = { { .name = "atmel-hlcdc-pwm", @@ -37,28 +42,62 @@ static const struct mfd_cell atmel_hlcdc_cells[] = { }, }; +static int regmap_atmel_hlcdc_reg_write(void *context, unsigned int reg, + unsigned int val) +{ + struct atmel_hlcdc_regmap *hregmap = context; + + if (reg <= ATMEL_HLCDC_DIS) { + u32 status; + + readl_poll_timeout(hregmap->regs + ATMEL_HLCDC_SR, status, + !(status & ATMEL_HLCDC_SIP), 1, 100); + } + + writel(val, hregmap->regs + reg); + + return 0; +} + +static int regmap_atmel_hlcdc_reg_read(void *context, unsigned int reg, + unsigned int *val) +{ + struct atmel_hlcdc_regmap *hregmap = context; + + *val = readl(hregmap->regs + reg); + + return 0; +} + static const struct regmap_config atmel_hlcdc_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, .max_register = ATMEL_HLCDC_REG_MAX, + .reg_write = regmap_atmel_hlcdc_reg_write, + .reg_read = regmap_atmel_hlcdc_reg_read, + .fast_io = true, }; static int atmel_hlcdc_probe(struct platform_device *pdev) { + struct atmel_hlcdc_regmap *hregmap; struct device *dev = &pdev->dev; struct atmel_hlcdc *hlcdc; struct resource *res; - void __iomem *regs; + + hregmap = devm_kzalloc(dev, sizeof(*hregmap), GFP_KERNEL); + if (!hregmap) + return -ENOMEM; hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL); if (!hlcdc) return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - regs = devm_ioremap_resource(dev, res); - if (IS_ERR(regs)) - return PTR_ERR(regs); + hregmap->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(hregmap->regs)) + return PTR_ERR(hregmap->regs); hlcdc->irq = platform_get_irq(pdev, 0); if (hlcdc->irq < 0) @@ -82,8 +121,8 @@ static int atmel_hlcdc_probe(struct platform_device *pdev) return PTR_ERR(hlcdc->slow_clk); } - hlcdc->regmap = devm_regmap_init_mmio(dev, regs, - &atmel_hlcdc_regmap_config); + hlcdc->regmap = devm_regmap_init(dev, NULL, hregmap, + &atmel_hlcdc_regmap_config); if (IS_ERR(hlcdc->regmap)) return PTR_ERR(hlcdc->regmap); From d8494ab0df22fe14e5c98c58abfa59566b58163f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 9 Sep 2015 15:24:46 +0200 Subject: [PATCH 117/381] pwm: atmel-hlcdc: add sama5d2 SoC support. Add sama5d2 hlcdc backlight PWM support. This chip doesn't have to deal with an errata, so it's a simple addition of the mfd compatible string. Signed-off-by: Nicolas Ferre --- drivers/pwm/pwm-atmel-hlcdc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index fa5feaba25a5d7..6974a0ef986e26 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -221,6 +221,9 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { .compatible = "atmel,at91sam9x5-hlcdc", .data = &atmel_hlcdc_pwm_at91sam9x5_errata, }, + { + .compatible = "atmel,sama5d2-hlcdc", + }, { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_pwm_sama5d3_errata, From 78e5481390190515ea1b4f7e381fc84d52775dc2 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 9 Sep 2015 15:37:42 +0200 Subject: [PATCH 118/381] drm: atmel-hlcdc: add support for sama5d2 SoCs As the hardware description for this chip is the same as the sama5d4, we use this SoC structures for layers and DC descriptions. Thus only 2 lines are added to the atmel_hlcdc_of_match table. The compatible string is already documented in the parent MFD driver's binding. Signed-off-by: Nicolas Ferre --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 8bc62ec407f9a9..498add1e5e58b5 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -332,6 +332,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = { .compatible = "atmel,at91sam9x5-hlcdc", .data = &atmel_hlcdc_dc_at91sam9x5, }, + { + .compatible = "atmel,sama5d2-hlcdc", + .data = &atmel_hlcdc_dc_sama5d4, + }, { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_dc_sama5d3, From e631199525582b72b8ce84d2fd0ade35336dd87e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 30 Apr 2015 15:02:58 +0200 Subject: [PATCH 119/381] drm: panel: simple-panel: set appropriate mode type All modes exposed by simple panels should be tagged as driver defined modes. Moreover, if a panel supports only one mode, this mode is obviously the preferred one. Doing this also fix a problem occurring when a 'video=' parameter is passed on the kernel cmdline. In some cases the user provided mode is preferred over the simple panel ones, which might result in unpredictable behavior. Signed-off-by: Boris Brezillon --- drivers/gpu/drm/panel/panel-simple.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 30904a9b2a4cc9..87d08f7b5053e0 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -128,6 +128,10 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel) continue; } + mode->type |= DRM_MODE_TYPE_DRIVER; + if (panel->desc->num_modes == 1) + mode->type |= DRM_MODE_TYPE_PREFERRED; + drm_mode_set_name(mode); drm_mode_probed_add(connector, mode); From 601f834a581aae7f0c69348c5ead1eaef3cb3ba0 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 27 Apr 2015 11:56:33 +0200 Subject: [PATCH 120/381] DRM: drm_probe_helper: reduce DRM_OUTPUT_POLL_PERIOD to 4 sec The default 10sec. is usually too long for having the fb0 ready when we need it for demo init scripts. Signed-off-by: Nicolas Ferre --- drivers/gpu/drm/drm_probe_helper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 63503879a676cc..25546e5f5222df 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -295,7 +295,7 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_hotplug_event); -#define DRM_OUTPUT_POLL_PERIOD (10*HZ) +#define DRM_OUTPUT_POLL_PERIOD (4*HZ) static void output_poll_execute(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); From ebb280521cd17ab6b3281e27b12e3fb178dffb36 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 30 Apr 2015 15:03:01 +0200 Subject: [PATCH 121/381] drm: atmel-hlcdc: add info messages Add dev_info messages to inform the user when the display controller is up and running. Signed-off-by: Boris Brezillon [nicolas.ferre@atmel.com: adapt to newer driver] Signed-off-by: Nicolas Ferre --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c index 498add1e5e58b5..9c519d3a23f45e 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c @@ -751,6 +751,7 @@ static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev) if (ret) goto err_unregister; + dev_info(ddev->dev, "DRM device successfully registered\n"); return 0; err_unregister: From 3d5613e7a4ec44db44983fd565406f99b27561e2 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 9 Jun 2015 13:53:52 +0200 Subject: [PATCH 122/381] spi: atmel: add support for the internal chip-select of the spi controller This patch relies on the CSAAT (Chip Select Active After Transfer) feature introduced by the version 2 of the spi controller. This new mode allows to use properly the internal chip-select output pin of the spi controller instead of using external gpios. Consequently, the "cs-gpios" device-tree property becomes optional. When the new CSAAT bit is set into the Chip Select Register, the internal chip-select output pin remains asserted till both the following conditions become true: - the LASTXFER bit is set into the Control Register (or the Transmit Data Register) - the Transmit Data Register and its shift register are empty. WARNING: if the LASTXFER bit is set into the Control Register then new data are written into the Transmit Data Register fast enough to keep its shifter not empty, the chip-select output pin remains asserted. Only when the shifter becomes empty, the chip-select output pin is unasserted. When the CSAAT bit is clear in the Chip Select Register, the LASTXFER bit is ignored in both the Control Register and the Transmit Data Register. The internal chip-select output pin remains active as long as the Transmit Data Register or its shift register are not empty. Signed-off-by: Cyrille Pitchen Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index a2f40b1b222500..aa7d202d6905fa 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -246,6 +246,7 @@ struct atmel_spi { bool use_dma; bool use_pdc; + bool use_cs_gpios; /* dmaengine data */ struct atmel_spi_dma dma; @@ -321,7 +322,8 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) } mr = spi_readl(as, MR); - gpio_set_value(asd->npcs_pin, active); + if (as->use_cs_gpios) + gpio_set_value(asd->npcs_pin, active); } else { u32 cpol = (spi->mode & SPI_CPOL) ? SPI_BIT(CPOL) : 0; int i; @@ -337,7 +339,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi) mr = spi_readl(as, MR); mr = SPI_BFINS(PCS, ~(1 << spi->chip_select), mr); - if (spi->chip_select != 0) + if (as->use_cs_gpios && spi->chip_select != 0) gpio_set_value(asd->npcs_pin, active); spi_writel(as, MR, mr); } @@ -366,7 +368,9 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) asd->npcs_pin, active ? " (low)" : "", mr); - if (atmel_spi_is_v2(as) || spi->chip_select != 0) + if (!as->use_cs_gpios) + spi_writel(as, CR, SPI_BIT(LASTXFER)); + else if (atmel_spi_is_v2(as) || spi->chip_select != 0) gpio_set_value(asd->npcs_pin, !active); } @@ -996,6 +1000,8 @@ static int atmel_spi_setup(struct spi_device *spi) csr |= SPI_BIT(CPOL); if (!(spi->mode & SPI_CPHA)) csr |= SPI_BIT(NCPHA); + if (!as->use_cs_gpios) + csr |= SPI_BIT(CSAAT); /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. * @@ -1009,7 +1015,9 @@ static int atmel_spi_setup(struct spi_device *spi) /* chipselect must have been muxed as GPIO (e.g. in board setup) */ npcs_pin = (unsigned long)spi->controller_data; - if (gpio_is_valid(spi->cs_gpio)) + if (!as->use_cs_gpios) + npcs_pin = spi->chip_select; + else if (gpio_is_valid(spi->cs_gpio)) npcs_pin = spi->cs_gpio; asd = spi->controller_state; @@ -1018,15 +1026,19 @@ static int atmel_spi_setup(struct spi_device *spi) if (!asd) return -ENOMEM; - ret = gpio_request(npcs_pin, dev_name(&spi->dev)); - if (ret) { - kfree(asd); - return ret; + if (as->use_cs_gpios) { + ret = gpio_request(npcs_pin, dev_name(&spi->dev)); + if (ret) { + kfree(asd); + return ret; + } + + gpio_direction_output(npcs_pin, + !(spi->mode & SPI_CS_HIGH)); } asd->npcs_pin = npcs_pin; spi->controller_state = asd; - gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); } asd->csr = csr; @@ -1338,6 +1350,13 @@ static int atmel_spi_probe(struct platform_device *pdev) atmel_get_caps(as); + as->use_cs_gpios = true; + if (atmel_spi_is_v2(as) && + !of_get_property(pdev->dev.of_node, "cs-gpios", NULL)) { + as->use_cs_gpios = false; + master->num_chipselect = 4; + } + as->use_dma = false; as->use_pdc = false; if (as->caps.has_dma_support) { From bab70a66958d585b2215905ff67b0e9685ec4580 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 16 Jun 2015 12:09:31 +0200 Subject: [PATCH 123/381] spi: atmel: add support to FIFOs The latest SPI controllers embedded inside sama5d2x SoCs come with FIFOs. When FIFOs are enabled, they can either work in SINGLE data mode or MULTIPLE data mode. The selected mode depends on the configuration of the SPI controller (see below). In SINGLE data mode (or legacy mode), for a single I/O access, only one data can be read from the Receive Data Register (RDR) or written into the Transmit Data Register (TDR). On the other hand, in MULTIPLE data mode, up to 4 data can be read from the RDR or up 2 data can be written into the TDR in a single 32bit I/O access. So programmers should take good care of the width of the I/O access to read/write the right number of data. The exact number of read/written data depends on both the I/O access width and the data width (from 8 up to 16 bits). To enable the FIFO feature a "atmel,fifo-size" property must be set to provide the maximum number of data (not bytes) the RX and TX FIFOs can store. Hence a 32 data FIFO can always store up to 32 data unrelated with the actual data width. When FIFOs are enabled, the RX one is forced to operate in SINGLE data mode because this driver configures the spi controller as a master. In master mode only, the Received Data Register has an additionnal Peripheral Chip Select field, which prevents us from reading more than a single data at each register access. Besides, the TX FIFO operates in MULTIPLE data mode. However, even when a 8bit data size is used, only two data by access could be written into the Transmit Data Register. Indeed the first data has to be written into the lowest 16 bits whereas the second data has to be written into the highest 16 bits of the TDR. When DMA transfers are used to send data, we don't rework the transmit buffer to cope with this hardware limitation: the additional copies required to prepare a new input buffer suited to both the DMA controller and the spi controller would waste all the benefit of the DMA transfer. Instead, the DMA controller is configured to write only one data at time into the TDR. In pio mode, two data are written in the TDR in a single access. Signed-off-by: Cyrille Pitchen Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 255 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 245 insertions(+), 10 deletions(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index aa7d202d6905fa..c9eca347787db7 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -41,6 +41,8 @@ #define SPI_CSR1 0x0034 #define SPI_CSR2 0x0038 #define SPI_CSR3 0x003c +#define SPI_FMR 0x0040 +#define SPI_FLR 0x0044 #define SPI_VERSION 0x00fc #define SPI_RPR 0x0100 #define SPI_RCR 0x0104 @@ -62,6 +64,14 @@ #define SPI_SWRST_SIZE 1 #define SPI_LASTXFER_OFFSET 24 #define SPI_LASTXFER_SIZE 1 +#define SPI_TXFCLR_OFFSET 16 +#define SPI_TXFCLR_SIZE 1 +#define SPI_RXFCLR_OFFSET 17 +#define SPI_RXFCLR_SIZE 1 +#define SPI_FIFOEN_OFFSET 30 +#define SPI_FIFOEN_SIZE 1 +#define SPI_FIFODIS_OFFSET 31 +#define SPI_FIFODIS_SIZE 1 /* Bitfields in MR */ #define SPI_MSTR_OFFSET 0 @@ -114,6 +124,22 @@ #define SPI_TXEMPTY_SIZE 1 #define SPI_SPIENS_OFFSET 16 #define SPI_SPIENS_SIZE 1 +#define SPI_TXFEF_OFFSET 24 +#define SPI_TXFEF_SIZE 1 +#define SPI_TXFFF_OFFSET 25 +#define SPI_TXFFF_SIZE 1 +#define SPI_TXFTHF_OFFSET 26 +#define SPI_TXFTHF_SIZE 1 +#define SPI_RXFEF_OFFSET 27 +#define SPI_RXFEF_SIZE 1 +#define SPI_RXFFF_OFFSET 28 +#define SPI_RXFFF_SIZE 1 +#define SPI_RXFTHF_OFFSET 29 +#define SPI_RXFTHF_SIZE 1 +#define SPI_TXFPTEF_OFFSET 30 +#define SPI_TXFPTEF_SIZE 1 +#define SPI_RXFPTEF_OFFSET 31 +#define SPI_RXFPTEF_SIZE 1 /* Bitfields in CSR0 */ #define SPI_CPOL_OFFSET 0 @@ -157,6 +183,22 @@ #define SPI_TXTDIS_OFFSET 9 #define SPI_TXTDIS_SIZE 1 +/* Bitfields in FMR */ +#define SPI_TXRDYM_OFFSET 0 +#define SPI_TXRDYM_SIZE 2 +#define SPI_RXRDYM_OFFSET 4 +#define SPI_RXRDYM_SIZE 2 +#define SPI_TXFTHRES_OFFSET 16 +#define SPI_TXFTHRES_SIZE 6 +#define SPI_RXFTHRES_OFFSET 24 +#define SPI_RXFTHRES_SIZE 6 + +/* Bitfields in FLR */ +#define SPI_TXFL_OFFSET 0 +#define SPI_TXFL_SIZE 6 +#define SPI_RXFL_OFFSET 16 +#define SPI_RXFL_SIZE 6 + /* Constants for BITS */ #define SPI_BITS_8_BPT 0 #define SPI_BITS_9_BPT 1 @@ -167,6 +209,9 @@ #define SPI_BITS_14_BPT 6 #define SPI_BITS_15_BPT 7 #define SPI_BITS_16_BPT 8 +#define SPI_ONE_DATA 0 +#define SPI_TWO_DATA 1 +#define SPI_FOUR_DATA 2 /* Bit manipulation macros */ #define SPI_BIT(name) \ @@ -185,11 +230,31 @@ __raw_readl((port)->regs + SPI_##reg) #define spi_writel(port, reg, value) \ __raw_writel((value), (port)->regs + SPI_##reg) + +#define spi_readw(port, reg) \ + __raw_readw((port)->regs + SPI_##reg) +#define spi_writew(port, reg, value) \ + __raw_writew((value), (port)->regs + SPI_##reg) + +#define spi_readb(port, reg) \ + __raw_readb((port)->regs + SPI_##reg) +#define spi_writeb(port, reg, value) \ + __raw_writeb((value), (port)->regs + SPI_##reg) #else #define spi_readl(port, reg) \ readl_relaxed((port)->regs + SPI_##reg) #define spi_writel(port, reg, value) \ writel_relaxed((value), (port)->regs + SPI_##reg) + +#define spi_readw(port, reg) \ + readw_relaxed((port)->regs + SPI_##reg) +#define spi_writew(port, reg, value) \ + writew_relaxed((value), (port)->regs + SPI_##reg) + +#define spi_readb(port, reg) \ + readb_relaxed((port)->regs + SPI_##reg) +#define spi_writeb(port, reg, value) \ + writeb_relaxed((value), (port)->regs + SPI_##reg) #endif /* use PIO for small transfers, avoiding DMA setup/teardown overhead and * cache operations; better heuristics consider wordsize and bitrate. @@ -252,6 +317,8 @@ struct atmel_spi { bool keep_cs; bool cs_active; + + u32 fifo_size; }; /* Controller-specific per-slave state */ @@ -410,6 +477,20 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, slave_config->dst_maxburst = 1; slave_config->device_fc = false; + /* + * This driver uses fixed peripheral select mode (PS bit set to '0' in + * the Mode Register). + * So according to the datasheet, when FIFOs are available (and + * enabled), the Transmit FIFO operates in Multiple Data Mode. + * In this mode, up to 2 data, not 4, can be written into the Transmit + * Data Register in a single access. + * However, the first data has to be written into the lowest 16 bits and + * the second data into the highest 16 bits of the Transmit + * Data Register. For 8bit data (the most frequent case), it would + * require to rework tx_buf so each data would actualy fit 16 bits. + * So we'd rather write only one data at the time. Hence the transmit + * path works the same whether FIFOs are available (and enabled) or not. + */ slave_config->direction = DMA_MEM_TO_DEV; if (dmaengine_slave_config(as->dma.chan_tx, slave_config)) { dev_err(&as->pdev->dev, @@ -417,6 +498,14 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as, err = -EINVAL; } + /* + * This driver configures the spi controller for master mode (MSTR bit + * set to '1' in the Mode Register). + * So according to the datasheet, when FIFOs are available (and + * enabled), the Receive FIFO operates in Single Data Mode. + * So the receive path works the same whether FIFOs are available (and + * enabled) or not. + */ slave_config->direction = DMA_DEV_TO_MEM; if (dmaengine_slave_config(as->dma.chan_rx, slave_config)) { dev_err(&as->pdev->dev, @@ -506,10 +595,10 @@ static void dma_callback(void *data) } /* - * Next transfer using PIO. + * Next transfer using PIO without FIFO. */ -static void atmel_spi_next_xfer_pio(struct spi_master *master, - struct spi_transfer *xfer) +static void atmel_spi_next_xfer_single(struct spi_master *master, + struct spi_transfer *xfer) { struct atmel_spi *as = spi_master_get_devdata(master); unsigned long xfer_pos = xfer->len - as->current_remaining_bytes; @@ -541,6 +630,99 @@ static void atmel_spi_next_xfer_pio(struct spi_master *master, spi_writel(as, IER, SPI_BIT(RDRF) | SPI_BIT(OVRES)); } +/* + * Next transfer using PIO with FIFO. + */ +static void atmel_spi_next_xfer_fifo(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + u32 current_remaining_data, num_data; + u32 offset = xfer->len - as->current_remaining_bytes; + const u16 *words = (const u16 *)((u8 *)xfer->tx_buf + offset); + const u8 *bytes = (const u8 *)((u8 *)xfer->tx_buf + offset); + u16 td0, td1; + u32 fifomr; + + dev_vdbg(master->dev.parent, "atmel_spi_next_xfer_fifo\n"); + + /* Compute the number of data to transfer in the current iteration */ + current_remaining_data = ((xfer->bits_per_word > 8) ? + ((u32)as->current_remaining_bytes >> 1) : + (u32)as->current_remaining_bytes); + num_data = min(current_remaining_data, as->fifo_size); + + /* Flush RX and TX FIFOs */ + spi_writel(as, CR, SPI_BIT(RXFCLR) | SPI_BIT(TXFCLR)); + while (spi_readl(as, FLR)) + cpu_relax(); + + /* Set RX FIFO Threshold to the number of data to transfer */ + fifomr = spi_readl(as, FMR); + spi_writel(as, FMR, SPI_BFINS(RXFTHRES, num_data, fifomr)); + + /* Clear FIFO flags in the Status Register, especially RXFTHF */ + (void)spi_readl(as, SR); + + /* Fill TX FIFO */ + while (num_data >= 2) { + if (xfer->tx_buf) { + if (xfer->bits_per_word > 8) { + td0 = *words++; + td1 = *words++; + } else { + td0 = *bytes++; + td1 = *bytes++; + } + } else { + td0 = 0; + td1 = 0; + } + + spi_writel(as, TDR, (td1 << 16) | td0); + num_data -= 2; + } + + if (num_data) { + if (xfer->tx_buf) { + if (xfer->bits_per_word > 8) + td0 = *words++; + else + td0 = *bytes++; + } else { + td0 = 0; + } + + spi_writew(as, TDR, td0); + num_data--; + } + + dev_dbg(master->dev.parent, + " start fifo xfer %p: len %u tx %p rx %p bitpw %d\n", + xfer, xfer->len, xfer->tx_buf, xfer->rx_buf, + xfer->bits_per_word); + + /* + * Enable RX FIFO Threshold Flag interrupt to be notified about + * transfer completion. + */ + spi_writel(as, IER, SPI_BIT(RXFTHF) | SPI_BIT(OVRES)); +} + +/* + * Next transfer using PIO. + */ +static void atmel_spi_next_xfer_pio(struct spi_master *master, + struct spi_transfer *xfer) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + + if (as->fifo_size) + atmel_spi_next_xfer_fifo(master, xfer); + else + atmel_spi_next_xfer_single(master, xfer); +} + /* * Submit next transfer for DMA. */ @@ -843,13 +1025,8 @@ static void atmel_spi_disable_pdc_transfer(struct atmel_spi *as) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); } -/* Called from IRQ - * - * Must update "current_remaining_bytes" to keep track of data - * to transfer. - */ static void -atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) +atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer) { u8 *rxp; u16 *rxp16; @@ -876,6 +1053,57 @@ atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) } } +static void +atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer) +{ + u32 fifolr = spi_readl(as, FLR); + u32 num_bytes, num_data = SPI_BFEXT(RXFL, fifolr); + u32 offset = xfer->len - as->current_remaining_bytes; + u16 *words = (u16 *)((u8 *)xfer->rx_buf + offset); + u8 *bytes = (u8 *)((u8 *)xfer->rx_buf + offset); + u16 rd; /* RD field is the lowest 16 bits of RDR */ + + /* Update the number of remaining bytes to transfer */ + num_bytes = ((xfer->bits_per_word > 8) ? + (num_data << 1) : + num_data); + + if (as->current_remaining_bytes > num_bytes) + as->current_remaining_bytes -= num_bytes; + else + as->current_remaining_bytes = 0; + + /* Handle odd number of bytes when data are more than 8bit width */ + if (xfer->bits_per_word > 8) + as->current_remaining_bytes &= ~0x1; + + /* Read data */ + while (num_data) { + rd = spi_readl(as, RDR); + if (xfer->rx_buf) { + if (xfer->bits_per_word > 8) + *words++ = rd; + else + *bytes++ = rd; + } + num_data--; + } +} + +/* Called from IRQ + * + * Must update "current_remaining_bytes" to keep track of data + * to transfer. + */ +static void +atmel_spi_pump_pio_data(struct atmel_spi *as, struct spi_transfer *xfer) +{ + if (as->fifo_size) + atmel_spi_pump_fifo_data(as, xfer); + else + atmel_spi_pump_single_data(as, xfer); +} + /* Interrupt * * No need for locking in this Interrupt handler: done_status is the @@ -916,7 +1144,7 @@ atmel_spi_pio_interrupt(int irq, void *dev_id) complete(&as->xfer_completion); - } else if (pending & SPI_BIT(RDRF)) { + } else if (pending & (SPI_BIT(RDRF) | SPI_BIT(RXFTHF))) { atmel_spi_lock(as); if (as->current_remaining_bytes) { @@ -1399,6 +1627,13 @@ static int atmel_spi_probe(struct platform_device *pdev) spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS)); spi_writel(as, CR, SPI_BIT(SPIEN)); + as->fifo_size = 0; + if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", + &as->fifo_size)) { + dev_info(&pdev->dev, "Using FIFO (%u data)\n", as->fifo_size); + spi_writel(as, CR, SPI_BIT(FIFOEN)); + } + /* go! */ dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n", (unsigned long)regs->start, irq); From d4d359111cee25cf63d9cc1a161b74edcbebc156 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:28:07 +0200 Subject: [PATCH 124/381] spi: atmel: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index c9eca347787db7..bf9ed380bb1c07 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include From baa933128d89d5056bf1143a7a599c1cc14665a0 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 9 Jun 2015 18:22:14 +0200 Subject: [PATCH 125/381] i2c: at91: fix a race condition when using the DMA controller For TX transactions, the TXCOMP bit in the Status Register is cleared when the first data is written into the Transmit Holding Register. In the lines from at91_do_twi_transfer(): at91_twi_write_data_dma(dev); at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); the TXCOMP interrupt may be enabled before the DMA controller has actually started to write into the THR. In such a case, the TXCOMP bit is still set into the Status Register so the interrupt is triggered immediately. The driver understands that a transaction completion has occurred but this transaction hasn't started yet. Hence the TXCOMP interrupt is no longer enabled by at91_do_twi_transfer() but instead by at91_twi_write_data_dma_callback(). Also, the TXCOMP bit in the Status Register in not a clear on read flag but a snapshot of the transmission state at the time the Status Register is read. When a NACK error is dectected by the I2C controller, the TXCOMP, NACK and TXRDY bits are set together to 1 in the SR. If enabled, the TXCOMP interrupt is triggered at the same time. Also setting the TXRDY to 1 triggers the DMA controller to write the next data into the THR. Such a write resets the TXCOMP bit to 0 in the SR. So depending on when the interrupt handler reads the SR, it may fail to detect the NACK error if it relies on the TXCOMP bit. The NACK bit and its interrupt should be used instead. For RX transactions, the TXCOMP bit in the Status Register is cleared when the START bit is set into the Control Register. However to unify the management of the TXCOMP bit when the DMA controller is used, the TXCOMP interrupt is now enabled by the DMA callbacks for both TX and RX transfers. Signed-off-by: Cyrille Pitchen Cc: stable@vger.kernel.org #3.10 and later Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 70 ++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index ff23d1bdd23072..9bd10a9b4b50ba 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -65,6 +65,9 @@ #define AT91_TWI_UNRE 0x0080 /* Underrun Error */ #define AT91_TWI_NACK 0x0100 /* Not Acknowledged */ +#define AT91_TWI_INT_MASK \ + (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) + #define AT91_TWI_IER 0x0024 /* Interrupt Enable Register */ #define AT91_TWI_IDR 0x0028 /* Interrupt Disable Register */ #define AT91_TWI_IMR 0x002c /* Interrupt Mask Register */ @@ -119,13 +122,12 @@ static void at91_twi_write(struct at91_twi_dev *dev, unsigned reg, unsigned val) 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); + at91_twi_write(dev, AT91_TWI_IDR, AT91_TWI_INT_MASK); } static void at91_twi_irq_save(struct at91_twi_dev *dev) { - dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & 0x7; + dev->imr = at91_twi_read(dev, AT91_TWI_IMR) & AT91_TWI_INT_MASK; at91_disable_twi_interrupts(dev); } @@ -215,6 +217,14 @@ static void at91_twi_write_data_dma_callback(void *data) dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), dev->buf_len, DMA_TO_DEVICE); + /* + * When this callback is called, THR/TX FIFO is likely not to be empty + * yet. So we have to wait for TXCOMP or NACK bits to be set into the + * Status Register to be sure that the STOP bit has been sent and the + * transfer is completed. The NACK interrupt has already been enabled, + * we just have to enable TXCOMP one. + */ + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); } @@ -309,7 +319,7 @@ static void at91_twi_read_data_dma_callback(void *data) /* The last two bytes have to be read without using dma */ dev->buf += dev->buf_len - 2; dev->buf_len = 2; - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY); + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY | AT91_TWI_TXCOMP); } static void at91_twi_read_data_dma(struct at91_twi_dev *dev) @@ -370,7 +380,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) /* catch error flags */ dev->transfer_status |= status; - if (irqstatus & AT91_TWI_TXCOMP) { + if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) { at91_disable_twi_interrupts(dev); complete(&dev->cmd_complete); } @@ -384,6 +394,34 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; + /* + * WARNING: the TXCOMP bit in the Status Register is NOT a clear on + * read flag but shows the state of the transmission at the time the + * Status Register is read. According to the programmer datasheet, + * TXCOMP is set when both holding register and internal shifter are + * empty and STOP condition has been sent. + * Consequently, we should enable NACK interrupt rather than TXCOMP to + * detect transmission failure. + * + * Besides, the TXCOMP bit is already set before the i2c transaction + * has been started. For read transactions, this bit is cleared when + * writing the START bit into the Control Register. So the + * corresponding interrupt can safely be enabled just after. + * However for write transactions managed by the CPU, we first write + * into THR, so TXCOMP is cleared. Then we can safely enable TXCOMP + * interrupt. If TXCOMP interrupt were enabled before writing into THR, + * the interrupt handler would be called immediately and the i2c command + * would be reported as completed. + * Also when a write transaction is managed by the DMA controller, + * enabling the TXCOMP interrupt in this function may lead to a race + * condition since we don't know whether the TXCOMP interrupt is enabled + * before or after the DMA has started to write into THR. So the TXCOMP + * interrupt is enabled later by at91_twi_write_data_dma_callback(). + * Immediately after in that DMA callback, we still need to send the + * STOP condition manually writing the corresponding bit into the + * Control Register. + */ + dev_dbg(dev->dev, "transfer: %s %d bytes.\n", (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); @@ -414,26 +452,24 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) * seems to be the best solution. */ if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK); at91_twi_read_data_dma(dev); - /* - * It is important to enable TXCOMP irq here because - * doing it only when transferring the last two bytes - * will mask NACK errors since TXCOMP is set when a - * NACK occurs. - */ - at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP); - } else + } else { at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_RXRDY); + AT91_TWI_TXCOMP | + AT91_TWI_NACK | + AT91_TWI_RXRDY); + } } else { if (dev->use_dma && (dev->buf_len > AT91_I2C_DMA_THRESHOLD)) { + at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_NACK); at91_twi_write_data_dma(dev); - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); } else { at91_twi_write_next_byte(dev); at91_twi_write(dev, AT91_TWI_IER, - AT91_TWI_TXCOMP | AT91_TWI_TXRDY); + AT91_TWI_TXCOMP | + AT91_TWI_NACK | + AT91_TWI_TXRDY); } } From 9505c191ba134253a200022aa90b7faab755ee4b Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 9 Jun 2015 18:22:15 +0200 Subject: [PATCH 126/381] i2c: at91: use BIT() macro to define register bits This patch just fixes typo before applying later patches which will use register bits with index above 16. Signed-off-by: Cyrille Pitchen Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 9bd10a9b4b50ba..0e88b68bb51994 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -41,29 +41,30 @@ /* 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_QUICK 0x0040 /* SMBus quick command */ -#define AT91_TWI_SWRST 0x0080 /* Software Reset */ +#define AT91_TWI_START BIT(0) /* Send a Start Condition */ +#define AT91_TWI_STOP BIT(1) /* Send a Stop Condition */ +#define AT91_TWI_MSEN BIT(2) /* Master Transfer Enable */ +#define AT91_TWI_MSDIS BIT(3) /* Master Transfer Disable */ +#define AT91_TWI_SVEN BIT(4) /* Slave Transfer Enable */ +#define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */ +#define AT91_TWI_QUICK BIT(6) /* SMBus quick command */ +#define AT91_TWI_SWRST BIT(7) /* 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 */ +#define AT91_TWI_MREAD BIT(12) /* Master Read Direction */ #define AT91_TWI_IADR 0x000c /* Internal Address Register */ #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_TXCOMP BIT(0) /* Transmission Complete */ +#define AT91_TWI_RXRDY BIT(1) /* Receive Holding Register Ready */ +#define AT91_TWI_TXRDY BIT(2) /* Transmit Holding Register Ready */ +#define AT91_TWI_OVRE BIT(6) /* Overrun Error */ +#define AT91_TWI_UNRE BIT(7) /* Underrun Error */ +#define AT91_TWI_NACK BIT(8) /* Not Acknowledged */ #define AT91_TWI_INT_MASK \ (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) From 4ab5df60a973ba055f35f9d9aa10fea0d1c03ff4 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 9 Jun 2015 18:22:17 +0200 Subject: [PATCH 127/381] i2c: at91: add support for new alternative command mode The alternative command mode was introduced to simplify the transmission of STOP conditions and to solve timing and latency issues around them. This mode relies on a new register, the Alternative Command Register, which must be set at the same time as the Master Mode Register. This new register was designed to allow simple setup of basic combined transactions built from up to two unitary transactions. Indeed, the ACR is split into two areas, which describe one unitary transaction each. Each area is filled with Data Length 8bit counter, a Direction and a PEC Request bit. The PEC bit is only used in SMBus mode and is not supported by this driver yet. Also when using alternative command mode, the MREAD bit from the Master Mode Register is ignored. Instead the Direction bits from ACR are used to setup the direction, read or write, of each unitary transaction. Finally the 8bit counters must filled with the data length of their respective transaction. Then if only one transaction is to be used, the data length of the second one must be set to zero. At the moment, this driver uses only the first transaction. In addition to MMR and ACR, the Control Register also need to be written to enable the alternative command mode. That's the purpose of its ACMEN bit, which stands for Alternative Command Mode Enable. Note that the alternative command mode is compatible with the use of the Internal Address Register. So combined transactions for eeprom read are actually implemented with the Internal Address Register. This register is written with up to 3 bytes, which are the internal address sent to the slave through the first write transaction. Then the first area of the ACR describe the write transaction to follow, which carries the data to be read from the eeprom. The second area of the ACR is not used so its Data Length 8bit counter is cleared. For each byte sent or received by the device, the Data Length 8bit counter is decremented. When it reaches 0, a STOP condition is automatically sent. Signed-off-by: Cyrille Pitchen Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 121 ++++++++++++++++++++++++++++------ 1 file changed, 101 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 0e88b68bb51994..817ae69cd1fbf5 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -49,6 +49,11 @@ #define AT91_TWI_SVDIS BIT(5) /* Slave Transfer Disable */ #define AT91_TWI_QUICK BIT(6) /* SMBus quick command */ #define AT91_TWI_SWRST BIT(7) /* Software Reset */ +#define AT91_TWI_ACMEN BIT(16) /* Alternative Command Mode Enable */ +#define AT91_TWI_ACMDIS BIT(17) /* Alternative Command Mode Disable */ +#define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */ +#define AT91_TWI_RHRCLR BIT(25) /* Receive Holding Register Clear */ +#define AT91_TWI_LOCKCLR BIT(26) /* Lock Clear */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ #define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ @@ -65,6 +70,7 @@ #define AT91_TWI_OVRE BIT(6) /* Overrun Error */ #define AT91_TWI_UNRE BIT(7) /* Underrun Error */ #define AT91_TWI_NACK BIT(8) /* Not Acknowledged */ +#define AT91_TWI_LOCK BIT(23) /* TWI Lock due to Frame Errors */ #define AT91_TWI_INT_MASK \ (AT91_TWI_TXCOMP | AT91_TWI_RXRDY | AT91_TWI_TXRDY | AT91_TWI_NACK) @@ -75,10 +81,15 @@ #define AT91_TWI_RHR 0x0030 /* Receive Holding Register */ #define AT91_TWI_THR 0x0034 /* Transmit Holding Register */ +#define AT91_TWI_ACR 0x0040 /* Alternative Command Register */ +#define AT91_TWI_ACR_DATAL(len) ((len) & 0xff) +#define AT91_TWI_ACR_DIR BIT(8) + struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; bool has_unre_flag; + bool has_alt_cmd; struct at_dma_slave dma_slave; }; @@ -204,7 +215,8 @@ static void at91_twi_write_next_byte(struct at91_twi_dev *dev) /* send stop when last byte has been written */ if (--dev->buf_len == 0) - at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + if (!dev->pdata->has_alt_cmd) + 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); @@ -226,7 +238,8 @@ static void at91_twi_write_data_dma_callback(void *data) * we just have to enable TXCOMP one. */ at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); - at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); + if (!dev->pdata->has_alt_cmd) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); } static void at91_twi_write_data_dma(struct at91_twi_dev *dev) @@ -302,7 +315,7 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) } /* send stop if second but last byte has been read */ - if (dev->buf_len == 1) + if (!dev->pdata->has_alt_cmd && dev->buf_len == 1) at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_STOP); dev_dbg(dev->dev, "read 0x%x, to go %d\n", *dev->buf, dev->buf_len); @@ -313,14 +326,18 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) static void at91_twi_read_data_dma_callback(void *data) { struct at91_twi_dev *dev = (struct at91_twi_dev *)data; + unsigned ier = AT91_TWI_TXCOMP; dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), dev->buf_len, DMA_FROM_DEVICE); - /* The last two bytes have to be read without using dma */ - dev->buf += dev->buf_len - 2; - dev->buf_len = 2; - at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_RXRDY | AT91_TWI_TXCOMP); + if (!dev->pdata->has_alt_cmd) { + /* The last two bytes have to be read without using dma */ + dev->buf += dev->buf_len - 2; + dev->buf_len = 2; + ier |= AT91_TWI_RXRDY; + } + at91_twi_write(dev, AT91_TWI_IER, ier); } static void at91_twi_read_data_dma(struct at91_twi_dev *dev) @@ -329,13 +346,14 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev) struct dma_async_tx_descriptor *rxdesc; struct at91_twi_dma *dma = &dev->dma; struct dma_chan *chan_rx = dma->chan_rx; + size_t buf_len; + buf_len = (dev->pdata->has_alt_cmd) ? dev->buf_len : dev->buf_len - 2; dma->direction = DMA_FROM_DEVICE; /* Keep in mind that we won't use dma to read the last two bytes */ at91_twi_irq_save(dev); - dma_addr = dma_map_single(dev->dev, dev->buf, dev->buf_len - 2, - DMA_FROM_DEVICE); + dma_addr = dma_map_single(dev->dev, dev->buf, buf_len, DMA_FROM_DEVICE); if (dma_mapping_error(dev->dev, dma_addr)) { dev_err(dev->dev, "dma map failed\n"); return; @@ -343,7 +361,7 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev) dma->buf_mapped = true; at91_twi_irq_restore(dev); dma->sg.dma_address = dma_addr; - sg_dma_len(&dma->sg) = dev->buf_len - 2; + sg_dma_len(&dma->sg) = buf_len; rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); @@ -394,6 +412,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) int ret; unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; + bool has_alt_cmd = dev->pdata->has_alt_cmd; /* * WARNING: the TXCOMP bit in the Status Register is NOT a clear on @@ -403,6 +422,21 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) * empty and STOP condition has been sent. * Consequently, we should enable NACK interrupt rather than TXCOMP to * detect transmission failure. + * Indeed let's take the case of an i2c write command using DMA. + * Whenever the slave doesn't acknowledge a byte, the LOCK, NACK and + * TXCOMP bits are set together into the Status Register. + * LOCK is a clear on write bit, which is set to prevent the DMA + * controller from sending new data on the i2c bus after a NACK + * condition has happened. Once locked, this i2c peripheral stops + * triggering the DMA controller for new data but it is more than + * likely that a new DMA transaction is already in progress, writing + * into the Transmit Holding Register. Since the peripheral is locked, + * these new data won't be sent to the i2c bus but they will remain + * into the Transmit Holding Register, so TXCOMP bit is cleared. + * Then when the interrupt handler is called, the Status Register is + * read: the TXCOMP bit is clear but NACK bit is still set. The driver + * manage the error properly, without waiting for timeout. + * This case can be reproduced easyly when writing into an at24 eeprom. * * Besides, the TXCOMP bit is already set before the i2c transaction * has been started. For read transactions, this bit is cleared when @@ -418,9 +452,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) * condition since we don't know whether the TXCOMP interrupt is enabled * before or after the DMA has started to write into THR. So the TXCOMP * interrupt is enabled later by at91_twi_write_data_dma_callback(). - * Immediately after in that DMA callback, we still need to send the - * STOP condition manually writing the corresponding bit into the - * Control Register. + * Immediately after in that DMA callback, if the alternative command + * mode is not used, we still need to send the STOP condition manually + * writing the corresponding bit into the Control Register. */ dev_dbg(dev->dev, "transfer: %s %d bytes.\n", @@ -441,14 +475,16 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) } /* if only one byte is to be read, immediately stop transfer */ - if (dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) + if (!has_alt_cmd && 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); /* - * When using dma, the last byte has to be read manually in - * order to not send the stop command too late and then - * to receive extra data. In practice, there are some issues - * if you use the dma to read n-1 bytes because of latency. + * When using dma without alternative command mode, the last + * byte has to be read manually in order to not send the stop + * command too late and then to receive extra data. + * In practice, there are some issues if you use the dma to + * read n-1 bytes because of latency. * Reading n-2 bytes with dma and the two last ones manually * seems to be the best solution. */ @@ -477,6 +513,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) time_left = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout); if (time_left == 0) { + dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR); dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; @@ -497,6 +534,11 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO; goto error; } + if (has_alt_cmd && (dev->transfer_status & AT91_TWI_LOCK)) { + dev_err(dev->dev, "tx locked\n"); + ret = -EIO; + goto error; + } if (dev->recv_len_abort) { dev_err(dev->dev, "invalid smbus block length recvd\n"); ret = -EPROTO; @@ -508,7 +550,14 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) return 0; error: + /* first stop DMA transfer if still in progress */ at91_twi_dma_cleanup(dev); + /* then flush THR/FIFO and unlock TX if locked */ + if (has_alt_cmd && (dev->transfer_status & AT91_TWI_LOCK)) { + dev_dbg(dev->dev, "unlock tx\n"); + at91_twi_write(dev, AT91_TWI_CR, + AT91_TWI_THRCLR | AT91_TWI_LOCKCLR); + } return ret; } @@ -518,6 +567,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) int ret; unsigned int_addr_flag = 0; struct i2c_msg *m_start = msg; + bool is_read, use_alt_cmd = false; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); @@ -540,8 +590,23 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) at91_twi_write(dev, AT91_TWI_IADR, internal_address); } - at91_twi_write(dev, AT91_TWI_MMR, (m_start->addr << 16) | int_addr_flag - | ((m_start->flags & I2C_M_RD) ? AT91_TWI_MREAD : 0)); + is_read = (m_start->flags & I2C_M_RD); + if (dev->pdata->has_alt_cmd) { + if (m_start->len > 0) { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMEN); + at91_twi_write(dev, AT91_TWI_ACR, + AT91_TWI_ACR_DATAL(m_start->len) | + ((is_read) ? AT91_TWI_ACR_DIR : 0)); + use_alt_cmd = true; + } else { + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_ACMDIS); + } + } + + at91_twi_write(dev, AT91_TWI_MMR, + (m_start->addr << 16) | + int_addr_flag | + ((!use_alt_cmd && is_read) ? AT91_TWI_MREAD : 0)); dev->buf_len = m_start->len; dev->buf = m_start->buf; @@ -582,30 +647,35 @@ static struct at91_twi_pdata at91rm9200_config = { .clk_max_div = 5, .clk_offset = 3, .has_unre_flag = true, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9261_config = { .clk_max_div = 5, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9260_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9g20_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static struct at91_twi_pdata at91sam9g10_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, }; static const struct platform_device_id at91_twi_devtypes[] = { @@ -634,6 +704,14 @@ static struct at91_twi_pdata at91sam9x5_config = { .clk_max_div = 7, .clk_offset = 4, .has_unre_flag = false, + .has_alt_cmd = false, +}; + +static struct at91_twi_pdata sama5d2_config = { + .clk_max_div = 7, + .clk_offset = 4, + .has_unre_flag = true, + .has_alt_cmd = true, }; static const struct of_device_id atmel_twi_dt_ids[] = { @@ -655,6 +733,9 @@ static const struct of_device_id atmel_twi_dt_ids[] = { }, { .compatible = "atmel,at91sam9x5-i2c", .data = &at91sam9x5_config, + }, { + .compatible = "atmel,sama5d2-i2c", + .data = &sama5d2_config, }, { /* sentinel */ } From 2054ba782b3e34770f029046eced07c9d2151669 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 9 Jun 2015 18:22:18 +0200 Subject: [PATCH 128/381] i2c: at91: print hardware version The probe() function now prints the hardware version of the I2C controller. Signed-off-by: Cyrille Pitchen [wsa: s/version/hw version/] for clarity] Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 817ae69cd1fbf5..abd93f3a05a03f 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -85,6 +85,8 @@ #define AT91_TWI_ACR_DATAL(len) ((len) & 0xff) #define AT91_TWI_ACR_DIR BIT(8) +#define AT91_TWI_VER 0x00fc /* Version Register */ + struct at91_twi_pdata { unsigned clk_max_div; unsigned clk_offset; @@ -908,7 +910,8 @@ static int at91_twi_probe(struct platform_device *pdev) return rc; } - dev_info(dev->dev, "AT91 i2c bus driver.\n"); + dev_info(dev->dev, "AT91 i2c bus driver (hw version: %#x).\n", + at91_twi_read(dev, AT91_TWI_VER)); return 0; } From 58b43635c529847893b063a30752fc0e952dc6ac Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 9 Jun 2015 18:22:19 +0200 Subject: [PATCH 129/381] i2c: at91: add support to FIFOs When FIFOs are available and enabled, the driver now configures the Atmel eXtended DMA Controller to perform word accesses instead of byte accesses when possible. The actual access width depends on the size of the buffer to transmit. To enable FIFO support the "atmel,fifo-size" property must be set properly in the I2C controller node of the device tree. Signed-off-by: Cyrille Pitchen Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 147 ++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 17 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index abd93f3a05a03f..9e54f97a902071 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -54,6 +54,8 @@ #define AT91_TWI_THRCLR BIT(24) /* Transmit Holding Register Clear */ #define AT91_TWI_RHRCLR BIT(25) /* Receive Holding Register Clear */ #define AT91_TWI_LOCKCLR BIT(26) /* Lock Clear */ +#define AT91_TWI_FIFOEN BIT(28) /* FIFO Enable */ +#define AT91_TWI_FIFODIS BIT(29) /* FIFO Disable */ #define AT91_TWI_MMR 0x0004 /* Master Mode Register */ #define AT91_TWI_IADRSZ_1 0x0100 /* Internal Device Address Size */ @@ -85,6 +87,22 @@ #define AT91_TWI_ACR_DATAL(len) ((len) & 0xff) #define AT91_TWI_ACR_DIR BIT(8) +#define AT91_TWI_FMR 0x0050 /* FIFO Mode Register */ +#define AT91_TWI_FMR_TXRDYM(mode) (((mode) & 0x3) << 0) +#define AT91_TWI_FMR_TXRDYM_MASK (0x3 << 0) +#define AT91_TWI_FMR_RXRDYM(mode) (((mode) & 0x3) << 4) +#define AT91_TWI_FMR_RXRDYM_MASK (0x3 << 4) +#define AT91_TWI_ONE_DATA 0x0 +#define AT91_TWI_TWO_DATA 0x1 +#define AT91_TWI_FOUR_DATA 0x2 + +#define AT91_TWI_FLR 0x0054 /* FIFO Level Register */ + +#define AT91_TWI_FSR 0x0060 /* FIFO Status Register */ +#define AT91_TWI_FIER 0x0064 /* FIFO Interrupt Enable Register */ +#define AT91_TWI_FIDR 0x0068 /* FIFO Interrupt Disable Register */ +#define AT91_TWI_FIMR 0x006c /* FIFO Interrupt Mask Register */ + #define AT91_TWI_VER 0x00fc /* Version Register */ struct at91_twi_pdata { @@ -98,7 +116,7 @@ struct at91_twi_pdata { struct at91_twi_dma { struct dma_chan *chan_rx; struct dma_chan *chan_tx; - struct scatterlist sg; + struct scatterlist sg[2]; struct dma_async_tx_descriptor *data_desc; enum dma_data_direction direction; bool buf_mapped; @@ -121,6 +139,7 @@ struct at91_twi_dev { struct at91_twi_pdata *pdata; bool use_dma; bool recv_len_abort; + u32 fifo_size; struct at91_twi_dma dma; }; @@ -154,6 +173,9 @@ 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); + /* FIFO should be enabled immediately after the software reset */ + if (dev->fifo_size) + at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_FIFOEN); 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); @@ -200,7 +222,7 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) dma->xfer_in_progress = false; } if (dma->buf_mapped) { - dma_unmap_single(dev->dev, sg_dma_address(&dma->sg), + dma_unmap_single(dev->dev, sg_dma_address(&dma->sg[0]), dev->buf_len, dma->direction); dma->buf_mapped = false; } @@ -213,7 +235,8 @@ 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); + /* 8bit write works with and without FIFO */ + writeb_relaxed(*dev->buf, dev->base + AT91_TWI_THR); /* send stop when last byte has been written */ if (--dev->buf_len == 0) @@ -229,7 +252,7 @@ static void at91_twi_write_data_dma_callback(void *data) { struct at91_twi_dev *dev = (struct at91_twi_dev *)data; - dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_TO_DEVICE); /* @@ -250,6 +273,7 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) struct dma_async_tx_descriptor *txdesc; struct at91_twi_dma *dma = &dev->dma; struct dma_chan *chan_tx = dma->chan_tx; + unsigned int sg_len = 1; if (dev->buf_len <= 0) return; @@ -265,10 +289,43 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) } dma->buf_mapped = true; at91_twi_irq_restore(dev); - sg_dma_len(&dma->sg) = dev->buf_len; - sg_dma_address(&dma->sg) = dma_addr; - txdesc = dmaengine_prep_slave_sg(chan_tx, &dma->sg, 1, DMA_MEM_TO_DEV, + if (dev->fifo_size) { + size_t part1_len, part2_len; + struct scatterlist *sg; + unsigned fifo_mr; + + sg_len = 0; + + part1_len = dev->buf_len & ~0x3; + if (part1_len) { + sg = &dma->sg[sg_len++]; + sg_dma_len(sg) = part1_len; + sg_dma_address(sg) = dma_addr; + } + + part2_len = dev->buf_len & 0x3; + if (part2_len) { + sg = &dma->sg[sg_len++]; + sg_dma_len(sg) = part2_len; + sg_dma_address(sg) = dma_addr + part1_len; + } + + /* + * DMA controller is triggered when at least 4 data can be + * written into the TX FIFO + */ + fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + fifo_mr &= ~AT91_TWI_FMR_TXRDYM_MASK; + fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_FOUR_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + } else { + sg_dma_len(&dma->sg[0]) = dev->buf_len; + sg_dma_address(&dma->sg[0]) = dma_addr; + } + + txdesc = dmaengine_prep_slave_sg(chan_tx, dma->sg, sg_len, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_err(dev->dev, "dma prep slave sg failed\n"); @@ -293,7 +350,8 @@ static void at91_twi_read_next_byte(struct at91_twi_dev *dev) if (dev->buf_len <= 0) return; - *dev->buf = at91_twi_read(dev, AT91_TWI_RHR) & 0xff; + /* 8bit read works with and without FIFO */ + *dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR); --dev->buf_len; /* return if aborting, we only needed to read RHR to clear RXRDY*/ @@ -330,7 +388,7 @@ static void at91_twi_read_data_dma_callback(void *data) struct at91_twi_dev *dev = (struct at91_twi_dev *)data; unsigned ier = AT91_TWI_TXCOMP; - dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg), + dma_unmap_single(dev->dev, sg_dma_address(&dev->dma.sg[0]), dev->buf_len, DMA_FROM_DEVICE); if (!dev->pdata->has_alt_cmd) { @@ -362,10 +420,24 @@ static void at91_twi_read_data_dma(struct at91_twi_dev *dev) } dma->buf_mapped = true; at91_twi_irq_restore(dev); - dma->sg.dma_address = dma_addr; - sg_dma_len(&dma->sg) = buf_len; - rxdesc = dmaengine_prep_slave_sg(chan_rx, &dma->sg, 1, DMA_DEV_TO_MEM, + if (dev->fifo_size && IS_ALIGNED(buf_len, 4)) { + unsigned fifo_mr; + + /* + * DMA controller is triggered when at least 4 data can be + * read from the RX FIFO + */ + fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + fifo_mr &= ~AT91_TWI_FMR_RXRDYM_MASK; + fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_FOUR_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + } + + sg_dma_len(&dma->sg[0]) = buf_len; + sg_dma_address(&dma->sg[0]) = dma_addr; + + rxdesc = dmaengine_prep_slave_sg(chan_rx, dma->sg, 1, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!rxdesc) { dev_err(dev->dev, "dma prep slave sg failed\n"); @@ -465,6 +537,21 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) reinit_completion(&dev->cmd_complete); dev->transfer_status = 0; + if (dev->fifo_size) { + unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); + + /* Reset FIFO mode register */ + fifo_mr &= ~(AT91_TWI_FMR_TXRDYM_MASK | + AT91_TWI_FMR_RXRDYM_MASK); + fifo_mr |= AT91_TWI_FMR_TXRDYM(AT91_TWI_ONE_DATA); + fifo_mr |= AT91_TWI_FMR_RXRDYM(AT91_TWI_ONE_DATA); + at91_twi_write(dev, AT91_TWI_FMR, fifo_mr); + + /* Flush FIFOs */ + at91_twi_write(dev, AT91_TWI_CR, + AT91_TWI_THRCLR | AT91_TWI_RHRCLR); + } + if (!dev->buf_len) { at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_QUICK); at91_twi_write(dev, AT91_TWI_IER, AT91_TWI_TXCOMP); @@ -536,7 +623,8 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) ret = -EIO; goto error; } - if (has_alt_cmd && (dev->transfer_status & AT91_TWI_LOCK)) { + if ((has_alt_cmd || dev->fifo_size) && + (dev->transfer_status & AT91_TWI_LOCK)) { dev_err(dev->dev, "tx locked\n"); ret = -EIO; goto error; @@ -555,7 +643,8 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) /* first stop DMA transfer if still in progress */ at91_twi_dma_cleanup(dev); /* then flush THR/FIFO and unlock TX if locked */ - if (has_alt_cmd && (dev->transfer_status & AT91_TWI_LOCK)) { + if ((has_alt_cmd || dev->fifo_size) && + (dev->transfer_status & AT91_TWI_LOCK)) { dev_dbg(dev->dev, "unlock tx\n"); at91_twi_write(dev, AT91_TWI_CR, AT91_TWI_THRCLR | AT91_TWI_LOCKCLR); @@ -750,13 +839,32 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) int ret = 0; struct dma_slave_config slave_config; struct at91_twi_dma *dma = &dev->dma; + enum dma_slave_buswidth addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + + /* + * The actual width of the access will be chosen in + * dmaengine_prep_slave_sg(): + * for each buffer in the scatter-gather list, if its size is aligned + * to addr_width then addr_width accesses will be performed to transfer + * the buffer. On the other hand, if the buffer size is not aligned to + * addr_width then the buffer is transferred using single byte accesses. + * Please refer to the Atmel eXtended DMA controller driver. + * When FIFOs are used, the TXRDYM threshold can always be set to + * trigger the XDMAC when at least 4 data can be written into the TX + * FIFO, even if single byte accesses are performed. + * However the RXRDYM threshold must be set to fit the access width, + * deduced from buffer length, so the XDMAC is triggered properly to + * read data from the RX FIFO. + */ + if (dev->fifo_size) + addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; memset(&slave_config, 0, sizeof(slave_config)); slave_config.src_addr = (dma_addr_t)phy_addr + AT91_TWI_RHR; - slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.src_addr_width = addr_width; slave_config.src_maxburst = 1; slave_config.dst_addr = (dma_addr_t)phy_addr + AT91_TWI_THR; - slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_addr_width = addr_width; slave_config.dst_maxburst = 1; slave_config.device_fc = false; @@ -788,7 +896,7 @@ static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) goto error; } - sg_init_table(&dma->sg, 1); + sg_init_table(dma->sg, 2); dma->buf_mapped = false; dma->xfer_in_progress = false; dev->use_dma = true; @@ -874,6 +982,11 @@ static int at91_twi_probe(struct platform_device *pdev) return rc; } + if (!of_property_read_u32(pdev->dev.of_node, "atmel,fifo-size", + &dev->fifo_size)) { + dev_info(dev->dev, "Using FIFO (%u data)\n", dev->fifo_size); + } + rc = of_property_read_u32(dev->dev->of_node, "clock-frequency", &bus_clk_rate); if (rc) From 28d8849f9a956516e55e7924f6500c6a71d760bf Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 11 Jun 2015 11:16:32 +0200 Subject: [PATCH 130/381] i2c: at91: fix code checker warnings buf_len is a size_t, so unsigned, but was tested with '<= 0'. Reported-by: Wolfram Sang Signed-off-by: Cyrille Pitchen Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 9e54f97a902071..1c758cd1e1ba82 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -232,7 +232,7 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) static void at91_twi_write_next_byte(struct at91_twi_dev *dev) { - if (dev->buf_len <= 0) + if (!dev->buf_len) return; /* 8bit write works with and without FIFO */ @@ -275,7 +275,7 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) struct dma_chan *chan_tx = dma->chan_tx; unsigned int sg_len = 1; - if (dev->buf_len <= 0) + if (!dev->buf_len) return; dma->direction = DMA_TO_DEVICE; @@ -347,7 +347,7 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { - if (dev->buf_len <= 0) + if (!dev->buf_len) return; /* 8bit read works with and without FIFO */ From f723ba3b46ae23ac9b96e22d2c0ab0bcfabb6fc1 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 31 Jul 2015 18:51:20 +0200 Subject: [PATCH 131/381] ARM: at91: pwm: atmel-hlcdc: Add at91sam9n12 errata The errata for HLCDC PWM of at91sam9n12 are the same as for at91sam9x5. Signed-off-by: Josh Wu Acked-by: Alexandre Belloni Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-hlcdc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index fa5feaba25a5d7..5df1db40fc075a 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -217,6 +217,11 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { }; static const struct of_device_id atmel_hlcdc_dt_ids[] = { + { + .compatible = "atmel,at91sam9n12-hlcdc", + /* 9n12 has same errata as 9x5 HLCDC PWM */ + .data = &atmel_hlcdc_pwm_at91sam9x5_errata, + }, { .compatible = "atmel,at91sam9x5-hlcdc", .data = &atmel_hlcdc_pwm_at91sam9x5_errata, From c952d3a0a271b423d8f4f1a276f7213c0e2c4abc Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 21 Jul 2015 14:33:34 +0200 Subject: [PATCH 132/381] mfd: atmel-flexcom: create include file with macros used by DT bindings This patch defines some macros to be used as value for the "atmel,flexcom-mode" DT property. This value is then written into the Operating Mode (OPMODE) bit field of the Flexcom Mode Register. Signed-off-by: Cyrille Pitchen --- include/dt-bindings/mfd/atmel-flexcom.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 include/dt-bindings/mfd/atmel-flexcom.h diff --git a/include/dt-bindings/mfd/atmel-flexcom.h b/include/dt-bindings/mfd/atmel-flexcom.h new file mode 100644 index 00000000000000..6728f2851b4d8e --- /dev/null +++ b/include/dt-bindings/mfd/atmel-flexcom.h @@ -0,0 +1,16 @@ +/* + * This header provides macros for Atmel Flexcom DT bindings. + * + * Copyright (C) 2015 Cyrille Pitchen + * + * GPLv2 only + */ + +#ifndef __DT_BINDINGS_ATMEL_FLEXCOM_H__ +#define __DT_BINDINGS_ATMEL_FLEXCOM_H__ + +#define ATMEL_FLEXCOM_MODE_USART 1 +#define ATMEL_FLEXCOM_MODE_SPI 2 +#define ATMEL_FLEXCOM_MODE_TWI 3 + +#endif /* __DT_BINDINGS_ATMEL_FLEXCOM_H__ */ From 69fb2c194153cb2d7b17b2e1349a5abc87c54079 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Wed, 3 Jun 2015 15:14:39 +0200 Subject: [PATCH 133/381] mfd: devicetree: add bindings for Atmel Flexcom This patch documents the DT bindings for the Atmel Flexcom which will be introduced by sama5d2x SoCs. These bindings will be used by the actual Flexcom driver to be sent in another patch. Signed-off-by: Cyrille Pitchen Acked-by: Boris Brezillon Acked-by: Alexandre Belloni --- .../devicetree/bindings/mfd/atmel-flexcom.txt | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/atmel-flexcom.txt diff --git a/Documentation/devicetree/bindings/mfd/atmel-flexcom.txt b/Documentation/devicetree/bindings/mfd/atmel-flexcom.txt new file mode 100644 index 00000000000000..fc3511e415425d --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/atmel-flexcom.txt @@ -0,0 +1,67 @@ +* Device tree bindings for Atmel Flexcom (Flexible Serial Communication Unit) + +The Atmel Flexcom is just a wrapper which embeds a SPI controller, an I2C +controller and an USART. Only one function can be used at a time and is chosen +at boot time according to the device tree. + +Required properties: +- compatible: Should be "atmel,sama5d2-flexcom" +- reg: Should be the offset/length value for Flexcom dedicated + I/O registers (without USART, TWI or SPI registers). +- clocks: Should be the Flexcom peripheral clock from PMC. +- #address-cells: Should be <1> +- #size-cells: Should be <1> +- ranges: Should be one range for the full I/O register region + (including USART, TWI and SPI registers). +- atmel,flexcom-mode: Should be one of the 3 following macros as defined in + include/dt-bindings/mfd/atmel-flexcom.h: + - ATMEL_FLEXCOM_MODE_USART for USART + - ATMEL_FLEXCOM_MODE_SPI for SPI + - ATMEL_FLEXCOM_MODE_TWI for I2C + +Required child: +a single child device of type matching the "atmel,flexcom-mode" property. + +The reg property of this child should be: +- <0x200 0x200> for USART +- <0x400 0x200> for SPI +- <0x600 0x200> for I2C + +The phandle provided by the clocks property of the child is the same as one for +the Flexcom parent. + +Other properties remain unchanged. See documentation of the respective device: +- ../serial/atmel-usart.txt +- ../spi/spi_atmel.txt +- ../i2c/i2c-at91.txt + +Example: + +flexcom@f8034000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xf8034000 0x200>; + clocks = <&flx0_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xf8034000 0x800>; + atmel,flexcom-mode = ; + + spi@400 { + compatible = "atmel,at91rm9200-spi"; + reg = <0x400 0x200>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx0_default>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx0_clk>; + clock-names = "spi_clk"; + atmel,fifo-size = <32>; + + mtd_dataflash@0 { + compatible = "atmel,at25f512b"; + reg = <0>; + spi-max-frequency = <20000000>; + }; + }; +}; From 10caa7f391bb4625cf9b3696edb66247eae31f3e Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Wed, 17 Sep 2014 10:32:38 +0200 Subject: [PATCH 134/381] mfd: atmel-flexcom: add a driver for Atmel Flexible Serial Communication Unit This driver supports the new Atmel Flexcom. The Flexcom is a wrapper which integrates one SPI controller, one I2C controller and one USART. Only one function can be enabled at a time. This driver selects the function once for all, when the Flexcom is probed, according to the value of the new "atmel,flexcom-mode" device tree property. This driver has chosen to present the Flexcom to the system as a MFD so the implementation is seamless for the existing Atmel SPI, I2C and USART drivers. Also the Flexcom embeds FIFOs: the latest patches of the SPI, I2C and USART drivers take advantage of this new feature. Signed-off-by: Cyrille Pitchen Acked-by: Boris Brezillon Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre --- drivers/mfd/Kconfig | 11 ++++ drivers/mfd/Makefile | 1 + drivers/mfd/atmel-flexcom.c | 104 ++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) create mode 100644 drivers/mfd/atmel-flexcom.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index d5ad04dad081df..9b33ad0653d186 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -59,6 +59,17 @@ config MFD_AAT2870_CORE additional drivers must be enabled in order to use the functionality of the device. +config MFD_ATMEL_FLEXCOM + tristate "Atmel Flexcom (Flexible Serial Communication Unit)" + select MFD_CORE + depends on OF + help + Select this to get support for Atmel Flexcom. This is a wrapper + which embeds a SPI controller, a I2C controller and a USART. Only + one function can be used at a time. The choice is done at boot time + by the probe function of this MFD driver according to a device tree + property. + config MFD_ATMEL_HLCDC tristate "Atmel HLCDC (High-end LCD Controller)" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 0e5cfeba107ca4..c666bf51abf36f 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -160,6 +160,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o +obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o diff --git a/drivers/mfd/atmel-flexcom.c b/drivers/mfd/atmel-flexcom.c new file mode 100644 index 00000000000000..e8e67be6b493ac --- /dev/null +++ b/drivers/mfd/atmel-flexcom.c @@ -0,0 +1,104 @@ +/* + * Driver for Atmel Flexcom + * + * Copyright (C) 2015 Atmel Corporation + * + * Author: Cyrille Pitchen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* I/O register offsets */ +#define FLEX_MR 0x0 /* Mode Register */ +#define FLEX_VERSION 0xfc /* Version Register */ + +/* Mode Register bit fields */ +#define FLEX_MR_OPMODE_OFFSET (0) /* Operating Mode */ +#define FLEX_MR_OPMODE_MASK (0x3 << FLEX_MR_OPMODE_OFFSET) +#define FLEX_MR_OPMODE(opmode) (((opmode) << FLEX_MR_OPMODE_OFFSET) & \ + FLEX_MR_OPMODE_MASK) + + +static int atmel_flexcom_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct clk *clk; + struct resource *res; + void __iomem *base; + u32 opmode; + int err; + + err = of_property_read_u32(np, "atmel,flexcom-mode", &opmode); + if (err) + return err; + + if (opmode < ATMEL_FLEXCOM_MODE_USART || + opmode > ATMEL_FLEXCOM_MODE_TWI) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + err = clk_prepare_enable(clk); + if (err) + return err; + + /* + * Set the Operating Mode in the Mode Register: only the selected device + * is clocked. Hence, registers of the other serial devices remain + * inaccessible and are read as zero. Also the external I/O lines of the + * Flexcom are muxed to reach the selected device. + */ + writel(FLEX_MR_OPMODE(opmode), base + FLEX_MR); + + clk_disable_unprepare(clk); + + return of_platform_populate(np, NULL, NULL, &pdev->dev); +} + +static const struct of_device_id atmel_flexcom_of_match[] = { + { .compatible = "atmel,sama5d2-flexcom" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, atmel_flexcom_of_match); + +static struct platform_driver atmel_flexcom_driver = { + .probe = atmel_flexcom_probe, + .driver = { + .name = "atmel_flexcom", + .of_match_table = atmel_flexcom_of_match, + }, +}; + +module_platform_driver(atmel_flexcom_driver); + +MODULE_AUTHOR("Cyrille Pitchen "); +MODULE_DESCRIPTION("Atmel Flexcom MFD driver"); +MODULE_LICENSE("GPL v2"); From ccec33cb4a76abe9ef7a46073327df47acf4e181 Mon Sep 17 00:00:00 2001 From: Jan Leupold Date: Wed, 17 Jun 2015 18:21:36 +0200 Subject: [PATCH 135/381] iio: adc: at91_adc: allow to use full range of startup time The DT-Property "atmel,adc-startup-time" is stored in an u8 for a microsecond value. When trying to increase the value of STARTUP in Register AT91_ADC_MR some higher values can't be reached. Change the type in function parameter and private structure field from u8 to u32. Signed-off-by: Jan Leupold [nicolas.ferre@atmel.com: change commit message, increase u16 to u32 for startup time] Signed-off-by: Nicolas Ferre Acked-by: Alexandre Belloni Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/adc/at91_adc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 8a0eb4a04fb55b..7b40925dd4ff29 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -182,7 +182,7 @@ struct at91_adc_caps { u8 ts_pen_detect_sensitivity; /* startup time calculate function */ - u32 (*calc_startup_ticks)(u8 startup_time, u32 adc_clk_khz); + u32 (*calc_startup_ticks)(u32 startup_time, u32 adc_clk_khz); u8 num_channels; struct at91_adc_reg_desc registers; @@ -201,7 +201,7 @@ struct at91_adc_state { u8 num_channels; void __iomem *reg_base; struct at91_adc_reg_desc *registers; - u8 startup_time; + u32 startup_time; u8 sample_hold_time; bool sleep_mode; struct iio_trigger **trig; @@ -779,7 +779,7 @@ static int at91_adc_of_get_resolution(struct at91_adc_state *st, return ret; } -static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz) +static u32 calc_startup_ticks_9260(u32 startup_time, u32 adc_clk_khz) { /* * Number of ticks needed to cover the startup time of the ADC @@ -790,7 +790,7 @@ static u32 calc_startup_ticks_9260(u8 startup_time, u32 adc_clk_khz) return round_up((startup_time * adc_clk_khz / 1000) - 1, 8) / 8; } -static u32 calc_startup_ticks_9x5(u8 startup_time, u32 adc_clk_khz) +static u32 calc_startup_ticks_9x5(u32 startup_time, u32 adc_clk_khz) { /* * For sama5d3x and at91sam9x5, the formula changes to: From e307fda39b74620f4ec43a257c57e3364aaaa408 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sat, 2 May 2015 00:46:44 +0900 Subject: [PATCH 136/381] power: at91-reset: Constify platform_device_id The platform_device_id is not modified by the driver and core uses it as const. Signed-off-by: Krzysztof Kozlowski Acked-by: Alexandre Belloni Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index ca461ebc7ae8f7..36dc52fb2ec8ba 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -243,7 +243,7 @@ static int at91_reset_probe(struct platform_device *pdev) return 0; } -static struct platform_device_id at91_reset_plat_match[] = { +static const struct platform_device_id at91_reset_plat_match[] = { { "at91-sam9260-reset", (unsigned long)at91sam9260_restart }, { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart }, { /* sentinel */ } From f7d14f4e1640d01292bde5547666d084017e2df4 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 20 Jul 2015 17:32:05 +0800 Subject: [PATCH 137/381] power: reset: at91: add sama5d3 reset function This patch introduces a new compatible string: "atmel,sama5d3-rstc" and new reset function for sama5d3 and later chips. As in sama5d3 or later chips, we don't have to shutdown the DDR controller before reset. Shutdown the DDR controller before reset is a workaround to avoid DDR signal driving the bus, but since sama5d3 and later chips there is no such a conflict. So in this patch: 1. the sama5d3 reset function only need to write the rstc register and return. 2. we can remove the code related with sama5d3 DDR controller as we don't use it at all. Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Reviewed-by: Guenter Roeck Signed-off-by: Sebastian Reichel --- .../devicetree/bindings/arm/atmel-at91.txt | 2 +- drivers/power/reset/at91-reset.c | 26 ++++++++++++++----- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 2e99b5b57350d0..057d2fb2b6924f 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -87,7 +87,7 @@ One interrupt per TC channel in a TC block: RSTC Reset Controller required properties: - compatible: Should be "atmel,-rstc". - can be "at91sam9260" or "at91sam9g45" + can be "at91sam9260" or "at91sam9g45" or "sama5d3" - reg: Should contain registers location and length Example: diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 36dc52fb2ec8ba..c378d4ec826f42 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -123,6 +123,15 @@ static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode, return NOTIFY_DONE; } +static int sama5d3_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + writel(cpu_to_le32(AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST), + at91_rstc_base); + + return NOTIFY_DONE; +} + static void __init at91_reset_status(struct platform_device *pdev) { u32 reg = readl(at91_rstc_base + AT91_RSTC_SR); @@ -155,13 +164,13 @@ static void __init at91_reset_status(struct platform_device *pdev) static const struct of_device_id at91_ramc_of_match[] = { { .compatible = "atmel,at91sam9260-sdramc", }, { .compatible = "atmel,at91sam9g45-ddramc", }, - { .compatible = "atmel,sama5d3-ddramc", }, { /* sentinel */ } }; static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,at91sam9260-rstc", .data = at91sam9260_restart }, { .compatible = "atmel,at91sam9g45-rstc", .data = at91sam9g45_restart }, + { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, { /* sentinel */ } }; @@ -181,13 +190,16 @@ static int at91_reset_of_probe(struct platform_device *pdev) return -ENODEV; } - for_each_matching_node(np, at91_ramc_of_match) { - at91_ramc_base[idx] = of_iomap(np, 0); - if (!at91_ramc_base[idx]) { - dev_err(&pdev->dev, "Could not map ram controller address\n"); - return -ENODEV; + if (!of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d3-rstc")) { + /* we need to shutdown the ddr controller, so get ramc base */ + for_each_matching_node(np, at91_ramc_of_match) { + at91_ramc_base[idx] = of_iomap(np, 0); + if (!at91_ramc_base[idx]) { + dev_err(&pdev->dev, "Could not map ram controller address\n"); + return -ENODEV; + } + idx++; } - idx++; } match = of_match_node(at91_reset_of_match, pdev->dev.of_node); From af33a77a5d268846bed6bedc737d761b03dff80d Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Jul 2015 17:38:55 +0200 Subject: [PATCH 138/381] power: reset: at91-reset/trivial: driver applies to SAMA5 family as well This diver doesn't applies only on SAM9 SoC families but on SAMA5 families as well. Signed-off-by: Nicolas Ferre --- drivers/power/reset/at91-reset.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index c378d4ec826f42..264b9b81b9f710 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -1,5 +1,5 @@ /* - * Atmel AT91 SAM9 SoCs reset code + * Atmel AT91 SAM9 & SAMA5 SoCs reset code * * Copyright (C) 2007 Atmel Corporation. * Copyright (C) BitBox Ltd 2010 From 0a75d70de66e3872a30cce749391745bf4109f0a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Jul 2015 17:26:57 +0200 Subject: [PATCH 139/381] ARM: at91/dt: shdwc binding: add new shutdown controller documentation The new shutdown controller compatible with sama5d2 has a new binding documentation and properties. Signed-off-by: Nicolas Ferre --- .../devicetree/bindings/arm/atmel-at91.txt | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 057d2fb2b6924f..36bd152e395353 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -155,3 +155,55 @@ required properties: compatible = "atmel,sama5d3-sfr", "syscon"; reg = <0xf0038000 0x60>; }; + +SHDWC Shutdown Controller (Alternative) + +1) shdwc node + +required properties: +- compatible: should be "atmel,sama5d2-shdwc". +- reg: should contain registers location and length +- #address-cells: should be one. The cell is the wake-up input index. +- #size-cells: should be zero. + +optional properties: + +- atmel,wakeup-debouncer: minimum wake-up inputs debouncer period in + micro-seconds. It's usually a board-related property. +- atmel,wakeup-rtc-timer: boolean to enable Real-Time Clock wake-up. + +The node contains child nodes for each wake-up input that the platform uses. + +2) input nodes + +Wake-up input nodes are usually described in the "board" part of the Device +Tree. Note also that input 0 is linked to the wake-up pin and is frequently +used. + +Required properties: +- reg: should contain the wake-up input index [0 - 15]. + +Optional properties: +- atmel,wakeup-type: string, operation mode of the input described by the child + node. Supported values are: "high" or "low". + +Example: + +On the SoC side: + shdwc@f8048010 { + compatible = "atmel,sama5d2-shdwc"; + reg = <0xf8048010 0x10>; + #address-cells = <1>; + #size-cells = <0>; + atmel,wakeup-rtc-timer; + }; + +On the board side: + shdwc@f8048010 { + atmel,shdwc-debouncer = <976>; + + input@0 { + reg = <0>; + atmel,wakeup-type = "low"; + }; + }; From 11fe5364caf93542491930a30e9e95e3122ea33e Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Jul 2015 17:37:23 +0200 Subject: [PATCH 140/381] power: reset: at91-shdwc: add new shutdown controller driver Sama5d2 SoC has a completely new shutdown controller with new features and register layout. It thus makes sense to add a new driver for this new peripheral. This driver is Device Tree only and handles events from the wake-up pin and the RTC. As the register layout may change in the future, so some values are encoded in a configuration structure. Signed-off-by: Nicolas Ferre --- drivers/power/reset/Kconfig | 8 + drivers/power/reset/Makefile | 1 + drivers/power/reset/at91-shdwc.c | 263 +++++++++++++++++++++++++++++++ 3 files changed, 272 insertions(+) create mode 100644 drivers/power/reset/at91-shdwc.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 17d93a73c5136e..1f967da24b3d3f 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -30,6 +30,14 @@ config POWER_RESET_AT91_RESET This driver supports restart for Atmel AT91SAM9 and SAMA5 SoCs +config POWER_RESET_AT91_SHDWC + bool "Atmel AT91 shutdown controller driver" + depends on ARCH_AT91 + default SOC_SAMA5 + help + This driver supports poweroff for some Atmel SAMA5 SoCs. It is + present for example on SAMA5D2 SoC. + config POWER_RESET_AXXIA bool "LSI Axxia reset driver" depends on ARCH_AXXIA diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index dbe06c36874322..1a2f024e84b8f0 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_POWER_RESET_AS3722) += as3722-poweroff.o obj-$(CONFIG_POWER_RESET_AT91_POWEROFF) += at91-poweroff.o obj-$(CONFIG_POWER_RESET_AT91_RESET) += at91-reset.o +obj-$(CONFIG_POWER_RESET_AT91_SHDWC) += at91-shdwc.o obj-$(CONFIG_POWER_RESET_AXXIA) += axxia-reset.o obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o diff --git a/drivers/power/reset/at91-shdwc.c b/drivers/power/reset/at91-shdwc.c new file mode 100644 index 00000000000000..bc5cbf2bc95b84 --- /dev/null +++ b/drivers/power/reset/at91-shdwc.c @@ -0,0 +1,263 @@ +/* + * Atmel Shutdown Controller (SHDWC) driver + * + * Copyright (C) 2015 Atmel Corporation, + * Nicolas Ferre + * + * Evolved from driver at91-poweroff.c. + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + * + * TODO: + * - addition to status of other wake-up inputs [1 - 15] + * - Analog Comparator wake-up alarm + * - Serial RX wake-up alarm + * - low power debouncer + */ + +#include +#include +#include +#include +#include + +#define SLOW_CLOCK_FREQ 32768 + +#define AT91_SHDW_CR 0x00 /* Shut Down Control Register */ +#define AT91_SHDW_SHDW BIT(0) /* Shut Down command */ +#define AT91_SHDW_KEY (0xa5 << 24) /* KEY Password */ + +#define AT91_SHDW_MR 0x04 /* Shut Down Mode Register */ +#define AT91_SHDW_WKUPDBC_SHIFT 24 +#define AT91_SHDW_WKUPDBC_MASK GENMASK(31, 16) +#define AT91_SHDW_WKUPDBC(x) (((x) << AT91_SHDW_WKUPDBC_SHIFT) \ + & AT91_SHDW_WKUPDBC_MASK) + +#define AT91_SHDW_SR 0x08 /* Shut Down Status Register */ +#define AT91_SHDW_WKUPIS_SHIFT 16 +#define AT91_SHDW_WKUPIS_MASK GENMASK(31, 16) +#define AT91_SHDW_WKUPIS(x) ((1 << (x)) << AT91_SHDW_WKUPIS_SHIFT \ + & AT91_SHDW_WKUPIS_MASK) + +#define AT91_SHDW_WUIR 0x0c /* Shutdown Wake-up Inputs Register */ +#define AT91_SHDW_WKUPEN_MASK GENMASK(15, 0) +#define AT91_SHDW_WKUPEN(x) ((1 << (x)) & AT91_SHDW_WKUPEN_MASK) +#define AT91_SHDW_WKUPT_SHIFT 16 +#define AT91_SHDW_WKUPT_MASK GENMASK(31, 16) +#define AT91_SHDW_WKUPT(x) ((1 << (x)) << AT91_SHDW_WKUPT_SHIFT \ + & AT91_SHDW_WKUPT_MASK) + +#define SHDW_WK_PIN(reg, cfg) ((reg) & AT91_SHDW_WKUPIS((cfg)->wkup_pin_input)) +#define SHDW_RTCWK(reg, cfg) (((reg) >> ((cfg)->sr_rtcwk_shift)) & 0x1) +#define SHDW_RTCWKEN(cfg) (1 << ((cfg)->mr_rtcwk_shift)) + +#define DBC_PERIOD_US(x) DIV_ROUND_UP_ULL((1000000 * (x)), \ + SLOW_CLOCK_FREQ) + +struct shdwc_config { + u8 wkup_pin_input; + u8 mr_rtcwk_shift; + u8 sr_rtcwk_shift; +}; + +struct shdwc { + struct shdwc_config *cfg; + void __iomem *at91_shdwc_base; +}; + +/* + * Hold configuration here, cannot be more than one instance of the driver + * since pm_power_off itself is global. + */ +static struct shdwc *at91_shdwc; + +static const unsigned long long sdwc_dbc_period[] = { + 0, 3, 32, 512, 4096, 32768, +}; + +static void __init at91_wakeup_status(struct platform_device *pdev) +{ + struct shdwc *shdw = platform_get_drvdata(pdev); + u32 reg; + char *reason = "unknown"; + + reg = readl(shdw->at91_shdwc_base + AT91_SHDW_SR); + + dev_dbg(&pdev->dev, "%s: status = %#x\n", __func__, reg); + + /* Simple power-on, just bail out */ + if (!reg) + return; + + if (SHDW_WK_PIN(reg, shdw->cfg)) + reason = "WKUP pin"; + else if (SHDW_RTCWK(reg, shdw->cfg)) + reason = "RTC"; + + pr_info("AT91: Wake-Up source: %s\n", reason); +} + +static void at91_poweroff(void) +{ + BUG_ON(!at91_shdwc); + + writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, + at91_shdwc->at91_shdwc_base + AT91_SHDW_CR); +} + +static u32 at91_shdwc_debouncer_value(struct platform_device *pdev, + u32 in_period_us) +{ + int i; + int max_idx = ARRAY_SIZE(sdwc_dbc_period) - 1; + unsigned long long period_us; + unsigned long long max_period_us = DBC_PERIOD_US(sdwc_dbc_period[max_idx]); + + if (in_period_us > max_period_us) { + dev_warn(&pdev->dev, + "debouncer period %u too big, reduced to %llu us\n", + in_period_us, max_period_us); + return max_idx; + } + + for (i = max_idx - 1; i > 0; i--) { + period_us = DBC_PERIOD_US(sdwc_dbc_period[i]); + dev_dbg(&pdev->dev, "%s: ref[%d] = %llu\n", + __func__, i, period_us); + if (in_period_us > period_us) + break; + } + + return i + 1; +} + +static u32 at91_shdwc_get_wakeup_input(struct platform_device *pdev, + struct device_node *np) +{ + struct device_node *cnp; + const char *pm; + u32 wk_input_mask; + u32 wuir = 0; + u32 wk_input; + + for_each_child_of_node(np, cnp) { + if (of_property_read_u32(cnp, "reg", &wk_input)) { + dev_warn(&pdev->dev, "reg property is missing for %s\n", + cnp->full_name); + continue; + } + + wk_input_mask = 1 << wk_input; + if (!(wk_input_mask & AT91_SHDW_WKUPEN_MASK)) { + dev_warn(&pdev->dev, + "wake-up input %d out of bounds ignore\n", + wk_input); + continue; + } + wuir |= wk_input_mask; + + if (!of_property_read_string(cnp, "atmel,wakeup-type", &pm)) { + if (!strcasecmp(pm, "high")) + /* + * only add a type if "high" is specified. Low + * is the default. + */ + wuir |= AT91_SHDW_WKUPT(wk_input); + } + dev_dbg(&pdev->dev, "%s: (child %d) wuir = %#x\n", + __func__, wk_input, wuir); + } + + return wuir; +} + +static void at91_shdwc_dt_configure(struct platform_device *pdev) +{ + struct shdwc *shdw = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; + u32 mode = 0, tmp, input; + + if (!np) { + dev_err(&pdev->dev, "device node not found\n"); + return; + } + + if (!of_property_read_u32(np, "atmel,shdwc-debouncer", &tmp)) { + mode |= AT91_SHDW_WKUPDBC(at91_shdwc_debouncer_value(pdev, tmp)); + } + + if (of_property_read_bool(np, "atmel,wakeup-rtc-timer")) + mode |= SHDW_RTCWKEN(shdw->cfg); + + dev_dbg(&pdev->dev, "%s: mode = %#x\n", __func__, mode); + writel(mode, shdw->at91_shdwc_base + AT91_SHDW_MR); + + input = at91_shdwc_get_wakeup_input(pdev, np); + writel(input, shdw->at91_shdwc_base + AT91_SHDW_WUIR); +} + +static const struct shdwc_config sama5d2_shdwc_config = { + .wkup_pin_input = 0, + .mr_rtcwk_shift = 17, + .sr_rtcwk_shift = 5, +}; + +static struct of_device_id at91_shdwc_of_match[] = { + { + .compatible = "atmel,sama5d2-shdwc", + .data = &sama5d2_shdwc_config, + }, { + /*sentinel*/ + } +}; + +static int at91_shdwc_probe(struct platform_device *pdev) +{ + struct resource *res; + const struct of_device_id *match; + + if (!pdev->dev.of_node) + return -ENODEV; + + at91_shdwc = devm_kzalloc(&pdev->dev, sizeof(*at91_shdwc), GFP_KERNEL); + if (!at91_shdwc) + return -ENOMEM; + + platform_set_drvdata(pdev, at91_shdwc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + at91_shdwc->at91_shdwc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(at91_shdwc->at91_shdwc_base)) { + dev_err(&pdev->dev, "Could not map reset controller address\n"); + return PTR_ERR(at91_shdwc->at91_shdwc_base); + } + + match = of_match_node(at91_shdwc_of_match, pdev->dev.of_node); + if (match != NULL) + at91_shdwc->cfg = (struct shdwc_config *)(match->data); + else + return -ENODATA; + + at91_wakeup_status(pdev); + + at91_shdwc_dt_configure(pdev); + + pm_power_off = at91_poweroff; + + return 0; +} + +static struct platform_driver at91_shdwc_driver = { + .probe = at91_shdwc_probe, + .driver = { + .name = "at91-shdwc", + .of_match_table = at91_shdwc_of_match, + }, +}; +module_platform_driver(at91_shdwc_driver); + +MODULE_AUTHOR("Nicolas Ferre "); +MODULE_DESCRIPTION("Atmel shutdown controller driver"); +MODULE_LICENSE("GPL v2"); From ad0b0706dbb4a0f1f1ab98611fc2fa6da52bfdd5 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 8 Jul 2015 18:50:01 +0800 Subject: [PATCH 141/381] ARM: at91: sama5d2: dts: add reset controller Add the rstc dt node. Signed-off-by: Josh Wu --- arch/arm/boot/dts/sama5d2.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 3590ebea158ab1..721661aa3bbeb5 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -874,6 +874,11 @@ status = "disabled"; }; + rstc@f8048000 { + compatible = "atmel,sama5d3-rstc"; + reg = <0xf8048000 0x10>; + }; + pit: timer@f8048030 { compatible = "atmel,at91sam9260-pit"; reg = <0xf8048030 0x10>; From 3f1622519919c9d307482309d28134e77698e352 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Jul 2015 17:39:47 +0200 Subject: [PATCH 142/381] ARM: at91/dt: add shutdown controller node Add shutdown controller node. Enable RTC wake-up event as well. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 721661aa3bbeb5..bffc111608483e 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -879,6 +879,14 @@ reg = <0xf8048000 0x10>; }; + shdwc@f8048010 { + compatible = "atmel,sama5d2-shdwc"; + reg = <0xf8048010 0x10>; + #address-cells = <1>; + #size-cells = <0>; + atmel,wakeup-rtc-timer; + }; + pit: timer@f8048030 { compatible = "atmel,at91sam9260-pit"; reg = <0xf8048030 0x10>; From 3368843d81d1b754b9c6f8f18ff507f10bc320c3 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Jul 2015 17:42:18 +0200 Subject: [PATCH 143/381] ARM: at91/dt: sama5d2 xplained: add shutdown controller Add shutdown controller for the sama5d2 xplained board. The wake-up pin is added with proper event type (low). The debounce value is also added otherwise any glitch would wake-up the SoC. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index efded66d89e7de..8b1417a33ad25e 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -133,6 +133,15 @@ status = "okay"; }; + shdwc@f8048010 { + atmel,shdwc-debouncer = <976>; + + input@0 { + reg = <0>; + atmel,wakeup-type = "low"; + }; + }; + uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; From 7d02e4a6a58ef604ce661a7ea2f9c668eb0978f2 Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Wed, 6 May 2015 22:27:16 +0530 Subject: [PATCH 144/381] net: macb: Add compatible string for Zynq Ultrascale+ MPSoC Add compatible string and config structure for Zynq Ultrascale+ MPSoC Signed-off-by: Harini Katakam Reviewed-by: Punnaiah Choudary Kalluri Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index fc646a41d54814..4abeeb5609798f 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2702,6 +2702,13 @@ static const struct macb_config emac_config = { .init = at91ether_init, }; +static const struct macb_config zynqmp_config = { + .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, +}; + static const struct macb_config zynq_config = { .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, @@ -2720,6 +2727,7 @@ static const struct of_device_id macb_dt_ids[] = { { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, { .compatible = "cdns,at91rm9200-emac", .data = &emac_config }, { .compatible = "cdns,emac", .data = &emac_config }, + { .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config}, { .compatible = "cdns,zynq-gem", .data = &zynq_config }, { /* sentinel */ } }; From c9e26c9f31fb6d9764f916622d9dc3c90ebcfb8a Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Wed, 6 May 2015 22:27:17 +0530 Subject: [PATCH 145/381] net: macb: Add support for jumbo frames Enable jumbo frame support for Zynq Ultrascale+ MPSoC. Update the NWCFG register and descriptor length masks accordingly. Jumbo max length register should be set according to support in SoC; it is set to 10240 for Zynq Ultrascale+ MPSoC. Signed-off-by: Harini Katakam Reviewed-by: Punnaiah Choudary Kalluri Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 22 ++++++++++++++++++---- drivers/net/ethernet/cadence/macb.h | 9 +++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 4abeeb5609798f..76b8f1bf3c13dd 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -785,7 +785,7 @@ static int gem_rx(struct macb *bp, int budget) } /* now everything is ready for receiving packet */ bp->rx_skbuff[entry] = NULL; - len = MACB_BFEXT(RX_FRMLEN, ctrl); + len = ctrl & bp->rx_frm_len_mask; netdev_vdbg(bp->dev, "gem_rx %u (len %u)\n", entry, len); @@ -831,7 +831,7 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, struct macb_dma_desc *desc; desc = macb_rx_desc(bp, last_frag); - len = MACB_BFEXT(RX_FRMLEN, desc->ctrl); + len = desc->ctrl & bp->rx_frm_len_mask; netdev_vdbg(bp->dev, "macb_rx_frame frags %u - %u (len %u)\n", macb_rx_ring_wrap(first_frag), @@ -1651,7 +1651,10 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ - config |= MACB_BIT(BIG); /* Receive oversized frames */ + if (bp->caps | MACB_CAPS_JUMBO) + config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ + else + config |= MACB_BIT(BIG); /* Receive oversized frames */ if (bp->dev->flags & IFF_PROMISC) config |= MACB_BIT(CAF); /* Copy All Frames */ else if (macb_is_gem(bp) && bp->dev->features & NETIF_F_RXCSUM) @@ -1660,8 +1663,13 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BIT(NBC); /* No BroadCast */ config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); + if ((bp->caps | MACB_CAPS_JUMBO) && bp->jumbo_max_len) + gem_writel(bp, JML, bp->jumbo_max_len); bp->speed = SPEED_10; bp->duplex = DUPLEX_HALF; + bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; + if (bp->caps | MACB_CAPS_JUMBO) + bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; macb_configure_dma(bp); @@ -2703,10 +2711,12 @@ static const struct macb_config emac_config = { }; static const struct macb_config zynqmp_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, + .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | + MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, + .jumbo_max_len = 10240, }; static const struct macb_config zynq_config = { @@ -2797,6 +2807,10 @@ static int macb_probe(struct platform_device *pdev) bp->pclk = pclk; bp->hclk = hclk; bp->tx_clk = tx_clk; + if (macb_config->jumbo_max_len) { + bp->jumbo_max_len = macb_config->jumbo_max_len; + } + spin_lock_init(&bp->lock); /* setup capabilities */ diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 24b1d9bcd8654d..d74655993d4bf1 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -71,6 +71,7 @@ #define GEM_NCFGR 0x0004 /* Network Config */ #define GEM_USRIO 0x000c /* User IO */ #define GEM_DMACFG 0x0010 /* DMA Configuration */ +#define GEM_JML 0x0048 /* Jumbo Max Length */ #define GEM_HRB 0x0080 /* Hash Bottom */ #define GEM_HRT 0x0084 /* Hash Top */ #define GEM_SA1B 0x0088 /* Specific1 Bottom */ @@ -398,6 +399,7 @@ #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 #define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 +#define MACB_CAPS_JUMBO 0x00000008 /* Bit manipulation macros */ #define MACB_BIT(name) \ @@ -515,6 +517,9 @@ struct macb_dma_desc { #define MACB_RX_BROADCAST_OFFSET 31 #define MACB_RX_BROADCAST_SIZE 1 +#define MACB_RX_FRMLEN_MASK 0xFFF +#define MACB_RX_JFRMLEN_MASK 0x3FFF + /* RX checksum offload disabled: bit 24 clear in NCFGR */ #define GEM_RX_TYPEID_MATCH_OFFSET 22 #define GEM_RX_TYPEID_MATCH_SIZE 2 @@ -758,6 +763,7 @@ struct macb_config { int (*clk_init)(struct platform_device *pdev, struct clk **pclk, struct clk **hclk, struct clk **tx_clk); int (*init)(struct platform_device *pdev); + int jumbo_max_len; }; struct macb_queue { @@ -827,6 +833,9 @@ struct macb { unsigned int max_tx_length; u64 ethtool_stats[GEM_STATS_LEN]; + + unsigned int rx_frm_len_mask; + unsigned int jumbo_max_len; }; static inline bool macb_is_gem(struct macb *bp) From 92e6b4b461f9aa402d6a6846ca80d0be3ad8672e Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Wed, 6 May 2015 22:27:18 +0530 Subject: [PATCH 146/381] net: macb: Add change_mtu callback with jumbo support Add macb_change_mtu callback; if jumbo frame support is present allow mtu size changes upto (jumbo max length allowed - headers). Signed-off-by: Harini Katakam Reviewed-by: Punnaiah Choudary Kalluri Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 76b8f1bf3c13dd..b0001e86863f50 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -54,6 +54,8 @@ #define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1)) #define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1)) +#define GEM_MTU_MIN_SIZE 68 + /* * Graceful stop timeouts in us. We should allow up to * 1 frame time (10 Mbits/s, full-duplex, ignoring collisions) @@ -1873,6 +1875,26 @@ static int macb_close(struct net_device *dev) return 0; } +static int macb_change_mtu(struct net_device *dev, int new_mtu) +{ + struct macb *bp = netdev_priv(dev); + u32 max_mtu; + + if (netif_running(dev)) + return -EBUSY; + + max_mtu = ETH_DATA_LEN; + if (bp->caps | MACB_CAPS_JUMBO) + max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN; + + if ((new_mtu > max_mtu) || (new_mtu < GEM_MTU_MIN_SIZE)) + return -EINVAL; + + dev->mtu = new_mtu; + + return 0; +} + static void gem_update_stats(struct macb *bp) { int i; @@ -2149,7 +2171,7 @@ static const struct net_device_ops macb_netdev_ops = { .ndo_get_stats = macb_get_stats, .ndo_do_ioctl = macb_ioctl, .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, + .ndo_change_mtu = macb_change_mtu, .ndo_set_mac_address = eth_mac_addr, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = macb_poll_controller, From 968cebf9efa008b7f2b070755ad14ab037331db8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 12 May 2015 21:15:24 +0300 Subject: [PATCH 147/381] net: macb: OR vs AND typos The bitwise tests are always true here because it uses '|' where '&' is intended. Fixes: 98b5a0f4a228 ('net: macb: Add support for jumbo frames') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index b0001e86863f50..94788c3530ffb5 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1653,7 +1653,7 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BF(RBOF, NET_IP_ALIGN); /* Make eth data aligned */ config |= MACB_BIT(PAE); /* PAuse Enable */ config |= MACB_BIT(DRFCS); /* Discard Rx FCS */ - if (bp->caps | MACB_CAPS_JUMBO) + if (bp->caps & MACB_CAPS_JUMBO) config |= MACB_BIT(JFRAME); /* Enable jumbo frames */ else config |= MACB_BIT(BIG); /* Receive oversized frames */ @@ -1665,12 +1665,12 @@ static void macb_init_hw(struct macb *bp) config |= MACB_BIT(NBC); /* No BroadCast */ config |= macb_dbw(bp); macb_writel(bp, NCFGR, config); - if ((bp->caps | MACB_CAPS_JUMBO) && bp->jumbo_max_len) + if ((bp->caps & MACB_CAPS_JUMBO) && bp->jumbo_max_len) gem_writel(bp, JML, bp->jumbo_max_len); bp->speed = SPEED_10; bp->duplex = DUPLEX_HALF; bp->rx_frm_len_mask = MACB_RX_FRMLEN_MASK; - if (bp->caps | MACB_CAPS_JUMBO) + if (bp->caps & MACB_CAPS_JUMBO) bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK; macb_configure_dma(bp); @@ -1884,7 +1884,7 @@ static int macb_change_mtu(struct net_device *dev, int new_mtu) return -EBUSY; max_mtu = ETH_DATA_LEN; - if (bp->caps | MACB_CAPS_JUMBO) + if (bp->caps & MACB_CAPS_JUMBO) max_mtu = gem_readl(bp, JML) - ETH_HLEN - ETH_FCS_LEN; if ((new_mtu > max_mtu) || (new_mtu < GEM_MTU_MIN_SIZE)) From 202ea6bb69130e3426f388c4f6300218e2221738 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 18 Jun 2015 16:27:23 +0200 Subject: [PATCH 148/381] net/macb: add config for Atmel sama5d2 SoCs Add the compatible string for Atmel sama5d2 SoC family as the configuration options differ from other instances of the GEM. Signed-off-by: Cyrille Pitchen Signed-off-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 94788c3530ffb5..6eaad8d1510e73 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2713,6 +2713,13 @@ static const struct macb_config pc302gem_config = { .init = macb_init, }; +static const struct macb_config sama5d2_config = { + .caps = 0, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, +}; + static const struct macb_config sama5d3_config = { .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE, .dma_burst_length = 16, @@ -2755,6 +2762,7 @@ static const struct of_device_id macb_dt_ids[] = { { .compatible = "cdns,macb" }, { .compatible = "cdns,pc302-gem", .data = &pc302gem_config }, { .compatible = "cdns,gem", .data = &pc302gem_config }, + { .compatible = "atmel,sama5d2-gem", .data = &sama5d2_config }, { .compatible = "atmel,sama5d3-gem", .data = &sama5d3_config }, { .compatible = "atmel,sama5d4-gem", .data = &sama5d4_config }, { .compatible = "cdns,at91rm9200-emac", .data = &emac_config }, From 83d29dcb6b257d0cc7b131ad5395844cbf3706d2 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sun, 21 Jun 2015 16:28:02 -0400 Subject: [PATCH 149/381] drivers/net: remove all references to obsolete Ethernet-HOWTO This howto made sense in the 1990s when users had to manually configure ISA cards with jumpers or vendor utilities, but with the implementation of PCI it became increasingly less and less relevant, to the point where it has been well over a decade since I last updated it. And there is no value in anyone else taking over updating it either. However the references to it continue to spread as boiler plate text from one Kconfig file into the next. We are not doing end users any favours by pointing them at this old document, so lets kill it with fire, once and for all, to hopefully stop any further spread. No code is changed in this commit, just Kconfig help text. Signed-off-by: Paul Gortmaker Signed-off-by: David S. Miller --- drivers/net/arcnet/Kconfig | 4 ---- drivers/net/ethernet/3com/Kconfig | 18 +++++---------- drivers/net/ethernet/8390/Kconfig | 26 +++++++--------------- drivers/net/ethernet/adaptec/Kconfig | 4 +--- drivers/net/ethernet/adi/Kconfig | 2 -- drivers/net/ethernet/agere/Kconfig | 4 +--- drivers/net/ethernet/allwinner/Kconfig | 3 +-- drivers/net/ethernet/alteon/Kconfig | 4 +--- drivers/net/ethernet/amd/Kconfig | 16 +++++-------- drivers/net/ethernet/apple/Kconfig | 7 ++---- drivers/net/ethernet/arc/Kconfig | 4 +--- drivers/net/ethernet/atheros/Kconfig | 4 +--- drivers/net/ethernet/broadcom/Kconfig | 3 +-- drivers/net/ethernet/brocade/Kconfig | 4 +--- drivers/net/ethernet/cadence/Kconfig | 2 -- drivers/net/ethernet/chelsio/Kconfig | 4 +--- drivers/net/ethernet/cirrus/Kconfig | 12 +++------- drivers/net/ethernet/cisco/Kconfig | 4 +--- drivers/net/ethernet/dec/Kconfig | 4 +--- drivers/net/ethernet/dec/tulip/Kconfig | 10 +++------ drivers/net/ethernet/dlink/Kconfig | 4 +--- drivers/net/ethernet/emulex/Kconfig | 4 +--- drivers/net/ethernet/faraday/Kconfig | 4 +--- drivers/net/ethernet/freescale/Kconfig | 4 +--- drivers/net/ethernet/fujitsu/Kconfig | 4 +--- drivers/net/ethernet/hisilicon/Kconfig | 4 +--- drivers/net/ethernet/hp/Kconfig | 8 ++----- drivers/net/ethernet/i825xx/Kconfig | 4 +--- drivers/net/ethernet/ibm/Kconfig | 4 +--- drivers/net/ethernet/intel/Kconfig | 4 +--- drivers/net/ethernet/marvell/Kconfig | 4 +--- drivers/net/ethernet/mellanox/Kconfig | 4 +--- drivers/net/ethernet/micrel/Kconfig | 4 +--- drivers/net/ethernet/microchip/Kconfig | 4 +--- drivers/net/ethernet/moxa/Kconfig | 4 +--- drivers/net/ethernet/myricom/Kconfig | 4 +--- drivers/net/ethernet/natsemi/Kconfig | 7 ++---- drivers/net/ethernet/neterion/Kconfig | 4 +--- drivers/net/ethernet/nuvoton/Kconfig | 4 +--- drivers/net/ethernet/nvidia/Kconfig | 8 ++----- drivers/net/ethernet/oki-semi/Kconfig | 4 +--- drivers/net/ethernet/packetengines/Kconfig | 8 ++----- drivers/net/ethernet/pasemi/Kconfig | 4 +--- drivers/net/ethernet/qlogic/Kconfig | 4 +--- drivers/net/ethernet/qualcomm/Kconfig | 4 +--- drivers/net/ethernet/rdc/Kconfig | 4 +--- drivers/net/ethernet/realtek/Kconfig | 14 ++++-------- drivers/net/ethernet/seeq/Kconfig | 4 +--- drivers/net/ethernet/sgi/Kconfig | 8 ++----- drivers/net/ethernet/silan/Kconfig | 4 +--- drivers/net/ethernet/sis/Kconfig | 4 +--- drivers/net/ethernet/smsc/Kconfig | 18 +++++---------- drivers/net/ethernet/stmicro/Kconfig | 4 +--- drivers/net/ethernet/sun/Kconfig | 4 +--- drivers/net/ethernet/tehuti/Kconfig | 4 +--- drivers/net/ethernet/ti/Kconfig | 8 ++----- drivers/net/ethernet/toshiba/Kconfig | 4 +--- drivers/net/ethernet/tundra/Kconfig | 4 +--- drivers/net/ethernet/via/Kconfig | 4 +--- drivers/net/ethernet/wiznet/Kconfig | 4 +--- drivers/net/ethernet/xilinx/Kconfig | 4 +--- drivers/net/ethernet/xircom/Kconfig | 4 +--- drivers/net/ethernet/xscale/Kconfig | 4 +--- 63 files changed, 93 insertions(+), 265 deletions(-) diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig index 84fb6349a59ab7..2a9c3c3abe9be2 100644 --- a/drivers/net/arcnet/Kconfig +++ b/drivers/net/arcnet/Kconfig @@ -15,10 +15,6 @@ menuconfig ARCNET COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset support" below. - You might also want to have a look at the Ethernet-HOWTO, available - from (even though ARCnet - is not really Ethernet). - To compile this driver as a module, choose M here. The module will be called arcnet. diff --git a/drivers/net/ethernet/3com/Kconfig b/drivers/net/ethernet/3com/Kconfig index afaab4b2333f82..5b7658bcf02095 100644 --- a/drivers/net/ethernet/3com/Kconfig +++ b/drivers/net/ethernet/3com/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_3COM default y depends on ISA || EISA || PCI || PCMCIA ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -23,8 +21,7 @@ config EL3 depends on (ISA || EISA) ---help--- If you have a network (Ethernet) card belonging to the 3Com - EtherLinkIII series, say Y and read the Ethernet-HOWTO, available - from . + EtherLinkIII series, say Y here. If your card is not working you may need to use the DOS setup disk to disable Plug & Play mode, and to select the default @@ -38,8 +35,7 @@ config 3C515 depends on ISA && ISA_DMA_API ---help--- If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet - network card, say Y and read the Ethernet-HOWTO, available from - . + network card, say Y here. To compile this driver as a module, choose M here. The module will be called 3c515. @@ -78,9 +74,7 @@ config VORTEX "Tornado" (3c905) PCI "Hurricane" (3c555/3cSOHO) PCI - If you have such a card, say Y and read the Ethernet-HOWTO, - available from . More - specific information is in + If you have such a card, say Y here. More specific information is in and in the comments at the beginning of . @@ -97,9 +91,7 @@ config TYPHOON 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server, 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card of this type, say Y here. To compile this driver as a module, choose M here. The module will be called typhoon. diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 2d89bd00de6190..edf72258ab1dda 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_8390 default y depends on NET_VENDOR_NATSEMI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -71,9 +69,7 @@ config MAC8390 select CRC32 ---help--- If you want to include a driver to support Nubus or LC-PDS - Ethernet cards using an NS8390 chipset or its equivalent, say Y - and read the Ethernet-HOWTO, available from - . + Ethernet cards using an NS8390 chipset or its equivalent, say Y. config MCF8390 tristate "ColdFire NS8390 based Ethernet support" @@ -95,10 +91,9 @@ config NE2000 ATARI_ETHERNEC) select CRC32 ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . Many Ethernet cards - without a specific driver are compatible with NE2000. + If you have a network (Ethernet) card of this type, say Y here. + Many Ethernet cards without a specific driver are compatible with + the NE2000. If you have a PCI NE2000 card however, say N here and Y to "PCI NE2000 and clone support" below. @@ -114,8 +109,7 @@ config NE2K_PCI This driver is for NE2000 compatible PCI cards. It will not work with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 support" below). If you have a PCI NE2000 network (Ethernet) card, - say Y and read the Ethernet-HOWTO, available from - . + say Y here. This driver also works for the following NE2000 clone cards: RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 @@ -164,9 +158,7 @@ config ULTRA depends on ISA select CRC32 ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card of this type, say Y here. Important: There have been many reports that, with some motherboards mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, @@ -183,9 +175,7 @@ config WD80x3 depends on ISA select CRC32 ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card of this type, say Y here. To compile this driver as a module, choose M here. The module will be called wd. diff --git a/drivers/net/ethernet/adaptec/Kconfig b/drivers/net/ethernet/adaptec/Kconfig index 5c804bbe3dabde..822cffb4174cfc 100644 --- a/drivers/net/ethernet/adaptec/Kconfig +++ b/drivers/net/ethernet/adaptec/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_ADAPTEC default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/adi/Kconfig b/drivers/net/ethernet/adi/Kconfig index c9cd3592ab739c..6b94ba61039954 100644 --- a/drivers/net/ethernet/adi/Kconfig +++ b/drivers/net/ethernet/adi/Kconfig @@ -7,8 +7,6 @@ config NET_BFIN depends on BF516 || BF518 || BF526 || BF527 || BF536 || BF537 ---help--- If you have a network (Ethernet) card belonging to this class, say Y. - Make sure you know the name of your card. Read the Ethernet-HOWTO, - available from . If unsure, say Y. diff --git a/drivers/net/ethernet/agere/Kconfig b/drivers/net/ethernet/agere/Kconfig index 63e805de619e16..b6fe9200355a27 100644 --- a/drivers/net/ethernet/agere/Kconfig +++ b/drivers/net/ethernet/agere/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_AGERE default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/allwinner/Kconfig b/drivers/net/ethernet/allwinner/Kconfig index d8d95d4cd45a9e..47da7e7a5b6a83 100644 --- a/drivers/net/ethernet/allwinner/Kconfig +++ b/drivers/net/ethernet/allwinner/Kconfig @@ -9,8 +9,7 @@ config NET_VENDOR_ALLWINNER depends on ARCH_SUNXI ---help--- If you have a network (Ethernet) card belonging to this - class, say Y and read the Ethernet-HOWTO, available from - . + class, say Y here. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator diff --git a/drivers/net/ethernet/alteon/Kconfig b/drivers/net/ethernet/alteon/Kconfig index 799a8528207043..e06ccab354b5b4 100644 --- a/drivers/net/ethernet/alteon/Kconfig +++ b/drivers/net/ethernet/alteon/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_ALTEON default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig index 42691603615164..b9710d37e1fce1 100644 --- a/drivers/net/ethernet/amd/Kconfig +++ b/drivers/net/ethernet/amd/Kconfig @@ -37,8 +37,7 @@ config AMD8111_ETH select MII ---help--- If you have an AMD 8111-based PCI LANCE ethernet card, - answer Y here and read the Ethernet-HOWTO, available from - . + answer Y here. To compile this driver as a module, choose M here. The module will be called amd8111e. @@ -47,10 +46,8 @@ config LANCE tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" depends on ISA && ISA_DMA_API && !ARM ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . Some LinkSys cards are - of this type. + If you have a network (Ethernet) card of this type, say Y here. + Some LinkSys cards are of this type. To compile this driver as a module, choose M here: the module will be called lance. This is recommended. @@ -62,8 +59,7 @@ config PCNET32 select MII ---help--- If you have a PCnet32 or PCnetPCI based network (Ethernet) card, - answer Y here and read the Ethernet-HOWTO, available from - . + answer Y here. To compile this driver as a module, choose M here. The module will be called pcnet32. @@ -144,9 +140,7 @@ config NI65 tristate "NI6510 support" depends on ISA && ISA_DMA_API && !ARM ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card of this type, say Y here. To compile this driver as a module, choose M here. The module will be called ni65. diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig index 1375e2dc94687d..d19a41b0c6d266 100644 --- a/drivers/net/ethernet/apple/Kconfig +++ b/drivers/net/ethernet/apple/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_APPLE default y depends on (PPC_PMAC && PPC32) || MAC ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -59,7 +57,6 @@ config MACMACE ---help--- Support for the onboard AMD 79C940 MACE Ethernet controller used in the 660AV and 840AV Macintosh. If you have one of these Macintoshes - say Y and read the Ethernet-HOWTO, available from - . + say Y here. endif # NET_VENDOR_APPLE diff --git a/drivers/net/ethernet/arc/Kconfig b/drivers/net/ethernet/arc/Kconfig index dea29ee24da4a2..52a6b16f57d206 100644 --- a/drivers/net/ethernet/arc/Kconfig +++ b/drivers/net/ethernet/arc/Kconfig @@ -6,9 +6,7 @@ config NET_VENDOR_ARC bool "ARC devices" default y ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/atheros/Kconfig b/drivers/net/ethernet/atheros/Kconfig index 58ad37c733bc8f..e05b2567533354 100644 --- a/drivers/net/ethernet/atheros/Kconfig +++ b/drivers/net/ethernet/atheros/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_ATHEROS default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index a6f9142b9048ce..8be9eab733203c 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -26,8 +26,7 @@ config B44 select PHYLIB ---help--- If you have a network (Ethernet) controller of this type, say Y - or M and read the Ethernet-HOWTO, available from - . + or M here. To compile this driver as a module, choose M here. The module will be called b44. diff --git a/drivers/net/ethernet/brocade/Kconfig b/drivers/net/ethernet/brocade/Kconfig index 4e8c0b6c57d02e..c4bbe54e2cadc5 100644 --- a/drivers/net/ethernet/brocade/Kconfig +++ b/drivers/net/ethernet/brocade/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_BROCADE default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index 1ba3e3a67389d8..f0bcb15d3fec0c 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -8,8 +8,6 @@ config NET_CADENCE default y ---help--- If you have a network (Ethernet) card belonging to this class, say Y. - Make sure you know the name of your card. Read the Ethernet-HOWTO, - available from . If unsure, say Y. diff --git a/drivers/net/ethernet/chelsio/Kconfig b/drivers/net/ethernet/chelsio/Kconfig index 7daa088a9bb7ad..a79813a17b6e58 100644 --- a/drivers/net/ethernet/chelsio/Kconfig +++ b/drivers/net/ethernet/chelsio/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_CHELSIO default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig index 905ac5f5d9a600..5ab912937aff2e 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_CIRRUS default y depends on ISA || EISA || ARM || MAC ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -23,9 +21,7 @@ config CS89x0 depends on ISA || EISA || ARM ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a - network (Ethernet) card of this type, say Y and read the - Ethernet-HOWTO, available from - as well as + network (Ethernet) card of this type, say Y and read the file . To compile this driver as a module, choose M here. The module @@ -55,9 +51,7 @@ config MAC89x0 depends on MAC ---help--- Support for CS89x0 chipset based Ethernet cards. If you have a - Nubus or LC-PDS network (Ethernet) card of this type, say Y and - read the Ethernet-HOWTO, available from - . + Nubus or LC-PDS network (Ethernet) card of this type, say Y here. To compile this driver as a module, choose M here. This module will be called mac89x0. diff --git a/drivers/net/ethernet/cisco/Kconfig b/drivers/net/ethernet/cisco/Kconfig index 1c7b884e337147..15b713a8962031 100644 --- a/drivers/net/ethernet/cisco/Kconfig +++ b/drivers/net/ethernet/cisco/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_CISCO default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/dec/Kconfig b/drivers/net/ethernet/dec/Kconfig index 68262aa57d017e..740bbad5ed38ba 100644 --- a/drivers/net/ethernet/dec/Kconfig +++ b/drivers/net/ethernet/dec/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_DEC default y depends on PCI || EISA || CARDBUS ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/dec/tulip/Kconfig b/drivers/net/ethernet/dec/tulip/Kconfig index eb9ba6e97d04a4..1003201b5d8067 100644 --- a/drivers/net/ethernet/dec/tulip/Kconfig +++ b/drivers/net/ethernet/dec/tulip/Kconfig @@ -21,8 +21,7 @@ config DE2104X of this type. (If your card is NOT SMC EtherPower 10/100 PCI (smc9332dst), you can also try the driver for "Generic DECchip" cards, below. However, most people with a network card of this type - will say Y here.) Do read the Ethernet-HOWTO, available from - . + will say Y here.) To compile this driver as a module, choose M here. The module will be called de2104x. @@ -50,8 +49,7 @@ config TULIP of this type. (If your card is NOT SMC EtherPower 10/100 PCI (smc9332dst), you can also try the driver for "Generic DECchip" cards, above. However, most people with a network card of this type - will say Y here.) Do read the Ethernet-HOWTO, available from - . + will say Y here.) To compile this driver as a module, choose M here. The module will be called tulip. @@ -113,9 +111,7 @@ config DE4X5 ---help--- This is support for the DIGITAL series of PCI/EISA Ethernet cards. These include the DE425, DE434, DE435, DE450 and DE500 models. If - you have a network card of this type, say Y and read the - Ethernet-HOWTO, available from - . More specific + you have a network card of this type, say Y. More specific information is contained in . diff --git a/drivers/net/ethernet/dlink/Kconfig b/drivers/net/ethernet/dlink/Kconfig index c543ac11ce0895..f6e858d0b9d421 100644 --- a/drivers/net/ethernet/dlink/Kconfig +++ b/drivers/net/ethernet/dlink/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_DLINK default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/emulex/Kconfig b/drivers/net/ethernet/emulex/Kconfig index 1b8d638c6cb189..fdbb27ceb02fe2 100644 --- a/drivers/net/ethernet/emulex/Kconfig +++ b/drivers/net/ethernet/emulex/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_EMULEX default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/faraday/Kconfig b/drivers/net/ethernet/faraday/Kconfig index 5918c68916946a..040c7f16332583 100644 --- a/drivers/net/ethernet/faraday/Kconfig +++ b/drivers/net/ethernet/faraday/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_FARADAY default y depends on ARM ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig index 25e3425729d0ad..b8de87b03046a1 100644 --- a/drivers/net/ethernet/freescale/Kconfig +++ b/drivers/net/ethernet/freescale/Kconfig @@ -9,9 +9,7 @@ config NET_VENDOR_FREESCALE M523x || M527x || M5272 || M528x || M520x || M532x || \ ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/fujitsu/Kconfig b/drivers/net/ethernet/fujitsu/Kconfig index 1085257385d2c2..faee34e44a356b 100644 --- a/drivers/net/ethernet/fujitsu/Kconfig +++ b/drivers/net/ethernet/fujitsu/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_FUJITSU default y depends on PCMCIA ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the the questions about Fujitsu cards. If you say Y, you will be asked for diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig index a54d8979131146..dead17b5d769ca 100644 --- a/drivers/net/ethernet/hisilicon/Kconfig +++ b/drivers/net/ethernet/hisilicon/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_HISILICON default y depends on ARM ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/hp/Kconfig b/drivers/net/ethernet/hp/Kconfig index a0b8ece1e3bcbf..d4df78c2abced4 100644 --- a/drivers/net/ethernet/hp/Kconfig +++ b/drivers/net/ethernet/hp/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_HP default y depends on ISA || EISA || PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -22,9 +20,7 @@ config HP100 tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support" depends on (ISA || EISA || PCI) ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card of this type, say Y here. To compile this driver as a module, choose M here. The module will be called hp100. diff --git a/drivers/net/ethernet/i825xx/Kconfig b/drivers/net/ethernet/i825xx/Kconfig index 9521e68aa3b3eb..e8d61f67047934 100644 --- a/drivers/net/ethernet/i825xx/Kconfig +++ b/drivers/net/ethernet/i825xx/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_I825XX default y depends on NET_VENDOR_INTEL ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question does not directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/ibm/Kconfig b/drivers/net/ethernet/ibm/Kconfig index 563a1ac71dbc8a..99c1cebd002d74 100644 --- a/drivers/net/ethernet/ibm/Kconfig +++ b/drivers/net/ethernet/ibm/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_IBM default y depends on PPC_PSERIES || PPC_DCR || (IBMEBUS && SPARSEMEM) ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index f4ff465584a082..4163b16489b35f 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -6,9 +6,7 @@ config NET_VENDOR_INTEL bool "Intel devices" default y ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index d323a695dfbcb4..80af9ffce5ead1 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_MARVELL default y depends on PCI || CPU_PXA168 || MV64X60 || PPC32 || PLAT_ORION || INET ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index 8cf7563a8d9208..52a6665b7abf4f 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_MELLANOX default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/micrel/Kconfig b/drivers/net/ethernet/micrel/Kconfig index d16b11ed2e5227..b7e2f49696b74b 100644 --- a/drivers/net/ethernet/micrel/Kconfig +++ b/drivers/net/ethernet/micrel/Kconfig @@ -8,9 +8,7 @@ config NET_VENDOR_MICREL depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM || \ (ARM && ARCH_KS8695) ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/microchip/Kconfig b/drivers/net/ethernet/microchip/Kconfig index afaf0c07f37f7b..3fd8ca6d4e7ca4 100644 --- a/drivers/net/ethernet/microchip/Kconfig +++ b/drivers/net/ethernet/microchip/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_MICROCHIP default y depends on SPI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/moxa/Kconfig b/drivers/net/ethernet/moxa/Kconfig index 1731e050fa2765..5b531da3693333 100644 --- a/drivers/net/ethernet/moxa/Kconfig +++ b/drivers/net/ethernet/moxa/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_MOXART default y depends on (ARM && ARCH_MOXART) ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/myricom/Kconfig b/drivers/net/ethernet/myricom/Kconfig index 3932d081fa2106..9645c7245bbfb4 100644 --- a/drivers/net/ethernet/myricom/Kconfig +++ b/drivers/net/ethernet/myricom/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_MYRI default y depends on PCI && INET ---help--- - If you have a network (Ethernet) card belonging to this class, say - Y and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/natsemi/Kconfig b/drivers/net/ethernet/natsemi/Kconfig index a100860d45e6fa..a10ef50e4f12c3 100644 --- a/drivers/net/ethernet/natsemi/Kconfig +++ b/drivers/net/ethernet/natsemi/Kconfig @@ -6,9 +6,7 @@ config NET_VENDOR_NATSEMI bool "National Semi-conductor devices" default y ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -24,8 +22,7 @@ config MACSONIC Support for NatSemi SONIC based Ethernet devices. This includes the onboard Ethernet in many Quadras as well as some LC-PDS, a few Nubus and all known Comm Slot Ethernet cards. If you have - one of these say Y and read the Ethernet-HOWTO, available from - . + one of these say Y here. To compile this driver as a module, choose M here. This module will be called macsonic. diff --git a/drivers/net/ethernet/neterion/Kconfig b/drivers/net/ethernet/neterion/Kconfig index 87abb4f10c43a4..71899009c468af 100644 --- a/drivers/net/ethernet/neterion/Kconfig +++ b/drivers/net/ethernet/neterion/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_EXAR default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say - Y and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/nuvoton/Kconfig b/drivers/net/ethernet/nuvoton/Kconfig index 01182b559473cc..71c973f8e50f44 100644 --- a/drivers/net/ethernet/nuvoton/Kconfig +++ b/drivers/net/ethernet/nuvoton/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_NUVOTON default y depends on ARM && ARCH_W90X900 ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/nvidia/Kconfig b/drivers/net/ethernet/nvidia/Kconfig index ace19e7f6d1323..4efc9fe8478526 100644 --- a/drivers/net/ethernet/nvidia/Kconfig +++ b/drivers/net/ethernet/nvidia/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_NVIDIA default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -22,9 +20,7 @@ config FORCEDETH tristate "nForce Ethernet support" depends on PCI ---help--- - If you have a network (Ethernet) controller of this type, say Y and - read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) controller of this type, say Y here. To compile this driver as a module, choose M here. The module will be called forcedeth. diff --git a/drivers/net/ethernet/oki-semi/Kconfig b/drivers/net/ethernet/oki-semi/Kconfig index ecd45f9ea9d950..5a975af4824b0a 100644 --- a/drivers/net/ethernet/oki-semi/Kconfig +++ b/drivers/net/ethernet/oki-semi/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_OKI default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/packetengines/Kconfig b/drivers/net/ethernet/packetengines/Kconfig index 8d5180043c7001..b5ea2a56106ef3 100644 --- a/drivers/net/ethernet/packetengines/Kconfig +++ b/drivers/net/ethernet/packetengines/Kconfig @@ -7,9 +7,7 @@ config NET_PACKET_ENGINE default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -23,9 +21,7 @@ config HAMACHI depends on PCI select MII ---help--- - If you have a Gigabit Ethernet card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a Gigabit Ethernet card of this type, say Y here. To compile this driver as a module, choose M here. The module will be called hamachi. diff --git a/drivers/net/ethernet/pasemi/Kconfig b/drivers/net/ethernet/pasemi/Kconfig index 01e6c329d78cd6..db19c6f49859d3 100644 --- a/drivers/net/ethernet/pasemi/Kconfig +++ b/drivers/net/ethernet/pasemi/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_PASEMI default y depends on PPC_PASEMI && PCI && INET ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig index d49cba1290814e..f1f0108c275d70 100644 --- a/drivers/net/ethernet/qlogic/Kconfig +++ b/drivers/net/ethernet/qlogic/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_QLOGIC default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/qualcomm/Kconfig b/drivers/net/ethernet/qualcomm/Kconfig index 9a49f42ac2ba4a..a76e380cf89aca 100644 --- a/drivers/net/ethernet/qualcomm/Kconfig +++ b/drivers/net/ethernet/qualcomm/Kconfig @@ -6,9 +6,7 @@ config NET_VENDOR_QUALCOMM bool "Qualcomm devices" default y ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/rdc/Kconfig b/drivers/net/ethernet/rdc/Kconfig index 2055f7eb2ba94f..a9c4e990d29b5d 100644 --- a/drivers/net/ethernet/rdc/Kconfig +++ b/drivers/net/ethernet/rdc/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_RDC default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index ae5d027096ed6f..7c69f4c8134da8 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_REALTEK default y depends on PCI || (PARPORT && X86) ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -24,8 +22,7 @@ config ATP select CRC32 ---help--- This is a network (Ethernet) device which attaches to your parallel - port. Read as well as the - Ethernet-HOWTO, available from , + port. Read the file if you want to use this. If you intend to use this driver, you should have said N to the "Parallel printer support", because the two drivers don't like each other. @@ -40,9 +37,7 @@ config 8139CP select MII ---help--- This is a driver for the Fast Ethernet PCI network cards based on - the RTL8139C+ chips. If you have one of those, say Y and read - the Ethernet-HOWTO, available from - . + the RTL8139C+ chips. If you have one of those, say Y here. To compile this driver as a module, choose M here: the module will be called 8139cp. This is recommended. @@ -54,8 +49,7 @@ config 8139TOO select MII ---help--- This is a driver for the Fast Ethernet PCI network cards based on - the RTL 8129/8130/8139 chips. If you have one of those, say Y and - read the Ethernet-HOWTO . + the RTL 8129/8130/8139 chips. If you have one of those, say Y here. To compile this driver as a module, choose M here: the module will be called 8139too. This is recommended. diff --git a/drivers/net/ethernet/seeq/Kconfig b/drivers/net/ethernet/seeq/Kconfig index 11f168e46ebe01..69c62d89295e33 100644 --- a/drivers/net/ethernet/seeq/Kconfig +++ b/drivers/net/ethernet/seeq/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_SEEQ default y depends on HAS_IOMEM ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/sgi/Kconfig b/drivers/net/ethernet/sgi/Kconfig index e832f46660c9ed..fbbb21c13e951e 100644 --- a/drivers/net/ethernet/sgi/Kconfig +++ b/drivers/net/ethernet/sgi/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_SGI default y depends on (PCI && SGI_IP27) || SGI_IP32 ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -24,9 +22,7 @@ config SGI_IOC3_ETH select CRC32 select MII ---help--- - If you have a network (Ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card of this type, say Y here. config SGI_O2MACE_ETH tristate "SGI O2 MACE Fast Ethernet support" diff --git a/drivers/net/ethernet/silan/Kconfig b/drivers/net/ethernet/silan/Kconfig index 3409b3f97a1ba0..ac982be3851065 100644 --- a/drivers/net/ethernet/silan/Kconfig +++ b/drivers/net/ethernet/silan/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_SILAN default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/sis/Kconfig b/drivers/net/ethernet/sis/Kconfig index 68d052b09af1e1..22ec98ec9d3e25 100644 --- a/drivers/net/ethernet/sis/Kconfig +++ b/drivers/net/ethernet/sis/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_SIS default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig index 3e97a8b43147cc..eb9230e2092f9d 100644 --- a/drivers/net/ethernet/smsc/Kconfig +++ b/drivers/net/ethernet/smsc/Kconfig @@ -9,9 +9,7 @@ config NET_VENDOR_SMSC ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \ PCMCIA || SUPERH || XTENSA ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -29,8 +27,7 @@ config SMC9194 option if you have a DELL laptop with the docking station, or another SMC9192/9194 based chipset. Say Y if you want it compiled into the kernel, and read the file - and the Ethernet-HOWTO, - available from . + . To compile this driver as a module, choose M here. The module will be called smc9194. @@ -46,8 +43,7 @@ config SMC91X This is a driver for SMC's 91x series of Ethernet chipsets, including the SMC91C94 and the SMC91C111. Say Y if you want it compiled into the kernel, and read the file - and the Ethernet-HOWTO, - available from . + . This driver is also available as a module ( = code which can be inserted in and removed from the running kernel whenever you want). @@ -85,9 +81,7 @@ config SMC911X ---help--- This is a driver for SMSC's LAN911x series of Ethernet chipsets including the new LAN9115, LAN9116, LAN9117, and LAN9118. - Say Y if you want it compiled into the kernel, - and read the Ethernet-HOWTO, available from - . + Say Y here if you want it compiled into the kernel. This driver is also available as a module. The module will be called smc911x. If you want to compile it as a module, say M @@ -122,9 +116,7 @@ config SMSC9420 select SMSC_PHY ---help--- This is a driver for SMSC's LAN9420 PCI ethernet adapter. - Say Y if you want it compiled into the kernel, - and read the Ethernet-HOWTO, available from - . + Say Y here if you want it compiled into the kernel. This driver is also available as a module. The module will be called smsc9420. If you want to compile it as a module, say M diff --git a/drivers/net/ethernet/stmicro/Kconfig b/drivers/net/ethernet/stmicro/Kconfig index f4a80da0065009..1c1157d2bd40ca 100644 --- a/drivers/net/ethernet/stmicro/Kconfig +++ b/drivers/net/ethernet/stmicro/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_STMICRO default y depends on HAS_IOMEM ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/sun/Kconfig b/drivers/net/ethernet/sun/Kconfig index 3074aa374c6bdc..dee94b67638c30 100644 --- a/drivers/net/ethernet/sun/Kconfig +++ b/drivers/net/ethernet/sun/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_SUN default y depends on SUN3 || SBUS || PCI || SUN_LDOMS ---help--- - If you have a network (Ethernet) card belonging to this class, say - Y and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/tehuti/Kconfig b/drivers/net/ethernet/tehuti/Kconfig index 1fc027eda33ea3..b17f0ca3f395e6 100644 --- a/drivers/net/ethernet/tehuti/Kconfig +++ b/drivers/net/ethernet/tehuti/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_TEHUTI default y depends on PCI ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig index 631e0afd07d2a2..e7f0b7d95b65ab 100644 --- a/drivers/net/ethernet/ti/Kconfig +++ b/drivers/net/ethernet/ti/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_TI default y depends on PCI || EISA || AR7 || ARCH_DAVINCI || ARCH_OMAP2PLUS || ARCH_KEYSTONE ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all @@ -110,9 +108,7 @@ config TLAN depends on (PCI || EISA) ---help--- If you have a PCI Ethernet network card based on the ThunderLAN chip - which is supported by this driver, say Y and read the - Ethernet-HOWTO, available from - . + which is supported by this driver, say Y here. Devices currently supported by this driver are Compaq Netelligent, Compaq NetFlex and Olicom cards. Please read the file diff --git a/drivers/net/ethernet/toshiba/Kconfig b/drivers/net/ethernet/toshiba/Kconfig index 5d244b6b5e3a08..6f1d5b623768df 100644 --- a/drivers/net/ethernet/toshiba/Kconfig +++ b/drivers/net/ethernet/toshiba/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_TOSHIBA default y depends on PCI && (PPC_IBM_CELL_BLADE || MIPS) || PPC_PS3 ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/tundra/Kconfig b/drivers/net/ethernet/tundra/Kconfig index cf7d69b62c42cc..81d845e4e23b40 100644 --- a/drivers/net/ethernet/tundra/Kconfig +++ b/drivers/net/ethernet/tundra/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_TUNDRA default y depends on TSI108_BRIDGE ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/via/Kconfig b/drivers/net/ethernet/via/Kconfig index f66ddaee0c877f..4b3995ed5ed27d 100644 --- a/drivers/net/ethernet/via/Kconfig +++ b/drivers/net/ethernet/via/Kconfig @@ -6,9 +6,7 @@ config NET_VENDOR_VIA bool "VIA devices" default y ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/wiznet/Kconfig b/drivers/net/ethernet/wiznet/Kconfig index b4d281626fb499..f98b91d21f3330 100644 --- a/drivers/net/ethernet/wiznet/Kconfig +++ b/drivers/net/ethernet/wiznet/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_WIZNET depends on HAS_IOMEM default y ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/xilinx/Kconfig b/drivers/net/ethernet/xilinx/Kconfig index 7b90a5eba09953..4f5c024c6192b0 100644 --- a/drivers/net/ethernet/xilinx/Kconfig +++ b/drivers/net/ethernet/xilinx/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_XILINX default y depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/xircom/Kconfig b/drivers/net/ethernet/xircom/Kconfig index 69f56a6de82162..d6208a4c9866fa 100644 --- a/drivers/net/ethernet/xircom/Kconfig +++ b/drivers/net/ethernet/xircom/Kconfig @@ -7,9 +7,7 @@ config NET_VENDOR_XIRCOM default y depends on PCMCIA ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question doesn't directly affect the kernel: saying N will just cause the configurator to skip all diff --git a/drivers/net/ethernet/xscale/Kconfig b/drivers/net/ethernet/xscale/Kconfig index b81bc9fca3782f..af3432fe9a5e0b 100644 --- a/drivers/net/ethernet/xscale/Kconfig +++ b/drivers/net/ethernet/xscale/Kconfig @@ -8,9 +8,7 @@ config NET_VENDOR_XSCALE depends on NET_VENDOR_INTEL && (ARM && ARCH_IXP4XX && \ IXP4XX_NPE && IXP4XX_QMGR) ---help--- - If you have a network (Ethernet) card belonging to this class, say Y - and read the Ethernet-HOWTO, available from - . + If you have a network (Ethernet) card belonging to this class, say Y. Note that the answer to this question does not directly affect the kernel: saying N will just cause the configurator to skip all From e28d1cc9068b177158be17e6b1dd33684c42fbf1 Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Mon, 6 Jul 2015 10:02:53 +0530 Subject: [PATCH 150/381] net: macb: Add SG support for Zynq SOC family Enable SG support for Zynq SOC family devices. Signed-off-by: Punnaiah Choudary Kalluri Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 6eaad8d1510e73..6f70c78dc61965 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2740,8 +2740,7 @@ static const struct macb_config emac_config = { }; static const struct macb_config zynqmp_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | - MACB_CAPS_JUMBO, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, @@ -2749,8 +2748,7 @@ static const struct macb_config zynqmp_config = { }; static const struct macb_config zynq_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | - MACB_CAPS_NO_GIGABIT_HALF, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, From bd45ab2d4420515bd6dc431127209b895d7b95af Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Thu, 23 Jul 2015 15:44:25 +0530 Subject: [PATCH 151/381] net: macb: Change capability mask for jumbo support JUMBO and NO_GIGABIT_HALF have the same capability masks. Change one of them. Signed-off-by: Harini Katakam Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d74655993d4bf1..8fb80b2dcf826a 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -399,7 +399,7 @@ #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 #define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 -#define MACB_CAPS_JUMBO 0x00000008 +#define MACB_CAPS_JUMBO 0x00000010 /* Bit manipulation macros */ #define MACB_BIT(name) \ From f76e1dee3889c1f73535f76055531b43a1ad7f95 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 24 Jul 2015 21:23:59 +0300 Subject: [PATCH 152/381] net/macb: improve big endian CPU support The commit a50dad355a53 (net: macb: Add big endian CPU support) converted I/O accessors to readl_relaxed() and writel_relaxed() and consequentially broke MACB driver on AVR32 platforms such as ATNGW100. This patch improves I/O access by checking endiannes first and use the corresponding methods. Fixes: a50dad355a53 (net: macb: Add big endian CPU support) Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 103 ++++++++++++++++++++-------- drivers/net/ethernet/cadence/macb.h | 28 +++----- 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 6f70c78dc61965..155d3c7e024ccd 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -104,6 +104,57 @@ static void *macb_rx_buffer(struct macb *bp, unsigned int index) return bp->rx_buffers + bp->rx_buffer_size * macb_rx_ring_wrap(index); } +/* I/O accessors */ +static u32 hw_readl_native(struct macb *bp, int offset) +{ + return __raw_readl(bp->regs + offset); +} + +static void hw_writel_native(struct macb *bp, int offset, u32 value) +{ + __raw_writel(value, bp->regs + offset); +} + +static u32 hw_readl(struct macb *bp, int offset) +{ + return readl_relaxed(bp->regs + offset); +} + +static void hw_writel(struct macb *bp, int offset, u32 value) +{ + writel_relaxed(value, bp->regs + offset); +} + +/* + * Find the CPU endianness by using the loopback bit of NCR register. When the + * CPU is in big endian we need to program swaped mode for management + * descriptor access. + */ +static bool hw_is_native_io(void __iomem *addr) +{ + u32 value = MACB_BIT(LLB); + + __raw_writel(value, addr + MACB_NCR); + value = __raw_readl(addr + MACB_NCR); + + /* Write 0 back to disable everything */ + __raw_writel(0, addr + MACB_NCR); + + return value == MACB_BIT(LLB); +} + +static bool hw_is_gem(void __iomem *addr, bool native_io) +{ + u32 id; + + if (native_io) + id = __raw_readl(addr + MACB_MID); + else + id = readl_relaxed(addr + MACB_MID); + + return MACB_BFEXT(IDNUM, id) >= 0x2; +} + static void macb_set_hwaddr(struct macb *bp) { u32 bottom; @@ -449,14 +500,14 @@ static int macb_mii_init(struct macb *bp) static void macb_update_stats(struct macb *bp) { - u32 __iomem *reg = bp->regs + MACB_PFR; u32 *p = &bp->hw_stats.macb.rx_pause_frames; u32 *end = &bp->hw_stats.macb.tx_pause_frames + 1; + int offset = MACB_PFR; WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); - for(; p < end; p++, reg++) - *p += readl_relaxed(reg); + for(; p < end; p++, offset += 4) + *p += bp->readl(bp, offset); } static int macb_halt_tx(struct macb *bp) @@ -1603,7 +1654,6 @@ static u32 macb_dbw(struct macb *bp) static void macb_configure_dma(struct macb *bp) { u32 dmacfg; - u32 tmp, ncr; if (macb_is_gem(bp)) { dmacfg = gem_readl(bp, DMACFG) & ~GEM_BF(RXBS, -1L); @@ -1613,22 +1663,11 @@ static void macb_configure_dma(struct macb *bp) dmacfg |= GEM_BIT(TXPBMS) | GEM_BF(RXBMS, -1L); dmacfg &= ~GEM_BIT(ENDIA_PKT); - /* Find the CPU endianness by using the loopback bit of net_ctrl - * register. save it first. When the CPU is in big endian we - * need to program swaped mode for management descriptor access. - */ - ncr = macb_readl(bp, NCR); - __raw_writel(MACB_BIT(LLB), bp->regs + MACB_NCR); - tmp = __raw_readl(bp->regs + MACB_NCR); - - if (tmp == MACB_BIT(LLB)) + if (bp->native_io) dmacfg &= ~GEM_BIT(ENDIA_DESC); else dmacfg |= GEM_BIT(ENDIA_DESC); /* CPU in big endian */ - /* Restore net_ctrl */ - macb_writel(bp, NCR, ncr); - if (bp->dev->features & NETIF_F_HW_CSUM) dmacfg |= GEM_BIT(TXCOEN); else @@ -1902,14 +1941,14 @@ static void gem_update_stats(struct macb *bp) for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { u32 offset = gem_statistics[i].offset; - u64 val = readl_relaxed(bp->regs + offset); + u64 val = bp->readl(bp, offset); bp->ethtool_stats[i] += val; *p += val; if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { /* Add GEM_OCTTXH, GEM_OCTRXH */ - val = readl_relaxed(bp->regs + offset + 4); + val = bp->readl(bp, offset + 4); bp->ethtool_stats[i] += ((u64)val) << 32; *(++p) += val; } @@ -2190,7 +2229,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co if (dt_conf) bp->caps = dt_conf->caps; - if (macb_is_gem_hw(bp->regs)) { + if (hw_is_gem(bp->regs, bp->native_io)) { bp->caps |= MACB_CAPS_MACB_IS_GEM; dcfg = gem_readl(bp, DCFG1); @@ -2205,6 +2244,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co } static void macb_probe_queues(void __iomem *mem, + bool native_io, unsigned int *queue_mask, unsigned int *num_queues) { @@ -2219,7 +2259,7 @@ static void macb_probe_queues(void __iomem *mem, * we are early in the probe process and don't have the * MACB_CAPS_MACB_IS_GEM flag positioned */ - if (!macb_is_gem_hw(mem)) + if (!hw_is_gem(mem, native_io)) return; /* bit 0 is never set but queue 0 always exists */ @@ -2783,6 +2823,7 @@ static int macb_probe(struct platform_device *pdev) struct clk *pclk, *hclk, *tx_clk; unsigned int queue_mask, num_queues; struct macb_platform_data *pdata; + bool native_io; struct phy_device *phydev; struct net_device *dev; struct resource *regs; @@ -2791,6 +2832,11 @@ static int macb_probe(struct platform_device *pdev) struct macb *bp; int err; + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mem = devm_ioremap_resource(&pdev->dev, regs); + if (IS_ERR(mem)) + return PTR_ERR(mem); + if (np) { const struct of_device_id *match; @@ -2806,14 +2852,9 @@ static int macb_probe(struct platform_device *pdev) if (err) return err; - regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mem = devm_ioremap_resource(&pdev->dev, regs); - if (IS_ERR(mem)) { - err = PTR_ERR(mem); - goto err_disable_clocks; - } + native_io = hw_is_native_io(mem); - macb_probe_queues(mem, &queue_mask, &num_queues); + macb_probe_queues(mem, native_io, &queue_mask, &num_queues); dev = alloc_etherdev_mq(sizeof(*bp), num_queues); if (!dev) { err = -ENOMEM; @@ -2828,6 +2869,14 @@ static int macb_probe(struct platform_device *pdev) bp->pdev = pdev; bp->dev = dev; bp->regs = mem; + bp->native_io = native_io; + if (native_io) { + bp->readl = hw_readl_native; + bp->writel = hw_writel_native; + } else { + bp->readl = hw_readl; + bp->writel = hw_writel; + } bp->num_queues = num_queues; bp->queue_mask = queue_mask; if (macb_config) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 8fb80b2dcf826a..619f9482263508 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -429,18 +429,12 @@ | GEM_BF(name, value)) /* Register access macros */ -#define macb_readl(port,reg) \ - readl_relaxed((port)->regs + MACB_##reg) -#define macb_writel(port,reg,value) \ - writel_relaxed((value), (port)->regs + MACB_##reg) -#define gem_readl(port, reg) \ - readl_relaxed((port)->regs + GEM_##reg) -#define gem_writel(port, reg, value) \ - writel_relaxed((value), (port)->regs + GEM_##reg) -#define queue_readl(queue, reg) \ - readl_relaxed((queue)->bp->regs + (queue)->reg) -#define queue_writel(queue, reg, value) \ - writel_relaxed((value), (queue)->bp->regs + (queue)->reg) +#define macb_readl(port, reg) (port)->readl((port), MACB_##reg) +#define macb_writel(port, reg, value) (port)->writel((port), MACB_##reg, (value)) +#define gem_readl(port, reg) (port)->readl((port), GEM_##reg) +#define gem_writel(port, reg, value) (port)->writel((port), GEM_##reg, (value)) +#define queue_readl(queue, reg) (queue)->bp->readl((queue)->bp, (queue)->reg) +#define queue_writel(queue, reg, value) (queue)->bp->writel((queue)->bp, (queue)->reg, (value)) /* Conditional GEM/MACB macros. These perform the operation to the correct * register dependent on whether the device is a GEM or a MACB. For registers @@ -785,6 +779,11 @@ struct macb_queue { struct macb { void __iomem *regs; + bool native_io; + + /* hardware IO accessors */ + u32 (*readl)(struct macb *bp, int offset); + void (*writel)(struct macb *bp, int offset, u32 value); unsigned int rx_tail; unsigned int rx_prepared_head; @@ -843,9 +842,4 @@ static inline bool macb_is_gem(struct macb *bp) return !!(bp->caps & MACB_CAPS_MACB_IS_GEM); } -static inline bool macb_is_gem_hw(void __iomem *addr) -{ - return !!(MACB_BFEXT(IDNUM, readl_relaxed(addr + MACB_MID)) >= 0x2); -} - #endif /* _MACB_H */ From 54f00a35390d3bd821e33218d8a49e5a43aa404b Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 24 Jul 2015 21:24:00 +0300 Subject: [PATCH 153/381] net/macb: check if macb_config present The commit 98b5a0f4a228 introduces jumbo frame support, but also it assumes that macb_config present which is not always true. The configuration without macb_config fails to boot. Unable to handle kernel NULL pointer dereference at virtual address 00000010 ptbr = 90350000 pgd = 00000000 Oops: Kernel access of bad area, sig: 11 [#1] FRAME_POINTER chip: 0x01f:0x1e82 rev 2 Modules linked in: CPU: 0 PID: 1 Comm: swapper Not tainted 4.2.0-rc3-next-20150723+ #13 task: 91c26000 ti: 91c28000 task.ti: 91c28000 PC is at macb_probe+0x140/0x61c Fixes: 98b5a0f4a228 (net: macb: Add support for jumbo frames) Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 155d3c7e024ccd..022efe1a969b1d 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2884,9 +2884,8 @@ static int macb_probe(struct platform_device *pdev) bp->pclk = pclk; bp->hclk = hclk; bp->tx_clk = tx_clk; - if (macb_config->jumbo_max_len) { + if (macb_config) bp->jumbo_max_len = macb_config->jumbo_max_len; - } spin_lock_init(&bp->lock); From 8874eccfbc9ec328d4a13e6795b10e75d40451b3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 24 Jul 2015 21:24:01 +0300 Subject: [PATCH 154/381] net/macb: use dev_*() when netdev is not yet registered To avoid messages like macb macb.0 (unnamed net_device) (uninitialized): Cadence caps 0x00000000 macb macb.0 (unnamed net_device) (uninitialized): invalid hw address, using random let's use dev_*() macros. Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 022efe1a969b1d..145f7d3bee5e13 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -211,7 +211,7 @@ static void macb_get_hwaddr(struct macb *bp) } } - netdev_info(bp->dev, "invalid hw address, using random\n"); + dev_info(&bp->pdev->dev, "invalid hw address, using random\n"); eth_hw_addr_random(bp->dev); } @@ -2240,7 +2240,7 @@ static void macb_configure_caps(struct macb *bp, const struct macb_config *dt_co bp->caps |= MACB_CAPS_FIFO_MODE; } - netdev_dbg(bp->dev, "Cadence caps 0x%08x\n", bp->caps); + dev_dbg(&bp->pdev->dev, "Cadence caps 0x%08x\n", bp->caps); } static void macb_probe_queues(void __iomem *mem, From 6cdc42b64abe96aa13201f558a5e3f6087dad812 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 24 Jul 2015 21:24:02 +0300 Subject: [PATCH 155/381] net/macb: suppress compiler warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the following warnings: drivers/net/ethernet/cadence/macb.c: In function ‘macb_handle_link_change’: drivers/net/ethernet/cadence/macb.c:266: warning: comparison between signed and unsigned drivers/net/ethernet/cadence/macb.c:267: warning: comparison between signed and unsigned drivers/net/ethernet/cadence/macb.c:291: warning: comparison between signed and unsigned drivers/net/ethernet/cadence/macb.c: In function ‘gem_update_stats’: drivers/net/ethernet/cadence/macb.c:1908: warning: comparison between signed and unsigned drivers/net/ethernet/cadence/macb.c: In function ‘gem_get_ethtool_strings’: drivers/net/ethernet/cadence/macb.c:1988: warning: comparison between signed and unsigned Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 5 ++--- drivers/net/ethernet/cadence/macb.h | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 145f7d3bee5e13..7cd6adf6d54892 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -303,7 +303,6 @@ static void macb_handle_link_change(struct net_device *dev) struct macb *bp = netdev_priv(dev); struct phy_device *phydev = bp->phy_dev; unsigned long flags; - int status_change = 0; spin_lock_irqsave(&bp->lock, flags); @@ -1936,7 +1935,7 @@ static int macb_change_mtu(struct net_device *dev, int new_mtu) static void gem_update_stats(struct macb *bp) { - int i; + unsigned int i; u32 *p = &bp->hw_stats.gem.tx_octets_31_0; for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { @@ -2015,7 +2014,7 @@ static int gem_get_sset_count(struct net_device *dev, int sset) static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p) { - int i; + unsigned int i; switch (sset) { case ETH_SS_STATS: diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index 619f9482263508..f684ba088fc76f 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -816,9 +816,9 @@ struct macb { struct mii_bus *mii_bus; struct phy_device *phy_dev; - unsigned int link; - unsigned int speed; - unsigned int duplex; + int link; + int speed; + int duplex; u32 caps; unsigned int dma_burst_length; From 0fdbbecf3f4500ed1f49a4f1f7b2c295c9a3bbb8 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 24 Jul 2015 21:24:03 +0300 Subject: [PATCH 156/381] net/macb: replace macb_count_tx_descriptors() by DIV_ROUND_UP() macb_count_tx_descriptors() repeats the generic macro DIV_ROUND_UP(). The patch does a replacement. There is no functional change. Signed-off-by: Andy Shevchenko Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 7cd6adf6d54892..5cb37b007c1dca 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -1157,12 +1157,6 @@ static void macb_poll_controller(struct net_device *dev) } #endif -static inline unsigned int macb_count_tx_descriptors(struct macb *bp, - unsigned int len) -{ - return (len + bp->max_tx_length - 1) / bp->max_tx_length; -} - static unsigned int macb_tx_map(struct macb *bp, struct macb_queue *queue, struct sk_buff *skb) @@ -1313,11 +1307,11 @@ static int macb_start_xmit(struct sk_buff *skb, struct net_device *dev) * socket buffer: skb fragments of jumbo frames may need to be * splitted into many buffer descriptors. */ - count = macb_count_tx_descriptors(bp, skb_headlen(skb)); + count = DIV_ROUND_UP(skb_headlen(skb), bp->max_tx_length); nr_frags = skb_shinfo(skb)->nr_frags; for (f = 0; f < nr_frags; f++) { frag_size = skb_frag_size(&skb_shinfo(skb)->frags[f]); - count += macb_count_tx_descriptors(bp, frag_size); + count += DIV_ROUND_UP(frag_size, bp->max_tx_length); } spin_lock_irqsave(&bp->lock, flags); From c7b525573cd74c17bd0b94dc3c8de8d10a6ef6ee Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 27 Jul 2015 14:24:48 -0700 Subject: [PATCH 157/381] macb: Fix build with macro'ized readl/writel. If an architecture defines readl/writel using CPP macros, we get the following kinds of build failure: > > > drivers/net/ethernet/cadence/macb.c:164:1: error: macro "writel" > > > passed 3 arguments, but takes just 2 > macb_or_gem_writel(bp, SA1B, bottom); > ^ Rename the methods so that this doesn't happen. Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 14 +++++++------- drivers/net/ethernet/cadence/macb.h | 16 ++++++++-------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 5cb37b007c1dca..6601fec1bc72ec 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -506,7 +506,7 @@ static void macb_update_stats(struct macb *bp) WARN_ON((unsigned long)(end - p - 1) != (MACB_TPF - MACB_PFR) / 4); for(; p < end; p++, offset += 4) - *p += bp->readl(bp, offset); + *p += bp->macb_reg_readl(bp, offset); } static int macb_halt_tx(struct macb *bp) @@ -1934,14 +1934,14 @@ static void gem_update_stats(struct macb *bp) for (i = 0; i < GEM_STATS_LEN; ++i, ++p) { u32 offset = gem_statistics[i].offset; - u64 val = bp->readl(bp, offset); + u64 val = bp->macb_reg_readl(bp, offset); bp->ethtool_stats[i] += val; *p += val; if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) { /* Add GEM_OCTTXH, GEM_OCTRXH */ - val = bp->readl(bp, offset + 4); + val = bp->macb_reg_readl(bp, offset + 4); bp->ethtool_stats[i] += ((u64)val) << 32; *(++p) += val; } @@ -2864,11 +2864,11 @@ static int macb_probe(struct platform_device *pdev) bp->regs = mem; bp->native_io = native_io; if (native_io) { - bp->readl = hw_readl_native; - bp->writel = hw_writel_native; + bp->macb_reg_readl = hw_readl_native; + bp->macb_reg_writel = hw_writel_native; } else { - bp->readl = hw_readl; - bp->writel = hw_writel; + bp->macb_reg_readl = hw_readl; + bp->macb_reg_writel = hw_writel; } bp->num_queues = num_queues; bp->queue_mask = queue_mask; diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index f684ba088fc76f..6e1faea00ca829 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -429,12 +429,12 @@ | GEM_BF(name, value)) /* Register access macros */ -#define macb_readl(port, reg) (port)->readl((port), MACB_##reg) -#define macb_writel(port, reg, value) (port)->writel((port), MACB_##reg, (value)) -#define gem_readl(port, reg) (port)->readl((port), GEM_##reg) -#define gem_writel(port, reg, value) (port)->writel((port), GEM_##reg, (value)) -#define queue_readl(queue, reg) (queue)->bp->readl((queue)->bp, (queue)->reg) -#define queue_writel(queue, reg, value) (queue)->bp->writel((queue)->bp, (queue)->reg, (value)) +#define macb_readl(port, reg) (port)->macb_reg_readl((port), MACB_##reg) +#define macb_writel(port, reg, value) (port)->macb_reg_writel((port), MACB_##reg, (value)) +#define gem_readl(port, reg) (port)->macb_reg_readl((port), GEM_##reg) +#define gem_writel(port, reg, value) (port)->macb_reg_writel((port), GEM_##reg, (value)) +#define queue_readl(queue, reg) (queue)->bp->macb_reg_readl((queue)->bp, (queue)->reg) +#define queue_writel(queue, reg, value) (queue)->bp->macb_reg_writel((queue)->bp, (queue)->reg, (value)) /* Conditional GEM/MACB macros. These perform the operation to the correct * register dependent on whether the device is a GEM or a MACB. For registers @@ -782,8 +782,8 @@ struct macb { bool native_io; /* hardware IO accessors */ - u32 (*readl)(struct macb *bp, int offset); - void (*writel)(struct macb *bp, int offset, u32 value); + u32 (*macb_reg_readl)(struct macb *bp, int offset); + void (*macb_reg_writel)(struct macb *bp, int offset, u32 value); unsigned int rx_tail; unsigned int rx_prepared_head; From 735b0b9418c3614d5aa92256cdb80b2a91c6c00d Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 13:52:58 +0200 Subject: [PATCH 158/381] ARM: at91/dt: sama5d2 xplained: add pin muxing for TWIHS0 and TWIHS1 add missing pin muxing to i2c0 and i2c1 nodes Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 8b1417a33ad25e..ee39aea0c2ffb7 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -130,6 +130,8 @@ i2c0: i2c@f8028000 { dmas = <0>, <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0_default>; status = "okay"; }; @@ -150,6 +152,8 @@ i2c1: i2c@fc028000 { dmas = <0>, <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_default>; status = "okay"; at24@54 { @@ -161,6 +165,16 @@ pinctrl@fc038000 { group_defs { + i2c0_0 { + pins = , + ; + }; + + i2c1_0 { + pins = , + ; + }; + sdmmc0_0 { pins = , , @@ -198,6 +212,32 @@ }; }; + pinctrl_i2c0_default: i2c0_default { + mux { + function = "B"; + groups = "i2c0_0"; + }; + + conf { + pins = , + ; + bias-disable; + }; + }; + + pinctrl_i2c1_default: i2c1_default { + mux { + function = "A"; + groups = "i2c1_0"; + }; + + conf { + pins = , + ; + bias-disable; + }; + }; + pinctrl_sdmmc0_default: sdmmc0_default { mux { function = "A"; From a30991693d00818fd44558aa781be4b3386ff8c3 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 14:09:10 +0200 Subject: [PATCH 159/381] ARM: at91/dt: sama5d2: add nodes for Flexcoms add flx0, flx1, flx2, flx3 and flx4 nodes Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index bffc111608483e..b6ef0b87360da1 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -874,6 +874,26 @@ status = "disabled"; }; + flx0: flexcom@f8034000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xf8034000 0x200>; + clocks = <&flx0_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xf8034000 0x800>; + status = "disabled"; + }; + + flx1: flexcom@f8038000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xf8038000 0x200>; + clocks = <&flx1_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xf8038000 0x800>; + status = "disabled"; + }; + rstc@f8048000 { compatible = "atmel,sama5d3-rstc"; reg = <0xf8048000 0x10>; @@ -964,6 +984,36 @@ status = "disabled"; }; + flx2: flexcom@fc010000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xfc010000 0x200>; + clocks = <&flx2_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xfc010000 0x800>; + status = "disabled"; + }; + + flx3: flexcom@fc014000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xfc014000 0x200>; + clocks = <&flx3_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xfc014000 0x800>; + status = "disabled"; + }; + + flx4: flexcom@fc018000 { + compatible = "atmel,sama5d2-flexcom"; + reg = <0xfc018000 0x200>; + clocks = <&flx4_clk>; + #address-cells = <1>; + #size-cells = <1>; + ranges = <0x0 0xfc018000 0x800>; + status = "disabled"; + }; + aic: interrupt-controller@fc020000 { #interrupt-cells = <3>; compatible = "atmel,sama5d2-aic"; From edd2c1a9131df8b7711cc3d71d3629f821720e87 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 14:31:31 +0200 Subject: [PATCH 160/381] ARM: at91/dt: sama5d2 xplained: set function to Flexcoms 0 and 4 configure Flexcom0 to function "usart" and Flexcom4 to function "twi" Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 74 +++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index ee39aea0c2ffb7..2243b40a5677f1 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -45,6 +45,7 @@ /dts-v1/; #include "sama5d2.dtsi" #include "sama5d2-pinfunc.h" +#include / { model = "Atmel SAMA5D2 Xplained"; @@ -135,6 +136,23 @@ status = "okay"; }; + flx0: flexcom@f8034000 { + atmel,flexcom-mode = ; + status = "disabled"; /* conflict with ISC_D2 & ISC_D3 data pins */ + + uart5: serial@200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&flx0_clk>; + clock-names = "usart"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx0_default>; + atmel,fifo-size = <32>; + status = "okay"; + }; + }; + shdwc@f8048010 { atmel,shdwc-debouncer = <976>; @@ -150,6 +168,26 @@ status = "okay"; }; + flx4: flexcom@fc018000 { + atmel,flexcom-mode = ; + status = "okay"; + + i2c2: i2c@600 { + compatible = "atmel,sama5d2-i2c"; + reg = <0x600 0x200>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <0>, <0>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx4_clk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx4_default>; + atmel,fifo-size = <16>; + status = "okay"; + }; + }; + i2c1: i2c@fc028000 { dmas = <0>, <0>; pinctrl-names = "default"; @@ -165,6 +203,16 @@ pinctrl@fc038000 { group_defs { + flx0_0 { + pins = , + ; + }; + + flx4_0 { + pins = , + ; + }; + i2c0_0 { pins = , ; @@ -212,6 +260,32 @@ }; }; + pinctrl_flx0_default: flx0_default { + mux { + function = "C"; + groups = "flx0_0"; + }; + + conf { + pin = , + ; + bias-disable; + }; + }; + + pinctrl_flx4_default: flx4_default { + mux { + function = "B"; + groups = "flx4_0"; + }; + + conf { + pins = , + ; + bias-disable; + }; + }; + pinctrl_i2c0_default: i2c0_default { mux { function = "B"; From 22c781e06db32c230186545a8799c5954fbd205d Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 14:52:53 +0200 Subject: [PATCH 161/381] ARM: at91/dt: sama5d2 xplained: add pin muxing for spi0 add missing pin muxing to spi0 node Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 2243b40a5677f1..ebf79063799ebd 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -109,6 +109,8 @@ apb { spi0: spi@f8000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0_default>; status = "okay"; m25p80@0 { @@ -249,6 +251,13 @@ ; }; + spi0_0 { + pins = , + , + , + ; + }; + uart1_0 { pins = , ; @@ -362,6 +371,21 @@ }; }; + pinctrl_spi0_default: spi0_default { + mux { + function = "A"; + groups = "spi0_0"; + }; + + conf { + pins = , + , + , + ; + bias-disable; + }; + }; + pinctrl_uart1_default: uart1_default { mux { function = "A"; From 8fb8c712893205385770d8a303d2ce378b3ee815 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 15:01:02 +0200 Subject: [PATCH 162/381] ARM: at91/dt: sama5d2: add nodes for QSPI0 and QPSI1 add qspi0 and qpsi1 DT nodes. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index b6ef0b87360da1..8c9591b7208f50 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -753,6 +753,28 @@ }; }; + qspi0: qspi@f0020000 { + compatible = "atmel,sama5d2-qspi"; + reg = <0xf0020000 0x100>, + <0xd0000000 0x08000000>; + interrupts = <52 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&qspi0_clk>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + + qspi1: qspi@f0024000 { + compatible = "atmel,sama5d2-qspi"; + reg = <0xf0024000 0x100>, + <0xd8000000 0x08000000>; + interrupts = <53 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&qspi1_clk>; + #address-cells = <1>; + #size-cells = <0>; + status = "disabled"; + }; + sha@f0028000 { compatible = "atmel,at91sam9g46-sha"; reg = <0xf0028000 0x100>; From 225c93d64d3bd3dd677e513572226585c186ffbc Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 15:15:34 +0200 Subject: [PATCH 163/381] ARM: at91/dt: sama5d2 xplained: add pin muxing for QSPI0 + Micron n25q128a13 Add pin muxing for qspi0 DT node. Also add one child node for Micron n25q128a13 QSPI memory. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 40 ++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index ebf79063799ebd..78113e1f3658f0 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -104,10 +104,23 @@ bus-width = <4>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc1_default>; - status = "okay"; + status = "okay"; /* conflict with qspi0 */ }; apb { + qspi0: qspi@f0020000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi0_default>; + /*status = "okay";*/ /* conflict with sdmmc1 */ + + m25p80@0 { + compatible = "micron,n25q128a13"; + reg = <0>; + spi-max-frequency = <83000000>; + m25p,num-dummy-cycles = <6>; + }; + }; + spi0: spi@f8000000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_spi0_default>; @@ -225,6 +238,15 @@ ; }; + qspi0_0 { + pins = , + , + , + , + , + ; + }; + sdmmc0_0 { pins = , , @@ -321,6 +343,22 @@ }; }; + pinctrl_qspi0_default: qspi0_default { + mux { + function = "F"; + groups = "qspi0_0"; + }; + + conf { + pins = , + , + , + , + , + ; + }; + }; + pinctrl_sdmmc0_default: sdmmc0_default { mux { function = "A"; From c612755142b4f0415dc2484672e1425755a300d9 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 15:25:23 +0200 Subject: [PATCH 164/381] ARM: at91/dt: sama5d2 xplained: add pin muxing for macb0 add missing pin muxing for macb0 DT node. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 78113e1f3658f0..d6bdfa4ccea4a6 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -134,6 +134,8 @@ }; macb0: ethernet@f8008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_macb0_rmii>; phy-mode = "rmii"; status = "okay"; }; @@ -238,6 +240,19 @@ ; }; + macb0_0 { + pins = , + , + , + , + , + , + , + , + , + ; + }; + qspi0_0 { pins = , , @@ -343,6 +358,27 @@ }; }; + pinctrl_macb0_rmii: macb0_rmii { + mux { + function = "F"; + groups = "macb0_0"; + }; + + conf { + pins = , + , + , + , + , + , + , + , + , + ; + bias-disable; + }; + }; + pinctrl_qspi0_default: qspi0_default { mux { function = "F"; From dcc4b8a07b7d510c6920b1a0a1cffeecb1ed1d58 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Mon, 27 Jul 2015 17:01:36 +0800 Subject: [PATCH 165/381] crypto: atmel-aes: add new version Add new version of atmel-aes available with SAMA5D2 devices. Signed-off-by: Leilei Zhao --- drivers/crypto/atmel-aes.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 0f9a9dc06a830f..3b149ede7e0b6c 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -74,6 +74,7 @@ struct atmel_aes_caps { bool has_dualbuff; bool has_cfb64; + bool has_aead; u32 max_burst_size; }; @@ -1250,10 +1251,17 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) { dd->caps.has_dualbuff = 0; dd->caps.has_cfb64 = 0; + dd->caps.has_aead = 0; dd->caps.max_burst_size = 1; /* keep only major version number */ switch (dd->hw_version & 0xff0) { + case 0x500: + dd->caps.has_dualbuff = 1; + dd->caps.has_cfb64 = 1; + dd->caps.has_aead = 1; + dd->caps.max_burst_size = 4; + break; case 0x200: dd->caps.has_dualbuff = 1; dd->caps.has_cfb64 = 1; From 096dd0979b2c081b58589b19d527ab8f8840e447 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Mon, 27 Jul 2015 17:02:33 +0800 Subject: [PATCH 166/381] crypto: atmel-sha: add new version Add new version of atmel-sha available with SAMA5D2 devices. Signed-off-by: Leilei Zhao --- drivers/crypto/atmel-sha.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 5b35433c5399b1..4380a6581fd42b 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -73,6 +73,7 @@ struct atmel_sha_caps { bool has_dualbuff; bool has_sha224; bool has_sha_384_512; + bool has_hmac; }; struct atmel_sha_dev; @@ -1269,9 +1270,17 @@ static void atmel_sha_get_cap(struct atmel_sha_dev *dd) dd->caps.has_dualbuff = 0; dd->caps.has_sha224 = 0; dd->caps.has_sha_384_512 = 0; + dd->caps.has_hmac = 0; /* keep only major version number */ switch (dd->hw_version & 0xff0) { + case 0x510: + dd->caps.has_dma = 1; + dd->caps.has_dualbuff = 1; + dd->caps.has_sha224 = 1; + dd->caps.has_sha_384_512 = 1; + dd->caps.has_hmac = 1; + break; case 0x420: dd->caps.has_dma = 1; dd->caps.has_dualbuff = 1; From 21e0b42f2ef9fac14b4da1426be44646e43cb4d1 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Tue, 28 Jul 2015 11:16:50 +0800 Subject: [PATCH 167/381] crypto: atmel-sha: add new regs for A5D2 Add new registers, interrupt flags, mask and offset for A5D2 boards. Signed-off-by: Leilei Zhao --- drivers/crypto/atmel-sha-regs.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/crypto/atmel-sha-regs.h b/drivers/crypto/atmel-sha-regs.h index 83b2d74256666e..ec4ec495ea47dd 100644 --- a/drivers/crypto/atmel-sha-regs.h +++ b/drivers/crypto/atmel-sha-regs.h @@ -8,6 +8,8 @@ #define SHA_CR_START (1 << 0) #define SHA_CR_FIRST (1 << 4) #define SHA_CR_SWRST (1 << 8) +#define SHA_CR_WUIHV (1 << 12) +#define SHA_CR_WUIEHV (1 << 13) #define SHA_MR 0x04 #define SHA_MR_MODE_MASK (0x3 << 0) @@ -15,11 +17,23 @@ #define SHA_MR_MODE_AUTO 0x1 #define SHA_MR_MODE_PDC 0x2 #define SHA_MR_PROCDLY (1 << 4) +#define SHA_MR_UIHV (1 << 5) +#define SHA_MR_UIHV2 (1 << 6) +#define SHA_MR_CHECK_MASK (3 << 24) +#define SHA_MR_CHECK_EHV (1 << 24) +#define SHA_MR_CHECK_MESSAGE (2 << 24) +#define SHA_MR_CHKCNT_OFFSET (28) +#define SHA_MR_CHKCNT_MASK (0xf << 28) #define SHA_MR_ALGO_SHA1 (0 << 8) #define SHA_MR_ALGO_SHA256 (1 << 8) #define SHA_MR_ALGO_SHA384 (2 << 8) #define SHA_MR_ALGO_SHA512 (3 << 8) #define SHA_MR_ALGO_SHA224 (4 << 8) +#define SHA_MR_ALGO_HMAC_SHA1 (8 << 8) +#define SHA_MR_ALGO_HMAC_SHA256 (9 << 8) +#define SHA_MR_ALGO_HMAC_SHA384 (10 << 8) +#define SHA_MR_ALGO_HMAC_SHA512 (11 << 8) +#define SHA_MR_ALGO_HMAC_SHA224 (12 << 8) #define SHA_MR_DUALBUFF (1 << 16) #define SHA_IER 0x10 @@ -30,11 +44,18 @@ #define SHA_INT_ENDTX (1 << 1) #define SHA_INT_TXBUFE (1 << 2) #define SHA_INT_URAD (1 << 8) +#define SHA_INT_CHECKF (1 << 16) #define SHA_ISR_URAT_MASK (0x7 << 12) #define SHA_ISR_URAT_IDR (0x0 << 12) #define SHA_ISR_URAT_ODR (0x1 << 12) #define SHA_ISR_URAT_MR (0x2 << 12) #define SHA_ISR_URAT_WO (0x5 << 12) +#define SHA_ISR_CHKST_OFFSET (20) +#define SHA_ISR_CHKST_MASK (0xf << 20) +#define SHA_ISR_CHKST (0x5 << 20) + +#define SHA_MSGSIZE 0x20 +#define SHA_BYTESCNT 0x30 #define SHA_HW_VERSION 0xFC From c536a8b25e2591aa3b65705a07bedcc8c3650819 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Thu, 30 Jul 2015 16:39:44 +0800 Subject: [PATCH 168/381] crypto: atmel-aes: add new regs for A5D2 Add new registers for IPSec using on A5D2 boards. Signed-off-by: Leilei Zhao --- drivers/crypto/atmel-aes-regs.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/crypto/atmel-aes-regs.h b/drivers/crypto/atmel-aes-regs.h index 2786bb1a5aa001..a4becb57eca68c 100644 --- a/drivers/crypto/atmel-aes-regs.h +++ b/drivers/crypto/atmel-aes-regs.h @@ -57,6 +57,12 @@ #define AES_ODATAR(x) (0x50 + ((x) * 0x04)) #define AES_IVR(x) (0x60 + ((x) * 0x04)) +#define AES_EMR 0xB0 +#define AES_EMR_APEN (1 << 0) +#define AES_EMR_APM (1 << 1) +#define AES_EMR_PLIPEN (1 << 4) +#define AES_EMR_PLIPD (1 << 5) + #define AES_HW_VERSION 0xFC #endif /* __ATMEL_AES_REGS_H__ */ From 29df4906380a36b1b02ace9e4dcf1a2254447870 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Thu, 30 Jul 2015 16:42:16 +0800 Subject: [PATCH 169/381] crypto: atmel-sha: add exported functions of HMAC The AEAD and HMAC algorithms are implemented in A5D2 board. So here adding the exported functions of HMAC for AEAD using in Atmel AES driver. Signed-off-by: Leilei Zhao --- drivers/crypto/atmel-sha.c | 284 +++++++++++++++++++++++++++++++++++++ drivers/crypto/atmel-sha.h | 14 ++ 2 files changed, 298 insertions(+) create mode 100644 drivers/crypto/atmel-sha.h diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c index 4380a6581fd42b..72bf7fc8bd7635 100644 --- a/drivers/crypto/atmel-sha.c +++ b/drivers/crypto/atmel-sha.c @@ -41,6 +41,7 @@ #include #include #include "atmel-sha-regs.h" +#include "atmel-sha.h" /* SHA flags */ #define SHA_FLAGS_BUSY BIT(0) @@ -68,6 +69,8 @@ #define ATMEL_SHA_DMA_THRESHOLD 56 +#define SIZE_IN_WORDS(x) ((x) >> 2) + struct atmel_sha_caps { bool has_dma; bool has_dualbuff; @@ -986,6 +989,287 @@ static int atmel_sha_cra_init(struct crypto_tfm *tfm) return 0; } +static struct atmel_sha_dev *atmel_hmac_find_dev(void) +{ + struct atmel_sha_dev *tmp, *dd = NULL; + + spin_lock_bh(&atmel_sha.lock); + + list_for_each_entry(tmp, &atmel_sha.dev_list, list) { + dd = tmp; + break; + } + spin_unlock_bh(&atmel_sha.lock); + + return dd; +} + +/* + * check and wait the flag set in isr until timeout + */ +static int atmel_hmac_check_isr(struct atmel_sha_dev *dd, int flag, u32 *reg) +{ + int timeout = 0x1000; + *reg = 0; + + while ((!(*reg & flag)) && (--timeout)) { + cpu_relax(); + *reg = atmel_sha_read(dd, SHA_ISR); + } + if (unlikely(!timeout)) { + dev_err(dd->dev, "timeout while reading sha status register\n"); + return -EINVAL; + } + + return 0; +} + +static inline void atmel_hmac_write_input(struct atmel_sha_dev *dd, + u32 *data, size_t size) +{ + int i; + + for (i = 0; i < SIZE_IN_WORDS(size); i++) + atmel_sha_write(dd, SHA_REG_DIN(i), data[i]); +} + +/* + * When IDATAR0 mode in SMOD is set, we can only write IDATAR0 + */ +static inline void atmel_hmac_write_input0(struct atmel_sha_dev *dd, + u32 *data, size_t size) +{ + int i; + + for (i = 0; i < SIZE_IN_WORDS(size); i++) + atmel_sha_write(dd, SHA_REG_DIN(0), data[i]); +} + +static inline void atmel_hmac_read_output(struct atmel_sha_dev *dd, + u32 *data, size_t size) +{ + int i; + + for (i = 0; i < SIZE_IN_WORDS(size); i++) + data[i] = atmel_sha_read(dd, SHA_REG_DIGEST(i)); +} + +static int atmel_hmac_get_uiv(struct atmel_sha_dev *dd, u32 *input, u32 *uiv, + u32 valmr, u32 valcr, + size_t block_size, size_t digest_size) +{ + int err; + u32 reg = 0; + + atmel_sha_write(dd, SHA_CR, valcr); + atmel_sha_write(dd, SHA_MR, valmr); + + atmel_sha_write(dd, SHA_MSGSIZE, 0); + atmel_sha_write(dd, SHA_BYTESCNT, 0); + + atmel_hmac_write_input(dd, input, block_size); + err = atmel_hmac_check_isr(dd, SHA_INT_DATARDY, ®); + if (err) + return err; + atmel_hmac_read_output(dd, uiv, digest_size); + + return err; +} + +static void atmel_hmac_set_uiv(struct atmel_sha_dev *dd, u32 *uiv, + u32 valmr, u32 valcr, size_t uiv_size) +{ + atmel_sha_write(dd, SHA_CR, valcr); + atmel_sha_write(dd, SHA_MR, valmr); + + atmel_hmac_write_input(dd, uiv, uiv_size); + valcr = 0; + atmel_sha_write(dd, SHA_CR, valcr); +} + +int atmel_hmac_write_key(const u8 *key, size_t keylen, unsigned long hmac_type) +{ + struct atmel_sha_dev *dd; + unsigned long flags; + u32 valcr = 0, valmr = 0; + int err; + + size_t i, block_size, digest_size; + char ipad[SHA512_BLOCK_SIZE]; + char opad[SHA512_BLOCK_SIZE]; + u8 ipad_digest[SHA512_DIGEST_SIZE]; + u8 opad_digest[SHA512_DIGEST_SIZE]; + + switch (hmac_type) { + case SHA_MR_ALGO_HMAC_SHA1: + valmr |= SHA_MR_ALGO_SHA1; + block_size = SHA1_BLOCK_SIZE; + digest_size = SHA1_DIGEST_SIZE; + break; + case SHA_MR_ALGO_HMAC_SHA224: + valmr |= SHA_MR_ALGO_SHA224; + block_size = SHA224_BLOCK_SIZE; + digest_size = SHA224_DIGEST_SIZE; + break; + case SHA_MR_ALGO_HMAC_SHA256: + valmr |= SHA_MR_ALGO_SHA256; + block_size = SHA256_BLOCK_SIZE; + digest_size = SHA256_DIGEST_SIZE; + break; + case SHA_MR_ALGO_HMAC_SHA384: + valmr |= SHA_MR_ALGO_SHA384; + block_size = SHA384_BLOCK_SIZE; + digest_size = SHA384_DIGEST_SIZE; + break; + case SHA_MR_ALGO_HMAC_SHA512: + valmr |= SHA_MR_ALGO_SHA512; + block_size = SHA512_BLOCK_SIZE; + digest_size = SHA512_DIGEST_SIZE; + break; + default: + return -EINVAL; + } + + dd = atmel_hmac_find_dev(); + if (!dd) + return -ENODEV; + + for (i = 0; i < keylen; ++i) { + ipad[i] = key[i] ^ 0x36; + opad[i] = key[i] ^ 0x5c; + } + for (i = keylen; i < SHA1_BLOCK_SIZE; ++i) { + ipad[i] = 0x36; + opad[i] = 0x5c; + } + + spin_lock_irqsave(&dd->lock, flags); + dd->flags |= SHA_FLAGS_BUSY; + spin_unlock_irqrestore(&dd->lock, flags); + + atmel_sha_hw_init(dd); + + /* set ipad and get user initial hash value 1 */ + valmr |= SHA_MR_MODE_AUTO; + valcr = SHA_CR_FIRST; + + err = atmel_hmac_get_uiv(dd, (u32 *)ipad, (u32 *)ipad_digest, + valmr, valcr, block_size, digest_size); + if (err) + return err; + + /* set opad and get user initial hash value 2 */ + err = atmel_hmac_get_uiv(dd, (u32 *)opad, (u32 *)opad_digest, + valmr, valcr, block_size, digest_size); + if (err) + return err; + + /* write user initial hash value 1 */ + valmr = 0; + valcr = SHA_CR_WUIHV; + atmel_hmac_set_uiv(dd, (u32 *)ipad_digest, valmr, valcr, digest_size); + + /* write user initial hash value 2 */ + valcr = SHA_CR_WUIEHV; + atmel_hmac_set_uiv(dd, (u32 *)opad_digest, valmr, valcr, digest_size); + + return 0; +} +EXPORT_SYMBOL(atmel_hmac_write_key); + +int atmel_hmac_write_esp(const u8 *esp_header, size_t head_len, + const u8 *iv, size_t iv_len, + size_t payload_len, u32 checkcnt, + unsigned long hmac_type) +{ + size_t msg_size; + struct atmel_sha_dev *dd = NULL; + u32 valcr = 0, valmr = 0; + + dd = atmel_hmac_find_dev(); + if (dd == NULL) + return -ENODEV; + + msg_size = head_len + iv_len + payload_len; + + valmr |= SHA_MR_MODE_PDC; + valmr |= SHA_MR_DUALBUFF; + valmr |= hmac_type; + valmr |= SHA_MR_UIHV; + valmr |= SHA_MR_UIHV2; + + if (checkcnt > 0) { + valmr |= SHA_MR_CHECK_MESSAGE; + valmr |= (SIZE_IN_WORDS(checkcnt) << SHA_MR_CHKCNT_OFFSET); + } + + valcr = SHA_CR_FIRST; + + atmel_sha_write(dd, SHA_MR, valmr); + + atmel_sha_write(dd, SHA_MSGSIZE, msg_size); + atmel_sha_write(dd, SHA_BYTESCNT, msg_size); + + atmel_sha_write(dd, SHA_CR, valcr); + + atmel_hmac_write_input0(dd, (u32 *)esp_header, head_len); + atmel_hmac_write_input0(dd, (u32 *)iv, iv_len); + + return 0; +} +EXPORT_SYMBOL(atmel_hmac_write_esp); + +int atmel_hmac_check_icv(u32 *hash, u32 cnt) +{ + struct atmel_sha_dev *dd; + unsigned long flags; + u32 reg = 0; + int rc = 0; + + dd = atmel_hmac_find_dev(); + if (dd == NULL) { + pr_err("can't find sha_dev\n"); + return -ENODEV; + } + + atmel_hmac_write_input0(dd, hash, cnt); + atmel_hmac_check_isr(dd, SHA_INT_CHECKF, ®); + + if (!(reg & SHA_ISR_CHKST)) + rc = -EINVAL; + + spin_lock_irqsave(&dd->lock, flags); + dd->flags &= ~SHA_FLAGS_BUSY; + clk_disable_unprepare(dd->iclk); + spin_unlock_irqrestore(&dd->lock, flags); + + return rc; +} +EXPORT_SYMBOL(atmel_hmac_check_icv); + +int atmel_hmac_read_icv(u32 *hash, u32 cnt) +{ + struct atmel_sha_dev *dd; + unsigned long flags; + int rc; + u32 reg = 0; + + dd = atmel_hmac_find_dev(); + if (dd == NULL) + return -EINVAL; + + rc = atmel_hmac_check_isr(dd, SHA_INT_DATARDY, ®); + atmel_hmac_read_output(dd, hash, cnt); + + spin_lock_irqsave(&dd->lock, flags); + dd->flags &= ~SHA_FLAGS_BUSY; + clk_disable_unprepare(dd->iclk); + spin_unlock_irqrestore(&dd->lock, flags); + + return rc; +} +EXPORT_SYMBOL(atmel_hmac_read_icv); + static struct ahash_alg sha_1_256_algs[] = { { .init = atmel_sha_init, diff --git a/drivers/crypto/atmel-sha.h b/drivers/crypto/atmel-sha.h new file mode 100644 index 00000000000000..5fd4a94c3bf88f --- /dev/null +++ b/drivers/crypto/atmel-sha.h @@ -0,0 +1,14 @@ +#ifndef __ATMEL_SHA_H__ +#define __ATMEL_SHA_H__ + +int atmel_hmac_write_key(const u8 *key, size_t keylen, + unsigned long hmac_type); + +int atmel_hmac_write_esp(const u8 *esp_header, size_t head_len, + const u8 *iv, size_t iv_len, + size_t payload_len, u32 checkcnt, + unsigned long hmac_type); +int atmel_hmac_check_icv(u32 *hash, u32 cnt); +int atmel_hmac_read_icv(u32 *hash, u32 cnt); + +#endif /* __ATMEL_SHA_H__ */ From 8d2e092a5d3c110fec8f4ddc7fcbffaae0d6c1e5 Mon Sep 17 00:00:00 2001 From: Leilei Zhao Date: Thu, 30 Jul 2015 16:59:35 +0800 Subject: [PATCH 170/381] crypto: atmel-aes: add AEAD support for IPSec Add new AEAD algorithms to support IPSec in A5D2 board. Signed-off-by: Leilei Zhao --- drivers/crypto/Kconfig | 1 + drivers/crypto/atmel-aes.c | 622 ++++++++++++++++++++++++++++++++++++- 2 files changed, 621 insertions(+), 2 deletions(-) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 033c0c86f6ec05..11b4c55ab934e8 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -347,6 +347,7 @@ config CRYPTO_DEV_ATMEL_AES select CRYPTO_ECB select CRYPTO_AES select CRYPTO_ALGAPI + select CRYPTO_AUTHENC select CRYPTO_BLKCIPHER select AT_HDMAC help diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 3b149ede7e0b6c..ad0544017e5dc0 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -38,10 +38,15 @@ #include #include #include +#include +#include +#include #include #include #include #include "atmel-aes-regs.h" +#include "atmel-sha-regs.h" +#include "atmel-sha.h" #define CFB8_BLOCK_SIZE 1 #define CFB16_BLOCK_SIZE 2 @@ -65,11 +70,15 @@ #define AES_FLAGS_DMA BIT(17) #define AES_FLAGS_BUSY BIT(18) #define AES_FLAGS_FAST BIT(19) +#define AES_FLAGS_PLIP BIT(20) +#define AES_FLAGS_GIV BIT(21) #define ATMEL_AES_QUEUE_LENGTH 50 #define ATMEL_AES_DMA_THRESHOLD 16 +#define ATMEL_MAX_KEY_SIZE 96 +#define ATMEL_MAX_IV_LENGTH 16 struct atmel_aes_caps { bool has_dualbuff; @@ -87,10 +96,22 @@ struct atmel_aes_ctx { u32 key[AES_KEYSIZE_256 / sizeof(u32)]; u16 block_size; + + u8 enckey[AES_KEYSIZE_256]; + u8 authkey[SHA512_BLOCK_SIZE]; + u8 iv[ATMEL_MAX_IV_LENGTH]; + size_t aead_keylen; + size_t enckeylen; + size_t authkeylen; + size_t authsize; + size_t cryptlen; + size_t ivsize; + u64 seq; }; struct atmel_aes_reqctx { unsigned long mode; + unsigned long hmac_type; }; struct atmel_aes_dma { @@ -113,13 +134,18 @@ struct atmel_aes_dev { spinlock_t lock; struct crypto_queue queue; + struct crypto_queue aead_queue; + atomic_t aead_configuring; struct tasklet_struct done_task; struct tasklet_struct queue_task; + struct tasklet_struct aead_task; struct ablkcipher_request *req; size_t total; + struct aead_request *aead_req; + struct scatterlist *in_sg; unsigned int nb_in_sg; size_t in_offset; @@ -300,12 +326,60 @@ static void atmel_aes_finish_req(struct atmel_aes_dev *dd, int err) req->base.complete(&req->base, err); } +static void atmel_aead_finish_req(struct atmel_aes_dev *dd) +{ + struct atmel_aes_ctx *ctx = dd->ctx; + struct aead_request *areq = dd->aead_req; + char hash[SHA512_DIGEST_SIZE]; + int err = 0; + + dma_unmap_sg(dd->dev, areq->dst, 1, DMA_FROM_DEVICE); + dma_unmap_sg(dd->dev, areq->src, 1, DMA_TO_DEVICE); + + if (dd->flags & AES_FLAGS_ENCRYPT) { + dma_sync_single_for_cpu(dd->dev, + sg_dma_address(areq->dst), + ctx->cryptlen, + DMA_FROM_DEVICE); + + err = atmel_hmac_read_icv((u32 *)hash, ctx->authsize); + if (sg_pcopy_from_buffer(areq->dst, 1, + hash, ctx->authsize, ctx->cryptlen)) { + + err = 0; + } else { + err = -EINVAL; + } + } else { + dma_sync_single_for_cpu(dd->dev, + sg_dma_address(areq->src), + ctx->cryptlen - ctx->authsize, + DMA_TO_DEVICE); + sg_pcopy_to_buffer(areq->src, 1, + dd->buf_in, ctx->authsize, + ctx->cryptlen - ctx->authsize); + err = atmel_hmac_check_icv(dd->buf_in, ctx->authsize); + if (err != 0) + err = -EBADMSG; + } + + aead_request_complete(dd->aead_req, err); + clk_disable_unprepare(dd->iclk); + dd->flags &= ~(AES_FLAGS_BUSY | AES_FLAGS_PLIP | AES_FLAGS_DMA); + + tasklet_schedule(&dd->aead_task); +} + static void atmel_aes_dma_callback(void *data) { struct atmel_aes_dev *dd = data; /* dma_lch_out - completed */ - tasklet_schedule(&dd->done_task); + if (dd->flags & AES_FLAGS_PLIP) { + atmel_aead_finish_req(dd); + } else { + tasklet_schedule(&dd->done_task); + } } static int atmel_aes_crypt_dma(struct atmel_aes_dev *dd, @@ -494,6 +568,7 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd) { int err; u32 valcr = 0, valmr = 0; + u32 valemr = AES_EMR_PLIPEN; err = atmel_aes_hw_init(dd); @@ -532,8 +607,11 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd) if (dd->flags & AES_FLAGS_ENCRYPT) valmr |= AES_MR_CYPHER_ENC; + else if (dd->flags & AES_FLAGS_PLIP) + valemr |= AES_EMR_PLIPD; - if (dd->total > ATMEL_AES_DMA_THRESHOLD) { + if ((dd->total > ATMEL_AES_DMA_THRESHOLD) || + (dd->flags & AES_FLAGS_PLIP)) { valmr |= AES_MR_SMOD_IDATAR0; if (dd->caps.has_dualbuff) valmr |= AES_MR_DUALBUFF; @@ -544,6 +622,23 @@ static int atmel_aes_write_ctrl(struct atmel_aes_dev *dd) atmel_aes_write(dd, AES_CR, valcr); atmel_aes_write(dd, AES_MR, valmr); + if (dd->flags & AES_FLAGS_PLIP) { + atmel_aes_write(dd, AES_EMR, valemr); + + atmel_aes_write_n(dd, AES_KEYWR(0), (u32 *)dd->ctx->enckey, + dd->ctx->enckeylen >> 2); + + if (((dd->flags & AES_FLAGS_CBC) || + (dd->flags & AES_FLAGS_CFB) || + (dd->flags & AES_FLAGS_OFB) || + (dd->flags & AES_FLAGS_CTR)) && + dd->ctx->iv) { + atmel_aes_write_n(dd, AES_IVR(0), + (u32 *)dd->ctx->iv, dd->ctx->ivsize >> 2); + } + return 0; + } + atmel_aes_write_n(dd, AES_KEYWR(0), dd->ctx->key, dd->ctx->keylen >> 2); @@ -953,6 +1048,383 @@ static void atmel_aes_cra_exit(struct crypto_tfm *tfm) { } +static int atmel_aead_cra_init(struct crypto_tfm *tfm) +{ + struct atmel_aes_ctx *ctx = crypto_tfm_ctx(tfm); + + tfm->crt_aead.reqsize = sizeof(struct atmel_aes_reqctx); + + /* random first IV */ + get_random_bytes(ctx->iv, ATMEL_MAX_IV_LENGTH); + + return 0; +} + +static void atmel_aead_cra_exit(struct crypto_tfm *tfm) +{ +} + +static int atmel_aead_setauthsize(struct crypto_aead *authenc, + unsigned int authsize) +{ + struct atmel_aes_ctx *ctx = crypto_aead_ctx(authenc); + + ctx->authsize = authsize; + + return 0; +} + +static int atmel_aead_setkey(struct crypto_aead *authenc, + const u8 *key, unsigned int keylen) +{ + struct atmel_aes_ctx *ctx = crypto_aead_ctx(authenc); + struct crypto_authenc_keys keys; + + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) + goto badkey; + + if (keys.authkeylen + keys.enckeylen > ATMEL_MAX_KEY_SIZE) + goto badkey; + + if (keys.authkeylen > SHA512_BLOCK_SIZE) + goto badkey; + + if (keys.enckeylen > AES_KEYSIZE_256) + goto badkey; + + memcpy(ctx->authkey, keys.authkey, keys.authkeylen); + memcpy(ctx->enckey, keys.enckey, keys.enckeylen); + + ctx->aead_keylen = keys.authkeylen + keys.enckeylen; + ctx->enckeylen = keys.enckeylen; + ctx->keylen = ctx->enckeylen; + ctx->authkeylen = keys.authkeylen; + + return 0; + +badkey: + crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +static inline struct aead_request *aead_request_cast( + struct crypto_async_request *req) +{ + return container_of(req, struct aead_request, base); +} + +static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained) +{ + struct scatterlist *sg = sg_list; + int sg_nents = 0; + + *chained = false; + while (nbytes > 0) { + sg_nents++; + nbytes -= sg->length; + if (!sg_is_last(sg) && (sg + 1)->length == 0) + *chained = true; + sg = sg_next(sg); + } + + return sg_nents; +} + +static int atmel_aead_perform(struct atmel_aes_dev *dd) +{ + struct aead_request *areq = dd->aead_req; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct atmel_aes_ctx *ctx = crypto_aead_ctx(aead); + struct atmel_aes_reqctx *rctx = aead_request_ctx(areq); + + int err; + size_t cryptlen = areq->cryptlen; + size_t authsize = ctx->authsize; + size_t ivsize = crypto_aead_ivsize(aead); + + int assoc_nents, src_nents, dst_nents = 0; + bool assoc_chained = false, src_chained = false, dst_chained = false; + + void *hmac_data = sg_virt(areq->assoc); + + dma_addr_t addr_in, addr_out; + + ctx->cryptlen = cryptlen; + ctx->ivsize = ivsize; + + if (!(rctx->mode & AES_FLAGS_GIV)) + memcpy(ctx->iv, areq->iv, ivsize); + + dd->flags = (dd->flags & ~AES_FLAGS_MODE_MASK) | rctx->mode; + + err = atmel_aes_write_ctrl(dd); + if (err) + return err; + + assoc_nents = sg_count(areq->assoc, areq->assoclen, &assoc_chained); + src_nents = sg_count(areq->src, areq->cryptlen, &src_chained); + + if (unlikely(areq->dst != areq->src)) { + dst_nents = sg_count(areq->dst, areq->cryptlen, &dst_chained); + dev_err(dd->dev, "aead src != dst, dst_nents %d\n", dst_nents); + } + + err = atmel_hmac_write_key(ctx->authkey, ctx->authkeylen, + rctx->hmac_type); + if (err) { + dev_err(dd->dev, "write hmac key error\n"); + return -EINVAL; + } + + if (rctx->mode & AES_FLAGS_ENCRYPT) + err = atmel_hmac_write_esp(hmac_data, areq->assoclen, + areq->iv, ivsize, cryptlen, 0, + rctx->hmac_type); + else + err = atmel_hmac_write_esp(hmac_data, areq->assoclen, + areq->iv, ivsize, + cryptlen - authsize, ctx->authsize, + rctx->hmac_type); + if (err) { + dev_err(dd->dev, "write esp header error\n"); + return -EINVAL; + } + + err = dma_map_sg(dd->dev, areq->src, 1, DMA_TO_DEVICE); + if (!err) { + dev_err(dd->dev, "dma_map_sg() error\n"); + return -EINVAL; + } + + err = dma_map_sg(dd->dev, areq->dst, 1, + DMA_FROM_DEVICE); + if (!err) { + dev_err(dd->dev, "dma_map_sg() error\n"); + dma_unmap_sg(dd->dev, areq->src, 1, + DMA_TO_DEVICE); + return -EINVAL; + } + + addr_in = sg_dma_address(areq->src); + addr_out = sg_dma_address(areq->dst); + + if (rctx->mode & AES_FLAGS_ENCRYPT) + atmel_aes_crypt_dma(dd, addr_in, addr_out, cryptlen); + else + atmel_aes_crypt_dma(dd, addr_in, addr_out, cryptlen - authsize); + + return -EINPROGRESS; +} + +static void atmel_aead_queue_task(unsigned long data) +{ + struct atmel_aes_dev *dd = (struct atmel_aes_dev *) data; + + struct crypto_async_request *async_req, *backlog; + struct crypto_aead *aead; + struct aead_request *req; + struct atmel_aes_ctx *ctx; + + int rc; + unsigned long flags; + + spin_lock_irqsave(&dd->lock, flags); + + if (dd->flags & AES_FLAGS_BUSY) { + spin_unlock_irqrestore(&dd->lock, flags); + return; + } + + if (atomic_read(&dd->aead_configuring)) { + spin_unlock_irqrestore(&dd->lock, flags); + return; + } + + atomic_inc(&dd->aead_configuring); + backlog = crypto_get_backlog(&dd->queue); + async_req = crypto_dequeue_request(&dd->aead_queue); + if (async_req) + dd->flags |= AES_FLAGS_BUSY; + + atomic_dec(&dd->aead_configuring); + spin_unlock_irqrestore(&dd->lock, flags); + + if (!async_req) + return; + + if (backlog) + backlog->complete(backlog, -EINPROGRESS); + + req = aead_request_cast(async_req); + aead = crypto_aead_reqtfm(req); + ctx = crypto_aead_ctx(aead); + + dd->flags |= AES_FLAGS_PLIP; + dd->ctx = ctx; + ctx->dd = dd; + dd->aead_req = req; + + rc = atmel_aead_perform(dd); + if (rc != -EINPROGRESS) { + dev_err(dd->dev, "perform aead error %d", rc); + aead_request_complete(dd->aead_req, rc); + clk_disable_unprepare(dd->iclk); + dd->flags &= ~(AES_FLAGS_BUSY | AES_FLAGS_PLIP); + + tasklet_schedule(&dd->aead_task); + } +} + +static int atmel_aead_enqueue(struct atmel_aes_dev *dd, + struct aead_request *req) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&dd->lock, flags); + if (atomic_read(&dd->aead_configuring)) { + spin_unlock_irqrestore(&dd->lock, flags); + return -EAGAIN; + } + + atomic_inc(&dd->aead_configuring); + ret = crypto_enqueue_request(&dd->aead_queue, &req->base); + if (ret == -EBUSY) + dev_err(dd->dev, "atmel aead queue is full"); + + atomic_dec(&dd->aead_configuring); + spin_unlock_irqrestore(&dd->lock, flags); + + tasklet_schedule(&dd->aead_task); + + return ret; +} + +static int atmel_aead_crypt(struct aead_request *req, + unsigned long aes_mode, + unsigned long hmac_type) +{ + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct atmel_aes_ctx *ctx = crypto_aead_ctx(aead); + struct atmel_aes_dev *dd; + struct atmel_aes_reqctx *rctx = aead_request_ctx(req); + + ctx->block_size = AES_BLOCK_SIZE; + dd = atmel_aes_find_dev(ctx); + if (!dd) + return -ENODEV; + + rctx->mode = aes_mode; + rctx->hmac_type = hmac_type; + + return atmel_aead_enqueue(dd, req); +} + +static int atmel_aead_givcrypt(struct aead_givcrypt_request *req, + unsigned long aes_mode, + unsigned long hmac_type) +{ + struct aead_request *areq = &req->areq; + struct crypto_aead *aead = crypto_aead_reqtfm(areq); + struct atmel_aes_ctx *ctx = crypto_aead_ctx(aead); + + memcpy(req->giv, ctx->iv, crypto_aead_ivsize(aead)); + memcpy(req->areq.iv, ctx->iv, crypto_aead_ivsize(aead)); + ctx->seq = req->seq; + + return atmel_aead_crypt(areq, aes_mode, hmac_type); +} + +static int atmel_aead_sha1_cbc_encrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA1); +} + +static int atmel_aead_sha1_cbc_decrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA1); +} + +static int atmel_aead_sha1_cbc_givencrypt(struct aead_givcrypt_request *req) +{ + return atmel_aead_givcrypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC | AES_FLAGS_GIV, + SHA_MR_ALGO_HMAC_SHA1); +} + +static int atmel_aead_sha224_cbc_encrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA224); +} + +static int atmel_aead_sha224_cbc_decrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA224); +} + +static int atmel_aead_sha224_cbc_givencrypt(struct aead_givcrypt_request *req) +{ + return atmel_aead_givcrypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC | AES_FLAGS_GIV, + SHA_MR_ALGO_HMAC_SHA224); +} + +static int atmel_aead_sha256_cbc_encrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA256); +} + +static int atmel_aead_sha256_cbc_decrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA256); +} + +static int atmel_aead_sha256_cbc_givencrypt(struct aead_givcrypt_request *req) +{ + return atmel_aead_givcrypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC | AES_FLAGS_GIV, + SHA_MR_ALGO_HMAC_SHA256); +} + +static int atmel_aead_sha384_cbc_encrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA384); +} + +static int atmel_aead_sha384_cbc_decrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA384); +} + +static int atmel_aead_sha384_cbc_givencrypt(struct aead_givcrypt_request *req) +{ + return atmel_aead_givcrypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC | AES_FLAGS_GIV, + SHA_MR_ALGO_HMAC_SHA384); +} + +static int atmel_aead_sha512_cbc_encrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA512); +} + +static int atmel_aead_sha512_cbc_decrypt(struct aead_request *req) +{ + return atmel_aead_crypt(req, AES_FLAGS_CBC, SHA_MR_ALGO_HMAC_SHA512); +} + +static int atmel_aead_sha512_cbc_givencrypt(struct aead_givcrypt_request *req) +{ + return atmel_aead_givcrypt(req, + AES_FLAGS_ENCRYPT | AES_FLAGS_CBC | AES_FLAGS_GIV, + SHA_MR_ALGO_HMAC_SHA512); +} + static struct crypto_alg aes_algs[] = { { .cra_name = "ecb(aes)", @@ -1145,6 +1617,124 @@ static struct crypto_alg aes_cfb64_alg = { } }; +static struct crypto_alg aead_algs[] = { +{ + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = "atmel-authenc-hmac-sha1-cbc-aes", + .cra_priority = 3000, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct atmel_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_aead_type, + .cra_module = THIS_MODULE, + .cra_init = atmel_aead_cra_init, + .cra_exit = atmel_aead_cra_exit, + .cra_u.aead = { + .setkey = atmel_aead_setkey, + .setauthsize = atmel_aead_setauthsize, + .encrypt = atmel_aead_sha1_cbc_encrypt, + .decrypt = atmel_aead_sha1_cbc_decrypt, + .givencrypt = atmel_aead_sha1_cbc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + } +}, +{ + .cra_name = "authenc(hmac(sha224),cbc(aes))", + .cra_driver_name = "atmel-authenc-hmac-sha224-cbc-aes", + .cra_priority = 3000, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct atmel_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_aead_type, + .cra_module = THIS_MODULE, + .cra_init = atmel_aead_cra_init, + .cra_exit = atmel_aead_cra_exit, + .cra_u.aead = { + .setkey = atmel_aead_setkey, + .setauthsize = atmel_aead_setauthsize, + .encrypt = atmel_aead_sha224_cbc_encrypt, + .decrypt = atmel_aead_sha224_cbc_decrypt, + .givencrypt = atmel_aead_sha224_cbc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + } +}, +{ + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = "atmel-authenc-hmac-sha256-cbc-aes", + .cra_priority = 3000, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct atmel_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_aead_type, + .cra_module = THIS_MODULE, + .cra_init = atmel_aead_cra_init, + .cra_exit = atmel_aead_cra_exit, + .cra_u.aead = { + .setkey = atmel_aead_setkey, + .setauthsize = atmel_aead_setauthsize, + .encrypt = atmel_aead_sha256_cbc_encrypt, + .decrypt = atmel_aead_sha256_cbc_decrypt, + .givencrypt = atmel_aead_sha256_cbc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + } +}, +{ + .cra_name = "authenc(hmac(sha384),cbc(aes))", + .cra_driver_name = "atmel-authenc-hmac-sha384-cbc-aes", + .cra_priority = 3000, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct atmel_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_aead_type, + .cra_module = THIS_MODULE, + .cra_init = atmel_aead_cra_init, + .cra_exit = atmel_aead_cra_exit, + .cra_u.aead = { + .setkey = atmel_aead_setkey, + .setauthsize = atmel_aead_setauthsize, + .encrypt = atmel_aead_sha384_cbc_encrypt, + .decrypt = atmel_aead_sha384_cbc_decrypt, + .givencrypt = atmel_aead_sha384_cbc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + } +}, +{ + .cra_name = "authenc(hmac(sha512),cbc(aes))", + .cra_driver_name = "atmel-authenc-hmac-sha512-cbc-aes", + .cra_priority = 3000, + .cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct atmel_aes_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_aead_type, + .cra_module = THIS_MODULE, + .cra_init = atmel_aead_cra_init, + .cra_exit = atmel_aead_cra_exit, + .cra_u.aead = { + .setkey = atmel_aead_setkey, + .setauthsize = atmel_aead_setauthsize, + .encrypt = atmel_aead_sha512_cbc_encrypt, + .decrypt = atmel_aead_sha512_cbc_decrypt, + .givencrypt = atmel_aead_sha512_cbc_givencrypt, + .geniv = "", + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + } +}, +}; + static void atmel_aes_queue_task(unsigned long data) { struct atmel_aes_dev *dd = (struct atmel_aes_dev *)data; @@ -1218,6 +1808,10 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) crypto_unregister_alg(&aes_algs[i]); if (dd->caps.has_cfb64) crypto_unregister_alg(&aes_cfb64_alg); + if (dd->caps.has_aead) { + for (i = 0; i < ARRAY_SIZE(aead_algs); i++) + crypto_unregister_alg(&aead_algs[i]); + } } static int atmel_aes_register_algs(struct atmel_aes_dev *dd) @@ -1236,8 +1830,20 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) goto err_aes_cfb64_alg; } + if (dd->caps.has_aead) { + for (i = 0; i < ARRAY_SIZE(aead_algs); i++) { + err = crypto_register_alg(&aead_algs[i]); + if (err) + goto err_aead_alg; + } + } + return 0; +err_aead_alg: + for (j = 0; j < i; j++) + crypto_unregister_alg(&aead_algs[j]); + crypto_unregister_alg(&aes_cfb64_alg); err_aes_cfb64_alg: i = ARRAY_SIZE(aes_algs); err_aes_algs: @@ -1424,6 +2030,14 @@ static int atmel_aes_probe(struct platform_device *pdev) list_add_tail(&aes_dd->list, &atmel_aes.dev_list); spin_unlock(&atmel_aes.lock); + if (aes_dd->caps.has_aead) { + atomic_set(&aes_dd->aead_configuring, 0); + tasklet_init(&aes_dd->aead_task, atmel_aead_queue_task, + (unsigned long)aes_dd); + crypto_init_queue(&aes_dd->aead_queue, + ATMEL_AES_QUEUE_LENGTH * 6); + } + err = atmel_aes_register_algs(aes_dd); if (err) goto err_algs; @@ -1451,6 +2065,8 @@ static int atmel_aes_probe(struct platform_device *pdev) res_err: tasklet_kill(&aes_dd->done_task); tasklet_kill(&aes_dd->queue_task); + if (aes_dd->caps.has_aead) + tasklet_kill(&aes_dd->aead_task); kfree(aes_dd); aes_dd = NULL; aes_dd_err: @@ -1474,6 +2090,8 @@ static int atmel_aes_remove(struct platform_device *pdev) tasklet_kill(&aes_dd->done_task); tasklet_kill(&aes_dd->queue_task); + if (aes_dd->caps.has_aead) + tasklet_kill(&aes_dd->aead_task); atmel_aes_dma_cleanup(aes_dd); From 41140f6026bb749f12fdc6fdc795889664b71cc9 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 17:17:05 +0200 Subject: [PATCH 171/381] ARM: at91/dt: sama5d2: add TDES node add DT node for tdes. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 8c9591b7208f50..26938944c39e58 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1072,6 +1072,22 @@ compatible = "atmel,sama5d2-pinctrl", "simple-bus"; atmel,pio_reg = <&pio_reg 0x0>; }; + + tdes@fc044000 { + compatible = "atmel,at91sam9g46-tdes"; + reg = <0xfc044000 0x100>; + interrupts = <11 IRQ_TYPE_LEVEL_HIGH 0>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(28))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(29))>; + dma-names = "tx", "rx"; + clocks = <&tdes_clk>; + clock-names = "tdes_clk"; + status = "disable"; + }; }; }; }; From 07ad51a49509e648b28a7ee98f7309e02fb832ff Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 10 Sep 2015 17:18:44 +0200 Subject: [PATCH 172/381] ARM: at91/dt: sama5d2: enable crypto devices Enable SHA, AES and TDES devices. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 26938944c39e58..8f6b5baa06ff36 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -785,7 +785,7 @@ dma-names = "tx"; clocks = <&sha_clk>; clock-names = "sha_clk"; - status = "disabled"; + status = "okay"; }; aes@f002c000 { @@ -801,7 +801,7 @@ dma-names = "tx", "rx"; clocks = <&aes_clk>; clock-names = "aes_clk"; - status = "disabled"; + status = "okay"; }; spi0: spi@f8000000 { @@ -1086,7 +1086,7 @@ dma-names = "tx", "rx"; clocks = <&tdes_clk>; clock-names = "tdes_clk"; - status = "disable"; + status = "okay"; }; }; }; From 584b7d20ef40733777f480b2419cd3e98df8d3aa Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 30 Mar 2015 18:40:22 +0800 Subject: [PATCH 173/381] ARM: at91/dt: at91sam9n12ek: fix the led labels name Correct the led labels in at91sam9n12ek. Signed-off-by: Josh Wu Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9n12ek.dts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index efa75064d38a62..186a1705f8d3da 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -204,13 +204,13 @@ }; d9 { - label = "d6"; + label = "d9"; gpios = <&pioB 5 GPIO_ACTIVE_LOW>; linux,default-trigger = "nand-disk"; }; d10 { - label = "d7"; + label = "d10"; gpios = <&pioB 6 GPIO_ACTIVE_HIGH>; linux,default-trigger = "heartbeat"; }; From 7502ee9a65a20e561585398af91d6257defc07cf Mon Sep 17 00:00:00 2001 From: Bo Shen Date: Thu, 11 Sep 2014 09:29:12 +0800 Subject: [PATCH 174/381] ARM: at91/dt: at91sam9n12ek: disable i2c1 No device connect to i2c1, so remove it to keep it as disabled. Signed-off-by: Bo Shen Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9n12ek.dts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/arm/boot/dts/at91sam9n12ek.dts b/arch/arm/boot/dts/at91sam9n12ek.dts index 186a1705f8d3da..acf3451a332da2 100644 --- a/arch/arm/boot/dts/at91sam9n12ek.dts +++ b/arch/arm/boot/dts/at91sam9n12ek.dts @@ -71,10 +71,6 @@ }; }; - i2c1: i2c@f8014000 { - status = "okay"; - }; - mmc0: mmc@f0008000 { pinctrl-0 = < &pinctrl_board_mmc0 From f8d03b141cbaeaa993169ee9cdd0c659ae6cac05 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 12 Jul 2013 18:17:00 +0800 Subject: [PATCH 175/381] ARM: at91/dt: at91sam9x5: enable iio touchscreen for 9x5ek Signed-off-by: Josh Wu Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9x5.dtsi | 3 ++- arch/arm/boot/dts/at91sam9x5ek.dtsi | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 747d8f070a5c26..9df8ca5666e9d3 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -68,7 +68,7 @@ adc_op_clk: adc_op_clk{ compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <5000000>; + clock-frequency = <1000000>; }; }; @@ -1043,6 +1043,7 @@ atmel,adc-channels-used = <0xffff>; atmel,adc-vref = <3300>; atmel,adc-startup-time = <40>; + atmel,adc-sample-hold-time = <11>; atmel,adc-res = <8 10>; atmel,adc-res-names = "lowres", "highres"; atmel,adc-use-res = "highres"; diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi index d237c462dfc6b1..36de329340d155 100644 --- a/arch/arm/boot/dts/at91sam9x5ek.dtsi +++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi @@ -100,6 +100,12 @@ }; }; + adc0: adc@f804c000 { + atmel,adc-ts-wires = <4>; + atmel,adc-ts-pressure-threshold = <10000>; + status = "okay"; + }; + pinctrl@fffff400 { camera_sensor { pinctrl_pck0_as_isi_mck: pck0_as_isi_mck-0 { From 7a8e5b850c420e630e12ea981509f333fec6b140 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 17 Apr 2015 15:27:19 +0200 Subject: [PATCH 176/381] ARM: at91/dt: sama5d3 xplained: disable pmic As PMIC act8865 can disturb communication on i2c1, and as it should be setup correctly then its i2c interface disabled by bootloader, we simply disregard it in DT. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d3_xplained.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained.dts b/arch/arm/boot/dts/at91-sama5d3_xplained.dts index d81474e0bcd600..8488ac53d22d3b 100644 --- a/arch/arm/boot/dts/at91-sama5d3_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d3_xplained.dts @@ -76,7 +76,7 @@ pmic: act8865@5b { compatible = "active-semi,act8865"; reg = <0x5b>; - status = "okay"; + status = "disabled"; regulators { vcc_1v8_reg: DCDC_REG1 { From 5465688f1a03d17223cd3d579e32469930b64c65 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 28 Jan 2015 14:39:34 +0100 Subject: [PATCH 177/381] ARM: at91/dt: sama5d3: update iio config for touchscreen Signed-off-by: Josh Wu Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d3.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d3.dtsi b/arch/arm/boot/dts/sama5d3.dtsi index 7fa276515f11b6..1832736201ffbd 100644 --- a/arch/arm/boot/dts/sama5d3.dtsi +++ b/arch/arm/boot/dts/sama5d3.dtsi @@ -75,7 +75,7 @@ adc_op_clk: adc_op_clk{ compatible = "fixed-clock"; #clock-cells = <0>; - clock-frequency = <20000000>; + clock-frequency = <1000000>; }; }; @@ -322,6 +322,7 @@ atmel,adc-use-external-triggers; atmel,adc-vref = <3000>; atmel,adc-res = <10 12>; + atmel,adc-sample-hold-time = <11>; atmel,adc-res-names = "lowres", "highres"; status = "disabled"; From 6939aebecd537f4b6d4f2e857667c17dda33249e Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Thu, 23 Apr 2015 10:07:18 +0200 Subject: [PATCH 178/381] ARM: at91/dt: sama5d4: add pioD pin mux mask and enable pioD Signed-off-by: Josh Wu Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d4.dtsi | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index fb92481e60d467..c367153eed40d8 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1350,7 +1350,7 @@ 0xffffffff 0x3ffcfe7c 0x1c010101 /* pioA */ 0x7fffffff 0xfffccc3a 0x3f00cc3a /* pioB */ 0xffffffff 0x3ff83fff 0xff00ffff /* pioC */ - 0x00000000 0x00000000 0x00000000 /* pioD */ + 0x0003ff00 0x8002a800 0x00000000 /* pioD */ 0xffffffff 0x7fffffff 0x76fff1bf /* pioE */ >; @@ -1396,7 +1396,6 @@ interrupt-controller; #interrupt-cells = <2>; clocks = <&pioD_clk>; - status = "disabled"; }; pioE: gpio@fc06d000 { From 02d54f5434480330514926db6c489723baa480f6 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 7 Apr 2015 14:28:53 +0200 Subject: [PATCH 179/381] ARM: at91/dt: sama5d4: enable crypto nodes The crypto modules will provide HW AES/TDES/SHA for any sama5d4 board. Enable them by default. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d4.dtsi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index c367153eed40d8..9760a7549f9014 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1238,7 +1238,7 @@ dma-names = "tx", "rx"; clocks = <&aes_clk>; clock-names = "aes_clk"; - status = "disabled"; + status = "okay"; }; tdes@fc04c000 { @@ -1252,7 +1252,7 @@ dma-names = "tx", "rx"; clocks = <&tdes_clk>; clock-names = "tdes_clk"; - status = "disabled"; + status = "okay"; }; sha@fc050000 { @@ -1264,7 +1264,7 @@ dma-names = "tx"; clocks = <&sha_clk>; clock-names = "sha_clk"; - status = "disabled"; + status = "okay"; }; rstc@fc068600 { From 6c4225b9963cbf5eecdb6516105910b5d285dcd9 Mon Sep 17 00:00:00 2001 From: Patrice Vilchez Date: Mon, 12 Jan 2015 11:34:45 +0100 Subject: [PATCH 180/381] ARM: at91/dt: sama5d4ek: Add support of QT1070 and Maxtouch As the EK board comes with a PDA 7" screen, add the touch buttons and touchscreen for it. Signed-off-by: Patrice Vilchez [nicolas.ferre@atmel.com: add commit message] Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d4ek.dts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index 49a59c7e4a5d1e..6d272c0125e365 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -148,6 +148,25 @@ clocks = <&pck2>; clock-names = "mclk"; }; + + qt1070:keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <25 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4c { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4c>; + interrupt-parent = <&pioE>; + interrupts = <24 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; }; macb0: ethernet@f8020000 { @@ -204,6 +223,14 @@ atmel,pins = ; /* PE13 gpio */ }; + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; + }; }; }; }; From 2c98b07f67b4d27c140da79ecd8f02aa5710f5ac Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Thu, 23 Apr 2015 10:08:04 +0200 Subject: [PATCH 181/381] ARM: at91/dt: sama5d4 xplained: enable the led D8 Enable D8 led as now the pioD is available. D8 is the power led and is on by default. Signed-off-by: Josh Wu [nicolas.ferre@atmel.com: split the patch in 2] Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d4_xplained.dts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained.dts b/arch/arm/boot/dts/at91-sama5d4_xplained.dts index 07f46963335bb6..45371a1b61b398 100644 --- a/arch/arm/boot/dts/at91-sama5d4_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d4_xplained.dts @@ -246,7 +246,7 @@ d8 { label = "d8"; gpios = <&pioD 30 GPIO_ACTIVE_HIGH>; - status = "disabled"; + default-state = "on"; }; d10 { From ecabd25ad2cdf24a1a097b0fe687197a168d7a4e Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 21 Sep 2015 14:23:48 +0200 Subject: [PATCH 182/381] ARM: at91/dt: fix name of macro helper for SPI1 MOSI The pin PD26 function A is for SPI1 MOSI, not MISO. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2-pinfunc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h index afdd71df207790..9db4b0e6b762ae 100644 --- a/arch/arm/boot/dts/sama5d2-pinfunc.h +++ b/arch/arm/boot/dts/sama5d2-pinfunc.h @@ -730,7 +730,7 @@ #define PIN_PD25__SPI1_SPCK PINMUX_PIN(PIN_PD25, 3) #define PIN_PD25__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD25, 3) #define PIN_PD26 122 -#define PIN_PD26__SPI1_MISO PINMUX_PIN(PIN_PD26, 3) +#define PIN_PD26__SPI1_MOSI PINMUX_PIN(PIN_PD26, 3) #define PIN_PD26__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD26, 2) #define PIN_PD27 123 #define PIN_PD27__SPI1_MISO PINMUX_PIN(PIN_PD27, 3) From fb46df05607f793ea6f21854c3663e983d2852ad Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 22 Sep 2015 10:08:51 +0200 Subject: [PATCH 183/381] pinctrl: at91-pio4: sync with mainline Signed-off-by: Ludovic Desroches --- .../bindings/pinctrl/atmel,at91-pinctrl.txt | 216 +-- arch/arm/boot/dts/sama5d2-pinfunc.h | 1382 +++++++++-------- drivers/pinctrl/Kconfig | 5 +- drivers/pinctrl/pinctrl-at91-pio4.c | 1175 +++++++++----- 4 files changed, 1627 insertions(+), 1151 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt index b7a93e80a3026e..61ac75706cc9c4 100644 --- a/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt @@ -1,150 +1,90 @@ -* Atmel AT91 Pinmux Controller +* Atmel PIO4 Controller -The AT91 Pinmux Controller, enables the IC -to share one PAD to several functional blocks. The sharing is done by -multiplexing the PAD input/output signals. For each PAD there are up to -8 muxing options (called periph modes). Since different modules require -different PAD settings (like pull up, keeper, etc) the contoller controls -also the PAD settings parameters. +The Atmel PIO4 controller is used to select the function of a pin and to +configure it. -Please refer to pinctrl-bindings.txt in this directory for details of the -common pinctrl bindings used by client devices, including the meaning of the -phrase "pin configuration node". - -Atmel AT91 pin configuration node is a node of a group of pins which can be -used for a specific device or function. This node represents both mux and config -of the pins in that group. The 'pins' selects the function mode(also named pin -mode) this pin can work on and the 'config' configures various pad settings -such as pull-up, multi drive, etc. - -Required properties for iomux controller: -- compatible: "atmel,at91rm9200-pinctrl" or "atmel,at91sam9x5-pinctrl" - or "atmel,sama5d3-pinctrl" -- atmel,mux-mask: array of mask (periph per bank) to describe if a pin can be - configured in this periph mode. All the periph and bank need to be describe. - -How to create such array: - -Each column will represent the possible peripheral of the pinctrl -Each line will represent a pio bank - -Take an example on the 9260 -Peripheral: 2 ( A and B) -Bank: 3 (A, B and C) -=> - - /* A B */ - 0xffffffff 0xffc00c3b /* pioA */ - 0xffffffff 0x7fff3ccf /* pioB */ - 0xffffffff 0x007fffff /* pioC */ - -For each peripheral/bank we will descibe in a u32 if a pin can be -configured in it by putting 1 to the pin bit (1 << pin) +Required properties: +- compatible: "atmel,sama5d2-pinctrl". +- reg: base address and length of the PIO controller. +- interrupts: interrupt outputs from the controller, one for each bank. +- interrupt-controller: mark the device node as an interrupt controller. +- #interrupt-cells: should be two. +- gpio-controller: mark the device node as a gpio controller. +- #gpio-cells: should be two. -Let's take the pioA on peripheral B -From the datasheet Table 10-2. -Peripheral B -PA0 MCDB0 -PA1 MCCDB -PA2 -PA3 MCDB3 -PA4 MCDB2 -PA5 MCDB1 -PA6 -PA7 -PA8 -PA9 -PA10 ETX2 -PA11 ETX3 -PA12 -PA13 -PA14 -PA15 -PA16 -PA17 -PA18 -PA19 -PA20 -PA21 -PA22 ETXER -PA23 ETX2 -PA24 ETX3 -PA25 ERX2 -PA26 ERX3 -PA27 ERXCK -PA28 ECRS -PA29 ECOL -PA30 RXD4 -PA31 TXD4 +Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for +a general description of GPIO and interrupt bindings. -=> 0xffc00c3b - -Required properties for pin configuration node: -- atmel,pins: 4 integers array, represents a group of pins mux and config - setting. The format is atmel,pins = . - The PERIPH 0 means gpio, PERIPH 1 is periph A, PERIPH 2 is periph B... - PIN_BANK 0 is pioA, PIN_BANK 1 is pioB... - -Bits used for CONFIG: -PULL_UP (1 << 0): indicate this pin needs a pull up. -MULTIDRIVE (1 << 1): indicate this pin needs to be configured as multi-drive. - Multi-drive is equivalent to open-drain type output. -DEGLITCH (1 << 2): indicate this pin needs deglitch. -PULL_DOWN (1 << 3): indicate this pin needs a pull down. -DIS_SCHMIT (1 << 4): indicate this pin needs to the disable schmitt trigger. -DRIVE_STRENGTH (3 << 5): indicate the drive strength of the pin using the - following values: - 00 - No change (reset state value kept) - 01 - Low - 10 - Medium - 11 - High -DEBOUNCE (1 << 16): indicate this pin needs debounce. -DEBOUNCE_VAL (0x3fff << 17): debounce value. +Please refer to pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices. -NOTE: -Some requirements for using atmel,at91rm9200-pinctrl binding: -1. We have pin function node defined under at91 controller node to represent - what pinmux functions this SoC supports. -2. The driver can use the function node's name and pin configuration node's - name describe the pin function and group hierarchy. - For example, Linux at91 pinctrl driver takes the function node's name - as the function name and pin configuration node's name as group name to - create the map table. -3. Each pin configuration node should have a phandle, devices can set pins - configurations by referring to the phandle of that pin configuration node. -4. The gpio controller must be describe in the pinctrl simple-bus. +Subnode format +Each node (or subnode) will list the pins it needs and how to configured these +pins. -Examples: + node { + pinmux = ; + GENERIC_PINCONFIG; + }; -pinctrl@fffff400 { - #address-cells = <1>; - #size-cells = <1>; - ranges; - compatible = "atmel,at91rm9200-pinctrl", "simple-bus"; - reg = <0xfffff400 0x600>; +Required properties: +- pinmux: integer array. Each integer represents a pin number plus mux and +ioset settings. Use the macros from boot/dts/-pinfunc.h file to get the +right representation of the pin. + +Optional properties: +- GENERIC_PINCONFIG: generic pinconfig options to use, bias-disable, +bias-pull-down, bias-pull-up, drive-open-drain, input-schmitt-enable, +input-debounce, output-low, output-high. + +Example: + +#include + +... +{ + pioA: pinctrl@fc038000 { + compatible = "atmel,sama5d2-pinctrl"; + reg = <0xfc038000 0x600>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH 7>, + <68 IRQ_TYPE_LEVEL_HIGH 7>, + <69 IRQ_TYPE_LEVEL_HIGH 7>, + <70 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pioA_clk>; + + pinctrl_i2c0_default: i2c0_default { + pinmux = , + ; + bias-disable; + }; - atmel,mux-mask = < - /* A B */ - 0xffffffff 0xffc00c3b /* pioA */ - 0xffffffff 0x7fff3ccf /* pioB */ - 0xffffffff 0x007fffff /* pioC */ - >; + pinctrl_led_gpio_default: led_gpio_default { + pinmux = , + ; + bias-pull-up; + }; - /* shared pinctrl settings */ - dbgu { - pinctrl_dbgu: dbgu-0 { - atmel,pins = - <1 14 0x1 0x0 /* PB14 periph A */ - 1 15 0x1 0x1>; /* PB15 periph A with pullup */ + pinctrl_sdmmc1_default: sdmmc1_default { + cmd_data { + pinmux = , + , + , + , + ; + bias-pull-up; + }; + + ck_cd { + pinmux = , + ; + bias-disable; + }; }; + ... }; }; - -dbgu: serial@fffff200 { - compatible = "atmel,at91sam9260-usart"; - reg = <0xfffff200 0x200>; - interrupts = <1 4 7>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_dbgu>; - status = "disabled"; -}; +... diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h index 9db4b0e6b762ae..1afe24629d1f85 100644 --- a/arch/arm/boot/dts/sama5d2-pinfunc.h +++ b/arch/arm/boot/dts/sama5d2-pinfunc.h @@ -1,760 +1,880 @@ -#define PINMUX_PIN(no, ioset) \ -( ((no) & 0xffff) | (((ioset) & 0xff) << 16) ) +#define PINMUX_PIN(no, func, ioset) \ +(((no) & 0xffff) | (((func) & 0xf) << 16) | (((ioset) & 0xff) << 20)) #define PIN_PA0 0 -#define PIN_PA0__SDMMC0_CK PINMUX_PIN(PIN_PA0, 1) -#define PIN_PA0__QSPI0_SCK PINMUX_PIN(PIN_PA0, 1) -#define PIN_PA0__D0 PINMUX_PIN(PIN_PA0, 2) +#define PIN_PA0__GPIO PINMUX_PIN(PIN_PA0, 0, 0) +#define PIN_PA0__SDMMC0_CK PINMUX_PIN(PIN_PA0, 1, 1) +#define PIN_PA0__QSPI0_SCK PINMUX_PIN(PIN_PA0, 2, 1) +#define PIN_PA0__D0 PINMUX_PIN(PIN_PA0, 6, 2) #define PIN_PA1 1 -#define PIN_PA1__SDMMC0_CMD PINMUX_PIN(PIN_PA1, 1) -#define PIN_PA1__QSPI0_CS PINMUX_PIN(PIN_PA1, 1) -#define PIN_PA1__D1 PINMUX_PIN(PIN_PA1, 2) +#define PIN_PA1__GPIO PINMUX_PIN(PIN_PA1, 0, 0) +#define PIN_PA1__SDMMC0_CMD PINMUX_PIN(PIN_PA1, 1, 1) +#define PIN_PA1__QSPI0_CS PINMUX_PIN(PIN_PA1, 2, 1) +#define PIN_PA1__D1 PINMUX_PIN(PIN_PA1, 6, 2) #define PIN_PA2 2 -#define PIN_PA2__SDMMC0_DAT0 PINMUX_PIN(PIN_PA2, 1) -#define PIN_PA2__QSPI0_IO0 PINMUX_PIN(PIN_PA2, 1) -#define PIN_PA2__D2 PINMUX_PIN(PIN_PA2, 2) +#define PIN_PA2__GPIO PINMUX_PIN(PIN_PA2, 0, 0) +#define PIN_PA2__SDMMC0_DAT0 PINMUX_PIN(PIN_PA2, 1, 1) +#define PIN_PA2__QSPI0_IO0 PINMUX_PIN(PIN_PA2, 2, 1) +#define PIN_PA2__D2 PINMUX_PIN(PIN_PA2, 6, 2) #define PIN_PA3 3 -#define PIN_PA3__SDMMC0_DAT1 PINMUX_PIN(PIN_PA3, 1) -#define PIN_PA3__QSPI0_IO1 PINMUX_PIN(PIN_PA3, 1) -#define PIN_PA3__D3 PINMUX_PIN(PIN_PA3, 2) +#define PIN_PA3__GPIO PINMUX_PIN(PIN_PA3, 0, 0) +#define PIN_PA3__SDMMC0_DAT1 PINMUX_PIN(PIN_PA3, 1, 1) +#define PIN_PA3__QSPI0_IO1 PINMUX_PIN(PIN_PA3, 2, 1) +#define PIN_PA3__D3 PINMUX_PIN(PIN_PA3, 6, 2) #define PIN_PA4 4 -#define PIN_PA4__SDMMC0_DAT2 PINMUX_PIN(PIN_PA4, 1) -#define PIN_PA4__QSPI0_IO2 PINMUX_PIN(PIN_PA4, 1) -#define PIN_PA4__D4 PINMUX_PIN(PIN_PA4, 2) +#define PIN_PA4__GPIO PINMUX_PIN(PIN_PA4, 0, 0) +#define PIN_PA4__SDMMC0_DAT2 PINMUX_PIN(PIN_PA4, 1, 1) +#define PIN_PA4__QSPI0_IO2 PINMUX_PIN(PIN_PA4, 2, 1) +#define PIN_PA4__D4 PINMUX_PIN(PIN_PA4, 6, 2) #define PIN_PA5 5 -#define PIN_PA5__SDMMC0_DAT3 PINMUX_PIN(PIN_PA5, 1) -#define PIN_PA5__QSPI0_IO3 PINMUX_PIN(PIN_PA5, 1) -#define PIN_PA5__D5 PINMUX_PIN(PIN_PA5, 2) +#define PIN_PA5__GPIO PINMUX_PIN(PIN_PA5, 0, 0) +#define PIN_PA5__SDMMC0_DAT3 PINMUX_PIN(PIN_PA5, 1, 1) +#define PIN_PA5__QSPI0_IO3 PINMUX_PIN(PIN_PA5, 2, 1) +#define PIN_PA5__D5 PINMUX_PIN(PIN_PA5, 6, 2) #define PIN_PA6 6 -#define PIN_PA6__SDMMC0_DAT4 PINMUX_PIN(PIN_PA6, 1) -#define PIN_PA6__QSPI1_SCK PINMUX_PIN(PIN_PA6, 1) -#define PIN_PA6__TIOA5 PINMUX_PIN(PIN_PA6, 1) -#define PIN_PA6__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA6, 1) -#define PIN_PA6__D6 PINMUX_PIN(PIN_PA6, 2) +#define PIN_PA6__GPIO PINMUX_PIN(PIN_PA6, 0, 0) +#define PIN_PA6__SDMMC0_DAT4 PINMUX_PIN(PIN_PA6, 1, 1) +#define PIN_PA6__QSPI1_SCK PINMUX_PIN(PIN_PA6, 2, 1) +#define PIN_PA6__TIOA5 PINMUX_PIN(PIN_PA6, 4, 1) +#define PIN_PA6__FLEXCOM2_IO0 PINMUX_PIN(PIN_PA6, 5, 1) +#define PIN_PA6__D6 PINMUX_PIN(PIN_PA6, 6, 2) #define PIN_PA7 7 -#define PIN_PA7__SDMMC0_DAT5 PINMUX_PIN(PIN_PA7, 1) -#define PIN_PA7__QSPI1_IO0 PINMUX_PIN(PIN_PA7, 1) -#define PIN_PA7__TIOB5 PINMUX_PIN(PIN_PA7, 1) -#define PIN_PA7__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA7, 1) -#define PIN_PA7__D7 PINMUX_PIN(PIN_PA7, 2) +#define PIN_PA7__GPIO PINMUX_PIN(PIN_PA7, 0, 0) +#define PIN_PA7__SDMMC0_DAT5 PINMUX_PIN(PIN_PA7, 1, 1) +#define PIN_PA7__QSPI1_IO0 PINMUX_PIN(PIN_PA7, 2, 1) +#define PIN_PA7__TIOB5 PINMUX_PIN(PIN_PA7, 4, 1) +#define PIN_PA7__FLEXCOM2_IO1 PINMUX_PIN(PIN_PA7, 5, 1) +#define PIN_PA7__D7 PINMUX_PIN(PIN_PA7, 6, 2) #define PIN_PA8 8 -#define PIN_PA8__SDMMC0_DAT6 PINMUX_PIN(PIN_PA8, 1) -#define PIN_PA8__QSPI1_IO1 PINMUX_PIN(PIN_PA8, 1) -#define PIN_PA8__TCLK5 PINMUX_PIN(PIN_PA8, 1) -#define PIN_PA8__FLEXCOM2_IO2 PINMUX_PIN(PIN_PA8, 1) -#define PIN_PA8__NWE_NANDWE PINMUX_PIN(PIN_PA8, 2) +#define PIN_PA8__GPIO PINMUX_PIN(PIN_PA8, 0, 0) +#define PIN_PA8__SDMMC0_DAT6 PINMUX_PIN(PIN_PA8, 1, 1) +#define PIN_PA8__QSPI1_IO1 PINMUX_PIN(PIN_PA8, 2, 1) +#define PIN_PA8__TCLK5 PINMUX_PIN(PIN_PA8, 4, 1) +#define PIN_PA8__FLEXCOM2_IO2 PINMUX_PIN(PIN_PA8, 5, 1) +#define PIN_PA8__NWE_NANDWE PINMUX_PIN(PIN_PA8, 6, 2) #define PIN_PA9 9 -#define PIN_PA9__SDMMC0_DAT7 PINMUX_PIN(PIN_PA9, 1) -#define PIN_PA9__QSPI1_IO2 PINMUX_PIN(PIN_PA9, 1) -#define PIN_PA9__TIOA4 PINMUX_PIN(PIN_PA9, 1) -#define PIN_PA9__FLEXCOM2_IO3 PINMUX_PIN(PIN_PA9, 1) -#define PIN_PA9__NCS3 PINMUX_PIN(PIN_PA9, 2) +#define PIN_PA9__GPIO PINMUX_PIN(PIN_PA9, 0, 0) +#define PIN_PA9__SDMMC0_DAT7 PINMUX_PIN(PIN_PA9, 1, 1) +#define PIN_PA9__QSPI1_IO2 PINMUX_PIN(PIN_PA9, 2, 1) +#define PIN_PA9__TIOA4 PINMUX_PIN(PIN_PA9, 4, 1) +#define PIN_PA9__FLEXCOM2_IO3 PINMUX_PIN(PIN_PA9, 5, 1) +#define PIN_PA9__NCS3 PINMUX_PIN(PIN_PA9, 6, 2) #define PIN_PA10 10 -#define PIN_PA10__SDMMC0_RSTN PINMUX_PIN(PIN_PA10, 1) -#define PIN_PA10__QSPI1_IO3 PINMUX_PIN(PIN_PA10, 1) -#define PIN_PA10__TIOB4 PINMUX_PIN(PIN_PA10, 1) -#define PIN_PA10__FLEXCOM2_IO4 PINMUX_PIN(PIN_PA10, 1) -#define PIN_PA10__A21_NANDALE PINMUX_PIN(PIN_PA10, 2) +#define PIN_PA10__GPIO PINMUX_PIN(PIN_PA10, 0, 0) +#define PIN_PA10__SDMMC0_RSTN PINMUX_PIN(PIN_PA10, 1, 1) +#define PIN_PA10__QSPI1_IO3 PINMUX_PIN(PIN_PA10, 2, 1) +#define PIN_PA10__TIOB4 PINMUX_PIN(PIN_PA10, 4, 1) +#define PIN_PA10__FLEXCOM2_IO4 PINMUX_PIN(PIN_PA10, 5, 1) +#define PIN_PA10__A21_NANDALE PINMUX_PIN(PIN_PA10, 6, 2) #define PIN_PA11 11 -#define PIN_PA11__SDMMC0_VDDSEL PINMUX_PIN(PIN_PA11, 1) -#define PIN_PA11__QSPI1_CS PINMUX_PIN(PIN_PA11, 1) -#define PIN_PA11__TCLK4 PINMUX_PIN(PIN_PA11, 1) -#define PIN_PA11__A22_NANDCLE PINMUX_PIN(PIN_PA11, 2) +#define PIN_PA11__GPIO PINMUX_PIN(PIN_PA11, 0, 0) +#define PIN_PA11__SDMMC0_VDDSEL PINMUX_PIN(PIN_PA11, 1, 1) +#define PIN_PA11__QSPI1_CS PINMUX_PIN(PIN_PA11, 2, 1) +#define PIN_PA11__TCLK4 PINMUX_PIN(PIN_PA11, 4, 1) +#define PIN_PA11__A22_NANDCLE PINMUX_PIN(PIN_PA11, 6, 2) #define PIN_PA12 12 -#define PIN_PA12__SDMMC0_WP PINMUX_PIN(PIN_PA12, 1) -#define PIN_PA12__IRQ PINMUX_PIN(PIN_PA12, 1) -#define PIN_PA12__NRD_NANDOE PINMUX_PIN(PIN_PA12, 2) +#define PIN_PA12__GPIO PINMUX_PIN(PIN_PA12, 0, 0) +#define PIN_PA12__SDMMC0_WP PINMUX_PIN(PIN_PA12, 1, 1) +#define PIN_PA12__IRQ PINMUX_PIN(PIN_PA12, 2, 1) +#define PIN_PA12__NRD_NANDOE PINMUX_PIN(PIN_PA12, 6, 2) #define PIN_PA13 13 -#define PIN_PA13__SDMMC0_CD PINMUX_PIN(PIN_PA13, 1) -#define PIN_PA13__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA13, 1) -#define PIN_PA13__D8 PINMUX_PIN(PIN_PA13, 2) +#define PIN_PA13__GPIO PINMUX_PIN(PIN_PA13, 0, 0) +#define PIN_PA13__SDMMC0_CD PINMUX_PIN(PIN_PA13, 1, 1) +#define PIN_PA13__FLEXCOM3_IO1 PINMUX_PIN(PIN_PA13, 5, 1) +#define PIN_PA13__D8 PINMUX_PIN(PIN_PA13, 6, 2) #define PIN_PA14 14 -#define PIN_PA14__SPI0_SPCK PINMUX_PIN(PIN_PA14, 1) -#define PIN_PA14__TK1 PINMUX_PIN(PIN_PA14, 1) -#define PIN_PA14__QSPI0_SCK PINMUX_PIN(PIN_PA14, 2) -#define PIN_PA14__I2SMCK1 PINMUX_PIN(PIN_PA14, 2) -#define PIN_PA14__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA14, 1) -#define PIN_PA14__D9 PINMUX_PIN(PIN_PA14, 2) +#define PIN_PA14__GPIO PINMUX_PIN(PIN_PA14, 0, 0) +#define PIN_PA14__SPI0_SPCK PINMUX_PIN(PIN_PA14, 1, 1) +#define PIN_PA14__TK1 PINMUX_PIN(PIN_PA14, 2, 1) +#define PIN_PA14__QSPI0_SCK PINMUX_PIN(PIN_PA14, 3, 2) +#define PIN_PA14__I2SC1_MCK PINMUX_PIN(PIN_PA14, 4, 2) +#define PIN_PA14__FLEXCOM3_IO2 PINMUX_PIN(PIN_PA14, 5, 1) +#define PIN_PA14__D9 PINMUX_PIN(PIN_PA14, 6, 2) #define PIN_PA15 14 -#define PIN_PA15__SPI0_MOSI PINMUX_PIN(PIN_PA15, 1) -#define PIN_PA15__TF1 PINMUX_PIN(PIN_PA15, 1) -#define PIN_PA15__QSPI0_CS PINMUX_PIN(PIN_PA15, 2) -#define PIN_PA15__I2SCK1 PINMUX_PIN(PIN_PA15, 2) -#define PIN_PA15__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA15, 1) -#define PIN_PA15__D10 PINMUX_PIN(PIN_PA15, 2) +#define PIN_PA15__GPIO PINMUX_PIN(PIN_PA15, 0, 0) +#define PIN_PA15__SPI0_MOSI PINMUX_PIN(PIN_PA15, 1, 1) +#define PIN_PA15__TF1 PINMUX_PIN(PIN_PA15, 2, 1) +#define PIN_PA15__QSPI0_CS PINMUX_PIN(PIN_PA15, 3, 2) +#define PIN_PA15__I2SC1_CK PINMUX_PIN(PIN_PA15, 4, 2) +#define PIN_PA15__FLEXCOM3_IO0 PINMUX_PIN(PIN_PA15, 5, 1) +#define PIN_PA15__D10 PINMUX_PIN(PIN_PA15, 6, 2) #define PIN_PA16 16 -#define PIN_PA16__SPI0_MISO PINMUX_PIN(PIN_PA16, 1) -#define PIN_PA16__TD1 PINMUX_PIN(PIN_PA16, 1) -#define PIN_PA16__QSPI0_IO0 PINMUX_PIN(PIN_PA16, 2) -#define PIN_PA16__I2SWS1 PINMUX_PIN(PIN_PA16, 2) -#define PIN_PA16__FLEXCOM3_IO3 PINMUX_PIN(PIN_PA16, 1) -#define PIN_PA16__D11 PINMUX_PIN(PIN_PA16, 2) +#define PIN_PA16__GPIO PINMUX_PIN(PIN_PA16, 0, 0) +#define PIN_PA16__SPI0_MISO PINMUX_PIN(PIN_PA16, 1, 1) +#define PIN_PA16__TD1 PINMUX_PIN(PIN_PA16, 2, 1) +#define PIN_PA16__QSPI0_IO0 PINMUX_PIN(PIN_PA16, 3, 2) +#define PIN_PA16__I2SC1_WS PINMUX_PIN(PIN_PA16, 4, 2) +#define PIN_PA16__FLEXCOM3_IO3 PINMUX_PIN(PIN_PA16, 5, 1) +#define PIN_PA16__D11 PINMUX_PIN(PIN_PA16, 6, 2) #define PIN_PA17 17 -#define PIN_PA17__SPI0_NPCS0 PINMUX_PIN(PIN_PA17, 1) -#define PIN_PA17__RD1 PINMUX_PIN(PIN_PA17, 1) -#define PIN_PA17__QSPI0_IO1 PINMUX_PIN(PIN_PA17, 2) -#define PIN_PA17__I2SDI1 PINMUX_PIN(PIN_PA17, 2) -#define PIN_PA17__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA17, 1) -#define PIN_PA17__D12 PINMUX_PIN(PIN_PA17, 2) +#define PIN_PA17__GPIO PINMUX_PIN(PIN_PA17, 0, 0) +#define PIN_PA17__SPI0_NPCS0 PINMUX_PIN(PIN_PA17, 1, 1) +#define PIN_PA17__RD1 PINMUX_PIN(PIN_PA17, 2, 1) +#define PIN_PA17__QSPI0_IO1 PINMUX_PIN(PIN_PA17, 3, 2) +#define PIN_PA17__I2SC1_DI0 PINMUX_PIN(PIN_PA17, 4, 2) +#define PIN_PA17__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA17, 5, 1) +#define PIN_PA17__D12 PINMUX_PIN(PIN_PA17, 6, 2) #define PIN_PA18 18 -#define PIN_PA18__SPI0_NPCS1 PINMUX_PIN(PIN_PA18, 1) -#define PIN_PA18__RK1 PINMUX_PIN(PIN_PA18, 1) -#define PIN_PA18__QSPI0_IO2 PINMUX_PIN(PIN_PA18, 2) -#define PIN_PA18__I2SDO1 PINMUX_PIN(PIN_PA18, 2) -#define PIN_PA18__SDMMC1_DAT0 PINMUX_PIN(PIN_PA18, 1) -#define PIN_PA18__D13 PINMUX_PIN(PIN_PA18, 2) +#define PIN_PA18__GPIO PINMUX_PIN(PIN_PA18, 0, 0) +#define PIN_PA18__SPI0_NPCS1 PINMUX_PIN(PIN_PA18, 1, 1) +#define PIN_PA18__RK1 PINMUX_PIN(PIN_PA18, 2, 1) +#define PIN_PA18__QSPI0_IO2 PINMUX_PIN(PIN_PA18, 3, 2) +#define PIN_PA18__I2SC1_DO0 PINMUX_PIN(PIN_PA18, 4, 2) +#define PIN_PA18__SDMMC1_DAT0 PINMUX_PIN(PIN_PA18, 5, 1) +#define PIN_PA18__D13 PINMUX_PIN(PIN_PA18, 6, 2) #define PIN_PA19 19 -#define PIN_PA19__SPI0_NPCS2 PINMUX_PIN(PIN_PA19, 1) -#define PIN_PA19__RF1 PINMUX_PIN(PIN_PA19, 1) -#define PIN_PA19__QSPI0_IO3 PINMUX_PIN(PIN_PA19, 2) -#define PIN_PA19__TIOA0 PINMUX_PIN(PIN_PA19, 1) -#define PIN_PA19__SDMMC1_DAT1 PINMUX_PIN(PIN_PA19, 1) -#define PIN_PA19__D14 PINMUX_PIN(PIN_PA19, 2) +#define PIN_PA19__GPIO PINMUX_PIN(PIN_PA19, 0, 0) +#define PIN_PA19__SPI0_NPCS2 PINMUX_PIN(PIN_PA19, 1, 1) +#define PIN_PA19__RF1 PINMUX_PIN(PIN_PA19, 2, 1) +#define PIN_PA19__QSPI0_IO3 PINMUX_PIN(PIN_PA19, 3, 2) +#define PIN_PA19__TIOA0 PINMUX_PIN(PIN_PA19, 4, 1) +#define PIN_PA19__SDMMC1_DAT1 PINMUX_PIN(PIN_PA19, 5, 1) +#define PIN_PA19__D14 PINMUX_PIN(PIN_PA19, 6, 2) #define PIN_PA20 20 -#define PIN_PA20__SPI0_NPCS3 PINMUX_PIN(PIN_PA20, 1) -#define PIN_PA20__TIOB0 PINMUX_PIN(PIN_PA20, 1) -#define PIN_PA20__SDMMC1_DAT2 PINMUX_PIN(PIN_PA20, 1) -#define PIN_PA20__D15 PINMUX_PIN(PIN_PA20, 2) +#define PIN_PA20__GPIO PINMUX_PIN(PIN_PA20, 0, 0) +#define PIN_PA20__SPI0_NPCS3 PINMUX_PIN(PIN_PA20, 1, 1) +#define PIN_PA20__TIOB0 PINMUX_PIN(PIN_PA20, 4, 1) +#define PIN_PA20__SDMMC1_DAT2 PINMUX_PIN(PIN_PA20, 5, 1) +#define PIN_PA20__D15 PINMUX_PIN(PIN_PA20, 6, 2) #define PIN_PA21 21 -#define PIN_PA21__IRQ PINMUX_PIN(PIN_PA21, 2) -#define PIN_PA21__PCK2 PINMUX_PIN(PIN_PA21, 3) -#define PIN_PA21__TCLK0 PINMUX_PIN(PIN_PA21, 1) -#define PIN_PA21__SDMMC1_DAT3 PINMUX_PIN(PIN_PA21, 1) -#define PIN_PA21__NANDRDY PINMUX_PIN(PIN_PA21, 2) +#define PIN_PA21__GPIO PINMUX_PIN(PIN_PA21, 0, 0) +#define PIN_PA21__IRQ PINMUX_PIN(PIN_PA21, 1, 2) +#define PIN_PA21__PCK2 PINMUX_PIN(PIN_PA21, 2, 3) +#define PIN_PA21__TCLK0 PINMUX_PIN(PIN_PA21, 4, 1) +#define PIN_PA21__SDMMC1_DAT3 PINMUX_PIN(PIN_PA21, 5, 1) +#define PIN_PA21__NANDRDY PINMUX_PIN(PIN_PA21, 6, 2) #define PIN_PA22 22 -#define PIN_PA22__FLEXCOM1_IO2 PINMUX_PIN(PIN_PA22, 1) -#define PIN_PA22__D0 PINMUX_PIN(PIN_PA22, 1) -#define PIN_PA22__TCK PINMUX_PIN(PIN_PA22, 4) -#define PIN_PA22__SPI1_SPCK PINMUX_PIN(PIN_PA22, 2) -#define PIN_PA22__SDMMC1_CK PINMUX_PIN(PIN_PA22, 1) -#define PIN_PA22__QSPI0_SCK PINMUX_PIN(PIN_PA22, 3) +#define PIN_PA22__GPIO PINMUX_PIN(PIN_PA22, 0, 0) +#define PIN_PA22__FLEXCOM1_IO2 PINMUX_PIN(PIN_PA22, 1, 1) +#define PIN_PA22__D0 PINMUX_PIN(PIN_PA22, 2, 1) +#define PIN_PA22__TCK PINMUX_PIN(PIN_PA22, 3, 4) +#define PIN_PA22__SPI1_SPCK PINMUX_PIN(PIN_PA22, 4, 2) +#define PIN_PA22__SDMMC1_CK PINMUX_PIN(PIN_PA22, 5, 1) +#define PIN_PA22__QSPI0_SCK PINMUX_PIN(PIN_PA22, 6, 3) #define PIN_PA23 23 -#define PIN_PA23__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA23, 1) -#define PIN_PA23__D1 PINMUX_PIN(PIN_PA23, 1) -#define PIN_PA23__TDI PINMUX_PIN(PIN_PA23, 4) -#define PIN_PA23__SPI1_MOSI PINMUX_PIN(PIN_PA23, 2) -#define PIN_PA23__QSPI0_CS PINMUX_PIN(PIN_PA23, 3) +#define PIN_PA23__GPIO PINMUX_PIN(PIN_PA23, 0, 0) +#define PIN_PA23__FLEXCOM1_IO1 PINMUX_PIN(PIN_PA23, 1, 1) +#define PIN_PA23__D1 PINMUX_PIN(PIN_PA23, 2, 1) +#define PIN_PA23__TDI PINMUX_PIN(PIN_PA23, 3, 4) +#define PIN_PA23__SPI1_MOSI PINMUX_PIN(PIN_PA23, 4, 2) +#define PIN_PA23__QSPI0_CS PINMUX_PIN(PIN_PA23, 6, 3) #define PIN_PA24 24 -#define PIN_PA24__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA24, 1) -#define PIN_PA24__D2 PINMUX_PIN(PIN_PA24, 1) -#define PIN_PA24__TDO PINMUX_PIN(PIN_PA24, 4) -#define PIN_PA24__SPI1_MISO PINMUX_PIN(PIN_PA24, 2) -#define PIN_PA24__QSPI0_IO0 PINMUX_PIN(PIN_PA24, 3) +#define PIN_PA24__GPIO PINMUX_PIN(PIN_PA24, 0, 0) +#define PIN_PA24__FLEXCOM1_IO0 PINMUX_PIN(PIN_PA24, 1, 1) +#define PIN_PA24__D2 PINMUX_PIN(PIN_PA24, 2, 1) +#define PIN_PA24__TDO PINMUX_PIN(PIN_PA24, 3, 4) +#define PIN_PA24__SPI1_MISO PINMUX_PIN(PIN_PA24, 4, 2) +#define PIN_PA24__QSPI0_IO0 PINMUX_PIN(PIN_PA24, 6, 3) #define PIN_PA25 25 -#define PIN_PA25__FLEXCOM1_IO3 PINMUX_PIN(PIN_PA25, 1) -#define PIN_PA25__D3 PINMUX_PIN(PIN_PA25, 1) -#define PIN_PA25__TMS PINMUX_PIN(PIN_PA25, 4) -#define PIN_PA25__SPI1_NPCS0 PINMUX_PIN(PIN_PA25, 2) -#define PIN_PA25__QSPI0_IO1 PINMUX_PIN(PIN_PA25, 3) +#define PIN_PA25__GPIO PINMUX_PIN(PIN_PA25, 0, 0) +#define PIN_PA25__FLEXCOM1_IO3 PINMUX_PIN(PIN_PA25, 1, 1) +#define PIN_PA25__D3 PINMUX_PIN(PIN_PA25, 2, 1) +#define PIN_PA25__TMS PINMUX_PIN(PIN_PA25, 3, 4) +#define PIN_PA25__SPI1_NPCS0 PINMUX_PIN(PIN_PA25, 4, 2) +#define PIN_PA25__QSPI0_IO1 PINMUX_PIN(PIN_PA25, 6, 3) #define PIN_PA26 26 -#define PIN_PA26__FLEXCOM1_IO4 PINMUX_PIN(PIN_PA26, 1) -#define PIN_PA26__D4 PINMUX_PIN(PIN_PA26, 1) -#define PIN_PA26__NTRST PINMUX_PIN(PIN_PA26, 4) -#define PIN_PA26__SPI1_NPCS1 PINMUX_PIN(PIN_PA26, 2) -#define PIN_PA26__QSPI0_IO2 PINMUX_PIN(PIN_PA26, 3) +#define PIN_PA26__GPIO PINMUX_PIN(PIN_PA26, 0, 0) +#define PIN_PA26__FLEXCOM1_IO4 PINMUX_PIN(PIN_PA26, 1, 1) +#define PIN_PA26__D4 PINMUX_PIN(PIN_PA26, 2, 1) +#define PIN_PA26__NTRST PINMUX_PIN(PIN_PA26, 3, 4) +#define PIN_PA26__SPI1_NPCS1 PINMUX_PIN(PIN_PA26, 4, 2) +#define PIN_PA26__QSPI0_IO2 PINMUX_PIN(PIN_PA26, 6, 3) #define PIN_PA27 27 -#define PIN_PA27__TIOA1 PINMUX_PIN(PIN_PA27, 2) -#define PIN_PA27__D5 PINMUX_PIN(PIN_PA27, 1) -#define PIN_PA27__SPI0_NPCS2 PINMUX_PIN(PIN_PA27, 2) -#define PIN_PA27__SPI1_NPCS2 PINMUX_PIN(PIN_PA27, 2) -#define PIN_PA27__SDMMC1_RSTN PINMUX_PIN(PIN_PA27, 1) -#define PIN_PA27__QSPI0_IO3 PINMUX_PIN(PIN_PA27, 3) +#define PIN_PA27__GPIO PINMUX_PIN(PIN_PA27, 0, 0) +#define PIN_PA27__TIOA1 PINMUX_PIN(PIN_PA27, 1, 2) +#define PIN_PA27__D5 PINMUX_PIN(PIN_PA27, 2, 1) +#define PIN_PA27__SPI0_NPCS2 PINMUX_PIN(PIN_PA27, 3, 2) +#define PIN_PA27__SPI1_NPCS2 PINMUX_PIN(PIN_PA27, 4, 2) +#define PIN_PA27__SDMMC1_RSTN PINMUX_PIN(PIN_PA27, 5, 1) +#define PIN_PA27__QSPI0_IO3 PINMUX_PIN(PIN_PA27, 6, 3) #define PIN_PA28 28 -#define PIN_PA28__TIOB1 PINMUX_PIN(PIN_PA28, 2) -#define PIN_PA28__D6 PINMUX_PIN(PIN_PA28, 1) -#define PIN_PA28__SPI0_NPCS3 PINMUX_PIN(PIN_PA28, 2) -#define PIN_PA28__SPI1_NPCS3 PINMUX_PIN(PIN_PA28, 2) -#define PIN_PA28__SDMMC1_CMD PINMUX_PIN(PIN_PA28, 1) -#define PIN_PA28__CLASSD_L0 PINMUX_PIN(PIN_PA28, 1) +#define PIN_PA28__GPIO PINMUX_PIN(PIN_PA28, 0, 0) +#define PIN_PA28__TIOB1 PINMUX_PIN(PIN_PA28, 1, 2) +#define PIN_PA28__D6 PINMUX_PIN(PIN_PA28, 2, 1) +#define PIN_PA28__SPI0_NPCS3 PINMUX_PIN(PIN_PA28, 3, 2) +#define PIN_PA28__SPI1_NPCS3 PINMUX_PIN(PIN_PA28, 4, 2) +#define PIN_PA28__SDMMC1_CMD PINMUX_PIN(PIN_PA28, 5, 1) +#define PIN_PA28__CLASSD_L0 PINMUX_PIN(PIN_PA28, 6, 1) #define PIN_PA29 29 -#define PIN_PA29__TCLK1 PINMUX_PIN(PIN_PA29, 2) -#define PIN_PA29__D7 PINMUX_PIN(PIN_PA29, 1) -#define PIN_PA29__SPI0_NPCS1 PINMUX_PIN(PIN_PA29, 2) -#define PIN_PA29__SDMMC1_WP PINMUX_PIN(PIN_PA29, 1) -#define PIN_PA29__CLASSD_L1 PINMUX_PIN(PIN_PA29, 1) +#define PIN_PA29__GPIO PINMUX_PIN(PIN_PA29, 0, 0) +#define PIN_PA29__TCLK1 PINMUX_PIN(PIN_PA29, 1, 2) +#define PIN_PA29__D7 PINMUX_PIN(PIN_PA29, 2, 1) +#define PIN_PA29__SPI0_NPCS1 PINMUX_PIN(PIN_PA29, 3, 2) +#define PIN_PA29__SDMMC1_WP PINMUX_PIN(PIN_PA29, 5, 1) +#define PIN_PA29__CLASSD_L1 PINMUX_PIN(PIN_PA29, 6, 1) #define PIN_PA30 30 -#define PIN_PA30__NWE_NANDWE PINMUX_PIN(PIN_PA30, 1) -#define PIN_PA30__SPI0_NPCS0 PINMUX_PIN(PIN_PA30, 2) -#define PIN_PA30__PWMH0 PINMUX_PIN(PIN_PA30, 1) -#define PIN_PA30__SDMMC1_CD PINMUX_PIN(PIN_PA30, 1) -#define PIN_PA30__CLASSD_L2 PINMUX_PIN(PIN_PA30, 1) +#define PIN_PA30__GPIO PINMUX_PIN(PIN_PA30, 0, 0) +#define PIN_PA30__NWE_NANDWE PINMUX_PIN(PIN_PA30, 2, 1) +#define PIN_PA30__SPI0_NPCS0 PINMUX_PIN(PIN_PA30, 3, 2) +#define PIN_PA30__PWMH0 PINMUX_PIN(PIN_PA30, 4, 1) +#define PIN_PA30__SDMMC1_CD PINMUX_PIN(PIN_PA30, 5, 1) +#define PIN_PA30__CLASSD_L2 PINMUX_PIN(PIN_PA30, 6, 1) #define PIN_PA31 31 -#define PIN_PA31__NCS3 PINMUX_PIN(PIN_PA31, 1) -#define PIN_PA31__SPI0_MISO PINMUX_PIN(PIN_PA31, 2) -#define PIN_PA31__PWML0 PINMUX_PIN(PIN_PA31, 1) -#define PIN_PA31__CLASSD_L3 PINMUX_PIN(PIN_PA31, 1) +#define PIN_PA31__GPIO PINMUX_PIN(PIN_PA31, 0, 0) +#define PIN_PA31__NCS3 PINMUX_PIN(PIN_PA31, 2, 1) +#define PIN_PA31__SPI0_MISO PINMUX_PIN(PIN_PA31, 3, 2) +#define PIN_PA31__PWML0 PINMUX_PIN(PIN_PA31, 4, 1) +#define PIN_PA31__CLASSD_L3 PINMUX_PIN(PIN_PA31, 6, 1) #define PIN_PB0 32 -#define PIN_PB0__A21_NANDALE PINMUX_PIN(PIN_PB0, 1) -#define PIN_PB0__SPI0_MOSI PINMUX_PIN(PIN_PB0, 2) -#define PIN_PB0__PWMH1 PINMUX_PIN(PIN_PB0, 1) -#define PIN_PB0__PTC_PORT0 PINMUX_PIN(PIN_PB0, 1) +#define PIN_PB0__GPIO PINMUX_PIN(PIN_PB0, 0, 0) +#define PIN_PB0__A21_NANDALE PINMUX_PIN(PIN_PB0, 2, 1) +#define PIN_PB0__SPI0_MOSI PINMUX_PIN(PIN_PB0, 3, 2) +#define PIN_PB0__PWMH1 PINMUX_PIN(PIN_PB0, 4, 1) #define PIN_PB1 33 -#define PIN_PB1__A22_NANDCLE PINMUX_PIN(PIN_PB1, 1) -#define PIN_PB1__SPI0_SPCK PINMUX_PIN(PIN_PB1, 2) -#define PIN_PB1__PWML1 PINMUX_PIN(PIN_PB1, 1) -#define PIN_PB1__PTC_PORT1 PINMUX_PIN(PIN_PB1, 1) -#define PIN_PB1__CLASSD_R0 PINMUX_PIN(PIN_PB1, 1) +#define PIN_PB1__GPIO PINMUX_PIN(PIN_PB1, 0, 0) +#define PIN_PB1__A22_NANDCLE PINMUX_PIN(PIN_PB1, 2, 1) +#define PIN_PB1__SPI0_SPCK PINMUX_PIN(PIN_PB1, 3, 2) +#define PIN_PB1__PWML1 PINMUX_PIN(PIN_PB1, 4, 1) +#define PIN_PB1__CLASSD_R0 PINMUX_PIN(PIN_PB1, 6, 1) #define PIN_PB2 34 -#define PIN_PB2__NRD_NANDOE PINMUX_PIN(PIN_PB2, 1) -#define PIN_PB2__PWMFI0 PINMUX_PIN(PIN_PB2, 1) -#define PIN_PB2__PTC_PORT2 PINMUX_PIN(PIN_PB2, 1) -#define PIN_PB2__CLASSD_R1 PINMUX_PIN(PIN_PB2, 1) +#define PIN_PB2__GPIO PINMUX_PIN(PIN_PB2, 0, 0) +#define PIN_PB2__NRD_NANDOE PINMUX_PIN(PIN_PB2, 2, 1) +#define PIN_PB2__PWMFI0 PINMUX_PIN(PIN_PB2, 4, 1) +#define PIN_PB2__CLASSD_R1 PINMUX_PIN(PIN_PB2, 6, 1) #define PIN_PB3 35 -#define PIN_PB3__URXD4 PINMUX_PIN(PIN_PB3, 1) -#define PIN_PB3__D8 PINMUX_PIN(PIN_PB3, 1) -#define PIN_PB3__IRQ PINMUX_PIN(PIN_PB3, 3) -#define PIN_PB3__PWMEXTRG0 PINMUX_PIN(PIN_PB3, 1) -#define PIN_PB3__PTC_PORT3 PINMUX_PIN(PIN_PB3, 1) -#define PIN_PB3__CLASSD_R2 PINMUX_PIN(PIN_PB3, 1) +#define PIN_PB3__GPIO PINMUX_PIN(PIN_PB3, 0, 0) +#define PIN_PB3__URXD4 PINMUX_PIN(PIN_PB3, 1, 1) +#define PIN_PB3__D8 PINMUX_PIN(PIN_PB3, 2, 1) +#define PIN_PB3__IRQ PINMUX_PIN(PIN_PB3, 3, 3) +#define PIN_PB3__PWMEXTRG0 PINMUX_PIN(PIN_PB3, 4, 1) +#define PIN_PB3__CLASSD_R2 PINMUX_PIN(PIN_PB3, 6, 1) #define PIN_PB4 36 -#define PIN_PB4__UTXD4 PINMUX_PIN(PIN_PB4, 1) -#define PIN_PB4__D9 PINMUX_PIN(PIN_PB4, 1) -#define PIN_PB4__FIQ PINMUX_PIN(PIN_PB4, 4) -#define PIN_PB4__PTC_PORT4 PINMUX_PIN(PIN_PB4, 1) -#define PIN_PB4__CLASSD_R3 PINMUX_PIN(PIN_PB4, 1) +#define PIN_PB4__GPIO PINMUX_PIN(PIN_PB4, 0, 0) +#define PIN_PB4__UTXD4 PINMUX_PIN(PIN_PB4, 1, 1) +#define PIN_PB4__D9 PINMUX_PIN(PIN_PB4, 2, 1) +#define PIN_PB4__FIQ PINMUX_PIN(PIN_PB4, 3, 4) +#define PIN_PB4__CLASSD_R3 PINMUX_PIN(PIN_PB4, 6, 1) #define PIN_PB5 37 -#define PIN_PB5__TCLK2 PINMUX_PIN(PIN_PB5, 1) -#define PIN_PB5__D10 PINMUX_PIN(PIN_PB5, 1) -#define PIN_PB5__PWMH2 PINMUX_PIN(PIN_PB5, 1) -#define PIN_PB5__QSPI1_SCK PINMUX_PIN(PIN_PB5, 2) -#define PIN_PB5__PTC_PORT5 PINMUX_PIN(PIN_PB5, 1) -#define PIN_PB5__GTSUCOMP PINMUX_PIN(PIN_PB5, 3) +#define PIN_PB5__GPIO PINMUX_PIN(PIN_PB5, 0, 0) +#define PIN_PB5__TCLK2 PINMUX_PIN(PIN_PB5, 1, 1) +#define PIN_PB5__D10 PINMUX_PIN(PIN_PB5, 2, 1) +#define PIN_PB5__PWMH2 PINMUX_PIN(PIN_PB5, 3, 1) +#define PIN_PB5__QSPI1_SCK PINMUX_PIN(PIN_PB5, 4, 2) +#define PIN_PB5__GTSUCOMP PINMUX_PIN(PIN_PB5, 6, 3) #define PIN_PB6 38 -#define PIN_PB6__TIOA2 PINMUX_PIN(PIN_PB6, 1) -#define PIN_PB6__D11 PINMUX_PIN(PIN_PB6, 1) -#define PIN_PB6__PWML2 PINMUX_PIN(PIN_PB6, 1) -#define PIN_PB6__QSPI1_CS PINMUX_PIN(PIN_PB6, 2) -#define PIN_PB6__PTC_PORT6 PINMUX_PIN(PIN_PB6, 1) -#define PIN_PB6__GTXER PINMUX_PIN(PIN_PB6, 3) +#define PIN_PB6__GPIO PINMUX_PIN(PIN_PB6, 0, 0) +#define PIN_PB6__TIOA2 PINMUX_PIN(PIN_PB6, 1, 1) +#define PIN_PB6__D11 PINMUX_PIN(PIN_PB6, 2, 1) +#define PIN_PB6__PWML2 PINMUX_PIN(PIN_PB6, 3, 1) +#define PIN_PB6__QSPI1_CS PINMUX_PIN(PIN_PB6, 4, 2) +#define PIN_PB6__GTXER PINMUX_PIN(PIN_PB6, 6, 3) #define PIN_PB7 39 -#define PIN_PB7__TIOB2 PINMUX_PIN(PIN_PB7, 1) -#define PIN_PB7__D12 PINMUX_PIN(PIN_PB7, 1) -#define PIN_PB7__PWMH3 PINMUX_PIN(PIN_PB7, 1) -#define PIN_PB7__QSPI1_IO0 PINMUX_PIN(PIN_PB7, 2) -#define PIN_PB7__PTC_PORT7 PINMUX_PIN(PIN_PB7, 1) -#define PIN_PB7__GRXCK PINMUX_PIN(PIN_PB7, 3) +#define PIN_PB7__GPIO PINMUX_PIN(PIN_PB7, 0, 0) +#define PIN_PB7__TIOB2 PINMUX_PIN(PIN_PB7, 1, 1) +#define PIN_PB7__D12 PINMUX_PIN(PIN_PB7, 2, 1) +#define PIN_PB7__PWMH3 PINMUX_PIN(PIN_PB7, 3, 1) +#define PIN_PB7__QSPI1_IO0 PINMUX_PIN(PIN_PB7, 4, 2) +#define PIN_PB7__GRXCK PINMUX_PIN(PIN_PB7, 6, 3) #define PIN_PB8 40 -#define PIN_PB8__TCLK3 PINMUX_PIN(PIN_PB8, 1) -#define PIN_PB8__D13 PINMUX_PIN(PIN_PB8, 1) -#define PIN_PB8__PWML3 PINMUX_PIN(PIN_PB8, 1) -#define PIN_PB8__QSPI1_IO1 PINMUX_PIN(PIN_PB8, 2) -#define PIN_PB8__GTSUCOMP PINMUX_PIN(PIN_PB8, 3) +#define PIN_PB8__GPIO PINMUX_PIN(PIN_PB8, 0, 0) +#define PIN_PB8__TCLK3 PINMUX_PIN(PIN_PB8, 1, 1) +#define PIN_PB8__D13 PINMUX_PIN(PIN_PB8, 2, 1) +#define PIN_PB8__PWML3 PINMUX_PIN(PIN_PB8, 3, 1) +#define PIN_PB8__QSPI1_IO1 PINMUX_PIN(PIN_PB8, 4, 2) +#define PIN_PB8__GCRS PINMUX_PIN(PIN_PB8, 6, 3) #define PIN_PB9 41 -#define PIN_PB9__TIOA3 PINMUX_PIN(PIN_PB9, 1) -#define PIN_PB9__D14 PINMUX_PIN(PIN_PB9, 1) -#define PIN_PB9__PWMFI1 PINMUX_PIN(PIN_PB9, 1) -#define PIN_PB9__QSPI1_IO2 PINMUX_PIN(PIN_PB9, 2) -#define PIN_PB9__GCOL PINMUX_PIN(PIN_PB9, 3) +#define PIN_PB9__GPIO PINMUX_PIN(PIN_PB9, 0, 0) +#define PIN_PB9__TIOA3 PINMUX_PIN(PIN_PB9, 1, 1) +#define PIN_PB9__D14 PINMUX_PIN(PIN_PB9, 2, 1) +#define PIN_PB9__PWMFI1 PINMUX_PIN(PIN_PB9, 3, 1) +#define PIN_PB9__QSPI1_IO2 PINMUX_PIN(PIN_PB9, 4, 2) +#define PIN_PB9__GCOL PINMUX_PIN(PIN_PB9, 6, 3) #define PIN_PB10 42 -#define PIN_PB10__TIOB3 PINMUX_PIN(PIN_PB10, 1) -#define PIN_PB10__D15 PINMUX_PIN(PIN_PB10, 1) -#define PIN_PB10__PWMEXTRG1 PINMUX_PIN(PIN_PB10, 1) -#define PIN_PB10__QSPI1_IO3 PINMUX_PIN(PIN_PB10, 2) -#define PIN_PB10__GRX2 PINMUX_PIN(PIN_PB10, 3) +#define PIN_PB10__GPIO PINMUX_PIN(PIN_PB10, 0, 0) +#define PIN_PB10__TIOB3 PINMUX_PIN(PIN_PB10, 1, 1) +#define PIN_PB10__D15 PINMUX_PIN(PIN_PB10, 2, 1) +#define PIN_PB10__PWMEXTRG1 PINMUX_PIN(PIN_PB10, 3, 1) +#define PIN_PB10__QSPI1_IO3 PINMUX_PIN(PIN_PB10, 4, 2) +#define PIN_PB10__GRX2 PINMUX_PIN(PIN_PB10, 6, 3) #define PIN_PB11 43 -#define PIN_PB11__LCDDAT0 PINMUX_PIN(PIN_PB11, 1) -#define PIN_PB11__A0_NBS0 PINMUX_PIN(PIN_PB11, 1) -#define PIN_PB11__URXD3 PINMUX_PIN(PIN_PB11, 3) -#define PIN_PB11__PDMIC_DAT0 PINMUX_PIN(PIN_PB11, 2) -#define PIN_PB11__GRX3 PINMUX_PIN(PIN_PB11, 3) +#define PIN_PB11__GPIO PINMUX_PIN(PIN_PB11, 0, 0) +#define PIN_PB11__LCDDAT0 PINMUX_PIN(PIN_PB11, 1, 1) +#define PIN_PB11__A0_NBS0 PINMUX_PIN(PIN_PB11, 2, 1) +#define PIN_PB11__URXD3 PINMUX_PIN(PIN_PB11, 3, 3) +#define PIN_PB11__PDMIC_DAT PINMUX_PIN(PIN_PB11, 4, 2) +#define PIN_PB11__GRX3 PINMUX_PIN(PIN_PB11, 6, 3) #define PIN_PB12 44 -#define PIN_PB12__LCDDAT1 PINMUX_PIN(PIN_PB12, 1) -#define PIN_PB12__A1 PINMUX_PIN(PIN_PB12, 1) -#define PIN_PB12__UTXD3 PINMUX_PIN(PIN_PB12, 3) -#define PIN_PB12__PDMIC_CLK0 PINMUX_PIN(PIN_PB12, 2) -#define PIN_PB12__GTX2 PINMUX_PIN(PIN_PB12, 3) +#define PIN_PB12__GPIO PINMUX_PIN(PIN_PB12, 0, 0) +#define PIN_PB12__LCDDAT1 PINMUX_PIN(PIN_PB12, 1, 1) +#define PIN_PB12__A1 PINMUX_PIN(PIN_PB12, 2, 1) +#define PIN_PB12__UTXD3 PINMUX_PIN(PIN_PB12, 3, 3) +#define PIN_PB12__PDMIC_CLK PINMUX_PIN(PIN_PB12, 4, 2) +#define PIN_PB12__GTX2 PINMUX_PIN(PIN_PB12, 6, 3) #define PIN_PB13 45 -#define PIN_PB13__LCDDAT2 PINMUX_PIN(PIN_PB13, 1) -#define PIN_PB13__A2 PINMUX_PIN(PIN_PB13, 1) -#define PIN_PB13__PCK1 PINMUX_PIN(PIN_PB13, 3) -#define PIN_PB13__GTX3 PINMUX_PIN(PIN_PB13, 3) +#define PIN_PB13__GPIO PINMUX_PIN(PIN_PB13, 0, 0) +#define PIN_PB13__LCDDAT2 PINMUX_PIN(PIN_PB13, 1, 1) +#define PIN_PB13__A2 PINMUX_PIN(PIN_PB13, 2, 1) +#define PIN_PB13__PCK1 PINMUX_PIN(PIN_PB13, 3, 3) +#define PIN_PB13__GTX3 PINMUX_PIN(PIN_PB13, 6, 3) #define PIN_PB14 46 -#define PIN_PB14__LCDDAT3 PINMUX_PIN(PIN_PB14, 1) -#define PIN_PB14__A3 PINMUX_PIN(PIN_PB14, 1) -#define PIN_PB14__TK1 PINMUX_PIN(PIN_PB14, 2) -#define PIN_PB14__I2SMCK1 PINMUX_PIN(PIN_PB14, 1) -#define PIN_PB14__QSPI1_SCK PINMUX_PIN(PIN_PB14, 3) -#define PIN_PB14__GTXCK PINMUX_PIN(PIN_PB14, 3) +#define PIN_PB14__GPIO PINMUX_PIN(PIN_PB14, 0, 0) +#define PIN_PB14__LCDDAT3 PINMUX_PIN(PIN_PB14, 1, 1) +#define PIN_PB14__A3 PINMUX_PIN(PIN_PB14, 2, 1) +#define PIN_PB14__TK1 PINMUX_PIN(PIN_PB14, 3, 2) +#define PIN_PB14__I2SC1_MCK PINMUX_PIN(PIN_PB14, 4, 1) +#define PIN_PB14__QSPI1_SCK PINMUX_PIN(PIN_PB14, 5, 3) +#define PIN_PB14__GTXCK PINMUX_PIN(PIN_PB14, 6, 3) #define PIN_PB15 47 -#define PIN_PB15__LCDDAT4 PINMUX_PIN(PIN_PB15, 1) -#define PIN_PB15__A4 PINMUX_PIN(PIN_PB15, 1) -#define PIN_PB15__TF1 PINMUX_PIN(PIN_PB15, 2) -#define PIN_PB15__I2SCK1 PINMUX_PIN(PIN_PB15, 1) -#define PIN_PB15__QSPI1_CS PINMUX_PIN(PIN_PB15, 3) -#define PIN_PB15__GTXEN PINMUX_PIN(PIN_PB15, 3) +#define PIN_PB15__GPIO PINMUX_PIN(PIN_PB15, 0, 0) +#define PIN_PB15__LCDDAT4 PINMUX_PIN(PIN_PB15, 1, 1) +#define PIN_PB15__A4 PINMUX_PIN(PIN_PB15, 2, 1) +#define PIN_PB15__TF1 PINMUX_PIN(PIN_PB15, 3, 2) +#define PIN_PB15__I2SC1_CK PINMUX_PIN(PIN_PB15, 4, 1) +#define PIN_PB15__QSPI1_CS PINMUX_PIN(PIN_PB15, 5, 3) +#define PIN_PB15__GTXEN PINMUX_PIN(PIN_PB15, 6, 3) #define PIN_PB16 48 -#define PIN_PB16__LCDDAT5 PINMUX_PIN(PIN_PB16, 1) -#define PIN_PB16__A5 PINMUX_PIN(PIN_PB16, 1) -#define PIN_PB16__TD1 PINMUX_PIN(PIN_PB16, 2) -#define PIN_PB16__I2SWS1 PINMUX_PIN(PIN_PB16, 1) -#define PIN_PB16__QSPI1_IO0 PINMUX_PIN(PIN_PB16, 3) -#define PIN_PB16__GRXDV PINMUX_PIN(PIN_PB16, 3) +#define PIN_PB16__GPIO PINMUX_PIN(PIN_PB16, 0, 0) +#define PIN_PB16__LCDDAT5 PINMUX_PIN(PIN_PB16, 1, 1) +#define PIN_PB16__A5 PINMUX_PIN(PIN_PB16, 2, 1) +#define PIN_PB16__TD1 PINMUX_PIN(PIN_PB16, 3, 2) +#define PIN_PB16__I2SC1_WS PINMUX_PIN(PIN_PB16, 4, 1) +#define PIN_PB16__QSPI1_IO0 PINMUX_PIN(PIN_PB16, 5, 3) +#define PIN_PB16__GRXDV PINMUX_PIN(PIN_PB16, 6, 3) #define PIN_PB17 49 -#define PIN_PB17__LCDDAT6 PINMUX_PIN(PIN_PB17, 1) -#define PIN_PB17__A6 PINMUX_PIN(PIN_PB17, 1) -#define PIN_PB17__RD1 PINMUX_PIN(PIN_PB17, 2) -#define PIN_PB17__I2SDI1 PINMUX_PIN(PIN_PB17, 1) -#define PIN_PB17__QSPI1_IO1 PINMUX_PIN(PIN_PB17, 3) -#define PIN_PB17__GRXER PINMUX_PIN(PIN_PB17, 3) +#define PIN_PB17__GPIO PINMUX_PIN(PIN_PB17, 0, 0) +#define PIN_PB17__LCDDAT6 PINMUX_PIN(PIN_PB17, 1, 1) +#define PIN_PB17__A6 PINMUX_PIN(PIN_PB17, 2, 1) +#define PIN_PB17__RD1 PINMUX_PIN(PIN_PB17, 3, 2) +#define PIN_PB17__I2SC1_DI0 PINMUX_PIN(PIN_PB17, 4, 1) +#define PIN_PB17__QSPI1_IO1 PINMUX_PIN(PIN_PB17, 5, 3) +#define PIN_PB17__GRXER PINMUX_PIN(PIN_PB17, 6, 3) #define PIN_PB18 50 -#define PIN_PB18__LCDDAT7 PINMUX_PIN(PIN_PB18, 1) -#define PIN_PB18__A7 PINMUX_PIN(PIN_PB18, 1) -#define PIN_PB18__RK1 PINMUX_PIN(PIN_PB18, 2) -#define PIN_PB18__I2SDO1 PINMUX_PIN(PIN_PB18, 1) -#define PIN_PB18__QSPI1_IO2 PINMUX_PIN(PIN_PB18, 3) -#define PIN_PB18__GRX0 PINMUX_PIN(PIN_PB18, 3) +#define PIN_PB18__GPIO PINMUX_PIN(PIN_PB18, 0, 0) +#define PIN_PB18__LCDDAT7 PINMUX_PIN(PIN_PB18, 1, 1) +#define PIN_PB18__A7 PINMUX_PIN(PIN_PB18, 2, 1) +#define PIN_PB18__RK1 PINMUX_PIN(PIN_PB18, 3, 2) +#define PIN_PB18__I2SC1_DO0 PINMUX_PIN(PIN_PB18, 4, 1) +#define PIN_PB18__QSPI1_IO2 PINMUX_PIN(PIN_PB18, 5, 3) +#define PIN_PB18__GRX0 PINMUX_PIN(PIN_PB18, 6, 3) #define PIN_PB19 51 -#define PIN_PB19__LCDDAT8 PINMUX_PIN(PIN_PB19, 1) -#define PIN_PB19__A8 PINMUX_PIN(PIN_PB19, 1) -#define PIN_PB19__RF1 PINMUX_PIN(PIN_PB19, 2) -#define PIN_PB19__TIOA3 PINMUX_PIN(PIN_PB19, 2) -#define PIN_PB19__QSPI1_IO3 PINMUX_PIN(PIN_PB19, 3) -#define PIN_PB19__GRX1 PINMUX_PIN(PIN_PB19, 3) +#define PIN_PB19__GPIO PINMUX_PIN(PIN_PB19, 0, 0) +#define PIN_PB19__LCDDAT8 PINMUX_PIN(PIN_PB19, 1, 1) +#define PIN_PB19__A8 PINMUX_PIN(PIN_PB19, 2, 1) +#define PIN_PB19__RF1 PINMUX_PIN(PIN_PB19, 3, 2) +#define PIN_PB19__TIOA3 PINMUX_PIN(PIN_PB19, 4, 2) +#define PIN_PB19__QSPI1_IO3 PINMUX_PIN(PIN_PB19, 5, 3) +#define PIN_PB19__GRX1 PINMUX_PIN(PIN_PB19, 6, 3) #define PIN_PB20 52 -#define PIN_PB20__LCDDAT9 PINMUX_PIN(PIN_PB20, 1) -#define PIN_PB20__A9 PINMUX_PIN(PIN_PB20, 1) -#define PIN_PB20__TK0 PINMUX_PIN(PIN_PB20, 1) -#define PIN_PB20__TIOB3 PINMUX_PIN(PIN_PB20, 2) -#define PIN_PB20__PCK1 PINMUX_PIN(PIN_PB20, 4) -#define PIN_PB20__GTX0 PINMUX_PIN(PIN_PB20, 3) +#define PIN_PB20__GPIO PINMUX_PIN(PIN_PB20, 0, 0) +#define PIN_PB20__LCDDAT9 PINMUX_PIN(PIN_PB20, 1, 1) +#define PIN_PB20__A9 PINMUX_PIN(PIN_PB20, 2, 1) +#define PIN_PB20__TK0 PINMUX_PIN(PIN_PB20, 3, 1) +#define PIN_PB20__TIOB3 PINMUX_PIN(PIN_PB20, 4, 2) +#define PIN_PB20__PCK1 PINMUX_PIN(PIN_PB20, 5, 4) +#define PIN_PB20__GTX0 PINMUX_PIN(PIN_PB20, 6, 3) #define PIN_PB21 53 -#define PIN_PB21__LCDDAT10 PINMUX_PIN(PIN_PB21, 1) -#define PIN_PB21__A10 PINMUX_PIN(PIN_PB21, 1) -#define PIN_PB21__TF0 PINMUX_PIN(PIN_PB21, 1) -#define PIN_PB21__TCLK3 PINMUX_PIN(PIN_PB21, 2) -#define PIN_PB21__FLEXCOM3_IO2 PINMUX_PIN(PIN_PB21, 3) -#define PIN_PB21__GTX1 PINMUX_PIN(PIN_PB21, 3) +#define PIN_PB21__GPIO PINMUX_PIN(PIN_PB21, 0, 0) +#define PIN_PB21__LCDDAT10 PINMUX_PIN(PIN_PB21, 1, 1) +#define PIN_PB21__A10 PINMUX_PIN(PIN_PB21, 2, 1) +#define PIN_PB21__TF0 PINMUX_PIN(PIN_PB21, 3, 1) +#define PIN_PB21__TCLK3 PINMUX_PIN(PIN_PB21, 4, 2) +#define PIN_PB21__FLEXCOM3_IO2 PINMUX_PIN(PIN_PB21, 5, 3) +#define PIN_PB21__GTX1 PINMUX_PIN(PIN_PB21, 6, 3) #define PIN_PB22 54 -#define PIN_PB22__LCDDAT11 PINMUX_PIN(PIN_PB22, 1) -#define PIN_PB22__A11 PINMUX_PIN(PIN_PB22, 1) -#define PIN_PB22__TDO PINMUX_PIN(PIN_PB22, 1) -#define PIN_PB22__TIOA2 PINMUX_PIN(PIN_PB22, 2) -#define PIN_PB22__FLEXCOM3_IO1 PINMUX_PIN(PIN_PB22, 3) -#define PIN_PB22__GMDC PINMUX_PIN(PIN_PB22, 3) +#define PIN_PB22__GPIO PINMUX_PIN(PIN_PB22, 0, 0) +#define PIN_PB22__LCDDAT11 PINMUX_PIN(PIN_PB22, 1, 1) +#define PIN_PB22__A11 PINMUX_PIN(PIN_PB22, 2, 1) +#define PIN_PB22__TDO PINMUX_PIN(PIN_PB22, 3, 1) +#define PIN_PB22__TIOA2 PINMUX_PIN(PIN_PB22, 4, 2) +#define PIN_PB22__FLEXCOM3_IO1 PINMUX_PIN(PIN_PB22, 5, 3) +#define PIN_PB22__GMDC PINMUX_PIN(PIN_PB22, 6, 3) #define PIN_PB23 55 -#define PIN_PB23__LCDDAT12 PINMUX_PIN(PIN_PB23, 1) -#define PIN_PB23__A12 PINMUX_PIN(PIN_PB23, 1) -#define PIN_PB23__RD0 PINMUX_PIN(PIN_PB23, 1) -#define PIN_PB23__TIOB2 PINMUX_PIN(PIN_PB23, 2) -#define PIN_PB23__FLEXCOM3_IO0 PINMUX_PIN(PIN_PB23, 3) -#define PIN_PB23__GMDIO PINMUX_PIN(PIN_PB23, 3) +#define PIN_PB23__GPIO PINMUX_PIN(PIN_PB23, 0, 0) +#define PIN_PB23__LCDDAT12 PINMUX_PIN(PIN_PB23, 1, 1) +#define PIN_PB23__A12 PINMUX_PIN(PIN_PB23, 2, 1) +#define PIN_PB23__RD0 PINMUX_PIN(PIN_PB23, 3, 1) +#define PIN_PB23__TIOB2 PINMUX_PIN(PIN_PB23, 4, 2) +#define PIN_PB23__FLEXCOM3_IO0 PINMUX_PIN(PIN_PB23, 5, 3) +#define PIN_PB23__GMDIO PINMUX_PIN(PIN_PB23, 6, 3) #define PIN_PB24 56 -#define PIN_PB24__LCDDAT13 PINMUX_PIN(PIN_PB24, 1) -#define PIN_PB24__A13 PINMUX_PIN(PIN_PB24, 1) -#define PIN_PB24__RK0 PINMUX_PIN(PIN_PB24, 1) -#define PIN_PB24__TCLK2 PINMUX_PIN(PIN_PB24, 2) -#define PIN_PB24__FLEXCOM3_IO3 PINMUX_PIN(PIN_PB24, 3) -#define PIN_PB24__ISI_D10 PINMUX_PIN(PIN_PB24, 3) +#define PIN_PB24__GPIO PINMUX_PIN(PIN_PB24, 0, 0) +#define PIN_PB24__LCDDAT13 PINMUX_PIN(PIN_PB24, 1, 1) +#define PIN_PB24__A13 PINMUX_PIN(PIN_PB24, 2, 1) +#define PIN_PB24__RK0 PINMUX_PIN(PIN_PB24, 3, 1) +#define PIN_PB24__TCLK2 PINMUX_PIN(PIN_PB24, 4, 2) +#define PIN_PB24__FLEXCOM3_IO3 PINMUX_PIN(PIN_PB24, 5, 3) +#define PIN_PB24__ISC_D10 PINMUX_PIN(PIN_PB24, 6, 3) #define PIN_PB25 57 -#define PIN_PB25__LCDDAT14 PINMUX_PIN(PIN_PB25, 1) -#define PIN_PB25__A14 PINMUX_PIN(PIN_PB25, 1) -#define PIN_PB25__RF0 PINMUX_PIN(PIN_PB25, 1) -#define PIN_PB25__FLEXCOM3_IO4 PINMUX_PIN(PIN_PB25, 3) -#define PIN_PB25__ISI_D11 PINMUX_PIN(PIN_PB25, 3) +#define PIN_PB25__GPIO PINMUX_PIN(PIN_PB25, 0, 0) +#define PIN_PB25__LCDDAT14 PINMUX_PIN(PIN_PB25, 1, 1) +#define PIN_PB25__A14 PINMUX_PIN(PIN_PB25, 2, 1) +#define PIN_PB25__RF0 PINMUX_PIN(PIN_PB25, 3, 1) +#define PIN_PB25__FLEXCOM3_IO4 PINMUX_PIN(PIN_PB25, 5, 3) +#define PIN_PB25__ISC_D11 PINMUX_PIN(PIN_PB25, 6, 3) #define PIN_PB26 58 -#define PIN_PB26__LCDDAT15 PINMUX_PIN(PIN_PB26, 1) -#define PIN_PB26__A15 PINMUX_PIN(PIN_PB26, 1) -#define PIN_PB26__URXD0 PINMUX_PIN(PIN_PB26, 1) -#define PIN_PB26__PDMIC_DAT0 PINMUX_PIN(PIN_PB26, 1) -#define PIN_PB26__ISI_D0 PINMUX_PIN(PIN_PB26, 3) +#define PIN_PB26__GPIO PINMUX_PIN(PIN_PB26, 0, 0) +#define PIN_PB26__LCDDAT15 PINMUX_PIN(PIN_PB26, 1, 1) +#define PIN_PB26__A15 PINMUX_PIN(PIN_PB26, 2, 1) +#define PIN_PB26__URXD0 PINMUX_PIN(PIN_PB26, 3, 1) +#define PIN_PB26__PDMIC_DAT PINMUX_PIN(PIN_PB26, 4, 1) +#define PIN_PB26__ISC_D0 PINMUX_PIN(PIN_PB26, 6, 3) #define PIN_PB27 59 -#define PIN_PB27__LCDDAT16 PINMUX_PIN(PIN_PB27, 1) -#define PIN_PB27__A16 PINMUX_PIN(PIN_PB27, 1) -#define PIN_PB27__UTXD0 PINMUX_PIN(PIN_PB27, 1) -#define PIN_PB27__PDMIC_CLK0 PINMUX_PIN(PIN_PB27, 1) -#define PIN_PB27__ISI_D1 PINMUX_PIN(PIN_PB27, 3) +#define PIN_PB27__GPIO PINMUX_PIN(PIN_PB27, 0, 0) +#define PIN_PB27__LCDDAT16 PINMUX_PIN(PIN_PB27, 1, 1) +#define PIN_PB27__A16 PINMUX_PIN(PIN_PB27, 2, 1) +#define PIN_PB27__UTXD0 PINMUX_PIN(PIN_PB27, 3, 1) +#define PIN_PB27__PDMIC_CLK PINMUX_PIN(PIN_PB27, 4, 1) +#define PIN_PB27__ISC_D1 PINMUX_PIN(PIN_PB27, 6, 3) #define PIN_PB28 60 -#define PIN_PB28__LCDDAT17 PINMUX_PIN(PIN_PB28, 1) -#define PIN_PB28__A17 PINMUX_PIN(PIN_PB28, 1) -#define PIN_PB28__FLEXCOM0_IO0 PINMUX_PIN(PIN_PB28, 1) -#define PIN_PB28__TIOA5 PINMUX_PIN(PIN_PB28, 2) -#define PIN_PB28__ISI_D2 PINMUX_PIN(PIN_PB28, 3) +#define PIN_PB28__GPIO PINMUX_PIN(PIN_PB28, 0, 0) +#define PIN_PB28__LCDDAT17 PINMUX_PIN(PIN_PB28, 1, 1) +#define PIN_PB28__A17 PINMUX_PIN(PIN_PB28, 2, 1) +#define PIN_PB28__FLEXCOM0_IO0 PINMUX_PIN(PIN_PB28, 3, 1) +#define PIN_PB28__TIOA5 PINMUX_PIN(PIN_PB28, 4, 2) +#define PIN_PB28__ISC_D2 PINMUX_PIN(PIN_PB28, 6, 3) #define PIN_PB29 61 -#define PIN_PB29__LCDDAT18 PINMUX_PIN(PIN_PB29, 1) -#define PIN_PB29__A18 PINMUX_PIN(PIN_PB29, 1) -#define PIN_PB29__FLEXCOM0_IO1 PINMUX_PIN(PIN_PB29, 1) -#define PIN_PB29__TIOB5 PINMUX_PIN(PIN_PB29, 2) -#define PIN_PB29__ISI_D3 PINMUX_PIN(PIN_PB29, 3) +#define PIN_PB29__GPIO PINMUX_PIN(PIN_PB29, 0, 0) +#define PIN_PB29__LCDDAT18 PINMUX_PIN(PIN_PB29, 1, 1) +#define PIN_PB29__A18 PINMUX_PIN(PIN_PB29, 2, 1) +#define PIN_PB29__FLEXCOM0_IO1 PINMUX_PIN(PIN_PB29, 3, 1) +#define PIN_PB29__TIOB5 PINMUX_PIN(PIN_PB29, 4, 2) +#define PIN_PB29__ISC_D3 PINMUX_PIN(PIN_PB29, 7, 3) #define PIN_PB30 62 -#define PIN_PB30__LCDDAT19 PINMUX_PIN(PIN_PB30, 1) -#define PIN_PB30__A19 PINMUX_PIN(PIN_PB30, 1) -#define PIN_PB30__FLEXCOM0_IO2 PINMUX_PIN(PIN_PB30, 1) -#define PIN_PB30__TCLK5 PINMUX_PIN(PIN_PB30, 2) -#define PIN_PB30__ISI_D4 PINMUX_PIN(PIN_PB30, 3) +#define PIN_PB30__GPIO PINMUX_PIN(PIN_PB30, 0, 0) +#define PIN_PB30__LCDDAT19 PINMUX_PIN(PIN_PB30, 1, 1) +#define PIN_PB30__A19 PINMUX_PIN(PIN_PB30, 2, 1) +#define PIN_PB30__FLEXCOM0_IO2 PINMUX_PIN(PIN_PB30, 3, 1) +#define PIN_PB30__TCLK5 PINMUX_PIN(PIN_PB30, 4, 2) +#define PIN_PB30__ISC_D4 PINMUX_PIN(PIN_PB30, 6, 3) #define PIN_PB31 63 -#define PIN_PB31__LCDDAT20 PINMUX_PIN(PIN_PB31, 1) -#define PIN_PB31__A20 PINMUX_PIN(PIN_PB31, 1) -#define PIN_PB31__FLEXCOM0_IO3 PINMUX_PIN(PIN_PB31, 1) -#define PIN_PB31__TWD0 PINMUX_PIN(PIN_PB31, 1) -#define PIN_PB31__ISI_D5 PINMUX_PIN(PIN_PB31, 3) +#define PIN_PB31__GPIO PINMUX_PIN(PIN_PB31, 0, 0) +#define PIN_PB31__LCDDAT20 PINMUX_PIN(PIN_PB31, 1, 1) +#define PIN_PB31__A20 PINMUX_PIN(PIN_PB31, 2, 1) +#define PIN_PB31__FLEXCOM0_IO3 PINMUX_PIN(PIN_PB31, 3, 1) +#define PIN_PB31__TWD0 PINMUX_PIN(PIN_PB31, 4, 1) +#define PIN_PB31__ISC_D5 PINMUX_PIN(PIN_PB31, 6, 3) #define PIN_PC0 64 -#define PIN_PC0__LCDDAT21 PINMUX_PIN(PIN_PC0, 1) -#define PIN_PC0__A23 PINMUX_PIN(PIN_PC0, 1) -#define PIN_PC0__FLEXCOM0_IO4 PINMUX_PIN(PIN_PC0, 1) -#define PIN_PC0__TWCK0 PINMUX_PIN(PIN_PC0, 1) -#define PIN_PC0__ISI_D6 PINMUX_PIN(PIN_PC0, 3) +#define PIN_PC0__GPIO PINMUX_PIN(PIN_PC0, 0, 0) +#define PIN_PC0__LCDDAT21 PINMUX_PIN(PIN_PC0, 1, 1) +#define PIN_PC0__A23 PINMUX_PIN(PIN_PC0, 2, 1) +#define PIN_PC0__FLEXCOM0_IO4 PINMUX_PIN(PIN_PC0, 3, 1) +#define PIN_PC0__TWCK0 PINMUX_PIN(PIN_PC0, 4, 1) +#define PIN_PC0__ISC_D6 PINMUX_PIN(PIN_PC0, 6, 3) #define PIN_PC1 65 -#define PIN_PC1__LCDDAT22 PINMUX_PIN(PIN_PC1, 1) -#define PIN_PC1__A24 PINMUX_PIN(PIN_PC1, 1) -#define PIN_PC1__CANTX0 PINMUX_PIN(PIN_PC1, 1) -#define PIN_PC1__SPI1_SPCK PINMUX_PIN(PIN_PC1, 1) -#define PIN_PC1__I2SCK0 PINMUX_PIN(PIN_PC1, 1) -#define PIN_PC1__ISI_D7 PINMUX_PIN(PIN_PC1, 3) +#define PIN_PC1__GPIO PINMUX_PIN(PIN_PC1, 0, 0) +#define PIN_PC1__LCDDAT22 PINMUX_PIN(PIN_PC1, 1, 1) +#define PIN_PC1__A24 PINMUX_PIN(PIN_PC1, 2, 1) +#define PIN_PC1__CANTX0 PINMUX_PIN(PIN_PC1, 3, 1) +#define PIN_PC1__SPI1_SPCK PINMUX_PIN(PIN_PC1, 4, 1) +#define PIN_PC1__I2SC0_CK PINMUX_PIN(PIN_PC1, 5, 1) +#define PIN_PC1__ISC_D7 PINMUX_PIN(PIN_PC1, 6, 3) #define PIN_PC2 66 -#define PIN_PC2__LCDDAT23 PINMUX_PIN(PIN_PC2, 1) -#define PIN_PC2__A25 PINMUX_PIN(PIN_PC2, 1) -#define PIN_PC2__CANRX0 PINMUX_PIN(PIN_PC2, 1) -#define PIN_PC2__SPI1_MOSI PINMUX_PIN(PIN_PC2, 1) -#define PIN_PC2__I2SMCK0 PINMUX_PIN(PIN_PC2, 1) -#define PIN_PC2__ISI_D8 PINMUX_PIN(PIN_PC2, 3) +#define PIN_PC2__GPIO PINMUX_PIN(PIN_PC2, 0, 0) +#define PIN_PC2__LCDDAT23 PINMUX_PIN(PIN_PC2, 1, 1) +#define PIN_PC2__A25 PINMUX_PIN(PIN_PC2, 2, 1) +#define PIN_PC2__CANRX0 PINMUX_PIN(PIN_PC2, 3, 1) +#define PIN_PC2__SPI1_MOSI PINMUX_PIN(PIN_PC2, 4, 1) +#define PIN_PC2__I2SC0_MCK PINMUX_PIN(PIN_PC2, 5, 1) +#define PIN_PC2__ISC_D8 PINMUX_PIN(PIN_PC2, 6, 3) #define PIN_PC3 67 -#define PIN_PC3__LCDPWM PINMUX_PIN(PIN_PC3, 1) -#define PIN_PC3__NWAIT PINMUX_PIN(PIN_PC3, 1) -#define PIN_PC3__TIOA1 PINMUX_PIN(PIN_PC3, 1) -#define PIN_PC3__SPI1_MISO PINMUX_PIN(PIN_PC3, 1) -#define PIN_PC3__I2SWS0 PINMUX_PIN(PIN_PC3, 1) -#define PIN_PC3__ISI_D9 PINMUX_PIN(PIN_PC3, 3) +#define PIN_PC3__GPIO PINMUX_PIN(PIN_PC3, 0, 0) +#define PIN_PC3__LCDPWM PINMUX_PIN(PIN_PC3, 1, 1) +#define PIN_PC3__NWAIT PINMUX_PIN(PIN_PC3, 2, 1) +#define PIN_PC3__TIOA1 PINMUX_PIN(PIN_PC3, 3, 1) +#define PIN_PC3__SPI1_MISO PINMUX_PIN(PIN_PC3, 4, 1) +#define PIN_PC3__I2SC0_WS PINMUX_PIN(PIN_PC3, 5, 1) +#define PIN_PC3__ISC_D9 PINMUX_PIN(PIN_PC3, 6, 3) #define PIN_PC4 68 -#define PIN_PC4__LCDDISP PINMUX_PIN(PIN_PC4, 1) -#define PIN_PC4__NWR1_NBS1 PINMUX_PIN(PIN_PC4, 1) -#define PIN_PC4__TIOB1 PINMUX_PIN(PIN_PC4, 1) -#define PIN_PC4__SPI1_NPCS0 PINMUX_PIN(PIN_PC4, 1) -#define PIN_PC4__I2SDI0 PINMUX_PIN(PIN_PC4, 1) -#define PIN_PC4__ISI_PCK PINMUX_PIN(PIN_PC4, 3) +#define PIN_PC4__GPIO PINMUX_PIN(PIN_PC4, 0, 0) +#define PIN_PC4__LCDDISP PINMUX_PIN(PIN_PC4, 1, 1) +#define PIN_PC4__NWR1_NBS1 PINMUX_PIN(PIN_PC4, 2, 1) +#define PIN_PC4__TIOB1 PINMUX_PIN(PIN_PC4, 3, 1) +#define PIN_PC4__SPI1_NPCS0 PINMUX_PIN(PIN_PC4, 4, 1) +#define PIN_PC4__I2SC0_DI0 PINMUX_PIN(PIN_PC4, 5, 1) +#define PIN_PC4__ISC_PCK PINMUX_PIN(PIN_PC4, 6, 3) #define PIN_PC5 69 -#define PIN_PC5__LCDVSYNC PINMUX_PIN(PIN_PC5, 1) -#define PIN_PC5__NCS0 PINMUX_PIN(PIN_PC5, 1) -#define PIN_PC5__TCLK1 PINMUX_PIN(PIN_PC5, 1) -#define PIN_PC5__SPI1_NPCS1 PINMUX_PIN(PIN_PC5, 1) -#define PIN_PC5__I2SDO0 PINMUX_PIN(PIN_PC5, 1) -#define PIN_PC5__ISI_VSYNC PINMUX_PIN(PIN_PC5, 3) +#define PIN_PC5__GPIO PINMUX_PIN(PIN_PC5, 0, 0) +#define PIN_PC5__LCDVSYNC PINMUX_PIN(PIN_PC5, 1, 1) +#define PIN_PC5__NCS0 PINMUX_PIN(PIN_PC5, 2, 1) +#define PIN_PC5__TCLK1 PINMUX_PIN(PIN_PC5, 3, 1) +#define PIN_PC5__SPI1_NPCS1 PINMUX_PIN(PIN_PC5, 4, 1) +#define PIN_PC5__I2SC0_DO0 PINMUX_PIN(PIN_PC5, 5, 1) +#define PIN_PC5__ISC_VSYNC PINMUX_PIN(PIN_PC5, 6, 3) #define PIN_PC6 70 -#define PIN_PC6__LCDHSYNC PINMUX_PIN(PIN_PC6, 1) -#define PIN_PC6__NCS1 PINMUX_PIN(PIN_PC6, 1) -#define PIN_PC6__TWD1 PINMUX_PIN(PIN_PC6, 1) -#define PIN_PC6__SPI1_NPCS2 PINMUX_PIN(PIN_PC6, 1) -#define PIN_PC6__ISI_HSYNC PINMUX_PIN(PIN_PC6, 3) +#define PIN_PC6__GPIO PINMUX_PIN(PIN_PC6, 0, 0) +#define PIN_PC6__LCDHSYNC PINMUX_PIN(PIN_PC6, 1, 1) +#define PIN_PC6__NCS1 PINMUX_PIN(PIN_PC6, 2, 1) +#define PIN_PC6__TWD1 PINMUX_PIN(PIN_PC6, 3, 1) +#define PIN_PC6__SPI1_NPCS2 PINMUX_PIN(PIN_PC6, 4, 1) +#define PIN_PC6__ISC_HSYNC PINMUX_PIN(PIN_PC6, 6, 3) #define PIN_PC7 71 -#define PIN_PC7__LCDPCK PINMUX_PIN(PIN_PC7, 1) -#define PIN_PC7__NCS2 PINMUX_PIN(PIN_PC7, 1) -#define PIN_PC7__TWCK1 PINMUX_PIN(PIN_PC7, 1) -#define PIN_PC7__SPI1_NPCS3 PINMUX_PIN(PIN_PC7, 1) -#define PIN_PC7__URXD1 PINMUX_PIN(PIN_PC7, 2) -#define PIN_PC7__ISI_MCK PINMUX_PIN(PIN_PC7, 3) +#define PIN_PC7__GPIO PINMUX_PIN(PIN_PC7, 0, 0) +#define PIN_PC7__LCDPCK PINMUX_PIN(PIN_PC7, 1, 1) +#define PIN_PC7__NCS2 PINMUX_PIN(PIN_PC7, 2, 1) +#define PIN_PC7__TWCK1 PINMUX_PIN(PIN_PC7, 3, 1) +#define PIN_PC7__SPI1_NPCS3 PINMUX_PIN(PIN_PC7, 4, 1) +#define PIN_PC7__URXD1 PINMUX_PIN(PIN_PC7, 5, 2) +#define PIN_PC7__ISC_MCK PINMUX_PIN(PIN_PC7, 6, 3) #define PIN_PC8 72 -#define PIN_PC8__LCDDEN PINMUX_PIN(PIN_PC8, 1) -#define PIN_PC8__NANDRDY PINMUX_PIN(PIN_PC8, 1) -#define PIN_PC8__FIQ PINMUX_PIN(PIN_PC8, 1) -#define PIN_PC8__PCK0 PINMUX_PIN(PIN_PC8, 3) -#define PIN_PC8__UTXD1 PINMUX_PIN(PIN_PC8, 2) -#define PIN_PC8__ISI_FIELD PINMUX_PIN(PIN_PC8, 3) +#define PIN_PC8__GPIO PINMUX_PIN(PIN_PC8, 0, 0) +#define PIN_PC8__LCDDEN PINMUX_PIN(PIN_PC8, 1, 1) +#define PIN_PC8__NANDRDY PINMUX_PIN(PIN_PC8, 2, 1) +#define PIN_PC8__FIQ PINMUX_PIN(PIN_PC8, 3, 1) +#define PIN_PC8__PCK0 PINMUX_PIN(PIN_PC8, 4, 3) +#define PIN_PC8__UTXD1 PINMUX_PIN(PIN_PC8, 5, 2) +#define PIN_PC8__ISC_FIELD PINMUX_PIN(PIN_PC8, 6, 3) #define PIN_PC9 73 -#define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 3) -#define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 1) -#define PIN_PC9__ISI_D0 PINMUX_PIN(PIN_PC9, 1) -#define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 2) +#define PIN_PC9__GPIO PINMUX_PIN(PIN_PC9, 0, 0) +#define PIN_PC9__FIQ PINMUX_PIN(PIN_PC9, 1, 3) +#define PIN_PC9__GTSUCOMP PINMUX_PIN(PIN_PC9, 2, 1) +#define PIN_PC9__ISC_D0 PINMUX_PIN(PIN_PC9, 2, 1) +#define PIN_PC9__TIOA4 PINMUX_PIN(PIN_PC9, 4, 2) #define PIN_PC10 74 -#define PIN_PC10__LCDDAT2 PINMUX_PIN(PIN_PC10, 2) -#define PIN_PC10__GTXCK PINMUX_PIN(PIN_PC10, 1) -#define PIN_PC10__ISI_D1 PINMUX_PIN(PIN_PC10, 1) -#define PIN_PC10__TIOB4 PINMUX_PIN(PIN_PC10, 2) -#define PIN_PC10__CANTX0 PINMUX_PIN(PIN_PC10, 2) +#define PIN_PC10__GPIO PINMUX_PIN(PIN_PC10, 0, 0) +#define PIN_PC10__LCDDAT2 PINMUX_PIN(PIN_PC10, 1, 2) +#define PIN_PC10__GTXCK PINMUX_PIN(PIN_PC10, 2, 1) +#define PIN_PC10__ISC_D1 PINMUX_PIN(PIN_PC10, 3, 1) +#define PIN_PC10__TIOB4 PINMUX_PIN(PIN_PC10, 4, 2) +#define PIN_PC10__CANTX0 PINMUX_PIN(PIN_PC10, 5, 2) #define PIN_PC11 75 -#define PIN_PC11__LCDDAT3 PINMUX_PIN(PIN_PC11, 2) -#define PIN_PC11__GTXEN PINMUX_PIN(PIN_PC11, 1) -#define PIN_PC11__ISI_D2 PINMUX_PIN(PIN_PC11, 1) -#define PIN_PC11__TCLK4 PINMUX_PIN(PIN_PC11, 2) -#define PIN_PC11__CANRX0 PINMUX_PIN(PIN_PC11, 2) -#define PIN_PC11__A0_NBS0 PINMUX_PIN(PIN_PC11, 2) +#define PIN_PC11__GPIO PINMUX_PIN(PIN_PC11, 0, 0) +#define PIN_PC11__LCDDAT3 PINMUX_PIN(PIN_PC11, 1, 2) +#define PIN_PC11__GTXEN PINMUX_PIN(PIN_PC11, 2, 1) +#define PIN_PC11__ISC_D2 PINMUX_PIN(PIN_PC11, 3, 1) +#define PIN_PC11__TCLK4 PINMUX_PIN(PIN_PC11, 4, 2) +#define PIN_PC11__CANRX0 PINMUX_PIN(PIN_PC11, 5, 2) +#define PIN_PC11__A0_NBS0 PINMUX_PIN(PIN_PC11, 6, 2) #define PIN_PC12 76 -#define PIN_PC12__LCDDAT4 PINMUX_PIN(PIN_PC12, 2) -#define PIN_PC12__GRXDV PINMUX_PIN(PIN_PC12, 1) -#define PIN_PC12__ISI_D3 PINMUX_PIN(PIN_PC12, 1) -#define PIN_PC12__URXD3 PINMUX_PIN(PIN_PC12, 1) -#define PIN_PC12__TK0 PINMUX_PIN(PIN_PC12, 2) -#define PIN_PC12__A1 PINMUX_PIN(PIN_PC12, 2) +#define PIN_PC12__GPIO PINMUX_PIN(PIN_PC12, 0, 0) +#define PIN_PC12__LCDDAT4 PINMUX_PIN(PIN_PC12, 1, 2) +#define PIN_PC12__GRXDV PINMUX_PIN(PIN_PC12, 2, 1) +#define PIN_PC12__ISC_D3 PINMUX_PIN(PIN_PC12, 3, 1) +#define PIN_PC12__URXD3 PINMUX_PIN(PIN_PC12, 4, 1) +#define PIN_PC12__TK0 PINMUX_PIN(PIN_PC12, 5, 2) +#define PIN_PC12__A1 PINMUX_PIN(PIN_PC12, 6, 2) #define PIN_PC13 77 -#define PIN_PC13__LCDDAT5 PINMUX_PIN(PIN_PC13, 2) -#define PIN_PC13__GRXER PINMUX_PIN(PIN_PC13, 1) -#define PIN_PC13__ISI_D4 PINMUX_PIN(PIN_PC13, 1) -#define PIN_PC13__UTXD3 PINMUX_PIN(PIN_PC13, 1) -#define PIN_PC13__TF0 PINMUX_PIN(PIN_PC13, 2) -#define PIN_PC13__A2 PINMUX_PIN(PIN_PC13, 2) +#define PIN_PC13__GPIO PINMUX_PIN(PIN_PC13, 0, 0) +#define PIN_PC13__LCDDAT5 PINMUX_PIN(PIN_PC13, 1, 2) +#define PIN_PC13__GRXER PINMUX_PIN(PIN_PC13, 2, 1) +#define PIN_PC13__ISC_D4 PINMUX_PIN(PIN_PC13, 3, 1) +#define PIN_PC13__UTXD3 PINMUX_PIN(PIN_PC13, 4, 1) +#define PIN_PC13__TF0 PINMUX_PIN(PIN_PC13, 5, 2) +#define PIN_PC13__A2 PINMUX_PIN(PIN_PC13, 6, 2) #define PIN_PC14 78 -#define PIN_PC14__LCDDAT6 PINMUX_PIN(PIN_PC14, 2) -#define PIN_PC14__GRX0 PINMUX_PIN(PIN_PC14, 1) -#define PIN_PC14__ISI_D5 PINMUX_PIN(PIN_PC14, 1) -#define PIN_PC14__TDO PINMUX_PIN(PIN_PC14, 2) -#define PIN_PC14__A3 PINMUX_PIN(PIN_PC14, 2) +#define PIN_PC14__GPIO PINMUX_PIN(PIN_PC14, 0, 0) +#define PIN_PC14__LCDDAT6 PINMUX_PIN(PIN_PC14, 1, 2) +#define PIN_PC14__GRX0 PINMUX_PIN(PIN_PC14, 2, 1) +#define PIN_PC14__ISC_D5 PINMUX_PIN(PIN_PC14, 3, 1) +#define PIN_PC14__TDO PINMUX_PIN(PIN_PC14, 5, 2) +#define PIN_PC14__A3 PINMUX_PIN(PIN_PC14, 6, 2) #define PIN_PC15 79 -#define PIN_PC15__LCDDAT7 PINMUX_PIN(PIN_PC15, 2) -#define PIN_PC15__GRX1 PINMUX_PIN(PIN_PC15, 1) -#define PIN_PC15__ISI_D6 PINMUX_PIN(PIN_PC15, 1) -#define PIN_PC15__RD0 PINMUX_PIN(PIN_PC15, 2) -#define PIN_PC15__A4 PINMUX_PIN(PIN_PC15, 2) +#define PIN_PC15__GPIO PINMUX_PIN(PIN_PC15, 0, 0) +#define PIN_PC15__LCDDAT7 PINMUX_PIN(PIN_PC15, 1, 2) +#define PIN_PC15__GRX1 PINMUX_PIN(PIN_PC15, 2, 1) +#define PIN_PC15__ISC_D6 PINMUX_PIN(PIN_PC15, 3, 1) +#define PIN_PC15__RD0 PINMUX_PIN(PIN_PC15, 5, 2) +#define PIN_PC15__A4 PINMUX_PIN(PIN_PC15, 6, 2) #define PIN_PC16 80 -#define PIN_PC16__LCDDAT10 PINMUX_PIN(PIN_PC16, 2) -#define PIN_PC16__GTX0 PINMUX_PIN(PIN_PC16, 1) -#define PIN_PC16__ISI_D7 PINMUX_PIN(PIN_PC16, 1) -#define PIN_PC16__RK0 PINMUX_PIN(PIN_PC16, 2) -#define PIN_PC16__A5 PINMUX_PIN(PIN_PC16, 2) +#define PIN_PC16__GPIO PINMUX_PIN(PIN_PC16, 0, 0) +#define PIN_PC16__LCDDAT10 PINMUX_PIN(PIN_PC16, 1, 2) +#define PIN_PC16__GTX0 PINMUX_PIN(PIN_PC16, 2, 1) +#define PIN_PC16__ISC_D7 PINMUX_PIN(PIN_PC16, 3, 1) +#define PIN_PC16__RK0 PINMUX_PIN(PIN_PC16, 5, 2) +#define PIN_PC16__A5 PINMUX_PIN(PIN_PC16, 6, 2) #define PIN_PC17 81 -#define PIN_PC17__LCDDAT11 PINMUX_PIN(PIN_PC17, 2) -#define PIN_PC17__GTX1 PINMUX_PIN(PIN_PC17, 1) -#define PIN_PC17__ISI_D8 PINMUX_PIN(PIN_PC17, 1) -#define PIN_PC17__TF0 PINMUX_PIN(PIN_PC17, 2) -#define PIN_PC17__A6 PINMUX_PIN(PIN_PC17, 2) +#define PIN_PC17__GPIO PINMUX_PIN(PIN_PC17, 0, 0) +#define PIN_PC17__LCDDAT11 PINMUX_PIN(PIN_PC17, 1, 2) +#define PIN_PC17__GTX1 PINMUX_PIN(PIN_PC17, 2, 1) +#define PIN_PC17__ISC_D8 PINMUX_PIN(PIN_PC17, 3, 1) +#define PIN_PC17__RF0 PINMUX_PIN(PIN_PC17, 5, 2) +#define PIN_PC17__A6 PINMUX_PIN(PIN_PC17, 6, 2) #define PIN_PC18 82 -#define PIN_PC18__LCDDAT12 PINMUX_PIN(PIN_PC18, 2) -#define PIN_PC18__GMDC PINMUX_PIN(PIN_PC18, 1) -#define PIN_PC18__ISI_D9 PINMUX_PIN(PIN_PC18, 1) -#define PIN_PC18__FLEXCOM3_IO2 PINMUX_PIN(PIN_PC18, 2) -#define PIN_PC18__A7 PINMUX_PIN(PIN_PC18, 2) +#define PIN_PC18__GPIO PINMUX_PIN(PIN_PC18, 0, 0) +#define PIN_PC18__LCDDAT12 PINMUX_PIN(PIN_PC18, 1, 2) +#define PIN_PC18__GMDC PINMUX_PIN(PIN_PC18, 2, 1) +#define PIN_PC18__ISC_D9 PINMUX_PIN(PIN_PC18, 3, 1) +#define PIN_PC18__FLEXCOM3_IO2 PINMUX_PIN(PIN_PC18, 5, 2) +#define PIN_PC18__A7 PINMUX_PIN(PIN_PC18, 6, 2) #define PIN_PC19 83 -#define PIN_PC19__LCDDAT13 PINMUX_PIN(PIN_PC19, 2) -#define PIN_PC19__GMDIO PINMUX_PIN(PIN_PC19, 1) -#define PIN_PC19__ISI_D10 PINMUX_PIN(PIN_PC19, 1) -#define PIN_PC19__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC19, 2) -#define PIN_PC19__A8 PINMUX_PIN(PIN_PC19, 2) +#define PIN_PC19__GPIO PINMUX_PIN(PIN_PC19, 0, 0) +#define PIN_PC19__LCDDAT13 PINMUX_PIN(PIN_PC19, 1, 2) +#define PIN_PC19__GMDIO PINMUX_PIN(PIN_PC19, 2, 1) +#define PIN_PC19__ISC_D10 PINMUX_PIN(PIN_PC19, 3, 1) +#define PIN_PC19__FLEXCOM3_IO1 PINMUX_PIN(PIN_PC19, 5, 2) +#define PIN_PC19__A8 PINMUX_PIN(PIN_PC19, 6, 2) #define PIN_PC20 84 -#define PIN_PC20__LCDDAT14 PINMUX_PIN(PIN_PC20, 2) -#define PIN_PC20__GRXCK PINMUX_PIN(PIN_PC20, 1) -#define PIN_PC20__ISI_D11 PINMUX_PIN(PIN_PC20, 1) -#define PIN_PC20__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC20, 2) -#define PIN_PC20__A9 PINMUX_PIN(PIN_PC20, 2) +#define PIN_PC20__GPIO PINMUX_PIN(PIN_PC20, 0, 0) +#define PIN_PC20__LCDDAT14 PINMUX_PIN(PIN_PC20, 1, 2) +#define PIN_PC20__GRXCK PINMUX_PIN(PIN_PC20, 2, 1) +#define PIN_PC20__ISC_D11 PINMUX_PIN(PIN_PC20, 3, 1) +#define PIN_PC20__FLEXCOM3_IO0 PINMUX_PIN(PIN_PC20, 5, 2) +#define PIN_PC20__A9 PINMUX_PIN(PIN_PC20, 6, 2) #define PIN_PC21 85 -#define PIN_PC21__LCDDAT15 PINMUX_PIN(PIN_PC21, 2) -#define PIN_PC21__GTXER PINMUX_PIN(PIN_PC21, 1) -#define PIN_PC21__ISI_PCK PINMUX_PIN(PIN_PC21, 1) -#define PIN_PC21__FLEXCOM3_IO3 PINMUX_PIN(PIN_PC21, 2) -#define PIN_PC21__A10 PINMUX_PIN(PIN_PC21, 2) +#define PIN_PC21__GPIO PINMUX_PIN(PIN_PC21, 0, 0) +#define PIN_PC21__LCDDAT15 PINMUX_PIN(PIN_PC21, 1, 2) +#define PIN_PC21__GTXER PINMUX_PIN(PIN_PC21, 2, 1) +#define PIN_PC21__ISC_PCK PINMUX_PIN(PIN_PC21, 3, 1) +#define PIN_PC21__FLEXCOM3_IO3 PINMUX_PIN(PIN_PC21, 5, 2) +#define PIN_PC21__A10 PINMUX_PIN(PIN_PC21, 6, 2) #define PIN_PC22 86 -#define PIN_PC22__LCDDAT18 PINMUX_PIN(PIN_PC22, 2) -#define PIN_PC22__GCRS PINMUX_PIN(PIN_PC22, 1) -#define PIN_PC22__ISI_VSYNC PINMUX_PIN(PIN_PC22, 1) -#define PIN_PC22__FLEXCOM3_IO4 PINMUX_PIN(PIN_PC22, 2) -#define PIN_PC22__A11 PINMUX_PIN(PIN_PC22, 2) +#define PIN_PC22__GPIO PINMUX_PIN(PIN_PC22, 0, 0) +#define PIN_PC22__LCDDAT18 PINMUX_PIN(PIN_PC22, 1, 2) +#define PIN_PC22__GCRS PINMUX_PIN(PIN_PC22, 2, 1) +#define PIN_PC22__ISC_VSYNC PINMUX_PIN(PIN_PC22, 3, 1) +#define PIN_PC22__FLEXCOM3_IO4 PINMUX_PIN(PIN_PC22, 5, 2) +#define PIN_PC22__A11 PINMUX_PIN(PIN_PC22, 6, 2) #define PIN_PC23 87 -#define PIN_PC23__LCDDAT19 PINMUX_PIN(PIN_PC23, 2) -#define PIN_PC23__GCOL PINMUX_PIN(PIN_PC23, 1) -#define PIN_PC23__ISI_HSYNC PINMUX_PIN(PIN_PC23, 1) -#define PIN_PC23__A12 PINMUX_PIN(PIN_PC23, 2) +#define PIN_PC23__GPIO PINMUX_PIN(PIN_PC23, 0, 0) +#define PIN_PC23__LCDDAT19 PINMUX_PIN(PIN_PC23, 1, 2) +#define PIN_PC23__GCOL PINMUX_PIN(PIN_PC23, 2, 1) +#define PIN_PC23__ISC_HSYNC PINMUX_PIN(PIN_PC23, 3, 1) +#define PIN_PC23__A12 PINMUX_PIN(PIN_PC23, 6, 2) #define PIN_PC24 88 -#define PIN_PC24__LCDDAT20 PINMUX_PIN(PIN_PC24, 2) -#define PIN_PC24__GRX2 PINMUX_PIN(PIN_PC24, 1) -#define PIN_PC24__ISI_MCK PINMUX_PIN(PIN_PC24, 1) -#define PIN_PC24__A13 PINMUX_PIN(PIN_PC24, 2) +#define PIN_PC24__GPIO PINMUX_PIN(PIN_PC24, 0, 0) +#define PIN_PC24__LCDDAT20 PINMUX_PIN(PIN_PC24, 1, 2) +#define PIN_PC24__GRX2 PINMUX_PIN(PIN_PC24, 2, 1) +#define PIN_PC24__ISC_MCK PINMUX_PIN(PIN_PC24, 3, 1) +#define PIN_PC24__A13 PINMUX_PIN(PIN_PC24, 6, 2) #define PIN_PC25 89 -#define PIN_PC25__LCDDAT21 PINMUX_PIN(PIN_PC25, 2) -#define PIN_PC25__GRX3 PINMUX_PIN(PIN_PC25, 1) -#define PIN_PC25__ISI_FIELD PINMUX_PIN(PIN_PC25, 1) -#define PIN_PC25__A14 PINMUX_PIN(PIN_PC25, 2) +#define PIN_PC25__GPIO PINMUX_PIN(PIN_PC25, 0, 0) +#define PIN_PC25__LCDDAT21 PINMUX_PIN(PIN_PC25, 1, 2) +#define PIN_PC25__GRX3 PINMUX_PIN(PIN_PC25, 2, 1) +#define PIN_PC25__ISC_FIELD PINMUX_PIN(PIN_PC25, 3, 1) +#define PIN_PC25__A14 PINMUX_PIN(PIN_PC25, 6, 2) #define PIN_PC26 90 -#define PIN_PC26__LCDDAT22 PINMUX_PIN(PIN_PC26, 2) -#define PIN_PC26__GTX2 PINMUX_PIN(PIN_PC26, 1) -#define PIN_PC26__CANTX1 PINMUX_PIN(PIN_PC26, 1) -#define PIN_PC26__A15 PINMUX_PIN(PIN_PC26, 2) +#define PIN_PC26__GPIO PINMUX_PIN(PIN_PC26, 0, 0) +#define PIN_PC26__LCDDAT22 PINMUX_PIN(PIN_PC26, 1, 2) +#define PIN_PC26__GTX2 PINMUX_PIN(PIN_PC26, 2, 1) +#define PIN_PC26__CANTX1 PINMUX_PIN(PIN_PC26, 4, 1) +#define PIN_PC26__A15 PINMUX_PIN(PIN_PC26, 6, 2) #define PIN_PC27 91 -#define PIN_PC27__LCDDAT23 PINMUX_PIN(PIN_PC27, 2) -#define PIN_PC27__GTX3 PINMUX_PIN(PIN_PC27, 1) -#define PIN_PC27__PCK1 PINMUX_PIN(PIN_PC27, 2) -#define PIN_PC27__CANRX1 PINMUX_PIN(PIN_PC27, 1) -#define PIN_PC27__TWD0 PINMUX_PIN(PIN_PC27, 2) -#define PIN_PC27__A16 PINMUX_PIN(PIN_PC27, 2) +#define PIN_PC27__GPIO PINMUX_PIN(PIN_PC27, 0, 0) +#define PIN_PC27__LCDDAT23 PINMUX_PIN(PIN_PC27, 1, 2) +#define PIN_PC27__GTX3 PINMUX_PIN(PIN_PC27, 2, 1) +#define PIN_PC27__PCK1 PINMUX_PIN(PIN_PC27, 3, 2) +#define PIN_PC27__CANRX1 PINMUX_PIN(PIN_PC27, 4, 1) +#define PIN_PC27__TWD0 PINMUX_PIN(PIN_PC27, 5, 2) +#define PIN_PC27__A16 PINMUX_PIN(PIN_PC27, 6, 2) #define PIN_PC28 92 -#define PIN_PC28__LCDPWM PINMUX_PIN(PIN_PC28, 2) -#define PIN_PC28__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC28, 1) -#define PIN_PC28__PCK2 PINMUX_PIN(PIN_PC28, 2) -#define PIN_PC28__TWCK0 PINMUX_PIN(PIN_PC28, 2) -#define PIN_PC28__A17 PINMUX_PIN(PIN_PC28, 2) +#define PIN_PC28__GPIO PINMUX_PIN(PIN_PC28, 0, 0) +#define PIN_PC28__LCDPWM PINMUX_PIN(PIN_PC28, 1, 2) +#define PIN_PC28__FLEXCOM4_IO0 PINMUX_PIN(PIN_PC28, 2, 1) +#define PIN_PC28__PCK2 PINMUX_PIN(PIN_PC28, 3, 2) +#define PIN_PC28__TWCK0 PINMUX_PIN(PIN_PC28, 5, 2) +#define PIN_PC28__A17 PINMUX_PIN(PIN_PC28, 6, 2) #define PIN_PC29 93 -#define PIN_PC29__LCDDISP PINMUX_PIN(PIN_PC29, 2) -#define PIN_PC29__FLEXCOM4_IO1 PINMUX_PIN(PIN_PC29, 1) -#define PIN_PC29__A18 PINMUX_PIN(PIN_PC29, 2) +#define PIN_PC29__GPIO PINMUX_PIN(PIN_PC29, 0, 0) +#define PIN_PC29__LCDDISP PINMUX_PIN(PIN_PC29, 1, 2) +#define PIN_PC29__FLEXCOM4_IO1 PINMUX_PIN(PIN_PC29, 2, 1) +#define PIN_PC29__A18 PINMUX_PIN(PIN_PC29, 6, 2) #define PIN_PC30 94 -#define PIN_PC30__LCDVSYNC PINMUX_PIN(PIN_PC30, 2) -#define PIN_PC30__FLEXCOM4_IO2 PINMUX_PIN(PIN_PC30, 1) -#define PIN_PC30__A19 PINMUX_PIN(PIN_PC30, 2) +#define PIN_PC30__GPIO PINMUX_PIN(PIN_PC30, 0, 0) +#define PIN_PC30__LCDVSYNC PINMUX_PIN(PIN_PC30, 1, 2) +#define PIN_PC30__FLEXCOM4_IO2 PINMUX_PIN(PIN_PC30, 2, 1) +#define PIN_PC30__A19 PINMUX_PIN(PIN_PC30, 6, 2) #define PIN_PC31 95 -#define PIN_PC31__LCDHSYNC PINMUX_PIN(PIN_PC31, 2) -#define PIN_PC31__FLEXCOM4_IO3 PINMUX_PIN(PIN_PC31, 1) -#define PIN_PC31__URXD3 PINMUX_PIN(PIN_PC31, 2) -#define PIN_PC31__A20 PINMUX_PIN(PIN_PC31, 2) +#define PIN_PC31__GPIO PINMUX_PIN(PIN_PC31, 0, 0) +#define PIN_PC31__LCDHSYNC PINMUX_PIN(PIN_PC31, 1, 2) +#define PIN_PC31__FLEXCOM4_IO3 PINMUX_PIN(PIN_PC31, 2, 1) +#define PIN_PC31__URXD3 PINMUX_PIN(PIN_PC31, 3, 2) +#define PIN_PC31__A20 PINMUX_PIN(PIN_PC31, 6, 2) #define PIN_PD0 96 -#define PIN_PD0__LCDPCK PINMUX_PIN(PIN_PD0, 2) -#define PIN_PD0__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD0, 1) -#define PIN_PD0__UTXD3 PINMUX_PIN(PIN_PD0, 2) -#define PIN_PD0__GTSUCOMP PINMUX_PIN(PIN_PD0, 2) -#define PIN_PD0__A23 PINMUX_PIN(PIN_PD0, 2) +#define PIN_PD0__GPIO PINMUX_PIN(PIN_PD0, 0, 0) +#define PIN_PD0__LCDPCK PINMUX_PIN(PIN_PD0, 1, 2) +#define PIN_PD0__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD0, 2, 1) +#define PIN_PD0__UTXD3 PINMUX_PIN(PIN_PD0, 3, 2) +#define PIN_PD0__GTSUCOMP PINMUX_PIN(PIN_PD0, 4, 2) +#define PIN_PD0__A23 PINMUX_PIN(PIN_PD0, 6, 2) #define PIN_PD1 97 -#define PIN_PD1__LCDDEN PINMUX_PIN(PIN_PD1, 2) -#define PIN_PD1__GRXCK PINMUX_PIN(PIN_PD1, 2) -#define PIN_PD1__A24 PINMUX_PIN(PIN_PD1, 2) +#define PIN_PD1__GPIO PINMUX_PIN(PIN_PD1, 0, 0) +#define PIN_PD1__LCDDEN PINMUX_PIN(PIN_PD1, 1, 2) +#define PIN_PD1__GRXCK PINMUX_PIN(PIN_PD1, 4, 2) +#define PIN_PD1__A24 PINMUX_PIN(PIN_PD1, 6, 2) #define PIN_PD2 98 -#define PIN_PD2__URXD1 PINMUX_PIN(PIN_PD2, 1) -#define PIN_PD2__UTXD3 PINMUX_PIN(PIN_PD2, 2) -#define PIN_PD2__GTXER PINMUX_PIN(PIN_PD2, 2) -#define PIN_PD2__A25 PINMUX_PIN(PIN_PD2, 2) +#define PIN_PD2__GPIO PINMUX_PIN(PIN_PD2, 0, 0) +#define PIN_PD2__URXD1 PINMUX_PIN(PIN_PD2, 1, 1) +#define PIN_PD2__GTXER PINMUX_PIN(PIN_PD2, 4, 2) +#define PIN_PD2__ISC_MCK PINMUX_PIN(PIN_PD2, 5, 2) +#define PIN_PD2__A25 PINMUX_PIN(PIN_PD2, 6, 2) #define PIN_PD3 99 -#define PIN_PD3__UTXD1 PINMUX_PIN(PIN_PD3, 1) -#define PIN_PD3__FIQ PINMUX_PIN(PIN_PD3, 2) -#define PIN_PD3__GCRS PINMUX_PIN(PIN_PD3, 2) -#define PIN_PD3__ISI_D11 PINMUX_PIN(PIN_PD3, 2) -#define PIN_PD3__NWAIT PINMUX_PIN(PIN_PD3, 2) +#define PIN_PD3__GPIO PINMUX_PIN(PIN_PD3, 0, 0) +#define PIN_PD3__UTXD1 PINMUX_PIN(PIN_PD3, 1, 1) +#define PIN_PD3__FIQ PINMUX_PIN(PIN_PD3, 2, 2) +#define PIN_PD3__GCRS PINMUX_PIN(PIN_PD3, 4, 2) +#define PIN_PD3__ISC_D11 PINMUX_PIN(PIN_PD3, 5, 2) +#define PIN_PD3__NWAIT PINMUX_PIN(PIN_PD3, 6, 2) #define PIN_PD4 100 -#define PIN_PD4__TWD1 PINMUX_PIN(PIN_PD4, 2) -#define PIN_PD4__URXD2 PINMUX_PIN(PIN_PD4, 1) -#define PIN_PD4__GCOL PINMUX_PIN(PIN_PD4, 2) -#define PIN_PD4__ISI_D10 PINMUX_PIN(PIN_PD4, 2) -#define PIN_PD4__NCS0 PINMUX_PIN(PIN_PD4, 2) +#define PIN_PD4__GPIO PINMUX_PIN(PIN_PD4, 0, 0) +#define PIN_PD4__TWD1 PINMUX_PIN(PIN_PD4, 1, 2) +#define PIN_PD4__URXD2 PINMUX_PIN(PIN_PD4, 2, 1) +#define PIN_PD4__GCOL PINMUX_PIN(PIN_PD4, 4, 2) +#define PIN_PD4__ISC_D10 PINMUX_PIN(PIN_PD4, 5, 2) +#define PIN_PD4__NCS0 PINMUX_PIN(PIN_PD4, 6, 2) #define PIN_PD5 101 -#define PIN_PD5__TWCK1 PINMUX_PIN(PIN_PD5, 2) -#define PIN_PD5__UTXD2 PINMUX_PIN(PIN_PD5, 1) -#define PIN_PD5__GRX2 PINMUX_PIN(PIN_PD5, 2) -#define PIN_PD5__ISI_D9 PINMUX_PIN(PIN_PD5, 2) -#define PIN_PD5__NCS1 PINMUX_PIN(PIN_PD5, 2) +#define PIN_PD5__GPIO PINMUX_PIN(PIN_PD5, 0, 0) +#define PIN_PD5__TWCK1 PINMUX_PIN(PIN_PD5, 1, 2) +#define PIN_PD5__UTXD2 PINMUX_PIN(PIN_PD5, 2, 1) +#define PIN_PD5__GRX2 PINMUX_PIN(PIN_PD5, 4, 2) +#define PIN_PD5__ISC_D9 PINMUX_PIN(PIN_PD5, 5, 2) +#define PIN_PD5__NCS1 PINMUX_PIN(PIN_PD5, 6, 2) #define PIN_PD6 102 -#define PIN_PD6__TCK PINMUX_PIN(PIN_PD6, 2) -#define PIN_PD6__PCK1 PINMUX_PIN(PIN_PD6, 1) -#define PIN_PD6__GRX3 PINMUX_PIN(PIN_PD6, 2) -#define PIN_PD6__ISI_D8 PINMUX_PIN(PIN_PD6, 2) -#define PIN_PD6__NCS2 PINMUX_PIN(PIN_PD6, 2) +#define PIN_PD6__GPIO PINMUX_PIN(PIN_PD6, 0, 0) +#define PIN_PD6__TCK PINMUX_PIN(PIN_PD6, 1, 2) +#define PIN_PD6__PCK1 PINMUX_PIN(PIN_PD6, 2, 1) +#define PIN_PD6__GRX3 PINMUX_PIN(PIN_PD6, 4, 2) +#define PIN_PD6__ISC_D8 PINMUX_PIN(PIN_PD6, 5, 2) +#define PIN_PD6__NCS2 PINMUX_PIN(PIN_PD6, 6, 2) #define PIN_PD7 103 -#define PIN_PD7__TDI PINMUX_PIN(PIN_PD7, 2) -#define PIN_PD7__UTMI_RXVAL PINMUX_PIN(PIN_PD7, 1) -#define PIN_PD7__GTX2 PINMUX_PIN(PIN_PD7, 2) -#define PIN_PD7__ISI_D0 PINMUX_PIN(PIN_PD7, 2) -#define PIN_PD7__NWR1_NBS1 PINMUX_PIN(PIN_PD7, 2) +#define PIN_PD7__GPIO PINMUX_PIN(PIN_PD7, 0, 0) +#define PIN_PD7__TDI PINMUX_PIN(PIN_PD7, 1, 2) +#define PIN_PD7__UTMI_RXVAL PINMUX_PIN(PIN_PD7, 3, 1) +#define PIN_PD7__GTX2 PINMUX_PIN(PIN_PD7, 4, 2) +#define PIN_PD7__ISC_D0 PINMUX_PIN(PIN_PD7, 5, 2) +#define PIN_PD7__NWR1_NBS1 PINMUX_PIN(PIN_PD7, 6, 2) #define PIN_PD8 104 -#define PIN_PD8__TDO PINMUX_PIN(PIN_PD8, 2) -#define PIN_PD8__UTMI_RXERR PINMUX_PIN(PIN_PD8, 1) -#define PIN_PD8__GTX3 PINMUX_PIN(PIN_PD8, 2) -#define PIN_PD8__ISI_D1 PINMUX_PIN(PIN_PD8, 2) -#define PIN_PD8__NANDRDY PINMUX_PIN(PIN_PD8, 2) +#define PIN_PD8__GPIO PINMUX_PIN(PIN_PD8, 0, 0) +#define PIN_PD8__TDO PINMUX_PIN(PIN_PD8, 1, 2) +#define PIN_PD8__UTMI_RXERR PINMUX_PIN(PIN_PD8, 3, 1) +#define PIN_PD8__GTX3 PINMUX_PIN(PIN_PD8, 4, 2) +#define PIN_PD8__ISC_D1 PINMUX_PIN(PIN_PD8, 5, 2) +#define PIN_PD8__NANDRDY PINMUX_PIN(PIN_PD8, 6, 2) #define PIN_PD9 105 -#define PIN_PD9__TMS PINMUX_PIN(PIN_PD9, 2) -#define PIN_PD9__UTMI_RXACT PINMUX_PIN(PIN_PD9, 1) -#define PIN_PD9__GTXCK PINMUX_PIN(PIN_PD9, 2) -#define PIN_PD9__ISI_D2 PINMUX_PIN(PIN_PD9, 2) +#define PIN_PD9__GPIO PINMUX_PIN(PIN_PD9, 0, 0) +#define PIN_PD9__TMS PINMUX_PIN(PIN_PD9, 1, 2) +#define PIN_PD9__UTMI_RXACT PINMUX_PIN(PIN_PD9, 3, 1) +#define PIN_PD9__GTXCK PINMUX_PIN(PIN_PD9, 4, 2) +#define PIN_PD9__ISC_D2 PINMUX_PIN(PIN_PD9, 5, 2) #define PIN_PD10 106 -#define PIN_PD10__NTRST PINMUX_PIN(PIN_PD10, 2) -#define PIN_PD10__UTMI_HDIS PINMUX_PIN(PIN_PD10, 1) -#define PIN_PD10__GTXEN PINMUX_PIN(PIN_PD10, 2) -#define PIN_PD10__ISI_D3 PINMUX_PIN(PIN_PD10, 2) +#define PIN_PD10__GPIO PINMUX_PIN(PIN_PD10, 0, 0) +#define PIN_PD10__NTRST PINMUX_PIN(PIN_PD10, 1, 2) +#define PIN_PD10__UTMI_HDIS PINMUX_PIN(PIN_PD10, 3, 1) +#define PIN_PD10__GTXEN PINMUX_PIN(PIN_PD10, 4, 2) +#define PIN_PD10__ISC_D3 PINMUX_PIN(PIN_PD10, 5, 2) #define PIN_PD11 107 -#define PIN_PD11__TIOA1 PINMUX_PIN(PIN_PD11, 3) -#define PIN_PD11__PCK2 PINMUX_PIN(PIN_PD11, 2) -#define PIN_PD11__UTMI_LS0 PINMUX_PIN(PIN_PD11, 1) -#define PIN_PD11__GRXDV PINMUX_PIN(PIN_PD11, 2) -#define PIN_PD11__ISI_D4 PINMUX_PIN(PIN_PD11, 2) -#define PIN_PD11__ISI_MCK PINMUX_PIN(PIN_PD11, 4) +#define PIN_PD11__GPIO PINMUX_PIN(PIN_PD11, 0, 0) +#define PIN_PD11__TIOA1 PINMUX_PIN(PIN_PD11, 1, 3) +#define PIN_PD11__PCK2 PINMUX_PIN(PIN_PD11, 2, 2) +#define PIN_PD11__UTMI_LS0 PINMUX_PIN(PIN_PD11, 3, 1) +#define PIN_PD11__GRXDV PINMUX_PIN(PIN_PD11, 4, 2) +#define PIN_PD11__ISC_D4 PINMUX_PIN(PIN_PD11, 5, 2) +#define PIN_PD11__ISC_MCK PINMUX_PIN(PIN_PD11, 7, 4) #define PIN_PD12 108 -#define PIN_PD12__TIOB1 PINMUX_PIN(PIN_PD12, 3) -#define PIN_PD12__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD12, 2) -#define PIN_PD12__UTMI_LS1 PINMUX_PIN(PIN_PD12, 1) -#define PIN_PD12__GRXER PINMUX_PIN(PIN_PD12, 2) -#define PIN_PD12__ISI_D5 PINMUX_PIN(PIN_PD12, 2) -#define PIN_PD12__ISI_D4 PINMUX_PIN(PIN_PD12, 4) +#define PIN_PD12__GPIO PINMUX_PIN(PIN_PD12, 0, 0) +#define PIN_PD12__TIOB1 PINMUX_PIN(PIN_PD12, 1, 3) +#define PIN_PD12__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD12, 2, 2) +#define PIN_PD12__UTMI_LS1 PINMUX_PIN(PIN_PD12, 3, 1) +#define PIN_PD12__GRXER PINMUX_PIN(PIN_PD12, 4, 2) +#define PIN_PD12__ISC_D5 PINMUX_PIN(PIN_PD12, 5, 2) +#define PIN_PD12__ISC_D4 PINMUX_PIN(PIN_PD12, 6, 4) #define PIN_PD13 109 -#define PIN_PD13__TCLK1 PINMUX_PIN(PIN_PD13, 3) -#define PIN_PD13__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD13, 2) -#define PIN_PD13__UTMI_CDRPCSEL0 PINMUX_PIN(PIN_PD13, 1) -#define PIN_PD13__GRX0 PINMUX_PIN(PIN_PD13, 2) -#define PIN_PD13__ISI_D6 PINMUX_PIN(PIN_PD13, 2) -#define PIN_PD13__ISI_D5 PINMUX_PIN(PIN_PD13, 4) +#define PIN_PD13__GPIO PINMUX_PIN(PIN_PD13, 0, 0) +#define PIN_PD13__TCLK1 PINMUX_PIN(PIN_PD13, 1, 3) +#define PIN_PD13__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD13, 2, 2) +#define PIN_PD13__UTMI_CDRPCSEL0 PINMUX_PIN(PIN_PD13, 3, 1) +#define PIN_PD13__GRX0 PINMUX_PIN(PIN_PD13, 4, 2) +#define PIN_PD13__ISC_D6 PINMUX_PIN(PIN_PD13, 5, 2) +#define PIN_PD13__ISC_D5 PINMUX_PIN(PIN_PD13, 6, 4) #define PIN_PD14 110 -#define PIN_PD14__TCK PINMUX_PIN(PIN_PD14, 1) -#define PIN_PD14__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD14, 2) -#define PIN_PD14__UTMI_CDRPCSEL1 PINMUX_PIN(PIN_PD14, 1) -#define PIN_PD14__GRX1 PINMUX_PIN(PIN_PD14, 2) -#define PIN_PD14__ISI_D7 PINMUX_PIN(PIN_PD14, 2) -#define PIN_PD14__ISI_D6 PINMUX_PIN(PIN_PD14, 4) +#define PIN_PD14__GPIO PINMUX_PIN(PIN_PD14, 0, 0) +#define PIN_PD14__TCK PINMUX_PIN(PIN_PD14, 1, 1) +#define PIN_PD14__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD14, 2, 2) +#define PIN_PD14__UTMI_CDRPCSEL1 PINMUX_PIN(PIN_PD14, 3, 1) +#define PIN_PD14__GRX1 PINMUX_PIN(PIN_PD14, 4, 2) +#define PIN_PD14__ISC_D7 PINMUX_PIN(PIN_PD14, 5, 2) +#define PIN_PD14__ISC_D6 PINMUX_PIN(PIN_PD14, 6, 4) #define PIN_PD15 111 -#define PIN_PD15__TDI PINMUX_PIN(PIN_PD15, 1) -#define PIN_PD15__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD15, 2) -#define PIN_PD15__UTMI_CDRCPDIVEN PINMUX_PIN(PIN_PD15, 1) -#define PIN_PD15__GTX0 PINMUX_PIN(PIN_PD15, 2) -#define PIN_PD15__ISI_PCK PINMUX_PIN(PIN_PD15, 2) -#define PIN_PD15__ISI_D7 PINMUX_PIN(PIN_PD15, 4) +#define PIN_PD15__GPIO PINMUX_PIN(PIN_PD15, 0, 0) +#define PIN_PD15__TDI PINMUX_PIN(PIN_PD15, 1, 1) +#define PIN_PD15__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD15, 2, 2) +#define PIN_PD15__UTMI_CDRCPDIVEN PINMUX_PIN(PIN_PD15, 3, 1) +#define PIN_PD15__GTX0 PINMUX_PIN(PIN_PD15, 4, 2) +#define PIN_PD15__ISC_PCK PINMUX_PIN(PIN_PD15, 5, 2) +#define PIN_PD15__ISC_D7 PINMUX_PIN(PIN_PD15, 6, 4) #define PIN_PD16 112 -#define PIN_PD16__TDO PINMUX_PIN(PIN_PD16, 1) -#define PIN_PD16__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD16, 2) -#define PIN_PD16__UTMI_CDRBISTEN PINMUX_PIN(PIN_PD16, 1) -#define PIN_PD16__GTX1 PINMUX_PIN(PIN_PD16, 2) -#define PIN_PD16__ISI_VSYNC PINMUX_PIN(PIN_PD16, 2) -#define PIN_PD16__ISI_D8 PINMUX_PIN(PIN_PD16, 4) +#define PIN_PD16__GPIO PINMUX_PIN(PIN_PD16, 0, 0) +#define PIN_PD16__TDO PINMUX_PIN(PIN_PD16, 1, 1) +#define PIN_PD16__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD16, 2, 2) +#define PIN_PD16__UTMI_CDRBISTEN PINMUX_PIN(PIN_PD16, 3, 1) +#define PIN_PD16__GTX1 PINMUX_PIN(PIN_PD16, 4, 2) +#define PIN_PD16__ISC_VSYNC PINMUX_PIN(PIN_PD16, 5, 2) +#define PIN_PD16__ISC_D8 PINMUX_PIN(PIN_PD16, 6, 4) #define PIN_PD17 113 -#define PIN_PD17__TMS PINMUX_PIN(PIN_PD17, 1) -#define PIN_PD17__UTMI_CDRCPSELDIV PINMUX_PIN(PIN_PD17, 1) -#define PIN_PD17__GMDC PINMUX_PIN(PIN_PD17, 2) -#define PIN_PD17__ISI_HSYNC PINMUX_PIN(PIN_PD17, 2) -#define PIN_PD17__ISI_D9 PINMUX_PIN(PIN_PD17, 4) +#define PIN_PD17__GPIO PINMUX_PIN(PIN_PD17, 0, 0) +#define PIN_PD17__TMS PINMUX_PIN(PIN_PD17, 1, 1) +#define PIN_PD17__UTMI_CDRCPSELDIV PINMUX_PIN(PIN_PD17, 3, 1) +#define PIN_PD17__GMDC PINMUX_PIN(PIN_PD17, 4, 2) +#define PIN_PD17__ISC_HSYNC PINMUX_PIN(PIN_PD17, 5, 2) +#define PIN_PD17__ISC_D9 PINMUX_PIN(PIN_PD17, 6, 4) #define PIN_PD18 114 -#define PIN_PD18__NTRST PINMUX_PIN(PIN_PD18, 1) -#define PIN_PD18__GMDIO PINMUX_PIN(PIN_PD18, 2) -#define PIN_PD18__ISI_FIELD PINMUX_PIN(PIN_PD18, 2) -#define PIN_PD18__ISI_D10 PINMUX_PIN(PIN_PD18, 4) +#define PIN_PD18__GPIO PINMUX_PIN(PIN_PD18, 0, 0) +#define PIN_PD18__NTRST PINMUX_PIN(PIN_PD18, 1, 1) +#define PIN_PD18__GMDIO PINMUX_PIN(PIN_PD18, 4, 2) +#define PIN_PD18__ISC_FIELD PINMUX_PIN(PIN_PD18, 5, 2) +#define PIN_PD18__ISC_D10 PINMUX_PIN(PIN_PD18, 6, 4) #define PIN_PD19 115 -#define PIN_PD19__PCK0 PINMUX_PIN(PIN_PD19, 1) -#define PIN_PD19__TWD1 PINMUX_PIN(PIN_PD19, 3) -#define PIN_PD19__URXD2 PINMUX_PIN(PIN_PD19, 3) -#define PIN_PD19__I2SCK0 PINMUX_PIN(PIN_PD19, 2) -#define PIN_PD19__ISI_D11 PINMUX_PIN(PIN_PD19, 4) +#define PIN_PD19__GPIO PINMUX_PIN(PIN_PD19, 0, 0) +#define PIN_PD19__PCK0 PINMUX_PIN(PIN_PD19, 1, 1) +#define PIN_PD19__TWD1 PINMUX_PIN(PIN_PD19, 2, 3) +#define PIN_PD19__URXD2 PINMUX_PIN(PIN_PD19, 3, 3) +#define PIN_PD19__I2SC0_CK PINMUX_PIN(PIN_PD19, 5, 2) +#define PIN_PD19__ISC_D11 PINMUX_PIN(PIN_PD19, 6, 4) #define PIN_PD20 116 -#define PIN_PD20__TIOA2 PINMUX_PIN(PIN_PD20, 3) -#define PIN_PD20__TWCK1 PINMUX_PIN(PIN_PD20, 3) -#define PIN_PD20__UTXD2 PINMUX_PIN(PIN_PD20, 3) -#define PIN_PD20__I2SMCK0 PINMUX_PIN(PIN_PD20, 2) -#define PIN_PD20__ISI_PCK PINMUX_PIN(PIN_PD20, 4) +#define PIN_PD20__GPIO PINMUX_PIN(PIN_PD20, 0, 0) +#define PIN_PD20__TIOA2 PINMUX_PIN(PIN_PD20, 1, 3) +#define PIN_PD20__TWCK1 PINMUX_PIN(PIN_PD20, 2, 3) +#define PIN_PD20__UTXD2 PINMUX_PIN(PIN_PD20, 3, 3) +#define PIN_PD20__I2SC0_MCK PINMUX_PIN(PIN_PD20, 5, 2) +#define PIN_PD20__ISC_PCK PINMUX_PIN(PIN_PD20, 6, 4) #define PIN_PD21 117 -#define PIN_PD21__TIOB2 PINMUX_PIN(PIN_PD21, 3) -#define PIN_PD21__TWD0 PINMUX_PIN(PIN_PD21, 4) -#define PIN_PD21__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD21, 3) -#define PIN_PD21__I2SWS0 PINMUX_PIN(PIN_PD21, 2) -#define PIN_PD21__ISI_VSYNC PINMUX_PIN(PIN_PD21, 4) +#define PIN_PD21__GPIO PINMUX_PIN(PIN_PD21, 0, 0) +#define PIN_PD21__TIOB2 PINMUX_PIN(PIN_PD21, 1, 3) +#define PIN_PD21__TWD0 PINMUX_PIN(PIN_PD21, 2, 4) +#define PIN_PD21__FLEXCOM4_IO0 PINMUX_PIN(PIN_PD21, 3, 3) +#define PIN_PD21__I2SC0_WS PINMUX_PIN(PIN_PD21, 5, 2) +#define PIN_PD21__ISC_VSYNC PINMUX_PIN(PIN_PD21, 6, 4) #define PIN_PD22 118 -#define PIN_PD22__TCLK2 PINMUX_PIN(PIN_PD22, 3) -#define PIN_PD22__TWCK0 PINMUX_PIN(PIN_PD22, 4) -#define PIN_PD22__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD22, 3) -#define PIN_PD22__I2SDI0 PINMUX_PIN(PIN_PD22, 2) -#define PIN_PD22__ISI_HSYNC PINMUX_PIN(PIN_PD22, 4) +#define PIN_PD22__GPIO PINMUX_PIN(PIN_PD22, 0, 0) +#define PIN_PD22__TCLK2 PINMUX_PIN(PIN_PD22, 1, 3) +#define PIN_PD22__TWCK0 PINMUX_PIN(PIN_PD22, 2, 4) +#define PIN_PD22__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD22, 3, 3) +#define PIN_PD22__I2SC0_DI0 PINMUX_PIN(PIN_PD22, 5, 2) +#define PIN_PD22__ISC_HSYNC PINMUX_PIN(PIN_PD22, 6, 4) #define PIN_PD23 119 -#define PIN_PD23__URXD2 PINMUX_PIN(PIN_PD23, 2) -#define PIN_PD23__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD23, 3) -#define PIN_PD23__I2SDO0 PINMUX_PIN(PIN_PD23, 2) -#define PIN_PD23__ISI_FIELD PINMUX_PIN(PIN_PD23, 4) +#define PIN_PD23__GPIO PINMUX_PIN(PIN_PD23, 0, 0) +#define PIN_PD23__URXD2 PINMUX_PIN(PIN_PD23, 1, 2) +#define PIN_PD23__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD23, 3, 3) +#define PIN_PD23__I2SC0_DO0 PINMUX_PIN(PIN_PD23, 5, 2) +#define PIN_PD23__ISC_FIELD PINMUX_PIN(PIN_PD23, 6, 4) #define PIN_PD24 120 -#define PIN_PD24__UTXD2 PINMUX_PIN(PIN_PD23, 2) -#define PIN_PD24__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD23, 3) +#define PIN_PD24__GPIO PINMUX_PIN(PIN_PD24, 0, 0) +#define PIN_PD24__UTXD2 PINMUX_PIN(PIN_PD23, 1, 2) +#define PIN_PD24__FLEXCOM4_IO3 PINMUX_PIN(PIN_PD23, 3, 3) #define PIN_PD25 121 -#define PIN_PD25__SPI1_SPCK PINMUX_PIN(PIN_PD25, 3) -#define PIN_PD25__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD25, 3) +#define PIN_PD25__GPIO PINMUX_PIN(PIN_PD25, 0, 0) +#define PIN_PD25__SPI1_SPCK PINMUX_PIN(PIN_PD25, 1, 3) +#define PIN_PD25__FLEXCOM4_IO4 PINMUX_PIN(PIN_PD25, 3, 3) #define PIN_PD26 122 -#define PIN_PD26__SPI1_MOSI PINMUX_PIN(PIN_PD26, 3) -#define PIN_PD26__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD26, 2) +#define PIN_PD26__GPIO PINMUX_PIN(PIN_PD26, 0, 0) +#define PIN_PD26__SPI1_MOSI PINMUX_PIN(PIN_PD26, 1, 3) +#define PIN_PD26__FLEXCOM2_IO0 PINMUX_PIN(PIN_PD26, 3, 2) #define PIN_PD27 123 -#define PIN_PD27__SPI1_MISO PINMUX_PIN(PIN_PD27, 3) -#define PIN_PD27__TCK PINMUX_PIN(PIN_PD27, 3) -#define PIN_PD27__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD27, 2) +#define PIN_PD27__GPIO PINMUX_PIN(PIN_PD27, 0, 0) +#define PIN_PD27__SPI1_MISO PINMUX_PIN(PIN_PD27, 1, 3) +#define PIN_PD27__TCK PINMUX_PIN(PIN_PD27, 2, 3) +#define PIN_PD27__FLEXCOM2_IO1 PINMUX_PIN(PIN_PD27, 3, 2) #define PIN_PD28 124 -#define PIN_PD28__SPI1_NPCS0 PINMUX_PIN(PIN_PD28, 3) -#define PIN_PD28__TCI PINMUX_PIN(PIN_PD28, 3) -#define PIN_PD28__FLEXCOM2_IO2 PINMUX_PIN(PIN_PD28, 2) +#define PIN_PD28__GPIO PINMUX_PIN(PIN_PD28, 0, 0) +#define PIN_PD28__SPI1_NPCS0 PINMUX_PIN(PIN_PD28, 1, 3) +#define PIN_PD28__TCI PINMUX_PIN(PIN_PD28, 2, 3) +#define PIN_PD28__FLEXCOM2_IO2 PINMUX_PIN(PIN_PD28, 3, 2) #define PIN_PD29 125 -#define PIN_PD29__SPI1_NPCS1 PINMUX_PIN(PIN_PD29, 3) -#define PIN_PD29__TDO PINMUX_PIN(PIN_PD29, 3) -#define PIN_PD29__FLEXCOM2_IO3 PINMUX_PIN(PIN_PD29, 2) -#define PIN_PD29__TIOA3 PINMUX_PIN(PIN_PD29, 3) -#define PIN_PD29__TWD0 PINMUX_PIN(PIN_PD29, 3) +#define PIN_PD29__GPIO PINMUX_PIN(PIN_PD29, 0, 0) +#define PIN_PD29__SPI1_NPCS1 PINMUX_PIN(PIN_PD29, 1, 3) +#define PIN_PD29__TDO PINMUX_PIN(PIN_PD29, 2, 3) +#define PIN_PD29__FLEXCOM2_IO3 PINMUX_PIN(PIN_PD29, 3, 2) +#define PIN_PD29__TIOA3 PINMUX_PIN(PIN_PD29, 4, 3) +#define PIN_PD29__TWD0 PINMUX_PIN(PIN_PD29, 5, 3) #define PIN_PD30 126 -#define PIN_PD30__SPI1_NPCS2 PINMUX_PIN(PIN_PD30, 3) -#define PIN_PD30__TMS PINMUX_PIN(PIN_PD30, 3) -#define PIN_PD30__FLEXCOM2_IO4 PINMUX_PIN(PIN_PD30, 2) -#define PIN_PD30__TIOB3 PINMUX_PIN(PIN_PD30, 3) -#define PIN_PD30__TWCK0 PINMUX_PIN(PIN_PD30, 3) +#define PIN_PD30__GPIO PINMUX_PIN(PIN_PD30, 0, 0) +#define PIN_PD30__SPI1_NPCS2 PINMUX_PIN(PIN_PD30, 1, 3) +#define PIN_PD30__TMS PINMUX_PIN(PIN_PD30, 2, 3) +#define PIN_PD30__FLEXCOM2_IO4 PINMUX_PIN(PIN_PD30, 3, 2) +#define PIN_PD30__TIOB3 PINMUX_PIN(PIN_PD30, 4, 3) +#define PIN_PD30__TWCK0 PINMUX_PIN(PIN_PD30, 5, 3) #define PIN_PD31 127 -#define PIN_PD31__ADTRG PINMUX_PIN(PIN_PD31, 1) -#define PIN_PD31__NTRST PINMUX_PIN(PIN_PD31, 3) -#define PIN_PD31__IRQ PINMUX_PIN(PIN_PD31, 4) -#define PIN_PD31__TCLK3 PINMUX_PIN(PIN_PD31, 3) -#define PIN_PD31__PCK0 PINMUX_PIN(PIN_PD31, 2) +#define PIN_PD31__GPIO PINMUX_PIN(PIN_PD31, 0, 0) +#define PIN_PD31__ADTRG PINMUX_PIN(PIN_PD31, 1, 1) +#define PIN_PD31__NTRST PINMUX_PIN(PIN_PD31, 2, 3) +#define PIN_PD31__IRQ PINMUX_PIN(PIN_PD31, 3, 4) +#define PIN_PD31__TCLK3 PINMUX_PIN(PIN_PD31, 4, 3) +#define PIN_PD31__PCK0 PINMUX_PIN(PIN_PD31, 5, 2) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index dcde1036181623..87e7435fb008f6 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -60,12 +60,13 @@ config PINCTRL_AT91 depends on OF depends on ARCH_AT91 select PINMUX - select PINCONF select GPIOLIB select OF_GPIO select GPIOLIB_IRQCHIP + select OF_GPIO help - Say Y here to enable the at91 pinctrl driver + Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4 + controller available on sama5d2 SoC. config PINCTRL_AT91PIO4 bool "AT91 PIO4 pinctrl driver" diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index b9db58516bf2ff..6aff632aaa46bc 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -1,24 +1,22 @@ /* * Driver for the Atmel PIO4 controller * - * Copyright (C) 2015 Atmel Corporation + * Copyright (C) 2015 Atmel, + * 2015 Ludovic Desroches * - * Author: Ludovic Desroches + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * 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, see . + * 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. */ -#include +#include +#include +#include #include #include #include @@ -26,250 +24,634 @@ #include #include #include -#include #include #include "core.h" +#include "pinconf.h" #include "pinctrl-utils.h" +/* + * Warning: + * In order to not introduce confusion between Atmel PIO groups and pinctrl + * framework groups, Atmel PIO groups will be called banks, line is kept to + * designed the pin id into this bank. + */ + +#define ATMEL_PIO_MSKR 0x0000 +#define ATMEL_PIO_CFGR 0x0004 +#define ATMEL_PIO_CFGR_FUNC_MASK GENMASK(2, 0) +#define ATMEL_PIO_DIR_MASK BIT(8) +#define ATMEL_PIO_PUEN_MASK BIT(9) +#define ATMEL_PIO_PDEN_MASK BIT(10) +#define ATMEL_PIO_IFEN_MASK BIT(12) +#define ATMEL_PIO_IFSCEN_MASK BIT(13) +#define ATMEL_PIO_OPD_MASK BIT(14) +#define ATMEL_PIO_SCHMITT_MASK BIT(15) +#define ATMEL_PIO_CFGR_EVTSEL_MASK GENMASK(26, 24) +#define ATMEL_PIO_CFGR_EVTSEL_FALLING (0 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_RISING (1 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_BOTH (2 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_LOW (3 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_HIGH (4 << 24) +#define ATMEL_PIO_PDSR 0x0008 +#define ATMEL_PIO_LOCKSR 0x000C +#define ATMEL_PIO_SODR 0x0010 +#define ATMEL_PIO_CODR 0x0014 +#define ATMEL_PIO_ODSR 0x0018 +#define ATMEL_PIO_IER 0x0020 +#define ATMEL_PIO_IDR 0x0024 +#define ATMEL_PIO_IMR 0x0028 +#define ATMEL_PIO_ISR 0x002C +#define ATMEL_PIO_IOFR 0x003C + +#define ATMEL_PIO_NPINS_PER_BANK 32 +#define ATMEL_PIO_BANK(pin_id) (pin_id / ATMEL_PIO_NPINS_PER_BANK) +#define ATMEL_PIO_LINE(pin_id) (pin_id % ATMEL_PIO_NPINS_PER_BANK) +#define ATMEL_PIO_BANK_OFFSET 0x40 + +#define ATMEL_GET_PIN_NO(pinfunc) ((pinfunc) & 0xff) +#define ATMEL_GET_PIN_FUNC(pinfunc) ((pinfunc >> 16) & 0xf) +#define ATMEL_GET_PIN_IOSET(pinfunc) ((pinfunc >> 20) & 0xf) + +struct atmel_pioctrl_data { + unsigned nbanks; +}; + +struct atmel_group { + const char *name; + u32 pin; +}; -#define ATMEL_PIO4_BANK_OFFSET 0x0040 -#define ATMEL_PIO4_MSKR 0x0000 -#define ATMEL_PIO4_CFGR 0x0004 -#define ATMEL_PIO4_CFGR_FUNC_MASK (0x7) -#define ATMEL_PIO4_DIR_MASK (0x1 << 8) -#define ATMEL_PIO4_PUEN_MASK (0x1 << 9) -#define ATMEL_PIO4_PDEN_MASK (0x1 << 10) -#define ATMEL_PIO4_IFEN_MASK (0x1 << 12) -#define ATMEL_PIO4_IFSCEN_MASK (0x1 << 13) -#define ATMEL_PIO4_OPD_MASK (0x1 << 14) -#define ATMEL_PIO4_SCHMITT_MASK (0x1 << 15) -#define ATMEL_PIO4_PDSR 0x0008 -#define ATMEL_PIO4_LOCKSR 0x000C -#define ATMEL_PIO4_SODR 0x0010 -#define ATMEL_PIO4_CODR 0x0014 -#define ATMEL_PIO4_ODSR 0x0018 -#define ATMEL_PIO4_IER 0x0020 -#define ATMEL_PIO4_IDR 0x0024 -#define ATMEL_PIO4_IMR 0x0028 -#define ATMEL_PIO4_ISR 0x002C -#define ATMEL_PIO4_IOFR 0x003C - -#define ATMEL_GET_IOSET(pin) ((pin >> 16) & 0xff) - - -struct atmel_pinctrl { - struct pinctrl_dev *pctrl; - struct regmap *regmap_base; - unsigned int nbanks; - unsigned int npins_per_bank; +struct atmel_pin { + unsigned pin_id; + unsigned mux; + unsigned ioset; + unsigned bank; + unsigned line; + const char *device; +}; + +/** + * struct atmel_pioctrl - Atmel PIO controller (pinmux + gpio) + * @reg_base: base address of the controller. + * @clk: clock of the controller. + * @nbanks: number of PIO groups, it can vary depending on the SoC. + * @pinctrl_dev: pinctrl device registered. + * @groups: groups table to provide group name and pin in the group to pinctrl. + * @group_names: group names table to provide all the group/pin names to + * pinctrl or gpio. + * @pins: pins table used for both pinctrl and gpio. pin_id, bank and line + * fields are set at probe time. Other ones are set when parsing dt + * pinctrl. + * @npins: number of pins. + * @gpio_chip: gpio chip registered. + * @irq_domain: irq domain for the gpio controller. + * @irqs: table containing the hw irq number of the bank. The index of the + * table is the bank id. + * @dev: device entry for the Atmel PIO controller. + * @node: node of the Atmel PIO controller. + */ +struct atmel_pioctrl { + void __iomem *reg_base; + struct clk *clk; + unsigned nbanks; + struct pinctrl_dev *pinctrl_dev; struct atmel_group *groups; - unsigned int ngroups; - const char* const *funcs; - unsigned int nfuncs; - struct pinctrl_desc *pctrl_desc; + const char * const *group_names; + struct atmel_pin **pins; + unsigned npins; + struct gpio_chip *gpio_chip; + struct irq_domain *irq_domain; + int *irqs; + struct device *dev; + struct device_node *node; }; -struct atmel_pinctrl_data { - const struct pinctrl_ops *pctlops; - const struct pinmux_ops *pmxops; - const struct pinconf_ops *confops; - bool complex_pin_desc; - unsigned nbanks; - struct atmel_pinctrl *atmel_pinctrl; +static const char * const atmel_functions[] = { + "GPIO", "A", "B", "C", "D", "E", "F", "G" }; -struct atmel_group { - const char *name; - u32 *pins; - unsigned npins; +/* --- GPIO --- */ +static unsigned int atmel_gpio_read(struct atmel_pioctrl *atmel_pioctrl, + unsigned int bank, unsigned int reg) +{ + return readl_relaxed(atmel_pioctrl->reg_base + + ATMEL_PIO_BANK_OFFSET * bank + reg); +} + +static void atmel_gpio_write(struct atmel_pioctrl *atmel_pioctrl, + unsigned int bank, unsigned int reg, + unsigned int val) +{ + writel_relaxed(val, atmel_pioctrl->reg_base + + ATMEL_PIO_BANK_OFFSET * bank + reg); +} + +static void atmel_gpio_irq_ack(struct irq_data *d) +{ + /* + * Nothing to do, interrupt is cleared when reading the status + * register. + */ +} + +static int atmel_gpio_irq_set_type(struct irq_data *d, unsigned type) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + struct atmel_pin *pin = atmel_pioctrl->pins[d->hwirq]; + unsigned reg; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_MSKR, + BIT(pin->line)); + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR); + reg &= (~ATMEL_PIO_CFGR_EVTSEL_MASK); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + __irq_set_handler_locked(d->irq, handle_edge_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + __irq_set_handler_locked(d->irq, handle_edge_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + __irq_set_handler_locked(d->irq, handle_edge_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_BOTH; + break; + case IRQ_TYPE_LEVEL_LOW: + __irq_set_handler_locked(d->irq, handle_level_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + __irq_set_handler_locked(d->irq, handle_level_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_HIGH; + break; + case IRQ_TYPE_NONE: + default: + return -EINVAL; + } + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR, reg); + + return 0; +} + +static void atmel_gpio_irq_mask(struct irq_data *d) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + struct atmel_pin *pin = atmel_pioctrl->pins[d->hwirq]; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_IDR, + BIT(pin->line)); +} + +static void atmel_gpio_irq_unmask(struct irq_data *d) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + struct atmel_pin *pin = atmel_pioctrl->pins[d->hwirq]; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_IER, + BIT(pin->line)); +} + +static struct irq_chip atmel_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = atmel_gpio_irq_ack, + .irq_mask = atmel_gpio_irq_mask, + .irq_unmask = atmel_gpio_irq_unmask, + .irq_set_type = atmel_gpio_irq_set_type, }; -static int atmel_pio4_pin_config_read(struct pinctrl_dev *pctldev, - unsigned pin_id, u32 *res) +static void atmel_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned long isr; + int n, bank = -1; + + /* Find from which bank is the irq received. */ + for (n = 0; n < atmel_pioctrl->nbanks; n++) { + if (atmel_pioctrl->irqs[n] == irq) { + bank = n; + break; + } + } + + if (bank < 0) { + dev_err(atmel_pioctrl->dev, + "no bank associated to irq %u\n", irq); + return; + } + + chained_irq_enter(chip, desc); + + for (;;) { + isr = (unsigned long)atmel_gpio_read(atmel_pioctrl, bank, + ATMEL_PIO_ISR); + isr &= (unsigned long)atmel_gpio_read(atmel_pioctrl, bank, + ATMEL_PIO_IMR); + if (!isr) + break; + + for_each_set_bit(n, &isr, BITS_PER_LONG) + generic_handle_irq(gpio_to_irq(bank * + ATMEL_PIO_NPINS_PER_BANK + n)); + } + + chained_irq_exit(chip, desc); +} + +static int atmel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + unsigned reg; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_MSKR, + BIT(pin->line)); + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR); + reg &= ~ATMEL_PIO_DIR_MASK; + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR, reg); + + return 0; +} + +static int atmel_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + unsigned reg; + + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_PDSR); + + return !!(reg & BIT(pin->line)); +} + +static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + unsigned reg; + + atmel_gpio_write(atmel_pioctrl, pin->bank, + value ? ATMEL_PIO_SODR : ATMEL_PIO_CODR, + BIT(pin->line)); + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_MSKR, + BIT(pin->line)); + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR); + reg |= ATMEL_PIO_DIR_MASK; + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR, reg); + + return 0; +} + +static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + + atmel_gpio_write(atmel_pioctrl, pin->bank, + val ? ATMEL_PIO_SODR : ATMEL_PIO_CODR, + BIT(pin->line)); +} + +static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) { - struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - unsigned bank, pin; - u32 mask; - - bank = pin_id / pctrl->npins_per_bank; - pin = pin_id % pctrl->npins_per_bank; - mask = 1 << pin; - dev_vdbg(pctldev->dev, "%s: bank %u, pin %u\n", __func__, bank, pin); - - regmap_write(pctrl->regmap_base, - bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_MSKR, - mask); - - return regmap_read(pctrl->regmap_base, - bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_CFGR, - res); + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + + return irq_find_mapping(atmel_pioctrl->irq_domain, offset); } -static void atmel_pio4_pin_config_write(struct pinctrl_dev *pctldev, - unsigned pin_id, u32 conf) +static struct gpio_chip atmel_gpio_chip = { + .direction_input = atmel_gpio_direction_input, + .get = atmel_gpio_get, + .direction_output = atmel_gpio_direction_output, + .set = atmel_gpio_set, + .to_irq = atmel_gpio_to_irq, + .base = 0, +}; + +/* --- PINCTRL --- */ +static unsigned int atmel_pin_config_read(struct pinctrl_dev *pctldev, + unsigned pin_id) { - struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - unsigned bank, pin; - u32 mask; - - bank = pin_id / pctrl->npins_per_bank; - pin = pin_id % pctrl->npins_per_bank; - mask = 1 << pin; - dev_vdbg(pctldev->dev, "%s: bank %u, pin %u\n", __func__, bank, pin); - - regmap_write(pctrl->regmap_base, - bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_MSKR, - mask); - - regmap_write(pctrl->regmap_base, - bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_CFGR, - conf); + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned bank = atmel_pioctrl->pins[pin_id]->bank; + unsigned line = atmel_pioctrl->pins[pin_id]->line; + void __iomem *addr = atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET; + + writel_relaxed(BIT(line), addr + ATMEL_PIO_MSKR); + /* Have to set MSKR first, to access the right pin CFGR. */ + wmb(); + + return readl_relaxed(addr + ATMEL_PIO_CFGR); } -/* ----- pinctrl part ----- */ +static void atmel_pin_config_write(struct pinctrl_dev *pctldev, + unsigned pin_id, u32 conf) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned bank = atmel_pioctrl->pins[pin_id]->bank; + unsigned line = atmel_pioctrl->pins[pin_id]->line; + void __iomem *addr = atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET; + + writel_relaxed(BIT(line), addr + ATMEL_PIO_MSKR); + /* Have to set MSKR first, to access the right pin CFGR. */ + wmb(); + writel_relaxed(conf, addr + ATMEL_PIO_CFGR); +} static int atmel_pctl_get_groups_count(struct pinctrl_dev *pctldev) { - struct atmel_pinctrl *atmel_pinctrl = pinctrl_dev_get_drvdata(pctldev); + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); - return atmel_pinctrl->ngroups; + return atmel_pioctrl->npins; } static const char *atmel_pctl_get_group_name(struct pinctrl_dev *pctldev, unsigned selector) { - struct atmel_pinctrl *atmel_pinctrl = pinctrl_dev_get_drvdata(pctldev); + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); - return atmel_pinctrl->groups[selector].name; + return atmel_pioctrl->groups[selector].name; } static int atmel_pctl_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, const unsigned **pins, unsigned *num_pins) { - struct atmel_pinctrl *atmel_pinctrl = pinctrl_dev_get_drvdata(pctldev); + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); - *pins = atmel_pinctrl->groups[selector].pins; - *num_pins = atmel_pinctrl->groups[selector].npins; + *pins = (unsigned *)&atmel_pioctrl->groups[selector].pin; + *num_pins = 1; return 0; } -static const struct pinctrl_ops atmel_pctlops = { - .get_groups_count = atmel_pctl_get_groups_count, - .get_group_name = atmel_pctl_get_group_name, - .get_group_pins = atmel_pctl_get_group_pins, - .dt_node_to_map = pinconf_generic_dt_node_to_map_all, - .dt_free_map = pinctrl_utils_dt_free_map, -}; - +struct atmel_group *atmel_pctl_find_group_by_pin(struct pinctrl_dev *pctldev, + unsigned pin) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + int i; -/* ----- pinmux part ----- */ + for (i = 0; i < atmel_pioctrl->npins; i++) { + struct atmel_group *grp = atmel_pioctrl->groups + i; -static int atmel_pmux_get_functions_count(struct pinctrl_dev *pctldev) -{ - struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + if (grp->pin == pin) + return grp; + } - return pctrl->nfuncs; + return NULL; } -static const char *atmel_pmux_get_function_name(struct pinctrl_dev *pctldev, - unsigned selector) +static int atmel_pctl_xlate_pinfunc(struct pinctrl_dev *pctldev, + struct device_node *np, + u32 pinfunc, const char **grp_name, + const char **func_name) { - struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned pin_id, func_id; + struct atmel_group *grp; - return pctrl->funcs[selector]; -} + pin_id = ATMEL_GET_PIN_NO(pinfunc); + func_id = ATMEL_GET_PIN_FUNC(pinfunc); -static int atmel_pmux_get_function_groups(struct pinctrl_dev *pctldev, - unsigned selector, - const char * const **groups, - unsigned * const num_groups) -{ - return -EINVAL; + if (func_id >= ARRAY_SIZE(atmel_functions)) + return -EINVAL; + + *func_name = atmel_functions[func_id]; + + grp = atmel_pctl_find_group_by_pin(pctldev, pin_id); + if (!grp) + return -EINVAL; + *grp_name = grp->name; + + atmel_pioctrl->pins[pin_id]->mux = func_id; + atmel_pioctrl->pins[pin_id]->ioset = ATMEL_GET_PIN_IOSET(pinfunc); + /* Want the device name not the group one. */ + if (np->parent == atmel_pioctrl->node) + atmel_pioctrl->pins[pin_id]->device = np->name; + else + atmel_pioctrl->pins[pin_id]->device = np->parent->name; + + return 0; } -static int atmel_pio4_set_mux(struct pinctrl_dev *pctldev, - unsigned function, - unsigned group) +static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) { - struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned num_pins, num_configs, reserve; + unsigned long *configs; + struct property *pins; + bool has_config; + u32 pinfunc; int ret, i; - u32 conf; - unsigned *pin; - dev_dbg(pctldev->dev, "enable function %s group %s\n", - pctrl->funcs[function], pctrl->groups[group].name); + pins = of_find_property(np, "pinmux", NULL); + if (!pins) + return -EINVAL; + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(pctldev->dev, "%s: could not parse node property\n", + of_node_full_name(np)); + return ret; + } + + if (num_configs) + has_config = true; + + num_pins = pins->length / sizeof(u32); + if (!num_pins) { + dev_err(pctldev->dev, "no pins found in node %s\n", + of_node_full_name(np)); + return -EINVAL; + } /* - * Unfortunately, we can't set the function for several pins in one - * operation. Inside a group, pins can have different configurations. + * Reserve maps, at least there is a mux map and an optional conf + * map for each pin. */ - pin = pctrl->groups[group].pins; - for (i = 0 ; i < pctrl->groups[group].npins ; i++) { - ret = atmel_pio4_pin_config_read(pctldev, pin[i], &conf); - conf &= (~ATMEL_PIO4_CFGR_FUNC_MASK); - conf |= (function & ATMEL_PIO4_CFGR_FUNC_MASK); - dev_dbg(pctldev->dev, "pin: %u, conf: 0x%08x\n", pin[i], conf); - atmel_pio4_pin_config_write(pctldev, pin[i], conf); + reserve = 1; + if (has_config && num_pins >= 1) + reserve++; + reserve *= num_pins; + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, + reserve); + if (ret < 0) + return ret; + + for (i = 0; i < num_pins; i++) { + const char *group, *func; + + ret = of_property_read_u32_index(np, "pinmux", i, &pinfunc); + if (ret) + return ret; + + ret = atmel_pctl_xlate_pinfunc(pctldev, np, pinfunc, &group, + &func); + if (ret) + return ret; + + pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, + group, func); + + if (has_config) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, group, + configs, num_configs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + return ret; + } } return 0; } -static const struct pinmux_ops atmel_pio4_pmxops = { - .mux_per_pin = true, - .get_functions_count = atmel_pmux_get_functions_count, - .get_function_name = atmel_pmux_get_function_name, - .get_function_groups = atmel_pmux_get_function_groups, - .set_mux = atmel_pio4_set_mux, - /* TODO */ - .gpio_request_enable = NULL, - .gpio_disable_free = NULL, - .gpio_set_direction = NULL, +static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) +{ + struct device_node *np; + unsigned reserved_maps; + int ret; + + *map = NULL; + *num_maps = 0; + reserved_maps = 0; + + /* + * If all the pins of a device have the same configuration (or no one), + * it is useless to add a subnode, so directly parse node referenced by + * phandle. + */ + ret = atmel_pctl_dt_subnode_to_map(pctldev, np_config, map, + &reserved_maps, num_maps); + if (ret) { + for_each_child_of_node(np_config, np) { + ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) + break; + } + } + + if (ret < 0) { + pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); + dev_err(pctldev->dev, "can't create maps for node %s\n", + np_config->full_name); + } + + return ret; +} + +static const struct pinctrl_ops atmel_pctlops = { + .get_groups_count = atmel_pctl_get_groups_count, + .get_group_name = atmel_pctl_get_group_name, + .get_group_pins = atmel_pctl_get_group_pins, + .dt_node_to_map = atmel_pctl_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, }; +static int atmel_pmx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(atmel_functions); +} + +static const char *atmel_pmx_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return atmel_functions[selector]; +} + +static int atmel_pmx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = atmel_pioctrl->group_names; + *num_groups = atmel_pioctrl->npins; + + return 0; +} + +static int atmel_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned pin; + u32 conf; + + dev_dbg(pctldev->dev, "enable function %s group %s\n", + atmel_functions[function], atmel_pioctrl->groups[group].name); + + pin = atmel_pioctrl->groups[group].pin; + conf = atmel_pin_config_read(pctldev, pin); + conf &= (~ATMEL_PIO_CFGR_FUNC_MASK); + conf |= (function & ATMEL_PIO_CFGR_FUNC_MASK); + dev_dbg(pctldev->dev, "pin: %u, conf: 0x%08x\n", pin, conf); + atmel_pin_config_write(pctldev, pin, conf); -/* ----- pinconf part ----- */ + return 0; +} -static int atmel_pio4_pin_config_get(struct pinctrl_dev *pctldev, - unsigned pin, - unsigned long *config) +static const struct pinmux_ops atmel_pmxops = { + .get_functions_count = atmel_pmx_get_functions_count, + .get_function_name = atmel_pmx_get_function_name, + .get_function_groups = atmel_pmx_get_function_groups, + .set_mux = atmel_pmx_set_mux, +}; + +static int atmel_conf_pin_config_group_get(struct pinctrl_dev *pctldev, + unsigned group, + unsigned long *config) { - unsigned int arg = 0; - unsigned int param = pinconf_to_config_param(*config); + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned param = pinconf_to_config_param(*config), arg = 0; + struct atmel_group *grp = atmel_pioctrl->groups + group; + unsigned pin_id = grp->pin; u32 res; - int ret; - ret = atmel_pio4_pin_config_read(pctldev, pin, &res); - if (ret) - return -EIO; + res = atmel_pin_config_read(pctldev, pin_id); switch (param) { case PIN_CONFIG_BIAS_PULL_UP: - if (!(res & ATMEL_PIO4_PUEN_MASK)) + if (!(res & ATMEL_PIO_PUEN_MASK)) return -EINVAL; arg = 1; break; case PIN_CONFIG_BIAS_PULL_DOWN: - if ((res & ATMEL_PIO4_PUEN_MASK) - || (!(res & ATMEL_PIO4_PDEN_MASK))) + if ((res & ATMEL_PIO_PUEN_MASK) || + (!(res & ATMEL_PIO_PDEN_MASK))) return -EINVAL; arg = 1; break; case PIN_CONFIG_BIAS_DISABLE: - if ((res & ATMEL_PIO4_PUEN_MASK) - || ((res & ATMEL_PIO4_PDEN_MASK))) + if ((res & ATMEL_PIO_PUEN_MASK) || + ((res & ATMEL_PIO_PDEN_MASK))) return -EINVAL; arg = 1; break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: - if (!(res & ATMEL_PIO4_OPD_MASK)) + if (!(res & ATMEL_PIO_OPD_MASK)) return -EINVAL; arg = 1; break; case PIN_CONFIG_INPUT_SCHMITT_ENABLE: - if (!(res & ATMEL_PIO4_SCHMITT_MASK)) + if (!(res & ATMEL_PIO_SCHMITT_MASK)) return -EINVAL; arg = 1; break; @@ -281,64 +663,80 @@ static int atmel_pio4_pin_config_get(struct pinctrl_dev *pctldev, return 0; } -static int atmel_pio4_pin_config_set(struct pinctrl_dev *pctldev, - unsigned pin_id, - unsigned long *configs, - unsigned num_configs) +static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned group, + unsigned long *configs, + unsigned num_configs) { - struct atmel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); - int i, ret; - u32 mask, conf = 0; - unsigned bank, pin; + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + struct atmel_group *grp = atmel_pioctrl->groups + group; + unsigned bank, pin, pin_id = grp->pin; + u32 mask, conf = 0; + int i; - ret = atmel_pio4_pin_config_read(pctldev, pin_id, &conf); - if (ret) - return -EIO; + conf = atmel_pin_config_read(pctldev, pin_id); for (i = 0; i < num_configs; i++) { - unsigned int param = pinconf_to_config_param(configs[i]); - unsigned int arg = pinconf_to_config_argument(configs[i]); + unsigned param = pinconf_to_config_param(configs[i]); + unsigned arg = pinconf_to_config_argument(configs[i]); dev_dbg(pctldev->dev, "%s: pin=%u, config=0x%lx\n", __func__, pin_id, configs[i]); - switch(param) { + switch (param) { case PIN_CONFIG_BIAS_DISABLE: - conf &= (~ATMEL_PIO4_PUEN_MASK); - conf &= (~ATMEL_PIO4_PDEN_MASK); + conf &= (~ATMEL_PIO_PUEN_MASK); + conf &= (~ATMEL_PIO_PDEN_MASK); break; case PIN_CONFIG_BIAS_PULL_UP: - conf |= ATMEL_PIO4_PUEN_MASK; + conf |= ATMEL_PIO_PUEN_MASK; break; case PIN_CONFIG_BIAS_PULL_DOWN: - conf |= ATMEL_PIO4_PDEN_MASK; + conf |= ATMEL_PIO_PDEN_MASK; break; case PIN_CONFIG_DRIVE_OPEN_DRAIN: if (arg == 0) - conf &= (~ATMEL_PIO4_OPD_MASK); + conf &= (~ATMEL_PIO_OPD_MASK); else - conf |= ATMEL_PIO4_OPD_MASK; + conf |= ATMEL_PIO_OPD_MASK; break; case PIN_CONFIG_INPUT_SCHMITT_ENABLE: if (arg == 0) - conf |= ATMEL_PIO4_SCHMITT_MASK; + conf |= ATMEL_PIO_SCHMITT_MASK; else - conf &= (~ATMEL_PIO4_SCHMITT_MASK); + conf &= (~ATMEL_PIO_SCHMITT_MASK); + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + if (arg == 0) { + conf &= (~ATMEL_PIO_IFEN_MASK); + conf &= (~ATMEL_PIO_IFSCEN_MASK); + } else { + /* + * We don't care about the debounce value for several reasons: + * - can't have different debounce periods inside a same group, + * - the register to configure this period is a secure register. + * The debouncing filter can filter a pulse with a duration of less + * than 1/2 slow clock period. + */ + conf |= ATMEL_PIO_IFEN_MASK; + conf |= ATMEL_PIO_IFSCEN_MASK; + } break; case PIN_CONFIG_OUTPUT: - conf |= ATMEL_PIO4_DIR_MASK; - bank = pin_id / pctrl->npins_per_bank; - pin = pin_id % pctrl->npins_per_bank; + conf |= ATMEL_PIO_DIR_MASK; + bank = ATMEL_PIO_BANK(pin_id); + pin = ATMEL_PIO_LINE(pin_id); mask = 1 << pin; - if (arg == 0) - regmap_write(pctrl->regmap_base, - bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_CODR, - mask); - else - regmap_write(pctrl->regmap_base, - bank * ATMEL_PIO4_BANK_OFFSET + ATMEL_PIO4_SODR, - mask); + if (arg == 0) { + writel_relaxed(mask, atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET + + ATMEL_PIO_CODR); + } else { + writel_relaxed(mask, atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET + + ATMEL_PIO_SODR); + } break; default: dev_warn(pctldev->dev, @@ -348,240 +746,258 @@ static int atmel_pio4_pin_config_set(struct pinctrl_dev *pctldev, } } - atmel_pio4_pin_config_write(pctldev, pin_id, conf); + dev_dbg(pctldev->dev, "%s: reg=0x%08x\n", __func__, conf); + atmel_pin_config_write(pctldev, pin_id, conf); return 0; } -static void atmel_pio4_pin_config_dbg_show(struct pinctrl_dev *pctldev, +static void atmel_conf_pin_config_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned pin_id) { - /* TODO */ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + u32 conf; - return; + if (!atmel_pioctrl->pins[pin_id]->device) + return; + + if (atmel_pioctrl->pins[pin_id]) + seq_printf(s, " (%s, ioset %u) ", + atmel_pioctrl->pins[pin_id]->device, + atmel_pioctrl->pins[pin_id]->ioset); + + conf = atmel_pin_config_read(pctldev, pin_id); + if (conf & ATMEL_PIO_PUEN_MASK) + seq_printf(s, "%s ", "pull-up"); + if (conf & ATMEL_PIO_PDEN_MASK) + seq_printf(s, "%s ", "pull-down"); + if (conf & ATMEL_PIO_IFEN_MASK) + seq_printf(s, "%s ", "debounce"); + if (conf & ATMEL_PIO_OPD_MASK) + seq_printf(s, "%s ", "open-drain"); + if (conf & ATMEL_PIO_SCHMITT_MASK) + seq_printf(s, "%s ", "schmitt"); } -static const struct pinconf_ops atmel_pio4_confops = { - .is_generic = true, - .pin_config_get = atmel_pio4_pin_config_get, - .pin_config_set = atmel_pio4_pin_config_set, - .pin_config_dbg_show = atmel_pio4_pin_config_dbg_show, +static const struct pinconf_ops atmel_confops = { + .pin_config_group_get = atmel_conf_pin_config_group_get, + .pin_config_group_set = atmel_conf_pin_config_group_set, + .pin_config_dbg_show = atmel_conf_pin_config_dbg_show, }; static struct pinctrl_desc atmel_pinctrl_desc = { - .name = "atmel_pinctrl", - .owner = THIS_MODULE, -}; - -static const char * const atmel_pio4_functions[] = { - "GPIO", "A", "B", "C", "D", "E", "F", "G" + .name = "atmel_pinctrl", + .confops = &atmel_confops, + .pctlops = &atmel_pctlops, + .pmxops = &atmel_pmxops, }; /* - * Set only values which are specific to PIO4. nbanks is related to the device - * so take this information from atmel_pinctrl_data. Groups will be parsed - * from the device tree. + * The number of banks can be different from a SoC to another one. + * We can have up to 16 banks. */ -struct atmel_pinctrl atmel_pio4_pinctrl = { - .npins_per_bank = 32, - .funcs = atmel_pio4_functions, - .nfuncs = ARRAY_SIZE(atmel_pio4_functions), -}; - -static const struct atmel_pinctrl_data atmel_sama5d2_pctrl_data = { - .pctlops = &atmel_pctlops, - .pmxops = &atmel_pio4_pmxops, - .confops = &atmel_pio4_confops, - .complex_pin_desc = true, - .nbanks = 4, - .atmel_pinctrl = &atmel_pio4_pinctrl, +static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = { + .nbanks = 4, }; -static const struct of_device_id atmel_pinctrl_of_match[] = { +static const struct of_device_id atmel_pctrl_of_match[] = { { .compatible = "atmel,sama5d2-pinctrl", - .data = &atmel_sama5d2_pctrl_data, + .data = &atmel_sama5d2_pioctrl_data, }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, atmel_pinctrl_of_match); +MODULE_DEVICE_TABLE(of, atmel_pctrl_of_match); -/* - * Groups are used to check if all the pins used are from the same ioset and - * for readability. The controller has no knowledge about groups, they are a - * virtual concept. Groups are defined in a subnode called group_defs. - */ -static int atmel_pinctrl_parse_groups(struct platform_device *pdev, - struct atmel_pinctrl *atmel_pinctrl) +static int atmel_pinctrl_probe(struct platform_device *pdev) { - struct device_node *np = pdev->dev.of_node, *groups_np, *group_np; - struct atmel_group *group; - int ret, i, ioset; - u32 pin; - - groups_np = of_find_node_by_name(np, "group_defs"); - if (!groups_np) { - dev_err(&pdev->dev, "group_defs node not found\n"); - return -EINVAL; + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pin_desc; + const char **group_names; + const struct of_device_id *match; + int i, ret; + struct resource *res; + struct atmel_pioctrl *atmel_pioctrl; + struct atmel_pioctrl_data *atmel_pioctrl_data; + + atmel_pioctrl = devm_kzalloc(dev, sizeof(*atmel_pioctrl), GFP_KERNEL); + if (!atmel_pioctrl) + return -ENOMEM; + atmel_pioctrl->dev = dev; + atmel_pioctrl->node = dev->of_node; + platform_set_drvdata(pdev, atmel_pioctrl); + + match = of_match_node(atmel_pctrl_of_match, dev->of_node); + if (!match) { + dev_err(dev, "unknown compatible string\n"); + return -ENODEV; } + atmel_pioctrl_data = (struct atmel_pioctrl_data *)match->data; + atmel_pioctrl->nbanks = atmel_pioctrl_data->nbanks; + atmel_pioctrl->npins = atmel_pioctrl->nbanks * ATMEL_PIO_NPINS_PER_BANK; - atmel_pinctrl->ngroups = of_get_child_count(groups_np); - if (!atmel_pinctrl->ngroups) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "unable to get atmel pinctrl resource\n"); + return -EINVAL; + } + atmel_pioctrl->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(atmel_pioctrl->reg_base)) return -EINVAL; - dev_dbg(&pdev->dev, "%u group(s)\n", atmel_pinctrl->ngroups); + atmel_pioctrl->clk = devm_clk_get(dev, NULL); + if (IS_ERR(atmel_pioctrl->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(atmel_pioctrl->clk); + } - atmel_pinctrl->groups = devm_kzalloc(&pdev->dev, - sizeof(*atmel_pinctrl->groups) * atmel_pinctrl->ngroups, - GFP_KERNEL); - if (!atmel_pinctrl->groups) + atmel_pioctrl->pins = devm_kzalloc(dev, sizeof(*atmel_pioctrl->pins) + * atmel_pioctrl->npins, GFP_KERNEL); + if (!atmel_pioctrl->pins) return -ENOMEM; - group = atmel_pinctrl->groups; - for_each_child_of_node(groups_np, group_np) { - ioset = -1; - group->name = group_np->name; - dev_dbg(&pdev->dev, "%s:\n", group->name); - group->npins = of_property_count_u32_elems(group_np, "pins"); - if (!group->npins) { - dev_err(&pdev->dev, "no pins for group %s\n", group->name); - return -EINVAL; - } - group->pins = devm_kzalloc(&pdev->dev, - sizeof(*group->pins) * group->npins, - GFP_KERNEL); - if (!group->pins) { - dev_err(&pdev->dev, - "can't allocate pin table for group %s\n", - group->name); + pin_desc = devm_kzalloc(dev, sizeof(*pin_desc) + * atmel_pioctrl->npins, GFP_KERNEL); + if (!pin_desc) + return -ENOMEM; + atmel_pinctrl_desc.pins = pin_desc; + atmel_pinctrl_desc.npins = atmel_pioctrl->npins; + + /* One pin is one group since a pin can achieve all functions. */ + group_names = devm_kzalloc(dev, sizeof(*group_names) + * atmel_pioctrl->npins, GFP_KERNEL); + if (!group_names) + return -ENOMEM; + atmel_pioctrl->group_names = group_names; + + atmel_pioctrl->groups = devm_kzalloc(&pdev->dev, + sizeof(*atmel_pioctrl->groups) * atmel_pioctrl->npins, + GFP_KERNEL); + if (!atmel_pioctrl->groups) + return -ENOMEM; + for (i = 0 ; i < atmel_pioctrl->npins; i++) { + struct atmel_group *group = atmel_pioctrl->groups + i; + unsigned bank = ATMEL_PIO_BANK(i); + unsigned line = ATMEL_PIO_LINE(i); + + atmel_pioctrl->pins[i] = devm_kzalloc(dev, + sizeof(**atmel_pioctrl->pins), GFP_KERNEL); + if (!atmel_pioctrl->pins[i]) return -ENOMEM; - } - for (i = 0; i < group->npins; i++) { - ret = of_property_read_u32_index(group_np, "pins", i, &pin); - if (ret) { - dev_err(&pdev->dev, - "can't get pins for group %s\n", - group->name); - return ret; - } - group->pins[i] = pin & PINCTRL_PIN_MASK; - dev_dbg(&pdev->dev, "%u\n", group->pins[i]); - /* - * All the pins of a group should have the same ioset - * because validation has been done in this way. It - * means you can have an unexpected behaviour if you - * mix signals from several iosets. - */ - if (ioset < 0) - ioset = ATMEL_GET_IOSET(pin); - if (ATMEL_GET_IOSET(pin) != ioset) - dev_warn(&pdev->dev, - "/!\\ pins from group %s are not using the same ioset /!\\\n", - group->name); - } - group++; - } - return 0; -} + atmel_pioctrl->pins[i]->pin_id = i; + atmel_pioctrl->pins[i]->bank = bank; + atmel_pioctrl->pins[i]->line = line; -static struct atmel_pinctrl *atmel_pinctrl_get_data(struct platform_device *pdev) { - struct atmel_pinctrl *atmel_pinctrl; - const struct of_device_id *match; - const struct atmel_pinctrl_data *data; + pin_desc[i].number = i; + /* Pin naming convention: P(bank_name)(bank_pin_number). */ + pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d", + bank + 'A', line); - atmel_pinctrl = devm_kzalloc(&pdev->dev, sizeof(*atmel_pinctrl), - GFP_KERNEL); - if (!atmel_pinctrl) { - dev_err(&pdev->dev, "can't allocate atmel_pinctrl structure\n"); - return ERR_PTR(-ENOMEM); - } + group->name = group_names[i] = pin_desc[i].name; + group->pin = pin_desc[i].number; - match = of_match_node(atmel_pinctrl_of_match, pdev->dev.of_node); - if (!match) { - dev_err(&pdev->dev, "unknow compatible string\n"); - return ERR_PTR(-ENODEV); + dev_dbg(dev, "pin_id=%u, bank=%u, line=%u", i, bank, line); } - data = match->data; - atmel_pinctrl = data->atmel_pinctrl; - atmel_pinctrl->nbanks = data->nbanks; - atmel_pinctrl_desc.pctlops = data->pctlops; - atmel_pinctrl_desc.pmxops = data->pmxops; - atmel_pinctrl_desc.confops = data->confops; - atmel_pinctrl_desc.complex_pin_desc = data->complex_pin_desc; - atmel_pinctrl_desc.npins = data->nbanks * atmel_pinctrl->npins_per_bank; - dev_dbg(&pdev->dev, "%u pins: %u banks, %u pins per bank\n", - atmel_pinctrl_desc.npins, atmel_pinctrl->nbanks, - atmel_pinctrl->npins_per_bank); - - return atmel_pinctrl; -} + atmel_pioctrl->gpio_chip = &atmel_gpio_chip; + atmel_pioctrl->gpio_chip->of_node = dev->of_node; + atmel_pioctrl->gpio_chip->ngpio = atmel_pioctrl->npins; + atmel_pioctrl->gpio_chip->label = dev_name(dev); + atmel_pioctrl->gpio_chip->dev = dev; + atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names; -static int atmel_pinctrl_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node, *regmap_np; - struct atmel_pinctrl *atmel_pinctrl; - struct pinctrl_pin_desc *pin_desc; - int ret, i; + atmel_pioctrl->irqs = devm_kzalloc(dev, sizeof(*atmel_pioctrl->irqs) + * atmel_pioctrl->nbanks, GFP_KERNEL); + if (!atmel_pioctrl->irqs) + return -ENOMEM; - atmel_pinctrl = atmel_pinctrl_get_data(pdev); - if (!atmel_pinctrl) - return PTR_ERR(atmel_pinctrl); + /* There is one controller but each bank has its own irq line. */ + for (i = 0; i < atmel_pioctrl->nbanks; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (!res) { + dev_err(dev, "missing irq resource for group %c\n", + 'A' + i); + return -EINVAL; + } + atmel_pioctrl->irqs[i] = res->start; + irq_set_chained_handler(res->start, atmel_gpio_irq_handler); + irq_set_handler_data(res->start, atmel_pioctrl); + dev_dbg(dev, "bank %i: hwirq=%u\n", i, res->start); + } - pin_desc = devm_kzalloc(&pdev->dev, - sizeof(*atmel_pinctrl_desc.pins) * atmel_pinctrl_desc.npins, - GFP_KERNEL); - if (!pin_desc) { - dev_err(&pdev->dev, "can't allocate pins structure\n"); - return -ENOMEM; + atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node, + atmel_pioctrl->gpio_chip->ngpio, + &irq_domain_simple_ops, NULL); + if (!atmel_pioctrl->irq_domain) { + dev_err(dev, "can't add the irq domain\n"); + return -ENODEV; } + atmel_pioctrl->irq_domain->name = "atmel gpio"; - /* Pin naming convention is P(bank_name)(bank_pin_number). */ - for (i = 0 ; i < atmel_pinctrl_desc.npins; i++) { - pin_desc[i].number = i; - pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d", - (i / atmel_pinctrl->npins_per_bank) + 'A', - i % atmel_pinctrl->npins_per_bank); + for (i = 0; i < atmel_pioctrl->npins; i++) { + int irq = irq_create_mapping(atmel_pioctrl->irq_domain, i); + + irq_set_chip_and_handler(irq, &atmel_gpio_irq_chip, + handle_simple_irq); + irq_set_chip_data(irq, atmel_pioctrl); + dev_dbg(dev, + "atmel gpio irq domain: hwirq: %d, linux irq: %d\n", + i, irq); } - atmel_pinctrl_desc.pins = pin_desc; - ret = atmel_pinctrl_parse_groups(pdev, atmel_pinctrl); - if (ret) - return ret; + ret = clk_prepare_enable(atmel_pioctrl->clk); + if (ret) { + dev_err(dev, "failed to prepare and enable clock\n"); + goto clk_prepare_enable_error; + } - /* Some registers are shared with the gpio controller driver. */ - regmap_np = of_parse_phandle(np, "atmel,pio_reg", 0); - if (regmap_np) { - atmel_pinctrl->regmap_base = syscon_node_to_regmap(regmap_np); - if (IS_ERR(atmel_pinctrl->regmap_base)) { - dev_err(&pdev->dev, "can't get regmap\n"); - return PTR_ERR(atmel_pinctrl->regmap_base); - } - } else { - dev_err(&pdev->dev, "atmel,pio_reg property is missing\n"); - return -EINVAL; + atmel_pioctrl->pinctrl_dev = pinctrl_register(&atmel_pinctrl_desc, + &pdev->dev, + atmel_pioctrl); + if (!atmel_pioctrl->pinctrl_dev) { + dev_err(dev, "pinctrl registration failed\n"); + goto pinctrl_register_error; } - atmel_pinctrl->pctrl = pinctrl_register(&atmel_pinctrl_desc, &pdev->dev, atmel_pinctrl); - if (!atmel_pinctrl->pctrl) { - dev_err(&pdev->dev, "pinctrl registration failed\n"); - return -ENOMEM; + ret = gpiochip_add(atmel_pioctrl->gpio_chip); + if (ret) { + dev_err(dev, "failed to add gpiochip\n"); + goto gpiochip_add_error; } - platform_set_drvdata(pdev, atmel_pinctrl); + ret = gpiochip_add_pin_range(atmel_pioctrl->gpio_chip, dev_name(dev), + 0, 0, atmel_pioctrl->gpio_chip->ngpio); + if (ret) { + dev_err(dev, "failed to add gpio pin range\n"); + goto gpiochip_add_pin_range_error; + } dev_info(&pdev->dev, "atmel pinctrl initialized\n"); return 0; + +clk_prepare_enable_error: + irq_domain_remove(atmel_pioctrl->irq_domain); +pinctrl_register_error: + clk_disable_unprepare(atmel_pioctrl->clk); +gpiochip_add_error: + pinctrl_unregister(atmel_pioctrl->pinctrl_dev); +gpiochip_add_pin_range_error: + gpiochip_remove(atmel_pioctrl->gpio_chip); + + return ret; } int atmel_pinctrl_remove(struct platform_device *pdev) { - struct atmel_pinctrl *atmel_pinctrl = platform_get_drvdata(pdev); + struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev); - pinctrl_unregister(atmel_pinctrl->pctrl); + irq_domain_remove(atmel_pioctrl->irq_domain); + clk_disable_unprepare(atmel_pioctrl->clk); + pinctrl_unregister(atmel_pioctrl->pinctrl_dev); + gpiochip_remove(atmel_pioctrl->gpio_chip); return 0; } @@ -589,12 +1005,11 @@ int atmel_pinctrl_remove(struct platform_device *pdev) static struct platform_driver atmel_pinctrl_driver = { .driver = { .name = "pinctrl-at91-pio4", - .of_match_table = atmel_pinctrl_of_match, + .of_match_table = atmel_pctrl_of_match, }, .probe = atmel_pinctrl_probe, .remove = atmel_pinctrl_remove, }; - module_platform_driver(atmel_pinctrl_driver); MODULE_AUTHOR(Ludovic Desroches ); From 38b43abf57762d59829fa257eda75cdbd1a9d8fb Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 22 Sep 2015 11:13:54 +0200 Subject: [PATCH 184/381] ARM: at91/dt: sama5d2: update to new pinmux binding Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 285 +++++--------------- arch/arm/boot/dts/sama5d2.dtsi | 20 +- 2 files changed, 75 insertions(+), 230 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index d6bdfa4ccea4a6..3b72637cb440a4 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -219,269 +219,112 @@ }; pinctrl@fc038000 { - group_defs { - flx0_0 { - pins = , - ; - }; - - flx4_0 { - pins = , - ; - }; - - i2c0_0 { - pins = , - ; - }; - - i2c1_0 { - pins = , - ; - }; - - macb0_0 { - pins = , - , - , - , - , - , - , - , - , - ; - }; - - qspi0_0 { - pins = , - , - , - , - , - ; - }; - - sdmmc0_0 { - pins = , - , - , - , - , - , - , - , - , - , - , - , - ; - }; - - sdmmc1_0 { - pins = , - , - , - , - , - , - ; - }; - - spi0_0 { - pins = , - , - , - ; - }; - - uart1_0 { - pins = , - ; - }; - - uart3_0 { - pins = , - ; - }; - }; - pinctrl_flx0_default: flx0_default { - mux { - function = "C"; - groups = "flx0_0"; - }; - - conf { - pin = , - ; - bias-disable; - }; + pinmux = , + ; + bias-disable; }; pinctrl_flx4_default: flx4_default { - mux { - function = "B"; - groups = "flx4_0"; - }; - - conf { - pins = , - ; - bias-disable; - }; + pinmux = , + ; + bias-disable; }; pinctrl_i2c0_default: i2c0_default { - mux { - function = "B"; - groups = "i2c0_0"; - }; - - conf { - pins = , - ; - bias-disable; - }; + pinmux = , + ; + bias-disable; }; pinctrl_i2c1_default: i2c1_default { - mux { - function = "A"; - groups = "i2c1_0"; - }; - - conf { - pins = , - ; - bias-disable; - }; + pinmux = , + ; + bias-disable; }; pinctrl_macb0_rmii: macb0_rmii { - mux { - function = "F"; - groups = "macb0_0"; - }; - - conf { - pins = , - , - , - , - , - , - , - , - , - ; - bias-disable; - }; + pinmux = , + , + , + , + , + , + , + , + , + ; + bias-disable; }; pinctrl_qspi0_default: qspi0_default { - mux { - function = "F"; - groups = "qspi0_0"; - }; - - conf { - pins = , - , - , - , - , - ; - }; + pinmux = , + , + , + , + , + ; + bias-disable; }; pinctrl_sdmmc0_default: sdmmc0_default { - mux { - function = "A"; - groups = "sdmmc0_0"; - }; - - conf-data { - pins = , - , - , - , - , - , - , - ; + cmd_data { + pinmux = , + , + , + , + , + , + , + , + ; bias-pull-up; }; - conf-cmd_ck_cd_rstn_vddsel { - pins = , - , - , - , - ; + ck_cd_rstn_vddsel { + pinmux = , + , + , + ; bias-disable; }; }; pinctrl_sdmmc1_default: sdmmc1_default { - mux { - function = "E"; - groups = "sdmmc1_0"; - }; - - conf-cmd_data { - pins = , - , - , - , - ; + cmd_data { + pinmux = , + , + , + , + ; bias-pull-up; }; conf-ck_cd { - pins = , - ; + pinmux = , + ; bias-disable; }; }; pinctrl_spi0_default: spi0_default { - mux { - function = "A"; - groups = "spi0_0"; - }; - - conf { - pins = , - , - , - ; - bias-disable; - }; + pinmux = , + , + , + ; + bias-disable; }; pinctrl_uart1_default: uart1_default { - mux { - function = "A"; - groups = "uart1_0"; - }; - - conf { - group = "uart1_0"; - bias-disable; - }; + pinmux = , + ; + bias-disable; }; pinctrl_uart3_default: uart3_default { - mux { - function = "C"; - groups = "uart3_0"; - }; - - conf { - group = "uart3_0"; - bias-disable; - }; + pinmux = , + ; + bias-disable; }; }; }; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 8f6b5baa06ff36..21e82296b1f4fd 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1061,16 +1061,18 @@ status = "disabled"; }; - pio_reg: syscon@fc038000 { - compatible = "atmel,sama5d2-pio_reg", "syscon"; + pioA: pinctrl@fc038000 { + compatible = "atmel,sama5d2-pinctrl"; reg = <0xfc038000 0x600>; - }; - - pinctrl@fc038000 { - #address-cells = <1>; - #size-cells = <1>; - compatible = "atmel,sama5d2-pinctrl", "simple-bus"; - atmel,pio_reg = <&pio_reg 0x0>; + interrupts = <18 IRQ_TYPE_LEVEL_HIGH 7>, + <68 IRQ_TYPE_LEVEL_HIGH 7>, + <69 IRQ_TYPE_LEVEL_HIGH 7>, + <70 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-controller; + #interrupt-cells = <2>; + gpio-controller; + #gpio-cells = <2>; + clocks = <&pioA_clk>; }; tdes@fc044000 { From 07fca7ee69feb2ac822738f57f4709fce736dc20 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 18 Sep 2015 19:28:22 +0800 Subject: [PATCH 185/381] ARM: at91/dt: ov2640: add hsync/vsync-active property On at91sam9x5ek/at91sam9m10g45ek/sama5d3xek boards, we use the parallel connection for ov2640. So we must set the hsync/vsync property (1 means active high). Otherwise, the connection would be seen as BT.656 or BT.1120. Signed-off-by: Josh Wu Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91sam9m10g45ek.dts | 2 ++ arch/arm/boot/dts/at91sam9x5ek.dtsi | 2 ++ arch/arm/boot/dts/sama5d3xmb.dtsi | 2 ++ 3 files changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9m10g45ek.dts b/arch/arm/boot/dts/at91sam9m10g45ek.dts index d1ae60a855d492..9d16ef8453c556 100644 --- a/arch/arm/boot/dts/at91sam9m10g45ek.dts +++ b/arch/arm/boot/dts/at91sam9m10g45ek.dts @@ -198,6 +198,8 @@ isi_0: endpoint { remote-endpoint = <&ov2640_0>; bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; }; }; }; diff --git a/arch/arm/boot/dts/at91sam9x5ek.dtsi b/arch/arm/boot/dts/at91sam9x5ek.dtsi index 36de329340d155..52425a4ca97e87 100644 --- a/arch/arm/boot/dts/at91sam9x5ek.dtsi +++ b/arch/arm/boot/dts/at91sam9x5ek.dtsi @@ -66,6 +66,8 @@ isi_0: endpoint@0 { remote-endpoint = <&ov2640_0>; bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; }; }; }; diff --git a/arch/arm/boot/dts/sama5d3xmb.dtsi b/arch/arm/boot/dts/sama5d3xmb.dtsi index 83bee7a3a617d0..89010422812d6a 100644 --- a/arch/arm/boot/dts/sama5d3xmb.dtsi +++ b/arch/arm/boot/dts/sama5d3xmb.dtsi @@ -87,6 +87,8 @@ isi_0: endpoint { remote-endpoint = <&ov2640_0>; bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; }; }; }; From 7792d1c921bb8de96dbd3921e8b4c74eb18baee9 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 21 Sep 2015 15:46:04 +0200 Subject: [PATCH 186/381] irqchip/atmel-aic5: Use per chip mask caches in mask/unmask() When masking/unmasking interrupts, mask_cache is updated and used later for suspend/resume. Unfortunately, it always was the mask_cache associated with the first irq chip which was updated. So when performing resume, only irqs 0-31 could be enabled. Fixes: b1479ebb7720 ("irqchip: atmel-aic: Add atmel AIC/AIC5 drivers") Signed-off-by: Ludovic Desroches Cc: Cc: Cc: Cc: Cc: Cc: Cc: Cc: Cc: stable@vger.kernel.org #3.18 Link: http://lkml.kernel.org/r/1442843173-2390-1-git-send-email-ludovic.desroches@atmel.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-atmel-aic5.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index a2e8c3f876cbd2..c2c578f0b268a6 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -88,28 +88,36 @@ static void aic5_mask(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - /* Disable interrupt on AIC5 */ - irq_gc_lock(gc); + /* + * Disable interrupt on AIC5. We always take the lock of the + * first irq chip as all chips share the same registers. + */ + irq_gc_lock(bgc); irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); irq_reg_writel(gc, 1, AT91_AIC5_IDCR); gc->mask_cache &= ~d->mask; - irq_gc_unlock(gc); + irq_gc_unlock(bgc); } static void aic5_unmask(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); - /* Enable interrupt on AIC5 */ - irq_gc_lock(gc); + /* + * Enable interrupt on AIC5. We always take the lock of the + * first irq chip as all chips share the same registers. + */ + irq_gc_lock(bgc); irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); irq_reg_writel(gc, 1, AT91_AIC5_IECR); gc->mask_cache |= d->mask; - irq_gc_unlock(gc); + irq_gc_unlock(bgc); } static int aic5_retrigger(struct irq_data *d) From 8d20c8d1d47c4a4114e0ea4ebdfbcdb0b919f6a9 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 21 Sep 2015 15:46:05 +0200 Subject: [PATCH 187/381] irqchip/atmel-aic5: Use explicit variable name for the base chip To avoid errors, use an explicit variable name when accessing the 'base' generic chip. Signed-off-by: Ludovic Desroches Acked-by: Nicholas Ferre Acked-by: Boris Brezillon Cc: Cc: Cc: Cc: Cc: Cc: Link: http://lkml.kernel.org/r/1442843173-2390-2-git-send-email-ludovic.desroches@atmel.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-atmel-aic5.c | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index c2c578f0b268a6..5e053af31fd92a 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -71,15 +71,15 @@ static asmlinkage void __exception_irq_entry aic5_handle(struct pt_regs *regs) { struct irq_domain_chip_generic *dgc = aic5_domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; u32 irqnr; u32 irqstat; - irqnr = irq_reg_readl(gc, AT91_AIC5_IVR); - irqstat = irq_reg_readl(gc, AT91_AIC5_ISR); + irqnr = irq_reg_readl(bgc, AT91_AIC5_IVR); + irqstat = irq_reg_readl(bgc, AT91_AIC5_ISR); if (!irqstat) - irq_reg_writel(gc, 0, AT91_AIC5_EOICR); + irq_reg_writel(bgc, 0, AT91_AIC5_EOICR); else handle_domain_irq(aic5_domain, irqnr, regs); } @@ -124,13 +124,13 @@ static int aic5_retrigger(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; /* Enable interrupt on AIC5 */ - irq_gc_lock(gc); - irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); - irq_reg_writel(gc, 1, AT91_AIC5_ISCR); - irq_gc_unlock(gc); + irq_gc_lock(bgc); + irq_reg_writel(bgc, d->hwirq, AT91_AIC5_SSR); + irq_reg_writel(bgc, 1, AT91_AIC5_ISCR); + irq_gc_unlock(bgc); return 0; } @@ -139,17 +139,17 @@ static int aic5_set_type(struct irq_data *d, unsigned type) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *gc = dgc->gc[0]; + struct irq_chip_generic *bgc = dgc->gc[0]; unsigned int smr; int ret; - irq_gc_lock(gc); - irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR); - smr = irq_reg_readl(gc, AT91_AIC5_SMR); + irq_gc_lock(bgc); + irq_reg_writel(bgc, d->hwirq, AT91_AIC5_SSR); + smr = irq_reg_readl(bgc, AT91_AIC5_SMR); ret = aic_common_set_type(d, type, &smr); if (!ret) - irq_reg_writel(gc, smr, AT91_AIC5_SMR); - irq_gc_unlock(gc); + irq_reg_writel(bgc, smr, AT91_AIC5_SMR); + irq_gc_unlock(bgc); return ret; } @@ -263,7 +263,7 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, unsigned int *out_type) { struct irq_domain_chip_generic *dgc = d->gc; - struct irq_chip_generic *gc; + struct irq_chip_generic *bgc; unsigned smr; int ret; @@ -275,15 +275,15 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, if (ret) return ret; - gc = dgc->gc[0]; + bgc = dgc->gc[0]; - irq_gc_lock(gc); - irq_reg_writel(gc, *out_hwirq, AT91_AIC5_SSR); - smr = irq_reg_readl(gc, AT91_AIC5_SMR); + irq_gc_lock(bgc); + irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR); + smr = irq_reg_readl(bgc, AT91_AIC5_SMR); ret = aic_common_set_priority(intspec[2], &smr); if (!ret) - irq_reg_writel(gc, intspec[2] | smr, AT91_AIC5_SMR); - irq_gc_unlock(gc); + irq_reg_writel(bgc, intspec[2] | smr, AT91_AIC5_SMR); + irq_gc_unlock(bgc); return ret; } From fc4a7389da8abe4e505183c6dcf300b8eff62e96 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 21 Sep 2015 15:46:06 +0200 Subject: [PATCH 188/381] irqchip/atmel-aic5: Simplify base chip selection Use irq_get_domain_generic_chip() to select the base chip. Signed-off-by: Ludovic Desroches Acked-by: Nicholas Ferre Acked-by: Boris Brezillon Cc: Cc: Cc: Cc: Cc: Cc: Link: http://lkml.kernel.org/r/1442843173-2390-3-git-send-email-ludovic.desroches@atmel.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-atmel-aic5.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c index 5e053af31fd92a..219524cf59faf2 100644 --- a/drivers/irqchip/irq-atmel-aic5.c +++ b/drivers/irqchip/irq-atmel-aic5.c @@ -70,8 +70,7 @@ static struct irq_domain *aic5_domain; static asmlinkage void __exception_irq_entry aic5_handle(struct pt_regs *regs) { - struct irq_domain_chip_generic *dgc = aic5_domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(aic5_domain, 0); u32 irqnr; u32 irqstat; @@ -87,8 +86,7 @@ aic5_handle(struct pt_regs *regs) static void aic5_mask(struct irq_data *d) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); /* @@ -105,8 +103,7 @@ static void aic5_mask(struct irq_data *d) static void aic5_unmask(struct irq_data *d) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); /* @@ -123,8 +120,7 @@ static void aic5_unmask(struct irq_data *d) static int aic5_retrigger(struct irq_data *d) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); /* Enable interrupt on AIC5 */ irq_gc_lock(bgc); @@ -138,8 +134,7 @@ static int aic5_retrigger(struct irq_data *d) static int aic5_set_type(struct irq_data *d, unsigned type) { struct irq_domain *domain = d->domain; - struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); unsigned int smr; int ret; @@ -159,7 +154,7 @@ static void aic5_suspend(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; u32 mask; @@ -183,7 +178,7 @@ static void aic5_resume(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; u32 mask; @@ -207,7 +202,7 @@ static void aic5_pm_shutdown(struct irq_data *d) { struct irq_domain *domain = d->domain; struct irq_domain_chip_generic *dgc = domain->gc; - struct irq_chip_generic *bgc = dgc->gc[0]; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(domain, 0); struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); int i; @@ -262,12 +257,11 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, irq_hw_number_t *out_hwirq, unsigned int *out_type) { - struct irq_domain_chip_generic *dgc = d->gc; - struct irq_chip_generic *bgc; + struct irq_chip_generic *bgc = irq_get_domain_generic_chip(d, 0); unsigned smr; int ret; - if (!dgc) + if (!bgc) return -EINVAL; ret = aic_common_irq_domain_xlate(d, ctrlr, intspec, intsize, @@ -275,8 +269,6 @@ static int aic5_irq_domain_xlate(struct irq_domain *d, if (ret) return ret; - bgc = dgc->gc[0]; - irq_gc_lock(bgc); irq_reg_writel(bgc, *out_hwirq, AT91_AIC5_SSR); smr = irq_reg_readl(bgc, AT91_AIC5_SMR); From f33acbc1898c046298413039a518eba782365489 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 23 Sep 2015 14:41:55 +0200 Subject: [PATCH 189/381] pinctrl: at91: fix bad sync from mainline Kconfig sync with mainline was false. Signed-off-by: Ludovic Desroches --- drivers/pinctrl/Kconfig | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 87e7435fb008f6..067a3c6bb8b016 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -60,23 +60,25 @@ config PINCTRL_AT91 depends on OF depends on ARCH_AT91 select PINMUX + select PINCONF select GPIOLIB select OF_GPIO select GPIOLIB_IRQCHIP - select OF_GPIO help - Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4 - controller available on sama5d2 SoC. + Say Y here to enable the at91 pinctrl driver config PINCTRL_AT91PIO4 bool "AT91 PIO4 pinctrl driver" depends on OF depends on ARCH_AT91 select PINMUX - select PINCONF select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + select OF_GPIO help - Say Y here to enable the at91-pio4 pinctrl driver + Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4 + controller available on sama5d2 SoC. config PINCTRL_AMD bool "AMD GPIO pin control" From 903eca7d0a2764ff86b13a75d8baedac44d4cb12 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 24 Jul 2015 17:53:01 +0200 Subject: [PATCH 190/381] ARM: at91/dt: sama5d2: add audio pll clock nodes Three audio pll clock nodes. It will provide access to both the PMC route and the special audio clock pad on the SoC. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 21e82296b1f4fd..3730e5eea12c2f 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -355,6 +355,24 @@ clocks = <&plla>; }; + audio_pll_frac: audiopll_fracck { + compatible = "atmel,sama5d2-clk-audio-pll-frac"; + #clock-cells = <0>; + clocks = <&main>; + }; + + audio_pll_pad: audiopll_padck { + compatible = "atmel,sama5d2-clk-audio-pll-pad"; + #clock-cells = <0>; + clocks = <&audio_pll_frac>; + }; + + audio_pll_pmc: audiopll_pmcck { + compatible = "atmel,sama5d2-clk-audio-pll-pmc"; + #clock-cells = <0>; + clocks = <&audio_pll_frac>; + }; + utmi: utmick { compatible = "atmel,at91sam9x5-clk-utmi"; #clock-cells = <0>; From c6ac66645cef1edf1149b9a71630625afe5c1f25 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 24 Jul 2015 17:55:03 +0200 Subject: [PATCH 191/381] ARM: at91/dt: sama5d2: add the audio pll to the gck mux The Generated Clock has an additional entry for the audio pll. Add it to the device tree so that we can choose it when using one gck. No additional code is needed to use it. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 3730e5eea12c2f..34ad88b4ab659d 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -739,7 +739,7 @@ #address-cells = <1>; #size-cells = <0>; interrupt-parent = <&pmc>; - clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>; + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; sdmmc0_gclk: sdmmc0_gclk { #clock-cells = <0>; From 2f6958ad3e0401f838f8785376f1cc18ceeb3e91 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 20 Jul 2015 17:01:52 +0200 Subject: [PATCH 192/381] ARM: at91/dt: sama5d2: add nodes for I2S controllers Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 54 ++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 34ad88b4ab659d..63db4d95a5dab6 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -655,6 +655,18 @@ atmel,clk-output-range = <0 83000000>; }; + i2s0_clk: i2s0_clk { + #clock-cells = <0>; + reg = <54>; + atmel,clk-output-range = <0 83000000>; + }; + + i2s1_clk: i2s1_clk { + #clock-cells = <0>; + reg = <55>; + atmel,clk-output-range = <0 83000000>; + }; + classd_clk: classd_clk { #clock-cells = <0>; reg = <59>; @@ -768,6 +780,16 @@ reg = <38>; atmel,clk-output-range = <0 83000000>; }; + + i2s0_gclk: i2s0_gclk { + #clock-cells = <0>; + reg = <54>; + }; + + i2s1_gclk: i2s1_gclk { + #clock-cells = <0>; + reg = <55>; + }; }; }; @@ -987,6 +1009,22 @@ clocks = <&clk32k>; }; + i2s0: i2s@f8050000 { + compatible = "atmel,sama5d2-i2s"; + reg = <0xf8050000 0x300>; + interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(31))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(32))>; + dma-names = "tx", "rx"; + clocks = <&i2s0_clk>, <&i2s0_gclk>, <&audio_pll_pmc>; + clock-names = "pclk", "gclk", "aclk"; + status = "disabled"; + }; + spi1: spi@fc000000 { compatible = "atmel,at91rm9200-spi"; reg = <0xfc000000 0x100>; @@ -1108,6 +1146,22 @@ clock-names = "tdes_clk"; status = "okay"; }; + + i2s1: i2s@fc04c000 { + compatible = "atmel,sama5d2-i2s"; + reg = <0xfc04c000 0x300>; + interrupts = <55 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(33))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(34))>; + dma-names = "tx", "rx"; + clocks = <&i2s1_clk>, <&i2s1_gclk>, <&audio_pll_pmc>; + clock-names = "pclk", "gclk", "aclk"; + status = "disabled"; + }; }; }; }; From 5c959bb89413af804130a7eca13b455daa4eb5a3 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 20 Jul 2015 17:04:42 +0200 Subject: [PATCH 193/381] ARM: at91/dt: sama5d2 xplained: add pin muxing for I2S0 This patch sets the pin muxing for the I2S0 controller. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 3b72637cb440a4..d2bdb8e1f30148 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -179,6 +179,11 @@ }; }; + i2s0: i2s@f8050000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s0_default>; + }; + uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; @@ -243,6 +248,15 @@ bias-disable; }; + pinctrl_i2s0_default: i2s0_default { + pinmux = , + , + , + , + ; + bias-disable; + }; + pinctrl_macb0_rmii: macb0_rmii { pinmux = , , From 189e69f0da11deaef19bb5cda0edbac57445e185 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 24 Sep 2015 15:02:06 +0200 Subject: [PATCH 194/381] ARM: at91/dt: fix name of I2S controller data in and data out pins The I2S controller has only one data in pin and one data out pin: remove the useless trailing '0' in the macro names. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2-pinfunc.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm/boot/dts/sama5d2-pinfunc.h b/arch/arm/boot/dts/sama5d2-pinfunc.h index 1afe24629d1f85..ee16eecae494af 100644 --- a/arch/arm/boot/dts/sama5d2-pinfunc.h +++ b/arch/arm/boot/dts/sama5d2-pinfunc.h @@ -111,7 +111,7 @@ #define PIN_PA17__SPI0_NPCS0 PINMUX_PIN(PIN_PA17, 1, 1) #define PIN_PA17__RD1 PINMUX_PIN(PIN_PA17, 2, 1) #define PIN_PA17__QSPI0_IO1 PINMUX_PIN(PIN_PA17, 3, 2) -#define PIN_PA17__I2SC1_DI0 PINMUX_PIN(PIN_PA17, 4, 2) +#define PIN_PA17__I2SC1_DI PINMUX_PIN(PIN_PA17, 4, 2) #define PIN_PA17__FLEXCOM3_IO4 PINMUX_PIN(PIN_PA17, 5, 1) #define PIN_PA17__D12 PINMUX_PIN(PIN_PA17, 6, 2) #define PIN_PA18 18 @@ -119,7 +119,7 @@ #define PIN_PA18__SPI0_NPCS1 PINMUX_PIN(PIN_PA18, 1, 1) #define PIN_PA18__RK1 PINMUX_PIN(PIN_PA18, 2, 1) #define PIN_PA18__QSPI0_IO2 PINMUX_PIN(PIN_PA18, 3, 2) -#define PIN_PA18__I2SC1_DO0 PINMUX_PIN(PIN_PA18, 4, 2) +#define PIN_PA18__I2SC1_DO PINMUX_PIN(PIN_PA18, 4, 2) #define PIN_PA18__SDMMC1_DAT0 PINMUX_PIN(PIN_PA18, 5, 1) #define PIN_PA18__D13 PINMUX_PIN(PIN_PA18, 6, 2) #define PIN_PA19 19 @@ -335,7 +335,7 @@ #define PIN_PB17__LCDDAT6 PINMUX_PIN(PIN_PB17, 1, 1) #define PIN_PB17__A6 PINMUX_PIN(PIN_PB17, 2, 1) #define PIN_PB17__RD1 PINMUX_PIN(PIN_PB17, 3, 2) -#define PIN_PB17__I2SC1_DI0 PINMUX_PIN(PIN_PB17, 4, 1) +#define PIN_PB17__I2SC1_DI PINMUX_PIN(PIN_PB17, 4, 1) #define PIN_PB17__QSPI1_IO1 PINMUX_PIN(PIN_PB17, 5, 3) #define PIN_PB17__GRXER PINMUX_PIN(PIN_PB17, 6, 3) #define PIN_PB18 50 @@ -343,7 +343,7 @@ #define PIN_PB18__LCDDAT7 PINMUX_PIN(PIN_PB18, 1, 1) #define PIN_PB18__A7 PINMUX_PIN(PIN_PB18, 2, 1) #define PIN_PB18__RK1 PINMUX_PIN(PIN_PB18, 3, 2) -#define PIN_PB18__I2SC1_DO0 PINMUX_PIN(PIN_PB18, 4, 1) +#define PIN_PB18__I2SC1_DO PINMUX_PIN(PIN_PB18, 4, 1) #define PIN_PB18__QSPI1_IO2 PINMUX_PIN(PIN_PB18, 5, 3) #define PIN_PB18__GRX0 PINMUX_PIN(PIN_PB18, 6, 3) #define PIN_PB19 51 @@ -480,7 +480,7 @@ #define PIN_PC4__NWR1_NBS1 PINMUX_PIN(PIN_PC4, 2, 1) #define PIN_PC4__TIOB1 PINMUX_PIN(PIN_PC4, 3, 1) #define PIN_PC4__SPI1_NPCS0 PINMUX_PIN(PIN_PC4, 4, 1) -#define PIN_PC4__I2SC0_DI0 PINMUX_PIN(PIN_PC4, 5, 1) +#define PIN_PC4__I2SC0_DI PINMUX_PIN(PIN_PC4, 5, 1) #define PIN_PC4__ISC_PCK PINMUX_PIN(PIN_PC4, 6, 3) #define PIN_PC5 69 #define PIN_PC5__GPIO PINMUX_PIN(PIN_PC5, 0, 0) @@ -488,7 +488,7 @@ #define PIN_PC5__NCS0 PINMUX_PIN(PIN_PC5, 2, 1) #define PIN_PC5__TCLK1 PINMUX_PIN(PIN_PC5, 3, 1) #define PIN_PC5__SPI1_NPCS1 PINMUX_PIN(PIN_PC5, 4, 1) -#define PIN_PC5__I2SC0_DO0 PINMUX_PIN(PIN_PC5, 5, 1) +#define PIN_PC5__I2SC0_DO PINMUX_PIN(PIN_PC5, 5, 1) #define PIN_PC5__ISC_VSYNC PINMUX_PIN(PIN_PC5, 6, 3) #define PIN_PC6 70 #define PIN_PC6__GPIO PINMUX_PIN(PIN_PC6, 0, 0) @@ -827,13 +827,13 @@ #define PIN_PD22__TCLK2 PINMUX_PIN(PIN_PD22, 1, 3) #define PIN_PD22__TWCK0 PINMUX_PIN(PIN_PD22, 2, 4) #define PIN_PD22__FLEXCOM4_IO1 PINMUX_PIN(PIN_PD22, 3, 3) -#define PIN_PD22__I2SC0_DI0 PINMUX_PIN(PIN_PD22, 5, 2) +#define PIN_PD22__I2SC0_DI PINMUX_PIN(PIN_PD22, 5, 2) #define PIN_PD22__ISC_HSYNC PINMUX_PIN(PIN_PD22, 6, 4) #define PIN_PD23 119 #define PIN_PD23__GPIO PINMUX_PIN(PIN_PD23, 0, 0) #define PIN_PD23__URXD2 PINMUX_PIN(PIN_PD23, 1, 2) #define PIN_PD23__FLEXCOM4_IO2 PINMUX_PIN(PIN_PD23, 3, 3) -#define PIN_PD23__I2SC0_DO0 PINMUX_PIN(PIN_PD23, 5, 2) +#define PIN_PD23__I2SC0_DO PINMUX_PIN(PIN_PD23, 5, 2) #define PIN_PD23__ISC_FIELD PINMUX_PIN(PIN_PD23, 6, 4) #define PIN_PD24 120 #define PIN_PD24__GPIO PINMUX_PIN(PIN_PD24, 0, 0) From 568c19a711cd6be9bcb557325f5a1511d1cfb49b Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 20 Jul 2015 16:30:18 +0200 Subject: [PATCH 195/381] ASoC: atmel-i2s: add DT bindings for I2S controller This patch adds DT bindings for the new Atmel I2S controller embedded inside sama5d2x SoCs. Signed-off-by: Cyrille Pitchen --- .../devicetree/bindings/sound/atmel-i2s.txt | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/atmel-i2s.txt diff --git a/Documentation/devicetree/bindings/sound/atmel-i2s.txt b/Documentation/devicetree/bindings/sound/atmel-i2s.txt new file mode 100644 index 00000000000000..83bc6b9070bfaf --- /dev/null +++ b/Documentation/devicetree/bindings/sound/atmel-i2s.txt @@ -0,0 +1,43 @@ +* Atmel I2S controller + +Required properties: +- compatible: Should be "atmel,sama5d2-i2s". +- reg: Should be the physical base address of the controller and the + length of memory mapped region. +- interrupts: Should contain the interrupt for the controller. +- dmas: Should be a list of pairs of DMA controller phandle and flags. +- dma-names: Should be a list of DMA channel name among "rx", "tx" or + "rx-tx". +- clocks: Should be a list of phandles of clocks used by the controller + (1). +- clock-names: Should be a list matching the clocks phandles list: + - "pclk" (peripheral clock) Required. + - "gclk" (generated clock) Optional (1). + - "aclk" (Audio PLL clock) Optional (1). + +Optional properties: +- pinctrl-0: Should specify pin control groups used for this controller. +- princtrl-names: Should contain only one value - "default". + + +(1) : Only the peripheral clock is required. The generated clock and the Audio + PLL clock are optional and should only be set together. + +Example: + + i2s@f8050000 { + compatible = "atmel,sama5d2-i2s"; + reg = <0xf8050000 0x300>; + interrupts = <54 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(31))>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) | + AT91_XDMAC_DT_PERID(32))>; + dma-names = "tx", "rx"; + clocks = <&i2s0_clk>, <&i2s0_gclk>, <&audio_pll_pmc>; + clock-names = "pclk", "gclk", "aclk"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s0_default>; + }; From cb6b4116eedd1e214a7d1f850dbcd77cb93b99f0 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 28 Sep 2015 12:18:45 +0200 Subject: [PATCH 196/381] ARM: at91/dt: sama5d2: add required aliases for I2S controller nodes This patch adds the i2s0 and i2s1 aliases: the I2S controller driver calls of_alias_get_id() to retrieve the controller ID and eventually updates the SFR_I2SCLKSEL register to switch to the PMC generated clock. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 63db4d95a5dab6..56e0764c1c8d7f 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -58,6 +58,8 @@ serial1 = &uart3; tcb0 = &tcb0; tcb1 = &tcb1; + i2s0 = &i2s0; + i2s1 = &i2s1; }; cpus { From d95c1f4ed7a40cf788e5c30f56a6cb6327c2d2a8 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 28 Sep 2015 12:26:18 +0200 Subject: [PATCH 197/381] ARM: at91/dt: sama5d2: add SFR node This SFR node is looked up by the I2S controller driver to tune the SFR_I2SCLKSEL register. Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/sama5d2.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 56e0764c1c8d7f..5efb877c63961b 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -938,6 +938,11 @@ status = "disabled"; }; + sfr: sfr@f8030000 { + compatible = "atmel,sama5d2-sfr", "syscon"; + reg = <0xf8030000 0x98>; + }; + flx0: flexcom@f8034000 { compatible = "atmel,sama5d2-flexcom"; reg = <0xf8034000 0x200>; From a3674e33f0faa55289c69ecc48becb7085c20831 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 29 Sep 2015 14:35:59 +0200 Subject: [PATCH 198/381] ARM: at91/soc: add support to the Audio PLL on sama5d2 This patch selects the Audio PLL support on sama5d2 SoC. Signed-off-by: Cyrille Pitchen --- arch/arm/mach-at91/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index 89a755b90db224..82f5d6920fe2f7 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -17,6 +17,7 @@ config SOC_SAMA5D2 select HAVE_AT91_USB_CLK select HAVE_AT91_H32MX select HAVE_AT91_GENERATED_CLK + select HAVE_AT91_AUDIO_PLL help Select this if ou are using one of Atmel's SAMA5D2 family SoC. From 549e769495a017229fc45d55b9a0fa2117a04073 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 24 Jul 2015 17:49:04 +0200 Subject: [PATCH 199/381] clk: at91: add audio pll clock driver This new clock driver set allows to have a fractional divided clock that would generate a precise clock particularly suitable for audio applications. The main audio pll clock has two children clocks: one that is connected to the PMC, the other that can directly drive a pad. As these two routes have different enable bits and different dividers and divider formula, they are handled by two different drivers. Each of them would modify the rate of the main audio pll parent. Signed-off-by: Nicolas Ferre Signed-off-by: Cyrille Pitchen --- arch/arm/mach-at91/Kconfig | 3 + drivers/clk/at91/Makefile | 2 + drivers/clk/at91/clk-audio-pll-pad.c | 224 +++++++++++++++++++++++++ drivers/clk/at91/clk-audio-pll-pmc.c | 175 +++++++++++++++++++ drivers/clk/at91/clk-audio-pll.c | 240 +++++++++++++++++++++++++++ drivers/clk/at91/pmc.c | 14 ++ drivers/clk/at91/pmc.h | 8 + include/linux/clk/at91_pmc.h | 25 +++ 8 files changed, 691 insertions(+) create mode 100644 drivers/clk/at91/clk-audio-pll-pad.c create mode 100644 drivers/clk/at91/clk-audio-pll-pmc.c create mode 100644 drivers/clk/at91/clk-audio-pll.c diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig index e8273e79f6babe..4bed13a7d245fc 100644 --- a/arch/arm/mach-at91/Kconfig +++ b/arch/arm/mach-at91/Kconfig @@ -93,6 +93,9 @@ config HAVE_AT91_H32MX config HAVE_AT91_GENERATED_CLK bool +config HAVE_AT91_AUDIO_PLL + bool + config SOC_SAM_V4_V5 bool diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile index 13e67bd35cff3c..c9353d17763a87 100644 --- a/drivers/clk/at91/Makefile +++ b/drivers/clk/at91/Makefile @@ -6,6 +6,8 @@ obj-y += pmc.o sckc.o obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o obj-y += clk-system.o clk-peripheral.o clk-programmable.o +obj-$(CONFIG_HAVE_AT91_AUDIO_PLL) += clk-audio-pll.o +obj-$(CONFIG_HAVE_AT91_AUDIO_PLL) += clk-audio-pll-pmc.o clk-audio-pll-pad.o obj-$(CONFIG_HAVE_AT91_UTMI) += clk-utmi.o obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o diff --git a/drivers/clk/at91/clk-audio-pll-pad.c b/drivers/clk/at91/clk-audio-pll-pad.c new file mode 100644 index 00000000000000..74dbb95471e8cd --- /dev/null +++ b/drivers/clk/at91/clk-audio-pll-pad.c @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2015 Atmel Corporation, + * Nicolas Ferre + * + * 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. + * + */ +#define DEBUG 12 + +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define AUDIO_PLL_FOUT_MIN 600000000 +#define AUDIO_PLL_FOUT_MAX 800000000 +#define AUDIO_PLL_REFERENCE_FOUT 700000000 + +#define AUDIO_PLL_QDPAD_MAX ((AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK >> \ + AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET) * \ + AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX) +#define AUDIO_PLL_QDPAD_EXTDIV_OFFSET (AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET - \ + AT91_PMC_AUDIO_PLL_QDPAD_OFFSET) +#define AUDIO_PLL_DIV2QD(div, ext_div) ((div) | ((ext_div) << \ + AUDIO_PLL_QDPAD_EXTDIV_OFFSET)) +#define AUDIO_PLL_QD2DIV(qd) ((qd) & (AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK >> \ + AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET)) +#define AUDIO_PLL_QD2EXTDIV(qd) (((qd) >> AUDIO_PLL_QDPAD_EXTDIV_OFFSET) \ + & (AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK >> \ + AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET)) + +struct clk_audio_pad { + struct clk_hw hw; + struct at91_pmc *pmc; + u8 qdpad; +}; + +#define to_clk_audio_pad(hw) container_of(hw, struct clk_audio_pad, hw) + +static int clk_audio_pll_pad_enable(struct clk_hw *hw) +{ + struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw); + struct at91_pmc *pmc = apad_ck->pmc; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL1) & ~AT91_PMC_AUDIO_PLL_QDPAD_MASK; + tmp |= AT91_PMC_AUDIO_PLL_QDPAD(apad_ck->qdpad); + pmc_write(pmc, AT91_PMC_AUDIO_PLL1, tmp); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0); + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp | AT91_PMC_AUDIO_PLL_PADEN); + pmc_unlock(pmc); + return 0; +} + +static void clk_audio_pll_pad_disable(struct clk_hw *hw) +{ + struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw); + struct at91_pmc *pmc = apad_ck->pmc; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_PADEN; + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); + pmc_unlock(pmc); +} + +static unsigned long clk_audio_pll_pad_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw); + unsigned long apad_rate = 0; + u8 tmp_div = AUDIO_PLL_QD2DIV(apad_ck->qdpad); + u8 tmp_ext_div = AUDIO_PLL_QD2EXTDIV(apad_ck->qdpad); + + if (tmp_div && tmp_ext_div) + apad_rate = parent_rate / (tmp_div * tmp_ext_div); + + pr_debug("A PLL/PAD: %s, apad_rate = %lu (div = %u, ext_div = %u)\n" , + __func__ , apad_rate, tmp_div, tmp_ext_div); + + return apad_rate; +} + +static int clk_audio_pll_compute_qdpad(unsigned long q_rate, unsigned long rate, + unsigned long *qd, u8 *div, u8 *ext_div) +{ + unsigned long tmp_qd; + unsigned long rem2, rem3; + unsigned long ldiv, lext_div;; + + if (!rate) + return -EINVAL; + + tmp_qd = q_rate / rate; + if (!tmp_qd || tmp_qd > AUDIO_PLL_QDPAD_MAX) + return -EINVAL; + + if (tmp_qd <= AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX) { + ldiv = 1; + lext_div = tmp_qd; + } else { + rem2 = tmp_qd % 2; + rem3 = tmp_qd % 3; + + if (rem3 == 0 || + tmp_qd > AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX * 2 || + rem3 < rem2) { + ldiv = 3; + lext_div = tmp_qd / 3; + } else { + ldiv = 2; + lext_div = tmp_qd >> 1; + } + } + + pr_debug("A PLL/PAD: %s, qd = %lu (div = %lu, ext_div = %lu)\n" , + __func__ , ldiv * lext_div, ldiv, lext_div); + + /* if we were given variable to store, we can provide them */ + if (qd) + *qd = ldiv * lext_div; + if (div && ext_div) { + /* we can cast here as we verified the bounds just above */ + *div = (u8)ldiv; + *ext_div = (u8)lext_div; + } + + return 0; +} + +static long clk_audio_pll_pad_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk *pclk = __clk_get_parent(hw->clk); + long best_rate = -EINVAL; + unsigned long best_parent_rate = 0; + unsigned long tmp_qd; + + pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n" , + __func__ , rate, *parent_rate); + + if (clk_audio_pll_compute_qdpad(AUDIO_PLL_REFERENCE_FOUT, rate, + &tmp_qd, NULL, NULL)) + return -EINVAL; + + best_parent_rate = __clk_round_rate(pclk, rate * tmp_qd); + best_rate = best_parent_rate / tmp_qd; + + pr_debug("A PLL/PAD: %s, best_rate = %ld, best_parent_rate = %lu\n", + __func__, best_rate, best_parent_rate); + + *parent_rate = best_parent_rate; + return best_rate; +} + +static int clk_audio_pll_pad_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_audio_pad *apad_ck = to_clk_audio_pad(hw); + u8 tmp_div, tmp_ext_div; + int ret; + + pr_debug("A PLL/PAD: %s, rate = %lu (parent_rate = %lu)\n" , + __func__ , rate, parent_rate); + + ret = clk_audio_pll_compute_qdpad(parent_rate, rate, NULL, + &tmp_div, &tmp_ext_div); + if (!ret) + apad_ck->qdpad = AUDIO_PLL_DIV2QD(tmp_div, tmp_ext_div); + + return ret; +} + +static const struct clk_ops audio_pll_pad_ops = { + .enable = clk_audio_pll_pad_enable, + .disable = clk_audio_pll_pad_disable, + .recalc_rate = clk_audio_pll_pad_recalc_rate, + .round_rate = clk_audio_pll_pad_round_rate, + .set_rate = clk_audio_pll_pad_set_rate, +}; + +void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk_audio_pad *apad_ck; + struct clk *clk = NULL; + struct clk_init_data init; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + apad_ck = kzalloc(sizeof(*apad_ck), GFP_KERNEL); + if (!apad_ck) + return; + + init.name = name; + init.ops = &audio_pll_pad_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT; + + apad_ck->hw.init = &init; + apad_ck->pmc = pmc; + + clk = clk_register(NULL, &apad_ck->hw); + if (IS_ERR(clk)) + kfree(apad_ck); + else + of_clk_add_provider(np, of_clk_src_simple_get, clk); + + return; +} diff --git a/drivers/clk/at91/clk-audio-pll-pmc.c b/drivers/clk/at91/clk-audio-pll-pmc.c new file mode 100644 index 00000000000000..e7be19320116b6 --- /dev/null +++ b/drivers/clk/at91/clk-audio-pll-pmc.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2015 Atmel Corporation, + * Nicolas Ferre + * + * 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. + * + */ +#define DEBUG 12 + +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define AUDIO_PLL_FOUT_MIN 600000000 +#define AUDIO_PLL_FOUT_MAX 800000000 +#define AUDIO_PLL_REFERENCE_FOUT 700000000 +//#define AUDIO_PLL_REFERENCE_FOUT 670000000 +#define AUDIO_PLL_QDPMC_MAX (AT91_PMC_AUDIO_PLL_QDPMC_MASK >> \ + AT91_PMC_AUDIO_PLL_QDPMC_OFFSET) +struct clk_audio_pmc { + struct clk_hw hw; + struct at91_pmc *pmc; + u8 qdpmc; +}; + +#define to_clk_audio_pmc(hw) container_of(hw, struct clk_audio_pmc, hw) + +static int clk_audio_pll_pmc_enable(struct clk_hw *hw) +{ + struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw); + struct at91_pmc *pmc = apmc_ck->pmc; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_QDPMC_MASK; + tmp |= AT91_PMC_AUDIO_PLL_PMCEN | AT91_PMC_AUDIO_PLL_QDPMC(apmc_ck->qdpmc); + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); + pmc_unlock(pmc); + return 0; +} + +static void clk_audio_pll_pmc_disable(struct clk_hw *hw) +{ + struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw); + struct at91_pmc *pmc = apmc_ck->pmc; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_PMCEN; + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); + pmc_unlock(pmc); +} + +static unsigned long clk_audio_pll_pmc_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw); + unsigned long apmc_rate = 0; + + apmc_rate = parent_rate / (apmc_ck->qdpmc + 1); + + pr_debug("A PLL/PMC: %s, apmc_rate = %lu (qdpmc = %u)\n" , + __func__ , apmc_rate, apmc_ck->qdpmc); + + return apmc_rate; +} + +static int clk_audio_pll_compute_qdpmc(unsigned long q_rate, unsigned long rate, + unsigned long *qd) +{ + unsigned long tmp_qd; + + if (!rate) + return -EINVAL; + + tmp_qd = q_rate / rate; + if (!tmp_qd || tmp_qd > AUDIO_PLL_QDPMC_MAX) + return -EINVAL; + + *qd = tmp_qd; + return 0; +} + +static long clk_audio_pll_pmc_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + struct clk *pclk = __clk_get_parent(hw->clk); + long best_rate = -EINVAL; + unsigned long best_parent_rate = 0; + unsigned long tmp_qd; + + pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n" , + __func__ , rate, *parent_rate); + + if (clk_audio_pll_compute_qdpmc(AUDIO_PLL_REFERENCE_FOUT, rate, &tmp_qd)) + return -EINVAL; + + best_parent_rate = __clk_round_rate(pclk, rate * tmp_qd); + best_rate = best_parent_rate / tmp_qd; + + pr_debug("A PLL/PMC: %s, best_rate = %ld, best_parent_rate = %lu (qd = %lu)\n", + __func__, best_rate, best_parent_rate, tmp_qd - 1); + + *parent_rate = best_parent_rate; + return best_rate; +} + +static int clk_audio_pll_pmc_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_audio_pmc *apmc_ck = to_clk_audio_pmc(hw); + unsigned long tmp_qd; + int ret; + + pr_debug("A PLL/PMC: %s, rate = %lu (parent_rate = %lu)\n" , + __func__ , rate, parent_rate); + + ret = clk_audio_pll_compute_qdpmc(parent_rate, rate, &tmp_qd); + if (!ret) + apmc_ck->qdpmc = tmp_qd - 1; + + return ret; +} + +static const struct clk_ops audio_pll_pmc_ops = { + .enable = clk_audio_pll_pmc_enable, + .disable = clk_audio_pll_pmc_disable, + .recalc_rate = clk_audio_pll_pmc_recalc_rate, + .round_rate = clk_audio_pll_pmc_round_rate, + .set_rate = clk_audio_pll_pmc_set_rate, +}; + +void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk_audio_pmc *apmc_ck; + struct clk *clk = NULL; + struct clk_init_data init; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + apmc_ck = kzalloc(sizeof(*apmc_ck), GFP_KERNEL); + if (!apmc_ck) + return; + + init.name = name; + init.ops = &audio_pll_pmc_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE | + CLK_SET_PARENT_GATE | CLK_SET_RATE_PARENT; + + apmc_ck->hw.init = &init; + apmc_ck->pmc = pmc; + + clk = clk_register(NULL, &apmc_ck->hw); + if (IS_ERR(clk)) + kfree(apmc_ck); + else + of_clk_add_provider(np, of_clk_src_simple_get, clk); + + return; +} diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c new file mode 100644 index 00000000000000..309f2845f85676 --- /dev/null +++ b/drivers/clk/at91/clk-audio-pll.c @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2015 Atmel Corporation, + * Songjun Wu , + * Nicolas Ferre + * + * 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. + * + */ +#define DEBUG 12 + +#include +#include +#include +#include +#include +#include + +#include "pmc.h" + +#define AUDIO_PLL_DIV_FRAC (1 << 22) +#define AUDIO_PLL_ND_MAX (AT91_PMC_AUDIO_PLL_ND_MASK >> \ + AT91_PMC_AUDIO_PLL_ND_OFFSET) + +struct clk_audio_frac { + struct clk_hw hw; + struct at91_pmc *pmc; + u32 fracr; + u8 nd; +}; + +#define to_clk_audio_frac(hw) container_of(hw, struct clk_audio_frac, hw) + +/* make sure that pll is in reset state beforehand */ +static int clk_audio_pll_prepare(struct clk_hw *hw) +{ + struct clk_audio_frac *fck = to_clk_audio_frac(hw); + struct at91_pmc *pmc = fck->pmc; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_RESETN; + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); + pmc_unlock(pmc); + return 0; +} + +static void clk_audio_pll_unprepare(struct clk_hw *hw) +{ + clk_audio_pll_prepare(hw); +} + +static int clk_audio_pll_enable(struct clk_hw *hw) +{ + struct clk_audio_frac *fck = to_clk_audio_frac(hw); + struct at91_pmc *pmc = fck->pmc; + u32 tmp, tmp2; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0); + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp | AT91_PMC_AUDIO_PLL_RESETN); + tmp2 = pmc_read(pmc, AT91_PMC_AUDIO_PLL1) & ~AT91_PMC_AUDIO_PLL_FRACR_MASK; + pmc_write(pmc, AT91_PMC_AUDIO_PLL1, tmp2 | fck->fracr); + + /* + * reset and enabled have to be done in 2 separated writes + * for AT91_PMC_AUDIO_PLL0 + */ + tmp &= ~AT91_PMC_AUDIO_PLL_ND_MASK; + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp | AT91_PMC_AUDIO_PLL_RESETN + | AT91_PMC_AUDIO_PLL_PLLEN + | AT91_PMC_AUDIO_PLL_ND(fck->nd)); + pmc_unlock(pmc); + return 0; +} + +static void clk_audio_pll_disable(struct clk_hw *hw) +{ + struct clk_audio_frac *fck = to_clk_audio_frac(hw); + struct at91_pmc *pmc = fck->pmc; + u32 tmp; + + pmc_lock(pmc); + tmp = pmc_read(pmc, AT91_PMC_AUDIO_PLL0) & ~AT91_PMC_AUDIO_PLL_PLLEN; + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp); + /* do it in 2 separated writes */ + pmc_write(pmc, AT91_PMC_AUDIO_PLL0, tmp & ~AT91_PMC_AUDIO_PLL_RESETN); + pmc_unlock(pmc); +} + +static unsigned long clk_audio_pll_fout(unsigned long parent_rate, + unsigned long nd, unsigned long fracr) +{ + unsigned long long fr = (unsigned long long)parent_rate * + (unsigned long long)fracr; + + pr_debug("A PLL: %s, fr = %llu\n" , + __func__ , fr); + + fr = DIV_ROUND_CLOSEST_ULL(fr, AUDIO_PLL_DIV_FRAC); + + pr_debug("A PLL: %s, fr = %llu\n" , + __func__ , fr); + + return parent_rate * (nd + 1) + fr; +} + + + +static unsigned long clk_audio_pll_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_audio_frac *fck = to_clk_audio_frac(hw); + unsigned long fout; + + fout = clk_audio_pll_fout(parent_rate, fck->nd, fck->fracr); + + pr_debug("A PLL: %s, fout = %lu (nd = %u, fracr = %lu)\n" , + __func__ , fout, fck->nd, (unsigned long)fck->fracr); + + return fout; +} + +static int clk_audio_pll_compute_frac(unsigned long rate, unsigned long parent_rate, + unsigned long *nd, unsigned long *fracr) +{ + unsigned long long tmp; + unsigned long long r; + + if (!rate) + return -EINVAL; + + tmp = rate; + r = do_div(tmp, parent_rate); + if (tmp == 0 || (tmp - 1) > AUDIO_PLL_ND_MAX) + return -EINVAL; + + *nd = tmp - 1; + + tmp = r * AUDIO_PLL_DIV_FRAC; + tmp = DIV_ROUND_CLOSEST_ULL(tmp, parent_rate); + if (tmp > AT91_PMC_AUDIO_PLL_FRACR_MASK) + return -EINVAL; + + /* we can cast here as we verified the bounds just above */ + *fracr = (unsigned long)tmp; + + return 0; +} + +static long clk_audio_pll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + long best_rate = -EINVAL; + unsigned long fracr; + unsigned long nd; + int ret; + + pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n" , + __func__ , rate, *parent_rate); + + ret = clk_audio_pll_compute_frac(rate, *parent_rate, &nd, &fracr); + if (ret) + return ret; + + best_rate = clk_audio_pll_fout(*parent_rate, nd, fracr); + + pr_debug("A PLL: %s, best_rate = %lu (nd = %lu, fracr = %lu)\n" , + __func__ , best_rate, nd, fracr); + + return best_rate; +} + +static int clk_audio_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct clk_audio_frac *fck = to_clk_audio_frac(hw); + unsigned long fracr; + unsigned long nd; + int ret; + + pr_debug("A PLL: %s, rate = %lu (parent_rate = %lu)\n" , + __func__ , rate, parent_rate); + + ret = clk_audio_pll_compute_frac(rate, parent_rate, &nd, &fracr); + if (ret) + return ret; + + fck->nd = nd; + fck->fracr = fracr; + + return 0; +} + +static const struct clk_ops audio_pll_ops = { + .prepare = clk_audio_pll_prepare, + .unprepare = clk_audio_pll_unprepare, + .enable = clk_audio_pll_enable, + .disable = clk_audio_pll_disable, + .recalc_rate = clk_audio_pll_recalc_rate, + .round_rate = clk_audio_pll_round_rate, + .set_rate = clk_audio_pll_set_rate, +}; + +void __init of_sama5d2_clk_audio_pll_setup(struct device_node *np, + struct at91_pmc *pmc) +{ + struct clk_audio_frac *fck; + struct clk *clk = NULL; + struct clk_init_data init; + const char *parent_name; + const char *name = np->name; + + parent_name = of_clk_get_parent_name(np, 0); + + of_property_read_string(np, "clock-output-names", &name); + + fck = kzalloc(sizeof(*fck), GFP_KERNEL); + if (!fck) + return; + + init.name = name; + init.ops = &audio_pll_ops; + init.parent_names = (parent_name ? &parent_name : NULL); + init.num_parents = 1; + init.flags = CLK_SET_RATE_GATE; + + fck->hw.init = &init; + fck->pmc = pmc; + + clk = clk_register(NULL, &fck->hw); + if (IS_ERR(clk)) + kfree(fck); + else + of_clk_add_provider(np, of_clk_src_simple_get, clk); + + return; +} diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c index af468e154ee529..ac905e6129dd00 100644 --- a/drivers/clk/at91/pmc.c +++ b/drivers/clk/at91/pmc.c @@ -307,6 +307,20 @@ static const struct of_device_id pmc_clk_ids[] __initconst = { .compatible = "atmel,at91sam9x5-clk-plldiv", .data = of_at91sam9x5_clk_plldiv_setup, }, +#if defined(CONFIG_HAVE_AT91_AUDIO_PLL) + { + .compatible = "atmel,sama5d2-clk-audio-pll-frac", + .data = of_sama5d2_clk_audio_pll_setup, + }, + { + .compatible = "atmel,sama5d2-clk-audio-pll-pad", + .data = of_sama5d2_clk_audio_pll_pad_setup, + }, + { + .compatible = "atmel,sama5d2-clk-audio-pll-pmc", + .data = of_sama5d2_clk_audio_pll_pmc_setup, + }, +#endif /* Master clock */ { .compatible = "atmel,at91rm9200-clk-master", diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h index f6a17f94a44dc6..0188792ecbbc4b 100644 --- a/drivers/clk/at91/pmc.h +++ b/drivers/clk/at91/pmc.h @@ -81,6 +81,14 @@ extern void __init of_sama5d3_clk_pll_setup(struct device_node *np, struct at91_pmc *pmc); extern void __init of_at91sam9x5_clk_plldiv_setup(struct device_node *np, struct at91_pmc *pmc); +#if defined(CONFIG_HAVE_AT91_AUDIO_PLL) +extern void __init of_sama5d2_clk_audio_pll_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_sama5d2_clk_audio_pll_pmc_setup(struct device_node *np, + struct at91_pmc *pmc); +extern void __init of_sama5d2_clk_audio_pll_pad_setup(struct device_node *np, + struct at91_pmc *pmc); +#endif extern void __init of_at91rm9200_clk_master_setup(struct device_node *np, struct at91_pmc *pmc); diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h index 1e6932222e110d..975ecd97163267 100644 --- a/include/linux/clk/at91_pmc.h +++ b/include/linux/clk/at91_pmc.h @@ -197,4 +197,29 @@ extern void __iomem *at91_pmc_base; #define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ #define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ +#define AT91_PMC_AUDIO_PLL0 0x14c +#define AT91_PMC_AUDIO_PLL_PLLEN (1 << 0) +#define AT91_PMC_AUDIO_PLL_PADEN (1 << 1) +#define AT91_PMC_AUDIO_PLL_PMCEN (1 << 2) +#define AT91_PMC_AUDIO_PLL_RESETN (1 << 3) +#define AT91_PMC_AUDIO_PLL_ND_OFFSET 8 +#define AT91_PMC_AUDIO_PLL_ND_MASK (0x7f << AT91_PMC_AUDIO_PLL_ND_OFFSET) +#define AT91_PMC_AUDIO_PLL_ND(n) ((n) << AT91_PMC_AUDIO_PLL_ND_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPMC_OFFSET 16 +#define AT91_PMC_AUDIO_PLL_QDPMC_MASK (0x7f << AT91_PMC_AUDIO_PLL_QDPMC_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPMC(n) ((n) << AT91_PMC_AUDIO_PLL_QDPMC_OFFSET) + +#define AT91_PMC_AUDIO_PLL1 0x150 +#define AT91_PMC_AUDIO_PLL_FRACR_MASK 0x3fffff +#define AT91_PMC_AUDIO_PLL_QDPAD_OFFSET 24 +#define AT91_PMC_AUDIO_PLL_QDPAD_MASK (0x7f << AT91_PMC_AUDIO_PLL_QDPAD_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET AT91_PMC_AUDIO_PLL_QDPAD_OFFSET +#define AT91_PMC_AUDIO_PLL_QDPAD_DIV_MASK (0x3 << AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_DIV(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_DIV_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET 26 +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX 0x1f +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MASK (AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_MAX << AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET) +#define AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV(n) ((n) << AT91_PMC_AUDIO_PLL_QDPAD_EXTDIV_OFFSET) + #endif From 196923eac7db3756cff603f65f70983b4957edcf Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 10 Nov 2014 14:50:05 +0100 Subject: [PATCH 200/381] ASoC: atmel-i2s: add driver for the new Atmel I2S controller This patch adds support for the Atmel I2S controller embedded into sama5d2x SoCs. Signed-off-by: Cyrille Pitchen --- sound/soc/atmel/Kconfig | 10 + sound/soc/atmel/Makefile | 2 + sound/soc/atmel/atmel-i2s.c | 760 ++++++++++++++++++++++++++++++++++++ 3 files changed, 772 insertions(+) create mode 100644 sound/soc/atmel/atmel-i2s.c diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e7d08806f3e92d..e63e0cabce20ea 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -55,3 +55,13 @@ config SND_AT91_SOC_SAM9X5_WM8731 help Say Y if you want to add support for audio SoC on an at91sam9x5 based board that is using WM8731 codec. + +config SND_ATMEL_SOC_I2S + tristate "SoC Audio support for the Atmel I2S module" + select SND_SOC_GENERIC_DMAENGINE_PCM + select REGMAP_MMIO + depends on OF && (ARCH_AT91 || COMPILE_TEST) + help + Say Y or M if you want to add support for codecs attached to + the Atmel I2S interface. You will also need + to select the audio interfaces to support below. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index b327e5cc8de352..4d960464aecba3 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -2,10 +2,12 @@ snd-soc-atmel-pcm-pdc-objs := atmel-pcm-pdc.o snd-soc-atmel-pcm-dma-objs := atmel-pcm-dma.o snd-soc-atmel_ssc_dai-objs := atmel_ssc_dai.o +snd-soc-atmel-i2s-objs := atmel-i2s.o obj-$(CONFIG_SND_ATMEL_SOC_PDC) += snd-soc-atmel-pcm-pdc.o obj-$(CONFIG_SND_ATMEL_SOC_DMA) += snd-soc-atmel-pcm-dma.o obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o +obj-$(CONFIG_SND_ATMEL_SOC_I2S) += snd-soc-atmel-i2s.o # AT91 Machine Support snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o diff --git a/sound/soc/atmel/atmel-i2s.c b/sound/soc/atmel/atmel-i2s.c new file mode 100644 index 00000000000000..9e15acabbaab72 --- /dev/null +++ b/sound/soc/atmel/atmel-i2s.c @@ -0,0 +1,760 @@ +/* + * Driver for Atmel I2S controller + * + * Copyright (C) 2015 Atmel Corporation + * + * Author: Cyrille Pitchen + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * 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, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define ATMEL_I2SC_MAX_TDM_CHANNELS 8 + +/* + * ---- I2S Controller Register map ---- + */ +#define ATMEL_I2SC_CR 0x0000 /* Control Register */ +#define ATMEL_I2SC_MR 0x0004 /* Mode Register */ +#define ATMEL_I2SC_SR 0x0008 /* Status Register */ +#define ATMEL_I2SC_SCR 0x000c /* Status Clear Register */ +#define ATMEL_I2SC_SSR 0x0010 /* Status Set Register */ +#define ATMEL_I2SC_IER 0x0014 /* Interrupt Enable Register */ +#define ATMEL_I2SC_IDR 0x0018 /* Interrupt Disable Register */ +#define ATMEL_I2SC_IMR 0x001c /* Interrupt Mask Register */ +#define ATMEL_I2SC_RHR 0x0020 /* Receiver Holding Register */ +#define ATMEL_I2SC_THR 0x0024 /* Transmitter Holding Register */ +#define ATMEL_I2SC_VERSION 0x0028 /* Version Register */ + + +/* + * ---- Control Register (Write-only) ---- + */ +#define ATMEL_I2SC_CR_RXEN BIT(0) /* Receiver Enable */ +#define ATMEL_I2SC_CR_RXDIS BIT(1) /* Receiver Disable */ +#define ATMEL_I2SC_CR_CKEN BIT(2) /* Clock Enable */ +#define ATMEL_I2SC_CR_CKDIS BIT(3) /* Clock Disable */ +#define ATMEL_I2SC_CR_TXEN BIT(4) /* Transmitter Enable */ +#define ATMEL_I2SC_CR_TXDIS BIT(5) /* Transmitter Disable */ +#define ATMEL_I2SC_CR_SWRST BIT(7) /* Software Reset */ + + +/* + * ---- Mode Register (Read/Write) ---- + */ +#define ATMEL_I2SC_MR_MODE_MASK GENMASK(0, 0) +#define ATMEL_I2SC_MR_MODE_SLAVE (0 << 0) +#define ATMEL_I2SC_MR_MODE_MASTER (1 << 0) + +#define ATMEL_I2SC_MR_DATALENGTH_MASK GENMASK(4, 2) +#define ATMEL_I2SC_MR_DATALENGTH_32_BITS (0 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_24_BITS (1 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_20_BITS (2 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_18_BITS (3 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_16_BITS (4 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_16_BITS_COMPACT (5 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_8_BITS (6 << 2) +#define ATMEL_I2SC_MR_DATALENGTH_8_BITS_COMPACT (7 << 2) + +#define ATMEL_I2SC_MR_FORMAT_MASK GENMASK(7, 6) +#define ATMEL_I2SC_MR_FORMAT_I2S (0 << 6) +#define ATMEL_I2SC_MR_FORMAT_LJ (1 << 6) /* Left Justified */ +#define ATMEL_I2SC_MR_FORMAT_TDM (2 << 6) +#define ATMEL_I2SC_MR_FORMAT_TDMLJ (3 << 6) + +/* Left audio samples duplicated to right audio channel */ +#define ATMEL_I2SC_MR_RXMONO BIT(8) + +/* Receiver uses one DMA channel ... */ +#define ATMEL_I2SC_MR_RXDMA_MASK GENMASK(9, 9) +#define ATMEL_I2SC_MR_RXDMA_SINGLE (0 << 9) /* for all audio channels */ +#define ATMEL_I2SC_MR_RXDMA_MULTIPLE (1 << 9) /* per audio channel */ + +/* I2SDO output of I2SC is internally connected to I2SDI input */ +#define ATMEL_I2SC_MR_RXLOOP BIT(10) + +/* Left audio samples duplicated to right audio channel */ +#define ATMEL_I2SC_MR_TXMONO BIT(12) + +/* Transmitter uses one DMA channel ... */ +#define ATMEL_I2SC_MR_TXDMA_MASK GENMASK(13, 13) +#define ATMEL_I2SC_MR_TXDMA_SINGLE (0 << 13) /* for all audio channels */ +#define ATMEL_I2SC_MR_TXDME_MULTIPLE (1 << 13) /* per audio channel */ + +/* x sample transmitted when underrun */ +#define ATMEL_I2SC_MR_TXSAME_MASK GENMASK(14, 14) +#define ATMEL_I2SC_MR_TXSAME_ZERO (0 << 14) /* Zero sample */ +#define ATMEL_I2SC_MR_TXSAME_PREVIOUS (1 << 14) /* Previous sample */ + +/* Audio Clock to I2SC Master Clock ratio */ +#define ATMEL_I2SC_MR_IMCKDIV_MASK GENMASK(21, 16) +#define ATMEL_I2SC_MR_IMCKDIV(div) \ + (((div) << 16) & ATMEL_I2SC_MR_IMCKDIV_MASK) + +/* Master Clock to fs ratio */ +#define ATMEL_I2SC_MR_IMCKFS_MASK GENMASK(29, 24) +#define ATMEL_I2SC_MR_IMCKFS(fs) \ + (((fs) << 24) & ATMEL_I2SC_MR_IMCKFS_MASK) + +/* Master Clock mode */ +#define ATMEL_I2SC_MR_IMCKMODE_MASK GENMASK(30, 30) +/* 0: No master clock generated (selected clock drives I2SCK pin) */ +#define ATMEL_I2SC_MR_IMCKMODE_I2SCK (0 << 30) +/* 1: master clock generated (internally generated clock drives I2SMCK pin) */ +#define ATMEL_I2SC_MR_IMCKMODE_I2SMCK (1 << 30) + +/* Slot Width */ +/* 0: slot is 32 bits wide for DATALENGTH = 18/20/24 bits. */ +/* 1: slot is 24 bits wide for DATALENGTH = 18/20/24 bits. */ +#define ATMEL_I2SC_MR_IWS BIT(31) + +/* + * ---- Status Registers ---- + */ +#define ATMEL_I2SC_SR_RXEN BIT(0) /* Receiver Enabled */ +#define ATMEL_I2SC_SR_RXRDY BIT(1) /* Receive Ready */ +#define ATMEL_I2SC_SR_RXOR BIT(2) /* Receive Overrun */ + +#define ATMEL_I2SC_SR_TXEN BIT(4) /* Transmitter Enabled */ +#define ATMEL_I2SC_SR_TXRDY BIT(5) /* Transmit Ready */ +#define ATMEL_I2SC_SR_TXUR BIT(6) /* Transmit Underrun */ + +/* Receive Overrun Channel */ +#define ATMEL_I2SC_SR_RXORCH_MASK GENMASK(15, 8) +#define ATMEL_I2SC_SR_RXORCH(ch) (1 << (((ch) & 0x7) + 8)) + +/* Transmit Underrun Channel */ +#define ATMEL_I2SC_SR_TXURCH_MASK GENMASK(27, 20) +#define ATMEL_I2SC_SR_TXURCH(ch) (1 << (((ch) & 0x7) + 20)) + + +/* + * ---- Interrupt Enable/Disable/Mask Registers ---- + */ +#define ATMEL_I2SC_INT_RXRDY ATMEL_I2SC_SR_RXRDY +#define ATMEL_I2SC_INT_RXOR ATMEL_I2SC_SR_RXOR +#define ATMEL_I2SC_INT_TXRDY ATMEL_I2SC_SR_TXRDY +#define ATMEL_I2SC_INT_TXUR ATMEL_I2SC_SR_TXUR + + +static const struct regmap_config atmel_i2s_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ATMEL_I2SC_VERSION, +}; + +struct atmel_i2s_gck_param { + int fs; + unsigned long mck; + int imckdiv; + int imckfs; +}; + +#define I2S_MCK_12M288 12288000UL +#define I2S_MCK_11M2896 11289600UL + +/* mck = (32 * (imckfs+1) / (imckdiv+1)) * fs */ +static const struct atmel_i2s_gck_param gck_params[] = { + /* mck = 12.288MHz */ + { 8000, I2S_MCK_12M288, 0, 47}, /* mck = 1536 fs */ + { 16000, I2S_MCK_12M288, 1, 47}, /* mck = 768 fs */ + { 24000, I2S_MCK_12M288, 3, 63}, /* mck = 512 fs */ + { 32000, I2S_MCK_12M288, 3, 47}, /* mck = 384 fs */ + { 48000, I2S_MCK_12M288, 7, 63}, /* mck = 256 fs */ + { 64000, I2S_MCK_12M288, 7, 47}, /* mck = 192 fs */ + { 96000, I2S_MCK_12M288, 7, 31}, /* mck = 128 fs */ + {192000, I2S_MCK_12M288, 7, 15}, /* mck = 64 fs */ + + /* mck = 11.2896MHz */ + { 11025, I2S_MCK_11M2896, 1, 63}, /* mck = 1024 fs */ + { 22050, I2S_MCK_11M2896, 3, 63}, /* mck = 512 fs */ + { 44100, I2S_MCK_11M2896, 7, 63}, /* mck = 256 fs */ + { 88200, I2S_MCK_11M2896, 7, 31}, /* mck = 128 fs */ + {176400, I2S_MCK_11M2896, 7, 15}, /* mck = 64 fs */ +}; + +struct atmel_i2s_dev; + +struct atmel_i2s_caps { + int (*mck_init)(struct atmel_i2s_dev *, struct device_node *np); +}; + +struct atmel_i2s_dev { + struct device *dev; + struct regmap *regmap; + struct clk *pclk; + struct clk *gclk; + struct clk *aclk; + struct snd_dmaengine_dai_dma_data playback; + struct snd_dmaengine_dai_dma_data capture; + unsigned int fmt; + const struct atmel_i2s_gck_param *gck_param; + const struct atmel_i2s_caps *caps; +}; + + +static irqreturn_t atmel_i2s_interrupt(int irq, void *dev_id) +{ + struct atmel_i2s_dev *dev = dev_id; + unsigned int sr, imr, pending, ch, mask; + + regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr); + regmap_read(dev->regmap, ATMEL_I2SC_IMR, &imr); + pending = sr & imr; + + if (!pending) + return IRQ_NONE; + + if (pending & ATMEL_I2SC_INT_RXOR) { + mask = ATMEL_I2SC_SR_RXOR; + + for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) + if (sr & ATMEL_I2SC_SR_RXORCH(ch)) { + mask |= ATMEL_I2SC_SR_RXORCH(ch); + dev_err(dev->dev, + "RX overrun on channel %d\n", ch); + } + regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask); + } + + if (pending & ATMEL_I2SC_INT_TXUR) { + mask = ATMEL_I2SC_SR_TXUR; + + for (ch = 0; ch < ATMEL_I2SC_MAX_TDM_CHANNELS; ++ch) + if (sr & ATMEL_I2SC_SR_TXURCH(ch)) { + mask |= ATMEL_I2SC_SR_TXURCH(ch); + dev_err(dev->dev, + "TX underrun on channel %d\n", ch); + } + regmap_write(dev->regmap, ATMEL_I2SC_SCR, mask); + + } + + return IRQ_HANDLED; +} + +#define ATMEL_I2S_RATES SNDRV_PCM_RATE_8000_192000 + +#define ATMEL_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S18_3LE | \ + SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + + +static int atmel_i2s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + dev->fmt = fmt; + return 0; +} + +static int atmel_i2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + unsigned int rhr, sr = 0; + + if (is_playback) { + regmap_read(dev->regmap, ATMEL_I2SC_SR, &sr); + if (sr & ATMEL_I2SC_SR_RXRDY) { + dev_dbg(dev->dev, "RXRDY is set\n"); + regmap_read(dev->regmap, ATMEL_I2SC_RHR, &rhr); + } + } + + return 0; +} + +static int atmel_i2s_get_gck_param(struct atmel_i2s_dev *dev, int fs) +{ + int i, best; + + if (!dev->gclk || !dev->aclk) { + dev_err(dev->dev, "cannot generate the I2S Master Clock\n"); + return -EINVAL; + } + + /* + * Find the best possible settings to generate the I2S Master Clock + * from the PLL Audio. + */ + dev->gck_param = NULL; + best = INT_MAX; + for (i = 0; i < ARRAY_SIZE(gck_params); ++i) { + const struct atmel_i2s_gck_param *gck_param = &gck_params[i]; + int val = abs(fs - gck_param->fs); + + if (val < best) { + best = val; + dev->gck_param = gck_param; + } + } + + return 0; +} + +static int atmel_i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + unsigned int mr = 0; + int ret; + + switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + mr |= ATMEL_I2SC_MR_FORMAT_I2S; + break; + + default: + dev_err(dev->dev, "unsupported bus format\n"); + return -EINVAL; + } + + switch (dev->fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + /* codec is slave, so cpu is master */ + mr |= ATMEL_I2SC_MR_MODE_MASTER; + ret = atmel_i2s_get_gck_param(dev, params_rate(params)); + if (ret) + return ret; + break; + + case SND_SOC_DAIFMT_CBM_CFM: + /* codec is master, so cpu is slave */ + mr |= ATMEL_I2SC_MR_MODE_SLAVE; + dev->gck_param = NULL; + break; + + default: + dev_err(dev->dev, "unsupported master/slave mode\n"); + return -EINVAL; + } + + switch (params_channels(params)) { + case 1: + mr |= is_playback ? ATMEL_I2SC_MR_TXMONO : ATMEL_I2SC_MR_RXMONO; + break; + case 2: + break; + default: + dev_err(dev->dev, "unsupported number of audio channels\n"); + break; + } + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S8: + mr |= ATMEL_I2SC_MR_DATALENGTH_8_BITS; + break; + + case SNDRV_PCM_FORMAT_S16_LE: + mr |= ATMEL_I2SC_MR_DATALENGTH_16_BITS; + break; + + case SNDRV_PCM_FORMAT_S18_3LE: + mr |= ATMEL_I2SC_MR_DATALENGTH_18_BITS | ATMEL_I2SC_MR_IWS; + break; + + case SNDRV_PCM_FORMAT_S20_3LE: + mr |= ATMEL_I2SC_MR_DATALENGTH_20_BITS | ATMEL_I2SC_MR_IWS; + break; + + case SNDRV_PCM_FORMAT_S24_3LE: + mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS | ATMEL_I2SC_MR_IWS; + break; + + case SNDRV_PCM_FORMAT_S24_LE: + mr |= ATMEL_I2SC_MR_DATALENGTH_24_BITS; + break; + + case SNDRV_PCM_FORMAT_S32_LE: + mr |= ATMEL_I2SC_MR_DATALENGTH_32_BITS; + break; + + default: + dev_err(dev->dev, "unsupported size/endianness for audio samples\n"); + return -EINVAL; + } + + return regmap_write(dev->regmap, ATMEL_I2SC_MR, mr); +} + +static int atmel_i2s_switch_mck_generator(struct atmel_i2s_dev *dev, + bool enabled) +{ + unsigned int mr, mr_mask; + unsigned long aclk_rate; + int ret; + + mr = 0; + mr_mask = (ATMEL_I2SC_MR_IMCKDIV_MASK | + ATMEL_I2SC_MR_IMCKFS_MASK | + ATMEL_I2SC_MR_IMCKMODE_MASK); + + if (!enabled) { + /* Disable the I2S Master Clock generator. */ + ret = regmap_write(dev->regmap, ATMEL_I2SC_CR, + ATMEL_I2SC_CR_CKDIS); + if (ret) + return ret; + + /* Reset the I2S Master Clock generator settings. */ + ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, + mr_mask, mr); + if (ret) + return ret; + + /* Disable/unprepare the PMC generated clock. */ + clk_disable_unprepare(dev->gclk); + + /* Disable/unprepare the PLL audio clock. */ + clk_disable_unprepare(dev->aclk); + return 0; + } + + if (!dev->gck_param) + return -EINVAL; + + aclk_rate = dev->gck_param->mck * (dev->gck_param->imckdiv+1); + + /* Fist change the PLL audio clock frequency ... */ + ret = clk_set_rate(dev->aclk, aclk_rate); + if (ret) + return ret; + + /* + * ... then set the PMC generated clock rate to the very same frequency + * to set the gclk parent to aclk. + */ + ret = clk_set_rate(dev->gclk, aclk_rate); + if (ret) + return ret; + + /* Prepare and enable the PLL audio clock first ... */ + ret = clk_prepare_enable(dev->aclk); + if (ret) + return ret; + + /* ... then prepare and enable the PMC generated clock. */ + ret = clk_prepare_enable(dev->gclk); + if (ret) + return ret; + + /* Update the Mode Register to generate the I2S Master Clock. */ + mr |= ATMEL_I2SC_MR_IMCKDIV(dev->gck_param->imckdiv); + mr |= ATMEL_I2SC_MR_IMCKFS(dev->gck_param->imckfs); + mr |= ATMEL_I2SC_MR_IMCKMODE_I2SMCK; + ret = regmap_update_bits(dev->regmap, ATMEL_I2SC_MR, mr_mask, mr); + if (ret) + return ret; + + /* Finally enable the I2S Master Clock generator. */ + return regmap_write(dev->regmap, ATMEL_I2SC_CR, + ATMEL_I2SC_CR_CKEN); +} + +static int atmel_i2s_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + bool is_master, mck_enabled; + unsigned int cr, mr; + int err; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + cr = is_playback ? ATMEL_I2SC_CR_TXEN : ATMEL_I2SC_CR_RXEN; + mck_enabled = true; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + cr = is_playback ? ATMEL_I2SC_CR_TXDIS : ATMEL_I2SC_CR_RXDIS; + mck_enabled = false; + break; + default: + return -EINVAL; + } + + /* Read the Mode Register to retrieve the master/slave state. */ + err = regmap_read(dev->regmap, ATMEL_I2SC_MR, &mr); + if (err) + return err; + is_master = (mr & ATMEL_I2SC_MR_MODE_MASK) == ATMEL_I2SC_MR_MODE_MASTER; + + /* If master starts, enable the audio clock. */ + if (is_master && mck_enabled) + err = atmel_i2s_switch_mck_generator(dev, true); + if (err) + return err; + + err = regmap_write(dev->regmap, ATMEL_I2SC_CR, cr); + if (err) + return err; + + /* If master stops, disable the audio clock. */ + if (is_master && !mck_enabled) + err = atmel_i2s_switch_mck_generator(dev, false); + + return err; +} + +static const struct snd_soc_dai_ops atmel_i2s_dai_ops = { + .prepare = atmel_i2s_prepare, + .trigger = atmel_i2s_trigger, + .hw_params = atmel_i2s_hw_params, + .set_fmt = atmel_i2s_set_dai_fmt, +}; + +static int atmel_i2s_dai_probe(struct snd_soc_dai *dai) +{ + struct atmel_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); + + snd_soc_dai_init_dma_data(dai, &dev->playback, &dev->capture); + return 0; +} + +static struct snd_soc_dai_driver atmel_i2s_dai = { + .probe = atmel_i2s_dai_probe, + .playback = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_I2S_RATES, + .formats = ATMEL_I2S_FORMATS, + }, + .capture = { + .channels_min = 1, + .channels_max = 2, + .rates = ATMEL_I2S_RATES, + .formats = ATMEL_I2S_FORMATS, + }, + .ops = &atmel_i2s_dai_ops, + .symmetric_rates = 1, +}; + +static const struct snd_soc_component_driver atmel_i2s_component = { + .name = "atmel-i2s", +}; + + +static int atmel_i2s_sama5d2_mck_init(struct atmel_i2s_dev *dev, + struct device_node *np) +{ + #define SFR_I2SCLKSEL 0x90U + struct regmap *sfr; + int id; + + id = of_alias_get_id(np, "i2s"); + if (id < 0) { + dev_err(dev->dev, "failed to get alias ID\n"); + return id; + } + if (id > 1) { + dev_err(dev->dev, "invalid I2S controller ID: %d\n", id); + return -EINVAL; + } + + sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(sfr)) { + dev_err(dev->dev, "failed to get SFR syscon\n"); + return PTR_ERR(sfr); + } + + return regmap_update_bits(sfr, SFR_I2SCLKSEL, BIT(id), BIT(id)); +} + +static const struct atmel_i2s_caps atmel_i2s_sama5d2_caps = { + .mck_init = atmel_i2s_sama5d2_mck_init, +}; + +static const struct of_device_id atmel_i2s_dt_ids[] = { + { + .compatible = "atmel,sama5d2-i2s", + .data = (void *)&atmel_i2s_sama5d2_caps, + }, + + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, atmel_i2s_dt_ids); + +static int atmel_i2s_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + struct atmel_i2s_dev *dev; + struct resource *mem; + struct regmap *regmap; + void __iomem *base; + int irq; + int err = -ENXIO; + unsigned int pcm_flags = 0; + unsigned int version; + + /* Get memory for driver data. */ + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + /* Get hardware capabilities. */ + match = of_match_node(atmel_i2s_dt_ids, np); + dev->caps = match ? match->data : NULL; + + /* Map I/O registers. */ + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(base)) + return PTR_ERR(base); + + regmap = devm_regmap_init_mmio(&pdev->dev, base, + &atmel_i2s_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* Request IRQ. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + err = devm_request_irq(&pdev->dev, irq, atmel_i2s_interrupt, 0, + dev_name(&pdev->dev), dev); + if (err) + return err; + + /* Get the peripheral clock. */ + dev->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(dev->pclk)) { + err = PTR_ERR(dev->pclk); + dev_err(&pdev->dev, + "failed to get the peripheral clock: %d\n", err); + return err; + } + + /* Get audio clocks to generate the I2S Master Clock (I2S_MCK) */ + dev->aclk = devm_clk_get(&pdev->dev, "aclk"); + dev->gclk = devm_clk_get(&pdev->dev, "gclk"); + if (IS_ERR(dev->aclk) && IS_ERR(dev->gclk)) { + /* Master Mode not supported */ + dev->aclk = NULL; + dev->gclk = NULL; + } else if (IS_ERR(dev->gclk)) { + err = PTR_ERR(dev->gclk); + dev_err(&pdev->dev, + "failed to get the PMC generated clock: %d\n", err); + return err; + } else if (IS_ERR(dev->aclk)) { + err = PTR_ERR(dev->aclk); + dev_err(&pdev->dev, + "failed to get the PLL audio clock: %d\n", err); + return err; + } + + dev->dev = &pdev->dev; + dev->regmap = regmap; + platform_set_drvdata(pdev, dev); + + /* Do hardware specific settings to initialize I2S_MCK generator */ + if (dev->caps && dev->caps->mck_init) { + err = dev->caps->mck_init(dev, np); + if (err) + return err; + } + + /* Enable the peripheral clock. */ + err = clk_prepare_enable(dev->pclk); + if (err) + return err; + + /* Get IP version. */ + regmap_read(dev->regmap, ATMEL_I2SC_VERSION, &version); + dev_info(&pdev->dev, "hw version: %#x\n", version); + + /* Enable error interrupts. */ + regmap_write(dev->regmap, ATMEL_I2SC_IER, + ATMEL_I2SC_INT_RXOR | ATMEL_I2SC_INT_TXUR); + + err = devm_snd_soc_register_component(&pdev->dev, + &atmel_i2s_component, + &atmel_i2s_dai, 1); + if (err) { + dev_err(&pdev->dev, "failed to register DAI: %d\n", err); + clk_disable_unprepare(dev->pclk); + return err; + } + + /* Prepare DMA config. */ + dev->playback.addr = (dma_addr_t)mem->start + ATMEL_I2SC_THR; + dev->playback.maxburst = 1; + dev->capture.addr = (dma_addr_t)mem->start + ATMEL_I2SC_RHR; + dev->capture.maxburst = 1; + + if (of_property_match_string(np, "dma-names", "rx-tx") == 0) + pcm_flags |= SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX; + err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, pcm_flags); + if (err) { + dev_err(&pdev->dev, "failed to register PCM: %d\n", err); + clk_disable_unprepare(dev->pclk); + return err; + } + + return 0; +} + +static int atmel_i2s_remove(struct platform_device *pdev) +{ + struct atmel_i2s_dev *dev = platform_get_drvdata(pdev); + + clk_disable_unprepare(dev->pclk); + + return 0; +} + +static struct platform_driver atmel_i2s_driver = { + .driver = { + .name = "atmel_i2s", + .of_match_table = of_match_ptr(atmel_i2s_dt_ids), + }, + .probe = atmel_i2s_probe, + .remove = atmel_i2s_remove, +}; +module_platform_driver(atmel_i2s_driver); + +MODULE_DESCRIPTION("Atmel I2S Controller driver"); +MODULE_AUTHOR("Cyrille Pitchen "); +MODULE_LICENSE("GPL v2"); From 0cc27b3bd397c385b3c604db68a3ee53cb3aa3ea Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 9 Jun 2015 17:07:05 +0200 Subject: [PATCH 201/381] dmaengine: at_xdmac: handle numf > 1 Handle 'numf > 1' case for interleaved mode. Signed-off-by: Maxime Ripard Signed-off-by: Ludovic Desroches --- drivers/dma/at_xdmac.c | 104 ++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 54 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index a165b4bfd3300e..0190d1ca30044f 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -929,13 +929,19 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, { struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); struct at_xdmac_desc *prev = NULL, *first = NULL; - struct data_chunk *chunk, *prev_chunk = NULL; dma_addr_t dst_addr, src_addr; - size_t dst_skip, src_skip, len = 0; - size_t prev_dst_icg = 0, prev_src_icg = 0; + size_t src_skip = 0, dst_skip = 0, len = 0; + struct data_chunk *chunk; int i; - if (!xt || (xt->numf != 1) || (xt->dir != DMA_MEM_TO_MEM)) + if (!xt || !xt->numf || (xt->dir != DMA_MEM_TO_MEM)) + return NULL; + + /* + * TODO: Handle the case where we have to repeat a chain of + * descriptors... + */ + if ((xt->numf > 1) && (xt->frame_size > 1)) return NULL; dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", @@ -945,66 +951,56 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, src_addr = xt->src_start; dst_addr = xt->dst_start; - for (i = 0; i < xt->frame_size; i++) { - struct at_xdmac_desc *desc; - size_t src_icg, dst_icg; - - chunk = xt->sgl + i; + if (xt->numf > 1) { + first = at_xdmac_interleaved_queue_desc(chan, atchan, + NULL, + src_addr, dst_addr, + xt, xt->sgl); + for (i = 0; i < xt->numf; i++) + at_xdmac_increment_block_count(chan, first); + } else { + for (i = 0; i < xt->frame_size; i++) { + size_t src_icg = 0, dst_icg = 0; + struct at_xdmac_desc *desc; - dst_icg = dmaengine_get_dst_icg(xt, chunk); - src_icg = dmaengine_get_src_icg(xt, chunk); + chunk = xt->sgl + i; - src_skip = chunk->size + src_icg; - dst_skip = chunk->size + dst_icg; + dst_icg = dmaengine_get_dst_icg(xt, chunk); + src_icg = dmaengine_get_src_icg(xt, chunk); - dev_dbg(chan2dev(chan), - "%s: chunk size=%d, src icg=%d, dst icg=%d\n", - __func__, chunk->size, src_icg, dst_icg); + src_skip = chunk->size + src_icg; + dst_skip = chunk->size + dst_icg; - /* - * Handle the case where we just have the same - * transfer to setup, we can just increase the - * block number and reuse the same descriptor. - */ - if (prev_chunk && prev && - (prev_chunk->size == chunk->size) && - (prev_src_icg == src_icg) && - (prev_dst_icg == dst_icg)) { dev_dbg(chan2dev(chan), - "%s: same configuration that the previous chunk, merging the descriptors...\n", - __func__); - at_xdmac_increment_block_count(chan, prev); - continue; - } - - desc = at_xdmac_interleaved_queue_desc(chan, atchan, - prev, - src_addr, dst_addr, - xt, chunk); - if (!desc) { - list_splice_init(&first->descs_list, - &atchan->free_descs_list); - return NULL; - } + "%s: chunk size=%d, src icg=%d, dst icg=%d\n", + __func__, chunk->size, src_icg, dst_icg); + + desc = at_xdmac_interleaved_queue_desc(chan, atchan, + prev, + src_addr, dst_addr, + xt, chunk); + if (!desc) { + list_splice_init(&first->descs_list, + &atchan->free_descs_list); + return NULL; + } - if (!first) - first = desc; + if (!first) + first = desc; - dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n", - __func__, desc, first); - list_add_tail(&desc->desc_node, &first->descs_list); + dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n", + __func__, desc, first); + list_add_tail(&desc->desc_node, &first->descs_list); - if (xt->src_sgl) - src_addr += src_skip; + if (xt->src_sgl) + src_addr += src_skip; - if (xt->dst_sgl) - dst_addr += dst_skip; + if (xt->dst_sgl) + dst_addr += dst_skip; - len += chunk->size; - prev_chunk = chunk; - prev_dst_icg = dst_icg; - prev_src_icg = src_icg; - prev = desc; + len += chunk->size; + prev = desc; + } } first->tx_dma_desc.cookie = -EBUSY; From 87ffb1920ba786e43cc12b9dde75335a352c9233 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 17 Jun 2015 14:35:03 +0200 Subject: [PATCH 202/381] dmaengine: at_xdmac: change block increment addressing mode The addressing mode we were using was not only incrementing the address at each microblock, but also at each data boundary, which was severely slowing the transfer, without any benefit since we were not using the data stride. Switch to the micro block increment only in order to get back to an acceptable performance level. Signed-off-by: Maxime Ripard Signed-off-by: Ludovic Desroches Fixes: 6007ccb57744 ("dmaengine: xdmac: Add interleaved transfer support") Cc: stable@vger.kernel.org #4.2 --- drivers/dma/at_xdmac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 0190d1ca30044f..3952bff50ba2e7 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -875,14 +875,14 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, if (xt->src_inc) { if (xt->src_sgl) - chan_cc |= AT_XDMAC_CC_SAM_UBS_DS_AM; + chan_cc |= AT_XDMAC_CC_SAM_UBS_AM; else chan_cc |= AT_XDMAC_CC_SAM_INCREMENTED_AM; } if (xt->dst_inc) { if (xt->dst_sgl) - chan_cc |= AT_XDMAC_CC_DAM_UBS_DS_AM; + chan_cc |= AT_XDMAC_CC_DAM_UBS_AM; else chan_cc |= AT_XDMAC_CC_DAM_INCREMENTED_AM; } From 2388b8d6fa0d4395ae0e058f6897618c32fc6c0c Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 30 Jun 2015 16:25:32 +0200 Subject: [PATCH 203/381] dmaengine: at_xdmac: fix memory leak in interleaved mode In interleaved mode, when numf > 1, we have only one descriptor for the transfer but this descriptor has to be added to the descs_list. If not, when doing remove_xfer, the descriptor won't be put back in the free_descs_list. Signed-off-by: Ludovic Desroches --- drivers/dma/at_xdmac.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 3952bff50ba2e7..fbd409340abaa6 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -958,6 +958,10 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, xt, xt->sgl); for (i = 0; i < xt->numf; i++) at_xdmac_increment_block_count(chan, first); + + dev_dbg(chan2dev(chan), "%s: add desc 0x%p to descs_list 0x%p\n", + __func__, first, first); + list_add_tail(&first->desc_node, &first->descs_list); } else { for (i = 0; i < xt->frame_size; i++) { size_t src_icg = 0, dst_icg = 0; From cf18181833dec57d909799e269540a9d6f4dae4d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 30 Jun 2015 16:44:26 +0200 Subject: [PATCH 204/381] dmaengine: at_xdmac: clean used descriptor When putting back a descriptor to the free descs list, some fields are not set to 0, it can cause bugs if someone uses it without having this in mind. Descriptor are not put back one by one so it is easier to clean descriptors when we request them. Signed-off-by: Ludovic Desroches Cc: stable@vger.kernel.org #4.2 --- drivers/dma/at_xdmac.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index fbd409340abaa6..b5e132d4bae5b5 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -455,6 +455,15 @@ static struct at_xdmac_desc *at_xdmac_alloc_desc(struct dma_chan *chan, return desc; } +void at_xdmac_init_used_desc(struct at_xdmac_desc *desc) +{ + memset(&desc->lld, 0, sizeof(desc->lld)); + INIT_LIST_HEAD(&desc->descs_list); + desc->direction = DMA_TRANS_NONE; + desc->xfer_size = 0; + desc->active_xfer = false; +} + /* Call must be protected by lock. */ static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan) { @@ -466,7 +475,7 @@ static struct at_xdmac_desc *at_xdmac_get_desc(struct at_xdmac_chan *atchan) desc = list_first_entry(&atchan->free_descs_list, struct at_xdmac_desc, desc_node); list_del(&desc->desc_node); - desc->active_xfer = false; + at_xdmac_init_used_desc(desc); } return desc; From 73a04fec1703f0c06e85ac9bf67a130f638b4655 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 23 Sep 2015 16:13:39 +0800 Subject: [PATCH 205/381] i2c: at91: add setting HOLD field of TWIHS_CWGR via DT This patch is to add setting the HOLD field to adapt to the different I2C slave device. To configure it more flexibly, add a DT property "atmel,twd-hold-cycles" to specify the HOLD field to increase the TWD hold time. Signed-off-by: Wenyou Yang --- drivers/i2c/busses/i2c-at91.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 1c758cd1e1ba82..06e66ef9b73ae6 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -64,6 +64,7 @@ #define AT91_TWI_IADR 0x000c /* Internal Address Register */ #define AT91_TWI_CWGR 0x0010 /* Clock Waveform Generator Reg */ +#define AT91_TWI_CWGR_HOLD(x) (((x) & 0x1f) << 24) #define AT91_TWI_SR 0x0020 /* Status Register */ #define AT91_TWI_TXCOMP BIT(0) /* Transmission Complete */ @@ -185,7 +186,8 @@ static void at91_init_twi_bus(struct at91_twi_dev *dev) * Calculate symmetric clock as stated in datasheet: * twi_clk = F_MAIN / (2 * (cdiv * (1 << ckdiv) + offset)) */ -static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) +static void at91_calc_twi_clock(struct at91_twi_dev *dev, + int twi_clk, u32 twd_hold) { int ckdiv, cdiv, div; struct at91_twi_pdata *pdata = dev->pdata; @@ -204,7 +206,9 @@ static void at91_calc_twi_clock(struct at91_twi_dev *dev, int twi_clk) cdiv = 255; } - dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv; + dev->twi_cwgr_reg = (ckdiv << 16) | (cdiv << 8) | cdiv + | AT91_TWI_CWGR_HOLD(twd_hold); + dev_dbg(dev->dev, "cdiv %d ckdiv %d\n", cdiv, ckdiv); } @@ -936,6 +940,7 @@ static int at91_twi_probe(struct platform_device *pdev) int rc; u32 phy_addr; u32 bus_clk_rate; + u32 twd_hold_cycles; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) @@ -992,7 +997,12 @@ static int at91_twi_probe(struct platform_device *pdev) if (rc) bus_clk_rate = DEFAULT_TWI_CLK_HZ; - at91_calc_twi_clock(dev, bus_clk_rate); + rc = of_property_read_u32(dev->dev->of_node, + "atmel,twd-hold-cycles", &twd_hold_cycles); + if (rc) + twd_hold_cycles = 0; + + at91_calc_twi_clock(dev, bus_clk_rate, twd_hold_cycles); at91_init_twi_bus(dev); snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); From 553d297c0f46e351ca30a93085836174c1074189 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 1 Jun 2015 16:56:00 +0200 Subject: [PATCH 206/381] i2c: at91: update documentation for DT bindings add a new value "atmel,sama5d2-i2c" for the "compatible" property. add a new optional property "atmel,fifo-size" to enable FIFO support when available. add missing optional properties "dmas" and "dma-names". Signed-off-by: Cyrille Pitchen --- .../devicetree/bindings/i2c/i2c-at91.txt | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt index 388f0a275fbacb..6e81dc153f3b95 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt @@ -2,8 +2,8 @@ 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" + "atmel,at91sam9260-i2c", "atmel,at91sam9g20-i2c", "atmel,at91sam9g10-i2c", + "atmel,at91sam9x5-i2c" or "atmel,sama5d2-i2c" - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt number to the cpu. @@ -13,6 +13,10 @@ Required properties : Optional properties: - clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000 +- dmas: A list of two dma specifiers, one for each entry in dma-names. +- dma-names: should contain "tx" and "rx". +- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO + capable I2C controllers. - Child nodes conforming to i2c bus binding Examples : @@ -32,3 +36,25 @@ i2c0: i2c@fff84000 { pagesize = <128>; } } + +i2c0: i2c@f8034600 { + compatible = "atmel,sama5d2-i2c"; + reg = <0xf8034600 0x100>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) + AT91_XDMAC_DT_PERID(11)>, + <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1)) + AT91_XDMAC_DT_PERID(12)>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx0>; + atmel,fifo-size = <16>; + + wm8731: wm8731@1a { + compatible = "wm8731"; + reg = <0x1a>; + }; +}; From 443da969723106328f23cf929c6dc70d107c993d Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 23 Sep 2015 16:42:37 +0800 Subject: [PATCH 207/381] i2c: at91: add DT property "atmel,twd-hold-cycles" to binding Add a DT property "atmel,twd-hold-cycles" to specify the HOLD filed of TWIHS_CWGR register to increase the TWD hold time. Signed-off-by: Wenyou Yang --- Documentation/devicetree/bindings/i2c/i2c-at91.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-at91.txt b/Documentation/devicetree/bindings/i2c/i2c-at91.txt index 6e81dc153f3b95..ccb8173de38dce 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-at91.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-at91.txt @@ -17,6 +17,8 @@ Optional properties: - dma-names: should contain "tx" and "rx". - atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO capable I2C controllers. +- atmel,twd-hold-cycles: specify hold cycles to increase the TWD hold time, + the maximum value is 0x1f. - Child nodes conforming to i2c bus binding Examples : @@ -29,6 +31,7 @@ i2c0: i2c@fff84000 { #size-cells = <0>; clocks = <&twi0_clk>; clock-frequency = <400000>; + atmel,twd-hold-cycles = <2>; 24c512@50 { compatible = "24c512"; From dd4c8f93e8269ca9a117161d9a6b8df3be138959 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 23 Sep 2015 16:45:48 +0800 Subject: [PATCH 208/381] ARM: dts: at91: specify DT property "atmel,twd-hold-cycles" Specify the device tree property "atmel,twd-hold-cycles" to 25 to adapt to the PMIC ACT8945A. Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index d2bdb8e1f30148..0a044fa7c5b563 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -150,6 +150,7 @@ dmas = <0>, <0>; pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2c0_default>; + atmel,twd-hold-cycles = <25>; status = "okay"; }; From 2fe18c889a0c96e583d9fffcec53818fef64f7ea Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Tue, 9 Jun 2015 13:01:50 +0530 Subject: [PATCH 209/381] mmc: sdhci: add quirk SDHCI_QUIRK_CLOCK_DIV_ZERO_BROKEN adds quirk for controllers whose clock divider zero is broken, sdhci_set_clock function will incorporate this modification. Signed-off-by: Suneel Garapati Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 3 +++ drivers/mmc/host/sdhci.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b53518451ee24e..58fb51769f032f 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1235,6 +1235,9 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) } real_div = div; div >>= 1; + if ((host->quirks2 & SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN) + && !div && host->max_clk <= 25000000) + div = 1; } } else { /* Version 2.00 divisors must be a power of 2. */ diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e639b7f435e564..19c18ea48411b3 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -409,6 +409,8 @@ struct sdhci_host { #define SDHCI_QUIRK2_SUPPORT_SINGLE (1<<13) /* Controller broken with using ACMD23 */ #define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) +/* Broken Clock divider zero in controller */ +#define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ From 301783419b21d90d11f3184b1bb95844baad2492 Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Thu, 17 Sep 2015 10:16:19 +0200 Subject: [PATCH 210/381] mmc: sdhci: add quirk SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST The Atmel sdhci device needs a new quirk. sdhci_set_clock set the Clock Control Register to 0 before computing the new value and writing it. It disables the internal clock which causes a reset mecanism. If we write the new value before this reset mecanism is done, it will prevent the stabilisation of the internal clock, so a delay is needed. This delay is about 2-3 cycles of the base clock. To be safe, a 1 ms delay is used. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 2 ++ drivers/mmc/host/sdhci.h | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 58fb51769f032f..5e253cd3065b80 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1171,6 +1171,8 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock = 0; sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST) + mdelay(1); if (clock == 0) return; diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 19c18ea48411b3..b238f6821c1ba7 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -411,6 +411,11 @@ struct sdhci_host { #define SDHCI_QUIRK2_ACMD23_BROKEN (1<<14) /* Broken Clock divider zero in controller */ #define SDHCI_QUIRK2_CLOCK_DIV_ZERO_BROKEN (1<<15) +/* + * When internal clock is disabled, a delay is needed before modifying the + * SD clock frequency or enabling back the internal clock. + */ +#define SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST (1<<16) int irq; /* Device IRQ */ void __iomem *ioaddr; /* Mapped address */ From b37f95b43c5515de9d9baef70757d615fcfca8ad Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Thu, 17 Sep 2015 10:16:20 +0200 Subject: [PATCH 211/381] mmc: sdhci-of-at91: use SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST quirk The Atmel sdhci device needs the SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST quirk. Without it, the internal clock could never stabilised when changing the sd clock frequency. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index d1556643a41d32..a0f05de5409f7d 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -43,6 +43,7 @@ static const struct sdhci_ops sdhci_at91_sama5d2_ops = { static const struct sdhci_pltfm_data soc_data_sama5d2 = { .ops = &sdhci_at91_sama5d2_ops, + .quirks2 = SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST, }; static const struct of_device_id sdhci_at91_dt_match[] = { From 231c41fffa0499bc7722662231a625101c943fd2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Sep 2015 09:19:49 +0300 Subject: [PATCH 212/381] mmc: sdhci-of-at91: remove a line of dead code The goto is correct and the unreachable "return -EINVAL" should be removed. Signed-off-by: Dan Carpenter Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index a0f05de5409f7d..06d0b50dfe71d2 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -111,7 +111,6 @@ static int sdhci_at91_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "failed to set gck"); goto hclock_disable_unprepare; - return -EINVAL; } /* * We need to check if we have the requested rate for gck because in From 9072c496d36149a70b2e984a265d4bd01a02da1b Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 12 Aug 2015 11:43:07 +0200 Subject: [PATCH 213/381] mmc: sdhci at91: add suspend/resume Add suspend and resume PM ops. Signed-off-by: Ludovic Desroches --- drivers/mmc/host/sdhci-of-at91.c | 55 +++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 06d0b50dfe71d2..b9751f20d4a028 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -51,6 +51,59 @@ static const struct of_device_id sdhci_at91_dt_match[] = { {} }; +#ifdef CONFIG_PM_SLEEP +static int sdhci_at91_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + int ret; + + ret = sdhci_suspend_host(host); + if (ret) + return ret; + + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->hclock); + clk_disable_unprepare(priv->mainck); + + return 0; +} + +static int sdhci_at91_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + int ret; + + ret = clk_prepare_enable(priv->mainck); + if (ret) { + dev_err(dev, "can't enable mainck\n"); + return ret; + } + + ret = clk_prepare_enable(priv->hclock); + if (ret) { + dev_err(dev, "can't enable hclock\n"); + return ret; + } + + ret = clk_prepare_enable(priv->gck); + if (ret) { + dev_err(dev, "can't enable gck\n"); + return ret; + } + + return sdhci_resume_host(host); +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(sdhci_at91_dev_pm_ops, sdhci_at91_suspend, + sdhci_at91_resume); + static int sdhci_at91_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -178,7 +231,7 @@ static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", .of_match_table = sdhci_at91_dt_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_at91_dev_pm_ops, }, .probe = sdhci_at91_probe, .remove = sdhci_at91_remove, From 1b5c5df106754792494a81040a53dd6731d557b6 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 23 Sep 2015 13:48:55 +0800 Subject: [PATCH 214/381] regulator: act8865: support output voltage by VSET2[] bits For the step-down DC/DC regulators, the output voltage is selectable by setting VSEL pin that when VSEL is low, output voltage is programmed by VSET1[] bits, and when VSEL is high, output voltage is programmed by VSET2[] bits. The DT property "active-semi,vsel-high" is used to specify the VSEL pin at high on the board. Signed-off-by: Wenyou Yang --- drivers/regulator/act8865-regulator.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 2ff73d72ca34ac..757de2a13bcd29 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -261,6 +261,16 @@ static const struct regulator_desc act8865_regulators[] = { ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), }; +static const struct regulator_desc act8865_alt_regulators[] = { + ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"), + ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"), + ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"), + ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), + ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), + ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), + ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), +}; + #ifdef CONFIG_OF static const struct of_device_id act8865_dt_ids[] = { { .compatible = "active-semi,act8600", .data = (void *)ACT8600 }, @@ -413,6 +423,7 @@ static int act8865_pmic_probe(struct i2c_client *client, struct act8865 *act8865; unsigned long type; int off_reg, off_mask; + int voltage_select = 0; pdata = dev_get_platdata(dev); @@ -424,6 +435,10 @@ static int act8865_pmic_probe(struct i2c_client *client, return -ENODEV; type = (unsigned long) id->data; + + voltage_select = !!of_get_property(dev->of_node, + "active-semi,vsel-high", + NULL); } else { type = i2c_id->driver_data; } @@ -442,8 +457,13 @@ static int act8865_pmic_probe(struct i2c_client *client, off_mask = ACT8846_OFF_SYSMASK; break; case ACT8865: - regulators = act8865_regulators; - num_regulators = ARRAY_SIZE(act8865_regulators); + if (voltage_select) { + regulators = act8865_alt_regulators; + num_regulators = ARRAY_SIZE(act8865_alt_regulators); + } else { + regulators = act8865_regulators; + num_regulators = ARRAY_SIZE(act8865_regulators); + } off_reg = ACT8865_SYS_CTRL; off_mask = ACT8865_MSTROFF; break; From a11fd9b87d98b1fced0e507723ba9157b4d25113 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 23 Sep 2015 14:32:28 +0800 Subject: [PATCH 215/381] regulator: act8865: add DT binding for property "active-semi,vsel-high" Add a DT property "active-semi,vsel-high" to indicate the VSEL pin is high. If this property is missing, then assume the VSEL pin is low(0). Signed-off-by: Wenyou Yang --- .../devicetree/bindings/regulator/act8865-regulator.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt index e91485d1124175..6067d9830d07d4 100644 --- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt @@ -8,6 +8,8 @@ Required properties: Optional properties: - system-power-controller: Telling whether or not this pmic is controlling the system power. See Documentation/devicetree/bindings/power/power-controller.txt . +- active-semi,vsel-high: Indicates the VSEL pin is high. + If this property is missing, assume the VSEL pin is low(0). Optional input supply properties: - for act8600: @@ -49,6 +51,7 @@ Example: pmic: act8865@5b { compatible = "active-semi,act8865"; reg = <0x5b>; + active-semi,vsel-high; status = "disabled"; regulators { From ab8185dd85129fcbc88bb60190a30834b1ecce15 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Wed, 23 Sep 2015 14:49:27 +0800 Subject: [PATCH 216/381] ARM: dts: at91: sama5d2_xplained: add regulator nodes Add regulator nodes of PMIC ACT8945A chip on the board. Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 57 +++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 0a044fa7c5b563..fd996dc8345e97 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -152,6 +152,63 @@ pinctrl-0 = <&pinctrl_i2c0_default>; atmel,twd-hold-cycles = <25>; status = "okay"; + + pmic: act8865@5b { + compatible = "active-semi,act8865"; + reg = <0x5b>; + active-semi,vsel-high; + status = "okay"; + + regulators { + vdd_1v35_reg: DCDC_REG1 { + regulator-name = "VDD_1V35"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + vdd_1v2_reg: DCDC_REG2 { + regulator-name = "VDD_1V2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + + vdd_3v3_reg: DCDC_REG3 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_fuse_reg: LDO_REG1 { + regulator-name = "VDD_FUSE"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vdd_3v3_lp_reg: LDO_REG2 { + regulator-name = "VDD_3V3_LP"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_led_reg: LDO_REG3 { + regulator-name = "VDD_LED"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_sdhc_1v8_reg: LDO_REG4 { + regulator-name = "VDD_SDHC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + }; }; flx0: flexcom@f8034000 { From 1f2e9d1210d9b2381f26ba3f1de1da6f277e6e70 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 16 Sep 2015 17:36:57 +0200 Subject: [PATCH 217/381] pinctrl: introduce driver for Atmel PIO4 controller Add a pinctrl/gpio driver for Atmel PIO4 controller available on SAMA5D2 chip family. Signed-off-by: Ludovic Desroches Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 13 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-at91-pio4.c | 1017 +++++++++++++++++++++++++++ 3 files changed, 1031 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-at91-pio4.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index aeb5729fbda619..067a3c6bb8b016 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -67,6 +67,19 @@ config PINCTRL_AT91 help Say Y here to enable the at91 pinctrl driver +config PINCTRL_AT91PIO4 + bool "AT91 PIO4 pinctrl driver" + depends on OF + depends on ARCH_AT91 + select PINMUX + select GENERIC_PINCONF + select GPIOLIB + select GPIOLIB_IRQCHIP + select OF_GPIO + help + Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4 + controller available on sama5d2 SoC. + config PINCTRL_AMD bool "AMD GPIO pin control" depends on GPIOLIB diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 6eadf04a33b3e5..a685d8698df332 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o +obj-$(CONFIG_PINCTRL_AT91PIO4) += pinctrl-at91-pio4.o obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MESON) += meson/ diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c new file mode 100644 index 00000000000000..6aff632aaa46bc --- /dev/null +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -0,0 +1,1017 @@ +/* + * Driver for the Atmel PIO4 controller + * + * Copyright (C) 2015 Atmel, + * 2015 Ludovic Desroches + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "core.h" +#include "pinconf.h" +#include "pinctrl-utils.h" + +/* + * Warning: + * In order to not introduce confusion between Atmel PIO groups and pinctrl + * framework groups, Atmel PIO groups will be called banks, line is kept to + * designed the pin id into this bank. + */ + +#define ATMEL_PIO_MSKR 0x0000 +#define ATMEL_PIO_CFGR 0x0004 +#define ATMEL_PIO_CFGR_FUNC_MASK GENMASK(2, 0) +#define ATMEL_PIO_DIR_MASK BIT(8) +#define ATMEL_PIO_PUEN_MASK BIT(9) +#define ATMEL_PIO_PDEN_MASK BIT(10) +#define ATMEL_PIO_IFEN_MASK BIT(12) +#define ATMEL_PIO_IFSCEN_MASK BIT(13) +#define ATMEL_PIO_OPD_MASK BIT(14) +#define ATMEL_PIO_SCHMITT_MASK BIT(15) +#define ATMEL_PIO_CFGR_EVTSEL_MASK GENMASK(26, 24) +#define ATMEL_PIO_CFGR_EVTSEL_FALLING (0 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_RISING (1 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_BOTH (2 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_LOW (3 << 24) +#define ATMEL_PIO_CFGR_EVTSEL_HIGH (4 << 24) +#define ATMEL_PIO_PDSR 0x0008 +#define ATMEL_PIO_LOCKSR 0x000C +#define ATMEL_PIO_SODR 0x0010 +#define ATMEL_PIO_CODR 0x0014 +#define ATMEL_PIO_ODSR 0x0018 +#define ATMEL_PIO_IER 0x0020 +#define ATMEL_PIO_IDR 0x0024 +#define ATMEL_PIO_IMR 0x0028 +#define ATMEL_PIO_ISR 0x002C +#define ATMEL_PIO_IOFR 0x003C + +#define ATMEL_PIO_NPINS_PER_BANK 32 +#define ATMEL_PIO_BANK(pin_id) (pin_id / ATMEL_PIO_NPINS_PER_BANK) +#define ATMEL_PIO_LINE(pin_id) (pin_id % ATMEL_PIO_NPINS_PER_BANK) +#define ATMEL_PIO_BANK_OFFSET 0x40 + +#define ATMEL_GET_PIN_NO(pinfunc) ((pinfunc) & 0xff) +#define ATMEL_GET_PIN_FUNC(pinfunc) ((pinfunc >> 16) & 0xf) +#define ATMEL_GET_PIN_IOSET(pinfunc) ((pinfunc >> 20) & 0xf) + +struct atmel_pioctrl_data { + unsigned nbanks; +}; + +struct atmel_group { + const char *name; + u32 pin; +}; + +struct atmel_pin { + unsigned pin_id; + unsigned mux; + unsigned ioset; + unsigned bank; + unsigned line; + const char *device; +}; + +/** + * struct atmel_pioctrl - Atmel PIO controller (pinmux + gpio) + * @reg_base: base address of the controller. + * @clk: clock of the controller. + * @nbanks: number of PIO groups, it can vary depending on the SoC. + * @pinctrl_dev: pinctrl device registered. + * @groups: groups table to provide group name and pin in the group to pinctrl. + * @group_names: group names table to provide all the group/pin names to + * pinctrl or gpio. + * @pins: pins table used for both pinctrl and gpio. pin_id, bank and line + * fields are set at probe time. Other ones are set when parsing dt + * pinctrl. + * @npins: number of pins. + * @gpio_chip: gpio chip registered. + * @irq_domain: irq domain for the gpio controller. + * @irqs: table containing the hw irq number of the bank. The index of the + * table is the bank id. + * @dev: device entry for the Atmel PIO controller. + * @node: node of the Atmel PIO controller. + */ +struct atmel_pioctrl { + void __iomem *reg_base; + struct clk *clk; + unsigned nbanks; + struct pinctrl_dev *pinctrl_dev; + struct atmel_group *groups; + const char * const *group_names; + struct atmel_pin **pins; + unsigned npins; + struct gpio_chip *gpio_chip; + struct irq_domain *irq_domain; + int *irqs; + struct device *dev; + struct device_node *node; +}; + +static const char * const atmel_functions[] = { + "GPIO", "A", "B", "C", "D", "E", "F", "G" +}; + +/* --- GPIO --- */ +static unsigned int atmel_gpio_read(struct atmel_pioctrl *atmel_pioctrl, + unsigned int bank, unsigned int reg) +{ + return readl_relaxed(atmel_pioctrl->reg_base + + ATMEL_PIO_BANK_OFFSET * bank + reg); +} + +static void atmel_gpio_write(struct atmel_pioctrl *atmel_pioctrl, + unsigned int bank, unsigned int reg, + unsigned int val) +{ + writel_relaxed(val, atmel_pioctrl->reg_base + + ATMEL_PIO_BANK_OFFSET * bank + reg); +} + +static void atmel_gpio_irq_ack(struct irq_data *d) +{ + /* + * Nothing to do, interrupt is cleared when reading the status + * register. + */ +} + +static int atmel_gpio_irq_set_type(struct irq_data *d, unsigned type) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + struct atmel_pin *pin = atmel_pioctrl->pins[d->hwirq]; + unsigned reg; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_MSKR, + BIT(pin->line)); + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR); + reg &= (~ATMEL_PIO_CFGR_EVTSEL_MASK); + + switch (type) { + case IRQ_TYPE_EDGE_RISING: + __irq_set_handler_locked(d->irq, handle_edge_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_RISING; + break; + case IRQ_TYPE_EDGE_FALLING: + __irq_set_handler_locked(d->irq, handle_edge_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_FALLING; + break; + case IRQ_TYPE_EDGE_BOTH: + __irq_set_handler_locked(d->irq, handle_edge_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_BOTH; + break; + case IRQ_TYPE_LEVEL_LOW: + __irq_set_handler_locked(d->irq, handle_level_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + __irq_set_handler_locked(d->irq, handle_level_irq); + reg |= ATMEL_PIO_CFGR_EVTSEL_HIGH; + break; + case IRQ_TYPE_NONE: + default: + return -EINVAL; + } + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR, reg); + + return 0; +} + +static void atmel_gpio_irq_mask(struct irq_data *d) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + struct atmel_pin *pin = atmel_pioctrl->pins[d->hwirq]; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_IDR, + BIT(pin->line)); +} + +static void atmel_gpio_irq_unmask(struct irq_data *d) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + struct atmel_pin *pin = atmel_pioctrl->pins[d->hwirq]; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_IER, + BIT(pin->line)); +} + +static struct irq_chip atmel_gpio_irq_chip = { + .name = "GPIO", + .irq_ack = atmel_gpio_irq_ack, + .irq_mask = atmel_gpio_irq_mask, + .irq_unmask = atmel_gpio_irq_unmask, + .irq_set_type = atmel_gpio_irq_set_type, +}; + +static void atmel_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned long isr; + int n, bank = -1; + + /* Find from which bank is the irq received. */ + for (n = 0; n < atmel_pioctrl->nbanks; n++) { + if (atmel_pioctrl->irqs[n] == irq) { + bank = n; + break; + } + } + + if (bank < 0) { + dev_err(atmel_pioctrl->dev, + "no bank associated to irq %u\n", irq); + return; + } + + chained_irq_enter(chip, desc); + + for (;;) { + isr = (unsigned long)atmel_gpio_read(atmel_pioctrl, bank, + ATMEL_PIO_ISR); + isr &= (unsigned long)atmel_gpio_read(atmel_pioctrl, bank, + ATMEL_PIO_IMR); + if (!isr) + break; + + for_each_set_bit(n, &isr, BITS_PER_LONG) + generic_handle_irq(gpio_to_irq(bank * + ATMEL_PIO_NPINS_PER_BANK + n)); + } + + chained_irq_exit(chip, desc); +} + +static int atmel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + unsigned reg; + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_MSKR, + BIT(pin->line)); + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR); + reg &= ~ATMEL_PIO_DIR_MASK; + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR, reg); + + return 0; +} + +static int atmel_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + unsigned reg; + + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_PDSR); + + return !!(reg & BIT(pin->line)); +} + +static int atmel_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + unsigned reg; + + atmel_gpio_write(atmel_pioctrl, pin->bank, + value ? ATMEL_PIO_SODR : ATMEL_PIO_CODR, + BIT(pin->line)); + + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_MSKR, + BIT(pin->line)); + reg = atmel_gpio_read(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR); + reg |= ATMEL_PIO_DIR_MASK; + atmel_gpio_write(atmel_pioctrl, pin->bank, ATMEL_PIO_CFGR, reg); + + return 0; +} + +static void atmel_gpio_set(struct gpio_chip *chip, unsigned offset, int val) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + struct atmel_pin *pin = atmel_pioctrl->pins[offset]; + + atmel_gpio_write(atmel_pioctrl, pin->bank, + val ? ATMEL_PIO_SODR : ATMEL_PIO_CODR, + BIT(pin->line)); +} + +static int atmel_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct atmel_pioctrl *atmel_pioctrl = dev_get_drvdata(chip->dev); + + return irq_find_mapping(atmel_pioctrl->irq_domain, offset); +} + +static struct gpio_chip atmel_gpio_chip = { + .direction_input = atmel_gpio_direction_input, + .get = atmel_gpio_get, + .direction_output = atmel_gpio_direction_output, + .set = atmel_gpio_set, + .to_irq = atmel_gpio_to_irq, + .base = 0, +}; + +/* --- PINCTRL --- */ +static unsigned int atmel_pin_config_read(struct pinctrl_dev *pctldev, + unsigned pin_id) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned bank = atmel_pioctrl->pins[pin_id]->bank; + unsigned line = atmel_pioctrl->pins[pin_id]->line; + void __iomem *addr = atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET; + + writel_relaxed(BIT(line), addr + ATMEL_PIO_MSKR); + /* Have to set MSKR first, to access the right pin CFGR. */ + wmb(); + + return readl_relaxed(addr + ATMEL_PIO_CFGR); +} + +static void atmel_pin_config_write(struct pinctrl_dev *pctldev, + unsigned pin_id, u32 conf) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned bank = atmel_pioctrl->pins[pin_id]->bank; + unsigned line = atmel_pioctrl->pins[pin_id]->line; + void __iomem *addr = atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET; + + writel_relaxed(BIT(line), addr + ATMEL_PIO_MSKR); + /* Have to set MSKR first, to access the right pin CFGR. */ + wmb(); + writel_relaxed(conf, addr + ATMEL_PIO_CFGR); +} + +static int atmel_pctl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + + return atmel_pioctrl->npins; +} + +static const char *atmel_pctl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + + return atmel_pioctrl->groups[selector].name; +} + +static int atmel_pctl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, const unsigned **pins, + unsigned *num_pins) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = (unsigned *)&atmel_pioctrl->groups[selector].pin; + *num_pins = 1; + + return 0; +} + +struct atmel_group *atmel_pctl_find_group_by_pin(struct pinctrl_dev *pctldev, + unsigned pin) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + int i; + + for (i = 0; i < atmel_pioctrl->npins; i++) { + struct atmel_group *grp = atmel_pioctrl->groups + i; + + if (grp->pin == pin) + return grp; + } + + return NULL; +} + +static int atmel_pctl_xlate_pinfunc(struct pinctrl_dev *pctldev, + struct device_node *np, + u32 pinfunc, const char **grp_name, + const char **func_name) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned pin_id, func_id; + struct atmel_group *grp; + + pin_id = ATMEL_GET_PIN_NO(pinfunc); + func_id = ATMEL_GET_PIN_FUNC(pinfunc); + + if (func_id >= ARRAY_SIZE(atmel_functions)) + return -EINVAL; + + *func_name = atmel_functions[func_id]; + + grp = atmel_pctl_find_group_by_pin(pctldev, pin_id); + if (!grp) + return -EINVAL; + *grp_name = grp->name; + + atmel_pioctrl->pins[pin_id]->mux = func_id; + atmel_pioctrl->pins[pin_id]->ioset = ATMEL_GET_PIN_IOSET(pinfunc); + /* Want the device name not the group one. */ + if (np->parent == atmel_pioctrl->node) + atmel_pioctrl->pins[pin_id]->device = np->name; + else + atmel_pioctrl->pins[pin_id]->device = np->parent->name; + + return 0; +} + +static int atmel_pctl_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned *reserved_maps, + unsigned *num_maps) +{ + unsigned num_pins, num_configs, reserve; + unsigned long *configs; + struct property *pins; + bool has_config; + u32 pinfunc; + int ret, i; + + pins = of_find_property(np, "pinmux", NULL); + if (!pins) + return -EINVAL; + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(pctldev->dev, "%s: could not parse node property\n", + of_node_full_name(np)); + return ret; + } + + if (num_configs) + has_config = true; + + num_pins = pins->length / sizeof(u32); + if (!num_pins) { + dev_err(pctldev->dev, "no pins found in node %s\n", + of_node_full_name(np)); + return -EINVAL; + } + + /* + * Reserve maps, at least there is a mux map and an optional conf + * map for each pin. + */ + reserve = 1; + if (has_config && num_pins >= 1) + reserve++; + reserve *= num_pins; + ret = pinctrl_utils_reserve_map(pctldev, map, reserved_maps, num_maps, + reserve); + if (ret < 0) + return ret; + + for (i = 0; i < num_pins; i++) { + const char *group, *func; + + ret = of_property_read_u32_index(np, "pinmux", i, &pinfunc); + if (ret) + return ret; + + ret = atmel_pctl_xlate_pinfunc(pctldev, np, pinfunc, &group, + &func); + if (ret) + return ret; + + pinctrl_utils_add_map_mux(pctldev, map, reserved_maps, num_maps, + group, func); + + if (has_config) { + ret = pinctrl_utils_add_map_configs(pctldev, map, + reserved_maps, num_maps, group, + configs, num_configs, + PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static int atmel_pctl_dt_node_to_map(struct pinctrl_dev *pctldev, + struct device_node *np_config, + struct pinctrl_map **map, + unsigned *num_maps) +{ + struct device_node *np; + unsigned reserved_maps; + int ret; + + *map = NULL; + *num_maps = 0; + reserved_maps = 0; + + /* + * If all the pins of a device have the same configuration (or no one), + * it is useless to add a subnode, so directly parse node referenced by + * phandle. + */ + ret = atmel_pctl_dt_subnode_to_map(pctldev, np_config, map, + &reserved_maps, num_maps); + if (ret) { + for_each_child_of_node(np_config, np) { + ret = atmel_pctl_dt_subnode_to_map(pctldev, np, map, + &reserved_maps, num_maps); + if (ret < 0) + break; + } + } + + if (ret < 0) { + pinctrl_utils_dt_free_map(pctldev, *map, *num_maps); + dev_err(pctldev->dev, "can't create maps for node %s\n", + np_config->full_name); + } + + return ret; +} + +static const struct pinctrl_ops atmel_pctlops = { + .get_groups_count = atmel_pctl_get_groups_count, + .get_group_name = atmel_pctl_get_group_name, + .get_group_pins = atmel_pctl_get_group_pins, + .dt_node_to_map = atmel_pctl_dt_node_to_map, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int atmel_pmx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(atmel_functions); +} + +static const char *atmel_pmx_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + return atmel_functions[selector]; +} + +static int atmel_pmx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = atmel_pioctrl->group_names; + *num_groups = atmel_pioctrl->npins; + + return 0; +} + +static int atmel_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned pin; + u32 conf; + + dev_dbg(pctldev->dev, "enable function %s group %s\n", + atmel_functions[function], atmel_pioctrl->groups[group].name); + + pin = atmel_pioctrl->groups[group].pin; + conf = atmel_pin_config_read(pctldev, pin); + conf &= (~ATMEL_PIO_CFGR_FUNC_MASK); + conf |= (function & ATMEL_PIO_CFGR_FUNC_MASK); + dev_dbg(pctldev->dev, "pin: %u, conf: 0x%08x\n", pin, conf); + atmel_pin_config_write(pctldev, pin, conf); + + return 0; +} + +static const struct pinmux_ops atmel_pmxops = { + .get_functions_count = atmel_pmx_get_functions_count, + .get_function_name = atmel_pmx_get_function_name, + .get_function_groups = atmel_pmx_get_function_groups, + .set_mux = atmel_pmx_set_mux, +}; + +static int atmel_conf_pin_config_group_get(struct pinctrl_dev *pctldev, + unsigned group, + unsigned long *config) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + unsigned param = pinconf_to_config_param(*config), arg = 0; + struct atmel_group *grp = atmel_pioctrl->groups + group; + unsigned pin_id = grp->pin; + u32 res; + + res = atmel_pin_config_read(pctldev, pin_id); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + if (!(res & ATMEL_PIO_PUEN_MASK)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if ((res & ATMEL_PIO_PUEN_MASK) || + (!(res & ATMEL_PIO_PDEN_MASK))) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_BIAS_DISABLE: + if ((res & ATMEL_PIO_PUEN_MASK) || + ((res & ATMEL_PIO_PDEN_MASK))) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (!(res & ATMEL_PIO_OPD_MASK)) + return -EINVAL; + arg = 1; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (!(res & ATMEL_PIO_SCHMITT_MASK)) + return -EINVAL; + arg = 1; + break; + default: + return -ENOTSUPP; + } + + *config = pinconf_to_config_packed(param, arg); + return 0; +} + +static int atmel_conf_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned group, + unsigned long *configs, + unsigned num_configs) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + struct atmel_group *grp = atmel_pioctrl->groups + group; + unsigned bank, pin, pin_id = grp->pin; + u32 mask, conf = 0; + int i; + + conf = atmel_pin_config_read(pctldev, pin_id); + + for (i = 0; i < num_configs; i++) { + unsigned param = pinconf_to_config_param(configs[i]); + unsigned arg = pinconf_to_config_argument(configs[i]); + + dev_dbg(pctldev->dev, "%s: pin=%u, config=0x%lx\n", + __func__, pin_id, configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + conf &= (~ATMEL_PIO_PUEN_MASK); + conf &= (~ATMEL_PIO_PDEN_MASK); + break; + case PIN_CONFIG_BIAS_PULL_UP: + conf |= ATMEL_PIO_PUEN_MASK; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + conf |= ATMEL_PIO_PDEN_MASK; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + if (arg == 0) + conf &= (~ATMEL_PIO_OPD_MASK); + else + conf |= ATMEL_PIO_OPD_MASK; + break; + case PIN_CONFIG_INPUT_SCHMITT_ENABLE: + if (arg == 0) + conf |= ATMEL_PIO_SCHMITT_MASK; + else + conf &= (~ATMEL_PIO_SCHMITT_MASK); + break; + case PIN_CONFIG_INPUT_DEBOUNCE: + if (arg == 0) { + conf &= (~ATMEL_PIO_IFEN_MASK); + conf &= (~ATMEL_PIO_IFSCEN_MASK); + } else { + /* + * We don't care about the debounce value for several reasons: + * - can't have different debounce periods inside a same group, + * - the register to configure this period is a secure register. + * The debouncing filter can filter a pulse with a duration of less + * than 1/2 slow clock period. + */ + conf |= ATMEL_PIO_IFEN_MASK; + conf |= ATMEL_PIO_IFSCEN_MASK; + } + break; + case PIN_CONFIG_OUTPUT: + conf |= ATMEL_PIO_DIR_MASK; + bank = ATMEL_PIO_BANK(pin_id); + pin = ATMEL_PIO_LINE(pin_id); + mask = 1 << pin; + + if (arg == 0) { + writel_relaxed(mask, atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET + + ATMEL_PIO_CODR); + } else { + writel_relaxed(mask, atmel_pioctrl->reg_base + + bank * ATMEL_PIO_BANK_OFFSET + + ATMEL_PIO_SODR); + } + break; + default: + dev_warn(pctldev->dev, + "unsupported configuration parameter: %u\n", + param); + continue; + } + } + + dev_dbg(pctldev->dev, "%s: reg=0x%08x\n", __func__, conf); + atmel_pin_config_write(pctldev, pin_id, conf); + + return 0; +} + +static void atmel_conf_pin_config_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned pin_id) +{ + struct atmel_pioctrl *atmel_pioctrl = pinctrl_dev_get_drvdata(pctldev); + u32 conf; + + if (!atmel_pioctrl->pins[pin_id]->device) + return; + + if (atmel_pioctrl->pins[pin_id]) + seq_printf(s, " (%s, ioset %u) ", + atmel_pioctrl->pins[pin_id]->device, + atmel_pioctrl->pins[pin_id]->ioset); + + conf = atmel_pin_config_read(pctldev, pin_id); + if (conf & ATMEL_PIO_PUEN_MASK) + seq_printf(s, "%s ", "pull-up"); + if (conf & ATMEL_PIO_PDEN_MASK) + seq_printf(s, "%s ", "pull-down"); + if (conf & ATMEL_PIO_IFEN_MASK) + seq_printf(s, "%s ", "debounce"); + if (conf & ATMEL_PIO_OPD_MASK) + seq_printf(s, "%s ", "open-drain"); + if (conf & ATMEL_PIO_SCHMITT_MASK) + seq_printf(s, "%s ", "schmitt"); +} + +static const struct pinconf_ops atmel_confops = { + .pin_config_group_get = atmel_conf_pin_config_group_get, + .pin_config_group_set = atmel_conf_pin_config_group_set, + .pin_config_dbg_show = atmel_conf_pin_config_dbg_show, +}; + +static struct pinctrl_desc atmel_pinctrl_desc = { + .name = "atmel_pinctrl", + .confops = &atmel_confops, + .pctlops = &atmel_pctlops, + .pmxops = &atmel_pmxops, +}; + +/* + * The number of banks can be different from a SoC to another one. + * We can have up to 16 banks. + */ +static const struct atmel_pioctrl_data atmel_sama5d2_pioctrl_data = { + .nbanks = 4, +}; + +static const struct of_device_id atmel_pctrl_of_match[] = { + { + .compatible = "atmel,sama5d2-pinctrl", + .data = &atmel_sama5d2_pioctrl_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_pctrl_of_match); + +static int atmel_pinctrl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pinctrl_pin_desc *pin_desc; + const char **group_names; + const struct of_device_id *match; + int i, ret; + struct resource *res; + struct atmel_pioctrl *atmel_pioctrl; + struct atmel_pioctrl_data *atmel_pioctrl_data; + + atmel_pioctrl = devm_kzalloc(dev, sizeof(*atmel_pioctrl), GFP_KERNEL); + if (!atmel_pioctrl) + return -ENOMEM; + atmel_pioctrl->dev = dev; + atmel_pioctrl->node = dev->of_node; + platform_set_drvdata(pdev, atmel_pioctrl); + + match = of_match_node(atmel_pctrl_of_match, dev->of_node); + if (!match) { + dev_err(dev, "unknown compatible string\n"); + return -ENODEV; + } + atmel_pioctrl_data = (struct atmel_pioctrl_data *)match->data; + atmel_pioctrl->nbanks = atmel_pioctrl_data->nbanks; + atmel_pioctrl->npins = atmel_pioctrl->nbanks * ATMEL_PIO_NPINS_PER_BANK; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "unable to get atmel pinctrl resource\n"); + return -EINVAL; + } + atmel_pioctrl->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(atmel_pioctrl->reg_base)) + return -EINVAL; + + atmel_pioctrl->clk = devm_clk_get(dev, NULL); + if (IS_ERR(atmel_pioctrl->clk)) { + dev_err(dev, "failed to get clock\n"); + return PTR_ERR(atmel_pioctrl->clk); + } + + atmel_pioctrl->pins = devm_kzalloc(dev, sizeof(*atmel_pioctrl->pins) + * atmel_pioctrl->npins, GFP_KERNEL); + if (!atmel_pioctrl->pins) + return -ENOMEM; + + pin_desc = devm_kzalloc(dev, sizeof(*pin_desc) + * atmel_pioctrl->npins, GFP_KERNEL); + if (!pin_desc) + return -ENOMEM; + atmel_pinctrl_desc.pins = pin_desc; + atmel_pinctrl_desc.npins = atmel_pioctrl->npins; + + /* One pin is one group since a pin can achieve all functions. */ + group_names = devm_kzalloc(dev, sizeof(*group_names) + * atmel_pioctrl->npins, GFP_KERNEL); + if (!group_names) + return -ENOMEM; + atmel_pioctrl->group_names = group_names; + + atmel_pioctrl->groups = devm_kzalloc(&pdev->dev, + sizeof(*atmel_pioctrl->groups) * atmel_pioctrl->npins, + GFP_KERNEL); + if (!atmel_pioctrl->groups) + return -ENOMEM; + for (i = 0 ; i < atmel_pioctrl->npins; i++) { + struct atmel_group *group = atmel_pioctrl->groups + i; + unsigned bank = ATMEL_PIO_BANK(i); + unsigned line = ATMEL_PIO_LINE(i); + + atmel_pioctrl->pins[i] = devm_kzalloc(dev, + sizeof(**atmel_pioctrl->pins), GFP_KERNEL); + if (!atmel_pioctrl->pins[i]) + return -ENOMEM; + + atmel_pioctrl->pins[i]->pin_id = i; + atmel_pioctrl->pins[i]->bank = bank; + atmel_pioctrl->pins[i]->line = line; + + pin_desc[i].number = i; + /* Pin naming convention: P(bank_name)(bank_pin_number). */ + pin_desc[i].name = kasprintf(GFP_KERNEL, "P%c%d", + bank + 'A', line); + + group->name = group_names[i] = pin_desc[i].name; + group->pin = pin_desc[i].number; + + dev_dbg(dev, "pin_id=%u, bank=%u, line=%u", i, bank, line); + } + + atmel_pioctrl->gpio_chip = &atmel_gpio_chip; + atmel_pioctrl->gpio_chip->of_node = dev->of_node; + atmel_pioctrl->gpio_chip->ngpio = atmel_pioctrl->npins; + atmel_pioctrl->gpio_chip->label = dev_name(dev); + atmel_pioctrl->gpio_chip->dev = dev; + atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names; + + atmel_pioctrl->irqs = devm_kzalloc(dev, sizeof(*atmel_pioctrl->irqs) + * atmel_pioctrl->nbanks, GFP_KERNEL); + if (!atmel_pioctrl->irqs) + return -ENOMEM; + + /* There is one controller but each bank has its own irq line. */ + for (i = 0; i < atmel_pioctrl->nbanks; i++) { + res = platform_get_resource(pdev, IORESOURCE_IRQ, i); + if (!res) { + dev_err(dev, "missing irq resource for group %c\n", + 'A' + i); + return -EINVAL; + } + atmel_pioctrl->irqs[i] = res->start; + irq_set_chained_handler(res->start, atmel_gpio_irq_handler); + irq_set_handler_data(res->start, atmel_pioctrl); + dev_dbg(dev, "bank %i: hwirq=%u\n", i, res->start); + } + + atmel_pioctrl->irq_domain = irq_domain_add_linear(dev->of_node, + atmel_pioctrl->gpio_chip->ngpio, + &irq_domain_simple_ops, NULL); + if (!atmel_pioctrl->irq_domain) { + dev_err(dev, "can't add the irq domain\n"); + return -ENODEV; + } + atmel_pioctrl->irq_domain->name = "atmel gpio"; + + for (i = 0; i < atmel_pioctrl->npins; i++) { + int irq = irq_create_mapping(atmel_pioctrl->irq_domain, i); + + irq_set_chip_and_handler(irq, &atmel_gpio_irq_chip, + handle_simple_irq); + irq_set_chip_data(irq, atmel_pioctrl); + dev_dbg(dev, + "atmel gpio irq domain: hwirq: %d, linux irq: %d\n", + i, irq); + } + + ret = clk_prepare_enable(atmel_pioctrl->clk); + if (ret) { + dev_err(dev, "failed to prepare and enable clock\n"); + goto clk_prepare_enable_error; + } + + atmel_pioctrl->pinctrl_dev = pinctrl_register(&atmel_pinctrl_desc, + &pdev->dev, + atmel_pioctrl); + if (!atmel_pioctrl->pinctrl_dev) { + dev_err(dev, "pinctrl registration failed\n"); + goto pinctrl_register_error; + } + + ret = gpiochip_add(atmel_pioctrl->gpio_chip); + if (ret) { + dev_err(dev, "failed to add gpiochip\n"); + goto gpiochip_add_error; + } + + ret = gpiochip_add_pin_range(atmel_pioctrl->gpio_chip, dev_name(dev), + 0, 0, atmel_pioctrl->gpio_chip->ngpio); + if (ret) { + dev_err(dev, "failed to add gpio pin range\n"); + goto gpiochip_add_pin_range_error; + } + + dev_info(&pdev->dev, "atmel pinctrl initialized\n"); + + return 0; + +clk_prepare_enable_error: + irq_domain_remove(atmel_pioctrl->irq_domain); +pinctrl_register_error: + clk_disable_unprepare(atmel_pioctrl->clk); +gpiochip_add_error: + pinctrl_unregister(atmel_pioctrl->pinctrl_dev); +gpiochip_add_pin_range_error: + gpiochip_remove(atmel_pioctrl->gpio_chip); + + return ret; +} + +int atmel_pinctrl_remove(struct platform_device *pdev) +{ + struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev); + + irq_domain_remove(atmel_pioctrl->irq_domain); + clk_disable_unprepare(atmel_pioctrl->clk); + pinctrl_unregister(atmel_pioctrl->pinctrl_dev); + gpiochip_remove(atmel_pioctrl->gpio_chip); + + return 0; +} + +static struct platform_driver atmel_pinctrl_driver = { + .driver = { + .name = "pinctrl-at91-pio4", + .of_match_table = atmel_pctrl_of_match, + }, + .probe = atmel_pinctrl_probe, + .remove = atmel_pinctrl_remove, +}; +module_platform_driver(atmel_pinctrl_driver); + +MODULE_AUTHOR(Ludovic Desroches ); +MODULE_DESCRIPTION("Atmel PIO4 pinctrl driver"); +MODULE_LICENSE("GPL v2"); From 9c077e31f52122ba76005d24fa932e283e9427c3 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Fri, 25 Sep 2015 11:14:09 +0200 Subject: [PATCH 218/381] pinctrl: at91-pio4: add PM stuff Allow GPIOs to be configured as wakeup sources. When going to suspend, disable all GPIO irqs excepting the one configured as wakeup sources. Signed-off-by: Ludovic Desroches Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91-pio4.c | 76 +++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/drivers/pinctrl/pinctrl-at91-pio4.c b/drivers/pinctrl/pinctrl-at91-pio4.c index 6aff632aaa46bc..5e2189f17fe175 100644 --- a/drivers/pinctrl/pinctrl-at91-pio4.c +++ b/drivers/pinctrl/pinctrl-at91-pio4.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -122,6 +123,8 @@ struct atmel_pioctrl { struct gpio_chip *gpio_chip; struct irq_domain *irq_domain; int *irqs; + unsigned *pm_wakeup_sources; + unsigned *pm_suspend_backup; struct device *dev; struct device_node *node; }; @@ -214,12 +217,35 @@ static void atmel_gpio_irq_unmask(struct irq_data *d) BIT(pin->line)); } +#ifdef CONFIG_PM_SLEEP + +static int atmel_gpio_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct atmel_pioctrl *atmel_pioctrl = irq_data_get_irq_chip_data(d); + int bank = ATMEL_PIO_BANK(d->hwirq); + int line = ATMEL_PIO_LINE(d->hwirq); + + /* The gpio controller has one interrupt line per bank. */ + irq_set_irq_wake(atmel_pioctrl->irqs[bank], on); + + if (on) + atmel_pioctrl->pm_wakeup_sources[bank] |= BIT(line); + else + atmel_pioctrl->pm_wakeup_sources[bank] &= ~(BIT(line)); + + return 0; +} +#else +#define atmel_gpio_irq_set_wake NULL +#endif /* CONFIG_PM_SLEEP */ + static struct irq_chip atmel_gpio_irq_chip = { .name = "GPIO", .irq_ack = atmel_gpio_irq_ack, .irq_mask = atmel_gpio_irq_mask, .irq_unmask = atmel_gpio_irq_unmask, .irq_set_type = atmel_gpio_irq_set_type, + .irq_set_wake = atmel_gpio_irq_set_wake, }; static void atmel_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) @@ -792,6 +818,43 @@ static struct pinctrl_desc atmel_pinctrl_desc = { .pmxops = &atmel_pmxops, }; +static int atmel_pctrl_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev); + int i; + + /* + * For each bank, save IMR to restore it later and disable all GPIO + * interrupts excepting the ones marked as wakeup sources. + */ + for (i = 0; i < atmel_pioctrl->nbanks; i++) { + atmel_pioctrl->pm_suspend_backup[i] = + atmel_gpio_read(atmel_pioctrl, i, ATMEL_PIO_IMR); + atmel_gpio_write(atmel_pioctrl, i, ATMEL_PIO_IDR, + ~atmel_pioctrl->pm_wakeup_sources[i]); + } + + return 0; +} + +static int atmel_pctrl_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < atmel_pioctrl->nbanks; i++) + atmel_gpio_write(atmel_pioctrl, i, ATMEL_PIO_IER, + atmel_pioctrl->pm_suspend_backup[i]); + + return 0; +} + +static const struct dev_pm_ops atmel_pctrl_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(atmel_pctrl_suspend, atmel_pctrl_resume) +}; + /* * The number of banks can be different from a SoC to another one. * We can have up to 16 banks. @@ -908,6 +971,18 @@ static int atmel_pinctrl_probe(struct platform_device *pdev) atmel_pioctrl->gpio_chip->dev = dev; atmel_pioctrl->gpio_chip->names = atmel_pioctrl->group_names; + atmel_pioctrl->pm_wakeup_sources = devm_kzalloc(dev, + sizeof(*atmel_pioctrl->pm_wakeup_sources) + * atmel_pioctrl->nbanks, GFP_KERNEL); + if (!atmel_pioctrl->pm_wakeup_sources) + return -ENOMEM; + + atmel_pioctrl->pm_suspend_backup = devm_kzalloc(dev, + sizeof(*atmel_pioctrl->pm_suspend_backup) + * atmel_pioctrl->nbanks, GFP_KERNEL); + if (!atmel_pioctrl->pm_suspend_backup) + return -ENOMEM; + atmel_pioctrl->irqs = devm_kzalloc(dev, sizeof(*atmel_pioctrl->irqs) * atmel_pioctrl->nbanks, GFP_KERNEL); if (!atmel_pioctrl->irqs) @@ -1006,6 +1081,7 @@ static struct platform_driver atmel_pinctrl_driver = { .driver = { .name = "pinctrl-at91-pio4", .of_match_table = atmel_pctrl_of_match, + .pm = &atmel_pctrl_pm_ops, }, .probe = atmel_pinctrl_probe, .remove = atmel_pinctrl_remove, From 87a05c4928c5095969254877ee0b3d83cd14d866 Mon Sep 17 00:00:00 2001 From: Patrick Doyle Date: Fri, 16 Oct 2015 12:39:05 +0200 Subject: [PATCH 219/381] ARM: at91: pm: at91_pm_suspend_in_sram() must be 8-byte aligned fncpy() requires that the source and the destination are both 8-byte aligned. Signed-off-by: Patrick Doyle Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Fixes: d94e688cae56 ("ARM: at91/pm: move the copying the sram function to the sram initialization phase") Cc: # 4.1+ --- arch/arm/mach-at91/pm_suspend.S | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/mach-at91/pm_suspend.S b/arch/arm/mach-at91/pm_suspend.S index 0d95f488b47a7f..a25defda3d226c 100644 --- a/arch/arm/mach-at91/pm_suspend.S +++ b/arch/arm/mach-at91/pm_suspend.S @@ -80,6 +80,8 @@ tmp2 .req r5 * @r2: base address of second SDRAM Controller or 0 if not present * @r3: pm information */ +/* at91_pm_suspend_in_sram must be 8-byte aligned per the requirements of fncpy() */ + .align 3 ENTRY(at91_pm_suspend_in_sram) /* Save registers on stack */ stmfd sp!, {r4 - r12, lr} From 5f9129b257d03733c64ada31726418080e0bdd17 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Wed, 21 Oct 2015 15:44:03 +0200 Subject: [PATCH 220/381] i2c: at91: fix write transfers by clearing pending interrupt first In some cases a NACK interrupt may be pending in the Status Register (SR) as a result of a previous transfer. However at91_do_twi_transfer() did not read the SR to clear pending interruptions before starting a new transfer. Hence a NACK interrupt rose as soon as it was enabled again at the I2C controller level, resulting in a wrong sequence of operations and strange patterns of behaviour on the I2C bus, such as a clock stretch followed by a restart of the transfer. This first issue occurred with both DMA and PIO write transfers. Also when a NACK error was detected during a PIO write transfer, the interrupt handler used to wrongly start a new transfer by writing into the Transmit Holding Register (THR). Then the I2C slave was likely to reply with a second NACK. This second issue is fixed in atmel_twi_interrupt() by handling the TXRDY status bit only if both the TXCOMP and NACK status bits are cleared. Tested with a at24 eeprom on sama5d36ek board running a linux-4.1-at91 kernel image. Adapted to linux-next. Signed-off-by: Cyrille Pitchen Fixes: 93563a6a71bb ("i2c: at91: fix a race condition when using the DMA controller") Reported-by: Peter Rosin Signed-off-by: Ludovic Desroches Tested-by: Peter Rosin Cc: stable@vger.kernel.org #4.1 --- drivers/i2c/busses/i2c-at91.c | 58 ++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 06e66ef9b73ae6..9a6deefd98a576 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -469,19 +469,57 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) 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; + /* + * When a NACK condition is detected, the I2C controller sets the NACK, + * TXCOMP and TXRDY bits all together in the Status Register (SR). + * + * 1 - Handling NACK errors with CPU write transfer. + * + * In such case, we should not write the next byte into the Transmit + * Holding Register (THR) otherwise the I2C controller would start a new + * transfer and the I2C slave is likely to reply by another NACK. + * + * 2 - Handling NACK errors with DMA write transfer. + * + * By setting the TXRDY bit in the SR, the I2C controller also triggers + * the DMA controller to write the next data into the THR. Then the + * result depends on the hardware version of the I2C controller. + * + * 2a - Without support of the Alternative Command mode. + * + * This is the worst case: the DMA controller is triggered to write the + * next data into the THR, hence starting a new transfer: the I2C slave + * is likely to reply by another NACK. + * Concurrently, this interrupt handler is likely to be called to manage + * the first NACK before the I2C controller detects the second NACK and + * sets once again the NACK bit into the SR. + * When handling the first NACK, this interrupt handler disables the I2C + * controller interruptions, especially the NACK interrupt. + * Hence, the NACK bit is pending into the SR. This is why we should + * read the SR to clear all pending interrupts at the beginning of + * at91_do_twi_transfer() before actually starting a new transfer. + * + * 2b - With support of the Alternative Command mode. + * + * When a NACK condition is detected, the I2C controller also locks the + * THR (and sets the LOCK bit in the SR): even though the DMA controller + * is triggered by the TXRDY bit to write the next data into the THR, + * this data actually won't go on the I2C bus hence a second NACK is not + * generated. + */ if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) { at91_disable_twi_interrupts(dev); complete(&dev->cmd_complete); + } 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; + return IRQ_HANDLED; } @@ -491,6 +529,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) unsigned long time_left; bool has_unre_flag = dev->pdata->has_unre_flag; bool has_alt_cmd = dev->pdata->has_alt_cmd; + unsigned sr; /* * WARNING: the TXCOMP bit in the Status Register is NOT a clear on @@ -541,6 +580,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) reinit_completion(&dev->cmd_complete); dev->transfer_status = 0; + /* Clear pending interrupts, such as NACK. */ + sr = at91_twi_read(dev, AT91_TWI_SR); + if (dev->fifo_size) { unsigned fifo_mr = at91_twi_read(dev, AT91_TWI_FMR); @@ -562,7 +604,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; - if (at91_twi_read(dev, AT91_TWI_SR) & AT91_TWI_RXRDY) { + if (sr & AT91_TWI_RXRDY) { dev_err(dev->dev, "RXRDY still set!"); at91_twi_read(dev, AT91_TWI_RHR); } From f2b19c6bb71d2aa7f7039391511dacaba3e0801d Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 21 Oct 2015 15:44:04 +0200 Subject: [PATCH 221/381] i2c: at91: manage unexpected RXRDY flag when starting a transfer In some cases, we could start a new i2c transfer with the RXRDY flag set. It is not a clean state and it leads to print annoying error messages even if there no real issue. The cause is only having garbage data in the Receive Holding Register because of a weird behavior of the RXRDY flag. Signed-off-by: Ludovic Desroches Fixes: 93563a6a71bb ("i2c: at91: fix a race condition when using the DMA controller") Reported-by: Peter Rosin Tested-by: Peter Rosin Cc: stable@vger.kernel.org #4.1 --- drivers/i2c/busses/i2c-at91.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 9a6deefd98a576..c4fbefb4460912 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -351,8 +351,14 @@ static void at91_twi_write_data_dma(struct at91_twi_dev *dev) static void at91_twi_read_next_byte(struct at91_twi_dev *dev) { - if (!dev->buf_len) + /* + * If we are in this case, it means there is garbage data in RHR, so + * delete them. + */ + if (!dev->buf_len) { + at91_twi_read(dev, AT91_TWI_RHR); return; + } /* 8bit read works with and without FIFO */ *dev->buf = readb_relaxed(dev->base + AT91_TWI_RHR); @@ -469,6 +475,24 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) if (!irqstatus) return IRQ_NONE; + /* + * In reception, the behavior of the twi device (before sama5d2) is + * weird. There is some magic about RXRDY flag! When a data has been + * almost received, the reception of a new one is anticipated if there + * is no stop command to send. That is the reason why ask for sending + * the stop command not on the last data but on the second last one. + * + * Unfortunately, we could still have the RXRDY flag set even if the + * transfer is done and we have read the last data. It might happen + * when the i2c slave device sends too quickly data after receiving the + * ack from the master. The data has been almost received before having + * the order to send stop. In this case, sending the stop command could + * cause a RXRDY interrupt with a TXCOMP one. It is better to manage + * the RXRDY interrupt first in order to not keep garbage data in the + * Receive Holding Register for the next transfer. + */ + if (irqstatus & AT91_TWI_RXRDY) + at91_twi_read_next_byte(dev); /* * When a NACK condition is detected, the I2C controller sets the NACK, @@ -511,8 +535,6 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id) if (irqstatus & (AT91_TWI_TXCOMP | AT91_TWI_NACK)) { at91_disable_twi_interrupts(dev); complete(&dev->cmd_complete); - } else if (irqstatus & AT91_TWI_RXRDY) { - at91_twi_read_next_byte(dev); } else if (irqstatus & AT91_TWI_TXRDY) { at91_twi_write_next_byte(dev); } @@ -604,11 +626,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) } else if (dev->msg->flags & I2C_M_RD) { unsigned start_flags = AT91_TWI_START; - if (sr & AT91_TWI_RXRDY) { - dev_err(dev->dev, "RXRDY still set!"); - at91_twi_read(dev, AT91_TWI_RHR); - } - /* if only one byte is to be read, immediately stop transfer */ if (!has_alt_cmd && dev->buf_len <= 1 && !(dev->msg->flags & I2C_M_RECV_LEN)) From 8c5032a42cc3d008b6beaee8a9483d7f23bc3c70 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Apr 2015 04:01:33 -0300 Subject: [PATCH 222/381] [media] v4l2: replace enum_mbus_fmt by enum_mbus_code Replace all calls to the enum_mbus_fmt video op by the pad enum_mbus_code op and remove the duplicate video op. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Acked-by: Scott Jiang Cc: Jonathan Corbet Cc: Kamil Debski Acked-by: Prabhakar Lad Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7170.c | 15 +++++++---- drivers/media/i2c/adv7175.c | 15 +++++++---- drivers/media/i2c/adv7183.c | 15 +++++++---- drivers/media/i2c/adv7842.c | 11 ++++---- drivers/media/i2c/ak881x.c | 15 +++++++---- drivers/media/i2c/ml86v7667.c | 15 +++++++---- drivers/media/i2c/mt9v011.c | 15 +++++++---- drivers/media/i2c/ov7670.c | 11 ++++---- drivers/media/i2c/soc_camera/imx074.c | 16 +++++++---- drivers/media/i2c/soc_camera/mt9m001.c | 15 +++++++---- drivers/media/i2c/soc_camera/mt9m111.c | 15 +++++++---- drivers/media/i2c/soc_camera/mt9t031.c | 15 +++++++---- drivers/media/i2c/soc_camera/mt9t112.c | 15 +++++++---- drivers/media/i2c/soc_camera/mt9v022.c | 15 +++++++---- drivers/media/i2c/soc_camera/ov2640.c | 15 +++++++---- drivers/media/i2c/soc_camera/ov5642.c | 15 +++++++---- drivers/media/i2c/soc_camera/ov6650.c | 15 +++++++---- drivers/media/i2c/soc_camera/ov772x.c | 15 +++++++---- drivers/media/i2c/soc_camera/ov9640.c | 15 +++++++---- drivers/media/i2c/soc_camera/ov9740.c | 19 ++++++++----- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 15 +++++++---- drivers/media/i2c/soc_camera/tw9910.c | 15 +++++++---- drivers/media/i2c/sr030pc30.c | 16 +++++++---- drivers/media/i2c/tvp514x.c | 20 -------------- drivers/media/i2c/tvp5150.c | 15 +++++++---- drivers/media/i2c/tvp7002.c | 20 -------------- drivers/media/i2c/vs6624.c | 15 +++++++---- .../media/platform/blackfin/bfin_capture.c | 17 +++++++----- drivers/media/platform/soc_camera/atmel-isi.c | 19 +++++++------ .../media/platform/soc_camera/mx2_camera.c | 27 ++++++++++--------- .../media/platform/soc_camera/mx3_camera.c | 23 +++++++++------- .../media/platform/soc_camera/omap1_camera.c | 21 ++++++++------- .../media/platform/soc_camera/pxa_camera.c | 19 +++++++------ drivers/media/platform/soc_camera/rcar_vin.c | 19 +++++++------ .../soc_camera/sh_mobile_ceu_camera.c | 19 +++++++------ .../media/platform/soc_camera/soc_camera.c | 15 +++++++---- .../platform/soc_camera/soc_camera_platform.c | 15 +++++++---- include/media/v4l2-subdev.h | 4 --- 38 files changed, 361 insertions(+), 250 deletions(-) diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c index 40a1a95c7ce977..cfe963b2fe1c7d 100644 --- a/drivers/media/i2c/adv7170.c +++ b/drivers/media/i2c/adv7170.c @@ -262,13 +262,14 @@ static int adv7170_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7170_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(adv7170_codes)) + if (code->pad || code->index >= ARRAY_SIZE(adv7170_codes)) return -EINVAL; - *code = adv7170_codes[index]; + code->code = adv7170_codes[code->index]; return 0; } @@ -323,11 +324,15 @@ static const struct v4l2_subdev_video_ops adv7170_video_ops = { .s_routing = adv7170_s_routing, .s_mbus_fmt = adv7170_s_fmt, .g_mbus_fmt = adv7170_g_fmt, - .enum_mbus_fmt = adv7170_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops adv7170_pad_ops = { + .enum_mbus_code = adv7170_enum_mbus_code, }; static const struct v4l2_subdev_ops adv7170_ops = { .video = &adv7170_video_ops, + .pad = &adv7170_pad_ops, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c index d220af579a640e..3f40304e856cbd 100644 --- a/drivers/media/i2c/adv7175.c +++ b/drivers/media/i2c/adv7175.c @@ -300,13 +300,14 @@ static int adv7175_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7175_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(adv7175_codes)) + if (code->pad || code->index >= ARRAY_SIZE(adv7175_codes)) return -EINVAL; - *code = adv7175_codes[index]; + code->code = adv7175_codes[code->index]; return 0; } @@ -376,12 +377,16 @@ static const struct v4l2_subdev_video_ops adv7175_video_ops = { .s_routing = adv7175_s_routing, .s_mbus_fmt = adv7175_s_fmt, .g_mbus_fmt = adv7175_g_fmt, - .enum_mbus_fmt = adv7175_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops adv7175_pad_ops = { + .enum_mbus_code = adv7175_enum_mbus_code, }; static const struct v4l2_subdev_ops adv7175_ops = { .core = &adv7175_core_ops, .video = &adv7175_video_ops, + .pad = &adv7175_pad_ops, }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 28940cc3a76652..a0bcfefc28fcdb 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -420,13 +420,14 @@ static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } -static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int adv7183_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->pad || code->index > 0) return -EINVAL; - *code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } @@ -514,16 +515,20 @@ static const struct v4l2_subdev_video_ops adv7183_video_ops = { .s_routing = adv7183_s_routing, .querystd = adv7183_querystd, .g_input_status = adv7183_g_input_status, - .enum_mbus_fmt = adv7183_enum_mbus_fmt, .try_mbus_fmt = adv7183_try_mbus_fmt, .s_mbus_fmt = adv7183_s_mbus_fmt, .g_mbus_fmt = adv7183_g_mbus_fmt, .s_stream = adv7183_s_stream, }; +static const struct v4l2_subdev_pad_ops adv7183_pad_ops = { + .enum_mbus_code = adv7183_enum_mbus_code, +}; + static const struct v4l2_subdev_ops adv7183_ops = { .core = &adv7183_core_ops, .video = &adv7183_video_ops, + .pad = &adv7183_pad_ops, }; static int adv7183_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index b5a37fe10a6a5d..644e910f9d8a91 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1867,13 +1867,14 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, return 0; } -static int adv7842_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int adv7842_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; /* Good enough for now */ - *code = MEDIA_BUS_FMT_FIXED; + code->code = MEDIA_BUS_FMT_FIXED; return 0; } @@ -2809,7 +2810,6 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { .s_dv_timings = adv7842_s_dv_timings, .g_dv_timings = adv7842_g_dv_timings, .query_dv_timings = adv7842_query_dv_timings, - .enum_mbus_fmt = adv7842_enum_mbus_fmt, .g_mbus_fmt = adv7842_g_mbus_fmt, .try_mbus_fmt = adv7842_g_mbus_fmt, .s_mbus_fmt = adv7842_g_mbus_fmt, @@ -2820,6 +2820,7 @@ static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { .set_edid = adv7842_set_edid, .enum_dv_timings = adv7842_enum_dv_timings, .dv_timings_cap = adv7842_dv_timings_cap, + .enum_mbus_code = adv7842_enum_mbus_code, }; static const struct v4l2_subdev_ops adv7842_ops = { diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index 69aeaf3976248a..4428fb95d0333e 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -118,13 +118,14 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, return ak881x_try_g_mbus_fmt(sd, mf); } -static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ak881x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_YUYV8_2X8; + code->code = MEDIA_BUS_FMT_YUYV8_2X8; return 0; } @@ -215,14 +216,18 @@ static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { .g_mbus_fmt = ak881x_try_g_mbus_fmt, .try_mbus_fmt = ak881x_try_g_mbus_fmt, .cropcap = ak881x_cropcap, - .enum_mbus_fmt = ak881x_enum_mbus_fmt, .s_std_output = ak881x_s_std_output, .s_stream = ak881x_s_stream, }; +static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = { + .enum_mbus_code = ak881x_enum_mbus_code, +}; + static struct v4l2_subdev_ops ak881x_subdev_ops = { .core = &ak881x_subdev_core_ops, .video = &ak881x_subdev_video_ops, + .pad = &ak881x_subdev_pad_ops, }; static int ak881x_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c index d7307862c2c5e7..e7b220239d3094 100644 --- a/drivers/media/i2c/ml86v7667.c +++ b/drivers/media/i2c/ml86v7667.c @@ -191,13 +191,14 @@ static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } -static int ml86v7667_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->pad || code->index > 0) return -EINVAL; - *code = MEDIA_BUS_FMT_YUYV8_2X8; + code->code = MEDIA_BUS_FMT_YUYV8_2X8; return 0; } @@ -279,13 +280,16 @@ static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = { .s_std = ml86v7667_s_std, .querystd = ml86v7667_querystd, .g_input_status = ml86v7667_g_input_status, - .enum_mbus_fmt = ml86v7667_enum_mbus_fmt, .try_mbus_fmt = ml86v7667_mbus_fmt, .g_mbus_fmt = ml86v7667_mbus_fmt, .s_mbus_fmt = ml86v7667_mbus_fmt, .g_mbus_config = ml86v7667_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = { + .enum_mbus_code = ml86v7667_enum_mbus_code, +}; + static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = ml86v7667_g_register, @@ -296,6 +300,7 @@ static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { static struct v4l2_subdev_ops ml86v7667_subdev_ops = { .core = &ml86v7667_subdev_core_ops, .video = &ml86v7667_subdev_video_ops, + .pad = &ml86v7667_subdev_pad_ops, }; static int ml86v7667_init(struct ml86v7667_priv *priv) diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index a10f7f8f05587f..6fae8fce461783 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -324,13 +324,14 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val) return 0; } -static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index > 0) + if (code->pad || code->index > 0) return -EINVAL; - *code = MEDIA_BUS_FMT_SGRBG8_1X8; + code->code = MEDIA_BUS_FMT_SGRBG8_1X8; return 0; } @@ -469,16 +470,20 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .enum_mbus_fmt = mt9v011_enum_mbus_fmt, .try_mbus_fmt = mt9v011_try_mbus_fmt, .s_mbus_fmt = mt9v011_s_mbus_fmt, .g_parm = mt9v011_g_parm, .s_parm = mt9v011_s_parm, }; +static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = { + .enum_mbus_code = mt9v011_enum_mbus_code, +}; + static const struct v4l2_subdev_ops mt9v011_ops = { .core = &mt9v011_core_ops, .video = &mt9v011_video_ops, + .pad = &mt9v011_pad_ops, }; diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index b9847527eb5a38..1033bd793fefc2 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -899,13 +899,14 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop, } -static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int ov7670_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= N_OV7670_FMTS) + if (code->pad || code->index >= N_OV7670_FMTS) return -EINVAL; - *code = ov7670_formats[index].mbus_code; + code->code = ov7670_formats[code->index].mbus_code; return 0; } @@ -1485,7 +1486,6 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = { }; static const struct v4l2_subdev_video_ops ov7670_video_ops = { - .enum_mbus_fmt = ov7670_enum_mbus_fmt, .try_mbus_fmt = ov7670_try_mbus_fmt, .s_mbus_fmt = ov7670_s_mbus_fmt, .s_parm = ov7670_s_parm, @@ -1495,6 +1495,7 @@ static const struct v4l2_subdev_video_ops ov7670_video_ops = { static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { .enum_frame_interval = ov7670_enum_frame_interval, .enum_frame_size = ov7670_enum_frame_size, + .enum_mbus_code = ov7670_enum_mbus_code, }; static const struct v4l2_subdev_ops ov7670_ops = { diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index ec89cfa927a2e8..7a2d90654fee28 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c @@ -235,13 +235,15 @@ static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int imx074_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts)) + if (code->pad || + (unsigned int)code->index >= ARRAY_SIZE(imx074_colour_fmts)) return -EINVAL; - *code = imx074_colour_fmts[index].code; + code->code = imx074_colour_fmts[code->index].code; return 0; } @@ -278,7 +280,6 @@ static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { .s_mbus_fmt = imx074_s_fmt, .g_mbus_fmt = imx074_g_fmt, .try_mbus_fmt = imx074_try_fmt, - .enum_mbus_fmt = imx074_enum_fmt, .g_crop = imx074_g_crop, .cropcap = imx074_cropcap, .g_mbus_config = imx074_g_mbus_config, @@ -288,9 +289,14 @@ static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { .s_power = imx074_s_power, }; +static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { + .enum_mbus_code = imx074_enum_mbus_code, +}; + static struct v4l2_subdev_ops imx074_subdev_ops = { .core = &imx074_subdev_core_ops, .video = &imx074_subdev_video_ops, + .pad = &imx074_subdev_pad_ops, }; static int imx074_video_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 2e9a53502551b1..ba18e010b9da87 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -562,16 +562,17 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = { .s_power = mt9m001_s_power, }; -static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); - if (index >= mt9m001->num_fmts) + if (code->pad || code->index >= mt9m001->num_fmts) return -EINVAL; - *code = mt9m001->fmts[index].code; + code->code = mt9m001->fmts[code->index].code; return 0; } @@ -617,7 +618,6 @@ static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_crop = mt9m001_s_crop, .g_crop = mt9m001_g_crop, .cropcap = mt9m001_cropcap, - .enum_mbus_fmt = mt9m001_enum_fmt, .g_mbus_config = mt9m001_g_mbus_config, .s_mbus_config = mt9m001_s_mbus_config, }; @@ -626,10 +626,15 @@ static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { .g_skip_top_lines = mt9m001_g_skip_top_lines, }; +static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { + .enum_mbus_code = mt9m001_enum_mbus_code, +}; + static struct v4l2_subdev_ops mt9m001_subdev_ops = { .core = &mt9m001_subdev_core_ops, .video = &mt9m001_subdev_video_ops, .sensor = &mt9m001_subdev_sensor_ops, + .pad = &mt9m001_subdev_pad_ops, }; static int mt9m001_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 441e0fda24fea3..b7731401dc39c2 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -839,13 +839,14 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = { #endif }; -static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9m111_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(mt9m111_colour_fmts)) + if (code->pad || code->index >= ARRAY_SIZE(mt9m111_colour_fmts)) return -EINVAL; - *code = mt9m111_colour_fmts[index].code; + code->code = mt9m111_colour_fmts[code->index].code; return 0; } @@ -871,13 +872,17 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { .s_crop = mt9m111_s_crop, .g_crop = mt9m111_g_crop, .cropcap = mt9m111_cropcap, - .enum_mbus_fmt = mt9m111_enum_fmt, .g_mbus_config = mt9m111_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { + .enum_mbus_code = mt9m111_enum_mbus_code, +}; + static struct v4l2_subdev_ops mt9m111_subdev_ops = { .core = &mt9m111_subdev_core_ops, .video = &mt9m111_subdev_video_ops, + .pad = &mt9m111_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 35d9c8d255898d..15ac4dc2996746 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -672,13 +672,14 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = { #endif }; -static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9t031_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_SBGGR10_1X10; + code->code = MEDIA_BUS_FMT_SBGGR10_1X10; return 0; } @@ -718,7 +719,6 @@ static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .s_crop = mt9t031_s_crop, .g_crop = mt9t031_g_crop, .cropcap = mt9t031_cropcap, - .enum_mbus_fmt = mt9t031_enum_fmt, .g_mbus_config = mt9t031_g_mbus_config, .s_mbus_config = mt9t031_s_mbus_config, }; @@ -727,10 +727,15 @@ static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { .g_skip_top_lines = mt9t031_g_skip_top_lines, }; +static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { + .enum_mbus_code = mt9t031_enum_mbus_code, +}; + static struct v4l2_subdev_ops mt9t031_subdev_ops = { .core = &mt9t031_subdev_core_ops, .video = &mt9t031_subdev_video_ops, .sensor = &mt9t031_subdev_sensor_ops, + .pad = &mt9t031_subdev_pad_ops, }; static int mt9t031_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 64f08365e6b2f8..8b0cfb7f80b182 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -966,16 +966,17 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9t112_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); - if (index >= priv->num_formats) + if (code->pad || code->index >= priv->num_formats) return -EINVAL; - *code = mt9t112_cfmts[index].code; + code->code = mt9t112_cfmts[code->index].code; return 0; } @@ -1016,17 +1017,21 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .cropcap = mt9t112_cropcap, .g_crop = mt9t112_g_crop, .s_crop = mt9t112_s_crop, - .enum_mbus_fmt = mt9t112_enum_fmt, .g_mbus_config = mt9t112_g_mbus_config, .s_mbus_config = mt9t112_s_mbus_config, }; +static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { + .enum_mbus_code = mt9t112_enum_mbus_code, +}; + /************************************************************************ i2c driver ************************************************************************/ static struct v4l2_subdev_ops mt9t112_subdev_ops = { .core = &mt9t112_subdev_core_ops, .video = &mt9t112_subdev_video_ops, + .pad = &mt9t112_subdev_pad_ops, }; static int mt9t112_camera_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index a246d4d64b8b0c..780c7ae74d698e 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -758,16 +758,17 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = { .s_power = mt9v022_s_power, }; -static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int mt9v022_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); - if (index >= mt9v022->num_fmts) + if (code->pad || code->index >= mt9v022->num_fmts) return -EINVAL; - *code = mt9v022->fmts[index].code; + code->code = mt9v022->fmts[code->index].code; return 0; } @@ -845,7 +846,6 @@ static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .s_crop = mt9v022_s_crop, .g_crop = mt9v022_g_crop, .cropcap = mt9v022_cropcap, - .enum_mbus_fmt = mt9v022_enum_fmt, .g_mbus_config = mt9v022_g_mbus_config, .s_mbus_config = mt9v022_s_mbus_config, }; @@ -854,10 +854,15 @@ static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { .g_skip_top_lines = mt9v022_g_skip_top_lines, }; +static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { + .enum_mbus_code = mt9v022_enum_mbus_code, +}; + static struct v4l2_subdev_ops mt9v022_subdev_ops = { .core = &mt9v022_subdev_core_ops, .video = &mt9v022_subdev_video_ops, .sensor = &mt9v022_subdev_sensor_ops, + .pad = &mt9v022_subdev_pad_ops, }; static int mt9v022_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index e3c907a977651a..4327871c8f9f4a 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -925,13 +925,14 @@ static int ov2640_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov2640_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes)) return -EINVAL; - *code = ov2640_codes[index]; + code->code = ov2640_codes[code->index]; return 0; } @@ -1036,13 +1037,17 @@ static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { .try_mbus_fmt = ov2640_try_fmt, .cropcap = ov2640_cropcap, .g_crop = ov2640_g_crop, - .enum_mbus_fmt = ov2640_enum_fmt, .g_mbus_config = ov2640_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { + .enum_mbus_code = ov2640_enum_mbus_code, +}; + static struct v4l2_subdev_ops ov2640_subdev_ops = { .core = &ov2640_subdev_core_ops, .video = &ov2640_subdev_video_ops, + .pad = &ov2640_subdev_pad_ops, }; /* OF probe functions */ diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index 93ae031bdafb19..fcddd0ded2e3db 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -839,13 +839,14 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd, return 0; } -static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov5642_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov5642_colour_fmts)) + if (code->pad || code->index >= ARRAY_SIZE(ov5642_colour_fmts)) return -EINVAL; - *code = ov5642_colour_fmts[index].code; + code->code = ov5642_colour_fmts[code->index].code; return 0; } @@ -942,13 +943,16 @@ static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { .s_mbus_fmt = ov5642_s_fmt, .g_mbus_fmt = ov5642_g_fmt, .try_mbus_fmt = ov5642_try_fmt, - .enum_mbus_fmt = ov5642_enum_fmt, .s_crop = ov5642_s_crop, .g_crop = ov5642_g_crop, .cropcap = ov5642_cropcap, .g_mbus_config = ov5642_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { + .enum_mbus_code = ov5642_enum_mbus_code, +}; + static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { .s_power = ov5642_s_power, #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -960,6 +964,7 @@ static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { static struct v4l2_subdev_ops ov5642_subdev_ops = { .core = &ov5642_subdev_core_ops, .video = &ov5642_subdev_video_ops, + .pad = &ov5642_subdev_pad_ops, }; static int ov5642_video_probe(struct i2c_client *client) diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index f4eef2fa6f6f55..99e0738fdb38c1 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -716,13 +716,14 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov6650_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov6650_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov6650_codes)) return -EINVAL; - *code = ov6650_codes[index]; + code->code = ov6650_codes[code->index]; return 0; } @@ -932,7 +933,6 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { .g_mbus_fmt = ov6650_g_fmt, .s_mbus_fmt = ov6650_s_fmt, .try_mbus_fmt = ov6650_try_fmt, - .enum_mbus_fmt = ov6650_enum_fmt, .cropcap = ov6650_cropcap, .g_crop = ov6650_g_crop, .s_crop = ov6650_s_crop, @@ -942,9 +942,14 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_mbus_config = ov6650_s_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { + .enum_mbus_code = ov6650_enum_mbus_code, +}; + static struct v4l2_subdev_ops ov6650_subdev_ops = { .core = &ov6650_core_ops, .video = &ov6650_video_ops, + .pad = &ov6650_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 8daac88b33fef2..e3a31f80663629 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -989,13 +989,14 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = { .s_power = ov772x_s_power, }; -static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov772x_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov772x_cfmts)) + if (code->pad || code->index >= ARRAY_SIZE(ov772x_cfmts)) return -EINVAL; - *code = ov772x_cfmts[index].code; + code->code = ov772x_cfmts[code->index].code; return 0; } @@ -1021,13 +1022,17 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .try_mbus_fmt = ov772x_try_fmt, .cropcap = ov772x_cropcap, .g_crop = ov772x_g_crop, - .enum_mbus_fmt = ov772x_enum_fmt, .g_mbus_config = ov772x_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { + .enum_mbus_code = ov772x_enum_mbus_code, +}; + static struct v4l2_subdev_ops ov772x_subdev_ops = { .core = &ov772x_subdev_core_ops, .video = &ov772x_subdev_video_ops, + .pad = &ov772x_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index aa93d2e88572c7..899b4d9352fe47 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -540,13 +540,14 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov9640_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov9640_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov9640_codes)) return -EINVAL; - *code = ov9640_codes[index]; + code->code = ov9640_codes[code->index]; return 0; } @@ -658,15 +659,19 @@ static struct v4l2_subdev_video_ops ov9640_video_ops = { .s_stream = ov9640_s_stream, .s_mbus_fmt = ov9640_s_fmt, .try_mbus_fmt = ov9640_try_fmt, - .enum_mbus_fmt = ov9640_enum_fmt, .cropcap = ov9640_cropcap, .g_crop = ov9640_g_crop, .g_mbus_config = ov9640_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { + .enum_mbus_code = ov9640_enum_mbus_code, +}; + static struct v4l2_subdev_ops ov9640_subdev_ops = { .core = &ov9640_core_ops, .video = &ov9640_video_ops, + .pad = &ov9640_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 841dc55457cf54..5d9b2492b7d246 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -716,13 +716,14 @@ static int ov9740_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov9740_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov9740_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov9740_codes)) return -EINVAL; - *code = ov9740_codes[index]; + code->code = ov9740_codes[code->index]; return 0; } @@ -906,7 +907,6 @@ static struct v4l2_subdev_video_ops ov9740_video_ops = { .s_stream = ov9740_s_stream, .s_mbus_fmt = ov9740_s_fmt, .try_mbus_fmt = ov9740_try_fmt, - .enum_mbus_fmt = ov9740_enum_fmt, .cropcap = ov9740_cropcap, .g_crop = ov9740_g_crop, .g_mbus_config = ov9740_g_mbus_config, @@ -920,9 +920,14 @@ static struct v4l2_subdev_core_ops ov9740_core_ops = { #endif }; +static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { + .enum_mbus_code = ov9740_enum_mbus_code, +}; + static struct v4l2_subdev_ops ov9740_subdev_ops = { - .core = &ov9740_core_ops, - .video = &ov9740_video_ops, + .core = &ov9740_core_ops, + .video = &ov9740_video_ops, + .pad = &ov9740_pad_ops, }; static const struct v4l2_ctrl_ops ov9740_ctrl_ops = { diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 1752428c43c54c..4927a76d2240ec 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -485,13 +485,14 @@ static int reg_write_multiple(struct i2c_client *client, return 0; } -static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int rj54n1_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(rj54n1_colour_fmts)) + if (code->pad || code->index >= ARRAY_SIZE(rj54n1_colour_fmts)) return -EINVAL; - *code = rj54n1_colour_fmts[index].code; + code->code = rj54n1_colour_fmts[code->index].code; return 0; } @@ -1252,7 +1253,6 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_mbus_fmt = rj54n1_s_fmt, .g_mbus_fmt = rj54n1_g_fmt, .try_mbus_fmt = rj54n1_try_fmt, - .enum_mbus_fmt = rj54n1_enum_fmt, .g_crop = rj54n1_g_crop, .s_crop = rj54n1_s_crop, .cropcap = rj54n1_cropcap, @@ -1260,9 +1260,14 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_mbus_config = rj54n1_s_mbus_config, }; +static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { + .enum_mbus_code = rj54n1_enum_mbus_code, +}; + static struct v4l2_subdev_ops rj54n1_subdev_ops = { .core = &rj54n1_subdev_core_ops, .video = &rj54n1_subdev_video_ops, + .pad = &rj54n1_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 9b853215d1469b..f8c0c713d06c6c 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -821,13 +821,14 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = { .s_power = tw9910_s_power, }; -static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int tw9910_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } @@ -885,15 +886,19 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .try_mbus_fmt = tw9910_try_fmt, .cropcap = tw9910_cropcap, .g_crop = tw9910_g_crop, - .enum_mbus_fmt = tw9910_enum_fmt, .g_mbus_config = tw9910_g_mbus_config, .s_mbus_config = tw9910_s_mbus_config, .g_tvnorms = tw9910_g_tvnorms, }; +static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { + .enum_mbus_code = tw9910_enum_mbus_code, +}; + static struct v4l2_subdev_ops tw9910_subdev_ops = { .core = &tw9910_subdev_core_ops, .video = &tw9910_subdev_video_ops, + .pad = &tw9910_subdev_pad_ops, }; /* diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index 10c735c3a082cb..0a0a1886ee4ca9 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -471,13 +471,15 @@ static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (!code || index >= ARRAY_SIZE(sr030pc30_formats)) + if (!code || code->pad || + code->index >= ARRAY_SIZE(sr030pc30_formats)) return -EINVAL; - *code = sr030pc30_formats[index].code; + code->code = sr030pc30_formats[code->index].code; return 0; } @@ -640,12 +642,16 @@ static const struct v4l2_subdev_video_ops sr030pc30_video_ops = { .g_mbus_fmt = sr030pc30_g_fmt, .s_mbus_fmt = sr030pc30_s_fmt, .try_mbus_fmt = sr030pc30_try_fmt, - .enum_mbus_fmt = sr030pc30_enum_fmt, +}; + +static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { + .enum_mbus_code = sr030pc30_enum_mbus_code, }; static const struct v4l2_subdev_ops sr030pc30_ops = { .core = &sr030pc30_core_ops, .video = &sr030pc30_video_ops, + .pad = &sr030pc30_pad_ops, }; /* diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 1c6bc306ecdcbf..a822d1541614b2 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -746,25 +746,6 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) return err; } -/** - * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @index: index of pixelcode to retrieve - * @code: receives the pixelcode - * - * Enumerates supported mediabus formats - */ -static int -tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) -{ - if (index) - return -EINVAL; - - *code = MEDIA_BUS_FMT_YUYV10_2X10; - return 0; -} - /** * tvp514x_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt * @sd: pointer to standard V4L2 sub-device structure @@ -1016,7 +997,6 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, - .enum_mbus_fmt = tvp514x_enum_mbus_fmt, .g_mbus_fmt = tvp514x_mbus_fmt, .try_mbus_fmt = tvp514x_mbus_fmt, .s_mbus_fmt = tvp514x_mbus_fmt, diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 68cdab9c0903fb..f2f87b73184c4f 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -817,13 +817,14 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd) } } -static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index) + if (code->pad || code->index) return -EINVAL; - *code = MEDIA_BUS_FMT_UYVY8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } @@ -1068,7 +1069,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_std = tvp5150_s_std, .s_routing = tvp5150_s_routing, - .enum_mbus_fmt = tvp5150_enum_mbus_fmt, .s_mbus_fmt = tvp5150_mbus_fmt, .try_mbus_fmt = tvp5150_mbus_fmt, .g_mbus_fmt = tvp5150_mbus_fmt, @@ -1084,11 +1084,16 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { .s_raw_fmt = tvp5150_s_raw_fmt, }; +static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { + .enum_mbus_code = tvp5150_enum_mbus_code, +}; + static const struct v4l2_subdev_ops tvp5150_ops = { .core = &tvp5150_core_ops, .tuner = &tvp5150_tuner_ops, .video = &tvp5150_video_ops, .vbi = &tvp5150_vbi_ops, + .pad = &tvp5150_pad_ops, }; diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 787cdfb0874959..d21fa1a62e41c6 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -746,25 +746,6 @@ static int tvp7002_s_register(struct v4l2_subdev *sd, } #endif -/* - * tvp7002_enum_mbus_fmt() - Enum supported mediabus formats - * @sd: pointer to standard V4L2 sub-device structure - * @index: format index - * @code: pointer to mediabus format - * - * Enumerate supported mediabus formats. - */ - -static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) -{ - /* Check requested format index is within range */ - if (index) - return -EINVAL; - *code = MEDIA_BUS_FMT_YUYV10_1X20; - return 0; -} - /* * tvp7002_s_stream() - V4L2 decoder i/f handler for s_stream * @sd: pointer to standard V4L2 sub-device structure @@ -927,7 +908,6 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = { .g_mbus_fmt = tvp7002_mbus_fmt, .try_mbus_fmt = tvp7002_mbus_fmt, .s_mbus_fmt = tvp7002_mbus_fmt, - .enum_mbus_fmt = tvp7002_enum_mbus_fmt, }; /* media pad related operation handlers */ diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 00e7f043977ed9..b1d0a1b28ca86d 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -557,13 +557,14 @@ static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl) return 0; } -static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, - u32 *code) +static int vs6624_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(vs6624_formats)) + if (code->pad || code->index >= ARRAY_SIZE(vs6624_formats)) return -EINVAL; - *code = vs6624_formats[index].mbus_code; + code->code = vs6624_formats[code->index].mbus_code; return 0; } @@ -738,7 +739,6 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = { }; static const struct v4l2_subdev_video_ops vs6624_video_ops = { - .enum_mbus_fmt = vs6624_enum_mbus_fmt, .try_mbus_fmt = vs6624_try_mbus_fmt, .s_mbus_fmt = vs6624_s_mbus_fmt, .g_mbus_fmt = vs6624_g_mbus_fmt, @@ -747,9 +747,14 @@ static const struct v4l2_subdev_video_ops vs6624_video_ops = { .s_stream = vs6624_s_stream, }; +static const struct v4l2_subdev_pad_ops vs6624_pad_ops = { + .enum_mbus_code = vs6624_enum_mbus_code, +}; + static const struct v4l2_subdev_ops vs6624_ops = { .core = &vs6624_core_ops, .video = &vs6624_video_ops, + .pad = &vs6624_pad_ops, }; static int vs6624_probe(struct i2c_client *client, diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 6a437f86dcdc61..6ea11b1e755e60 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -156,14 +156,18 @@ static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb) static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) { - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct bcap_format *sf; unsigned int num_formats = 0; int i, j; - while (!v4l2_subdev_call(bcap_dev->sd, video, - enum_mbus_fmt, num_formats, &code)) + while (!v4l2_subdev_call(bcap_dev->sd, pad, + enum_mbus_code, NULL, &code)) { num_formats++; + code.index++; + } if (!num_formats) return -ENXIO; @@ -172,10 +176,11 @@ static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) return -ENOMEM; for (i = 0; i < num_formats; i++) { - v4l2_subdev_call(bcap_dev->sd, video, - enum_mbus_fmt, i, &code); + code.index = i; + v4l2_subdev_call(bcap_dev->sd, pad, + enum_mbus_code, NULL, &code); for (j = 0; j < BCAP_MAX_FMTS; j++) - if (code == bcap_formats[j].mbus_code) + if (code.code == bcap_formats[j].mbus_code) break; if (j == BCAP_MAX_FMTS) { /* we don't allow this sensor working with our bridge */ diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index c835beb2a1a8f3..cbb7e22cab40c7 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -648,19 +648,22 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); int formats = 0, ret; /* sensor format */ - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; /* soc camera host format */ const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { dev_err(icd->parent, - "Invalid format code #%u: %d\n", idx, code); + "Invalid format code #%u: %d\n", idx, code.code); return 0; } @@ -672,7 +675,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, return 0; } - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: @@ -680,10 +683,10 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = &isi_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(icd->parent, "Providing format %s using code %d\n", - isi_camera_formats[0].name, code); + isi_camera_formats[0].name, code.code); } break; default: @@ -699,7 +702,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index 192377f55840b5..b891b7f2b7e9d5 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -943,22 +943,25 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_mbus_pixelfmt *fmt; struct device *dev = icd->parent; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; int ret, formats = 0; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* no more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); return 0; } - if (code == MEDIA_BUS_FMT_YUYV8_2X8 || - code == MEDIA_BUS_FMT_UYVY8_2X8) { + if (code.code == MEDIA_BUS_FMT_YUYV8_2X8 || + code.code == MEDIA_BUS_FMT_UYVY8_2X8) { formats++; if (xlate) { /* @@ -967,21 +970,21 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, */ xlate->host_fmt = soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_1_5X8); - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing host format %s for sensor code %d\n", - xlate->host_fmt->name, code); + xlate->host_fmt->name, code.code); xlate++; } } - if (code == MEDIA_BUS_FMT_UYVY8_2X8) { + if (code.code == MEDIA_BUS_FMT_UYVY8_2X8) { formats++; if (xlate) { xlate->host_fmt = soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_2X8); - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing host format %s for sensor code %d\n", - xlate->host_fmt->name, code); + xlate->host_fmt->name, code.code); xlate++; } } @@ -990,7 +993,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } return formats; diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 3435fd2ca8ecd2..a29848976f92a7 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -659,18 +659,21 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; int formats = 0, ret; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { dev_warn(icd->parent, - "Unsupported format code #%u: 0x%x\n", idx, code); + "Unsupported format code #%u: 0x%x\n", idx, code.code); return 0; } @@ -679,25 +682,25 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id if (ret < 0) return 0; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_SBGGR10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code 0x%x\n", - mx3_camera_formats[0].name, code); + mx3_camera_formats[0].name, code.code); } break; case MEDIA_BUS_FMT_Y10_1X10: formats++; if (xlate) { xlate->host_fmt = &mx3_camera_formats[1]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code 0x%x\n", - mx3_camera_formats[1].name, code); + mx3_camera_formats[1].name, code.code); } break; default: @@ -709,7 +712,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing format %c%c%c%c in pass-through mode\n", (fmt->fourcc >> (0*8)) & 0xFF, (fmt->fourcc >> (1*8)) & 0xFF, diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 16f65ecb70a3e1..3f250767d162fe 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1068,18 +1068,21 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; int formats = 0, ret; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { dev_warn(dev, "%s: unsupported format code #%d: %d\n", __func__, - idx, code); + idx, code.code); return 0; } @@ -1087,7 +1090,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, if (fmt->bits_per_sample != 8) return 0; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: case MEDIA_BUS_FMT_UYVY8_2X8: @@ -1098,14 +1101,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, case MEDIA_BUS_FMT_RGB565_2X8_LE: formats++; if (xlate) { - xlate->host_fmt = soc_mbus_find_fmtdesc(code, + xlate->host_fmt = soc_mbus_find_fmtdesc(code.code, omap1_cam_formats, ARRAY_SIZE(omap1_cam_formats)); - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "%s: providing format %s as byte swapped code #%d\n", - __func__, xlate->host_fmt->name, code); + __func__, xlate->host_fmt->name, code.code); } default: if (xlate) @@ -1116,7 +1119,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 8d6e343fec0f28..f6fa0acc525107 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1253,17 +1253,20 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id struct device *dev = icd->parent; int formats = 0, ret; struct pxa_cam *cam; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_err(dev, "Invalid format code #%u: %d\n", idx, code); + dev_err(dev, "Invalid format code #%u: %d\n", idx, code.code); return 0; } @@ -1282,15 +1285,15 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id cam = icd->host_priv; } - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: formats++; if (xlate) { xlate->host_fmt = &pxa_camera_formats[0]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", - pxa_camera_formats[0].name, code); + pxa_camera_formats[0].name, code.code); } case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: @@ -1314,7 +1317,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 6460f8e1b07fc6..2dc8c816abc750 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1323,16 +1323,19 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, int ret, k, n; int formats = 0; struct rcar_vin_cam *cam; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); + dev_warn(dev, "unsupported format code #%u: %d\n", idx, code.code); return 0; } @@ -1413,7 +1416,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, if (!idx) cam->extra_fmt = NULL; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_YUYV8_1X16: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YUYV10_2X10: @@ -1427,9 +1430,9 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, formats += n; for (k = 0; xlate && k < n; k++, xlate++) { xlate->host_fmt = &rcar_vin_formats[k]; - xlate->code = code; + xlate->code = code.code; dev_dbg(dev, "Providing format %s using code %d\n", - rcar_vin_formats[k].name, code); + rcar_vin_formats[k].name, code.code); } break; default: @@ -1445,7 +1448,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; } diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 9ce202f539344a..b4faf8f1fd15e3 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1048,17 +1048,20 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int int ret, k, n; int formats = 0; struct sh_mobile_ceu_cam *cam; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .index = idx, + }; const struct soc_mbus_pixelfmt *fmt; - ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code); + ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); if (ret < 0) /* No more formats */ return 0; - fmt = soc_mbus_get_fmtdesc(code); + fmt = soc_mbus_get_fmtdesc(code.code); if (!fmt) { - dev_warn(dev, "unsupported format code #%u: %d\n", idx, code); + dev_warn(dev, "unsupported format code #%u: %d\n", idx, code.code); return 0; } @@ -1140,7 +1143,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int if (!idx) cam->extra_fmt = NULL; - switch (code) { + switch (code.code) { case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: @@ -1163,10 +1166,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int formats += n; for (k = 0; xlate && k < n; k++) { xlate->host_fmt = &sh_mobile_ceu_formats[k]; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s using code %d\n", - sh_mobile_ceu_formats[k].name, code); + sh_mobile_ceu_formats[k].name, code.code); } break; default: @@ -1178,7 +1181,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int formats++; if (xlate) { xlate->host_fmt = fmt; - xlate->code = code; + xlate->code = code.code; xlate++; dev_dbg(dev, "Providing format %s in pass-through mode\n", fmt->name); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 7bfe7665687fad..7fd49cb009d329 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -484,10 +484,14 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); unsigned int i, fmts = 0, raw_fmts = 0; int ret; - u32 code; + struct v4l2_subdev_mbus_code_enum code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code)) + while (!v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code)) { raw_fmts++; + code.index++; + } if (!ici->ops->get_formats) /* @@ -521,11 +525,12 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd) fmts = 0; for (i = 0; i < raw_fmts; i++) if (!ici->ops->get_formats) { - v4l2_subdev_call(sd, video, enum_mbus_fmt, i, &code); + code.index = i; + v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code); icd->user_formats[fmts].host_fmt = - soc_mbus_get_fmtdesc(code); + soc_mbus_get_fmtdesc(code.code); if (icd->user_formats[fmts].host_fmt) - icd->user_formats[fmts++].code = code; + icd->user_formats[fmts++].code = code.code; } else { ret = ici->ops->get_formats(icd, i, &icd->user_formats[fmts]); diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index f535910b4187db..934b9183cea8d8 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c @@ -61,15 +61,16 @@ static struct v4l2_subdev_core_ops platform_subdev_core_ops = { .s_power = soc_camera_platform_s_power, }; -static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int soc_camera_platform_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); - if (index) + if (code->pad || code->index) return -EINVAL; - *code = p->format.code; + code->code = p->format.code; return 0; } @@ -117,7 +118,6 @@ static int soc_camera_platform_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .s_stream = soc_camera_platform_s_stream, - .enum_mbus_fmt = soc_camera_platform_enum_fmt, .cropcap = soc_camera_platform_cropcap, .g_crop = soc_camera_platform_g_crop, .try_mbus_fmt = soc_camera_platform_fill_fmt, @@ -126,9 +126,14 @@ static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .g_mbus_config = soc_camera_platform_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = { + .enum_mbus_code = soc_camera_platform_enum_mbus_code, +}; + static struct v4l2_subdev_ops platform_subdev_ops = { .core = &platform_subdev_core_ops, .video = &platform_subdev_video_ops, + .pad = &platform_subdev_pad_ops, }; static int soc_camera_platform_probe(struct platform_device *pdev) diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 2f0a345a7fed1b..c2eed99ebc7889 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -293,8 +293,6 @@ struct v4l2_mbus_frame_desc { g_dv_timings(): Get custom dv timings in the sub device. - enum_mbus_fmt: enumerate pixel formats, provided by a video data source - g_mbus_fmt: get the current pixel format, provided by a video data source try_mbus_fmt: try to set a pixel format on a video data source @@ -338,8 +336,6 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*query_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); - int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index, - u32 *code); int (*g_mbus_fmt)(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt); int (*try_mbus_fmt)(struct v4l2_subdev *sd, From 5fd99963daaf72fc9b1076953f9e0706149da40d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Apr 2015 04:02:34 -0300 Subject: [PATCH 223/381] [media] v4l2: replace video op g_mbus_fmt by pad op get_fmt The g_mbus_fmt video op is a duplicate of the pad op. Replace all uses by the get_fmt pad op and remove the video op. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Acked-by: Prabhakar Lad Cc: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7170.c | 11 ++-- drivers/media/i2c/adv7175.c | 11 ++-- drivers/media/i2c/adv7183.c | 12 +++-- drivers/media/i2c/adv7842.c | 14 +++-- drivers/media/i2c/ak881x.c | 24 ++++----- drivers/media/i2c/ml86v7667.c | 14 +++-- drivers/media/i2c/saa6752hs.c | 14 ++++- drivers/media/i2c/soc_camera/imx074.c | 11 ++-- drivers/media/i2c/soc_camera/mt9m001.c | 11 ++-- drivers/media/i2c/soc_camera/mt9m111.c | 11 ++-- drivers/media/i2c/soc_camera/mt9t031.c | 11 ++-- drivers/media/i2c/soc_camera/mt9t112.c | 11 ++-- drivers/media/i2c/soc_camera/mt9v022.c | 11 ++-- drivers/media/i2c/soc_camera/ov2640.c | 11 ++-- drivers/media/i2c/soc_camera/ov5642.c | 11 ++-- drivers/media/i2c/soc_camera/ov6650.c | 11 ++-- drivers/media/i2c/soc_camera/ov772x.c | 11 ++-- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 11 ++-- drivers/media/i2c/soc_camera/tw9910.c | 11 ++-- drivers/media/i2c/sr030pc30.c | 12 +++-- drivers/media/i2c/tvp514x.c | 35 ++---------- drivers/media/i2c/tvp5150.c | 15 +++--- drivers/media/i2c/tvp7002.c | 28 ---------- drivers/media/i2c/vs6624.c | 12 +++-- drivers/media/pci/saa7134/saa7134-empress.c | 9 ++-- drivers/media/platform/am437x/am437x-vpfe.c | 6 +-- drivers/media/platform/davinci/vpfe_capture.c | 19 ++++--- drivers/media/platform/s5p-tv/hdmi_drv.c | 12 +++-- drivers/media/platform/s5p-tv/mixer_drv.c | 15 ++++-- drivers/media/platform/s5p-tv/sdo_drv.c | 14 +++-- .../media/platform/soc_camera/mx2_camera.c | 13 +++-- .../media/platform/soc_camera/mx3_camera.c | 25 +++++---- .../media/platform/soc_camera/omap1_camera.c | 17 +++--- .../media/platform/soc_camera/pxa_camera.c | 21 ++++---- drivers/media/platform/soc_camera/rcar_vin.c | 46 +++++++++------- .../soc_camera/sh_mobile_ceu_camera.c | 54 ++++++++++--------- .../media/platform/soc_camera/soc_camera.c | 15 +++--- .../platform/soc_camera/soc_camera_platform.c | 9 ++-- include/media/v4l2-subdev.h | 4 -- 39 files changed, 352 insertions(+), 261 deletions(-) diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c index cfe963b2fe1c7d..58d0a3cc0759e0 100644 --- a/drivers/media/i2c/adv7170.c +++ b/drivers/media/i2c/adv7170.c @@ -273,11 +273,16 @@ static int adv7170_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int adv7170_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int adv7170_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; u8 val = adv7170_read(sd, 0x7); + if (format->pad) + return -EINVAL; + if ((val & 0x40) == (1 << 6)) mf->code = MEDIA_BUS_FMT_UYVY8_1X16; else @@ -323,11 +328,11 @@ static const struct v4l2_subdev_video_ops adv7170_video_ops = { .s_std_output = adv7170_s_std_output, .s_routing = adv7170_s_routing, .s_mbus_fmt = adv7170_s_fmt, - .g_mbus_fmt = adv7170_g_fmt, }; static const struct v4l2_subdev_pad_ops adv7170_pad_ops = { .enum_mbus_code = adv7170_enum_mbus_code, + .get_fmt = adv7170_get_fmt, }; static const struct v4l2_subdev_ops adv7170_ops = { diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c index 3f40304e856cbd..f7443454f682b7 100644 --- a/drivers/media/i2c/adv7175.c +++ b/drivers/media/i2c/adv7175.c @@ -311,11 +311,16 @@ static int adv7175_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int adv7175_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int adv7175_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; u8 val = adv7175_read(sd, 0x7); + if (format->pad) + return -EINVAL; + if ((val & 0x40) == (1 << 6)) mf->code = MEDIA_BUS_FMT_UYVY8_1X16; else @@ -376,11 +381,11 @@ static const struct v4l2_subdev_video_ops adv7175_video_ops = { .s_std_output = adv7175_s_std_output, .s_routing = adv7175_s_routing, .s_mbus_fmt = adv7175_s_fmt, - .g_mbus_fmt = adv7175_g_fmt, }; static const struct v4l2_subdev_pad_ops adv7175_pad_ops = { .enum_mbus_code = adv7175_enum_mbus_code, + .get_fmt = adv7175_get_fmt, }; static const struct v4l2_subdev_ops adv7175_ops = { diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index a0bcfefc28fcdb..9d58b750ef1ef5 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -460,12 +460,16 @@ static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int adv7183_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int adv7183_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7183 *decoder = to_adv7183(sd); - *fmt = decoder->fmt; + if (format->pad) + return -EINVAL; + + format->format = decoder->fmt; return 0; } @@ -517,12 +521,12 @@ static const struct v4l2_subdev_video_ops adv7183_video_ops = { .g_input_status = adv7183_g_input_status, .try_mbus_fmt = adv7183_try_mbus_fmt, .s_mbus_fmt = adv7183_s_mbus_fmt, - .g_mbus_fmt = adv7183_g_mbus_fmt, .s_stream = adv7183_s_stream, }; static const struct v4l2_subdev_pad_ops adv7183_pad_ops = { .enum_mbus_code = adv7183_enum_mbus_code, + .get_fmt = adv7183_get_fmt, }; static const struct v4l2_subdev_ops adv7183_ops = { diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 644e910f9d8a91..86e65a8a54096a 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1878,11 +1878,16 @@ static int adv7842_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int adv7842_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct adv7842_state *state = to_state(sd); + if (format->pad) + return -EINVAL; + fmt->width = state->timings.bt.width; fmt->height = state->timings.bt.height; fmt->code = MEDIA_BUS_FMT_FIXED; @@ -2810,9 +2815,6 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = { .s_dv_timings = adv7842_s_dv_timings, .g_dv_timings = adv7842_g_dv_timings, .query_dv_timings = adv7842_query_dv_timings, - .g_mbus_fmt = adv7842_g_mbus_fmt, - .try_mbus_fmt = adv7842_g_mbus_fmt, - .s_mbus_fmt = adv7842_g_mbus_fmt, }; static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { @@ -2821,6 +2823,8 @@ static const struct v4l2_subdev_pad_ops adv7842_pad_ops = { .enum_dv_timings = adv7842_enum_dv_timings, .dv_timings_cap = adv7842_dv_timings_cap, .enum_mbus_code = adv7842_enum_mbus_code, + .get_fmt = adv7842_fill_fmt, + .set_fmt = adv7842_fill_fmt, }; static const struct v4l2_subdev_ops adv7842_ops = { diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index 4428fb95d0333e..29846245aa3bb6 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -93,12 +93,17 @@ static int ak881x_s_register(struct v4l2_subdev *sd, } #endif -static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ak881x_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ak881x *ak881x = to_ak881x(client); + if (format->pad) + return -EINVAL; + v4l_bound_align_image(&mf->width, 0, 720, 2, &mf->height, 0, ak881x->lines, 1, 0); mf->field = V4L2_FIELD_INTERLACED; @@ -108,16 +113,6 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - if (mf->field != V4L2_FIELD_INTERLACED || - mf->code != MEDIA_BUS_FMT_YUYV8_2X8) - return -EINVAL; - - return ak881x_try_g_mbus_fmt(sd, mf); -} - static int ak881x_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) @@ -212,9 +207,6 @@ static struct v4l2_subdev_core_ops ak881x_subdev_core_ops = { }; static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { - .s_mbus_fmt = ak881x_s_mbus_fmt, - .g_mbus_fmt = ak881x_try_g_mbus_fmt, - .try_mbus_fmt = ak881x_try_g_mbus_fmt, .cropcap = ak881x_cropcap, .s_std_output = ak881x_s_std_output, .s_stream = ak881x_s_stream, @@ -222,6 +214,8 @@ static struct v4l2_subdev_video_ops ak881x_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ak881x_subdev_pad_ops = { .enum_mbus_code = ak881x_enum_mbus_code, + .set_fmt = ak881x_fill_fmt, + .get_fmt = ak881x_fill_fmt, }; static struct v4l2_subdev_ops ak881x_subdev_ops = { diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c index e7b220239d3094..af5eaf2db2a078 100644 --- a/drivers/media/i2c/ml86v7667.c +++ b/drivers/media/i2c/ml86v7667.c @@ -203,10 +203,15 @@ static int ml86v7667_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int ml86v7667_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct ml86v7667_priv *priv = to_ml86v7667(sd); + struct v4l2_mbus_framefmt *fmt = &format->format; + + if (format->pad) + return -EINVAL; fmt->code = MEDIA_BUS_FMT_YUYV8_2X8; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -280,14 +285,13 @@ static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = { .s_std = ml86v7667_s_std, .querystd = ml86v7667_querystd, .g_input_status = ml86v7667_g_input_status, - .try_mbus_fmt = ml86v7667_mbus_fmt, - .g_mbus_fmt = ml86v7667_mbus_fmt, - .s_mbus_fmt = ml86v7667_mbus_fmt, .g_mbus_config = ml86v7667_g_mbus_config, }; static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = { .enum_mbus_code = ml86v7667_enum_mbus_code, + .get_fmt = ml86v7667_fill_fmt, + .set_fmt = ml86v7667_fill_fmt, }; static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = { diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index f14c0e6435a3d7..b3829078d646f4 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -554,10 +554,16 @@ static int saa6752hs_init(struct v4l2_subdev *sd, u32 leading_null_bytes) return 0; } -static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) +static int saa6752hs_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *f = &format->format; struct saa6752hs_state *h = to_state(sd); + if (format->pad) + return -EINVAL; + if (h->video_format == SAA6752HS_VF_UNKNOWN) h->video_format = SAA6752HS_VF_D1; f->width = v4l2_format_table[h->video_format].fmt.pix.width; @@ -649,12 +655,16 @@ static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { .s_std = saa6752hs_s_std, .s_mbus_fmt = saa6752hs_s_mbus_fmt, .try_mbus_fmt = saa6752hs_try_mbus_fmt, - .g_mbus_fmt = saa6752hs_g_mbus_fmt, +}; + +static const struct v4l2_subdev_pad_ops saa6752hs_pad_ops = { + .get_fmt = saa6752hs_get_fmt, }; static const struct v4l2_subdev_ops saa6752hs_ops = { .core = &saa6752hs_core_ops, .video = &saa6752hs_video_ops, + .pad = &saa6752hs_pad_ops, }; static int saa6752hs_probe(struct i2c_client *client, diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index 7a2d90654fee28..ba60ccfffa4f0f 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c @@ -191,14 +191,19 @@ static int imx074_s_fmt(struct v4l2_subdev *sd, return 0; } -static int imx074_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int imx074_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct imx074 *priv = to_imx074(client); const struct imx074_datafmt *fmt = priv->fmt; + if (format->pad) + return -EINVAL; + mf->code = fmt->code; mf->colorspace = fmt->colorspace; mf->width = IMX074_WIDTH; @@ -278,7 +283,6 @@ static int imx074_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { .s_stream = imx074_s_stream, .s_mbus_fmt = imx074_s_fmt, - .g_mbus_fmt = imx074_g_fmt, .try_mbus_fmt = imx074_try_fmt, .g_crop = imx074_g_crop, .cropcap = imx074_cropcap, @@ -291,6 +295,7 @@ static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { .enum_mbus_code = imx074_enum_mbus_code, + .get_fmt = imx074_get_fmt, }; static struct v4l2_subdev_ops imx074_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index ba18e010b9da87..06f4e116978de1 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -250,11 +250,16 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9m001_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m001_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; mf->width = mt9m001->rect.width; mf->height = mt9m001->rect.height; @@ -613,7 +618,6 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, .s_mbus_fmt = mt9m001_s_fmt, - .g_mbus_fmt = mt9m001_g_fmt, .try_mbus_fmt = mt9m001_try_fmt, .s_crop = mt9m001_s_crop, .g_crop = mt9m001_g_crop, @@ -628,6 +632,7 @@ static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { .enum_mbus_code = mt9m001_enum_mbus_code, + .get_fmt = mt9m001_get_fmt, }; static struct v4l2_subdev_ops mt9m001_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index b7731401dc39c2..7ac87b112a11c1 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -447,11 +447,16 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9m111_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m111_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); + if (format->pad) + return -EINVAL; + mf->width = mt9m111->width; mf->height = mt9m111->height; mf->code = mt9m111->fmt->code; @@ -867,7 +872,6 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { .s_mbus_fmt = mt9m111_s_fmt, - .g_mbus_fmt = mt9m111_g_fmt, .try_mbus_fmt = mt9m111_try_fmt, .s_crop = mt9m111_s_crop, .g_crop = mt9m111_g_crop, @@ -877,6 +881,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { .enum_mbus_code = mt9m111_enum_mbus_code, + .get_fmt = mt9m111_get_fmt, }; static struct v4l2_subdev_ops mt9m111_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 15ac4dc2996746..97193e471ab557 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -337,12 +337,17 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9t031_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9t031_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); + if (format->pad) + return -EINVAL; + mf->width = mt9t031->rect.width / mt9t031->xskip; mf->height = mt9t031->rect.height / mt9t031->yskip; mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; @@ -714,7 +719,6 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .s_stream = mt9t031_s_stream, .s_mbus_fmt = mt9t031_s_fmt, - .g_mbus_fmt = mt9t031_g_fmt, .try_mbus_fmt = mt9t031_try_fmt, .s_crop = mt9t031_s_crop, .g_crop = mt9t031_g_crop, @@ -729,6 +733,7 @@ static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { .enum_mbus_code = mt9t031_enum_mbus_code, + .get_fmt = mt9t031_get_fmt, }; static struct v4l2_subdev_ops mt9t031_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 8b0cfb7f80b182..889e98ee8c6203 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -904,12 +904,17 @@ static int mt9t112_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) return mt9t112_set_params(priv, rect, priv->format->code); } -static int mt9t112_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9t112_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); + if (format->pad) + return -EINVAL; + mf->width = priv->frame.width; mf->height = priv->frame.height; mf->colorspace = priv->format->colorspace; @@ -1011,7 +1016,6 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .s_stream = mt9t112_s_stream, - .g_mbus_fmt = mt9t112_g_fmt, .s_mbus_fmt = mt9t112_s_fmt, .try_mbus_fmt = mt9t112_try_fmt, .cropcap = mt9t112_cropcap, @@ -1023,6 +1027,7 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { .enum_mbus_code = mt9t112_enum_mbus_code, + .get_fmt = mt9t112_get_fmt, }; /************************************************************************ diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 780c7ae74d698e..b4ba3c5930e3a1 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -375,12 +375,17 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int mt9v022_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9v022_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); + if (format->pad) + return -EINVAL; + mf->width = mt9v022->rect.width; mf->height = mt9v022->rect.height; mf->code = mt9v022->fmt->code; @@ -841,7 +846,6 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .s_stream = mt9v022_s_stream, .s_mbus_fmt = mt9v022_s_fmt, - .g_mbus_fmt = mt9v022_g_fmt, .try_mbus_fmt = mt9v022_try_fmt, .s_crop = mt9v022_s_crop, .g_crop = mt9v022_g_crop, @@ -856,6 +860,7 @@ static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { .enum_mbus_code = mt9v022_enum_mbus_code, + .get_fmt = mt9v022_get_fmt, }; static struct v4l2_subdev_ops mt9v022_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 4327871c8f9f4a..0dffc63ee83fdc 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -845,12 +845,17 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, return ret; } -static int ov2640_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov2640_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2640_priv *priv = to_ov2640(client); + if (format->pad) + return -EINVAL; + if (!priv->win) { u32 width = SVGA_WIDTH, height = SVGA_HEIGHT; priv->win = ov2640_select_win(&width, &height); @@ -1032,7 +1037,6 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { .s_stream = ov2640_s_stream, - .g_mbus_fmt = ov2640_g_fmt, .s_mbus_fmt = ov2640_s_fmt, .try_mbus_fmt = ov2640_try_fmt, .cropcap = ov2640_cropcap, @@ -1042,6 +1046,7 @@ static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { .enum_mbus_code = ov2640_enum_mbus_code, + .get_fmt = ov2640_get_fmt, }; static struct v4l2_subdev_ops ov2640_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index fcddd0ded2e3db..a88397f60b8c15 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -822,14 +822,19 @@ static int ov5642_s_fmt(struct v4l2_subdev *sd, return 0; } -static int ov5642_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov5642_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); const struct ov5642_datafmt *fmt = priv->fmt; + if (format->pad) + return -EINVAL; + mf->code = fmt->code; mf->colorspace = fmt->colorspace; mf->width = priv->crop_rect.width; @@ -941,7 +946,6 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on) static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { .s_mbus_fmt = ov5642_s_fmt, - .g_mbus_fmt = ov5642_g_fmt, .try_mbus_fmt = ov5642_try_fmt, .s_crop = ov5642_s_crop, .g_crop = ov5642_g_crop, @@ -951,6 +955,7 @@ static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { .enum_mbus_code = ov5642_enum_mbus_code, + .get_fmt = ov5642_get_fmt, }; static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 99e0738fdb38c1..29f73a55a31244 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -499,12 +499,17 @@ static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov6650_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov6650_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); + if (format->pad) + return -EINVAL; + mf->width = priv->rect.width >> priv->half_scale; mf->height = priv->rect.height >> priv->half_scale; mf->code = priv->code; @@ -930,7 +935,6 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_stream = ov6650_s_stream, - .g_mbus_fmt = ov6650_g_fmt, .s_mbus_fmt = ov6650_s_fmt, .try_mbus_fmt = ov6650_try_fmt, .cropcap = ov6650_cropcap, @@ -944,6 +948,7 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { .enum_mbus_code = ov6650_enum_mbus_code, + .get_fmt = ov6650_get_fmt, }; static struct v4l2_subdev_ops ov6650_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index e3a31f80663629..1db2044513845c 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -876,11 +876,16 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int ov772x_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov772x_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct ov772x_priv *priv = to_ov772x(sd); + if (format->pad) + return -EINVAL; + mf->width = priv->win->rect.width; mf->height = priv->win->rect.height; mf->code = priv->cfmt->code; @@ -1017,7 +1022,6 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .s_stream = ov772x_s_stream, - .g_mbus_fmt = ov772x_g_fmt, .s_mbus_fmt = ov772x_s_fmt, .try_mbus_fmt = ov772x_try_fmt, .cropcap = ov772x_cropcap, @@ -1027,6 +1031,7 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { .enum_mbus_code = ov772x_enum_mbus_code, + .get_fmt = ov772x_get_fmt, }; static struct v4l2_subdev_ops ov772x_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 4927a76d2240ec..8787142493cc94 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -598,12 +598,17 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int rj54n1_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int rj54n1_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct rj54n1 *rj54n1 = to_rj54n1(client); + if (format->pad) + return -EINVAL; + mf->code = rj54n1->fmt->code; mf->colorspace = rj54n1->fmt->colorspace; mf->field = V4L2_FIELD_NONE; @@ -1251,7 +1256,6 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_stream = rj54n1_s_stream, .s_mbus_fmt = rj54n1_s_fmt, - .g_mbus_fmt = rj54n1_g_fmt, .try_mbus_fmt = rj54n1_try_fmt, .g_crop = rj54n1_g_crop, .s_crop = rj54n1_s_crop, @@ -1262,6 +1266,7 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { .enum_mbus_code = rj54n1_enum_mbus_code, + .get_fmt = rj54n1_get_fmt, }; static struct v4l2_subdev_ops rj54n1_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index f8c0c713d06c6c..95837959f409af 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -691,12 +691,17 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a) return 0; } -static int tw9910_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int tw9910_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); + if (format->pad) + return -EINVAL; + if (!priv->scale) { priv->scale = tw9910_select_norm(priv->norm, 640, 480); if (!priv->scale) @@ -881,7 +886,6 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .s_std = tw9910_s_std, .g_std = tw9910_g_std, .s_stream = tw9910_s_stream, - .g_mbus_fmt = tw9910_g_fmt, .s_mbus_fmt = tw9910_s_fmt, .try_mbus_fmt = tw9910_try_fmt, .cropcap = tw9910_cropcap, @@ -893,6 +897,7 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { .enum_mbus_code = tw9910_enum_mbus_code, + .get_fmt = tw9910_get_fmt, }; static struct v4l2_subdev_ops tw9910_subdev_ops = { diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index 0a0a1886ee4ca9..c0fa94570c4fb5 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -483,15 +483,19 @@ static int sr030pc30_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int sr030pc30_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int sr030pc30_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf; struct sr030pc30_info *info = to_sr030pc30(sd); int ret; - if (!mf) + if (!format || format->pad) return -EINVAL; + mf = &format->format; + if (!info->curr_win || !info->curr_fmt) { ret = sr030pc30_set_params(sd); if (ret) @@ -639,13 +643,13 @@ static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { }; static const struct v4l2_subdev_video_ops sr030pc30_video_ops = { - .g_mbus_fmt = sr030pc30_g_fmt, .s_mbus_fmt = sr030pc30_s_fmt, .try_mbus_fmt = sr030pc30_try_fmt, }; static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { .enum_mbus_code = sr030pc30_enum_mbus_code, + .get_fmt = sr030pc30_get_fmt, }; static const struct v4l2_subdev_ops sr030pc30_ops = { diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index a822d1541614b2..24e47279e30c1e 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -746,35 +746,6 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl) return err; } -/** - * tvp514x_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to the mediabus format structure - * - * Negotiates the image capture size and mediabus format. - */ -static int -tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct tvp514x_decoder *decoder = to_decoder(sd); - enum tvp514x_std current_std; - - if (f == NULL) - return -EINVAL; - - /* Calculate height and width based on current standard */ - current_std = decoder->current_std; - - f->code = MEDIA_BUS_FMT_YUYV8_2X8; - f->width = decoder->std_list[current_std].width; - f->height = decoder->std_list[current_std].height; - f->field = V4L2_FIELD_INTERLACED; - f->colorspace = V4L2_COLORSPACE_SMPTE170M; - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n", - f->width, f->height); - return 0; -} - /** * tvp514x_g_parm() - V4L2 decoder interface handler for g_parm * @sd: pointer to standard V4L2 sub-device structure @@ -943,6 +914,9 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, struct tvp514x_decoder *decoder = to_decoder(sd); __u32 which = format->which; + if (format->pad) + return -EINVAL; + if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { format->format = decoder->format; return 0; @@ -997,9 +971,6 @@ static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, .querystd = tvp514x_querystd, - .g_mbus_fmt = tvp514x_mbus_fmt, - .try_mbus_fmt = tvp514x_mbus_fmt, - .s_mbus_fmt = tvp514x_mbus_fmt, .g_parm = tvp514x_g_parm, .s_parm = tvp514x_s_parm, .s_stream = tvp514x_s_stream, diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index f2f87b73184c4f..e4fa0746f75e03 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -828,14 +828,18 @@ static int tvp5150_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int tvp5150_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *f) +static int tvp5150_fill_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *f; struct tvp5150 *decoder = to_tvp5150(sd); - if (f == NULL) + if (!format || format->pad) return -EINVAL; + f = &format->format; + tvp5150_reset(sd, 0); f->width = decoder->rect.width; @@ -1069,9 +1073,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = { static const struct v4l2_subdev_video_ops tvp5150_video_ops = { .s_std = tvp5150_s_std, .s_routing = tvp5150_s_routing, - .s_mbus_fmt = tvp5150_mbus_fmt, - .try_mbus_fmt = tvp5150_mbus_fmt, - .g_mbus_fmt = tvp5150_mbus_fmt, .s_crop = tvp5150_s_crop, .g_crop = tvp5150_g_crop, .cropcap = tvp5150_cropcap, @@ -1086,6 +1087,8 @@ static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = { static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = { .enum_mbus_code = tvp5150_enum_mbus_code, + .set_fmt = tvp5150_fill_fmt, + .get_fmt = tvp5150_fill_fmt, }; static const struct v4l2_subdev_ops tvp5150_ops = { diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index d21fa1a62e41c6..05077cffd2351d 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -610,31 +610,6 @@ static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl) return -EINVAL; } -/* - * tvp7002_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt - * @sd: pointer to standard V4L2 sub-device structure - * @f: pointer to mediabus format structure - * - * Negotiate the image capture size and mediabus format. - * There is only one possible format, so this single function works for - * get, set and try. - */ -static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct tvp7002 *device = to_tvp7002(sd); - const struct v4l2_bt_timings *bt = &device->current_timings->timings.bt; - - f->width = bt->width; - f->height = bt->height; - f->code = MEDIA_BUS_FMT_YUYV10_1X20; - f->field = device->current_timings->scanmode; - f->colorspace = device->current_timings->color_space; - - v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d", - f->width, f->height); - return 0; -} - /* * tvp7002_query_dv() - query DV timings * @sd: pointer to standard V4L2 sub-device structure @@ -905,9 +880,6 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = { .s_dv_timings = tvp7002_s_dv_timings, .query_dv_timings = tvp7002_query_dv_timings, .s_stream = tvp7002_s_stream, - .g_mbus_fmt = tvp7002_mbus_fmt, - .try_mbus_fmt = tvp7002_mbus_fmt, - .s_mbus_fmt = tvp7002_mbus_fmt, }; /* media pad related operation handlers */ diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index b1d0a1b28ca86d..59f733524620a7 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -649,12 +649,16 @@ static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, return 0; } -static int vs6624_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int vs6624_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct vs6624 *sensor = to_vs6624(sd); - *fmt = sensor->fmt; + if (format->pad) + return -EINVAL; + + format->format = sensor->fmt; return 0; } @@ -741,7 +745,6 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = { static const struct v4l2_subdev_video_ops vs6624_video_ops = { .try_mbus_fmt = vs6624_try_mbus_fmt, .s_mbus_fmt = vs6624_s_mbus_fmt, - .g_mbus_fmt = vs6624_g_mbus_fmt, .s_parm = vs6624_s_parm, .g_parm = vs6624_g_parm, .s_stream = vs6624_s_stream, @@ -749,6 +752,7 @@ static const struct v4l2_subdev_video_ops vs6624_video_ops = { static const struct v4l2_subdev_pad_ops vs6624_pad_ops = { .enum_mbus_code = vs6624_enum_mbus_code, + .get_fmt = vs6624_get_fmt, }; static const struct v4l2_subdev_ops vs6624_ops = { diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 594dc3ad4750e0..22632f9e34e6c2 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -121,11 +121,14 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; - saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); + saa_call_all(dev, pad, get_fmt, NULL, &fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_pix_format(&f->fmt.pix, mbus_fmt); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; f->fmt.pix.bytesperline = 0; diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index a30cc2f7e4f126..57403f5d76e3b9 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1095,7 +1095,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe) * For a given standard, this functions sets up the default * pix format & crop values in the vpfe device and ccdc. It first * starts with defaults based values from the standard table. - * It then checks if sub device support g_mbus_fmt and then override the + * It then checks if sub device supports get_fmt and then override the * values based on that.Sets crop values to match with scan resolution * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the * values in ccdc @@ -1432,8 +1432,8 @@ static int __vpfe_get_format(struct vpfe_device *vpfe, } else { ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id, - video, g_mbus_fmt, - &mbus_fmt); + pad, get_fmt, + NULL, &fmt); if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ccfcf3f528d377..7767e072d62330 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -370,7 +370,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev) * For a given standard, this functions sets up the default * pix format & crop values in the vpfe device and ccdc. It first * starts with defaults based values from the standard table. - * It then checks if sub device support g_mbus_fmt and then override the + * It then checks if sub device supports get_fmt and then override the * values based on that.Sets crop values to match with scan resolution * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the * values in ccdc @@ -379,7 +379,10 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, v4l2_std_id std_id) { struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; int i, ret = 0; @@ -413,26 +416,26 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, pix->field = V4L2_FIELD_INTERLACED; /* assume V4L2_PIX_FMT_UYVY as default */ pix->pixelformat = V4L2_PIX_FMT_UYVY; - v4l2_fill_mbus_format(&mbus_fmt, pix, + v4l2_fill_mbus_format(mbus_fmt, pix, MEDIA_BUS_FMT_YUYV10_2X10); } else { pix->field = V4L2_FIELD_NONE; /* assume V4L2_PIX_FMT_SBGGR8 */ pix->pixelformat = V4L2_PIX_FMT_SBGGR8; - v4l2_fill_mbus_format(&mbus_fmt, pix, + v4l2_fill_mbus_format(mbus_fmt, pix, MEDIA_BUS_FMT_SBGGR8_1X8); } - /* if sub device supports g_mbus_fmt, override the defaults */ + /* if sub device supports get_fmt, override the defaults */ ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, - sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt); + sdinfo->grp_id, pad, get_fmt, NULL, &fmt); if (ret && ret != -ENOIOCTLCMD) { v4l2_err(&vpfe_dev->v4l2_dev, - "error in getting g_mbus_fmt from sub device\n"); + "error in getting get_fmt from sub device\n"); return ret; } - v4l2_fill_pix_format(pix, &mbus_fmt); + v4l2_fill_pix_format(pix, mbus_fmt); pix->bytesperline = pix->width * 2; pix->sizeimage = pix->bytesperline * pix->height; diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c index 0e74aabf5f9a6e..618ecd1d5b27a6 100644 --- a/drivers/media/platform/s5p-tv/hdmi_drv.c +++ b/drivers/media/platform/s5p-tv/hdmi_drv.c @@ -648,15 +648,20 @@ static int hdmi_g_dv_timings(struct v4l2_subdev *sd, return 0; } -static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int hdmi_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct hdmi_device *hdev = sd_to_hdmi_dev(sd); const struct hdmi_timings *t = hdev->cur_conf; dev_dbg(hdev->dev, "%s\n", __func__); if (!hdev->cur_conf) return -EINVAL; + if (format->pad) + return -EINVAL; + memset(fmt, 0, sizeof(*fmt)); fmt->width = t->hact.end - t->hact.beg; fmt->height = t->vact[0].end - t->vact[0].beg; @@ -712,18 +717,19 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = { static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = { .s_dv_timings = hdmi_s_dv_timings, .g_dv_timings = hdmi_g_dv_timings, - .g_mbus_fmt = hdmi_g_mbus_fmt, .s_stream = hdmi_s_stream, }; static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops = { .enum_dv_timings = hdmi_enum_dv_timings, .dv_timings_cap = hdmi_dv_timings_cap, + .get_fmt = hdmi_get_fmt, }; static const struct v4l2_subdev_ops hdmi_sd_ops = { .core = &hdmi_sd_core_ops, .video = &hdmi_sd_video_ops, + .pad = &hdmi_sd_pad_ops, }; static int hdmi_runtime_suspend(struct device *dev) diff --git a/drivers/media/platform/s5p-tv/mixer_drv.c b/drivers/media/platform/s5p-tv/mixer_drv.c index 2a9501d7e7c832..5ef67774971dc3 100644 --- a/drivers/media/platform/s5p-tv/mixer_drv.c +++ b/drivers/media/platform/s5p-tv/mixer_drv.c @@ -46,11 +46,15 @@ void mxr_get_mbus_fmt(struct mxr_device *mdev, struct v4l2_mbus_framefmt *mbus_fmt) { struct v4l2_subdev *sd; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; mutex_lock(&mdev->mutex); sd = to_outsd(mdev); - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, mbus_fmt); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); + *mbus_fmt = fmt.format; WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name); mutex_unlock(&mdev->mutex); } @@ -62,7 +66,10 @@ void mxr_streamer_get(struct mxr_device *mdev) mxr_dbg(mdev, "%s(%d)\n", __func__, mdev->n_streamer); if (mdev->n_streamer == 1) { struct v4l2_subdev *sd = to_outsd(mdev); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; struct mxr_resources *res = &mdev->res; int ret; @@ -72,12 +79,12 @@ void mxr_streamer_get(struct mxr_device *mdev) clk_set_parent(res->sclk_mixer, res->sclk_hdmi); mxr_reg_s_output(mdev, to_output(mdev)->cookie); - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mbus_fmt); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); WARN(ret, "failed to get mbus_fmt for output %s\n", sd->name); ret = v4l2_subdev_call(sd, video, s_stream, 1); WARN(ret, "starting stream failed for output %s\n", sd->name); - mxr_reg_set_mbus_fmt(mdev, &mbus_fmt); + mxr_reg_set_mbus_fmt(mdev, mbus_fmt); mxr_reg_streamon(mdev); ret = mxr_reg_wait4vsync(mdev); WARN(ret, "failed to get vsync (%d) from output\n", ret); diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c index 3621af91d46092..c75d4354d182b1 100644 --- a/drivers/media/platform/s5p-tv/sdo_drv.c +++ b/drivers/media/platform/s5p-tv/sdo_drv.c @@ -160,13 +160,17 @@ static int sdo_g_std_output(struct v4l2_subdev *sd, v4l2_std_id *std) return 0; } -static int sdo_g_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int sdo_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; struct sdo_device *sdev = sd_to_sdev(sd); if (!sdev->fmt) return -ENXIO; + if (format->pad) + return -EINVAL; /* all modes are 720 pixels wide */ fmt->width = 720; fmt->height = sdev->fmt->height; @@ -256,13 +260,17 @@ static const struct v4l2_subdev_video_ops sdo_sd_video_ops = { .s_std_output = sdo_s_std_output, .g_std_output = sdo_g_std_output, .g_tvnorms_output = sdo_g_tvnorms_output, - .g_mbus_fmt = sdo_g_mbus_fmt, .s_stream = sdo_s_stream, }; +static const struct v4l2_subdev_pad_ops sdo_sd_pad_ops = { + .get_fmt = sdo_get_fmt, +}; + static const struct v4l2_subdev_ops sdo_sd_ops = { .core = &sdo_sd_core_ops, .video = &sdo_sd_video_ops, + .pad = &sdo_sd_pad_ops, }; static int sdo_runtime_suspend(struct device *dev) diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index b891b7f2b7e9d5..a1b42645871973 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -912,7 +912,10 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, struct v4l2_crop a_writable = *a; struct v4l2_rect *rect = &a_writable.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); @@ -923,15 +926,15 @@ static int mx2_camera_set_crop(struct soc_camera_device *icd, return ret; /* The capture device might have changed its output */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; dev_dbg(icd->parent, "Sensor cropped %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; return ret; } diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index a29848976f92a7..6c34dbb878b21a 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -804,7 +804,10 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx3_camera_dev *mx3_cam = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096); @@ -815,30 +818,30 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, return ret; /* The capture device might have changed its output sizes */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (mf.code != icd->current_fmt->code) + if (mf->code != icd->current_fmt->code) return -EINVAL; - if (mf.width & 7) { + if (mf->width & 7) { /* Ouch! We can only handle 8-byte aligned width... */ - stride_align(&mf.width); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + stride_align(&mf->width); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); if (ret < 0) return ret; } - if (mf.width != icd->user_width || mf.height != icd->user_height) - configure_geometry(mx3_cam, mf.width, mf.height, + if (mf->width != icd->user_width || mf->height != icd->user_height) + configure_geometry(mx3_cam, mf->width, mf->height, icd->current_fmt->host_fmt); dev_dbg(icd->parent, "Sensor cropped %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; return ret; } diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 3f250767d162fe..6663645d1be443 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1224,7 +1224,10 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd, struct device *dev = icd->parent; struct soc_camera_host *ici = to_soc_camera_host(dev); struct omap1_cam_dev *pcdev = ici->priv; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop); @@ -1234,32 +1237,32 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd, return ret; } - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) { dev_warn(dev, "%s: failed to fetch current format\n", __func__); return ret; } - ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, + ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, false); if (ret < 0) { dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", - __func__, mf.width, mf.height, + __func__, mf->width, mf->height, xlate->host_fmt->name); return ret; } if (!ret) { /* sensor returned geometry not DMA aligned, trying to fix */ - ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); + ret = set_mbus_format(pcdev, dev, icd, sd, mf, xlate); if (ret < 0) { dev_err(dev, "%s: failed to set format\n", __func__); return ret; } } - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; return 0; } diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index f6fa0acc525107..48999f3cb2bbda 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1349,7 +1349,10 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, .master_clock = pcdev->mclk, .pixel_clock_max = pcdev->ciclk / 4, }; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct pxa_cam *cam = icd->host_priv; u32 fourcc = icd->current_fmt->host_fmt->fourcc; int ret; @@ -1368,23 +1371,23 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, return ret; } - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (pxa_camera_check_frame(mf.width, mf.height)) { + if (pxa_camera_check_frame(mf->width, mf->height)) { /* * Camera cropping produced a frame beyond our capabilities. * FIXME: just extract a subframe, that we can process. */ - v4l_bound_align_image(&mf.width, 48, 2048, 1, - &mf.height, 32, 2048, 0, + v4l_bound_align_image(&mf->width, 48, 2048, 1, + &mf->height, 32, 2048, 0, fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); if (ret < 0) return ret; - if (pxa_camera_check_frame(mf.width, mf.height)) { + if (pxa_camera_check_frame(mf->width, mf->height)) { dev_warn(icd->parent, "Inconsistent state. Use S_FMT to repair\n"); return -EINVAL; @@ -1401,8 +1404,8 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, recalculate_fifo_timeout(pcdev, sense.pixel_clock); } - icd->user_width = mf.width; - icd->user_height = mf.height; + icd->user_width = mf->width; + icd->user_height = mf->height; pxa_camera_setup_cicr(icd, cam->flags, fourcc); diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 2dc8c816abc750..76b90dce3b0581 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1344,12 +1344,15 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, return 0; if (!icd->host_priv) { - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct v4l2_rect rect; struct device *dev = icd->parent; int shift; - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; @@ -1359,8 +1362,8 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, /* Sensor driver doesn't support cropping */ rect.left = 0; rect.top = 0; - rect.width = mf.width; - rect.height = mf.height; + rect.width = mf->width; + rect.height = mf->height; } else if (ret < 0) { return ret; } @@ -1370,16 +1373,16 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, * 1280x960, 640x480, 320x240 */ for (shift = 0; shift < 3; shift++) { - if (mf.width <= VIN_MAX_WIDTH && - mf.height <= VIN_MAX_HEIGHT) + if (mf->width <= VIN_MAX_WIDTH && + mf->height <= VIN_MAX_HEIGHT) break; - mf.width = 1280 >> shift; - mf.height = 960 >> shift; + mf->width = 1280 >> shift; + mf->height = 960 >> shift; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), video, s_mbus_fmt, - &mf); + mf); if (ret < 0) return ret; } @@ -1387,11 +1390,11 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, if (shift == 3) { dev_err(dev, "Failed to configure the client below %ux%u\n", - mf.width, mf.height); + mf->width, mf->height); return -EIO; } - dev_dbg(dev, "camera fmt %ux%u\n", mf.width, mf.height); + dev_dbg(dev, "camera fmt %ux%u\n", mf->width, mf->height); cam = kzalloc(sizeof(*cam), GFP_KERNEL); if (!cam) @@ -1402,10 +1405,10 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, */ cam->rect = rect; cam->subrect = rect; - cam->width = mf.width; - cam->height = mf.height; - cam->out_width = mf.width; - cam->out_height = mf.height; + cam->width = mf->width; + cam->height = mf->height; + cam->out_width = mf->width; + cam->out_height = mf->height; icd->host_priv = cam; } else { @@ -1473,7 +1476,10 @@ static int rcar_vin_set_crop(struct soc_camera_device *icd, struct v4l2_rect *cam_rect = &cam_crop.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; u32 vnmc; int ret, i; @@ -1497,16 +1503,16 @@ static int rcar_vin_set_crop(struct soc_camera_device *icd, /* On success cam_crop contains current camera crop */ /* Retrieve camera output window */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (mf.width > VIN_MAX_WIDTH || mf.height > VIN_MAX_HEIGHT) + if (mf->width > VIN_MAX_WIDTH || mf->height > VIN_MAX_HEIGHT) return -EINVAL; /* Cache camera output window */ - cam->width = mf.width; - cam->height = mf.height; + cam->width = mf->width; + cam->height = mf->height; icd->user_width = cam->width; icd->user_height = cam->height; diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index b4faf8f1fd15e3..566fd74c46396b 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1073,7 +1073,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int } if (!icd->host_priv) { - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; struct v4l2_rect rect; int shift = 0; @@ -1091,7 +1094,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int return ret; /* First time */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; @@ -1102,14 +1105,14 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int * sizes, just try VGA multiples. If needed, this can be * adjusted in the future. */ - while ((mf.width > pcdev->max_width || - mf.height > pcdev->max_height) && shift < 4) { + while ((mf->width > pcdev->max_width || + mf->height > pcdev->max_height) && shift < 4) { /* Try 2560x1920, 1280x960, 640x480, 320x240 */ - mf.width = 2560 >> shift; - mf.height = 1920 >> shift; + mf->width = 2560 >> shift; + mf->height = 1920 >> shift; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), video, - s_mbus_fmt, &mf); + s_mbus_fmt, mf); if (ret < 0) return ret; shift++; @@ -1117,11 +1120,11 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int if (shift == 4) { dev_err(dev, "Failed to configure the client below %ux%x\n", - mf.width, mf.height); + mf->width, mf->height); return -EIO; } - dev_geo(dev, "camera fmt %ux%u\n", mf.width, mf.height); + dev_geo(dev, "camera fmt %ux%u\n", mf->width, mf->height); cam = kzalloc(sizeof(*cam), GFP_KERNEL); if (!cam) @@ -1131,8 +1134,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int cam->rect = rect; cam->subrect = rect; - cam->width = mf.width; - cam->height = mf.height; + cam->width = mf->width; + cam->height = mf->height; icd->host_priv = cam; } else { @@ -1217,7 +1220,10 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, struct sh_mobile_ceu_cam *cam = icd->host_priv; struct v4l2_rect *cam_rect = &cam_crop.c; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; unsigned int scale_cam_h, scale_cam_v, scale_ceu_h, scale_ceu_v, out_width, out_height; int interm_width, interm_height; @@ -1247,16 +1253,16 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, /* On success cam_crop contains current camera crop */ /* 3. Retrieve camera output window */ - ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); if (ret < 0) return ret; - if (mf.width > pcdev->max_width || mf.height > pcdev->max_height) + if (mf->width > pcdev->max_width || mf->height > pcdev->max_height) return -EINVAL; /* 4. Calculate camera scales */ - scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); + scale_cam_h = calc_generic_scale(cam_rect->width, mf->width); + scale_cam_v = calc_generic_scale(cam_rect->height, mf->height); /* Calculate intermediate window */ interm_width = scale_down(rect->width, scale_cam_h); @@ -1267,7 +1273,7 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, new_scale_h = calc_generic_scale(rect->width, icd->user_width); - mf.width = scale_down(cam_rect->width, new_scale_h); + mf->width = scale_down(cam_rect->width, new_scale_h); } if (interm_height < icd->user_height) { @@ -1275,26 +1281,26 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, new_scale_v = calc_generic_scale(rect->height, icd->user_height); - mf.height = scale_down(cam_rect->height, new_scale_v); + mf->height = scale_down(cam_rect->height, new_scale_v); } if (interm_width < icd->user_width || interm_height < icd->user_height) { ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), video, - s_mbus_fmt, &mf); + s_mbus_fmt, mf); if (ret < 0) return ret; - dev_geo(dev, "New camera output %ux%u\n", mf.width, mf.height); - scale_cam_h = calc_generic_scale(cam_rect->width, mf.width); - scale_cam_v = calc_generic_scale(cam_rect->height, mf.height); + dev_geo(dev, "New camera output %ux%u\n", mf->width, mf->height); + scale_cam_h = calc_generic_scale(cam_rect->width, mf->width); + scale_cam_v = calc_generic_scale(cam_rect->height, mf->height); interm_width = scale_down(rect->width, scale_cam_h); interm_height = scale_down(rect->height, scale_cam_v); } /* Cache camera output window */ - cam->width = mf.width; - cam->height = mf.height; + cam->width = mf->width; + cam->height = mf->height; if (pcdev->image_mode) { out_width = min(interm_width, icd->user_width); diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 7fd49cb009d329..d708df410f74cb 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1289,7 +1289,10 @@ static struct soc_camera_device *soc_camera_add_pdev(struct soc_camera_async_cli static int soc_camera_probe_finish(struct soc_camera_device *icd) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; sd->grp_id = soc_camera_grp_id(icd); @@ -1319,11 +1322,11 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd) goto evidstart; /* Try to improve our guess of a reasonable window format */ - if (!v4l2_subdev_call(sd, video, g_mbus_fmt, &mf)) { - icd->user_width = mf.width; - icd->user_height = mf.height; - icd->colorspace = mf.colorspace; - icd->field = mf.field; + if (!v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt)) { + icd->user_width = mf->width; + icd->user_height = mf->height; + icd->colorspace = mf->colorspace; + icd->field = mf->field; } soc_camera_remove_device(icd); diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c index 934b9183cea8d8..cc8eb07582193a 100644 --- a/drivers/media/platform/soc_camera/soc_camera_platform.c +++ b/drivers/media/platform/soc_camera/soc_camera_platform.c @@ -37,9 +37,11 @@ static int soc_camera_platform_s_stream(struct v4l2_subdev *sd, int enable) } static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &format->format; mf->width = p->format.width; mf->height = p->format.height; @@ -120,14 +122,13 @@ static struct v4l2_subdev_video_ops platform_subdev_video_ops = { .s_stream = soc_camera_platform_s_stream, .cropcap = soc_camera_platform_cropcap, .g_crop = soc_camera_platform_g_crop, - .try_mbus_fmt = soc_camera_platform_fill_fmt, - .g_mbus_fmt = soc_camera_platform_fill_fmt, - .s_mbus_fmt = soc_camera_platform_fill_fmt, .g_mbus_config = soc_camera_platform_g_mbus_config, }; static const struct v4l2_subdev_pad_ops platform_subdev_pad_ops = { .enum_mbus_code = soc_camera_platform_enum_mbus_code, + .get_fmt = soc_camera_platform_fill_fmt, + .set_fmt = soc_camera_platform_fill_fmt, }; static struct v4l2_subdev_ops platform_subdev_ops = { diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index c2eed99ebc7889..67a8e4e58d9af3 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -293,8 +293,6 @@ struct v4l2_mbus_frame_desc { g_dv_timings(): Get custom dv timings in the sub device. - g_mbus_fmt: get the current pixel format, provided by a video data source - try_mbus_fmt: try to set a pixel format on a video data source s_mbus_fmt: set a pixel format on a video data source @@ -336,8 +334,6 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*query_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); - int (*g_mbus_fmt)(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt); int (*try_mbus_fmt)(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt); int (*s_mbus_fmt)(struct v4l2_subdev *sd, From 29b419857a03fbd90d60862005300da66e5df63b Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Apr 2015 06:24:36 -0300 Subject: [PATCH 224/381] [media] v4l2: replace try_mbus_fmt by set_fmt The try_mbus_fmt video op is a duplicate of the pad op. Replace all uses in sub-devices by the set_fmt() pad op. Since try_mbus_fmt and s_mbus_fmt both map to the set_fmt pad op (but with a different 'which' argument), this patch will replace both try_mbus_fmt and s_mbus_fmt by set_fmt. Signed-off-by: Hans Verkuil Cc: Guennadi Liakhovetski Cc: Jonathan Corbet Cc: Kamil Debski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7183.c | 36 +++++++------- drivers/media/i2c/mt9v011.c | 38 +++++++-------- drivers/media/i2c/ov7670.c | 27 ++++++----- drivers/media/i2c/saa6752hs.c | 28 ++++++----- drivers/media/i2c/soc_camera/imx074.c | 39 +++++++-------- drivers/media/i2c/soc_camera/mt9m001.c | 17 +++++-- drivers/media/i2c/soc_camera/mt9m111.c | 31 +++++------- drivers/media/i2c/soc_camera/mt9t031.c | 48 ++++++++++--------- drivers/media/i2c/soc_camera/mt9t112.c | 15 ++++-- drivers/media/i2c/soc_camera/mt9v022.c | 17 +++++-- drivers/media/i2c/soc_camera/ov2640.c | 36 +++++--------- drivers/media/i2c/soc_camera/ov5642.c | 34 ++++++------- drivers/media/i2c/soc_camera/ov6650.c | 17 +++++-- drivers/media/i2c/soc_camera/ov772x.c | 15 ++++-- drivers/media/i2c/soc_camera/ov9640.c | 17 +++++-- drivers/media/i2c/soc_camera/ov9740.c | 16 +++++-- drivers/media/i2c/soc_camera/rj54n1cb0c.c | 40 ++++++---------- drivers/media/i2c/soc_camera/tw9910.c | 15 ++++-- drivers/media/i2c/sr030pc30.c | 38 +++++++-------- drivers/media/i2c/vs6624.c | 28 +++++------ .../platform/soc_camera/sh_mobile_csi2.c | 35 +++++++------- 21 files changed, 304 insertions(+), 283 deletions(-) diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index 9d58b750ef1ef5..e2dd1617662fb0 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -431,10 +431,15 @@ static int adv7183_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int adv7183_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct adv7183 *decoder = to_adv7183(sd); + struct v4l2_mbus_framefmt *fmt = &format->format; + + if (format->pad) + return -EINVAL; fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -447,16 +452,10 @@ static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd, fmt->width = 720; fmt->height = 576; } - return 0; -} - -static int adv7183_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - struct adv7183 *decoder = to_adv7183(sd); - - adv7183_try_mbus_fmt(sd, fmt); - decoder->fmt = *fmt; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + decoder->fmt = *fmt; + else + cfg->try_fmt = *fmt; return 0; } @@ -519,14 +518,13 @@ static const struct v4l2_subdev_video_ops adv7183_video_ops = { .s_routing = adv7183_s_routing, .querystd = adv7183_querystd, .g_input_status = adv7183_g_input_status, - .try_mbus_fmt = adv7183_try_mbus_fmt, - .s_mbus_fmt = adv7183_s_mbus_fmt, .s_stream = adv7183_s_stream, }; static const struct v4l2_subdev_pad_ops adv7183_pad_ops = { .enum_mbus_code = adv7183_enum_mbus_code, .get_fmt = adv7183_get_fmt, + .set_fmt = adv7183_set_fmt, }; static const struct v4l2_subdev_ops adv7183_ops = { @@ -542,7 +540,9 @@ static int adv7183_probe(struct i2c_client *client, struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; int ret; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; const unsigned *pin_array; /* Check if the adapter supports the needed features */ @@ -612,9 +612,9 @@ static int adv7183_probe(struct i2c_client *client, adv7183_writeregs(sd, adv7183_init_regs, ARRAY_SIZE(adv7183_init_regs)); adv7183_s_std(sd, decoder->std); - fmt.width = 720; - fmt.height = 576; - adv7183_s_mbus_fmt(sd, &fmt); + fmt.format.width = 720; + fmt.format.height = 576; + adv7183_set_fmt(sd, NULL, &fmt); /* initialize the hardware to the default control values */ ret = v4l2_ctrl_handler_setup(hdl); diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c index 6fae8fce461783..57132cdba5ea2b 100644 --- a/drivers/media/i2c/mt9v011.c +++ b/drivers/media/i2c/mt9v011.c @@ -335,9 +335,14 @@ static int mt9v011_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) +static int mt9v011_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (fmt->code != MEDIA_BUS_FMT_SGRBG8_1X8) + struct v4l2_mbus_framefmt *fmt = &format->format; + struct mt9v011 *core = to_mt9v011(sd); + + if (format->pad || fmt->code != MEDIA_BUS_FMT_SGRBG8_1X8) return -EINVAL; v4l_bound_align_image(&fmt->width, 48, 639, 1, @@ -345,6 +350,15 @@ static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm fmt->field = V4L2_FIELD_NONE; fmt->colorspace = V4L2_COLORSPACE_SRGB; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + core->width = fmt->width; + core->height = fmt->height; + + set_res(sd); + } else { + cfg->try_fmt = *fmt; + } + return 0; } @@ -386,23 +400,6 @@ static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms) return 0; } -static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - struct mt9v011 *core = to_mt9v011(sd); - int rc; - - rc = mt9v011_try_mbus_fmt(sd, fmt); - if (rc < 0) - return -EINVAL; - - core->width = fmt->width; - core->height = fmt->height; - - set_res(sd); - - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9v011_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -470,14 +467,13 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = { }; static const struct v4l2_subdev_video_ops mt9v011_video_ops = { - .try_mbus_fmt = mt9v011_try_mbus_fmt, - .s_mbus_fmt = mt9v011_s_mbus_fmt, .g_parm = mt9v011_g_parm, .s_parm = mt9v011_s_parm, }; static const struct v4l2_subdev_pad_ops mt9v011_pad_ops = { .enum_mbus_code = mt9v011_enum_mbus_code, + .set_fmt = mt9v011_set_fmt, }; static const struct v4l2_subdev_ops mt9v011_ops = { diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index 1033bd793fefc2..23053ce387637f 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -971,17 +971,12 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd, return 0; } -static int ov7670_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - return ov7670_try_fmt_internal(sd, fmt, NULL, NULL); -} - /* * Set a format. */ -static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int ov7670_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct ov7670_format_struct *ovfmt; struct ov7670_win_size *wsize; @@ -989,7 +984,18 @@ static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd, unsigned char com7; int ret; - ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize); + if (format->pad) + return -EINVAL; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL); + if (ret) + return ret; + cfg->try_fmt = format->format; + return 0; + } + + ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize); if (ret) return ret; @@ -1486,8 +1492,6 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = { }; static const struct v4l2_subdev_video_ops ov7670_video_ops = { - .try_mbus_fmt = ov7670_try_mbus_fmt, - .s_mbus_fmt = ov7670_s_mbus_fmt, .s_parm = ov7670_s_parm, .g_parm = ov7670_g_parm, }; @@ -1496,6 +1500,7 @@ static const struct v4l2_subdev_pad_ops ov7670_pad_ops = { .enum_frame_interval = ov7670_enum_frame_interval, .enum_frame_size = ov7670_enum_frame_size, .enum_mbus_code = ov7670_enum_mbus_code, + .set_fmt = ov7670_set_fmt, }; static const struct v4l2_subdev_ops ov7670_ops = { diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index b3829078d646f4..ba3c4156644d50 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -574,10 +574,17 @@ static int saa6752hs_get_fmt(struct v4l2_subdev *sd, return 0; } -static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) +static int saa6752hs_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *f = &format->format; + struct saa6752hs_state *h = to_state(sd); int dist_352, dist_480, dist_720; + if (format->pad) + return -EINVAL; + f->code = MEDIA_BUS_FMT_FIXED; dist_352 = abs(f->width - 352); @@ -598,15 +605,11 @@ static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_frame } f->field = V4L2_FIELD_INTERLACED; f->colorspace = V4L2_COLORSPACE_SMPTE170M; - return 0; -} -static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f) -{ - struct saa6752hs_state *h = to_state(sd); - - if (f->code != MEDIA_BUS_FMT_FIXED) - return -EINVAL; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *f; + return 0; + } /* FIXME: translate and round width/height into EMPRESS @@ -620,7 +623,9 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm D1 | 720x576 | 720x480 */ - saa6752hs_try_mbus_fmt(sd, f); + if (f->code != MEDIA_BUS_FMT_FIXED) + return -EINVAL; + if (f->width == 720) h->video_format = SAA6752HS_VF_D1; else if (f->width == 480) @@ -653,12 +658,11 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = { static const struct v4l2_subdev_video_ops saa6752hs_video_ops = { .s_std = saa6752hs_s_std, - .s_mbus_fmt = saa6752hs_s_mbus_fmt, - .try_mbus_fmt = saa6752hs_try_mbus_fmt, }; static const struct v4l2_subdev_pad_ops saa6752hs_pad_ops = { .get_fmt = saa6752hs_get_fmt, + .set_fmt = saa6752hs_set_fmt, }; static const struct v4l2_subdev_ops saa6752hs_ops = { diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c index ba60ccfffa4f0f..f68c2352c63c4e 100644 --- a/drivers/media/i2c/soc_camera/imx074.c +++ b/drivers/media/i2c/soc_camera/imx074.c @@ -153,14 +153,24 @@ static int reg_read(struct i2c_client *client, const u16 addr) return buf[0] & 0xff; /* no sign-extension */ } -static int imx074_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int imx074_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code); + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct imx074 *priv = to_imx074(client); + + if (format->pad) + return -EINVAL; dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); if (!fmt) { + /* MIPI CSI could have changed the format, double-check */ + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; mf->code = imx074_colour_fmts[0].code; mf->colorspace = imx074_colour_fmts[0].colorspace; } @@ -169,24 +179,10 @@ static int imx074_try_fmt(struct v4l2_subdev *sd, mf->height = IMX074_HEIGHT; mf->field = V4L2_FIELD_NONE; - return 0; -} - -static int imx074_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct imx074 *priv = to_imx074(client); - - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); - - /* MIPI CSI could have changed the format, double-check */ - if (!imx074_find_datafmt(mf->code)) - return -EINVAL; - - imx074_try_fmt(sd, mf); - - priv->fmt = imx074_find_datafmt(mf->code); + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + priv->fmt = imx074_find_datafmt(mf->code); + else + cfg->try_fmt = *mf; return 0; } @@ -282,8 +278,6 @@ static int imx074_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops imx074_subdev_video_ops = { .s_stream = imx074_s_stream, - .s_mbus_fmt = imx074_s_fmt, - .try_mbus_fmt = imx074_try_fmt, .g_crop = imx074_g_crop, .cropcap = imx074_cropcap, .g_mbus_config = imx074_g_mbus_config, @@ -296,6 +290,7 @@ static struct v4l2_subdev_core_ops imx074_subdev_core_ops = { static const struct v4l2_subdev_pad_ops imx074_subdev_pad_ops = { .enum_mbus_code = imx074_enum_mbus_code, .get_fmt = imx074_get_fmt, + .set_fmt = imx074_set_fmt, }; static struct v4l2_subdev_ops imx074_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c index 06f4e116978de1..4fbdd1e9f7ee0e 100644 --- a/drivers/media/i2c/soc_camera/mt9m001.c +++ b/drivers/media/i2c/soc_camera/mt9m001.c @@ -205,7 +205,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) /* * The caller provides a supported format, as verified per - * call to .try_mbus_fmt() + * call to .set_fmt(FORMAT_TRY). */ if (!ret) ret = reg_write(client, MT9M001_COLUMN_START, rect.left); @@ -298,13 +298,18 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd, return ret; } -static int mt9m001_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m001_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m001 *mt9m001 = to_mt9m001(client); const struct mt9m001_datafmt *fmt; + if (format->pad) + return -EINVAL; + v4l_bound_align_image(&mf->width, MT9M001_MIN_WIDTH, MT9M001_MAX_WIDTH, 1, &mf->height, MT9M001_MIN_HEIGHT + mt9m001->y_skip_top, @@ -322,6 +327,9 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd, mf->colorspace = fmt->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9m001_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -617,8 +625,6 @@ static int mt9m001_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = { .s_stream = mt9m001_s_stream, - .s_mbus_fmt = mt9m001_s_fmt, - .try_mbus_fmt = mt9m001_try_fmt, .s_crop = mt9m001_s_crop, .g_crop = mt9m001_g_crop, .cropcap = mt9m001_cropcap, @@ -633,6 +639,7 @@ static struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = { static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = { .enum_mbus_code = mt9m001_enum_mbus_code, .get_fmt = mt9m001_get_fmt, + .set_fmt = mt9m001_set_fmt, }; static struct v4l2_subdev_ops mt9m001_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c index 7ac87b112a11c1..6dfaead6aaa834 100644 --- a/drivers/media/i2c/soc_camera/mt9m111.c +++ b/drivers/media/i2c/soc_camera/mt9m111.c @@ -536,14 +536,20 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111, return ret; } -static int mt9m111_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9m111_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); const struct mt9m111_datafmt *fmt; struct v4l2_rect *rect = &mt9m111->rect; bool bayer; + int ret; + + if (format->pad) + return -EINVAL; fmt = mt9m111_find_datafmt(mt9m111, mf->code); @@ -577,20 +583,10 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd, mf->code = fmt->code; mf->colorspace = fmt->colorspace; - return 0; -} - -static int mt9m111_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - const struct mt9m111_datafmt *fmt; - struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev); - struct v4l2_rect *rect = &mt9m111->rect; - int ret; - - mt9m111_try_fmt(sd, mf); - fmt = mt9m111_find_datafmt(mt9m111, mf->code); - /* try_fmt() guarantees fmt != NULL && fmt->code == mf->code */ + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } ret = mt9m111_setup_geometry(mt9m111, rect, mf->width, mf->height, mf->code); if (!ret) @@ -871,8 +867,6 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd, } static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { - .s_mbus_fmt = mt9m111_s_fmt, - .try_mbus_fmt = mt9m111_try_fmt, .s_crop = mt9m111_s_crop, .g_crop = mt9m111_g_crop, .cropcap = mt9m111_cropcap, @@ -882,6 +876,7 @@ static struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = { static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = { .enum_mbus_code = mt9m111_enum_mbus_code, .get_fmt = mt9m111_get_fmt, + .set_fmt = mt9m111_set_fmt, }; static struct v4l2_subdev_ops mt9m111_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c index 97193e471ab557..3b6eeed2e2b96d 100644 --- a/drivers/media/i2c/soc_camera/mt9t031.c +++ b/drivers/media/i2c/soc_camera/mt9t031.c @@ -264,7 +264,7 @@ static int mt9t031_set_params(struct i2c_client *client, /* * The caller provides a supported format, as guaranteed by - * .try_mbus_fmt(), soc_camera_s_crop() and soc_camera_cropcap() + * .set_fmt(FORMAT_TRY), soc_camera_s_crop() and soc_camera_cropcap() */ if (ret >= 0) ret = reg_write(client, MT9T031_COLUMN_START, rect->left); @@ -357,16 +357,36 @@ static int mt9t031_get_fmt(struct v4l2_subdev *sd, return 0; } -static int mt9t031_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +/* + * If a user window larger than sensor window is requested, we'll increase the + * sensor window. + */ +static int mt9t031_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t031 *mt9t031 = to_mt9t031(client); u16 xskip, yskip; struct v4l2_rect rect = mt9t031->rect; + if (format->pad) + return -EINVAL; + + mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; + mf->colorspace = V4L2_COLORSPACE_SRGB; + v4l_bound_align_image( + &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, + &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } + /* - * try_fmt has put width and height within limits. + * Width and height are within limits. * S_FMT: use binning and skipping for scaling */ xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH); @@ -379,23 +399,6 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd, return mt9t031_set_params(client, &rect, xskip, yskip); } -/* - * If a user window larger than sensor window is requested, we'll increase the - * sensor window. - */ -static int mt9t031_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - v4l_bound_align_image( - &mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1, - &mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0); - - mf->code = MEDIA_BUS_FMT_SBGGR10_1X10; - mf->colorspace = V4L2_COLORSPACE_SRGB; - - return 0; -} - #ifdef CONFIG_VIDEO_ADV_DEBUG static int mt9t031_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) @@ -718,8 +721,6 @@ static int mt9t031_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9t031_subdev_video_ops = { .s_stream = mt9t031_s_stream, - .s_mbus_fmt = mt9t031_s_fmt, - .try_mbus_fmt = mt9t031_try_fmt, .s_crop = mt9t031_s_crop, .g_crop = mt9t031_g_crop, .cropcap = mt9t031_cropcap, @@ -734,6 +735,7 @@ static struct v4l2_subdev_sensor_ops mt9t031_subdev_sensor_ops = { static const struct v4l2_subdev_pad_ops mt9t031_subdev_pad_ops = { .enum_mbus_code = mt9t031_enum_mbus_code, .get_fmt = mt9t031_get_fmt, + .set_fmt = mt9t031_set_fmt, }; static struct v4l2_subdev_ops mt9t031_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 889e98ee8c6203..de10a76ba6dfb8 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -945,14 +945,19 @@ static int mt9t112_s_fmt(struct v4l2_subdev *sd, return ret; } -static int mt9t112_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9t112_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9t112_priv *priv = to_mt9t112(client); unsigned int top, left; int i; + if (format->pad) + return -EINVAL; + for (i = 0; i < priv->num_formats; i++) if (mt9t112_cfmts[i].code == mf->code) break; @@ -968,6 +973,9 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9t112_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -1016,8 +1024,6 @@ static int mt9t112_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { .s_stream = mt9t112_s_stream, - .s_mbus_fmt = mt9t112_s_fmt, - .try_mbus_fmt = mt9t112_try_fmt, .cropcap = mt9t112_cropcap, .g_crop = mt9t112_g_crop, .s_crop = mt9t112_s_crop, @@ -1028,6 +1034,7 @@ static struct v4l2_subdev_video_ops mt9t112_subdev_video_ops = { static const struct v4l2_subdev_pad_ops mt9t112_subdev_pad_ops = { .enum_mbus_code = mt9t112_enum_mbus_code, .get_fmt = mt9t112_get_fmt, + .set_fmt = mt9t112_set_fmt, }; /************************************************************************ diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index b4ba3c5930e3a1..f31377408550ba 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -412,7 +412,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, /* * The caller provides a supported format, as verified per call to - * .try_mbus_fmt(), datawidth is from our supported format list + * .set_fmt(FORMAT_TRY), datawidth is from our supported format list */ switch (mf->code) { case MEDIA_BUS_FMT_Y8_1X8: @@ -442,15 +442,20 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd, return ret; } -static int mt9v022_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int mt9v022_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); const struct mt9v022_datafmt *fmt; int align = mf->code == MEDIA_BUS_FMT_SBGGR8_1X8 || mf->code == MEDIA_BUS_FMT_SBGGR10_1X10; + if (format->pad) + return -EINVAL; + v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH, MT9V022_MAX_WIDTH, align, &mf->height, MT9V022_MIN_HEIGHT + mt9v022->y_skip_top, @@ -465,6 +470,9 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd, mf->colorspace = fmt->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return mt9v022_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -845,8 +853,6 @@ static int mt9v022_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops mt9v022_subdev_video_ops = { .s_stream = mt9v022_s_stream, - .s_mbus_fmt = mt9v022_s_fmt, - .try_mbus_fmt = mt9v022_try_fmt, .s_crop = mt9v022_s_crop, .g_crop = mt9v022_g_crop, .cropcap = mt9v022_cropcap, @@ -861,6 +867,7 @@ static struct v4l2_subdev_sensor_ops mt9v022_subdev_sensor_ops = { static const struct v4l2_subdev_pad_ops mt9v022_subdev_pad_ops = { .enum_mbus_code = mt9v022_enum_mbus_code, .get_fmt = mt9v022_get_fmt, + .set_fmt = mt9v022_set_fmt, }; static struct v4l2_subdev_ops mt9v022_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 0dffc63ee83fdc..9b4f5deec748dc 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -881,33 +881,16 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, return 0; } -static int ov2640_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov2640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - switch (mf->code) { - case MEDIA_BUS_FMT_RGB565_2X8_BE: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = MEDIA_BUS_FMT_UYVY8_2X8; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - - ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code); - - return ret; -} + if (format->pad) + return -EINVAL; -static int ov2640_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ /* * select suitable win, but don't store it */ @@ -927,6 +910,10 @@ static int ov2640_try_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov2640_set_params(client, &mf->width, + &mf->height, mf->code); + cfg->try_fmt = *mf; return 0; } @@ -1037,8 +1024,6 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { .s_stream = ov2640_s_stream, - .s_mbus_fmt = ov2640_s_fmt, - .try_mbus_fmt = ov2640_try_fmt, .cropcap = ov2640_cropcap, .g_crop = ov2640_g_crop, .g_mbus_config = ov2640_g_mbus_config, @@ -1047,6 +1032,7 @@ static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov2640_subdev_pad_ops = { .enum_mbus_code = ov2640_enum_mbus_code, .get_fmt = ov2640_get_fmt, + .set_fmt = ov2640_set_fmt, }; static struct v4l2_subdev_ops ov2640_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c index a88397f60b8c15..bab9ac0c176481 100644 --- a/drivers/media/i2c/soc_camera/ov5642.c +++ b/drivers/media/i2c/soc_camera/ov5642.c @@ -786,39 +786,34 @@ static int ov5642_set_resolution(struct v4l2_subdev *sd) return ret; } -static int ov5642_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov5642_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov5642 *priv = to_ov5642(client); const struct ov5642_datafmt *fmt = ov5642_find_datafmt(mf->code); + if (format->pad) + return -EINVAL; + mf->width = priv->crop_rect.width; mf->height = priv->crop_rect.height; if (!fmt) { + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return -EINVAL; mf->code = ov5642_colour_fmts[0].code; mf->colorspace = ov5642_colour_fmts[0].colorspace; } mf->field = V4L2_FIELD_NONE; - return 0; -} - -static int ov5642_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov5642 *priv = to_ov5642(client); - - /* MIPI CSI could have changed the format, double-check */ - if (!ov5642_find_datafmt(mf->code)) - return -EINVAL; - - ov5642_try_fmt(sd, mf); - priv->fmt = ov5642_find_datafmt(mf->code); - + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + priv->fmt = ov5642_find_datafmt(mf->code); + else + cfg->try_fmt = *mf; return 0; } @@ -945,8 +940,6 @@ static int ov5642_s_power(struct v4l2_subdev *sd, int on) } static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { - .s_mbus_fmt = ov5642_s_fmt, - .try_mbus_fmt = ov5642_try_fmt, .s_crop = ov5642_s_crop, .g_crop = ov5642_g_crop, .cropcap = ov5642_cropcap, @@ -956,6 +949,7 @@ static struct v4l2_subdev_video_ops ov5642_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov5642_subdev_pad_ops = { .enum_mbus_code = ov5642_enum_mbus_code, .get_fmt = ov5642_get_fmt, + .set_fmt = ov5642_set_fmt, }; static struct v4l2_subdev_core_ops ov5642_subdev_core_ops = { diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c index 29f73a55a31244..1f8af1ee8352bf 100644 --- a/drivers/media/i2c/soc_camera/ov6650.c +++ b/drivers/media/i2c/soc_camera/ov6650.c @@ -685,16 +685,20 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) mf->width = priv->rect.width >> half_scale; mf->height = priv->rect.height >> half_scale; } - return ret; } -static int ov6650_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov6650_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); + if (format->pad) + return -EINVAL; + if (is_unscaled_ok(mf->width, mf->height, &priv->rect)) v4l_bound_align_image(&mf->width, 2, W_CIF, 1, &mf->height, 2, H_CIF, 1, 0); @@ -718,6 +722,10 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd, break; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov6650_s_fmt(sd, mf); + cfg->try_fmt = *mf; + return 0; } @@ -935,8 +943,6 @@ static int ov6650_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov6650_video_ops = { .s_stream = ov6650_s_stream, - .s_mbus_fmt = ov6650_s_fmt, - .try_mbus_fmt = ov6650_try_fmt, .cropcap = ov6650_cropcap, .g_crop = ov6650_g_crop, .s_crop = ov6650_s_crop, @@ -949,6 +955,7 @@ static struct v4l2_subdev_video_ops ov6650_video_ops = { static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { .enum_mbus_code = ov6650_enum_mbus_code, .get_fmt = ov6650_get_fmt, + .set_fmt = ov6650_set_fmt, }; static struct v4l2_subdev_ops ov6650_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 1db2044513845c..f150a8bd94dc8d 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -920,12 +920,17 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) return 0; } -static int ov772x_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov772x_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; const struct ov772x_color_format *cfmt; const struct ov772x_win_size *win; + if (format->pad) + return -EINVAL; + ov772x_select_params(mf, &cfmt, &win); mf->code = cfmt->code; @@ -934,6 +939,9 @@ static int ov772x_try_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; mf->colorspace = cfmt->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov772x_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -1022,8 +1030,6 @@ static int ov772x_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { .s_stream = ov772x_s_stream, - .s_mbus_fmt = ov772x_s_fmt, - .try_mbus_fmt = ov772x_try_fmt, .cropcap = ov772x_cropcap, .g_crop = ov772x_g_crop, .g_mbus_config = ov772x_g_mbus_config, @@ -1032,6 +1038,7 @@ static struct v4l2_subdev_video_ops ov772x_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov772x_subdev_pad_ops = { .enum_mbus_code = ov772x_enum_mbus_code, .get_fmt = ov772x_get_fmt, + .set_fmt = ov772x_set_fmt, }; static struct v4l2_subdev_ops ov772x_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c index 899b4d9352fe47..8caae1c075413d 100644 --- a/drivers/media/i2c/soc_camera/ov9640.c +++ b/drivers/media/i2c/soc_camera/ov9640.c @@ -519,9 +519,15 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd, return ret; } -static int ov9640_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov9640_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; + ov9640_res_roundup(&mf->width, &mf->height); mf->field = V4L2_FIELD_NONE; @@ -537,6 +543,10 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov9640_s_fmt(sd, mf); + + cfg->try_fmt = *mf; return 0; } @@ -657,8 +667,6 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov9640_video_ops = { .s_stream = ov9640_s_stream, - .s_mbus_fmt = ov9640_s_fmt, - .try_mbus_fmt = ov9640_try_fmt, .cropcap = ov9640_cropcap, .g_crop = ov9640_g_crop, .g_mbus_config = ov9640_g_mbus_config, @@ -666,6 +674,7 @@ static struct v4l2_subdev_video_ops ov9640_video_ops = { static const struct v4l2_subdev_pad_ops ov9640_pad_ops = { .enum_mbus_code = ov9640_enum_mbus_code, + .set_fmt = ov9640_set_fmt, }; static struct v4l2_subdev_ops ov9640_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 5d9b2492b7d246..03a7fc7316ae34 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -704,15 +704,24 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd, return ret; } -static int ov9740_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov9740_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; + + if (format->pad) + return -EINVAL; + ov9740_res_roundup(&mf->width, &mf->height); mf->field = V4L2_FIELD_NONE; mf->code = MEDIA_BUS_FMT_YUYV8_2X8; mf->colorspace = V4L2_COLORSPACE_SRGB; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov9740_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -905,8 +914,6 @@ static int ov9740_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov9740_video_ops = { .s_stream = ov9740_s_stream, - .s_mbus_fmt = ov9740_s_fmt, - .try_mbus_fmt = ov9740_try_fmt, .cropcap = ov9740_cropcap, .g_crop = ov9740_g_crop, .g_mbus_config = ov9740_g_mbus_config, @@ -922,6 +929,7 @@ static struct v4l2_subdev_core_ops ov9740_core_ops = { static const struct v4l2_subdev_pad_ops ov9740_pad_ops = { .enum_mbus_code = ov9740_enum_mbus_code, + .set_fmt = ov9740_set_fmt, }; static struct v4l2_subdev_ops ov9740_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c index 8787142493cc94..c769cf663f8423 100644 --- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c +++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c @@ -965,17 +965,25 @@ static int rj54n1_reg_init(struct i2c_client *client) return ret; } -static int rj54n1_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int rj54n1_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct rj54n1 *rj54n1 = to_rj54n1(client); const struct rj54n1_datafmt *fmt; + int output_w, output_h, max_w, max_h, + input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; int align = mf->code == MEDIA_BUS_FMT_SBGGR10_1X10 || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE || mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE; + int ret; + + if (format->pad) + return -EINVAL; dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", __func__, mf->code, mf->width, mf->height); @@ -993,24 +1001,10 @@ static int rj54n1_try_fmt(struct v4l2_subdev *sd, v4l_bound_align_image(&mf->width, 112, RJ54N1_MAX_WIDTH, align, &mf->height, 84, RJ54N1_MAX_HEIGHT, align, 0); - return 0; -} - -static int rj54n1_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct rj54n1 *rj54n1 = to_rj54n1(client); - const struct rj54n1_datafmt *fmt; - int output_w, output_h, max_w, max_h, - input_w = rj54n1->rect.width, input_h = rj54n1->rect.height; - int ret; - - /* - * The host driver can call us without .try_fmt(), so, we have to take - * care ourseleves - */ - rj54n1_try_fmt(sd, mf); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } /* * Verify if the sensor has just been powered on. TODO: replace this @@ -1026,9 +1020,6 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd, return ret; } - dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n", - __func__, mf->code, mf->width, mf->height); - /* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */ switch (mf->code) { case MEDIA_BUS_FMT_YUYV8_2X8: @@ -1255,8 +1246,6 @@ static int rj54n1_s_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { .s_stream = rj54n1_s_stream, - .s_mbus_fmt = rj54n1_s_fmt, - .try_mbus_fmt = rj54n1_try_fmt, .g_crop = rj54n1_g_crop, .s_crop = rj54n1_s_crop, .cropcap = rj54n1_cropcap, @@ -1267,6 +1256,7 @@ static struct v4l2_subdev_video_ops rj54n1_subdev_video_ops = { static const struct v4l2_subdev_pad_ops rj54n1_subdev_pad_ops = { .enum_mbus_code = rj54n1_enum_mbus_code, .get_fmt = rj54n1_get_fmt, + .set_fmt = rj54n1_set_fmt, }; static struct v4l2_subdev_ops rj54n1_subdev_ops = { diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 95837959f409af..42bec9bf1892b2 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -742,13 +742,18 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd, return ret; } -static int tw9910_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int tw9910_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct tw9910_priv *priv = to_tw9910(client); const struct tw9910_scale_ctrl *scale; + if (format->pad) + return -EINVAL; + if (V4L2_FIELD_ANY == mf->field) { mf->field = V4L2_FIELD_INTERLACED_BT; } else if (V4L2_FIELD_INTERLACED_BT != mf->field) { @@ -769,6 +774,9 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd, mf->width = scale->width; mf->height = scale->height; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return tw9910_s_fmt(sd, mf); + cfg->try_fmt = *mf; return 0; } @@ -886,8 +894,6 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { .s_std = tw9910_s_std, .g_std = tw9910_g_std, .s_stream = tw9910_s_stream, - .s_mbus_fmt = tw9910_s_fmt, - .try_mbus_fmt = tw9910_try_fmt, .cropcap = tw9910_cropcap, .g_crop = tw9910_g_crop, .g_mbus_config = tw9910_g_mbus_config, @@ -898,6 +904,7 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = { static const struct v4l2_subdev_pad_ops tw9910_subdev_pad_ops = { .enum_mbus_code = tw9910_enum_mbus_code, .get_fmt = tw9910_get_fmt, + .set_fmt = tw9910_set_fmt, }; static struct v4l2_subdev_ops tw9910_subdev_ops = { diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index c0fa94570c4fb5..b62b6ddc435651 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -529,25 +529,28 @@ static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd, } /* Return nearest media bus frame format. */ -static int sr030pc30_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int sr030pc30_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (!sd || !mf) - return -EINVAL; - - try_fmt(sd, mf); - return 0; -} + struct sr030pc30_info *info = sd ? to_sr030pc30(sd) : NULL; + const struct sr030pc30_format *fmt; + struct v4l2_mbus_framefmt *mf; -static int sr030pc30_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sr030pc30_info *info = to_sr030pc30(sd); + if (!sd || !format) + return -EINVAL; - if (!sd || !mf) + mf = &format->format; + if (format->pad) return -EINVAL; - info->curr_fmt = try_fmt(sd, mf); + fmt = try_fmt(sd, mf); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } + + info->curr_fmt = fmt; return sr030pc30_set_params(sd); } @@ -642,19 +645,14 @@ static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { .querymenu = v4l2_subdev_querymenu, }; -static const struct v4l2_subdev_video_ops sr030pc30_video_ops = { - .s_mbus_fmt = sr030pc30_s_fmt, - .try_mbus_fmt = sr030pc30_try_fmt, -}; - static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { .enum_mbus_code = sr030pc30_enum_mbus_code, .get_fmt = sr030pc30_get_fmt, + .set_fmt = sr030pc30_set_fmt, }; static const struct v4l2_subdev_ops sr030pc30_ops = { .core = &sr030pc30_core_ops, - .video = &sr030pc30_video_ops, .pad = &sr030pc30_pad_ops, }; diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 59f733524620a7..4c72a18c0b8c8a 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -568,11 +568,17 @@ static int vs6624_enum_mbus_code(struct v4l2_subdev *sd, return 0; } -static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) +static int vs6624_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *fmt = &format->format; + struct vs6624 *sensor = to_vs6624(sd); int index; + if (format->pad) + return -EINVAL; + for (index = 0; index < ARRAY_SIZE(vs6624_formats); index++) if (vs6624_formats[index].mbus_code == fmt->code) break; @@ -591,18 +597,11 @@ static int vs6624_try_mbus_fmt(struct v4l2_subdev *sd, fmt->height = fmt->height & (~3); fmt->field = V4L2_FIELD_NONE; fmt->colorspace = vs6624_formats[index].colorspace; - return 0; -} -static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt) -{ - struct vs6624 *sensor = to_vs6624(sd); - int ret; - - ret = vs6624_try_mbus_fmt(sd, fmt); - if (ret) - return ret; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *fmt; + return 0; + } /* set image format */ switch (fmt->code) { @@ -743,8 +742,6 @@ static const struct v4l2_subdev_core_ops vs6624_core_ops = { }; static const struct v4l2_subdev_video_ops vs6624_video_ops = { - .try_mbus_fmt = vs6624_try_mbus_fmt, - .s_mbus_fmt = vs6624_s_mbus_fmt, .s_parm = vs6624_s_parm, .g_parm = vs6624_g_parm, .s_stream = vs6624_s_stream, @@ -753,6 +750,7 @@ static const struct v4l2_subdev_video_ops vs6624_video_ops = { static const struct v4l2_subdev_pad_ops vs6624_pad_ops = { .enum_mbus_code = vs6624_enum_mbus_code, .get_fmt = vs6624_get_fmt, + .set_fmt = vs6624_set_fmt, }; static const struct v4l2_subdev_ops vs6624_ops = { diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c index cd93241eb4976c..12d3626ecf2221 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c +++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c @@ -45,11 +45,17 @@ struct sh_csi2 { static void sh_csi2_hwinit(struct sh_csi2 *priv); -static int sh_csi2_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int sh_csi2_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; + struct v4l2_mbus_framefmt *mf = &format->format; + u32 tmp = (priv->client->channel & 3) << 8; + + if (format->pad) + return -EINVAL; if (mf->width > 8188) mf->width = 8188; @@ -85,21 +91,11 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd, break; } - return 0; -} - -/* - * We have done our best in try_fmt to try and tell the sensor, which formats - * we support. If now the configuration is unsuitable for us we can only - * error out. - */ -static int sh_csi2_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ - struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev); - u32 tmp = (priv->client->channel & 3) << 8; + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + cfg->try_fmt = *mf; + return 0; + } - dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code); if (mf->width > 8188 || mf->width & 1) return -EINVAL; @@ -211,12 +207,14 @@ static int sh_csi2_s_mbus_config(struct v4l2_subdev *sd, } static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = { - .s_mbus_fmt = sh_csi2_s_fmt, - .try_mbus_fmt = sh_csi2_try_fmt, .g_mbus_config = sh_csi2_g_mbus_config, .s_mbus_config = sh_csi2_s_mbus_config, }; +static struct v4l2_subdev_pad_ops sh_csi2_subdev_pad_ops = { + .set_fmt = sh_csi2_set_fmt, +}; + static void sh_csi2_hwinit(struct sh_csi2 *priv) { struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data; @@ -313,6 +311,7 @@ static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops = { static struct v4l2_subdev_ops sh_csi2_subdev_ops = { .core = &sh_csi2_subdev_core_ops, .video = &sh_csi2_subdev_video_ops, + .pad = &sh_csi2_subdev_pad_ops, }; static int sh_csi2_probe(struct platform_device *pdev) From 5adf4a2e7b79daaf68572bd96034d571edfcbfca Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Apr 2015 04:05:35 -0300 Subject: [PATCH 225/381] [media] v4l2: replace try_mbus_fmt by set_fmt in bridge drivers Replace all calls to try_mbus_fmt in bridge drivers by calls to the set_fmt pad op. [mchehab@osg.samsung.com: fix a merge conflict at mcam-core.c] Signed-off-by: Hans Verkuil Cc: Guennadi Liakhovetski Acked-by: Scott Jiang Cc: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Josh Wu Conflicts: drivers/media/platform/marvell-ccic/mcam-core.c --- drivers/media/pci/saa7134/saa7134-empress.c | 11 +++-- .../media/platform/blackfin/bfin_capture.c | 15 ++++--- .../media/platform/marvell-ccic/mcam-core.c | 14 ++++--- drivers/media/platform/soc_camera/atmel-isi.c | 28 +++++++------ .../media/platform/soc_camera/mx2_camera.c | 38 +++++++++-------- .../media/platform/soc_camera/mx3_camera.c | 28 +++++++------ .../media/platform/soc_camera/omap1_camera.c | 26 +++++++----- .../media/platform/soc_camera/pxa_camera.c | 28 +++++++------ drivers/media/platform/soc_camera/rcar_vin.c | 42 ++++++++++--------- .../soc_camera/sh_mobile_ceu_camera.c | 38 +++++++++-------- drivers/media/platform/via-camera.c | 11 +++-- 11 files changed, 159 insertions(+), 120 deletions(-) diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 22632f9e34e6c2..dc14930be90942 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -157,11 +157,14 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + saa_call_all(dev, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 6ea11b1e755e60..aa50eba623c390 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -602,7 +602,10 @@ static int bcap_try_format(struct bcap_device *bcap, { struct bcap_format *sf = bcap->sensor_formats; struct bcap_format *fmt = NULL; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; int ret, i; for (i = 0; i < bcap->num_sensor_formats; i++) { @@ -613,16 +616,16 @@ static int bcap_try_format(struct bcap_device *bcap, if (i == bcap->num_sensor_formats) fmt = &sf[0]; - v4l2_fill_mbus_format(&mbus_fmt, pixfmt, fmt->mbus_code); - ret = v4l2_subdev_call(bcap->sd, video, - try_mbus_fmt, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, pixfmt, fmt->mbus_code); + ret = v4l2_subdev_call(bcap->sd, pad, set_fmt, &pad_cfg, + &format); if (ret < 0) return ret; - v4l2_fill_pix_format(pixfmt, &mbus_fmt); + v4l2_fill_pix_format(pixfmt, &format.format); if (bcap_fmt) { for (i = 0; i < bcap->num_sensor_formats; i++) { fmt = &sf[i]; - if (mbus_fmt.code == fmt->mbus_code) + if (format.format.code == fmt->mbus_code) break; } *bcap_fmt = *fmt; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 110fd70c73269d..44c5f62ab11ffe 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1413,16 +1413,18 @@ static int mcam_vidioc_try_fmt_vid_cap(struct file *filp, void *priv, struct mcam_camera *cam = priv; struct mcam_format_struct *f; struct v4l2_pix_format *pix = &fmt->fmt.pix; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; int ret; f = mcam_find_format(pix->pixelformat); pix->pixelformat = f->pixelformat; - v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code); - mutex_lock(&cam->s_mutex); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - mutex_unlock(&cam->s_mutex); - v4l2_fill_pix_format(pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, pix, f->mbus_code); + ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(pix, &format.format); + pix->bytesperline = pix->width * f->bpp; switch (f->pixelformat) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index cbb7e22cab40c7..903dbf27d0e07b 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -535,7 +535,11 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; u32 pixfmt = pix->pixelformat; int ret; @@ -552,21 +556,21 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, pix->width = MAX_SUPPORT_WIDTH; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: pix->field = V4L2_FIELD_NONE; break; @@ -574,7 +578,7 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, break; default: dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); ret = -EINVAL; } diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index a1b42645871973..d45f50a3a9ebfa 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1187,7 +1187,11 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); struct mx2_camera_dev *pcdev = ici->priv; @@ -1210,13 +1214,13 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, pix->width &= ~0x7; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; @@ -1227,29 +1231,29 @@ static int mx2_camera_try_fmt(struct soc_camera_device *icd, emma_prp = mx27_emma_prp_get_format(xlate->code, xlate->host_fmt->fourcc); - if ((mf.width != pix->width || mf.height != pix->height) && + if ((mf->width != pix->width || mf->height != pix->height) && emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { - if (mx2_emmaprp_resize(pcdev, &mf, pix, false) < 0) + if (mx2_emmaprp_resize(pcdev, mf, pix, false) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } - if (mf.field == V4L2_FIELD_ANY) - mf.field = V4L2_FIELD_NONE; + if (mf->field == V4L2_FIELD_ANY) + mf->field = V4L2_FIELD_NONE; /* * Driver supports interlaced images provided they have * both fields so that they can be processed as if they * were progressive. */ - if (mf.field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf.field)) { + if (mf->field != V4L2_FIELD_NONE && !V4L2_FIELD_HAS_BOTH(mf->field)) { dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); return -EINVAL; } - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", __func__, pix->width, pix->height); diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index 6c34dbb878b21a..f63501771072a7 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -912,7 +912,11 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int ret; @@ -929,21 +933,21 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, pix->width = 4096; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: pix->field = V4L2_FIELD_NONE; break; @@ -951,7 +955,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd, break; default: dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); ret = -EINVAL; } diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 6663645d1be443..2a715e1e22def1 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1322,7 +1322,11 @@ static int omap1_cam_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; /* TODO: limit to mx1 hardware capabilities */ @@ -1333,21 +1337,21 @@ static int omap1_cam_try_fmt(struct soc_camera_device *icd, return -EINVAL; } - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; /* limit to sensor capabilities */ - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; return 0; } diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 48999f3cb2bbda..7ccd76f7ca1ad4 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1488,7 +1488,11 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int ret; @@ -1509,22 +1513,22 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, pixfmt == V4L2_PIX_FMT_YUV422P ? 4 : 0); /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; + mf->width = pix->width; + mf->height = pix->height; /* Only progressive video supported so far */ - mf.field = V4L2_FIELD_NONE; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->field = V4L2_FIELD_NONE; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->colorspace = mf->colorspace; - switch (mf.field) { + switch (mf->field) { case V4L2_FIELD_ANY: case V4L2_FIELD_NONE: pix->field = V4L2_FIELD_NONE; @@ -1532,7 +1536,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd, default: /* TODO: support interlaced at least in pass-through mode */ dev_err(icd->parent, "Field type %d unsupported.\n", - mf.field); + mf->field); return -EINVAL; } diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 76b90dce3b0581..1fcc30e57da793 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1688,7 +1688,11 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int width, height; int ret; @@ -1715,25 +1719,25 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, pix->sizeimage = 0; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.code = xlate->code; - mf.colorspace = pix->colorspace; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->code = xlate->code; + mf->colorspace = pix->colorspace; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, try_mbus_fmt, &mf); + pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; /* Adjust only if VIN cannot scale */ - if (pix->width > mf.width * 2) - pix->width = mf.width * 2; - if (pix->height > mf.height * 3) - pix->height = mf.height * 3; + if (pix->width > mf->width * 2) + pix->width = mf->width * 2; + if (pix->height > mf->height * 3) + pix->height = mf->height * 3; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->field = mf->field; + pix->colorspace = mf->colorspace; if (pixfmt == V4L2_PIX_FMT_NV16) { /* FIXME: check against rect_max after converting soc-camera */ @@ -1744,12 +1748,12 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, * requested a bigger rectangle, it will not return a * smaller one. */ - mf.width = VIN_MAX_WIDTH; - mf.height = VIN_MAX_HEIGHT; + mf->width = VIN_MAX_WIDTH; + mf->height = VIN_MAX_HEIGHT; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, try_mbus_fmt, - &mf); + pad, set_fmt, &pad_cfg, + &format); if (ret < 0) { dev_err(icd->parent, "client try_fmt() = %d\n", ret); @@ -1757,9 +1761,9 @@ static int rcar_vin_try_fmt(struct soc_camera_device *icd, } } /* We will scale exactly */ - if (mf.width > width) + if (mf->width > width) pix->width = width; - if (mf.height > height) + if (mf->height > height) pix->height = height; } diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 566fd74c46396b..91c48ab6cd1369 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1499,7 +1499,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + struct v4l2_mbus_framefmt *mf = &format.format; __u32 pixfmt = pix->pixelformat; int width, height; int ret; @@ -1527,21 +1531,21 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, height = pix->height; /* limit to sensor capabilities */ - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.code = xlate->code; - mf.colorspace = pix->colorspace; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->code = xlate->code; + mf->colorspace = pix->colorspace; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, try_mbus_fmt, &mf); + pad, set_fmt, &pad_cfg, &format); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; switch (pixfmt) { case V4L2_PIX_FMT_NV12: @@ -1556,11 +1560,11 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, * requested a bigger rectangle, it will not return a * smaller one. */ - mf.width = pcdev->max_width; - mf.height = pcdev->max_height; + mf->width = pcdev->max_width; + mf->height = pcdev->max_height; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - try_mbus_fmt, &mf); + soc_camera_grp_id(icd), pad, + set_fmt, &pad_cfg, &format); if (ret < 0) { /* Shouldn't actually happen... */ dev_err(icd->parent, @@ -1569,9 +1573,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd, } } /* We will scale exactly */ - if (mf.width > width) + if (mf->width > width) pix->width = width; - if (mf.height > height) + if (mf->height > height) pix->height = height; pix->bytesperline = max(pix->bytesperline, pix->width); diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 678ed9f353cbb6..6331d6b99d23ba 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -903,14 +903,17 @@ static int viacam_do_try_fmt(struct via_camera *cam, struct v4l2_pix_format *upix, struct v4l2_pix_format *spix) { int ret; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; struct via_format *f = via_find_format(upix->pixelformat); upix->pixelformat = f->pixelformat; viacam_fmt_pre(upix, spix); - v4l2_fill_mbus_format(&mbus_fmt, spix, f->mbus_code); - ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(spix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, spix, f->mbus_code); + ret = sensor_call(cam, pad, set_fmt, &pad_cfg, &format); + v4l2_fill_pix_format(spix, &format.format); viacam_fmt_post(upix, spix); return ret; } From 5d68853c33195f61a8443d8bfef2fcdb9260ccb2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 9 Apr 2015 04:05:59 -0300 Subject: [PATCH 226/381] [media] v4l2: replace s_mbus_fmt by set_fmt in bridge drivers Replace all calls to s_mbus_fmt in bridge drivers by calls to the set_fmt pad op. Remove the old try/s_mbus_fmt video ops since they are now no longer used. Signed-off-by: Hans Verkuil Cc: Guennadi Liakhovetski Acked-by: Prabhakar Lad Acked-by: Scott Jiang Cc: Jonathan Corbet Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-controls.c | 13 ++-- drivers/media/pci/cx18/cx18-ioctl.c | 12 ++-- drivers/media/pci/cx23885/cx23885-video.c | 12 ++-- drivers/media/pci/ivtv/ivtv-controls.c | 12 ++-- drivers/media/pci/ivtv/ivtv-ioctl.c | 12 ++-- drivers/media/pci/saa7134/saa7134-empress.c | 10 +-- drivers/media/platform/am437x/am437x-vpfe.c | 19 +----- .../media/platform/blackfin/bfin_capture.c | 8 ++- .../media/platform/marvell-ccic/mcam-core.c | 8 ++- drivers/media/platform/sh_vou.c | 61 ++++++++++--------- drivers/media/platform/soc_camera/atmel-isi.c | 27 ++++---- .../media/platform/soc_camera/mx2_camera.c | 35 ++++++----- .../media/platform/soc_camera/mx3_camera.c | 31 +++++----- .../media/platform/soc_camera/omap1_camera.c | 44 +++++++------ .../media/platform/soc_camera/pxa_camera.c | 33 +++++----- drivers/media/platform/soc_camera/rcar_vin.c | 4 +- .../soc_camera/sh_mobile_ceu_camera.c | 8 +-- .../platform/soc_camera/soc_scale_crop.c | 37 ++++++----- drivers/media/platform/via-camera.c | 8 ++- drivers/media/usb/cx231xx/cx231xx-417.c | 12 ++-- drivers/media/usb/cx231xx/cx231xx-video.c | 23 ++++--- drivers/media/usb/em28xx/em28xx-camera.c | 12 ++-- drivers/media/usb/go7007/go7007-v4l2.c | 12 ++-- drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 17 +++--- include/media/v4l2-subdev.h | 8 --- 25 files changed, 256 insertions(+), 222 deletions(-) diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c index 4aeb7c6b8ce1a7..71227a155cba5c 100644 --- a/drivers/media/pci/cx18/cx18-controls.c +++ b/drivers/media/pci/cx18/cx18-controls.c @@ -93,13 +93,16 @@ static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *fmt = &format.format; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); + fmt->width = cxhdl->width / (is_mpeg1 ? 2 : 1); + fmt->height = cxhdl->height; + fmt->code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 79aee30d5fd863..55525af1f4826d 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -267,7 +267,9 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct cx18_stream *s = &cx->streams[id->type]; int ret; int w, h; @@ -296,10 +298,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, s->vb_bytes_per_line = 1440; /* Packed */ } - mbus_fmt.width = cx->cxhdl.width = w; - mbus_fmt.height = cx->cxhdl.height = h; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); + format.format.width = cx->cxhdl.width = w; + format.format.height = cx->cxhdl.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); return cx18_g_fmt_vid_cap(file, fh, fmt); } diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 2232b389c441dc..ec76470d12a47b 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -581,7 +581,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx23885_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int err; dprintk(2, "%s()\n", __func__); @@ -600,10 +602,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, dev->width, dev->height, dev->field); - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); - /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */ + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); + /* set_fmt overwrites f->fmt.pix.field, restore it */ f->fmt.pix.field = dev->field; return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c index ccf548c255f121..8a55ccb8f0c97e 100644 --- a/drivers/media/pci/ivtv/ivtv-controls.c +++ b/drivers/media/pci/ivtv/ivtv-controls.c @@ -64,13 +64,15 @@ static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt); + format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + format.format.height = cxhdl->height; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 6fe6c4a0e85854..10c31cd43e0356 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -581,7 +581,9 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f { struct ivtv_open_id *id = fh2id(fh); struct ivtv *itv = id->itv; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret = ivtv_try_fmt_vid_cap(file, fh, fmt); int w = fmt->fmt.pix.width; int h = fmt->fmt.pix.height; @@ -599,10 +601,10 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f itv->cxhdl.height = h; if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) fmt->fmt.pix.width /= 2; - mbus_fmt.width = fmt->fmt.pix.width; - mbus_fmt.height = h; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt); + format.format.width = fmt->fmt.pix.width; + format.format.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(itv->sd_video, pad, set_fmt, NULL, &format); return ivtv_g_fmt_vid_cap(file, fh, fmt); } diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index dc14930be90942..c9118e0cbe005d 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -140,11 +140,13 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct saa7134_dev *dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + saa_call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 57403f5d76e3b9..064c91574a9d6a 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1455,7 +1455,6 @@ static int __vpfe_get_format(struct vpfe_device *vpfe, static int __vpfe_set_format(struct vpfe_device *vpfe, struct v4l2_format *format, unsigned int *bpp) { - struct v4l2_mbus_framefmt mbus_fmt; struct vpfe_subdev_info *sdinfo; struct v4l2_subdev_format fmt; int ret; @@ -1472,23 +1471,11 @@ static int __vpfe_set_format(struct vpfe_device *vpfe, pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format); ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt); - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) + if (ret) return ret; - if (!ret) { - v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); - mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); - } else { - ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, - sdinfo->grp_id, - video, s_mbus_fmt, - &mbus_fmt); - if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - - v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt); - mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp); - } + v4l2_fill_pix_format(&format->fmt.pix, &fmt.format); + mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp); format->type = vpfe->fmt.type; diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index aa50eba623c390..b7e70fb05eb81e 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -674,7 +674,9 @@ static int bcap_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { struct bcap_device *bcap_dev = video_drvdata(file); - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; struct bcap_format bcap_fmt; struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; int ret; @@ -687,8 +689,8 @@ static int bcap_s_fmt_vid_cap(struct file *file, void *priv, if (ret < 0) return ret; - v4l2_fill_mbus_format(&mbus_fmt, pixfmt, bcap_fmt.mbus_code); - ret = v4l2_subdev_call(bcap_dev->sd, video, s_mbus_fmt, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, pixfmt, bcap_fmt.mbus_code); + ret = v4l2_subdev_call(bcap_dev->sd, pad, set_fmt, NULL, &format); if (ret < 0) return ret; bcap_dev->fmt = *pixfmt; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 44c5f62ab11ffe..b61a6e946e31ac 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -998,13 +998,15 @@ static int mcam_cam_set_flip(struct mcam_camera *cam) static int mcam_cam_configure(struct mcam_camera *cam) { - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; - v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code); + v4l2_fill_mbus_format(&format.format, &cam->pix_format, cam->mbus_code); ret = sensor_call(cam, core, init, 0); if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); + ret = sensor_call(cam, pad, set_fmt, NULL, &format); /* * OV7670 does weird things if flip is set *before* format... */ diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index dde1ccc730be0c..829e85c26610ec 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -679,12 +679,14 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, unsigned int img_height_max; int pix_idx; struct sh_vou_geometry geo; - struct v4l2_mbus_framefmt mbfmt = { + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, /* Revisit: is this the correct code? */ - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .field = V4L2_FIELD_INTERLACED, - .colorspace = V4L2_COLORSPACE_SMPTE170M, + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, }; + struct v4l2_mbus_framefmt *mbfmt = &format.format; int ret; dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, @@ -720,27 +722,27 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, vou_adjust_output(&geo, vou_dev->std); - mbfmt.width = geo.output.width; - mbfmt.height = geo.output.height; - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_mbus_fmt, &mbfmt); + mbfmt->width = geo.output.width; + mbfmt->height = geo.output.height; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, + set_fmt, NULL, &format); /* Must be implemented, so, don't check for -ENOIOCTLCMD */ if (ret < 0) return ret; dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - geo.output.width, geo.output.height, mbfmt.width, mbfmt.height); + geo.output.width, geo.output.height, mbfmt->width, mbfmt->height); /* Sanity checks */ - if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || - (unsigned)mbfmt.height > img_height_max || - mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8) + if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH || + (unsigned)mbfmt->height > img_height_max || + mbfmt->code != MEDIA_BUS_FMT_YUYV8_2X8) return -EIO; - if (mbfmt.width != geo.output.width || - mbfmt.height != geo.output.height) { - geo.output.width = mbfmt.width; - geo.output.height = mbfmt.height; + if (mbfmt->width != geo.output.width || + mbfmt->height != geo.output.height) { + geo.output.width = mbfmt->width; + geo.output.height = mbfmt->height; vou_adjust_input(&geo, vou_dev->std); } @@ -942,11 +944,12 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; - struct v4l2_mbus_framefmt mbfmt = { + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, /* Revisit: is this the correct code? */ - .code = MEDIA_BUS_FMT_YUYV8_2X8, - .field = V4L2_FIELD_INTERLACED, - .colorspace = V4L2_COLORSPACE_SMPTE170M, + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, }; unsigned int img_height_max; int ret; @@ -984,22 +987,22 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) */ v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_crop, &sd_crop); - mbfmt.width = geo.output.width; - mbfmt.height = geo.output.height; - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, - s_mbus_fmt, &mbfmt); + format.format.width = geo.output.width; + format.format.height = geo.output.height; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, pad, + set_fmt, NULL, &format); /* Must be implemented, so, don't check for -ENOIOCTLCMD */ if (ret < 0) return ret; /* Sanity checks */ - if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH || - (unsigned)mbfmt.height > img_height_max || - mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8) + if ((unsigned)format.format.width > VOU_MAX_IMAGE_WIDTH || + (unsigned)format.format.height > img_height_max || + format.format.code != MEDIA_BUS_FMT_YUYV8_2X8) return -EIO; - geo.output.width = mbfmt.width; - geo.output.height = mbfmt.height; + geo.output.width = format.format.width; + geo.output.height = format.format.height; /* * No down-scaling. According to the API, current call has precedence: diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 903dbf27d0e07b..287902681164ff 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -487,7 +487,10 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -500,27 +503,27 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, dev_dbg(icd->parent, "Plan to set format %dx%d\n", pix->width, pix->height); - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; ret = configure_geometry(isi, pix->width, pix->height, xlate->code); if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; dev_dbg(icd->parent, "Finally set format %dx%d\n", diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c index d45f50a3a9ebfa..ea4c423f0cf871 100644 --- a/drivers/media/platform/soc_camera/mx2_camera.c +++ b/drivers/media/platform/soc_camera/mx2_camera.c @@ -1127,7 +1127,10 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; dev_dbg(icd->parent, "%s: requested params: width = %d, height = %d\n", @@ -1140,19 +1143,19 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); if (ret < 0 && ret != -ENOIOCTLCMD) return ret; /* Store width and height returned by the sensor for resizing */ - pcdev->s_width = mf.width; - pcdev->s_height = mf.height; + pcdev->s_width = mf->width; + pcdev->s_height = mf->height; dev_dbg(icd->parent, "%s: sensor params: width = %d, height = %d\n", __func__, pcdev->s_width, pcdev->s_height); @@ -1160,19 +1163,19 @@ static int mx2_camera_set_fmt(struct soc_camera_device *icd, xlate->host_fmt->fourcc); memset(pcdev->resizing, 0, sizeof(pcdev->resizing)); - if ((mf.width != pix->width || mf.height != pix->height) && + if ((mf->width != pix->width || mf->height != pix->height) && pcdev->emma_prp->cfg.in_fmt == PRP_CNTL_DATA_IN_YUV422) { - if (mx2_emmaprp_resize(pcdev, &mf, pix, true) < 0) + if (mx2_emmaprp_resize(pcdev, mf, pix, true) < 0) dev_dbg(icd->parent, "%s: can't resize\n", __func__); } - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; dev_dbg(icd->parent, "%s: returned params: width = %d, height = %d\n", diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c index f63501771072a7..ace41f53caca30 100644 --- a/drivers/media/platform/soc_camera/mx3_camera.c +++ b/drivers/media/platform/soc_camera/mx3_camera.c @@ -828,7 +828,7 @@ static int mx3_camera_set_crop(struct soc_camera_device *icd, if (mf->width & 7) { /* Ouch! We can only handle 8-byte aligned width... */ stride_align(&mf->width); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); if (ret < 0) return ret; } @@ -854,7 +854,10 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -875,17 +878,17 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, configure_geometry(mx3_cam, pix->width, pix->height, xlate->host_fmt); - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); if (ret < 0) return ret; - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; if (!mx3_cam->idmac_channel[0]) { @@ -894,11 +897,11 @@ static int mx3_camera_set_fmt(struct soc_camera_device *icd, return ret; } - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - mx3_cam->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + mx3_cam->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; dev_dbg(icd->parent, "Sensor set %dx%d\n", pix->width, pix->height); diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c index 2a715e1e22def1..ba8dcd11ae0ec9 100644 --- a/drivers/media/platform/soc_camera/omap1_camera.c +++ b/drivers/media/platform/soc_camera/omap1_camera.c @@ -1157,7 +1157,7 @@ static int dma_align(int *width, int *height, return 1; } -#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \ +#define subdev_call_with_sense(pcdev, dev, icd, sd, op, function, args...) \ ({ \ struct soc_camera_sense sense = { \ .master_clock = pcdev->camexclk, \ @@ -1168,7 +1168,7 @@ static int dma_align(int *width, int *height, if (pcdev->pdata) \ sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \ icd->sense = &sense; \ - __ret = v4l2_subdev_call(sd, video, function, ##args); \ + __ret = v4l2_subdev_call(sd, op, function, ##args); \ icd->sense = NULL; \ \ if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \ @@ -1182,16 +1182,17 @@ static int dma_align(int *width, int *height, __ret; \ }) -static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev, +static int set_format(struct omap1_cam_dev *pcdev, struct device *dev, struct soc_camera_device *icd, struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf, + struct v4l2_subdev_format *format, const struct soc_camera_format_xlate *xlate) { s32 bytes_per_line; - int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf); + struct v4l2_mbus_framefmt *mf = &format->format; + int ret = subdev_call_with_sense(pcdev, dev, icd, sd, pad, set_fmt, NULL, format); if (ret < 0) { - dev_err(dev, "%s: s_mbus_fmt failed\n", __func__); + dev_err(dev, "%s: set_fmt failed\n", __func__); return ret; } @@ -1230,7 +1231,7 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd, struct v4l2_mbus_framefmt *mf = &fmt.format; int ret; - ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop); + ret = subdev_call_with_sense(pcdev, dev, icd, sd, video, s_crop, crop); if (ret < 0) { dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__, rect->width, rect->height, rect->left, rect->top); @@ -1254,7 +1255,7 @@ static int omap1_cam_set_crop(struct soc_camera_device *icd, if (!ret) { /* sensor returned geometry not DMA aligned, trying to fix */ - ret = set_mbus_format(pcdev, dev, icd, sd, mf, xlate); + ret = set_format(pcdev, dev, icd, sd, &fmt, xlate); if (ret < 0) { dev_err(dev, "%s: failed to set format\n", __func__); return ret; @@ -1276,7 +1277,10 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd, struct soc_camera_host *ici = to_soc_camera_host(dev); struct omap1_cam_dev *pcdev = ici->priv; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1286,13 +1290,13 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode, + ret = dma_align(&mf->width, &mf->height, xlate->host_fmt, pcdev->vb_mode, true); if (ret < 0) { dev_err(dev, "%s: failed to align %ux%u %s with DMA\n", @@ -1301,16 +1305,16 @@ static int omap1_cam_set_fmt(struct soc_camera_device *icd, return ret; } - ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate); + ret = set_format(pcdev, dev, icd, sd, &format, xlate); if (ret < 0) { dev_err(dev, "%s: failed to set format\n", __func__); return ret; } - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; return 0; diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c index 7ccd76f7ca1ad4..fcb942de0c7f06 100644 --- a/drivers/media/platform/soc_camera/pxa_camera.c +++ b/drivers/media/platform/soc_camera/pxa_camera.c @@ -1383,7 +1383,7 @@ static int pxa_camera_set_crop(struct soc_camera_device *icd, v4l_bound_align_image(&mf->width, 48, 2048, 1, &mf->height, 32, 2048, 0, fourcc == V4L2_PIX_FMT_YUV422P ? 4 : 0); - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &fmt); if (ret < 0) return ret; @@ -1425,7 +1425,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, .pixel_clock_max = pcdev->ciclk / 4, }; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_mbus_framefmt mf; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct v4l2_mbus_framefmt *mf = &format.format; int ret; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1439,15 +1442,15 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, /* The caller holds a mutex. */ icd->sense = &sense; - mf.width = pix->width; - mf.height = pix->height; - mf.field = pix->field; - mf.colorspace = pix->colorspace; - mf.code = xlate->code; + mf->width = pix->width; + mf->height = pix->height; + mf->field = pix->field; + mf->colorspace = pix->colorspace; + mf->code = xlate->code; - ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf); + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); - if (mf.code != xlate->code) + if (mf->code != xlate->code) return -EINVAL; icd->sense = NULL; @@ -1455,10 +1458,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, if (ret < 0) { dev_warn(dev, "Failed to configure for format %x\n", pix->pixelformat); - } else if (pxa_camera_check_frame(mf.width, mf.height)) { + } else if (pxa_camera_check_frame(mf->width, mf->height)) { dev_warn(dev, "Camera driver produced an unsupported frame %dx%d\n", - mf.width, mf.height); + mf->width, mf->height); ret = -EINVAL; } else if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { if (sense.pixel_clock > sense.pixel_clock_max) { @@ -1473,10 +1476,10 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd, if (ret < 0) return ret; - pix->width = mf.width; - pix->height = mf.height; - pix->field = mf.field; - pix->colorspace = mf.colorspace; + pix->width = mf->width; + pix->height = mf->height; + pix->field = mf->field; + pix->colorspace = mf->colorspace; icd->current_fmt = xlate; return ret; diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c index 1fcc30e57da793..4c30d0dbdb301e 100644 --- a/drivers/media/platform/soc_camera/rcar_vin.c +++ b/drivers/media/platform/soc_camera/rcar_vin.c @@ -1381,8 +1381,8 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx, mf->height = 960 >> shift; ret = v4l2_device_call_until_err(sd->v4l2_dev, soc_camera_grp_id(icd), - video, s_mbus_fmt, - mf); + pad, set_fmt, NULL, + &fmt); if (ret < 0) return ret; } diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 91c48ab6cd1369..c5c6c4e91f7b4d 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1111,8 +1111,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int mf->width = 2560 >> shift; mf->height = 1920 >> shift; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, &fmt); if (ret < 0) return ret; shift++; @@ -1286,8 +1286,8 @@ static int sh_mobile_ceu_set_crop(struct soc_camera_device *icd, if (interm_width < icd->user_width || interm_height < icd->user_height) { ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, &fmt); if (ret < 0) return ret; diff --git a/drivers/media/platform/soc_camera/soc_scale_crop.c b/drivers/media/platform/soc_camera/soc_scale_crop.c index 8e74fb7f2a078f..bda29bc1b9331c 100644 --- a/drivers/media/platform/soc_camera/soc_scale_crop.c +++ b/drivers/media/platform/soc_camera/soc_scale_crop.c @@ -211,22 +211,23 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd, } EXPORT_SYMBOL(soc_camera_client_s_crop); -/* Iterative s_mbus_fmt, also updates cached client crop on success */ -static int client_s_fmt(struct soc_camera_device *icd, +/* Iterative set_fmt, also updates cached client crop on success */ +static int client_set_fmt(struct soc_camera_device *icd, struct v4l2_rect *rect, struct v4l2_rect *subrect, unsigned int max_width, unsigned int max_height, - struct v4l2_mbus_framefmt *mf, bool host_can_scale) + struct v4l2_subdev_format *format, bool host_can_scale) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct device *dev = icd->parent; + struct v4l2_mbus_framefmt *mf = &format->format; unsigned int width = mf->width, height = mf->height, tmp_w, tmp_h; struct v4l2_cropcap cap; bool host_1to1; int ret; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, format); if (ret < 0) return ret; @@ -265,8 +266,8 @@ static int client_s_fmt(struct soc_camera_device *icd, mf->width = tmp_w; mf->height = tmp_h; ret = v4l2_device_call_until_err(sd->v4l2_dev, - soc_camera_grp_id(icd), video, - s_mbus_fmt, mf); + soc_camera_grp_id(icd), pad, + set_fmt, NULL, format); dev_geo(dev, "Camera scaled to %ux%u\n", mf->width, mf->height); if (ret < 0) { @@ -309,7 +310,11 @@ int soc_camera_client_scale(struct soc_camera_device *icd, bool host_can_scale, unsigned int shift) { struct device *dev = icd->parent; - struct v4l2_mbus_framefmt mf_tmp = *mf; + struct v4l2_subdev_format fmt_tmp = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + .format = *mf, + }; + struct v4l2_mbus_framefmt *mf_tmp = &fmt_tmp.format; unsigned int scale_h, scale_v; int ret; @@ -317,25 +322,25 @@ int soc_camera_client_scale(struct soc_camera_device *icd, * 5. Apply iterative camera S_FMT for camera user window (also updates * client crop cache and the imaginary sub-rectangle). */ - ret = client_s_fmt(icd, rect, subrect, *width, *height, - &mf_tmp, host_can_scale); + ret = client_set_fmt(icd, rect, subrect, *width, *height, + &fmt_tmp, host_can_scale); if (ret < 0) return ret; dev_geo(dev, "5: camera scaled to %ux%u\n", - mf_tmp.width, mf_tmp.height); + mf_tmp->width, mf_tmp->height); /* 6. Retrieve camera output window (g_fmt) */ /* unneeded - it is already in "mf_tmp" */ /* 7. Calculate new client scales. */ - scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp.width); - scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp.height); + scale_h = soc_camera_calc_scale(rect->width, shift, mf_tmp->width); + scale_v = soc_camera_calc_scale(rect->height, shift, mf_tmp->height); - mf->width = mf_tmp.width; - mf->height = mf_tmp.height; - mf->colorspace = mf_tmp.colorspace; + mf->width = mf_tmp->width; + mf->height = mf_tmp->height; + mf->colorspace = mf_tmp->colorspace; /* * 8. Calculate new host crop - apply camera scales to previously diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 6331d6b99d23ba..32e4ff46daf336 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -249,13 +249,15 @@ static int viacam_set_flip(struct via_camera *cam) */ static int viacam_configure_sensor(struct via_camera *cam) { - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int ret; - v4l2_fill_mbus_format(&mbus_fmt, &cam->sensor_format, cam->mbus_code); + v4l2_fill_mbus_format(&format.format, &cam->sensor_format, cam->mbus_code); ret = sensor_call(cam, core, init, 0); if (ret == 0) - ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt); + ret = sensor_call(cam, pad, set_fmt, NULL, &format); /* * OV7670 does weird things if flip is set *before* format... */ diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 983ea83391540a..3474af7d740948 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1878,13 +1878,15 @@ static int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) { struct cx231xx *dev = container_of(cxhdl, struct cx231xx, mpeg_ctrl_handler); int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(dev->sd_cx25840, video, s_mbus_fmt, &fmt); + format.format.width = cxhdl->width / (is_mpeg1 ? 2 : 1); + format.format.height = cxhdl->height; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(dev->sd_cx25840, pad, set_fmt, NULL, &format); return 0; } diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index c261e160c158f9..af44f2d1c0a1a2 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1013,7 +1013,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct cx231xx *dev = fh->dev; int rc; struct cx231xx_fmt *fmt; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; rc = check_dev(dev); if (rc < 0) @@ -1041,9 +1043,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, dev->height = f->fmt.pix.height; dev->format = fmt; - v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); - call_all(dev, video, s_mbus_fmt, &mbus_fmt); - v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, MEDIA_BUS_FMT_FIXED); + call_all(dev, pad, set_fmt, NULL, &format); + v4l2_fill_pix_format(&f->fmt.pix, &format.format); return rc; } @@ -1061,7 +1063,9 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) { struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; int rc; rc = check_dev(dev); @@ -1085,11 +1089,10 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) /* We need to reset basic properties in the decoder related to resolution (since a standard change effects things like the number of lines in VACT, etc) */ - memset(&mbus_fmt, 0, sizeof(mbus_fmt)); - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - mbus_fmt.width = dev->width; - mbus_fmt.height = dev->height; - call_all(dev, video, s_mbus_fmt, &mbus_fmt); + format.format.code = MEDIA_BUS_FMT_FIXED; + format.format.width = dev->width; + format.format.height = dev->height; + call_all(dev, pad, set_fmt, NULL, &format); /* do mode control overrides */ cx231xx_do_mode_ctrl_overrides(dev); diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index a4b22c2c3ba7f9..ed0b3a87983e45 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -404,7 +404,9 @@ int em28xx_init_camera(struct em28xx *dev) .addr = client->addr, .platform_data = &camlink, }; - struct v4l2_mbus_framefmt fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; /* * FIXME: sensor supports resolutions up to 1600x1200, but @@ -425,10 +427,10 @@ int em28xx_init_camera(struct em28xx *dev) break; } - fmt.code = MEDIA_BUS_FMT_YUYV8_2X8; - fmt.width = 640; - fmt.height = 480; - v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt); + format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; + format.format.width = 640; + format.format.height = 480; + v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); /* NOTE: for UXGA=1600x1200 switch to 12MHz */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index d6bf982efa4251..c57207e268c372 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -250,15 +250,17 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try) go->encoder_v_offset = go->board_info->sensor_v_offset; if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) { - struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; - mbus_fmt.code = MEDIA_BUS_FMT_FIXED; - mbus_fmt.width = fmt ? fmt->fmt.pix.width : width; - mbus_fmt.height = height; + format.format.code = MEDIA_BUS_FMT_FIXED; + format.format.width = fmt ? fmt->fmt.pix.width : width; + format.format.height = height; go->encoder_h_halve = 0; go->encoder_v_halve = 0; go->encoder_subsample = 0; - call_all(&go->v4l2_dev, video, s_mbus_fmt, &mbus_fmt); + call_all(&go->v4l2_dev, pad, set_fmt, NULL, &format); } else { if (width <= sensor_width / 4) { go->encoder_h_halve = 1; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 930593d7028dd8..12569726be608a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -2958,14 +2958,17 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw) } if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) { - struct v4l2_mbus_framefmt fmt; - memset(&fmt, 0, sizeof(fmt)); - fmt.width = hdw->res_hor_val; - fmt.height = hdw->res_ver_val; - fmt.code = MEDIA_BUS_FMT_FIXED; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + format.format.width = hdw->res_hor_val; + format.format.height = hdw->res_ver_val; + format.format.code = MEDIA_BUS_FMT_FIXED; pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)", - fmt.width, fmt.height); - v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt); + format.format.width, format.format.height); + v4l2_device_call_all(&hdw->v4l2_dev, 0, pad, set_fmt, + NULL, &format); } if (hdw->srate_dirty || hdw->force_dirty) { diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 67a8e4e58d9af3..8f5da73dacff9f 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -293,10 +293,6 @@ struct v4l2_mbus_frame_desc { g_dv_timings(): Get custom dv timings in the sub device. - try_mbus_fmt: try to set a pixel format on a video data source - - s_mbus_fmt: set a pixel format on a video data source - g_mbus_config: get supported mediabus configurations s_mbus_config: set a certain mediabus configuration. This operation is added @@ -334,10 +330,6 @@ struct v4l2_subdev_video_ops { struct v4l2_dv_timings *timings); int (*query_dv_timings)(struct v4l2_subdev *sd, struct v4l2_dv_timings *timings); - int (*try_mbus_fmt)(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt); - int (*s_mbus_fmt)(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *fmt); int (*g_mbus_config)(struct v4l2_subdev *sd, struct v4l2_mbus_config *cfg); int (*s_mbus_config)(struct v4l2_subdev *sd, From a0e3e2900500b9a6915937cbf17b74bd6738b79f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:36 -0300 Subject: [PATCH 227/381] [media] soc_camera: fix enum_input Fill in the std field from the video_device tvnorms field. This fixes a v4l2-compliance failure. Signed-off-by: Hans Verkuil Signed-off-by: Rob Taylor Acked-by: Guennadi Liakhovetski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index d708df410f74cb..f24062ddd4cd64 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -309,11 +309,14 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv, static int soc_camera_enum_input(struct file *file, void *priv, struct v4l2_input *inp) { + struct soc_camera_device *icd = file->private_data; + if (inp->index != 0) return -EINVAL; /* default is camera */ inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = icd->vdev->tvnorms; strcpy(inp->name, "Camera"); return 0; From 12c7885238325e6dbc584baedb420c0279f7990c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:37 -0300 Subject: [PATCH 228/381] [media] soc_camera: fix expbuf support - For vb1 drivers just return -ENOTTY. - For vb2 drivers allow vb2_expbuf without there being a stream owner: the vb2_expbuf function will return the correct error message in that case. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index f24062ddd4cd64..5f1e5a8cbab41b 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -470,14 +470,13 @@ static int soc_camera_expbuf(struct file *file, void *priv, struct soc_camera_device *icd = file->private_data; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - if (icd->streamer != file) - return -EBUSY; - /* videobuf2 only */ if (ici->ops->init_videobuf) - return -EINVAL; - else - return vb2_expbuf(&icd->vb2_vidq, p); + return -ENOTTY; + + if (icd->streamer && icd->streamer != file) + return -EBUSY; + return vb2_expbuf(&icd->vb2_vidq, p); } /* Always entered with .host_lock held */ From 3447a80d48327f2379918fe87d0f1759e6024890 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:38 -0300 Subject: [PATCH 229/381] [media] soc_camera: compliance fixes - REQBUFS(0) will stop streaming, free buffers and release the file ownership. - Return ENOTTY for create_bufs for a vb1 driver - Return EBUSY if there is a different streaming owner and set the new owner on success. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 5f1e5a8cbab41b..6ce65762f55603 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -384,9 +384,8 @@ static int soc_camera_reqbufs(struct file *file, void *priv, ret = vb2_reqbufs(&icd->vb2_vidq, p); } - if (!ret && !icd->streamer) - icd->streamer = file; - + if (!ret) + icd->streamer = p->count ? file : NULL; return ret; } @@ -443,12 +442,19 @@ static int soc_camera_create_bufs(struct file *file, void *priv, { struct soc_camera_device *icd = file->private_data; struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + int ret; /* videobuf2 only */ if (ici->ops->init_videobuf) - return -EINVAL; - else - return vb2_create_bufs(&icd->vb2_vidq, create); + return -ENOTTY; + + if (icd->streamer && icd->streamer != file) + return -EBUSY; + + ret = vb2_create_bufs(&icd->vb2_vidq, create); + if (!ret) + icd->streamer = file; + return ret; } static int soc_camera_prepare_buf(struct file *file, void *priv, From 83b182b66c6f9e0bd54dc9c470e258db5a9c7dcf Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:39 -0300 Subject: [PATCH 230/381] [media] soc_camera: pass on streamoff error If streamoff returned an error, then pass that on to the caller. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 6ce65762f55603..0b09281bdd7f20 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1000,6 +1000,7 @@ static int soc_camera_streamoff(struct file *file, void *priv, struct soc_camera_device *icd = file->private_data; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + int ret; WARN_ON(priv != file->private_data); @@ -1014,13 +1015,13 @@ static int soc_camera_streamoff(struct file *file, void *priv, * remaining buffers. When the last buffer is freed, stop capture */ if (ici->ops->init_videobuf) - videobuf_streamoff(&icd->vb_vidq); + ret = videobuf_streamoff(&icd->vb_vidq); else - vb2_streamoff(&icd->vb2_vidq, i); + ret = vb2_streamoff(&icd->vb2_vidq, i); v4l2_subdev_call(sd, video, s_stream, 0); - return 0; + return ret; } static int soc_camera_cropcap(struct file *file, void *fh, From cf89e094ade9aa1b6529a3cde27a335a566d6925 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:40 -0300 Subject: [PATCH 231/381] [media] soc_camera: always release queue for queue owner Always release the queue if the owner closes its filehandle and not when it is the last open filehandle. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/soc_camera.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 0b09281bdd7f20..9087fed586fba2 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -788,20 +788,21 @@ static int soc_camera_close(struct file *file) struct soc_camera_host *ici = to_soc_camera_host(icd->parent); mutex_lock(&ici->host_lock); + if (icd->streamer == file) { + if (ici->ops->init_videobuf2) + vb2_queue_release(&icd->vb2_vidq); + icd->streamer = NULL; + } icd->use_count--; if (!icd->use_count) { pm_runtime_suspend(&icd->vdev->dev); pm_runtime_disable(&icd->vdev->dev); - if (ici->ops->init_videobuf2) - vb2_queue_release(&icd->vb2_vidq); __soc_camera_power_off(icd); soc_camera_remove_device(icd); } - if (icd->streamer == file) - icd->streamer = NULL; mutex_unlock(&ici->host_lock); module_put(ici->ops->owner); From 2142bd1d665d0a8a0528f74831d88d7fb8bcd633 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 4 Aug 2015 18:51:09 +0800 Subject: [PATCH 232/381] soc-camera: increase the length of clk_name on soc_of_bind() Since in soc_of_bind() it may use the of node's full name as the clk_name, and this full name may be longer than 32 characters, take at91 i2c sensor as an example, length is 34 bytes: /ahb/apb/i2c@f8028000/camera@0x30 So this patch increase the clk_name[] array size to 64. It seems big enough so far. Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/soc_camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 9087fed586fba2..43f9d67e9d7f7e 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1631,7 +1631,7 @@ static int soc_of_bind(struct soc_camera_host *ici, struct soc_camera_async_client *sasc; struct soc_of_info *info; struct i2c_client *client; - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_SUBDEV_NAME_SIZE + 32]; int ret; /* allocate a new subdev and add match info to it */ From a0d89994d23101937fc49d5e9c072e1d571e6b94 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:45 -0300 Subject: [PATCH 233/381] [media] atmel-isi: disable ISI even if it has codec request In current code, stop_streaming() will just return if ISI is still working in the codec. But this is incorrect, we need to disable ISI even it is working on the codec, otherwise stop_streaming() will not work as we expected. Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 287902681164ff..22270225b202bf 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -431,11 +431,9 @@ static void stop_streaming(struct vb2_queue *vq) time_before(jiffies, timeout)) msleep(1); - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout)) dev_err(icd->parent, "Timeout waiting for finishing codec request\n"); - return; - } /* Disable interrupts */ isi_writel(isi, ISI_INTDIS, From 333b6e7f69a8d94540644808a4f5e2472c7ded9a Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:46 -0300 Subject: [PATCH 234/381] [media] atmel-isi: add runtime pm support The runtime pm resume/suspend will enable/disable pclk (ISI peripheral clock). We have to call runtime_pm_get_sync()/runtime_pm_put() when we need to access ISI registers. In atmel_isi_probe(), remove the isi disable code as at that moment ISI peripheral clock is not enable yet. Besides, clock_start()/clock_stop() is used to control the mclk, not the ISI peripheral clock. So move this to start[stop]_streaming() function. Signed-off-by: Josh Wu Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 22270225b202bf..0ea360acea8177 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -386,10 +387,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) struct atmel_isi *isi = ici->priv; int ret; + pm_runtime_get_sync(ici->v4l2_dev.dev); + /* Reset ISI */ ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); if (ret < 0) { dev_err(icd->parent, "Reset ISI timed out\n"); + pm_runtime_put(ici->v4l2_dev.dev); return ret; } /* Disable all interrupts */ @@ -443,6 +447,8 @@ static void stop_streaming(struct vb2_queue *vq) ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); if (ret < 0) dev_err(icd->parent, "Disable ISI timed out\n"); + + pm_runtime_put(ici->v4l2_dev.dev); } static struct vb2_ops isi_video_qops = { @@ -514,7 +520,13 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, if (mf->code != xlate->code) return -EINVAL; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + ret = configure_geometry(isi, pix->width, pix->height, xlate->code); + + pm_runtime_put(ici->v4l2_dev.dev); + if (ret < 0) return ret; @@ -734,14 +746,9 @@ static int isi_camera_clock_start(struct soc_camera_host *ici) struct atmel_isi *isi = ici->priv; int ret; - ret = clk_prepare_enable(isi->pclk); - if (ret) - return ret; - if (!IS_ERR(isi->mck)) { ret = clk_prepare_enable(isi->mck); if (ret) { - clk_disable_unprepare(isi->pclk); return ret; } } @@ -756,7 +763,6 @@ static void isi_camera_clock_stop(struct soc_camera_host *ici) if (!IS_ERR(isi->mck)) clk_disable_unprepare(isi->mck); - clk_disable_unprepare(isi->pclk); } static unsigned int isi_camera_poll(struct file *file, poll_table *pt) @@ -853,9 +859,14 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) cfg1 |= ISI_CFG1_THMASK_BEATS_16; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); isi_writel(isi, ISI_CFG1, cfg1); + pm_runtime_put(ici->v4l2_dev.dev); + return 0; } @@ -887,6 +898,7 @@ static int atmel_isi_remove(struct platform_device *pdev) sizeof(struct fbd) * MAX_BUFFER_NUM, isi->p_fb_descriptors, isi->fb_descriptors_phys); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1025,8 +1037,6 @@ static int atmel_isi_probe(struct platform_device *pdev) if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) isi->width_flags |= 1 << 9; - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - irq = platform_get_irq(pdev, 0); if (IS_ERR_VALUE(irq)) { ret = irq; @@ -1047,6 +1057,9 @@ static int atmel_isi_probe(struct platform_device *pdev) soc_host->v4l2_dev.dev = &pdev->dev; soc_host->nr = pdev->id; + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (isi->pdata.asd_sizes) { soc_host->asd = isi->pdata.asd; soc_host->asd_sizes = isi->pdata.asd_sizes; @@ -1060,6 +1073,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return 0; err_register_soc_camera_host: + pm_runtime_disable(&pdev->dev); err_req_irq: err_ioremap: vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); @@ -1072,6 +1086,30 @@ static int atmel_isi_probe(struct platform_device *pdev) return ret; } +static int atmel_isi_runtime_suspend(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + clk_disable_unprepare(isi->pclk); + + return 0; +} +static int atmel_isi_runtime_resume(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + return clk_prepare_enable(isi->pclk); +} + +static const struct dev_pm_ops atmel_isi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, + atmel_isi_runtime_resume, NULL) +}; + static const struct of_device_id atmel_isi_of_match[] = { { .compatible = "atmel,at91sam9g45-isi" }, { } @@ -1083,6 +1121,7 @@ static struct platform_driver atmel_isi_driver = { .driver = { .name = "atmel_isi", .of_match_table = of_match_ptr(atmel_isi_of_match), + .pm = &atmel_isi_dev_pm_ops, }, }; From b5b332b850f894ecfa7657560446165dd0b449a0 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:47 -0300 Subject: [PATCH 235/381] [media] atmel-isi: remove mck backward compatibility code The master clock should be handled by sensor itself. Signed-off-by: Josh Wu Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 0ea360acea8177..90701726a06a2e 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -35,7 +35,6 @@ #define VID_LIMIT_BYTES (16 * 1024 * 1024) #define MIN_FRAME_RATE 15 #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) -#define ISI_DEFAULT_MCLK_FREQ 25000000 /* Frame buffer descriptor */ struct fbd { @@ -83,8 +82,6 @@ struct atmel_isi { struct completion complete; /* ISI peripherial clock */ struct clk *pclk; - /* ISI_MCK, feed to camera sensor to generate pixel clock */ - struct clk *mck; unsigned int irq; struct isi_platform_data pdata; @@ -740,31 +737,6 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) icd->devnum); } -/* Called with .host_lock held */ -static int isi_camera_clock_start(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - int ret; - - if (!IS_ERR(isi->mck)) { - ret = clk_prepare_enable(isi->mck); - if (ret) { - return ret; - } - } - - return 0; -} - -/* Called with .host_lock held */ -static void isi_camera_clock_stop(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - - if (!IS_ERR(isi->mck)) - clk_disable_unprepare(isi->mck); -} - static unsigned int isi_camera_poll(struct file *file, poll_table *pt) { struct soc_camera_device *icd = file->private_data; @@ -874,8 +846,6 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { .owner = THIS_MODULE, .add = isi_camera_add_device, .remove = isi_camera_remove_device, - .clock_start = isi_camera_clock_start, - .clock_stop = isi_camera_clock_stop, .set_fmt = isi_camera_set_fmt, .try_fmt = isi_camera_try_fmt, .get_formats = isi_camera_get_formats, @@ -912,7 +882,6 @@ static int atmel_isi_probe_dt(struct atmel_isi *isi, /* Default settings for ISI */ isi->pdata.full_mode = 1; - isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ; isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; np = of_graph_get_next_endpoint(np, NULL); @@ -988,21 +957,6 @@ static int atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); - /* ISI_MCK is the sensor master clock. It should be handled by the - * sensor driver directly, as the ISI has no use for that clock. Make - * the clock optional here while platforms transition to the correct - * model. - */ - isi->mck = devm_clk_get(dev, "isi_mck"); - if (!IS_ERR(isi->mck)) { - /* Set ISI_MCK's frequency, it should be faster than pixel - * clock. - */ - ret = clk_set_rate(isi->mck, isi->pdata.mck_hz); - if (ret < 0) - return ret; - } - isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, From 880ba9bbf29bb6603387fe23dc751c3349aedad1 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sun, 6 Sep 2015 12:08:49 +0200 Subject: [PATCH 236/381] atmel-isi: Protect PM-only functions to kill warning If CONFIG_PM=n: drivers/media/platform/soc_camera/atmel-isi.c:1044: warning: 'atmel_isi_runtime_suspend' defined but not used drivers/media/platform/soc_camera/atmel-isi.c:1054: warning: 'atmel_isi_runtime_resume' defined but not used Protect the unused functions by #ifdef CONFIG_PM to fix this. Signed-off-by: Geert Uytterhoeven Acked-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 90701726a06a2e..ccf30ccbe38923 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -1040,6 +1040,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return ret; } +#ifdef CONFIG_PM static int atmel_isi_runtime_suspend(struct device *dev) { struct soc_camera_host *soc_host = to_soc_camera_host(dev); @@ -1058,6 +1059,7 @@ static int atmel_isi_runtime_resume(struct device *dev) return clk_prepare_enable(isi->pclk); } +#endif /* CONFIG_PM */ static const struct dev_pm_ops atmel_isi_dev_pm_ops = { SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, From d511b561179fc1a6f2d6dd58b8ebe199ee1a6a12 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 17 Jun 2015 18:27:08 +0800 Subject: [PATCH 237/381] atmel-isi: increase timeout to disable/enable isi If ISI is working on a 1024x768 or higher resolution, it needs longer time to disable ISI. So this patch will increase timeout to 500ms. Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index ccf30ccbe38923..b018fa37f4dff1 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -225,7 +225,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) } timeout = wait_for_completion_timeout(&isi->complete, - msecs_to_jiffies(100)); + msecs_to_jiffies(500)); if (timeout == 0) return -ETIMEDOUT; From afe1fb0bbaff888461a0cabe6071c319790003aa Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 11 Sep 2015 15:00:14 +0800 Subject: [PATCH 238/381] atmel-isi: setup the ISI_CFG2 register directly In the function configure_geometry(), we will setup the ISI CFG2 according to the sensor output format. It make no sense to just read back the CFG2 register and just set part of it. So just set up this register directly makes things simpler. Currently only support YUV format from camera sensor. Signed-off-by: Josh Wu Reviewed-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 20 +++++++------------ include/media/atmel-isi.h | 2 ++ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index b018fa37f4dff1..3a85d44ba2dc95 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -105,24 +105,25 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg) static int configure_geometry(struct atmel_isi *isi, u32 width, u32 height, u32 code) { - u32 cfg2, cr; + u32 cfg2; + /* According to sensor's output format to set cfg2 */ switch (code) { /* YUV, including grey */ case MEDIA_BUS_FMT_Y8_1X8: - cr = ISI_CFG2_GRAYSCALE; + cfg2 = ISI_CFG2_GRAYSCALE | ISI_CFG2_COL_SPACE_YCbCr; break; case MEDIA_BUS_FMT_VYUY8_2X8: - cr = ISI_CFG2_YCC_SWAP_MODE_3; + cfg2 = ISI_CFG2_YCC_SWAP_MODE_3 | ISI_CFG2_COL_SPACE_YCbCr; break; case MEDIA_BUS_FMT_UYVY8_2X8: - cr = ISI_CFG2_YCC_SWAP_MODE_2; + cfg2 = ISI_CFG2_YCC_SWAP_MODE_2 | ISI_CFG2_COL_SPACE_YCbCr; break; case MEDIA_BUS_FMT_YVYU8_2X8: - cr = ISI_CFG2_YCC_SWAP_MODE_1; + cfg2 = ISI_CFG2_YCC_SWAP_MODE_1 | ISI_CFG2_COL_SPACE_YCbCr; break; case MEDIA_BUS_FMT_YUYV8_2X8: - cr = ISI_CFG2_YCC_SWAP_DEFAULT; + cfg2 = ISI_CFG2_YCC_SWAP_DEFAULT | ISI_CFG2_COL_SPACE_YCbCr; break; /* RGB, TODO */ default: @@ -130,17 +131,10 @@ static int configure_geometry(struct atmel_isi *isi, u32 width, } isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - - cfg2 = isi_readl(isi, ISI_CFG2); - /* Set YCC swap mode */ - cfg2 &= ~ISI_CFG2_YCC_SWAP_MODE_MASK; - cfg2 |= cr; /* Set width */ - cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK); cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) & ISI_CFG2_IM_HSIZE_MASK; /* Set height */ - cfg2 &= ~(ISI_CFG2_IM_VSIZE_MASK); cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) & ISI_CFG2_IM_VSIZE_MASK; isi_writel(isi, ISI_CFG2, cfg2); diff --git a/include/media/atmel-isi.h b/include/media/atmel-isi.h index 6008b0985b7b18..e7a96b85e37468 100644 --- a/include/media/atmel-isi.h +++ b/include/media/atmel-isi.h @@ -66,6 +66,8 @@ /* Bitfields in CFG2 */ #define ISI_CFG2_GRAYSCALE (1 << 13) +#define ISI_CFG2_COL_SPACE_YCbCr (0 << 15) +#define ISI_CFG2_COL_SPACE_RGB (1 << 15) /* Constants for YCC_SWAP(ISI_V2) */ #define ISI_CFG2_YCC_SWAP_DEFAULT (0 << 28) #define ISI_CFG2_YCC_SWAP_MODE_1 (1 << 28) From 5124fef99513c6bd40fa82a488809ee4c6b2ffcd Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 11 Sep 2015 15:00:15 +0800 Subject: [PATCH 239/381] atmel-isi: move configure_geometry() to start_streaming() As in set_fmt() function we only need to know which format is been set, we don't need to access the ISI hardware in this moment. So move the configure_geometry(), which access the ISI hardware, to start_streaming() will make code more consistent and simpler. Signed-off-by: Josh Wu Reviewed-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 3a85d44ba2dc95..add324590abe03 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -390,6 +390,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* Disable all interrupts */ isi_writel(isi, ISI_INTDIS, (u32)~0UL); + ret = configure_geometry(isi, icd->user_width, icd->user_height, + icd->current_fmt->code); + if (ret < 0) + return ret; + spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ isi_readl(isi, ISI_STATUS); @@ -477,8 +482,6 @@ static int isi_camera_init_videobuf(struct vb2_queue *q, static int isi_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f) { - struct soc_camera_host *ici = to_soc_camera_host(icd->parent); - struct atmel_isi *isi = ici->priv; struct v4l2_subdev *sd = soc_camera_to_subdev(icd); const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; @@ -511,16 +514,6 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, if (mf->code != xlate->code) return -EINVAL; - /* Enable PM and peripheral clock before operate isi registers */ - pm_runtime_get_sync(ici->v4l2_dev.dev); - - ret = configure_geometry(isi, pix->width, pix->height, xlate->code); - - pm_runtime_put(ici->v4l2_dev.dev); - - if (ret < 0) - return ret; - pix->width = mf->width; pix->height = mf->height; pix->field = mf->field; From e0222711c2b5198f220b143bec42dbb27c1ea939 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 11 Sep 2015 15:00:16 +0800 Subject: [PATCH 240/381] atmel-isi: add sanity check for supported formats in try/set_fmt() After adding the format check in try_fmt()/set_fmt(), we don't need any format check in configure_geometry(). So make configure_geometry() as void type. Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index add324590abe03..a3ddec73fe5ccc 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -102,17 +102,19 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg) return readl(isi->regs + reg); } -static int configure_geometry(struct atmel_isi *isi, u32 width, +static void configure_geometry(struct atmel_isi *isi, u32 width, u32 height, u32 code) { u32 cfg2; /* According to sensor's output format to set cfg2 */ switch (code) { - /* YUV, including grey */ + default: + /* Grey */ case MEDIA_BUS_FMT_Y8_1X8: cfg2 = ISI_CFG2_GRAYSCALE | ISI_CFG2_COL_SPACE_YCbCr; break; + /* YUV */ case MEDIA_BUS_FMT_VYUY8_2X8: cfg2 = ISI_CFG2_YCC_SWAP_MODE_3 | ISI_CFG2_COL_SPACE_YCbCr; break; @@ -126,8 +128,6 @@ static int configure_geometry(struct atmel_isi *isi, u32 width, cfg2 = ISI_CFG2_YCC_SWAP_DEFAULT | ISI_CFG2_COL_SPACE_YCbCr; break; /* RGB, TODO */ - default: - return -EINVAL; } isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); @@ -138,8 +138,23 @@ static int configure_geometry(struct atmel_isi *isi, u32 width, cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) & ISI_CFG2_IM_VSIZE_MASK; isi_writel(isi, ISI_CFG2, cfg2); +} - return 0; +static bool is_supported(struct soc_camera_device *icd, + const u32 pixformat) +{ + switch (pixformat) { + /* YUV, including grey */ + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + return true; + /* RGB, TODO */ + default: + return false; + } } static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) @@ -390,10 +405,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* Disable all interrupts */ isi_writel(isi, ISI_INTDIS, (u32)~0UL); - ret = configure_geometry(isi, icd->user_width, icd->user_height, + configure_geometry(isi, icd->user_width, icd->user_height, icd->current_fmt->code); - if (ret < 0) - return ret; spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ @@ -491,6 +504,10 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, struct v4l2_mbus_framefmt *mf = &format.format; int ret; + /* check with atmel-isi support format, if not support use YUYV */ + if (!is_supported(icd, pix->pixelformat)) + pix->pixelformat = V4L2_PIX_FMT_YUYV; + xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); if (!xlate) { dev_warn(icd->parent, "Format %x not found\n", @@ -540,6 +557,10 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, u32 pixfmt = pix->pixelformat; int ret; + /* check with atmel-isi support format, if not support use YUYV */ + if (!is_supported(icd, pix->pixelformat)) + pix->pixelformat = V4L2_PIX_FMT_YUYV; + xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); if (pixfmt && !xlate) { dev_warn(icd->parent, "Format %x not found\n", pixfmt); From f8b3fd0a18420475ec7dd4525e8dd5993c9efcaa Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 1 Aug 2015 12:22:53 +0300 Subject: [PATCH 241/381] v4l: atmel-isi: Simplify error handling during DT parsing Put the endpoint DT node earlier to avoid the need for goto statements to a cleanup code block in case of errors. Signed-off-by: Laurent Pinchart Acked-by: Josh Wu Tested-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index a3ddec73fe5ccc..0f23984bb6aa5c 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -899,9 +899,10 @@ static int atmel_isi_probe_dt(struct atmel_isi *isi, } err = v4l2_of_parse_endpoint(np, &ep); + of_node_put(np); if (err) { dev_err(&pdev->dev, "Could not parse the endpoint\n"); - goto err_probe_dt; + return err; } switch (ep.bus.parallel.bus_width) { @@ -915,14 +916,10 @@ static int atmel_isi_probe_dt(struct atmel_isi *isi, default: dev_err(&pdev->dev, "Unsupported bus width: %d\n", ep.bus.parallel.bus_width); - err = -EINVAL; - goto err_probe_dt; + return -EINVAL; } -err_probe_dt: - of_node_put(np); - - return err; + return 0; } static int atmel_isi_probe(struct platform_device *pdev) From e60899cd16fa001e76fa75308a4fd82fc506a937 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 1 Aug 2015 12:22:54 +0300 Subject: [PATCH 242/381] v4l: atmel-isi: Remove support for platform data All in-tree users have migrated to DT, remove support for platform data. Signed-off-by: Laurent Pinchart Acked-by: Josh Wu Tested-by: Josh Wu [josh.wu@atmel.com: squash the commit to remove the unused variable: dev] Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 24 +++++-------------- .../media/platform/soc_camera}/atmel-isi.h | 0 2 files changed, 6 insertions(+), 18 deletions(-) rename {include/media => drivers/media/platform/soc_camera}/atmel-isi.h (100%) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 0f23984bb6aa5c..58dfec3c90e61c 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -23,12 +23,13 @@ #include #include -#include #include #include #include #include +#include "atmel-isi.h" + #define MAX_BUFFER_NUM 32 #define MAX_SUPPORT_WIDTH 2048 #define MAX_SUPPORT_HEIGHT 2048 @@ -881,7 +882,7 @@ static int atmel_isi_remove(struct platform_device *pdev) return 0; } -static int atmel_isi_probe_dt(struct atmel_isi *isi, +static int atmel_isi_parse_dt(struct atmel_isi *isi, struct platform_device *pdev) { struct device_node *np= pdev->dev.of_node; @@ -928,16 +929,7 @@ static int atmel_isi_probe(struct platform_device *pdev) struct atmel_isi *isi; struct resource *regs; int ret, i; - struct device *dev = &pdev->dev; struct soc_camera_host *soc_host; - struct isi_platform_data *pdata; - - pdata = dev->platform_data; - if ((!pdata || !pdata->data_width_flags) && !pdev->dev.of_node) { - dev_err(&pdev->dev, - "No config available for Atmel ISI\n"); - return -EINVAL; - } isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL); if (!isi) { @@ -949,13 +941,9 @@ static int atmel_isi_probe(struct platform_device *pdev) if (IS_ERR(isi->pclk)) return PTR_ERR(isi->pclk); - if (pdata) { - memcpy(&isi->pdata, pdata, sizeof(isi->pdata)); - } else { - ret = atmel_isi_probe_dt(isi, pdev); - if (ret) - return ret; - } + ret = atmel_isi_parse_dt(isi, pdev); + if (ret) + return ret; isi->active = NULL; spin_lock_init(&isi->lock); diff --git a/include/media/atmel-isi.h b/drivers/media/platform/soc_camera/atmel-isi.h similarity index 100% rename from include/media/atmel-isi.h rename to drivers/media/platform/soc_camera/atmel-isi.h From b0c9b991d8539f9b3ae62cb31d96f2c4d152ed20 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sat, 1 Aug 2015 12:22:56 +0300 Subject: [PATCH 243/381] v4l: atmel-isi: Remove unused platform data fields The emb_crc_sync, mck_hz, asd and asd_sizes platform data fields are unused, remove them. Signed-off-by: Laurent Pinchart Acked-by: Josh Wu Tested-by: Josh Wu Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 5 ----- drivers/media/platform/soc_camera/atmel-isi.h | 5 ----- 2 files changed, 10 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 58dfec3c90e61c..19131d3f9af6e4 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -1007,11 +1007,6 @@ static int atmel_isi_probe(struct platform_device *pdev) pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); - if (isi->pdata.asd_sizes) { - soc_host->asd = isi->pdata.asd; - soc_host->asd_sizes = isi->pdata.asd_sizes; - } - ret = soc_camera_host_register(soc_host); if (ret) { dev_err(&pdev->dev, "Unable to register soc camera host\n"); diff --git a/drivers/media/platform/soc_camera/atmel-isi.h b/drivers/media/platform/soc_camera/atmel-isi.h index e7a96b85e37468..5acc771d2edcd6 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.h +++ b/drivers/media/platform/soc_camera/atmel-isi.h @@ -116,7 +116,6 @@ struct v4l2_async_subdev; struct isi_platform_data { u8 has_emb_sync; - u8 emb_crc_sync; u8 hsync_act_low; u8 vsync_act_low; u8 pclk_act_falling; @@ -124,10 +123,6 @@ struct isi_platform_data { u32 data_width_flags; /* Using for ISI_CFG1 */ u32 frate; - /* Using for ISI_MCK */ - u32 mck_hz; - struct v4l2_async_subdev **asd; /* Flat array, arranged in groups */ - int *asd_sizes; /* 0-terminated array of asd group sizes */ }; #endif /* __ATMEL_ISI_H__ */ From 3b69033234eb3b5c319ca25cbf7b54d3b861f8a9 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 4 Aug 2015 17:37:49 +0800 Subject: [PATCH 244/381] atmel-isi: parse the DT parameters for vsync/hsync/pixclock polarity This patch will get the DT parameters of vsync/hsync/pixclock polarity, and pass to driver. Also add a debug information for test purpose. Signed-off-by: Josh Wu Reviewed-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski --- drivers/media/platform/soc_camera/atmel-isi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 19131d3f9af6e4..45e304a3dd85b5 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -833,6 +833,11 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; + dev_dbg(icd->parent, "vsync active %s, hsync active %s, sampling on pix clock %s edge\n", + common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? "low" : "high", + common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? "low" : "high", + common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING ? "falling" : "rising"); + if (isi->pdata.has_emb_sync) cfg1 |= ISI_CFG1_EMB_SYNC; if (isi->pdata.full_mode) @@ -920,6 +925,16 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi, return -EINVAL; } + if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + isi->pdata.hsync_act_low = true; + if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + isi->pdata.vsync_act_low = true; + if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + isi->pdata.pclk_act_falling = true; + + if (ep.bus_type == V4L2_MBUS_BT656) + isi->pdata.has_emb_sync = true; + return 0; } From 5d92c31ba7eeb849b43ee6755a6dbd0ac633c252 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 18 Sep 2013 16:59:18 +0800 Subject: [PATCH 245/381] ov2643: add ov2643 support Signed-off-by: Josh Wu Conflicts: drivers/media/i2c/soc_camera/ov2640.c --- drivers/media/i2c/soc_camera/ov2640.c | 86 +++- drivers/media/i2c/soc_camera/ov2643.h | 635 ++++++++++++++++++++++++++ 2 files changed, 703 insertions(+), 18 deletions(-) create mode 100644 drivers/media/i2c/soc_camera/ov2643.h diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 9b4f5deec748dc..092c8ebf633784 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -264,6 +264,9 @@ #define PID_OV2640 0x2642 #define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) +#define OV2640_SIZE(n, w, h, r) \ + {.name = n, .width = w , .height = h, .regs = r } + /* * Struct */ @@ -279,6 +282,10 @@ struct ov2640_win_size { const struct regval_list *regs; }; +#include "ov2643.h" + +#define V4L2_IDENT_OV2640 0 +#define V4L2_IDENT_OV2643 3 struct ov2640_priv { struct v4l2_subdev subdev; @@ -286,6 +293,7 @@ struct ov2640_priv { u32 cfmt_code; struct v4l2_clk *clk; const struct ov2640_win_size *win; + int model; struct soc_camera_subdev_desc ssdd_dt; struct gpio_desc *resetb_gpio; @@ -548,9 +556,6 @@ static const struct regval_list ov2640_uxga_regs[] = { ENDMARKER, }; -#define OV2640_SIZE(n, w, h, r) \ - {.name = n, .width = w , .height = h, .regs = r } - static const struct ov2640_win_size ov2640_supported_win_sizes[] = { OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs), OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs), @@ -751,22 +756,32 @@ static int ov2640_s_power(struct v4l2_subdev *sd, int on) } /* Select the nearest higher resolution for capture */ -static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height) +static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height, + struct ov2640_priv *priv) { int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1; + const struct ov2640_win_size *p_win_sizes; + + if (priv->model == V4L2_IDENT_OV2640) { + p_win_sizes = ov2640_supported_win_sizes; + default_size = ARRAY_SIZE(ov2640_supported_win_sizes); + } else { + p_win_sizes = ov2643_supported_win_sizes; + default_size = ARRAY_SIZE(ov2643_supported_win_sizes); + } - for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) { - if (ov2640_supported_win_sizes[i].width >= *width && - ov2640_supported_win_sizes[i].height >= *height) { - *width = ov2640_supported_win_sizes[i].width; - *height = ov2640_supported_win_sizes[i].height; - return &ov2640_supported_win_sizes[i]; + for (i = 0; i < default_size + 1; i++) { + if (p_win_sizes[i].width >= *width && + p_win_sizes[i].height >= *height) { + *width = p_win_sizes[i].width; + *height = p_win_sizes[i].height; + return &p_win_sizes[i]; } } - *width = ov2640_supported_win_sizes[default_size].width; - *height = ov2640_supported_win_sizes[default_size].height; - return &ov2640_supported_win_sizes[default_size]; + *width = p_win_sizes[default_size].width; + *height = p_win_sizes[default_size].height; + return &p_win_sizes[default_size]; } static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, @@ -777,7 +792,7 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, int ret; /* select win */ - priv->win = ov2640_select_win(width, height); + priv->win = ov2640_select_win(width, height, priv); /* select format */ priv->cfmt_code = 0; @@ -845,6 +860,30 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, return ret; } +static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, + u32 code) +{ + struct ov2640_priv *priv = to_ov2640(client); + int ret; + + /* select win */ + priv->win = ov2640_select_win(width, height, priv); + + if (code != MEDIA_BUS_FMT_UYVY8_2X8) { + dev_err(&client->dev, "Not supported format: %d\n", code); + return -1; + } + + /* set size win */ + ret = ov2640_write_array(client, priv->win->regs); + + priv->cfmt_code = code; + *width = priv->win->width; + *height = priv->win->height; + + return 0; +} + static int ov2640_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) @@ -858,7 +897,7 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, if (!priv->win) { u32 width = SVGA_WIDTH, height = SVGA_HEIGHT; - priv->win = ov2640_select_win(&width, &height); + priv->win = ov2640_select_win(&width, &height, priv); priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8; } @@ -887,6 +926,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, { struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2640_priv *priv = to_ov2640(client); if (format->pad) return -EINVAL; @@ -894,7 +934,7 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, /* * select suitable win, but don't store it */ - ov2640_select_win(&mf->width, &mf->height); + ov2640_select_win(&mf->width, &mf->height, priv); mf->field = V4L2_FIELD_NONE; @@ -910,9 +950,14 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; } - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - return ov2640_set_params(client, &mf->width, + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (priv->model == V4L2_IDENT_OV2640) + return ov2640_set_params(client, &mf->width, + &mf->height, mf->code); + else + return ov2643_set_params(client, &mf->width, &mf->height, mf->code); + } cfg->try_fmt = *mf; return 0; } @@ -976,6 +1021,11 @@ static int ov2640_video_probe(struct i2c_client *client) switch (VERSION(pid, ver)) { case PID_OV2640: devname = "ov2640"; + priv->model = V4L2_IDENT_OV2640; + break; + case PID_OV2643: + devname = "ov2643"; + priv->model = V4L2_IDENT_OV2643; break; default: dev_err(&client->dev, diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h new file mode 100644 index 00000000000000..14e8cda3115890 --- /dev/null +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -0,0 +1,635 @@ +#define PID_OV2643 0x2643 + +static const struct regval_list ov2643_yuv_uxga[]= { + {0x12, 0x80}, + {0xc3, 0x1f}, + {0xc4, 0xff}, + {0x3d, 0x48}, + {0xdd, 0xa5}, + {0x0e, 0xb4}, + {0x10, 0x0a}, + {0x11, 0x00}, + {0x0f, 0x14}, + {0x21, 0x25}, + {0x23, 0x0c}, + {0x12, 0x08}, + {0x39, 0x10}, + {0xcd, 0x12}, + {0x13, 0xff}, + {0x14, 0xa7}, + {0x15, 0x42}, + {0x3c, 0xa4}, + {0x18, 0x60}, + {0x19, 0x50}, + {0x1a, 0xe2}, + {0x37, 0xe8}, + {0x16, 0x90}, + {0x43, 0x00}, + {0x40, 0xfb}, + {0xa9, 0x44}, + {0x2f, 0xec}, + {0x35, 0x10}, + {0x36, 0x10}, + {0x0c, 0x00}, + {0x0d, 0x00}, + {0xd0, 0x93}, + {0xdc, 0x2b}, + {0xd9, 0x41}, + {0xd3, 0x02}, + {0x3d, 0x08}, + {0x0c, 0x00}, + {0x18, 0x2c}, + {0x19, 0x24}, + {0x1a, 0x71}, + {0x9b, 0x69}, + {0x9c, 0x7d}, + {0x9d, 0x7d}, + {0x9e, 0x69}, + {0x35, 0x04}, + {0x36, 0x04}, + {0x65, 0x12}, + {0x66, 0x20}, + {0x67, 0x39}, + {0x68, 0x4e}, + {0x69, 0x62}, + {0x6a, 0x74}, + {0x6b, 0x85}, + {0x6c, 0x92}, + {0x6d, 0x9e}, + {0x6e, 0xb2}, + {0x6f, 0xc0}, + {0x70, 0xcc}, + {0x71, 0xe0}, + {0x72, 0xee}, + {0x73, 0xf6}, + {0x74, 0x11}, + {0xab, 0x20}, + {0xac, 0x5b}, + {0xad, 0x05}, + {0xae, 0x1b}, + {0xaf, 0x76}, + {0xb0, 0x90}, + {0xb1, 0x90}, + {0xb2, 0x8c}, + {0xb3, 0x04}, + {0xb4, 0x98}, + {0x4c, 0x03}, + {0x4d, 0x30}, + {0x4e, 0x02}, + {0x4f, 0x5c}, + {0x50, 0x56}, + {0x51, 0x00}, + {0x52, 0x66}, + {0x53, 0x03}, + {0x54, 0x30}, + {0x55, 0x02}, + {0x56, 0x5c}, + {0x57, 0x40}, + {0x58, 0x00}, + {0x59, 0x66}, + {0x5a, 0x03}, + {0x5b, 0x20}, + {0x5c, 0x02}, + {0x5d, 0x5c}, + {0x5e, 0x3a}, + {0x5f, 0x00}, + {0x60, 0x66}, + {0x41, 0x1f}, + {0xb5, 0x01}, + {0xb6, 0x02}, + {0xb9, 0x40}, + {0xba, 0x28}, + {0xbf, 0x0c}, + {0xc0, 0x3e}, + {0xa3, 0x0a}, + {0xa4, 0x0f}, + {0xa5, 0x09}, + {0xa6, 0x16}, + {0x9f, 0x0a}, + {0xa0, 0x0f}, + {0xa7, 0x0a}, + {0xa8, 0x0f}, + {0xa1, 0x10}, + {0xa2, 0x04}, + {0xa9, 0x04}, + {0xaa, 0xa6}, + {0x75, 0x6a}, + {0x76, 0x11}, + {0x77, 0x92}, + {0x78, 0x21}, + {0x79, 0xe1}, + {0x7a, 0x02}, + {0x7c, 0x05}, + {0x7d, 0x08}, + {0x7e, 0x08}, + {0x7f, 0x7c}, + {0x80, 0x58}, + {0x81, 0x2a}, + {0x82, 0xc5}, + {0x83, 0x46}, + {0x84, 0x3a}, + {0x85, 0x54}, + {0x86, 0x44}, + {0x87, 0xf8}, + {0x88, 0x08}, + {0x89, 0x70}, + {0x8a, 0xf0}, + {0x8b, 0xf0}, + {0x90, 0xe3}, + {0x93, 0x10}, + {0x94, 0x20}, + {0x95, 0x10}, + {0x96, 0x18}, + {0x0f, 0x34}, + + {0x12, 0x80}, + {0xc3, 0x1f}, + {0xc4, 0xff}, + {0x3d, 0x48}, + {0xdd, 0xa5}, + {0x0e, 0xb4}, + {0x10, 0x0a}, + {0x11, 0x00}, + {0x0f, 0x14}, + {0x21, 0x25}, + {0x23, 0x0c}, + {0x12, 0x08}, + {0x39, 0x10}, + {0xcd, 0x12}, + {0x13, 0xff}, + {0x14, 0xa7}, + {0x15, 0x42}, + {0x3c, 0xa4}, + {0x18, 0x60}, + {0x19, 0x50}, + {0x1a, 0xe2}, + {0x37, 0xe8}, + {0x16, 0x90}, + {0x43, 0x00}, + {0x40, 0xfb}, + {0xa9, 0x44}, + {0x2f, 0xec}, + {0x35, 0x10}, + {0x36, 0x10}, + {0x0c, 0x00}, + {0x0d, 0x20}, /* YUV/RGB format */ + {0xd0, 0x93}, + {0xdc, 0x2b}, + {0xd9, 0x41}, + {0xd3, 0x02}, + {0x3d, 0x08}, + {0x0c, 0x00}, + {0x18, 0x2c}, + {0x19, 0x24}, + {0x1a, 0x71}, + {0x9b, 0x69}, + {0x9c, 0x7d}, + {0x9d, 0x7d}, + {0x9e, 0x69}, + {0x35, 0x04}, + {0x36, 0x04}, + {0x65, 0x12}, + {0x66, 0x20}, + {0x67, 0x39}, + {0x68, 0x4e}, + {0x69, 0x62}, + {0x6a, 0x74}, + {0x6b, 0x85}, + {0x6c, 0x92}, + {0x6d, 0x9e}, + {0x6e, 0xb2}, + {0x6f, 0xc0}, + {0x70, 0xcc}, + {0x71, 0xe0}, + {0x72, 0xee}, + {0x73, 0xf6}, + {0x74, 0x11}, + {0xab, 0x20}, + {0xac, 0x5b}, + {0xad, 0x05}, + {0xae, 0x1b}, + {0xaf, 0x76}, + {0xb0, 0x90}, + {0xb1, 0x90}, + {0xb2, 0x8c}, + {0xb3, 0x04}, + {0xb4, 0x98}, + {0x4c, 0x03}, + {0x4d, 0x30}, + {0x4e, 0x02}, + {0x4f, 0x5c}, + {0x50, 0x56}, + {0x51, 0x00}, + {0x52, 0x66}, + {0x53, 0x03}, + {0x54, 0x30}, + {0x55, 0x02}, + {0x56, 0x5c}, + {0x57, 0x40}, + {0x58, 0x00}, + {0x59, 0x66}, + {0x5a, 0x03}, + {0x5b, 0x20}, + {0x5c, 0x02}, + {0x5d, 0x5c}, + {0x5e, 0x3a}, + {0x5f, 0x00}, + {0x60, 0x66}, + {0x41, 0x1f}, + {0xb5, 0x01}, + {0xb6, 0x02}, + {0xb9, 0x40}, + {0xba, 0x28}, + {0xbf, 0x0c}, + {0xc0, 0x3e}, + {0xa3, 0x0a}, + {0xa4, 0x0f}, + {0xa5, 0x09}, + {0xa6, 0x16}, + {0x9f, 0x0a}, + {0xa0, 0x0f}, + {0xa7, 0x0a}, + {0xa8, 0x0f}, + {0xa1, 0x10}, + {0xa2, 0x04}, + {0xa9, 0x04}, + {0xaa, 0xa6}, + {0x75, 0x6a}, + {0x76, 0x11}, + {0x77, 0x92}, + {0x78, 0x21}, + {0x79, 0xe1}, + {0x7a, 0x02}, + {0x7c, 0x05}, + {0x7d, 0x08}, + {0x7e, 0x08}, + {0x7f, 0x7c}, + {0x80, 0x58}, + {0x81, 0x2a}, + {0x82, 0xc5}, + {0x83, 0x46}, + {0x84, 0x3a}, + {0x85, 0x54}, + {0x86, 0x44}, + {0x87, 0xf8}, + {0x88, 0x08}, + {0x89, 0x70}, + {0x8a, 0xf0}, + {0x8b, 0xf0}, + {0x90, 0xe3}, + {0x93, 0x10}, + {0x94, 0x20}, + {0x95, 0x10}, + {0x96, 0x18}, + {0x0f, 0x34}, + {0xFF, 0xFF}, +}; + +static const struct regval_list ov2643_yuv_swvga[]= { + {0x12, 0x80}, + {0xc3, 0x1f}, + {0xc4, 0xff}, + {0x3d, 0x48}, + {0xdd, 0xa5}, + {0x0e, 0xb4}, + {0x10, 0x0a}, + {0x11, 0x00}, + {0x0f, 0x14}, + {0x21, 0x25}, + {0x23, 0x0c}, + {0x12, 0x08}, + {0x39, 0x10}, + {0xcd, 0x12}, + {0x13, 0xff}, + {0x14, 0xa7}, + {0x15, 0x42}, + {0x3c, 0xa4}, + {0x18, 0x60}, + {0x19, 0x50}, + {0x1a, 0xe2}, + {0x37, 0xe8}, + {0x16, 0x90}, + {0x43, 0x00}, + {0x40, 0xfb}, + {0xa9, 0x44}, + {0x2f, 0xec}, + {0x35, 0x10}, + {0x36, 0x10}, + {0x0c, 0x00}, + {0x0d, 0x20}, /* YUV/RGB format */ + {0xd0, 0x93}, + {0xdc, 0x2b}, + {0xd9, 0x41}, + {0xd3, 0x02}, + {0x3d, 0x08}, + {0x0c, 0x00}, + {0x18, 0x2c}, + {0x19, 0x24}, + {0x1a, 0x71}, + {0x9b, 0x69}, + {0x9c, 0x7d}, + {0x9d, 0x7d}, + {0x9e, 0x69}, + {0x35, 0x04}, + {0x36, 0x04}, + {0x65, 0x12}, + {0x66, 0x20}, + {0x67, 0x39}, + {0x68, 0x4e}, + {0x69, 0x62}, + {0x6a, 0x74}, + {0x6b, 0x85}, + {0x6c, 0x92}, + {0x6d, 0x9e}, + {0x6e, 0xb2}, + {0x6f, 0xc0}, + {0x70, 0xcc}, + {0x71, 0xe0}, + {0x72, 0xee}, + {0x73, 0xf6}, + {0x74, 0x11}, + {0xab, 0x20}, + {0xac, 0x5b}, + {0xad, 0x05}, + {0xae, 0x1b}, + {0xaf, 0x76}, + {0xb0, 0x90}, + {0xb1, 0x90}, + {0xb2, 0x8c}, + {0xb3, 0x04}, + {0xb4, 0x98}, + {0x4c, 0x03}, + {0x4d, 0x30}, + {0x4e, 0x02}, + {0x4f, 0x5c}, + {0x50, 0x56}, + {0x51, 0x00}, + {0x52, 0x66}, + {0x53, 0x03}, + {0x54, 0x30}, + {0x55, 0x02}, + {0x56, 0x5c}, + {0x57, 0x40}, + {0x58, 0x00}, + {0x59, 0x66}, + {0x5a, 0x03}, + {0x5b, 0x20}, + {0x5c, 0x02}, + {0x5d, 0x5c}, + {0x5e, 0x3a}, + {0x5f, 0x00}, + {0x60, 0x66}, + {0x41, 0x1f}, + {0xb5, 0x01}, + {0xb6, 0x02}, + {0xb9, 0x40}, + {0xba, 0x28}, + {0xbf, 0x0c}, + {0xc0, 0x3e}, + {0xa3, 0x0a}, + {0xa4, 0x0f}, + {0xa5, 0x09}, + {0xa6, 0x16}, + {0x9f, 0x0a}, + {0xa0, 0x0f}, + {0xa7, 0x0a}, + {0xa8, 0x0f}, + {0xa1, 0x10}, + {0xa2, 0x04}, + {0xa9, 0x04}, + {0xaa, 0xa6}, + {0x75, 0x6a}, + {0x76, 0x11}, + {0x77, 0x92}, + {0x78, 0x21}, + {0x79, 0xe1}, + {0x7a, 0x02}, + {0x7c, 0x05}, + {0x7d, 0x08}, + {0x7e, 0x08}, + {0x7f, 0x7c}, + {0x80, 0x58}, + {0x81, 0x2a}, + {0x82, 0xc5}, + {0x83, 0x46}, + {0x84, 0x3a}, + {0x85, 0x54}, + {0x86, 0x44}, + {0x87, 0xf8}, + {0x88, 0x08}, + {0x89, 0x70}, + {0x8a, 0xf0}, + {0x8b, 0xf0}, + {0x90, 0xe3}, + {0x93, 0x10}, + {0x94, 0x20}, + {0x95, 0x10}, + {0x96, 0x18}, + {0x0f, 0x34}, + + {0x3d, 0x48}, + {0x0e, 0xb8}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x20, 0x01}, + {0x21, 0x98}, + {0x22, 0x00}, + {0x23, 0x06}, + {0x24, 0x32}, + {0x25, 0x04}, + {0x26, 0x25}, + {0x27, 0x84}, + {0x28, 0x40}, + {0x29, 0x04}, + {0x2a, 0xce}, + {0x2b, 0x02}, + {0x2c, 0x8a}, + {0x12, 0x09}, + {0x39, 0xd0}, + {0xcd, 0x13}, + {0xde, 0x7c}, + {0x3d, 0x08}, + {0x15, 0x42}, + {0xde, 0x7c}, + {0x0f, 0x24}, + {0xFF, 0xFF}, +}; + +static const struct regval_list ov2643_yuv_vga[]= { + {0x12, 0x80}, + {0xc3, 0x1f}, + {0xc4, 0xff}, + {0x3d, 0x48}, + {0xdd, 0xa5}, + {0x0e, 0xb4}, + {0x10, 0x0a}, + {0x11, 0x00}, + {0x0f, 0x14}, + {0x21, 0x25}, + {0x23, 0x0c}, + {0x12, 0x08}, + {0x39, 0x10}, + {0xcd, 0x12}, + {0x13, 0xff}, + {0x14, 0xa7}, + {0x15, 0x42}, + {0x3c, 0xa4}, + {0x18, 0x60}, + {0x19, 0x50}, + {0x1a, 0xe2}, + {0x37, 0xe8}, + {0x16, 0x90}, + {0x43, 0x00}, + {0x40, 0xfb}, + {0xa9, 0x44}, + {0x2f, 0xec}, + {0x35, 0x10}, + {0x36, 0x10}, + {0x0c, 0x00}, + {0x0d, 0x20}, /* YUV/RGB format */ + {0xd0, 0x93}, + {0xdc, 0x2b}, + {0xd9, 0x41}, + {0xd3, 0x02}, + {0x3d, 0x08}, + {0x0c, 0x00}, + {0x18, 0x2c}, + {0x19, 0x24}, + {0x1a, 0x71}, + {0x9b, 0x69}, + {0x9c, 0x7d}, + {0x9d, 0x7d}, + {0x9e, 0x69}, + {0x35, 0x04}, + {0x36, 0x04}, + {0x65, 0x12}, + {0x66, 0x20}, + {0x67, 0x39}, + {0x68, 0x4e}, + {0x69, 0x62}, + {0x6a, 0x74}, + {0x6b, 0x85}, + {0x6c, 0x92}, + {0x6d, 0x9e}, + {0x6e, 0xb2}, + {0x6f, 0xc0}, + {0x70, 0xcc}, + {0x71, 0xe0}, + {0x72, 0xee}, + {0x73, 0xf6}, + {0x74, 0x11}, + {0xab, 0x20}, + {0xac, 0x5b}, + {0xad, 0x05}, + {0xae, 0x1b}, + {0xaf, 0x76}, + {0xb0, 0x90}, + {0xb1, 0x90}, + {0xb2, 0x8c}, + {0xb3, 0x04}, + {0xb4, 0x98}, + {0x4c, 0x03}, + {0x4d, 0x30}, + {0x4e, 0x02}, + {0x4f, 0x5c}, + {0x50, 0x56}, + {0x51, 0x00}, + {0x52, 0x66}, + {0x53, 0x03}, + {0x54, 0x30}, + {0x55, 0x02}, + {0x56, 0x5c}, + {0x57, 0x40}, + {0x58, 0x00}, + {0x59, 0x66}, + {0x5a, 0x03}, + {0x5b, 0x20}, + {0x5c, 0x02}, + {0x5d, 0x5c}, + {0x5e, 0x3a}, + {0x5f, 0x00}, + {0x60, 0x66}, + {0x41, 0x1f}, + {0xb5, 0x01}, + {0xb6, 0x02}, + {0xb9, 0x40}, + {0xba, 0x28}, + {0xbf, 0x0c}, + {0xc0, 0x3e}, + {0xa3, 0x0a}, + {0xa4, 0x0f}, + {0xa5, 0x09}, + {0xa6, 0x16}, + {0x9f, 0x0a}, + {0xa0, 0x0f}, + {0xa7, 0x0a}, + {0xa8, 0x0f}, + {0xa1, 0x10}, + {0xa2, 0x04}, + {0xa9, 0x04}, + {0xaa, 0xa6}, + {0x75, 0x6a}, + {0x76, 0x11}, + {0x77, 0x92}, + {0x78, 0x21}, + {0x79, 0xe1}, + {0x7a, 0x02}, + {0x7c, 0x05}, + {0x7d, 0x08}, + {0x7e, 0x08}, + {0x7f, 0x7c}, + {0x80, 0x58}, + {0x81, 0x2a}, + {0x82, 0xc5}, + {0x83, 0x46}, + {0x84, 0x3a}, + {0x85, 0x54}, + {0x86, 0x44}, + {0x87, 0xf8}, + {0x88, 0x08}, + {0x89, 0x70}, + {0x8a, 0xf0}, + {0x8b, 0xf0}, + {0x90, 0xe3}, + {0x93, 0x10}, + {0x94, 0x20}, + {0x95, 0x10}, + {0x96, 0x18}, + {0x0f, 0x34}, + + {0x13, 0x00}, + {0x3d, 0x48}, + {0x0e, 0xb8}, + {0x20, 0x02}, + {0x21, 0x18}, + {0x22, 0x00}, + {0x23, 0x42}, + {0x24, 0x28}, + {0x25, 0x04}, + {0x26, 0x1e}, + {0x27, 0x04}, + {0x28, 0x40}, + {0x29, 0x04}, + {0x2a, 0xce}, + {0x2b, 0x02}, + {0x2c, 0x8a}, + {0x12, 0x09}, + {0x39, 0xd0}, + {0xcd, 0x13}, + {0xde, 0x7c}, + {0x3d, 0x08}, + {0x13, 0xff}, + {0x15, 0x42}, + {0xFF, 0xFF}, +}; + +static const struct ov2640_win_size ov2643_supported_win_sizes[] = { + OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2643_yuv_vga), + OV2640_SIZE("SWVGA", XGA_WIDTH, SVGA_HEIGHT, ov2643_yuv_swvga), + OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2643_yuv_uxga), +}; From bd9958ba8d656a59e93a5c2f2f32bb95c3b43f14 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 15 Jun 2015 14:49:11 +0800 Subject: [PATCH 246/381] ov2643: correct enum_mbus_code() function as ov2643 only support UYVY Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 092c8ebf633784..cf6d3ad8afd27f 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -966,6 +966,19 @@ static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2640_priv *priv = to_ov2640(client); + + if (priv->model == V4L2_IDENT_OV2643) { + /* OV2643 only support UYVY format */ + if (code->pad || code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_UYVY8_2X8; + return 0; + } + + /* OV2640 */ if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes)) return -EINVAL; From 6e081e16e99ad4b0e70b3cf5b4af89016867ec5a Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 15 Jun 2015 16:30:35 +0800 Subject: [PATCH 247/381] ov2643: add flip control support Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 32 +++++++++++++++++++++++---- drivers/media/i2c/soc_camera/ov2643.h | 6 +++++ 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index cf6d3ad8afd27f..271b1be69e5b5f 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -694,6 +694,8 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) struct v4l2_subdev *sd = &container_of(ctrl->handler, struct ov2640_priv, hdl)->subdev; struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov2640_priv *priv = to_ov2640(client); + u8 val; int ret; @@ -703,11 +705,25 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case V4L2_CID_VFLIP: - val = ctrl->val ? REG04_VFLIP_IMG : 0x00; - return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); + if (priv->model == V4L2_IDENT_OV2640) { + val = ctrl->val ? REG04_VFLIP_IMG : 0x00; + return ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val); + } else { + val = ctrl->val ? OV2643_VFLIP_IMG : 0x00; + ov2643_flip_reg = ctrl->val ? ov2643_flip_reg | OV2643_VFLIP_IMG : + ov2643_flip_reg & ~OV2643_VFLIP_IMG; + return ov2640_mask_set(client, OV2643_FLIP_REG, OV2643_VFLIP_IMG, val); + } case V4L2_CID_HFLIP: - val = ctrl->val ? REG04_HFLIP_IMG : 0x00; - return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); + if (priv->model == V4L2_IDENT_OV2640) { + val = ctrl->val ? REG04_HFLIP_IMG : 0x00; + return ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val); + } else { + val = ctrl->val ? OV2643_HFLIP_IMG : 0x00; + ov2643_flip_reg = ctrl->val ? ov2643_flip_reg | OV2643_HFLIP_IMG : + ov2643_flip_reg & ~OV2643_HFLIP_IMG; + return ov2640_mask_set(client, OV2643_FLIP_REG, OV2643_HFLIP_IMG, val); + } } return -EINVAL; @@ -865,6 +881,7 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, { struct ov2640_priv *priv = to_ov2640(client); int ret; + s32 val; /* select win */ priv->win = ov2640_select_win(width, height, priv); @@ -877,6 +894,13 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, /* set size win */ ret = ov2640_write_array(client, priv->win->regs); + /* set flip control */ + val = i2c_smbus_read_byte_data(client, OV2643_FLIP_REG); + val |= ov2643_flip_reg; + + dev_err(&client->dev, "set flip reg: 0x%08x\n", val); + ret = i2c_smbus_write_byte_data(client, OV2643_FLIP_REG, val); + priv->cfmt_code = code; *width = priv->win->width; *height = priv->win->height; diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h index 14e8cda3115890..4d223ee909a69d 100644 --- a/drivers/media/i2c/soc_camera/ov2643.h +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -1,5 +1,11 @@ #define PID_OV2643 0x2643 +#define OV2643_FLIP_REG 0x12 +#define OV2643_HFLIP_IMG 0x20 /* Horizontal mirror image ON/OFF */ +#define OV2643_VFLIP_IMG 0x10 /* Vertical flip image ON/OFF */ + +static u8 ov2643_flip_reg; + static const struct regval_list ov2643_yuv_uxga[]= { {0x12, 0x80}, {0xc3, 0x1f}, From 849f2ffbe5b90f449573ea31e705fb390f367876 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 26 Jun 2015 17:27:30 +0800 Subject: [PATCH 248/381] ov2643: correct the name of the register:0x12 In the datasheet, 0x12 register is SYS register. In SYS register, it includes functions: RESET, CROP, FLIP, MIRROR, FRM_CTRL0, size_sel Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 8 ++++---- drivers/media/i2c/soc_camera/ov2643.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 271b1be69e5b5f..efd64dbf5fa686 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -712,7 +712,7 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) val = ctrl->val ? OV2643_VFLIP_IMG : 0x00; ov2643_flip_reg = ctrl->val ? ov2643_flip_reg | OV2643_VFLIP_IMG : ov2643_flip_reg & ~OV2643_VFLIP_IMG; - return ov2640_mask_set(client, OV2643_FLIP_REG, OV2643_VFLIP_IMG, val); + return ov2640_mask_set(client, OV2643_SYS_REG, OV2643_VFLIP_IMG, val); } case V4L2_CID_HFLIP: if (priv->model == V4L2_IDENT_OV2640) { @@ -722,7 +722,7 @@ static int ov2640_s_ctrl(struct v4l2_ctrl *ctrl) val = ctrl->val ? OV2643_HFLIP_IMG : 0x00; ov2643_flip_reg = ctrl->val ? ov2643_flip_reg | OV2643_HFLIP_IMG : ov2643_flip_reg & ~OV2643_HFLIP_IMG; - return ov2640_mask_set(client, OV2643_FLIP_REG, OV2643_HFLIP_IMG, val); + return ov2640_mask_set(client, OV2643_SYS_REG, OV2643_HFLIP_IMG, val); } } @@ -895,11 +895,11 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, ret = ov2640_write_array(client, priv->win->regs); /* set flip control */ - val = i2c_smbus_read_byte_data(client, OV2643_FLIP_REG); + val = i2c_smbus_read_byte_data(client, OV2643_SYS_REG); val |= ov2643_flip_reg; dev_err(&client->dev, "set flip reg: 0x%08x\n", val); - ret = i2c_smbus_write_byte_data(client, OV2643_FLIP_REG, val); + ret = i2c_smbus_write_byte_data(client, OV2643_SYS_REG, val); priv->cfmt_code = code; *width = priv->win->width; diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h index 4d223ee909a69d..b3c7db170e215c 100644 --- a/drivers/media/i2c/soc_camera/ov2643.h +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -1,8 +1,8 @@ #define PID_OV2643 0x2643 -#define OV2643_FLIP_REG 0x12 -#define OV2643_HFLIP_IMG 0x20 /* Horizontal mirror image ON/OFF */ -#define OV2643_VFLIP_IMG 0x10 /* Vertical flip image ON/OFF */ +#define OV2643_SYS_REG 0x12 +#define OV2643_HFLIP_IMG 0x20 /* Horizontal mirror image ON/OFF */ +#define OV2643_VFLIP_IMG 0x10 /* Vertical flip image ON/OFF */ static u8 ov2643_flip_reg; From 7aba96ea8d6d09adee261185899be56ecd259187 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 26 Jun 2015 16:53:30 +0800 Subject: [PATCH 249/381] ov2643: add more information Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2643.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h index b3c7db170e215c..fddd83e6dbfe32 100644 --- a/drivers/media/i2c/soc_camera/ov2643.h +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -18,7 +18,7 @@ static const struct regval_list ov2643_yuv_uxga[]= { {0x0f, 0x14}, {0x21, 0x25}, {0x23, 0x0c}, - {0x12, 0x08}, + {0x12, 0x08}, /* YUV output, Bit[3:2] = 1x, Bit[1:0] = 00, no subsample */ {0x39, 0x10}, {0xcd, 0x12}, {0x13, 0xff}, @@ -159,7 +159,7 @@ static const struct regval_list ov2643_yuv_uxga[]= { {0x0f, 0x14}, {0x21, 0x25}, {0x23, 0x0c}, - {0x12, 0x08}, + {0x12, 0x08}, /* YUV output, Bit[3:2] = 1x, Bit[1:0] = 00, no subsample */ {0x39, 0x10}, {0xcd, 0x12}, {0x13, 0xff}, @@ -178,7 +178,7 @@ static const struct regval_list ov2643_yuv_uxga[]= { {0x35, 0x10}, {0x36, 0x10}, {0x0c, 0x00}, - {0x0d, 0x20}, /* YUV/RGB format */ + {0x0d, 0x20}, /* Bit[6:5] = 01, UYVY/BGRG */ {0xd0, 0x93}, {0xdc, 0x2b}, {0xd9, 0x41}, @@ -303,7 +303,7 @@ static const struct regval_list ov2643_yuv_swvga[]= { {0x0f, 0x14}, {0x21, 0x25}, {0x23, 0x0c}, - {0x12, 0x08}, + {0x12, 0x08}, /* YUV output, Bit[3:2] = 1x, Bit[1:0] = 00, no subsample */ {0x39, 0x10}, {0xcd, 0x12}, {0x13, 0xff}, @@ -322,7 +322,7 @@ static const struct regval_list ov2643_yuv_swvga[]= { {0x35, 0x10}, {0x36, 0x10}, {0x0c, 0x00}, - {0x0d, 0x20}, /* YUV/RGB format */ + {0x0d, 0x20}, /* Bit[6:5] = 01, UYVY/BGRG */ {0xd0, 0x93}, {0xdc, 0x2b}, {0xd9, 0x41}, @@ -455,7 +455,7 @@ static const struct regval_list ov2643_yuv_swvga[]= { {0x2a, 0xce}, {0x2b, 0x02}, {0x2c, 0x8a}, - {0x12, 0x09}, + {0x12, 0x09}, /* YUV output, Bit[3:2] = 1x, Bit[1:0] = 01, subsample */ {0x39, 0xd0}, {0xcd, 0x13}, {0xde, 0x7c}, @@ -478,7 +478,7 @@ static const struct regval_list ov2643_yuv_vga[]= { {0x0f, 0x14}, {0x21, 0x25}, {0x23, 0x0c}, - {0x12, 0x08}, + {0x12, 0x08}, /* YUV output, Bit[3:2] = 1x, Bit[1:0] = 00, no subsample */ {0x39, 0x10}, {0xcd, 0x12}, {0x13, 0xff}, @@ -497,7 +497,7 @@ static const struct regval_list ov2643_yuv_vga[]= { {0x35, 0x10}, {0x36, 0x10}, {0x0c, 0x00}, - {0x0d, 0x20}, /* YUV/RGB format */ + {0x0d, 0x20}, /* Bit[6:5] = 01, UYVY/BGRG */ {0xd0, 0x93}, {0xdc, 0x2b}, {0xd9, 0x41}, @@ -624,7 +624,7 @@ static const struct regval_list ov2643_yuv_vga[]= { {0x2a, 0xce}, {0x2b, 0x02}, {0x2c, 0x8a}, - {0x12, 0x09}, + {0x12, 0x09}, /* YUV output, Bit[3:2] = 1x, Bit[1:0] = 01, subsample */ {0x39, 0xd0}, {0xcd, 0x13}, {0xde, 0x7c}, From 52a08efb87dda02ada4e153f919e606a68e5eac3 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 29 Jun 2015 14:29:48 +0800 Subject: [PATCH 250/381] ov2643: add RGB565 support We only need to setup SYS, DVP2 registers to let ov2643 output RGB565 format. Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 11 ++++++++++- drivers/media/i2c/soc_camera/ov2643.h | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index efd64dbf5fa686..df7c4b95c6e466 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -886,7 +886,7 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, /* select win */ priv->win = ov2640_select_win(width, height, priv); - if (code != MEDIA_BUS_FMT_UYVY8_2X8) { + if (code != MEDIA_BUS_FMT_UYVY8_2X8 && code != MEDIA_BUS_FMT_RGB565_2X8_LE) { dev_err(&client->dev, "Not supported format: %d\n", code); return -1; } @@ -901,6 +901,15 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, dev_err(&client->dev, "set flip reg: 0x%08x\n", val); ret = i2c_smbus_write_byte_data(client, OV2643_SYS_REG, val); + /* set RGB565 output */ + if (code == MEDIA_BUS_FMT_RGB565_2X8_LE) { + ov2640_mask_set(client, OV2643_SYS_REG, + OV2643_SYS_MASK_FORMAT_SEL, OV2643_SYS_FORMAT_RGB); + + ov2640_mask_set(client, OV2643_DVP2_REG, + OV2643_DVP2_MASK_RGB_SEL, OV2643_DVP2_FORMAT_RGB565); + } + priv->cfmt_code = code; *width = priv->win->width; *height = priv->win->height; diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h index fddd83e6dbfe32..961ac27aa80f31 100644 --- a/drivers/media/i2c/soc_camera/ov2643.h +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -4,6 +4,18 @@ #define OV2643_HFLIP_IMG 0x20 /* Horizontal mirror image ON/OFF */ #define OV2643_VFLIP_IMG 0x10 /* Vertical flip image ON/OFF */ +#define OV2643_SYS_MASK_FORMAT_SEL 0xc /* format_sel, Bit[3:2] */ +#define OV2643_SYS_FORMAT_RAW (0x0 << 2) +#define OV2643_SYS_FORMAT_RGB (0x1 << 2) +#define OV2643_SYS_FORMAT_YUV (0x2 << 2) + +#define OV2643_DVP2_REG 0x0d +#define OV2643_DVP2_MASK_RGB_SEL 0xc /* rgb_sel, Bit[3:2] */ +#define OV2643_DVP2_FORMAT_RGB555 (0x0 << 2) +#define OV2643_DVP2_FORMAT_RGB565 (0x1 << 2) +#define OV2643_DVP2_FORMAT_GBR422 (0x2 << 2) +/* Bit[6:5]: YUV422/GBR422 only impact YUV422 & raw RGB. no effect for RGB565/RGB555. */ + static u8 ov2643_flip_reg; static const struct regval_list ov2643_yuv_uxga[]= { From 08ddc4cf79b92c1e4547048a6f7f3a85c2b818ab Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 26 Jun 2015 15:57:38 +0800 Subject: [PATCH 251/381] ov2643: add rgb565 output support Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 19 ++++++++++--------- drivers/media/i2c/soc_camera/ov2643.h | 5 +++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index df7c4b95c6e466..37b8b4d3c8a2b7 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -1002,20 +1002,21 @@ static int ov2640_enum_mbus_code(struct v4l2_subdev *sd, struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov2640_priv *priv = to_ov2640(client); - if (priv->model == V4L2_IDENT_OV2643) { - /* OV2643 only support UYVY format */ - if (code->pad || code->index > 0) - return -EINVAL; + int support_fmt_num; + u32 *support_codes; - code->code = MEDIA_BUS_FMT_UYVY8_2X8; - return 0; + if (priv->model == V4L2_IDENT_OV2643) { + support_fmt_num = ARRAY_SIZE(ov2643_codes); + support_codes = ov2643_codes; + } else { + support_fmt_num = ARRAY_SIZE(ov2640_codes); + support_codes = ov2640_codes; } - /* OV2640 */ - if (code->pad || code->index >= ARRAY_SIZE(ov2640_codes)) + if (code->pad || code->index >= support_fmt_num) return -EINVAL; - code->code = ov2640_codes[code->index]; + code->code = support_codes[code->index]; return 0; } diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h index 961ac27aa80f31..9159f75bbf4e3a 100644 --- a/drivers/media/i2c/soc_camera/ov2643.h +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -646,6 +646,11 @@ static const struct regval_list ov2643_yuv_vga[]= { {0xFF, 0xFF}, }; +static u32 ov2643_codes[] = { + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_RGB565_2X8_LE, +}; + static const struct ov2640_win_size ov2643_supported_win_sizes[] = { OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2643_yuv_vga), OV2640_SIZE("SWVGA", XGA_WIDTH, SVGA_HEIGHT, ov2643_yuv_swvga), From 58fc65273b93526217d5b2c54c6a4094319693f3 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 29 Jun 2015 17:26:32 +0800 Subject: [PATCH 252/381] ov2643: enable raw rgb support (Bayer BGGR) Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 14 +++++++++++++- drivers/media/i2c/soc_camera/ov2643.h | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 37b8b4d3c8a2b7..0c16e1bb35e9ab 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -886,7 +886,8 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, /* select win */ priv->win = ov2640_select_win(width, height, priv); - if (code != MEDIA_BUS_FMT_UYVY8_2X8 && code != MEDIA_BUS_FMT_RGB565_2X8_LE) { + if (code != MEDIA_BUS_FMT_UYVY8_2X8 && code != MEDIA_BUS_FMT_RGB565_2X8_LE && + code != MEDIA_BUS_FMT_SBGGR8_1X8) { dev_err(&client->dev, "Not supported format: %d\n", code); return -1; } @@ -908,6 +909,13 @@ static int ov2643_set_params(struct i2c_client *client, u32 *width, u32 *height, ov2640_mask_set(client, OV2643_DVP2_REG, OV2643_DVP2_MASK_RGB_SEL, OV2643_DVP2_FORMAT_RGB565); + } else if (code == MEDIA_BUS_FMT_SBGGR8_1X8) { + /* set raw RGB BGGR output */ + ov2640_mask_set(client, OV2643_SYS_REG, + OV2643_SYS_MASK_FORMAT_SEL, OV2643_SYS_FORMAT_RAW); + + ov2640_mask_set(client, OV2643_DVP2_REG, + OV2643_DVP2_MASK_RAW_SEL, OV2643_DVP2_RAW_FROM_ISP); } priv->cfmt_code = code; @@ -941,6 +949,8 @@ static int ov2640_get_fmt(struct v4l2_subdev *sd, switch (mf->code) { case MEDIA_BUS_FMT_RGB565_2X8_BE: case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: @@ -974,6 +984,8 @@ static int ov2640_set_fmt(struct v4l2_subdev *sd, switch (mf->code) { case MEDIA_BUS_FMT_RGB565_2X8_BE: case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: diff --git a/drivers/media/i2c/soc_camera/ov2643.h b/drivers/media/i2c/soc_camera/ov2643.h index 9159f75bbf4e3a..e7794a53d7960b 100644 --- a/drivers/media/i2c/soc_camera/ov2643.h +++ b/drivers/media/i2c/soc_camera/ov2643.h @@ -14,6 +14,9 @@ #define OV2643_DVP2_FORMAT_RGB555 (0x0 << 2) #define OV2643_DVP2_FORMAT_RGB565 (0x1 << 2) #define OV2643_DVP2_FORMAT_GBR422 (0x2 << 2) +#define OV2643_DVP2_MASK_RAW_SEL 0x10 /* raw data selection, Bit[4] */ +#define OV2643_DVP2_RAW_FROM_ISP (0x0 << 4) +#define OV2643_DVP2_RAW_FROM_SENSOR (0x1 << 4) /* Bit[6:5]: YUV422/GBR422 only impact YUV422 & raw RGB. no effect for RGB565/RGB555. */ static u8 ov2643_flip_reg; @@ -649,6 +652,7 @@ static const struct regval_list ov2643_yuv_vga[]= { static u32 ov2643_codes[] = { MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_RGB565_2X8_LE, + MEDIA_BUS_FMT_SBGGR8_1X8, }; static const struct ov2640_win_size ov2643_supported_win_sizes[] = { From ec98874344c69ea44bb5c90c00ab951a1fd93ef5 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 28 Oct 2015 16:56:38 +0800 Subject: [PATCH 253/381] soc_camera: get the clock name by using macro: v4l2_clk_name_i2c() Since v4l2_clk_name_i2c() is defined, so just reuse it. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/soc_camera.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 43f9d67e9d7f7e..69e4224f6e60a1 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1391,8 +1391,8 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, ssdd->sd_pdata.regulators = NULL; shd->board_info->platform_data = ssdd; - snprintf(clk_name, sizeof(clk_name), "%d-%04x", - shd->i2c_adapter_id, shd->board_info->addr); + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + shd->i2c_adapter_id, shd->board_info->addr); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { @@ -1572,8 +1572,9 @@ static int scan_async_group(struct soc_camera_host *ici, icd->sasc = sasc; icd->parent = ici->v4l2_dev.dev; - snprintf(clk_name, sizeof(clk_name), "%d-%04x", - sasd->asd.match.i2c.adapter_id, sasd->asd.match.i2c.address); + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + sasd->asd.match.i2c.adapter_id, + sasd->asd.match.i2c.address); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { @@ -1674,8 +1675,8 @@ static int soc_of_bind(struct soc_camera_host *ici, client = of_find_i2c_device_by_node(remote); if (client) - snprintf(clk_name, sizeof(clk_name), "%d-%04x", - client->adapter->nr, client->addr); + v4l2_clk_name_i2c(clk_name, sizeof(clk_name), + client->adapter->nr, client->addr); else snprintf(clk_name, sizeof(clk_name), "of-%s", of_node_full_name(remote)); From aebeb733cc795ad30486415c4c72c15217948742 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 28 Oct 2015 17:01:45 +0800 Subject: [PATCH 254/381] v4l2-clk: add new macro for v4l2_clk_name_of() This macro is used to generate a OF string for a v4l2 clock. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/soc_camera.c | 4 ++-- include/media/v4l2-clk.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index 69e4224f6e60a1..d509e93c9dbefd 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1678,8 +1678,8 @@ static int soc_of_bind(struct soc_camera_host *ici, v4l2_clk_name_i2c(clk_name, sizeof(clk_name), client->adapter->nr, client->addr); else - snprintf(clk_name, sizeof(clk_name), "of-%s", - of_node_full_name(remote)); + v4l2_clk_name_of(clk_name, sizeof(clk_name), + of_node_full_name(remote)); icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, icd); if (IS_ERR(icd->clk)) { diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h index 3ef6e3d5ed6c6f..34891ea5f3291c 100644 --- a/include/media/v4l2-clk.h +++ b/include/media/v4l2-clk.h @@ -68,4 +68,7 @@ static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id, #define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \ "%d-%04x", adap, client) +#define v4l2_clk_name_of(name, size, of_full_name) snprintf(name, size, \ + "of-%s", of_full_name) + #endif From 5326033d64e41e9e5700ace1b390567634d07f63 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 28 Oct 2015 17:05:12 +0800 Subject: [PATCH 255/381] v4l2-clk: add new definition: V4L2_CLK_NAME_SIZE Make all v4l2-clk's clock name use V4L2_CLK_NAME_SIZE definition. In future, if the string increased we just need to change the V4L2_CLK_NAME_SIZE once. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/soc_camera.c | 6 +++--- drivers/media/usb/em28xx/em28xx-camera.c | 2 +- include/media/v4l2-clk.h | 2 ++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index d509e93c9dbefd..f6cb826debdab1 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1360,7 +1360,7 @@ static int soc_camera_i2c_init(struct soc_camera_device *icd, struct soc_camera_host_desc *shd = &sdesc->host_desc; struct i2c_adapter *adap; struct v4l2_subdev *subdev; - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_CLK_NAME_SIZE]; int ret; /* First find out how we link the main client */ @@ -1526,7 +1526,7 @@ static int scan_async_group(struct soc_camera_host *ici, struct soc_camera_async_client *sasc; struct soc_camera_device *icd; struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,}; - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_CLK_NAME_SIZE]; unsigned int i; int ret; @@ -1632,7 +1632,7 @@ static int soc_of_bind(struct soc_camera_host *ici, struct soc_camera_async_client *sasc; struct soc_of_info *info; struct i2c_client *client; - char clk_name[V4L2_SUBDEV_NAME_SIZE + 32]; + char clk_name[V4L2_CLK_NAME_SIZE]; int ret; /* allocate a new subdev and add match info to it */ diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index ed0b3a87983e45..121cdfc6933bed 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -322,7 +322,7 @@ int em28xx_detect_sensor(struct em28xx *dev) int em28xx_init_camera(struct em28xx *dev) { - char clk_name[V4L2_SUBDEV_NAME_SIZE]; + char clk_name[V4L2_CLK_NAME_SIZE]; struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; struct em28xx_v4l2 *v4l2 = dev->v4l2; diff --git a/include/media/v4l2-clk.h b/include/media/v4l2-clk.h index 34891ea5f3291c..2b94662d005c49 100644 --- a/include/media/v4l2-clk.h +++ b/include/media/v4l2-clk.h @@ -65,6 +65,8 @@ static inline struct v4l2_clk *v4l2_clk_register_fixed(const char *dev_id, return __v4l2_clk_register_fixed(dev_id, rate, THIS_MODULE); } +#define V4L2_CLK_NAME_SIZE 64 + #define v4l2_clk_name_i2c(name, size, adap, client) snprintf(name, size, \ "%d-%04x", adap, client) From e6d3e10cad617d2345b6e4b79735242d36f9e441 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 28 Oct 2015 16:41:28 +0800 Subject: [PATCH 256/381] v4l2-clk: v4l2_clk_get() also need to find the of_fullname clock The soc-camera host will be probed and register a v4l2_clk, but if on that moment, the i2c device is not available, then the registered v4l2_clk name is a OF string not a I2C string. So when i2c sensor probed and call v4l2_clk_get(), it only search the clock with I2C string, like "1-0030". This patch will search the clock with OF string name if fail to find the clock with I2C string name. Signed-off-by: Josh Wu --- drivers/media/v4l2-core/v4l2-clk.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-clk.c b/drivers/media/v4l2-core/v4l2-clk.c index 34e416a554f642..297e10e698986b 100644 --- a/drivers/media/v4l2-core/v4l2-clk.c +++ b/drivers/media/v4l2-core/v4l2-clk.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) { struct v4l2_clk *clk; struct clk *ccf_clk = clk_get(dev, id); + char clk_name[V4L2_CLK_NAME_SIZE]; if (PTR_ERR(ccf_clk) == -EPROBE_DEFER) return ERR_PTR(-EPROBE_DEFER); @@ -57,6 +59,13 @@ struct v4l2_clk *v4l2_clk_get(struct device *dev, const char *id) mutex_lock(&clk_lock); clk = v4l2_clk_find(dev_name(dev)); + /* if dev_name is not found, try use the OF name to find again */ + if (PTR_ERR(clk) == -ENODEV && dev->of_node) { + v4l2_clk_name_of(clk_name, sizeof(clk_name), + of_node_full_name(dev->of_node)); + clk = v4l2_clk_find(clk_name); + } + if (!IS_ERR(clk)) atomic_inc(&clk->use_count); mutex_unlock(&clk_lock); From 01ec1029d696d6d189f8d28c872f2235fa806964 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 7 Jan 2015 15:23:38 +0800 Subject: [PATCH 257/381] media: soc_camera: enable multiple subdevice support Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/soc_camera.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index f6cb826debdab1..05f68f461f4699 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -1723,16 +1723,9 @@ static void scan_of_host(struct soc_camera_host *ici) continue; } - /* so we now have a remote node to connect */ - if (!i) - soc_of_bind(ici, epn, ren->parent); + soc_of_bind(ici, epn, ren->parent); of_node_put(ren); - - if (i) { - dev_err(dev, "multiple subdevices aren't supported yet!\n"); - break; - } } of_node_put(epn); From af00f5883f5cc5ae8c8b0363bd319de7beafc88c Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 31 Jul 2015 16:05:06 +0800 Subject: [PATCH 258/381] ov2643: make vsync-active low Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov2640.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index 0c16e1bb35e9ab..4dea2250a086af 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -1124,6 +1124,7 @@ static int ov2640_g_mbus_config(struct v4l2_subdev *sd, cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_PARALLEL; cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); From 14744bef785372e11528149e95f9befa138d3f95 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 30 Oct 2015 14:11:43 +0100 Subject: [PATCH 259/381] ARM: at91/dt: add xplained device trees for PDA screens Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/Makefile | 6 + .../dts/at91-sama5d2_xplained_dm_pda4.dtsi | 243 +++++++++ .../boot/dts/at91-sama5d2_xplained_pda4.dts | 493 ++++++++++++++++++ .../dts/at91-sama5d3_xplained_dm_pda4.dtsi | 110 ++++ .../dts/at91-sama5d3_xplained_dm_pda7.dtsi | 110 ++++ .../boot/dts/at91-sama5d3_xplained_pda4.dts | 337 ++++++++++++ .../boot/dts/at91-sama5d3_xplained_pda7.dts | 337 ++++++++++++ .../dts/at91-sama5d4_xplained_dm_pda4.dtsi | 146 ++++++ .../dts/at91-sama5d4_xplained_dm_pda7.dtsi | 146 ++++++ .../boot/dts/at91-sama5d4_xplained_hdmi.dts | 320 ++++++++++++ .../boot/dts/at91-sama5d4_xplained_pda4.dts | 281 ++++++++++ .../boot/dts/at91-sama5d4_xplained_pda7.dts | 281 ++++++++++ 12 files changed, 2810 insertions(+) create mode 100644 arch/arm/boot/dts/at91-sama5d2_xplained_dm_pda4.dtsi create mode 100644 arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts create mode 100644 arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda4.dtsi create mode 100644 arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda7.dtsi create mode 100644 arch/arm/boot/dts/at91-sama5d3_xplained_pda4.dts create mode 100644 arch/arm/boot/dts/at91-sama5d3_xplained_pda7.dts create mode 100644 arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda4.dtsi create mode 100644 arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda7.dtsi create mode 100644 arch/arm/boot/dts/at91-sama5d4_xplained_hdmi.dts create mode 100644 arch/arm/boot/dts/at91-sama5d4_xplained_pda4.dts create mode 100644 arch/arm/boot/dts/at91-sama5d4_xplained_pda7.dts diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index a2c3853a26bc40..78dc1f828a9eaf 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -42,13 +42,19 @@ dtb-$(CONFIG_SOC_SAM_V4_V5) += \ dtb-$(CONFIG_SOC_SAM_V7) += \ at91-kizbox2.dtb \ at91-sama5d2_xplained.dtb \ + at91-sama5d2_xplained_pda4.dtb \ at91-sama5d3_xplained.dtb \ sama5d31ek.dtb \ + at91-sama5d3_xplained_pda4.dtb \ + at91-sama5d3_xplained_pda7.dtb \ sama5d33ek.dtb \ sama5d34ek.dtb \ sama5d35ek.dtb \ sama5d36ek.dtb \ at91-sama5d4_xplained.dtb \ + at91-sama5d4_xplained_hdmi.dtb \ + at91-sama5d4_xplained_pda4.dtb \ + at91-sama5d4_xplained_pda7.dtb \ at91-sama5d4ek.dtb dtb-$(CONFIG_ARCH_ATLAS6) += \ atlas6-evb.dtb diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_dm_pda4.dtsi b/arch/arm/boot/dts/at91-sama5d2_xplained_dm_pda4.dtsi new file mode 100644 index 00000000000000..403c2ea8554889 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_dm_pda4.dtsi @@ -0,0 +1,243 @@ +/* + * Device Tree Include file for PDA4 display module on SAMA5D2 Xplained board + * + * Copyright (C) 2015 Atmel, + * 2015 Nicolas Ferre + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/ { + ahb { + apb { + hlcdc: hlcdc@f0000000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_pwm>; + }; + }; + + i2c1: i2c@fc028000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_default>; + status = "okay"; + + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioA>; + interrupts = <40 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4a { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4a>; + interrupt-parent = <&pioA>; + interrupts = <39 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_irq>; + }; + }; + + pinctrl@fc038000 { + group_defs { + i2c1_0 { + pins = , + ; + }; + + lcd_base_0 { + pins = , /* LCDVSYNC */ + , /* LCDHSYNC */ + , /* LCDDEN */ + ; /* LCDPCK */ + }; + + lcd_pwm_0 { + pins = ; /* LCDPWM */ + }; + + lcd_rgb666_0 { + pins = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + }; + + mxt_irq { + pins = ; + }; + + qt1070_irq { + pins = ; + }; + }; + + pinctrl_i2c1_default: i2c1_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_lcd_base: pinctrl_lcd_base { + pinmux = , + , + , + ; + bias-disable; + }; + + pinctrl_lcd_pwm: pinctrl_lcd_pwm { + pinmux = ; + bias-disable; + }; + + pinctrl_lcd_rgb666: pinctrl_lcd_rgb666 { + pinmux = , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + , + ; + bias-disable; + }; + + pinctrl_mxt_irq: pinctrl_mxt_irq { + pinmux = ; + bias-pull-up; + input-debounce = <1>; + }; + + pinctrl_qt1070_irq: pinctrl_qt1070_irq { + pinmux = ; + bias-pull-up; + input-debounce = <1>; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "innolux,at043tn24", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts new file mode 100644 index 00000000000000..195b0563b99e7e --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -0,0 +1,493 @@ +/* + * at91-sama5d2_xplained.dts - Device Tree file for SAMA5D2 Xplained board + * + * Copyright (C) 2015 Atmel, + * 2015 Nicolas Ferre + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; +#include "sama5d2.dtsi" +#include "sama5d2-pinfunc.h" +#include +#include +#include "at91-sama5d2_xplained_dm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D2 Xplained TM43xx"; + compatible = "atmel,sama5d2-xplained", "atmel,sama5d2", "atmel,sama5"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x80000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + usb0: gadget@00300000 { + atmel,vbus-gpio = <&pioA 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00400000 { + num-ports = <3>; + atmel,vbus-gpio = <0 /* &pioA 41 GPIO_ACTIVE_HIGH */ + &pioA 42 GPIO_ACTIVE_HIGH + 0 + >; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_default>; + status = "okay"; + }; + + usb2: ehci@00500000 { + status = "okay"; + }; + + sdmmc0: sdio-host@a0000000 { + bus-width = <8>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc0_default>; + non-removable; + mmc-ddr-1_8v; + status = "okay"; + }; + + sdmmc1: sdio-host@b0000000 { + bus-width = <4>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sdmmc1_default>; + status = "okay"; /* conflict with qspi0 */ + }; + + apb { + qspi0: qspi@f0020000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qspi0_default>; + /*status = "okay";*/ /* conflict with sdmmc1 */ + + m25p80@0 { + compatible = "micron,n25q128a13"; + reg = <0>; + spi-max-frequency = <83000000>; + m25p,num-dummy-cycles = <6>; + }; + }; + + spi0: spi@f8000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spi0_default>; + status = "okay"; + + m25p80@0 { + compatible = "atmel,at25df321a"; + reg = <0>; + spi-max-frequency = <50000000>; + }; + }; + + macb0: ethernet@f8008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_macb0_rmii>; + phy-mode = "rmii"; + status = "okay"; + }; + + uart1: serial@f8020000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart1_default>; + status = "okay"; + }; + + i2c0: i2c@f8028000 { + dmas = <0>, <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0_default>; + atmel,twd-hold-cycles = <25>; + status = "okay"; + + pmic: act8865@5b { + compatible = "active-semi,act8865"; + reg = <0x5b>; + active-semi,vsel-high; + status = "okay"; + + regulators { + vdd_1v35_reg: DCDC_REG1 { + regulator-name = "VDD_1V35"; + regulator-min-microvolt = <1350000>; + regulator-max-microvolt = <1350000>; + regulator-always-on; + }; + + vdd_1v2_reg: DCDC_REG2 { + regulator-name = "VDD_1V2"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + }; + + vdd_3v3_reg: DCDC_REG3 { + regulator-name = "VDD_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_fuse_reg: LDO_REG1 { + regulator-name = "VDD_FUSE"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + regulator-always-on; + }; + + vdd_3v3_lp_reg: LDO_REG2 { + regulator-name = "VDD_3V3_LP"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_led_reg: LDO_REG3 { + regulator-name = "VDD_LED"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vdd_sdhc_1v8_reg: LDO_REG4 { + regulator-name = "VDD_SDHC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + }; + }; + }; + + flx0: flexcom@f8034000 { + atmel,flexcom-mode = ; + status = "disabled"; /* conflict with ISC_D2 & ISC_D3 data pins */ + + uart5: serial@200 { + compatible = "atmel,at91sam9260-usart"; + reg = <0x200 0x200>; + interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&flx0_clk>; + clock-names = "usart"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx0_default>; + atmel,fifo-size = <32>; + status = "okay"; + }; + }; + + shdwc@f8048010 { + atmel,shdwc-debouncer = <976>; + + input@0 { + reg = <0>; + atmel,wakeup-type = "low"; + }; + }; + + i2s0: i2s@f8050000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2s0_default>; + }; + + watchdog@f8048040 { + status = "okay"; + }; + + uart3: serial@fc008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_uart3_default>; + status = "disabled"; /* conflict with sensor's reset/pwdn pins */ + }; + + flx4: flexcom@fc018000 { + atmel,flexcom-mode = ; + status = "okay"; + + i2c2: i2c@600 { + compatible = "atmel,sama5d2-i2c"; + reg = <0x600 0x200>; + interrupts = <23 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <0>, <0>; + dma-names = "tx", "rx"; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&flx4_clk>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_flx4_default>; + atmel,fifo-size = <16>; + status = "okay"; + }; + }; + + i2c1: i2c@fc028000 { + dmas = <0>, <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c1_default>; + status = "okay"; + + at24@54 { + compatible = "atmel,24c02"; + reg = <0x54>; + pagesize = <16>; + }; + }; + + pinctrl@fc038000 { + pinctrl_flx0_default: flx0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_flx4_default: flx4_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_i2c0_default: i2c0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_i2c1_default: i2c1_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_i2s0_default: i2s0_default { + pinmux = , + , + , + , + ; + bias-disable; + }; + + pinctrl_key_gpio_default: key_gpio_default { + pinmux = ; + bias-pull-up; + }; + + pinctrl_led_gpio_default: led_gpio_default { + pinmux = , + , + ; + bias-pull-up; + }; + + pinctrl_macb0_rmii: macb0_rmii { + pinmux = , + , + , + , + , + , + , + , + , + ; + bias-disable; + }; + + pinctrl_qspi0_default: qspi0_default { + pinmux = , + , + , + , + , + ; + }; + + pinctrl_sensor_power: sensor_power { + pinmux = ; + bias-disable; + }; + + pinctrl_sensor_reset: sensor_reset { + pinmux = ; + bias-disable; + }; + + pinctrl_sdmmc0_default: sdmmc0_default { + cmd_data { + pinmux = , + , + , + , + , + , + , + , + ; + bias-pull-up; + }; + + ck_cd_rstn_vddsel { + pinmux = , + , + , + ; + bias-disable; + }; + }; + + pinctrl_sdmmc1_default: sdmmc1_default { + cmd_data { + pinmux = , + , + , + , + ; + bias-pull-up; + }; + + conf-ck_cd { + pinmux = , + ; + bias-disable; + }; + }; + + pinctrl_spi0_default: spi0_default { + pinmux = , + , + , + ; + bias-disable; + }; + + pinctrl_uart1_default: uart1_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_uart3_default: uart3_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_usb_default: usb_default { + pinmux = ; + bias-disable; + }; + + pinctrl_usba_vbus: usba_vbus { + pinmux = ; + bias-disable; + }; + + pinctrl_i2c1_default: i2c1_default { + pinmux = , + ; + bias-disable; + }; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio_default>; + + bp1 { + label = "PB_USER"; + gpios = <&pioA 41 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + }; + }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_led_gpio_default>; + status = "okay"; + + red { + label = "red"; + gpios = <&pioA 38 GPIO_ACTIVE_LOW>; + }; + + green { + label = "green"; + gpios = <&pioA 37 GPIO_ACTIVE_LOW>; + }; + + blue { + label = "blue"; + gpios = <&pioA 32 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda4.dtsi b/arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda4.dtsi new file mode 100644 index 00000000000000..a0bec2712f1a9f --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda4.dtsi @@ -0,0 +1,110 @@ +/* + * Device Tree Include file for PDA4 display module on SAMA5D3 Xplained board + * + * Copyright (C) 2014 Atmel, + * 2014 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c1: i2c@f0018000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <8 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4a { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4a>; + interrupt-parent = <&pioE>; + interrupts = <7 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; + }; + + hlcdc: hlcdc@f0030000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + + pinctrl@fffff200 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "innolux,at043tn24", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda7.dtsi b/arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda7.dtsi new file mode 100644 index 00000000000000..5d9362b59532ee --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d3_xplained_dm_pda7.dtsi @@ -0,0 +1,110 @@ +/* + * Device Tree Include file for PDA7 display module on SAMA5D3 Xplained board + * + * Copyright (C) 2014 Atmel, + * 2014 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c1: i2c@f0018000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <8 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4c { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4c>; + interrupt-parent = <&pioE>; + interrupts = <7 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; + }; + + hlcdc: hlcdc@f0030000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666_alt>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + + pinctrl@fffff200 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "shelly,sca07010-bfn-lnn", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d3_xplained_pda4.dts new file mode 100644 index 00000000000000..a65dd79653db0d --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d3_xplained_pda4.dts @@ -0,0 +1,337 @@ +/* + * Device Tree file for the SAMA5D3 Xplained board with PDA4.3 screen + * + * Copyright (C) 2014 Atmel, + * 2014 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "at91-sama5d3_xplained_dm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D3 Xplained TM43xx"; + compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x10000000>; + }; + + clocks { + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + mmc0: mmc@f0000000 { + pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>; + vmmc-supply = <&vcc_mmc0_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <8>; + cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>; + }; + }; + + mmc1: mmc@f8000000 { + vmmc-supply = <&vcc_3v3_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "disabled"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 1 GPIO_ACTIVE_LOW>; + }; + }; + + spi0: spi@f0004000 { + cs-gpios = <&pioD 13 0>, <0>, <0>, <&pioD 16 0>; + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + pinctrl-0 = <&pinctrl_i2c0_pu>; + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + pmic: act8865@5b { + compatible = "active-semi,act8865"; + reg = <0x5b>; + status = "disabled"; + + regulators { + vcc_1v8_reg: DCDC_REG1 { + regulator-name = "VCC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vcc_1v2_reg: DCDC_REG2 { + regulator-name = "VCC_1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vcc_3v3_reg: DCDC_REG3 { + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vddfuse_reg: LDO_REG1 { + regulator-name = "FUSE_2V5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + vddana_reg: LDO_REG2 { + regulator-name = "VDDANA"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + }; + + macb0: ethernet@f0028000 { + phy-mode = "rgmii"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet-phy@7 { + reg = <0x7>; + }; + }; + + pwm0: pwm@f002c000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_pwmh0_0 &pinctrl_pwm0_pwmh1_0>; + status = "okay"; + }; + + usart0: serial@f001c000 { + status = "okay"; + }; + + usart1: serial@f0020000 { + pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>; + status = "okay"; + }; + + uart0: serial@f0024000 { + status = "okay"; + }; + + mmc1: mmc@f8000000 { + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>; + }; + }; + + spi1: spi@f8008000 { + cs-gpios = <&pioC 25 0>; + status = "okay"; + }; + + adc0: adc@f8018000 { + pinctrl-0 = < + &pinctrl_adc0_adtrg + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + &pinctrl_adc0_ad5 + &pinctrl_adc0_ad6 + &pinctrl_adc0_ad7 + &pinctrl_adc0_ad8 + &pinctrl_adc0_ad9 + >; + status = "okay"; + }; + + i2c2: i2c@f801c000 { + dmas = <0>, <0>; /* Do not use DMA for i2c2 */ + pinctrl-0 = <&pinctrl_i2c2_pu>; + status = "okay"; + }; + + macb1: ethernet@f802c000 { + phy-mode = "rmii"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet-phy@1 { + reg = <0x1>; + }; + }; + + dbgu: serial@ffffee00 { + status = "okay"; + }; + + pinctrl@fffff200 { + board { + pinctrl_i2c0_pu: i2c0_pu { + atmel,pins = + , + ; + }; + + pinctrl_i2c2_pu: i2c2_pu { + atmel,pins = + , + ; + }; + + pinctrl_key_gpio: key_gpio_0 { + atmel,pins = + ; + }; + + pinctrl_mmc0_cd: mmc0_cd { + atmel,pins = + ; + }; + + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; /* PE9, conflicts with A9 */ + }; + }; + }; + }; + + nand0: nand@60000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + atmel,has-pmecc; + atmel,pmecc-cap = <4>; + atmel,pmecc-sector-size = <512>; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + + usb0: gadget@00500000 { + atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>; /* PE9, conflicts with A9 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00600000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 3 GPIO_ACTIVE_LOW + &pioE 4 GPIO_ACTIVE_LOW + >; + status = "okay"; + }; + + usb2: ehci@00700000 { + status = "okay"; + }; + }; + + vcc_mmc0_reg: fixedregulator@0 { + compatible = "regulator-fixed"; + gpio = <&pioE 2 GPIO_ACTIVE_LOW>; + regulator-name = "mmc0-card-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio>; + + bp3 { + label = "PB_USER"; + gpios = <&pioE 29 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + + d2 { + label = "d2"; + gpios = <&pioE 23 GPIO_ACTIVE_LOW>; /* PE23, conflicts with A23, CTS2 */ + linux,default-trigger = "heartbeat"; + }; + + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d3_xplained_pda7.dts b/arch/arm/boot/dts/at91-sama5d3_xplained_pda7.dts new file mode 100644 index 00000000000000..05ee35dee6efb2 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d3_xplained_pda7.dts @@ -0,0 +1,337 @@ +/* + * Device Tree file for the SAMA5D3 Xplained board with PDA7 screen + * + * Copyright (C) 2014 Atmel, + * 2014 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "at91-sama5d3_xplained_dm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D3 Xplained TM70xx"; + compatible = "atmel,sama5d3-xplained", "atmel,sama5d3", "atmel,sama5"; + + chosen { + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x10000000>; + }; + + clocks { + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + mmc0: mmc@f0000000 { + pinctrl-0 = <&pinctrl_mmc0_clk_cmd_dat0 &pinctrl_mmc0_dat1_3 &pinctrl_mmc0_dat4_7 &pinctrl_mmc0_cd>; + vmmc-supply = <&vcc_mmc0_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <8>; + cd-gpios = <&pioE 0 GPIO_ACTIVE_LOW>; + }; + }; + + mmc1: mmc@f8000000 { + vmmc-supply = <&vcc_3v3_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "disabled"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 1 GPIO_ACTIVE_LOW>; + }; + }; + + spi0: spi@f0004000 { + cs-gpios = <&pioD 13 0>, <0>, <0>, <&pioD 16 0>; + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + pinctrl-0 = <&pinctrl_i2c0_pu>; + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + pmic: act8865@5b { + compatible = "active-semi,act8865"; + reg = <0x5b>; + status = "disabled"; + + regulators { + vcc_1v8_reg: DCDC_REG1 { + regulator-name = "VCC_1V8"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + vcc_1v2_reg: DCDC_REG2 { + regulator-name = "VCC_1V2"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + + vcc_3v3_reg: DCDC_REG3 { + regulator-name = "VCC_3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + + vddfuse_reg: LDO_REG1 { + regulator-name = "FUSE_2V5"; + regulator-min-microvolt = <2500000>; + regulator-max-microvolt = <2500000>; + }; + + vddana_reg: LDO_REG2 { + regulator-name = "VDDANA"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-always-on; + }; + }; + }; + }; + + macb0: ethernet@f0028000 { + phy-mode = "rgmii"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet-phy@7 { + reg = <0x7>; + }; + }; + + pwm0: pwm@f002c000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pwm0_pwmh0_0 &pinctrl_pwm0_pwmh1_0>; + status = "okay"; + }; + + usart0: serial@f001c000 { + status = "okay"; + }; + + usart1: serial@f0020000 { + pinctrl-0 = <&pinctrl_usart1 &pinctrl_usart1_rts_cts>; + status = "okay"; + }; + + uart0: serial@f0024000 { + status = "okay"; + }; + + mmc1: mmc@f8000000 { + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 1 GPIO_ACTIVE_HIGH>; + }; + }; + + spi1: spi@f8008000 { + cs-gpios = <&pioC 25 0>; + status = "okay"; + }; + + adc0: adc@f8018000 { + pinctrl-0 = < + &pinctrl_adc0_adtrg + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + &pinctrl_adc0_ad5 + &pinctrl_adc0_ad6 + &pinctrl_adc0_ad7 + &pinctrl_adc0_ad8 + &pinctrl_adc0_ad9 + >; + status = "okay"; + }; + + i2c2: i2c@f801c000 { + dmas = <0>, <0>; /* Do not use DMA for i2c2 */ + pinctrl-0 = <&pinctrl_i2c2_pu>; + status = "okay"; + }; + + macb1: ethernet@f802c000 { + phy-mode = "rmii"; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + ethernet-phy@1 { + reg = <0x1>; + }; + }; + + dbgu: serial@ffffee00 { + status = "okay"; + }; + + pinctrl@fffff200 { + board { + pinctrl_i2c0_pu: i2c0_pu { + atmel,pins = + , + ; + }; + + pinctrl_i2c2_pu: i2c2_pu { + atmel,pins = + , + ; + }; + + pinctrl_key_gpio: key_gpio_0 { + atmel,pins = + ; + }; + + pinctrl_mmc0_cd: mmc0_cd { + atmel,pins = + ; + }; + + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; /* PE9, conflicts with A9 */ + }; + }; + }; + }; + + nand0: nand@60000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + atmel,has-pmecc; + atmel,pmecc-cap = <4>; + atmel,pmecc-sector-size = <512>; + nand-on-flash-bbt; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + + usb0: gadget@00500000 { + atmel,vbus-gpio = <&pioE 9 GPIO_ACTIVE_HIGH>; /* PE9, conflicts with A9 */ + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00600000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 3 GPIO_ACTIVE_LOW + &pioE 4 GPIO_ACTIVE_LOW + >; + status = "okay"; + }; + + usb2: ehci@00700000 { + status = "okay"; + }; + }; + + vcc_mmc0_reg: fixedregulator@0 { + compatible = "regulator-fixed"; + gpio = <&pioE 2 GPIO_ACTIVE_LOW>; + regulator-name = "mmc0-card-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio>; + + bp3 { + label = "PB_USER"; + gpios = <&pioE 29 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + + d2 { + label = "d2"; + gpios = <&pioE 23 GPIO_ACTIVE_LOW>; /* PE23, conflicts with A23, CTS2 */ + linux,default-trigger = "heartbeat"; + }; + + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda4.dtsi b/arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda4.dtsi new file mode 100644 index 00000000000000..598618e9708257 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda4.dtsi @@ -0,0 +1,146 @@ +/* + * Device Tree Include file for PDA4 display module on SAMA5D4 Xplained board + * + * Copyright (C) 2014 Atmel, + * 2014 Josh Wu + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/ { + ahb { + apb { + i2c0: i2c@f8014000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <10 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4a { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4a>; + interrupt-parent = <&pioE>; + interrupts = <9 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; + }; + + hlcdc: hlcdc@f0000000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb777>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + + pinctrl@fc06a000 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "innolux,at043tn24", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda7.dtsi b/arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda7.dtsi new file mode 100644 index 00000000000000..d64752f5d0c9ac --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d4_xplained_dm_pda7.dtsi @@ -0,0 +1,146 @@ +/* + * Device Tree Include file for PDA7 display module on SAMA5D4 Xplained board + * + * Copyright (C) 2015 Atmel, + * 2015 Josh Wu + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/ { + ahb { + apb { + i2c0: i2c@f8014000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <10 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4c { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4c>; + interrupt-parent = <&pioE>; + interrupts = <9 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; + }; + + hlcdc: hlcdc@f0000000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + + pinctrl@fc06a000 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; + }; + + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "shelly,sca07010-bfn-lnn", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained_hdmi.dts b/arch/arm/boot/dts/at91-sama5d4_xplained_hdmi.dts new file mode 100644 index 00000000000000..fffc12662d5718 --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d4_xplained_hdmi.dts @@ -0,0 +1,320 @@ +/* + * Device Tree file for the SAMA5D4 Xplained board with HDMI + * + * Copyright (C) 2014 Atmel, + * 2014 Josh Wu + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; +#include "sama5d4.dtsi" + +/ { + model = "Atmel SAMA5D4 Xplained Sil9022"; + compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5"; + + chosen { + bootargs = "ignore_loglevel earlyprintk"; + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x20000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + hlcdc: hlcdc@f0000000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb777>; + + port@0 { + hlcdc_hdmi_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&hdmi_input>; + }; + }; + }; + }; + + spi0: spi@f8010000 { + cs-gpios = <&pioC 3 0>, <0>, <0>, <0>; + status = "okay"; + m25p80@0 { + compatible = "atmel,at25df321a"; + spi-max-frequency = <50000000>; + reg = <0>; + }; + }; + + i2c0: i2c@f8014000 { + status = "okay"; + + sil9022: hdmi-encoder@39 { + compatible = "sil,sil9022"; + reg = <0x39>; + reset-gpios = <&pioB 15 GPIO_ACTIVE_LOW>; + interrupts-extended = <&pioA 25 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sil9022_irq>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_hdmi_output>; + }; + }; + }; + + }; + + macb0: ethernet@f8020000 { + phy-mode = "rmii"; + status = "okay"; + + phy0: ethernet-phy@1 { + interrupt-parent = <&pioE>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + reg = <1>; + }; + }; + + mmc1: mmc@fc000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + vmmc-supply = <&vcc_mmc1_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 3 0>; + }; + }; + + usart3: serial@fc00c000 { + status = "okay"; + }; + + usart4: serial@fc010000 { + status = "okay"; + }; + + spi1: spi@fc018000 { + cs-gpios = <&pioB 21 0>; + status = "okay"; + }; + + adc0: adc@fc034000 { + pinctrl-names = "default"; + pinctrl-0 = < + /* external trigger conflicts with USBA_VBUS */ + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + >; + atmel,adc-vref = <3300>; + status = "okay"; + }; + + watchdog@fc068640 { + status = "okay"; + }; + + pinctrl@fc06a000 { + board { + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; + }; + pinctrl_key_gpio: key_gpio_0 { + atmel,pins = + ; + }; + pinctrl_sil9022_irq: sil9022_irq-0 { + atmel,pins = + ; + }; + }; + }; + }; + + vdec0: vdec@00300000 { + status = "okay"; + }; + + usb0: gadget@00400000 { + atmel,vbus-gpio = <&pioE 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00500000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 11 GPIO_ACTIVE_HIGH + &pioE 14 GPIO_ACTIVE_HIGH + >; + status = "okay"; + }; + + usb2: ehci@00600000 { + status = "okay"; + }; + + nand0: nand@80000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + atmel,has-pmecc; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio>; + + pb_user1 { + label = "pb_user1"; + gpios = <&pioE 8 GPIO_ACTIVE_HIGH>; + linux,code = <0x100>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + status = "okay"; + + d8 { + label = "d8"; + gpios = <&pioD 30 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + d10 { + label = "d10"; + gpios = <&pioE 15 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + vcc_3v3_reg: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "VCC 3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vcc_mmc1_reg: fixedregulator@1 { + compatible = "regulator-fixed"; + gpio = <&pioE 4 GPIO_ACTIVE_LOW>; + regulator-name = "VDD MCI1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_reg>; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d4_xplained_pda4.dts new file mode 100644 index 00000000000000..d302309687293e --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d4_xplained_pda4.dts @@ -0,0 +1,281 @@ +/* + * Device Tree file for the SAMA5D4 Xplained board with PDA4 screen + * + * Copyright (C) 2014 Atmel, + * 2014 Josh Wu + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; +#include "sama5d4.dtsi" +#include "at91-sama5d4_xplained_dm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D4 Xplained TM43xx"; + compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5"; + + chosen { + bootargs = "ignore_loglevel earlyprintk"; + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x20000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + spi0: spi@f8010000 { + cs-gpios = <&pioC 3 0>, <0>, <0>, <0>; + status = "okay"; + m25p80@0 { + compatible = "atmel,at25df321a"; + spi-max-frequency = <50000000>; + reg = <0>; + }; + }; + + i2c0: i2c@f8014000 { + status = "okay"; + }; + + macb0: ethernet@f8020000 { + phy-mode = "rmii"; + status = "okay"; + + phy0: ethernet-phy@1 { + interrupt-parent = <&pioE>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + reg = <1>; + }; + }; + + mmc1: mmc@fc000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + vmmc-supply = <&vcc_mmc1_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 3 0>; + }; + }; + + usart3: serial@fc00c000 { + status = "okay"; + }; + + usart4: serial@fc010000 { + status = "okay"; + }; + + spi1: spi@fc018000 { + cs-gpios = <&pioB 21 0>; + status = "okay"; + }; + + adc0: adc@fc034000 { + pinctrl-names = "default"; + pinctrl-0 = < + /* external trigger conflicts with USBA_VBUS */ + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + >; + atmel,adc-vref = <3300>; + status = "okay"; + }; + + watchdog@fc068640 { + status = "okay"; + }; + + pinctrl@fc06a000 { + board { + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; + }; + pinctrl_key_gpio: key_gpio_0 { + atmel,pins = + ; + }; + }; + }; + }; + + vdec0: vdec@00300000 { + status = "okay"; + }; + + usb0: gadget@00400000 { + atmel,vbus-gpio = <&pioE 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00500000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 11 GPIO_ACTIVE_HIGH + &pioE 14 GPIO_ACTIVE_HIGH + >; + status = "okay"; + }; + + usb2: ehci@00600000 { + status = "okay"; + }; + + nand0: nand@80000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + atmel,has-pmecc; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio>; + + pb_user1 { + label = "pb_user1"; + gpios = <&pioE 8 GPIO_ACTIVE_HIGH>; + linux,code = <0x100>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + status = "okay"; + + d8 { + label = "d8"; + gpios = <&pioD 30 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + d10 { + label = "d10"; + gpios = <&pioE 15 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + vcc_3v3_reg: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "VCC 3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vcc_mmc1_reg: fixedregulator@1 { + compatible = "regulator-fixed"; + gpio = <&pioE 4 GPIO_ACTIVE_LOW>; + regulator-name = "VDD MCI1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_reg>; + }; +}; diff --git a/arch/arm/boot/dts/at91-sama5d4_xplained_pda7.dts b/arch/arm/boot/dts/at91-sama5d4_xplained_pda7.dts new file mode 100644 index 00000000000000..ab896f79a21c5e --- /dev/null +++ b/arch/arm/boot/dts/at91-sama5d4_xplained_pda7.dts @@ -0,0 +1,281 @@ +/* + * Device Tree file for the SAMA5D4 Xplained board with PDA7 screen + * + * Copyright (C) 2015 Atmel, + * 2015 Josh Wu + * + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This file 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. + * + * Or, alternatively, + * + * b) Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +/dts-v1/; +#include "sama5d4.dtsi" +#include "at91-sama5d4_xplained_dm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D4 Xplained TM70xx"; + compatible = "atmel,sama5d4-xplained", "atmel,sama5d4", "atmel,sama5"; + + chosen { + bootargs = "ignore_loglevel earlyprintk"; + stdout-path = "serial0:115200n8"; + }; + + memory { + reg = <0x20000000 0x20000000>; + }; + + clocks { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + main_clock: clock@0 { + compatible = "atmel,osc", "fixed-clock"; + clock-frequency = <12000000>; + }; + + slow_xtal { + clock-frequency = <32768>; + }; + + main_xtal { + clock-frequency = <12000000>; + }; + }; + + ahb { + apb { + spi0: spi@f8010000 { + cs-gpios = <&pioC 3 0>, <0>, <0>, <0>; + status = "okay"; + m25p80@0 { + compatible = "atmel,at25df321a"; + spi-max-frequency = <50000000>; + reg = <0>; + }; + }; + + i2c0: i2c@f8014000 { + status = "okay"; + }; + + macb0: ethernet@f8020000 { + phy-mode = "rmii"; + status = "okay"; + + phy0: ethernet-phy@1 { + interrupt-parent = <&pioE>; + interrupts = <1 IRQ_TYPE_EDGE_FALLING>; + reg = <1>; + }; + }; + + mmc1: mmc@fc000000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mmc1_clk_cmd_dat0 &pinctrl_mmc1_dat1_3 &pinctrl_mmc1_cd>; + vmmc-supply = <&vcc_mmc1_reg>; + vqmmc-supply = <&vcc_3v3_reg>; + status = "okay"; + slot@0 { + reg = <0>; + bus-width = <4>; + cd-gpios = <&pioE 3 0>; + }; + }; + + usart3: serial@fc00c000 { + status = "okay"; + }; + + usart4: serial@fc010000 { + status = "okay"; + }; + + spi1: spi@fc018000 { + cs-gpios = <&pioB 21 0>; + status = "okay"; + }; + + adc0: adc@fc034000 { + pinctrl-names = "default"; + pinctrl-0 = < + /* external trigger conflicts with USBA_VBUS */ + &pinctrl_adc0_ad0 + &pinctrl_adc0_ad1 + &pinctrl_adc0_ad2 + &pinctrl_adc0_ad3 + &pinctrl_adc0_ad4 + >; + atmel,adc-vref = <3300>; + status = "okay"; + }; + + watchdog@fc068640 { + status = "okay"; + }; + + pinctrl@fc06a000 { + board { + pinctrl_mmc1_cd: mmc1_cd { + atmel,pins = + ; + }; + pinctrl_usba_vbus: usba_vbus { + atmel,pins = + ; + }; + pinctrl_key_gpio: key_gpio_0 { + atmel,pins = + ; + }; + }; + }; + }; + + vdec0: vdec@00300000 { + status = "okay"; + }; + + usb0: gadget@00400000 { + atmel,vbus-gpio = <&pioE 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; + status = "okay"; + }; + + usb1: ohci@00500000 { + num-ports = <3>; + atmel,vbus-gpio = <0 + &pioE 11 GPIO_ACTIVE_HIGH + &pioE 14 GPIO_ACTIVE_HIGH + >; + status = "okay"; + }; + + usb2: ehci@00600000 { + status = "okay"; + }; + + nand0: nand@80000000 { + nand-bus-width = <8>; + nand-ecc-mode = "hw"; + nand-on-flash-bbt; + atmel,has-pmecc; + status = "okay"; + + at91bootstrap@0 { + label = "at91bootstrap"; + reg = <0x0 0x40000>; + }; + + bootloader@40000 { + label = "bootloader"; + reg = <0x40000 0x80000>; + }; + + bootloaderenv@c0000 { + label = "bootloader env"; + reg = <0xc0000 0xc0000>; + }; + + dtb@180000 { + label = "device tree"; + reg = <0x180000 0x80000>; + }; + + kernel@200000 { + label = "kernel"; + reg = <0x200000 0x600000>; + }; + + rootfs@800000 { + label = "rootfs"; + reg = <0x800000 0x0f800000>; + }; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio>; + + pb_user1 { + label = "pb_user1"; + gpios = <&pioE 8 GPIO_ACTIVE_HIGH>; + linux,code = <0x100>; + gpio-key,wakeup; + }; + }; + + leds { + compatible = "gpio-leds"; + status = "okay"; + + d8 { + label = "d8"; + gpios = <&pioD 30 GPIO_ACTIVE_HIGH>; + default-state = "on"; + }; + + d10 { + label = "d10"; + gpios = <&pioE 15 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; + + vcc_3v3_reg: fixedregulator@0 { + compatible = "regulator-fixed"; + regulator-name = "VCC 3V3"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + regulator-boot-on; + regulator-always-on; + }; + + vcc_mmc1_reg: fixedregulator@1 { + compatible = "regulator-fixed"; + gpio = <&pioE 4 GPIO_ACTIVE_LOW>; + regulator-name = "VDD MCI1"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + vin-supply = <&vcc_3v3_reg>; + }; +}; From 271c30f44439cbf80e338e6eeba9d7905c118ccb Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Fri, 18 Sep 2015 18:58:21 +0200 Subject: [PATCH 260/381] pwm: atmel-hlcdc: Fix module autoload for OF platform driver This platform driver has a OF device ID table but the OF module alias information is not created so module autoloading won't work. This patch adds the missing MODULE_DEVICE_TABLE() for OF to export that information so modules have the correct aliases built-in and autoloading works correctly. A longer explanation by Javier Canillas can be found here: https://lkml.org/lkml/2015/7/30/519 Signed-off-by: Luis de Bethencourt Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-hlcdc.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index 5df1db40fc075a..be7bb05325b897 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -236,6 +236,7 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, atmel_hlcdc_dt_ids); static int atmel_hlcdc_pwm_probe(struct platform_device *pdev) { From 6f2ef54825cec05a13c29574604e7c003f335c3f Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 9 Sep 2015 15:32:30 +0200 Subject: [PATCH 261/381] pwm: atmel-hlcdc: add sama5d2 SoC support. Add sama5d2 hlcdc backlight PWM support. This chip doesn't have to deal with an errata, so it's a simple addition of the mfd compatible string. Signed-off-by: Nicolas Ferre Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-hlcdc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index be7bb05325b897..f994c7eaf41c6c 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -226,6 +226,9 @@ static const struct of_device_id atmel_hlcdc_dt_ids[] = { .compatible = "atmel,at91sam9x5-hlcdc", .data = &atmel_hlcdc_pwm_at91sam9x5_errata, }, + { + .compatible = "atmel,sama5d2-hlcdc", + }, { .compatible = "atmel,sama5d3-hlcdc", .data = &atmel_hlcdc_pwm_sama5d3_errata, From eac9351af6dfd005ea868b722c3934d0412323a0 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 19 Jun 2015 15:51:09 +0200 Subject: [PATCH 262/381] ARM: at91/dt: sama5d2: add LCD controller Add LCD controller node that binds to the DRM driver. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 5efb877c63961b..446ecbd97795a6 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -289,6 +289,32 @@ #size-cells = <1>; ranges; + hlcdc: hlcdc@f0000000 { + compatible = "atmel,sama5d4-hlcdc"; + reg = <0xf0000000 0x2000>; + interrupts = <45 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; + clock-names = "periph_clk","sys_clk", "slow_clk"; + status = "disabled"; + + hlcdc-display-controller { + compatible = "atmel,hlcdc-display-controller"; + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + reg = <0>; + }; + }; + + hlcdc_pwm: hlcdc-pwm { + compatible = "atmel,hlcdc-pwm"; + #pwm-cells = <3>; + }; + }; + ramc0: ramc@f000c000 { compatible = "atmel,sama5d3-ddramc"; reg = <0xf000c000 0x200>; From 5da8937b6926f5914b8997ac359dbf5745eb12f2 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 19 Jun 2015 16:45:45 +0200 Subject: [PATCH 263/381] ARM: at91/dt: move to new LCD compatibility string Move to another compatibility string as the sama5d2 is the first SoC to not have an errata on the LCD PWM controller. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/sama5d2.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 446ecbd97795a6..3389d55a3f3c85 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -290,7 +290,7 @@ ranges; hlcdc: hlcdc@f0000000 { - compatible = "atmel,sama5d4-hlcdc"; + compatible = "atmel,sama5d2-hlcdc"; reg = <0xf0000000 0x2000>; interrupts = <45 IRQ_TYPE_LEVEL_HIGH 0>; clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>; From f3607862a3fe769a32dceb0d62a5fb8860f140a5 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 18 Aug 2015 10:17:45 +0200 Subject: [PATCH 264/381] ARM: at91: use chipid device for soc detection So far, the CIDR and EXID registers were in the DBGU interface. This device has disappeared with the SAMA5D2 family. These registers are exposed through a new device called chipid. Signed-off-by: Ludovic Desroches --- .../devicetree/bindings/arm/atmel-at91.txt | 4 + arch/arm/mach-at91/soc.c | 80 +++++++++++++++---- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/Documentation/devicetree/bindings/arm/atmel-at91.txt b/Documentation/devicetree/bindings/arm/atmel-at91.txt index 929a7d477bd27d..9e1c4638d17feb 100644 --- a/Documentation/devicetree/bindings/arm/atmel-at91.txt +++ b/Documentation/devicetree/bindings/arm/atmel-at91.txt @@ -41,6 +41,10 @@ compatible: must be one of: - "atmel,sama5d43" - "atmel,sama5d44" +Chipid required properties: +- compatible: Should be "atmel,sama5d2-chipid" +- reg : Should contain registers location and length + PIT Timer required properties: - compatible: Should be "atmel,at91sam9260-pit" - reg: Should contain registers location and length diff --git a/arch/arm/mach-at91/soc.c b/arch/arm/mach-at91/soc.c index 54343ffa3e5335..a1f4c12e04c827 100644 --- a/arch/arm/mach-at91/soc.c +++ b/arch/arm/mach-at91/soc.c @@ -22,28 +22,25 @@ #include "soc.h" #define AT91_DBGU_CIDR 0x40 -#define AT91_DBGU_CIDR_VERSION(x) ((x) & 0x1f) -#define AT91_DBGU_CIDR_EXT BIT(31) -#define AT91_DBGU_CIDR_MATCH_MASK 0x7fffffe0 #define AT91_DBGU_EXID 0x44 +#define AT91_CHIPID_CIDR 0x00 +#define AT91_CHIPID_EXID 0x04 +#define AT91_CIDR_VERSION(x) ((x) & 0x1f) +#define AT91_CIDR_EXT BIT(31) +#define AT91_CIDR_MATCH_MASK 0x7fffffe0 -struct soc_device * __init at91_soc_init(const struct at91_soc *socs) +int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid) { - struct soc_device_attribute *soc_dev_attr; - const struct at91_soc *soc; - struct soc_device *soc_dev; struct device_node *np; void __iomem *regs; - u32 cidr, exid; np = of_find_compatible_node(NULL, NULL, "atmel,at91rm9200-dbgu"); if (!np) np = of_find_compatible_node(NULL, NULL, "atmel,at91sam9260-dbgu"); - if (!np) { pr_warn("Could not find DBGU node"); - return NULL; + return -ENODEV; } regs = of_iomap(np, 0); @@ -51,19 +48,68 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) if (!regs) { pr_warn("Could not map DBGU iomem range"); - return NULL; + return -ENXIO; } - cidr = readl(regs + AT91_DBGU_CIDR); - exid = readl(regs + AT91_DBGU_EXID); + *cidr = readl(regs + AT91_DBGU_CIDR); + *exid = readl(regs + AT91_DBGU_EXID); iounmap(regs); + return 0; +} + +int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) +{ + struct device_node *np; + void __iomem *regs; + + np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); + if (!np) { + pr_warn("Could not find Chip ID node"); + return -ENODEV; + } + + regs = of_iomap(np, 0); + of_node_put(np); + + if (!regs) { + pr_warn("Could not map DBGU iomem range"); + return -ENXIO; + } + + *cidr = readl(regs + AT91_CHIPID_CIDR); + *exid = readl(regs + AT91_CHIPID_EXID); + + iounmap(regs); + + return 0; +} + +struct soc_device * __init at91_soc_init(const struct at91_soc *socs) +{ + struct soc_device_attribute *soc_dev_attr; + const struct at91_soc *soc; + struct soc_device *soc_dev; + u32 cidr, exid; + int ret; + + /* + * With SAMA5D2 and later SoCs, CIDR and EXID registers are no more + * in the dbgu device but in the chipid device whose purpose is only + * to expose these two registers. + */ + ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid); + if (ret) + ret = at91_get_cidr_exid_from_chipid(&cidr, &exid); + if (ret) + return NULL; + for (soc = socs; soc->name; soc++) { - if (soc->cidr_match != (cidr & AT91_DBGU_CIDR_MATCH_MASK)) + if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) continue; - if (!(cidr & AT91_DBGU_CIDR_EXT) || soc->exid_match == exid) + if (!(cidr & AT91_CIDR_EXT) || soc->exid_match == exid) break; } @@ -79,7 +125,7 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) soc_dev_attr->family = soc->family; soc_dev_attr->soc_id = soc->name; soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%X", - AT91_DBGU_CIDR_VERSION(cidr)); + AT91_CIDR_VERSION(cidr)); soc_dev = soc_device_register(soc_dev_attr); if (IS_ERR(soc_dev)) { kfree(soc_dev_attr->revision); @@ -91,7 +137,7 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) if (soc->family) pr_info("Detected SoC family: %s\n", soc->family); pr_info("Detected SoC: %s, revision %X\n", soc->name, - AT91_DBGU_CIDR_VERSION(cidr)); + AT91_CIDR_VERSION(cidr)); return soc_dev; } From cc40e7a2b565e20cd04f13fad4c5459f2d0bcb91 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 18 Aug 2015 16:46:00 +0200 Subject: [PATCH 265/381] ARM: at91/soc: reference the whole sama5d2 family Add EXID of all SoCs of the SAMA5D2 family. Signed-off-by: Ludovic Desroches --- arch/arm/mach-at91/sama5.c | 20 +++++++++++++++++++- arch/arm/mach-at91/soc.h | 12 +++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/arch/arm/mach-at91/sama5.c b/arch/arm/mach-at91/sama5.c index 90c3c3051ae752..3caaf74c8cb5ae 100644 --- a/arch/arm/mach-at91/sama5.c +++ b/arch/arm/mach-at91/sama5.c @@ -18,8 +18,26 @@ #include "soc.h" static const struct at91_soc sama5_socs[] = { - AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27_EXID_MATCH, + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D21CU_EXID_MATCH, + "sama5d21", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D22CU_EXID_MATCH, + "sama5d22", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D23CU_EXID_MATCH, + "sama5d23", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CX_EXID_MATCH, + "sama5d24", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D24CU_EXID_MATCH, + "sama5d24", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D26CU_EXID_MATCH, + "sama5d26", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CU_EXID_MATCH, "sama5d27", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D27CN_EXID_MATCH, + "sama5d27", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CU_EXID_MATCH, + "sama5d28", "sama5d2"), + AT91_SOC(SAMA5D2_CIDR_MATCH, SAMA5D28CN_EXID_MATCH, + "sama5d28", "sama5d2"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D31_EXID_MATCH, "sama5d31", "sama5d3"), AT91_SOC(SAMA5D3_CIDR_MATCH, SAMA5D33_EXID_MATCH, diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h index 8ede0ef86172a6..228efded5085da 100644 --- a/arch/arm/mach-at91/soc.h +++ b/arch/arm/mach-at91/soc.h @@ -63,7 +63,17 @@ at91_soc_init(const struct at91_soc *socs); #define AT91SAM9XE512_CIDR_MATCH 0x329aa3a0 #define SAMA5D2_CIDR_MATCH 0x0a5c08c0 -#define SAMA5D27_EXID_MATCH 0x00000021 +#define SAMA5D21CU_EXID_MATCH 0x0000005a +#define SAMA5D22CU_EXID_MATCH 0x00000059 +#define SAMA5D22CN_EXID_MATCH 0x00000069 +#define SAMA5D23CU_EXID_MATCH 0x00000058 +#define SAMA5D24CX_EXID_MATCH 0x00000004 +#define SAMA5D24CU_EXID_MATCH 0x00000014 +#define SAMA5D26CU_EXID_MATCH 0x00000012 +#define SAMA5D27CU_EXID_MATCH 0x00000011 +#define SAMA5D27CN_EXID_MATCH 0x00000021 +#define SAMA5D28CU_EXID_MATCH 0x00000010 +#define SAMA5D28CN_EXID_MATCH 0x00000020 #define SAMA5D3_CIDR_MATCH 0x0a5c07c0 #define SAMA5D31_EXID_MATCH 0x00444300 From 8991b28da324ffe492e01a536c181d22087af578 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 18 Aug 2015 14:55:13 +0200 Subject: [PATCH 266/381] ARM: at91/dt: sama5d2: add chipid node Add node for chipid device in order to have access to the CIDR and EXID values. Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/sama5d2.dtsi | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 3389d55a3f3c85..da288578f819bf 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1195,6 +1195,11 @@ clock-names = "pclk", "gclk", "aclk"; status = "disabled"; }; + + chipid@fc069000 { + compatible = "atmel,sama5d2-chipid"; + reg = <0xfc069000 0x8>; + }; }; }; }; From f2c5d9d31d66127924b8f219f871c39a17956b3e Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 2 Nov 2015 17:59:49 +0100 Subject: [PATCH 267/381] ARM: at91: chipid: print warning only if needed Remove the warning inserted in the boot log by the DBGU code. As we rely on chipid with sama5d2, this DBGU portion will always print an unnecessary message. Signed-off-by: Nicolas Ferre --- arch/arm/mach-at91/soc.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-at91/soc.c b/arch/arm/mach-at91/soc.c index a1f4c12e04c827..034d563dadad1e 100644 --- a/arch/arm/mach-at91/soc.c +++ b/arch/arm/mach-at91/soc.c @@ -38,10 +38,8 @@ int __init at91_get_cidr_exid_from_dbgu(u32 *cidr, u32 *exid) if (!np) np = of_find_compatible_node(NULL, NULL, "atmel,at91sam9260-dbgu"); - if (!np) { - pr_warn("Could not find DBGU node"); + if (!np) return -ENODEV; - } regs = of_iomap(np, 0); of_node_put(np); @@ -65,10 +63,8 @@ int __init at91_get_cidr_exid_from_chipid(u32 *cidr, u32 *exid) void __iomem *regs; np = of_find_compatible_node(NULL, NULL, "atmel,sama5d2-chipid"); - if (!np) { - pr_warn("Could not find Chip ID node"); + if (!np) return -ENODEV; - } regs = of_iomap(np, 0); of_node_put(np); @@ -102,8 +98,11 @@ struct soc_device * __init at91_soc_init(const struct at91_soc *socs) ret = at91_get_cidr_exid_from_dbgu(&cidr, &exid); if (ret) ret = at91_get_cidr_exid_from_chipid(&cidr, &exid); - if (ret) + if (ret) { + if (ret == -ENODEV) + pr_warn("Could not find identification node"); return NULL; + } for (soc = socs; soc->name; soc++) { if (soc->cidr_match != (cidr & AT91_CIDR_MATCH_MASK)) From fabb6d33450351fe478717021b5f64fb9ea31c50 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 21 Sep 2015 15:10:41 +0800 Subject: [PATCH 268/381] media: atmel-isi: correct yuv swap according to different sensor outputs we need to configure the YCC_SWAP bits in ISI_CFG2 according to current sensor output and Atmel ISI output format. Current there are two cases Atmel ISI supported: 1. Atmel ISI outputs YUYV format. This case we need to setup YCC_SWAP according to sensor output format. 2. Atmel ISI output a pass-through formats, which means no swap. Just setup YCC_SWAP as default with no swap. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 45e304a3dd85b5..ce87a160397b11 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -103,13 +103,37 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg) return readl(isi->regs + reg); } +static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, + const struct soc_camera_format_xlate *xlate) +{ + if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUYV) { + /* all convert to YUYV */ + switch (xlate->code) { + case MEDIA_BUS_FMT_VYUY8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_3; + case MEDIA_BUS_FMT_UYVY8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_2; + case MEDIA_BUS_FMT_YVYU8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_1; + } + } + + /* + * By default, no swap for the codec path of Atmel ISI. So codec + * output is same as sensor's output. + * For instance, if sensor's output is YUYV, then codec outputs YUYV. + * And if sensor's output is UYVY, then codec outputs UYVY. + */ + return ISI_CFG2_YCC_SWAP_DEFAULT; +} + static void configure_geometry(struct atmel_isi *isi, u32 width, - u32 height, u32 code) + u32 height, const struct soc_camera_format_xlate *xlate) { u32 cfg2; /* According to sensor's output format to set cfg2 */ - switch (code) { + switch (xlate->code) { default: /* Grey */ case MEDIA_BUS_FMT_Y8_1X8: @@ -117,16 +141,11 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, break; /* YUV */ case MEDIA_BUS_FMT_VYUY8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_MODE_3 | ISI_CFG2_COL_SPACE_YCbCr; - break; case MEDIA_BUS_FMT_UYVY8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_MODE_2 | ISI_CFG2_COL_SPACE_YCbCr; - break; case MEDIA_BUS_FMT_YVYU8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_MODE_1 | ISI_CFG2_COL_SPACE_YCbCr; - break; case MEDIA_BUS_FMT_YUYV8_2X8: - cfg2 = ISI_CFG2_YCC_SWAP_DEFAULT | ISI_CFG2_COL_SPACE_YCbCr; + cfg2 = ISI_CFG2_COL_SPACE_YCbCr | + setup_cfg2_yuv_swap(isi, xlate); break; /* RGB, TODO */ } @@ -407,7 +426,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) isi_writel(isi, ISI_INTDIS, (u32)~0UL); configure_geometry(isi, icd->user_width, icd->user_height, - icd->current_fmt->code); + icd->current_fmt); spin_lock_irq(&isi->lock); /* Clear any pending interrupt */ From 93970828b2c8c22dc9e59b8c13ab3d29b2a78c67 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 6 Dec 2013 17:46:27 +0800 Subject: [PATCH 269/381] media: atmel-isi: prepare for the support of preview path Atmel ISI support a preview path which can output RGB data. So this patch introduces a bool variable to choose which path is enabled currently. And also we need setup corresponding path registers. By default the preview path is disabled. We only use Codec path. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 72 +++++++++++++------ 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index ce87a160397b11..24501a4fcd6d4b 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -79,6 +79,7 @@ struct atmel_isi { dma_addr_t fb_descriptors_phys; struct list_head dma_desc_head; struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; + bool enable_preview_path; struct completion complete; /* ISI peripherial clock */ @@ -195,11 +196,19 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) /* start next dma frame. */ isi->active = list_entry(isi->video_buffer_list.next, struct frame_buffer, list); - isi_writel(isi, ISI_DMA_C_DSCR, - (u32)isi->active->p_dma_desc->fbd_phys); - isi_writel(isi, ISI_DMA_C_CTRL, - ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); - isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + if (!isi->enable_preview_path) { + isi_writel(isi, ISI_DMA_C_DSCR, + (u32)isi->active->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + } else { + isi_writel(isi, ISI_DMA_P_DSCR, + (u32)isi->active->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_P_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); + } } return IRQ_HANDLED; } @@ -226,7 +235,8 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id) isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS); ret = IRQ_HANDLED; } else { - if (likely(pending & ISI_SR_CXFR_DONE)) + if (likely(pending & ISI_SR_CXFR_DONE) || + likely(pending & ISI_SR_PXFR_DONE)) ret = atmel_isi_handle_streaming(isi); } @@ -368,21 +378,35 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); /* Check if already in a frame */ - if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { - dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n"); - return; - } + if (!isi->enable_preview_path) { + if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { + dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n"); + return; + } - isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys); - isi_writel(isi, ISI_DMA_C_CTRL, ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); - isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + isi_writel(isi, ISI_DMA_C_DSCR, + (u32)buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_C_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); + } else { + isi_writel(isi, ISI_DMA_P_DSCR, + (u32)buffer->p_dma_desc->fbd_phys); + isi_writel(isi, ISI_DMA_P_CTRL, + ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); + isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); + } cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; /* Enable linked list */ cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR; - /* Enable codec path and ISI */ - ctrl = ISI_CTRL_CDC | ISI_CTRL_EN; + /* Enable ISI */ + ctrl = ISI_CTRL_EN; + + if (!isi->enable_preview_path) + ctrl |= ISI_CTRL_CDC; + isi_writel(isi, ISI_CTRL, ctrl); isi_writel(isi, ISI_CFG1, cfg1); } @@ -458,15 +482,17 @@ static void stop_streaming(struct vb2_queue *vq) } spin_unlock_irq(&isi->lock); - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; - /* Wait until the end of the current frame. */ - while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && - time_before(jiffies, timeout)) - msleep(1); + if (!isi->enable_preview_path) { + timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + /* Wait until the end of the current frame. */ + while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && + time_before(jiffies, timeout)) + msleep(1); - if (time_after(jiffies, timeout)) - dev_err(icd->parent, - "Timeout waiting for finishing codec request\n"); + if (time_after(jiffies, timeout)) + dev_err(icd->parent, + "Timeout waiting for finishing codec request\n"); + } /* Disable interrupts */ isi_writel(isi, ISI_INTDIS, From df8f9f79afe975ceddbfb80aaf3c41c93170c904 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 24 Jun 2015 17:20:13 +0800 Subject: [PATCH 270/381] media: atmel-isi: add code to setup correct resolution for preview path Not like codec path, preview path can do downsampling, so we should setup a extra preview width, height for it. This patch add preview resolution setup without down sampling. So currently preview path will output same size as sensor output size. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 12 +++++++++++- drivers/media/platform/soc_camera/atmel-isi.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 24501a4fcd6d4b..ae8206827c774c 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -131,7 +131,7 @@ static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, static void configure_geometry(struct atmel_isi *isi, u32 width, u32 height, const struct soc_camera_format_xlate *xlate) { - u32 cfg2; + u32 cfg2, psize; /* According to sensor's output format to set cfg2 */ switch (xlate->code) { @@ -159,6 +159,16 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET) & ISI_CFG2_IM_VSIZE_MASK; isi_writel(isi, ISI_CFG2, cfg2); + + /* No down sampling, preview size equal to sensor output size */ + psize = ((width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) & + ISI_PSIZE_PREV_HSIZE_MASK; + psize |= ((height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) & + ISI_PSIZE_PREV_VSIZE_MASK; + isi_writel(isi, ISI_PSIZE, psize); + isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING); + + return; } static bool is_supported(struct soc_camera_device *icd, diff --git a/drivers/media/platform/soc_camera/atmel-isi.h b/drivers/media/platform/soc_camera/atmel-isi.h index 5acc771d2edcd6..0acb32a2b65ce3 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.h +++ b/drivers/media/platform/soc_camera/atmel-isi.h @@ -79,6 +79,16 @@ #define ISI_CFG2_IM_VSIZE_MASK (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET) #define ISI_CFG2_IM_HSIZE_MASK (0x7FF << ISI_CFG2_IM_HSIZE_OFFSET) +/* Bitfields in PSIZE */ +#define ISI_PSIZE_PREV_VSIZE_OFFSET 0 +#define ISI_PSIZE_PREV_HSIZE_OFFSET 16 +#define ISI_PSIZE_PREV_VSIZE_MASK (0x3FF << ISI_PSIZE_PREV_VSIZE_OFFSET) +#define ISI_PSIZE_PREV_HSIZE_MASK (0x3FF << ISI_PSIZE_PREV_HSIZE_OFFSET) + +/* Bitfields in PDECF */ +#define ISI_PDECF_DEC_FACTOR_MASK (0xFF << 0) +#define ISI_PDECF_NO_SAMPLING (16) + /* Bitfields in CTRL */ /* Also using in SR(ISI_V2) */ #define ISI_CTRL_EN (1 << 0) From 1ab2fcd336a1e4c916d7da400672a535fafeea7b Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 24 Jun 2015 17:57:48 +0800 Subject: [PATCH 271/381] media: atmel-isi: setup YCC_SWAP correctly when using preview path The preview path only can convert UYVY format to RGB data. To make preview path work correctly, we need to set up YCC_SWAP according to sensor output and convert them to UYVY. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index ae8206827c774c..826d04e9abab65 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -117,6 +117,20 @@ static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, case MEDIA_BUS_FMT_YVYU8_2X8: return ISI_CFG2_YCC_SWAP_MODE_1; } + } else if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) { + /* + * Preview path is enabled, it will convert UYVY to RGB format. + * But if sensor output format is not UYVY, we need to set + * YCC_SWAP_MODE to convert it as UYVY. + */ + switch (xlate->code) { + case MEDIA_BUS_FMT_VYUY8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_1; + case MEDIA_BUS_FMT_YUYV8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_2; + case MEDIA_BUS_FMT_YVYU8_2X8: + return ISI_CFG2_YCC_SWAP_MODE_3; + } } /* From d9d1c4c9acad999645727228f0802262171b6639 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 17 Jun 2015 18:10:01 +0800 Subject: [PATCH 272/381] media: atmel-isi: support RGB565 output when sensor output YUV formats This patch enable Atmel ISI preview path to convert the YUV to RGB format. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 826d04e9abab65..8abeeebf422c84 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -146,6 +146,10 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, u32 height, const struct soc_camera_format_xlate *xlate) { u32 cfg2, psize; + u32 fourcc = xlate->host_fmt->fourcc; + + isi->enable_preview_path = (fourcc == V4L2_PIX_FMT_RGB565 || + fourcc == V4L2_PIX_FMT_RGB32); /* According to sensor's output format to set cfg2 */ switch (xlate->code) { @@ -195,8 +199,9 @@ static bool is_supported(struct soc_camera_device *icd, case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: + /* RGB */ + case V4L2_PIX_FMT_RGB565: return true; - /* RGB, TODO */ default: return false; } @@ -682,6 +687,14 @@ static const struct soc_mbus_pixelfmt isi_camera_formats[] = { .order = SOC_MBUS_ORDER_LE, .layout = SOC_MBUS_LAYOUT_PACKED, }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .name = "RGB565", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + .layout = SOC_MBUS_LAYOUT_PACKED, + }, }; /* This will be corrected as we get more formats */ @@ -738,7 +751,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - int formats = 0, ret; + int formats = 0, ret, i, n; /* sensor format */ struct v4l2_subdev_mbus_code_enum code = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, @@ -772,11 +785,11 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: - formats++; - if (xlate) { - xlate->host_fmt = &isi_camera_formats[0]; + n = ARRAY_SIZE(isi_camera_formats); + formats += n; + for (i = 0; xlate && i < n; i++, xlate++) { + xlate->host_fmt = &isi_camera_formats[i]; xlate->code = code.code; - xlate++; dev_dbg(icd->parent, "Providing format %s using code %d\n", isi_camera_formats[0].name, code.code); } From 50b531090e81b6a37d44bb059668fa47f0b315c4 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 7 Sep 2015 09:30:05 +0800 Subject: [PATCH 273/381] media: atmel-isi: use try_or_set_fmt() for both set_fmt() and try_fmt() Since atmel-isi has similar set_fmt() and try_fmt() functions. So this patch will add a new function which can be called by set_fmt() and try_fmt(). That can increase the reusability. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 105 +++++++----------- 1 file changed, 41 insertions(+), 64 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 8abeeebf422c84..21a76ee1237de4 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -567,16 +567,16 @@ static int isi_camera_init_videobuf(struct vb2_queue *q, return vb2_queue_init(q); } -static int isi_camera_set_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) +static int try_or_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f, + struct v4l2_subdev_format *format) { - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct v4l2_mbus_framefmt *mf = &format.format; + const struct soc_camera_format_xlate *xlate; + struct v4l2_subdev_pad_config pad_cfg; + + struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct v4l2_mbus_framefmt *mf = &format->format; int ret; /* check with atmel-isi support format, if not support use YUYV */ @@ -590,8 +590,11 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, return -EINVAL; } - dev_dbg(icd->parent, "Plan to set format %dx%d\n", - pix->width, pix->height); + /* limit to Atmel ISI hardware capabilities */ + if (pix->height > MAX_SUPPORT_HEIGHT) + pix->height = MAX_SUPPORT_HEIGHT; + if (pix->width > MAX_SUPPORT_WIDTH) + pix->width = MAX_SUPPORT_WIDTH; mf->width = pix->width; mf->height = pix->height; @@ -599,7 +602,11 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, mf->colorspace = pix->colorspace; mf->code = xlate->code; - ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format); + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, format); + else + ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, format); + if (ret < 0) return ret; @@ -610,64 +617,14 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, pix->height = mf->height; pix->field = mf->field; pix->colorspace = mf->colorspace; - icd->current_fmt = xlate; - - dev_dbg(icd->parent, "Finally set format %dx%d\n", - pix->width, pix->height); - - return ret; -} - -static int isi_camera_try_fmt(struct soc_camera_device *icd, - struct v4l2_format *f) -{ - struct v4l2_subdev *sd = soc_camera_to_subdev(icd); - const struct soc_camera_format_xlate *xlate; - struct v4l2_pix_format *pix = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - struct v4l2_mbus_framefmt *mf = &format.format; - u32 pixfmt = pix->pixelformat; - int ret; - - /* check with atmel-isi support format, if not support use YUYV */ - if (!is_supported(icd, pix->pixelformat)) - pix->pixelformat = V4L2_PIX_FMT_YUYV; - - xlate = soc_camera_xlate_by_fourcc(icd, pixfmt); - if (pixfmt && !xlate) { - dev_warn(icd->parent, "Format %x not found\n", pixfmt); - return -EINVAL; - } - /* limit to Atmel ISI hardware capabilities */ - if (pix->height > MAX_SUPPORT_HEIGHT) - pix->height = MAX_SUPPORT_HEIGHT; - if (pix->width > MAX_SUPPORT_WIDTH) - pix->width = MAX_SUPPORT_WIDTH; - - /* limit to sensor capabilities */ - mf->width = pix->width; - mf->height = pix->height; - mf->field = pix->field; - mf->colorspace = pix->colorspace; - mf->code = xlate->code; - - ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format); - if (ret < 0) - return ret; - - pix->width = mf->width; - pix->height = mf->height; - pix->colorspace = mf->colorspace; + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + icd->current_fmt = xlate; switch (mf->field) { case V4L2_FIELD_ANY: - pix->field = V4L2_FIELD_NONE; - break; case V4L2_FIELD_NONE: + pix->field = V4L2_FIELD_NONE; break; default: dev_err(icd->parent, "Field type %d unsupported.\n", @@ -678,6 +635,26 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, return ret; } +static int isi_camera_set_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + return try_or_set_fmt(icd, f, &format); +} + +static int isi_camera_try_fmt(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + + return try_or_set_fmt(icd, f, &format); +} + static const struct soc_mbus_pixelfmt isi_camera_formats[] = { { .fourcc = V4L2_PIX_FMT_YUYV, From 3e005f878a2bb5280a07245555e7ba38dd24ad99 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Fri, 10 Jun 2011 17:21:28 +0200 Subject: [PATCH 274/381] media/video: atmel-isi: add dumb set_parm() Add dumb set_parm() & get_parm() function to struct soc_camera_host_ops. Needed for ffmpeg to be able to capture frames from ISI driver. Signed-off-by: Nicolas Ferre Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 21a76ee1237de4..2ede19ad910bf2 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -915,6 +915,11 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) return 0; } +static int isi_camera_set_parm(struct soc_camera_device *icd, struct v4l2_streamparm *parm) +{ + return 0; +} + static struct soc_camera_host_ops isi_soc_camera_host_ops = { .owner = THIS_MODULE, .add = isi_camera_add_device, @@ -926,6 +931,8 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { .poll = isi_camera_poll, .querycap = isi_camera_querycap, .set_bus_param = isi_camera_set_bus_param, + .set_parm = isi_camera_set_parm, + .get_parm = isi_camera_set_parm, }; /* -----------------------------------------------------------------------*/ From ec06eba8b172edf6c8b36df1716e9e13a66708be Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 25 Sep 2015 15:50:35 +0800 Subject: [PATCH 275/381] media: atmel-isi: add isi_hw_initialize() function to handle hw setup Move the hardware operation to one isi_hw_initialize(). Then we will set up hardware in start_streaming(). Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 2ede19ad910bf2..ba0401c82ebb89 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -88,6 +88,7 @@ struct atmel_isi { struct isi_platform_data pdata; u16 width_flags; /* max 12 bits */ + u32 bus_param; struct list_head video_buffer_list; struct frame_buffer *active; @@ -459,6 +460,30 @@ static void buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&isi->lock, flags); } +static void isi_hw_initialize(struct atmel_isi *isi) +{ + u32 common_flags = isi->bus_param; + u32 cfg1 = 0; + + /* set bus param for ISI */ + if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; + if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; + if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; + + if (isi->pdata.has_emb_sync) + cfg1 |= ISI_CFG1_EMB_SYNC; + if (isi->pdata.full_mode) + cfg1 |= ISI_CFG1_FULL_MODE; + + cfg1 |= ISI_CFG1_THMASK_BEATS_16; + + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); + isi_writel(isi, ISI_CFG1, cfg1); +} + static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); @@ -478,6 +503,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) /* Disable all interrupts */ isi_writel(isi, ISI_INTDIS, (u32)~0UL); + isi_hw_initialize(isi); + configure_geometry(isi, icd->user_width, icd->user_height, icd->current_fmt); @@ -831,7 +858,6 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,}; unsigned long common_flags; int ret; - u32 cfg1 = 0; ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg); if (!ret) { @@ -884,33 +910,12 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) return ret; } - /* set bus param for ISI */ - if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; - if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW; - if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING; - dev_dbg(icd->parent, "vsync active %s, hsync active %s, sampling on pix clock %s edge\n", common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? "low" : "high", common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? "low" : "high", common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING ? "falling" : "rising"); - if (isi->pdata.has_emb_sync) - cfg1 |= ISI_CFG1_EMB_SYNC; - if (isi->pdata.full_mode) - cfg1 |= ISI_CFG1_FULL_MODE; - - cfg1 |= ISI_CFG1_THMASK_BEATS_16; - - /* Enable PM and peripheral clock before operate isi registers */ - pm_runtime_get_sync(ici->v4l2_dev.dev); - - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - isi_writel(isi, ISI_CFG1, cfg1); - - pm_runtime_put(ici->v4l2_dev.dev); + isi->bus_param = common_flags; return 0; } From b813f76d419992cc6cce176924ac3ff518138d1d Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 30 Sep 2015 11:05:18 +0800 Subject: [PATCH 276/381] media: atmel-isi: add interrupt initialization on isi_hw_initialize() Add interrupt initialization in isi_hw_initialize() function. This isi_hw_initialize() function will only called on start_streaming(). Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index ba0401c82ebb89..d438ce7a5c9d60 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -465,6 +465,12 @@ static void isi_hw_initialize(struct atmel_isi *isi) u32 common_flags = isi->bus_param; u32 cfg1 = 0; + /* Disable all interrupts */ + isi_writel(isi, ISI_INTDIS, (u32)~0UL); + + /* Clear any pending interrupt */ + isi_readl(isi, ISI_STATUS); + /* set bus param for ISI */ if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW; @@ -500,8 +506,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) pm_runtime_put(ici->v4l2_dev.dev); return ret; } - /* Disable all interrupts */ - isi_writel(isi, ISI_INTDIS, (u32)~0UL); isi_hw_initialize(isi); @@ -509,8 +513,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) icd->current_fmt); spin_lock_irq(&isi->lock); - /* Clear any pending interrupt */ - isi_readl(isi, ISI_STATUS); if (count) start_dma(isi, isi->active); From c4bde32549d097a54446a4523cad0d3a72b33597 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 15:22:36 +0800 Subject: [PATCH 277/381] media: atmel-isi: move the cfg1 initialize to isi_hw_initialize() Since cfg1 initialization just about the frame rate, and it hardware related, just move it to isi_hw_initialize(). Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index d438ce7a5c9d60..4e0cf8e90d377e 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -400,9 +400,8 @@ static void buffer_cleanup(struct vb2_buffer *vb) static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) { - u32 ctrl, cfg1; + u32 ctrl; - cfg1 = isi_readl(isi, ISI_CFG1); /* Enable irq: cxfr for the codec path, pxfr for the preview path */ isi_writel(isi, ISI_INTEN, ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); @@ -427,10 +426,6 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); } - cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK; - /* Enable linked list */ - cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR; - /* Enable ISI */ ctrl = ISI_CTRL_EN; @@ -438,7 +433,6 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) ctrl |= ISI_CTRL_CDC; isi_writel(isi, ISI_CTRL, ctrl); - isi_writel(isi, ISI_CFG1, cfg1); } static void buffer_queue(struct vb2_buffer *vb) @@ -486,6 +480,10 @@ static void isi_hw_initialize(struct atmel_isi *isi) cfg1 |= ISI_CFG1_THMASK_BEATS_16; + cfg1 |= isi->pdata.frate & ISI_CFG1_FRATE_DIV_MASK; + + cfg1 |= ISI_CFG1_DISCR; + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); isi_writel(isi, ISI_CFG1, cfg1); } From 73f4d07820825c38c93211a78e83cce15916b5b4 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 29 Sep 2015 11:35:43 +0800 Subject: [PATCH 278/381] media: atmel-isi: add isi_hw_enable_interrupt() function Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 4e0cf8e90d377e..b8256fd82d3e82 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -274,8 +274,19 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id) return ret; } -#define WAIT_ISI_RESET 1 -#define WAIT_ISI_DISABLE 0 +#define WAIT_HW_RESET 1 +#define WAIT_HW_DISABLE 0 +static void isi_hw_enable_interrupt(struct atmel_isi *isi, int type) +{ + if (type == WAIT_HW_RESET) { + isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); + isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); + } else { + isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); + } +} + static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) { unsigned long timeout; @@ -285,13 +296,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) */ init_completion(&isi->complete); - if (wait_reset) { - isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST); - isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST); - } else { - isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS); - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - } + isi_hw_enable_interrupt(isi, wait_reset); timeout = wait_for_completion_timeout(&isi->complete, msecs_to_jiffies(500)); @@ -498,7 +503,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) pm_runtime_get_sync(ici->v4l2_dev.dev); /* Reset ISI */ - ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); + ret = atmel_isi_wait_status(isi, WAIT_HW_RESET); if (ret < 0) { dev_err(icd->parent, "Reset ISI timed out\n"); pm_runtime_put(ici->v4l2_dev.dev); @@ -555,7 +560,7 @@ static void stop_streaming(struct vb2_queue *vq) ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); /* Disable ISI and wait for it is done */ - ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); + ret = atmel_isi_wait_status(isi, WAIT_HW_DISABLE); if (ret < 0) dev_err(icd->parent, "Disable ISI timed out\n"); From 064ae80ee0ec1cacf260440ebd32de9fa1f93b79 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 29 Sep 2015 14:37:15 +0800 Subject: [PATCH 279/381] media: atmel-isi: remove the function set_dma_ctrl() as it just use once Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index b8256fd82d3e82..3a6fcedfc76ae8 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -47,11 +47,6 @@ struct fbd { u32 next_fbd_address; }; -static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl) -{ - fb_desc->dma_ctrl = ctrl; -} - struct isi_dma_desc { struct list_head list; struct fbd *p_fbd; @@ -383,7 +378,7 @@ static int buffer_prepare(struct vb2_buffer *vb) desc->p_fbd->fb_address = vb2_dma_contig_plane_dma_addr(vb, 0); desc->p_fbd->next_fbd_address = 0; - set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB); + desc->p_fbd->dma_ctrl = ISI_DMA_CTRL_WB; buf->p_dma_desc = desc; } From 165eaa99f60103034c401fd7601766cf2a832383 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 23 Jun 2015 17:51:45 +0200 Subject: [PATCH 280/381] ARM: at91/dt: sama5d2 Xplained: set pin muxing for usb gadget and usb host For USB gadget on port A (device mode): - pin PA31 is configured as an input GPIO which triggers an interrupt when vbus is detected on USB port A. - pin PB9 is configured as an output GPIO and set to low level so the board doesn't supply vbus to USB port A. For USB host: - pin PB10 is configured as an output GPIO and is active at high level. The ohci driver will activate this pin so the board supplies vbus to USB port B. - pin PB9 should be configured as an output GPIO and active at high level to use to USB port A in host mode (conflicts with USB gadget). Signed-off-by: Cyrille Pitchen --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index fd996dc8345e97..62a3430105d915 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -46,6 +46,7 @@ #include "sama5d2.dtsi" #include "sama5d2-pinfunc.h" #include +#include / { model = "Atmel SAMA5D2 Xplained"; @@ -80,11 +81,20 @@ ahb { usb0: gadget@00300000 { + atmel,vbus-gpio = <&pioA 31 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usba_vbus>; status = "okay"; }; usb1: ohci@00400000 { num-ports = <3>; + atmel,vbus-gpio = <0 /* &pioA 41 GPIO_ACTIVE_HIGH */ + &pioA 42 GPIO_ACTIVE_HIGH + 0 + >; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usb_default>; status = "okay"; }; @@ -398,6 +408,17 @@ ; bias-disable; }; + + pinctrl_usb_default: usb_default { + pinmux = ; + bias-disable; + }; + + pinctrl_usba_vbus: usba_vbus { + pinmux = ; + bias-disable; + }; + }; }; }; From d447428f408455060381faa7e322ee5d8ccc6dee Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 22 Jun 2015 10:01:20 +0200 Subject: [PATCH 281/381] ARM: at91/dt: sama5d2 Xplained: add user push button Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 62a3430105d915..fcd1b46a277211 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -325,6 +325,11 @@ bias-disable; }; + pinctrl_key_gpio_default: key_gpio_default { + pinmux = ; + bias-pull-up; + }; + pinctrl_macb0_rmii: macb0_rmii { pinmux = , , @@ -422,4 +427,17 @@ }; }; }; + + gpio_keys { + compatible = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_key_gpio_default>; + + bp1 { + label = "PB_USER"; + gpios = <&pioA 41 GPIO_ACTIVE_LOW>; + linux,code = <0x104>; + }; + }; }; From 5442e1f8e72c5f95cc0a2f401dfb1f8d335d88f4 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 25 Jun 2015 14:05:26 +0800 Subject: [PATCH 282/381] ARM: at91/dt: sama5d2: add watchdog node Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 4 ++++ arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts | 8 ++++---- arch/arm/boot/dts/sama5d2.dtsi | 7 +++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index fcd1b46a277211..3c3a0494fc3903 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -247,6 +247,10 @@ }; }; + watchdog@f8048040 { + status = "okay"; + }; + i2s0: i2s@f8050000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2s0_default>; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index 195b0563b99e7e..87c236f4f29517 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -249,15 +249,15 @@ }; }; + watchdog@f8048040 { + status = "okay"; + }; + i2s0: i2s@f8050000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_i2s0_default>; }; - watchdog@f8048040 { - status = "okay"; - }; - uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index da288578f819bf..c34cb25c65f938 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1009,6 +1009,13 @@ clocks = <&h32ck>; }; + watchdog@f8048040 { + compatible = "atmel,at91sam9260-wdt"; + reg = <0xf8048040 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>; + status = "disabled"; + }; + sckc@f8048050 { compatible = "atmel,at91sam9x5-sckc"; reg = <0xf8048050 0x4>; From 632d3f3ae1d2a9226820f76e3083e84e7f4388c6 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 25 Jun 2015 18:13:49 +0800 Subject: [PATCH 283/381] ARM: at91/dt: sama5d2 Xplained: add leds node Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 3c3a0494fc3903..8a2a01387da1cc 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -334,6 +334,13 @@ bias-pull-up; }; + pinctrl_led_gpio_default: led_gpio_default { + pinmux = , + , + ; + bias-pull-up; + }; + pinctrl_macb0_rmii: macb0_rmii { pinmux = , , @@ -444,4 +451,27 @@ linux,code = <0x104>; }; }; + + leds { + compatible = "gpio-leds"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_led_gpio_default>; + status = "okay"; + + red { + label = "red"; + gpios = <&pioA 38 GPIO_ACTIVE_LOW>; + }; + + green { + label = "green"; + gpios = <&pioA 37 GPIO_ACTIVE_LOW>; + }; + + blue { + label = "blue"; + gpios = <&pioA 32 GPIO_ACTIVE_LOW>; + linux,default-trigger = "heartbeat"; + }; + }; }; From 5211a2307fe910a6796819cedd25bc43c3ce7c1d Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 15:05:00 +0100 Subject: [PATCH 284/381] ARM: at91: sama5d2_defconfig: enable CONFIG_KUSER_HELPERS option CONFIG_KUSER_HELPERS is useful for user programs. If the option is disabled, some user programs will not work properly, for example: a buildroot rootfs (busybox) application that was built for ARM9 cannot run. Signed-off-by: Josh Wu --- arch/arm/configs/sama5d2_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index 9962aa142a3d5c..17e692b888de77 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -18,7 +18,6 @@ CONFIG_ARCH_AT91=y CONFIG_SOC_SAMA5D2=y CONFIG_SOC_SAMA5D3=y CONFIG_SOC_SAMA5D4=y -# CONFIG_KUSER_HELPERS is not set CONFIG_AEABI=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y From a2a7759306abc1fd45af199ba042bc8d766721ac Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 3 Nov 2015 15:26:15 +0100 Subject: [PATCH 285/381] ARM: at91/sama5d2_defconfig: remove FB console & logo Not needed so remove them. Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5d2_defconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index 17e692b888de77..3abf20e2eecff6 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -159,9 +159,6 @@ CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_BACKLIGHT_PWM=y -CONFIG_FRAMEBUFFER_CONSOLE=y -CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y -CONFIG_LOGO=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y From a89edaf6e59fabeb498775777b1dfc674d197b4a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 3 Nov 2015 15:26:57 +0100 Subject: [PATCH 286/381] ARM: at91/sama5d2_defconfig: add Atmel SoC I2S driver Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5d2_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index 3abf20e2eecff6..8584fa40e398e1 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -165,6 +165,7 @@ CONFIG_SND_SOC=y CONFIG_SND_ATMEL_SOC=y CONFIG_SND_ATMEL_SOC_WM8904=y CONFIG_SND_ATMEL_SOC_CLASSD=y +CONFIG_SND_ATMEL_SOC_I2S=y # CONFIG_HID_GENERIC is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y From db62577128e45a8f934c104c018cafacb6dc0e44 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 3 Nov 2015 15:29:49 +0100 Subject: [PATCH 287/381] ARM: at91/sama5_defconfig: update to include sama5d2 needs DRM/KMS, CMA, SRAM, and the sama5d2 plus the needed drivers like flexcom, sdhci, classD, i2S... Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5_defconfig | 52 +++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 31eb951880aee1..8f80502b1078c9 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -1,8 +1,7 @@ -# CONFIG_LOCALVERSION_AUTO is not set # CONFIG_SWAP is not set CONFIG_SYSVIPC=y CONFIG_IRQ_DOMAIN_DEBUG=y -CONFIG_LOG_BUF_SHIFT=14 +CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y CONFIG_SLAB=y @@ -15,10 +14,12 @@ CONFIG_LBDAF=y # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set CONFIG_ARCH_AT91=y -CONFIG_SOC_SAM_V7=y +CONFIG_SOC_SAMA5D2=y CONFIG_SOC_SAMA5D3=y CONFIG_SOC_SAMA5D4=y CONFIG_AEABI=y +CONFIG_CMA=y +CONFIG_CMA_DEBUGFS=y CONFIG_UACCESS_WITH_MEMCPY=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 @@ -62,6 +63,7 @@ CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y # CONFIG_STANDALONE is not set # CONFIG_PREVENT_FIRMWARE_BUILD is not set +CONFIG_DMA_CMA=y CONFIG_MTD=y CONFIG_MTD_CMDLINE_PARTS=y CONFIG_MTD_BLOCK=y @@ -78,7 +80,9 @@ CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=y +CONFIG_SRAM=y CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_93CX6=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set @@ -130,31 +134,51 @@ CONFIG_I2C_GPIO=y CONFIG_SPI=y CONFIG_SPI_ATMEL=y CONFIG_SPI_GPIO=y +CONFIG_SPI_SPIDEV=m +CONFIG_PINCTRL_AT91PIO4=y CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_SYSCON=y CONFIG_POWER_SUPPLY=y CONFIG_POWER_RESET=y # CONFIG_HWMON is not set +CONFIG_WATCHDOG=y +CONFIG_AT91SAM9X_WATCHDOG=y CONFIG_SSB=m +CONFIG_MFD_ATMEL_FLEXCOM=y +CONFIG_MFD_ATMEL_HLCDC=y +CONFIG_MFD_SYSCON=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_VIRTUAL_CONSUMER=y CONFIG_REGULATOR_ACT8865=y CONFIG_MEDIA_SUPPORT=y CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y CONFIG_V4L_PLATFORM_DRIVERS=y CONFIG_SOC_CAMERA=y -CONFIG_SOC_CAMERA_OV2640=y CONFIG_VIDEO_ATMEL_ISI=y -CONFIG_FB=y +CONFIG_SOC_CAMERA_OV2640=m +CONFIG_SOC_CAMERA_OV5642=m +CONFIG_SOC_CAMERA_OV6650=m +CONFIG_SOC_CAMERA_OV772X=m +CONFIG_SOC_CAMERA_OV9640=m +CONFIG_SOC_CAMERA_OV9740=m +CONFIG_DRM=y +CONFIG_DRM_ATMEL_HLCDC=y +CONFIG_DRM_PANEL_SIMPLE=y CONFIG_BACKLIGHT_LCD_SUPPORT=y -# CONFIG_LCD_CLASS_DEVICE is not set +CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set +CONFIG_BACKLIGHT_PWM=y CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_ATMEL_SOC=y CONFIG_SND_ATMEL_SOC_WM8904=y +CONFIG_SND_ATMEL_SOC_I2S=y # CONFIG_HID_GENERIC is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y @@ -167,10 +191,17 @@ CONFIG_USB_SERIAL_GENERIC=y CONFIG_USB_SERIAL_FTDI_SIO=y CONFIG_USB_SERIAL_PL2303=y CONFIG_USB_GADGET=y -CONFIG_USB_ATMEL_USBA=y -CONFIG_USB_G_SERIAL=y +CONFIG_USB_ATMEL_USBA=m +CONFIG_USB_CONFIGFS=m +CONFIG_USB_CONFIGFS_ACM=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_MASS_STORAGE=m +CONFIG_USB_G_SERIAL=m CONFIG_MMC=y # CONFIG_MMC_BLOCK_BOUNCE is not set +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_AT91=y CONFIG_MMC_ATMELMCI=y CONFIG_NEW_LEDS=y CONFIG_LEDS_CLASS=y @@ -178,21 +209,26 @@ CONFIG_LEDS_GPIO=y CONFIG_LEDS_PWM=y CONFIG_LEDS_TRIGGER_TIMER=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_CPU=y CONFIG_LEDS_TRIGGER_GPIO=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_AT91RM9200=y CONFIG_DMADEVICES=y CONFIG_AT_XDMAC=y +CONFIG_DMATEST=m # CONFIG_IOMMU_SUPPORT is not set CONFIG_IIO=y CONFIG_AT91_ADC=y CONFIG_PWM=y CONFIG_PWM_ATMEL=y +CONFIG_PWM_ATMEL_HLCDC_PWM=y CONFIG_PWM_ATMEL_TCB=y +CONFIG_RESET_CONTROLLER=y CONFIG_EXT4_FS=y CONFIG_FANOTIFY=y CONFIG_VFAT_FS=y CONFIG_TMPFS=y +CONFIG_CONFIGFS_FS=y CONFIG_UBIFS_FS=y CONFIG_UBIFS_FS_ADVANCED_COMPR=y CONFIG_NFS_FS=y From 86c7d0f171b452589480bbd011faf738c03aa776 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 3 Nov 2015 16:53:54 +0100 Subject: [PATCH 288/381] ARM: at91/defconfig: remove CONFIG_SSB from Atmel defconfigs This "Sonics Silicon Backplane" support is not needed on Atmel SoCs: remove it. Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91_dt_defconfig | 1 - arch/arm/configs/sama5_defconfig | 1 - arch/arm/configs/sama5d2_defconfig | 1 - 3 files changed, 3 deletions(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index 090c5b25dbed59..c4cf47f7a7776a 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -129,7 +129,6 @@ CONFIG_POWER_RESET=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y -CONFIG_SSB=m CONFIG_MFD_ATMEL_HLCDC=y CONFIG_REGULATOR=y CONFIG_REGULATOR_FIXED_VOLTAGE=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 8f80502b1078c9..7bb7bfa0b0c1df 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -143,7 +143,6 @@ CONFIG_POWER_RESET=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y -CONFIG_SSB=m CONFIG_MFD_ATMEL_FLEXCOM=y CONFIG_MFD_ATMEL_HLCDC=y CONFIG_MFD_SYSCON=y diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index 8584fa40e398e1..f06f3b55b70737 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -129,7 +129,6 @@ CONFIG_POWER_RESET=y CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y CONFIG_SAMA5D4_WATCHDOG=y -CONFIG_SSB=m CONFIG_MFD_ATMEL_FLEXCOM=y CONFIG_MFD_ATMEL_HLCDC=y CONFIG_MFD_SYSCON=y From 734fccebf5c65f740f0d3bc309053c538a3b2431 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 3 Nov 2015 18:15:21 +0800 Subject: [PATCH 289/381] ARM: at91/dt: sama5d2: add classD node Add classD node to dts Signed-off-by: Songjun Wu --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 16 ++++++++++++++++ .../boot/dts/at91-sama5d2_xplained_pda4.dts | 16 ++++++++++++++++ arch/arm/boot/dts/sama5d2.dtsi | 19 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 8a2a01387da1cc..5f94a2df7c778f 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -296,6 +296,14 @@ }; pinctrl@fc038000 { + pinctrl_classd_default: classd_default { + pinmux = , + , + , + ; + bias-pull-up; + }; + pinctrl_flx0_default: flx0_default { pinmux = , ; @@ -436,6 +444,14 @@ }; }; + + classd@fc048000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_classd_default>; + atmel,pwm-type = "diff"; + atmel,non-overlap-time = <10>; + status = "okay"; + }; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index 87c236f4f29517..fb22ca674585ee 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -298,6 +298,14 @@ }; pinctrl@fc038000 { + pinctrl_classd_default: classd_default { + pinmux = , + , + , + ; + bias-pull-up; + }; + pinctrl_flx0_default: flx0_default { pinmux = , ; @@ -452,6 +460,14 @@ bias-disable; }; }; + + classd@fc048000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_classd_default>; + atmel,pwm-type = "diff"; + atmel,non-overlap-time = <10>; + status = "okay"; + }; }; }; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index c34cb25c65f938..fe6a78d6510902 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -818,6 +818,12 @@ #clock-cells = <0>; reg = <55>; }; + + classd_gclk: classd_gclk { + #clock-cells = <0>; + reg = <59>; + atmel,clk-output-range = <0 100000000>; + }; }; }; @@ -1187,6 +1193,19 @@ status = "okay"; }; + classd: classd@fc048000 { + compatible = "atmel,sama5d2-classd"; + reg = <0xfc048000 0x100>; + interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(47))>; + dma-names = "tx"; + clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>; + clock-names = "pclk", "gclk", "aclk"; + status = "disabled"; + }; + i2s1: i2s@fc04c000 { compatible = "atmel,sama5d2-i2s"; reg = <0xfc04c000 0x300>; From 9c0c5833c1f09e0c0700c04372bb8ff4ba4dd086 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 3 Nov 2015 11:31:04 +0800 Subject: [PATCH 290/381] ASoC: atmel-classd: add the Audio Class D Amplifier code Add driver for the digital imput to PWM output stereo class D amplifier. It comes with filter, digitally controlled gain, an equalizer and a dmphase filter Signed-off-by: Songjun Wu --- sound/soc/atmel/atmel-classd.c | 679 +++++++++++++++++++++++++++++++++ sound/soc/atmel/atmel-classd.h | 120 ++++++ 2 files changed, 799 insertions(+) create mode 100644 sound/soc/atmel/atmel-classd.c create mode 100644 sound/soc/atmel/atmel-classd.h diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c new file mode 100644 index 00000000000000..8276675730ef12 --- /dev/null +++ b/sound/soc/atmel/atmel-classd.c @@ -0,0 +1,679 @@ +/* Atmel ALSA SoC Audio Class D Amplifier (CLASSD) driver + * + * Copyright (C) 2015 Atmel + * + * Author: Songjun Wu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 or later + * as published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "atmel-classd.h" + +struct atmel_classd_pdata { + bool non_overlap_enable; + int non_overlap_time; + int pwm_type; + const char *card_name; +}; + +struct atmel_classd { + dma_addr_t phy_base; + struct regmap *regmap; + struct clk *pclk; + struct clk *gclk; + struct clk *aclk; + int irq; + const struct atmel_classd_pdata *pdata; +}; + +#ifdef CONFIG_OF +static const struct of_device_id atmel_classd_of_match[] = { + { + .compatible = "atmel,sama5d2-classd", + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, atmel_classd_of_match); + +static struct atmel_classd_pdata *atmel_classd_dt_init(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct atmel_classd_pdata *pdata; + const char *pwm_type; + int ret; + + if (!np) { + dev_err(dev, "device node not found\n"); + return ERR_PTR(-EINVAL); + } + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + ret = of_property_read_string(np, "atmel,pwm-type", &pwm_type); + if ((ret == 0) && (strcmp(pwm_type, "diff") == 0)) + pdata->pwm_type = CLASSD_MR_PWMTYP_DIFF; + else + pdata->pwm_type = CLASSD_MR_PWMTYP_SINGLE; + + ret = of_property_read_u32(np, + "atmel,non-overlap-time", &pdata->non_overlap_time); + if (ret) + pdata->non_overlap_enable = false; + else + pdata->non_overlap_enable = true; + + ret = of_property_read_string(np, "atmel,model", &pdata->card_name); + if (ret) + pdata->card_name = "CLASSD"; + + return pdata; +} +#else +static inline struct atmel_classd_pdata * +atmel_classd_dt_init(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} +#endif + +#define ATMEL_CLASSD_RATES (SNDRV_PCM_RATE_8000 \ + | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 \ + | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 \ + | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 \ + | SNDRV_PCM_RATE_96000) + +static const struct snd_pcm_hardware atmel_classd_hw = { + .info = SNDRV_PCM_INFO_MMAP + | SNDRV_PCM_INFO_MMAP_VALID + | SNDRV_PCM_INFO_INTERLEAVED + | SNDRV_PCM_INFO_RESUME + | SNDRV_PCM_INFO_PAUSE, + .formats = (SNDRV_PCM_FMTBIT_S16_LE), + .rates = ATMEL_CLASSD_RATES, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = 64 * 1024, + .period_bytes_min = 256, + .period_bytes_max = 32 * 1024, + .periods_min = 2, + .periods_max = 256, +}; + +#define ATMEL_CLASSD_PREALLOC_BUF_SIZE (64 * 1024) + +/* cpu dai component */ +static int atmel_classd_cpu_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); + + regmap_write(dd->regmap, CLASSD_THR, 0x0); + + return clk_prepare_enable(dd->pclk); +} + +static void atmel_classd_cpu_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); + + clk_disable_unprepare(dd->pclk); +} + +static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = { + .startup = atmel_classd_cpu_dai_startup, + .shutdown = atmel_classd_cpu_dai_shutdown, +}; + +static struct snd_soc_dai_driver atmel_classd_cpu_dai = { + .playback = { + .channels_min = 2, + .channels_max = 2, + .rates = ATMEL_CLASSD_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE,}, + .ops = &atmel_classd_cpu_dai_ops, +}; + +static const struct snd_soc_component_driver atmel_classd_cpu_dai_component = { + .name = "atmel-classd", +}; + +/* platform */ +static int +atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct dma_slave_config *slave_config) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); + + if (params_physical_width(params) != 16) { + dev_err(rtd->platform->dev, + "only supports 16-bit audio data\n"); + return -EINVAL; + } + + slave_config->direction = DMA_MEM_TO_DEV; + slave_config->dst_addr = dd->phy_base + CLASSD_THR; + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config->dst_maxburst = 1; + slave_config->src_maxburst = 1; + slave_config->device_fc = false; + + return 0; +} + +static const struct snd_dmaengine_pcm_config +atmel_classd_dmaengine_pcm_config = { + .prepare_slave_config = atmel_classd_platform_configure_dma, + .pcm_hardware = &atmel_classd_hw, + .prealloc_buffer_size = ATMEL_CLASSD_PREALLOC_BUF_SIZE, +}; + +/* codec */ +static const char * const mono_mode_text[] = { + "mix", "sat", "left", "right" +}; + +static SOC_ENUM_SINGLE_DECL(classd_mono_mode_enum, + CLASSD_INTPMR, CLASSD_INTPMR_MONO_MODE_SHIFT, + mono_mode_text); + +static const char * const eqcfg_text[] = { + "Treble-12dB", "Treble-6dB", + "Medium-8dB", "Medium-3dB", + "Bass-12dB", "Bass-6dB", + "0 dB", + "Bass+6dB", "Bass+12dB", + "Medium+3dB", "Medium+8dB", + "Treble+6dB", "Treble+12dB", +}; + +static const unsigned int eqcfg_value[] = { + CLASSD_INTPMR_EQCFG_T_CUT_12, CLASSD_INTPMR_EQCFG_T_CUT_6, + CLASSD_INTPMR_EQCFG_M_CUT_8, CLASSD_INTPMR_EQCFG_M_CUT_3, + CLASSD_INTPMR_EQCFG_B_CUT_12, CLASSD_INTPMR_EQCFG_B_CUT_6, + CLASSD_INTPMR_EQCFG_FLAT, + CLASSD_INTPMR_EQCFG_B_BOOST_6, CLASSD_INTPMR_EQCFG_B_BOOST_12, + CLASSD_INTPMR_EQCFG_M_BOOST_3, CLASSD_INTPMR_EQCFG_M_BOOST_8, + CLASSD_INTPMR_EQCFG_T_BOOST_6, CLASSD_INTPMR_EQCFG_T_BOOST_12, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(classd_eqcfg_enum, + CLASSD_INTPMR, CLASSD_INTPMR_EQCFG_SHIFT, 0xf, + eqcfg_text, eqcfg_value); + +static const DECLARE_TLV_DB_SCALE(classd_digital_tlv, -7800, 100, 1); + +static const struct snd_kcontrol_new atmel_classd_snd_controls[] = { +SOC_DOUBLE_TLV("Playback Volume", CLASSD_INTPMR, + CLASSD_INTPMR_ATTL_SHIFT, CLASSD_INTPMR_ATTR_SHIFT, + 78, 1, classd_digital_tlv), + +SOC_SINGLE("Deemphasis Switch", CLASSD_INTPMR, + CLASSD_INTPMR_DEEMP_SHIFT, 1, 0), + +SOC_SINGLE("Mono Switch", CLASSD_INTPMR, CLASSD_INTPMR_MONO_SHIFT, 1, 0), + +SOC_SINGLE("Swap Switch", CLASSD_INTPMR, CLASSD_INTPMR_SWAP_SHIFT, 1, 0), + +SOC_ENUM("Mono Mode", classd_mono_mode_enum), + +SOC_ENUM("EQ", classd_eqcfg_enum), +}; + +static const char * const pwm_type[] = { + "Single ended", "Differential" +}; + +static int atmel_classd_codec_probe(struct snd_soc_codec *codec) +{ + struct snd_soc_card *card = snd_soc_codec_get_drvdata(codec); + struct atmel_classd *dd = snd_soc_card_get_drvdata(card); + const struct atmel_classd_pdata *pdata = dd->pdata; + u32 mask, val; + + mask = CLASSD_MR_PWMTYP_MASK; + val = pdata->pwm_type << CLASSD_MR_PWMTYP_SHIFT; + + mask |= CLASSD_MR_NON_OVERLAP_MASK; + if (pdata->non_overlap_enable) { + val |= (CLASSD_MR_NON_OVERLAP_EN + << CLASSD_MR_NON_OVERLAP_SHIFT); + + mask |= CLASSD_MR_NOVR_VAL_MASK; + switch (pdata->non_overlap_time) { + case 5: + val |= (CLASSD_MR_NOVR_VAL_5NS + << CLASSD_MR_NOVR_VAL_SHIFT); + break; + case 10: + val |= (CLASSD_MR_NOVR_VAL_10NS + << CLASSD_MR_NOVR_VAL_SHIFT); + break; + case 15: + val |= (CLASSD_MR_NOVR_VAL_15NS + << CLASSD_MR_NOVR_VAL_SHIFT); + break; + case 20: + val |= (CLASSD_MR_NOVR_VAL_20NS + << CLASSD_MR_NOVR_VAL_SHIFT); + break; + default: + val |= (CLASSD_MR_NOVR_VAL_10NS + << CLASSD_MR_NOVR_VAL_SHIFT); + dev_warn(codec->dev, + "non-overlapping value %d is invalid, the default value 10 is specified\n", + pdata->non_overlap_time); + break; + } + } + + snd_soc_update_bits(codec, CLASSD_MR, mask, val); + + dev_info(codec->dev, + "PWM modulation type is %s, non-overlapping is %s\n", + pwm_type[pdata->pwm_type], + pdata->non_overlap_enable?"enabled":"disabled"); + + return 0; +} + +static struct regmap *atmel_classd_codec_get_remap(struct device *dev) +{ + return dev_get_regmap(dev, NULL); +} + +static struct snd_soc_codec_driver soc_codec_dev_classd = { + .probe = atmel_classd_codec_probe, + .controls = atmel_classd_snd_controls, + .num_controls = ARRAY_SIZE(atmel_classd_snd_controls), + .get_regmap = atmel_classd_codec_get_remap, +}; + +/* codec dai component */ +static int atmel_classd_codec_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); + int ret; + + ret = clk_prepare_enable(dd->aclk); + if (ret) + return ret; + + return clk_prepare_enable(dd->gclk); +} + +static int atmel_classd_codec_dai_digital_mute(struct snd_soc_dai *codec_dai, + int mute) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 mask, val; + + mask = CLASSD_MR_LMUTE_MASK | CLASSD_MR_RMUTE_MASK; + + if (mute) + val = mask; + else + val = 0; + + snd_soc_update_bits(codec, CLASSD_MR, mask, val); + + return 0; +} + +#define CLASSD_ACLK_RATE_11M2896_MPY_8 (112896 * 100 * 8) +#define CLASSD_ACLK_RATE_12M288_MPY_8 (12228 * 1000 * 8) + +static struct { + int rate; + int sample_rate; + int dsp_clk; + unsigned long aclk_rate; +} const sample_rates[] = { + { 8000, CLASSD_INTPMR_FRAME_8K, + CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 }, + { 16000, CLASSD_INTPMR_FRAME_16K, + CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 }, + { 32000, CLASSD_INTPMR_FRAME_32K, + CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 }, + { 48000, CLASSD_INTPMR_FRAME_48K, + CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 }, + { 96000, CLASSD_INTPMR_FRAME_96K, + CLASSD_INTPMR_DSP_CLK_FREQ_12M288, CLASSD_ACLK_RATE_12M288_MPY_8 }, + { 22050, CLASSD_INTPMR_FRAME_22K, + CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_ACLK_RATE_11M2896_MPY_8 }, + { 44100, CLASSD_INTPMR_FRAME_44K, + CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_ACLK_RATE_11M2896_MPY_8 }, + { 88200, CLASSD_INTPMR_FRAME_88K, + CLASSD_INTPMR_DSP_CLK_FREQ_11M2896, CLASSD_ACLK_RATE_11M2896_MPY_8 }, +}; + +static int +atmel_classd_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_codec *codec = codec_dai->codec; + int fs; + int i, best, best_val, cur_val, ret; + u32 mask, val; + + fs = params_rate(params); + + best = 0; + best_val = abs(fs - sample_rates[0].rate); + for (i = 1; i < ARRAY_SIZE(sample_rates); i++) { + /* Closest match */ + cur_val = abs(fs - sample_rates[i].rate); + if (cur_val < best_val) { + best = i; + best_val = cur_val; + } + } + + dev_dbg(codec->dev, + "Selected SAMPLE_RATE of %dHz, ACLK_RATE of %ldHz\n", + sample_rates[best].rate, sample_rates[best].aclk_rate); + + clk_disable_unprepare(dd->gclk); + clk_disable_unprepare(dd->aclk); + + ret = clk_set_rate(dd->aclk, sample_rates[best].aclk_rate); + if (ret) + return ret; + + mask = CLASSD_INTPMR_DSP_CLK_FREQ_MASK | CLASSD_INTPMR_FRAME_MASK; + val = (sample_rates[best].dsp_clk << CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT) + | (sample_rates[best].sample_rate << CLASSD_INTPMR_FRAME_SHIFT); + + snd_soc_update_bits(codec, CLASSD_INTPMR, mask, val); + + ret = clk_prepare_enable(dd->aclk); + if (ret) + return ret; + + return clk_prepare_enable(dd->gclk); +} + +static void +atmel_classd_codec_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct atmel_classd *dd = snd_soc_card_get_drvdata(rtd->card); + + clk_disable_unprepare(dd->gclk); + clk_disable_unprepare(dd->aclk); +} + +static int atmel_classd_codec_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + + snd_soc_update_bits(codec, CLASSD_MR, + CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK, + (CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT) + |(CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT)); + + return 0; +} + +static int atmel_classd_codec_dai_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *codec_dai) +{ + struct snd_soc_codec *codec = codec_dai->codec; + u32 mask, val; + + mask = CLASSD_MR_LEN_MASK | CLASSD_MR_REN_MASK; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + val = mask; + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + val = (CLASSD_MR_LEN_DIS << CLASSD_MR_LEN_SHIFT) + | (CLASSD_MR_REN_DIS << CLASSD_MR_REN_SHIFT); + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, CLASSD_MR, mask, val); + + return 0; +} + +static const struct snd_soc_dai_ops atmel_classd_codec_dai_ops = { + .digital_mute = atmel_classd_codec_dai_digital_mute, + .startup = atmel_classd_codec_dai_startup, + .shutdown = atmel_classd_codec_dai_shutdown, + .hw_params = atmel_classd_codec_dai_hw_params, + .prepare = atmel_classd_codec_dai_prepare, + .trigger = atmel_classd_codec_dai_trigger, +}; + +#define ATMEL_CLASSD_CODEC_DAI_NAME "atmel-classd-hifi" + +static struct snd_soc_dai_driver atmel_classd_codec_dai = { + .name = ATMEL_CLASSD_CODEC_DAI_NAME, + .playback = { + .stream_name = "Playback", + .channels_min = 2, + .channels_max = 2, + .rates = ATMEL_CLASSD_RATES, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .ops = &atmel_classd_codec_dai_ops, +}; + +/* ASoC sound card */ +static int atmel_classd_asoc_card_init(struct device *dev, + struct snd_soc_card *card) +{ + struct snd_soc_dai_link *dai_link; + struct atmel_classd *dd = snd_soc_card_get_drvdata(card); + + dai_link = devm_kzalloc(dev, sizeof(*dai_link), GFP_KERNEL); + if (!dai_link) + return -ENOMEM; + + dai_link->name = "CLASSD"; + dai_link->stream_name = "CLASSD PCM"; + dai_link->codec_dai_name = ATMEL_CLASSD_CODEC_DAI_NAME; + dai_link->cpu_dai_name = dev_name(dev); + dai_link->codec_name = dev_name(dev); + dai_link->platform_name = dev_name(dev); + + card->dai_link = dai_link; + card->num_links = 1; + card->name = dd->pdata->card_name; + card->dev = dev; + + return 0; +}; + +/* regmap configuration */ +static const struct reg_default atmel_classd_reg_defaults[] = { + { CLASSD_INTPMR, 0x00301212 }, +}; + +#define ATMEL_CLASSD_REG_MAX 0xE4 +static const struct regmap_config atmel_classd_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ATMEL_CLASSD_REG_MAX, + + .cache_type = REGCACHE_FLAT, + .reg_defaults = atmel_classd_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(atmel_classd_reg_defaults), +}; + +static int atmel_classd_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct atmel_classd *dd; + struct resource *res; + void __iomem *io_base; + const struct atmel_classd_pdata *pdata; + struct snd_soc_card *card; + int ret; + + pdata = dev_get_platdata(dev); + if (!pdata) { + pdata = atmel_classd_dt_init(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); + if (!dd) + return -ENOMEM; + + dd->pdata = pdata; + + dd->irq = platform_get_irq(pdev, 0); + if (dd->irq < 0) { + ret = dd->irq; + dev_err(dev, "failed to could not get irq: %d\n", ret); + return ret; + } + + dd->pclk = devm_clk_get(dev, "pclk"); + if (IS_ERR(dd->pclk)) { + ret = PTR_ERR(dd->pclk); + dev_err(dev, "failed to get peripheral clock: %d\n", ret); + return ret; + } + + dd->gclk = devm_clk_get(dev, "gclk"); + if (IS_ERR(dd->gclk)) { + ret = PTR_ERR(dd->gclk); + dev_err(dev, "failed to get GCK clock: %d\n", ret); + return ret; + } + + dd->aclk = devm_clk_get(dev, "aclk"); + if (IS_ERR(dd->aclk)) { + ret = PTR_ERR(dd->aclk); + dev_err(dev, "failed to get audio clock: %d\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "no memory resource\n"); + return -ENXIO; + } + + io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) { + ret = PTR_ERR(io_base); + dev_err(dev, "failed to remap register memory: %d\n", ret); + return ret; + } + + dd->phy_base = res->start; + + dd->regmap = devm_regmap_init_mmio(dev, io_base, + &atmel_classd_regmap_config); + if (IS_ERR(dd->regmap)) { + ret = PTR_ERR(dd->regmap); + dev_err(dev, "failed to init register map: %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_component(dev, + &atmel_classd_cpu_dai_component, + &atmel_classd_cpu_dai, 1); + if (ret) { + dev_err(dev, "could not register CPU DAI: %d\n", ret); + return ret; + } + + ret = devm_snd_dmaengine_pcm_register(dev, + &atmel_classd_dmaengine_pcm_config, + 0); + if (ret) { + dev_err(dev, "could not register platform: %d\n", ret); + return ret; + } + + ret = snd_soc_register_codec(dev, &soc_codec_dev_classd, + &atmel_classd_codec_dai, 1); + if (ret) { + dev_err(dev, "could not register codec: %d\n", ret); + return ret; + } + + /* register sound card */ + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + snd_soc_card_set_drvdata(card, dd); + platform_set_drvdata(pdev, card); + + ret = atmel_classd_asoc_card_init(dev, card); + if (ret) { + dev_err(dev, "failed to init sound card\n"); + return ret; + } + + ret = devm_snd_soc_register_card(dev, card); + if (ret) { + dev_err(dev, "failed to register sound card: %d\n", ret); + return ret; + } + + return 0; +} + +static int atmel_classd_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver atmel_classd_driver = { + .driver = { + .name = "atmel-classd", + .of_match_table = of_match_ptr(atmel_classd_of_match), + .pm = &snd_soc_pm_ops, + }, + .probe = atmel_classd_probe, + .remove = atmel_classd_remove, +}; +module_platform_driver(atmel_classd_driver); + +MODULE_DESCRIPTION("Atmel ClassD driver under ALSA SoC architecture"); +MODULE_AUTHOR("Songjun Wu "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/atmel/atmel-classd.h b/sound/soc/atmel/atmel-classd.h new file mode 100644 index 00000000000000..73f8fdd1ca830d --- /dev/null +++ b/sound/soc/atmel/atmel-classd.h @@ -0,0 +1,120 @@ +#ifndef __ATMEL_CLASSD_H_ +#define __ATMEL_CLASSD_H_ + +#define CLASSD_CR 0x00000000 +#define CLASSD_CR_RESET 0x1 + +#define CLASSD_MR 0x00000004 + +#define CLASSD_MR_LEN_DIS 0x0 +#define CLASSD_MR_LEN_EN 0x1 +#define CLASSD_MR_LEN_MASK (0x1 << 0) +#define CLASSD_MR_LEN_SHIFT (0) + +#define CLASSD_MR_LMUTE_DIS 0x0 +#define CLASSD_MR_LMUTE_EN 0x1 +#define CLASSD_MR_LMUTE_SHIFT (0x1) +#define CLASSD_MR_LMUTE_MASK (0x1 << 1) + +#define CLASSD_MR_REN_DIS 0x0 +#define CLASSD_MR_REN_EN 0x1 +#define CLASSD_MR_REN_MASK (0x1 << 4) +#define CLASSD_MR_REN_SHIFT (4) + +#define CLASSD_MR_RMUTE_DIS 0x0 +#define CLASSD_MR_RMUTE_EN 0x1 +#define CLASSD_MR_RMUTE_SHIFT (0x5) +#define CLASSD_MR_RMUTE_MASK (0x1 << 5) + +#define CLASSD_MR_PWMTYP_SINGLE 0x0 +#define CLASSD_MR_PWMTYP_DIFF 0x1 +#define CLASSD_MR_PWMTYP_MASK (0x1 << 8) +#define CLASSD_MR_PWMTYP_SHIFT (8) + +#define CLASSD_MR_NON_OVERLAP_DIS 0x0 +#define CLASSD_MR_NON_OVERLAP_EN 0x1 +#define CLASSD_MR_NON_OVERLAP_MASK (0x1 << 16) +#define CLASSD_MR_NON_OVERLAP_SHIFT (16) + +#define CLASSD_MR_NOVR_VAL_5NS 0x0 +#define CLASSD_MR_NOVR_VAL_10NS 0x1 +#define CLASSD_MR_NOVR_VAL_15NS 0x2 +#define CLASSD_MR_NOVR_VAL_20NS 0x3 +#define CLASSD_MR_NOVR_VAL_MASK (0x3 << 20) +#define CLASSD_MR_NOVR_VAL_SHIFT (20) + +#define CLASSD_INTPMR 0x00000008 + +#define CLASSD_INTPMR_ATTL_MASK (0x3f << 0) +#define CLASSD_INTPMR_ATTL_SHIFT (0) +#define CLASSD_INTPMR_ATTR_MASK (0x3f << 8) +#define CLASSD_INTPMR_ATTR_SHIFT (8) + +#define CLASSD_INTPMR_DSP_CLK_FREQ_12M288 0x0 +#define CLASSD_INTPMR_DSP_CLK_FREQ_11M2896 0x1 +#define CLASSD_INTPMR_DSP_CLK_FREQ_MASK (0x1 << 16) +#define CLASSD_INTPMR_DSP_CLK_FREQ_SHIFT (16) + +#define CLASSD_INTPMR_DEEMP_DIS 0x0 +#define CLASSD_INTPMR_DEEMP_EN 0x1 +#define CLASSD_INTPMR_DEEMP_MASK (0x1 << 18) +#define CLASSD_INTPMR_DEEMP_SHIFT (18) + +#define CLASSD_INTPMR_SWAP_LEFT_ON_LSB 0x0 +#define CLASSD_INTPMR_SWAP_RIGHT_ON_LSB 0x1 +#define CLASSD_INTPMR_SWAP_MASK (0x1 << 19) +#define CLASSD_INTPMR_SWAP_SHIFT (19) + +#define CLASSD_INTPMR_FRAME_8K 0x0 +#define CLASSD_INTPMR_FRAME_16K 0x1 +#define CLASSD_INTPMR_FRAME_32K 0x2 +#define CLASSD_INTPMR_FRAME_48K 0x3 +#define CLASSD_INTPMR_FRAME_96K 0x4 +#define CLASSD_INTPMR_FRAME_22K 0x5 +#define CLASSD_INTPMR_FRAME_44K 0x6 +#define CLASSD_INTPMR_FRAME_88K 0x7 +#define CLASSD_INTPMR_FRAME_MASK (0x7 << 20) +#define CLASSD_INTPMR_FRAME_SHIFT (20) + +#define CLASSD_INTPMR_EQCFG_FLAT 0x0 +#define CLASSD_INTPMR_EQCFG_B_BOOST_12 0x1 +#define CLASSD_INTPMR_EQCFG_B_BOOST_6 0x2 +#define CLASSD_INTPMR_EQCFG_B_CUT_12 0x3 +#define CLASSD_INTPMR_EQCFG_B_CUT_6 0x4 +#define CLASSD_INTPMR_EQCFG_M_BOOST_3 0x5 +#define CLASSD_INTPMR_EQCFG_M_BOOST_8 0x6 +#define CLASSD_INTPMR_EQCFG_M_CUT_3 0x7 +#define CLASSD_INTPMR_EQCFG_M_CUT_8 0x8 +#define CLASSD_INTPMR_EQCFG_T_BOOST_12 0x9 +#define CLASSD_INTPMR_EQCFG_T_BOOST_6 0xa +#define CLASSD_INTPMR_EQCFG_T_CUT_12 0xb +#define CLASSD_INTPMR_EQCFG_T_CUT_6 0xc +#define CLASSD_INTPMR_EQCFG_SHIFT (24) + +#define CLASSD_INTPMR_MONO_DIS 0x0 +#define CLASSD_INTPMR_MONO_EN 0x1 +#define CLASSD_INTPMR_MONO_MASK (0x1 << 28) +#define CLASSD_INTPMR_MONO_SHIFT (28) + +#define CLASSD_INTPMR_MONO_MODE_MIX 0x0 +#define CLASSD_INTPMR_MONO_MODE_SAT 0x1 +#define CLASSD_INTPMR_MONO_MODE_LEFT 0x2 +#define CLASSD_INTPMR_MONO_MODE_RIGHT 0x3 +#define CLASSD_INTPMR_MONO_MODE_MASK (0x3 << 29) +#define CLASSD_INTPMR_MONO_MODE_SHIFT (29) + +#define CLASSD_INTSR 0x0000000c + +#define CLASSD_THR 0x00000010 + +#define CLASSD_IER 0x00000014 + +#define CLASSD_IDR 0x00000018 + +#define CLASSD_IMR 0x0000001c + +#define CLASSD_ISR 0x00000020 + +#define CLASSD_WPMR 0x000000e4 + +#endif From 987243fd7799f1a4900fbf2c41a3a1667d8d804b Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Tue, 3 Nov 2015 13:48:30 +0800 Subject: [PATCH 291/381] ASoC: atmel-classd: DT binding for Class D audio amplifier driver DT binding documentation for this new ASoC driver. Signed-off-by: Songjun Wu --- .../bindings/sound/atmel-classd.txt | 52 +++++++++++++++++++ sound/soc/atmel/Kconfig | 9 ++++ sound/soc/atmel/Makefile | 2 + 3 files changed, 63 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/atmel-classd.txt diff --git a/Documentation/devicetree/bindings/sound/atmel-classd.txt b/Documentation/devicetree/bindings/sound/atmel-classd.txt new file mode 100644 index 00000000000000..0018451c435148 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/atmel-classd.txt @@ -0,0 +1,52 @@ +* Atmel ClassD driver under ALSA SoC architecture + +Required properties: +- compatible + Should be "atmel,sama5d2-classd". +- reg + Should contain ClassD registers location and length. +- interrupts + Should contain the IRQ line for the ClassD. +- dmas + One DMA specifiers as described in atmel-dma.txt and dma.txt files. +- dma-names + Must be "tx". +- clock-names + Tuple listing input clock names. + Required elements: "pclk", "gclk" and "aclk". +- clocks + Please refer to clock-bindings.txt. + +Optional properties: +- pinctrl-names, pinctrl-0 + Please refer to pinctrl-bindings.txt. +- atmel,model + The user-visible name of this sound complex. + The default value is "CLASSD". +- atmel,pwm-type + PWM modulation type, "single" or "diff". + The default value is "single". +- atmel,non-overlap-time + Set non-overlapping time, the unit is nanosecond(ns). + There are four values, + <5>, <10>, <15>, <20>, the default value is <10>. + Non-overlapping will be disabled if not specified. + +Example: +classd: classd@fc048000 { + compatible = "atmel,sama5d2-classd"; + reg = <0xfc048000 0x100>; + interrupts = <59 IRQ_TYPE_LEVEL_HIGH 7>; + dmas = <&dma0 + (AT91_XDMAC_DT_MEM_IF(0) | AT91_XDMAC_DT_PER_IF(1) + | AT91_XDMAC_DT_PERID(47))>; + dma-names = "tx"; + clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>; + clock-names = "pclk", "gclk", "aclk"; + + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_classd_default>; + atmel,model = "classd @ SAMA5D2-Xplained"; + atmel,pwm-type = "diff"; + atmel,non-overlap-time = <10>; +}; diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e7d08806f3e92d..db1675eaa97789 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig @@ -55,3 +55,12 @@ config SND_AT91_SOC_SAM9X5_WM8731 help Say Y if you want to add support for audio SoC on an at91sam9x5 based board that is using WM8731 codec. + +config SND_ATMEL_SOC_CLASSD + tristate "Atmel ASoC driver for boards using CLASSD" + depends on ARCH_AT91 || COMPILE_TEST + select SND_ATMEL_SOC_DMA + select REGMAP_MMIO + help + Say Y if you want to add support for Atmel ASoC driver for boards using + CLASSD. diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index b327e5cc8de352..f6f7db4282164a 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile @@ -11,7 +11,9 @@ obj-$(CONFIG_SND_ATMEL_SOC_SSC) += snd-soc-atmel_ssc_dai.o snd-soc-sam9g20-wm8731-objs := sam9g20_wm8731.o snd-atmel-soc-wm8904-objs := atmel_wm8904.o snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o +snd-atmel-soc-classd-objs := atmel-classd.o obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o +obj-$(CONFIG_SND_ATMEL_SOC_CLASSD) += snd-atmel-soc-classd.o From ef504e774784d7b9ecd016c948573db10a33c924 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 14 Sep 2015 11:36:40 +0200 Subject: [PATCH 292/381] mmc: sdhci: don't disable the internal clock when setting sd clock When setting the SD clock, the internal clock is disabled at the beginning of the function and enabled later when writting the new sd clock configuration. Only disabling the SD clock is needed when reconfiguring it. Signed-off-by: Ludovic Desroches --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 5e253cd3065b80..89009c1b5edd49 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1170,7 +1170,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock = 0; - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + sdhci_writew(host, 1, SDHCI_CLOCK_CONTROL); if (host->quirks2 & SDHCI_QUIRK2_NEED_DELAY_AFTER_INT_CLK_RST) mdelay(1); From 0939dea95ec8ae26cee0fb9898a025348ef97044 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 15 Apr 2015 10:31:10 -0700 Subject: [PATCH 293/381] Input: atmel_mxt_ts - use BIT() macro when reporting button state This makes the intent a tad more clear. Reviewed-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 40b98dda8f38be..dfc7309e3d3898 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -726,15 +726,15 @@ static void mxt_input_button(struct mxt_data *data, u8 *message) { struct input_dev *input = data->input_dev; const struct mxt_platform_data *pdata = data->pdata; - bool button; int i; - /* Active-low switch */ for (i = 0; i < pdata->t19_num_keys; i++) { if (pdata->t19_keymap[i] == KEY_RESERVED) continue; - button = !(message[1] & (1 << i)); - input_report_key(input, pdata->t19_keymap[i], button); + + /* Active-low switch */ + input_report_key(input, pdata->t19_keymap[i], + !(message[1] & BIT(i))); } } From 545f086a4a97dd6a37e9ee768f52e1a2e785047d Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:36:29 -0700 Subject: [PATCH 294/381] Input: atmel_mxt_ts - use deep sleep mode when stopped The hardcoded 0x83 CTRL setting overrides other settings in that byte, enabling extra reporting that may not be useful on a particular platform. Implement improved suspend mechanism via deep sleep. By writing zero to both the active and idle cycle times the maXTouch device can be put into a deep sleep mode, using minimal power. It is necessary to issue a calibrate command after the chip has spent any time in deep sleep, however a soft reset is unnecessary. Use the old method on Chromebook Pixel via platform data option. This patch also deals with the situation where the power configuration is zero on probe, which would mean that the device never wakes up to execute commands. After a config download, the T7 power configuration may have changed so it is necessary to re-read it. Signed-off-by: Nick Dyer Acked-by: Benson Leung Acked-by: Yufeng Shen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 119 ++++++++++++++++-- drivers/platform/chrome/chromeos_laptop.c | 4 +- .../{i2c => platform_data}/atmel_mxt_ts.h | 12 +- 3 files changed, 120 insertions(+), 15 deletions(-) rename include/linux/{i2c => platform_data}/atmel_mxt_ts.h (70%) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index dfc7309e3d3898..f39cee696e3dae 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -103,9 +103,13 @@ #define MXT_T6_STATUS_COMSERR (1 << 2) /* MXT_GEN_POWER_T7 field */ -#define MXT_POWER_IDLEACQINT 0 -#define MXT_POWER_ACTVACQINT 1 -#define MXT_POWER_ACTV2IDLETO 2 +struct t7_config { + u8 idle; + u8 active; +} __packed; + +#define MXT_POWER_CFG_RUN 0 +#define MXT_POWER_CFG_DEEPSLEEP 1 /* MXT_GEN_ACQUIRE_T8 field */ #define MXT_ACQUIRE_CHRGTIME 0 @@ -117,7 +121,7 @@ #define MXT_ACQUIRE_ATCHCALSTHR 7 /* MXT_TOUCH_MULTI_T9 field */ -#define MXT_TOUCH_CTRL 0 +#define MXT_T9_CTRL 0 #define MXT_T9_ORIENT 9 #define MXT_T9_RANGE 18 @@ -291,6 +295,7 @@ struct mxt_data { u8 last_message_count; u8 num_touchids; u8 multitouch; + struct t7_config t7_cfg; /* Cached parameters from object table */ u16 T5_address; @@ -1361,6 +1366,8 @@ static int mxt_upload_cfg_mem(struct mxt_data *data, unsigned int cfg_start, return 0; } +static int mxt_init_t7_power_cfg(struct mxt_data *data); + /* * mxt_update_cfg - download configuration to chip * @@ -1508,6 +1515,9 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *cfg) dev_info(dev, "Config successfully updated\n"); + /* T7 config may have changed */ + mxt_init_t7_power_cfg(data); + release_mem: kfree(config_mem); return ret; @@ -2051,6 +2061,60 @@ static int mxt_initialize(struct mxt_data *data) return error; } +static int mxt_set_t7_power_cfg(struct mxt_data *data, u8 sleep) +{ + struct device *dev = &data->client->dev; + int error; + struct t7_config *new_config; + struct t7_config deepsleep = { .active = 0, .idle = 0 }; + + if (sleep == MXT_POWER_CFG_DEEPSLEEP) + new_config = &deepsleep; + else + new_config = &data->t7_cfg; + + error = __mxt_write_reg(data->client, data->T7_address, + sizeof(data->t7_cfg), new_config); + if (error) + return error; + + dev_dbg(dev, "Set T7 ACTV:%d IDLE:%d\n", + new_config->active, new_config->idle); + + return 0; +} + +static int mxt_init_t7_power_cfg(struct mxt_data *data) +{ + struct device *dev = &data->client->dev; + int error; + bool retry = false; + +recheck: + error = __mxt_read_reg(data->client, data->T7_address, + sizeof(data->t7_cfg), &data->t7_cfg); + if (error) + return error; + + if (data->t7_cfg.active == 0 || data->t7_cfg.idle == 0) { + if (!retry) { + dev_dbg(dev, "T7 cfg zero, resetting\n"); + mxt_soft_reset(data); + retry = true; + goto recheck; + } else { + dev_dbg(dev, "T7 cfg zero after reset, overriding\n"); + data->t7_cfg.active = 20; + data->t7_cfg.idle = 100; + return mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); + } + } + + dev_dbg(dev, "Initialized power cfg: ACTV %d, IDLE %d\n", + data->t7_cfg.active, data->t7_cfg.idle); + return 0; +} + static int mxt_configure_objects(struct mxt_data *data, const struct firmware *cfg) { @@ -2058,6 +2122,12 @@ static int mxt_configure_objects(struct mxt_data *data, struct mxt_info *info = &data->info; int error; + error = mxt_init_t7_power_cfg(data); + if (error) { + dev_err(dev, "Failed to initialize power cfg\n"); + return error; + } + if (cfg) { error = mxt_update_cfg(data, cfg); if (error) @@ -2346,14 +2416,41 @@ static const struct attribute_group mxt_attr_group = { static void mxt_start(struct mxt_data *data) { - /* Touch enable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0x83); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_T9_CTRL: + mxt_soft_reset(data); + + /* Touch enable */ + /* 0x83 = SCANEN | RPTEN | ENABLE */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN); + + /* Recalibrate since chip has been in deep sleep */ + mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); + break; + } + } static void mxt_stop(struct mxt_data *data) { - /* Touch disable */ - mxt_write_object(data, data->multitouch, MXT_TOUCH_CTRL, 0); + switch (data->pdata->suspend_mode) { + case MXT_SUSPEND_T9_CTRL: + /* Touch disable */ + mxt_write_object(data, + MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0); + break; + + case MXT_SUSPEND_DEEP_SLEEP: + default: + mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP); + break; + } } static int mxt_input_open(struct input_dev *dev) @@ -2409,6 +2506,8 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) pdata->t19_keymap = keymap; } + pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; + return pdata; } #else @@ -2625,8 +2724,6 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; - mxt_soft_reset(data); - mutex_lock(&input_dev->mutex); if (input_dev->users) diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index a04019ab9feb36..02072749fff371 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include @@ -111,6 +111,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = { .irqflags = IRQF_TRIGGER_FALLING, .t19_num_keys = ARRAY_SIZE(mxt_t19_keys), .t19_keymap = mxt_t19_keys, + .suspend_mode = MXT_SUSPEND_T9_CTRL, }; static struct i2c_board_info atmel_224s_tp_device = { @@ -121,6 +122,7 @@ static struct i2c_board_info atmel_224s_tp_device = { static struct mxt_platform_data atmel_1664s_platform_data = { .irqflags = IRQF_TRIGGER_FALLING, + .suspend_mode = MXT_SUSPEND_T9_CTRL, }; static struct i2c_board_info atmel_1664s_device = { diff --git a/include/linux/i2c/atmel_mxt_ts.h b/include/linux/platform_data/atmel_mxt_ts.h similarity index 70% rename from include/linux/i2c/atmel_mxt_ts.h rename to include/linux/platform_data/atmel_mxt_ts.h index 02bf6ea317015c..695035a8d7fb96 100644 --- a/include/linux/i2c/atmel_mxt_ts.h +++ b/include/linux/platform_data/atmel_mxt_ts.h @@ -10,16 +10,22 @@ * option) any later version. */ -#ifndef __LINUX_ATMEL_MXT_TS_H -#define __LINUX_ATMEL_MXT_TS_H +#ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H +#define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H #include +enum mxt_suspend_mode { + MXT_SUSPEND_DEEP_SLEEP = 0, + MXT_SUSPEND_T9_CTRL = 1, +}; + /* The platform data for the Atmel maXTouch touchscreen driver */ struct mxt_platform_data { unsigned long irqflags; u8 t19_num_keys; const unsigned int *t19_keymap; + enum mxt_suspend_mode suspend_mode; }; -#endif /* __LINUX_ATMEL_MXT_TS_H */ +#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */ From bb7fae4ede5b24e8ce99ce53ed7dd80592beb284 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:49:34 -0700 Subject: [PATCH 295/381] Input: atmel_mxt_ts - remove unused defines Many of these values are out of date and they aren't used in the driver - all they do is increase the size of the kernel source. Signed-off-by: Nick Dyer Acked-by: Benson Leung Acked-by: Yufeng Shen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 66 +----------------------- 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index f39cee696e3dae..93fc967df79b1d 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -29,27 +29,13 @@ #include #include -/* Version */ -#define MXT_VER_20 20 -#define MXT_VER_21 21 -#define MXT_VER_22 22 - /* Firmware files */ #define MXT_FW_NAME "maxtouch.fw" #define MXT_CFG_NAME "maxtouch.cfg" #define MXT_CFG_MAGIC "OBP_RAW V1" /* Registers */ -#define MXT_INFO 0x00 -#define MXT_FAMILY_ID 0x00 -#define MXT_VARIANT_ID 0x01 -#define MXT_VERSION 0x02 -#define MXT_BUILD 0x03 -#define MXT_MATRIX_X_SIZE 0x04 -#define MXT_MATRIX_Y_SIZE 0x05 -#define MXT_OBJECT_NUM 0x06 #define MXT_OBJECT_START 0x07 - #define MXT_OBJECT_SIZE 6 #define MXT_INFO_CHECKSUM_SIZE 3 #define MXT_MAX_BLOCK_WRITE 256 @@ -111,15 +97,6 @@ struct t7_config { #define MXT_POWER_CFG_RUN 0 #define MXT_POWER_CFG_DEEPSLEEP 1 -/* MXT_GEN_ACQUIRE_T8 field */ -#define MXT_ACQUIRE_CHRGTIME 0 -#define MXT_ACQUIRE_TCHDRIFT 2 -#define MXT_ACQUIRE_DRIFTST 3 -#define MXT_ACQUIRE_TCHAUTOCAL 4 -#define MXT_ACQUIRE_SYNC 5 -#define MXT_ACQUIRE_ATCHCALST 6 -#define MXT_ACQUIRE_ATCHCALSTHR 7 - /* MXT_TOUCH_MULTI_T9 field */ #define MXT_T9_CTRL 0 #define MXT_T9_ORIENT 9 @@ -143,51 +120,10 @@ struct t9_range { /* MXT_TOUCH_MULTI_T9 orient */ #define MXT_T9_ORIENT_SWITCH (1 << 0) -/* MXT_PROCI_GRIPFACE_T20 field */ -#define MXT_GRIPFACE_CTRL 0 -#define MXT_GRIPFACE_XLOGRIP 1 -#define MXT_GRIPFACE_XHIGRIP 2 -#define MXT_GRIPFACE_YLOGRIP 3 -#define MXT_GRIPFACE_YHIGRIP 4 -#define MXT_GRIPFACE_MAXTCHS 5 -#define MXT_GRIPFACE_SZTHR1 7 -#define MXT_GRIPFACE_SZTHR2 8 -#define MXT_GRIPFACE_SHPTHR1 9 -#define MXT_GRIPFACE_SHPTHR2 10 -#define MXT_GRIPFACE_SUPEXTTO 11 - -/* MXT_PROCI_NOISE field */ -#define MXT_NOISE_CTRL 0 -#define MXT_NOISE_OUTFLEN 1 -#define MXT_NOISE_GCAFUL_LSB 3 -#define MXT_NOISE_GCAFUL_MSB 4 -#define MXT_NOISE_GCAFLL_LSB 5 -#define MXT_NOISE_GCAFLL_MSB 6 -#define MXT_NOISE_ACTVGCAFVALID 7 -#define MXT_NOISE_NOISETHR 8 -#define MXT_NOISE_FREQHOPSCALE 10 -#define MXT_NOISE_FREQ0 11 -#define MXT_NOISE_FREQ1 12 -#define MXT_NOISE_FREQ2 13 -#define MXT_NOISE_FREQ3 14 -#define MXT_NOISE_FREQ4 15 -#define MXT_NOISE_IDLEGCAFVALID 16 - /* MXT_SPT_COMMSCONFIG_T18 */ #define MXT_COMMS_CTRL 0 #define MXT_COMMS_CMD 1 -/* MXT_SPT_CTECONFIG_T28 field */ -#define MXT_CTE_CTRL 0 -#define MXT_CTE_CMD 1 -#define MXT_CTE_MODE 2 -#define MXT_CTE_IDLEGCAFDEPTH 3 -#define MXT_CTE_ACTVGCAFDEPTH 4 -#define MXT_CTE_VOLTAGE 5 - -#define MXT_VOLTAGE_DEFAULT 2700000 -#define MXT_VOLTAGE_STEP 10000 - /* Define for MXT_GEN_COMMAND_T6 */ #define MXT_BOOT_VALUE 0xa5 #define MXT_RESET_VALUE 0x01 @@ -1543,7 +1479,7 @@ static int mxt_get_info(struct mxt_data *data) int error; /* Read 7-byte info block starting at address 0 */ - error = __mxt_read_reg(client, MXT_INFO, sizeof(*info), info); + error = __mxt_read_reg(client, 0, sizeof(*info), info); if (error) return error; From 930974a64c3a9120efc4fee06daccc5db6115430 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Tue, 4 Aug 2015 16:53:04 -0700 Subject: [PATCH 296/381] Input: atmel_mxt_ts - suspend/resume causes panic if input_dev fails to init input_dev may be NULL if mxt_initialize_input_device fails. But pm ops is still available and suspend/resume assume input_dev is not NULL. To fix this issue, we add a check if (!input_dev). Signed-off-by: Pan Xinhui Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 93fc967df79b1d..fd827a738cbc51 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2644,6 +2644,9 @@ static int __maybe_unused mxt_suspend(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; + if (!input_dev) + return 0; + mutex_lock(&input_dev->mutex); if (input_dev->users) @@ -2660,6 +2663,9 @@ static int __maybe_unused mxt_resume(struct device *dev) struct mxt_data *data = i2c_get_clientdata(client); struct input_dev *input_dev = data->input_dev; + if (!input_dev) + return 0; + mutex_lock(&input_dev->mutex); if (input_dev->users) From 3bb310c18b407c7e1f4bf26f1ea7ed60f5f6e19f Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:53:16 -0700 Subject: [PATCH 297/381] Input: atmel_mxt_ts - improve device tree parsing Use function rather than loop, define np to reduce wrapping. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index fd827a738cbc51..82d6f89e56761b 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2409,19 +2409,18 @@ static void mxt_input_close(struct input_dev *dev) static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) { struct mxt_platform_data *pdata; + struct device_node *np = client->dev.of_node; u32 *keymap; - u32 keycode; - int proplen, i, ret; + int proplen, ret; - if (!client->dev.of_node) + if (!np) return ERR_PTR(-ENOENT); pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - if (of_find_property(client->dev.of_node, "linux,gpio-keymap", - &proplen)) { + if (of_find_property(np, "linux,gpio-keymap", &proplen)) { pdata->t19_num_keys = proplen / sizeof(u32); keymap = devm_kzalloc(&client->dev, @@ -2430,14 +2429,11 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) if (!keymap) return ERR_PTR(-ENOMEM); - for (i = 0; i < pdata->t19_num_keys; i++) { - ret = of_property_read_u32_index(client->dev.of_node, - "linux,gpio-keymap", i, &keycode); - if (ret) - keycode = KEY_RESERVED; - - keymap[i] = keycode; - } + ret = of_property_read_u32_array(np, "linux,gpio-keymap", + keymap, pdata->t19_num_keys); + if (ret) + dev_warn(&client->dev, + "Couldn't read linux,gpio-keymap: %d\n", ret); pdata->t19_keymap = keymap; } From 5e0202c250b983002dd3479b84f5ed0eedb0b9fe Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:57:25 -0700 Subject: [PATCH 298/381] Input: atmel_mxt_ts - disable interrupt for 50ms after reset The CHG/interrupt line is momentarily set (approximately 100 ms) as an input after power-up or reset for diagnostic purposes. This may cause spurious interrupts, so disable interrupt handler during this period. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 82d6f89e56761b..65d1d759868ce3 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1098,7 +1098,9 @@ static int mxt_soft_reset(struct mxt_data *data) struct device *dev = &data->client->dev; int ret = 0; - dev_info(dev, "Resetting chip\n"); + dev_info(dev, "Resetting device\n"); + + disable_irq(data->irq); reinit_completion(&data->reset_completion); @@ -1106,6 +1108,11 @@ static int mxt_soft_reset(struct mxt_data *data) if (ret) return ret; + /* Ignore CHG line for 100ms after reset */ + msleep(100); + + enable_irq(data->irq); + ret = mxt_wait_for_completion(data, &data->reset_completion, MXT_RESET_TIMEOUT); if (ret) From 2ad0f0333b6aa33a6365c2d0e9c22e89b2a2b666 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:57:40 -0700 Subject: [PATCH 299/381] Input: atmel_mxt_ts - initialise input slots with INPUT_MT_DIRECT This indicates the device coordinates should be directly mapped to screen. This is valid since scaling/flipping/rotation should be done by configuring the MXT device. It also flags to Android using INPUT_PROP_DIRECT that the device should be treated as a touch screen by default, and removes the necessity for a default IDC file. Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 65d1d759868ce3..4aea485fe6801c 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -1858,6 +1858,8 @@ static int mxt_initialize_input_device(struct mxt_data *data) if (pdata->t19_num_keys) { mxt_set_up_as_touchpad(input_dev, data); mt_flags |= INPUT_MT_POINTER; + } else { + mt_flags |= INPUT_MT_DIRECT; } /* For multi touch */ From a232ad9ccb5a044f4b145aa1f85bcf20804bbc0e Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:58:05 -0700 Subject: [PATCH 300/381] Input: atmel_mxt_ts - remove warning on zero T44 count Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/atmel_mxt_ts.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 4aea485fe6801c..443ea21cd04c96 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -938,16 +938,15 @@ static irqreturn_t mxt_process_messages_t44(struct mxt_data *data) count = data->msg_buf[0]; - if (count == 0) { - /* - * This condition is caused by the CHG line being configured - * in Mode 0. It results in unnecessary I2C operations but it - * is benign. - */ - dev_dbg(dev, "Interrupt triggered but zero messages\n"); + /* + * This condition may be caused by the CHG line being configured in + * Mode 0. It results in unnecessary I2C operations but it is benign. + */ + if (count == 0) return IRQ_NONE; - } else if (count > data->max_reportid) { - dev_err(dev, "T44 count %d exceeded max report id\n", count); + + if (count > data->max_reportid) { + dev_warn(dev, "T44 count %d exceeded max report id\n", count); count = data->max_reportid; } From c473faaed0509207d591d17e18d5e2fc3fd1a573 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 4 Aug 2015 16:22:54 -0700 Subject: [PATCH 301/381] MAINTAINERS: Add maintainer for atmel_mxt_ts Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index d8afd29536786b..88c2e4f886783d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1862,6 +1862,14 @@ W: http://atmelwlandriver.sourceforge.net/ S: Maintained F: drivers/net/wireless/atmel* +ATMEL MAXTOUCH DRIVER +M: Nick Dyer +T: git git://github.com/atmel-maxtouch/linux.git +S: Supported +F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt +F: drivers/input/touchscreen/atmel_mxt_ts.c +F: include/linux/platform_data/atmel_mxt_ts.h + ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER M: Bradley Grove L: linux-scsi@vger.kernel.org From 271898027a508101cc3f092c3df6d9fb13f2e360 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 30 Apr 2015 14:27:50 +0200 Subject: [PATCH 302/381] Input: atmel_mxt_ts: add a second try if initialization fails For an unknown reason, the maxtouch can not ack the i2c request when we want to communicate. Trying to establish the communication finally works after about 200 ms. So when probing the driver if the first time initilization fails then wait and try a second time. Signed-off-by: Ludovic Desroches --- drivers/input/touchscreen/atmel_mxt_ts.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 443ea21cd04c96..333b57cf4637f8 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2607,8 +2607,14 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) disable_irq(client->irq); error = mxt_initialize(data); - if (error) - goto err_free_irq; + if (error) { + /* Wait and try a second time */ + msleep(MXT_RESET_TIME); + dev_warn(&client->dev, "Try a second time to init maxtouch\n"); + error = mxt_initialize(data); + if (error) + goto err_free_irq; + } error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group); if (error) { From e236146361848b5f632871b28a08da607a7ce2dd Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 15:39:53 +0800 Subject: [PATCH 303/381] media: atmel-isi: add parameter for start_dma() and reuse it The parameter is used to enable the ISI dma interrupt. After add the parameter we can reuse the start_dma() in other place. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 3a6fcedfc76ae8..8bc1eb4da4c410 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -203,6 +203,7 @@ static bool is_supported(struct soc_camera_device *icd, } } +static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer, bool irq); static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) { if (isi->active) { @@ -221,19 +222,7 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) /* start next dma frame. */ isi->active = list_entry(isi->video_buffer_list.next, struct frame_buffer, list); - if (!isi->enable_preview_path) { - isi_writel(isi, ISI_DMA_C_DSCR, - (u32)isi->active->p_dma_desc->fbd_phys); - isi_writel(isi, ISI_DMA_C_CTRL, - ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); - isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH); - } else { - isi_writel(isi, ISI_DMA_P_DSCR, - (u32)isi->active->p_dma_desc->fbd_phys); - isi_writel(isi, ISI_DMA_P_CTRL, - ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE); - isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH); - } + start_dma(isi, isi->active, false); } return IRQ_HANDLED; } @@ -398,13 +387,14 @@ static void buffer_cleanup(struct vb2_buffer *vb) list_add(&buf->p_dma_desc->list, &isi->dma_desc_head); } -static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer) +static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer, + bool enable_irq) { u32 ctrl; - /* Enable irq: cxfr for the codec path, pxfr for the preview path */ - isi_writel(isi, ISI_INTEN, - ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); + if (enable_irq) + /* Enable irq: cxfr for the codec path, pxfr for the preview path */ + isi_writel(isi, ISI_INTEN, ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); /* Check if already in a frame */ if (!isi->enable_preview_path) { @@ -449,7 +439,7 @@ static void buffer_queue(struct vb2_buffer *vb) if (isi->active == NULL) { isi->active = buf; if (vb2_is_streaming(vb->vb2_queue)) - start_dma(isi, buf); + start_dma(isi, buf, true); } spin_unlock_irqrestore(&isi->lock, flags); } @@ -513,7 +503,8 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) spin_lock_irq(&isi->lock); if (count) - start_dma(isi, isi->active); + start_dma(isi, isi->active, true); + spin_unlock_irq(&isi->lock); return 0; From c6b72628ab7909d0d9573601fce6d341a8abc7d0 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 14:46:21 +0800 Subject: [PATCH 304/381] media: atmel-isi: can we meet such situation? if yes, then we cannot delete this line. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 8bc1eb4da4c410..862ebefa2a8570 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -398,11 +398,6 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer, /* Check if already in a frame */ if (!isi->enable_preview_path) { - if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) { - dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n"); - return; - } - isi_writel(isi, ISI_DMA_C_DSCR, (u32)buffer->p_dma_desc->fbd_phys); isi_writel(isi, ISI_DMA_C_CTRL, From 3b3de1229414ef89e13c56d92268810c7e0cd1a2 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 30 Sep 2015 11:41:28 +0800 Subject: [PATCH 305/381] media: atmel-isi: add function hw_uninitialize() This hw_uninitialze() function is only called on stop_streaming(). Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 862ebefa2a8570..7e2266deb83b75 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -473,6 +473,27 @@ static void isi_hw_initialize(struct atmel_isi *isi) isi_writel(isi, ISI_CFG1, cfg1); } +static void isi_hw_uninitialize(struct atmel_isi *isi) +{ + unsigned long timeout; + + if (!isi->enable_preview_path) { + timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + /* Wait until the end of the current frame. */ + while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && + time_before(jiffies, timeout)) + msleep(1); + + if (time_after(jiffies, timeout)) + dev_err(isi->soc_host.v4l2_dev.dev, + "Timeout waiting for finishing codec request\n"); + } + + /* Disable interrupts */ + isi_writel(isi, ISI_INTDIS, + ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); +} + static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); @@ -513,32 +534,18 @@ static void stop_streaming(struct vb2_queue *vq) struct atmel_isi *isi = ici->priv; struct frame_buffer *buf, *node; int ret = 0; - unsigned long timeout; spin_lock_irq(&isi->lock); isi->active = NULL; /* Release all active buffers */ list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) { list_del_init(&buf->list); - vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + if (buf != isi->active) + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } spin_unlock_irq(&isi->lock); - if (!isi->enable_preview_path) { - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; - /* Wait until the end of the current frame. */ - while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) && - time_before(jiffies, timeout)) - msleep(1); - - if (time_after(jiffies, timeout)) - dev_err(icd->parent, - "Timeout waiting for finishing codec request\n"); - } - - /* Disable interrupts */ - isi_writel(isi, ISI_INTDIS, - ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); + isi_hw_uninitialize(isi); /* Disable ISI and wait for it is done */ ret = atmel_isi_wait_status(isi, WAIT_HW_DISABLE); From 81fef60376f70570238c71cb4b49d6756dc65bba Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 14:35:39 +0800 Subject: [PATCH 306/381] media: atmel-isi: use union for the fbd This way, we can easy to add other type of fbd. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 7e2266deb83b75..d150b641cadb67 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -38,7 +38,7 @@ #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) /* Frame buffer descriptor */ -struct fbd { +struct fbd_isi_v2 { /* Physical address of the frame buffer */ u32 fb_address; /* DMA Control Register(only in HISI2) */ @@ -47,9 +47,13 @@ struct fbd { u32 next_fbd_address; }; +union fbd { + struct fbd_isi_v2 fbd_isi; +}; + struct isi_dma_desc { struct list_head list; - struct fbd *p_fbd; + union fbd *p_fbd; dma_addr_t fbd_phys; }; @@ -70,7 +74,7 @@ struct atmel_isi { struct vb2_alloc_ctx *alloc_ctx; /* Allocate descriptors for dma buffer use */ - struct fbd *p_fb_descriptors; + union fbd *p_fb_descriptors; dma_addr_t fb_descriptors_phys; struct list_head dma_desc_head; struct isi_dma_desc dma_desc[MAX_BUFFER_NUM]; @@ -333,6 +337,14 @@ static int buffer_init(struct vb2_buffer *vb) return 0; } +static void isi_hw_init_dma_desc(union fbd *p_fdb, u32 fb_addr, u32 next_fbd_addr) +{ + struct fbd_isi_v2 *p = &(p_fdb->fbd_isi); + p->fb_address = fb_addr; + p->next_fbd_address = next_fbd_addr; + p->dma_ctrl = ISI_DMA_CTRL_WB; +} + static int buffer_prepare(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); @@ -364,10 +376,7 @@ static int buffer_prepare(struct vb2_buffer *vb) list_del_init(&desc->list); /* Initialize the dma descriptor */ - desc->p_fbd->fb_address = - vb2_dma_contig_plane_dma_addr(vb, 0); - desc->p_fbd->next_fbd_address = 0; - desc->p_fbd->dma_ctrl = ISI_DMA_CTRL_WB; + isi_hw_init_dma_desc(desc->p_fbd, vb2_dma_contig_plane_dma_addr(vb, 0), 0); buf->p_dma_desc = desc; } @@ -943,7 +952,7 @@ static int atmel_isi_remove(struct platform_device *pdev) soc_camera_host_unregister(soc_host); vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); dma_free_coherent(&pdev->dev, - sizeof(struct fbd) * MAX_BUFFER_NUM, + sizeof(union fbd) * MAX_BUFFER_NUM, isi->p_fb_descriptors, isi->fb_descriptors_phys); pm_runtime_disable(&pdev->dev); @@ -1030,7 +1039,7 @@ static int atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->dma_desc_head); isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, - sizeof(struct fbd) * MAX_BUFFER_NUM, + sizeof(union fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, GFP_KERNEL); if (!isi->p_fb_descriptors) { @@ -1041,7 +1050,7 @@ static int atmel_isi_probe(struct platform_device *pdev) for (i = 0; i < MAX_BUFFER_NUM; i++) { isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i; isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys + - i * sizeof(struct fbd); + i * sizeof(union fbd); list_add(&isi->dma_desc[i].list, &isi->dma_desc_head); } @@ -1100,7 +1109,7 @@ static int atmel_isi_probe(struct platform_device *pdev) vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); err_alloc_ctx: dma_free_coherent(&pdev->dev, - sizeof(struct fbd) * MAX_BUFFER_NUM, + sizeof(union fbd) * MAX_BUFFER_NUM, isi->p_fb_descriptors, isi->fb_descriptors_phys); From 7a71c0fff20b2a60a96f7dde7313dd347862fa34 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 29 Sep 2015 18:40:05 +0800 Subject: [PATCH 307/381] media: atmel-isi: use hw_ops function table according compatible string Add a new hw_ops functions table, which has all hardware related functions. That can make us easy to add another hardware support. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 54 +++++++++++++++---- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index d150b641cadb67..55e93ecd0ff6ac 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -93,6 +94,7 @@ struct atmel_isi { struct frame_buffer *active; struct soc_camera_host soc_host; + struct at91_camera_hw_ops *hw_ops; }; static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) @@ -104,6 +106,19 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg) return readl(isi->regs + reg); } +struct at91_camera_hw_ops { + void (*start_dma)(struct atmel_isi *isi, struct frame_buffer *buffer, + bool enable_irq); + void (*hw_initialize)(struct atmel_isi *isi); + void (*hw_uninitialize)(struct atmel_isi *isi); + void (*hw_configure)(struct atmel_isi *isi, u32 width, u32 height, + const struct soc_camera_format_xlate *xlate); + irqreturn_t (*interrupt)(int irq, void *dev_id); + void (*init_dma_desc)(union fbd *p_fdb, u32 fb_addr, + u32 next_fbd_addr); + void (*hw_enable_interrupt)(struct atmel_isi *isi, int type); +}; + static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, const struct soc_camera_format_xlate *xlate) { @@ -207,7 +222,6 @@ static bool is_supported(struct soc_camera_device *icd, } } -static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer, bool irq); static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) { if (isi->active) { @@ -226,7 +240,8 @@ static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi) /* start next dma frame. */ isi->active = list_entry(isi->video_buffer_list.next, struct frame_buffer, list); - start_dma(isi, isi->active, false); + + (*isi->hw_ops->start_dma)(isi, isi->active, false); } return IRQ_HANDLED; } @@ -284,7 +299,7 @@ static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) */ init_completion(&isi->complete); - isi_hw_enable_interrupt(isi, wait_reset); + (*isi->hw_ops->hw_enable_interrupt)(isi, wait_reset); timeout = wait_for_completion_timeout(&isi->complete, msecs_to_jiffies(500)); @@ -353,6 +368,7 @@ static int buffer_prepare(struct vb2_buffer *vb) struct atmel_isi *isi = ici->priv; unsigned long size; struct isi_dma_desc *desc; + u32 vb_addr; size = icd->sizeimage; @@ -376,7 +392,8 @@ static int buffer_prepare(struct vb2_buffer *vb) list_del_init(&desc->list); /* Initialize the dma descriptor */ - isi_hw_init_dma_desc(desc->p_fbd, vb2_dma_contig_plane_dma_addr(vb, 0), 0); + vb_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + (*isi->hw_ops->init_dma_desc)(desc->p_fbd, vb_addr, 0); buf->p_dma_desc = desc; } @@ -443,7 +460,7 @@ static void buffer_queue(struct vb2_buffer *vb) if (isi->active == NULL) { isi->active = buf; if (vb2_is_streaming(vb->vb2_queue)) - start_dma(isi, buf, true); + (*isi->hw_ops->start_dma)(isi, buf, true); } spin_unlock_irqrestore(&isi->lock, flags); } @@ -520,15 +537,15 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } - isi_hw_initialize(isi); + (*isi->hw_ops->hw_initialize)(isi); - configure_geometry(isi, icd->user_width, icd->user_height, + (*isi->hw_ops->hw_configure)(isi, icd->user_width, icd->user_height, icd->current_fmt); spin_lock_irq(&isi->lock); if (count) - start_dma(isi, isi->active, true); + (*isi->hw_ops->start_dma)(isi, isi->active, true); spin_unlock_irq(&isi->lock); @@ -554,7 +571,7 @@ static void stop_streaming(struct vb2_queue *vq) } spin_unlock_irq(&isi->lock); - isi_hw_uninitialize(isi); + (*isi->hw_ops->hw_uninitialize)(isi); /* Disable ISI and wait for it is done */ ret = atmel_isi_wait_status(isi, WAIT_HW_DISABLE); @@ -1011,6 +1028,7 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi, return 0; } +static const struct of_device_id atmel_isi_of_match[]; static int atmel_isi_probe(struct platform_device *pdev) { unsigned int irq; @@ -1033,6 +1051,9 @@ static int atmel_isi_probe(struct platform_device *pdev) if (ret) return ret; + isi->hw_ops = (struct at91_camera_hw_ops *) + of_match_device(atmel_isi_of_match, &pdev->dev)->data; + isi->active = NULL; spin_lock_init(&isi->lock); INIT_LIST_HEAD(&isi->video_buffer_list); @@ -1078,7 +1099,8 @@ static int atmel_isi_probe(struct platform_device *pdev) goto err_req_irq; } - ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi); + ret = devm_request_irq(&pdev->dev, irq, isi->hw_ops->interrupt, 0, + "isi", isi); if (ret) { dev_err(&pdev->dev, "Unable to request irq %d\n", irq); goto err_req_irq; @@ -1137,13 +1159,23 @@ static int atmel_isi_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ +static struct at91_camera_hw_ops at91sam9g45_ops = { + .hw_initialize = isi_hw_initialize, + .hw_uninitialize = isi_hw_uninitialize, + .hw_configure = configure_geometry, + .start_dma = start_dma, + .interrupt = isi_interrupt, + .init_dma_desc = isi_hw_init_dma_desc, + .hw_enable_interrupt = isi_hw_enable_interrupt, +}; + static const struct dev_pm_ops atmel_isi_dev_pm_ops = { SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, atmel_isi_runtime_resume, NULL) }; static const struct of_device_id atmel_isi_of_match[] = { - { .compatible = "atmel,at91sam9g45-isi" }, + { .compatible = "atmel,at91sam9g45-isi", .data = &at91sam9g45_ops }, { } }; MODULE_DEVICE_TABLE(of, atmel_isi_of_match); From 9665b3a59fdd17fefc7548a5f993edf8823d7741 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Sun, 25 Oct 2015 16:41:26 +0800 Subject: [PATCH 308/381] media: atmel-isi: add hw_set_clock() function for mclk operation Hardware can define hw_set_clock(), which used to enable/disable mclk that provided by atmel-isi hardware for sensor to operate. But it's optional as customer can choose to use host camera to provide the clock for sensor or not. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 55e93ecd0ff6ac..02b53f42146ca4 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -117,6 +117,7 @@ struct at91_camera_hw_ops { void (*init_dma_desc)(union fbd *p_fdb, u32 fb_addr, u32 next_fbd_addr); void (*hw_enable_interrupt)(struct atmel_isi *isi, int type); + void (*hw_set_clock)(struct atmel_isi *isi, bool enable_clk); }; static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, @@ -944,6 +945,24 @@ static int isi_camera_set_parm(struct soc_camera_device *icd, struct v4l2_stream return 0; } +static int clock_start(struct soc_camera_host *ici) +{ + struct atmel_isi *isi = ici->priv; + + if (isi->hw_ops->hw_set_clock) + (*isi->hw_ops->hw_set_clock)(isi, true); + + return 0; +} + +static void clock_stop(struct soc_camera_host *ici) +{ + struct atmel_isi *isi = ici->priv; + + if (isi->hw_ops->hw_set_clock) + (*isi->hw_ops->hw_set_clock)(isi, false); +} + static struct soc_camera_host_ops isi_soc_camera_host_ops = { .owner = THIS_MODULE, .add = isi_camera_add_device, @@ -957,6 +976,8 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { .set_bus_param = isi_camera_set_bus_param, .set_parm = isi_camera_set_parm, .get_parm = isi_camera_set_parm, + .clock_start = clock_start, + .clock_stop = clock_stop, }; /* -----------------------------------------------------------------------*/ From 9402a7bc4a1dc5a21c99815e8e0572cc3737d152 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Sun, 25 Oct 2015 10:52:09 +0800 Subject: [PATCH 309/381] media: atmel-isi: isc: add the header file ISC hardware Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isc.h | 176 ++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 drivers/media/platform/soc_camera/atmel-isc.h diff --git a/drivers/media/platform/soc_camera/atmel-isc.h b/drivers/media/platform/soc_camera/atmel-isc.h new file mode 100644 index 00000000000000..4f9b18c3f3a6d6 --- /dev/null +++ b/drivers/media/platform/soc_camera/atmel-isc.h @@ -0,0 +1,176 @@ +/* + * Register definitions for the Atmel Image Sensor Controller (ISC). + * + * Copyright (C) 2015 Atmel Corporation + * Josh Wu, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ATMEL_ISC_H__ +#define __ATMEL_ISC_H__ + +#include + +/* register offsets */ +#define ISC_CTRLEN 0x0000 +#define ISC_CTRLDIS 0x0004 +#define ISC_CTRLSR 0x0008 +#define ISC_PFE_CFG0 0x000c +#define ISC_PFE_CFG1 0x0010 +#define ISC_PFE_CFG2 0x0014 +#define ISC_CLKEN 0x0018 +#define ISC_CLKDIS 0x001C +#define ISC_CLKSR 0x0020 +#define ISC_CLKCFG 0x0024 +#define ISC_INTEN 0x0028 +#define ISC_INTDIS 0x002C +#define ISC_INTMASK 0x0030 +#define ISC_INTSR 0x0034 + +#define ISC_CFA_CTRL 0x0070 +#define ISC_CFA_CFG 0x0074 + +#define ISC_GAM_CTRL 0x0094 +#define ISC_GAM_BENTRY0 0x0098 +#define ISC_GAM_GENTRY0 (ISC_GAM_BENTRY0 + 4 * 64) +#define ISC_GAM_RENTRY0 (ISC_GAM_GENTRY0 + 4 * 64) + +#define ISC_RLP_CFG 0x03d0 + +#define ISC_DCFG 0x03e0 +#define ISC_DCTRL 0x03e4 +#define ISC_DNDA 0x03e8 +#define ISC_DAD0 0x03ec +#define ISC_DST0 0x03f0 +#define ISC_DAD1 0x03f4 +#define ISC_DST1 0x03f8 +#define ISC_DAD2 0x03fc +#define ISC_DST2 0x0400 + +/* Bitfields in ISC_CTRLEN */ +#define ISC_CTRLEN_CAPTURE (1 << 0) +#define ISC_CTRLEN_UPPRO (1 << 1) /* update profile */ +#define ISC_CTRLEN_HISREQ (1 << 2) /* update histogram table */ +#define ISC_CTRLEN_HISCLR (1 << 3) /* clear histogram table */ +/* Bitfields in ISC_CTRLDIS */ +#define ISC_CTRLDIS_CAPTURE (1 << 0) +#define ISC_CTRLDIS_SWRST (1 << 8) +/* Bitfields in ISC_CTRLSR */ +#define ISC_CTRLSR_CAPTURE (1 << 0) /* capture pending */ +#define ISC_CTRLSR_UPPRO (1 << 1) /* update profile pending */ +#define ISC_CTRLSR_HISREQ (1 << 2) /* update histogram table pending */ +#define ISC_CTRLSR_FIELD (1 << 4) /* field status */ +#define ISC_CTRLSR_SIP (1 << 31) /* Synchronization In Progress */ + +/* Bitfields in ISC_PFE */ +#define ISC_PFE_HSYNC_ACTIVE_HIGH (0 << 0) +#define ISC_PFE_HSYNC_ACTIVE_LOW (1 << 0) +#define ISC_PFE_VSYNC_ACTIVE_HIGH (0 << 1) +#define ISC_PFE_VSYNC_ACTIVE_LOW (1 << 1) +#define ISC_PFE_PIX_CLK_RISING_EDGE (0 << 2) +#define ISC_PFE_PIX_CLK_FALLING_EDGE (1 << 2) +#define ISC_PFE_FPOL (1 << 3) +#define ISC_PFE_MODE_PROGRESSIVE (0 << 4) +#define ISC_PFE_CONT_SINGLE_SHOT (0 << 7) +#define ISC_PFE_CONT_VIDEO (1 << 7) +#define ISC_PFE_GATED_PIX_CLK (1 << 8) +#define ISC_PFE_COL_CROP (1 << 12) +#define ISC_PFE_ROW_CROP (1 << 13) + +#define ISC_PFE_BPS_12_BIT (0 << 28) +#define ISC_PFE_BPS_11_BIT (1 << 28) +#define ISC_PFE_BPS_10_BIT (2 << 28) +#define ISC_PFE_BPS_9_BIT (3 << 28) +#define ISC_PFE_BPS_8_BIT (4 << 28) + +/* Bitfields in ISC_CLKEN/CLKDIS/CLKSR */ +#define ISC_CLK_ISP (1 << 0) +#define ISC_CLK_MASTER (1 << 1) +#define ISC_CLK_ISP_RESET (1 << 8) +#define ISC_CLK_MASTER_RESET (1 << 9) +#define ISC_CLK_SIP (1 << 31) + +/* Bitfields in ISC_CLKCFG */ +#define ISC_CLKCFG_ICDIV_OFFSET (0) +#define ISC_CLKCFG_ICDIV_MASK (0xFF << ISC_CLKCFG_ICDIV_OFFSET) +#define ISC_CLKCFG_ICDIV(n) ((n) << ISC_CLKCFG_ICDIV_OFFSET) +#define ISC_CLKCFG_ISP_SEL_HCLOCK (0 << 8) +#define ISC_CLKCFG_ISP_SEL_GCK (1 << 8) +#define ISC_CLKCFG_MCDIV_OFFSET (16) +#define ISC_CLKCFG_MCDIV_MASK (0xFF << ISC_CLKCFG_MCDIV_OFFSET) +#define ISC_CLKCFG_MCDIV(n) ((n) << ISC_CLKCFG_MCDIV_OFFSET) +#define ISC_CLKCFG_MASTER_SEL_HCLOCK (0 << 24) +#define ISC_CLKCFG_MASTER_SEL_GCK (1 << 24) +#define ISC_CLKCFG_MASTER_SEL_480M (2 << 24) + +/* Bitfields in ISC_GAM_CTRL */ +#define ISC_GAM_CTRL_ENABLE BIT(0) +#define ISC_GAM_CTRL_B_ENABLE BIT(1) +#define ISC_GAM_CTRL_G_ENABLE BIT(2) +#define ISC_GAM_CTRL_R_ENABLE BIT(3) +#define ISC_GAM_CTRL_ENABLE_ALL_CHAN (ISC_GAM_CTRL_B_ENABLE | \ + ISC_GAM_CTRL_G_ENABLE | \ + ISC_GAM_CTRL_R_ENABLE) + +/* Bitfields in ISC_RLP_CFG */ +#define ISC_RLP_CFG_MODE_DAT8 (0 << 0) +#define ISC_RLP_CFG_MODE_DAT9 (1 << 0) +#define ISC_RLP_CFG_MODE_DAT10 (2 << 0) +#define ISC_RLP_CFG_MODE_DAT11 (3 << 0) +#define ISC_RLP_CFG_MODE_DAT12 (4 << 0) +#define ISC_RLP_CFG_MODE_DAT_Y8 (5 << 0) +#define ISC_RLP_CFG_MODE_DAT_Y10 (6 << 0) +#define ISC_RLP_CFG_MODE_ARGB444 (7 << 0) +#define ISC_RLP_CFG_MODE_ARGB555 (8 << 0) +#define ISC_RLP_CFG_MODE_RGB565 (9 << 0) +#define ISC_RLP_CFG_MODE_ARGB32 (10 << 0) +#define ISC_RLP_CFG_MODE_YCC (11 << 0) +#define ISC_RLP_CFG_MODE_YCC_LIMITED (12 << 0) +#define ISC_RLP_CFG_ALPHA_OFFSET (8) +#define ISC_RLP_CFG_ALPHA_MASK (0xFF << ISC_RLP_CFG_ALPHA_OFFSET) + +/* Bitfields in ISC_INTEN/INTDIS/INTMASK/INTSR */ +#define ISC_INT_VSYNC (1 << 0) +#define ISC_INT_HSYNC (1 << 1) +#define ISC_INT_SWRST_COMPLETE (1 << 4) +#define ISC_INT_DISABLE_COMPLETE (1 << 5) +#define ISC_INT_DMA_DONE (1 << 8) +#define ISC_INT_DMA_LIST_DONE (1 << 9) +#define ISC_INT_HISTOGRAM_DONE (1 << 12) +#define ISC_INT_HISTOGRAM_CLEAR (1 << 13) + +/* Bitfields in ISC_DCFG (DMA config)*/ +#define ISC_DCFG_IMODE_PACKED8 (0 << 0) +#define ISC_DCFG_IMODE_PACKED16 (1 << 0) +#define ISC_DCFG_IMODE_PACKED32 (2 << 0) +#define ISC_DCFG_IMODE_YC422SP (3 << 0) +#define ISC_DCFG_IMODE_YC422P (4 << 0) +#define ISC_DCFG_IMODE_YC420SP (5 << 0) +#define ISC_DCFG_IMODE_YC420P (6 << 0) +#define ISC_DCFG_MBSIZE_SINGLE (0) +#define ISC_DCFG_MBSIZE_BEATS_4 (1) +#define ISC_DCFG_MBSIZE_BEATS_8 (2) +#define ISC_DCFG_MBSIZE_BEATS_16 (3) +#define ISC_DCFG_MBSIZE_CHAN_Y_OFFSET (4) +#define ISC_DCFG_MBSIZE_CHAN_C_OFFSET (8) +#define ISC_DCFG_YMBSIZE(x) (x << ISC_DCFG_MBSIZE_CHAN_Y_OFFSET) +#define ISC_DCFG_CMBSIZE(x) (x << ISC_DCFG_MBSIZE_CHAN_C_OFFSET) + +/* Bitfields in ISC_DCTRL (DMA control)*/ +#define ISC_DCTRL_DESC_DISABLE (0 << 0) +#define ISC_DCTRL_DESC_ENABLE (1 << 0) +#define ISC_DCTRL_DVIEW_PACKED (0 << 1) +#define ISC_DCTRL_DVIEW_SEMIPLANAR (1 << 1) +#define ISC_DCTRL_DVIEW_PLANAR (2 << 1) +#define ISC_DCTRL_DMA_DONE_INT_DISABLE (0 << 4) +#define ISC_DCTRL_DMA_DONE_INT_ENABLE (1 << 4) +#define ISC_DCTRL_WRITE_BACK_DISABLE (0 << 5) +#define ISC_DCTRL_WRITE_BACK_ENABLE (1 << 5) + +/* Definition for isc_platform_data */ +#define ISC_DATAWIDTH_8 0x01 +#define ISC_DATAWIDTH_10 0x02 + +#endif /* __ATMEL_ISC_H__ */ From 0796e4978ae031905e4e13320aa51163e9f180fd Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 16:49:12 +0800 Subject: [PATCH 310/381] media: atmel-isi: isc: add new sama5d2 ISC (Image Sensor Controller) support Implement the hardware related functions: hw_initialize()/hw_uninitialize(): hardware init/uninitialization. hw_configure(): hardware format configuration. interrupt(): hardware interrupt service harndler. hw_enable_interrupt(): interrupt enabling. hw_set_clock(): enable/disable the ISC peripheral as the clock will start/stop automatically. start_dma(): dma configuration to start. init_dma_desc(): initialize the dma description. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 203 +++++++++++++++++- 1 file changed, 202 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 02b53f42146ca4..95ba128a1ff5fd 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -1,7 +1,9 @@ /* - * Copyright (c) 2011 Atmel Corporation + * Copyright (c) 2015 Atmel Corporation * Josh Wu, * + * Add SAMA5D2 chip's ISC (Image Sensor Controller) hardware support. + * * Based on previous work by Lars Haring, * and Sedji Gaouaou * Based on the bttv driver for Bt848 with respective copyright holders @@ -30,6 +32,7 @@ #include #include "atmel-isi.h" +#include "atmel-isc.h" #define MAX_BUFFER_NUM 32 #define MAX_SUPPORT_WIDTH 2048 @@ -48,8 +51,20 @@ struct fbd_isi_v2 { u32 next_fbd_address; }; +struct fbd_view { + /* DMA Control Register */ + u32 dma_ctrl; + /* Physical address of the next fbd */ + u32 next_fbd_address; + /* Physical address of the frame buffer 0 */ + u32 fb_address; + /* stride 0 */ + u32 fb_stride; +}; + union fbd { struct fbd_isi_v2 fbd_isi; + struct fbd_view fbd_isc; }; struct isi_dma_desc { @@ -205,6 +220,42 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, return; } +static void isc_configure_geometry(struct atmel_isi *isc, u32 width, + u32 height, const struct soc_camera_format_xlate *xlate) +{ + /* According to sensor's output format to set cfg2 */ + switch (xlate->code) { + /* YUV, including grey */ + case MEDIA_BUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + default: + isi_writel(isc, ISC_CFA_CTRL, 0); + isi_writel(isc, ISC_GAM_CTRL, 0); + isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_DAT8); + isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED8); + break; + /* Bayer RGB */ + case MEDIA_BUS_FMT_SBGGR8_1X8: + if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) { + isi_writel(isc, ISC_CFA_CTRL, 1); + isi_writel(isc, ISC_CFA_CFG, 3 | 1 << 4); + isi_writel(isc, ISC_GAM_CTRL, ISC_GAM_CTRL_ENABLE | ISC_GAM_CTRL_ENABLE_ALL_CHAN); + isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_RGB565); + isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED16); + } else { + /* output to Bayer RGB */ + isi_writel(isc, ISC_CFA_CTRL, 0); + isi_writel(isc, ISC_GAM_CTRL, 0); + isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_DAT8); + isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED8); + } + break; + } +} + static bool is_supported(struct soc_camera_device *icd, const u32 pixformat) { @@ -278,6 +329,34 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id) return ret; } +static irqreturn_t isc_interrupt(int irq, void *dev_id) +{ + struct atmel_isi *isc = dev_id; + u32 status, mask, pending; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&isc->lock); + + status = isi_readl(isc, ISC_INTSR); + mask = isi_readl(isc, ISC_INTMASK); + pending = status & mask; + + if (pending & ISC_INT_SWRST_COMPLETE) { + complete(&isc->complete); + isi_writel(isc, ISC_INTEN, ISC_INT_SWRST_COMPLETE); + ret = IRQ_HANDLED; + } else if (pending & ISC_INT_DISABLE_COMPLETE) { + complete(&isc->complete); + isi_writel(isc, ISC_INTEN, ISC_INT_DISABLE_COMPLETE); + ret = IRQ_HANDLED; + } else if (likely(pending & ISC_INT_DMA_DONE)) { + ret = atmel_isi_handle_streaming(isc); + } + + spin_unlock(&isc->lock); + return ret; +} + #define WAIT_HW_RESET 1 #define WAIT_HW_DISABLE 0 static void isi_hw_enable_interrupt(struct atmel_isi *isi, int type) @@ -291,6 +370,17 @@ static void isi_hw_enable_interrupt(struct atmel_isi *isi, int type) } } +static void isc_hw_enable_interrupt(struct atmel_isi *isc, int type) +{ + if (type == WAIT_HW_RESET) { + isi_writel(isc, ISC_INTEN, ISC_INT_SWRST_COMPLETE); + isi_writel(isc, ISC_CTRLDIS, ISC_CTRLDIS_SWRST); + } else { + isi_writel(isc, ISC_INTEN, ISC_INT_DISABLE_COMPLETE); + isi_writel(isc, ISC_CTRLDIS, ISC_CTRLDIS_CAPTURE); + } +} + static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) { unsigned long timeout; @@ -361,6 +451,15 @@ static void isi_hw_init_dma_desc(union fbd *p_fdb, u32 fb_addr, u32 next_fbd_add p->dma_ctrl = ISI_DMA_CTRL_WB; } +static void isc_hw_init_dma_desc(union fbd *p_fbd, u32 fb_addr, u32 next_fbd_addr) +{ + struct fbd_view *p = &(p_fbd->fbd_isc); + p->fb_address = fb_addr; + p->next_fbd_address = 0; + p->fb_stride = 0; + p->dma_ctrl = ISC_DCTRL_DESC_ENABLE | ISC_DCTRL_DVIEW_PACKED; +} + static int buffer_prepare(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); @@ -447,6 +546,20 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer, isi_writel(isi, ISI_CTRL, ctrl); } +static void isc_start_dma(struct atmel_isi *isc, struct frame_buffer *buffer, + bool enable_irq) +{ + if (enable_irq) + isi_writel(isc, ISC_INTEN, ISC_INT_DMA_DONE); + + isi_writel(isc, ISC_DNDA, (u32)buffer->p_dma_desc->fbd_phys); + isi_writel(isc, ISC_DCTRL, ISC_DCTRL_DESC_ENABLE | ISC_DCTRL_DVIEW_PACKED | + ISC_DCTRL_DMA_DONE_INT_ENABLE | ISC_DCTRL_WRITE_BACK_ENABLE); + isi_writel(isc, ISC_DAD0, buffer->p_dma_desc->p_fbd->fbd_isc.fb_address); + + isi_writel(isc, ISC_CTRLEN, ISC_CTRLEN_CAPTURE); +} + static void buffer_queue(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); @@ -521,6 +634,52 @@ static void isi_hw_uninitialize(struct atmel_isi *isi) ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); } +static void isc_hw_initialize(struct atmel_isi *isc) +{ + u32 pfe_cfg0 = 0; + + if (isc->bus_param & V4L2_MBUS_HSYNC_ACTIVE_LOW) + pfe_cfg0 |= ISC_PFE_HSYNC_ACTIVE_LOW; + if (isc->bus_param & V4L2_MBUS_VSYNC_ACTIVE_LOW) + pfe_cfg0 |= ISC_PFE_VSYNC_ACTIVE_LOW; + if (isc->bus_param & V4L2_MBUS_PCLK_SAMPLE_FALLING) + pfe_cfg0 |= ISC_PFE_PIX_CLK_FALLING_EDGE; + + pfe_cfg0 |= ISC_PFE_MODE_PROGRESSIVE | ISC_PFE_CONT_VIDEO; + + /* TODO: need to revisit. */ + pfe_cfg0 |= ISC_PFE_BPS_8_BIT; + + isi_writel(isc, ISC_PFE_CFG0, pfe_cfg0); +} + +static void isc_hw_uninitialize(struct atmel_isi *isc) +{ + unsigned long timeout; + + timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + /* Wait until the end of the current frame. */ + while ((isi_readl(isc, ISC_CTRLSR) & ISC_CTRLSR_CAPTURE) && time_before(jiffies, timeout)) + msleep(1); + + if (time_after(jiffies, timeout)) + dev_err(isc->soc_host.v4l2_dev.dev, + "Timeout waiting for finishing codec request\n"); + + /* Disable interrupts */ + isi_writel(isc, ISC_INTDIS, ISC_INT_DMA_DONE); +} + +static void isc_hw_set_clock(struct atmel_isi *isc, bool enable_clk) +{ + if (enable_clk) + /* as the clock (ISC_MCK) is provided by peripheral clock, so just resume pm */ + pm_runtime_get_sync(isc->soc_host.v4l2_dev.dev); + else + /* as the clock (ISC_MCK) is provided by peripheral clock, so just suspend pm */ + pm_runtime_put(isc->soc_host.v4l2_dev.dev); +} + static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); @@ -1049,6 +1208,32 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi, return 0; } +static void isc_enable_clock(struct atmel_isi *isc) +{ + u32 cfg; + + pm_runtime_get_sync(isc->soc_host.v4l2_dev.dev); + + /*Config the MCK div and select it to isc_clk(hclock) */ + cfg = ISC_CLKCFG_MCDIV(6) & ISC_CLKCFG_MCDIV_MASK; + cfg |= ISC_CLKCFG_MASTER_SEL_HCLOCK; + + isi_writel(isc, ISC_CLKCFG, cfg); + while ((isi_readl(isc, ISC_CLKSR) & ISC_CLK_SIP) == ISC_CLK_SIP); + isi_writel(isc, ISC_CLKEN, ISC_CLK_MASTER); + + /* keep original clock config */ + cfg |= ISC_CLKCFG_ICDIV(5) & ISC_CLKCFG_ICDIV_MASK; + cfg |= ISC_CLKCFG_ISP_SEL_HCLOCK; + + isi_writel(isc, ISC_CLKCFG, cfg); + while ((isi_readl(isc, ISC_CLKSR) & ISC_CLK_SIP) == ISC_CLK_SIP); + /* Enable isp clock */ + isi_writel(isc, ISC_CLKEN, ISC_CLK_ISP); + + pm_runtime_put(isc->soc_host.v4l2_dev.dev); +} + static const struct of_device_id atmel_isi_of_match[]; static int atmel_isi_probe(struct platform_device *pdev) { @@ -1143,6 +1328,10 @@ static int atmel_isi_probe(struct platform_device *pdev) dev_err(&pdev->dev, "Unable to register soc camera host\n"); goto err_register_soc_camera_host; } + + if (of_device_is_compatible(pdev->dev.of_node, "atmel,sama5d2-isc")) + isc_enable_clock(isi); + return 0; err_register_soc_camera_host: @@ -1190,6 +1379,17 @@ static struct at91_camera_hw_ops at91sam9g45_ops = { .hw_enable_interrupt = isi_hw_enable_interrupt, }; +static struct at91_camera_hw_ops sama5d2_ops = { + .hw_initialize = isc_hw_initialize, + .hw_uninitialize = isc_hw_uninitialize, + .hw_configure = isc_configure_geometry, + .start_dma = isc_start_dma, + .init_dma_desc = isc_hw_init_dma_desc, + .interrupt = isc_interrupt, + .hw_enable_interrupt = isc_hw_enable_interrupt, + .hw_set_clock = isc_hw_set_clock, +}; + static const struct dev_pm_ops atmel_isi_dev_pm_ops = { SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, atmel_isi_runtime_resume, NULL) @@ -1197,6 +1397,7 @@ static const struct dev_pm_ops atmel_isi_dev_pm_ops = { static const struct of_device_id atmel_isi_of_match[] = { { .compatible = "atmel,at91sam9g45-isi", .data = &at91sam9g45_ops }, + { .compatible = "atmel,sama5d2-isc", .data = &sama5d2_ops}, { } }; MODULE_DEVICE_TABLE(of, atmel_isi_of_match); From 186e456a43e79866967ba50072de6a16a27d0173 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 17:15:25 +0800 Subject: [PATCH 311/381] media: atmel-isi: dt-binding: add atmel,sama5d2-isc support in document Signed-off-by: Josh Wu --- Documentation/devicetree/bindings/media/atmel-isi.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/atmel-isi.txt b/Documentation/devicetree/bindings/media/atmel-isi.txt index 251f008f220cff..7440bb9e393180 100644 --- a/Documentation/devicetree/bindings/media/atmel-isi.txt +++ b/Documentation/devicetree/bindings/media/atmel-isi.txt @@ -2,7 +2,7 @@ Atmel Image Sensor Interface (ISI) SoC Camera Subsystem ---------------------------------------------- Required properties: -- compatible: must be "atmel,at91sam9g45-isi" +- compatible: should be "atmel,at91sam9g45-isi" or "atmel,sama5d2-isc"; - reg: physical base address and length of the registers set for the device; - interrupts: should contain IRQ line for the ISI; - clocks: list of clock specifiers, corresponding to entries in From d5091415603153d508143cb75b3702cfed0018cb Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 27 Oct 2015 17:12:04 +0800 Subject: [PATCH 312/381] media: atmel-isi: isc: add iscck support But iscck is optional. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 95ba128a1ff5fd..d4e37b881f8c21 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -99,6 +99,9 @@ struct atmel_isi { struct completion complete; /* ISI peripherial clock */ struct clk *pclk; + /* ISC clock */ + struct clk *iscck; + unsigned int irq; struct isi_platform_data pdata; @@ -1253,6 +1256,10 @@ static int atmel_isi_probe(struct platform_device *pdev) if (IS_ERR(isi->pclk)) return PTR_ERR(isi->pclk); + isi->iscck = devm_clk_get(&pdev->dev, "iscck"); + if (IS_ERR(isi->iscck)) + isi->iscck = NULL; + ret = atmel_isi_parse_dt(isi, pdev); if (ret) return ret; @@ -1355,6 +1362,8 @@ static int atmel_isi_runtime_suspend(struct device *dev) struct atmel_isi *isi = container_of(soc_host, struct atmel_isi, soc_host); + if (isi->iscck) + clk_disable_unprepare(isi->iscck); clk_disable_unprepare(isi->pclk); return 0; @@ -1365,6 +1374,8 @@ static int atmel_isi_runtime_resume(struct device *dev) struct atmel_isi *isi = container_of(soc_host, struct atmel_isi, soc_host); + if (isi->iscck) + clk_prepare_enable(isi->iscck); return clk_prepare_enable(isi->pclk); } #endif /* CONFIG_PM */ From 7878c531cc6ed0fa45c9711a2bfd941ed1f08876 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 30 Oct 2015 17:02:21 +0800 Subject: [PATCH 313/381] media: atmel-isi: add dependency on CONFIG_PM As atmel-isi driver use runtime pm API to control the clock, so add dependency on it. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index f2776cd415ca81..1b4980e606fe4a 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -84,6 +84,7 @@ config VIDEO_ATMEL_ISI depends on VIDEO_DEV && SOC_CAMERA depends on ARCH_AT91 || COMPILE_TEST depends on HAS_DMA + depends on PM select VIDEOBUF2_DMA_CONTIG ---help--- This module makes the ATMEL Image Sensor Interface available From e4ecf933820cf88894c2209426cb597cc7c8d493 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 3 Nov 2015 18:15:34 +0800 Subject: [PATCH 314/381] atmel-isi: isc: move function into one section Signed-off-by: Josh Wu Conflicts: drivers/media/platform/soc_camera/atmel-isi.c --- drivers/media/platform/soc_camera/atmel-isi.c | 343 +++++++++--------- 1 file changed, 173 insertions(+), 170 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index d4e37b881f8c21..388a37bc91d9c6 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -223,42 +223,6 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, return; } -static void isc_configure_geometry(struct atmel_isi *isc, u32 width, - u32 height, const struct soc_camera_format_xlate *xlate) -{ - /* According to sensor's output format to set cfg2 */ - switch (xlate->code) { - /* YUV, including grey */ - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_YUYV8_2X8: - default: - isi_writel(isc, ISC_CFA_CTRL, 0); - isi_writel(isc, ISC_GAM_CTRL, 0); - isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_DAT8); - isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED8); - break; - /* Bayer RGB */ - case MEDIA_BUS_FMT_SBGGR8_1X8: - if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) { - isi_writel(isc, ISC_CFA_CTRL, 1); - isi_writel(isc, ISC_CFA_CFG, 3 | 1 << 4); - isi_writel(isc, ISC_GAM_CTRL, ISC_GAM_CTRL_ENABLE | ISC_GAM_CTRL_ENABLE_ALL_CHAN); - isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_RGB565); - isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED16); - } else { - /* output to Bayer RGB */ - isi_writel(isc, ISC_CFA_CTRL, 0); - isi_writel(isc, ISC_GAM_CTRL, 0); - isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_DAT8); - isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED8); - } - break; - } -} - static bool is_supported(struct soc_camera_device *icd, const u32 pixformat) { @@ -332,34 +296,6 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id) return ret; } -static irqreturn_t isc_interrupt(int irq, void *dev_id) -{ - struct atmel_isi *isc = dev_id; - u32 status, mask, pending; - irqreturn_t ret = IRQ_NONE; - - spin_lock(&isc->lock); - - status = isi_readl(isc, ISC_INTSR); - mask = isi_readl(isc, ISC_INTMASK); - pending = status & mask; - - if (pending & ISC_INT_SWRST_COMPLETE) { - complete(&isc->complete); - isi_writel(isc, ISC_INTEN, ISC_INT_SWRST_COMPLETE); - ret = IRQ_HANDLED; - } else if (pending & ISC_INT_DISABLE_COMPLETE) { - complete(&isc->complete); - isi_writel(isc, ISC_INTEN, ISC_INT_DISABLE_COMPLETE); - ret = IRQ_HANDLED; - } else if (likely(pending & ISC_INT_DMA_DONE)) { - ret = atmel_isi_handle_streaming(isc); - } - - spin_unlock(&isc->lock); - return ret; -} - #define WAIT_HW_RESET 1 #define WAIT_HW_DISABLE 0 static void isi_hw_enable_interrupt(struct atmel_isi *isi, int type) @@ -373,17 +309,6 @@ static void isi_hw_enable_interrupt(struct atmel_isi *isi, int type) } } -static void isc_hw_enable_interrupt(struct atmel_isi *isc, int type) -{ - if (type == WAIT_HW_RESET) { - isi_writel(isc, ISC_INTEN, ISC_INT_SWRST_COMPLETE); - isi_writel(isc, ISC_CTRLDIS, ISC_CTRLDIS_SWRST); - } else { - isi_writel(isc, ISC_INTEN, ISC_INT_DISABLE_COMPLETE); - isi_writel(isc, ISC_CTRLDIS, ISC_CTRLDIS_CAPTURE); - } -} - static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset) { unsigned long timeout; @@ -454,15 +379,6 @@ static void isi_hw_init_dma_desc(union fbd *p_fdb, u32 fb_addr, u32 next_fbd_add p->dma_ctrl = ISI_DMA_CTRL_WB; } -static void isc_hw_init_dma_desc(union fbd *p_fbd, u32 fb_addr, u32 next_fbd_addr) -{ - struct fbd_view *p = &(p_fbd->fbd_isc); - p->fb_address = fb_addr; - p->next_fbd_address = 0; - p->fb_stride = 0; - p->dma_ctrl = ISC_DCTRL_DESC_ENABLE | ISC_DCTRL_DVIEW_PACKED; -} - static int buffer_prepare(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); @@ -549,20 +465,6 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer, isi_writel(isi, ISI_CTRL, ctrl); } -static void isc_start_dma(struct atmel_isi *isc, struct frame_buffer *buffer, - bool enable_irq) -{ - if (enable_irq) - isi_writel(isc, ISC_INTEN, ISC_INT_DMA_DONE); - - isi_writel(isc, ISC_DNDA, (u32)buffer->p_dma_desc->fbd_phys); - isi_writel(isc, ISC_DCTRL, ISC_DCTRL_DESC_ENABLE | ISC_DCTRL_DVIEW_PACKED | - ISC_DCTRL_DMA_DONE_INT_ENABLE | ISC_DCTRL_WRITE_BACK_ENABLE); - isi_writel(isc, ISC_DAD0, buffer->p_dma_desc->p_fbd->fbd_isc.fb_address); - - isi_writel(isc, ISC_CTRLEN, ISC_CTRLEN_CAPTURE); -} - static void buffer_queue(struct vb2_buffer *vb) { struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue); @@ -637,52 +539,6 @@ static void isi_hw_uninitialize(struct atmel_isi *isi) ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE); } -static void isc_hw_initialize(struct atmel_isi *isc) -{ - u32 pfe_cfg0 = 0; - - if (isc->bus_param & V4L2_MBUS_HSYNC_ACTIVE_LOW) - pfe_cfg0 |= ISC_PFE_HSYNC_ACTIVE_LOW; - if (isc->bus_param & V4L2_MBUS_VSYNC_ACTIVE_LOW) - pfe_cfg0 |= ISC_PFE_VSYNC_ACTIVE_LOW; - if (isc->bus_param & V4L2_MBUS_PCLK_SAMPLE_FALLING) - pfe_cfg0 |= ISC_PFE_PIX_CLK_FALLING_EDGE; - - pfe_cfg0 |= ISC_PFE_MODE_PROGRESSIVE | ISC_PFE_CONT_VIDEO; - - /* TODO: need to revisit. */ - pfe_cfg0 |= ISC_PFE_BPS_8_BIT; - - isi_writel(isc, ISC_PFE_CFG0, pfe_cfg0); -} - -static void isc_hw_uninitialize(struct atmel_isi *isc) -{ - unsigned long timeout; - - timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; - /* Wait until the end of the current frame. */ - while ((isi_readl(isc, ISC_CTRLSR) & ISC_CTRLSR_CAPTURE) && time_before(jiffies, timeout)) - msleep(1); - - if (time_after(jiffies, timeout)) - dev_err(isc->soc_host.v4l2_dev.dev, - "Timeout waiting for finishing codec request\n"); - - /* Disable interrupts */ - isi_writel(isc, ISC_INTDIS, ISC_INT_DMA_DONE); -} - -static void isc_hw_set_clock(struct atmel_isi *isc, bool enable_clk) -{ - if (enable_clk) - /* as the clock (ISC_MCK) is provided by peripheral clock, so just resume pm */ - pm_runtime_get_sync(isc->soc_host.v4l2_dev.dev); - else - /* as the clock (ISC_MCK) is provided by peripheral clock, so just suspend pm */ - pm_runtime_put(isc->soc_host.v4l2_dev.dev); -} - static int start_streaming(struct vb2_queue *vq, unsigned int count) { struct soc_camera_device *icd = soc_camera_from_vb2q(vq); @@ -756,6 +612,179 @@ static struct vb2_ops isi_video_qops = { .wait_finish = vb2_ops_wait_finish, }; +/* ------------------------------------------------------------------ + ISC hardware operations + ------------------------------------------------------------------*/ +static void isc_hw_enable_interrupt(struct atmel_isi *isc, int type) +{ + if (type == WAIT_HW_RESET) { + isi_writel(isc, ISC_INTEN, ISC_INT_SWRST_COMPLETE); + isi_writel(isc, ISC_CTRLDIS, ISC_CTRLDIS_SWRST); + } else { + isi_writel(isc, ISC_INTEN, ISC_INT_DISABLE_COMPLETE); + isi_writel(isc, ISC_CTRLDIS, ISC_CTRLDIS_CAPTURE); + } +} + +static void isc_hw_init_dma_desc(union fbd *p_fbd, u32 fb_addr, u32 next_fbd_addr) +{ + struct fbd_view *p = &(p_fbd->fbd_isc); + p->fb_address = fb_addr; + p->next_fbd_address = 0; + p->fb_stride = 0; + p->dma_ctrl = ISC_DCTRL_DESC_ENABLE | ISC_DCTRL_DVIEW_PACKED; +} + +static void isc_start_dma(struct atmel_isi *isc, struct frame_buffer *buffer, + bool enable_irq) +{ + if (enable_irq) + isi_writel(isc, ISC_INTEN, ISC_INT_DMA_DONE); + + isi_writel(isc, ISC_DNDA, (u32)buffer->p_dma_desc->fbd_phys); + isi_writel(isc, ISC_DCTRL, ISC_DCTRL_DESC_ENABLE | ISC_DCTRL_DVIEW_PACKED | + ISC_DCTRL_DMA_DONE_INT_ENABLE | ISC_DCTRL_WRITE_BACK_ENABLE); + isi_writel(isc, ISC_DAD0, buffer->p_dma_desc->p_fbd->fbd_isc.fb_address); + + isi_writel(isc, ISC_CTRLEN, ISC_CTRLEN_CAPTURE); +} + +static void isc_hw_initialize(struct atmel_isi *isc) +{ + u32 pfe_cfg0 = 0; + + if (isc->bus_param & V4L2_MBUS_HSYNC_ACTIVE_LOW) + pfe_cfg0 |= ISC_PFE_HSYNC_ACTIVE_LOW; + if (isc->bus_param & V4L2_MBUS_VSYNC_ACTIVE_LOW) + pfe_cfg0 |= ISC_PFE_VSYNC_ACTIVE_LOW; + if (isc->bus_param & V4L2_MBUS_PCLK_SAMPLE_FALLING) + pfe_cfg0 |= ISC_PFE_PIX_CLK_FALLING_EDGE; + + pfe_cfg0 |= ISC_PFE_MODE_PROGRESSIVE | ISC_PFE_CONT_VIDEO; + + /* TODO: need to revisit. */ + pfe_cfg0 |= ISC_PFE_BPS_8_BIT; + + isi_writel(isc, ISC_PFE_CFG0, pfe_cfg0); +} + +static void isc_hw_uninitialize(struct atmel_isi *isc) +{ + unsigned long timeout; + + timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ; + /* Wait until the end of the current frame. */ + while ((isi_readl(isc, ISC_CTRLSR) & ISC_CTRLSR_CAPTURE) && time_before(jiffies, timeout)) + msleep(1); + + if (time_after(jiffies, timeout)) + dev_err(isc->soc_host.v4l2_dev.dev, + "Timeout waiting for finishing codec request\n"); + + /* Disable interrupts */ + isi_writel(isc, ISC_INTDIS, ISC_INT_DMA_DONE); +} + +static void isc_hw_set_clock(struct atmel_isi *isc, bool enable_clk) +{ + if (enable_clk) + /* as the clock (ISC_MCK) is provided by peripheral clock, so just resume pm */ + pm_runtime_get_sync(isc->soc_host.v4l2_dev.dev); + else + /* as the clock (ISC_MCK) is provided by peripheral clock, so just suspend pm */ + pm_runtime_put(isc->soc_host.v4l2_dev.dev); +} + +static void isc_configure_geometry(struct atmel_isi *isc, u32 width, + u32 height, const struct soc_camera_format_xlate *xlate) +{ + /* According to sensor's output format to set cfg2 */ + switch (xlate->code) { + /* YUV, including grey */ + case MEDIA_BUS_FMT_Y8_1X8: + case MEDIA_BUS_FMT_VYUY8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_YVYU8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + default: + isi_writel(isc, ISC_CFA_CTRL, 0); + isi_writel(isc, ISC_GAM_CTRL, 0); + isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_DAT8); + isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED8); + break; + /* Bayer RGB */ + case MEDIA_BUS_FMT_SBGGR8_1X8: + if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) { + isi_writel(isc, ISC_CFA_CTRL, 1); + isi_writel(isc, ISC_CFA_CFG, 3 | 1 << 4); + isi_writel(isc, ISC_GAM_CTRL, ISC_GAM_CTRL_ENABLE | ISC_GAM_CTRL_ENABLE_ALL_CHAN); + isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_RGB565); + isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED16); + } else { + /* output to Bayer RGB */ + isi_writel(isc, ISC_CFA_CTRL, 0); + isi_writel(isc, ISC_GAM_CTRL, 0); + isi_writel(isc, ISC_RLP_CFG, ISC_RLP_CFG_MODE_DAT8); + isi_writel(isc, ISC_DCFG, ISC_DCFG_IMODE_PACKED8); + } + break; + } +} + +static irqreturn_t isc_interrupt(int irq, void *dev_id) +{ + struct atmel_isi *isc = dev_id; + u32 status, mask, pending; + irqreturn_t ret = IRQ_NONE; + + spin_lock(&isc->lock); + + status = isi_readl(isc, ISC_INTSR); + mask = isi_readl(isc, ISC_INTMASK); + pending = status & mask; + + if (pending & ISC_INT_SWRST_COMPLETE) { + complete(&isc->complete); + isi_writel(isc, ISC_INTEN, ISC_INT_SWRST_COMPLETE); + ret = IRQ_HANDLED; + } else if (pending & ISC_INT_DISABLE_COMPLETE) { + complete(&isc->complete); + isi_writel(isc, ISC_INTEN, ISC_INT_DISABLE_COMPLETE); + ret = IRQ_HANDLED; + } else if (likely(pending & ISC_INT_DMA_DONE)) { + ret = atmel_isi_handle_streaming(isc); + } + + spin_unlock(&isc->lock); + return ret; +} + +static void isc_enable_clock(struct atmel_isi *isc) +{ + u32 cfg; + + pm_runtime_get_sync(isc->soc_host.v4l2_dev.dev); + + /*Config the MCK div and select it to isc_clk(hclock) */ + cfg = ISC_CLKCFG_MCDIV(6) & ISC_CLKCFG_MCDIV_MASK; + cfg |= ISC_CLKCFG_MASTER_SEL_HCLOCK; + + isi_writel(isc, ISC_CLKCFG, cfg); + while ((isi_readl(isc, ISC_CLKSR) & ISC_CLK_SIP) == ISC_CLK_SIP); + isi_writel(isc, ISC_CLKEN, ISC_CLK_MASTER); + + /* keep original clock config */ + cfg |= ISC_CLKCFG_ICDIV(5) & ISC_CLKCFG_ICDIV_MASK; + cfg |= ISC_CLKCFG_ISP_SEL_HCLOCK; + + isi_writel(isc, ISC_CLKCFG, cfg); + while ((isi_readl(isc, ISC_CLKSR) & ISC_CLK_SIP) == ISC_CLK_SIP); + /* Enable isp clock */ + isi_writel(isc, ISC_CLKEN, ISC_CLK_ISP); + + pm_runtime_put(isc->soc_host.v4l2_dev.dev); +} + /* ------------------------------------------------------------------ SOC camera operations for the device ------------------------------------------------------------------*/ @@ -1211,32 +1240,6 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi, return 0; } -static void isc_enable_clock(struct atmel_isi *isc) -{ - u32 cfg; - - pm_runtime_get_sync(isc->soc_host.v4l2_dev.dev); - - /*Config the MCK div and select it to isc_clk(hclock) */ - cfg = ISC_CLKCFG_MCDIV(6) & ISC_CLKCFG_MCDIV_MASK; - cfg |= ISC_CLKCFG_MASTER_SEL_HCLOCK; - - isi_writel(isc, ISC_CLKCFG, cfg); - while ((isi_readl(isc, ISC_CLKSR) & ISC_CLK_SIP) == ISC_CLK_SIP); - isi_writel(isc, ISC_CLKEN, ISC_CLK_MASTER); - - /* keep original clock config */ - cfg |= ISC_CLKCFG_ICDIV(5) & ISC_CLKCFG_ICDIV_MASK; - cfg |= ISC_CLKCFG_ISP_SEL_HCLOCK; - - isi_writel(isc, ISC_CLKCFG, cfg); - while ((isi_readl(isc, ISC_CLKSR) & ISC_CLK_SIP) == ISC_CLK_SIP); - /* Enable isp clock */ - isi_writel(isc, ISC_CLKEN, ISC_CLK_ISP); - - pm_runtime_put(isc->soc_host.v4l2_dev.dev); -} - static const struct of_device_id atmel_isi_of_match[]; static int atmel_isi_probe(struct platform_device *pdev) { From 09e3b6e3304ee918864579e5c14dfa6d85696044 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 4 Nov 2015 14:33:36 +0800 Subject: [PATCH 315/381] media: atmel-isi: fix debug message which alwasy show the first item Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 388a37bc91d9c6..ded24b006732ba 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -1006,7 +1006,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, xlate->host_fmt = &isi_camera_formats[i]; xlate->code = code.code; dev_dbg(icd->parent, "Providing format %s using code %d\n", - isi_camera_formats[0].name, code.code); + xlate->host_fmt->name, xlate->code); } break; default: From 4c8067e36fb5fd1ca7a26d044bbede8c5c17ce8d Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 4 Nov 2015 14:35:51 +0800 Subject: [PATCH 316/381] atmel-isi: pass the support format to the structure add support_formats[] in hardware caps as every hardware support different formats. Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 103 +++++++++++------- 1 file changed, 62 insertions(+), 41 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index ded24b006732ba..19e3183bff822c 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -113,6 +113,7 @@ struct atmel_isi { struct soc_camera_host soc_host; struct at91_camera_hw_ops *hw_ops; + struct at91_camera_caps *caps; }; static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val) @@ -138,6 +139,11 @@ struct at91_camera_hw_ops { void (*hw_set_clock)(struct atmel_isi *isi, bool enable_clk); }; +struct at91_camera_caps { + struct at91_camera_hw_ops hw_ops; + struct soc_mbus_pixelfmt yuv_support_formats[]; +}; + static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi, const struct soc_camera_format_xlate *xlate) { @@ -893,25 +899,6 @@ static int isi_camera_try_fmt(struct soc_camera_device *icd, return try_or_set_fmt(icd, f, &format); } -static const struct soc_mbus_pixelfmt isi_camera_formats[] = { - { - .fourcc = V4L2_PIX_FMT_YUYV, - .name = "Packed YUV422 16 bit", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - .name = "RGB565", - .bits_per_sample = 8, - .packing = SOC_MBUS_PACKING_2X8_PADHI, - .order = SOC_MBUS_ORDER_LE, - .layout = SOC_MBUS_LAYOUT_PACKED, - }, -}; - /* This will be corrected as we get more formats */ static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt) { @@ -966,6 +953,8 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, struct soc_camera_format_xlate *xlate) { struct v4l2_subdev *sd = soc_camera_to_subdev(icd); + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; int formats = 0, ret, i, n; /* sensor format */ struct v4l2_subdev_mbus_code_enum code = { @@ -1000,10 +989,12 @@ static int isi_camera_get_formats(struct soc_camera_device *icd, case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: - n = ARRAY_SIZE(isi_camera_formats); + for (n = 0; isi->caps->yuv_support_formats[n].name != NULL; n++) + /* Empty! */; + formats += n; for (i = 0; xlate && i < n; i++, xlate++) { - xlate->host_fmt = &isi_camera_formats[i]; + xlate->host_fmt = isi->caps->yuv_support_formats + i; xlate->code = code.code; dev_dbg(icd->parent, "Providing format %s using code %d\n", xlate->host_fmt->name, xlate->code); @@ -1267,8 +1258,9 @@ static int atmel_isi_probe(struct platform_device *pdev) if (ret) return ret; - isi->hw_ops = (struct at91_camera_hw_ops *) + isi->caps = (struct at91_camera_caps *) of_match_device(atmel_isi_of_match, &pdev->dev)->data; + isi->hw_ops = &isi->caps->hw_ops; isi->active = NULL; spin_lock_init(&isi->lock); @@ -1383,25 +1375,54 @@ static int atmel_isi_runtime_resume(struct device *dev) } #endif /* CONFIG_PM */ -static struct at91_camera_hw_ops at91sam9g45_ops = { - .hw_initialize = isi_hw_initialize, - .hw_uninitialize = isi_hw_uninitialize, - .hw_configure = configure_geometry, - .start_dma = start_dma, - .interrupt = isi_interrupt, - .init_dma_desc = isi_hw_init_dma_desc, - .hw_enable_interrupt = isi_hw_enable_interrupt, +static struct at91_camera_caps at91sam9g45_caps = { + .hw_ops = { + .hw_initialize = isi_hw_initialize, + .hw_uninitialize = isi_hw_uninitialize, + .hw_configure = configure_geometry, + .start_dma = start_dma, + .interrupt = isi_interrupt, + .init_dma_desc = isi_hw_init_dma_desc, + .hw_enable_interrupt = isi_hw_enable_interrupt, + }, + + .yuv_support_formats = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .name = "Packed YUV422 16 bit", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + .layout = SOC_MBUS_LAYOUT_PACKED, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .name = "RGB565", + .bits_per_sample = 8, + .packing = SOC_MBUS_PACKING_2X8_PADHI, + .order = SOC_MBUS_ORDER_LE, + .layout = SOC_MBUS_LAYOUT_PACKED, + }, + { /* terminator */ }, + }, }; -static struct at91_camera_hw_ops sama5d2_ops = { - .hw_initialize = isc_hw_initialize, - .hw_uninitialize = isc_hw_uninitialize, - .hw_configure = isc_configure_geometry, - .start_dma = isc_start_dma, - .init_dma_desc = isc_hw_init_dma_desc, - .interrupt = isc_interrupt, - .hw_enable_interrupt = isc_hw_enable_interrupt, - .hw_set_clock = isc_hw_set_clock, +static struct at91_camera_caps sama5d2_caps = { + .hw_ops = { + .hw_initialize = isc_hw_initialize, + .hw_uninitialize = isc_hw_uninitialize, + .hw_configure = isc_configure_geometry, + .start_dma = isc_start_dma, + .init_dma_desc = isc_hw_init_dma_desc, + .interrupt = isc_interrupt, + .hw_enable_interrupt = isc_hw_enable_interrupt, + .hw_set_clock = isc_hw_set_clock, + }, + + .yuv_support_formats = { + /* use default pass through */ + { /* terminator */ }, + }, }; static const struct dev_pm_ops atmel_isi_dev_pm_ops = { @@ -1410,8 +1431,8 @@ static const struct dev_pm_ops atmel_isi_dev_pm_ops = { }; static const struct of_device_id atmel_isi_of_match[] = { - { .compatible = "atmel,at91sam9g45-isi", .data = &at91sam9g45_ops }, - { .compatible = "atmel,sama5d2-isc", .data = &sama5d2_ops}, + { .compatible = "atmel,at91sam9g45-isi", .data = &at91sam9g45_caps}, + { .compatible = "atmel,sama5d2-isc", .data = &sama5d2_caps}, { } }; MODULE_DEVICE_TABLE(of, atmel_isi_of_match); From fc977b9fb168ea6866fe2ceabfbc1774cca8b44e Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 4 Nov 2015 15:59:21 +0800 Subject: [PATCH 317/381] media: atmel-isi: add host_fmt_support() as hosts support different formats Signed-off-by: Josh Wu --- drivers/media/platform/soc_camera/atmel-isi.c | 27 ++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 19e3183bff822c..8a7a1d7f1df1b6 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -137,6 +137,7 @@ struct at91_camera_hw_ops { u32 next_fbd_addr); void (*hw_enable_interrupt)(struct atmel_isi *isi, int type); void (*hw_set_clock)(struct atmel_isi *isi, bool enable_clk); + bool (*host_fmt_supported)(const u32 pixformat); }; struct at91_camera_caps { @@ -229,8 +230,7 @@ static void configure_geometry(struct atmel_isi *isi, u32 width, return; } -static bool is_supported(struct soc_camera_device *icd, - const u32 pixformat) +static bool isi_fmt_supported(const u32 pixformat) { switch (pixformat) { /* YUV, including grey */ @@ -791,6 +791,23 @@ static void isc_enable_clock(struct atmel_isi *isc) pm_runtime_put(isc->soc_host.v4l2_dev.dev); } +static bool isc_fmt_supported(const u32 pixformat) +{ + switch (pixformat) { + /* YUV, including grey */ + case V4L2_PIX_FMT_GREY: + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + case V4L2_PIX_FMT_VYUY: + /* Bayer RGB */ + case V4L2_PIX_FMT_SBGGR8: + return true; + default: + return false; + } +} + /* ------------------------------------------------------------------ SOC camera operations for the device ------------------------------------------------------------------*/ @@ -815,6 +832,8 @@ static int try_or_set_fmt(struct soc_camera_device *icd, struct v4l2_format *f, struct v4l2_subdev_format *format) { + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + struct atmel_isi *isi = ici->priv; struct v4l2_pix_format *pix = &f->fmt.pix; const struct soc_camera_format_xlate *xlate; struct v4l2_subdev_pad_config pad_cfg; @@ -824,7 +843,7 @@ static int try_or_set_fmt(struct soc_camera_device *icd, int ret; /* check with atmel-isi support format, if not support use YUYV */ - if (!is_supported(icd, pix->pixelformat)) + if (!(*isi->hw_ops->host_fmt_supported)(pix->pixelformat)) pix->pixelformat = V4L2_PIX_FMT_YUYV; xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat); @@ -1384,6 +1403,7 @@ static struct at91_camera_caps at91sam9g45_caps = { .interrupt = isi_interrupt, .init_dma_desc = isi_hw_init_dma_desc, .hw_enable_interrupt = isi_hw_enable_interrupt, + .host_fmt_supported = isi_fmt_supported, }, .yuv_support_formats = { @@ -1416,6 +1436,7 @@ static struct at91_camera_caps sama5d2_caps = { .init_dma_desc = isc_hw_init_dma_desc, .interrupt = isc_interrupt, .hw_enable_interrupt = isc_hw_enable_interrupt, + .host_fmt_supported = isc_fmt_supported, .hw_set_clock = isc_hw_set_clock, }, From eaa1a98cb2329d071729f2e91425b4ec54350041 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Wed, 4 Nov 2015 17:29:52 +0100 Subject: [PATCH 318/381] ARM: at91/dt: sama5d2 Xplained PDA4: remvoe mmc-ddr-1_8v for now Remove this sdmmc property for the sama5d2 Xplained PDA4 board as it seems disturb the on-board eMMC. Even if it should be present, we experience a lot of timeouts with this option set. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index fb22ca674585ee..24bb15ca81420c 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -108,7 +108,6 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc0_default>; non-removable; - mmc-ddr-1_8v; status = "okay"; }; From 6222ca2673ddc5db4609dd7e99bfb347ad92c373 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 6 Aug 2015 18:16:46 +0800 Subject: [PATCH 319/381] watchdog: add a driver to support SAMA5D4 watchdog timer From SAMA5D4, the watchdog timer is upgrated with a new feature, which is describled as in the datasheet, "WDT_MR can be written until a LOCKMR command is issued in WDT_CR". That is to say, as long as the bootstrap and u-boot don't issue a LOCKMR command, WDT_MR can be written more than once in the driver. So the SAMA5D4 watchdog driver's implementation is different from the at91sam9260 watchdog driver implemented in file at91sam9_wdt.c. The user application open the device file to enable the watchdog timer hardware, and close to disable it, and set the watchdog timer timeout by seting WDV and WDD fields of WDT_MR register, and ping the watchdog by issuing WDRSTT command to WDT_CR register with hard-coded key. Signed-off-by: Wenyou Yang Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 9 + drivers/watchdog/Makefile | 1 + drivers/watchdog/at91sam9_wdt.h | 2 + drivers/watchdog/sama5d4_wdt.c | 280 ++++++++++++++++++++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 drivers/watchdog/sama5d4_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e5e7c5505de7dc..47ad39a62deed5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -167,6 +167,15 @@ config AT91SAM9X_WATCHDOG Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will reboot your system when the timeout is reached. +config SAMA5D4_WATCHDOG + tristate "Atmel SAMA5D4 Watchdog Timer" + depends on ARCH_AT91 + select WATCHDOG_CORE + help + Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. + Its Watchdog Timer Mode Register can be written more than once. + This will reboot your system when the timeout is reached. + config CADENCE_WATCHDOG tristate "Cadence Watchdog Timer" select WATCHDOG_CORE diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5c19294d1c3015..f24b8204731800 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o +obj-$(CONFIG_SAMA5D4_WATCHDOG) += sama5d4_wdt.o obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o diff --git a/drivers/watchdog/at91sam9_wdt.h b/drivers/watchdog/at91sam9_wdt.h index c6fbb2e6c41baa..b79a83b467cec8 100644 --- a/drivers/watchdog/at91sam9_wdt.h +++ b/drivers/watchdog/at91sam9_wdt.h @@ -22,11 +22,13 @@ #define AT91_WDT_MR 0x04 /* Watchdog Mode Register */ #define AT91_WDT_WDV (0xfff << 0) /* Counter Value */ +#define AT91_WDT_SET_WDV(x) ((x) & AT91_WDT_WDV) #define AT91_WDT_WDFIEN (1 << 12) /* Fault Interrupt Enable */ #define AT91_WDT_WDRSTEN (1 << 13) /* Reset Processor */ #define AT91_WDT_WDRPROC (1 << 14) /* Timer Restart */ #define AT91_WDT_WDDIS (1 << 15) /* Watchdog Disable */ #define AT91_WDT_WDD (0xfff << 16) /* Delta Value */ +#define AT91_WDT_SET_WDD(x) (((x) << 16) & AT91_WDT_WDD) #define AT91_WDT_WDDBGHLT (1 << 28) /* Debug Halt */ #define AT91_WDT_WDIDLEHLT (1 << 29) /* Idle Halt */ diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c new file mode 100644 index 00000000000000..a49634cdc1ccbc --- /dev/null +++ b/drivers/watchdog/sama5d4_wdt.c @@ -0,0 +1,280 @@ +/* + * Driver for Atmel SAMA5D4 Watchdog Timer + * + * Copyright (C) 2015 Atmel Corporation + * + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "at91sam9_wdt.h" + +/* minimum and maximum watchdog timeout, in seconds */ +#define MIN_WDT_TIMEOUT 1 +#define MAX_WDT_TIMEOUT 16 +#define WDT_DEFAULT_TIMEOUT MAX_WDT_TIMEOUT + +#define WDT_SEC2TICKS(s) ((s) ? (((s) << 8) - 1) : 0) + +struct sama5d4_wdt { + struct watchdog_device wdd; + void __iomem *reg_base; + u32 config; +}; + +static int wdt_timeout = WDT_DEFAULT_TIMEOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; + +module_param(wdt_timeout, int, 0); +MODULE_PARM_DESC(wdt_timeout, + "Watchdog timeout in seconds. (default = " + __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); + +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +#define wdt_read(wdt, field) \ + readl_relaxed((wdt)->reg_base + (field)) + +#define wdt_write(wtd, field, val) \ + writel_relaxed((val), (wdt)->reg_base + (field)) + +static int sama5d4_wdt_start(struct watchdog_device *wdd) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + u32 reg; + + reg = wdt_read(wdt, AT91_WDT_MR); + reg &= ~AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, reg); + + return 0; +} + +static int sama5d4_wdt_stop(struct watchdog_device *wdd) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + u32 reg; + + reg = wdt_read(wdt, AT91_WDT_MR); + reg |= AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, reg); + + return 0; +} + +static int sama5d4_wdt_ping(struct watchdog_device *wdd) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + + wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); + + return 0; +} + +static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + u32 value = WDT_SEC2TICKS(timeout); + u32 reg; + + reg = wdt_read(wdt, AT91_WDT_MR); + reg &= ~AT91_WDT_WDV; + reg &= ~AT91_WDT_WDD; + reg |= AT91_WDT_SET_WDV(value); + reg |= AT91_WDT_SET_WDD(value); + wdt_write(wdt, AT91_WDT_MR, reg); + + wdd->timeout = timeout; + + return 0; +} + +static const struct watchdog_info sama5d4_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, + .identity = "Atmel SAMA5D4 Watchdog", +}; + +static struct watchdog_ops sama5d4_wdt_ops = { + .owner = THIS_MODULE, + .start = sama5d4_wdt_start, + .stop = sama5d4_wdt_stop, + .ping = sama5d4_wdt_ping, + .set_timeout = sama5d4_wdt_set_timeout, +}; + +static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id) +{ + struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id); + + if (wdt_read(wdt, AT91_WDT_SR)) { + pr_crit("Atmel Watchdog Software Reset\n"); + emergency_restart(); + pr_crit("Reboot didn't succeed\n"); + } + + return IRQ_HANDLED; +} + +static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) +{ + const char *tmp; + + wdt->config = AT91_WDT_WDDIS; + + if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && + !strcmp(tmp, "software")) + wdt->config |= AT91_WDT_WDFIEN; + else + wdt->config |= AT91_WDT_WDRSTEN; + + if (of_property_read_bool(np, "atmel,idle-halt")) + wdt->config |= AT91_WDT_WDIDLEHLT; + + if (of_property_read_bool(np, "atmel,dbg-halt")) + wdt->config |= AT91_WDT_WDDBGHLT; + + return 0; +} + +static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) +{ + struct watchdog_device *wdd = &wdt->wdd; + u32 value = WDT_SEC2TICKS(wdd->timeout); + u32 reg; + + /* + * Because the fields WDV and WDD must not be modified when the WDDIS + * bit is set, so clear the WDDIS bit before writing the WDT_MR. + */ + reg = wdt_read(wdt, AT91_WDT_MR); + reg &= ~AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, reg); + + reg = wdt->config; + reg |= AT91_WDT_SET_WDD(value); + reg |= AT91_WDT_SET_WDV(value); + + wdt_write(wdt, AT91_WDT_MR, reg); + + return 0; +} + +static int sama5d4_wdt_probe(struct platform_device *pdev) +{ + struct watchdog_device *wdd; + struct sama5d4_wdt *wdt; + struct resource *res; + void __iomem *regs; + u32 irq = 0; + int ret; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdd = &wdt->wdd; + wdd->timeout = wdt_timeout; + wdd->info = &sama5d4_wdt_info; + wdd->ops = &sama5d4_wdt_ops; + wdd->min_timeout = MIN_WDT_TIMEOUT; + wdd->max_timeout = MAX_WDT_TIMEOUT; + + watchdog_set_drvdata(wdd, wdt); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + wdt->reg_base = regs; + + if (pdev->dev.of_node) { + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + dev_warn(&pdev->dev, "failed to get IRQ from DT\n"); + + ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt); + if (ret) + return ret; + } + + if ((wdt->config & AT91_WDT_WDFIEN) && irq) { + ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, + IRQF_SHARED | IRQF_IRQPOLL | + IRQF_NO_SUSPEND, pdev->name, pdev); + if (ret) { + dev_err(&pdev->dev, + "cannot register interrupt handler\n"); + return ret; + } + } + + ret = watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "unable to set timeout value\n"); + return ret; + } + + ret = sama5d4_wdt_init(wdt); + if (ret) + return ret; + + watchdog_set_nowayout(wdd, nowayout); + + ret = watchdog_register_device(wdd); + if (ret) { + dev_err(&pdev->dev, "failed to register watchdog device\n"); + return ret; + } + + platform_set_drvdata(pdev, wdt); + + dev_info(&pdev->dev, "initialized (timeout = %d sec, nowayout = %d)\n", + wdt_timeout, nowayout); + + return 0; +} + +static int sama5d4_wdt_remove(struct platform_device *pdev) +{ + struct sama5d4_wdt *wdt = platform_get_drvdata(pdev); + + sama5d4_wdt_stop(&wdt->wdd); + + watchdog_unregister_device(&wdt->wdd); + + return 0; +} + +static const struct of_device_id sama5d4_wdt_of_match[] = { + { .compatible = "atmel,sama5d4-wdt", }, + { } +}; +MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); + +static struct platform_driver sama5d4_wdt_driver = { + .probe = sama5d4_wdt_probe, + .remove = sama5d4_wdt_remove, + .driver = { + .name = "sama5d4_wdt", + .of_match_table = sama5d4_wdt_of_match, + } +}; +module_platform_driver(sama5d4_wdt_driver); + +MODULE_AUTHOR("Atmel Corporation"); +MODULE_DESCRIPTION("Atmel SAMA5D4 Watchdog Timer driver"); +MODULE_LICENSE("GPL v2"); From 15420ee6bb4aeccc8cff7e3d3bb06cd022c2cff5 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 6 Aug 2015 18:17:05 +0800 Subject: [PATCH 320/381] Documentation: dt: binding: atmel-sama5d4-wdt: for SAMA5D4 watchdog driver The compatible "atmel,sama5d4-wdt" supports the SAMA5D4 watchdog driver and the watchdog's WDT_MR register can be written more than once. Signed-off-by: Wenyou Yang Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/atmel-sama5d4-wdt.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt diff --git a/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt new file mode 100644 index 00000000000000..f7cc7c0609107d --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt @@ -0,0 +1,35 @@ +* Atmel SAMA5D4 Watchdog Timer (WDT) Controller + +Required properties: +- compatible: "atmel,sama5d4-wdt" +- reg: base physical address and length of memory mapped region. + +Optional properties: +- timeout-sec: watchdog timeout value (in seconds). +- interrupts: interrupt number to the CPU. +- atmel,watchdog-type: should be "hardware" or "software". + "hardware": enable watchdog fault reset. A watchdog fault triggers + watchdog reset. + "software": enable watchdog fault interrupt. A watchdog fault asserts + watchdog interrupt. +- atmel,idle-halt: present if you want to stop the watchdog when the CPU is + in idle state. + CAUTION: This property should be used with care, it actually makes the + watchdog not counting when the CPU is in idle state, therefore the + watchdog reset time depends on mean CPU usage and will not reset at all + if the CPU stop working while it is in idle state, which is probably + not what you want. +- atmel,dbg-halt: present if you want to stop the watchdog when the CPU is + in debug state. + +Example: + watchdog@fc068640 { + compatible = "atmel,sama5d4-wdt"; + reg = <0xfc068640 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; + timeout-sec = <10>; + atmel,watchdog-type = "hardware"; + atmel,dbg-halt; + atmel,idle-halt; + status = "okay"; + }; From d089867ff858ae1b2e375e539620e9301ca61f1a Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 5 Nov 2015 13:47:10 +0800 Subject: [PATCH 321/381] ARM: at91/dt: sama5d2: change watchdog compatible Change the watchdog compatible to "atmel,sama5d4-wdt" to support SAMA5D4 watchdog driver. Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/sama5d2.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index fe6a78d6510902..eb6c739ade56ab 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1016,7 +1016,7 @@ }; watchdog@f8048040 { - compatible = "atmel,at91sam9260-wdt"; + compatible = "atmel,sama5d4-wdt"; reg = <0xf8048040 0x10>; interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>; status = "disabled"; From b397f362a856528bc8d7b8eb6aed01c9f7dca999 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 5 Nov 2015 14:05:30 +0800 Subject: [PATCH 322/381] ARM: at91/dt: sama5d4: change watchdog compatible Change the watchdog compatible to "atmel,sama5d4-wdt" to support SAMA5D4 watchdog driver. Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/sama5d4.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/sama5d4.dtsi b/arch/arm/boot/dts/sama5d4.dtsi index 9760a7549f9014..c81bd32998988e 100644 --- a/arch/arm/boot/dts/sama5d4.dtsi +++ b/arch/arm/boot/dts/sama5d4.dtsi @@ -1287,7 +1287,7 @@ }; watchdog@fc068640 { - compatible = "atmel,at91sam9260-wdt"; + compatible = "atmel,sama5d4-wdt"; reg = <0xfc068640 0x10>; clocks = <&clk32k>; status = "disabled"; From 1e682f1e50c9f26c13e71237ce56a46c52448a7a Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 5 Nov 2015 14:23:15 +0800 Subject: [PATCH 323/381] ARM: at91/sama5_defconfig: support SAMA5D4 watchdog Enable CONFIG_SAMA5D4_WATCHDOG to support SAMA5D4 watchdog driver. Signed-off-by: Wenyou Yang --- arch/arm/configs/sama5_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 7bb7bfa0b0c1df..2b8496eb5b82ee 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -143,6 +143,7 @@ CONFIG_POWER_RESET=y # CONFIG_HWMON is not set CONFIG_WATCHDOG=y CONFIG_AT91SAM9X_WATCHDOG=y +CONFIG_SAMA5D4_WATCHDOG=y CONFIG_MFD_ATMEL_FLEXCOM=y CONFIG_MFD_ATMEL_HLCDC=y CONFIG_MFD_SYSCON=y From 1d9ee8ecaea7411f629363b0e2d4a25a2da86703 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Thu, 30 Jul 2015 17:17:19 +0800 Subject: [PATCH 324/381] ARM: at91: sama5d2/dt: add atmel isc node with pinctrl The sama5d2 use new compatible string: atmel,sama5d2-isc. Also it will use isc_clk for the isc peripheral clock. And the iscck is not used yet. Signed-off-by: Josh Wu Conflicts: arch/arm/boot/dts/at91-sama5d2_xplained.dts arch/arm/boot/dts/sama5d2.dtsi --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 37 +++++++++++++++++++++ arch/arm/boot/dts/sama5d2.dtsi | 13 ++++++++ 2 files changed, 50 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 5f94a2df7c778f..e736c5b6ab4908 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -118,6 +118,11 @@ }; apb { + isc: isc@f0008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>; + }; + qspi0: qspi@f0020000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_qspi0_default>; @@ -337,6 +342,38 @@ bias-disable; }; + pinctrl_isc_base: isc_base { + pinmux = , + , + , + ; + bias-disable; + }; + + pinctrl_isc_data_8bit: isc_data_8bit { + pinmux = , + , + , + , + , + , + , + ; + bias-disable; + }; + + pinctrl_isc_data_9_10: isc_data_9_10 { + pinmux = , + ; + bias-disable; + }; + + pinctrl_isc_data_11_12: isc_data_11_12 { + pinmux = , + ; + bias-disable; + }; + pinctrl_key_gpio_default: key_gpio_default { pinmux = ; bias-pull-up; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index eb6c739ade56ab..d649bb6dac8683 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -315,6 +315,19 @@ }; }; + isc: isc@f0008000 { + compatible = "atmel,sama5d2-isc"; + reg = <0xf0008000 0x4000>; + interrupts = <46 IRQ_TYPE_LEVEL_HIGH 5>; + clocks = <&isc_clk>, <&iscck>; + clock-names = "isi_clk", "iscck"; + status = "disabled"; + port { + #address-cells = <1>; + #size-cells = <0>; + }; + }; + ramc0: ramc@f000c000 { compatible = "atmel,sama5d3-ddramc"; reg = <0xf000c000 0x200>; From 4ffb410b4854d87fe3974d8ed3b1694c6821a8db Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 2 Nov 2015 11:39:09 +0800 Subject: [PATCH 325/381] ARM: at91: sama5d2/dt: add ov2640/ov7740 sensors and connect with ISC Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 56 +++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index e736c5b6ab4908..d42f63dafa8a70 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -121,6 +121,20 @@ isc: isc@f0008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>; + + port { + isc_0: endpoint@1 { + remote-endpoint = <&ov7740_0>; + bus-width = <8>; + vsync-active = <0>; + }; + + isc_1: endpoint@0 { + remote-endpoint = <&ov2640_0>; + bus-width = <8>; + vsync-active = <0>; + }; + }; }; qspi0: qspi@f0020000 { @@ -168,6 +182,38 @@ atmel,twd-hold-cycles = <25>; status = "okay"; + ov7740: camera@0x21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isc_0>; + bus-width = <8>; + }; + }; + }; + + ov2640: camera@0x30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isc_1>; + bus-width = <8>; + }; + }; + }; + pmic: act8865@5b { compatible = "active-semi,act8865"; reg = <0x5b>; @@ -450,6 +496,16 @@ }; }; + pinctrl_sensor_power: sensor_power { + pinmux = ; + bias-disable; + }; + + pinctrl_sensor_reset: sensor_reset { + pinmux = ; + bias-disable; + }; + pinctrl_spi0_default: spi0_default { pinmux = , , From b67ac25dfb71d1c9943b7140d98bfe5d3547b12e Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 27 Oct 2015 16:40:08 +0800 Subject: [PATCH 326/381] ARM: at91: sama5d2/dt: enable isc node on sama5d2_xplained board Meantime disabled uart3 since the PB12 conflict with sensor's power down pin. Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index d42f63dafa8a70..32a8a365595521 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -121,6 +121,7 @@ isc: isc@f0008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>; + status = "okay"; port { isc_0: endpoint@1 { @@ -310,7 +311,7 @@ uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; - status = "okay"; + status = "disabled"; /* conflict with sensor power down pin: PB12 */ }; flx4: flexcom@fc018000 { From 465a4cd7e3b5b9eeb936637bb8b1b48c04e42f74 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 30 Oct 2015 17:26:49 +0800 Subject: [PATCH 327/381] ARM: at91: sama5d2/dt: move sensor node to i2c1 as hardware changed In the latest sama5d2_xplained board, the sensor node is connect to i2c1 instead of i2c0. So move the dt node to adapt to such changes. Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 64 ++++++++++----------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 32a8a365595521..9e60c2ba066823 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -183,38 +183,6 @@ atmel,twd-hold-cycles = <25>; status = "okay"; - ov7740: camera@0x21 { - compatible = "ovti,ov7740"; - reg = <0x21>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; - resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; - pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; - - port { - ov7740_0: endpoint { - remote-endpoint = <&isc_0>; - bus-width = <8>; - }; - }; - }; - - ov2640: camera@0x30 { - compatible = "ovti,ov2640"; - reg = <0x30>; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; - resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; - pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; - - port { - ov2640_0: endpoint { - remote-endpoint = <&isc_1>; - bus-width = <8>; - }; - }; - }; - pmic: act8865@5b { compatible = "active-semi,act8865"; reg = <0x5b>; @@ -340,6 +308,38 @@ pinctrl-0 = <&pinctrl_i2c1_default>; status = "okay"; + ov7740: camera@0x21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isc_0>; + bus-width = <8>; + }; + }; + }; + + ov2640: camera@0x30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isc_1>; + bus-width = <8>; + }; + }; + }; + at24@54 { compatible = "atmel,24c02"; reg = <0x54>; From 5bae23fab2432d87c26c88704f738f2966989666 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 4 Nov 2015 20:11:37 +0800 Subject: [PATCH 328/381] ARM: at91: sama5d2/dts: add isc dt node in pda4.dts Signed-off-by: Josh Wu --- .../boot/dts/at91-sama5d2_xplained_pda4.dts | 104 ++++++++++++++++-- 1 file changed, 94 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index 24bb15ca81420c..48cc7990031ee3 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -119,6 +119,26 @@ }; apb { + isc: isc@f0008000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_isc_base &pinctrl_isc_data_8bit &pinctrl_isc_data_9_10 &pinctrl_isc_data_11_12>; + status = "okay"; + + port { + isc_0: endpoint@1 { + remote-endpoint = <&ov7740_0>; + bus-width = <8>; + vsync-active = <0>; + }; + + isc_1: endpoint@0 { + remote-endpoint = <&ov2640_0>; + bus-width = <8>; + vsync-active = <0>; + }; + }; + }; + qspi0: qspi@f0020000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_qspi0_default>; @@ -289,6 +309,38 @@ pinctrl-0 = <&pinctrl_i2c1_default>; status = "okay"; + ov7740: camera@0x21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isc_0>; + bus-width = <8>; + }; + }; + }; + + ov2640: camera@0x30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioA 43 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isc_1>; + bus-width = <8>; + }; + }; + }; + at24@54 { compatible = "atmel,24c02"; reg = <0x54>; @@ -338,6 +390,38 @@ bias-disable; }; + pinctrl_isc_base: isc_base { + pinmux = , + , + , + ; + bias-disable; + }; + + pinctrl_isc_data_8bit: isc_data_8bit { + pinmux = , + , + , + , + , + , + , + ; + bias-disable; + }; + + pinctrl_isc_data_9_10: isc_data_9_10 { + pinmux = , + ; + bias-disable; + }; + + pinctrl_isc_data_11_12: isc_data_11_12 { + pinmux = , + ; + bias-disable; + }; + pinctrl_key_gpio_default: key_gpio_default { pinmux = ; bias-pull-up; @@ -373,16 +457,6 @@ ; }; - pinctrl_sensor_power: sensor_power { - pinmux = ; - bias-disable; - }; - - pinctrl_sensor_reset: sensor_reset { - pinmux = ; - bias-disable; - }; - pinctrl_sdmmc0_default: sdmmc0_default { cmd_data { pinmux = , @@ -423,6 +497,16 @@ }; }; + pinctrl_sensor_power: sensor_power { + pinmux = ; + bias-disable; + }; + + pinctrl_sensor_reset: sensor_reset { + pinmux = ; + bias-disable; + }; + pinctrl_spi0_default: spi0_default { pinmux = , , From 5e4dbd58f20d538ef0e34402751ca82dfc4a4b3c Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Mon, 26 Oct 2015 18:20:02 +0800 Subject: [PATCH 329/381] ARM: at91: sama5d2_defconfig: add nfs rootfs support enable network setting for nfs rootfs mount. Signed-off-by: Josh Wu --- arch/arm/configs/sama5d2_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index f06f3b55b70737..22a272bf13928c 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -37,6 +37,8 @@ CONFIG_PACKET=y CONFIG_UNIX=y CONFIG_INET=y CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set From 27f727ae0ea97367d2c9e91eca95ea5ef9d1adf3 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 28 Oct 2015 15:37:18 +0800 Subject: [PATCH 330/381] ARM: at91: sama5d2_defconfig: enable CONFIG_SUSPEND to enable PM support atmel-isi use runtime PM to manage the peripheral clock. Without CONFIG_PM, atmel-isi driver will not work. Signed-off-by: Josh Wu --- arch/arm/configs/sama5d2_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index 22a272bf13928c..834813b04564dc 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -31,7 +31,6 @@ CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -# CONFIG_SUSPEND is not set CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y From 78d3e5fe15aaa3e022003c5f8711dd65acdf2efc Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 29 Jan 2014 09:58:06 +0800 Subject: [PATCH 331/381] media: ov7740: ov7740 support vga now by modifying base on ov2640 driver Remove IDENT_OV7740 relevant code, as now it's not used. Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 657 ++++++++++++++++++++++++++ 1 file changed, 657 insertions(+) create mode 100644 drivers/media/i2c/soc_camera/ov7740.c diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c new file mode 100644 index 00000000000000..b3a24674fb887a --- /dev/null +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -0,0 +1,657 @@ +/* + * ov7740 Camera Driver + * + * Copyright (C) 2013 Josh Wu + * + * Based on ov2640, ov772x, ov9640 drivers and previous non merged implementations. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define VAL_SET(x, mask, rshift, lshift) \ + ((((x) >> rshift) & mask) << lshift) + +#define REG0C 0x0C /* Register 0C */ +#define REG0C_HFLIP_IMG 0x40 /* Horizontal mirror image ON/OFF */ +#define REG0C_VFLIP_IMG 0x80 /* Vertical flip image ON/OFF */ + +/* + * ID + */ +#define PID 0x0A /* Product ID Number MSB */ +#define VER 0x0B /* Product ID Number LSB */ +#define MIDH 0x1C /* Manufacturer ID byte - high */ +#define MIDL 0x1D /* Manufacturer ID byte - low */ + +#define PID_OV7740 0x7742 +#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF)) + +/* + * Struct + */ +struct regval_list { + u8 reg_num; + u8 value; +}; + +/* Supported resolutions */ +enum ov7740_width { + W_VGA = 640, +}; + +enum ov7740_height { + H_VGA = 480, +}; + +struct ov7740_win_size { + char *name; + enum ov7740_width width; + enum ov7740_height height; + const struct regval_list *regs; +}; + + +struct ov7740_priv { + struct v4l2_subdev subdev; + struct v4l2_ctrl_handler hdl; + enum v4l2_mbus_pixelcode cfmt_code; + const struct ov7740_win_size *win; +}; + +/* + * Registers settings + */ + +#define ENDMARKER { 0xff, 0xff } + +static const struct regval_list ov7740_init_regs[] = { + {0x55 ,0x40}, + {0x11 ,0x02}, + + {0x12 ,0x00}, + {0xd5 ,0x10}, + {0x0c ,0x12}, + {0x0d ,0x34}, + {0x17 ,0x25}, + {0x18 ,0xa0}, + {0x19 ,0x03}, + {0x1a ,0xf0}, + {0x1b ,0x89}, + {0x22 ,0x03}, + {0x29 ,0x18}, + {0x2b ,0xf8}, + {0x2c ,0x01}, + {0x31 ,0xa0}, + {0x32 ,0xf0}, + {0x33 ,0xc4}, + {0x35 ,0x05}, + {0x36 ,0x3f}, + {0x04 ,0x60}, + {0x27 ,0x80}, + {0x3d ,0x0f}, + {0x3e ,0x80}, + {0x3f ,0x40}, + {0x40 ,0x7f}, + {0x41 ,0x6a}, + {0x42 ,0x29}, + {0x44 ,0x22}, + {0x45 ,0x41}, + {0x47 ,0x02}, + {0x49 ,0x64}, + {0x4a ,0xa1}, + {0x4b ,0x40}, + {0x4c ,0x1a}, + {0x4d ,0x50}, + {0x4e ,0x13}, + {0x64 ,0x00}, + {0x67 ,0x88}, + {0x68 ,0x1a}, + + {0x14 ,0x28}, + {0x24 ,0x3c}, + {0x25 ,0x30}, + {0x26 ,0x72}, + {0x50 ,0x97}, + {0x51 ,0x1f}, + {0x52 ,0x00}, + {0x53 ,0x00}, + {0x20 ,0x00}, + {0x21 ,0xcf}, + {0x50, 0x4b}, + {0x38 ,0x14}, + {0xe9 ,0x00}, + {0x56 ,0x55}, + {0x57 ,0xff}, + {0x58 ,0xff}, + {0x59 ,0xff}, + {0x5f ,0x04}, + {0xec ,0x00}, + {0x13 ,0xff}, + + {0x80 ,0x7f}, + {0x81 ,0x3f}, + {0x82 ,0x32}, + {0x83 ,0x01}, + {0x38 ,0x11}, + {0x84 ,0x70}, + {0x85 ,0x00}, + {0x86 ,0x03}, + {0x87 ,0x01}, + {0x88 ,0x05}, + {0x89 ,0x30}, + {0x8d ,0x30}, + {0x8f ,0x85}, + {0x93 ,0x30}, + {0x95 ,0x85}, + {0x99 ,0x30}, + {0x9b ,0x85}, + + {0x9c ,0x08}, + {0x9d ,0x12}, + {0x9e ,0x23}, + {0x9f ,0x45}, + {0xa0 ,0x55}, + {0xa1 ,0x64}, + {0xa2 ,0x72}, + {0xa3 ,0x7f}, + {0xa4 ,0x8b}, + {0xa5 ,0x95}, + {0xa6 ,0xa7}, + {0xa7 ,0xb5}, + {0xa8 ,0xcb}, + {0xa9 ,0xdd}, + {0xaa ,0xec}, + {0xab ,0x1a}, + + {0xce ,0x78}, + {0xcf ,0x6e}, + {0xd0 ,0x0a}, + {0xd1 ,0x0c}, + {0xd2 ,0x84}, + {0xd3 ,0x90}, + {0xd4 ,0x1e}, + + {0x5a ,0x24}, + {0x5b ,0x1f}, + {0x5c ,0x88}, + {0x5d ,0x60}, + + {0xac ,0x6e}, + {0xbe ,0xff}, + {0xbf ,0x00}, + + {0x0f ,0x1d}, + {0x0f ,0x1f}, + ENDMARKER, +}; + +static const struct regval_list ov7740_vga_regs[] = { + /* Initial registers is for vga format, no setting needed */ + ENDMARKER, +}; + +#define OV7740_SIZE(n, w, h, r) \ + {.name = n, .width = w , .height = h, .regs = r } + +static const struct ov7740_win_size ov7740_supported_win_sizes[] = { + OV7740_SIZE("VGA", W_VGA, H_VGA, ov7740_vga_regs), +}; + +static enum v4l2_mbus_pixelcode ov7740_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8, +}; + +/* + * General functions + */ +static struct ov7740_priv *to_ov7740(const struct i2c_client *client) +{ + return container_of(i2c_get_clientdata(client), struct ov7740_priv, + subdev); +} + +static int ov7740_write_array(struct i2c_client *client, + const struct regval_list *vals) +{ + int ret; + + while ((vals->reg_num != 0xff) || (vals->value != 0xff)) { + ret = i2c_smbus_write_byte_data(client, + vals->reg_num, vals->value); + dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x", + vals->reg_num, vals->value); + + if (ret < 0) { + dev_err(&client->dev, "array: 0x%02x, 0x%02x write failed", + vals->reg_num, vals->value); + return ret; + } + vals++; + } + return 0; +} + +static int ov7740_mask_set(struct i2c_client *client, + u8 reg, u8 mask, u8 set) +{ + s32 val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) + return val; + + val &= ~mask; + val |= set & mask; + + dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val); + + return i2c_smbus_write_byte_data(client, reg, val); +} + +static int ov7740_reset(struct i2c_client *client) +{ + int ret; + const struct regval_list reset_seq[] = { + {0x12 ,0x80}, + ENDMARKER, + }; + + ret = ov7740_write_array(client, reset_seq); + if (ret) + goto err; + + msleep(5); +err: + dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret); + return ret; +} + +/* + * soc_camera_ops functions + */ +static int ov7740_s_stream(struct v4l2_subdev *sd, int enable) +{ + return 0; +} + +static int ov7740_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = + &container_of(ctrl->handler, struct ov7740_priv, hdl)->subdev; + struct i2c_client *client = v4l2_get_subdevdata(sd); + u8 val; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + val = ctrl->val ? REG0C_VFLIP_IMG : 0x00; + return ov7740_mask_set(client, REG0C, REG0C_VFLIP_IMG, val); + case V4L2_CID_HFLIP: + val = ctrl->val ? REG0C_HFLIP_IMG : 0x00; + return ov7740_mask_set(client, REG0C, REG0C_HFLIP_IMG, val); + } + + return -EINVAL; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int ov7740_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + reg->size = 1; + if (reg->reg > 0xff) + return -EINVAL; + + ret = i2c_smbus_read_byte_data(client, reg->reg); + if (ret < 0) + return ret; + + reg->val = ret; + + return 0; +} + +static int ov7740_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + if (reg->reg > 0xff || + reg->val > 0xff) + return -EINVAL; + + return i2c_smbus_write_byte_data(client, reg->reg, reg->val); +} +#endif + +static int ov7740_s_power(struct v4l2_subdev *sd, int on) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + + return soc_camera_set_power(&client->dev, ssdd, on); +} + +/* Select the nearest higher resolution for capture */ +static const struct ov7740_win_size *ov7740_select_win(u32 *width, u32 *height) +{ + int i, default_size = ARRAY_SIZE(ov7740_supported_win_sizes) - 1; + + for (i = 0; i < ARRAY_SIZE(ov7740_supported_win_sizes); i++) { + if (ov7740_supported_win_sizes[i].width >= *width && + ov7740_supported_win_sizes[i].height >= *height) { + *width = ov7740_supported_win_sizes[i].width; + *height = ov7740_supported_win_sizes[i].height; + return &ov7740_supported_win_sizes[i]; + } + } + + *width = ov7740_supported_win_sizes[default_size].width; + *height = ov7740_supported_win_sizes[default_size].height; + return &ov7740_supported_win_sizes[default_size]; +} + +static int ov7740_set_params(struct i2c_client *client, u32 *width, u32 *height, + enum v4l2_mbus_pixelcode code) +{ + struct ov7740_priv *priv = to_ov7740(client); + int ret; + + /* select win */ + priv->win = ov7740_select_win(width, height); + + /* select format */ + priv->cfmt_code = 0; + switch (code) { + default: + case V4L2_MBUS_FMT_YUYV8_2X8: + dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); + } + + /* reset hardware */ + ov7740_reset(client); + + /* initialize the sensor with default data */ + dev_dbg(&client->dev, "%s: Init default", __func__); + ret = ov7740_write_array(client, ov7740_init_regs); + if (ret < 0) + goto err; + + priv->cfmt_code = code; + *width = priv->win->width; + *height = priv->win->height; + + return 0; + +err: + dev_err(&client->dev, "%s: Error %d", __func__, ret); + ov7740_reset(client); + priv->win = NULL; + + return ret; +} + +static int ov7740_g_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct ov7740_priv *priv = to_ov7740(client); + + if (!priv->win) { + u32 width = W_VGA, height = H_VGA; + priv->win = ov7740_select_win(&width, &height); + priv->cfmt_code = V4L2_MBUS_FMT_YUYV8_2X8; + } + + mf->width = priv->win->width; + mf->height = priv->win->height; + mf->code = priv->cfmt_code; + + switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + mf->colorspace = V4L2_COLORSPACE_SRGB; + break; + default: + case V4L2_MBUS_FMT_YUYV8_2X8: + case V4L2_MBUS_FMT_UYVY8_2X8: + mf->colorspace = V4L2_COLORSPACE_JPEG; + } + mf->field = V4L2_FIELD_NONE; + + return 0; +} + +static int ov7740_s_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + + switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + mf->colorspace = V4L2_COLORSPACE_SRGB; + break; + default: + mf->code = V4L2_MBUS_FMT_YUYV8_2X8; + case V4L2_MBUS_FMT_YUYV8_2X8: + case V4L2_MBUS_FMT_UYVY8_2X8: + mf->colorspace = V4L2_COLORSPACE_JPEG; + } + + ret = ov7740_set_params(client, &mf->width, &mf->height, mf->code); + + return ret; +} + +static int ov7740_try_fmt(struct v4l2_subdev *sd, + struct v4l2_mbus_framefmt *mf) +{ + /* + * select suitable win, but don't store it + */ + ov7740_select_win(&mf->width, &mf->height); + + mf->field = V4L2_FIELD_NONE; + + switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: + case V4L2_MBUS_FMT_RGB565_2X8_LE: + mf->colorspace = V4L2_COLORSPACE_SRGB; + break; + default: + mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + case V4L2_MBUS_FMT_YUYV8_2X8: + case V4L2_MBUS_FMT_UYVY8_2X8: + mf->colorspace = V4L2_COLORSPACE_JPEG; + } + + return 0; +} + +static int ov7740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, + enum v4l2_mbus_pixelcode *code) +{ + if (index >= ARRAY_SIZE(ov7740_codes)) + return -EINVAL; + + *code = ov7740_codes[index]; + return 0; +} + +static int ov7740_video_probe(struct i2c_client *client) +{ + struct ov7740_priv *priv = to_ov7740(client); + u8 pid, ver, midh, midl; + const char *devname; + int ret; + + ret = ov7740_s_power(&priv->subdev, 1); + if (ret < 0) + return ret; + + /* + * check and show product ID and manufacturer ID + */ + pid = i2c_smbus_read_byte_data(client, PID); + ver = i2c_smbus_read_byte_data(client, VER); + midh = i2c_smbus_read_byte_data(client, MIDH); + midl = i2c_smbus_read_byte_data(client, MIDL); + + switch (VERSION(pid, ver)) { + case PID_OV7740: + devname = "ov7740"; + break; + default: + dev_err(&client->dev, + "Product ID error %x:%x\n", pid, ver); + ret = -ENODEV; + goto done; + } + + dev_info(&client->dev, + "%s Product ID %0x:%0x Manufacturer ID %x:%x\n", + devname, pid, ver, midh, midl); + + ret = v4l2_ctrl_handler_setup(&priv->hdl); + +done: + ov7740_s_power(&priv->subdev, 0); + return ret; +} + +static const struct v4l2_ctrl_ops ov7740_ctrl_ops = { + .s_ctrl = ov7740_s_ctrl, +}; + +static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = { +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = ov7740_g_register, + .s_register = ov7740_s_register, +#endif + .s_power = ov7740_s_power, +}; + +static int ov7740_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + + cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | + V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_DATA_ACTIVE_HIGH; + cfg->type = V4L2_MBUS_PARALLEL; + cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); + + return 0; +} + +static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { + .s_stream = ov7740_s_stream, + .g_mbus_fmt = ov7740_g_fmt, + .s_mbus_fmt = ov7740_s_fmt, + .try_mbus_fmt = ov7740_try_fmt, + .enum_mbus_fmt = ov7740_enum_fmt, + .g_mbus_config = ov7740_g_mbus_config, +}; + +static struct v4l2_subdev_ops ov7740_subdev_ops = { + .core = &ov7740_subdev_core_ops, + .video = &ov7740_subdev_video_ops, +}; + +/* + * i2c_driver functions + */ +static int ov7740_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct ov7740_priv *priv; + struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + int ret; + + if (!ssdd) { + dev_err(&adapter->dev, + "OV7740: Missing platform_data for driver\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_err(&adapter->dev, + "OV7740: I2C-Adapter doesn't support SMBUS\n"); + return -EIO; + } + + priv = devm_kzalloc(&client->dev, sizeof(struct ov7740_priv), GFP_KERNEL); + if (!priv) { + dev_err(&adapter->dev, + "Failed to allocate memory for private data!\n"); + return -ENOMEM; + } + + v4l2_i2c_subdev_init(&priv->subdev, client, &ov7740_subdev_ops); + v4l2_ctrl_handler_init(&priv->hdl, 2); + v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + priv->subdev.ctrl_handler = &priv->hdl; + if (priv->hdl.error) + return priv->hdl.error; + + ret = ov7740_video_probe(client); + if (ret) + v4l2_ctrl_handler_free(&priv->hdl); + else + dev_info(&adapter->dev, "OV7740 Probed\n"); + + return ret; +} + +static int ov7740_remove(struct i2c_client *client) +{ + struct ov7740_priv *priv = to_ov7740(client); + + v4l2_device_unregister_subdev(&priv->subdev); + v4l2_ctrl_handler_free(&priv->hdl); + return 0; +} + +static const struct i2c_device_id ov7740_id[] = { + { "ov7740", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ov7740_id); + +static struct i2c_driver ov7740_i2c_driver = { + .driver = { + .name = "ov7740", + }, + .probe = ov7740_probe, + .remove = ov7740_remove, + .id_table = ov7740_id, +}; + +module_i2c_driver(ov7740_i2c_driver); + +MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 7740 sensor"); +MODULE_AUTHOR("Josh Wu"); +MODULE_LICENSE("GPL v2"); From 99141d0049daa6cce706bf75dcde140736f43cc0 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Wed, 29 Jan 2014 11:50:17 +0800 Subject: [PATCH 332/381] media: ov7740: add ov7740 in menuconfig Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/Kconfig | 6 ++++++ drivers/media/i2c/soc_camera/Makefile | 1 + 2 files changed, 7 insertions(+) diff --git a/drivers/media/i2c/soc_camera/Kconfig b/drivers/media/i2c/soc_camera/Kconfig index 23d352f0adf0af..81de22b0627f98 100644 --- a/drivers/media/i2c/soc_camera/Kconfig +++ b/drivers/media/i2c/soc_camera/Kconfig @@ -74,6 +74,12 @@ config SOC_CAMERA_OV9740 help This is a ov9740 camera driver +config SOC_CAMERA_OV7740 + tristate "ov7740 camera support" + depends on SOC_CAMERA && I2C + help + This is a ov7740 camera driver + config SOC_CAMERA_RJ54N1 tristate "rj54n1cb0c support" depends on SOC_CAMERA && I2C diff --git a/drivers/media/i2c/soc_camera/Makefile b/drivers/media/i2c/soc_camera/Makefile index d0421feaa79611..57d67ff6c3f73d 100644 --- a/drivers/media/i2c/soc_camera/Makefile +++ b/drivers/media/i2c/soc_camera/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o +obj-$(CONFIG_SOC_CAMERA_OV7740) += ov7740.o obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o From 042323b748285c3fc5b383885b01a168453cb7b4 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 13 Jan 2015 14:44:06 +0800 Subject: [PATCH 333/381] media: ov7740: switch I2C subdevice drivers to use v4l2-clk, add async probe Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 32 ++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index b3a24674fb887a..6d9a0dd6456a70 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -69,6 +70,7 @@ struct ov7740_priv { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; enum v4l2_mbus_pixelcode cfmt_code; + struct v4l2_clk *clk; const struct ov7740_win_size *win; }; @@ -342,8 +344,9 @@ static int ov7740_s_power(struct v4l2_subdev *sd, int on) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); + struct ov7740_priv *priv = to_ov7740(client); - return soc_camera_set_power(&client->dev, ssdd, on); + return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); } /* Select the nearest higher resolution for capture */ @@ -607,6 +610,10 @@ static int ov7740_probe(struct i2c_client *client, return -ENOMEM; } + priv->clk = v4l2_clk_get(&client->dev, "mclk"); + if (IS_ERR(priv->clk)) + return -EPROBE_DEFER; + v4l2_i2c_subdev_init(&priv->subdev, client, &ov7740_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, @@ -614,15 +621,26 @@ static int ov7740_probe(struct i2c_client *client, v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) - return priv->hdl.error; + if (priv->hdl.error) { + ret = priv->hdl.error; + goto err_clk; + } ret = ov7740_video_probe(client); if (ret) - v4l2_ctrl_handler_free(&priv->hdl); - else - dev_info(&adapter->dev, "OV7740 Probed\n"); + goto err_handler; + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret < 0) + goto err_handler; + + dev_info(&adapter->dev, "OV7740 Probed\n"); + return 0; +err_handler: + v4l2_ctrl_handler_free(&priv->hdl); +err_clk: + v4l2_clk_put(priv->clk); return ret; } @@ -630,6 +648,8 @@ static int ov7740_remove(struct i2c_client *client) { struct ov7740_priv *priv = to_ov7740(client); + v4l2_async_unregister_subdev(&priv->subdev); + v4l2_clk_put(priv->clk); v4l2_device_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; From 0f052f706056923a0ac1abe246883ede7bbb4a71 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 13 Jan 2015 14:55:08 +0800 Subject: [PATCH 334/381] media: ov7740: Make use of media_bus_format enum Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 42 +++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index 6d9a0dd6456a70..01e4684a6f20a3 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -69,7 +69,7 @@ struct ov7740_win_size { struct ov7740_priv { struct v4l2_subdev subdev; struct v4l2_ctrl_handler hdl; - enum v4l2_mbus_pixelcode cfmt_code; + u32 cfmt_code; struct v4l2_clk *clk; const struct ov7740_win_size *win; }; @@ -213,8 +213,8 @@ static const struct ov7740_win_size ov7740_supported_win_sizes[] = { OV7740_SIZE("VGA", W_VGA, H_VGA, ov7740_vga_regs), }; -static enum v4l2_mbus_pixelcode ov7740_codes[] = { - V4L2_MBUS_FMT_YUYV8_2X8, +static u32 ov7740_codes[] = { + MEDIA_BUS_FMT_YUYV8_2X8, }; /* @@ -369,7 +369,7 @@ static const struct ov7740_win_size *ov7740_select_win(u32 *width, u32 *height) } static int ov7740_set_params(struct i2c_client *client, u32 *width, u32 *height, - enum v4l2_mbus_pixelcode code) + u32 code) { struct ov7740_priv *priv = to_ov7740(client); int ret; @@ -381,7 +381,7 @@ static int ov7740_set_params(struct i2c_client *client, u32 *width, u32 *height, priv->cfmt_code = 0; switch (code) { default: - case V4L2_MBUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); } @@ -417,7 +417,7 @@ static int ov7740_g_fmt(struct v4l2_subdev *sd, if (!priv->win) { u32 width = W_VGA, height = H_VGA; priv->win = ov7740_select_win(&width, &height); - priv->cfmt_code = V4L2_MBUS_FMT_YUYV8_2X8; + priv->cfmt_code = MEDIA_BUS_FMT_YUYV8_2X8; } mf->width = priv->win->width; @@ -425,13 +425,13 @@ static int ov7740_g_fmt(struct v4l2_subdev *sd, mf->code = priv->cfmt_code; switch (mf->code) { - case V4L2_MBUS_FMT_RGB565_2X8_BE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_UYVY8_2X8: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } mf->field = V4L2_FIELD_NONE; @@ -447,14 +447,14 @@ static int ov7740_s_fmt(struct v4l2_subdev *sd, switch (mf->code) { - case V4L2_MBUS_FMT_RGB565_2X8_BE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: - mf->code = V4L2_MBUS_FMT_YUYV8_2X8; - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_UYVY8_2X8: + mf->code = MEDIA_BUS_FMT_YUYV8_2X8; + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } @@ -474,14 +474,14 @@ static int ov7740_try_fmt(struct v4l2_subdev *sd, mf->field = V4L2_FIELD_NONE; switch (mf->code) { - case V4L2_MBUS_FMT_RGB565_2X8_BE: - case V4L2_MBUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + case MEDIA_BUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: - mf->code = V4L2_MBUS_FMT_UYVY8_2X8; - case V4L2_MBUS_FMT_YUYV8_2X8: - case V4L2_MBUS_FMT_UYVY8_2X8: + mf->code = MEDIA_BUS_FMT_UYVY8_2X8; + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } @@ -489,7 +489,7 @@ static int ov7740_try_fmt(struct v4l2_subdev *sd, } static int ov7740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - enum v4l2_mbus_pixelcode *code) + u32 *code) { if (index >= ARRAY_SIZE(ov7740_codes)) return -EINVAL; From ee3d95a18289c764a1d12673e7c64ce990690973 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 13 Jan 2015 15:18:51 +0800 Subject: [PATCH 335/381] media: ov7740: add primary dt support Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 102 +++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 9 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index 01e4684a6f20a3..f1c542c56cf798 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -11,17 +11,19 @@ */ #include -#include +#include +#include #include +#include +#include #include -#include #include #include #include #include -#include #include +#include #define VAL_SET(x, mask, rshift, lshift) \ ((((x) >> rshift) & mask) << lshift) @@ -72,6 +74,10 @@ struct ov7740_priv { u32 cfmt_code; struct v4l2_clk *clk; const struct ov7740_win_size *win; + + struct soc_camera_subdev_desc ssdd_dt; + struct gpio_desc *resetb_gpio; + struct gpio_desc *pwdn_gpio; }; /* @@ -580,6 +586,70 @@ static struct v4l2_subdev_ops ov7740_subdev_ops = { .video = &ov7740_subdev_video_ops, }; +/* OF probe functions */ +static int ov7740_hw_power(struct device *dev, int on) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ov7740_priv *priv = to_ov7740(client); + + dev_dbg(&client->dev, "%s: %s the camera\n", + __func__, on ? "ENABLE" : "DISABLE"); + + if (priv->pwdn_gpio) + gpiod_direction_output(priv->pwdn_gpio, !on); + + /* We need wait for ~1ms, then access the SCCB */ + if (on) + usleep_range(1000, 2000); + + return 0; +} + +static int ov7740_hw_reset(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ov7740_priv *priv = to_ov7740(client); + + if (priv->resetb_gpio) { + /* Active the resetb pin to perform a reset pulse */ + gpiod_direction_output(priv->resetb_gpio, 1); + usleep_range(1000, 3000); + gpiod_direction_output(priv->resetb_gpio, 0); + } + + /* We need wait for ~20ms, then access the SCCB */ + usleep_range(20000, 21000); + + return 0; +} + +static int ov7740_probe_dt(struct i2c_client *client, + struct ov7740_priv *priv) +{ + /* Request the reset GPIO deasserted */ + priv->resetb_gpio = devm_gpiod_get_optional(&client->dev, "resetb", + GPIOD_OUT_LOW); + if (!priv->resetb_gpio) + dev_dbg(&client->dev, "resetb gpio is not assigned!\n"); + else if (IS_ERR(priv->resetb_gpio)) + return PTR_ERR(priv->resetb_gpio); + + /* Request the power down GPIO asserted */ + priv->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "pwdn", + GPIOD_OUT_HIGH); + if (!priv->pwdn_gpio) + dev_dbg(&client->dev, "pwdn gpio is not assigned!\n"); + else if (IS_ERR(priv->pwdn_gpio)) + return PTR_ERR(priv->pwdn_gpio); + + /* Initialize the soc_camera_subdev_desc */ + priv->ssdd_dt.power = ov7740_hw_power; + priv->ssdd_dt.reset = ov7740_hw_reset; + client->dev.platform_data = &priv->ssdd_dt; + + return 0; +} + /* * i2c_driver functions */ @@ -591,12 +661,6 @@ static int ov7740_probe(struct i2c_client *client, struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); int ret; - if (!ssdd) { - dev_err(&adapter->dev, - "OV7740: Missing platform_data for driver\n"); - return -EINVAL; - } - if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, "OV7740: I2C-Adapter doesn't support SMBUS\n"); @@ -614,6 +678,19 @@ static int ov7740_probe(struct i2c_client *client, if (IS_ERR(priv->clk)) return -EPROBE_DEFER; + if (!ssdd && !client->dev.of_node) { + dev_err(&adapter->dev, + "OV7740: Missing platform_data for driver\n"); + ret = -EINVAL; + goto err_clk; + } + + if (!ssdd) { + ret = ov7740_probe_dt(client, priv); + if (ret) + goto err_clk; + } + v4l2_i2c_subdev_init(&priv->subdev, client, &ov7740_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, @@ -661,9 +738,16 @@ static const struct i2c_device_id ov7740_id[] = { }; MODULE_DEVICE_TABLE(i2c, ov7740_id); +static const struct of_device_id ov7740_of_match[] = { + {.compatible = "ovti,ov7740", }, + {}, +}; +MODULE_DEVICE_TABLE(of, ov7740_of_match); + static struct i2c_driver ov7740_i2c_driver = { .driver = { .name = "ov7740", + .of_match_table = of_match_ptr(ov7740_of_match), }, .probe = ov7740_probe, .remove = ov7740_remove, From 0cd1f03671960be7a57f64253f546ae8d0f1a74b Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 13 Jan 2015 15:26:20 +0800 Subject: [PATCH 336/381] media: ov7740: add xvclk CCF support Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index f1c542c56cf798..e887c76293d9a1 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -73,6 +74,7 @@ struct ov7740_priv { struct v4l2_ctrl_handler hdl; u32 cfmt_code; struct v4l2_clk *clk; + struct clk *xvclk; const struct ov7740_win_size *win; struct soc_camera_subdev_desc ssdd_dt; @@ -352,6 +354,11 @@ static int ov7740_s_power(struct v4l2_subdev *sd, int on) struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct ov7740_priv *priv = to_ov7740(client); + if (on) + clk_prepare_enable(priv->xvclk); + else + clk_disable_unprepare(priv->xvclk); + return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); } @@ -691,6 +698,12 @@ static int ov7740_probe(struct i2c_client *client, goto err_clk; } + priv->xvclk = devm_clk_get(&client->dev, "xvclk"); + if (IS_ERR(priv->xvclk)) { + ret = PTR_ERR(priv->xvclk); + goto err_clk; + } + v4l2_i2c_subdev_init(&priv->subdev, client, &ov7740_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, From 363f69348995cfc1b6b48c2994d4fe12dac0ad9e Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 16:12:50 +0800 Subject: [PATCH 337/381] v4l2: ov7740: replace enum_mbus_fmt by enum_mbus_code Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index e887c76293d9a1..49f1eb03538122 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -501,13 +501,14 @@ static int ov7740_try_fmt(struct v4l2_subdev *sd, return 0; } -static int ov7740_enum_fmt(struct v4l2_subdev *sd, unsigned int index, - u32 *code) +static int ov7740_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - if (index >= ARRAY_SIZE(ov7740_codes)) + if (code->pad || code->index >= ARRAY_SIZE(ov7740_codes)) return -EINVAL; - *code = ov7740_codes[index]; + code->code = ov7740_codes[code->index]; return 0; } @@ -584,13 +585,17 @@ static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { .g_mbus_fmt = ov7740_g_fmt, .s_mbus_fmt = ov7740_s_fmt, .try_mbus_fmt = ov7740_try_fmt, - .enum_mbus_fmt = ov7740_enum_fmt, .g_mbus_config = ov7740_g_mbus_config, }; +static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { + .enum_mbus_code = ov7740_enum_mbus_code, +}; + static struct v4l2_subdev_ops ov7740_subdev_ops = { .core = &ov7740_subdev_core_ops, .video = &ov7740_subdev_video_ops, + .pad = &ov7740_subdev_pad_ops, }; /* OF probe functions */ From 52caa672836261139dd985400c0752fa2bf39a0e Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 16:16:19 +0800 Subject: [PATCH 338/381] v4l2: ov7740: replace video op g_mbus_fmt by pad op get_fmt Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index 49f1eb03538122..46b9f159e833b7 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -421,12 +421,17 @@ static int ov7740_set_params(struct i2c_client *client, u32 *width, u32 *height, return ret; } -static int ov7740_g_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov7740_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov7740_priv *priv = to_ov7740(client); + if (format->pad) + return -EINVAL; + if (!priv->win) { u32 width = W_VGA, height = H_VGA; priv->win = ov7740_select_win(&width, &height); @@ -582,7 +587,6 @@ static int ov7740_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { .s_stream = ov7740_s_stream, - .g_mbus_fmt = ov7740_g_fmt, .s_mbus_fmt = ov7740_s_fmt, .try_mbus_fmt = ov7740_try_fmt, .g_mbus_config = ov7740_g_mbus_config, @@ -590,6 +594,7 @@ static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { .enum_mbus_code = ov7740_enum_mbus_code, + .get_fmt = ov7740_get_fmt, }; static struct v4l2_subdev_ops ov7740_subdev_ops = { From 82b196779622552206a31ca924592e64c0f865d7 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 16:23:36 +0800 Subject: [PATCH 339/381] v4l2: ov7740: replace try_mbus_fmt by set_fmt Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 37 +++++++++------------------ 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index 46b9f159e833b7..baf29a7ecdccbb 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -457,33 +457,16 @@ static int ov7740_get_fmt(struct v4l2_subdev *sd, return 0; } -static int ov7740_s_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) +static int ov7740_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { + struct v4l2_mbus_framefmt *mf = &format->format; struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - switch (mf->code) { - case MEDIA_BUS_FMT_RGB565_2X8_BE: - case MEDIA_BUS_FMT_RGB565_2X8_LE: - mf->colorspace = V4L2_COLORSPACE_SRGB; - break; - default: - mf->code = MEDIA_BUS_FMT_YUYV8_2X8; - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - mf->colorspace = V4L2_COLORSPACE_JPEG; - } - - ret = ov7740_set_params(client, &mf->width, &mf->height, mf->code); - - return ret; -} + if (format->pad) + return -EINVAL; -static int ov7740_try_fmt(struct v4l2_subdev *sd, - struct v4l2_mbus_framefmt *mf) -{ /* * select suitable win, but don't store it */ @@ -503,6 +486,11 @@ static int ov7740_try_fmt(struct v4l2_subdev *sd, mf->colorspace = V4L2_COLORSPACE_JPEG; } + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + return ov7740_set_params(client, &mf->width, &mf->height, + mf->code); + + cfg->try_fmt = *mf; return 0; } @@ -587,14 +575,13 @@ static int ov7740_g_mbus_config(struct v4l2_subdev *sd, static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = { .s_stream = ov7740_s_stream, - .s_mbus_fmt = ov7740_s_fmt, - .try_mbus_fmt = ov7740_try_fmt, .g_mbus_config = ov7740_g_mbus_config, }; static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = { .enum_mbus_code = ov7740_enum_mbus_code, .get_fmt = ov7740_get_fmt, + .set_fmt = ov7740_set_fmt, }; static struct v4l2_subdev_ops ov7740_subdev_ops = { From 0f3747eb548c388e40e035bcb3096d3f240bd0c0 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 17:51:10 +0800 Subject: [PATCH 340/381] media: ov7740: add VSYNC_LOW support Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index baf29a7ecdccbb..dddff24acf184c 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -566,6 +566,7 @@ static int ov7740_g_mbus_config(struct v4l2_subdev *sd, cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER | V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH | + V4L2_MBUS_VSYNC_ACTIVE_LOW | V4L2_MBUS_DATA_ACTIVE_HIGH; cfg->type = V4L2_MBUS_PARALLEL; cfg->flags = soc_camera_apply_board_flags(ssdd, cfg); From a330ba96062ea99f9ae07d96019016a5b8672851 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 12 Nov 2015 13:05:18 +0100 Subject: [PATCH 341/381] ARM: at91/dt: add sama5d3xek device trees Signed-off-by: Alexandre Belloni --- arch/arm/boot/dts/Makefile | 23 +++- arch/arm/boot/dts/sama5d31ek_pda4.dts | 54 +++++++++ arch/arm/boot/dts/sama5d31ek_pda7.dts | 54 +++++++++ arch/arm/boot/dts/sama5d31ek_revc.dts | 54 +++++++++ arch/arm/boot/dts/sama5d31ek_revc_pda4.dts | 55 +++++++++ arch/arm/boot/dts/sama5d31ek_revc_pda7.dts | 55 +++++++++ arch/arm/boot/dts/sama5d33ek_pda4.dts | 54 +++++++++ arch/arm/boot/dts/sama5d33ek_pda7.dts | 54 +++++++++ arch/arm/boot/dts/sama5d33ek_revc.dts | 54 +++++++++ arch/arm/boot/dts/sama5d33ek_revc_pda4.dts | 55 +++++++++ arch/arm/boot/dts/sama5d33ek_revc_pda7.dts | 55 +++++++++ arch/arm/boot/dts/sama5d34ek_pda4.dts | 64 ++++++++++ arch/arm/boot/dts/sama5d34ek_pda7.dts | 64 ++++++++++ arch/arm/boot/dts/sama5d34ek_revc.dts | 64 ++++++++++ arch/arm/boot/dts/sama5d34ek_revc_pda4.dts | 65 +++++++++++ arch/arm/boot/dts/sama5d34ek_revc_pda7.dts | 65 +++++++++++ arch/arm/boot/dts/sama5d35ek_revc.dts | 75 ++++++++++++ arch/arm/boot/dts/sama5d36ek_pda4.dts | 62 ++++++++++ arch/arm/boot/dts/sama5d36ek_pda7.dts | 63 ++++++++++ arch/arm/boot/dts/sama5d36ek_revc.dts | 62 ++++++++++ arch/arm/boot/dts/sama5d36ek_revc_pda4.dts | 63 ++++++++++ arch/arm/boot/dts/sama5d36ek_revc_pda7.dts | 63 ++++++++++ arch/arm/boot/dts/sama5d3xdm.dtsi | 60 ++++++++++ arch/arm/boot/dts/sama5d3xdm_pda4.dtsi | 110 +++++++++++++++++ arch/arm/boot/dts/sama5d3xdm_pda7.dtsi | 117 +++++++++++++++++++ arch/arm/boot/dts/sama5d3xmb.dtsi | 34 ------ arch/arm/boot/dts/sama5d3xmb_audio.dtsi | 43 +++++++ arch/arm/boot/dts/sama5d3xmb_hdmi.dtsi | 58 +++++++++ arch/arm/boot/dts/sama5d3xmb_revc_audio.dtsi | 43 +++++++ arch/arm/boot/dts/sama5d3xmb_revc_hdmi.dtsi | 58 +++++++++ 30 files changed, 1765 insertions(+), 35 deletions(-) create mode 100644 arch/arm/boot/dts/sama5d31ek_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d31ek_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d31ek_revc.dts create mode 100644 arch/arm/boot/dts/sama5d31ek_revc_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d31ek_revc_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d33ek_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d33ek_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d33ek_revc.dts create mode 100644 arch/arm/boot/dts/sama5d33ek_revc_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d33ek_revc_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d34ek_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d34ek_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d34ek_revc.dts create mode 100644 arch/arm/boot/dts/sama5d34ek_revc_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d34ek_revc_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d35ek_revc.dts create mode 100644 arch/arm/boot/dts/sama5d36ek_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d36ek_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d36ek_revc.dts create mode 100644 arch/arm/boot/dts/sama5d36ek_revc_pda4.dts create mode 100644 arch/arm/boot/dts/sama5d36ek_revc_pda7.dts create mode 100644 arch/arm/boot/dts/sama5d3xdm_pda4.dtsi create mode 100644 arch/arm/boot/dts/sama5d3xdm_pda7.dtsi create mode 100644 arch/arm/boot/dts/sama5d3xmb_audio.dtsi create mode 100644 arch/arm/boot/dts/sama5d3xmb_hdmi.dtsi create mode 100644 arch/arm/boot/dts/sama5d3xmb_revc_audio.dtsi create mode 100644 arch/arm/boot/dts/sama5d3xmb_revc_hdmi.dtsi diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile index 78dc1f828a9eaf..0fe6b71bac1a5d 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -44,13 +44,34 @@ dtb-$(CONFIG_SOC_SAM_V7) += \ at91-sama5d2_xplained.dtb \ at91-sama5d2_xplained_pda4.dtb \ at91-sama5d3_xplained.dtb \ - sama5d31ek.dtb \ at91-sama5d3_xplained_pda4.dtb \ at91-sama5d3_xplained_pda7.dtb \ + sama5d31ek.dtb \ + sama5d31ek_pda4.dtb \ + sama5d31ek_pda7.dtb \ + sama5d31ek_revc.dtb \ + sama5d31ek_revc_pda4.dtb \ + sama5d31ek_revc_pda7.dtb \ sama5d33ek.dtb \ + sama5d33ek_pda4.dtb \ + sama5d33ek_pda7.dtb \ + sama5d33ek_revc.dtb \ + sama5d33ek_revc_pda4.dtb \ + sama5d33ek_revc_pda7.dtb \ sama5d34ek.dtb \ + sama5d34ek_pda4.dtb \ + sama5d34ek_pda7.dtb \ + sama5d34ek_revc.dtb \ + sama5d34ek_revc_pda4.dtb \ + sama5d34ek_revc_pda7.dtb \ sama5d35ek.dtb \ + sama5d35ek_revc.dtb \ sama5d36ek.dtb \ + sama5d36ek_pda4.dtb \ + sama5d36ek_pda7.dtb \ + sama5d36ek_revc.dtb \ + sama5d36ek_revc_pda4.dtb \ + sama5d36ek_revc_pda7.dtb \ at91-sama5d4_xplained.dtb \ at91-sama5d4_xplained_hdmi.dtb \ at91-sama5d4_xplained_pda4.dtb \ diff --git a/arch/arm/boot/dts/sama5d31ek_pda4.dts b/arch/arm/boot/dts/sama5d31ek_pda4.dts new file mode 100644 index 00000000000000..51e87052531a59 --- /dev/null +++ b/arch/arm/boot/dts/sama5d31ek_pda4.dts @@ -0,0 +1,54 @@ +/* + * sama5d31ek_pda4.dts - Device Tree file for SAMA5D31-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d31.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D31-EK TM43xx"; + compatible = "atmel,sama5d31ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d31ek_pda7.dts b/arch/arm/boot/dts/sama5d31ek_pda7.dts new file mode 100644 index 00000000000000..c32c8d3815f348 --- /dev/null +++ b/arch/arm/boot/dts/sama5d31ek_pda7.dts @@ -0,0 +1,54 @@ +/* + * sama5d31ek_pda7.dts - Device Tree file for SAMA5D31-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d31.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* Conflict with LCD pin mux */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D31-EK TM70xx"; + compatible = "atmel,sama5d31ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d31ek_revc.dts b/arch/arm/boot/dts/sama5d31ek_revc.dts new file mode 100644 index 00000000000000..b37ec7ebf8bf20 --- /dev/null +++ b/arch/arm/boot/dts/sama5d31ek_revc.dts @@ -0,0 +1,54 @@ +/* + * sama5d31ek_revc.dts - Device Tree file for SAMA5D31-EK up to rev.C MB + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d31.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm.dtsi" + +/ { + model = "Atmel SAMA5D31-EK - rev.C"; + compatible = "atmel,sama5d31ek", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d31ek_revc_pda4.dts b/arch/arm/boot/dts/sama5d31ek_revc_pda4.dts new file mode 100644 index 00000000000000..179c99678791a1 --- /dev/null +++ b/arch/arm/boot/dts/sama5d31ek_revc_pda4.dts @@ -0,0 +1,55 @@ +/* + * sama5d31ek_revc_pda4.dts - Device Tree file for SAMA5D31-EK up to rev.C MB + * + PDA4.3" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d31.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D31-EK TM43xx - rev.C"; + compatible = "atmel,sama5d31ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d31ek_revc_pda7.dts b/arch/arm/boot/dts/sama5d31ek_revc_pda7.dts new file mode 100644 index 00000000000000..0b580364a8d386 --- /dev/null +++ b/arch/arm/boot/dts/sama5d31ek_revc_pda7.dts @@ -0,0 +1,55 @@ +/* + * sama5d31ek_revc_pda7.dts - Device Tree file for SAMA5D31-EK up to rev.C MB + * + PDA7" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d31.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D31-EK TM70xx - rev.C"; + compatible = "atmel,sama5d31ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d31", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d33ek_pda4.dts b/arch/arm/boot/dts/sama5d33ek_pda4.dts new file mode 100644 index 00000000000000..22101ef96f06bd --- /dev/null +++ b/arch/arm/boot/dts/sama5d33ek_pda4.dts @@ -0,0 +1,54 @@ +/* + * sama5d33ek_pda4.dts - Device Tree file for SAMA5D33-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d33.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D33-EK TM43xx"; + compatible = "atmel,sama5d33ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d33ek_pda7.dts b/arch/arm/boot/dts/sama5d33ek_pda7.dts new file mode 100644 index 00000000000000..c1605f9c2b45a1 --- /dev/null +++ b/arch/arm/boot/dts/sama5d33ek_pda7.dts @@ -0,0 +1,54 @@ +/* + * sama5d33ek_pda7.dts - Device Tree file for SAMA5D33-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d33.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* Conflict with LCD pin mux */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D33-EK TM70xx"; + compatible = "atmel,sama5d33ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d33", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d33ek_revc.dts b/arch/arm/boot/dts/sama5d33ek_revc.dts new file mode 100644 index 00000000000000..9317b632cc2a04 --- /dev/null +++ b/arch/arm/boot/dts/sama5d33ek_revc.dts @@ -0,0 +1,54 @@ +/* + * sama5d33ek_revc.dts - Device Tree file for SAMA5D33-EK up to rev.C MB + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d33.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm.dtsi" + +/ { + model = "Atmel SAMA5D33-EK - rev.C"; + compatible = "atmel,sama5d33ek", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d33", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d33ek_revc_pda4.dts b/arch/arm/boot/dts/sama5d33ek_revc_pda4.dts new file mode 100644 index 00000000000000..3665eb0aee0f6b --- /dev/null +++ b/arch/arm/boot/dts/sama5d33ek_revc_pda4.dts @@ -0,0 +1,55 @@ +/* + * sama5d33ek_revc_pda4.dts - Device Tree file for SAMA5D33-EK up to rev.C MB + * + PDA4.3" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d33.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D33-EK TM43xx - rev.C"; + compatible = "atmel,sama5d33ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d33", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d33ek_revc_pda7.dts b/arch/arm/boot/dts/sama5d33ek_revc_pda7.dts new file mode 100644 index 00000000000000..9551b851cd900e --- /dev/null +++ b/arch/arm/boot/dts/sama5d33ek_revc_pda7.dts @@ -0,0 +1,55 @@ +/* + * sama5d33ek_revc_pda7.dts - Device Tree file for SAMA5D33-EK up to rev.C MB + * + PDA7" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d33.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D33-EK TM70xx - rev.C"; + compatible = "atmel,sama5d33ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d33", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d34ek_pda4.dts b/arch/arm/boot/dts/sama5d34ek_pda4.dts new file mode 100644 index 00000000000000..19bbcc153cc6a3 --- /dev/null +++ b/arch/arm/boot/dts/sama5d34ek_pda4.dts @@ -0,0 +1,64 @@ +/* + * sama5d34ek_pda4.dts - Device Tree file for SAMA5D34-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d34.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D34-EK TM43xx"; + compatible = "atmel,sama5d34ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + 24c256@50 { + compatible = "24c256"; + reg = <0x50>; + pagesize = <64>; + }; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d34ek_pda7.dts b/arch/arm/boot/dts/sama5d34ek_pda7.dts new file mode 100644 index 00000000000000..a93695f652381e --- /dev/null +++ b/arch/arm/boot/dts/sama5d34ek_pda7.dts @@ -0,0 +1,64 @@ +/* + * sama5d34ek_pda7.dts - Device Tree file for SAMA5D34-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d34.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* Conflict with LCD pin mux */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D34-EK TM70xx"; + compatible = "atmel,sama5d34ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d34", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + 24c256@50 { + compatible = "24c256"; + reg = <0x50>; + pagesize = <64>; + }; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d34ek_revc.dts b/arch/arm/boot/dts/sama5d34ek_revc.dts new file mode 100644 index 00000000000000..b9948372436b72 --- /dev/null +++ b/arch/arm/boot/dts/sama5d34ek_revc.dts @@ -0,0 +1,64 @@ +/* + * sama5d34ek_revc.dts - Device Tree file for SAMA5D34-EK up to rev.C MB + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d34.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm.dtsi" + +/ { + model = "Atmel SAMA5D34-EK - rev.C"; + compatible = "atmel,sama5d34ek", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d34", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + 24c256@50 { + compatible = "24c256"; + reg = <0x50>; + pagesize = <64>; + }; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d34ek_revc_pda4.dts b/arch/arm/boot/dts/sama5d34ek_revc_pda4.dts new file mode 100644 index 00000000000000..43dd7f261a10df --- /dev/null +++ b/arch/arm/boot/dts/sama5d34ek_revc_pda4.dts @@ -0,0 +1,65 @@ +/* + * sama5d34ek_revc_pda4.dts - Device Tree file for SAMA5D34-EK up to rev.C MB + * + PDA4.3" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d34.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D34-EK TM43xx - rev.C"; + compatible = "atmel,sama5d34ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d34", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + 24c256@50 { + compatible = "24c256"; + reg = <0x50>; + pagesize = <64>; + }; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d34ek_revc_pda7.dts b/arch/arm/boot/dts/sama5d34ek_revc_pda7.dts new file mode 100644 index 00000000000000..614899da7251e8 --- /dev/null +++ b/arch/arm/boot/dts/sama5d34ek_revc_pda7.dts @@ -0,0 +1,65 @@ +/* + * sama5d34ek_revc_pda7.dts - Device Tree file for SAMA5D34-EK up to rev.C MB + * + PDA7" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d34.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D34-EK TM70xx - rev.C"; + compatible = "atmel,sama5d34ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d34", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + + 24c256@50 { + compatible = "24c256"; + reg = <0x50>; + pagesize = <64>; + }; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d35ek_revc.dts b/arch/arm/boot/dts/sama5d35ek_revc.dts new file mode 100644 index 00000000000000..e3dd5c8b3c5380 --- /dev/null +++ b/arch/arm/boot/dts/sama5d35ek_revc.dts @@ -0,0 +1,75 @@ +/* + * sama5d35ek_revc.dts - Device Tree file for SAMA5D35-EK up to rev.C MB + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d35.dtsi" +#include "sama5d3xmb.dtsi" +/* #include "sama5d3xmb_revc_audio.dtsi" */ /* require i2c0 */ + +/ { + model = "Atmel SAMA5D35-EK - rev.C"; + compatible = "atmel,sama5d35ek", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d35", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "disabled"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "disabled"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + /* Conflict with LCD pins */ + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + pb_user1 { + label = "pb_user1"; + gpios = <&pioE 27 GPIO_ACTIVE_HIGH>; + linux,code = <0x100>; + gpio-key,wakeup; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + status = "disabled"; + }; + }; + + sound { + status = "disable"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d36ek_pda4.dts b/arch/arm/boot/dts/sama5d36ek_pda4.dts new file mode 100644 index 00000000000000..43b0fc1b4aef0a --- /dev/null +++ b/arch/arm/boot/dts/sama5d36ek_pda4.dts @@ -0,0 +1,62 @@ +/* + * sama5d36ek_pda4.dts - Device Tree file for SAMA5D36-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D36-EK TM43xx"; + compatible = "atmel,sama5d36ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d36ek_pda7.dts b/arch/arm/boot/dts/sama5d36ek_pda7.dts new file mode 100644 index 00000000000000..fc13eaa84529a8 --- /dev/null +++ b/arch/arm/boot/dts/sama5d36ek_pda7.dts @@ -0,0 +1,63 @@ +/* + * sama5d36ek_pda7.dts - Device Tree file for SAMA5D36-EK board + * + * Copyright (C) 2013 Atmel, + * 2013 Ludovic Desroches + * 2013 Josh Wu + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_audio.dtsi" +/* #include "sama5d3xmb_hdmi.dtsi" */ /* Conflict with LCD pin mux */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D36-EK TM70xx"; + compatible = "atmel,sama5d36ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d36", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d36ek_revc.dts b/arch/arm/boot/dts/sama5d36ek_revc.dts new file mode 100644 index 00000000000000..1abcdc7f21cd56 --- /dev/null +++ b/arch/arm/boot/dts/sama5d36ek_revc.dts @@ -0,0 +1,62 @@ +/* + * sama5d36ek_revc.dts - Device Tree file for SAMA5D36-EK up to rev.C MB + * + * Copyright (C) 2013 Atmel, + * 2013 Josh Wu + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm.dtsi" + +/ { + model = "Atmel SAMA5D36-EK - rev.C"; + compatible = "atmel,sama5d36ek", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d36", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d36ek_revc_pda4.dts b/arch/arm/boot/dts/sama5d36ek_revc_pda4.dts new file mode 100644 index 00000000000000..22f8e98c7048d8 --- /dev/null +++ b/arch/arm/boot/dts/sama5d36ek_revc_pda4.dts @@ -0,0 +1,63 @@ +/* + * sama5d36ek_revc_pda4.dts - Device Tree file for SAMA5D36-EK up to rev.C MB + * + PDA4.3" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Josh Wu + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda4.dtsi" + +/ { + model = "Atmel SAMA5D36-EK TM43xx - rev.C"; + compatible = "atmel,sama5d36ek", "pda,tm43xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d36", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d36ek_revc_pda7.dts b/arch/arm/boot/dts/sama5d36ek_revc_pda7.dts new file mode 100644 index 00000000000000..d9323f2ffe2e9f --- /dev/null +++ b/arch/arm/boot/dts/sama5d36ek_revc_pda7.dts @@ -0,0 +1,63 @@ +/* + * sama5d36ek_revc_pda7.dts - Device Tree file for SAMA5D36-EK up to rev.C MB + * + PDA7" LCD + * + * Copyright (C) 2013 Atmel, + * 2013 Josh Wu + * + * Licensed under GPLv2 or later. + */ +/dts-v1/; +#include "sama5d36.dtsi" +#include "sama5d3xmb.dtsi" +#include "sama5d3xmb_revc_audio.dtsi" /* require i2c0 */ +/* #include "sama5d3xmb_revc_hdmi.dtsi" */ /* require i2c0 *//* need sil902x driver */ +#include "sama5d3xdm_pda7.dtsi" + +/ { + model = "Atmel SAMA5D36-EK TM70xx - rev.C"; + compatible = "atmel,sama5d36ek", "pda,tm70xx", "atmel,sama5d3xmb", "atmel,sama5d3xcm", "atmel,sama5d36", "atmel,sama5d3", "atmel,sama5"; + + ahb { + apb { + spi0: spi@f0004000 { + status = "okay"; + }; + + ssc0: ssc@f0008000 { + status = "okay"; + }; + + can0: can@f000c000 { + status = "okay"; + }; + + i2c0: i2c@f0014000 { + status = "okay"; + }; + + i2c1: i2c@f0018000 { + status = "okay"; + }; + + macb0: ethernet@f0028000 { + status = "okay"; + }; + + macb1: ethernet@f802c000 { + status = "okay"; + }; + }; + }; + + leds { + d3 { + label = "d3"; + gpios = <&pioE 24 GPIO_ACTIVE_HIGH>; + }; + }; + + sound { + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d3xdm.dtsi b/arch/arm/boot/dts/sama5d3xdm.dtsi index 035ab72b39903c..c743221003a7ad 100644 --- a/arch/arm/boot/dts/sama5d3xdm.dtsi +++ b/arch/arm/boot/dts/sama5d3xdm.dtsi @@ -22,6 +22,22 @@ }; }; + hlcdc: hlcdc@f0030000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + adc0: adc@f8018000 { atmel,adc-ts-wires = <4>; atmel,adc-ts-pressure-threshold = <10000>; @@ -38,4 +54,48 @@ }; }; }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "foxlink,fl500wvr00-a0t", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; }; diff --git a/arch/arm/boot/dts/sama5d3xdm_pda4.dtsi b/arch/arm/boot/dts/sama5d3xdm_pda4.dtsi new file mode 100644 index 00000000000000..ee907051d920f6 --- /dev/null +++ b/arch/arm/boot/dts/sama5d3xdm_pda4.dtsi @@ -0,0 +1,110 @@ +/* + * sama5d3xdm_pda4.dtsi - Device Tree file for SAMA5 display module + * + * Copyright (C) 2014 Atmel, + * 2014 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c1: i2c@f0018000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <30 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4a { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4a>; + interrupt-parent = <&pioE>; + interrupts = <31 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; + }; + + hlcdc: hlcdc@f0030000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + + pinctrl@fffff200 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; /* PE30 GPIO with pull up deglith */ + }; + + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; /* PE31 GPIO with pull up deglith */ + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "innolux,at043tn24", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d3xdm_pda7.dtsi b/arch/arm/boot/dts/sama5d3xdm_pda7.dtsi new file mode 100644 index 00000000000000..22d7c7026c4670 --- /dev/null +++ b/arch/arm/boot/dts/sama5d3xdm_pda7.dtsi @@ -0,0 +1,117 @@ +/* + * sama5d3xdm_pda7.dtsi - Device Tree file for SAMA5 display module + * + * Copyright (C) 2014 Atmel, + * 2014 Ludovic Desroches + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c1: i2c@f0018000 { + qt1070: keyboard@1b { + compatible = "qt1070"; + reg = <0x1b>; + interrupt-parent = <&pioE>; + interrupts = <30 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_qt1070_irq>; + wakeup-source; + }; + + atmel_mxt_ts@4c { + compatible = "atmel,atmel_mxt_ts"; + reg = <0x4c>; + interrupt-parent = <&pioE>; + interrupts = <31 0x0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_mxt_ts>; + }; + }; + + hlcdc: hlcdc@f0030000 { + status = "okay"; + + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb666_alt>; + + port@0 { + hlcdc_panel_output: endpoint@0 { + reg = <0>; + remote-endpoint = <&panel_input>; + }; + }; + }; + }; + + adc0: adc@f8018000 { + atmel,adc-clock-rate = <1000000>; + /* atmel,adc-ts-wires = <4>;*/ + /* atmel,adc-ts-pressure-threshold = <10000>;*/ + status = "okay"; + }; + + pinctrl@fffff200 { + board { + pinctrl_qt1070_irq: qt1070_irq { + atmel,pins = + ; /* PE30 GPIO with pull up deglith */ + }; + + pinctrl_mxt_ts: mxt_irq { + atmel,pins = + ; /* PE31 GPIO with pull up deglith */ + }; + }; + }; + }; + }; + + backlight: backlight { + compatible = "pwm-backlight"; + pwms = <&hlcdc_pwm 0 50000 0>; + brightness-levels = <0 4 8 16 32 64 128 255>; + default-brightness-level = <6>; + power-supply = <&bl_reg>; + status = "okay"; + }; + + bl_reg: backlight_regulator { + compatible = "regulator-fixed"; + regulator-name = "backlight-power-supply"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + status = "okay"; + }; + + panel: panel { + compatible = "shelly,sca07010-bfn-lnn", "simple-panel"; + backlight = <&backlight>; + power-supply = <&panel_reg>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + port@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + panel_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_panel_output>; + }; + }; + }; + + panel_reg: panel_regulator { + compatible = "regulator-fixed"; + regulator-name = "panel-power-supply"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + status = "okay"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d3xmb.dtsi b/arch/arm/boot/dts/sama5d3xmb.dtsi index 89010422812d6a..aff9b648163d69 100644 --- a/arch/arm/boot/dts/sama5d3xmb.dtsi +++ b/arch/arm/boot/dts/sama5d3xmb.dtsi @@ -38,20 +38,6 @@ atmel,clk-from-rk-pin; }; - /* - * i2c0 conflicts with ISI: - * disable it to allow the use of ISI - * can not enable audio when i2c0 disabled - */ - i2c0: i2c@f0014000 { - wm8904: wm8904@1a { - compatible = "wlf,wm8904"; - reg = <0x1a>; - clocks = <&pck0>; - clock-names = "mclk"; - }; - }; - i2c1: i2c@f0018000 { ov2640: camera@0x30 { compatible = "ovti,ov2640"; @@ -198,24 +184,4 @@ status = "okay"; }; }; - - sound { - compatible = "atmel,asoc-wm8904"; - pinctrl-names = "default"; - pinctrl-0 = <&pinctrl_pck0_as_audio_mck>; - - atmel,model = "wm8904 @ SAMA5D3EK"; - atmel,audio-routing = - "Headphone Jack", "HPOUTL", - "Headphone Jack", "HPOUTR", - "IN2L", "Line In Jack", - "IN2R", "Line In Jack", - "Mic", "MICBIAS", - "IN1L", "Mic"; - - atmel,ssc-controller = <&ssc0>; - atmel,audio-codec = <&wm8904>; - - status = "disabled"; - }; }; diff --git a/arch/arm/boot/dts/sama5d3xmb_audio.dtsi b/arch/arm/boot/dts/sama5d3xmb_audio.dtsi new file mode 100644 index 00000000000000..91cf88fef7b2e5 --- /dev/null +++ b/arch/arm/boot/dts/sama5d3xmb_audio.dtsi @@ -0,0 +1,43 @@ +/* + * sama5d3xmb_audio.dtsi - Device Tree file for audio on mother board + * + * Copyright (C) 2015 Atmel, + * 2015 Bo Shen + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c1: i2c@f0018000 { + wm8904: wm8904@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + clocks = <&pck0>; + clock-names = "mclk"; + }; + }; + }; + }; + + sound { + compatible = "atmel,asoc-wm8904"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_audio_mck>; + + atmel,model = "wm8904 @ SAMA5D3EK"; + atmel,audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "IN2L", "Line In Jack", + "IN2R", "Line In Jack", + "Mic", "MICBIAS", + "IN1L", "Mic"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8904>; + + status = "disabled"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d3xmb_hdmi.dtsi b/arch/arm/boot/dts/sama5d3xmb_hdmi.dtsi new file mode 100644 index 00000000000000..d53a0c56511380 --- /dev/null +++ b/arch/arm/boot/dts/sama5d3xmb_hdmi.dtsi @@ -0,0 +1,58 @@ +/* + * Device Tree file for HDMI on sama5d3x mother board + * + * Copyright (C) 2015 Atmel, + * 2015 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c1: i2c@f0018000 { + sil9022: hdmi-encoder@39 { + compatible = "sil,sil9022"; + reg = <0x39>; + reset-gpio = <&pioC 31 GPIO_ACTIVE_LOW>; + interrupt-extended = <&pioC 29 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sil9022_irq>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_hdmi_output>; + }; + }; + }; + }; + + hlcdc: hlcdc@f0030000 { + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>; + + port@0 { + hlcdc_hdmi_output: endpoint@1 { + reg = <1>; + remote-endpoint = <&hdmi_input>; + }; + }; + }; + }; + + pinctrl@fffff200 { + board { + pinctrl_sil9022_irq: sil9022_irq-0 { + atmel,pins = + ; + }; + }; + }; + }; + }; +}; diff --git a/arch/arm/boot/dts/sama5d3xmb_revc_audio.dtsi b/arch/arm/boot/dts/sama5d3xmb_revc_audio.dtsi new file mode 100644 index 00000000000000..1eda4fbd595d38 --- /dev/null +++ b/arch/arm/boot/dts/sama5d3xmb_revc_audio.dtsi @@ -0,0 +1,43 @@ +/* + * sama5d3xmb_revc_audio.dtsi - Device Tree file for audio on revision C mother board + * + * Copyright (C) 2015 Atmel, + * 2015 Bo Shen + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c0: i2c@f0014000 { + wm8904: wm8904@1a { + compatible = "wlf,wm8904"; + reg = <0x1a>; + clocks = <&pck0>; + clock-names = "mclk"; + }; + }; + }; + }; + + sound { + compatible = "atmel,asoc-wm8904"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck0_as_audio_mck>; + + atmel,model = "wm8904 @ SAMA5D3EK"; + atmel,audio-routing = + "Headphone Jack", "HPOUTL", + "Headphone Jack", "HPOUTR", + "IN2L", "Line In Jack", + "IN2R", "Line In Jack", + "Mic", "MICBIAS", + "IN1L", "Mic"; + + atmel,ssc-controller = <&ssc0>; + atmel,audio-codec = <&wm8904>; + + status = "disabled"; + }; +}; diff --git a/arch/arm/boot/dts/sama5d3xmb_revc_hdmi.dtsi b/arch/arm/boot/dts/sama5d3xmb_revc_hdmi.dtsi new file mode 100644 index 00000000000000..645010285c2833 --- /dev/null +++ b/arch/arm/boot/dts/sama5d3xmb_revc_hdmi.dtsi @@ -0,0 +1,58 @@ +/* + * Device Tree file for HDMI on sama5d3x up to rev.C mother board + * + * Copyright (C) 2015 Atmel, + * 2015 Nicolas Ferre + * + * Licensed under GPLv2 or later. + */ + +/ { + ahb { + apb { + i2c0: i2c@f0014000 { + sil9022: hdmi-encoder@39 { + compatible = "sil,sil9022"; + reg = <0x39>; + reset-gpio = <&pioC 31 GPIO_ACTIVE_LOW>; + interrupt-extended = <&pioC 29 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_sil9022_irq>; + + port { + #address-cells = <1>; + #size-cells = <0>; + + hdmi_input: endpoint@0 { + reg = <0>; + remote-endpoint = <&hlcdc_hdmi_output>; + }; + }; + }; + }; + + hlcdc: hlcdc@f0030000 { + hlcdc-display-controller { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888_alt>; + + port@0 { + hlcdc_hdmi_output: endpoint@1 { + reg = <1>; + remote-endpoint = <&hdmi_input>; + }; + }; + }; + }; + + pinctrl@fffff200 { + board { + pinctrl_sil9022_irq: sil9022_irq-0 { + atmel,pins = + ; + }; + }; + }; + }; + }; +}; From 3ddde846e73f35dab616469b6af8662aae26f6bd Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 18:32:06 +0800 Subject: [PATCH 342/381] media: ov7740: remove xvclk common clock part as it is not need now soc_camera framework is updated. In new framework, if v4l2_clk_get will first try get the common clock (xvclk), if common clock is not found then get the v4l2_clk which provided by soc_camera, that can communicate with camera host driver. So we don't need common clock xvclk now. v4l2_clk can do the common clock job for us. Signed-off-by: Josh Wu --- drivers/media/i2c/soc_camera/ov7740.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/media/i2c/soc_camera/ov7740.c b/drivers/media/i2c/soc_camera/ov7740.c index dddff24acf184c..514b4513f3f102 100644 --- a/drivers/media/i2c/soc_camera/ov7740.c +++ b/drivers/media/i2c/soc_camera/ov7740.c @@ -74,7 +74,6 @@ struct ov7740_priv { struct v4l2_ctrl_handler hdl; u32 cfmt_code; struct v4l2_clk *clk; - struct clk *xvclk; const struct ov7740_win_size *win; struct soc_camera_subdev_desc ssdd_dt; @@ -354,11 +353,6 @@ static int ov7740_s_power(struct v4l2_subdev *sd, int on) struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client); struct ov7740_priv *priv = to_ov7740(client); - if (on) - clk_prepare_enable(priv->xvclk); - else - clk_disable_unprepare(priv->xvclk); - return soc_camera_set_power(&client->dev, ssdd, priv->clk, on); } @@ -679,7 +673,7 @@ static int ov7740_probe(struct i2c_client *client, return -ENOMEM; } - priv->clk = v4l2_clk_get(&client->dev, "mclk"); + priv->clk = v4l2_clk_get(&client->dev, "xvclk"); if (IS_ERR(priv->clk)) return -EPROBE_DEFER; @@ -696,12 +690,6 @@ static int ov7740_probe(struct i2c_client *client, goto err_clk; } - priv->xvclk = devm_clk_get(&client->dev, "xvclk"); - if (IS_ERR(priv->xvclk)) { - ret = PTR_ERR(priv->xvclk); - goto err_clk; - } - v4l2_i2c_subdev_init(&priv->subdev, client, &ov7740_subdev_ops); v4l2_ctrl_handler_init(&priv->hdl, 2); v4l2_ctrl_new_std(&priv->hdl, &ov7740_ctrl_ops, From ee645bac968b362f6530b7ff1304939091d859db Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 15:31:07 +0800 Subject: [PATCH 343/381] ARM: at91: sama5d4ek/dts: re-order the pinctrl dt nodes organized pinctrl dt nodes by alphabet. Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d4ek.dts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index 6d272c0125e365..82ac55d98f1124 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -203,6 +203,10 @@ pinctrl@fc06a000 { board { + pinctrl_key_gpio: key_gpio_0 { + atmel,pins = + ; /* PE13 gpio */ + }; pinctrl_mmc0_cd: mmc0_cd { atmel,pins = ; @@ -211,25 +215,21 @@ atmel,pins = ; }; - pinctrl_pck2_as_audio_mck: pck2_as_audio_mck { - atmel,pins = - ; - }; - pinctrl_usba_vbus: usba_vbus { + pinctrl_mxt_ts: mxt_irq { atmel,pins = - ; + ; }; - pinctrl_key_gpio: key_gpio_0 { + pinctrl_pck2_as_audio_mck: pck2_as_audio_mck { atmel,pins = - ; /* PE13 gpio */ + ; }; pinctrl_qt1070_irq: qt1070_irq { atmel,pins = ; }; - pinctrl_mxt_ts: mxt_irq { + pinctrl_usba_vbus: usba_vbus { atmel,pins = - ; + ; }; }; }; From cb224598d03c024f79fa65ac6199553fc5906de5 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 18:58:07 +0800 Subject: [PATCH 344/381] ARM: at91: sama5d4ek/dts: add sensor power/reset pin ctrl Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d4ek.dts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index 82ac55d98f1124..ea2309d6541454 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -219,6 +219,10 @@ atmel,pins = ; }; + pinctrl_pck1_as_isi_mck: pck1_as_isi_mck-0 { + atmel,pins = + ; /* PC4 periph C PCK1, conflicted with SPI0_NPCS1, MCI0_CK */ + }; pinctrl_pck2_as_audio_mck: pck2_as_audio_mck { atmel,pins = ; @@ -227,6 +231,14 @@ atmel,pins = ; }; + pinctrl_sensor_reset: sensor_reset-0 { + atmel,pins = + ; /* PB11 gpio */ + }; + pinctrl_sensor_power: sensor_power-0 { + atmel,pins = + ; /* PB5 gpio */ + }; pinctrl_usba_vbus: usba_vbus { atmel,pins = ; From 47f1859c30fee728483acda2fcb8a3efc5b91d77 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 15:32:06 +0800 Subject: [PATCH 345/381] ARM: at91: sama5d4ek/dts: enable isi & ov2640 support Since usart2 conflict with ISI & sensor power pin, so disable usart2. Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d4ek.dts | 34 +++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index ea2309d6541454..6efa79955cd76a 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -99,6 +99,18 @@ }; }; + isi: isi@f0008000 { + status = "okay"; + port { + isi_0: endpoint@0 { + remote-endpoint = <&ov2640_0>; + bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; + }; + }; + }; + adc0: adc@fc034000 { pinctrl-names = "default"; pinctrl-0 = < @@ -159,6 +171,26 @@ wakeup-source; }; + ov2640: camera@30 { + compatible = "ovti,ov2640"; + reg = <0x30>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck1_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioB 11 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioB 5 GPIO_ACTIVE_HIGH>; + clocks = <&pck1>; + clock-names = "xvclk"; + assigned-clocks = <&pck1>; + assigned-clock-rates = <25000000>; + + port { + ov2640_0: endpoint { + remote-endpoint = <&isi_0>; + bus-width = <8>; + }; + }; + }; + atmel_mxt_ts@4c { compatible = "atmel,atmel_mxt_ts"; reg = <0x4c>; @@ -186,7 +218,7 @@ }; usart2: serial@fc008000 { - status = "okay"; + status = "disabled"; /* confict with ISI pins & sensor power pin */ }; usart3: serial@fc00c000 { From 80fa83e95d795d83bc6a4b9be6d4d734545415bd Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 15:36:45 +0800 Subject: [PATCH 346/381] ARM: at91: sama5d4ek/dts: add ov7740 support Signed-off-by: Josh Wu --- arch/arm/boot/dts/at91-sama5d4ek.dts | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d4ek.dts b/arch/arm/boot/dts/at91-sama5d4ek.dts index 6efa79955cd76a..10c311af75022a 100644 --- a/arch/arm/boot/dts/at91-sama5d4ek.dts +++ b/arch/arm/boot/dts/at91-sama5d4ek.dts @@ -108,6 +108,13 @@ vsync-active = <1>; hsync-active = <1>; }; + + isi_1: endpoint@1 { + remote-endpoint = <&ov7740_0>; + bus-width = <8>; + vsync-active = <1>; + hsync-active = <1>; + }; }; }; @@ -171,6 +178,26 @@ wakeup-source; }; + ov7740: camera@21 { + compatible = "ovti,ov7740"; + reg = <0x21>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_pck1_as_isi_mck &pinctrl_sensor_power &pinctrl_sensor_reset>; + resetb-gpios = <&pioB 11 GPIO_ACTIVE_LOW>; + pwdn-gpios = <&pioB 5 GPIO_ACTIVE_HIGH>; + clocks = <&pck1>; + clock-names = "xvclk"; + assigned-clocks = <&pck1>; + assigned-clock-rates = <25000000>; + + port { + ov7740_0: endpoint { + remote-endpoint = <&isi_1>; + bus-width = <8>; + }; + }; + }; + ov2640: camera@30 { compatible = "ovti,ov2640"; reg = <0x30>; From 9e947bd3187e35f884d356399f437759752d13da Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 13 Nov 2015 19:10:07 +0800 Subject: [PATCH 347/381] sama5_defconfig: add ov7740 module support Signed-off-by: Josh Wu --- arch/arm/configs/sama5_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 2b8496eb5b82ee..a511dceeaa5c6c 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -162,6 +162,7 @@ CONFIG_SOC_CAMERA_OV2640=m CONFIG_SOC_CAMERA_OV5642=m CONFIG_SOC_CAMERA_OV6650=m CONFIG_SOC_CAMERA_OV772X=m +CONFIG_SOC_CAMERA_OV7740=m CONFIG_SOC_CAMERA_OV9640=m CONFIG_SOC_CAMERA_OV9740=m CONFIG_DRM=y From a5041675b13529a542a4fc0b7b56e01a7f49165f Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 9 Nov 2015 15:03:59 +0100 Subject: [PATCH 348/381] mmc: core: set regulator not found message as debug Turn the informative message about no vmmc/vqmmc regulator found in debug one. There is no need to indicate that something optional is missing. Moreover, it can bring confusion, people who doesn't know it is optional may consider these messages as warnings or errors. Signed-off-by: Ludovic Desroches --- drivers/mmc/core/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 92e7671426ebc2..a249da7c8b30e8 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1410,7 +1410,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vmmc)) { if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(dev, "No vmmc regulator found\n"); + dev_dbg(dev, "No vmmc regulator found\n"); } else { ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc); if (ret > 0) @@ -1422,7 +1422,7 @@ int mmc_regulator_get_supply(struct mmc_host *mmc) if (IS_ERR(mmc->supply.vqmmc)) { if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER) return -EPROBE_DEFER; - dev_info(dev, "No vqmmc regulator found\n"); + dev_dbg(dev, "No vqmmc regulator found\n"); } return 0; From e469b894b6e506fb68c834b43840a898a3572019 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 14 Sep 2015 16:56:29 +0200 Subject: [PATCH 349/381] ARM: at91/dt: sama5d2 Xplained: add emmc ddr-1.8v support The eMMC supports double data rate with a 1.8 voltage. Signed-off-by: Ludovic Desroches --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 1 + arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 5f94a2df7c778f..bf040b3ab982a7 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -107,6 +107,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc0_default>; non-removable; + mmc-ddr-1_8v; status = "okay"; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index 24bb15ca81420c..fb22ca674585ee 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -108,6 +108,7 @@ pinctrl-names = "default"; pinctrl-0 = <&pinctrl_sdmmc0_default>; non-removable; + mmc-ddr-1_8v; status = "okay"; }; From 15607e63f2a4d5ea764f91aa8506f5d4a6155b97 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 17 Nov 2015 16:25:45 +0100 Subject: [PATCH 350/381] ARM: at91/dt: add always-on to 1.8V regulator As the SDHCI controller needs the 1.8V line to be always enabled for some eMMC configurations, set the proper "regulator-always-on" property to the board DTS files. Note that the sdhci classical regulator definitions doesn't suit our controller for this 1.8V purpose. Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 1 + arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index bf040b3ab982a7..c5f98cf1679982 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -217,6 +217,7 @@ regulator-name = "VDD_SDHC_1V8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + regulator-always-on; }; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index fb22ca674585ee..5f5ccf58274874 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -218,6 +218,7 @@ regulator-name = "VDD_SDHC_1V8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; + regulator-always-on; }; }; }; From dbe62cb2fbb652da8c5ee61b3f595a7bb868bf7a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 17 Nov 2015 16:41:45 +0100 Subject: [PATCH 351/381] Makefile: add EXTRAVERSION for linux4sam 5.0-beta1 Signed-off-by: Nicolas Ferre --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f5c8983aeeb7fc..064617258497aa 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 PATCHLEVEL = 1 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -linux4sam_5.0-beta1 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* From 75f5de052c909c537ba9ea9b0ab5c765eefccf6b Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Wed, 18 Nov 2015 15:10:28 +0800 Subject: [PATCH 352/381] [linux-4.1-at91] ARM: at91: classd: add gclk's parent clock Set the gclk's parent clock to audio clock. Signed-off-by: Songjun Wu --- sound/soc/atmel/atmel-classd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 8276675730ef12..2f5190b8a6cebd 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -588,6 +588,12 @@ static int atmel_classd_probe(struct platform_device *pdev) return ret; } + ret = clk_set_parent(dd->gclk, dd->aclk); + if (ret) { + dev_err(dev, "failed to set GCK parent clock: %d\n", ret); + return ret; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(dev, "no memory resource\n"); From 225af79aa2ff061bc6a01fa6bfce4c58102736a8 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Wed, 18 Nov 2015 16:46:52 +0800 Subject: [PATCH 353/381] [linux-4.1-at91] ARM: at91: classd: support the mono channel Add code to support the mono channel audio. Signed-off-by: Songjun Wu --- sound/soc/atmel/atmel-classd.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 2f5190b8a6cebd..10ac47df6d3452 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -106,7 +106,7 @@ static const struct snd_pcm_hardware atmel_classd_hw = { .rates = ATMEL_CLASSD_RATES, .rate_min = 8000, .rate_max = 96000, - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .buffer_bytes_max = 64 * 1024, .period_bytes_min = 256, @@ -145,7 +145,7 @@ static const struct snd_soc_dai_ops atmel_classd_cpu_dai_ops = { static struct snd_soc_dai_driver atmel_classd_cpu_dai = { .playback = { - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = ATMEL_CLASSD_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE,}, @@ -171,9 +171,13 @@ atmel_classd_platform_configure_dma(struct snd_pcm_substream *substream, return -EINVAL; } + if (params_channels(params) == 1) + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + else + slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + slave_config->direction = DMA_MEM_TO_DEV; slave_config->dst_addr = dd->phy_base + CLASSD_THR; - slave_config->dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; slave_config->dst_maxburst = 1; slave_config->src_maxburst = 1; slave_config->device_fc = false; @@ -486,7 +490,7 @@ static struct snd_soc_dai_driver atmel_classd_codec_dai = { .name = ATMEL_CLASSD_CODEC_DAI_NAME, .playback = { .stream_name = "Playback", - .channels_min = 2, + .channels_min = 1, .channels_max = 2, .rates = ATMEL_CLASSD_RATES, .formats = SNDRV_PCM_FMTBIT_S16_LE, From aaace60940431762a005b25c9ba47d4246c7d3bb Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Mon, 16 Nov 2015 19:22:08 +0100 Subject: [PATCH 354/381] usb: gadget: atmel_usba_udc: Expose correct device speed Following changes that appeared in lk 4.0.0, the gadget udc driver for some ARM based Atmel SoCs (e.g. at91sam9x5 and sama5d3 families) incorrectly deduced full-speed USB link speed even when the hardware had negotiated a high-speed link. The fix is to make sure that the UDPHS Interrupt Enable Register value does not mask the SPEED bit in the Interrupt Status Register. For a mass storage gadget this problem lead to failures when the host had a USB 3 port with the xhci_hcd driver. If the host was a USB 2 port using the ehci_hcd driver then the mass storage gadget worked (but probably at a lower speed than it should have). Signed-off-by: Douglas Gilbert Reviewed-by: Boris Brezillon Cc: #4.0+ Fixes: 9870d895ad87 ("usb: atmel_usba_udc: Mask status with enabled irqs") Signed-off-by: Felipe Balbi --- drivers/usb/gadget/udc/atmel_usba_udc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 351d48550c332a..d6ca3697d3c8db 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -1634,7 +1634,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) spin_lock(&udc->lock); int_enb = usba_int_enb_get(udc); - status = usba_readl(udc, INT_STA) & int_enb; + status = usba_readl(udc, INT_STA) & (int_enb | USBA_HIGH_SPEED); DBG(DBG_INT, "irq, status=%#08x\n", status); if (status & USBA_DET_SUSPEND) { From 7928127a01863cc267de7485607f131d76e4b0a3 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Fri, 20 Nov 2015 10:02:59 +0800 Subject: [PATCH 355/381] ARM: defconfig/at91: sama5: enable Bosch M_CAN driver Add CONFIG_CAN_M_CAN=y to enable Bosch M_CAN devices driver. Signed-off-by: Wenyou Yang --- arch/arm/configs/sama5_defconfig | 1 + arch/arm/configs/sama5d2_defconfig | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 2b8496eb5b82ee..38082920f1f6fd 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -55,6 +55,7 @@ CONFIG_IPV6=y CONFIG_IPV6_SIT_6RD=y CONFIG_CAN=y CONFIG_CAN_AT91=y +CONFIG_CAN_M_CAN=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_MAC80211_LEDS=y diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig index f06f3b55b70737..67311e1f12d381 100644 --- a/arch/arm/configs/sama5d2_defconfig +++ b/arch/arm/configs/sama5d2_defconfig @@ -45,6 +45,7 @@ CONFIG_IP_MULTICAST=y # CONFIG_IPV6 is not set CONFIG_CAN=y CONFIG_CAN_AT91=y +CONFIG_CAN_M_CAN=y CONFIG_CFG80211=y CONFIG_MAC80211=y CONFIG_MAC80211_LEDS=y From deb4ced62108b4b9e6c9641048994713ee852838 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Tue, 10 Nov 2015 14:49:04 +0800 Subject: [PATCH 356/381] ARM: at91/dt: sama5d2: add M_CAN device nodes Due to the CAN Message RAM can be shared by multi M_CAN instances, so the base address of the CAN Message RAM for CAN0 and CAN1 are shared at 0x00210000. The default base address of the CAN Message RAM for CAN0 and CAN1 are configured at 0x200000 in CAN Memories Address-based Register. To avoid conflict with SRAM map for pm, change them to 0x2100000 in the AT91Bootstrap. As said in SAMA5D2 datasheet, the CAN clock is recommended to use frequencies of 20, 40 or 80 MHz, and to select the UPLLCK(480 MHz) as source clock. So, the "assigned-clock-rates" property has three options: 20000000, 40000000, and 80000000. The "assigned-clock-parents" property should be referred to utmi fixedly. Signed-off-by: Wenyou Yang --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 25 ++++++++- .../boot/dts/at91-sama5d2_xplained_pda4.dts | 22 ++++++++ arch/arm/boot/dts/sama5d2.dtsi | 56 +++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index c5f98cf1679982..9020b4be18f601 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -258,6 +258,12 @@ pinctrl-0 = <&pinctrl_i2s0_default>; }; + can0: can@f8054000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can0_default>; + status = "okay"; + }; + uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; @@ -298,6 +304,18 @@ }; pinctrl@fc038000 { + pinctrl_can0_default: can0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_can1_default: can1_default { + pinmux = , + ; + bias-disable; + }; + pinctrl_classd_default: classd_default { pinmux = , , @@ -444,7 +462,6 @@ pinmux = ; bias-disable; }; - }; classd@fc048000 { @@ -454,6 +471,12 @@ atmel,non-overlap-time = <10>; status = "okay"; }; + + can1: can@fc050000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can1_default>; + status = "okay"; + }; }; }; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index 5f5ccf58274874..55f6eae235073f 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -259,6 +259,11 @@ pinctrl-0 = <&pinctrl_i2s0_default>; }; + can0: can@f8054000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can0_default>; + }; + uart3: serial@fc008000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart3_default>; @@ -299,6 +304,18 @@ }; pinctrl@fc038000 { + pinctrl_can0_default: can0_default { + pinmux = , + ; + bias-disable; + }; + + pinctrl_can1_default: can1_default { + pinmux = , + ; + bias-disable; + }; + pinctrl_classd_default: classd_default { pinmux = , , @@ -469,6 +486,11 @@ atmel,non-overlap-time = <10>; status = "okay"; }; + + can1: can@fc050000 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_can1_default>; + }; }; }; diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index eb6c739ade56ab..3c03074fad15f2 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -695,6 +695,18 @@ atmel,clk-output-range = <0 83000000>; }; + can0_clk: can0_clk { + #clock-cells = <0>; + reg = <56>; + atmel,clk-output-range = <0 83000000>; + }; + + can1_clk: can1_clk { + #clock-cells = <0>; + reg = <57>; + atmel,clk-output-range = <0 83000000>; + }; + classd_clk: classd_clk { #clock-cells = <0>; reg = <59>; @@ -819,6 +831,18 @@ reg = <55>; }; + can0_gclk: can0_gclk { + #clock-cells = <0>; + reg = <56>; + atmel,clk-output-range = <0 80000000>; + }; + + can1_gclk: can1_gclk { + #clock-cells = <0>; + reg = <57>; + atmel,clk-output-range = <0 80000000>; + }; + classd_gclk: classd_gclk { #clock-cells = <0>; reg = <59>; @@ -1071,6 +1095,22 @@ status = "disabled"; }; + can0: can@f8054000 { + compatible = "bosch,m_can"; + reg = <0xf8054000 0x4000>, <0x210000 0x4000>; + reg-names = "m_can", "message_ram"; + interrupts = <56 IRQ_TYPE_LEVEL_HIGH 7>, + <64 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-names = "int0", "int1"; + clocks = <&can0_clk>, <&can0_gclk>; + clock-names = "hclk", "cclk"; + assigned-clocks = <&can0_gclk>; + assigned-clock-parents = <&utmi>; + assigned-clock-rates = <40000000>; + bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>; + status = "disabled"; + }; + spi1: spi@fc000000 { compatible = "atmel,at91rm9200-spi"; reg = <0xfc000000 0x100>; @@ -1222,6 +1262,22 @@ status = "disabled"; }; + can1: can@fc050000 { + compatible = "bosch,m_can"; + reg = <0xfc050000 0x4000>, <0x210000 0x4000>; + reg-names = "m_can", "message_ram"; + interrupts = <57 IRQ_TYPE_LEVEL_HIGH 7>, + <65 IRQ_TYPE_LEVEL_HIGH 7>; + interrupt-names = "int0", "int1"; + clocks = <&can1_clk>, <&can1_gclk>; + clock-names = "hclk", "cclk"; + assigned-clocks = <&can1_gclk>; + assigned-clock-parents = <&utmi>; + assigned-clock-rates = <40000000>; + bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>; + status = "disabled"; + }; + chipid@fc069000 { compatible = "atmel,sama5d2-chipid"; reg = <0xfc069000 0x8>; From 0a5f57cc9ac0b312c7234c5e98283b283c9361b3 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Mon, 23 Nov 2015 11:13:00 +0100 Subject: [PATCH 357/381] ARM: at91/defconfig: align sama5 with sama5d2 defconfig The sama5d2_defconfig is about to be removed, align the generic one with sama5d2 support Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5_defconfig | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 38082920f1f6fd..84ff2a7433d81b 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -5,11 +5,11 @@ CONFIG_LOG_BUF_SHIFT=16 CONFIG_BLK_DEV_INITRD=y CONFIG_EMBEDDED=y CONFIG_SLAB=y +CONFIG_JUMP_LABEL=y CONFIG_MODULES=y CONFIG_MODULE_FORCE_LOAD=y CONFIG_MODULE_UNLOAD=y CONFIG_MODULE_FORCE_UNLOAD=y -CONFIG_LBDAF=y # CONFIG_BLK_DEV_BSG is not set # CONFIG_IOSCHED_DEADLINE is not set # CONFIG_IOSCHED_CFQ is not set @@ -21,19 +21,16 @@ CONFIG_AEABI=y CONFIG_CMA=y CONFIG_CMA_DEBUGFS=y CONFIG_UACCESS_WITH_MEMCPY=y +# CONFIG_ATAGS is not set CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_ARM_APPENDED_DTB=y CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" CONFIG_KEXEC=y -CONFIG_AUTO_ZRELADDR=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_PM=y CONFIG_PM_DEBUG=y -CONFIG_PM_ADVANCED_DEBUG=y CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -41,18 +38,12 @@ CONFIG_INET=y CONFIG_IP_MULTICAST=y CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y -CONFIG_IP_PNP_BOOTP=y -CONFIG_IP_PNP_RARP=y # CONFIG_INET_XFRM_MODE_TRANSPORT is not set # CONFIG_INET_XFRM_MODE_TUNNEL is not set # CONFIG_INET_XFRM_MODE_BEET is not set # CONFIG_INET_LRO is not set # CONFIG_INET_DIAG is not set -CONFIG_IPV6=y -# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET6_XFRM_MODE_TUNNEL is not set -# CONFIG_INET6_XFRM_MODE_BEET is not set -CONFIG_IPV6_SIT_6RD=y +# CONFIG_IPV6 is not set CONFIG_CAN=y CONFIG_CAN_AT91=y CONFIG_CAN_M_CAN=y @@ -81,25 +72,29 @@ CONFIG_BLK_DEV_RAM_COUNT=4 CONFIG_BLK_DEV_RAM_SIZE=8192 CONFIG_ATMEL_TCLIB=y CONFIG_ATMEL_SSC=y -CONFIG_SRAM=y CONFIG_EEPROM_AT24=y -CONFIG_EEPROM_93CX6=m CONFIG_SCSI=y CONFIG_BLK_DEV_SD=y # CONFIG_SCSI_LOWLEVEL is not set CONFIG_NETDEVICES=y +# CONFIG_NET_VENDOR_ARC is not set CONFIG_MACB=y # CONFIG_NET_VENDOR_BROADCOM is not set # CONFIG_NET_VENDOR_CIRRUS is not set # CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HISILICON is not set # CONFIG_NET_VENDOR_INTEL is not set # CONFIG_NET_VENDOR_MARVELL is not set # CONFIG_NET_VENDOR_MICREL is not set # CONFIG_NET_VENDOR_MICROCHIP is not set # CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_ROCKER is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set # CONFIG_NET_VENDOR_SEEQ is not set # CONFIG_NET_VENDOR_SMSC is not set # CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_VIA is not set # CONFIG_NET_VENDOR_WIZNET is not set CONFIG_MICREL_PHY=y CONFIG_LIBERTAS_THINFIRM=m @@ -128,7 +123,6 @@ CONFIG_LEGACY_PTY_COUNT=4 CONFIG_SERIAL_ATMEL=y CONFIG_SERIAL_ATMEL_CONSOLE=y CONFIG_HW_RANDOM=y -CONFIG_I2C=y CONFIG_I2C_CHARDEV=y CONFIG_I2C_AT91=y CONFIG_I2C_GPIO=y @@ -163,6 +157,7 @@ CONFIG_SOC_CAMERA_OV2640=m CONFIG_SOC_CAMERA_OV5642=m CONFIG_SOC_CAMERA_OV6650=m CONFIG_SOC_CAMERA_OV772X=m +CONFIG_SOC_CAMERA_OV7740=m CONFIG_SOC_CAMERA_OV9640=m CONFIG_SOC_CAMERA_OV9740=m CONFIG_DRM=y @@ -173,12 +168,12 @@ CONFIG_LCD_CLASS_DEVICE=y CONFIG_BACKLIGHT_CLASS_DEVICE=y # CONFIG_BACKLIGHT_GENERIC is not set CONFIG_BACKLIGHT_PWM=y -CONFIG_FRAMEBUFFER_CONSOLE=y CONFIG_SOUND=y CONFIG_SND=y CONFIG_SND_SOC=y CONFIG_SND_ATMEL_SOC=y CONFIG_SND_ATMEL_SOC_WM8904=y +CONFIG_SND_ATMEL_SOC_CLASSD=y CONFIG_SND_ATMEL_SOC_I2S=y # CONFIG_HID_GENERIC is not set CONFIG_USB=y @@ -243,12 +238,11 @@ CONFIG_DEBUG_FS=y CONFIG_DEBUG_MEMORY_INIT=y # CONFIG_SCHED_DEBUG is not set # CONFIG_FTRACE is not set -CONFIG_DEBUG_USER=y +CONFIG_CRYPTO_HMAC=y # CONFIG_CRYPTO_ANSI_CPRNG is not set CONFIG_CRYPTO_USER_API_HASH=m CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_USER_API_RNG=m CONFIG_CRYPTO_DEV_ATMEL_AES=y CONFIG_CRYPTO_DEV_ATMEL_TDES=y CONFIG_CRYPTO_DEV_ATMEL_SHA=y -CONFIG_CRC_CCITT=m -CONFIG_CRC_ITU_T=m From c6952f8327afce2766ab3fbebed731132e2a5a28 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Tue, 24 Nov 2015 12:05:09 +0100 Subject: [PATCH 358/381] clk: at91: audio PLL: remove debug directive Signed-off-by: Nicolas Ferre --- drivers/clk/at91/clk-audio-pll-pad.c | 2 -- drivers/clk/at91/clk-audio-pll-pmc.c | 2 -- drivers/clk/at91/clk-audio-pll.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/drivers/clk/at91/clk-audio-pll-pad.c b/drivers/clk/at91/clk-audio-pll-pad.c index 74dbb95471e8cd..b0c8fdd13f03ee 100644 --- a/drivers/clk/at91/clk-audio-pll-pad.c +++ b/drivers/clk/at91/clk-audio-pll-pad.c @@ -8,8 +8,6 @@ * (at your option) any later version. * */ -#define DEBUG 12 - #include #include #include diff --git a/drivers/clk/at91/clk-audio-pll-pmc.c b/drivers/clk/at91/clk-audio-pll-pmc.c index e7be19320116b6..f32a470934fb19 100644 --- a/drivers/clk/at91/clk-audio-pll-pmc.c +++ b/drivers/clk/at91/clk-audio-pll-pmc.c @@ -8,8 +8,6 @@ * (at your option) any later version. * */ -#define DEBUG 12 - #include #include #include diff --git a/drivers/clk/at91/clk-audio-pll.c b/drivers/clk/at91/clk-audio-pll.c index 309f2845f85676..5f8db937a2c2d7 100644 --- a/drivers/clk/at91/clk-audio-pll.c +++ b/drivers/clk/at91/clk-audio-pll.c @@ -9,8 +9,6 @@ * (at your option) any later version. * */ -#define DEBUG 12 - #include #include #include From 4643b2e2e66b78c27d9be6f4b3193ceb2453a6ce Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 12 Nov 2015 15:16:53 +0100 Subject: [PATCH 359/381] dmaengine: at_xdmac: use %pad format string for dma_addr_t dma_addr_t may be defined as 32 or 64 bit depending on configuration, so it cannot be printed using the normal format strings, as gcc correctly warns: drivers/dma/at_xdmac.c: In function 'at_xdmac_interleaved_queue_desc': drivers/dma/at_xdmac.c:922:51: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'dma_addr_t {aka long long unsigned int}' [-Wformat=] This changes the format strings to use the special "%pad" format string that prints a dma_addr_t, and changes the arguments so we pass the address by reference as required. Signed-off-by: Arnd Bergmann Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b5e132d4bae5b5..7f039de143f0d0 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -920,8 +920,8 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, desc->lld.mbr_cfg = chan_cc; dev_dbg(chan2dev(chan), - "%s: lld: mbr_sa=0x%08x, mbr_da=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", - __func__, desc->lld.mbr_sa, desc->lld.mbr_da, + "%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", + __func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc, desc->lld.mbr_cfg); /* Chain lld. */ @@ -953,8 +953,8 @@ at_xdmac_prep_interleaved(struct dma_chan *chan, if ((xt->numf > 1) && (xt->frame_size > 1)) return NULL; - dev_dbg(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", - __func__, xt->src_start, xt->dst_start, xt->numf, + dev_dbg(chan2dev(chan), "%s: src=%pad, dest=%pad, numf=%d, frame_size=%d, flags=0x%lx\n", + __func__, &xt->src_start, &xt->dst_start, xt->numf, xt->frame_size, flags); src_addr = xt->src_start; @@ -1179,8 +1179,8 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, desc->lld.mbr_cfg = chan_cc; dev_dbg(chan2dev(chan), - "%s: lld: mbr_da=0x%08x, mbr_ds=0x%08x, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", - __func__, desc->lld.mbr_da, desc->lld.mbr_ds, desc->lld.mbr_ubc, + "%s: lld: mbr_da=%pad, mbr_ds=%pad, mbr_ubc=0x%08x, mbr_cfg=0x%08x\n", + __func__, &desc->lld.mbr_da, &desc->lld.mbr_ds, desc->lld.mbr_ubc, desc->lld.mbr_cfg); return desc; @@ -1193,8 +1193,8 @@ at_xdmac_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); struct at_xdmac_desc *desc; - dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", - __func__, dest, len, value, flags); + dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, &dest, len, value, flags); if (unlikely(!len)) return NULL; @@ -1229,8 +1229,8 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl, /* Prepare descriptors. */ for_each_sg(sgl, sg, sg_len, i) { - dev_dbg(chan2dev(chan), "%s: dest=0x%08x, len=%d, pattern=0x%x, flags=0x%lx\n", - __func__, sg_dma_address(sg), sg_dma_len(sg), + dev_dbg(chan2dev(chan), "%s: dest=%pad, len=%d, pattern=0x%x, flags=0x%lx\n", + __func__, &sg_dma_address(sg), sg_dma_len(sg), value, flags); desc = at_xdmac_memset_create_desc(chan, atchan, sg_dma_address(sg), From 639642a9385086b1a1822f95c720d3ee906358b3 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 23 Nov 2015 13:58:00 +0100 Subject: [PATCH 360/381] dmaengine: at_xdmac: fix macro typo Fix typo in a macro which was not used until now. It explains why there is no error at compilation time. Signed-off-by: Ludovic Desroches Fixes: e1f7c9eee707 "dmaengine: at_xdmac: creation of the atmel eXtended DMA Controller driver" Cc: stable@vger.kernel.org # 3.19 and later --- drivers/dma/at_xdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 7f039de143f0d0..d09277f7dd1a02 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -156,7 +156,7 @@ #define AT_XDMAC_CC_WRIP (0x1 << 23) /* Write in Progress (read only) */ #define AT_XDMAC_CC_WRIP_DONE (0x0 << 23) #define AT_XDMAC_CC_WRIP_IN_PROGRESS (0x1 << 23) -#define AT_XDMAC_CC_PERID(i) (0x7f & (h) << 24) /* Channel Peripheral Identifier */ +#define AT_XDMAC_CC_PERID(i) (0x7f & (i) << 24) /* Channel Peripheral Identifier */ #define AT_XDMAC_CDS_MSP 0x2C /* Channel Data Stride Memory Set Pattern */ #define AT_XDMAC_CSUS 0x30 /* Channel Source Microblock Stride */ #define AT_XDMAC_CDUS 0x34 /* Channel Destination Microblock Stride */ From 38c874dc0a3e62d46c8701ad858a4aed364ebccf Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 23 Nov 2015 10:46:15 +0100 Subject: [PATCH 361/381] dmaengine: at_xdmac: fix spurious flag status for mem2mem transfers When setting the channel configuration register, the perid field is not set to 0 since it is useless for mem2mem transfers. Unfortunately, a device has 0 as perid. It could cause spurious flags status because the controller could mix some events from the two channels. For that reason, use the highest perid value for mem2mem transfers since it doesn't match the perid of other devices. Signed-off-by: Ludovic Desroches --- drivers/dma/at_xdmac.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index d09277f7dd1a02..b90e62fe72ad6d 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -863,8 +863,12 @@ at_xdmac_interleaved_queue_desc(struct dma_chan *chan, * access. Hopefully we can access DDR through both ports (at least on * SAMA5D4x), so we can use the same interface for source and dest, * that solves the fact we don't know the direction. + * ERRATA: Even if useless for memory transfers, the PERID has to not + * match the one of another channel. If not, it could lead to spurious + * flag status. */ - u32 chan_cc = AT_XDMAC_CC_DIF(0) + u32 chan_cc = AT_XDMAC_CC_PERID(0x3f) + | AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0) | AT_XDMAC_CC_MBSIZE_SIXTEEN | AT_XDMAC_CC_TYPE_MEM_TRAN; @@ -1039,8 +1043,12 @@ at_xdmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, * access DDR through both ports (at least on SAMA5D4x), so we can use * the same interface for source and dest, that solves the fact we * don't know the direction. + * ERRATA: Even if useless for memory transfers, the PERID has to not + * match the one of another channel. If not, it could lead to spurious + * flag status. */ - u32 chan_cc = AT_XDMAC_CC_DAM_INCREMENTED_AM + u32 chan_cc = AT_XDMAC_CC_PERID(0x3f) + | AT_XDMAC_CC_DAM_INCREMENTED_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0) @@ -1140,8 +1148,12 @@ static struct at_xdmac_desc *at_xdmac_memset_create_desc(struct dma_chan *chan, * access. Hopefully we can access DDR through both ports (at least on * SAMA5D4x), so we can use the same interface for source and dest, * that solves the fact we don't know the direction. + * ERRATA: Even if useless for memory transfers, the PERID has to not + * match the one of another channel. If not, it could lead to spurious + * flag status. */ - u32 chan_cc = AT_XDMAC_CC_DAM_UBS_AM + u32 chan_cc = AT_XDMAC_CC_PERID(0x3f) + | AT_XDMAC_CC_DAM_UBS_AM | AT_XDMAC_CC_SAM_INCREMENTED_AM | AT_XDMAC_CC_DIF(0) | AT_XDMAC_CC_SIF(0) From 9ed55fd98f49fc54ce023ce3f08c9b8060cf4e92 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 15 Apr 2015 10:37:52 +0200 Subject: [PATCH 362/381] dmaengine: at_xdmac: fix false condition for memset_sg transfers The code was not in agreement with the comments. Signed-off-by: Ludovic Desroches --- drivers/dma/at_xdmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b90e62fe72ad6d..305c04d89b9c5b 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -1345,7 +1345,7 @@ at_xdmac_prep_dma_memset_sg(struct dma_chan *chan, struct scatterlist *sgl, * since we don't care about the stride anymore. */ if ((i == (sg_len - 1)) && - sg_dma_len(ppsg) == sg_dma_len(psg)) { + sg_dma_len(psg) == sg_dma_len(sg)) { dev_dbg(chan2dev(chan), "%s: desc 0x%p can be merged with desc 0x%p\n", __func__, desc, pdesc); From 3080f4689d199eb0ef1aca045072b2da87f62e9f Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 11 Nov 2015 19:11:48 +0100 Subject: [PATCH 363/381] mmc: sdhci-of-at91: add PM support Add runtime PM support and use runtime_force_suspend|resume() for system PM. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 72 +++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 06d0b50dfe71d2..81ab9db6103a67 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "sdhci-pltfm.h" @@ -51,6 +53,60 @@ static const struct of_device_id sdhci_at91_dt_match[] = { {} }; +#ifdef CONFIG_PM +static int sdhci_at91_runtime_suspend(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + int ret; + + ret = sdhci_runtime_suspend_host(host); + + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->hclock); + clk_disable_unprepare(priv->mainck); + + return ret; +} + +static int sdhci_at91_runtime_resume(struct device *dev) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + int ret; + + ret = clk_prepare_enable(priv->mainck); + if (ret) { + dev_err(dev, "can't enable mainck\n"); + return ret; + } + + ret = clk_prepare_enable(priv->hclock); + if (ret) { + dev_err(dev, "can't enable hclock\n"); + return ret; + } + + ret = clk_prepare_enable(priv->gck); + if (ret) { + dev_err(dev, "can't enable gck\n"); + return ret; + } + + return sdhci_runtime_resume_host(host); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops sdhci_at91_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SET_RUNTIME_PM_OPS(sdhci_at91_runtime_suspend, + sdhci_at91_runtime_resume, + NULL) +}; + static int sdhci_at91_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -144,12 +200,20 @@ static int sdhci_at91_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, 50); + pm_runtime_use_autosuspend(&pdev->dev); + ret = sdhci_add_host(host); if (ret) - goto clocks_disable_unprepare; + goto pm_runtime_disable; return 0; +pm_runtime_disable: + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); clocks_disable_unprepare: clk_disable_unprepare(priv->gck); clk_disable_unprepare(priv->mainck); @@ -165,6 +229,10 @@ static int sdhci_at91_remove(struct platform_device *pdev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_at91_priv *priv = pltfm_host->priv; + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + sdhci_pltfm_unregister(pdev); clk_disable_unprepare(priv->gck); @@ -178,7 +246,7 @@ static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", .of_match_table = sdhci_at91_dt_match, - .pm = SDHCI_PLTFM_PMOPS, + .pm = &sdhci_at91_dev_pm_ops, }, .probe = sdhci_at91_probe, .remove = sdhci_at91_remove, From 769be0cd885c5f3ca97ac6419836ab1b6711060e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 23 Nov 2015 15:22:13 +0100 Subject: [PATCH 364/381] mmc: atmel-mci: move atmel-mci-regs.h content in atmel-mci.c atmel-mci-regs.h is only included in atmel-mci.c so move its content in the driver and do some cleanup in these definitions to remove checkpatch errors. Signed-off-by: Ludovic Desroches --- drivers/mmc/host/atmel-mci-regs.h | 171 ------------------------------ drivers/mmc/host/atmel-mci.c | 150 +++++++++++++++++++++++++- 2 files changed, 149 insertions(+), 172 deletions(-) delete mode 100644 drivers/mmc/host/atmel-mci-regs.h diff --git a/drivers/mmc/host/atmel-mci-regs.h b/drivers/mmc/host/atmel-mci-regs.h deleted file mode 100644 index 0aa44e679df496..00000000000000 --- a/drivers/mmc/host/atmel-mci-regs.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Atmel MultiMedia Card Interface driver - * - * Copyright (C) 2004-2006 Atmel Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -/* - * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors - * Registers and bitfields marked with [2] are only available in MCI2 - */ - -#ifndef __DRIVERS_MMC_ATMEL_MCI_H__ -#define __DRIVERS_MMC_ATMEL_MCI_H__ - -/* MCI Register Definitions */ -#define ATMCI_CR 0x0000 /* Control */ -# define ATMCI_CR_MCIEN ( 1 << 0) /* MCI Enable */ -# define ATMCI_CR_MCIDIS ( 1 << 1) /* MCI Disable */ -# define ATMCI_CR_PWSEN ( 1 << 2) /* Power Save Enable */ -# define ATMCI_CR_PWSDIS ( 1 << 3) /* Power Save Disable */ -# define ATMCI_CR_SWRST ( 1 << 7) /* Software Reset */ -#define ATMCI_MR 0x0004 /* Mode */ -# define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ -# define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ -# define ATMCI_MR_RDPROOF ( 1 << 11) /* Read Proof */ -# define ATMCI_MR_WRPROOF ( 1 << 12) /* Write Proof */ -# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */ -# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */ -# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */ -# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ -#define ATMCI_DTOR 0x0008 /* Data Timeout */ -# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ -# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ -#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ -# define ATMCI_SDCSEL_SLOT_A ( 0 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_SLOT_B ( 1 << 0) /* Select SD slot A */ -# define ATMCI_SDCSEL_MASK ( 3 << 0) -# define ATMCI_SDCBUS_1BIT ( 0 << 6) /* 1-bit data bus */ -# define ATMCI_SDCBUS_4BIT ( 2 << 6) /* 4-bit data bus */ -# define ATMCI_SDCBUS_8BIT ( 3 << 6) /* 8-bit data bus[2] */ -# define ATMCI_SDCBUS_MASK ( 3 << 6) -#define ATMCI_ARGR 0x0010 /* Command Argument */ -#define ATMCI_CMDR 0x0014 /* Command */ -# define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ -# define ATMCI_CMDR_RSPTYP_NONE ( 0 << 6) /* No response */ -# define ATMCI_CMDR_RSPTYP_48BIT ( 1 << 6) /* 48-bit response */ -# define ATMCI_CMDR_RSPTYP_136BIT ( 2 << 6) /* 136-bit response */ -# define ATMCI_CMDR_SPCMD_INIT ( 1 << 8) /* Initialization command */ -# define ATMCI_CMDR_SPCMD_SYNC ( 2 << 8) /* Synchronized command */ -# define ATMCI_CMDR_SPCMD_INT ( 4 << 8) /* Interrupt command */ -# define ATMCI_CMDR_SPCMD_INTRESP ( 5 << 8) /* Interrupt response */ -# define ATMCI_CMDR_OPDCMD ( 1 << 11) /* Open Drain */ -# define ATMCI_CMDR_MAXLAT_5CYC ( 0 << 12) /* Max latency 5 cycles */ -# define ATMCI_CMDR_MAXLAT_64CYC ( 1 << 12) /* Max latency 64 cycles */ -# define ATMCI_CMDR_START_XFER ( 1 << 16) /* Start data transfer */ -# define ATMCI_CMDR_STOP_XFER ( 2 << 16) /* Stop data transfer */ -# define ATMCI_CMDR_TRDIR_WRITE ( 0 << 18) /* Write data */ -# define ATMCI_CMDR_TRDIR_READ ( 1 << 18) /* Read data */ -# define ATMCI_CMDR_BLOCK ( 0 << 19) /* Single-block transfer */ -# define ATMCI_CMDR_MULTI_BLOCK ( 1 << 19) /* Multi-block transfer */ -# define ATMCI_CMDR_STREAM ( 2 << 19) /* MMC Stream transfer */ -# define ATMCI_CMDR_SDIO_BYTE ( 4 << 19) /* SDIO Byte transfer */ -# define ATMCI_CMDR_SDIO_BLOCK ( 5 << 19) /* SDIO Block transfer */ -# define ATMCI_CMDR_SDIO_SUSPEND ( 1 << 24) /* SDIO Suspend Command */ -# define ATMCI_CMDR_SDIO_RESUME ( 2 << 24) /* SDIO Resume Command */ -#define ATMCI_BLKR 0x0018 /* Block */ -# define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ -# define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ -#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ -# define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ -# define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ -#define ATMCI_RSPR 0x0020 /* Response 0 */ -#define ATMCI_RSPR1 0x0024 /* Response 1 */ -#define ATMCI_RSPR2 0x0028 /* Response 2 */ -#define ATMCI_RSPR3 0x002c /* Response 3 */ -#define ATMCI_RDR 0x0030 /* Receive Data */ -#define ATMCI_TDR 0x0034 /* Transmit Data */ -#define ATMCI_SR 0x0040 /* Status */ -#define ATMCI_IER 0x0044 /* Interrupt Enable */ -#define ATMCI_IDR 0x0048 /* Interrupt Disable */ -#define ATMCI_IMR 0x004c /* Interrupt Mask */ -# define ATMCI_CMDRDY ( 1 << 0) /* Command Ready */ -# define ATMCI_RXRDY ( 1 << 1) /* Receiver Ready */ -# define ATMCI_TXRDY ( 1 << 2) /* Transmitter Ready */ -# define ATMCI_BLKE ( 1 << 3) /* Data Block Ended */ -# define ATMCI_DTIP ( 1 << 4) /* Data Transfer In Progress */ -# define ATMCI_NOTBUSY ( 1 << 5) /* Data Not Busy */ -# define ATMCI_ENDRX ( 1 << 6) /* End of RX Buffer */ -# define ATMCI_ENDTX ( 1 << 7) /* End of TX Buffer */ -# define ATMCI_SDIOIRQA ( 1 << 8) /* SDIO IRQ in slot A */ -# define ATMCI_SDIOIRQB ( 1 << 9) /* SDIO IRQ in slot B */ -# define ATMCI_SDIOWAIT ( 1 << 12) /* SDIO Read Wait Operation Status */ -# define ATMCI_CSRCV ( 1 << 13) /* CE-ATA Completion Signal Received */ -# define ATMCI_RXBUFF ( 1 << 14) /* RX Buffer Full */ -# define ATMCI_TXBUFE ( 1 << 15) /* TX Buffer Empty */ -# define ATMCI_RINDE ( 1 << 16) /* Response Index Error */ -# define ATMCI_RDIRE ( 1 << 17) /* Response Direction Error */ -# define ATMCI_RCRCE ( 1 << 18) /* Response CRC Error */ -# define ATMCI_RENDE ( 1 << 19) /* Response End Bit Error */ -# define ATMCI_RTOE ( 1 << 20) /* Response Time-Out Error */ -# define ATMCI_DCRCE ( 1 << 21) /* Data CRC Error */ -# define ATMCI_DTOE ( 1 << 22) /* Data Time-Out Error */ -# define ATMCI_CSTOE ( 1 << 23) /* Completion Signal Time-out Error */ -# define ATMCI_BLKOVRE ( 1 << 24) /* DMA Block Overrun Error */ -# define ATMCI_DMADONE ( 1 << 25) /* DMA Transfer Done */ -# define ATMCI_FIFOEMPTY ( 1 << 26) /* FIFO Empty Flag */ -# define ATMCI_XFRDONE ( 1 << 27) /* Transfer Done Flag */ -# define ATMCI_ACKRCV ( 1 << 28) /* Boot Operation Acknowledge Received */ -# define ATMCI_ACKRCVE ( 1 << 29) /* Boot Operation Acknowledge Error */ -# define ATMCI_OVRE ( 1 << 30) /* RX Overrun Error */ -# define ATMCI_UNRE ( 1 << 31) /* TX Underrun Error */ -#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ -# define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ -# define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ -# define ATMCI_DMAEN ( 1 << 8) /* DMA Hardware Handshaking Enable */ -#define ATMCI_CFG 0x0054 /* Configuration[2] */ -# define ATMCI_CFG_FIFOMODE_1DATA ( 1 << 0) /* MCI Internal FIFO control mode */ -# define ATMCI_CFG_FERRCTRL_COR ( 1 << 4) /* Flow Error flag reset control mode */ -# define ATMCI_CFG_HSMODE ( 1 << 8) /* High Speed Mode */ -# define ATMCI_CFG_LSYNC ( 1 << 12) /* Synchronize on the last block */ -#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ -# define ATMCI_WP_EN ( 1 << 0) /* WP Enable */ -# define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ -#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ -# define ATMCI_GET_WP_VS(x) ((x) & 0x0f) -# define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) -#define ATMCI_VERSION 0x00FC /* Version */ -#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ - -/* This is not including the FIFO Aperture on MCI2 */ -#define ATMCI_REGS_SIZE 0x100 - -/* Register access macros */ -#ifdef CONFIG_AVR32 -#define atmci_readl(port, reg) \ - __raw_readl((port)->regs + reg) -#define atmci_writel(port, reg, value) \ - __raw_writel((value), (port)->regs + reg) -#else -#define atmci_readl(port, reg) \ - readl_relaxed((port)->regs + reg) -#define atmci_writel(port, reg, value) \ - writel_relaxed((value), (port)->regs + reg) -#endif - -/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ -#ifdef CONFIG_AVR32 -# define ATMCI_PDC_CONNECTED 0 -#else -# define ATMCI_PDC_CONNECTED 1 -#endif - -/* - * Fix sconfig's burst size according to atmel MCI. We need to convert them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * This can be done by finding most significant bit set. - */ -static inline unsigned int atmci_convert_chksize(unsigned int maxburst) -{ - if (maxburst > 1) - return fls(maxburst) - 2; - else - return 0; -} - -#endif /* __DRIVERS_MMC_ATMEL_MCI_H__ */ diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 9a39e0b7e58362..72647bd36cf754 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -45,7 +45,155 @@ #include #include -#include "atmel-mci-regs.h" +/* + * Superset of MCI IP registers integrated in Atmel AVR32 and AT91 Processors + * Registers and bitfields marked with [2] are only available in MCI2 + */ + +/* MCI Register Definitions */ +#define ATMCI_CR 0x0000 /* Control */ +#define ATMCI_CR_MCIEN BIT(0) /* MCI Enable */ +#define ATMCI_CR_MCIDIS BIT(1) /* MCI Disable */ +#define ATMCI_CR_PWSEN BIT(2) /* Power Save Enable */ +#define ATMCI_CR_PWSDIS BIT(3) /* Power Save Disable */ +#define ATMCI_CR_SWRST BIT(7) /* Software Reset */ +#define ATMCI_MR 0x0004 /* Mode */ +#define ATMCI_MR_CLKDIV(x) ((x) << 0) /* Clock Divider */ +#define ATMCI_MR_PWSDIV(x) ((x) << 8) /* Power Saving Divider */ +#define ATMCI_MR_RDPROOF BIT(11) /* Read Proof */ +#define ATMCI_MR_WRPROOF BIT(12) /* Write Proof */ +#define ATMCI_MR_PDCFBYTE BIT(13) /* Force Byte Transfer */ +#define ATMCI_MR_PDCPADV BIT(14) /* Padding Value */ +#define ATMCI_MR_PDCMODE BIT(15) /* PDC-oriented Mode */ +#define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */ +#define ATMCI_DTOR 0x0008 /* Data Timeout */ +#define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */ +#define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */ +#define ATMCI_SDCR 0x000c /* SD Card / SDIO */ +#define ATMCI_SDCSEL_SLOT_A (0 << 0) /* Select SD slot A */ +#define ATMCI_SDCSEL_SLOT_B (1 << 0) /* Select SD slot A */ +#define ATMCI_SDCSEL_MASK (3 << 0) +#define ATMCI_SDCBUS_1BIT (0 << 6) /* 1-bit data bus */ +#define ATMCI_SDCBUS_4BIT (2 << 6) /* 4-bit data bus */ +#define ATMCI_SDCBUS_8BIT (3 << 6) /* 8-bit data bus[2] */ +#define ATMCI_SDCBUS_MASK (3 << 6) +#define ATMCI_ARGR 0x0010 /* Command Argument */ +#define ATMCI_CMDR 0x0014 /* Command */ +#define ATMCI_CMDR_CMDNB(x) ((x) << 0) /* Command Opcode */ +#define ATMCI_CMDR_RSPTYP_NONE (0 << 6) /* No response */ +#define ATMCI_CMDR_RSPTYP_48BIT (1 << 6) /* 48-bit response */ +#define ATMCI_CMDR_RSPTYP_136BIT (2 << 6) /* 136-bit response */ +#define ATMCI_CMDR_SPCMD_INIT (1 << 8) /* Initialization command */ +#define ATMCI_CMDR_SPCMD_SYNC (2 << 8) /* Synchronized command */ +#define ATMCI_CMDR_SPCMD_INT (4 << 8) /* Interrupt command */ +#define ATMCI_CMDR_SPCMD_INTRESP (5 << 8) /* Interrupt response */ +#define ATMCI_CMDR_OPDCMD (1 << 11) /* Open Drain */ +#define ATMCI_CMDR_MAXLAT_5CYC (0 << 12) /* Max latency 5 cycles */ +#define ATMCI_CMDR_MAXLAT_64CYC (1 << 12) /* Max latency 64 cycles */ +#define ATMCI_CMDR_START_XFER (1 << 16) /* Start data transfer */ +#define ATMCI_CMDR_STOP_XFER (2 << 16) /* Stop data transfer */ +#define ATMCI_CMDR_TRDIR_WRITE (0 << 18) /* Write data */ +#define ATMCI_CMDR_TRDIR_READ (1 << 18) /* Read data */ +#define ATMCI_CMDR_BLOCK (0 << 19) /* Single-block transfer */ +#define ATMCI_CMDR_MULTI_BLOCK (1 << 19) /* Multi-block transfer */ +#define ATMCI_CMDR_STREAM (2 << 19) /* MMC Stream transfer */ +#define ATMCI_CMDR_SDIO_BYTE (4 << 19) /* SDIO Byte transfer */ +#define ATMCI_CMDR_SDIO_BLOCK (5 << 19) /* SDIO Block transfer */ +#define ATMCI_CMDR_SDIO_SUSPEND (1 << 24) /* SDIO Suspend Command */ +#define ATMCI_CMDR_SDIO_RESUME (2 << 24) /* SDIO Resume Command */ +#define ATMCI_BLKR 0x0018 /* Block */ +#define ATMCI_BCNT(x) ((x) << 0) /* Data Block Count */ +#define ATMCI_BLKLEN(x) ((x) << 16) /* Data Block Length */ +#define ATMCI_CSTOR 0x001c /* Completion Signal Timeout[2] */ +#define ATMCI_CSTOCYC(x) ((x) << 0) /* CST cycles */ +#define ATMCI_CSTOMUL(x) ((x) << 4) /* CST multiplier */ +#define ATMCI_RSPR 0x0020 /* Response 0 */ +#define ATMCI_RSPR1 0x0024 /* Response 1 */ +#define ATMCI_RSPR2 0x0028 /* Response 2 */ +#define ATMCI_RSPR3 0x002c /* Response 3 */ +#define ATMCI_RDR 0x0030 /* Receive Data */ +#define ATMCI_TDR 0x0034 /* Transmit Data */ +#define ATMCI_SR 0x0040 /* Status */ +#define ATMCI_IER 0x0044 /* Interrupt Enable */ +#define ATMCI_IDR 0x0048 /* Interrupt Disable */ +#define ATMCI_IMR 0x004c /* Interrupt Mask */ +#define ATMCI_CMDRDY BIT(0) /* Command Ready */ +#define ATMCI_RXRDY BIT(1) /* Receiver Ready */ +#define ATMCI_TXRDY BIT(2) /* Transmitter Ready */ +#define ATMCI_BLKE BIT(3) /* Data Block Ended */ +#define ATMCI_DTIP BIT(4) /* Data Transfer In Progress */ +#define ATMCI_NOTBUSY BIT(5) /* Data Not Busy */ +#define ATMCI_ENDRX BIT(6) /* End of RX Buffer */ +#define ATMCI_ENDTX BIT(7) /* End of TX Buffer */ +#define ATMCI_SDIOIRQA BIT(8) /* SDIO IRQ in slot A */ +#define ATMCI_SDIOIRQB BIT(9) /* SDIO IRQ in slot B */ +#define ATMCI_SDIOWAIT BIT(12) /* SDIO Read Wait Operation Status */ +#define ATMCI_CSRCV BIT(13) /* CE-ATA Completion Signal Received */ +#define ATMCI_RXBUFF BIT(14) /* RX Buffer Full */ +#define ATMCI_TXBUFE BIT(15) /* TX Buffer Empty */ +#define ATMCI_RINDE BIT(16) /* Response Index Error */ +#define ATMCI_RDIRE BIT(17) /* Response Direction Error */ +#define ATMCI_RCRCE BIT(18) /* Response CRC Error */ +#define ATMCI_RENDE BIT(19) /* Response End Bit Error */ +#define ATMCI_RTOE BIT(20) /* Response Time-Out Error */ +#define ATMCI_DCRCE BIT(21) /* Data CRC Error */ +#define ATMCI_DTOE BIT(22) /* Data Time-Out Error */ +#define ATMCI_CSTOE BIT(23) /* Completion Signal Time-out Error */ +#define ATMCI_BLKOVRE BIT(24) /* DMA Block Overrun Error */ +#define ATMCI_DMADONE BIT(25) /* DMA Transfer Done */ +#define ATMCI_FIFOEMPTY BIT(26) /* FIFO Empty Flag */ +#define ATMCI_XFRDONE BIT(27) /* Transfer Done Flag */ +#define ATMCI_ACKRCV BIT(28) /* Boot Operation Acknowledge Received */ +#define ATMCI_ACKRCVE BIT(29) /* Boot Operation Acknowledge Error */ +#define ATMCI_OVRE BIT(30) /* RX Overrun Error */ +#define ATMCI_UNRE BIT(31) /* TX Underrun Error */ +#define ATMCI_DMA 0x0050 /* DMA Configuration[2] */ +#define ATMCI_DMA_OFFSET(x) ((x) << 0) /* DMA Write Buffer Offset */ +#define ATMCI_DMA_CHKSIZE(x) ((x) << 4) /* DMA Channel Read and Write Chunk Size */ +#define ATMCI_DMAEN BIT(8) /* DMA Hardware Handshaking Enable */ +#define ATMCI_CFG 0x0054 /* Configuration[2] */ +#define ATMCI_CFG_FIFOMODE_1DATA BIT(0) /* MCI Internal FIFO control mode */ +#define ATMCI_CFG_FERRCTRL_COR BIT(4) /* Flow Error flag reset control mode */ +#define ATMCI_CFG_HSMODE BIT(8) /* High Speed Mode */ +#define ATMCI_CFG_LSYNC BIT(12) /* Synchronize on the last block */ +#define ATMCI_WPMR 0x00e4 /* Write Protection Mode[2] */ +#define ATMCI_WP_EN BIT(0) /* WP Enable */ +#define ATMCI_WP_KEY (0x4d4349 << 8) /* WP Key */ +#define ATMCI_WPSR 0x00e8 /* Write Protection Status[2] */ +#define ATMCI_GET_WP_VS(x) ((x) & 0x0f) +#define ATMCI_GET_WP_VSRC(x) (((x) >> 8) & 0xffff) +#define ATMCI_VERSION 0x00FC /* Version */ +#define ATMCI_FIFO_APERTURE 0x0200 /* FIFO Aperture[2] */ + +/* This is not including the FIFO Aperture on MCI2 */ +#define ATMCI_REGS_SIZE 0x100 + +/* Register access macros */ +#define atmci_readl(port, reg) \ + __raw_readl((port)->regs + reg) +#define atmci_writel(port, reg, value) \ + __raw_writel((value), (port)->regs + reg) + +/* On AVR chips the Peripheral DMA Controller is not connected to MCI. */ +#ifdef CONFIG_AVR32 +# define ATMCI_PDC_CONNECTED 0 +#else +# define ATMCI_PDC_CONNECTED 1 +#endif + +/* + * Fix sconfig's burst size according to atmel MCI. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + * + * This can be done by finding most significant bit set. + */ +static inline unsigned int atmci_convert_chksize(unsigned int maxburst) +{ + if (maxburst > 1) + return fls(maxburst) - 2; + else + return 0; +} #define AUTOSUSPEND_DELAY 50 From c289c410497af2bdb6b343a8108075baf48d36b5 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 23 Nov 2015 15:37:10 +0100 Subject: [PATCH 365/381] MAINTAINERS: remove atmel-mci-regs.h file Remove atmel-mci-regs.h file since it has been merged in atmel-mci.c. Signed-off-by: Ludovic Desroches --- MAINTAINERS | 1 - 1 file changed, 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index c418509dfa1fce..16cf66288c637f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1770,7 +1770,6 @@ ATMEL AT91 / AT32 MCI DRIVER M: Ludovic Desroches S: Maintained F: drivers/mmc/host/atmel-mci.c -F: drivers/mmc/host/atmel-mci-regs.h ATMEL AT91 / AT32 SERIAL DRIVER M: Nicolas Ferre From 0c2012c3b5191dda67e9e11ae8f7c460c33c8b7e Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 23 Nov 2015 16:17:13 +0100 Subject: [PATCH 366/381] mmc: atmel-mci: atmci_convert_chksize depends on controller version The atmci_convert_chksize() function is no more valid for controller version 0x600 due to the introduction of '2 data' chunk size. Signed-off-by: Ludovic Desroches --- drivers/mmc/host/atmel-mci.c | 43 ++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 72647bd36cf754..12a23beadcfb76 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -181,20 +181,6 @@ # define ATMCI_PDC_CONNECTED 1 #endif -/* - * Fix sconfig's burst size according to atmel MCI. We need to convert them as: - * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. - * - * This can be done by finding most significant bit set. - */ -static inline unsigned int atmci_convert_chksize(unsigned int maxburst) -{ - if (maxburst > 1) - return fls(maxburst) - 2; - else - return 0; -} - #define AUTOSUSPEND_DELAY 50 #define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE) @@ -733,6 +719,29 @@ static inline unsigned int atmci_get_version(struct atmel_mci *host) return atmci_readl(host, ATMCI_VERSION) & 0x00000fff; } +/* + * Fix sconfig's burst size according to atmel MCI. We need to convert them as: + * 1 -> 0, 4 -> 1, 8 -> 2, 16 -> 3. + * With version 0x600, we need to convert them as: 1 -> 0, 2 -> 1, 4 -> 2, + * 8 -> 3, 16 -> 4. + * + * This can be done by finding most significant bit set. + */ +static inline unsigned int atmci_convert_chksize(struct atmel_mci *host, + unsigned int maxburst) +{ + unsigned int version = atmci_get_version(host); + unsigned int offset = 2; + + if (version >= 0x600) + offset = 1; + + if (maxburst > 1) + return fls(maxburst) - offset; + else + return 0; +} + static void atmci_timeout_timer(unsigned long data) { struct atmel_mci *host; @@ -1183,11 +1192,13 @@ atmci_prepare_data_dma(struct atmel_mci *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) { direction = DMA_FROM_DEVICE; host->dma_conf.direction = slave_dirn = DMA_DEV_TO_MEM; - maxburst = atmci_convert_chksize(host->dma_conf.src_maxburst); + maxburst = atmci_convert_chksize(host, + host->dma_conf.src_maxburst); } else { direction = DMA_TO_DEVICE; host->dma_conf.direction = slave_dirn = DMA_MEM_TO_DEV; - maxburst = atmci_convert_chksize(host->dma_conf.dst_maxburst); + maxburst = atmci_convert_chksize(host, + host->dma_conf.dst_maxburst); } if (host->caps.has_dma_conf_reg) From e84a966e56c28f1a39355852ee2921d7b5635e35 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Tue, 24 Nov 2015 16:37:59 +0100 Subject: [PATCH 367/381] Revert "mmc: sdhci at91: add suspend/resume" This reverts commit 9072c496d36149a70b2e984a265d4bd01a02da1b. --- drivers/mmc/host/sdhci-of-at91.c | 55 +------------------------------- 1 file changed, 1 insertion(+), 54 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index b9751f20d4a028..06d0b50dfe71d2 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -51,59 +51,6 @@ static const struct of_device_id sdhci_at91_dt_match[] = { {} }; -#ifdef CONFIG_PM_SLEEP -static int sdhci_at91_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_at91_priv *priv = pltfm_host->priv; - int ret; - - ret = sdhci_suspend_host(host); - if (ret) - return ret; - - clk_disable_unprepare(priv->gck); - clk_disable_unprepare(priv->hclock); - clk_disable_unprepare(priv->mainck); - - return 0; -} - -static int sdhci_at91_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct sdhci_host *host = platform_get_drvdata(pdev); - struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); - struct sdhci_at91_priv *priv = pltfm_host->priv; - int ret; - - ret = clk_prepare_enable(priv->mainck); - if (ret) { - dev_err(dev, "can't enable mainck\n"); - return ret; - } - - ret = clk_prepare_enable(priv->hclock); - if (ret) { - dev_err(dev, "can't enable hclock\n"); - return ret; - } - - ret = clk_prepare_enable(priv->gck); - if (ret) { - dev_err(dev, "can't enable gck\n"); - return ret; - } - - return sdhci_resume_host(host); -} -#endif /* CONFIG_PM_SLEEP */ - -static SIMPLE_DEV_PM_OPS(sdhci_at91_dev_pm_ops, sdhci_at91_suspend, - sdhci_at91_resume); - static int sdhci_at91_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -231,7 +178,7 @@ static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", .of_match_table = sdhci_at91_dt_match, - .pm = &sdhci_at91_dev_pm_ops, + .pm = SDHCI_PLTFM_PMOPS, }, .probe = sdhci_at91_probe, .remove = sdhci_at91_remove, From b248b513466a36116f74b33d74e6b3c78e15d9e6 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 26 Nov 2015 10:33:57 +0100 Subject: [PATCH 368/381] ARM: at91/defconfig: add the HID_GENERIC to sama5_defconfig This option can be handy for connecting an USB mouse of keyboard. Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5_defconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index 84ff2a7433d81b..a734be39434d08 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -175,7 +175,6 @@ CONFIG_SND_ATMEL_SOC=y CONFIG_SND_ATMEL_SOC_WM8904=y CONFIG_SND_ATMEL_SOC_CLASSD=y CONFIG_SND_ATMEL_SOC_I2S=y -# CONFIG_HID_GENERIC is not set CONFIG_USB=y CONFIG_USB_ANNOUNCE_NEW_DEVICES=y CONFIG_USB_EHCI_HCD=y From 4da8aec771c3d0a475c31029f523f2125748f954 Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 26 Nov 2015 10:37:15 +0100 Subject: [PATCH 369/381] ARM: at91/defconfig: remove the special sama5d2_defconfig This SoC is now handled normally by the generic sama5_defconfig, no need to keep a special defconfig. Signed-off-by: Nicolas Ferre --- arch/arm/configs/sama5d2_defconfig | 243 ----------------------------- 1 file changed, 243 deletions(-) delete mode 100644 arch/arm/configs/sama5d2_defconfig diff --git a/arch/arm/configs/sama5d2_defconfig b/arch/arm/configs/sama5d2_defconfig deleted file mode 100644 index 67311e1f12d381..00000000000000 --- a/arch/arm/configs/sama5d2_defconfig +++ /dev/null @@ -1,243 +0,0 @@ -# CONFIG_SWAP is not set -CONFIG_SYSVIPC=y -CONFIG_IRQ_DOMAIN_DEBUG=y -CONFIG_LOG_BUF_SHIFT=16 -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_LZMA=y -CONFIG_EMBEDDED=y -CONFIG_SLAB=y -CONFIG_JUMP_LABEL=y -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_MODULE_FORCE_UNLOAD=y -# CONFIG_BLK_DEV_BSG is not set -# CONFIG_IOSCHED_DEADLINE is not set -# CONFIG_IOSCHED_CFQ is not set -CONFIG_ARCH_AT91=y -CONFIG_SOC_SAMA5D2=y -CONFIG_SOC_SAMA5D3=y -CONFIG_SOC_SAMA5D4=y -CONFIG_AEABI=y -CONFIG_CMA=y -CONFIG_CMA_DEBUGFS=y -CONFIG_UACCESS_WITH_MEMCPY=y -# CONFIG_ATAGS is not set -CONFIG_ZBOOT_ROM_TEXT=0x0 -CONFIG_ZBOOT_ROM_BSS=0x0 -CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" -CONFIG_KEXEC=y -CONFIG_VFP=y -CONFIG_NEON=y -CONFIG_KERNEL_MODE_NEON=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -# CONFIG_SUSPEND is not set -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -# CONFIG_INET_XFRM_MODE_TRANSPORT is not set -# CONFIG_INET_XFRM_MODE_TUNNEL is not set -# CONFIG_INET_XFRM_MODE_BEET is not set -# CONFIG_INET_LRO is not set -# CONFIG_INET_DIAG is not set -# CONFIG_IPV6 is not set -CONFIG_CAN=y -CONFIG_CAN_AT91=y -CONFIG_CAN_M_CAN=y -CONFIG_CFG80211=y -CONFIG_MAC80211=y -CONFIG_MAC80211_LEDS=y -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -# CONFIG_STANDALONE is not set -# CONFIG_PREVENT_FIRMWARE_BUILD is not set -CONFIG_DMA_CMA=y -CONFIG_MTD=y -CONFIG_MTD_CMDLINE_PARTS=y -CONFIG_MTD_BLOCK=y -CONFIG_MTD_CFI=y -CONFIG_MTD_NAND=y -CONFIG_MTD_NAND_ATMEL=y -CONFIG_MTD_UBI=y -CONFIG_MTD_UBI_GLUEBI=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_COUNT=4 -CONFIG_BLK_DEV_RAM_SIZE=8192 -CONFIG_ATMEL_TCLIB=y -CONFIG_ATMEL_SSC=y -CONFIG_SRAM=y -CONFIG_EEPROM_AT24=y -CONFIG_EEPROM_93CX6=m -CONFIG_SCSI=y -CONFIG_BLK_DEV_SD=y -# CONFIG_SCSI_LOWLEVEL is not set -CONFIG_NETDEVICES=y -# CONFIG_NET_VENDOR_ARC is not set -CONFIG_MACB=y -# CONFIG_NET_VENDOR_BROADCOM is not set -# CONFIG_NET_VENDOR_CIRRUS is not set -# CONFIG_NET_VENDOR_FARADAY is not set -# CONFIG_NET_VENDOR_HISILICON is not set -# CONFIG_NET_VENDOR_INTEL is not set -# CONFIG_NET_VENDOR_MARVELL is not set -# CONFIG_NET_VENDOR_MICREL is not set -# CONFIG_NET_VENDOR_MICROCHIP is not set -# CONFIG_NET_VENDOR_NATSEMI is not set -# CONFIG_NET_VENDOR_QUALCOMM is not set -# CONFIG_NET_VENDOR_ROCKER is not set -# CONFIG_NET_VENDOR_SAMSUNG is not set -# CONFIG_NET_VENDOR_SEEQ is not set -# CONFIG_NET_VENDOR_SMSC is not set -# CONFIG_NET_VENDOR_STMICRO is not set -# CONFIG_NET_VENDOR_VIA is not set -# CONFIG_NET_VENDOR_WIZNET is not set -CONFIG_MICREL_PHY=y -CONFIG_RT2X00=y -CONFIG_RT2800USB=y -# CONFIG_RT2800USB_RT35XX is not set -CONFIG_RT2800USB_RT53XX=y -# CONFIG_RTL_CARDS is not set -# CONFIG_INPUT_MOUSEDEV is not set -CONFIG_INPUT_EVDEV=y -# CONFIG_KEYBOARD_ATKBD is not set -CONFIG_KEYBOARD_QT1070=y -CONFIG_KEYBOARD_GPIO=y -# CONFIG_INPUT_MOUSE is not set -CONFIG_INPUT_TOUCHSCREEN=y -CONFIG_TOUCHSCREEN_ATMEL_MXT=y -# CONFIG_SERIO is not set -CONFIG_LEGACY_PTY_COUNT=4 -CONFIG_SERIAL_ATMEL=y -CONFIG_SERIAL_ATMEL_CONSOLE=y -CONFIG_HW_RANDOM=y -CONFIG_I2C_CHARDEV=y -CONFIG_I2C_AT91=y -CONFIG_I2C_GPIO=y -CONFIG_SPI=y -CONFIG_SPI_ATMEL=y -CONFIG_SPI_GPIO=y -CONFIG_PINCTRL_AT91PIO4=y -CONFIG_SPI_SPIDEV=m -CONFIG_GPIO_SYSFS=y -CONFIG_GPIO_SYSCON=y -CONFIG_POWER_SUPPLY=y -CONFIG_POWER_RESET=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_AT91SAM9X_WATCHDOG=y -CONFIG_SAMA5D4_WATCHDOG=y -CONFIG_MFD_ATMEL_FLEXCOM=y -CONFIG_MFD_ATMEL_HLCDC=y -CONFIG_MFD_SYSCON=y -CONFIG_REGULATOR=y -CONFIG_REGULATOR_FIXED_VOLTAGE=y -CONFIG_REGULATOR_VIRTUAL_CONSUMER=y -CONFIG_REGULATOR_ACT8865=y -CONFIG_MEDIA_SUPPORT=y -CONFIG_MEDIA_CAMERA_SUPPORT=y -CONFIG_MEDIA_CONTROLLER=y -CONFIG_VIDEO_V4L2_SUBDEV_API=y -CONFIG_V4L_PLATFORM_DRIVERS=y -CONFIG_SOC_CAMERA=y -CONFIG_VIDEO_ATMEL_ISI=y -CONFIG_SOC_CAMERA_OV2640=y -CONFIG_SOC_CAMERA_OV5642=y -CONFIG_SOC_CAMERA_OV6650=y -CONFIG_SOC_CAMERA_OV772X=y -CONFIG_SOC_CAMERA_OV9640=y -CONFIG_SOC_CAMERA_OV9740=y -CONFIG_DRM=y -CONFIG_DRM_I2C_SIL902X=y -CONFIG_DRM_ATMEL_HLCDC=y -CONFIG_DRM_PANEL_SIMPLE=y -CONFIG_BACKLIGHT_LCD_SUPPORT=y -CONFIG_LCD_CLASS_DEVICE=y -CONFIG_BACKLIGHT_CLASS_DEVICE=y -# CONFIG_BACKLIGHT_GENERIC is not set -CONFIG_BACKLIGHT_PWM=y -CONFIG_SOUND=y -CONFIG_SND=y -CONFIG_SND_SOC=y -CONFIG_SND_ATMEL_SOC=y -CONFIG_SND_ATMEL_SOC_WM8904=y -CONFIG_SND_ATMEL_SOC_CLASSD=y -CONFIG_SND_ATMEL_SOC_I2S=y -# CONFIG_HID_GENERIC is not set -CONFIG_USB=y -CONFIG_USB_ANNOUNCE_NEW_DEVICES=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_ACM=y -CONFIG_USB_STORAGE=y -CONFIG_USB_SERIAL=y -CONFIG_USB_SERIAL_GENERIC=y -CONFIG_USB_SERIAL_FTDI_SIO=y -CONFIG_USB_SERIAL_PL2303=y -CONFIG_USB_GADGET=y -CONFIG_USB_ATMEL_USBA=m -CONFIG_USB_CONFIGFS=m -CONFIG_USB_CONFIGFS_ACM=y -CONFIG_USB_CONFIGFS_MASS_STORAGE=y -CONFIG_USB_MASS_STORAGE=m -CONFIG_USB_G_SERIAL=m -CONFIG_MMC=y -# CONFIG_MMC_BLOCK_BOUNCE is not set -CONFIG_MMC_SDHCI=y -CONFIG_MMC_SDHCI_PLTFM=y -CONFIG_MMC_SDHCI_OF_AT91=y -CONFIG_MMC_ATMELMCI=y -CONFIG_NEW_LEDS=y -CONFIG_LEDS_CLASS=y -CONFIG_LEDS_GPIO=y -CONFIG_LEDS_PWM=y -CONFIG_LEDS_TRIGGER_TIMER=y -CONFIG_LEDS_TRIGGER_HEARTBEAT=y -CONFIG_LEDS_TRIGGER_CPU=y -CONFIG_LEDS_TRIGGER_GPIO=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_AT91RM9200=y -CONFIG_DMADEVICES=y -CONFIG_AT_XDMAC=y -CONFIG_DMATEST=m -# CONFIG_IOMMU_SUPPORT is not set -CONFIG_IIO=y -CONFIG_AT91_ADC=y -CONFIG_PWM=y -CONFIG_PWM_ATMEL=y -CONFIG_PWM_ATMEL_HLCDC_PWM=y -CONFIG_PWM_ATMEL_TCB=y -CONFIG_RESET_CONTROLLER=y -CONFIG_EXT4_FS=y -CONFIG_FANOTIFY=y -CONFIG_VFAT_FS=y -CONFIG_TMPFS=y -CONFIG_CONFIGFS_FS=y -CONFIG_UBIFS_FS=y -CONFIG_UBIFS_FS_ADVANCED_COMPR=y -CONFIG_NFS_FS=y -CONFIG_ROOT_NFS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_UTF8=y -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_FS=y -CONFIG_DEBUG_MEMORY_INIT=y -# CONFIG_SCHED_DEBUG is not set -# CONFIG_FTRACE is not set -CONFIG_DEBUG_USER=y -CONFIG_DEBUG_LL=y -CONFIG_AT91_DEBUG_LL_DBGU3=y -CONFIG_EARLY_PRINTK=y -# CONFIG_CRYPTO_ANSI_CPRNG is not set -CONFIG_CRYPTO_DRBG_MENU=y -CONFIG_CRYPTO_USER_API_HASH=m -CONFIG_CRYPTO_USER_API_SKCIPHER=m -CONFIG_CRYPTO_DEV_ATMEL_AES=y -CONFIG_CRYPTO_DEV_ATMEL_TDES=y -CONFIG_CRYPTO_DEV_ATMEL_SHA=y -CONFIG_CRC_ITU_T=m From 6fdbaf7173babb5c8b227e6865d2de20cd33ced8 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 26 Nov 2015 12:36:22 +0100 Subject: [PATCH 370/381] ARM: at91/sama5_defconfig: enable CPU idle Add CONFIG_CPU_IDLE=y to enable CPU idle PM support. Signed-off-by: Wenyou Yang --- arch/arm/configs/sama5_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index a734be39434d08..cb064130fbc2a2 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -26,6 +26,7 @@ CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" CONFIG_KEXEC=y +CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y CONFIG_KERNEL_MODE_NEON=y From 379047c5d8d66478bd3aa5effeb9a13d7400bf3a Mon Sep 17 00:00:00 2001 From: Nicolas Ferre Date: Thu, 26 Nov 2015 13:56:35 +0100 Subject: [PATCH 371/381] ARM: at91/defconfig: remove KEXEC from defconfig This option is not frequently used and easy to add by whoever needs it. Signed-off-by: Nicolas Ferre --- arch/arm/configs/at91_dt_defconfig | 1 - arch/arm/configs/sama5_defconfig | 1 - 2 files changed, 2 deletions(-) diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig index c4cf47f7a7776a..e9b164789a7ad6 100644 --- a/arch/arm/configs/at91_dt_defconfig +++ b/arch/arm/configs/at91_dt_defconfig @@ -27,7 +27,6 @@ CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_ARM_APPENDED_DTB=y CONFIG_ARM_ATAG_DTB_COMPAT=y CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" -CONFIG_KEXEC=y CONFIG_AUTO_ZRELADDR=y # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set CONFIG_NET=y diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig index cb064130fbc2a2..1c9b84df998015 100644 --- a/arch/arm/configs/sama5_defconfig +++ b/arch/arm/configs/sama5_defconfig @@ -25,7 +25,6 @@ CONFIG_UACCESS_WITH_MEMCPY=y CONFIG_ZBOOT_ROM_TEXT=0x0 CONFIG_ZBOOT_ROM_BSS=0x0 CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 rw" -CONFIG_KEXEC=y CONFIG_CPU_IDLE=y CONFIG_VFP=y CONFIG_NEON=y From 2f1b9426f0ea69c0f22421390e090a660bbd7128 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Wed, 25 Nov 2015 09:45:26 +0100 Subject: [PATCH 372/381] mmc: sdhci-of-at91: add presets setup The controller claims to support SDR104 but is not totally true since the maximum sd clock frequency is 120 MHz instead of 208 MHz for this mode. The sdhci core is not aware about this and will compute a wrong clock divider so preset has to be used to fix that. Signed-off-by: Ludovic Desroches --- drivers/mmc/host/sdhci-of-at91.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 06d0b50dfe71d2..0e701547afeb36 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +63,7 @@ static int sdhci_at91_probe(struct platform_device *pdev) unsigned int clk_base, clk_mul; unsigned int gck_rate, real_gck_rate; int ret; + unsigned int preset_div, preset_common = 0x400; /* drv type B, programmable clock mode */ match = of_match_device(sdhci_at91_dt_match, &pdev->dev); if (!match) @@ -132,6 +134,28 @@ static int sdhci_at91_probe(struct platform_device *pdev) clk_mul, real_gck_rate); } + /* + * We have to set preset values because it depends on the clk_mul + * value. Moreover, SDR104 is supported in a degraded mode since the + * maximum sd clock value is 120 MHz instead of 208 MHz. For that + * reason, we need to use presets to support SDR104. + */ + preset_div = DIV_ROUND_UP(real_gck_rate, 24000000) - 1; + writew(preset_common | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR12); + preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; + writew(preset_common | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR25); + preset_div = DIV_ROUND_UP(real_gck_rate, 100000000) - 1; + writew(preset_common | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR50); + preset_div = DIV_ROUND_UP(real_gck_rate, 120000000) - 1; + writew(preset_common | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_SDR104); + preset_div = DIV_ROUND_UP(real_gck_rate, 50000000) - 1; + writew(preset_common | preset_div, + host->ioaddr + SDHCI_PRESET_FOR_DDR50); + clk_prepare_enable(priv->mainck); clk_prepare_enable(priv->gck); From 0480abe5ce2bae99a7a5072fd22872724d817f59 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Thu, 9 Jul 2015 15:35:15 +0200 Subject: [PATCH 373/381] wireless: regulatory: reduce log level of CRDA related messages With a basic Linux userspace, the messages "Calling CRDA to update world regulatory domain" appears 10 times after boot every second or so, followed by a final "Exceeded CRDA call max attempts. Not calling CRDA". For those of us not having the corresponding userspace parts, having those messages repeatedly displayed at boot time is a bit annoying, so this commit reduces their log level to pr_debug(). Signed-off-by: Thomas Petazzoni Signed-off-by: Johannes Berg --- net/wireless/reg.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 0e347f888fe910..88d61780e570e8 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -544,15 +544,15 @@ static int call_crda(const char *alpha2) reg_regdb_query(alpha2); if (reg_crda_timeouts > REG_MAX_CRDA_TIMEOUTS) { - pr_info("Exceeded CRDA call max attempts. Not calling CRDA\n"); + pr_debug("Exceeded CRDA call max attempts. Not calling CRDA\n"); return -EINVAL; } if (!is_world_regdom((char *) alpha2)) - pr_info("Calling CRDA for country: %c%c\n", + pr_debug("Calling CRDA for country: %c%c\n", alpha2[0], alpha2[1]); else - pr_info("Calling CRDA to update world regulatory domain\n"); + pr_debug("Calling CRDA to update world regulatory domain\n"); return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, env); } From e4e8d409c9f2834d1a81a8fb5eb1e0bb682957a7 Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Mon, 23 Nov 2015 15:20:10 +0800 Subject: [PATCH 374/381] ARM: at91/dt: sama5d2: classd: add GCK's parent clock Set GCK's parent as audio pmc clock. Signed-off-by: Songjun Wu --- arch/arm/boot/dts/sama5d2.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi index 3c03074fad15f2..baeaaac0f40d24 100644 --- a/arch/arm/boot/dts/sama5d2.dtsi +++ b/arch/arm/boot/dts/sama5d2.dtsi @@ -1243,6 +1243,8 @@ dma-names = "tx"; clocks = <&classd_clk>, <&classd_gclk>, <&audio_pll_pmc>; clock-names = "pclk", "gclk", "aclk"; + assigned-clocks = <&classd_gclk>; + assigned-clock-parents = <&audio_pll_pmc>; status = "disabled"; }; From 86192818f3205eae437af5d891c3f8b753dcf0ee Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Mon, 23 Nov 2015 15:33:54 +0800 Subject: [PATCH 375/381] ARM: at91/dt: sama5d2: classd: add sound card name Add sound card name for samad2-xplained. Signed-off-by: Songjun Wu [nicolas.ferre@atmel.com: add name to sama5d2 Xplained pda4 as well] Signed-off-by: Nicolas Ferre --- arch/arm/boot/dts/at91-sama5d2_xplained.dts | 1 + arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts | 1 + 2 files changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained.dts b/arch/arm/boot/dts/at91-sama5d2_xplained.dts index 9020b4be18f601..69cbe679c09bab 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained.dts @@ -467,6 +467,7 @@ classd@fc048000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_classd_default>; + atmel,model = "classd @ SAMA5D2-Xplained"; atmel,pwm-type = "diff"; atmel,non-overlap-time = <10>; status = "okay"; diff --git a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts index 55f6eae235073f..91f12c86fe7429 100644 --- a/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts +++ b/arch/arm/boot/dts/at91-sama5d2_xplained_pda4.dts @@ -482,6 +482,7 @@ classd@fc048000 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_classd_default>; + atmel,model = "classd @ SAMA5D2-Xplained"; atmel,pwm-type = "diff"; atmel,non-overlap-time = <10>; status = "okay"; From d0d9bbea490a0f43cf2743401fbc3b33fa479e61 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Thu, 26 Nov 2015 17:10:06 +0100 Subject: [PATCH 376/381] mmc: sdhci-of-at91: controller is suspended too early The controller is suspended before sdhci_add_host(). It causes to read 0 in register because the controller clock is disabled. Increment the usage count before calling sdhci_add_host(), decrement it after and put it in suspend if it is possible. Signed-off-by: Ludovic Desroches --- drivers/mmc/host/sdhci-of-at91.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index d5c409130aef31..7c0b45c6001b90 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -224,6 +224,7 @@ static int sdhci_at91_probe(struct platform_device *pdev) sdhci_get_of_property(pdev); + pm_runtime_get_noresume(&pdev->dev); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); pm_runtime_set_autosuspend_delay(&pdev->dev, 50); @@ -233,6 +234,8 @@ static int sdhci_at91_probe(struct platform_device *pdev) if (ret) goto pm_runtime_disable; + pm_runtime_put_autosuspend(&pdev->dev); + return 0; pm_runtime_disable: From 2e82102c9cec45a51ef513f124289a4bbf03f773 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Tue, 16 Jun 2015 12:09:30 +0200 Subject: [PATCH 377/381] spi: atmel: update DT bindings documentation - add new property "atmel,fifo-size" - change "cs-gpios" to optional for SPI controller version >= 2. Please be aware that the VERSION register can not be used to guess the size of FIFOs. Indeed, for a given hardware version, the SPI controller can be integrated on Atmel SoCs with different FIFO sizes. Also the "atmel,fifo-size" property is optional as older SPI controllers don't embed FIFO at all. Besides, the FIFO size can not be read or guessed from other registers: When designing the FIFO feature, no dedicated registers were added to store this size. Unused spaces in the I/O register range are limited and better reserved for future usages. Instead, the FIFO size of each peripheral is documented in the programmer datasheet. Finally, on a given SoC, there can be several instances of the SPI controller with different FIFO sizes. This explain why we'd rather use a dedicated DT property than use the "compatible" property. For instance, sama5d2x SoCs come with some SPI controllers, the ones inside Flexcoms, integrating 32 data FIFOs whereas other SPI controllers use 16 data FIFOs. All these SPI controllers share the same IP version. Signed-off-by: Cyrille Pitchen Acked-by: Nicolas Ferre Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/spi/spi_atmel.txt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/spi/spi_atmel.txt b/Documentation/devicetree/bindings/spi/spi_atmel.txt index 4f8184d069cb5a..fb588b3e6a9a3d 100644 --- a/Documentation/devicetree/bindings/spi/spi_atmel.txt +++ b/Documentation/devicetree/bindings/spi/spi_atmel.txt @@ -4,11 +4,16 @@ Required properties: - compatible : should be "atmel,at91rm9200-spi". - reg: Address and length of the register set for the device - interrupts: Should contain spi interrupt -- cs-gpios: chipselects +- cs-gpios: chipselects (optional for SPI controller version >= 2 with the + Chip Select Active After Transfer feature). - clock-names: tuple listing input clock names. Required elements: "spi_clk" - clocks: phandles to input clocks. +Optional properties: +- atmel,fifo-size: maximum number of data the RX and TX FIFOs can store for FIFO + capable SPI controllers. + Example: spi1: spi@fffcc000 { @@ -20,6 +25,7 @@ spi1: spi@fffcc000 { clocks = <&spi1_clk>; clock-names = "spi_clk"; cs-gpios = <&pioB 3 0>; + atmel,fifo-size = <32>; status = "okay"; mmc-slot@0 { From 51b968a9548cd4dc1ba8e5521531f0521918c55f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 10 Sep 2015 10:19:52 +0200 Subject: [PATCH 378/381] spi: atmel: remove warning when !CONFIG_PM_SLEEP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_PM is defined but not CONFIG_PM_SLEEP (this happens when CONFIG_SUSPEND is not defined), there is the following warning: drivers/spi/spi-atmel.c:1723:12: warning: ‘atmel_spi_suspend’ defined but not used [-Wunused-function] drivers/spi/spi-atmel.c:1741:12: warning: ‘atmel_spi_resume’ defined but not used [-Wunused-function] Enclose both atmel_spi_suspend and atmel_spi_resume in #ifdef CONFIG_PM_SLEEP/#endif to solve that. Signed-off-by: Alexandre Belloni Signed-off-by: Mark Brown --- drivers/spi/spi-atmel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index bf9ed380bb1c07..63318e2afba190 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -1720,6 +1720,7 @@ static int atmel_spi_runtime_resume(struct device *dev) return clk_prepare_enable(as->clk); } +#ifdef CONFIG_PM_SLEEP static int atmel_spi_suspend(struct device *dev) { struct spi_master *master = dev_get_drvdata(dev); @@ -1756,6 +1757,7 @@ static int atmel_spi_resume(struct device *dev) return ret; } +#endif static const struct dev_pm_ops atmel_spi_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume) From 837fc401fcc9072c914382db264ed31c72ebd35e Mon Sep 17 00:00:00 2001 From: David Mosberger-Tang Date: Tue, 20 Oct 2015 14:26:47 +0200 Subject: [PATCH 379/381] spi: atmel: Fix DMA-setup for transfers with more than 8 bits per word The DMA-slave configuration depends on the whether <= 8 or > 8 bits are transferred per word, so we need to call atmel_spi_dma_slave_config() with the correct value. Signed-off-by: David Mosberger Signed-off-by: Nicolas Ferre Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- drivers/spi/spi-atmel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c index 63318e2afba190..3fff59ce065f30 100644 --- a/drivers/spi/spi-atmel.c +++ b/drivers/spi/spi-atmel.c @@ -773,7 +773,8 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master, *plen = len; - if (atmel_spi_dma_slave_config(as, &slave_config, 8)) + if (atmel_spi_dma_slave_config(as, &slave_config, + xfer->bits_per_word)) goto err_exit; /* Send both scatterlists */ From 40f57ddd026b5f21f11b76948f927f037a704d74 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Tue, 18 Jun 2013 14:57:13 +0400 Subject: [PATCH 380/381] ARM: at91sam9260/dt: add I2C pinctl definitions This patch adds missing devicetree definitions for IO pins of I2C bus. Without them transfers on I2C just time out. Definitions affect boards based on at91sam9260 and at91sam9g20 CPUs. --- arch/arm/boot/dts/at91sam9260.dtsi | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9260.dtsi b/arch/arm/boot/dts/at91sam9260.dtsi index be9c027ddd979c..0eefc32a6dbd5b 100644 --- a/arch/arm/boot/dts/at91sam9260.dtsi +++ b/arch/arm/boot/dts/at91sam9260.dtsi @@ -720,6 +720,14 @@ }; }; + i2c0 { + pinctrl_i2c0: i2c0-0 { + atmel,pins = + ; /* PA24 periph A I2C0 clock */ + }; + }; + pioA: gpio@fffff400 { compatible = "atmel,at91rm9200-gpio"; reg = <0xfffff400 0x200>; @@ -869,6 +877,8 @@ interrupts = <11 IRQ_TYPE_LEVEL_HIGH 6>; #address-cells = <1>; #size-cells = <0>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_i2c0>; clocks = <&twi0_clk>; status = "disabled"; }; From dce2ca7ce7e02153f0e70d46664559851f23b308 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Wed, 27 Feb 2013 14:58:33 +0400 Subject: [PATCH 381/381] ARM: at91sam9x5/dt: usart3 definitions This patch adds missing usart3 structures in device tree description of at91sam9x5 SoC family. --- arch/arm/boot/dts/at91sam9x5.dtsi | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi index 9df8ca5666e9d3..8fd752a82c3a2a 100644 --- a/arch/arm/boot/dts/at91sam9x5.dtsi +++ b/arch/arm/boot/dts/at91sam9x5.dtsi @@ -26,6 +26,7 @@ serial1 = &usart0; serial2 = &usart1; serial3 = &usart2; + serial4 = &usart3; gpio0 = &pioA; gpio1 = &pioB; gpio2 = &pioC; @@ -286,6 +287,11 @@ reg = <7>; }; + usart3_clk: usart3_clk { + #clock-cells = <0>; + reg = <8>; + }; + twi0_clk: twi0_clk { reg = <9>; #clock-cells = <0>; @@ -534,6 +540,29 @@ }; }; + usart3 { + pinctrl_usart3: usart3-0 { + atmel,pins = + ; /* PC23 periph B */ + }; + + pinctrl_usart3_rts: usart3_rts-0 { + atmel,pins = + ; /* PC24 periph B */ + }; + + pinctrl_usart3_cts: usart3_cts-0 { + atmel,pins = + ; /* PC25 periph B */ + }; + + pinctrl_usart3_sck: usart3_sck-0 { + atmel,pins = + ; /* PC26 periph B */ + }; + }; + uart0 { pinctrl_uart0: uart0-0 { atmel,pins = @@ -963,6 +992,20 @@ status = "disabled"; }; + usart3: serial@f8028000 { + compatible = "atmel,at91sam9260-usart"; + reg = <0xf8028000 0x200>; + interrupts = <8 4 5>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_usart3>; + dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(14)>, + <&dma1 1 (AT91_DMA_CFG_PER_ID(15) | AT91_DMA_CFG_FIFOCFG_ASAP)>; + dma-names = "tx", "rx"; + clocks = <&usart3_clk>; + clock-names = "usart"; + status = "disabled"; + }; + i2c0: i2c@f8010000 { compatible = "atmel,at91sam9x5-i2c"; reg = <0xf8010000 0x100>;