Devicetree
 help / color / mirror / Atom feed
* [PATCH] ARM: dts: colibri/apalis: use correct compatible for RTC
From: Stefan Agner @ 2017-12-06 10:29 UTC (permalink / raw)
  To: shawnguo
  Cc: devicetree, Marcel Ziswiler, Stefan Agner, Sanchayan Maity,
	kernel, fabio.estevam, linux-arm-kernel

All Toradex Carrier Boards use a st,m41t0 compatible RTC. Compared
to a st,m41t00 this RTC has also an oscillator fail bit which allows
to detect when the RTC lost track of time.

Cc: Sanchayan Maity <maitysanchayan@gmail.com>
Cc: Marcel Ziswiler <marcel.ziswiler@toradex.com>
Signed-off-by: Stefan Agner <stefan@agner.ch>
---
 arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts  | 2 +-
 arch/arm/boot/dts/imx6q-apalis-eval.dts       | 2 +-
 arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts | 2 +-
 arch/arm/boot/dts/imx6q-apalis-ixora.dts      | 2 +-
 arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi   | 2 +-
 arch/arm/boot/dts/vf-colibri-eval-v3.dtsi     | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
index 5705ebee0595..dcf9206f3e0d 100644
--- a/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/imx6dl-colibri-eval-v3.dts
@@ -163,7 +163,7 @@
 
 	/* M41T0M6 real time clock on carrier board */
 	rtc_i2c: rtc@68 {
-		compatible = "st,m41t00";
+		compatible = "st,m41t0";
 		reg = <0x68>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-apalis-eval.dts b/arch/arm/boot/dts/imx6q-apalis-eval.dts
index 8b56656e53da..aa0e631f3c0a 100644
--- a/arch/arm/boot/dts/imx6q-apalis-eval.dts
+++ b/arch/arm/boot/dts/imx6q-apalis-eval.dts
@@ -158,7 +158,7 @@
 
 	/* M41T0M6 real time clock on carrier board */
 	rtc_i2c: rtc@68 {
-		compatible = "st,m41t00";
+		compatible = "st,m41t0";
 		reg = <0x68>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts
index 27dc0fc686a9..e8dccf552122 100644
--- a/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts
+++ b/arch/arm/boot/dts/imx6q-apalis-ixora-v1.1.dts
@@ -170,7 +170,7 @@
 
 	/* M41T0M6 real time clock on carrier board */
 	rtc_i2c: rtc@68 {
-		compatible = "st,m41t00";
+		compatible = "st,m41t0";
 		reg = <0x68>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx6q-apalis-ixora.dts b/arch/arm/boot/dts/imx6q-apalis-ixora.dts
index 40b2c67fe7af..6831dfd24cc1 100644
--- a/arch/arm/boot/dts/imx6q-apalis-ixora.dts
+++ b/arch/arm/boot/dts/imx6q-apalis-ixora.dts
@@ -174,7 +174,7 @@
 
 	/* M41T0M6 real time clock on carrier board */
 	rtc_i2c: rtc@68 {
-		compatible = "st,m41t00";
+		compatible = "st,m41t0";
 		reg = <0x68>;
 	};
 };
diff --git a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
index 3d6c282dd258..3cf9b077d4f3 100644
--- a/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/imx7-colibri-eval-v3.dtsi
@@ -133,7 +133,7 @@
 
 	/* M41T0M6 real time clock on carrier board */
 	rtc: m41t0m6@68 {
-		compatible = "st,m41t00";
+		compatible = "st,m41t0";
 		reg = <0x68>;
 	};
 };
diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
index 091b738041a0..d8b2972527eb 100644
--- a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -140,7 +140,7 @@
 
 	/* M41T0M6 real time clock on carrier board */
 	rtc: m41t0m6@68 {
-		compatible = "st,m41t00";
+		compatible = "st,m41t0";
 		reg = <0x68>;
 	};
 };
-- 
2.15.1

^ permalink raw reply related

* RE: [PATCH v2 5/5] rtc: add mxc driver for i.MX53 SRTC
From: Patrick Brünn @ 2017-12-06 10:17 UTC (permalink / raw)
  To: Sascha Hauer, linux-kernel-dev
  Cc: Shawn Guo, Sascha Hauer, Alessandro Zummo, Alexandre Belloni,
	Mark Rutland, open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Philippe Ombredanne, Fabio Estevam,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20171206083618.eea63zqmpgaaazwl@pengutronix.de>

>From: Sascha Hauer [mailto:s.hauer@pengutronix.de]
>Sent: Mittwoch, 6. Dezember 2017 09:36
>On Tue, Dec 05, 2017 at 03:06:46PM +0100, linux-kernel-dev@beckhoff.com
>wrote:
>> +static int mxc_rtc_write_alarm_locked(struct mxc_rtc_data *const pdata,
>> +                                  struct rtc_time *alarm_tm)
>> +{
>> +    void __iomem *const ioaddr = pdata->ioaddr;
>> +    unsigned long time;
>> +
>> +    rtc_tm_to_time(alarm_tm, &time);
>> +
>> +    if (time > U32_MAX) {
>> +            pr_err("Hopefully I am out of service by then :-(\n");
>> +            return -EINVAL;
>> +    }
>
>This will never happen as on your target hardware unsigned long is a
>32bit type. Not sure what is best to do here. Maybe you should test
>the return value of rtc_tm_to_time. ATM it returns 0 unconditionally,
>but rtc_tm_to_time could detect when the input time doesn't fit into
>its return type and return an error in this case.
>Also I just realized that it's unsigned and only overflows in the year
>2106. I'm most likely dead then so I don't care that much ;)
>
please see my response to Alexandre's follow up

>> +/* This function is the RTC interrupt service routine. */
>> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
>> +{
>> +    struct platform_device *pdev = dev_id;
>> +    struct mxc_rtc_data *pdata = platform_get_drvdata(pdev);
>> +    void __iomem *ioaddr = pdata->ioaddr;
>> +    unsigned long flags;
>> +    u32 events = 0;
>> +    u32 lp_status;
>> +    u32 lp_cr;
>> +
>> +    spin_lock_irqsave(&pdata->lock, flags);
>> +    if (clk_prepare_enable(pdata->clk)) {
>> +            spin_unlock_irqrestore(&pdata->lock, flags);
>> +            return IRQ_NONE;
>> +    }
>
>You are not allowed to do a clk_prepare under a spinlock. That was the
>original reason to split enabling a clk into clk_prepare and clk_enable.
>Everything that can block is done in clk_prepare and only non blocking
>things are done in clk_enable.
>If you want to enable/disable the clock on demand you can clk_prepare()
>in probe and clk_enable when you actually need it.
>
Thanks for clarification. To be honest when I read Lothar's suggestion it was
the first time I thought about the idea of keeping the clk disabled most of
the time. I am not very experienced with this. But a rtctest loop run for
hours so I assume it would be okay to keep the clk disabled until hw access.
If there is no objection from somebody who knows the i.MX53 SRTC HW
better, I will stick to the clock on demand model and make sure I avoid
blocking.
>> +
>> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
>> +{
>> +    struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
>> +    time_t now;
>> +    int ret = mxc_rtc_lock(pdata);
>> +
>> +    if (ret)
>> +            return ret;
>> +
>> +    now = readl(pdata->ioaddr + SRTC_LPSCMR);
>> +    rtc_time_to_tm(now, tm);
>> +    ret = rtc_valid_tm(tm);
>> +    mxc_rtc_unlock(pdata);
>
>I don't think this needs to be locked.
I will change this to only enable the clock for the readl()

>> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
>> +{
>> +    struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
>> +    int ret = mxc_rtc_lock(pdata);
>> +
>> +    if (ret)
>> +            return ret;
>> +
>> +    ret = mxc_rtc_write_alarm_locked(pdata, &alrm->time);
>
>Is it worth it to make this a separate function?
Maybe not, I think it is an artifact from a refactoring. I will reconsider this
for the next version.
>
>> +    if (!ret) {
>> +            mxc_rtc_alarm_irq_enable_locked(pdata, alrm->enabled);
>> +            mxc_rtc_sync_lp_locked(pdata->ioaddr);
>> +    }
>> +    mxc_rtc_unlock(pdata);
>> +    return ret;
>> +}
>> +
>> +static const struct rtc_class_ops mxc_rtc_ops = {
>> +    .read_time = mxc_rtc_read_time,
>> +    .set_time = mxc_rtc_set_time,
>> +    .read_alarm = mxc_rtc_read_alarm,
>> +    .set_alarm = mxc_rtc_set_alarm,
>> +    .alarm_irq_enable = mxc_rtc_alarm_irq_enable,
>> +};
>> +
>> +static int mxc_rtc_wait_for_flag(void *__iomem ioaddr, int flag)
>> +{
>> +    unsigned int timeout = REG_READ_TIMEOUT;
>> +
>> +    while (!(readl(ioaddr) & flag)) {
>> +            if (!--timeout) {
>> +                    pr_err("Wait timeout for 0x%x@%p!\n", flag, ioaddr);
>
>Please use dev_* functions for printing. In this case the message should
>probably be printed from the caller.
Do you have a link at hand about dev_* vs. pr_*? I just choose pr_err here,
because I would have to change the functions signature to get a device.
However, I will drop the message and move it to the caller.

>> +    /* clear lp interrupt status */
>> +    writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
>> +
>> +    /* move out of init state */
>> +    writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
>> +    xc_rtc_wait_for_flag(ioaddr + SRTC_LPSR, SRTC_LPSR_IES);
>
>If this can fail, shouldn't you test for an error?
very probably
>> +
>> +    /* move out of non-valid state */
>> +    writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
>> +            SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
>> +    mxc_rtc_wait_for_flag(ioaddr + SRTC_LPSR, SRTC_LPSR_NVES);
>
>dito
sure

Thanks,
Patrick
---
Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075

^ permalink raw reply

* [PATCH] dt-bindings: at24/eeprom: add an undocumented compatible string
From: Bartosz Golaszewski @ 2017-12-06 10:12 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Wolfram Sang, Divagar Mohandass,
	Javier Martinez Canillas, David Lechner
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Bartosz Golaszewski

The "atmel,sdp" compatible is reported by checkpatch as undocumented.

Add it to the device tree bindings document for at24.

Signed-off-by: Bartosz Golaszewski <brgl-ARrdPY/1zhM@public.gmane.org>
---
 Documentation/devicetree/bindings/eeprom/eeprom.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
index 27f2bc15298a..5b5ceee6ce02 100644
--- a/Documentation/devicetree/bindings/eeprom/eeprom.txt
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -8,6 +8,8 @@ Required properties:
 	"atmel,24c08", "atmel,24c16", "atmel,24c32", "atmel,24c64",
 	"atmel,24c128", "atmel,24c256", "atmel,24c512", "atmel,24c1024"
 
+	"atmel,spd"
+
 	"catalyst,24c32"
 
 	"microchip,24c128"
-- 
2.15.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v3 2/3] dt-bindings: iio: temperature: add MLX90632 device bindings
From: Crt Mori @ 2017-12-06  9:55 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Crt Mori

Add device tree bindings for MLX90632 IR temperature sensor.

Signed-off-by: Crt Mori <cmo-fc6wVz46lShBDgjK7y7TUQ@public.gmane.org>
Reviewed-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 .../bindings/iio/temperature/mlx90632.txt          | 28 ++++++++++++++++++++++
 1 file changed, 28 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/temperature/mlx90632.txt

diff --git a/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
new file mode 100644
index 000000000000..0b05812001f8
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/temperature/mlx90632.txt
@@ -0,0 +1,28 @@
+* Melexis MLX90632 contactless Infra Red temperature sensor
+
+Link to datasheet: https://www.melexis.com/en/documents/documentation/datasheets/datasheet-mlx90632
+
+There are various applications for the Infra Red contactless temperature sensor
+and MLX90632 is most suitable for consumer applications where measured object
+temperature is in range between -20 to 200 degrees Celsius with relative error
+of measurement below 1 degree Celsius in object temperature range for
+industrial applications. Since it can operate and measure ambient temperature
+in range of -20 to 85 degrees Celsius it is suitable also for outdoor use.
+
+Be aware that electronics surrounding the sensor can increase ambient
+temperature. MLX90632 can be calibrated to reduce the housing effect via
+already existing EEPROM parameters.
+
+Since measured object emissivity effects Infra Red energy emitted, emissivity
+should be set before requesting the object temperature.
+
+Required properties:
+  - compatible: should be "melexis,mlx90632"
+  - reg: the I2C address of the sensor (default 0x3a)
+
+Example:
+
+mlx90632@3a {
+	compatible = "melexis,mlx90632";
+	reg = <0x3a>;
+};
-- 
2.15.0

^ permalink raw reply related

* RE: [PATCH v2 5/5] rtc: add mxc driver for i.MX53 SRTC
From: Patrick Brünn @ 2017-12-06  9:28 UTC (permalink / raw)
  To: Alexandre Belloni, Sascha Hauer
  Cc: linux-kernel-dev, Shawn Guo, Sascha Hauer, Alessandro Zummo,
	Mark Rutland, open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Philippe Ombredanne, Fabio Estevam,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20171206085825.GM21780-m++hUPXGwpdeoWH0uzbU5w@public.gmane.org>

>From: Alexandre Belloni [mailto:alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org]
>Sent: Mittwoch, 6. Dezember 2017 09:58
>On 06/12/2017 at 09:36:18 +0100, Sascha Hauer wrote:
>> > +/*
>> > + * This function updates the RTC alarm registers and then clears all the
>> > + * interrupt status bits.
>> > + * The caller should hold the pdata->lock
>> > + *
>> > + * @param  alrm         the new alarm value to be updated in the RTC
>> > + *
>> > + * @return  0 if successful; non-zero otherwise.
>> > + */
>> > +static int mxc_rtc_write_alarm_locked(struct mxc_rtc_data *const pdata,
>> > +                                struct rtc_time *alarm_tm)
>> > +{
>> > +  void __iomem *const ioaddr = pdata->ioaddr;
>> > +  unsigned long time;
>> > +
>> > +  rtc_tm_to_time(alarm_tm, &time);
>> > +
>> > +  if (time > U32_MAX) {
>> > +          pr_err("Hopefully I am out of service by then :-(\n");
>> > +          return -EINVAL;
>> > +  }
>>
>> This will never happen as on your target hardware unsigned long is a
>> 32bit type. Not sure what is best to do here. Maybe you should test
>> the return value of rtc_tm_to_time. ATM it returns 0 unconditionally,
>> but rtc_tm_to_time could detect when the input time doesn't fit into
>> its return type and return an error in this case.
>> Also I just realized that it's unsigned and only overflows in the year
>> 2106. I'm most likely dead then so I don't care that much ;)
>>
>
>One solution is to use the 64bit version instead so it doesn't overflow.
>This makes the time > U32_MAX work.
>Also, I'll send (hopefully soon) a series adding proper range checking
>for the whole RTC subsystem. And yes, it not urgent as I don't think I
>will care so much in 2106 too ;)
>
I just noticed that in mxc_rtc_set_time() I am using the 64bit version.
After thinking a while about this issue, I think the 64bit version is better
suited for my use case. It makes explicitly clear that I need to push the
time into a 32bit hw register and "unsigned long" is just by accident the
correct size for me.

>> > +/*
>> > + * This function reads the current RTC time into tm in Gregorian date.
>> > + *
>> > + * @param  tm           contains the RTC time value upon return
>> > + *
>> > + * @return  0 if successful; non-zero otherwise.
>> > + */
>> > +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
>> > +{
>> > +  struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
>> > +  time_t now;
>> > +  int ret = mxc_rtc_lock(pdata);
>> > +
>> > +  if (ret)
>> > +          return ret;
>> > +
>> > +  now = readl(pdata->ioaddr + SRTC_LPSCMR);
>> > +  rtc_time_to_tm(now, tm);
>> > +  ret = rtc_valid_tm(tm);
>
>This check is useless for two reasons: you know that rtc_time_to_tm will
>generate a valid tm and the core always checks the tm anyway.
I will remove this with the next version

Thanks for your time and help,
Patrick

Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075



--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 5/5] rtc: add mxc driver for i.MX53 SRTC
From: Alexandre Belloni @ 2017-12-06  8:58 UTC (permalink / raw)
  To: Sascha Hauer
  Cc: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w, Shawn Guo, Sascha Hauer,
	Alessandro Zummo, Mark Rutland,
	open list:REAL TIME CLOCK (RTC) SUBSYSTEM, Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Philippe Ombredanne, Fabio Estevam,
	moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE
In-Reply-To: <20171206083618.eea63zqmpgaaazwl-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

On 06/12/2017 at 09:36:18 +0100, Sascha Hauer wrote:
> > +/*
> > + * This function updates the RTC alarm registers and then clears all the
> > + * interrupt status bits.
> > + * The caller should hold the pdata->lock
> > + *
> > + * @param  alrm         the new alarm value to be updated in the RTC
> > + *
> > + * @return  0 if successful; non-zero otherwise.
> > + */
> > +static int mxc_rtc_write_alarm_locked(struct mxc_rtc_data *const pdata,
> > +				      struct rtc_time *alarm_tm)
> > +{
> > +	void __iomem *const ioaddr = pdata->ioaddr;
> > +	unsigned long time;
> > +
> > +	rtc_tm_to_time(alarm_tm, &time);
> > +
> > +	if (time > U32_MAX) {
> > +		pr_err("Hopefully I am out of service by then :-(\n");
> > +		return -EINVAL;
> > +	}
> 
> This will never happen as on your target hardware unsigned long is a
> 32bit type. Not sure what is best to do here. Maybe you should test
> the return value of rtc_tm_to_time. ATM it returns 0 unconditionally,
> but rtc_tm_to_time could detect when the input time doesn't fit into
> its return type and return an error in this case.
> Also I just realized that it's unsigned and only overflows in the year
> 2106. I'm most likely dead then so I don't care that much ;)
> 

One solution is to use the 64bit version instead so it doesn't overflow.
This makes the time > U32_MAX work.
Also, I'll send (hopefully soon) a series adding proper range checking
for the whole RTC subsystem. And yes, it not urgent as I don't think I
will care so much in 2106 too ;)

> > +/*
> > + * This function reads the current RTC time into tm in Gregorian date.
> > + *
> > + * @param  tm           contains the RTC time value upon return
> > + *
> > + * @return  0 if successful; non-zero otherwise.
> > + */
> > +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> > +{
> > +	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
> > +	time_t now;
> > +	int ret = mxc_rtc_lock(pdata);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	now = readl(pdata->ioaddr + SRTC_LPSCMR);
> > +	rtc_time_to_tm(now, tm);
> > +	ret = rtc_valid_tm(tm);

This check is useless for two reasons: you know that rtc_time_to_tm will
generate a valid tm and the core always checks the tm anyway.


-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 0/4] arm64: defconfig: enable additional led triggers
From: Amit Kucheria @ 2017-12-06  8:57 UTC (permalink / raw)
  To: Amit Kucheria, LKML, Arnd Bergmann, Andy Gross
  Cc: linux-arm-msm, lakml, Wei Xu, manivannan.sadhasivam, devicetree,
	timur
In-Reply-To: <cover.1509951550.git.amit.kucheria@linaro.org>

(Adding Arnd)

Now that the merge window rush has abated, can you please apply this
trivial series?

On Mon, Nov 6, 2017 at 12:38 PM, Amit Kucheria <amit.kucheria@linaro.org> wrote:
> This patchset enables the kernel panic and disk-activity trigger for LEDs
> and then enables the panic trigger for three 96Boards - DB410c, Hikey and
> Hikey960.
>
> DB410c and Hikey panic behaviour has been tested by triggering a panic
> through /proc/sysrq-trigger, while Hikey960 is only compile-tested.
>
>
> Amit Kucheria (4):
>   arm64: defconfig: enable new trigger modes for leds
>   arm64: dts: qcom: apq8016-sbc: Allow USR4 LED to notify kernel panic
>   arm64: dts: hisilicon: hi6220-hikey: Allow USR1 LED to notify kernel
>     panic
>   arm64: dts: hisilicon: hi3660-hikey960: Allow USR4 LED to notify
>     kernel panic
>
>  arch/arm64/boot/dts/hisilicon/hi3660-hikey960.dts | 1 +
>  arch/arm64/boot/dts/hisilicon/hi6220-hikey.dts    | 1 +
>  arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi         | 1 +
>  arch/arm64/configs/defconfig                      | 2 ++
>  4 files changed, 5 insertions(+)
>
> --
> 2.7.4
>

^ permalink raw reply

* RE: [PATCH net-next v3 4/4] net: fec: add phy_reset_after_clk_enable() support
From: Andy Duan @ 2017-12-06  8:41 UTC (permalink / raw)
  To: Richard Leitner, Richard Leitner,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	andrew-g2DYL2Zd6BY@public.gmane.org,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org,
	geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org,
	baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org,
	david.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org,
	lukma-ynQEQJNshbs@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1e7b3e7f-251d-4101-1441-702e891f2ca9-WcANXNA0UjBBDgjK7y7TUQ@public.gmane.org>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 2834 bytes --]

From: Richard Leitner <richard.leitner@skidata.com> Sent: Wednesday, December 06, 2017 4:12 PM
>To: Andy Duan <fugang.duan@nxp.com>; Richard Leitner <dev@g0hl1n.net>;
>robh+dt@kernel.org; mark.rutland@arm.com; andrew@lunn.ch;
>f.fainelli@gmail.com; frowand.list@gmail.com
>Cc: davem@davemloft.net; geert+renesas@glider.be;
>sergei.shtylyov@cogentembedded.com; baruch@tkos.co.il; david.wu@rock-
>chips.com; lukma@denx.de; netdev@vger.kernel.org;
>devicetree@vger.kernel.org; linux-kernel@vger.kernel.org
>Subject: Re: [PATCH net-next v3 4/4] net: fec: add
>phy_reset_after_clk_enable() support
>
>Hi Andy,
>
>On 12/06/2017 02:50 AM, Andy Duan wrote:
>> From: Richard Leitner <dev@g0hl1n.net> Sent: Tuesday, December 05,
>> 2017 9:26 PM
>>> Some PHYs (for example the SMSC LAN8710/LAN8720) doesn't allow
>>> turning the refclk on and off again during operation (according to their
>datasheet).
>>> Nonetheless exactly this behaviour was introduced for power saving
>>> reasons by commit e8fcfcd5684a ("net: fec: optimize the clock
>>> management to save power").
>>> Therefore add support for the phy_reset_after_clk_enable function
>>> from phylib to mitigate this issue.
>
>...
>
>>> diff --git a/drivers/net/ethernet/freescale/fec_main.c
>>> b/drivers/net/ethernet/freescale/fec_main.c
>>> index 610573855213..8c3d0fb7db20 100644
>>> --- a/drivers/net/ethernet/freescale/fec_main.c
>>> +++ b/drivers/net/ethernet/freescale/fec_main.c
>>> @@ -1862,6 +1862,8 @@ static int fec_enet_clk_enable(struct
>>> net_device *ndev, bool enable)
>>> 		ret = clk_prepare_enable(fep->clk_ref);
>>> 		if (ret)
>>> 			goto failed_clk_ref;
>>> +
>>> +		phy_reset_after_clk_enable(ndev->phydev);
>>> 	} else {
>>> 		clk_disable_unprepare(fep->clk_ahb);
>>> 		clk_disable_unprepare(fep->clk_enet_out);
>>> @@ -2860,6 +2862,11 @@ fec_enet_open(struct net_device *ndev)
>>> 	if (ret)
>>> 		goto err_enet_mii_probe;
>>>
>>> +	/* reset phy if needed here, due to the fact this is the first time we
>>> +	 * have the net_device to phy_driver link
>>> +	 */
>>> +	phy_reset_after_clk_enable(ndev->phydev);
>>> +
>>
>> The patch series look better.
>> But why does it need to reset phy here since phy already is hard reset after
>clock enable.
>
>The problem here is that in fec_enet_open() the fec_enet_clk_enable() call is
>done before the phy is probed. Therefore (as mentioned in the
>comment) there's no link from the net_device (ndev) to the phy_driver
>(which holds the flags).
>
>Any suggestions for a better solution are highly appreciated here! Thanks!
>
>regards;Richard.L

Okay, I see.

For the patch: Acked-by: Fugang Duan <fugang.duan@nxp.com>
N‹§²æìr¸›yúèšØb²X¬¶Ç§vØ^–)Þº{.nÇ+‰·zøœzÚÞz)í…æèw*\x1fjg¬±¨\x1e¶‰šŽŠÝ¢j.ïÛ°\½½MŽúgjÌæa×\x02››–' ™©Þ¢¸\f¢·¦j:+v‰¨ŠwèjØm¶Ÿÿ¾\a«‘êçzZ+ƒùšŽŠÝ¢j"ú!¶i

^ permalink raw reply

* Re: [PATCH v2 5/5] rtc: add mxc driver for i.MX53 SRTC
From: Sascha Hauer @ 2017-12-06  8:36 UTC (permalink / raw)
  To: linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w
  Cc: Shawn Guo, Sascha Hauer, Alessandro Zummo, Alexandre Belloni,
	Mark Rutland, open list:REAL TIME CLOCK (RTC) SUBSYSTEM,
	Patrick Bruenn,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Juergen Borleis, open list, Russell King, Noel Vellemans,
	Rob Herring, Philippe Ombredanne, Fabio Estevam
In-Reply-To: <20171205140646.30367-6-linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>

On Tue, Dec 05, 2017 at 03:06:46PM +0100, linux-kernel-dev-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org wrote:
> From: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
> 
> Neither rtc-imxdi, rtc-mxc nor rtc-snvs are compatible with i.MX53.
> 
> This is driver enables support for the low power domain SRTC features:
> - 32-bit MSB of non-rollover time counter
> - 32-bit alarm register
> 
> Based on:
> http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git/tree/drivers/rtc/rtc-mxc_v2.c?h=imx_2.6.35_11.09.01
> 
> Signed-off-by: Patrick Bruenn <p.bruenn-QonKdJ6Bx35Wk0Htik3J/w@public.gmane.org>
> 
> ---
> 
> v2:
> - have seperate patches for dt-binding, CONFIG option, imx53.dtsi and driver
> - add SPDX-License-Identifier and cleanup copyright notice
> - replace __raw_readl/writel() with readl/writel()
> - fix PM_SLEEP callbacks
> - add CONFIG_RTC_DRV_MXC_V2 to build rtc-mxc_v2.c
> - remove misleading or obvious comments and fix style of the remaining
> - avoid endless loop while waiting for hw
> - implement consistent locking; make spinlock a member of dev struct
> - enable clk only for register accesses
> - remove all udelay() calls since they are obsolete or redundant
>   (we are already waiting for register flags to change)
> - init platform_data before registering irq callback
> - let set_time() fail, when 32 bit rtc counter exceeded
> - make names more consistent
> - cleanup and reorder includes
> - cleanup and remove unused defines
> 
> To: Alessandro Zummo <a.zummo-BfzFCNDTiLLj+vYz1yj4TQ@public.gmane.org>
> To: Alexandre Belloni <alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org> (maintainer:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-rtc-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:REAL TIME CLOCK (RTC) SUBSYSTEM)
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS)
> Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org (open list)
> Cc: Fabio Estevam <fabio.estevam-3arQi8VN3Tc@public.gmane.org>
> Cc: Juergen Borleis <jbe-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
> Cc: Noel Vellemans <Noel.Vellemans-8UENEgx6w+makBO8gow8eQ@public.gmane.org>
> Cc: Shawn Guo <shawnguo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Sascha Hauer <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> (maintainer:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> Cc: Russell King <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> (maintainer:ARM PORT)
> Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org (moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE)
> 
> Cc: Philippe Ombredanne <pombredanne-od1rfyK75/E@public.gmane.org>
> Cc: Lothar Waßmann <LW-bxm8fMRDkQLDiMYJYoSAnRvVK+yQ3ZXh@public.gmane.org>
> ---
>  drivers/rtc/Makefile     |   1 +
>  drivers/rtc/rtc-mxc_v2.c | 433 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 434 insertions(+)
>  create mode 100644 drivers/rtc/rtc-mxc_v2.c
> 
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index f2f50c11dc38..dcf60e61ae5c 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -106,6 +106,7 @@ obj-$(CONFIG_RTC_DRV_MT6397)	+= rtc-mt6397.o
>  obj-$(CONFIG_RTC_DRV_MT7622)	+= rtc-mt7622.o
>  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
>  obj-$(CONFIG_RTC_DRV_MXC)	+= rtc-mxc.o
> +obj-$(CONFIG_RTC_DRV_MXC_V2)	+= rtc-mxc_v2.o
>  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
>  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
>  obj-$(CONFIG_RTC_DRV_OPAL)	+= rtc-opal.o
> diff --git a/drivers/rtc/rtc-mxc_v2.c b/drivers/rtc/rtc-mxc_v2.c
> new file mode 100644
> index 000000000000..c5a6d2c293bb
> --- /dev/null
> +++ b/drivers/rtc/rtc-mxc_v2.c
> @@ -0,0 +1,433 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Real Time Clock (RTC) Driver for i.MX53
> + * Copyright (c) 2004-2011 Freescale Semiconductor, Inc.
> + * Copyright (c) 2017 Beckhoff Automation GmbH & Co. KG
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/rtc.h>
> +
> +#define SRTC_LPPDR_INIT       0x41736166	/* init for glitch detect */
> +
> +#define SRTC_LPCR_EN_LP       BIT(3)	/* lp enable */
> +#define SRTC_LPCR_WAE         BIT(4)	/* lp wakeup alarm enable */
> +#define SRTC_LPCR_ALP         BIT(7)	/* lp alarm flag */
> +#define SRTC_LPCR_NSA         BIT(11)	/* lp non secure access */
> +#define SRTC_LPCR_NVE         BIT(14)	/* lp non valid state exit bit */
> +#define SRTC_LPCR_IE          BIT(15)	/* lp init state exit bit */
> +
> +#define SRTC_LPSR_ALP         BIT(3)	/* lp alarm flag */
> +#define SRTC_LPSR_NVES        BIT(14)	/* lp non-valid state exit status */
> +#define SRTC_LPSR_IES         BIT(15)	/* lp init state exit status */
> +
> +#define SRTC_LPSCMR	0x00	/* LP Secure Counter MSB Reg */
> +#define SRTC_LPSCLR	0x04	/* LP Secure Counter LSB Reg */
> +#define SRTC_LPSAR	0x08	/* LP Secure Alarm Reg */
> +#define SRTC_LPCR	0x10	/* LP Control Reg */
> +#define SRTC_LPSR	0x14	/* LP Status Reg */
> +#define SRTC_LPPDR	0x18	/* LP Power Supply Glitch Detector Reg */
> +
> +/* max. number of retries to read registers, 120 was max during test */
> +#define REG_READ_TIMEOUT 2000
> +
> +struct mxc_rtc_data {
> +	struct rtc_device *rtc;
> +	void __iomem *ioaddr;
> +	struct clk *clk;
> +	spinlock_t lock; /* protects register access */
> +	int irq;
> +};
> +
> +/*
> + * This function does write synchronization for writes to the lp srtc block.
> + * To take care of the asynchronous CKIL clock, all writes from the IP domain
> + * will be synchronized to the CKIL domain.
> + * The caller should hold the pdata->lock
> + */
> +static inline void mxc_rtc_sync_lp_locked(void __iomem *ioaddr)
> +{
> +	unsigned int i;
> +
> +	/* Wait for 3 CKIL cycles */
> +	for (i = 0; i < 3; i++) {
> +		const u32 count = readl(ioaddr + SRTC_LPSCLR);
> +		unsigned int timeout = REG_READ_TIMEOUT;
> +
> +		while ((readl(ioaddr + SRTC_LPSCLR)) == count) {
> +			if (!--timeout) {
> +				pr_err("SRTC_LPSCLR stuck! Check your hw.\n");
> +				return;
> +			}
> +		}
> +	}
> +}
> +
> +/*
> + * This function updates the RTC alarm registers and then clears all the
> + * interrupt status bits.
> + * The caller should hold the pdata->lock
> + *
> + * @param  alrm         the new alarm value to be updated in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_write_alarm_locked(struct mxc_rtc_data *const pdata,
> +				      struct rtc_time *alarm_tm)
> +{
> +	void __iomem *const ioaddr = pdata->ioaddr;
> +	unsigned long time;
> +
> +	rtc_tm_to_time(alarm_tm, &time);
> +
> +	if (time > U32_MAX) {
> +		pr_err("Hopefully I am out of service by then :-(\n");
> +		return -EINVAL;
> +	}

This will never happen as on your target hardware unsigned long is a
32bit type. Not sure what is best to do here. Maybe you should test
the return value of rtc_tm_to_time. ATM it returns 0 unconditionally,
but rtc_tm_to_time could detect when the input time doesn't fit into
its return type and return an error in this case.
Also I just realized that it's unsigned and only overflows in the year
2106. I'm most likely dead then so I don't care that much ;)

> +
> +	writel((u32)time, ioaddr + SRTC_LPSAR);
> +
> +	/* clear alarm interrupt status bit */
> +	writel(SRTC_LPSR_ALP, ioaddr + SRTC_LPSR);
> +
> +	mxc_rtc_sync_lp_locked(ioaddr);
> +	return 0;
> +}
> +
> +/* This function is the RTC interrupt service routine. */
> +static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
> +{
> +	struct platform_device *pdev = dev_id;
> +	struct mxc_rtc_data *pdata = platform_get_drvdata(pdev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	unsigned long flags;
> +	u32 events = 0;
> +	u32 lp_status;
> +	u32 lp_cr;
> +
> +	spin_lock_irqsave(&pdata->lock, flags);
> +	if (clk_prepare_enable(pdata->clk)) {
> +		spin_unlock_irqrestore(&pdata->lock, flags);
> +		return IRQ_NONE;
> +	}

You are not allowed to do a clk_prepare under a spinlock. That was the
original reason to split enabling a clk into clk_prepare and clk_enable.
Everything that can block is done in clk_prepare and only non blocking
things are done in clk_enable.
If you want to enable/disable the clock on demand you can clk_prepare()
in probe and clk_enable when you actually need it.

> +
> +	lp_status = readl(ioaddr + SRTC_LPSR);
> +	lp_cr = readl(ioaddr + SRTC_LPCR);
> +
> +	/* update irq data & counter */
> +	if (lp_status & SRTC_LPSR_ALP) {
> +		if (lp_cr & SRTC_LPCR_ALP)
> +			events = (RTC_AF | RTC_IRQF);
> +
> +		/* disable further lp alarm interrupts */
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	}
> +
> +	/* Update interrupt enables */
> +	writel(lp_cr, ioaddr + SRTC_LPCR);
> +
> +	/* clear interrupt status */
> +	writel(lp_status, ioaddr + SRTC_LPSR);
> +
> +	mxc_rtc_sync_lp_locked(ioaddr);
> +	rtc_update_irq(pdata->rtc, 1, events);
> +	clk_disable_unprepare(pdata->clk);
> +	spin_unlock_irqrestore(&pdata->lock, flags);
> +	return IRQ_HANDLED;
> +}
> +
> +/*
> + * Enable clk and aquire spinlock
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_lock(struct mxc_rtc_data *const pdata)
> +{
> +	int ret;
> +
> +	spin_lock_irq(&pdata->lock);
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret) {
> +		spin_unlock_irq(&pdata->lock);
> +		return ret;
> +	}
> +	return 0;
> +}
> +
> +static int mxc_rtc_unlock(struct mxc_rtc_data *const pdata)
> +{
> +	clk_disable_unprepare(pdata->clk);
> +	spin_unlock_irq(&pdata->lock);
> +	return 0;
> +}
> +
> +/*
> + * This function reads the current RTC time into tm in Gregorian date.
> + *
> + * @param  tm           contains the RTC time value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
> +	time_t now;
> +	int ret = mxc_rtc_lock(pdata);
> +
> +	if (ret)
> +		return ret;
> +
> +	now = readl(pdata->ioaddr + SRTC_LPSCMR);
> +	rtc_time_to_tm(now, tm);
> +	ret = rtc_valid_tm(tm);
> +	mxc_rtc_unlock(pdata);

I don't think this needs to be locked.

> +	return ret;
> +}
> +
> +/*
> + * This function sets the internal RTC time based on tm in Gregorian date.
> + *
> + * @param  tm           the time value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
> +	time64_t time = rtc_tm_to_time64(tm);
> +	int ret;
> +
> +	if (time > U32_MAX) {
> +		dev_err(dev, "RTC exceeded by %llus\n", time - U32_MAX);
> +		return -EINVAL;
> +	}
> +
> +	ret = mxc_rtc_lock(pdata);
> +	if (ret)
> +		return ret;
> +
> +	writel(time, pdata->ioaddr + SRTC_LPSCMR);
> +	mxc_rtc_sync_lp_locked(pdata->ioaddr);
> +	return mxc_rtc_unlock(pdata);
> +}
> +
> +/*
> + * This function reads the current alarm value into the passed in \b alrm
> + * argument. It updates the \b alrm's pending field value based on the whether
> + * an alarm interrupt occurs or not.
> + *
> + * @param  alrm         contains the RTC alarm value upon return
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
> +	void __iomem *ioaddr = pdata->ioaddr;
> +	int ret;
> +
> +	ret = mxc_rtc_lock(pdata);
> +	if (ret)
> +		return ret;
> +
> +	rtc_time_to_tm(readl(ioaddr + SRTC_LPSAR), &alrm->time);
> +	alrm->pending = !!(readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP);
> +	return mxc_rtc_unlock(pdata);
> +}
> +
> +/*
> + * Enable/Disable alarm interrupt
> + * The caller should hold the pdata->lock
> + */
> +static void mxc_rtc_alarm_irq_enable_locked(struct mxc_rtc_data *pdata,
> +					    unsigned int enable)
> +{
> +	u32 lp_cr = readl(pdata->ioaddr + SRTC_LPCR);
> +
> +	if (enable)
> +		lp_cr |= (SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +	else
> +		lp_cr &= ~(SRTC_LPCR_ALP | SRTC_LPCR_WAE);
> +
> +	writel(lp_cr, pdata->ioaddr + SRTC_LPCR);
> +}
> +
> +static int mxc_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
> +{
> +	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
> +	int ret = mxc_rtc_lock(pdata);
> +
> +	if (ret)
> +		return ret;
> +
> +	mxc_rtc_alarm_irq_enable_locked(pdata, enable);
> +	return mxc_rtc_unlock(pdata);
> +}
> +
> +/*
> + * This function sets the RTC alarm based on passed in alrm.
> + *
> + * @param  alrm         the alarm value to be set in the RTC
> + *
> + * @return  0 if successful; non-zero otherwise.
> + */
> +static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct mxc_rtc_data *pdata = dev_get_drvdata(dev);
> +	int ret = mxc_rtc_lock(pdata);
> +
> +	if (ret)
> +		return ret;
> +
> +	ret = mxc_rtc_write_alarm_locked(pdata, &alrm->time);

Is it worth it to make this a separate function?

> +	if (!ret) {
> +		mxc_rtc_alarm_irq_enable_locked(pdata, alrm->enabled);
> +		mxc_rtc_sync_lp_locked(pdata->ioaddr);
> +	}
> +	mxc_rtc_unlock(pdata);
> +	return ret;
> +}
> +
> +static const struct rtc_class_ops mxc_rtc_ops = {
> +	.read_time = mxc_rtc_read_time,
> +	.set_time = mxc_rtc_set_time,
> +	.read_alarm = mxc_rtc_read_alarm,
> +	.set_alarm = mxc_rtc_set_alarm,
> +	.alarm_irq_enable = mxc_rtc_alarm_irq_enable,
> +};
> +
> +static int mxc_rtc_wait_for_flag(void *__iomem ioaddr, int flag)
> +{
> +	unsigned int timeout = REG_READ_TIMEOUT;
> +
> +	while (!(readl(ioaddr) & flag)) {
> +		if (!--timeout) {
> +			pr_err("Wait timeout for 0x%x@%p!\n", flag, ioaddr);

Please use dev_* functions for printing. In this case the message should
probably be printed from the caller.

> +			return -EBUSY;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int mxc_rtc_probe(struct platform_device *pdev)
> +{
> +	struct mxc_rtc_data *pdata;
> +	struct resource *res;
> +	void __iomem *ioaddr;
> +	int ret = 0;
> +
> +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	pdata->ioaddr = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(pdata->ioaddr))
> +		return PTR_ERR(pdata->ioaddr);
> +
> +	ioaddr = pdata->ioaddr;
> +
> +	pdata->clk = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(pdata->clk)) {
> +		dev_err(&pdev->dev, "unable to get rtc clock!\n");
> +		return PTR_ERR(pdata->clk);
> +	}
> +
> +	spin_lock_init(&pdata->lock);
> +	pdata->irq = platform_get_irq(pdev, 0);
> +	if (pdata->irq < 0)
> +		return pdata->irq;
> +
> +	device_init_wakeup(&pdev->dev, 1);
> +
> +	ret = clk_prepare_enable(pdata->clk);
> +	if (ret)
> +		return ret;
> +	/* initialize glitch detect */
> +	writel(SRTC_LPPDR_INIT, ioaddr + SRTC_LPPDR);
> +
> +	/* clear lp interrupt status */
> +	writel(0xFFFFFFFF, ioaddr + SRTC_LPSR);
> +
> +	/* move out of init state */
> +	writel((SRTC_LPCR_IE | SRTC_LPCR_NSA), ioaddr + SRTC_LPCR);
> +	xc_rtc_wait_for_flag(ioaddr + SRTC_LPSR, SRTC_LPSR_IES);

If this can fail, shouldn't you test for an error?

> +
> +	/* move out of non-valid state */
> +	writel((SRTC_LPCR_IE | SRTC_LPCR_NVE | SRTC_LPCR_NSA |
> +		SRTC_LPCR_EN_LP), ioaddr + SRTC_LPCR);
> +	mxc_rtc_wait_for_flag(ioaddr + SRTC_LPSR, SRTC_LPSR_NVES);

dito

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH net-next v3 4/4] net: fec: add phy_reset_after_clk_enable() support
From: Richard Leitner @ 2017-12-06  8:12 UTC (permalink / raw)
  To: Andy Duan, Richard Leitner,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org,
	mark.rutland-5wv7dgnIgG8@public.gmane.org,
	andrew-g2DYL2Zd6BY@public.gmane.org,
	f.fainelli-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org,
	frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
  Cc: davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org,
	geert+renesas-gXvu3+zWzMSzQB+pC5nmwQ@public.gmane.org,
	sergei.shtylyov-M4DtvfQ/ZS1MRgGoP+s0PdBPR1lH4CV8@public.gmane.org,
	baruch-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org,
	david.wu-TNX95d0MmH7DzftRWevZcw@public.gmane.org,
	lukma-ynQEQJNshbs@public.gmane.org,
	netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <DB6PR0401MB2264B5060F745CEB5405FFBCFF320-2mNvjAGDOPl4towakvZX7o3W/0Ik+aLCnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>

Hi Andy,

On 12/06/2017 02:50 AM, Andy Duan wrote:
> From: Richard Leitner <dev-M/VWbR8SM2SsTnJN9+BGXg@public.gmane.org> Sent: Tuesday, December 05, 2017 9:26 PM
>> Some PHYs (for example the SMSC LAN8710/LAN8720) doesn't allow turning
>> the refclk on and off again during operation (according to their datasheet).
>> Nonetheless exactly this behaviour was introduced for power saving reasons
>> by commit e8fcfcd5684a ("net: fec: optimize the clock management to save
>> power").
>> Therefore add support for the phy_reset_after_clk_enable function from
>> phylib to mitigate this issue.

...

>> diff --git a/drivers/net/ethernet/freescale/fec_main.c
>> b/drivers/net/ethernet/freescale/fec_main.c
>> index 610573855213..8c3d0fb7db20 100644
>> --- a/drivers/net/ethernet/freescale/fec_main.c
>> +++ b/drivers/net/ethernet/freescale/fec_main.c
>> @@ -1862,6 +1862,8 @@ static int fec_enet_clk_enable(struct net_device
>> *ndev, bool enable)
>> 		ret = clk_prepare_enable(fep->clk_ref);
>> 		if (ret)
>> 			goto failed_clk_ref;
>> +
>> +		phy_reset_after_clk_enable(ndev->phydev);
>> 	} else {
>> 		clk_disable_unprepare(fep->clk_ahb);
>> 		clk_disable_unprepare(fep->clk_enet_out);
>> @@ -2860,6 +2862,11 @@ fec_enet_open(struct net_device *ndev)
>> 	if (ret)
>> 		goto err_enet_mii_probe;
>>
>> +	/* reset phy if needed here, due to the fact this is the first time we
>> +	 * have the net_device to phy_driver link
>> +	 */
>> +	phy_reset_after_clk_enable(ndev->phydev);
>> +
> 
> The patch series look better.
> But why does it need to reset phy here since phy already is hard reset after clock enable.

The problem here is that in fec_enet_open() the fec_enet_clk_enable()
call is done before the phy is probed. Therefore (as mentioned in the
comment) there's no link from the net_device (ndev) to the phy_driver
(which holds the flags).

Any suggestions for a better solution are highly appreciated here! Thanks!

regards;Richard.L
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v6 6/6] ARM: dts: imx6: RIoTboard provide standby on power off option
From: Oleksij Rempel @ 2017-12-06  7:24 UTC (permalink / raw)
  To: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Liam Girdwood,
	Mark Brown, Leonard Crestez
In-Reply-To: <20171206072402.11694-1-o.rempel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

This board, as well as some other boards with i.MX6 and a PMIC, uses a
"PMIC_STBY_REQ" line to notify the PMIC about a state change.
The PMIC is programmed for a specific state change before triggering the
line.
In this case, PMIC_STBY_REQ can be used for stand by, sleep
and power off modes.

Signed-off-by: Oleksij Rempel <o.rempel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
---
 arch/arm/boot/dts/imx6dl-riotboard.dts | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/imx6dl-riotboard.dts b/arch/arm/boot/dts/imx6dl-riotboard.dts
index 275c6c05219d..574f6b261ecd 100644
--- a/arch/arm/boot/dts/imx6dl-riotboard.dts
+++ b/arch/arm/boot/dts/imx6dl-riotboard.dts
@@ -90,6 +90,10 @@
 	status = "okay";
 };
 
+&clks {
+	fsl,pmic-stby-poweroff;
+};
+
 &fec {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_enet>;
@@ -170,6 +174,7 @@
 		reg = <0x08>;
 		interrupt-parent = <&gpio5>;
 		interrupts = <16 8>;
+		fsl,pmic-stby-poweroff;
 
 		regulators {
 			reg_vddcore: sw1ab {				/* VDDARM_IN */
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v6 5/6] regulator: pfuze100-regulator: provide pm_power_off_prepare handler
From: Oleksij Rempel @ 2017-12-06  7:24 UTC (permalink / raw)
  To: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel, devicetree, linux-arm-kernel, linux-clk,
	linux-kernel, Andrew Morton, Liam Girdwood, Mark Brown,
	Leonard Crestez
In-Reply-To: <20171206072402.11694-1-o.rempel@pengutronix.de>

On some boards the SoC can use one pin "PMIC_STBY_REQ" to notify th PMIC
about state changes. In this case internal state of PMIC must be
preconfigured for upcomming state change.
It works fine with the current regulator framework, except with the
power-off case.

This patch is providing an optional pm_power_off_prepare handler
which will configure standby state of the PMIC to disable all power lines.

In my power consumption test on RIoTBoard, I got the following results:
power off without this patch:	320 mA
power off with this patch:	2   mA
suspend to ram:			40  mA

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
---
 drivers/regulator/pfuze100-regulator.c | 92 ++++++++++++++++++++++++++++++++++
 1 file changed, 92 insertions(+)

diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index 63922a2167e5..f6c276ed91d8 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -28,6 +28,7 @@
 #include <linux/regulator/pfuze100.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
+#include <linux/kallsyms.h>
 #include <linux/regmap.h>
 
 #define PFUZE_NUMREGS		128
@@ -42,11 +43,17 @@
 
 #define PFUZE100_COINVOL	0x1a
 #define PFUZE100_SW1ABVOL	0x20
+#define PFUZE100_SW1ABMODE	0x23
 #define PFUZE100_SW1CVOL	0x2e
+#define PFUZE100_SW1CMODE	0x31
 #define PFUZE100_SW2VOL		0x35
+#define PFUZE100_SW2MODE	0x38
 #define PFUZE100_SW3AVOL	0x3c
+#define PFUZE100_SW3AMODE	0x3f
 #define PFUZE100_SW3BVOL	0x43
+#define PFUZE100_SW3BMODE	0x46
 #define PFUZE100_SW4VOL		0x4a
+#define PFUZE100_SW4MODE	0x4d
 #define PFUZE100_SWBSTCON1	0x66
 #define PFUZE100_VREFDDRCON	0x6a
 #define PFUZE100_VSNVSVOL	0x6b
@@ -57,6 +64,13 @@
 #define PFUZE100_VGEN5VOL	0x70
 #define PFUZE100_VGEN6VOL	0x71
 
+#define PFUZE100_SWxMODE_MASK	0xf
+#define PFUZE100_SWxMODE_APS_APS	0x8
+#define PFUZE100_SWxMODE_APS_OFF	0x4
+
+#define PFUZE100_VGENxLPWR	BIT(6)
+#define PFUZE100_VGENxSTBY	BIT(5)
+
 enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 };
 
 struct pfuze_regulator {
@@ -489,6 +503,69 @@ static inline struct device_node *match_of_node(int index)
 }
 #endif
 
+static struct pfuze_chip *syspm_pfuze_chip;
+
+static void pfuze_power_off_prepare(void)
+{
+	dev_info(syspm_pfuze_chip->dev, "Configure standy mode for power off");
+
+	/* Switch from default mode: APS/APS to APS/Off */
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1ABMODE,
+			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW1CMODE,
+			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW2MODE,
+			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3AMODE,
+			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW3BMODE,
+			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_SW4MODE,
+			   PFUZE100_SWxMODE_MASK, PFUZE100_SWxMODE_APS_OFF);
+
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN1VOL,
+			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+			   PFUZE100_VGENxSTBY);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN2VOL,
+			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+			   PFUZE100_VGENxSTBY);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN3VOL,
+			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+			   PFUZE100_VGENxSTBY);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN4VOL,
+			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+			   PFUZE100_VGENxSTBY);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN5VOL,
+			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+			   PFUZE100_VGENxSTBY);
+	regmap_update_bits(syspm_pfuze_chip->regmap, PFUZE100_VGEN6VOL,
+			   PFUZE100_VGENxLPWR | PFUZE100_VGENxSTBY,
+			   PFUZE100_VGENxSTBY);
+}
+
+static int pfuze_power_off_prepare_init(struct pfuze_chip *pfuze_chip)
+{
+	if (pfuze_chip->chip_id != PFUZE100) {
+		dev_warn(pfuze_chip->dev, "Requested pm_power_off_prepare handler for not supported chip\n");
+		return -ENODEV;
+	}
+
+	if (pm_power_off_prepare) {
+		dev_warn(pfuze_chip->dev, "pm_power_off_prepare is already registered.\n");
+		return -EBUSY;
+	}
+
+	if (syspm_pfuze_chip) {
+		dev_warn(pfuze_chip->dev, "syspm_pfuze_chip is already set.\n");
+		return -EBUSY;
+	}
+
+	syspm_pfuze_chip = pfuze_chip;
+	pm_power_off_prepare = pfuze_power_off_prepare;
+
+	return 0;
+}
+
 static int pfuze_identify(struct pfuze_chip *pfuze_chip)
 {
 	unsigned int value;
@@ -659,6 +736,20 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
 		}
 	}
 
+	if (of_property_read_bool(client->dev.of_node,
+				  "fsl,pmic-stby-poweroff"))
+		return pfuze_power_off_prepare_init(pfuze_chip);
+
+	return 0;
+}
+
+static int pfuze100_regulator_remove(struct i2c_client *client)
+{
+	if (syspm_pfuze_chip) {
+		syspm_pfuze_chip = NULL;
+		pm_power_off_prepare = NULL;
+	}
+
 	return 0;
 }
 
@@ -669,6 +760,7 @@ static struct i2c_driver pfuze_driver = {
 		.of_match_table = pfuze_dt_ids,
 	},
 	.probe = pfuze100_regulator_probe,
+	.remove = pfuze100_regulator_remove,
 };
 module_i2c_driver(pfuze_driver);
 
-- 
2.11.0

^ permalink raw reply related

* [PATCH v6 4/6] regulator: pfuze100: add fsl,pmic-stby-poweroff property
From: Oleksij Rempel @ 2017-12-06  7:24 UTC (permalink / raw)
  To: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Liam Girdwood,
	Mark Brown, Leonard Crestez
In-Reply-To: <20171206072402.11694-1-o.rempel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>

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

Signed-off-by: Oleksij Rempel <o.rempel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.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

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ 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: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel, devicetree, linux-arm-kernel, linux-clk,
	linux-kernel, Andrew Morton, Liam Girdwood, Mark Brown,
	Leonard Crestez
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: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel, devicetree, linux-arm-kernel, linux-clk,
	linux-kernel, Andrew Morton, Liam Girdwood, Mark Brown,
	Leonard Crestez
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: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel, devicetree, linux-arm-kernel, linux-clk,
	linux-kernel, Andrew Morton, Liam Girdwood, Mark Brown,
	Leonard Crestez
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: Linus Torvalds, Rob Herring, Mark Rutland, Michael Turquette,
	Stephen Boyd, Shawn Guo, Fabio Estevam, Russell King
  Cc: Oleksij Rempel, kernel-bIcnvbaLZ9MEGnE8C9+IrQ,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andrew Morton, Liam Girdwood,
	Mark Brown, Leonard Crestez

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

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] ARM: dts: introduce the sama5d2 ptc ek board
From: Ludovic Desroches @ 2017-12-06  7:01 UTC (permalink / raw)
  To: Baruch Siach
  Cc: Ludovic Desroches, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20171205170141.qleqh6rou2ow54je-Gk1+JqxT0KghR1HGirfZ1z4kX+cae0hd@public.gmane.org>

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-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
> > ---
> 
> [...]
> 
> > +	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-NswTu9S1W3P6gbPvEgmw2w@public.gmane.org - tel: +972.52.368.4656, http://www.tkos.co.il -
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ 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: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: nicolas.ferre-UWL1GkI3JZL3oGB3hsPCZA,
	alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Ludovic Desroches

Add the official SAMA5D2 Peripheral Touch Controller Evaluation
Kit board.

Signed-off-by: Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
---

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-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
+ *		  2017 Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
+ *
+ * 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@300000 {
+			atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usba_vbus>;
+			status = "okay";
+		};
+
+		usb1: ohci@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@500000 {
+			status = "okay";
+		};
+
+		ebi: ebi@10000000 {
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_nand_default>;
+			status = "okay"; /* conflicts with sdmmc1 and qspi0 */
+
+			nand_controller: nand-controller {
+				status = "okay";
+
+				nand@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@0 {
+							label = "bootstrap";
+							reg = <0x0 0x40000>;
+						};
+
+						bootloader@40000 {
+							label = "bootloader";
+							reg = <0x40000 0xc0000>;
+						};
+
+						bootloaderenv@0x100000 {
+							label = "bootloader env";
+							reg = <0x100000 0x40000>;
+						};
+
+						bootloaderenvred@0x140000 {
+							label = "bootloader env redundant";
+							reg = <0x140000 0x40000>;
+						};
+
+						dtb@180000 {
+							label = "device tree";
+							reg = <0x180000 0x80000>;
+						};
+
+						kernel@200000 {
+							label = "kernel";
+							reg = <0x200000 0x600000>;
+						};
+
+						rootfs@800000 {
+							label = "rootfs";
+							reg = <0x800000 0x1f800000>;
+						};
+					};
+				};
+			};
+		};
+
+		sdmmc0: sdio-host@a0000000 {
+			bus-width = <8>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_sdmmc0_default>;
+			non-removable;
+			mmc-ddr-1_8v;
+			status = "okay";
+		};
+
+		apb {
+			spi0: spi@f8000000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_spi0_default>;
+				status = "okay";
+			};
+
+			macb0: ethernet@f8008000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_macb0_default &pinctrl_macb0_phy_irq>;
+				phy-mode = "rmii";
+				status = "okay";
+
+				ethernet-phy@1 {
+					reg = <0x1>;
+					interrupt-parent = <&pioA>;
+					interrupts = <56 IRQ_TYPE_LEVEL_LOW>;
+				};
+			};
+
+			uart0: serial@f801c000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_uart0_default>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "okay";
+			};
+
+			uart2: serial@f8024000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_uart2_default>;
+				atmel,use-dma-rx;
+				atmel,use-dma-tx;
+				status = "okay";
+			};
+
+			i2c0: i2c@f8028000 {
+				dmas = <0>, <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_i2c0_default>;
+				status = "okay";
+			};
+
+			flx0: flexcom@f8034000 {
+				atmel,flexcom-mode = <ATMEL_FLEXCOM_MODE_TWI>;
+				status = "okay";
+
+				i2c2: i2c@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@f8048010 {
+				atmel,shdwc-debouncer = <976>;
+
+				input@0 {
+					reg = <0>;
+					atmel,wakeup-type = "low";
+				};
+			};
+
+			watchdog@f8048040 {
+				status = "okay";
+			};
+
+			spi1: spi@fc000000 {
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_spi1_default>;
+				status = "okay";
+			};
+
+			i2c1: i2c@fc028000 {
+				dmas = <0>, <0>;
+				pinctrl-names = "default";
+				pinctrl-0 = <&pinctrl_i2c1_default>;
+				status = "okay";
+
+				at24@50 {
+					compatible = "24c02";
+					reg = <0x50>;
+					pagesize = <8>;
+				};
+			};
+
+			pinctrl@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

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [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: Jean-Philippe Brucker, linux-arm-kernel, linux-pci, linux-acpi,
	devicetree, iommu
  Cc: joro, robh+dt, mark.rutland, catalin.marinas, will.deacon,
	lorenzo.pieralisi, hanjun.guo, sudeep.holla, rjw, lenb,
	robin.murphy, bhelgaas, alex.williamson, tn, liubo95,
	thunder.leizhen, gabriele.paoloni, nwatters, okaya, rfranz, dwmw2,
	jacob.jun.pan, yi.l.liu, ashok.raj, robdclark
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: Mathias Nyman
  Cc: Greg Kroah-Hartman, Matthias Brugger, Felipe Balbi, Chunfeng Yun,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-usb-u79uwXL29TY76Z2rM5mHXA,
	linux-mediatek-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA

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-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
---
 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

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [PATCH 0/4] add support of pinctrl to MT7622 SoC
From: biao huang @ 2017-12-06  6:19 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Maoguang Meng, Hongzhou Yang, sean.wang-NuS5LvNUpcJWk0Htik3J/w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-gpio-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
	moderated list:ARM/Mediatek SoC support, Matthias Brugger, Joe.C,
	Linux ARM
In-Reply-To: <CACRpkdaL5W5r_4PoYwVK6mcO583Cep5t-ePWqccKx2YDz9=iyA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Fri, 2017-12-01 at 20:50 +0100, Linus Walleij wrote:
> On Tue, Nov 28, 2017 at 4:49 AM,  <sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org> wrote:
> 
> > From: Sean Wang <sean.wang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> >
> > 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-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
Biao

^ permalink raw reply

* Re: [PATCH 5/8] ASoC: uniphier: add support for UniPhier AIO driver
From: Katsuhiro Suzuki @ 2017-12-06  6:03 UTC (permalink / raw)
  To: 'Mark Brown',
	Suzuki, Katsuhiro/鈴木 勝博
  Cc: alsa-devel, Rob Herring, devicetree,
	Yamada, Masahiro/山田 真弘,
	Masami Hiramatsu, Jassi Brar, linux-arm-kernel, linux-kernel
In-Reply-To: <20171205121440.GC11658@finisterre>

Hello,

> -----Original Message-----
> From: Mark Brown [mailto:broonie@kernel.org]
> Sent: Tuesday, December 5, 2017 9:15 PM
> To: Suzuki, Katsuhiro/鈴木 勝博 <suzuki.katsuhiro@socionext.com>
> Cc: alsa-devel@alsa-project.org; Rob Herring <robh+dt@kernel.org>;
> devicetree@vger.kernel.org; Yamada, Masahiro/山田 真弘
> <yamada.masahiro@socionext.com>; Masami Hiramatsu
> <masami.hiramatsu@linaro.org>; Jassi Brar <jaswinder.singh@linaro.org>;
> linux-arm-kernel@lists.infradead.org; linux-kernel@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@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

* Re: [PATCH v11 0/6] Add support for Qualcomm A53 CPU clock
From: Amit Kucheria @ 2017-12-06  5:51 UTC (permalink / raw)
  To: Georgi Djakov
  Cc: Stephen Boyd, jassisinghbrar-Re5JQEeQqe8AvxtiuMwx3w,
	bjorn.andersson-QSEj5FYQhm4dnm+yROfE0A, Michael Turquette,
	Rob Herring, linux-clk-u79uwXL29TY76Z2rM5mHXA, LKML,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20171205154701.27730-1-georgi.djakov-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

On Tue, Dec 5, 2017 at 9:16 PM, Georgi Djakov <georgi.djakov-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
> This patchset adds support for the A53 CPU clock on MSM8916 platforms
> and allows scaling of the CPU frequency on msm8916 based platforms.

Though it currently needs some additional patches (that'll follow
soon), FWIW, Tested-by: Amit Kucheria <amit.kucheria-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

> Changes since v10 (https://lkml.org/lkml/2017/12/1/577)
> * Addressed Bjorn's comments on APCS clock driver.
> * Picked Acks from Rob and Bjorn.
>
> Changes since v9 (https://lkml.org/lkml/2017/9/21/511)
> * Added the clock properties to the APCS DT node, instead of adding a subnode
> and also replaced patch "mailbox: qcom: Populate APCS child platform devices"
> with "mailbox: qcom: Create APCS child device for clock controller".
> * Dropped patch "mailbox: qcom: Move the apcs struct into a separate header",
> and use dev_get_regmap(dev->parent) in the child driver.
> * Addressed Bjorn's comments on a53-pll and apcs-clk drivers.
> * Added SPDX copyright identifiers.
>
> Changes since v8 (https://lkml.org/lkml/2017/6/23/476)
>  * Converted APCS mailbox driver to use regmap and to populate child
>  platform devices that will handle the rest of the functionality
>  provided by APCS block.
>  * Picked Rob's Ack for the PLL binding.
>  * Changed the APCS binding and put it into a separate patch.
>  * Addressed review comments.
>  * Minor changes.
>
> Changes since v7 (https://lkml.org/lkml/2016/10/31/296)
>  * Add the APCS clock controller to the APCS driver to expose both the
>  mailbox and clock controller functionality as discussed earlier:
>  https://lkml.org/lkml/2016/11/14/860
>  * Changed the a53pll compatible string as suggested by Rob.
>
> Changes since v6 (https://lkml.org/lkml/2016/9/7/347)
>  * Addressed various comments from Stephen Boyd
>
> Changes since v5 (https://lkml.org/lkml/2016/2/1/407)
>  * Rebase to clk-next and update according to the recent API changes.
>
> Changes since v4 (https://lkml.org/lkml/2015/12/14/367)
>  * Convert to builtin drivers as now __clk_lookup() is used
>
> Changes since v3 (https://lkml.org/lkml/2015/8/12/585)
>  * Split driver into two parts - and separate A53 PLL and
>    A53 clock controller drivers.
>  * Drop the safe switch hook patch. Add a clock notifier in
>    the clock provider to handle switching via safe mux and
>    divider configuration.
>
> Changes since v2 (https://lkml.org/lkml/2015/7/24/526)
>  * Drop gpll0_vote patch.
>  * Switch to the new clk_hw_* APIs.
>  * Rebase to the current clk-next.
>
> Changes since v1 (https://lkml.org/lkml/2015/6/12/193)
>  * Drop SR2 PLL patch, as it is already applied.
>  * Add gpll0_vote rate propagation patch.
>  * Update/rebase patches to the current clk-next.
>
> Georgi Djakov (6):
>   mailbox: qcom: Convert APCS IPC driver to use regmap
>   mailbox: qcom: Create APCS child device for clock controller
>   clk: qcom: Add A53 PLL support
>   clk: qcom: Add regmap mux-div clocks support
>   dt-bindings: mailbox: qcom: Document the APCS clock binding
>   clk: qcom: Add APCS clock controller support
>
>  .../devicetree/bindings/clock/qcom,a53pll.txt      |  22 ++
>  .../bindings/mailbox/qcom,apcs-kpss-global.txt     |  18 ++
>  drivers/clk/qcom/Kconfig                           |  21 ++
>  drivers/clk/qcom/Makefile                          |   3 +
>  drivers/clk/qcom/a53-pll.c                         | 110 ++++++++++
>  drivers/clk/qcom/apcs-msm8916.c                    | 149 ++++++++++++++
>  drivers/clk/qcom/clk-regmap-mux-div.c              | 229 +++++++++++++++++++++
>  drivers/clk/qcom/clk-regmap-mux-div.h              |  46 +++++
>  drivers/mailbox/qcom-apcs-ipc-mailbox.c            |  35 +++-
>  9 files changed, 628 insertions(+), 5 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/qcom,a53pll.txt
>  create mode 100644 drivers/clk/qcom/a53-pll.c
>  create mode 100644 drivers/clk/qcom/apcs-msm8916.c
>  create mode 100644 drivers/clk/qcom/clk-regmap-mux-div.c
>  create mode 100644 drivers/clk/qcom/clk-regmap-mux-div.h
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v6 2/2] media: i2c: Add the ov7740 image sensor driver
From: Yang, Wenyou @ 2017-12-06  5:38 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Mauro Carvalho Chehab, Rob Herring, Mark Rutland,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Nicolas Ferre,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Jonathan Corbet, Hans Verkuil,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Linux Media Mailing List, Songjun Wu
In-Reply-To: <20171205104549.aoturlmm3s6net37-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>

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-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
>> Signed-off-by: Wenyou Yang <wenyou.yang-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
>> ---
>>
>> 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-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
>> +L:	linux-media-u79uwXL29TY76Z2rM5mHXA@public.gmane.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-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
>>   L:	linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.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-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>");
>> +MODULE_LICENSE("GPL v2");
>> -- 
>> 2.15.0
>>
Best Regards,
Wenyou Yang
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ 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