* Re: [PATCH RESEND 2/2] gpio: axp209: add pinctrl support
From: Linus Walleij @ 2016-12-02 12:30 UTC (permalink / raw)
To: Quentin Schulz
Cc: Alexandre Courbot, Rob Herring, Mark Rutland, Chen-Yu Tsai,
Maxime Ripard, linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
In-Reply-To: <f46c89f2-478b-93b8-5a66-12d1307d4514-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
On Tue, Nov 29, 2016 at 11:13 PM, Quentin Schulz
<quentin.schulz-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org> wrote:
> So basically:
>
> - first patch for adding pinctrl to the existing driver
> - second patch for moving the driver and binding from gpio to pinctrl
> subsystem
> - third patch for both removing Kconfig entry and Makefile rule from
> gpio subsystem, and adding a Kconfig entry and a Makefile rule in
> pinctrl subsystem
>
> Is that what you want?
No.
Make the patch moving it to pinctrl first. This will be the same as
the patch augmenting Kcongfig and Makefile or it will not compile.
Then a second patch to add the pinctrl features.
Yours,
Linus Walleij
--
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: [resend v2: PATCH 1/2] dt-bindings: Document the hi3660 reset bindings
From: Arnd Bergmann @ 2016-12-02 12:32 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: zhangfei, Philipp Zabel, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <e15e76e2-b32d-a4d0-eb8b-850626a3946a-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On Friday, December 2, 2016 8:21:33 AM CET zhangfei wrote:
> Hi, Arnd
>
> On 2016年12月01日 20:05, Arnd Bergmann wrote:
> > On Thursday, December 1, 2016 8:48:40 AM CET Zhangfei Gao wrote:
> >> + hisi,reset-bits = <0x20 0x8 /* 0: i2c0 */
> >> + 0x20 0x10 /* 1: i2c1 */
> >> + 0x20 0x20 /* 2: i2c2 */
> >> + 0x20 0x8000000>; /* 3: i2c6 */
> >> + };
> >> +
> >> +Specifying reset lines connected to IP modules
> >> +==============================================
> >> +example:
> >> +
> >> + i2c0: i2c@..... {
> >> + ...
> >> + resets = <&iomcu_rst 0>;
> >> + ...
> >> + };
> > I don't really like this approach, since now the information is
> > in two places. Why not put the data into the reset specifier
> > directly when it is used?
> Any example, still not understand.
> They are consumer and provider.
I mean in the i2c node, have
i2c0: i2c@..... {
...
resets = <&iomcu_rst 0x20 0x8>;
...
}
> > Also the format seems a little too close to the actual register
> > layout and could be a little more abstract, using bit numbers instead
> > of a bitmask and register numbers instead of offsets.
> We use bit numbers first.
> But in the developing process, we found several bits may be required for
> one driver.
> And they may not be continuous as the bits may already be occupied.
> Directly using offset, we can set several bits together for simple, to
> give more flexibility.
> So after discussion, we directly use offset.
Can you give an example for why this is needed? Is this different
from a device that has multiple reset lines?
Arnd
--
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 1/5] pinctrl: core: Use delayed work for hogs
From: Linus Walleij @ 2016-12-02 13:08 UTC (permalink / raw)
To: Tony Lindgren
Cc: Haojian Zhuang, Masahiro Yamada, Grygorii Strashko,
Nishanth Menon, linux-gpio@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
Linux-OMAP
In-Reply-To: <20161115170838.GK4082@atomide.com>
On Tue, Nov 15, 2016 at 6:08 PM, Tony Lindgren <tony@atomide.com> wrote:
> * Tony Lindgren <tony@atomide.com> [161115 07:42]:
>> * Linus Walleij <linus.walleij@linaro.org> [161114 22:53]:
>> > On Tue, Nov 15, 2016 at 1:47 AM, Tony Lindgren <tony@atomide.com> wrote:
>> >
>> > > 8< --------------------------------
>> > > From tony Mon Sep 17 00:00:00 2001
>> > > From: Tony Lindgren <tony@atomide.com>
>> > > Date: Tue, 25 Oct 2016 08:33:35 -0700
>> > > Subject: [PATCH] pinctrl: core: Use delayed work for hogs
>> > >
>> > > Having the pin control framework call pin controller functions
>> > > before it's probe has finished is not nice as the pin controller
>> > > device driver does not yet have struct pinctrl_dev handle.
>> > >
>> > > Let's fix this issue by adding deferred work for late init. This is
>> > > needed to be able to add pinctrl generic helper functions that expect
>> > > to know struct pinctrl_dev handle. Note that we now need to call
>> > > create_pinctrl() directly as we don't want to add the pin controller
>> > > to the list of controllers until the hogs are claimed. We also need
>> > > to pass the pinctrl_dev to the device tree parser functions as they
>> > > otherwise won't find the right controller at this point.
>> > >
>> > > Signed-off-by: Tony Lindgren <tony@atomide.com>
>> >
>> > This looks a lot better!
>> >
>> > So if I understand correctly, we can guarantee that the delayed
>> > work will not execute until the device driver probe() has finished,
>> > and it *will* execute immediately after that?
>> >
>> > So:
>> > - Device driver probes
>> > - Delayed work is called
>> > - Next initcall
>> >
>> > I'm not 100% familiar with how delayed work works... :/
>>
>> Yeah well the delayed work gets scheduled for next jiffy but may
>> be pre-empted as it runs in process context.
>>
>> So in the worst case it could that we still may need to fix few
>> drivers to support -EPROBE_DEFER. I wonder if we should check for
>> hogs in probe already and only defer if hogs are defined?
>
> Below is a version using delayed_work only if pinctrl_dt_has_hogs().
>
> Not sure if testing only for pinctrl-0 is enough there though?
Sorry for the lack of attention to this patch set on my part. :(
Do you think you could resend these last 5 patches after the
release of v4.10-rc1 so we merge it early for the next cycle
and people get a chance to test and see if it works well for
everyone?
I'm worried about adding it to the tree this late in the kernel
cycle...
However I like the look of the series overall a lot.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH v3 7/7] ARM: dts: stm32: add stm32 general purpose timer driver in DT
From: Lee Jones @ 2016-12-02 13:22 UTC (permalink / raw)
To: Benjamin Gaignard
Cc: robh+dt, mark.rutland, alexandre.torgue, devicetree, linux-kernel,
thierry.reding, linux-pwm, jic23, knaack.h, lars, pmeerw,
linux-iio, linux-arm-kernel, fabrice.gasnier, gerald.baeza,
arnaud.pouliquen, linus.walleij, linaro-kernel, Benjamin Gaignard
In-Reply-To: <1480673842-20804-8-git-send-email-benjamin.gaignard@st.com>
On Fri, 02 Dec 2016, Benjamin Gaignard wrote:
> Add general purpose timers and it sub-nodes into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
>
> version 3:
> - use "st,stm32-timer-trigger" in DT
>
> version 2:
> - use parameters to describe hardware capabilities
> - do not use references for pwm and iio timer subnodes
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
> ---
> arch/arm/boot/dts/stm32f429.dtsi | 333 +++++++++++++++++++++++++++++++++-
> arch/arm/boot/dts/stm32f469-disco.dts | 28 +++
> 2 files changed, 360 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..8c50d03 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -48,7 +48,7 @@
> #include "skeleton.dtsi"
> #include "armv7-m.dtsi"
> #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> -
> +#include <dt-bindings/iio/timer/st,stm32-timer-triggers.h>
> / {
> clocks {
> clk_hse: clk-hse {
> @@ -355,6 +355,21 @@
> slew-rate = <2>;
> };
> };
> +
> + pwm1_pins: pwm@1 {
> + pins {
> + pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> + <STM32F429_PB13_FUNC_TIM1_CH1N>,
> + <STM32F429_PB12_FUNC_TIM1_BKIN>;
> + };
> + };
> +
> + pwm3_pins: pwm@3 {
> + pins {
> + pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> + <STM32F429_PB5_FUNC_TIM3_CH2>;
> + };
> + };
> };
>
> rcc: rcc@40023810 {
> @@ -426,6 +441,322 @@
> interrupts = <80>;
> clocks = <&rcc 0 38>;
> };
> +
> + gptimer1: gptimer1@40010000 {
timer@xxxxxxx
Node names should be generic and not numbered.
I suggest that this isn't actually a timer either. Is contains a
timer (and a PWM), but in it's completeness it is not a timer per
say.
> + compatible = "st,stm32-gptimer";
> + reg = <0x40010000 0x400>;
> + clocks = <&rcc 0 160>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm1@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,breakinput;
> + st,complementary;
> + status = "disabled";
> + };
> +
> + timer1@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <27>;
> + st,input-triggers-names = TIM5_TRGO,
> + TIM2_TRGO,
> + TIM4_TRGO,
> + TIM3_TRGO;
I'm still dubious with matching by strings.
I'll take a look at the C code to see what the alternatives could be.
> + st,output-triggers-names = TIM1_TRGO,
> + TIM1_CH1,
> + TIM1_CH2,
> + TIM1_CH3,
> + TIM1_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer2: gptimer2@40000000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000000 0x400>;
> + clocks = <&rcc 0 128>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm2@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,32bits-counter;
> + status = "disabled";
> + };
> +
> + timer2@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <28>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM8_TRGO,
> + TIM3_TRGO,
> + TIM4_TRGO;
> + st,output-triggers-names = TIM2_TRGO,
> + TIM2_CH1,
> + TIM2_CH2,
> + TIM2_CH3,
> + TIM2_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer3: gptimer3@40000400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000400 0x400>;
> + clocks = <&rcc 0 129>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm3@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + status = "disabled";
> + };
> +
> + timer3@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <29>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM8_TRGO,
> + TIM5_TRGO,
> + TIM4_TRGO;
> + st,output-triggers-names = TIM3_TRGO,
> + TIM3_CH1,
> + TIM3_CH2,
> + TIM3_CH3,
> + TIM3_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer4: gptimer4@40000800 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000800 0x400>;
> + clocks = <&rcc 0 130>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm4@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + status = "disabled";
> + };
> +
> + timer4@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <30>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM2_TRGO,
> + TIM3_TRGO,
> + TIM8_TRGO;
> + st,output-triggers-names = TIM4_TRGO,
> + TIM4_CH1,
> + TIM4_CH2,
> + TIM4_CH3,
> + TIM4_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer5: gptimer5@40000C00 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000C00 0x400>;
> + clocks = <&rcc 0 131>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm5@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,32bits-counter;
> + status = "disabled";
> + };
> +
> + timer5@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <50>;
> + st,input-triggers-names = TIM2_TRGO,
> + TIM3_TRGO,
> + TIM4_TRGO,
> + TIM8_TRGO;
> + st,output-triggers-names = TIM5_TRGO,
> + TIM5_CH1,
> + TIM5_CH2,
> + TIM5_CH3,
> + TIM5_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer6: gptimer6@40001000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001000 0x400>;
> + clocks = <&rcc 0 132>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + timer6@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <54>;
> + st,output-triggers-names = TIM6_TRGO;
> + status = "disabled";
> + };
> + };
> +
> + gptimer7: gptimer7@40001400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001400 0x400>;
> + clocks = <&rcc 0 133>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + timer7@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <55>;
> + st,output-triggers-names = TIM7_TRGO;
> + status = "disabled";
> + };
> + };
> +
> + gptimer8: gptimer8@40010400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40010400 0x400>;
> + clocks = <&rcc 0 161>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm8@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,complementary;
> + st,breakinput;
> + status = "disabled";
> + };
> +
> + timer8@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <46>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM2_TRGO,
> + TIM4_TRGO,
> + TIM5_TRGO;
> + st,output-triggers-names = TIM8_TRGO,
> + TIM8_CH1,
> + TIM8_CH2,
> + TIM8_CH3,
> + TIM8_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer9: gptimer9@40014000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40014000 0x400>;
> + clocks = <&rcc 0 176>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm9@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <2>;
> + status = "disabled";
> + };
> +
> + timer9@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <24>;
> + st,input-triggers-names = TIM2_TRGO,
> + TIM3_TRGO;
> + st,output-triggers-names = TIM9_TRGO,
> + TIM9_CH1,
> + TIM9_CH2;
> + status = "disabled";
> + };
> + };
> +
> + gptimer10: gptimer10@40014400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40014400 0x400>;
> + clocks = <&rcc 0 177>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm10@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> +
> + gptimer11: gptimer11@40014800 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40014800 0x400>;
> + clocks = <&rcc 0 178>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm11@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> +
> + gptimer12: gptimer12@40001800 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001800 0x400>;
> + clocks = <&rcc 0 134>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm12@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <2>;
> + status = "disabled";
> + };
> +
> + timer12@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <43>;
> + st,input-triggers-names = TIM4_TRGO,
> + TIM5_TRGO;
> + st,output-triggers-names = TIM12_TRGO,
> + TIM12_CH1,
> + TIM12_CH2;
> + status = "disabled";
> + };
> + };
> +
> + gptimer13: gptimer13@40001C00 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001C00 0x400>;
> + clocks = <&rcc 0 135>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm13@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> +
> + gptimer14: gptimer14@40002000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40002000 0x400>;
> + clocks = <&rcc 0 136>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm14@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> };
> };
>
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..df4ca7e 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,31 @@
> &usart3 {
> status = "okay";
> };
> +
> +&gptimer1 {
> + status = "okay";
> +
> + pwm1@0 {
> + pinctrl-0 = <&pwm1_pins>;
> + pinctrl-names = "default";
> + status = "okay";
> + };
> +
> + timer1@0 {
> + status = "okay";
> + };
> +};
This is a much *better* format than before.
I still don't like the '&' syntax though.
> +&gptimer3 {
> + status = "okay";
> +
> + pwm3@0 {
> + pinctrl-0 = <&pwm3_pins>;
> + pinctrl-names = "default";
> + status = "okay";
> + };
> +
> + timer3@0 {
> + status = "okay";
> + };
> +};
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* Re: [PATCH] ARM: omap3: beagleboard-xm: dt: Add ethernet to the device tree
From: Laurent Pinchart @ 2016-12-02 13:38 UTC (permalink / raw)
To: Tony Lindgren
Cc: linux-omap-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, Benoît Cousson
In-Reply-To: <20161202011807.GF3703-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
Hi Tony,
On Thursday 01 Dec 2016 17:18:08 Tony Lindgren wrote:
> * Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org> [161130 09:58]:
> > &usbhsehci {
> >
> > phys = <0 &hsusb2_phy>;
> >
> > +
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + usb2@2 {
>
> I think this should be usb1@2 instead of usb2@2? That's because it's
> at /sys/bus/usb/devices/1-2 and not at /sys/bus/usb/devices/2-2?
>
> Or what's the naming standard here?
Good question. As far as I know, the node name is irrelevant, only the reg
value is important. Maybe we should call it hub@2 ?
--
Regards,
Laurent Pinchart
--
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 v3 7/7] ARM: dts: stm32: add stm32 general purpose timer driver in DT
From: Alexandre Torgue @ 2016-12-02 13:41 UTC (permalink / raw)
To: Benjamin Gaignard, lee.jones-QSEj5FYQhm4dnm+yROfE0A,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
arnaud.pouliquen-qxv4g6HH51o,
linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard
In-Reply-To: <1480673842-20804-8-git-send-email-benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
Hi Benjamin,
On 12/02/2016 11:17 AM, Benjamin Gaignard wrote:
> Add general purpose timers and it sub-nodes into DT for stm32f4.
> Define and enable pwm1 and pwm3 for stm32f469 discovery board
>
> version 3:
> - use "st,stm32-timer-trigger" in DT
>
> version 2:
> - use parameters to describe hardware capabilities
> - do not use references for pwm and iio timer subnodes
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
> ---
> arch/arm/boot/dts/stm32f429.dtsi | 333 +++++++++++++++++++++++++++++++++-
> arch/arm/boot/dts/stm32f469-disco.dts | 28 +++
> 2 files changed, 360 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> index bca491d..8c50d03 100644
> --- a/arch/arm/boot/dts/stm32f429.dtsi
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -48,7 +48,7 @@
> #include "skeleton.dtsi"
> #include "armv7-m.dtsi"
> #include <dt-bindings/pinctrl/stm32f429-pinfunc.h>
> -
> +#include <dt-bindings/iio/timer/st,stm32-timer-triggers.h>
> / {
> clocks {
> clk_hse: clk-hse {
> @@ -355,6 +355,21 @@
> slew-rate = <2>;
> };
> };
> +
> + pwm1_pins: pwm@1 {
> + pins {
> + pinmux = <STM32F429_PA8_FUNC_TIM1_CH1>,
> + <STM32F429_PB13_FUNC_TIM1_CH1N>,
> + <STM32F429_PB12_FUNC_TIM1_BKIN>;
> + };
> + };
> +
> + pwm3_pins: pwm@3 {
> + pins {
> + pinmux = <STM32F429_PB4_FUNC_TIM3_CH1>,
> + <STM32F429_PB5_FUNC_TIM3_CH2>;
> + };
> + };
> };
>
> rcc: rcc@40023810 {
> @@ -426,6 +441,322 @@
> interrupts = <80>;
> clocks = <&rcc 0 38>;
> };
> +
> + gptimer1: gptimer1@40010000 {
Currently, nodes are ordered following base address.
> + compatible = "st,stm32-gptimer";
> + reg = <0x40010000 0x400>;
> + clocks = <&rcc 0 160>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm1@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,breakinput;
> + st,complementary;
> + status = "disabled";
> + };
> +
> + timer1@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <27>;
> + st,input-triggers-names = TIM5_TRGO,
> + TIM2_TRGO,
> + TIM4_TRGO,
> + TIM3_TRGO;
> + st,output-triggers-names = TIM1_TRGO,
> + TIM1_CH1,
> + TIM1_CH2,
> + TIM1_CH3,
> + TIM1_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer2: gptimer2@40000000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000000 0x400>;
> + clocks = <&rcc 0 128>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm2@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,32bits-counter;
> + status = "disabled";
> + };
> +
> + timer2@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <28>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM8_TRGO,
> + TIM3_TRGO,
> + TIM4_TRGO;
> + st,output-triggers-names = TIM2_TRGO,
> + TIM2_CH1,
> + TIM2_CH2,
> + TIM2_CH3,
> + TIM2_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer3: gptimer3@40000400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000400 0x400>;
> + clocks = <&rcc 0 129>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm3@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + status = "disabled";
> + };
> +
> + timer3@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <29>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM8_TRGO,
> + TIM5_TRGO,
> + TIM4_TRGO;
> + st,output-triggers-names = TIM3_TRGO,
> + TIM3_CH1,
> + TIM3_CH2,
> + TIM3_CH3,
> + TIM3_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer4: gptimer4@40000800 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000800 0x400>;
> + clocks = <&rcc 0 130>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm4@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + status = "disabled";
> + };
> +
> + timer4@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <30>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM2_TRGO,
> + TIM3_TRGO,
> + TIM8_TRGO;
> + st,output-triggers-names = TIM4_TRGO,
> + TIM4_CH1,
> + TIM4_CH2,
> + TIM4_CH3,
> + TIM4_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer5: gptimer5@40000C00 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40000C00 0x400>;
> + clocks = <&rcc 0 131>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm5@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,32bits-counter;
> + status = "disabled";
> + };
> +
> + timer5@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <50>;
> + st,input-triggers-names = TIM2_TRGO,
> + TIM3_TRGO,
> + TIM4_TRGO,
> + TIM8_TRGO;
> + st,output-triggers-names = TIM5_TRGO,
> + TIM5_CH1,
> + TIM5_CH2,
> + TIM5_CH3,
> + TIM5_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer6: gptimer6@40001000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001000 0x400>;
> + clocks = <&rcc 0 132>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + timer6@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <54>;
> + st,output-triggers-names = TIM6_TRGO;
> + status = "disabled";
> + };
> + };
> +
> + gptimer7: gptimer7@40001400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001400 0x400>;
> + clocks = <&rcc 0 133>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + timer7@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <55>;
> + st,output-triggers-names = TIM7_TRGO;
> + status = "disabled";
> + };
> + };
> +
> + gptimer8: gptimer8@40010400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40010400 0x400>;
> + clocks = <&rcc 0 161>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm8@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <4>;
> + st,complementary;
> + st,breakinput;
> + status = "disabled";
> + };
> +
> + timer8@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <46>;
> + st,input-triggers-names = TIM1_TRGO,
> + TIM2_TRGO,
> + TIM4_TRGO,
> + TIM5_TRGO;
> + st,output-triggers-names = TIM8_TRGO,
> + TIM8_CH1,
> + TIM8_CH2,
> + TIM8_CH3,
> + TIM8_CH4;
> + status = "disabled";
> + };
> + };
> +
> + gptimer9: gptimer9@40014000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40014000 0x400>;
> + clocks = <&rcc 0 176>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm9@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <2>;
> + status = "disabled";
> + };
> +
> + timer9@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <24>;
> + st,input-triggers-names = TIM2_TRGO,
> + TIM3_TRGO;
> + st,output-triggers-names = TIM9_TRGO,
> + TIM9_CH1,
> + TIM9_CH2;
> + status = "disabled";
> + };
> + };
> +
> + gptimer10: gptimer10@40014400 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40014400 0x400>;
> + clocks = <&rcc 0 177>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm10@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> +
> + gptimer11: gptimer11@40014800 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40014800 0x400>;
> + clocks = <&rcc 0 178>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm11@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> +
> + gptimer12: gptimer12@40001800 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001800 0x400>;
> + clocks = <&rcc 0 134>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm12@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <2>;
> + status = "disabled";
> + };
> +
> + timer12@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <43>;
> + st,input-triggers-names = TIM4_TRGO,
> + TIM5_TRGO;
> + st,output-triggers-names = TIM12_TRGO,
> + TIM12_CH1,
> + TIM12_CH2;
> + status = "disabled";
> + };
> + };
> +
> + gptimer13: gptimer13@40001C00 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40001C00 0x400>;
> + clocks = <&rcc 0 135>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm13@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> +
> + gptimer14: gptimer14@40002000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40002000 0x400>;
> + clocks = <&rcc 0 136>;
> + clock-names = "clk_int";
> + status = "disabled";
> +
> + pwm14@0 {
> + compatible = "st,stm32-pwm";
> + st,pwm-num-chan = <1>;
> + status = "disabled";
> + };
> + };
> };
> };
>
> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts b/arch/arm/boot/dts/stm32f469-disco.dts
> index 8a163d7..df4ca7e 100644
> --- a/arch/arm/boot/dts/stm32f469-disco.dts
> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
> @@ -81,3 +81,31 @@
> &usart3 {
> status = "okay";
> };
> +
> +&gptimer1 {
> + status = "okay";
> +
> + pwm1@0 {
> + pinctrl-0 = <&pwm1_pins>;
> + pinctrl-names = "default";
> + status = "okay";
> + };
> +
> + timer1@0 {
> + status = "okay";
> + };
> +};
> +
> +&gptimer3 {
> + status = "okay";
> +
> + pwm3@0 {
> + pinctrl-0 = <&pwm3_pins>;
> + pinctrl-names = "default";
> + status = "okay";
> + };
> +
> + timer3@0 {
> + status = "okay";
> + };
> +};
>
^ permalink raw reply
* [RESEND PATCH v2 0/7] drm/vc4: VEC (SDTV) output support
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter, dri-devel
Cc: Mark Rutland, devicetree, Ian Campbell, Florian Fainelli,
Pawel Moll, Scott Branden, Stephen Warren, Ray Jui, Lee Jones,
Rob Herring, bcm-kernel-feedback-list, linux-rpi-kernel,
Kumar Gala, linux-arm-kernel
Sorry for the noise, but I forgot to Cc the DT maintainers.
Here is the 2nd version of the VC4/VEC series.
We still miss the two clock patches mentioned by Eric in the first
version to make the encoder work no matter the setting applied by the
bootloader.
Regards,
Boris
Boris Brezillon (7):
drm/vc4: Fix ->clock_select setting for the VEC encoder
drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
drm: Add TV connector states to drm_connector_state
drm/vc4: Add support for the VEC (Video Encoder) IP
drm/vc4: Document VEC DT binding
ARM: bcm/dt: Add VEC node in bcm283x.dtsi
ARM: bcm/dt: Enable the VEC IP on all RaspeberryPi boards
.../devicetree/bindings/display/brcm,bcm-vc4.txt | 14 +
arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +
arch/arm/boot/dts/bcm283x.dtsi | 8 +
drivers/gpu/drm/drm_atomic.c | 50 ++
drivers/gpu/drm/vc4/Makefile | 1 +
drivers/gpu/drm/vc4/vc4_crtc.c | 38 +-
drivers/gpu/drm/vc4/vc4_debugfs.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.h | 6 +
drivers/gpu/drm/vc4/vc4_regs.h | 3 +-
drivers/gpu/drm/vc4/vc4_vec.c | 657 +++++++++++++++++++++
include/drm/drm_connector.h | 32 +
include/uapi/drm/drm_mode.h | 18 +-
13 files changed, 810 insertions(+), 24 deletions(-)
create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c
--
2.7.4
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply
* [RESEND PATCH v2 1/7] drm/vc4: Fix ->clock_select setting for the VEC encoder
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
PV_CONTROL_CLK_SELECT_VEC is actually 2 and not 0. Fix the definition and
rework the vc4_set_crtc_possible_masks() to cover the full range of the
PV_CONTROL_CLK_SELECT field.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/gpu/drm/vc4/vc4_crtc.c | 38 +++++++++++++++++++++++---------------
drivers/gpu/drm/vc4/vc4_drv.h | 1 +
drivers/gpu/drm/vc4/vc4_regs.h | 3 ++-
3 files changed, 26 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7f08d681a74b..c317e9103f9b 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -83,8 +83,7 @@ struct vc4_crtc_data {
/* Which channel of the HVS this pixelvalve sources from. */
int hvs_channel;
- enum vc4_encoder_type encoder0_type;
- enum vc4_encoder_type encoder1_type;
+ enum vc4_encoder_type encoder_types[4];
};
#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
@@ -859,20 +858,26 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
static const struct vc4_crtc_data pv0_data = {
.hvs_channel = 0,
- .encoder0_type = VC4_ENCODER_TYPE_DSI0,
- .encoder1_type = VC4_ENCODER_TYPE_DPI,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI0,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_DPI,
+ },
};
static const struct vc4_crtc_data pv1_data = {
.hvs_channel = 2,
- .encoder0_type = VC4_ENCODER_TYPE_DSI1,
- .encoder1_type = VC4_ENCODER_TYPE_SMI,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DSI] = VC4_ENCODER_TYPE_DSI1,
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_SMI,
+ },
};
static const struct vc4_crtc_data pv2_data = {
.hvs_channel = 1,
- .encoder0_type = VC4_ENCODER_TYPE_VEC,
- .encoder1_type = VC4_ENCODER_TYPE_HDMI,
+ .encoder_types = {
+ [PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI] = VC4_ENCODER_TYPE_HDMI,
+ [PV_CONTROL_CLK_SELECT_VEC] = VC4_ENCODER_TYPE_VEC,
+ },
};
static const struct of_device_id vc4_crtc_dt_match[] = {
@@ -886,17 +891,20 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
struct drm_crtc *crtc)
{
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
+ const struct vc4_crtc_data *crtc_data = vc4_crtc->data;
+ const enum vc4_encoder_type *encoder_types = crtc_data->encoder_types;
struct drm_encoder *encoder;
drm_for_each_encoder(encoder, drm) {
struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
-
- if (vc4_encoder->type == vc4_crtc->data->encoder0_type) {
- vc4_encoder->clock_select = 0;
- encoder->possible_crtcs |= drm_crtc_mask(crtc);
- } else if (vc4_encoder->type == vc4_crtc->data->encoder1_type) {
- vc4_encoder->clock_select = 1;
- encoder->possible_crtcs |= drm_crtc_mask(crtc);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(crtc_data->encoder_types); i++) {
+ if (vc4_encoder->type == encoder_types[i]) {
+ vc4_encoder->clock_select = i;
+ encoder->possible_crtcs |= drm_crtc_mask(crtc);
+ break;
+ }
}
}
}
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 7c1e4d97486f..946d48c33668 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -194,6 +194,7 @@ to_vc4_plane(struct drm_plane *plane)
}
enum vc4_encoder_type {
+ VC4_ENCODER_TYPE_NONE,
VC4_ENCODER_TYPE_HDMI,
VC4_ENCODER_TYPE_VEC,
VC4_ENCODER_TYPE_DSI0,
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
index 1aa44c2db556..39f6886b2410 100644
--- a/drivers/gpu/drm/vc4/vc4_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
@@ -177,8 +177,9 @@
# define PV_CONTROL_WAIT_HSTART BIT(12)
# define PV_CONTROL_PIXEL_REP_MASK VC4_MASK(5, 4)
# define PV_CONTROL_PIXEL_REP_SHIFT 4
-# define PV_CONTROL_CLK_SELECT_DSI_VEC 0
+# define PV_CONTROL_CLK_SELECT_DSI 0
# define PV_CONTROL_CLK_SELECT_DPI_SMI_HDMI 1
+# define PV_CONTROL_CLK_SELECT_VEC 2
# define PV_CONTROL_CLK_SELECT_MASK VC4_MASK(3, 2)
# define PV_CONTROL_CLK_SELECT_SHIFT 2
# define PV_CONTROL_FIFO_CLR BIT(1)
--
2.7.4
--
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
* [RESEND PATCH v2 2/7] drm: Turn DRM_MODE_SUBCONNECTOR_xx definitions into an enum
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
List of values like the DRM_MODE_SUBCONNECTOR_xx ones are better
represented with enums.
Turn the DRM_MODE_SUBCONNECTOR_xx macros into an enum.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Suggested-by: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
Reviewed-by: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
---
include/uapi/drm/drm_mode.h | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index df0e3504c349..970bfc0d7107 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -220,14 +220,16 @@ struct drm_mode_get_encoder {
/* This is for connectors with multiple signal types. */
/* Try to match DRM_MODE_CONNECTOR_X as closely as possible. */
-#define DRM_MODE_SUBCONNECTOR_Automatic 0
-#define DRM_MODE_SUBCONNECTOR_Unknown 0
-#define DRM_MODE_SUBCONNECTOR_DVID 3
-#define DRM_MODE_SUBCONNECTOR_DVIA 4
-#define DRM_MODE_SUBCONNECTOR_Composite 5
-#define DRM_MODE_SUBCONNECTOR_SVIDEO 6
-#define DRM_MODE_SUBCONNECTOR_Component 8
-#define DRM_MODE_SUBCONNECTOR_SCART 9
+enum drm_mode_subconnector {
+ DRM_MODE_SUBCONNECTOR_Automatic = 0,
+ DRM_MODE_SUBCONNECTOR_Unknown = 0,
+ DRM_MODE_SUBCONNECTOR_DVID = 3,
+ DRM_MODE_SUBCONNECTOR_DVIA = 4,
+ DRM_MODE_SUBCONNECTOR_Composite = 5,
+ DRM_MODE_SUBCONNECTOR_SVIDEO = 6,
+ DRM_MODE_SUBCONNECTOR_Component = 8,
+ DRM_MODE_SUBCONNECTOR_SCART = 9,
+};
#define DRM_MODE_CONNECTOR_Unknown 0
#define DRM_MODE_CONNECTOR_VGA 1
--
2.7.4
--
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
* [RESEND PATCH v2 3/7] drm: Add TV connector states to drm_connector_state
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Some generic TV connector properties are exposed in drm_mode_config, but
they are currently handled independently in each DRM encoder driver.
Extend the drm_connector_state to store TV related states, and modify the
drm_atomic_connector_{set,get}_property() helpers to fill the connector
state accordingly.
Each driver is then responsible for checking and applying the new config
in its ->atomic_mode_{check,set}() operations.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Reviewed-by: Daniel Vetter <daniel.vetter-/w4YWyX8dFk@public.gmane.org>
---
Changes in v2
- fix copy/paste errors
- use an enum for the subconnector field
- switch all fields to unsigned int
---
drivers/gpu/drm/drm_atomic.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_connector.h | 32 ++++++++++++++++++++++++++++
2 files changed, 82 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index e6862a744210..f93395c3c181 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -989,12 +989,38 @@ int drm_atomic_connector_set_property(struct drm_connector *connector,
* now?) atomic writes to DPMS property:
*/
return -EINVAL;
+ } else if (property == config->tv_select_subconnector_property) {
+ state->tv.subconnector = val;
+ } else if (property == config->tv_left_margin_property) {
+ state->tv.margins.left = val;
+ } else if (property == config->tv_right_margin_property) {
+ state->tv.margins.right = val;
+ } else if (property == config->tv_top_margin_property) {
+ state->tv.margins.top = val;
+ } else if (property == config->tv_bottom_margin_property) {
+ state->tv.margins.bottom = val;
+ } else if (property == config->tv_mode_property) {
+ state->tv.mode = val;
+ } else if (property == config->tv_brightness_property) {
+ state->tv.brightness = val;
+ } else if (property == config->tv_contrast_property) {
+ state->tv.contrast = val;
+ } else if (property == config->tv_flicker_reduction_property) {
+ state->tv.flicker_reduction = val;
+ } else if (property == config->tv_overscan_property) {
+ state->tv.overscan = val;
+ } else if (property == config->tv_saturation_property) {
+ state->tv.saturation = val;
+ } else if (property == config->tv_hue_property) {
+ state->tv.hue = val;
} else if (connector->funcs->atomic_set_property) {
return connector->funcs->atomic_set_property(connector,
state, property, val);
} else {
return -EINVAL;
}
+
+ return 0;
}
EXPORT_SYMBOL(drm_atomic_connector_set_property);
@@ -1025,6 +1051,30 @@ drm_atomic_connector_get_property(struct drm_connector *connector,
*val = (state->crtc) ? state->crtc->base.id : 0;
} else if (property == config->dpms_property) {
*val = connector->dpms;
+ } else if (property == config->tv_select_subconnector_property) {
+ *val = state->tv.subconnector;
+ } else if (property == config->tv_left_margin_property) {
+ *val = state->tv.margins.left;
+ } else if (property == config->tv_right_margin_property) {
+ *val = state->tv.margins.right;
+ } else if (property == config->tv_top_margin_property) {
+ *val = state->tv.margins.top;
+ } else if (property == config->tv_bottom_margin_property) {
+ *val = state->tv.margins.bottom;
+ } else if (property == config->tv_mode_property) {
+ *val = state->tv.mode;
+ } else if (property == config->tv_brightness_property) {
+ *val = state->tv.brightness;
+ } else if (property == config->tv_contrast_property) {
+ *val = state->tv.contrast;
+ } else if (property == config->tv_flicker_reduction_property) {
+ *val = state->tv.flicker_reduction;
+ } else if (property == config->tv_overscan_property) {
+ *val = state->tv.overscan;
+ } else if (property == config->tv_saturation_property) {
+ *val = state->tv.saturation;
+ } else if (property == config->tv_hue_property) {
+ *val = state->tv.hue;
} else if (connector->funcs->atomic_get_property) {
return connector->funcs->atomic_get_property(connector,
state, property, val);
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index ac9d7d8e0e43..2645e8038572 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -194,10 +194,40 @@ int drm_display_info_set_bus_formats(struct drm_display_info *info,
unsigned int num_formats);
/**
+ * struct drm_tv_connector_state - TV connector related states
+ * @subconnector: selected subconnector
+ * @margins: left/right/top/bottom margins
+ * @mode: TV mode
+ * @brightness: brightness in percent
+ * @contrast: contrast in percent
+ * @flicker_reduction: flicker reduction in percent
+ * @overscan: overscan in percent
+ * @saturation: saturation in percent
+ * @hue: hue in percent
+ */
+struct drm_tv_connector_state {
+ enum drm_mode_subconnector subconnector;
+ struct {
+ unsigned int left;
+ unsigned int right;
+ unsigned int top;
+ unsigned int bottom;
+ } margins;
+ unsigned int mode;
+ unsigned int brightness;
+ unsigned int contrast;
+ unsigned int flicker_reduction;
+ unsigned int overscan;
+ unsigned int saturation;
+ unsigned int hue;
+};
+
+/**
* struct drm_connector_state - mutable connector state
* @connector: backpointer to the connector
* @best_encoder: can be used by helpers and drivers to select the encoder
* @state: backpointer to global drm_atomic_state
+ * @tv: TV connector state
*/
struct drm_connector_state {
struct drm_connector *connector;
@@ -213,6 +243,8 @@ struct drm_connector_state {
struct drm_encoder *best_encoder;
struct drm_atomic_state *state;
+
+ struct drm_tv_connector_state tv;
};
/**
--
2.7.4
--
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
* [RESEND PATCH v2 4/7] drm/vc4: Add support for the VEC (Video Encoder) IP
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
The VEC IP is a TV DAC, providing support for PAL and NTSC standards.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
drivers/gpu/drm/vc4/Makefile | 1 +
drivers/gpu/drm/vc4/vc4_debugfs.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.c | 1 +
drivers/gpu/drm/vc4/vc4_drv.h | 5 +
drivers/gpu/drm/vc4/vc4_vec.c | 657 ++++++++++++++++++++++++++++++++++++++
5 files changed, 665 insertions(+)
create mode 100644 drivers/gpu/drm/vc4/vc4_vec.c
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index fb77db755e0a..7757f69a8a77 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -11,6 +11,7 @@ vc4-y := \
vc4_kms.o \
vc4_gem.o \
vc4_hdmi.o \
+ vc4_vec.o \
vc4_hvs.o \
vc4_irq.o \
vc4_plane.o \
diff --git a/drivers/gpu/drm/vc4/vc4_debugfs.c b/drivers/gpu/drm/vc4/vc4_debugfs.c
index 245115d49c46..caf817bac885 100644
--- a/drivers/gpu/drm/vc4/vc4_debugfs.c
+++ b/drivers/gpu/drm/vc4/vc4_debugfs.c
@@ -19,6 +19,7 @@ static const struct drm_info_list vc4_debugfs_list[] = {
{"bo_stats", vc4_bo_stats_debugfs, 0},
{"dpi_regs", vc4_dpi_debugfs_regs, 0},
{"hdmi_regs", vc4_hdmi_debugfs_regs, 0},
+ {"vec_regs", vc4_vec_debugfs_regs, 0},
{"hvs_regs", vc4_hvs_debugfs_regs, 0},
{"crtc0_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)0},
{"crtc1_regs", vc4_crtc_debugfs_regs, 0, (void *)(uintptr_t)1},
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 8703f56b7947..3e6cb78f7381 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -289,6 +289,7 @@ static const struct component_master_ops vc4_drm_ops = {
static struct platform_driver *const component_drivers[] = {
&vc4_hdmi_driver,
+ &vc4_vec_driver,
&vc4_dpi_driver,
&vc4_hvs_driver,
&vc4_crtc_driver,
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 946d48c33668..b3a46a51f9d0 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -17,6 +17,7 @@ struct vc4_dev {
struct vc4_crtc *crtc[3];
struct vc4_v3d *v3d;
struct vc4_dpi *dpi;
+ struct vc4_vec *vec;
struct drm_fbdev_cma *fbdev;
@@ -484,6 +485,10 @@ int vc4_queue_seqno_cb(struct drm_device *dev,
extern struct platform_driver vc4_hdmi_driver;
int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused);
+/* vc4_hdmi.c */
+extern struct platform_driver vc4_vec_driver;
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused);
+
/* vc4_irq.c */
irqreturn_t vc4_irq(int irq, void *arg);
void vc4_irq_preinstall(struct drm_device *dev);
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
new file mode 100644
index 000000000000..2d4256fcc6f2
--- /dev/null
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -0,0 +1,657 @@
+/*
+ * Copyright (C) 2016 Broadcom Limited
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * DOC: VC4 SDTV module
+ */
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_panel.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/of_graph.h>
+#include <linux/of_platform.h>
+#include <linux/pm_runtime.h>
+
+#include "vc4_drv.h"
+#include "vc4_regs.h"
+
+/* WSE Registers */
+#define VEC_WSE_RESET 0xc0
+
+#define VEC_WSE_CONTROL 0xc4
+#define VEC_WSE_WSS_ENABLE BIT(7)
+
+#define VEC_WSE_WSS_DATA 0xc8
+#define VEC_WSE_VPS_DATA1 0xcc
+#define VEC_WSE_VPS_CONTROL 0xd0
+
+/* VEC Registers */
+#define VEC_REVID 0x100
+
+#define VEC_CONFIG0 0x104
+#define VEC_CONFIG0_YDEL_MASK GENMASK(28, 26)
+#define VEC_CONFIG0_YDEL(x) ((x) << 26)
+#define VEC_CONFIG0_CDEL_MASK GENMASK(25, 24)
+#define VEC_CONFIG0_CDEL(x) ((x) << 24)
+#define VEC_CONFIG0_PBPR_FIL BIT(18)
+#define VEC_CONFIG0_CHROMA_GAIN_MASK GENMASK(17, 16)
+#define VEC_CONFIG0_CHROMA_GAIN_UNITY (0 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_32 (1 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_16 (2 << 16)
+#define VEC_CONFIG0_CHROMA_GAIN_1_8 (3 << 16)
+#define VEC_CONFIG0_CBURST_GAIN_MASK GENMASK(14, 13)
+#define VEC_CONFIG0_CBURST_GAIN_UNITY (0 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_128 (1 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_64 (2 << 13)
+#define VEC_CONFIG0_CBURST_GAIN_1_32 (3 << 13)
+#define VEC_CONFIG0_CHRBW1 BIT(11)
+#define VEC_CONFIG0_CHRBW0 BIT(10)
+#define VEC_CONFIG0_SYNCDIS BIT(9)
+#define VEC_CONFIG0_BURDIS BIT(8)
+#define VEC_CONFIG0_CHRDIS BIT(7)
+#define VEC_CONFIG0_PDEN BIT(6)
+#define VEC_CONFIG0_YCDELAY BIT(4)
+#define VEC_CONFIG0_RAMPEN BIT(2)
+#define VEC_CONFIG0_YCDIS BIT(2)
+#define VEC_CONFIG0_STD_MASK GENMASK(1, 0)
+#define VEC_CONFIG0_NTSC_STD 0
+#define VEC_CONFIG0_PAL_BDGHI_STD 1
+#define VEC_CONFIG0_PAL_N_STD 3
+
+#define VEC_SCHPH 0x108
+#define VEC_SOFT_RESET 0x10c
+#define VEC_CLMP0_START 0x144
+#define VEC_CLMP0_END 0x148
+#define VEC_FREQ3_2 0x180
+#define VEC_FREQ1_0 0x184
+
+#define VEC_CONFIG1 0x188
+#define VEC_CONFIG_VEC_RESYNC_OFF BIT(18)
+#define VEC_CONFIG_RGB219 BIT(17)
+#define VEC_CONFIG_CBAR_EN BIT(16)
+#define VEC_CONFIG_TC_OBB BIT(15)
+#define VEC_CONFIG1_OUTPUT_MODE_MASK GENMASK(12, 10)
+#define VEC_CONFIG1_C_Y_CVBS (0 << 10)
+#define VEC_CONFIG1_CVBS_Y_C (1 << 10)
+#define VEC_CONFIG1_PR_Y_PB (2 << 10)
+#define VEC_CONFIG1_RGB (4 << 10)
+#define VEC_CONFIG1_Y_C_CVBS (5 << 10)
+#define VEC_CONFIG1_C_CVBS_Y (6 << 10)
+#define VEC_CONFIG1_C_CVBS_CVBS (7 << 10)
+#define VEC_CONFIG1_DIS_CHR BIT(9)
+#define VEC_CONFIG1_DIS_LUMA BIT(8)
+#define VEC_CONFIG1_YCBCR_IN BIT(6)
+#define VEC_CONFIG1_DITHER_TYPE_LFSR 0
+#define VEC_CONFIG1_DITHER_TYPE_COUNTER BIT(5)
+#define VEC_CONFIG1_DITHER_EN BIT(4)
+#define VEC_CONFIG1_CYDELAY BIT(3)
+#define VEC_CONFIG1_LUMADIS BIT(2)
+#define VEC_CONFIG1_COMPDIS BIT(1)
+#define VEC_CONFIG1_CUSTOM_FREQ BIT(0)
+
+#define VEC_CONFIG2 0x18c
+#define VEC_CONFIG2_PROG_SCAN BIT(15)
+#define VEC_CONFIG2_SYNC_ADJ_MASK GENMASK(14, 12)
+#define VEC_CONFIG2_SYNC_ADJ(x) (((x) / 2) << 12)
+#define VEC_CONFIG2_PBPR_EN BIT(10)
+#define VEC_CONFIG2_UV_DIG_DIS BIT(6)
+#define VEC_CONFIG2_RGB_DIG_DIS BIT(5)
+#define VEC_CONFIG2_TMUX_MASK GENMASK(3, 2)
+#define VEC_CONFIG2_TMUX_DRIVE0 (0 << 2)
+#define VEC_CONFIG2_TMUX_RG_COMP (1 << 2)
+#define VEC_CONFIG2_TMUX_UV_YC (2 << 2)
+#define VEC_CONFIG2_TMUX_SYNC_YC (3 << 2)
+
+#define VEC_INTERRUPT_CONTROL 0x190
+#define VEC_INTERRUPT_STATUS 0x194
+#define VEC_FCW_SECAM_B 0x198
+#define VEC_SECAM_GAIN_VAL 0x19c
+
+#define VEC_CONFIG3 0x1a0
+#define VEC_CONFIG3_HORIZ_LEN_STD (0 << 0)
+#define VEC_CONFIG3_HORIZ_LEN_MPEG1_SIF (1 << 0)
+#define VEC_CONFIG3_SHAPE_NON_LINEAR BIT(1)
+
+#define VEC_STATUS0 0x200
+#define VEC_MASK0 0x204
+
+#define VEC_CFG 0x208
+#define VEC_CFG_SG_MODE_MASK GENMASK(6, 5)
+#define VEC_CFG_SG_MODE(x) ((x) << 5)
+#define VEC_CFG_SG_EN BIT(4)
+#define VEC_CFG_VEC_EN BIT(3)
+#define VEC_CFG_MB_EN BIT(2)
+#define VEC_CFG_ENABLE BIT(1)
+#define VEC_CFG_TB_EN BIT(0)
+
+#define VEC_DAC_TEST 0x20c
+
+#define VEC_DAC_CONFIG 0x210
+#define VEC_DAC_CONFIG_LDO_BIAS_CTRL(x) ((x) << 24)
+#define VEC_DAC_CONFIG_DRIVER_CTRL(x) ((x) << 16)
+#define VEC_DAC_CONFIG_DAC_CTRL(x) (x)
+
+#define VEC_DAC_MISC 0x214
+#define VEC_DAC_MISC_VCD_CTRL_MASK GENMASK(31, 16)
+#define VEC_DAC_MISC_VCD_CTRL(x) ((x) << 16)
+#define VEC_DAC_MISC_VID_ACT BIT(8)
+#define VEC_DAC_MISC_VCD_PWRDN BIT(6)
+#define VEC_DAC_MISC_BIAS_PWRDN BIT(5)
+#define VEC_DAC_MISC_DAC_PWRDN BIT(2)
+#define VEC_DAC_MISC_LDO_PWRDN BIT(1)
+#define VEC_DAC_MISC_DAC_RST_N BIT(0)
+
+
+/* General VEC hardware state. */
+struct vc4_vec {
+ struct platform_device *pdev;
+
+ struct drm_encoder *encoder;
+ struct drm_connector *connector;
+
+ void __iomem *regs;
+
+ struct clk *clock;
+
+ const struct vc4_vec_tv_mode *tv_mode;
+};
+
+#define VEC_READ(offset) readl(vec->regs + (offset))
+#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
+
+/* VC4 VEC encoder KMS struct */
+struct vc4_vec_encoder {
+ struct vc4_encoder base;
+ struct vc4_vec *vec;
+};
+
+static inline struct vc4_vec_encoder *
+to_vc4_vec_encoder(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct vc4_vec_encoder, base.base);
+}
+
+/* VC4 VEC connector KMS struct */
+struct vc4_vec_connector {
+ struct drm_connector base;
+ struct vc4_vec *vec;
+
+ /* Since the connector is attached to just the one encoder,
+ * this is the reference to it so we can do the best_encoder()
+ * hook.
+ */
+ struct drm_encoder *encoder;
+};
+
+static inline struct vc4_vec_connector *
+to_vc4_vec_connector(struct drm_connector *connector)
+{
+ return container_of(connector, struct vc4_vec_connector, base);
+}
+
+enum vc4_vec_tv_mode_id {
+ VC4_VEC_TV_MODE_NTSC,
+ VC4_VEC_TV_MODE_NTSC_J,
+ VC4_VEC_TV_MODE_PAL,
+ VC4_VEC_TV_MODE_PAL_M,
+};
+
+struct vc4_vec_tv_mode {
+ const struct drm_display_mode *mode;
+ void (*mode_set)(struct vc4_vec *vec);
+};
+
+#define VEC_REG(reg) { reg, #reg }
+static const struct {
+ u32 reg;
+ const char *name;
+} vec_regs[] = {
+ VEC_REG(VEC_WSE_CONTROL),
+ VEC_REG(VEC_WSE_WSS_DATA),
+ VEC_REG(VEC_WSE_VPS_DATA1),
+ VEC_REG(VEC_WSE_VPS_CONTROL),
+ VEC_REG(VEC_REVID),
+ VEC_REG(VEC_CONFIG0),
+ VEC_REG(VEC_SCHPH),
+ VEC_REG(VEC_CLMP0_START),
+ VEC_REG(VEC_CLMP0_END),
+ VEC_REG(VEC_FREQ3_2),
+ VEC_REG(VEC_FREQ1_0),
+ VEC_REG(VEC_CONFIG1),
+ VEC_REG(VEC_CONFIG2),
+ VEC_REG(VEC_INTERRUPT_CONTROL),
+ VEC_REG(VEC_INTERRUPT_STATUS),
+ VEC_REG(VEC_FCW_SECAM_B),
+ VEC_REG(VEC_SECAM_GAIN_VAL),
+ VEC_REG(VEC_CONFIG3),
+ VEC_REG(VEC_STATUS0),
+ VEC_REG(VEC_MASK0),
+ VEC_REG(VEC_CFG),
+ VEC_REG(VEC_DAC_TEST),
+ VEC_REG(VEC_DAC_CONFIG),
+ VEC_REG(VEC_DAC_MISC),
+};
+
+#ifdef CONFIG_DEBUG_FS
+int vc4_vec_debugfs_regs(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = (struct drm_info_node *)m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct vc4_dev *vc4 = to_vc4_dev(dev);
+ struct vc4_vec *vec = vc4->vec;
+ int i;
+
+ if (!vec)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(vec_regs); i++) {
+ seq_printf(m, "%s (0x%04x): 0x%08x\n",
+ vec_regs[i].name, vec_regs[i].reg,
+ VEC_READ(vec_regs[i].reg));
+ }
+
+ return 0;
+}
+#endif
+
+static void vc4_vec_ntsc_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD | VEC_CONFIG0_PDEN);
+ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_ntsc_j_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_NTSC_STD);
+ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static const struct drm_display_mode ntsc_mode = {
+ DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 13500,
+ 720, 720 + 14, 720 + 14 + 64, 720 + 14 + 64 + 60, 0,
+ 480, 480 + 3, 480 + 3 + 3, 480 + 3 + 3 + 16, 0,
+ DRM_MODE_FLAG_INTERLACE)
+};
+
+static void vc4_vec_pal_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+ VEC_WRITE(VEC_CONFIG1, VEC_CONFIG1_C_CVBS_CVBS);
+}
+
+static void vc4_vec_pal_m_mode_set(struct vc4_vec *vec)
+{
+ VEC_WRITE(VEC_CONFIG0, VEC_CONFIG0_PAL_BDGHI_STD);
+ VEC_WRITE(VEC_CONFIG1,
+ VEC_CONFIG1_C_CVBS_CVBS | VEC_CONFIG1_CUSTOM_FREQ);
+ VEC_WRITE(VEC_FREQ3_2, 0x223b);
+ VEC_WRITE(VEC_FREQ1_0, 0x61d1);
+}
+
+static const struct drm_display_mode pal_mode = {
+ DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 13500,
+ 720, 720 + 20, 720 + 20 + 64, 720 + 20 + 64 + 60, 0,
+ 576, 576 + 2, 576 + 2 + 3, 576 + 2 + 3 + 20, 0,
+ DRM_MODE_FLAG_INTERLACE)
+};
+
+static const struct vc4_vec_tv_mode vc4_vec_tv_modes[] = {
+ [VC4_VEC_TV_MODE_NTSC] = {
+ .mode = &ntsc_mode,
+ .mode_set = vc4_vec_ntsc_mode_set,
+ },
+ [VC4_VEC_TV_MODE_NTSC_J] = {
+ .mode = &ntsc_mode,
+ .mode_set = vc4_vec_ntsc_j_mode_set,
+ },
+ [VC4_VEC_TV_MODE_PAL] = {
+ .mode = &pal_mode,
+ .mode_set = vc4_vec_pal_mode_set,
+ },
+ [VC4_VEC_TV_MODE_PAL_M] = {
+ .mode = &pal_mode,
+ .mode_set = vc4_vec_pal_m_mode_set,
+ },
+};
+
+static enum drm_connector_status
+vc4_vec_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_unknown;
+}
+
+static void vc4_vec_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static int vc4_vec_connector_get_modes(struct drm_connector *connector)
+{
+ struct drm_connector_state *state = connector->state;
+ struct drm_display_mode *mode;
+
+ mode = drm_mode_duplicate(connector->dev,
+ vc4_vec_tv_modes[state->tv.mode].mode);
+ if (!mode) {
+ DRM_ERROR("Failed to create a new display mode\n");
+ return -ENOMEM;
+ }
+
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
+static const struct drm_connector_funcs vc4_vec_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = vc4_vec_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .set_property = drm_atomic_helper_connector_set_property,
+ .destroy = vc4_vec_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs vc4_vec_connector_helper_funcs = {
+ .get_modes = vc4_vec_connector_get_modes,
+};
+
+static struct drm_connector *vc4_vec_connector_init(struct drm_device *dev,
+ struct vc4_vec *vec)
+{
+ struct drm_connector *connector = NULL;
+ struct vc4_vec_connector *vec_connector;
+
+ vec_connector = devm_kzalloc(dev->dev, sizeof(*vec_connector),
+ GFP_KERNEL);
+ if (!vec_connector)
+ return ERR_PTR(-ENOMEM);
+
+ connector = &vec_connector->base;
+ connector->interlace_allowed = true;
+
+ vec_connector->encoder = vec->encoder;
+ vec_connector->vec = vec;
+
+ drm_connector_init(dev, connector, &vc4_vec_connector_funcs,
+ DRM_MODE_CONNECTOR_Composite);
+ drm_connector_helper_add(connector, &vc4_vec_connector_helper_funcs);
+
+ drm_object_attach_property(&connector->base,
+ dev->mode_config.tv_mode_property,
+ VC4_VEC_TV_MODE_NTSC);
+ vec->tv_mode = &vc4_vec_tv_modes[VC4_VEC_TV_MODE_NTSC];
+
+ drm_mode_connector_attach_encoder(connector, vec->encoder);
+
+ return connector;
+}
+
+static const struct drm_encoder_funcs vc4_vec_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void vc4_vec_encoder_disable(struct drm_encoder *encoder)
+{
+ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+ struct vc4_vec *vec = vc4_vec_encoder->vec;
+ int ret;
+
+ VEC_WRITE(VEC_CFG, 0);
+ VEC_WRITE(VEC_DAC_MISC,
+ VEC_DAC_MISC_VCD_PWRDN |
+ VEC_DAC_MISC_BIAS_PWRDN |
+ VEC_DAC_MISC_DAC_PWRDN |
+ VEC_DAC_MISC_LDO_PWRDN);
+
+ clk_disable_unprepare(vec->clock);
+
+ ret = pm_runtime_put(&vec->pdev->dev);
+ if (ret < 0) {
+ DRM_ERROR("Failed to release power domain: %d\n", ret);
+ return;
+ }
+}
+
+static void vc4_vec_encoder_enable(struct drm_encoder *encoder)
+{
+ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+ struct vc4_vec *vec = vc4_vec_encoder->vec;
+ int ret;
+
+ ret = pm_runtime_get_sync(&vec->pdev->dev);
+ if (ret < 0) {
+ DRM_ERROR("Failed to retain power domain: %d\n", ret);
+ return;
+ }
+
+ /*
+ * We need to set the clock rate each time we enable the encoder
+ * because there's a chance we share the same parent with the HDMI
+ * clock, and both drivers are requesting different rates.
+ * The good news is, these 2 encoders cannot be enabled at the same
+ * time, thus preventing incompatible rate requests.
+ */
+ ret = clk_set_rate(vec->clock, 108000000);
+ if (ret) {
+ DRM_ERROR("Failed to set clock rate: %d\n", ret);
+ return;
+ }
+
+ ret = clk_prepare_enable(vec->clock);
+ if (ret) {
+ DRM_ERROR("Failed to turn on core clock: %d\n", ret);
+ return;
+ }
+
+ /* Reset the different blocks */
+ VEC_WRITE(VEC_WSE_RESET, 1);
+ VEC_WRITE(VEC_SOFT_RESET, 1);
+
+ /* Disable the CGSM-A and WSE blocks */
+ VEC_WRITE(VEC_WSE_CONTROL, 0);
+
+ /* Write config common to all modes. */
+
+ /*
+ * Color subcarrier phase: phase = 360 * SCHPH / 256.
+ * 0x28 <=> 39.375 deg.
+ */
+ VEC_WRITE(VEC_SCHPH, 0x28);
+
+ /*
+ * Reset to default values.
+ */
+ VEC_WRITE(VEC_CLMP0_START, 0xac);
+ VEC_WRITE(VEC_CLMP0_END, 0xec);
+ VEC_WRITE(VEC_CONFIG2,
+ VEC_CONFIG2_UV_DIG_DIS | VEC_CONFIG2_RGB_DIG_DIS);
+ VEC_WRITE(VEC_CONFIG3, VEC_CONFIG3_HORIZ_LEN_STD);
+ VEC_WRITE(VEC_DAC_CONFIG,
+ VEC_DAC_CONFIG_DAC_CTRL(0xc) |
+ VEC_DAC_CONFIG_DRIVER_CTRL(0xc) |
+ VEC_DAC_CONFIG_LDO_BIAS_CTRL(0x46));
+
+ /* Mask all interrupts. */
+ VEC_WRITE(VEC_MASK0, 0);
+
+ vec->tv_mode->mode_set(vec);
+
+ VEC_WRITE(VEC_DAC_MISC,
+ VEC_DAC_MISC_VID_ACT | VEC_DAC_MISC_DAC_RST_N);
+ VEC_WRITE(VEC_CFG, VEC_CFG_VEC_EN);
+}
+
+
+static bool vc4_vec_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void vc4_vec_encoder_atomic_mode_set(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct vc4_vec_encoder *vc4_vec_encoder = to_vc4_vec_encoder(encoder);
+ struct vc4_vec *vec = vc4_vec_encoder->vec;
+
+ vec->tv_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+}
+
+static int vc4_vec_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ const struct vc4_vec_tv_mode *vec_mode;
+
+ vec_mode = &vc4_vec_tv_modes[conn_state->tv.mode];
+
+ if (conn_state->crtc &&
+ !drm_mode_equal(vec_mode->mode, &crtc_state->adjusted_mode))
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct drm_encoder_helper_funcs vc4_vec_encoder_helper_funcs = {
+ .disable = vc4_vec_encoder_disable,
+ .enable = vc4_vec_encoder_enable,
+ .mode_fixup = vc4_vec_encoder_mode_fixup,
+ .atomic_check = vc4_vec_encoder_atomic_check,
+ .atomic_mode_set = vc4_vec_encoder_atomic_mode_set,
+};
+
+static const struct of_device_id vc4_vec_dt_match[] = {
+ { .compatible = "brcm,bcm2835-vec", .data = NULL },
+ { /* sentinel */ },
+};
+
+static const char * const tv_mode_names[] = {
+ [VC4_VEC_TV_MODE_NTSC] = "NTSC",
+ [VC4_VEC_TV_MODE_NTSC_J] = "NTSC-J",
+ [VC4_VEC_TV_MODE_PAL] = "PAL",
+ [VC4_VEC_TV_MODE_PAL_M] = "PAL-M",
+};
+
+static int vc4_vec_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_vec *vec;
+ struct vc4_vec_encoder *vc4_vec_encoder;
+ int ret;
+
+ ret = drm_mode_create_tv_properties(drm, ARRAY_SIZE(tv_mode_names),
+ tv_mode_names);
+ if (ret)
+ return ret;
+
+ vec = devm_kzalloc(dev, sizeof(*vec), GFP_KERNEL);
+ if (!vec)
+ return -ENOMEM;
+
+ vc4_vec_encoder = devm_kzalloc(dev, sizeof(*vc4_vec_encoder),
+ GFP_KERNEL);
+ if (!vc4_vec_encoder)
+ return -ENOMEM;
+ vc4_vec_encoder->base.type = VC4_ENCODER_TYPE_VEC;
+ vc4_vec_encoder->vec = vec;
+ vec->encoder = &vc4_vec_encoder->base.base;
+
+ vec->pdev = pdev;
+ vec->regs = vc4_ioremap_regs(pdev, 0);
+ if (IS_ERR(vec->regs))
+ return PTR_ERR(vec->regs);
+
+ vec->clock = devm_clk_get(dev, NULL);
+ if (IS_ERR(vec->clock)) {
+ ret = PTR_ERR(vec->clock);
+ if (ret != -EPROBE_DEFER)
+ DRM_ERROR("Failed to get clock: %d\n", ret);
+ return ret;
+ }
+
+ pm_runtime_enable(dev);
+
+ drm_encoder_init(drm, vec->encoder, &vc4_vec_encoder_funcs,
+ DRM_MODE_ENCODER_TVDAC, NULL);
+ drm_encoder_helper_add(vec->encoder, &vc4_vec_encoder_helper_funcs);
+
+ vec->connector = vc4_vec_connector_init(drm, vec);
+ if (IS_ERR(vec->connector)) {
+ ret = PTR_ERR(vec->connector);
+ goto err_destroy_encoder;
+ }
+
+ dev_set_drvdata(dev, vec);
+
+ vc4->vec = vec;
+
+ return 0;
+
+err_destroy_encoder:
+ drm_encoder_cleanup(vec->encoder);
+ pm_runtime_disable(dev);
+
+ return ret;
+}
+
+static void vc4_vec_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_vec *vec = dev_get_drvdata(dev);
+
+ vc4_vec_connector_destroy(vec->connector);
+ drm_encoder_cleanup(vec->encoder);
+ pm_runtime_disable(dev);
+
+ vc4->vec = NULL;
+}
+
+static const struct component_ops vc4_vec_ops = {
+ .bind = vc4_vec_bind,
+ .unbind = vc4_vec_unbind,
+};
+
+static int vc4_vec_dev_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &vc4_vec_ops);
+}
+
+static int vc4_vec_dev_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &vc4_vec_ops);
+ return 0;
+}
+
+struct platform_driver vc4_vec_driver = {
+ .probe = vc4_vec_dev_probe,
+ .remove = vc4_vec_dev_remove,
+ .driver = {
+ .name = "vc4_vec",
+ .of_match_table = vc4_vec_dt_match,
+ },
+};
--
2.7.4
--
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
* [RESEND PATCH v2 5/7] drm/vc4: Document VEC DT binding
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Document the DT binding for the VEC (Video EnCoder) IP.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
index a5ea451e67fc..e2768703ac2b 100644
--- a/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
+++ b/Documentation/devicetree/bindings/display/brcm,bcm-vc4.txt
@@ -43,6 +43,13 @@ Required properties for DPI:
- port: Port node with a single endpoint connecting to the panel
device, as defined in [1]
+Required properties for VEC:
+- compatible: Should be "brcm,bcm2835-vec"
+- reg: Physical base address and length of the registers
+- clocks: The core clock the unit runs on
+- interrupts: The interrupt number
+ See bindings/interrupt-controller/brcm,bcm2835-armctrl-ic.txt
+
Required properties for V3D:
- compatible: Should be "brcm,bcm2835-v3d"
- reg: Physical base address and length of the V3D's registers
@@ -92,6 +99,13 @@ dpi: dpi@7e208000 {
};
};
+vec: vec@7e806000 {
+ compatible = "brcm,bcm2835-vec";
+ reg = <0x7e806000 0x1000>;
+ clocks = <&clocks BCM2835_CLOCK_VEC>;
+ interrupts = <2 27>;
+};
+
v3d: v3d@7ec00000 {
compatible = "brcm,bcm2835-v3d";
reg = <0x7ec00000 0x1000>;
--
2.7.4
--
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
* [RESEND PATCH v2 6/7] ARM: bcm/dt: Add VEC node in bcm283x.dtsi
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Add the VEC (Video EnCoder) node definition in bcm283x.dtsi.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
arch/arm/boot/dts/bcm283x.dtsi | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/bcm283x.dtsi b/arch/arm/boot/dts/bcm283x.dtsi
index 46d46d894a44..44a9c0539437 100644
--- a/arch/arm/boot/dts/bcm283x.dtsi
+++ b/arch/arm/boot/dts/bcm283x.dtsi
@@ -266,6 +266,14 @@
status = "disabled";
};
+ vec: vec@7e806000 {
+ compatible = "brcm,bcm2835-vec";
+ reg = <0x7e806000 0x1000>;
+ clocks = <&clocks BCM2835_CLOCK_VEC>;
+ interrupts = <2 27>;
+ status = "disabled";
+ };
+
pixelvalve@7e807000 {
compatible = "brcm,bcm2835-pixelvalve2";
reg = <0x7e807000 0x100>;
--
2.7.4
--
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
* [RESEND PATCH v2 7/7] ARM: bcm/dt: Enable the VEC IP on all RaspberryPi boards
From: Boris Brezillon @ 2016-12-02 13:48 UTC (permalink / raw)
To: David Airlie, Daniel Vetter,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW
Cc: Florian Fainelli, Ray Jui, Scott Branden,
bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w, Stephen Warren,
Lee Jones, Eric Anholt,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Boris Brezillon
In-Reply-To: <1480686493-4813-1-git-send-email-boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Enable the VEC IP on all RaspberryPi boards.
Signed-off-by: Boris Brezillon <boris.brezillon-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---
arch/arm/boot/dts/bcm2835-rpi.dtsi | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index e9b47b2bbc33..8893240da5f6 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -84,3 +84,8 @@
power-domains = <&power RPI_POWER_DOMAIN_HDMI>;
status = "okay";
};
+
+&vec {
+ power-domains = <&power RPI_POWER_DOMAIN_VEC>;
+ status = "okay";
+};
--
2.7.4
--
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: [PATCH v5 11/14] ASoC: add simple-graph-card document
From: Rob Herring @ 2016-12-02 13:50 UTC (permalink / raw)
To: Kuninori Morimoto
Cc: Mark Brown, Linux-ALSA, Liam Girdwood, Simon, Laurent, Guennadi,
Grant Likely, Frank Rowand, Linux-DT, Linux-Kernel
In-Reply-To: <874m2swcbx.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
On Mon, Nov 28, 2016 at 02:47:57AM +0000, Kuninori Morimoto wrote:
>
> From: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
> ---
> .../bindings/sound/simple-graph-card.txt | 67 ++++++++++++++++++++++
> 1 file changed, 67 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/sound/simple-graph-card.txt
>
> diff --git a/Documentation/devicetree/bindings/sound/simple-graph-card.txt b/Documentation/devicetree/bindings/sound/simple-graph-card.txt
> new file mode 100644
> index 0000000..3d4c5a8
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/simple-graph-card.txt
> @@ -0,0 +1,67 @@
> +Simple-Graph-Card:
There's nothing simple about this. graph-audio-card or audio-card-graph.
> +
> +Simple-Graph-Card specifies audio DAI connections of SoC <-> codec.
> +It is based on common bindings for device graphs.
> +see ${LINUX}/Documentation/devicetree/bindings/graph.txt
> +
> +Basically, Simple-Graph-Card property is same as Simple-Card.
> +see ${LINUX}/Documentation/devicetree/bindings/sound/simple-card.txt
> +
> +Below are same as Simple-Card.
> +
> +- simple-audio-card,name
> +- simple-audio-card,widgets
> +- simple-audio-card,routing
> +- simple-audio-card,mclk-fs
> +- simple-audio-card,hp-det-gpio
> +- simple-audio-card,mic-det-gpio
> +- simple-audio-card,format
> +- simple-audio-card,frame-master
> +- simple-audio-card,bitclock-master
> +- simple-audio-card,bitclock-inversion
> +- simple-audio-card,frame-inversion
> +- simple-audio-card,mclk-fs
> +- simple-audio-card,dai-tdm-slot-num
> +- simple-audio-card,dai-tdm-slot-width
The simple-audio-card prefix is pointless. It's fine to reuse, but don't
add to it.
> +- clocks / system-clock-frequency
> +
> +In Simple-Graph-Card, above properties need in CPU side port on DT.
> +And it needs to have "compatible" property too.
> +In addition, CPU side driver needs to call asoc_simple_card_try_to_probe_graph_card().
> +It will probe specified Card driver if it could find "compatible" property on port.
> +Otherwise, it will do nothing.
> +
> +Required properties:
> +
> +- compatible : "asoc-simple-graph-card";
> +- type : "sound";
> +
> +Example
> +
> +ak4643: codec@12 {
> + compatible = "asahi-kasei,ak4643";
> + ...
> + port {
> + type = "sound";
> + ak4643_port: endpoint {
> + remote-endpoint = <&rcar_ak4643_port>;
> + ...
> + };
> + };
> +};
> +
> +rcar_sound {
> + ...
> + port {
> + compatible = "asoc-simple-graph-card";
Do you have an example where you'd have multiple ports? If not, this
should go up a level.
> +
> + simple-audio-card,format = "left_j";
> + simple-audio-card,bitclock-master = <&ak4643_port>;
> + simple-audio-card,frame-master = <&ak4643_port>;
If you follow video-interfaces.txt, these should all go in the endpoint
node.
> + type = "sound";
> + rcar_ak4643_port: endpoint {
> + remote-endpoint = <&ak4643_port>;
> + ...
> + };
> + };
> +};
> --
> 1.9.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
* [PATCH 0/3] Enable ADC on STM32
From: Fabrice Gasnier @ 2016-12-02 13:56 UTC (permalink / raw)
To: alexandre.torgue, mcoquelin.stm32, linux, mark.rutland, robh+dt
Cc: devicetree, linux-arm-kernel, linux-kernel
Enable minimal configuration and device tree to support ADC on STM32,
using ADC driver: https://lwn.net/Articles/706445/
Simple test on stm32f429i-eval board, using on-board potentiometer:
- cd /sys/bus/iio/devices/iio\:device0/
- cat in_voltage8_raw
Fabrice Gasnier (3):
ARM: configs: stm32: enable ADC driver
ARM: dts: stm32: Add ADC support to stm32f429
ARM: dts: stm32: enable ADC on stm32f429i-eval board
arch/arm/boot/dts/stm32429i-eval.dts | 25 ++++++++++++++++++
arch/arm/boot/dts/stm32f429.dtsi | 49 ++++++++++++++++++++++++++++++++++++
arch/arm/configs/stm32_defconfig | 5 ++++
3 files changed, 79 insertions(+)
--
1.9.1
^ permalink raw reply
* [PATCH 1/3] ARM: configs: stm32: enable ADC driver
From: Fabrice Gasnier @ 2016-12-02 13:57 UTC (permalink / raw)
To: alexandre.torgue-qxv4g6HH51o,
mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
linux-I+IVW8TIWO2tmTQ+vhA3Yw, mark.rutland-5wv7dgnIgG8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1480687022-12851-1-git-send-email-fabrice.gasnier-qxv4g6HH51o@public.gmane.org>
ADC driver depends on REGULATOR and IIO that are not yet selected.
Current hardware boards (like stm32f429i-eval) is using fixed
regulators.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier-qxv4g6HH51o@public.gmane.org>
---
arch/arm/configs/stm32_defconfig | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/arch/arm/configs/stm32_defconfig b/arch/arm/configs/stm32_defconfig
index a60b5cb..92ccc3c 100644
--- a/arch/arm/configs/stm32_defconfig
+++ b/arch/arm/configs/stm32_defconfig
@@ -49,6 +49,8 @@ CONFIG_SERIAL_STM32=y
CONFIG_SERIAL_STM32_CONSOLE=y
# CONFIG_HW_RANDOM is not set
# CONFIG_HWMON is not set
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
# CONFIG_USB_SUPPORT is not set
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
@@ -57,6 +59,9 @@ CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_DMADEVICES=y
CONFIG_STM32_DMA=y
+CONFIG_IIO=y
+CONFIG_STM32_ADC_CORE=y
+CONFIG_STM32_ADC=y
# CONFIG_FILE_LOCKING is not set
# CONFIG_DNOTIFY is not set
# CONFIG_INOTIFY_USER is not set
--
1.9.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 2/3] ARM: dts: stm32: Add ADC support to stm32f429
From: Fabrice Gasnier @ 2016-12-02 13:57 UTC (permalink / raw)
To: alexandre.torgue, mcoquelin.stm32, linux, mark.rutland, robh+dt
Cc: devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <1480687022-12851-1-git-send-email-fabrice.gasnier@st.com>
Add ADC support & pinctrl analog phandle (adc3_in8) to stm32f429.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
arch/arm/boot/dts/stm32f429.dtsi | 49 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 49 insertions(+)
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index 3dd47eb..be1d970 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -172,6 +172,49 @@
status = "disabled";
};
+ adc: adc@40012000 {
+ compatible = "st,stm32f4-adc-core";
+ reg = <0x40012000 0x400>;
+ interrupts = <18>;
+ clocks = <&rcc 0 168>;
+ clock-names = "adc";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+
+ adc1: adc@0 {
+ compatible = "st,stm32f4-adc";
+ #io-channel-cells = <1>;
+ reg = <0x0>;
+ clocks = <&rcc 0 168>;
+ interrupt-parent = <&adc>;
+ interrupts = <0>;
+ status = "disabled";
+ };
+
+ adc2: adc@100 {
+ compatible = "st,stm32f4-adc";
+ #io-channel-cells = <1>;
+ reg = <0x100>;
+ clocks = <&rcc 0 169>;
+ interrupt-parent = <&adc>;
+ interrupts = <1>;
+ status = "disabled";
+ };
+
+ adc3: adc@200 {
+ compatible = "st,stm32f4-adc";
+ #io-channel-cells = <1>;
+ reg = <0x200>;
+ clocks = <&rcc 0 170>;
+ interrupt-parent = <&adc>;
+ interrupts = <2>;
+ status = "disabled";
+ };
+ };
+
syscfg: system-config@40013800 {
compatible = "syscon";
reg = <0x40013800 0x400>;
@@ -334,6 +377,12 @@
slew-rate = <2>;
};
};
+
+ adc3_in8_pin: adc@200 {
+ pins {
+ pinmux = <STM32F429_PF10_FUNC_ANALOG>;
+ };
+ };
};
rcc: rcc@40023810 {
--
1.9.1
^ permalink raw reply related
* [PATCH 3/3] ARM: dts: stm32: enable ADC on stm32f429i-eval board
From: Fabrice Gasnier @ 2016-12-02 13:57 UTC (permalink / raw)
To: alexandre.torgue, mcoquelin.stm32, linux, mark.rutland, robh+dt
Cc: devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <1480687022-12851-1-git-send-email-fabrice.gasnier@st.com>
Enable analog to digital converter on stm32f429i-eval board.
It has on-board potentimeter wired to ADC3 in8 analog pin and
uses fixed regulator to provide reference voltage.
Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
arch/arm/boot/dts/stm32429i-eval.dts | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts
index 13c7cd2..6be0a24 100644
--- a/arch/arm/boot/dts/stm32429i-eval.dts
+++ b/arch/arm/boot/dts/stm32429i-eval.dts
@@ -65,6 +65,20 @@
serial0 = &usart1;
};
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_vref: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "vref";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+
leds {
compatible = "gpio-leds";
green {
@@ -123,3 +137,14 @@
pinctrl-names = "default";
status = "okay";
};
+
+&adc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&adc3_in8_pin>;
+ vref-supply = <®_vref>;
+ status = "okay";
+ adc3: adc@200 {
+ st,adc-channels = <8>;
+ status = "okay";
+ };
+};
--
1.9.1
^ permalink raw reply related
* Re: [PATCH v3 6/7] IIO: add STM32 timer trigger driver
From: Lee Jones @ 2016-12-02 13:57 UTC (permalink / raw)
To: Benjamin Gaignard
Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
arnaud.pouliquen-qxv4g6HH51o,
linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard
In-Reply-To: <1480673842-20804-7-git-send-email-benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
On Fri, 02 Dec 2016, Benjamin Gaignard wrote:
> Timers IPs can be used to generate triggers for other IPs like
> DAC, ADC or other timers.
> Each trigger may result of timer internals signals like counter enable,
> reset or edge, this configuration could be done through "master_mode"
> device attribute.
>
> A timer device could be triggered by other timers, we use the trigger
> name and is_stm32_iio_timer_trigger() function to distinguish them
> and configure IP input switch.
>
> Timer may also decide on which event (edge, level) they could
> be activated by a trigger, this configuration is done by writing in
> "slave_mode" device attribute.
>
> Since triggers could also be used by DAC or ADC their names are defined
> in include/dt-bindings/iio/timer/st,stm32-iio-timer.h so those IPs will be able
> to configure themselves in valid_trigger function
>
> Trigger have a "sampling_frequency" attribute which allow to configure
> timer sampling frequency without using pwm interface
>
> version 3:
> - change compatible to "st,stm32-timer-trigger"
> - fix attributes access right
> - use string instead of int for master_mode and slave_mode
> - document device attributes in sysfs-bus-iio-timer-stm32
>
> version 2:
> - keep only one compatible
> - use st,input-triggers-names and st,output-triggers-names
> to know which triggers are accepted and/or create by the device
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
> ---
> .../ABI/testing/sysfs-bus-iio-timer-stm32 | 47 ++
> drivers/iio/Kconfig | 2 +-
> drivers/iio/Makefile | 1 +
> drivers/iio/timer/Kconfig | 15 +
> drivers/iio/timer/Makefile | 1 +
> drivers/iio/timer/stm32-timer-trigger.c | 477 +++++++++++++++++++++
> drivers/iio/trigger/Kconfig | 1 -
> .../iio/timer/st,stm32-timer-triggers.h | 60 +++
> include/linux/iio/timer/stm32-timer-trigger.h | 16 +
> 9 files changed, 618 insertions(+), 2 deletions(-)
> create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
> create mode 100644 drivers/iio/timer/Kconfig
> create mode 100644 drivers/iio/timer/Makefile
> create mode 100644 drivers/iio/timer/stm32-timer-trigger.c
> create mode 100644 include/dt-bindings/iio/timer/st,stm32-timer-triggers.h
> create mode 100644 include/linux/iio/timer/stm32-timer-trigger.h
>
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
> new file mode 100644
> index 0000000..b70bb2a
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
> @@ -0,0 +1,47 @@
> +What: /sys/bus/iio/devices/iio:deviceX/master_mode_available
> +KernelVersion: 4.10
> +Contact: benjamin.gaignard-qxv4g6HH51o@public.gmane.org
> +Description:
> + Reading returns the list possible master modes which are:
> + - "reset" : The UG bit from the TIMx_EGR register is used as trigger output (TRGO).
> + - "enable" : The Counter Enable signal CNT_EN is used as trigger output.
> + - "update" : The update event is selected as trigger output.
> + For instance a master timer can then be used as a prescaler for a slave timer.
> + - "compare_pulse" : The trigger output send a positive pulse when the CC1IF flag is to be set.
> + - "OC1REF" : OC1REF signal is used as trigger output.
> + - "OC2REF" : OC2REF signal is used as trigger output.
> + - "OC3REF" : OC3REF signal is used as trigger output.
> + - "OC4REF" : OC4REF signal is used as trigger output.
> +
> +What: /sys/bus/iio/devices/iio:deviceX/master_mode
> +KernelVersion: 4.10
> +Contact: benjamin.gaignard-qxv4g6HH51o@public.gmane.org
> +Description:
> + Reading returns the current master modes.
> + Writing set the master mode
> +
> +What: /sys/bus/iio/devices/iio:deviceX/slave_mode_available
> +KernelVersion: 4.10
> +Contact: benjamin.gaignard-qxv4g6HH51o@public.gmane.org
> +Description:
> + Reading returns the list possible slave modes which are:
> + - "disabled" : The prescaler is clocked directly by the internal clock.
> + - "encoder_1" : Counter counts up/down on TI2FP1 edge depending on TI1FP2 level.
> + - "encoder_2" : Counter counts up/down on TI1FP2 edge depending on TI2FP1 level.
> + - "encoder_3" : Counter counts up/down on both TI1FP1 and TI2FP2 edges depending
> + on the level of the other input.
> + - "reset" : Rising edge of the selected trigger input reinitializes the counter
> + and generates an update of the registers.
> + - "gated" : The counter clock is enabled when the trigger input is high.
> + The counter stops (but is not reset) as soon as the trigger becomes low.
> + Both start and stop of the counter are controlled.
> + - "trigger" : The counter starts at a rising edge of the trigger TRGI (but it is not
> + reset). Only the start of the counter is controlled.
> + - "external_clock": Rising edges of the selected trigger (TRGI) clock the counter.
> +
> +What: /sys/bus/iio/devices/iio:deviceX/slave_mode
> +KernelVersion: 4.10
> +Contact: benjamin.gaignard-qxv4g6HH51o@public.gmane.org
> +Description:
> + Reading returns the current slave mode.
> + Writing set the slave mode
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> index 6743b18..2de2a80 100644
> --- a/drivers/iio/Kconfig
> +++ b/drivers/iio/Kconfig
> @@ -90,5 +90,5 @@ source "drivers/iio/potentiometer/Kconfig"
> source "drivers/iio/pressure/Kconfig"
> source "drivers/iio/proximity/Kconfig"
> source "drivers/iio/temperature/Kconfig"
> -
> +source "drivers/iio/timer/Kconfig"
> endif # IIO
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> index 87e4c43..b797c08 100644
> --- a/drivers/iio/Makefile
> +++ b/drivers/iio/Makefile
> @@ -32,4 +32,5 @@ obj-y += potentiometer/
> obj-y += pressure/
> obj-y += proximity/
> obj-y += temperature/
> +obj-y += timer/
> obj-y += trigger/
> diff --git a/drivers/iio/timer/Kconfig b/drivers/iio/timer/Kconfig
> new file mode 100644
> index 0000000..149a917
> --- /dev/null
> +++ b/drivers/iio/timer/Kconfig
> @@ -0,0 +1,15 @@
> +#
> +# Timers drivers
> +
> +menu "Timers"
> +
> +config IIO_STM32_TIMER_TRIGGER
> + tristate "stm32 timer trigger"
"STM32 Timer Trigger"
> + depends on ARCH_STM32
> + depends on OF
Are these build or run time dependencies?
If they are only run-time, add "|| COMPILE_TEST".
> + select IIO_TRIGGERED_EVENT
> + select MFD_STM32_GP_TIMER
> + help
> + Select this option to enable stm32 timer trigger
> +
> +endmenu
> diff --git a/drivers/iio/timer/Makefile b/drivers/iio/timer/Makefile
> new file mode 100644
> index 0000000..4ad95ec9
> --- /dev/null
> +++ b/drivers/iio/timer/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o
> diff --git a/drivers/iio/timer/stm32-timer-trigger.c b/drivers/iio/timer/stm32-timer-trigger.c
> new file mode 100644
> index 0000000..0c51601
> --- /dev/null
> +++ b/drivers/iio/timer/stm32-timer-trigger.c
> @@ -0,0 +1,477 @@
> +/*
> + * stm32-iio-timer.c
Swap this out for a description.
Filenames have a habit of becoming out-of-date.
> + * Copyright (C) STMicroelectronics 2016
'\n'
> + * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
You don't need to put the "for" bit. That's just what we do when
Linaro are writing drivers for other companies. Your email address
says enough.
> + * License terms: GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/timer/stm32-timer-trigger.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/iio/triggered_event.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/stm32-gptimer.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +#define DRIVER_NAME "stm32-timer-trigger"
Just use the name in the correct places. Defining device names is an
ugly practice IMHO.
> +#define MAX_MODES 8
> +
> +struct stm32_timer_trigger_dev {
> + struct device *dev;
> + struct regmap *regmap;
> + struct clk *clk;
> + int irq;
> + bool own_timer;
> + unsigned int sampling_frequency;
> + struct iio_trigger *active_trigger;
> +};
> +
> +static ssize_t _store_frequency(struct device *dev,
What's with the '_' naming scheme?
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct iio_trigger *trig = to_iio_trigger(dev);
> + struct stm32_timer_trigger_dev *stm32 = iio_trigger_get_drvdata(trig);
> + unsigned int freq;
> + int ret;
> +
> + ret = kstrtouint(buf, 10, &freq);
> + if (ret)
> + return ret;
No bounds checking required?
> + stm32->sampling_frequency = freq;
Where is this value placed into the registers?
> + return len;
> +}
> +
> +static ssize_t _read_frequency(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct iio_trigger *trig = to_iio_trigger(dev);
> + struct stm32_timer_trigger_dev *stm32 = iio_trigger_get_drvdata(trig);
> + unsigned long long freq = stm32->sampling_frequency;
> + u32 psc, arr, cr1;
> +
> + regmap_read(stm32->regmap, TIM_CR1, &cr1);
> + regmap_read(stm32->regmap, TIM_PSC, &psc);
> + regmap_read(stm32->regmap, TIM_ARR, &arr);
> +
> + if (psc && arr && (cr1 & TIM_CR1_CEN)) {
> + freq = (unsigned long long)clk_get_rate(stm32->clk);
> + do_div(freq, psc);
> + do_div(freq, arr);
> + }
> +
> + return sprintf(buf, "%d\n", (unsigned int)freq);
> +}
> +
> +static IIO_DEV_ATTR_SAMP_FREQ(0660, _read_frequency, _store_frequency);
> +
> +static struct attribute *stm32_trigger_attrs[] = {
> + &iio_dev_attr_sampling_frequency.dev_attr.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group stm32_trigger_attr_group = {
> + .attrs = stm32_trigger_attrs,
> +};
> +
> +static const struct attribute_group *stm32_trigger_attr_groups[] = {
> + &stm32_trigger_attr_group,
> + NULL,
> +};
A lot of generic code here.
Are there macros that could help with this?
> +static char *master_mode_table[] = {
> + "reset",
> + "enable",
> + "update",
> + "compare_pulse",
> + "OC1REF",
> + "OC2REF",
> + "OC3REF",
> + "OC4REF"
> +};
> +
> +static
Why the line break here?
[and the ones below]
> +ssize_t _show_master_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct stm32_timer_trigger_dev *stm32 = iio_priv(indio_dev);
> + u32 cr2;
> +
> + regmap_read(stm32->regmap, TIM_CR2, &cr2);
> + cr2 = (cr2 >> 4) & 0x7;
Define these SHIFT and MASK values.
> + return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);
> +}
> +
> +static
> +ssize_t _store_master_mode(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct stm32_timer_trigger_dev *stm32 = iio_priv(indio_dev);
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) {
> + if (!strncmp(master_mode_table[i], buf,
> + strlen(master_mode_table[i]))) {
> + regmap_update_bits(stm32->regmap, TIM_CR2,
> + TIM_CR2_MMS, i << 4);
Define all of the SHIFT and MASK values in this set.
> + return len;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> +static IIO_CONST_ATTR(master_mode_available,
> + "reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF");
> +
> +static IIO_DEVICE_ATTR(master_mode, 0660,
> + _show_master_mode,
> + _store_master_mode,
> + 0);
> +
> +static char *slave_mode_table[] = {
> + "disabled",
> + "encoder_1",
> + "encoder_2",
> + "encoder_3",
> + "reset",
> + "gated",
> + "trigger",
> + "external_clock",
> +};
> +
> +static
> +ssize_t _show_slave_mode(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct stm32_timer_trigger_dev *stm32 = iio_priv(indio_dev);
> + u32 smcr;
> +
> + regmap_read(stm32->regmap, TIM_SMCR, &smcr);
> + smcr &= 0x7;
> +
> + return snprintf(buf, PAGE_SIZE, "%s\n", slave_mode_table[smcr]);
> +}
> +
> +static
> +ssize_t _store_slave_mode(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t len)
> +{
> + struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> + struct stm32_timer_trigger_dev *stm32 = iio_priv(indio_dev);
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(slave_mode_table); i++) {
> + if (!strncmp(slave_mode_table[i], buf,
> + strlen(slave_mode_table[i]))) {
> + regmap_update_bits(stm32->regmap,
> + TIM_SMCR, TIM_SMCR_SMS, i);
> + return len;
> + }
> + }
> +
> + return -EINVAL;
> +}
> +
> +static IIO_CONST_ATTR(slave_mode_available,
> + "disabled encoder_1 encoder_2 encoder_3 reset gated trigger external_clock");
> +
> +static IIO_DEVICE_ATTR(slave_mode, 0660,
> + _show_slave_mode,
> + _store_slave_mode,
> + 0);
> +
> +static struct attribute *stm32_timer_attrs[] = {
> + &iio_dev_attr_master_mode.dev_attr.attr,
> + &iio_const_attr_master_mode_available.dev_attr.attr,
> + &iio_dev_attr_slave_mode.dev_attr.attr,
> + &iio_const_attr_slave_mode_available.dev_attr.attr,
> + NULL,
> +};
> +
> +static const struct attribute_group stm32_timer_attr_group = {
> + .attrs = stm32_timer_attrs,
> +};
> +
> +static int stm32_timer_start(struct stm32_timer_trigger_dev *stm32)
> +{
> + unsigned long long prd, div;
> + int prescaler = 0;
> + u32 max_arr = 0xFFFF, cr1;
Since this is const, it'll be better of as a define.
> + if (stm32->sampling_frequency == 0)
> + return 0;
Is this okay? Or is this an error?
> + /* Period and prescaler values depends of clock rate */
> + div = (unsigned long long)clk_get_rate(stm32->clk);
> +
> + do_div(div, stm32->sampling_frequency);
> +
> + prd = div;
> +
> + while (div > max_arr) {
> + prescaler++;
> + div = prd;
> + do_div(div, (prescaler + 1));
> + }
> + prd = div;
Best to place a comment here. Saves the reader having to work it out.
> + if (prescaler > MAX_TIM_PSC) {
> + dev_err(stm32->dev, "prescaler exceeds the maximum value\n");
> + return -EINVAL;
> + }
> +
> + /* Check that we own the timer */
> + regmap_read(stm32->regmap, TIM_CR1, &cr1);
> + if ((cr1 & TIM_CR1_CEN) && !stm32->own_timer)
> + return -EBUSY;
What happens if the timer is already enabled and you do own it?
I guess this *re*-starts it?
> + if (!stm32->own_timer) {
> + stm32->own_timer = true;
> + clk_enable(stm32->clk);
> + }
At the very least you're going to require some shared locking here.
At best you should have a shared "device held" flag.
> + regmap_write(stm32->regmap, TIM_PSC, prescaler);
> + regmap_write(stm32->regmap, TIM_ARR, prd - 1);
> + regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
> +
> + /* Force master mode to update mode */
> + regmap_update_bits(stm32->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
> +
> + /* Make sure that registers are updated */
> + regmap_update_bits(stm32->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
> +
> + /* Enable interrupt */
> + regmap_write(stm32->regmap, TIM_SR, 0);
> + regmap_update_bits(stm32->regmap, TIM_DIER, TIM_DIER_UIE, TIM_DIER_UIE);
> +
> + /* Enable controller */
> + regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
> +
> + return 0;
> +}
> +
> +static int stm32_timer_stop(struct stm32_timer_trigger_dev *stm32)
> +{
> + if (!stm32->own_timer)
> + return 0;
> +
> + /* Stop timer */
> + regmap_update_bits(stm32->regmap, TIM_DIER, TIM_DIER_UIE, 0);
> + regmap_update_bits(stm32->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> + regmap_write(stm32->regmap, TIM_PSC, 0);
> + regmap_write(stm32->regmap, TIM_ARR, 0);
> +
> + clk_disable(stm32->clk);
> +
> + stm32->own_timer = false;
> + stm32->active_trigger = NULL;
> +
> + return 0;
> +}
> +
> +static int stm32_set_trigger_state(struct iio_trigger *trig, bool state)
> +{
> + struct stm32_timer_trigger_dev *stm32 = iio_trigger_get_drvdata(trig);
> +
> + stm32->active_trigger = trig;
> +
> + if (state)
> + return stm32_timer_start(stm32);
> + else
> + return stm32_timer_stop(stm32);
> +}
> +
> +static irqreturn_t stm32_timer_irq_handler(int irq, void *private)
> +{
> + struct stm32_timer_trigger_dev *stm32 = private;
> + u32 sr;
> +
> + regmap_read(stm32->regmap, TIM_SR, &sr);
> + regmap_write(stm32->regmap, TIM_SR, 0);
> +
> + if ((sr & TIM_SR_UIF) && stm32->active_trigger)
> + iio_trigger_poll(stm32->active_trigger);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static const struct iio_trigger_ops timer_trigger_ops = {
> + .owner = THIS_MODULE,
> + .set_trigger_state = stm32_set_trigger_state,
> +};
> +
> +static int stm32_setup_iio_triggers(struct stm32_timer_trigger_dev *stm32)
> +{
> + int ret;
> + struct property *p;
> + const char *cur = NULL;
> +
> + p = of_find_property(stm32->dev->of_node,
> + "st,output-triggers-names", NULL);
> +
> + while ((cur = of_prop_next_string(p, cur)) != NULL) {
> + struct iio_trigger *trig;
> +
> + trig = devm_iio_trigger_alloc(stm32->dev, "%s", cur);
> + if (!trig)
> + return -ENOMEM;
> +
> + trig->dev.parent = stm32->dev->parent;
> + trig->ops = &timer_trigger_ops;
> + trig->dev.groups = stm32_trigger_attr_groups;
> + iio_trigger_set_drvdata(trig, stm32);
> +
> + ret = devm_iio_trigger_register(stm32->dev, trig);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * is_stm32_timer_trigger
> + * @trig: trigger to be checked
> + *
> + * return true if the trigger is a valid stm32 iio timer trigger
> + * either return false
> + */
> +bool is_stm32_timer_trigger(struct iio_trigger *trig)
> +{
> + return (trig->ops == &timer_trigger_ops);
> +}
> +EXPORT_SYMBOL(is_stm32_timer_trigger);
> +
> +static int stm32_validate_trigger(struct iio_dev *indio_dev,
> + struct iio_trigger *trig)
> +{
> + struct stm32_timer_trigger_dev *dev = iio_priv(indio_dev);
> + int ret;
> +
> + if (!is_stm32_timer_trigger(trig))
> + return -EINVAL;
> +
> + ret = of_property_match_string(dev->dev->of_node,
> + "st,input-triggers-names",
> + trig->name);
> +
> + if (ret < 0)
> + return ret;
> +
> + regmap_update_bits(dev->regmap, TIM_SMCR, TIM_SMCR_TS, ret << 4);
> +
> + return 0;
> +}
> +
> +static const struct iio_info stm32_trigger_info = {
> + .driver_module = THIS_MODULE,
> + .validate_trigger = stm32_validate_trigger,
> + .attrs = &stm32_timer_attr_group,
> +};
> +
> +static struct stm32_timer_trigger_dev *stm32_setup_iio_device(struct device *dev)
> +{
> + struct iio_dev *indio_dev;
> + int ret;
> + indio_dev = devm_iio_device_alloc(dev, sizeof(struct stm32_timer_trigger_dev));
Did you run checkpatch.pl?
> + if (!indio_dev)
> + return NULL;
> +
> + indio_dev->name = dev_name(dev);
> + indio_dev->dev.parent = dev;
> + indio_dev->info = &stm32_trigger_info;
> + indio_dev->modes = INDIO_EVENT_TRIGGERED;
> + indio_dev->num_channels = 0;
> + indio_dev->dev.of_node = dev->of_node;
> +
> + ret = iio_triggered_event_setup(indio_dev,
> + NULL,
> + stm32_timer_irq_handler);
> + if (ret)
> + return NULL;
Return ERR_PTR(ret).
> + ret = devm_iio_device_register(dev, indio_dev);
> + if (ret) {
> + iio_triggered_event_cleanup(indio_dev);
> + return NULL;
Return ERR_PTR(ret).
> + }
> +
> + return iio_priv(indio_dev);
> +}
> +
> +static int stm32_timer_trigger_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct stm32_timer_trigger_dev *stm32;
> + struct stm32_gptimer_dev *mfd = dev_get_drvdata(pdev->dev.parent);
> + int ret;
> +
> + stm32 = stm32_setup_iio_device(dev);
> + if (!stm32)
> + return -ENOMEM;
Return stm32.
> + stm32->dev = dev;
> + stm32->regmap = mfd->regmap;
> + stm32->clk = mfd->clk;
> +
> + stm32->irq = platform_get_irq(pdev, 0);
> + if (stm32->irq < 0)
> + return -EINVAL;
return stm32->irq.
> + ret = devm_request_irq(stm32->dev, stm32->irq,
> + stm32_timer_irq_handler, IRQF_SHARED,
> + "timer_event", stm32);
> + if (ret)
> + return ret;
> +
> + ret = stm32_setup_iio_triggers(stm32);
> + if (ret)
> + return ret;
> +
> + platform_set_drvdata(pdev, stm32);
> +
> + return 0;
> +}
> +
> +static int stm32_timer_trigger_remove(struct platform_device *pdev)
> +{
> + struct stm32_timer_trigger_dev *stm32 = platform_get_drvdata(pdev);
> +
> + iio_triggered_event_cleanup((struct iio_dev *)stm32);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id stm32_trig_of_match[] = {
> + {
> + .compatible = "st,stm32-timer-trigger",
> + },
> +};
Make this one line.
{ .compatible = "st,stm32-timer-trigger" },
> +MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
> +
> +static struct platform_driver stm32_timer_trigger_driver = {
> + .probe = stm32_timer_trigger_probe,
> + .remove = stm32_timer_trigger_remove,
> + .driver = {
> + .name = DRIVER_NAME,
Yuk!
> + .of_match_table = stm32_trig_of_match,
> + },
> +};
> +module_platform_driver(stm32_timer_trigger_driver);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_DESCRIPTION("STMicroelectronics STM32 timer trigger driver");
> +MODULE_LICENSE("GPL");
I thought this was "GPL v2"?
> diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
> index 809b2e7..f2af4fe 100644
> --- a/drivers/iio/trigger/Kconfig
> +++ b/drivers/iio/trigger/Kconfig
> @@ -46,5 +46,4 @@ config IIO_SYSFS_TRIGGER
>
> To compile this driver as a module, choose M here: the
> module will be called iio-trig-sysfs.
> -
> endmenu
> diff --git a/include/dt-bindings/iio/timer/st,stm32-timer-triggers.h b/include/dt-bindings/iio/timer/st,stm32-timer-triggers.h
> new file mode 100644
> index 0000000..a13db63
> --- /dev/null
> +++ b/include/dt-bindings/iio/timer/st,stm32-timer-triggers.h
> @@ -0,0 +1,60 @@
> +/*
> + * st,stm32-timer-triggers.h
> + * Copyright (C) STMicroelectronics 2016
> + * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
> + * License terms: GNU General Public License (GPL), version 2
> + */
Same comments as the top header.
> +#ifndef _DT_BINDINGS_STM32_TIMER_TRIGGERS_H_
> +#define _DT_BINDINGS_STM32_TIMER_TRIGGERS_H_
> +
> +#define TIM1_TRGO "tim1_trgo"
> +#define TIM1_CH1 "tim1_ch1"
> +#define TIM1_CH2 "tim1_ch2"
> +#define TIM1_CH3 "tim1_ch3"
> +#define TIM1_CH4 "tim1_ch4"
> +
> +#define TIM2_TRGO "tim2_trgo"
> +#define TIM2_CH1 "tim2_ch1"
> +#define TIM2_CH2 "tim2_ch2"
> +#define TIM2_CH3 "tim2_ch3"
> +#define TIM2_CH4 "tim2_ch4"
> +
> +#define TIM3_TRGO "tim3_trgo"
> +#define TIM3_CH1 "tim3_ch1"
> +#define TIM3_CH2 "tim3_ch2"
> +#define TIM3_CH3 "tim3_ch3"
> +#define TIM3_CH4 "tim3_ch4"
> +
> +#define TIM4_TRGO "tim4_trgo"
> +#define TIM4_CH1 "tim4_ch1"
> +#define TIM4_CH2 "tim4_ch2"
> +#define TIM4_CH3 "tim4_ch3"
> +#define TIM4_CH4 "tim4_ch4"
> +
> +#define TIM5_TRGO "tim5_trgo"
> +#define TIM5_CH1 "tim5_ch1"
> +#define TIM5_CH2 "tim5_ch2"
> +#define TIM5_CH3 "tim5_ch3"
> +#define TIM5_CH4 "tim5_ch4"
> +
> +#define TIM6_TRGO "tim6_trgo"
> +
> +#define TIM7_TRGO "tim7_trgo"
> +
> +#define TIM8_TRGO "tim8_trgo"
> +#define TIM8_CH1 "tim8_ch1"
> +#define TIM8_CH2 "tim8_ch2"
> +#define TIM8_CH3 "tim8_ch3"
> +#define TIM8_CH4 "tim8_ch4"
> +
> +#define TIM9_TRGO "tim9_trgo"
> +#define TIM9_CH1 "tim9_ch1"
> +#define TIM9_CH2 "tim9_ch2"
> +
> +#define TIM12_TRGO "tim12_trgo"
> +#define TIM12_CH1 "tim12_ch1"
> +#define TIM12_CH2 "tim12_ch2"
Grim!
uint8 valid_timers[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 12 };
uint8 valid_channels[] = { 0, 1, 2, 3, 4 };
> +#endif
> diff --git a/include/linux/iio/timer/stm32-timer-trigger.h b/include/linux/iio/timer/stm32-timer-trigger.h
> new file mode 100644
> index 0000000..c22fb3b
> --- /dev/null
> +++ b/include/linux/iio/timer/stm32-timer-trigger.h
> @@ -0,0 +1,16 @@
> +/*
> + * stm32-timer-trigger.h
> + * Copyright (C) STMicroelectronics 2016
> + * Author: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org> for STMicroelectronics.
> + * License terms: GNU General Public License (GPL), version 2
> + */
Same comments as the top header.
> +#ifndef _STM32_TIMER_TRIGGER_H_
> +#define _STM32_TIMER_TRIGGER_H_
> +
> +#include <dt-bindings/iio/timer/st,stm32-timer-triggers.h>
> +
> +bool is_stm32_timer_trigger(struct iio_trigger *trig);
> +
> +#endif
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
--
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 v3 5/7] IIO: add bindings for stm32 timer trigger driver
From: Lee Jones @ 2016-12-02 13:59 UTC (permalink / raw)
To: Benjamin Gaignard
Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
alexandre.torgue-qxv4g6HH51o, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
thierry.reding-Re5JQEeQqe8AvxtiuMwx3w,
linux-pwm-u79uwXL29TY76Z2rM5mHXA, jic23-DgEjT+Ai2ygdnm+yROfE0A,
knaack.h-Mmb7MZpHnFY, lars-Qo5EllUWu/uELgA04lAiVw,
pmeerw-jW+XmwGofnusTnJN9+BGXg, linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
fabrice.gasnier-qxv4g6HH51o, gerald.baeza-qxv4g6HH51o,
arnaud.pouliquen-qxv4g6HH51o,
linus.walleij-QSEj5FYQhm4dnm+yROfE0A,
linaro-kernel-cunTk1MwBs8s++Sfvej+rw, Benjamin Gaignard
In-Reply-To: <1480673842-20804-6-git-send-email-benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
On Fri, 02 Dec 2016, Benjamin Gaignard wrote:
> Define bindings for stm32 timer trigger
>
> version 3:
> - change file name
> - add cross reference with mfd bindings
>
> version 2:
> - only keep one compatible
> - add DT parameters to set lists of the triggers:
> one list describe the triggers created by the device
> another one give the triggers accepted by the device
>
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard-qxv4g6HH51o@public.gmane.org>
> ---
> .../bindings/iio/timer/stm32-timer-trigger.txt | 39 ++++++++++++++++++++++
> 1 file changed, 39 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
>
> diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
> new file mode 100644
> index 0000000..858816d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
> @@ -0,0 +1,39 @@
> +timer trigger bindings for STM32
> +
> +Must be a sub-node of STM32 general purpose timer driver
> +Parent node properties are describe in ../mfd/stm32-general-purpose-timer.txt
> +
> +Required parameters:
> +- compatible: must be "st,stm32-iio-timer"
> +- interrupts: Interrupt for this device
> + See ../interrupt-controller/st,stm32-exti.txt
> +
> +Optional parameters:
> +- st,input-triggers-names: List of the possible input triggers for
> + the device
> +- st,output-triggers-names: List of the possible output triggers for
> + the device
> +
> +Possible triggers are defined in include/dt-bindings/iio/timer/st,stm32-timer-trigger.h
> +
> +Example:
> + gptimer1: gptimer1@40010000 {
> + compatible = "st,stm32-gptimer";
> + reg = <0x40010000 0x400>;
> + clocks = <&rcc 0 160>;
> + clock-names = "clk_int";
> +
> + timer1@0 {
> + compatible = "st,stm32-timer-trigger";
> + interrupts = <27>;
> + st,input-triggers-names = TIM5_TRGO,
> + TIM2_TRGO,
> + TIM4_TRGO,
> + TIM3_TRGO;
> + st,output-triggers-names = TIM1_TRGO,
> + TIM1_CH1,
> + TIM1_CH2,
> + TIM1_CH3,
> + TIM1_CH4;
I see why you've done it like this now ... because it makes things
easier for you in the driver, since the IIO subsystem matches on names
such as these.
BUT, this is a Linux-implementation-ism. Just use pairs of integers
and create the Linux-ism strings in the driver.
> + };
> + };
--
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog
^ permalink raw reply
* [PATCH 0/8] Add support for STM32 RTC
From: Amelie Delaunay @ 2016-12-02 14:09 UTC (permalink / raw)
To: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
alexandre.torgue-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
gabriel.fernandez-qxv4g6HH51o, amelie.delaunay-qxv4g6HH51o
This patchset adds support for the STM32 Real-Time Clock.
This RTC is an independent BCD timer/counter and provides a time-of-day
clock/calendar with programmable alarm interrupt.
RTC calendar can be driven by three clock sources LSE, LSI or HSE.
Amelie Delaunay (8):
ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
dt-bindings: document the STM32 RTC bindings
rtc: add STM32 RTC driver
ARM: dts: stm32: Add STM32 RTC support for STM32F429 MCU
ARM: dts: stm32: enable RTC on stm32f429-disco
ARM: dts: stm32: enable RTC on stm32f469-disco
ARM: dts: stm32: enable RTC on stm32429i-eval
ARM: configs: stm32: Add STM32 RTC support in STM32 defconfig
.../devicetree/bindings/rtc/st,stm32-rtc.txt | 31 +
arch/arm/boot/dts/stm32429i-eval.dts | 4 +
arch/arm/boot/dts/stm32f429-disco.dts | 6 +
arch/arm/boot/dts/stm32f429.dtsi | 16 +
arch/arm/boot/dts/stm32f469-disco.dts | 4 +
arch/arm/configs/stm32_defconfig | 2 +
drivers/rtc/Kconfig | 10 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-stm32.c | 777 +++++++++++++++++++++
9 files changed, 851 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
create mode 100644 drivers/rtc/rtc-stm32.c
--
1.9.1
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
* [PATCH 1/8] ARM: dts: stm32: set HSE_RTC clock frequency to 1 MHz on stm32f429
From: Amelie Delaunay @ 2016-12-02 14:09 UTC (permalink / raw)
To: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
alexandre.torgue-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
gabriel.fernandez-qxv4g6HH51o, amelie.delaunay-qxv4g6HH51o
In-Reply-To: <1480687801-19525-2-git-send-email-amelie.delaunay-qxv4g6HH51o@public.gmane.org>
This patch set HSE_RTC clock frequency to 1 MHz, as the clock supplied to
the RTC must be 1 MHz.
Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
---
arch/arm/boot/dts/stm32f429.dtsi | 2 ++
1 file changed, 2 insertions(+)
diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
index b077f99..d195ccf 100644
--- a/arch/arm/boot/dts/stm32f429.dtsi
+++ b/arch/arm/boot/dts/stm32f429.dtsi
@@ -371,6 +371,8 @@
reg = <0x40023800 0x400>;
clocks = <&clk_hse>, <&clk_i2s_ckin>;
st,syscfg = <&pwrcfg>;
+ assigned-clocks = <&rcc 1 CLK_HSE_RTC>;
+ assigned-clock-rates = <1000000>;
};
dma1: dma-controller@40026000 {
--
1.9.1
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related
* [PATCH 2/8] dt-bindings: document the STM32 RTC bindings
From: Amelie Delaunay @ 2016-12-02 14:09 UTC (permalink / raw)
To: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
alexandre.torgue-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
gabriel.fernandez-qxv4g6HH51o, amelie.delaunay-qxv4g6HH51o
In-Reply-To: <1480687801-19525-2-git-send-email-amelie.delaunay-qxv4g6HH51o@public.gmane.org>
This patch adds documentation of device tree bindings for the STM32 RTC.
Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
---
.../devicetree/bindings/rtc/st,stm32-rtc.txt | 31 ++++++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
new file mode 100644
index 0000000..4578838
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
@@ -0,0 +1,31 @@
+STM32 Real Time Clock
+
+Required properties:
+- compatible: "st,stm32-rtc".
+- reg: address range of rtc register set.
+- clocks: reference to the clock entry ck_rtc.
+- clock-names: name of the clock used. Should be "ck_rtc".
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+- interrupt-names: rtc alarm interrupt name, should be "alarm".
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+ (RTC registers) write protection.
+
+Optional properties (to override default ck_rtc parent clock):
+- assigned-clocks: reference to the ck_rtc clock entry.
+- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+
+Example:
+
+ rtc: rtc@40002800 {
+ compatible = "st,stm32-rtc";
+ reg = <0x40002800 0x400>;
+ clocks = <&rcc 1 CLK_RTC>;
+ clock-names = "ck_rtc";
+ assigned-clocks = <&rcc 1 CLK_RTC>;
+ assigned-clock-parents = <&rcc 1 CLK_LSE>;
+ interrupt-parent = <&exti>;
+ interrupts = <17 1>;
+ interrupt-names = "alarm";
+ st,syscfg = <&pwrcfg>;
+ };
--
1.9.1
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related
* [PATCH 3/8] rtc: add STM32 RTC driver
From: Amelie Delaunay @ 2016-12-02 14:09 UTC (permalink / raw)
To: a.zummo-BfzFCNDTiLLj+vYz1yj4TQ,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w,
alexandre.torgue-qxv4g6HH51o, linux-I+IVW8TIWO2tmTQ+vhA3Yw
Cc: rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
gabriel.fernandez-qxv4g6HH51o, amelie.delaunay-qxv4g6HH51o
In-Reply-To: <1480687801-19525-2-git-send-email-amelie.delaunay-qxv4g6HH51o@public.gmane.org>
This patch adds support for the STM32 RTC.
Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
---
drivers/rtc/Kconfig | 10 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-stm32.c | 777 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 788 insertions(+)
create mode 100644 drivers/rtc/rtc-stm32.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e859d14..dd8b218 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1706,6 +1706,16 @@ config RTC_DRV_PIC32
This driver can also be built as a module. If so, the module
will be called rtc-pic32
+config RTC_DRV_STM32
+ tristate "STM32 On-Chip RTC"
+ depends on ARCH_STM32
+ help
+ If you say yes here you get support for the STM32 On-Chip
+ Real Time Clock.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-stm32".
+
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 1ac694a..87bd9cc 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
new file mode 100644
index 0000000..9e710ff
--- /dev/null
+++ b/drivers/rtc/rtc-stm32.c
@@ -0,0 +1,777 @@
+/*
+ * Copyright (C) Amelie Delaunay 2015
+ * Author: Amelie Delaunay <adelaunay.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/spinlock.h>
+
+#define DRIVER_NAME "stm32_rtc"
+
+/* STM32 RTC registers */
+#define STM32_RTC_TR 0x00
+#define STM32_RTC_DR 0x04
+#define STM32_RTC_CR 0x08
+#define STM32_RTC_ISR 0x0C
+#define STM32_RTC_PRER 0x10
+#define STM32_RTC_ALRMAR 0x1C
+#define STM32_RTC_WPR 0x24
+
+/* STM32_RTC_TR bit fields */
+#define STM32_RTC_TR_SEC_SHIFT 0
+#define STM32_RTC_TR_SEC GENMASK(6, 0)
+#define STM32_RTC_TR_MIN_SHIFT 8
+#define STM32_RTC_TR_MIN GENMASK(14, 8)
+#define STM32_RTC_TR_HOUR_SHIFT 16
+#define STM32_RTC_TR_HOUR GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DR_DATE_SHIFT 0
+#define STM32_RTC_DR_DATE GENMASK(5, 0)
+#define STM32_RTC_DR_MONTH_SHIFT 8
+#define STM32_RTC_DR_MONTH GENMASK(11, 8)
+#define STM32_RTC_DR_WDAY_SHIFT 13
+#define STM32_RTC_DR_WDAY GENMASK(15, 13)
+#define STM32_RTC_DR_YEAR_SHIFT 16
+#define STM32_RTC_DR_YEAR GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT BIT(6)
+#define STM32_RTC_CR_ALRAE BIT(8)
+#define STM32_RTC_CR_ALRAIE BIT(12)
+
+/* STM32_RTC_ISR bit fields */
+#define STM32_RTC_ISR_ALRAWF BIT(0)
+#define STM32_RTC_ISR_INITS BIT(4)
+#define STM32_RTC_ISR_RSF BIT(5)
+#define STM32_RTC_ISR_INITF BIT(6)
+#define STM32_RTC_ISR_INIT BIT(7)
+#define STM32_RTC_ISR_ALRAF BIT(8)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT 0
+#define STM32_RTC_PRER_PRED_S GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT 16
+#define STM32_RTC_PRER_PRED_A GENMASK(22, 16)
+
+/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
+#define STM32_RTC_ALRMXR_SEC_SHIFT 0
+#define STM32_RTC_ALRMXR_SEC GENMASK(6, 0)
+#define STM32_RTC_ALRMXR_SEC_MASK BIT(7)
+#define STM32_RTC_ALRMXR_MIN_SHIFT 8
+#define STM32_RTC_ALRMXR_MIN GENMASK(14, 8)
+#define STM32_RTC_ALRMXR_MIN_MASK BIT(15)
+#define STM32_RTC_ALRMXR_HOUR_SHIFT 16
+#define STM32_RTC_ALRMXR_HOUR GENMASK(21, 16)
+#define STM32_RTC_ALRMXR_PM BIT(22)
+#define STM32_RTC_ALRMXR_HOUR_MASK BIT(23)
+#define STM32_RTC_ALRMXR_DATE_SHIFT 24
+#define STM32_RTC_ALRMXR_DATE GENMASK(29, 24)
+#define STM32_RTC_ALRMXR_WDSEL BIT(30)
+#define STM32_RTC_ALRMXR_WDAY_SHIFT 24
+#define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24)
+#define STM32_RTC_ALRMXR_DATE_MASK BIT(31)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY 0xCA
+#define RTC_WPR_2ND_KEY 0x53
+#define RTC_WPR_WRONG_KEY 0xFF
+
+/*
+ * RTC registers are protected agains parasitic write access.
+ * PWR_CR_DBP bit must be set to enable write access to RTC registers.
+ */
+/* STM32_PWR_CR */
+#define PWR_CR 0x00
+/* STM32_PWR_CR bit field */
+#define PWR_CR_DBP BIT(8)
+
+static struct regmap *dbp;
+
+struct stm32_rtc {
+ struct rtc_device *rtc_dev;
+ void __iomem *base;
+ struct clk *pclk;
+ struct clk *ck_rtc;
+ unsigned int clksrc;
+ spinlock_t lock; /* Protects registers accesses */
+ int irq_alarm;
+ struct regmap *pwrcr;
+};
+
+static inline unsigned int stm32_rtc_readl(struct stm32_rtc *rtc,
+ unsigned int offset)
+{
+ return readl_relaxed(rtc->base + offset);
+}
+
+static inline void stm32_rtc_writel(struct stm32_rtc *rtc,
+ unsigned int offset, unsigned int value)
+{
+ writel_relaxed(value, rtc->base + offset);
+}
+
+static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
+{
+// if (dbp)
+// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+ stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_1ST_KEY);
+ stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_2ND_KEY);
+}
+
+static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
+{
+ stm32_rtc_writel(rtc, STM32_RTC_WPR, RTC_WPR_WRONG_KEY);
+
+// if (dbp)
+// regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+}
+
+static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
+{
+ unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
+
+ if (!(isr & STM32_RTC_ISR_INITF)) {
+ isr |= STM32_RTC_ISR_INIT;
+ stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
+
+ return readl_relaxed_poll_timeout_atomic(
+ rtc->base + STM32_RTC_ISR,
+ isr, (isr & STM32_RTC_ISR_INITF),
+ 10, 100000);
+ }
+
+ return 0;
+}
+
+static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
+{
+ unsigned int isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_INIT;
+ stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
+}
+
+static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
+{
+ unsigned int isr;
+
+ isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
+
+ isr &= ~STM32_RTC_ISR_RSF;
+ stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
+
+ /* Wait the registers to be synchronised */
+ return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+ isr,
+ (isr & STM32_RTC_ISR_RSF),
+ 10, 100000);
+}
+
+static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
+{
+ struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
+ unsigned long irqflags, events = 0;
+ unsigned int isr, cr;
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
+ cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
+
+ if ((isr & STM32_RTC_ISR_ALRAF) &&
+ (cr & STM32_RTC_CR_ALRAIE)) {
+ /* Alarm A flag - Alarm interrupt */
+ events |= RTC_IRQF | RTC_AF;
+ isr &= ~STM32_RTC_ISR_ALRAF;
+ }
+
+ /* Clear event irqflags, otherwise new events won't be received */
+ stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ if (events) {
+ dev_info(&rtc->rtc_dev->dev, "Alarm occurred\n");
+
+ /* Pass event to the kernel */
+ rtc_update_irq(rtc->rtc_dev, 1, events);
+ return IRQ_HANDLED;
+ } else {
+ return IRQ_NONE;
+ }
+}
+
+/* Convert rtc_time structure from bin to bcd format */
+static void tm2bcd(struct rtc_time *tm)
+{
+ tm->tm_sec = bin2bcd(tm->tm_sec);
+ tm->tm_min = bin2bcd(tm->tm_min);
+ tm->tm_hour = bin2bcd(tm->tm_hour);
+
+ tm->tm_mday = bin2bcd(tm->tm_mday);
+ tm->tm_mon = bin2bcd(tm->tm_mon + 1);
+ tm->tm_year = bin2bcd(tm->tm_year - 100);
+ /*
+ * Number of days since Sunday
+ * - on kernel side, 0=Sunday...6=Saturday
+ * - on rtc side, 0=invalid,1=Monday...7=Sunday
+ */
+ tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
+}
+
+/* Convert rtc_time structure from bcd to bin format */
+static void bcd2tm(struct rtc_time *tm)
+{
+ tm->tm_sec = bcd2bin(tm->tm_sec);
+ tm->tm_min = bcd2bin(tm->tm_min);
+ tm->tm_hour = bcd2bin(tm->tm_hour);
+
+ tm->tm_mday = bcd2bin(tm->tm_mday);
+ tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
+ tm->tm_year = bcd2bin(tm->tm_year) + 100;
+ /*
+ * Number of days since Sunday
+ * - on kernel side, 0=Sunday...6=Saturday
+ * - on rtc side, 0=invalid,1=Monday...7=Sunday
+ */
+ tm->tm_wday %= 7;
+}
+
+static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tr, dr;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ /* Time and Date in BCD format */
+ tr = stm32_rtc_readl(rtc, STM32_RTC_TR);
+ dr = stm32_rtc_readl(rtc, STM32_RTC_DR);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+ tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+ tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+ tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+ tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+ tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+ tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
+
+ /* We don't report tm_yday and tm_isdst */
+
+ bcd2tm(tm);
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tr, dr;
+ unsigned long irqflags;
+ int ret = 0;
+
+ if (rtc_valid_tm(tm) < 0) {
+ dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
+ return -EINVAL;
+ }
+
+ tm2bcd(tm);
+
+ /* Time in BCD format */
+ tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
+ ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
+ ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
+
+ /* Date in BCD format */
+ dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
+ ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
+ ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
+ ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ stm32_rtc_wpr_unlock(rtc);
+
+ ret = stm32_rtc_enter_init_mode(rtc);
+ if (ret) {
+ dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
+ goto end;
+ }
+
+ stm32_rtc_writel(rtc, STM32_RTC_TR, tr);
+ stm32_rtc_writel(rtc, STM32_RTC_DR, dr);
+
+ stm32_rtc_exit_init_mode(rtc);
+
+ ret = stm32_rtc_wait_sync(rtc);
+end:
+ stm32_rtc_wpr_lock(rtc);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ return ret;
+}
+
+static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ unsigned int alrmar, cr, isr;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ alrmar = stm32_rtc_readl(rtc, STM32_RTC_ALRMAR);
+ cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
+ isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
+ /*
+ * Date/day don't care in Alarm comparison so alarm triggers
+ * every day
+ */
+ tm->tm_mday = -1;
+ tm->tm_wday = -1;
+ } else {
+ if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
+ /* Alarm is set to a day of week */
+ tm->tm_mday = -1;
+ tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
+ STM32_RTC_ALRMXR_WDAY_SHIFT;
+ tm->tm_wday %= 7;
+ } else {
+ /* Alarm is set to a day of month */
+ tm->tm_wday = -1;
+ tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
+ STM32_RTC_ALRMXR_DATE_SHIFT;
+ }
+ }
+
+ if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
+ /* Hours don't care in Alarm comparison */
+ tm->tm_hour = -1;
+ } else {
+ tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
+ STM32_RTC_ALRMXR_HOUR_SHIFT;
+ if (alrmar & STM32_RTC_ALRMXR_PM)
+ tm->tm_hour += 12;
+ }
+
+ if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
+ /* Minutes don't care in Alarm comparison */
+ tm->tm_min = -1;
+ } else {
+ tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
+ STM32_RTC_ALRMXR_MIN_SHIFT;
+ }
+
+ if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
+ /* Seconds don't care in Alarm comparison */
+ tm->tm_sec = -1;
+ } else {
+ tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
+ STM32_RTC_ALRMXR_SEC_SHIFT;
+ }
+
+ bcd2tm(tm);
+
+ alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
+ alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
+
+ return 0;
+}
+
+static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long irqflags;
+ unsigned int isr, cr;
+
+ cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ stm32_rtc_wpr_unlock(rtc);
+
+ /* We expose Alarm A to the kernel */
+ if (enabled)
+ cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+ else
+ cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+ stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
+
+ /* Clear event irqflags, otherwise new events won't be received */
+ isr = stm32_rtc_readl(rtc, STM32_RTC_ISR);
+ isr &= ~STM32_RTC_ISR_ALRAF;
+ stm32_rtc_writel(rtc, STM32_RTC_ISR, isr);
+
+ stm32_rtc_wpr_lock(rtc);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ return 0;
+}
+
+static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+ struct rtc_time *tm = &alrm->time;
+ unsigned long irqflags;
+ unsigned int cr, isr, alrmar;
+ int ret = 0;
+
+ if (rtc_valid_tm(tm)) {
+ dev_err(dev, "Alarm time not valid.\n");
+ return -EINVAL;
+ }
+
+ tm2bcd(tm);
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ stm32_rtc_wpr_unlock(rtc);
+
+ /* Disable Alarm */
+ cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
+ cr &= ~STM32_RTC_CR_ALRAE;
+ stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
+
+ /* Poll Alarm write flag to be sure that Alarm update is allowed */
+ ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+ isr,
+ (isr & STM32_RTC_ISR_ALRAWF),
+ 10, 100);
+
+ if (ret) {
+ dev_err(dev, "Alarm update not allowed\n");
+ goto end;
+ }
+
+ alrmar = 0;
+
+ if (tm->tm_mday < 0 && tm->tm_wday < 0) {
+ /*
+ * Date/day don't care in Alarm comparison so alarm triggers
+ * every day
+ */
+ alrmar |= STM32_RTC_ALRMXR_DATE_MASK;
+ } else {
+ if (tm->tm_mday > 0) {
+ /* Date is selected (ignoring wday) */
+ alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
+ STM32_RTC_ALRMXR_DATE;
+ } else {
+ /* Day of week is selected */
+ int wday = (tm->tm_wday == 0) ? 7 : tm->tm_wday;
+
+ alrmar |= STM32_RTC_ALRMXR_WDSEL;
+ alrmar |= (wday << STM32_RTC_ALRMXR_WDAY_SHIFT) &
+ STM32_RTC_ALRMXR_WDAY;
+ }
+ }
+
+ if (tm->tm_hour < 0) {
+ /* Hours don't care in Alarm comparison */
+ alrmar |= STM32_RTC_ALRMXR_HOUR_MASK;
+ } else {
+ /* 24-hour format */
+ alrmar &= ~STM32_RTC_ALRMXR_PM;
+ alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
+ STM32_RTC_ALRMXR_HOUR;
+ }
+
+ if (tm->tm_min < 0) {
+ /* Minutes don't care in Alarm comparison */
+ alrmar |= STM32_RTC_ALRMXR_MIN_MASK;
+ } else {
+ alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
+ STM32_RTC_ALRMXR_MIN;
+ }
+
+ if (tm->tm_sec < 0) {
+ /* Seconds don't care in Alarm comparison */
+ alrmar |= STM32_RTC_ALRMXR_SEC_MASK;
+ } else {
+ alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
+ STM32_RTC_ALRMXR_SEC;
+ }
+
+ /* Write to Alarm register */
+ stm32_rtc_writel(rtc, STM32_RTC_ALRMAR, alrmar);
+
+ if (alrm->enabled)
+ stm32_rtc_alarm_irq_enable(dev, 1);
+ else
+ stm32_rtc_alarm_irq_enable(dev, 0);
+
+end:
+ stm32_rtc_wpr_lock(rtc);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ return ret;
+}
+
+static const struct rtc_class_ops stm32_rtc_ops = {
+ .read_time = stm32_rtc_read_time,
+ .set_time = stm32_rtc_set_time,
+ .read_alarm = stm32_rtc_read_alarm,
+ .set_alarm = stm32_rtc_set_alarm,
+ .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id stm32_rtc_of_match[] = {
+ { .compatible = "st,stm32-rtc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
+#endif
+
+static int stm32_rtc_init(struct platform_device *pdev,
+ struct stm32_rtc *rtc)
+{
+ unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+ unsigned int rate;
+ unsigned long irqflags;
+ int ret = 0;
+
+ rate = clk_get_rate(rtc->ck_rtc);
+
+ /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+ pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+ pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+ for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
+ pred_s = (rate / (pred_a + 1)) - 1;
+
+ if (((pred_s + 1) * (pred_a + 1)) == rate)
+ break;
+ }
+
+ /*
+ * Can't find a 1Hz, so give priority to RTC power consumption
+ * by choosing the higher possible value for prediv_a
+ */
+ if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
+ pred_a = pred_a_max;
+ pred_s = (rate / (pred_a + 1)) - 1;
+
+ dev_warn(&pdev->dev, "ck_rtc is %s\n",
+ (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
+ "fast" : "slow");
+ }
+
+ spin_lock_irqsave(&rtc->lock, irqflags);
+
+ stm32_rtc_wpr_unlock(rtc);
+
+ ret = stm32_rtc_enter_init_mode(rtc);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Can't enter in init mode. Prescaler config failed.\n");
+ goto end;
+ }
+
+ prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+ stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
+ prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+ stm32_rtc_writel(rtc, STM32_RTC_PRER, prer);
+
+ /* Force 24h time format */
+ cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
+ cr &= ~STM32_RTC_CR_FMT;
+ stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
+
+ stm32_rtc_exit_init_mode(rtc);
+
+ ret = stm32_rtc_wait_sync(rtc);
+
+ if (stm32_rtc_readl(rtc, STM32_RTC_ISR) & STM32_RTC_ISR_INITS)
+ dev_warn(&pdev->dev, "Date/Time must be initialized\n");
+end:
+ stm32_rtc_wpr_lock(rtc);
+
+ spin_unlock_irqrestore(&rtc->lock, irqflags);
+
+ return ret;
+}
+
+static int stm32_rtc_probe(struct platform_device *pdev)
+{
+ struct stm32_rtc *rtc;
+ struct resource *res;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rtc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtc->base))
+ return PTR_ERR(rtc->base);
+
+ dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "st,syscfg");
+ if (IS_ERR(dbp)) {
+ dev_err(&pdev->dev, "no st,syscfg\n");
+ return PTR_ERR(dbp);
+ }
+
+ spin_lock_init(&rtc->lock);
+
+ rtc->ck_rtc = devm_clk_get(&pdev->dev, "ck_rtc");
+ if (IS_ERR(rtc->ck_rtc)) {
+ dev_err(&pdev->dev, "no ck_rtc clock");
+ return PTR_ERR(rtc->ck_rtc);
+ }
+
+ ret = clk_prepare_enable(rtc->ck_rtc);
+ if (ret)
+ return ret;
+
+ if (dbp)
+ regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+ ret = stm32_rtc_init(pdev, rtc);
+ if (ret)
+ goto err;
+
+ rtc->irq_alarm = platform_get_irq_byname(pdev, "alarm");
+ if (rtc->irq_alarm <= 0) {
+ dev_err(&pdev->dev, "no alarm irq\n");
+ ret = -ENOENT;
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ device_init_wakeup(&pdev->dev, true);
+
+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &stm32_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc_dev)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
+ ret);
+ goto err;
+ }
+
+ /* Handle RTC alarm interrupts */
+ ret = devm_request_irq(&pdev->dev, rtc->irq_alarm,
+ stm32_rtc_alarm_irq, IRQF_TRIGGER_RISING,
+ dev_name(&rtc->rtc_dev->dev), rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
+ rtc->irq_alarm);
+ goto err;
+ }
+
+ return 0;
+err:
+ clk_disable_unprepare(rtc->ck_rtc);
+
+ if (dbp)
+ regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+ device_init_wakeup(&pdev->dev, false);
+
+ return ret;
+}
+
+static int __exit stm32_rtc_remove(struct platform_device *pdev)
+{
+ struct stm32_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int cr;
+
+ /* Disable interrupts */
+ stm32_rtc_wpr_unlock(rtc);
+ cr = stm32_rtc_readl(rtc, STM32_RTC_CR);
+ cr &= ~STM32_RTC_CR_ALRAIE;
+ stm32_rtc_writel(rtc, STM32_RTC_CR, cr);
+ stm32_rtc_wpr_lock(rtc);
+
+ clk_disable_unprepare(rtc->ck_rtc);
+
+ /* Enable backup domain write protection */
+ if (dbp)
+ regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
+
+ device_init_wakeup(&pdev->dev, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32_rtc_suspend(struct device *dev)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ return enable_irq_wake(rtc->irq_alarm);
+
+ return 0;
+}
+
+static int stm32_rtc_resume(struct device *dev)
+{
+ struct stm32_rtc *rtc = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = stm32_rtc_wait_sync(rtc);
+ if (ret < 0)
+ return ret;
+
+ if (device_may_wakeup(dev))
+ return disable_irq_wake(rtc->irq_alarm);
+
+ return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
+ stm32_rtc_suspend, stm32_rtc_resume);
+
+static struct platform_driver stm32_rtc_driver = {
+ .probe = stm32_rtc_probe,
+ .remove = stm32_rtc_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .pm = &stm32_rtc_pm_ops,
+ .of_match_table = stm32_rtc_of_match,
+ },
+};
+
+module_platform_driver(stm32_rtc_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox