Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 4/6] regulator: pfuze100: add fsl, pmic-stby-poweroff property
From: Oleksij Rempel @ 2017-12-06  7:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171206072402.11694-1-o.rempel@pengutronix.de>

Document the new optional "fsl,pmic-stby-poweroff" property.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/regulator/pfuze100.txt | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/regulator/pfuze100.txt b/Documentation/devicetree/bindings/regulator/pfuze100.txt
index 444c47831a40..197f1a52e960 100644
--- a/Documentation/devicetree/bindings/regulator/pfuze100.txt
+++ b/Documentation/devicetree/bindings/regulator/pfuze100.txt
@@ -4,6 +4,13 @@ Required properties:
 - compatible: "fsl,pfuze100", "fsl,pfuze200", "fsl,pfuze3000"
 - reg: I2C slave address
 
+Optional properties:
+- fsl,pmic-stby-poweroff: if present, configure the PMIC to shutdown all
+  power rails when PMIC_STBY_REQ line is asserted during the power off sequence.
+  Use this option if the SoC should be powered off by external power
+  management IC (PMIC) on PMIC_STBY_REQ signal.
+  As opposite to PMIC_STBY_REQ boards can implement PMIC_ON_REQ signal.
+
 Required child node:
 - regulators: This is the list of child nodes that specify the regulator
   initialization data for defined regulators. Please refer to below doc
-- 
2.11.0

^ permalink raw reply related

* [PATCH v6 3/6] kernel/reboot.c: export pm_power_off_prepare
From: Oleksij Rempel @ 2017-12-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171206072402.11694-1-o.rempel@pengutronix.de>

Export pm_power_off_prepare. It is needed to implement power off on
Freescale/NXP iMX6 based boards with external power management
integrated circuit (PMIC).

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 kernel/reboot.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/reboot.c b/kernel/reboot.c
index bd30a973fe94..a6903bf772c7 100644
--- a/kernel/reboot.c
+++ b/kernel/reboot.c
@@ -49,6 +49,7 @@ int reboot_force;
  */
 
 void (*pm_power_off_prepare)(void);
+EXPORT_SYMBOL(pm_power_off_prepare);
 
 /**
  *	emergency_restart - reboot the system
-- 
2.11.0

^ permalink raw reply related

* [PATCH v6 2/6] ARM: imx6: register pm_power_off handler if "fsl, pmic-stby-poweroff" is set
From: Oleksij Rempel @ 2017-12-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171206072402.11694-1-o.rempel@pengutronix.de>

One of the Freescale recommended sequences for power off with external
PMIC is the following:
...
3.  SoC is programming PMIC for power off when standby is asserted.
4.  In CCM STOP mode, Standby is asserted, PMIC gates SoC supplies.

See:
http://www.nxp.com/assets/documents/data/en/reference-manuals/IMX6DQRM.pdf
page 5083

This patch implements step 4. of this sequence.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 arch/arm/mach-imx/pm-imx6.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index ecdf071653d4..24689260a2a5 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -604,6 +604,28 @@ static void __init imx6_pm_common_init(const struct imx6_pm_socdata
 				   IMX6Q_GPR1_GINT);
 }
 
+static void imx6_pm_stby_poweroff(void)
+{
+	imx6_set_lpm(STOP_POWER_OFF);
+	cpu_suspend(0, imx6q_suspend_finish);
+
+	mdelay(1000);
+
+	pr_emerg("Unable to poweroff system\n");
+}
+
+static int imx6_pm_stby_poweroff_probe(void)
+{
+	if (pm_power_off) {
+		pr_warn("%s: pm_power_off already claimed  %p %pf!\n",
+			__func__, pm_power_off, pm_power_off);
+		return -EBUSY;
+	}
+
+	pm_power_off = imx6_pm_stby_poweroff;
+	return 0;
+}
+
 void __init imx6_pm_ccm_init(const char *ccm_compat)
 {
 	struct device_node *np;
@@ -620,6 +642,9 @@ void __init imx6_pm_ccm_init(const char *ccm_compat)
 	val = readl_relaxed(ccm_base + CLPCR);
 	val &= ~BM_CLPCR_LPM;
 	writel_relaxed(val, ccm_base + CLPCR);
+
+	if (of_property_read_bool(np, "fsl,pmic-stby-poweroff"))
+		imx6_pm_stby_poweroff_probe();
 }
 
 void __init imx6q_pm_init(void)
-- 
2.11.0

^ permalink raw reply related

* [PATCH v6 1/6] ARM: imx6q: provide documentation for new fsl, pmic-stby-poweroff property
From: Oleksij Rempel @ 2017-12-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171206072402.11694-1-o.rempel@pengutronix.de>

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/clock/imx6q-clock.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/clock/imx6q-clock.txt b/Documentation/devicetree/bindings/clock/imx6q-clock.txt
index aa0a4d423ef5..9fed9dfe4a23 100644
--- a/Documentation/devicetree/bindings/clock/imx6q-clock.txt
+++ b/Documentation/devicetree/bindings/clock/imx6q-clock.txt
@@ -6,6 +6,14 @@ Required properties:
 - interrupts: Should contain CCM interrupt
 - #clock-cells: Should be <1>
 
+Optional properties:
+- fsl,pmic-stby-poweroff: Configure CCM to assert PMIC_STBY_REQ signal
+  on power off.
+  Use this property if the SoC should be powered off by external power
+  management IC (PMIC) triggered via PMIC_STBY_REQ signal.
+  Boards that are designed to initiate poweroff on PMIC_ON_REQ signal should
+  be using "syscon-poweroff" driver instead.
+
 The clock consumer should specify the desired clock by having the clock
 ID in its "clocks" phandle cell.  See include/dt-bindings/clock/imx6qdl-clock.h
 for the full list of i.MX6 Quad and DualLite clock IDs.
-- 
2.11.0

^ permalink raw reply related

* [PATCH RESEND v6 0/6] provide power off support for iMX6 with external PMIC
From: Oleksij Rempel @ 2017-12-06  7:23 UTC (permalink / raw)
  To: linux-arm-kernel

2017.12.06:
Adding Linus. Probably there is no maintainer for this patch set.
No changes are made, tested on v4.15-rc1.

2017.10.27:
Last version of this patch set was send at 20 Jun 2017, this is a rebase against
kernel v4.14-rc6. Probably this set got lost. If I forgot to address some comments,
please point me.

This patch series is providing power off support for Freescale/NXP iMX6 based
boards with external power management integrated circuit (PMIC).

changes:
v6:
 - rename imx6_pm_poweroff to imx6_pm_stby_poweroff
 - fix "MPIC_STBY_REQ" typo in the comment.

v5:
 - remove useless includes from pm-imx6.c patch
 - add Acked-by to "regulator: pfuze100: add fsl,pmic-stby-poweroff property"
   patch

v4:
 - update comment in "regulator: pfuze100: add fsl,pmic-stby-poweroff ..."
   patch
 - add Acked-by to "ARM: imx6q: provide documentation for new ..."
   patch

v3:
 - set pm_power_off_prepare = NULL on .remove.
 - documentation and spelling fixes.
 - use %pf instead of lookup_symbol_name.

Oleksij Rempel (6):
  ARM: imx6q: provide documentation for new fsl,pmic-stby-poweroff
    property
  ARM: imx6: register pm_power_off handler if "fsl,pmic-stby-poweroff"
    is set
  kernel/reboot.c: export pm_power_off_prepare
  regulator: pfuze100: add fsl,pmic-stby-poweroff property
  regulator: pfuze100-regulator: provide pm_power_off_prepare handler
  ARM: dts: imx6: RIoTboard provide standby on power off option

 .../devicetree/bindings/clock/imx6q-clock.txt      |  8 ++
 .../devicetree/bindings/regulator/pfuze100.txt     |  7 ++
 arch/arm/boot/dts/imx6dl-riotboard.dts             |  5 ++
 arch/arm/mach-imx/pm-imx6.c                        | 25 ++++++
 drivers/regulator/pfuze100-regulator.c             | 92 ++++++++++++++++++++++
 kernel/reboot.c                                    |  1 +
 6 files changed, 138 insertions(+)

-- 
2.11.0

^ permalink raw reply

* [PATCH] ARM: dts: introduce the sama5d2 ptc ek board
From: Ludovic Desroches @ 2017-12-06  7:01 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171205170141.qleqh6rou2ow54je@tarshish.tkos.co.il>

On Tue, Dec 05, 2017 at 07:01:41PM +0200, Baruch Siach wrote:
> Hi Ludovic,
> 
> On Tue, Dec 05, 2017 at 03:23:12PM +0100, Ludovic Desroches wrote:
> > Add the official SAMA5D2 Peripheral Touch Controller Evaluation
> > Kit board.
> > 
> > Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
> > ---
> 
> [...]
> 
> > +	memory {
> > +		reg = <0x20000000 0x80000>;
> > +	};
> 
> The size value is clearly wrong; you surely don't run on 512KB RAM. You most 
> likely rely on the bootloader to fix the size value. Since sama5d2.dtsi has a 
> memory node already with the same address, you can just drop it from here.
> 

Thanks, fixed in v2.

Ludovic

> baruch
> 
> -- 
>      http://baruch.siach.name/blog/                  ~. .~   Tk Open Systems
> =}------------------------------------------------ooO--U--Ooo------------{=
>    - baruch at tkos.co.il - tel: +972.52.368.4656, http://www.tkos.co.il -

^ permalink raw reply

* [PATCH V2] ARM: dts: introduce the sama5d2 ptc ek board
From: Ludovic Desroches @ 2017-12-06  6:58 UTC (permalink / raw)
  To: linux-arm-kernel

Add the official SAMA5D2 Peripheral Touch Controller Evaluation
Kit board.

Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---

Changes:
- v2:
  - remove memory node
  - use SPDX-License-Identifier

arch/arm/boot/dts/Makefile                |   1 +
 arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts | 402 ++++++++++++++++++++++++++++++
 2 files changed, 403 insertions(+)
 create mode 100644 arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 043d7c720d0c..ed60582eb1da 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -48,6 +48,7 @@ dtb-$(CONFIG_SOC_AT91SAM9) += \
 dtb-$(CONFIG_SOC_SAM_V7) += \
 	at91-kizbox2.dtb \
 	at91-sama5d27_som1_ek.dtb \
+	at91-sama5d2_ptc_ek.dtb \
 	at91-sama5d2_xplained.dtb \
 	at91-sama5d3_xplained.dtb \
 	at91-tse850-3.dtb \
diff --git a/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
new file mode 100644
index 000000000000..89ad23a7f92d
--- /dev/null
+++ b/arch/arm/boot/dts/at91-sama5d2_ptc_ek.dts
@@ -0,0 +1,402 @@
+/*
+ * at91-sama5d2_ptc_ek.dts - Device Tree file for SAMA5D2 PTC EK board
+ *
+ *  Copyright (C) 2017 Microchip/Atmel,
+ *		  2017 Wenyou Yang <wenyou.yang@microchip.com>
+ *		  2017 Ludovic Desroches <ludovic.desroches@microchip.com>
+ *
+ * SPDX-License-Identifier: (GPL-2.0+ OR X11)
+ */
+/dts-v1/;
+#include "sama5d2.dtsi"
+#include "sama5d2-pinfunc.h"
+#include <dt-bindings/mfd/atmel-flexcom.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Atmel SAMA5D2 PTC EK";
+	compatible = "atmel,sama5d2-ptc_ek", "atmel,sama5d2", "atmel,sama5";
+
+	aliases {
+		serial0 = &uart0;
+		i2c0	= &i2c0;
+		i2c1	= &i2c1;
+		i2c2	= &i2c2;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	clocks {
+		slow_xtal {
+			clock-frequency = <32768>;
+		};
+
+		main_xtal {
+			clock-frequency = <24000000>;
+		};
+	};
+
+	ahb {
+		usb0: gadget at 300000 {
+			atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usba_vbus>;
+			status = "okay";
+		};
+
+		usb1: ohci at 400000 {
+			num-ports = <3>;
+			atmel,vbus-gpio = <0
+					   &pioA PIN_PB12 GPIO_ACTIVE_HIGH
+					   0
+					  >;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb_default>;
+			status = "okay";
+		};
+
+		usb2: ehci at 500000 {
+			status = "okay";
+		};
+
+		ebi: ebi at 10000000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_nand_default>;
+			status = "okay"; /* conflicts with sdmmc1 and qspi0 */
+
+			nand_controller: nand-controller {
+				status = "okay";
+
+				nand at 3 {
+					reg = <0x3 0x0 0x2>;
+					atmel,rb = <0>;
+					nand-bus-width = <8>;
+					nand-ecc-mode = "hw";
+					nand-on-flash-bbt;
+					label = "atmel_nand";
+
+					partitions {
+						compatible = "fixed-partitions";
+						#address-cells = <1>;
+						#size-cells = <1>;
+
+						at91bootstrap at 0 {
+							label = "bootstrap";
+							reg = <0x0 0x40000>;
+						};
+
+						bootloader at 40000 {
+							label = "bootloader";
+							reg = <0x40000 0xc0000>;
+						};
+
+						bootloaderenv at 0x100000 {
+							label = "bootloader env";
+							reg = <0x100000 0x40000>;
+						};
+
+						bootloaderenvred at 0x140000 {
+							label = "bootloader env redundant";
+							reg = <0x140000 0x40000>;
+						};
+
+						dtb at 180000 {
+							label = "device tree";
+							reg = <0x180000 0x80000>;
+						};
+
+						kernel at 200000 {
+							label = "kernel";
+							reg = <0x200000 0x600000>;
+						};
+
+						rootfs at 800000 {
+							label = "rootfs";
+							reg = <0x800000 0x1f800000>;
+						};
+					};
+				};
+			};
+		};
+
+		sdmmc0: sdio-host at a0000000 {
+			bus-width = <8>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_sdmmc0_default>;
+			non-removable;
+			mmc-ddr-1_8v;
+			status = "okay";
+		};
+
+		apb {
+			spi0: spi at f8000000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_spi0_default>;
+				status = "okay";
+			};
+
+			macb0: ethernet at f8008000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>;
+				phy-mode = "rmii";
+				status = "okay";
+
+				ethernet-phy at 1 {
+					reg = <0x1>;
+					interrupt-parent = <&pioA>;
+					interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
+				};
+			};
+
+			uart0: serial at f801c000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_uart0_default>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "okay";
+			};
+
+			uart2: serial at f8024000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_uart2_default>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "okay";
+			};
+
+			i2c0: i2c at f8028000 {
+				dmas = <0>, <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_i2c0_default>;
+				status = "okay";
+			};
+
+			flx0: flexcom at f8034000 {
+				atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+				status = "okay";
+
+				i2c2: i2c at 600 {
+					compatible = "atmel,sama5d2-i2c";
+					reg = <0x600 0x200>;
+					interrupts = <19 IRQ_TYPE_LEVEL_HIGH 7>;
+					dmas = <0>, <0>;
+					dma-names = "tx", "rx";
+					#address-cells = <1>;
+					#size-cells = <0>;
+					clocks = <&flx0_clk>;
+					pinctrl-names = "default";
+					pinctrl-0 = <&pinctrl_flx0_default>;
+					atmel,fifo-size = <16>;
+					status = "okay";
+				};
+			};
+
+			shdwc at f8048010 {
+				atmel,shdwc-debouncer = <976>;
+
+				input at 0 {
+					reg = <0>;
+					atmel,wakeup-type = "low";
+				};
+			};
+
+			watchdog at f8048040 {
+				status = "okay";
+			};
+
+			spi1: spi at fc000000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_spi1_default>;
+				status = "okay";
+			};
+
+			i2c1: i2c at fc028000 {
+				dmas = <0>, <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_i2c1_default>;
+				status = "okay";
+
+				at24 at 50 {
+					compatible = "24c02";
+					reg = <0x50>;
+					pagesize = <8>;
+				};
+			};
+
+			pinctrl at fc038000 {
+				pinctrl_flx0_default: flx0_default {
+					pinmux = <PIN_PB28__FLEXCOM0_IO0>,
+						 <PIN_PB29__FLEXCOM0_IO1>;
+					bias-disable;
+				};
+
+				pinctrl_i2c0_default: i2c0_default {
+					pinmux = <PIN_PD21__TWD0>,
+						 <PIN_PD22__TWCK0>;
+					bias-disable;
+				};
+
+				pinctrl_i2c1_default: i2c1_default {
+					pinmux = <PIN_PC6__TWD1>,
+						 <PIN_PC7__TWCK1>;
+					bias-disable;
+				};
+
+				pinctrl_key_gpio_default: key_gpio_default {
+					pinmux = <PIN_PA10__GPIO>;
+					bias-pull-up;
+				};
+
+				pinctrl_led_gpio_default: led_gpio_default {
+					pinmux = <PIN_PB6__GPIO>,
+						 <PIN_PB8__GPIO>,
+						 <PIN_PB10__GPIO>;
+					bias-pull-up;
+				};
+
+				pinctrl_macb0_default: macb0_default {
+					pinmux = <PIN_PB14__GTXCK>,
+						 <PIN_PB15__GTXEN>,
+						 <PIN_PB16__GRXDV>,
+						 <PIN_PB17__GRXER>,
+						 <PIN_PB18__GRX0>,
+						 <PIN_PB19__GRX1>,
+						 <PIN_PB20__GTX0>,
+						 <PIN_PB21__GTX1>,
+						 <PIN_PB22__GMDC>,
+						 <PIN_PB23__GMDIO>;
+					bias-disable;
+				};
+
+				pinctrl_macb0_phy_irq: macb0_phy_irq {
+					pinmux = <PIN_PB24__GPIO>;
+					bias-disable;
+				};
+
+				pinctrl_nand_default: nand_default {
+					re_we_data {
+						pinmux = <PIN_PA22__D0>,
+							 <PIN_PA23__D1>,
+							 <PIN_PA24__D2>,
+							 <PIN_PA25__D3>,
+							 <PIN_PA26__D4>,
+							 <PIN_PA27__D5>,
+							 <PIN_PA28__D6>,
+							 <PIN_PA29__D7>,
+							 <PIN_PA30__NWE_NANDWE>,
+							 <PIN_PB2__NRD_NANDOE>;
+						bias-pull-up;
+					};
+
+					ale_cle_rdy_cs {
+						pinmux = <PIN_PB0__A21_NANDALE>,
+							 <PIN_PB1__A22_NANDCLE>,
+							 <PIN_PC8__NANDRDY>,
+							 <PIN_PA31__NCS3>;
+						bias-pull-up;
+					};
+				};
+
+				pinctrl_sdmmc0_default: sdmmc0_default {
+					cmd_data {
+						pinmux = <PIN_PA1__SDMMC0_CMD>,
+							 <PIN_PA2__SDMMC0_DAT0>,
+							 <PIN_PA3__SDMMC0_DAT1>,
+							 <PIN_PA4__SDMMC0_DAT2>,
+							 <PIN_PA5__SDMMC0_DAT3>,
+							 <PIN_PA6__SDMMC0_DAT4>,
+							 <PIN_PA7__SDMMC0_DAT5>,
+							 <PIN_PA8__SDMMC0_DAT6>,
+							 <PIN_PA9__SDMMC0_DAT7>;
+						bias-pull-up;
+					};
+
+					ck_cd_vddsel {
+						pinmux = <PIN_PA0__SDMMC0_CK>,
+							 <PIN_PA11__SDMMC0_VDDSEL>,
+							 <PIN_PA13__SDMMC0_CD>;
+						bias-disable;
+					};
+				};
+
+				pinctrl_spi0_default: spi0_default {
+					pinmux = <PIN_PA14__SPI0_SPCK>,
+						 <PIN_PA15__SPI0_MOSI>,
+						 <PIN_PA16__SPI0_MISO>,
+						 <PIN_PA17__SPI0_NPCS0>;
+					bias-disable;
+				};
+
+				pinctrl_spi1_default: spi1_default {
+					pinmux = <PIN_PC1__SPI1_SPCK>,
+						 <PIN_PC2__SPI1_MOSI>,
+						 <PIN_PC3__SPI1_MISO>,
+						 <PIN_PC4__SPI1_NPCS0>;
+					bias-disable;
+				};
+
+				pinctrl_uart0_default: uart0_default {
+					pinmux = <PIN_PB26__URXD0>,
+						 <PIN_PB27__UTXD0>;
+					bias-disable;
+				};
+
+				pinctrl_uart2_default: uart2_default {
+					pinmux = <PIN_PD23__URXD2>,
+						 <PIN_PD24__UTXD2>;
+					bias-disable;
+				};
+
+				pinctrl_usb_default: usb_default {
+					pinmux = <PIN_PB12__GPIO>;
+					bias-disable;
+				};
+
+				pinctrl_usba_vbus: usba_vbus {
+					pinmux = <PIN_PB11__GPIO>;
+					bias-disable;
+				};
+
+			};
+
+		};
+	};
+
+	gpio_keys {
+		compatible = "gpio-keys";
+
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_key_gpio_default>;
+
+		bp1 {
+			label = "PB_USER";
+			gpios = <&pioA PIN_PA10 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 PIN_PB10 GPIO_ACTIVE_HIGH>;
+		};
+
+		green {
+			label = "green";
+			gpios = <&pioA PIN_PB8 GPIO_ACTIVE_HIGH>;
+		};
+
+		blue {
+			label = "blue";
+			gpios = <&pioA PIN_PB6 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+		};
+	};
+};
-- 
2.12.2

^ permalink raw reply related

* [PATCH 2/5] arm_pmu: have armpmu_alloc() take GFP flags
From: Zhangshaokun @ 2017-12-06  6:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171101141239.45340-3-mark.rutland@arm.com>

Hi Mark,

We (HiSilicon) also met this issue and it works happily with this patch,
but it is still not in 4.15 version, any special reasons?

Thanks,
Shaokun

On 2017/11/1 22:12, Mark Rutland wrote:
> In ACPI systems, we don't know the makeup of CPUs until we hotplug them
> on, and thus have to allocate the PMU datastrcutures at hotplug time.
> Thus, we must use GFP_ATOMIC allocations.
> 
> Reorganise the PMU allocators to take a GFP argument so that we can
> permit this.
> 
> Signed-off-by: Mark Rutland <mark.rutland@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> ---
>  drivers/perf/arm_pmu.c          | 6 +++---
>  drivers/perf/arm_pmu_acpi.c     | 2 +-
>  drivers/perf/arm_pmu_platform.c | 2 +-
>  include/linux/perf/arm_pmu.h    | 2 +-
>  4 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c
> index 57df8dce8e19..3d6d4c5f2356 100644
> --- a/drivers/perf/arm_pmu.c
> +++ b/drivers/perf/arm_pmu.c
> @@ -779,18 +779,18 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
>  					    &cpu_pmu->node);
>  }
>  
> -struct arm_pmu *armpmu_alloc(void)
> +struct arm_pmu *armpmu_alloc(gfp_t flags)
>  {
>  	struct arm_pmu *pmu;
>  	int cpu;
>  
> -	pmu = kzalloc(sizeof(*pmu), GFP_KERNEL);
> +	pmu = kzalloc(sizeof(*pmu), flags);
>  	if (!pmu) {
>  		pr_info("failed to allocate PMU device!\n");
>  		goto out;
>  	}
>  
> -	pmu->hw_events = alloc_percpu(struct pmu_hw_events);
> +	pmu->hw_events = alloc_percpu_gfp(struct pmu_hw_events, flags);
>  	if (!pmu->hw_events) {
>  		pr_info("failed to allocate per-cpu PMU data.\n");
>  		goto out_free_pmu;
> diff --git a/drivers/perf/arm_pmu_acpi.c b/drivers/perf/arm_pmu_acpi.c
> index 705f1a390e31..a52f5b673a15 100644
> --- a/drivers/perf/arm_pmu_acpi.c
> +++ b/drivers/perf/arm_pmu_acpi.c
> @@ -127,7 +127,7 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
>  		return pmu;
>  	}
>  
> -	pmu = armpmu_alloc();
> +	pmu = armpmu_alloc(GFP_ATOMIC);
>  	if (!pmu) {
>  		pr_warn("Unable to allocate PMU for CPU%d\n",
>  			smp_processor_id());
> diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c
> index db863f14c406..686b3f28c5d1 100644
> --- a/drivers/perf/arm_pmu_platform.c
> +++ b/drivers/perf/arm_pmu_platform.c
> @@ -203,7 +203,7 @@ int arm_pmu_device_probe(struct platform_device *pdev,
>  	struct arm_pmu *pmu;
>  	int ret = -ENODEV;
>  
> -	pmu = armpmu_alloc();
> +	pmu = armpmu_alloc(GFP_KERNEL);
>  	if (!pmu)
>  		return -ENOMEM;
>  
> diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h
> index 97426407904d..52e6d56a6a4e 100644
> --- a/include/linux/perf/arm_pmu.h
> +++ b/include/linux/perf/arm_pmu.h
> @@ -173,7 +173,7 @@ static inline int arm_pmu_acpi_probe(armpmu_init_fn init_fn) { return 0; }
>  #endif
>  
>  /* Internal functions only for core arm_pmu code */
> -struct arm_pmu *armpmu_alloc(void);
> +struct arm_pmu *armpmu_alloc(gfp_t flags);
>  void armpmu_free(struct arm_pmu *pmu);
>  int armpmu_register(struct arm_pmu *pmu);
>  int armpmu_request_irq(struct arm_pmu *armpmu, int cpu);
> 

^ permalink raw reply

* [RFCv2 PATCH 26/36] iommu/arm-smmu-v3: Add support for Hardware Translation Table Update
From: Yisheng Xie @ 2017-12-06  6:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171006133203.22803-27-jean-philippe.brucker@arm.com>

Hi Jean,

On 2017/10/6 21:31, Jean-Philippe Brucker wrote:
> If the SMMU supports it and the kernel was built with HTTU support, enable
> +	if (IS_ENABLED(CONFIG_ARM64_HW_AFDBM) && (reg & (IDR0_HA | IDR0_HD))) {
> +		smmu->features |= ARM_SMMU_FEAT_HA;
> +		if (reg & IDR0_HD)
> +			smmu->features |= ARM_SMMU_FEAT_HD;
> +	}

What is relationship of armv8.1 HW_AFDBM and SMMUv3 HTTU? I mean why we need
IS_ENABLED(CONFIG_ARM64_HW_AFDBM) ?

If CONFIG_ARM64_HW_AFDBM=y but the process do not support ARMv8.1, should it also
enable related feature for SMMUv3?

Thanks
Yisheng Xie
> +
>  	/*
>  	 * If the CPU is using VHE, but the SMMU doesn't support it, the SMMU
>  	 * will create TLB entries for NH-EL1 world and will miss the
> 

^ permalink raw reply

* [PATCH] usb: xhci: fix TDS for MTK xHCI1.1
From: Chunfeng Yun @ 2017-12-06  6:42 UTC (permalink / raw)
  To: linux-arm-kernel

For MTK's xHCI 1.0 or latter, TD size is the number of max
packet sized packets remaining in the TD, not including
this TRB (following spec).

For MTK's xHCI 0.96 and older, TD size is the number of max
packet sized packets remaining in the TD, including this TRB
(not following spec).

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
---
 drivers/usb/host/xhci-ring.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c239c68..0619869 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3108,7 +3108,7 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
 {
 	u32 maxp, total_packet_count;
 
-	/* MTK xHCI is mostly 0.97 but contains some features from 1.0 */
+	/* MTK xHCI 0.96 contains some features from 1.0 */
 	if (xhci->hci_version < 0x100 && !(xhci->quirks & XHCI_MTK_HOST))
 		return ((td_total_len - transferred) >> 10);
 
@@ -3117,8 +3117,8 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
 	    trb_buff_len == td_total_len)
 		return 0;
 
-	/* for MTK xHCI, TD size doesn't include this TRB */
-	if (xhci->quirks & XHCI_MTK_HOST)
+	/* for MTK xHCI 0.96, TD size include this TRB, but not in 1.x */
+	if ((xhci->quirks & XHCI_MTK_HOST) && (xhci->hci_version < 0x100))
 		trb_buff_len = 0;
 
 	maxp = usb_endpoint_maxp(&urb->ep->desc);
-- 
1.9.1

^ permalink raw reply related

* [PATCH 0/4] add support of pinctrl to MT7622 SoC
From: biao huang @ 2017-12-06  6:19 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdaL5W5r_4PoYwVK6mcO583Cep5t-ePWqccKx2YDz9=iyA@mail.gmail.com>

On Fri, 2017-12-01 at 20:50 +0100, Linus Walleij wrote:
> On Tue, Nov 28, 2017 at 4:49 AM,  <sean.wang@mediatek.com> wrote:
> 
> > From: Sean Wang <sean.wang@mediatek.com>
> >
> > The patchset adds support for pinctrl on MT7622 SoC.
> 
> It would be good if the other Mediatek driver authors,
> Honzhou, Yingjoe, Biao and Maoguang could review this patch set.
> 
> Yours,
> Linus Walleij

It's ok with these patches for MT7622 Pinctrl.
Thanks.

Reviewed-by: Biao Huang <biao.huang@mediatek.com>
Biao

^ permalink raw reply

* [PATCH 5/8] ASoC: uniphier: add support for UniPhier AIO driver
From: Katsuhiro Suzuki @ 2017-12-06  6:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171205121440.GC11658@finisterre>

Hello,

> -----Original Message-----
> From: Mark Brown [mailto:broonie at kernel.org]
> Sent: Tuesday, December 5, 2017 9:15 PM
> To: Suzuki, Katsuhiro/?? ?? <suzuki.katsuhiro@socionext.com>
> Cc: alsa-devel at alsa-project.org; Rob Herring <robh+dt@kernel.org>;
> devicetree at vger.kernel.org; Yamada, Masahiro/?? ??
> <yamada.masahiro@socionext.com>; Masami Hiramatsu
> <masami.hiramatsu@linaro.org>; Jassi Brar <jaswinder.singh@linaro.org>;
> linux-arm-kernel at lists.infradead.org; linux-kernel at vger.kernel.org
> Subject: Re: [PATCH 5/8] ASoC: uniphier: add support for UniPhier AIO driver
> 
> On Tue, Dec 05, 2017 at 01:48:39PM +0900, Katsuhiro Suzuki wrote:
> 
> Please fix your mail client to word wrap within paragraphs at something
> substantially less than 80 columns.  Doing this makes your messages much
> easier to read and reply to.
> 

Thank you, I set it.


> > > Is there a mux in the SoC here?
> 
> > Sorry for confusing, It's not mux.
> 
> > uniphier_srcport_reset() resets HW SRC (sampling rate converter) block.
> > Audio data out ports of UniPhier audio system have HW SRC.
> 
> Is the SRC just a single block sitting between the DMA and the external
> audio port or is there more going on?  Some of the other code made me
> think the hardware was more flexible than this (all the writing to
> registers with names like RXSEL for example).
> 

This hardware has 2 types of HW SRC. First type sit before audio port and
cannot change routing. I use it in this driver. Second type is like a loopback,
but this block is not used in this driver to simplify the first version.

Type 1:
  Mem -> DMA -> SRC -> Out Port -> External pin
Type 2:
  Mem -> DMA -> SRC -> Out Port -> In Port -> DMA -> Mem


> > > > +#endif /* CONFIG_SND_SOC_UNIPHIER_LD11 */
> 
> > > Why is there an ifdef here?  There's no other conditional code in here,
> > > it seems pointless.
> 
> > This config is used to support or not LD11 SoC.
> > aio-ld11.c is not build and 'uniphier_aio_ldxx_spec' is undefined if this
config is
> disabled.
> >
> > aio-ld11.c defines SoC dependent resources (port, HW ring buffer, DMA ch,
etc.)
> > and fixed settings.
> > I know it's better to move such information into device-tree, but register
areas of
> > UniPhier's audio system is very strange and interleaved. It's hard to split
each
> nodes...
> 
> I'd expect this code to be structured more like a library - have a
> driver that handles the specific IPs then have it call into a shared
> block of code that does the generic bits.  Though in this case the
> device specific bit looks like a couple of tiny data tables so I'm not
> sure it's worth making it conditional or separate at all.
> 

Sorry... I agree your opinion, but I can't imagine the detail.

I think my driver has structure as follows (ex. startup):
  DAI: uniphier_aio_startup()@aio-core.c
  Lib: uniphier_aio_init()@aio-regctrl.c
  SoC specific: uniphier_aio_ld11_spec at aio-ld11.c

Am I wrong? Would you mean split the functions in aio-regctl.[ch] to other
kernel module? I wonder if you could tell me the example from existing
drivers. I'll try to fix my driver like as it.


> > > This looks awfully like compressed audio support...  should there be
> > > integration with the compressed audio API/
> 
> > Thanks, I'll try it. Is there Documentation in
> sound/designes/compress-offload.rst?
> > And best sample is... Intel's driver?
> 
> Yes.
> 
> > (Summary)
> > I think I should fix as follows:
> 
> >   - Split DMA, DAI patches from large one
> >   - Validate parameters in hw_params
> >   - Add description about HW SRC (or fix bad name 'srcport')
> >   - Add comments about uniphier_aiodma_irq()
> >   - Expose clocking and audio routing to userspace, or at the very
> >     least machine driver configuration
> >   - Support compress-audio API for S/PDIF
> 
> > and post V2.
> 
> At least.  I do think we need to get to the bottom of how flexible the
> hardware is first though.

Yes, indeed. This hardware is more flexible and complex, but now I (and our
company) don't use it. Of course, I don't want to hide some features of this
hardware from ALSA people. I should try to upstream all features in the future,
I think.


Regards,
--
Katsuhiro Suzuki

^ permalink raw reply

* [PATCH v6 2/2] media: i2c: Add the ov7740 image sensor driver
From: Yang, Wenyou @ 2017-12-06  5:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171205104549.aoturlmm3s6net37@valkosipuli.retiisi.org.uk>

Hi Sakari,


On 2017/12/5 18:45, Sakari Ailus wrote:
> Hi Wenyou,
>
> On Mon, Dec 04, 2017 at 02:58:58PM +0800, Wenyou Yang wrote:
>> The ov7740 (color) image sensor is a high performance VGA CMOS
>> image snesor, which supports for output formats: RAW RGB and YUV
>> and image sizes: VGA, and QVGA, CIF and any size smaller.
>>
>> Signed-off-by: Songjun Wu <songjun.wu@microchip.com>
>> Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
>> ---
>>
>> Changes in v6:
>>   - Remove unnecessary #include <linux/init>.
>>   - Remove unnecessary comments and extra newline.
>>   - Add const for some structures.
>>   - Add the check of the return value from regmap_write().
>>   - Simplify the calling of __v4l2_ctrl_handler_setup().
>>   - Add the default format initialization function.
>>   - Integrate the set_power() and enable/disable the clock into
>>     one function.
>>
>> Changes in v5:
>>   - Squash the driver and MAINTAINERS entry patches to one.
>>   - Precede the driver patch with the bindings patch.
>>
>> Changes in v4:
>>   - Assign 'val' a initial value to avoid warning: 'val' may be
>>     used uninitialized.
>>   - Rename REG_REG15 to avoid warning: "REG_REG15" redefined.
>>
>> Changes in v3:
>>   - Put the MAINTAINERS change to a separate patch.
>>
>> Changes in v2:
>>   - Split off the bindings into a separate patch.
>>   - Add a new entry to the MAINTAINERS file.
>>
>>   MAINTAINERS                |    8 +
>>   drivers/media/i2c/Kconfig  |    8 +
>>   drivers/media/i2c/Makefile |    1 +
>>   drivers/media/i2c/ov7740.c | 1226 ++++++++++++++++++++++++++++++++++++++++++++
>>   4 files changed, 1243 insertions(+)
>>   create mode 100644 drivers/media/i2c/ov7740.c
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 7a52a66aa991..1de965009b13 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -10053,6 +10053,14 @@ S:	Maintained
>>   F:	drivers/media/i2c/ov7670.c
>>   F:	Documentation/devicetree/bindings/media/i2c/ov7670.txt
>>   
>> +OMNIVISION OV7740 SENSOR DRIVER
>> +M:	Wenyou Yang <wenyou.yang@microchip.com>
>> +L:	linux-media at vger.kernel.org
>> +T:	git git://linuxtv.org/media_tree.git
>> +S:	Maintained
>> +F:	drivers/media/i2c/ov7740.c
>> +F:	Documentation/devicetree/bindings/media/i2c/ov7740.txt
>> +
>>   ONENAND FLASH DRIVER
>>   M:	Kyungmin Park <kyungmin.park@samsung.com>
>>   L:	linux-mtd at lists.infradead.org
>> diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
>> index cb5d7ff82915..00b1c4c031d4 100644
>> --- a/drivers/media/i2c/Kconfig
>> +++ b/drivers/media/i2c/Kconfig
>> @@ -665,6 +665,14 @@ config VIDEO_OV7670
>>   	  OV7670 VGA camera.  It currently only works with the M88ALP01
>>   	  controller.
>>   
>> +config VIDEO_OV7740
>> +	tristate "OmniVision OV7740 sensor support"
>> +	depends on I2C && VIDEO_V4L2
>> +	depends on MEDIA_CAMERA_SUPPORT
>> +	---help---
>> +	  This is a Video4Linux2 sensor-level driver for the OmniVision
>> +	  OV7740 VGA camera sensor.
>> +
>>   config VIDEO_OV9650
>>   	tristate "OmniVision OV9650/OV9652 sensor support"
>>   	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
>> diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
>> index 548a9efce966..9b19ec7fcaf4 100644
>> --- a/drivers/media/i2c/Makefile
>> +++ b/drivers/media/i2c/Makefile
>> @@ -68,6 +68,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
>>   obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
>>   obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
>>   obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
>> +obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
>>   obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
>>   obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
>>   obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
>> diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
>> new file mode 100644
>> index 000000000000..42c25277d005
>> --- /dev/null
>> +++ b/drivers/media/i2c/ov7740.c
>> @@ -0,0 +1,1226 @@
>> +/*
>> + * Copyright (c) 2017 Microchip 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.
>> + *
>> + * 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 <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio.h>
>> +#include <linux/i2c.h>
>> +#include <linux/module.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <media/v4l2-ctrls.h>
>> +#include <media/v4l2-event.h>
>> +#include <media/v4l2-image-sizes.h>
>> +#include <media/v4l2-subdev.h>
>> +
>> +#define REG_OUTSIZE_LSB 0x34
>> +
>> +/* OV7740 register tables */
>> +#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
>> +#define REG_BGAIN	0x01	/* blue gain */
>> +#define REG_RGAIN	0x02	/* red gain */
>> +#define REG_GGAIN	0x03	/* green gain */
>> +#define REG_REG04	0x04	/* analog setting, dont change*/
>> +#define REG_BAVG	0x05	/* b channel average */
>> +#define REG_GAVG	0x06	/* g channel average */
>> +#define REG_RAVG	0x07	/* r channel average */
>> +
>> +#define REG_REG0C	0x0C	/* filp enable */
>> +#define REG0C_IMG_FLIP		0x80
>> +#define REG0C_IMG_MIRROR	0x40
>> +
>> +#define REG_REG0E	0x0E	/* blc line */
>> +#define REG_HAEC	0x0F	/* auto exposure cntrl */
>> +#define REG_AEC		0x10	/* auto exposure cntrl */
>> +
>> +#define REG_CLK		0x11	/* Clock control */
>> +#define REG_REG55	0x55	/* Clock PLL DIV/PreDiv */
>> +
>> +#define REG_REG12	0x12
>> +
>> +#define REG_REG13	0x13	/* auto/manual AGC, AEC, Write Balance*/
>> +#define REG13_AEC_EN	0x01
>> +#define REG13_AGC_EN	0x04
>> +
>> +#define REG_REG14	0x14
>> +#define REG_CTRL15	0x15
>> +#define REG15_GAIN_MSB	0x03
>> +
>> +#define REG_REG16	0x16
>> +
>> +#define REG_MIDH	0x1C	/* manufacture id byte */
>> +#define REG_MIDL	0x1D	/* manufacture id byre */
>> +#define REG_PIDH	0x0A	/* Product ID MSB */
>> +#define REG_PIDL	0x0B	/* Product ID LSB */
>> +
>> +#define REG_84		0x84	/* lots of stuff */
>> +#define REG_REG38	0x38	/* sub-addr */
>> +
>> +#define REG_AHSTART	0x17	/* Horiz start high bits */
>> +#define REG_AHSIZE	0x18
>> +#define REG_AVSTART	0x19	/* Vert start high bits */
>> +#define REG_AVSIZE	0x1A
>> +#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
>> +
>> +#define REG_HOUTSIZE	0x31
>> +#define REG_VOUTSIZE	0x32
>> +#define REG_HVSIZEOFF	0x33
>> +#define REG_REG34	0x34	/* DSP output size H/V LSB*/
>> +
>> +#define REG_ISP_CTRL00	0x80
>> +#define ISPCTRL00_AWB_EN	0x10
>> +#define ISPCTRL00_AWB_GAIN_EN	0x04
>> +
>> +#define	REG_YGAIN	0xE2	/* ygain for contrast control */
>> +
>> +#define	REG_YBRIGHT	  0xE3
>> +#define	REG_SGNSET	  0xE4
>> +#define	SGNSET_YBRIGHT_MASK	  0x08
>> +
>> +#define REG_USAT	0xDD
>> +#define REG_VSAT	0xDE
>> +
>> +
>> +struct ov7740 {
>> +	struct v4l2_subdev subdev;
>> +#if defined(CONFIG_MEDIA_CONTROLLER)
>> +	struct media_pad pad;
>> +#endif
>> +	struct v4l2_mbus_framefmt format;
>> +	const struct ov7740_pixfmt *fmt;  /* Current format */
>> +	const struct ov7740_framesize *frmsize;
>> +	struct regmap *regmap;
>> +	struct clk *xvclk;
>> +	struct v4l2_ctrl_handler ctrl_handler;
>> +	struct {
>> +		/* gain cluster */
>> +		struct v4l2_ctrl *auto_gain;
>> +		struct v4l2_ctrl *gain;
>> +	};
>> +	struct {
>> +		struct v4l2_ctrl *auto_wb;
>> +		struct v4l2_ctrl *blue_balance;
>> +		struct v4l2_ctrl *red_balance;
>> +	};
>> +	struct {
>> +		struct v4l2_ctrl *hflip;
>> +		struct v4l2_ctrl *vflip;
>> +	};
>> +	struct {
>> +		/* exposure cluster */
>> +		struct v4l2_ctrl *auto_exposure;
>> +		struct v4l2_ctrl *exposure;
>> +	};
>> +	struct {
>> +		/* saturation/hue cluster */
>> +		struct v4l2_ctrl *saturation;
>> +		struct v4l2_ctrl *hue;
>> +	};
>> +	struct v4l2_ctrl *brightness;
>> +	struct v4l2_ctrl *contrast;
>> +
>> +	struct mutex mutex;	/* To serialize asynchronus callbacks */
>> +	bool streaming;		/* Streaming on/off */
>> +
>> +	struct gpio_desc *resetb_gpio;
>> +	struct gpio_desc *pwdn_gpio;
>> +};
>> +
>> +struct ov7740_pixfmt {
>> +	u32 mbus_code;
>> +	enum v4l2_colorspace colorspace;
>> +	const struct reg_sequence *regs;
>> +	u32 reg_num;
>> +};
>> +
>> +struct ov7740_framesize {
>> +	u16 width;
>> +	u16 height;
>> +	const struct reg_sequence *regs;
>> +	u32 reg_num;
>> +};
>> +
>> +static const struct reg_sequence ov7740_vga[] = {
>> +	{0x55, 0x40},
>> +	{0x11, 0x02},
>> +
>> +	{0xd5, 0x10},
>> +	{0x0c, 0x12},
>> +	{0x0d, 0x34},
>> +	{0x17, 0x25},
>> +	{0x18, 0xa0},
>> +	{0x19, 0x03},
>> +	{0x1a, 0xf0},
>> +	{0x1b, 0x89},
>> +	{0x22, 0x03},
>> +	{0x29, 0x18},
>> +	{0x2b, 0xf8},
>> +	{0x2c, 0x01},
>> +	{REG_HOUTSIZE, 0xa0},
>> +	{REG_VOUTSIZE, 0xf0},
>> +	{0x33, 0xc4},
>> +	{REG_OUTSIZE_LSB, 0x0},
>> +	{0x35, 0x05},
>> +	{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},
>> +
>> +	{0x81, 0x3f},
>> +	{0x82, 0x32},
>> +	{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},
>> +};
>> +
>> +static const struct ov7740_framesize ov7740_framesizes[] = {
>> +	{
>> +		.width		= VGA_WIDTH,
>> +		.height		= VGA_HEIGHT,
>> +		.regs		= ov7740_vga,
>> +		.reg_num	= ARRAY_SIZE(ov7740_vga),
>> +	},
>> +};
>> +
>> +#ifdef CONFIG_VIDEO_ADV_DEBUG
>> +static int ov7740_get_register(struct v4l2_subdev *sd,
>> +			       struct v4l2_dbg_register *reg)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int val = 0;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, reg->reg & 0xff, &val);
>> +	reg->val = val;
>> +	reg->size = 1;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_register(struct v4l2_subdev *sd,
>> +			       const struct v4l2_dbg_register *reg)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct regmap *regmap = ov7740->regmap;
>> +
>> +	regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff);
>> +
>> +	return 0;
>> +}
>> +#endif
>> +
>> +static int ov7740_set_power(struct ov7740 *ov7740, int on)
>> +{
>> +	int ret;
>> +
>> +	if (on) {
>> +		ret = clk_prepare_enable(ov7740->xvclk);
>> +		if (ret)
>> +			return ret;
>> +
>> +		if (ov7740->pwdn_gpio)
>> +			gpiod_direction_output(ov7740->pwdn_gpio, 0);
>> +
>> +		if (ov7740->resetb_gpio) {
>> +			gpiod_set_value(ov7740->resetb_gpio, 1);
>> +			usleep_range(500, 1000);
>> +			gpiod_set_value(ov7740->resetb_gpio, 0);
>> +			usleep_range(3000, 5000);
>> +		}
>> +	} else {
>> +		clk_disable_unprepare(ov7740->xvclk);
>> +
>> +		if (ov7740->pwdn_gpio)
>> +			gpiod_direction_output(ov7740->pwdn_gpio, 0);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
>> +	.log_status = v4l2_ctrl_subdev_log_status,
>> +#ifdef CONFIG_VIDEO_ADV_DEBUG
>> +	.g_register = ov7740_get_register,
>> +	.s_register = ov7740_set_register,
>> +#endif
>> +	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
>> +	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
>> +};
>> +
>> +static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb)
>> +{
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int value;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_ISP_CTRL00, &value);
>> +	if (!ret) {
>> +		if (awb)
>> +			value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
>> +		else
>> +			value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
>> +		ret = regmap_write(regmap, REG_ISP_CTRL00, value);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	if (!awb) {
>> +		ret = regmap_write(regmap, REG_BGAIN,
>> +				   ov7740->blue_balance->val);
>> +		if (ret)
>> +			return ret;
>> +
>> +		ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val);
>> +		if (ret)
>> +			return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_saturation(struct regmap *regmap, int value)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_write(regmap, REG_USAT, (unsigned char)value);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_write(regmap, REG_VSAT, (unsigned char)value);
>> +}
>> +
>> +static int ov7740_set_gain(struct regmap *regmap, int value)
>> +{
>> +	int ret;
>> +
>> +	ret = regmap_write(regmap, REG_GAIN, value & 0xff);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_update_bits(regmap, REG_CTRL15,
>> +				 REG15_GAIN_MSB, (value >> 8) & 0x3);
>> +	if (!ret)
>> +		ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
>> +
>> +	return ret;
>> +}
>> +
>> +static int ov7740_set_autogain(struct regmap *regmap, int value)
>> +{
>> +	unsigned int reg;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_REG13, &reg);
>> +	if (ret)
>> +		return ret;
>> +	if (value)
>> +		reg |= REG13_AGC_EN;
>> +	else
>> +		reg &= ~REG13_AGC_EN;
>> +	return regmap_write(regmap, REG_REG13, reg);
>> +}
>> +
>> +static int ov7740_set_brightness(struct regmap *regmap, int value)
>> +{
>> +	/* Turn off AEC/AGC */
>> +	regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0);
>> +	regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
>> +
>> +	if (value >= 0) {
>> +		regmap_write(regmap, REG_YBRIGHT, (unsigned char)value);
>> +		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0);
>> +	} else{
>> +		regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value));
>> +		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_contrast(struct regmap *regmap, int value)
>> +{
>> +	return regmap_write(regmap, REG_YGAIN, (unsigned char)value);
>> +}
>> +
>> +static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl)
>> +{
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int value0, value1;
>> +	int ret;
>> +
>> +	if (!ctrl->val)
>> +		return 0;
>> +
>> +	ret = regmap_read(regmap, REG_GAIN, &value0);
>> +	if (ret)
>> +		return ret;
>> +	ret = regmap_read(regmap, REG_CTRL15, &value1);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ov7740->gain->val = (value1 << 8) | (value0 & 0xff);
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_exp(struct regmap *regmap, int value)
>> +{
>> +	int ret;
>> +
>> +	/* Turn off AEC/AGC */
>> +	ret = regmap_update_bits(regmap, REG_REG13,
>> +				 REG13_AEC_EN | REG13_AGC_EN, 0);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_write(regmap, REG_AEC, (unsigned char)value);
>> +	if (ret)
>> +		return ret;
>> +
>> +	return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8));
>> +}
>> +
>> +static int ov7740_set_autoexp(struct regmap *regmap,
>> +			      enum v4l2_exposure_auto_type value)
>> +{
>> +	unsigned int reg;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_REG13, &reg);
>> +	if (!ret) {
>> +		if (value == V4L2_EXPOSURE_AUTO)
>> +			reg |= (REG13_AEC_EN | REG13_AGC_EN);
>> +		else
>> +			reg &= ~(REG13_AEC_EN | REG13_AGC_EN);
>> +		ret = regmap_write(regmap, REG_REG13, reg);
>> +	}
>> +
>> +	return ret;
>> +}
>> +
>> +
>> +static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +	struct ov7740 *ov7740 = container_of(ctrl->handler,
>> +					     struct ov7740, ctrl_handler);
>> +	int ret;
>> +
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_AUTOGAIN:
>> +		ret = ov7740_get_gain(ov7740, ctrl);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +	return ret;
>> +}
>> +
>> +static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
>> +{
>> +	struct ov7740 *ov7740 = container_of(ctrl->handler,
>> +					     struct ov7740, ctrl_handler);
>> +	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
>> +	struct regmap *regmap = ov7740->regmap;
>> +	int ret;
>> +	u8 val = 0;
>> +
>> +	if (pm_runtime_get_if_in_use(&client->dev) <= 0)
>> +		return 0;
>> +
>> +	switch (ctrl->id) {
>> +	case V4L2_CID_AUTO_WHITE_BALANCE:
>> +		ret = ov7740_set_white_balance(ov7740, ctrl->val);
>> +		break;
>> +	case V4L2_CID_SATURATION:
>> +		ret = ov7740_set_saturation(regmap, ctrl->val);
>> +		break;
>> +	case V4L2_CID_BRIGHTNESS:
>> +		ret = ov7740_set_brightness(regmap, ctrl->val);
>> +		break;
>> +	case V4L2_CID_CONTRAST:
>> +		ret = ov7740_set_contrast(regmap, ctrl->val);
>> +		break;
>> +	case V4L2_CID_VFLIP:
>> +		ret = regmap_update_bits(regmap, REG_REG0C,
>> +					 REG0C_IMG_FLIP, val);
>> +		break;
>> +	case V4L2_CID_HFLIP:
>> +		val = ctrl->val ? REG0C_IMG_MIRROR : 0x00;
>> +		ret = regmap_update_bits(regmap, REG_REG0C,
>> +					 REG0C_IMG_MIRROR, val);
>> +		break;
>> +	case V4L2_CID_AUTOGAIN:
>> +		if (!ctrl->val)
>> +			return ov7740_set_gain(regmap, ov7740->gain->val);
>> +
>> +		ret = ov7740_set_autogain(regmap, ctrl->val);
>> +		break;
>> +
>> +	case V4L2_CID_EXPOSURE_AUTO:
>> +		if (ctrl->val == V4L2_EXPOSURE_MANUAL)
>> +			return ov7740_set_exp(regmap, ov7740->exposure->val);
>> +
>> +		ret = ov7740_set_autoexp(regmap, ctrl->val);
>> +		break;
>> +	default:
>> +		ret = -EINVAL;
>> +		break;
>> +	}
>> +
>> +	pm_runtime_put(&client->dev);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_ctrl_ops ov7740_ctrl_ops = {
>> +	.g_volatile_ctrl = ov7740_get_volatile_ctrl,
>> +	.s_ctrl = ov7740_set_ctrl,
>> +};
>> +
>> +static int ov7740_start_streaming(struct ov7740 *ov7740)
>> +{
>> +	return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler);
>> +}
>> +
>> +static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct i2c_client *client = v4l2_get_subdevdata(sd);
>> +	int ret = 0;
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	if (ov7740->streaming == enable) {
>> +		mutex_unlock(&ov7740->mutex);
>> +		return 0;
>> +	}
>> +
>> +	if (enable) {
>> +		ret = pm_runtime_get_sync(&client->dev);
>> +		if (ret < 0) {
>> +			pm_runtime_put_noidle(&client->dev);
>> +			goto err_unlock;
>> +		}
>> +
>> +		ret = ov7740_start_streaming(ov7740);
>> +		if (ret)
>> +			goto err_rpm_put;
>> +	} else {
>> +		pm_runtime_put(&client->dev);
>> +	}
>> +
>> +	ov7740->streaming = enable;
>> +
>> +	mutex_unlock(&ov7740->mutex);
>> +	return ret;
>> +
>> +err_rpm_put:
>> +	pm_runtime_put(&client->dev);
>> +err_unlock:
>> +	mutex_unlock(&ov7740->mutex);
>> +	return ret;
>> +}
>> +
>> +static int ov7740_get_parm(struct v4l2_subdev *sd,
>> +			   struct v4l2_streamparm *parms)
>> +{
>> +	struct v4l2_captureparm *cp = &parms->parm.capture;
>> +	struct v4l2_fract *tpf = &cp->timeperframe;
>> +
>> +	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +		return -EINVAL;
>> +
>> +	memset(cp, 0, sizeof(struct v4l2_captureparm));
>> +	cp->capability = V4L2_CAP_TIMEPERFRAME;
>> +
>> +	tpf->numerator = 1;
>> +	tpf->denominator = 60;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_parm(struct v4l2_subdev *sd,
>> +			   struct v4l2_streamparm *parms)
>> +{
>> +	struct v4l2_captureparm *cp = &parms->parm.capture;
>> +	struct v4l2_fract *tpf = &cp->timeperframe;
>> +
>> +	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
>> +		return -EINVAL;
>> +	if (cp->extendedmode != 0)
>> +		return -EINVAL;
>> +
>> +	cp->capability = V4L2_CAP_TIMEPERFRAME;
>> +
>> +	tpf->numerator = 1;
>> +	tpf->denominator = 60;
>> +
>> +	return 0;
>> +}
>> +
>> +static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
>> +	.s_stream = ov7740_set_stream,
>> +	.s_parm = ov7740_set_parm,
>> +	.g_parm = ov7740_get_parm,
>> +};
>> +
>> +static const struct reg_sequence ov7740_format_yuyv[] = {
>> +	{0x12, 0x00},
>> +	{0x36, 0x3f},
>> +	{0x80, 0x7f},
>> +	{0x83, 0x01},
>> +};
>> +
>> +static const struct reg_sequence ov7740_format_bggr8[] = {
>> +	{0x36, 0x2f},
>> +	{0x80, 0x01},
>> +	{0x83, 0x04},
>> +};
>> +
>> +static const struct ov7740_pixfmt ov7740_formats[] = {
>> +	{
>> +		.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
>> +		.colorspace = V4L2_COLORSPACE_SRGB,
>> +		.regs = ov7740_format_yuyv,
>> +		.reg_num = ARRAY_SIZE(ov7740_format_yuyv),
>> +	},
>> +	{
>> +		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
>> +		.colorspace = V4L2_COLORSPACE_SRGB,
>> +		.regs = ov7740_format_bggr8,
>> +		.reg_num = ARRAY_SIZE(ov7740_format_bggr8),
>> +	}
>> +};
>> +#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)
>> +
>> +static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
>> +				 struct v4l2_subdev_pad_config *cfg,
>> +				 struct v4l2_subdev_mbus_code_enum *code)
>> +{
>> +	if (code->pad || code->index >= N_OV7740_FMTS)
>> +		return -EINVAL;
>> +
>> +	code->code = ov7740_formats[code->index].mbus_code;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
>> +				struct v4l2_subdev_pad_config *cfg,
>> +				struct v4l2_subdev_frame_interval_enum *fie)
>> +{
>> +	if (fie->pad)
>> +		return -EINVAL;
>> +
>> +	if (fie->index >= 1)
>> +		return -EINVAL;
>> +
>> +	if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT))
>> +		return -EINVAL;
>> +
>> +	fie->interval.numerator = 1;
>> +	fie->interval.denominator = 60;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_enum_frame_size(struct v4l2_subdev *sd,
>> +				  struct v4l2_subdev_pad_config *cfg,
>> +				  struct v4l2_subdev_frame_size_enum *fse)
>> +{
>> +	if (fse->pad)
>> +		return -EINVAL;
>> +
>> +	if (fse->index > 0)
>> +		return -EINVAL;
>> +
>> +	fse->min_width = fse->max_width = VGA_WIDTH;
>> +	fse->min_height = fse->max_height = VGA_HEIGHT;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
>> +				   struct v4l2_mbus_framefmt *fmt,
>> +				   const struct ov7740_pixfmt **ret_fmt,
>> +				   const struct ov7740_framesize **ret_frmsize)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	const struct ov7740_framesize *fsize = &ov7740_framesizes[0];
>> +	int index, i;
>> +
>> +	for (index = 0; index < N_OV7740_FMTS; index++) {
>> +		if (ov7740_formats[index].mbus_code == fmt->code)
>> +			break;
>> +	}
>> +	if (index >= N_OV7740_FMTS) {
>> +		/* default to first format */
>> +		index = 0;
>> +		fmt->code = ov7740_formats[0].mbus_code;
>> +	}
>> +	if (ret_fmt != NULL)
>> +		*ret_fmt = ov7740_formats + index;
>> +
>> +	for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) {
>> +		if ((fsize->width >= fmt->width) &&
>> +		    (fsize->height >= fmt->height)) {
>> +			fmt->width = fsize->width;
>> +			fmt->height = fsize->height;
>> +			break;
>> +		}
>> +
>> +		fsize++;
>> +	}
>> +
>> +	if (ret_frmsize != NULL)
>> +		*ret_frmsize = fsize;
>> +
>> +	fmt->field = V4L2_FIELD_NONE;
>> +	fmt->colorspace = ov7740_formats[index].colorspace;
>> +
>> +	ov7740->format = *fmt;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_set_fmt(struct v4l2_subdev *sd,
>> +			  struct v4l2_subdev_pad_config *cfg,
>> +			  struct v4l2_subdev_format *format)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	const struct ov7740_pixfmt *ovfmt;
>> +	const struct ov7740_framesize *fsize;
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +	struct v4l2_mbus_framefmt *mbus_fmt;
>> +#endif
>> +	int ret;
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	if (format->pad) {
>> +		ret = -EINVAL;
>> +		goto error;
>> +	}
>> +
>> +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
>> +		ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL);
>> +		if (ret)
>> +			goto error;
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
>> +		*mbus_fmt = format->format;
>> +
>> +		mutex_unlock(&ov7740->mutex);
>> +		return 0;
>> +#else
>> +		ret = -ENOTTY;
>> +		goto error;
>> +#endif
>> +	}
>> +
>> +	ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize);
>> +	if (ret)
>> +		goto error;
>> +
>> +	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
>> +		regmap_multi_reg_write(ov7740->regmap,
>> +				       ovfmt->regs, ovfmt->reg_num);
>> +
>> +		regmap_multi_reg_write(ov7740->regmap,
>> +				       fsize->regs, fsize->reg_num);
>> +	}
>> +
>> +	ov7740->fmt = ovfmt;
>> +
>> +	mutex_unlock(&ov7740->mutex);
>> +	return 0;
>> +
>> +error:
>> +	mutex_unlock(&ov7740->mutex);
>> +	return ret;
>> +}
>> +
>> +static int ov7740_get_fmt(struct v4l2_subdev *sd,
>> +			  struct v4l2_subdev_pad_config *cfg,
>> +			  struct v4l2_subdev_format *format)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +	struct v4l2_mbus_framefmt *mbus_fmt;
>> +#endif
>> +	int ret = 0;
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
>> +		format->format = *mbus_fmt;
>> +		ret = 0;
>> +#else
>> +		ret = -ENOTTY;
>> +#endif
>> +	} else {
>> +		format->format = ov7740->format;
>> +	}
>> +	mutex_unlock(&ov7740->mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
>> +	.enum_frame_interval = ov7740_enum_frame_interval,
>> +	.enum_frame_size = ov7740_enum_frame_size,
>> +	.enum_mbus_code = ov7740_enum_mbus_code,
>> +	.get_fmt = ov7740_get_fmt,
>> +	.set_fmt = ov7740_set_fmt,
>> +};
>> +
>> +static const struct v4l2_subdev_ops ov7740_subdev_ops = {
>> +	.core	= &ov7740_subdev_core_ops,
>> +	.video	= &ov7740_subdev_video_ops,
>> +	.pad	= &ov7740_subdev_pad_ops,
>> +};
>> +
>> +static void ov7740_get_default_format(struct v4l2_subdev *sd,
>> +				      struct v4l2_mbus_framefmt *format)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	format->width = ov7740->frmsize->width;
>> +	format->height = ov7740->frmsize->height;
>> +	format->colorspace = ov7740->fmt->colorspace;
>> +	format->code = ov7740->fmt->mbus_code;
>> +	format->field = V4L2_FIELD_NONE;
>> +}
>> +
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
>> +{
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +	struct v4l2_mbus_framefmt *format =
>> +				v4l2_subdev_get_try_format(sd, fh->pad, 0);
>> +
>> +	mutex_lock(&ov7740->mutex);
>> +	ov7740_get_default_format(sd, format);
>> +	mutex_unlock(&ov7740->mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = {
>> +	.open = ov7740_open,
>> +};
>> +#endif
>> +
>> +static void ov7740_init_default_format(struct ov7740 *ov7740)
>> +{
>> +	ov7740->frmsize = &ov7740_framesizes[0];
>> +	ov7740->fmt = &ov7740_formats[0];
>> +
>> +	regmap_multi_reg_write(ov7740->regmap,
>> +			       ov7740->fmt->regs, ov7740->fmt->reg_num);
>> +
>> +	regmap_multi_reg_write(ov7740->regmap,
>> +			       ov7740->frmsize->regs, ov7740->frmsize->reg_num);
>> +}
>> +
>> +static int ov7740_probe_dt(struct i2c_client *client,
>> +			   struct ov7740 *ov7740)
>> +{
>> +	ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset",
>> +			GPIOD_OUT_HIGH);
>> +	if (IS_ERR(ov7740->resetb_gpio)) {
>> +		dev_info(&client->dev, "can't get %s GPIO\n", "reset");
>> +		return PTR_ERR(ov7740->resetb_gpio);
>> +	}
>> +
>> +	ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
>> +			GPIOD_OUT_LOW);
>> +	if (IS_ERR(ov7740->pwdn_gpio)) {
>> +		dev_info(&client->dev, "can't get %s GPIO\n", "powerdown");
>> +		return PTR_ERR(ov7740->pwdn_gpio);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_detect(struct ov7740 *ov7740)
>> +{
>> +	struct regmap *regmap = ov7740->regmap;
>> +	unsigned int midh, midl, pidh, pidl;
>> +	int ret;
>> +
>> +	ret = regmap_read(regmap, REG_MIDH, &midh);
>> +	if (ret)
>> +		return ret;
>> +	if (midh != 0x7f)
>> +		return -ENODEV;
>> +
>> +	ret = regmap_read(regmap, REG_MIDL, &midl);
>> +	if (ret)
>> +		return ret;
>> +	if (midl != 0xa2)
>> +		return -ENODEV;
>> +
>> +	ret = regmap_read(regmap, REG_PIDH, &pidh);
>> +	if (ret)
>> +		return ret;
>> +	if (pidh != 0x77)
>> +		return -ENODEV;
>> +
>> +	ret = regmap_read(regmap, REG_PIDL, &pidl);
>> +	if (ret)
>> +		return ret;
>> +	if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42))
>> +		return -ENODEV;
>> +
>> +	return 0;
>> +}
>> +
>> +static int ov7740_init_controls(struct ov7740 *ov7740)
>> +{
>> +	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
>> +	struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler;
>> +	int ret;
>> +
>> +	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	ctrl_hdlr->lock = &ov7740->mutex;
>> +	ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					  V4L2_CID_AUTO_WHITE_BALANCE,
>> +					  0, 1, 1, 1);
>> +	ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					       V4L2_CID_BLUE_BALANCE,
>> +					       0, 0xff, 1, 0x80);
>> +	ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					      V4L2_CID_RED_BALANCE,
>> +					      0, 0xff, 1, 0x80);
>> +
>> +	ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					     V4L2_CID_BRIGHTNESS,
>> +					     -255, 255, 1, 0);
>> +	ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					   V4L2_CID_CONTRAST,
>> +					   0, 127, 1, 0x20);
>> +	ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +			  V4L2_CID_SATURATION, 0, 256, 1, 0x80);
>> +	ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					V4L2_CID_HFLIP, 0, 1, 1, 0);
>> +	ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					V4L2_CID_VFLIP, 0, 1, 1, 0);
>> +	ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +				       V4L2_CID_GAIN, 0, 1023, 1, 500);
>> +	ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					    V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
>> +	ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
>> +					   V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
>> +	ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr,
>> +					&ov7740_ctrl_ops,
>> +					V4L2_CID_EXPOSURE_AUTO,
>> +					V4L2_EXPOSURE_MANUAL, 0,
>> +					V4L2_EXPOSURE_AUTO);
>> +
>> +	ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
>> +	ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
>> +
>> +	v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false);
>> +	v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);
>> +	v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,
>> +			       V4L2_EXPOSURE_MANUAL, false);
>> +	v4l2_ctrl_cluster(2, &ov7740->hflip);
>> +
>> +	ret = v4l2_ctrl_handler_setup(ctrl_hdlr);
>> +	if (ret) {
>> +		dev_err(&client->dev, "%s control init failed (%d)\n",
>> +			__func__, ret);
>> +		goto error;
>> +	}
>> +
>> +	ov7740->subdev.ctrl_handler = ctrl_hdlr;
>> +	return 0;
>> +
>> +error:
>> +	v4l2_ctrl_handler_free(ctrl_hdlr);
>> +	mutex_destroy(&ov7740->mutex);
>> +	return ret;
>> +}
>> +
>> +static void ov7740_free_controls(struct ov7740 *ov7740)
>> +{
>> +	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
>> +	mutex_destroy(&ov7740->mutex);
>> +}
>> +
>> +#define OV7740_MAX_REGISTER     0xff
>> +static const struct regmap_config ov7740_regmap_config = {
>> +	.reg_bits	= 8,
>> +	.val_bits	= 8,
>> +	.max_register	= OV7740_MAX_REGISTER,
>> +};
>> +
>> +static int ov7740_probe(struct i2c_client *client,
>> +			const struct i2c_device_id *id)
>> +{
>> +	struct ov7740 *ov7740;
>> +	struct v4l2_subdev *sd;
>> +	int ret;
>> +
>> +	if (!i2c_check_functionality(client->adapter,
>> +				     I2C_FUNC_SMBUS_BYTE_DATA)) {
>> +		dev_err(&client->dev,
>> +			"OV7740: I2C-Adapter doesn't support SMBUS\n");
>> +		return -EIO;
>> +	}
>> +
>> +	ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL);
>> +	if (!ov7740)
>> +		return -ENOMEM;
>> +
>> +	ov7740->xvclk = devm_clk_get(&client->dev, "xvclk");
>> +	if (IS_ERR(ov7740->xvclk)) {
>> +		ret = PTR_ERR(ov7740->xvclk);
>> +		dev_err(&client->dev,
>> +			"OV7740: fail to get xvclk: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = ov7740_probe_dt(client, ov7740);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config);
>> +	if (IS_ERR(ov7740->regmap)) {
>> +		ret = PTR_ERR(ov7740->regmap);
>> +		dev_err(&client->dev, "Failed to allocate register map: %d\n",
>> +			ret);
>> +		return ret;
>> +	}
>> +
>> +	sd = &ov7740->subdev;
>> +	client->flags |= I2C_CLIENT_SCCB;
>> +	v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops);
>> +
>> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
>> +	sd->internal_ops = &ov7740_subdev_internal_ops;
>> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
>> +#endif
>> +
>> +#if defined(CONFIG_MEDIA_CONTROLLER)
>> +	ov7740->pad.flags = MEDIA_PAD_FL_SOURCE;
>> +	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
>> +	ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad);
>> +	if (ret)
>> +		return ret;
>> +#endif
>> +
>> +	ret = ov7740_set_power(ov7740, 1);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = ov7740_detect(ov7740);
>> +	if (ret)
>> +		goto error_detect;
>> +
>> +	mutex_init(&ov7740->mutex);
>> +
>> +	ret = ov7740_init_controls(ov7740);
>> +	if (ret)
>> +		goto error_init_controls;
>> +
>> +	v4l_info(client, "chip found @ 0x%02x (%s)\n",
>> +			client->addr << 1, client->adapter->name);
>> +
>> +	ov7740_init_default_format(ov7740);
> This doesn't yet address the issue. The sensor will be powered off just a
> few lines below, so the device state will be lost. You need to ensure the
> registers get programmed after the sensor is powered on and before
> streaming is started.
Right.
Thank you.

>
>> +
>> +	ov7740_get_default_format(sd, &ov7740->format);
>> +
>> +	ret = v4l2_async_register_subdev(sd);
>> +	if (ret)
>> +		goto error_async_register;
>> +
>> +	pm_runtime_set_active(&client->dev);
>> +	pm_runtime_enable(&client->dev);
>> +	pm_runtime_idle(&client->dev);
>> +
>> +	return 0;
>> +
>> +error_async_register:
>> +	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
>> +error_init_controls:
>> +	ov7740_free_controls(ov7740);
>> +error_detect:
>> +	ov7740_set_power(ov7740, 0);
>> +	media_entity_cleanup(&ov7740->subdev.entity);
>> +
>> +	return ret;
>> +}
>> +
>> +static int ov7740_remove(struct i2c_client *client)
>> +{
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	mutex_destroy(&ov7740->mutex);
>> +	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
>> +#if defined(CONFIG_MEDIA_CONTROLLER)
>> +	media_entity_cleanup(&ov7740->subdev.entity);
>> +#endif
>> +	v4l2_async_unregister_subdev(sd);
>> +	ov7740_free_controls(ov7740);
>> +
>> +	pm_runtime_get_sync(&client->dev);
>> +	pm_runtime_disable(&client->dev);
>> +	pm_runtime_set_suspended(&client->dev);
>> +	pm_runtime_put_noidle(&client->dev);
>> +
>> +	ov7740_set_power(ov7740, 0);
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused ov7740_runtime_suspend(struct device *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	ov7740_set_power(ov7740, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static int __maybe_unused ov7740_runtime_resume(struct device *dev)
>> +{
>> +	struct i2c_client *client = to_i2c_client(dev);
>> +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
>> +	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
>> +
>> +	return ov7740_set_power(ov7740, 1);
>> +}
>> +
>> +static const struct i2c_device_id ov7740_id[] = {
>> +	{ "ov7740", 0 },
>> +	{ /* sentinel */ }
>> +};
>> +MODULE_DEVICE_TABLE(i2c, ov7740_id);
>> +
>> +static const struct dev_pm_ops ov7740_pm_ops = {
>> +	SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL)
>> +};
>> +
>> +static const struct of_device_id ov7740_of_match[] = {
>> +	{.compatible = "ovti,ov7740", },
>> +	{ /* sentinel */ },
>> +};
>> +MODULE_DEVICE_TABLE(of, ov7740_of_match);
>> +
>> +static struct i2c_driver ov7740_i2c_driver = {
>> +	.driver = {
>> +		.name = "ov7740",
>> +		.pm = &ov7740_pm_ops,
>> +		.of_match_table = of_match_ptr(ov7740_of_match),
>> +	},
>> +	.probe    = ov7740_probe,
>> +	.remove   = ov7740_remove,
>> +	.id_table = ov7740_id,
>> +};
>> +module_i2c_driver(ov7740_i2c_driver);
>> +
>> +MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor");
>> +MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
>> +MODULE_LICENSE("GPL v2");
>> -- 
>> 2.15.0
>>
Best Regards,
Wenyou Yang

^ permalink raw reply

* [PATCH v6 2/3] dmaeninge: xilinx_dma: Fix bug in multiple frame stores scenario in vdma
From: Appana Durga Kedareswara Rao @ 2017-12-06  4:11 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CY1PR02MB169299C7AA719D4CE56F328DDC3B0@CY1PR02MB1692.namprd02.prod.outlook.com>

Hi Mike Looijmans,

	Thanks for the review...
	Sorry for the long delay in the reply...
Please find comments inline... 

<Snip>
>On 14-01-17 06:35, Kedareswara rao Appana wrote:
>>??When VDMA is configured for more than one frame in the h/w.
>>??For example h/w is configured for n number of frames, user
>>??Submits n number of frames and triggered the DMA using issue_pending API.
>>
>>??In the current driver flow we are submitting one frame at a time,
>>??But we should submit all the n number of frames at one time
>>??As the h/w is configured for n number of frames.
>
>The hardware can always handle a single frame submission, by using the "park"
>bit. This would make a good "cyclic" implementation too (using vdma as
>framebuffer).
>
>It could also handle all cases for "k" frames where n%k==0 (n is a multiple of
>k) by simply replicating the frame pointers.

Agree with your comments will fix it in the next version.
Somehow didn't get enough time to send next version of the patch series.
Will modify the driver as per your comments and will post next version of the patch series at the earliest... 

Regards,
Kedar.

^ permalink raw reply

* [RFC v3 PATCH 0/2] Introduce Security Version to EFI Stub
From: Gary Lin @ 2017-12-06  3:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CA+5PVA4k9RN22i2d=4GCPnm9bwi5KUgp8PiV=9X1pBZxN1xPmg@mail.gmail.com>

On Tue, Dec 05, 2017 at 04:14:26PM -0500, Josh Boyer wrote:
> On Tue, Dec 5, 2017 at 5:01 AM, Gary Lin <glin@suse.com> wrote:
> > The series of patches introduce Security Version to EFI stub.
> >
> > Security Version is a monotonically increasing number and designed to
> > prevent the user from loading an insecure kernel accidentally. The
> > bootloader maintains a list of security versions corresponding to
> > different distributions. After fixing a critical vulnerability, the
> > distribution kernel maintainer bumps the "version", and the bootloader
> > updates the list automatically. When the user tries to load a kernel
> > with a lower security version, the bootloader shows a warning prompt
> > to notify the user the potential risk.
> 
> If a distribution releases a kernel with a higher security version and
> that it automatically updated on boot, what happens if that kernel
> contains a different bug that causes it to fail to boot or break
> critical functionality?  At that point, the user's machine would be in
> a state where the higher security version is enforced but the only
> kernel that provides that is broken.  Wouldn't that make a bad
> situation even worse by now requiring manual acceptance of the older
> SV kernel boot physically at the machine?
> 
> I feel like I'm missing a detail here or something.
> 
If the new kernel fails to boot, then the user has to choose the kernel
manually anyway, and there will be an option in the warning prompt to
lower SV.

Since Security Version is meant to be a warning, not a hard block, we
can introduce a timeout to the warning prompt if necessary. The system
still boots, but with a longer boot time.

Gary Lin

> josh
> 
> > For more details: https://github.com/lcp/shim/wiki/Security-Version
> >
> > The original idea is to add a new PE/COFF section to store the data.
> > However, there are some restrictions.
> >
> > 1. For x86, the size limit of the EFI header is 0x200, and a section entry
> >    in the section table takes 40 bytes. Currently, the EFI header already
> >    occupies the first 0x1da bytes, so there is no room for a new section
> >    entry.
> >
> > 2. The MemoryAttributes table sets the attributes of memory pages according
> >    to the section flags. For ARM64, the minimal granularity is 4KB, but
> >    Security Version only needs a few bytes, and it's pointless to allocate
> >    4KB for it.
> >
> > Fortunately, there is a special section defined in PE/COFF: resource
> > section. The only known user of the resource section in UEFI is the HII
> > protocol which fetches data from "HII" directory. For Security Version, a
> > new directory called "LinuxSV" is created and it contains the file offset
> > to the struct of Security Version. The bootloader just follows the
> > resource table to fetch the "version" from the image file.
> >
> > v3:
> >     - Move everything to the resource section to be compatible with both
> >       x86 and ARM64
> > v2:
> >     - Decrease the size of secdata_offset to 2 bytes since the setup header
> >       is limited to around 32KB.
> >     - Restructure the secdata section. The signer is now a null-terminated
> >       string. The type of distro_version changes to u32 in case the distro
> >       uses a long version.
> >     - Modify the Kconfig names and add help.
> >     - Remove the signer name hack in build.c.
> >
> > Cc: "H. Peter Anvin" <hpa@zytor.com>
> > Cc: Thomas Gleixner <tglx@linutronix.de>
> > Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > Cc: Ingo Molnar <mingo@redhat.com>
> > Cc: Matt Fleming <matt@codeblueprint.co.uk>
> > Cc: Catalin Marinas <catalin.marinas@arm.com>
> > Cc: Will Deacon <will.deacon@arm.com>
> > Cc: Joey Lee <jlee@suse.com>
> > Signed-off-by: Gary Lin <glin@suse.com>
> >
> > Gary Lin (2):
> >   x86/efi: Introduce Security Version to x86
> >   arm64/efi: Introduce Security Version to ARM64
> >
> >  arch/arm64/kernel/efi-header.S | 57 ++++++++++++++++++++++++++++++++++++++++++
> >  arch/x86/boot/header.S         | 55 ++++++++++++++++++++++++++++++++++++++++
> >  drivers/firmware/efi/Kconfig   | 40 +++++++++++++++++++++++++++++
> >  3 files changed, 152 insertions(+)
> >
> > --
> > 2.15.0
> >
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-efi" in
> > the body of a message to majordomo at vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* [PATCH v2 3/3] ARM: dts: imx6sl-evk: Convert from fbdev to drm bindings
From: Marco Franchi @ 2017-12-06  2:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512528784-29288-1-git-send-email-marcofrk@gmail.com>

It is preferred to use the panel compatible string rather than passing 
the LCD timing in the device tree.

So pass the "sii,43wvf1g" compatible string which describes the parallel 
LCD.

Also, pass the 'backlight' property as described in 
Documentation/devicetree/bindings/display/panel/simple-panel.txt

Signed-off-by: Marco Franchi <marco.franchi@nxp.com>
---
Changes since v1:
-change subject
-change message log
-includes into a set of patches
-fix regulator name and properties
 arch/arm/boot/dts/imx6sl-evk.dts | 48 ++++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 645a460..a395de4 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -20,7 +20,7 @@
 		reg = <0x80000000 0x40000000>;
 	};
 
-	backlight {
+	backlight_display: backlight_display {
 		compatible = "pwm-backlight";
 		pwms = <&pwm1 0 5000000>;
 		brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -82,6 +82,13 @@
 		enable-active-high;
 	};
 
+	reg_lcd_5v: regulator-lcd-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "lcd-5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
 	sound {
 		compatible = "fsl,imx6sl-evk-wm8962", "fsl,imx-audio-wm8962";
 		model = "wm8962-audio";
@@ -97,6 +104,19 @@
 		mux-int-port = <2>;
 		mux-ext-port = <3>;
 	};
+
+	panel {
+		compatible = "sii,43wvf1g";
+		backlight = <&backlight_display>;
+		dvdd-supply = <&reg_lcd_3v3>;
+		avdd-supply = <&reg_lcd_5v>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
+	};
 };
 
 &audmux {
@@ -535,31 +555,11 @@
 &lcdif {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_lcd>;
-	lcd-supply = <&reg_lcd_3v3>;
-	display = <&display0>;
 	status = "okay";
 
-	display0: display0 {
-		bits-per-pixel = <32>;
-		bus-width = <24>;
-
-		display-timings {
-			native-mode = <&timing0>;
-			timing0: timing0 {
-				clock-frequency = <33500000>;
-				hactive = <800>;
-				vactive = <480>;
-				hback-porch = <89>;
-				hfront-porch = <164>;
-				vback-porch = <23>;
-				vfront-porch = <10>;
-				hsync-len = <10>;
-				vsync-len = <10>;
-				hsync-active = <0>;
-				vsync-active = <0>;
-				de-active = <1>;
-				pixelclk-active = <0>;
-			};
+	port {
+		display_out: endpoint {
+			remote-endpoint = <&panel_in>;
 		};
 	};
 };
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/3] ARM: dts: imx6sl-evk: Rearrange the regulators node
From: Marco Franchi @ 2017-12-06  2:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512528784-29288-1-git-send-email-marcofrk@gmail.com>

It is not recommended to place regulators inside "simple-bus", so move 
them out.

The motivation for doing this is to make it easier to adding new 
regulators.

Signed-off-by: Marco Franchi <marcofrk@gmail.com>
---
 arch/arm/boot/dts/imx6sl-evk.dts | 85 +++++++++++++++++-----------------------
 1 file changed, 37 insertions(+), 48 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 60600b4..645a460 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -39,58 +39,47 @@
 		};
 	};
 
-	regulators {
-		compatible = "simple-bus";
-		#address-cells = <1>;
-		#size-cells = <0>;
-
-		reg_usb_otg1_vbus: regulator at 0 {
-			compatible = "regulator-fixed";
-			reg = <0>;
-			regulator-name = "usb_otg1_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			gpio = <&gpio4 0 0>;
-			enable-active-high;
-			vin-supply = <&swbst_reg>;
-		};
+	reg_usb_otg1_vbus: regulator-usb-otg1-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_otg1_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio4 0 0>;
+		enable-active-high;
+		vin-supply = <&swbst_reg>;
+	};
 
-		reg_usb_otg2_vbus: regulator at 1 {
-			compatible = "regulator-fixed";
-			reg = <1>;
-			regulator-name = "usb_otg2_vbus";
-			regulator-min-microvolt = <5000000>;
-			regulator-max-microvolt = <5000000>;
-			gpio = <&gpio4 2 0>;
-			enable-active-high;
-			vin-supply = <&swbst_reg>;
-		};
+	reg_usb_otg2_vbus: regulator-usb-otg2-vbus {
+		compatible = "regulator-fixed";
+		regulator-name = "usb_otg2_vbus";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio4 2 0>;
+		enable-active-high;
+		vin-supply = <&swbst_reg>;
+	};
 
-		reg_aud3v: regulator at 2 {
-			compatible = "regulator-fixed";
-			reg = <2>;
-			regulator-name = "wm8962-supply-3v15";
-			regulator-min-microvolt = <3150000>;
-			regulator-max-microvolt = <3150000>;
-			regulator-boot-on;
-		};
+	reg_aud3v: regulator-aud3v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8962-supply-3v15";
+		regulator-min-microvolt = <3150000>;
+		regulator-max-microvolt = <3150000>;
+		regulator-boot-on;
+	};
 
-		reg_aud4v: regulator at 3 {
-			compatible = "regulator-fixed";
-			reg = <3>;
-			regulator-name = "wm8962-supply-4v2";
-			regulator-min-microvolt = <4325000>;
-			regulator-max-microvolt = <4325000>;
-			regulator-boot-on;
-		};
+	reg_aud4v: regulator-aud4v {
+		compatible = "regulator-fixed";
+		regulator-name = "wm8962-supply-4v2";
+		regulator-min-microvolt = <4325000>;
+		regulator-max-microvolt = <4325000>;
+		regulator-boot-on;
+	};
 
-		reg_lcd_3v3: regulator at 4 {
-			compatible = "regulator-fixed";
-			reg = <4>;
-			regulator-name = "lcd-3v3";
-			gpio = <&gpio4 3 0>;
-			enable-active-high;
-		};
+	reg_lcd_3v3: regulator-lcd-3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "lcd-3v3";
+		gpio = <&gpio4 3 0>;
+		enable-active-high;
 	};
 
 	sound {
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/3] ARM: dts: imx6sx-sdb: Convert from fbdev to drm bindings
From: Marco Franchi @ 2017-12-06  2:53 UTC (permalink / raw)
  To: linux-arm-kernel

It is preferred to use the panel compatible string rather than passing
the LCD timing in the device tree.

So pass the "sii,43wvf1g" compatible string, which describes the parallel 
LCD.

Also pass the 'backlight' property as described in
Documentation/devicetree/bindings/display/panel/simple-panel.txt

Signed-off-by: Marco Franchi <marcofrk@gmail.com>
---
Changes since v1:
-change subject
-change message log
-includes into a set of patches
-rebase to linux-next
-fix regulator name and properties
 arch/arm/boot/dts/imx6sx-sdb.dtsi | 48 +++++++++++++++++++--------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sx-sdb.dtsi b/arch/arm/boot/dts/imx6sx-sdb.dtsi
index d57a41c..d35aa85 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dtsi
+++ b/arch/arm/boot/dts/imx6sx-sdb.dtsi
@@ -24,7 +24,7 @@
 		reg = <0x80000000 0x40000000>;
 	};
 
-	backlight {
+	backlight_display: backlight-display {
 		compatible = "pwm-backlight";
 		pwms = <&pwm3 0 5000000>;
 		brightness-levels = <0 4 8 16 32 64 128 255>;
@@ -129,6 +129,13 @@
 		enable-active-high;
 	};
 
+	reg_lcd_5v: regulator-lcd-5v {
+		compatible = "regulator-fixed";
+		regulator-name = "lcd-5v0";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+	};
+
 	sound {
 		compatible = "fsl,imx6sx-sdb-wm8962", "fsl,imx-audio-wm8962";
 		model = "wm8962-audio";
@@ -144,6 +151,19 @@
 		mux-int-port = <2>;
 		mux-ext-port = <6>;
 	};
+
+	panel {
+		compatible = "sii,43wvf1g";
+		backlight = <&backlight_display>;
+		dvdd-supply = <&reg_lcd_3v3>;
+		avdd-supply = <&reg_lcd_5v>;
+
+		port {
+			panel_in: endpoint {
+				remote-endpoint = <&display_out>;
+			};
+		};
+	};
 };
 
 &audmux {
@@ -221,31 +241,11 @@
 &lcdif1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_lcd>;
-	lcd-supply = <&reg_lcd_3v3>;
-	display = <&display0>;
 	status = "okay";
 
-	display0: display0 {
-		bits-per-pixel = <16>;
-		bus-width = <24>;
-
-		display-timings {
-			native-mode = <&timing0>;
-			timing0: timing0 {
-				clock-frequency = <33500000>;
-				hactive = <800>;
-				vactive = <480>;
-				hback-porch = <89>;
-				hfront-porch = <164>;
-				vback-porch = <23>;
-				vfront-porch = <10>;
-				hsync-len = <10>;
-				vsync-len = <10>;
-				hsync-active = <0>;
-				vsync-active = <0>;
-				de-active = <1>;
-				pixelclk-active = <0>;
-			};
+	port {
+		display_out: endpoint {
+			remote-endpoint = <&panel_in>;
 		};
 	};
 };
-- 
2.7.4

^ permalink raw reply related

* [PATCH 2/2] clk: sunxi-ng: sun50i: a64: Add 2x fixed post-divider to MMC module clocks
From: Chen-Yu Tsai @ 2017-12-06  2:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171205195956.xdil2dsbtfwx35jj@flea.lan>

On Wed, Dec 6, 2017 at 3:59 AM, Maxime Ripard
<maxime.ripard@free-electrons.com> wrote:
> Hi,
>
> On Mon, Dec 04, 2017 at 01:19:12PM +0800, Chen-Yu Tsai wrote:
>> On the A64, the MMC module clocks are fixed in the new timing mode,
>> i.e. they do not have a bit to select the mode. These clocks have
>> a 2x divider somewhere between the clock and the MMC module.
>>
>> To be consistent with other SoCs supporting the new timing mode,
>> we model the 2x divider as a fixed post-divider on the MMC module
>> clocks.
>>
>> This patch adds the post-dividers to the MMC clocks.
>>
>> Signed-off-by: Chen-Yu Tsai <wens@csie.org>
>
> I had a doubt applying that one... sorry.
>
>> ---
>>  drivers/clk/sunxi-ng/ccu-sun50i-a64.c | 57 +++++++++++++++++++++++------------
>>  1 file changed, 37 insertions(+), 20 deletions(-)
>>
>> diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
>> index 2bb4cabf802f..ee9c12cf3f08 100644
>> --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
>> +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c
>> @@ -400,28 +400,45 @@ static SUNXI_CCU_MP_WITH_MUX_GATE(nand_clk, "nand", mod0_default_parents, 0x080,
>>                                 BIT(31),      /* gate */
>>                                 0);
>>
>> +/*
>> + * MMC clocks are the new timing mode (see A83T & H3) variety, but without
>> + * the mode switch. This means they have a 2x post divider between the clock
>> + * and the MMC module. This is not documented in the manual, but is taken
>> + * into consideration when setting the mmc module clocks in the BSP kernel.
>> + * Without it, MMC performance is degraded.
>> + *
>> + * We model it here to be consistent with other SoCs supporting this mode.
>> + * The alternative would be to add the 2x multiplier when setting the MMC
>> + * module clock in the MMC driver, just for the A64.
>> + */
>>  static const char * const mmc_default_parents[] = { "osc24M", "pll-periph0-2x",
>>                                                   "pll-periph1-2x" };
>> -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc_default_parents, 0x088,
>> -                               0, 4,         /* M */
>> -                               16, 2,        /* P */
>> -                               24, 2,        /* mux */
>> -                               BIT(31),      /* gate */
>> -                               0);
>> -
>> -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc_default_parents, 0x08c,
>> -                               0, 4,         /* M */
>> -                               16, 2,        /* P */
>> -                               24, 2,        /* mux */
>> -                               BIT(31),      /* gate */
>> -                               0);
>> -
>> -static SUNXI_CCU_MP_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc_default_parents, 0x090,
>> -                               0, 4,         /* M */
>> -                               16, 2,        /* P */
>> -                               24, 2,        /* mux */
>> -                               BIT(31),      /* gate */
>> -                               0);
>> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc0_clk, "mmc0",
>> +                                       mmc_default_parents, 0x088,
>> +                                       0, 4,         /* M */
>> +                                       16, 2,        /* P */
>> +                                       24, 2,        /* mux */
>> +                                       BIT(31),      /* gate */
>> +                                       2,            /* post-div */
>> +                                       0);
>> +
>> +static SUNXI_CCU_MP_WITH_MUX_GATE_POSTDIV(mmc1_clk, "mmc1",
>> +                                       mmc_default_parents, 0x08c,
>> +                                       0, 4,         /* M */
>> +                                       16, 2,        /* P */
>> +                                       24, 2,        /* mux */
>> +                                       BIT(31),      /* gate */
>> +                                       2,            /* post-div */
>> +                                       0);
>> +
>
> Are you sure that the divider there for the non-eMMC clocks? Usually,
> the new mode is only here for the eMMC, so we would divide the rate by
> two in the non-eMMC case.

The new mode is there for all MMC controllers. The other two MMC
controllers even have the old/new timing mode switch. In case you
forgot we have ".need_new_timings" set for the A64 compatible.

But to eliminate any doubts or concerns, I've rerun tests for the
micro SD card, instead of the eMMC. And yes the results are the same,
2x improvement (12 MB/s vs 23.7 MB/s).

ChenYu

^ permalink raw reply

* [PATCH v7 2/2] media: i2c: Add the ov7740 image sensor driver
From: Wenyou Yang @ 2017-12-06  2:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171206022343.31104-1-wenyou.yang@microchip.com>

The ov7740 (color) image sensor is a high performance VGA CMOS
image snesor, which supports for output formats: RAW RGB and YUV
and image sizes: VGA, and QVGA, CIF and any size smaller.

Signed-off-by: Songjun Wu <songjun.wu@microchip.com>
Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
---

Changes in v7:
 - Fix the wrong handle of default register configuration.
 - Add the missed assignment of ov7740->frmsize.

Changes in v6:
 - Remove unnecessary #include <linux/init>.
 - Remove unnecessary comments and extra newline.
 - Add const for some structures.
 - Add the check of the return value from regmap_write().
 - Simplify the calling of __v4l2_ctrl_handler_setup().
 - Add the default format initialization function.
 - Integrate the set_power() and enable/disable the clock into
   one function.

Changes in v5:
 - Squash the driver and MAINTAINERS entry patches to one.
 - Precede the driver patch with the bindings patch.

Changes in v4:
 - Assign 'val' a initial value to avoid warning: 'val' may be
   used uninitialized.
 - Rename REG_REG15 to avoid warning: "REG_REG15" redefined.

Changes in v3:
 - Put the MAINTAINERS change to a separate patch.

Changes in v2:
 - Split off the bindings into a separate patch.
 - Add a new entry to the MAINTAINERS file.

 MAINTAINERS                |    8 +
 drivers/media/i2c/Kconfig  |    8 +
 drivers/media/i2c/Makefile |    1 +
 drivers/media/i2c/ov7740.c | 1234 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1251 insertions(+)
 create mode 100644 drivers/media/i2c/ov7740.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 7a52a66aa991..1de965009b13 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -10053,6 +10053,14 @@ S:	Maintained
 F:	drivers/media/i2c/ov7670.c
 F:	Documentation/devicetree/bindings/media/i2c/ov7670.txt
 
+OMNIVISION OV7740 SENSOR DRIVER
+M:	Wenyou Yang <wenyou.yang@microchip.com>
+L:	linux-media at vger.kernel.org
+T:	git git://linuxtv.org/media_tree.git
+S:	Maintained
+F:	drivers/media/i2c/ov7740.c
+F:	Documentation/devicetree/bindings/media/i2c/ov7740.txt
+
 ONENAND FLASH DRIVER
 M:	Kyungmin Park <kyungmin.park@samsung.com>
 L:	linux-mtd at lists.infradead.org
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index cb5d7ff82915..00b1c4c031d4 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -665,6 +665,14 @@ config VIDEO_OV7670
 	  OV7670 VGA camera.  It currently only works with the M88ALP01
 	  controller.
 
+config VIDEO_OV7740
+	tristate "OmniVision OV7740 sensor support"
+	depends on I2C && VIDEO_V4L2
+	depends on MEDIA_CAMERA_SUPPORT
+	---help---
+	  This is a Video4Linux2 sensor-level driver for the OmniVision
+	  OV7740 VGA camera sensor.
+
 config VIDEO_OV9650
 	tristate "OmniVision OV9650/OV9652 sensor support"
 	depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 548a9efce966..9b19ec7fcaf4 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -68,6 +68,7 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o
 obj-$(CONFIG_VIDEO_OV6650) += ov6650.o
 obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
 obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
+obj-$(CONFIG_VIDEO_OV7740) += ov7740.o
 obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
 obj-$(CONFIG_VIDEO_OV13858) += ov13858.o
 obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
new file mode 100644
index 000000000000..26b56a627377
--- /dev/null
+++ b/drivers/media/i2c/ov7740.c
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (c) 2017 Microchip 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.
+ *
+ * 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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-image-sizes.h>
+#include <media/v4l2-subdev.h>
+
+#define REG_OUTSIZE_LSB 0x34
+
+/* OV7740 register tables */
+#define REG_GAIN	0x00	/* Gain lower 8 bits (rest in vref) */
+#define REG_BGAIN	0x01	/* blue gain */
+#define REG_RGAIN	0x02	/* red gain */
+#define REG_GGAIN	0x03	/* green gain */
+#define REG_REG04	0x04	/* analog setting, dont change*/
+#define REG_BAVG	0x05	/* b channel average */
+#define REG_GAVG	0x06	/* g channel average */
+#define REG_RAVG	0x07	/* r channel average */
+
+#define REG_REG0C	0x0C	/* filp enable */
+#define REG0C_IMG_FLIP		0x80
+#define REG0C_IMG_MIRROR	0x40
+
+#define REG_REG0E	0x0E	/* blc line */
+#define REG_HAEC	0x0F	/* auto exposure cntrl */
+#define REG_AEC		0x10	/* auto exposure cntrl */
+
+#define REG_CLK		0x11	/* Clock control */
+#define REG_REG55	0x55	/* Clock PLL DIV/PreDiv */
+
+#define REG_REG12	0x12
+
+#define REG_REG13	0x13	/* auto/manual AGC, AEC, Write Balance*/
+#define REG13_AEC_EN	0x01
+#define REG13_AGC_EN	0x04
+
+#define REG_REG14	0x14
+#define REG_CTRL15	0x15
+#define REG15_GAIN_MSB	0x03
+
+#define REG_REG16	0x16
+
+#define REG_MIDH	0x1C	/* manufacture id byte */
+#define REG_MIDL	0x1D	/* manufacture id byre */
+#define REG_PIDH	0x0A	/* Product ID MSB */
+#define REG_PIDL	0x0B	/* Product ID LSB */
+
+#define REG_84		0x84	/* lots of stuff */
+#define REG_REG38	0x38	/* sub-addr */
+
+#define REG_AHSTART	0x17	/* Horiz start high bits */
+#define REG_AHSIZE	0x18
+#define REG_AVSTART	0x19	/* Vert start high bits */
+#define REG_AVSIZE	0x1A
+#define REG_PSHFT	0x1b	/* Pixel delay after HREF */
+
+#define REG_HOUTSIZE	0x31
+#define REG_VOUTSIZE	0x32
+#define REG_HVSIZEOFF	0x33
+#define REG_REG34	0x34	/* DSP output size H/V LSB*/
+
+#define REG_ISP_CTRL00	0x80
+#define ISPCTRL00_AWB_EN	0x10
+#define ISPCTRL00_AWB_GAIN_EN	0x04
+
+#define	REG_YGAIN	0xE2	/* ygain for contrast control */
+
+#define	REG_YBRIGHT	  0xE3
+#define	REG_SGNSET	  0xE4
+#define	SGNSET_YBRIGHT_MASK	  0x08
+
+#define REG_USAT	0xDD
+#define REG_VSAT	0xDE
+
+
+struct ov7740 {
+	struct v4l2_subdev subdev;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	struct media_pad pad;
+#endif
+	struct v4l2_mbus_framefmt format;
+	const struct ov7740_pixfmt *fmt;  /* Current format */
+	const struct ov7740_framesize *frmsize;
+	struct regmap *regmap;
+	struct clk *xvclk;
+	struct v4l2_ctrl_handler ctrl_handler;
+	struct {
+		/* gain cluster */
+		struct v4l2_ctrl *auto_gain;
+		struct v4l2_ctrl *gain;
+	};
+	struct {
+		struct v4l2_ctrl *auto_wb;
+		struct v4l2_ctrl *blue_balance;
+		struct v4l2_ctrl *red_balance;
+	};
+	struct {
+		struct v4l2_ctrl *hflip;
+		struct v4l2_ctrl *vflip;
+	};
+	struct {
+		/* exposure cluster */
+		struct v4l2_ctrl *auto_exposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct {
+		/* saturation/hue cluster */
+		struct v4l2_ctrl *saturation;
+		struct v4l2_ctrl *hue;
+	};
+	struct v4l2_ctrl *brightness;
+	struct v4l2_ctrl *contrast;
+
+	struct mutex mutex;	/* To serialize asynchronus callbacks */
+	bool streaming;		/* Streaming on/off */
+
+	struct gpio_desc *resetb_gpio;
+	struct gpio_desc *pwdn_gpio;
+};
+
+struct ov7740_pixfmt {
+	u32 mbus_code;
+	enum v4l2_colorspace colorspace;
+	const struct reg_sequence *regs;
+	u32 reg_num;
+};
+
+struct ov7740_framesize {
+	u16 width;
+	u16 height;
+	const struct reg_sequence *regs;
+	u32 reg_num;
+};
+
+static const struct reg_sequence ov7740_vga[] = {
+	{0x55, 0x40},
+	{0x11, 0x02},
+
+	{0xd5, 0x10},
+	{0x0c, 0x12},
+	{0x0d, 0x34},
+	{0x17, 0x25},
+	{0x18, 0xa0},
+	{0x19, 0x03},
+	{0x1a, 0xf0},
+	{0x1b, 0x89},
+	{0x22, 0x03},
+	{0x29, 0x18},
+	{0x2b, 0xf8},
+	{0x2c, 0x01},
+	{REG_HOUTSIZE, 0xa0},
+	{REG_VOUTSIZE, 0xf0},
+	{0x33, 0xc4},
+	{REG_OUTSIZE_LSB, 0x0},
+	{0x35, 0x05},
+	{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},
+
+	{0x81, 0x3f},
+	{0x82, 0x32},
+	{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},
+};
+
+static const struct ov7740_framesize ov7740_framesizes[] = {
+	{
+		.width		= VGA_WIDTH,
+		.height		= VGA_HEIGHT,
+		.regs		= ov7740_vga,
+		.reg_num	= ARRAY_SIZE(ov7740_vga),
+	},
+};
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov7740_get_register(struct v4l2_subdev *sd,
+			       struct v4l2_dbg_register *reg)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int val = 0;
+	int ret;
+
+	ret = regmap_read(regmap, reg->reg & 0xff, &val);
+	reg->val = val;
+	reg->size = 1;
+
+	return 0;
+}
+
+static int ov7740_set_register(struct v4l2_subdev *sd,
+			       const struct v4l2_dbg_register *reg)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct regmap *regmap = ov7740->regmap;
+
+	regmap_write(regmap, reg->reg & 0xff, reg->val & 0xff);
+
+	return 0;
+}
+#endif
+
+static int ov7740_set_power(struct ov7740 *ov7740, int on)
+{
+	int ret;
+
+	if (on) {
+		ret = clk_prepare_enable(ov7740->xvclk);
+		if (ret)
+			return ret;
+
+		if (ov7740->pwdn_gpio)
+			gpiod_direction_output(ov7740->pwdn_gpio, 0);
+
+		if (ov7740->resetb_gpio) {
+			gpiod_set_value(ov7740->resetb_gpio, 1);
+			usleep_range(500, 1000);
+			gpiod_set_value(ov7740->resetb_gpio, 0);
+			usleep_range(3000, 5000);
+		}
+	} else {
+		clk_disable_unprepare(ov7740->xvclk);
+
+		if (ov7740->pwdn_gpio)
+			gpiod_direction_output(ov7740->pwdn_gpio, 0);
+	}
+
+	return 0;
+}
+
+static struct v4l2_subdev_core_ops ov7740_subdev_core_ops = {
+	.log_status = v4l2_ctrl_subdev_log_status,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+	.g_register = ov7740_get_register,
+	.s_register = ov7740_set_register,
+#endif
+	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static int ov7740_set_white_balance(struct ov7740 *ov7740, int awb)
+{
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int value;
+	int ret;
+
+	ret = regmap_read(regmap, REG_ISP_CTRL00, &value);
+	if (!ret) {
+		if (awb)
+			value |= (ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
+		else
+			value &= ~(ISPCTRL00_AWB_EN | ISPCTRL00_AWB_GAIN_EN);
+		ret = regmap_write(regmap, REG_ISP_CTRL00, value);
+		if (ret)
+			return ret;
+	}
+
+	if (!awb) {
+		ret = regmap_write(regmap, REG_BGAIN,
+				   ov7740->blue_balance->val);
+		if (ret)
+			return ret;
+
+		ret = regmap_write(regmap, REG_RGAIN, ov7740->red_balance->val);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int ov7740_set_saturation(struct regmap *regmap, int value)
+{
+	int ret;
+
+	ret = regmap_write(regmap, REG_USAT, (unsigned char)value);
+	if (ret)
+		return ret;
+
+	return regmap_write(regmap, REG_VSAT, (unsigned char)value);
+}
+
+static int ov7740_set_gain(struct regmap *regmap, int value)
+{
+	int ret;
+
+	ret = regmap_write(regmap, REG_GAIN, value & 0xff);
+	if (ret)
+		return ret;
+
+	ret = regmap_update_bits(regmap, REG_CTRL15,
+				 REG15_GAIN_MSB, (value >> 8) & 0x3);
+	if (!ret)
+		ret = regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
+
+	return ret;
+}
+
+static int ov7740_set_autogain(struct regmap *regmap, int value)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, REG_REG13, &reg);
+	if (ret)
+		return ret;
+	if (value)
+		reg |= REG13_AGC_EN;
+	else
+		reg &= ~REG13_AGC_EN;
+	return regmap_write(regmap, REG_REG13, reg);
+}
+
+static int ov7740_set_brightness(struct regmap *regmap, int value)
+{
+	/* Turn off AEC/AGC */
+	regmap_update_bits(regmap, REG_REG13, REG13_AEC_EN, 0);
+	regmap_update_bits(regmap, REG_REG13, REG13_AGC_EN, 0);
+
+	if (value >= 0) {
+		regmap_write(regmap, REG_YBRIGHT, (unsigned char)value);
+		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 0);
+	} else{
+		regmap_write(regmap, REG_YBRIGHT, (unsigned char)(-value));
+		regmap_update_bits(regmap, REG_SGNSET, SGNSET_YBRIGHT_MASK, 1);
+	}
+
+	return 0;
+}
+
+static int ov7740_set_contrast(struct regmap *regmap, int value)
+{
+	return regmap_write(regmap, REG_YGAIN, (unsigned char)value);
+}
+
+static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl)
+{
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int value0, value1;
+	int ret;
+
+	if (!ctrl->val)
+		return 0;
+
+	ret = regmap_read(regmap, REG_GAIN, &value0);
+	if (ret)
+		return ret;
+	ret = regmap_read(regmap, REG_CTRL15, &value1);
+	if (ret)
+		return ret;
+
+	ov7740->gain->val = (value1 << 8) | (value0 & 0xff);
+
+	return 0;
+}
+
+static int ov7740_set_exp(struct regmap *regmap, int value)
+{
+	int ret;
+
+	/* Turn off AEC/AGC */
+	ret = regmap_update_bits(regmap, REG_REG13,
+				 REG13_AEC_EN | REG13_AGC_EN, 0);
+	if (ret)
+		return ret;
+
+	ret = regmap_write(regmap, REG_AEC, (unsigned char)value);
+	if (ret)
+		return ret;
+
+	return regmap_write(regmap, REG_HAEC, (unsigned char)(value >> 8));
+}
+
+static int ov7740_set_autoexp(struct regmap *regmap,
+			      enum v4l2_exposure_auto_type value)
+{
+	unsigned int reg;
+	int ret;
+
+	ret = regmap_read(regmap, REG_REG13, &reg);
+	if (!ret) {
+		if (value == V4L2_EXPOSURE_AUTO)
+			reg |= (REG13_AEC_EN | REG13_AGC_EN);
+		else
+			reg &= ~(REG13_AEC_EN | REG13_AGC_EN);
+		ret = regmap_write(regmap, REG_REG13, reg);
+	}
+
+	return ret;
+}
+
+
+static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov7740 *ov7740 = container_of(ctrl->handler,
+					     struct ov7740, ctrl_handler);
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTOGAIN:
+		ret = ov7740_get_gain(ov7740, ctrl);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+	struct ov7740 *ov7740 = container_of(ctrl->handler,
+					     struct ov7740, ctrl_handler);
+	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
+	struct regmap *regmap = ov7740->regmap;
+	int ret;
+	u8 val = 0;
+
+	if (pm_runtime_get_if_in_use(&client->dev) <= 0)
+		return 0;
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUTO_WHITE_BALANCE:
+		ret = ov7740_set_white_balance(ov7740, ctrl->val);
+		break;
+	case V4L2_CID_SATURATION:
+		ret = ov7740_set_saturation(regmap, ctrl->val);
+		break;
+	case V4L2_CID_BRIGHTNESS:
+		ret = ov7740_set_brightness(regmap, ctrl->val);
+		break;
+	case V4L2_CID_CONTRAST:
+		ret = ov7740_set_contrast(regmap, ctrl->val);
+		break;
+	case V4L2_CID_VFLIP:
+		ret = regmap_update_bits(regmap, REG_REG0C,
+					 REG0C_IMG_FLIP, val);
+		break;
+	case V4L2_CID_HFLIP:
+		val = ctrl->val ? REG0C_IMG_MIRROR : 0x00;
+		ret = regmap_update_bits(regmap, REG_REG0C,
+					 REG0C_IMG_MIRROR, val);
+		break;
+	case V4L2_CID_AUTOGAIN:
+		if (!ctrl->val)
+			return ov7740_set_gain(regmap, ov7740->gain->val);
+
+		ret = ov7740_set_autogain(regmap, ctrl->val);
+		break;
+
+	case V4L2_CID_EXPOSURE_AUTO:
+		if (ctrl->val == V4L2_EXPOSURE_MANUAL)
+			return ov7740_set_exp(regmap, ov7740->exposure->val);
+
+		ret = ov7740_set_autoexp(regmap, ctrl->val);
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	pm_runtime_put(&client->dev);
+
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops ov7740_ctrl_ops = {
+	.g_volatile_ctrl = ov7740_get_volatile_ctrl,
+	.s_ctrl = ov7740_set_ctrl,
+};
+
+static int ov7740_start_streaming(struct ov7740 *ov7740)
+{
+	int ret;
+
+	if (ov7740->fmt) {
+		ret = regmap_multi_reg_write(ov7740->regmap,
+					     ov7740->fmt->regs,
+					     ov7740->fmt->reg_num);
+		if (ret)
+			return ret;
+	}
+
+	if (ov7740->frmsize) {
+		ret = regmap_multi_reg_write(ov7740->regmap,
+					     ov7740->frmsize->regs,
+					     ov7740->frmsize->reg_num);
+		if (ret)
+			return ret;
+	}
+
+	return __v4l2_ctrl_handler_setup(ov7740->subdev.ctrl_handler);
+}
+
+static int ov7740_set_stream(struct v4l2_subdev *sd, int enable)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct i2c_client *client = v4l2_get_subdevdata(sd);
+	int ret = 0;
+
+	mutex_lock(&ov7740->mutex);
+	if (ov7740->streaming == enable) {
+		mutex_unlock(&ov7740->mutex);
+		return 0;
+	}
+
+	if (enable) {
+		ret = pm_runtime_get_sync(&client->dev);
+		if (ret < 0) {
+			pm_runtime_put_noidle(&client->dev);
+			goto err_unlock;
+		}
+
+		ret = ov7740_start_streaming(ov7740);
+		if (ret)
+			goto err_rpm_put;
+	} else {
+		pm_runtime_put(&client->dev);
+	}
+
+	ov7740->streaming = enable;
+
+	mutex_unlock(&ov7740->mutex);
+	return ret;
+
+err_rpm_put:
+	pm_runtime_put(&client->dev);
+err_unlock:
+	mutex_unlock(&ov7740->mutex);
+	return ret;
+}
+
+static int ov7740_get_parm(struct v4l2_subdev *sd,
+			   struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+
+	memset(cp, 0, sizeof(struct v4l2_captureparm));
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+	tpf->numerator = 1;
+	tpf->denominator = 60;
+
+	return 0;
+}
+
+static int ov7740_set_parm(struct v4l2_subdev *sd,
+			   struct v4l2_streamparm *parms)
+{
+	struct v4l2_captureparm *cp = &parms->parm.capture;
+	struct v4l2_fract *tpf = &cp->timeperframe;
+
+	if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+		return -EINVAL;
+	if (cp->extendedmode != 0)
+		return -EINVAL;
+
+	cp->capability = V4L2_CAP_TIMEPERFRAME;
+
+	tpf->numerator = 1;
+	tpf->denominator = 60;
+
+	return 0;
+}
+
+static struct v4l2_subdev_video_ops ov7740_subdev_video_ops = {
+	.s_stream = ov7740_set_stream,
+	.s_parm = ov7740_set_parm,
+	.g_parm = ov7740_get_parm,
+};
+
+static const struct reg_sequence ov7740_format_yuyv[] = {
+	{0x12, 0x00},
+	{0x36, 0x3f},
+	{0x80, 0x7f},
+	{0x83, 0x01},
+};
+
+static const struct reg_sequence ov7740_format_bggr8[] = {
+	{0x36, 0x2f},
+	{0x80, 0x01},
+	{0x83, 0x04},
+};
+
+static const struct ov7740_pixfmt ov7740_formats[] = {
+	{
+		.mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.regs = ov7740_format_yuyv,
+		.reg_num = ARRAY_SIZE(ov7740_format_yuyv),
+	},
+	{
+		.mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
+		.colorspace = V4L2_COLORSPACE_SRGB,
+		.regs = ov7740_format_bggr8,
+		.reg_num = ARRAY_SIZE(ov7740_format_bggr8),
+	}
+};
+#define N_OV7740_FMTS ARRAY_SIZE(ov7740_formats)
+
+static int ov7740_enum_mbus_code(struct v4l2_subdev *sd,
+				 struct v4l2_subdev_pad_config *cfg,
+				 struct v4l2_subdev_mbus_code_enum *code)
+{
+	if (code->pad || code->index >= N_OV7740_FMTS)
+		return -EINVAL;
+
+	code->code = ov7740_formats[code->index].mbus_code;
+
+	return 0;
+}
+
+static int ov7740_enum_frame_interval(struct v4l2_subdev *sd,
+				struct v4l2_subdev_pad_config *cfg,
+				struct v4l2_subdev_frame_interval_enum *fie)
+{
+	if (fie->pad)
+		return -EINVAL;
+
+	if (fie->index >= 1)
+		return -EINVAL;
+
+	if ((fie->width != VGA_WIDTH) || (fie->height != VGA_HEIGHT))
+		return -EINVAL;
+
+	fie->interval.numerator = 1;
+	fie->interval.denominator = 60;
+
+	return 0;
+}
+
+static int ov7740_enum_frame_size(struct v4l2_subdev *sd,
+				  struct v4l2_subdev_pad_config *cfg,
+				  struct v4l2_subdev_frame_size_enum *fse)
+{
+	if (fse->pad)
+		return -EINVAL;
+
+	if (fse->index > 0)
+		return -EINVAL;
+
+	fse->min_width = fse->max_width = VGA_WIDTH;
+	fse->min_height = fse->max_height = VGA_HEIGHT;
+
+	return 0;
+}
+
+static int ov7740_try_fmt_internal(struct v4l2_subdev *sd,
+				   struct v4l2_mbus_framefmt *fmt,
+				   const struct ov7740_pixfmt **ret_fmt,
+				   const struct ov7740_framesize **ret_frmsize)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	const struct ov7740_framesize *fsize = &ov7740_framesizes[0];
+	int index, i;
+
+	for (index = 0; index < N_OV7740_FMTS; index++) {
+		if (ov7740_formats[index].mbus_code == fmt->code)
+			break;
+	}
+	if (index >= N_OV7740_FMTS) {
+		/* default to first format */
+		index = 0;
+		fmt->code = ov7740_formats[0].mbus_code;
+	}
+	if (ret_fmt != NULL)
+		*ret_fmt = ov7740_formats + index;
+
+	for (i = 0; i < ARRAY_SIZE(ov7740_framesizes); i++) {
+		if ((fsize->width >= fmt->width) &&
+		    (fsize->height >= fmt->height)) {
+			fmt->width = fsize->width;
+			fmt->height = fsize->height;
+			break;
+		}
+
+		fsize++;
+	}
+
+	if (ret_frmsize != NULL)
+		*ret_frmsize = fsize;
+
+	fmt->field = V4L2_FIELD_NONE;
+	fmt->colorspace = ov7740_formats[index].colorspace;
+
+	ov7740->format = *fmt;
+
+	return 0;
+}
+
+static int ov7740_set_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	const struct ov7740_pixfmt *ovfmt;
+	const struct ov7740_framesize *fsize;
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	struct v4l2_mbus_framefmt *mbus_fmt;
+#endif
+	int ret;
+
+	mutex_lock(&ov7740->mutex);
+	if (format->pad) {
+		ret = -EINVAL;
+		goto error;
+	}
+
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+		ret = ov7740_try_fmt_internal(sd, &format->format, NULL, NULL);
+		if (ret)
+			goto error;
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
+		*mbus_fmt = format->format;
+
+		mutex_unlock(&ov7740->mutex);
+		return 0;
+#else
+		ret = -ENOTTY;
+		goto error;
+#endif
+	}
+
+	ret = ov7740_try_fmt_internal(sd, &format->format, &ovfmt, &fsize);
+	if (ret)
+		goto error;
+
+	if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+		regmap_multi_reg_write(ov7740->regmap,
+				       ovfmt->regs, ovfmt->reg_num);
+
+		regmap_multi_reg_write(ov7740->regmap,
+				       fsize->regs, fsize->reg_num);
+	}
+
+	ov7740->fmt = ovfmt;
+	ov7740->frmsize = fsize;
+
+	mutex_unlock(&ov7740->mutex);
+	return 0;
+
+error:
+	mutex_unlock(&ov7740->mutex);
+	return ret;
+}
+
+static int ov7740_get_fmt(struct v4l2_subdev *sd,
+			  struct v4l2_subdev_pad_config *cfg,
+			  struct v4l2_subdev_format *format)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	struct v4l2_mbus_framefmt *mbus_fmt;
+#endif
+	int ret = 0;
+
+	mutex_lock(&ov7740->mutex);
+	if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+		mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
+		format->format = *mbus_fmt;
+		ret = 0;
+#else
+		ret = -ENOTTY;
+#endif
+	} else {
+		format->format = ov7740->format;
+	}
+	mutex_unlock(&ov7740->mutex);
+
+	return ret;
+}
+
+static const struct v4l2_subdev_pad_ops ov7740_subdev_pad_ops = {
+	.enum_frame_interval = ov7740_enum_frame_interval,
+	.enum_frame_size = ov7740_enum_frame_size,
+	.enum_mbus_code = ov7740_enum_mbus_code,
+	.get_fmt = ov7740_get_fmt,
+	.set_fmt = ov7740_set_fmt,
+};
+
+static const struct v4l2_subdev_ops ov7740_subdev_ops = {
+	.core	= &ov7740_subdev_core_ops,
+	.video	= &ov7740_subdev_video_ops,
+	.pad	= &ov7740_subdev_pad_ops,
+};
+
+static void ov7740_get_default_format(struct v4l2_subdev *sd,
+				      struct v4l2_mbus_framefmt *format)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	format->width = ov7740->frmsize->width;
+	format->height = ov7740->frmsize->height;
+	format->colorspace = ov7740->fmt->colorspace;
+	format->code = ov7740->fmt->mbus_code;
+	format->field = V4L2_FIELD_NONE;
+}
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+static int ov7740_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+	struct v4l2_mbus_framefmt *format =
+				v4l2_subdev_get_try_format(sd, fh->pad, 0);
+
+	mutex_lock(&ov7740->mutex);
+	ov7740_get_default_format(sd, format);
+	mutex_unlock(&ov7740->mutex);
+
+	return 0;
+}
+
+static const struct v4l2_subdev_internal_ops ov7740_subdev_internal_ops = {
+	.open = ov7740_open,
+};
+#endif
+
+static int ov7740_probe_dt(struct i2c_client *client,
+			   struct ov7740 *ov7740)
+{
+	ov7740->resetb_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+			GPIOD_OUT_HIGH);
+	if (IS_ERR(ov7740->resetb_gpio)) {
+		dev_info(&client->dev, "can't get %s GPIO\n", "reset");
+		return PTR_ERR(ov7740->resetb_gpio);
+	}
+
+	ov7740->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
+			GPIOD_OUT_LOW);
+	if (IS_ERR(ov7740->pwdn_gpio)) {
+		dev_info(&client->dev, "can't get %s GPIO\n", "powerdown");
+		return PTR_ERR(ov7740->pwdn_gpio);
+	}
+
+	return 0;
+}
+
+static int ov7740_detect(struct ov7740 *ov7740)
+{
+	struct regmap *regmap = ov7740->regmap;
+	unsigned int midh, midl, pidh, pidl;
+	int ret;
+
+	ret = regmap_read(regmap, REG_MIDH, &midh);
+	if (ret)
+		return ret;
+	if (midh != 0x7f)
+		return -ENODEV;
+
+	ret = regmap_read(regmap, REG_MIDL, &midl);
+	if (ret)
+		return ret;
+	if (midl != 0xa2)
+		return -ENODEV;
+
+	ret = regmap_read(regmap, REG_PIDH, &pidh);
+	if (ret)
+		return ret;
+	if (pidh != 0x77)
+		return -ENODEV;
+
+	ret = regmap_read(regmap, REG_PIDL, &pidl);
+	if (ret)
+		return ret;
+	if ((pidl != 0x40) && (pidl != 0x41) && (pidl != 0x42))
+		return -ENODEV;
+
+	return 0;
+}
+
+static int ov7740_init_controls(struct ov7740 *ov7740)
+{
+	struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev);
+	struct v4l2_ctrl_handler *ctrl_hdlr = &ov7740->ctrl_handler;
+	int ret;
+
+	ret = v4l2_ctrl_handler_init(ctrl_hdlr, 2);
+	if (ret < 0)
+		return ret;
+
+	ctrl_hdlr->lock = &ov7740->mutex;
+	ov7740->auto_wb = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					  V4L2_CID_AUTO_WHITE_BALANCE,
+					  0, 1, 1, 1);
+	ov7740->blue_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					       V4L2_CID_BLUE_BALANCE,
+					       0, 0xff, 1, 0x80);
+	ov7740->red_balance = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					      V4L2_CID_RED_BALANCE,
+					      0, 0xff, 1, 0x80);
+
+	ov7740->brightness = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					     V4L2_CID_BRIGHTNESS,
+					     -255, 255, 1, 0);
+	ov7740->contrast = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					   V4L2_CID_CONTRAST,
+					   0, 127, 1, 0x20);
+	ov7740->saturation = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+			  V4L2_CID_SATURATION, 0, 256, 1, 0x80);
+	ov7740->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					V4L2_CID_HFLIP, 0, 1, 1, 0);
+	ov7740->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					V4L2_CID_VFLIP, 0, 1, 1, 0);
+	ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+				       V4L2_CID_GAIN, 0, 1023, 1, 500);
+	ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					    V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops,
+					   V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
+	ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr,
+					&ov7740_ctrl_ops,
+					V4L2_CID_EXPOSURE_AUTO,
+					V4L2_EXPOSURE_MANUAL, 0,
+					V4L2_EXPOSURE_AUTO);
+
+	ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE;
+	ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+	v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false);
+	v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true);
+	v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure,
+			       V4L2_EXPOSURE_MANUAL, false);
+	v4l2_ctrl_cluster(2, &ov7740->hflip);
+
+	ret = v4l2_ctrl_handler_setup(ctrl_hdlr);
+	if (ret) {
+		dev_err(&client->dev, "%s control init failed (%d)\n",
+			__func__, ret);
+		goto error;
+	}
+
+	ov7740->subdev.ctrl_handler = ctrl_hdlr;
+	return 0;
+
+error:
+	v4l2_ctrl_handler_free(ctrl_hdlr);
+	mutex_destroy(&ov7740->mutex);
+	return ret;
+}
+
+static void ov7740_free_controls(struct ov7740 *ov7740)
+{
+	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
+	mutex_destroy(&ov7740->mutex);
+}
+
+#define OV7740_MAX_REGISTER     0xff
+static const struct regmap_config ov7740_regmap_config = {
+	.reg_bits	= 8,
+	.val_bits	= 8,
+	.max_register	= OV7740_MAX_REGISTER,
+};
+
+static int ov7740_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct ov7740 *ov7740;
+	struct v4l2_subdev *sd;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter,
+				     I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(&client->dev,
+			"OV7740: I2C-Adapter doesn't support SMBUS\n");
+		return -EIO;
+	}
+
+	ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL);
+	if (!ov7740)
+		return -ENOMEM;
+
+	ov7740->xvclk = devm_clk_get(&client->dev, "xvclk");
+	if (IS_ERR(ov7740->xvclk)) {
+		ret = PTR_ERR(ov7740->xvclk);
+		dev_err(&client->dev,
+			"OV7740: fail to get xvclk: %d\n", ret);
+		return ret;
+	}
+
+	ret = ov7740_probe_dt(client, ov7740);
+	if (ret)
+		return ret;
+
+	ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config);
+	if (IS_ERR(ov7740->regmap)) {
+		ret = PTR_ERR(ov7740->regmap);
+		dev_err(&client->dev, "Failed to allocate register map: %d\n",
+			ret);
+		return ret;
+	}
+
+	sd = &ov7740->subdev;
+	client->flags |= I2C_CLIENT_SCCB;
+	v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops);
+
+#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
+	sd->internal_ops = &ov7740_subdev_internal_ops;
+	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+#endif
+
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	ov7740->pad.flags = MEDIA_PAD_FL_SOURCE;
+	sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+	ret = media_entity_pads_init(&sd->entity, 1, &ov7740->pad);
+	if (ret)
+		return ret;
+#endif
+
+	ret = ov7740_set_power(ov7740, 1);
+	if (ret)
+		return ret;
+
+	ret = ov7740_detect(ov7740);
+	if (ret)
+		goto error_detect;
+
+	mutex_init(&ov7740->mutex);
+
+	ret = ov7740_init_controls(ov7740);
+	if (ret)
+		goto error_init_controls;
+
+	v4l_info(client, "chip found @ 0x%02x (%s)\n",
+			client->addr << 1, client->adapter->name);
+
+	ov7740->fmt = &ov7740_formats[0];
+	ov7740->frmsize = &ov7740_framesizes[0];
+
+	ov7740_get_default_format(sd, &ov7740->format);
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret)
+		goto error_async_register;
+
+	pm_runtime_set_active(&client->dev);
+	pm_runtime_enable(&client->dev);
+	pm_runtime_idle(&client->dev);
+
+	return 0;
+
+error_async_register:
+	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
+error_init_controls:
+	ov7740_free_controls(ov7740);
+error_detect:
+	ov7740_set_power(ov7740, 0);
+	media_entity_cleanup(&ov7740->subdev.entity);
+
+	return ret;
+}
+
+static int ov7740_remove(struct i2c_client *client)
+{
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	mutex_destroy(&ov7740->mutex);
+	v4l2_ctrl_handler_free(ov7740->subdev.ctrl_handler);
+#if defined(CONFIG_MEDIA_CONTROLLER)
+	media_entity_cleanup(&ov7740->subdev.entity);
+#endif
+	v4l2_async_unregister_subdev(sd);
+	ov7740_free_controls(ov7740);
+
+	pm_runtime_get_sync(&client->dev);
+	pm_runtime_disable(&client->dev);
+	pm_runtime_set_suspended(&client->dev);
+	pm_runtime_put_noidle(&client->dev);
+
+	ov7740_set_power(ov7740, 0);
+	return 0;
+}
+
+static int __maybe_unused ov7740_runtime_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	ov7740_set_power(ov7740, 0);
+
+	return 0;
+}
+
+static int __maybe_unused ov7740_runtime_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7740 *ov7740 = container_of(sd, struct ov7740, subdev);
+
+	return ov7740_set_power(ov7740, 1);
+}
+
+static const struct i2c_device_id ov7740_id[] = {
+	{ "ov7740", 0 },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(i2c, ov7740_id);
+
+static const struct dev_pm_ops ov7740_pm_ops = {
+	SET_RUNTIME_PM_OPS(ov7740_runtime_suspend, ov7740_runtime_resume, NULL)
+};
+
+static const struct of_device_id ov7740_of_match[] = {
+	{.compatible = "ovti,ov7740", },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, ov7740_of_match);
+
+static struct i2c_driver ov7740_i2c_driver = {
+	.driver = {
+		.name = "ov7740",
+		.pm = &ov7740_pm_ops,
+		.of_match_table = of_match_ptr(ov7740_of_match),
+	},
+	.probe    = ov7740_probe,
+	.remove   = ov7740_remove,
+	.id_table = ov7740_id,
+};
+module_i2c_driver(ov7740_i2c_driver);
+
+MODULE_DESCRIPTION("The V4L2 driver for Omnivision 7740 sensor");
+MODULE_AUTHOR("Songjun Wu <songjun.wu@atmel.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.15.0

^ permalink raw reply related

* [PATCH v7 1/2] media: ov7740: Document device tree bindings
From: Wenyou Yang @ 2017-12-06  2:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171206022343.31104-1-wenyou.yang@microchip.com>

Add the device tree binding documentation for the ov7740 sensor driver.

Signed-off-by: Wenyou Yang <wenyou.yang@microchip.com>
Acked-by: Rob Herring <robh@kernel.org>
---

Changes in v7:
 - Add Acked-by tag.

Changes in v6: None
Changes in v5: None
Changes in v4: None
Changes in v3:
 - Explicitly document the "remote-endpoint" property.

Changes in v2: None

 .../devicetree/bindings/media/i2c/ov7740.txt       | 47 ++++++++++++++++++++++
 1 file changed, 47 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/ov7740.txt

diff --git a/Documentation/devicetree/bindings/media/i2c/ov7740.txt b/Documentation/devicetree/bindings/media/i2c/ov7740.txt
new file mode 100644
index 000000000000..af781c3a5f0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ov7740.txt
@@ -0,0 +1,47 @@
+* Omnivision OV7740 CMOS image sensor
+
+The Omnivision OV7740 image sensor supports multiple output image
+size, such as VGA, and QVGA, CIF and any size smaller. It also
+supports the RAW RGB and YUV output formats.
+
+The common video interfaces bindings (see video-interfaces.txt) should
+be used to specify link to the image data receiver. The OV7740 device
+node should contain one 'port' child node with an 'endpoint' subnode.
+
+Required Properties:
+- compatible:	"ovti,ov7740".
+- reg:		I2C slave address of the sensor.
+- clocks:	Reference to the xvclk input clock.
+- clock-names:	"xvclk".
+
+Optional Properties:
+- reset-gpios: Rreference to the GPIO connected to the reset_b pin,
+  if any. Active low with pull-ip resistor.
+- powerdown-gpios: Reference to the GPIO connected to the pwdn pin,
+  if any. Active high with pull-down resistor.
+
+Endpoint node mandatory properties:
+- remote-endpoint: A phandle to the bus receiver's endpoint node.
+
+Example:
+
+	i2c1: i2c at fc028000 {
+		ov7740: camera at 21 {
+			compatible = "ovti,ov7740";
+			reg = <0x21>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_sensor_power &pinctrl_sensor_reset>;
+			clocks = <&isc>;
+			clock-names = "xvclk";
+			assigned-clocks = <&isc>;
+			assigned-clock-rates = <24000000>;
+			reset-gpios = <&pioA 43 GPIO_ACTIVE_LOW>;
+			powerdown-gpios = <&pioA 44 GPIO_ACTIVE_HIGH>;
+
+			port {
+				ov7740_0: endpoint {
+					remote-endpoint = <&isc_0>;
+				};
+			};
+		};
+	};
-- 
2.15.0

^ permalink raw reply related

* [PATCH v7 0/2] media: ov7740: Add a V4L2 sensor-level driver
From: Wenyou Yang @ 2017-12-06  2:23 UTC (permalink / raw)
  To: linux-arm-kernel

Add a Video4Linux2 sensor-level driver for the OmniVision OV7740
VGA camera image sensor.

Changes in v7:
 - Add Acked-by tag.
 - Fix the wrong handle of default register configuration.
 - Add the missed assignment of ov7740->frmsize.

Changes in v6:
 - Remove unnecessary #include <linux/init>.
 - Remove unnecessary comments and extra newline.
 - Add const for some structures.
 - Add the check of the return value from regmap_write().
 - Simplify the calling of __v4l2_ctrl_handler_setup().
 - Add the default format initialization function.
 - Integrate the set_power() and enable/disable the clock into
   one function.

Changes in v5:
 - Squash the driver and MAINTAINERS entry patches to one.
 - Precede the driver patch with the bindings patch.

Changes in v4:
 - Assign 'val' a initial value to avoid warning: 'val' may be
   used uninitialized.
 - Rename REG_REG15 to avoid warning: "REG_REG15" redefined.

Changes in v3:
 - Explicitly document the "remote-endpoint" property.
 - Put the MAINTAINERS change to a separate patch.

Changes in v2:
 - Split off the bindings into a separate patch.
 - Add a new entry to the MAINTAINERS file.

Wenyou Yang (2):
  media: ov7740: Document device tree bindings
  media: i2c: Add the ov7740 image sensor driver

 .../devicetree/bindings/media/i2c/ov7740.txt       |   47 +
 MAINTAINERS                                        |    8 +
 drivers/media/i2c/Kconfig                          |    8 +
 drivers/media/i2c/Makefile                         |    1 +
 drivers/media/i2c/ov7740.c                         | 1234 ++++++++++++++++++++
 5 files changed, 1298 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/i2c/ov7740.txt
 create mode 100644 drivers/media/i2c/ov7740.c

-- 
2.15.0

^ permalink raw reply

* [PATCH] PM: Provide a config snippet for disabling PM
From: Rafael J. Wysocki @ 2017-12-06  1:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20171129111227.26798-1-broonie@kernel.org>

On Wednesday, November 29, 2017 12:12:27 PM CET Mark Brown wrote:
> A frequent source of build problems is poor handling of optional PM
> support, almost all development is done with the PM options enabled
> but they can be turned off.  Currently few if any of the build test
> services do this as standard as there is no standard config for it and
> the use of selects and def_bool means that simply setting CONFIG_PM=n
> doesn't do what is expected.  To make this easier provide a fragement
> that can be used with KCONFIG_ALLCONFIG to force PM off.
> 
> CONFIG_XEN is disabled as Xen uses hibernation callbacks which end up
> turning on power management on architectures with Xen.  Some cpuidle
> implementations on ARM select PM so CONFIG_CPU_IDLE is disabled, and
> some ARM architectures unconditionally enable PM so they are also
> disabled.
> 
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
>  MAINTAINERS                |  1 +
>  kernel/configs/nopm.config | 15 +++++++++++++++
>  2 files changed, 16 insertions(+)
>  create mode 100644 kernel/configs/nopm.config
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 07d9067f68fd..539808dc7928 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -10895,6 +10895,7 @@ F:	include/linux/pm.h
>  F:	include/linux/pm_*
>  F:	include/linux/powercap.h
>  F:	drivers/powercap/
> +F:	kernel/configs/nopm.config
>  
>  POWER STATE COORDINATION INTERFACE (PSCI)
>  M:	Mark Rutland <mark.rutland@arm.com>
> diff --git a/kernel/configs/nopm.config b/kernel/configs/nopm.config
> new file mode 100644
> index 000000000000..81ff07863576
> --- /dev/null
> +++ b/kernel/configs/nopm.config
> @@ -0,0 +1,15 @@
> +CONFIG_PM=n
> +CONFIG_SUSPEND=n
> +CONFIG_HIBERNATION=n
> +
> +# Triggers PM on OMAP
> +CONFIG_CPU_IDLE=n
> +
> +# Triggers enablement via hibernate callbacks
> +CONFIG_XEN=n
> +
> +# ARM/ARM64 architectures that select PM unconditionally
> +CONFIG_ARCH_OMAP2PLUS_TYPICAL=n
> +CONFIG_ARCH_RENESAS=n
> +CONFIG_ARCH_TEGRA=n
> +CONFIG_ARCH_VEXPRESS=n
> 

Applied, thanks!

^ permalink raw reply

* [PATCH v3 3/3] arm64: dts: meson-axg: add clock DT info for Meson AXG SoC
From: Stephen Boyd @ 2017-12-06  1:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1512147583.12869.10.camel@baylibre.com>

On 12/01, Jerome Brunet wrote:
> On Fri, 2017-12-01 at 08:34 -0800, Stephen Boyd wrote:
> > On 11/30, Yixun Lan wrote:
> > > Hi Stephen
> > > 
> > > On 11/30/17 03:35, Stephen Boyd wrote:
> > > > 
> > > > Maybe just call the node "bus at ff63c000"?
> > > > 
> > > 
> > > isn't this just a name? what's the benefits to change?
> > > personally, I tend to keep it this way, because it's better map to the
> > > data sheet
> > > 
> > > we also has 'aobus', 'cbus' scattered there..
> > 
> > Per the ePAPR node names are supposed to be generic, like disk,
> > cpu, display-controller, gpu, etc. I've never heard of a hiubus,
> > so probably it's some vendor specific thing? We have the phandle
> > anyway so it's not like we're losing much information here.
> 
> Stephen, there is a lot of busses on platform. We can't just call them all
> 'bus'.
> I don't get the problem with this name.
> We are re-using the name from the datasheet here, no fancy invention. It seems
> to be quite common. 
> 

Ok. I'm not the maintainer of the DTS so no worries from me. I'm
just pointing out that the ePAPR says that node names should be
generic, and 'hiubus' doesn't sound generic to me. If it matches
some datasheet then I suppose that's good, but probably that sort
of distinction should have gone into the compatible string
instead of the node name.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply

* [RFC PATCH 1/3] dt-bindings: pinctrl: sunxi: document new generic binding
From: André Przywara @ 2017-12-06  0:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CACRpkdZ70a7Vk1QPFhkms6ucWmSH6rOUD9_J0h=NjhK+vfXNAA@mail.gmail.com>

Hi Linus,

thanks for the reply!

On 01/12/17 09:56, Linus Walleij wrote:
> On Fri, Nov 24, 2017 at 6:19 PM, Andre Przywara <andre.przywara@arm.com> wrote:
> 
>> Conceptually I consider the DT being
>> part of the firmware,
> 
> As it is a subset of open firmware it is obviously firmware.
> 
>> so one trust level above the kernel.
> 
> We are several kernel developers who don't trust firmware one
> bit. Several disasters in ACPI has made me ever more convinced
> that firmware should be trusted less than kernel code.

I know what you mean, check commit acd316248205 ;-)

But in the Allwinner case all the firmware is open source, and even
controlled by the community (ATF & U-Boot). This is even more true for
the DT. Allwinner came up with their own DT, but since it uses
completely non-standard bindings, we don't use it at all.

So I don't consider firmware this dark, evil and unhackable blob that
many people see in it. Instead it is a good opportunity to separate very
tedious machine-specific parts from the kernel (think of PSCI).

> But this is all very academic.

I agree!

>>> Also, device tree bindings are not documentation for how to write a
>>> driver. They are not a replacement for hardware documentation. Nobody
>>> should be expected to be able to write an OS driver solely based on a
>>> device tree binding. Device tree bindings are more of a configuration
>>> interface specification for OS drivers.
>>
>> Yes, but together with the hardware docs you should be able to write a
>> driver. And here you can't, because you are missing the strings. So a
>> BSD developer has to look at Linux code.
> 
> This is a fair point. It appears in several drivers.
> 
> BSD or even Windows (would they use DT) would have to sit in the
> back seat just like Linux has been doing for years when it comes
> to the hopeless Windowsisms in the x86 BIOSes. I suspect some
> Windows on ARM is already experiencing this, but in the ACPI world,
> where, incidentally, the servers were being deployed for Linux first
> and Windows had to follow their example. I bet they have been
> swearing a lot in Redmond about that.

On the other hand a lot of the ACPI tables have been either taken from
x86 or designed also with Windows in mind. And frankly, my sympathy for
MS is quite limited in this respect ;-)

> In general it's one of these areas where we can not be utopian about the
> hardware descriptions, just fail gracefully in different ways.
> 
> I usually try to keep the IETF motto "rough consensus and running
> code" in mind. I don't know if it helps in this discussion though.
> 
>>> So that's about 40% of the kernel image. Code really is no good without
>>> data to process.
>>
>> But how much of this is SoC specific configuration data? How much is it
>> in x86? Yes, historically we had and have a lot of configuration data in
>> ARM kernels. But that doesn't mean that we have to continue with this or
>> even increase the share.
> 
> What people have been doing is trying to have better Kconfig setups
> and compile it out by doing kernel modules. It is a bit hopeless with
> pin controllers: almost all of them have to be built in. And if they come
> with a lot of data, yeah there you have a real good point.
> 
> It would be sad if the ARMv7 multiboot or Aarch64 kernel just grows
> so that we can't use it but have to go back to shipping board-specific
> kernels with a huge bunch of stuff compiled out.
> 
> I was hoping Moore's law would save us here :/
> 
> An option that has been discussed is better used of  __initdata
> and similar tags, especially with built-in drivers. Sadly, this is
> hurt by another snag: the compiler or linker file or whatever it is,
> is preventing us from discarding any strings from the kernel.
> And pin controllers tend to stack up a lot of these.
> 
> This is really sucky and something we should solve in general.
> I'm not smart enough to tackle any of these problems myself, just
> to see them and "Oh that's bad. Very bad."

I am sure one can find clever hac^Wsolutions for this problem, but I was
wondering if a new approach - like putting the per machine data actually
in DT - isn't the smarter way.
Hence my suggestion with this driver: we *need* the DT anyway to assign
pins to devices, so why not just add the few bytes *there*, which allows
us to have a more or less "data-less" DT driver?

>From what I learned the pinctrl subsystem seems to predates the ARM DT
endeavor, so many design decisions probably didn't consider DT as a
possible solution in the first way. And this is fine, because this is
how it was back then. But it doesn't mean it has to stay this way. And I
carefully thought of solving this problem without alienating existing
users and developers - by keeping the driver and staying compatible with
the existing binding and the DTs.

>>> The majority of the improvements over the years have been achieved by
>>> moving drivers out of arch/arm and moving board files to DT. The goal
>>> was never to get rid of all data.
>>
>> Sure, not all data. But if we have the relatively easy opportunity to
>> avoid further addition of data, we should do it, I believe.
>> This significantly reduces the amount of kernel code we need to add to
>> support new SoCs.
> 
> This is the core of your argument as I perceive it: get rid of data
> from the kernel, because it is growing wild.

Yes, this, but also to avoid replicating data in other DT consumers. I
very much like the idea of the DT describing the hardware, but I am a
bit afraid we loose many good opportunities by treating the DT more like
a "Linux config file" or an external Linux board file.
So I wanted to propose a way where we simplify DT usage in other
systems, while still keeping the Linux driver intact.

> It is a valid cause. Just
> has to be weighed with other stuff, like maintainability, debuggability,
> maintainers viewpoint. ...

So to keep Maxime happy I actually designed this "driver" more like a
shim: to generate the table the current driver expects from the DT, and
actually not touching the existing driver at all.
So maintainability should actually be less of a concern: the driver will
just work with whatever one throws at it from the DT side, without
requiring frequent changes or additions.
In the moment we still need to write, review and merge *data* files for
each new SoC. And as I mentioned before, Allwinner decided to push for
new, slightly different chips every few months, so there will be more to
come. With at least the pinctrl driver out of the way we have one
problem less to worry about.

Cheers,
Andre.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox