* Re: [PATCH 0/5] Meson GXL and GXM USB support
From: Rob Herring @ 2016-11-30 22:22 UTC (permalink / raw)
To: Martin Blumenstingl
Cc: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, catalin.marinas-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, narmstrong-rdvid1DuHRBWk0Htik3J/w
In-Reply-To: <CAFBinCAA_JEtr_0Ze0thoRaEKMnWQMKcPxJ8y88zkWAAhuxsMw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Sun, Nov 27, 2016 at 11:42:02PM +0100, Martin Blumenstingl wrote:
> Hello Kishon,
>
> On Sat, Nov 26, 2016 at 3:56 PM, Martin Blumenstingl
> <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:
> > USB support on GXL and GXM differs a lot from Meson8b and GXBB:
> > The most obvious change is that GXL and GXM now have one dwc3
> > controller and one dwc2 controller (instead of two dwc2 controllers).
> > With that there are also new USB PHYs.
> >
> > Due to lack of hardware I was only able to test this on a board with
> > GXM, but as far as I understand the hardware my preparations should be
> > correct (so it should also work on GXL).
> >
> > dwc2 will probably stay unused on most GXM devices since it's limited
> > to device mode via some dwc2 hardware configuration register.
> >
> > dwc3 is probably used on all devices, even if there is more than just
> > one USB port. dwc3 has a built-in USB2 hub - on GXL this hub has two
> > ports enabled, while on GXM there are three ports enabled (see below
This hub is an actual USB hub? If so, then you should probably model the
USB bus topology (which we have a binding definition for).
> > for lsusb output). There are no USB3 ports enabled in the dwc3 hardware
> > configuration, meaning that the SoC is limited to high-speed mode.
> > On my GXM device the dwc3 hardware configuration forces it into "host
> > only" mode.
> >
> > The SoCs contain two PHY blocks: one USB3 PHY and up to four USB2 PHYs
> > (on GXM there are only three enabled, but the registers should support
> > up to four).
> > The USB3 PHY also handles the OTG interrupts, but since dwc3's hardware
> > configuration enforces "host only" mode I was not able to test this. It
> > simply takes care of an interrupt and then notifies all related PHYs
> > about the new mode.
> > The USB2 PHY block is a bit different: I created one PHY driver which
> > spans all "PHY ports" because the handling is a bit tricky. It turns
> > out that for each available USB port in dwc3's hub the corresponding
> > PHY must be enabled (even if there is no physical port - in my case
> > port 3 is not connected to anything, but disabling the PHY breaks
> > ports 1 and 2 as well).
> > I decided not not pass the USB2 PHYs directly to dwc3 due to three
> > reasons: 1. the USB3 PHY (which holds a reference to all relevant
> > USB2 PHY ports) controls the mode of the USB2 PHY ports (since both
> > are used with the same controller and thus it makes sense to keep the
> > mode consistent across all ports) 2. the dwc3 driver does not support
> > passing multiple USB2 PHYs (only one USB2 and one USB3 PHY can be
> > passed to it) 3. it is similar to how the vendor reference driver
> > manages the PHYs. Please note that this coupling is not a fixed, this
> > is all configurable via devicetree (so if the third USB2 PHY has to
> > be passed two the dwc2 controller then this is still possible by
> > just moving on PHY reference in the .dts).
> after not staring at my own code for 24 hours I realized this:
> (I went through quite a few iterations before getting these drivers to work)
> I'm basically re-modelling an "USB PHY hub" with my USB3 PHY driver
> (there's one "upstream" PHY interface which is passed to dwc3 and
> multiple downstream PHYs, each for one port on dwc3's internal hub).
> With this approach I could split each of the the USB2s into separate
> nodes again (instead of one devicetree node with #phy-cells = <1>) as
> the USB3 PHY is taking care of that special "we have to enable all
> ports or no port will be usable".
>
> We could go even one step further: why implement this in the Meson GXL
> specific PHY driver - why not implement a generic "phy-hub" driver
> (which would be valid whenever the PHY controller has to manage
> multiple PHYs at once, but wants to keep them all in a consistent
> state).
> The devicetree could look like this:
> usb2_phy_hub: phy@0 {
> compatible = "phy-hub";
> phys = <&other_phy1>, <&other_phy 2>;
> };
>
> &dwc3 {
> phys = <&usb2_phy_hub>, <&usb3_phy0>;
> phy-names = "usb2-phy", "usb3-phy";
> };
I'm okay with a hub if it is modeled as a USB hub. Here though, it
looks like you are just trying to group things which doesn't need to be
in DT.
>
> The generic phy-hub driver would then implement all phy_ops callbacks
> and pass then to each of it's downstream PHYs.
You can have generic drivers without a generic binding.
> That's just what came into my head - please let me know what you think
> of this or share your ideas on how to approach this!
>
> > The coupling of the USB2 and USB3 PHYs is the reason why I sent the
> > two drivers in one patch, even though they are handling different IP
> > blocks (different registers, etc.).
> >
> > Unfortunately there are no datasheets available for any of these PHYs.
> > Both drivers were written by reading the reference drivers provided by
> > Amlogic and analyzing the registers on the kernel that was shipped with
> > my board.
> >
> > As a last note: the dwc3 driver currently only explicitly enables the
> > first USB port "DWC3_GUSB2PHYCFG(0)" in the internal hub. The hardware
> > seems to enable the other two (DWC3_GUSB2PHYCFG(1) and
> > DWC3_GUSB2PHYCFG(2)) automatically. I will ask the dwc3 maintainers if
> > changes to dwc3 are desired any how these should look like, but for now
> > it's working fine even without changes there.
> >
> > lsusb output on GXM for the dwc3 hub:
> > Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
> > ...
> > Hub Port Status:
> > Port 1: 0000.0100 power
> > Port 2: 0000.0100 power
> > Port 3: 0000.0100 power
> >
> > NOTE: The devicetree changes depend on my previous series:
> > "[PATCH 0/2] minor GXL and GXM improvements" - see [0]
> >
> > NOTE2: This series depends on an upstream dwc3/xhci-plat DMA fix
> > (special thanks to Arnd Bergmann and Sriram Dash for fixing that):
> > "[PATCH v5 0/6] inherit dma configuration from parent dev" - see [1]
> >
> > I have a tree with all dependencies applied available at [2] if
> > someone wants a quick way to test this (I don't take any responsibility
> > if anything explodes though).
> >
> > [0] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001665.html
> > [1] http://marc.info/?l=linux-usb&m=147938307209685&w=2
> > [2] https://github.com/xdarklight/linux/commits/meson-gx-integration-4.10-20161126
> >
> > Martin Blumenstingl (5):
> > Documentation: dt-bindings: Add documentation for Meson GXL USB2/3
> > PHYs
> > phy: meson: add USB2 and USB3 PHY support for Meson GXL
> > arm64: dts: meson-gxl: add USB support
> > ARM64: dts: meson-gxm: add GXM specific USB configuration
> > ARM64: dts: meson-gx-p23x-q20x: enable USB on P23x and Q20x boards
> >
> > .../devicetree/bindings/phy/meson-gxl-usb2-phy.txt | 25 ++
> > .../devicetree/bindings/phy/meson-gxl-usb3-phy.txt | 27 ++
> > .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +
> > arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 49 +++
> > .../arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 17 +
> > arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 10 +
> > drivers/phy/Kconfig | 13 +
> > drivers/phy/Makefile | 2 +
> > drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++
> > drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++
> > 10 files changed, 906 insertions(+)
> > create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
> > create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
> > create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
> > create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
> >
> > --
> > 2.10.2
> >
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3 0/2] Support for Axentia TSE-850
From: Arnd Bergmann @ 2016-11-30 22:25 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Mark Rutland, devicetree, Russell King, linux-kernel, Rob Herring,
Alexandre Belloni, Peter Rosin
In-Reply-To: <1480510102-24587-1-git-send-email-peda@axentia.se>
On Wednesday, November 30, 2016 1:48:20 PM CET Peter Rosin wrote:
> Hi!
>
> changes v2 -> v3
> - document the new compatible strings prefixed with "axentia,".
>
> changes v1 -> v2
> - squash the fixup into the correct patch, sorry for the noise.
>
> After finally having all essintial drivers upstreamed (the
> last ones are currently in -next) I would like to have the
> dts and the defconfig also upstreamed.
>
> Cheers,
> Peter
>
> Peter Rosin (2):
> ARM: dts: add devicetree for the Axentia TSE-850
> ARM: tse850_defconfig: add Axentia TSE-850
>
> Documentation/devicetree/bindings/arm/axentia.txt | 19 ++
> MAINTAINERS | 8 +
> arch/arm/boot/dts/Makefile | 1 +
> arch/arm/boot/dts/axentia-linea.dtsi | 53 +++++
> arch/arm/boot/dts/axentia-tse850-3.dts | 276 ++++++++++++++++++++++
> arch/arm/configs/tse850_defconfig | 223 +++++++++++++++++
> 6 files changed, 580 insertions(+)
Hi Peter,
I'm a bit confused. Are these just boards using the sama5d31 SoC,
or something else?
Normally, dts files are picked up by the SoC platform maintainers
and named with a prefix for that soc.
Also, we don't normally add a defconfig file for a specific
machine, just add the options you want to sama5_defconfig
and multi_v7_defconfig, and send all patches to the
at91 maitainers.
Arnd
^ permalink raw reply
* Re: [PATCH v2 8/9] arm64: dts: rockchip: support dwc3 USB for rk3399
From: Brian Norris @ 2016-11-30 22:28 UTC (permalink / raw)
To: Caesar Wang
Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
Grygorii Strashko, Catalin Marinas, Heiko Stuebner, Arnd Bergmann,
Felipe Balbi, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Shawn Lin,
zhangqing, Will Deacon, Douglas Anderson,
tfiga-F7+t8E8rja9g9hUCZPvPmw,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Rob Herring,
eddie.cai-TNX95d0MmH7DzftRWevZcw, David Wu, Sriram Dash,
Jianqun Xu, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1478697721-2323-9-git-send-email-wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
+ Felipe, Arnd, others
Hi Caesar,
On Wed, Nov 09, 2016 at 09:22:00PM +0800, Caesar Wang wrote:
> From: Brian Norris <briannorris-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>
> Add the dwc3 usb needed node information for rk3399.
>
> Signed-off-by: Brian Norris <briannorris-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> Signed-off-by: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Note that none of this can work yet (at least for host mode, which I've
been testing), because DWC3 still hasn't been patched for ARM64 support.
It's been 7+ months and multiple people have tried to patch the issue,
but nothing has been merged.
See for instance:
usb: dwc3: host: inherit dma configuration from parent dev
https://lkml.org/lkml/2016/4/25/813
https://lkml.org/lkml/2016/5/5/391
Thread was resurrected in September:
https://lkml.org/lkml/2016/9/1/715
but there's still no end in sight. Maybe the following is the latest
incarnation?
[PATCH v2 0/6] inherit dma configuration from parent dev
https://www.mail-archive.com/linux-usb-u79uwXL29TY76Z2rM5mHXA@public.gmane.org/msg82369.html
I guess nothing prevents a valid device tree being merged here, but it's
severely limited by the above bug still, so I just wanted to call
attention to it.
(Let me guess: you've still been testing an internal non-upstream tree
that has this patched already, Caesar?)
> ---
>
> Changes in v2:
> - the original patches from brian posting on
> https://chromium-review.googlesource.com/343603
>
> arch/arm64/boot/dts/rockchip/rk3399.dtsi | 54 ++++++++++++++++++++++++++++++++
> 1 file changed, 54 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 09ebf4e..3659c56 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -353,6 +353,60 @@
> status = "disabled";
> };
>
> + usbdrd3_0: usb@fe800000 {
> + compatible = "rockchip,rk3399-dwc3";
> + clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
> + <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>;
> + clock-names = "ref_clk", "suspend_clk",
> + "bus_clk", "grf_clk";
> + #address-cells = <2>;
> + #size-cells = <2>;
> + ranges;
> + status = "disabled";
> + usbdrd_dwc3_0: dwc3@fe800000 {
> + compatible = "snps,dwc3";
> + reg = <0x0 0xfe800000 0x0 0x100000>;
> + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
> + dr_mode = "otg";
> + phys = <&tcphy0_usb3>;
> + phy-names = "usb3-phy";
The USB3/TypeC PHY won't probe without extcon support, and no rk3399
platforms have proper extcon support upstream AFAIK, right? Seems like
it'd be better to leave this phy property off for now, with the hope of
at least getting USB2 working. We can add it later once somebody proves
USB3 support upstream.
> + phy_type = "utmi_wide";
> + snps,dis_enblslpm_quirk;
> + snps,dis-u2-freeclk-exists-quirk;
> + snps,dis_u2_susphy_quirk;
> + snps,dis-del-phy-power-chg-quirk;
> + snps,xhci-slow-suspend-quirk;
This property isn't supported upstream. Seems like we should drop it for
now.
Same comments on the other DWC3 instance below, of course.
Brian
> + status = "disabled";
> + };
> + };
> +
> + usbdrd3_1: usb@fe900000 {
> + compatible = "rockchip,rk3399-dwc3";
> + clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>,
> + <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_GRF>;
> + clock-names = "ref_clk", "suspend_clk",
> + "bus_clk", "grf_clk";
> + #address-cells = <2>;
> + #size-cells = <2>;
> + ranges;
> + status = "disabled";
> + usbdrd_dwc3_1: dwc3@fe900000 {
> + compatible = "snps,dwc3";
> + reg = <0x0 0xfe900000 0x0 0x100000>;
> + interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
> + dr_mode = "host";
> + phys = <&tcphy1_usb3>;
> + phy-names = "usb3-phy";
> + phy_type = "utmi_wide";
> + snps,dis_enblslpm_quirk;
> + snps,dis-u2-freeclk-exists-quirk;
> + snps,dis_u2_susphy_quirk;
> + snps,dis-del-phy-power-chg-quirk;
> + snps,xhci-slow-suspend-quirk;
> + status = "disabled";
> + };
> + };
> +
> gic: interrupt-controller@fee00000 {
> compatible = "arm,gic-v3";
> #interrupt-cells = <4>;
> --
> 2.7.4
>
^ permalink raw reply
* Re: [PATCH v2 1/7] net: dt-bindings: add RGMII TX delay configuration to meson8b-dwmac
From: Martin Blumenstingl @ 2016-11-30 22:33 UTC (permalink / raw)
To: Rob Herring
Cc: linux-amlogic, devicetree, netdev, davem, khilman, mark.rutland,
linux-arm-kernel, alexandre.torgue, peppe.cavallaro, will.deacon,
catalin.marinas, carlo, f.fainelli
In-Reply-To: <20161130214429.albylffpoumbeugi@rob-hp-laptop>
On Wed, Nov 30, 2016 at 10:44 PM, Rob Herring <robh@kernel.org> wrote:
> On Fri, Nov 25, 2016 at 02:01:50PM +0100, Martin Blumenstingl wrote:
>> This allows configuring the RGMII TX clock delay. The RGMII clock is
>> generated by underlying hardware of the the Meson 8b / GXBB DWMAC glue.
>> The configuration depends on the actual hardware (no delay may be
>> needed due to the design of the actual circuit, the PHY might add this
>> delay, etc.).
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
>> ---
>> Documentation/devicetree/bindings/net/meson-dwmac.txt | 14 ++++++++++++++
>> 1 file changed, 14 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/net/meson-dwmac.txt b/Documentation/devicetree/bindings/net/meson-dwmac.txt
>> index 89e62dd..f8bc540 100644
>> --- a/Documentation/devicetree/bindings/net/meson-dwmac.txt
>> +++ b/Documentation/devicetree/bindings/net/meson-dwmac.txt
>> @@ -25,6 +25,20 @@ Required properties on Meson8b and newer:
>> - "clkin0" - first parent clock of the internal mux
>> - "clkin1" - second parent clock of the internal mux
>>
>> +Optional properties on Meson8b and newer:
>> +- amlogic,tx-delay-ns: The internal RGMII TX clock delay (provided
>> + by this driver) in nanoseconds. Allowed values
>> + are: 0ns, 2ns, 4ns, 6ns.
>> + This must be configured when the phy-mode is
>> + "rgmii" (typically a value of 2ns is used in
>> + this case).
>> + When phy-mode is set to "rgmii-id" or
>> + "rgmii-txid" the TX clock delay is already
>> + provided by the PHY. In that case this
>> + property should be set to 0ns (which disables
>> + the TX clock delay in the MAC to prevent the
>> + clock from going off because both PHY and MAC
>> + are adding a delay).
>
> What's the default? Why can't no property mean 0ns delay?
This value (2ns) was previously hardcoded. Having a default of 0ns
means that patch 7 ("ARM64: dts: amlogic: add the ethernet TX delay
configuration") becomes mandatory (otherwise we'll have broken Gbit
ethernet again because the TX delay is now disabled in the PHY when
phy-mode is "rgmii" and additionally we don't apply the 2ns TX delay
on the MAC side when the property is missing).
I'm fine with either way though - just let me know so I can adjust the
code accordingly.
^ permalink raw reply
* Re: [PATCH V6 06/10] PM / OPP: Add infrastructure to manage multiple regulators
From: Stephen Boyd @ 2016-11-30 22:37 UTC (permalink / raw)
To: Viresh Kumar
Cc: Rafael Wysocki, Viresh Kumar, Nishanth Menon,
linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
linux-pm-u79uwXL29TY76Z2rM5mHXA, Vincent Guittot,
robh-DgEjT+Ai2ygdnm+yROfE0A, d-gerlach-l0cyMroinI0,
broonie-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <3b3ce1dac198fb668b97e81490bcbcf03d31e40d.1480481312.git.viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
On 11/30, Viresh Kumar wrote:
> @@ -1337,26 +1408,44 @@ struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
> goto err;
> }
>
> - /* Already have a regulator set */
> - if (WARN_ON(!IS_ERR(opp_table->regulator))) {
> + /* Already have regulators set */
> + if (WARN_ON(opp_table->regulators)) {
> opp_table = ERR_PTR(-EBUSY);
> goto err;
> }
> - /* Allocate the regulator */
> - reg = regulator_get_optional(dev, name);
> - if (IS_ERR(reg)) {
> - opp_table = (struct opp_table *)reg;
> - if (PTR_ERR(reg) != -EPROBE_DEFER)
> - dev_err(dev, "%s: no regulator (%s) found: %ld\n",
> - __func__, name, PTR_ERR(reg));
> +
> + opp_table->regulators = kmalloc_array(count,
> + sizeof(*opp_table->regulators),
> + GFP_KERNEL);
> + if (!opp_table->regulators) {
> + opp_table = ERR_PTR(-ENOMEM);
> goto err;
> }
>
> - opp_table->regulator = reg;
> + for (i = 0; i < count; i++) {
> + reg = regulator_get_optional(dev, names[i]);
> + if (IS_ERR(reg)) {
> + opp_table = (struct opp_table *)reg;
This should be an ERR_CAST() instead. But this is not based on
the correct patch anyway so this should be rebased.
> + if (PTR_ERR(reg) != -EPROBE_DEFER)
> + dev_err(dev, "%s: no regulator (%s) found: %ld\n",
> + __func__, names[i], PTR_ERR(reg));
> + goto free_regulators;
> + }
> +
> + opp_table->regulators[i] = reg;
> + }
> +
> + opp_table->regulator_count = count;
>
> mutex_unlock(&opp_table_lock);
> return opp_table;
>
> +free_regulators:
> + while (i != 0)
> + regulator_put(opp_table->regulators[--i]);
> +
> + kfree(opp_table->regulators);
> + opp_table->regulators = NULL;
> err:
> _remove_opp_table(opp_table);
> unlock:
> @@ -1364,10 +1453,10 @@ struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
>
> return opp_table;
> }
> -EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
> +EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
>
> /**
> - * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
> + * dev_pm_opp_put_regulators() - Releases resources blocked for regulators
> * @opp_table: opp_table returned from dev_pm_opp_set_regulator
This needs an update too ^
> *
> * Locking: The internal opp_table and opp structures are RCU protected.
> diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
> index c897676ca35f..95f433db4ac7 100644
> --- a/drivers/base/power/opp/debugfs.c
> +++ b/drivers/base/power/opp/debugfs.c
> @@ -34,6 +35,46 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
> debugfs_remove_recursive(opp->dentry);
> }
>
> +static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
> + struct opp_table *opp_table,
> + struct dentry *pdentry)
> +{
> + struct dentry *d;
> + int i = 0;
> + char *name;
> +
> + /* Always create at least supply-0 directory */
> + do {
> + name = kasprintf(GFP_KERNEL, "supply-%d", i);
Sorry I haven't noticed this before. Wouldn't we want to put the
supply name here instead of a number?
> +
> + /* Create per-opp directory */
> + d = debugfs_create_dir(name, pdentry);
> +
> + kfree(name);
> diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
> index 4d3ec92cbabf..1cd1fcfe835a 100644
> --- a/drivers/cpufreq/cpufreq-dt.c
> +++ b/drivers/cpufreq/cpufreq-dt.c
> @@ -188,7 +188,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
> */
> name = find_supply_name(cpu_dev);
> if (name) {
> - opp_table = dev_pm_opp_set_regulator(cpu_dev, name);
> + const char *names[] = {name};
> +
> + opp_table = dev_pm_opp_set_regulators(cpu_dev, names,
> + ARRAY_SIZE(names));
This can be simplified to:
opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1);
> if (IS_ERR(opp_table)) {
> ret = PTR_ERR(opp_table);
> dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
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 3/3] gpio: Support gpio nexus dt bindings
From: Rob Herring @ 2016-11-30 22:48 UTC (permalink / raw)
To: Stephen Boyd
Cc: Frank Rowand, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
linux-gpio@vger.kernel.org, Pantelis Antoniou, Linus Walleij,
Mark Brown
In-Reply-To: <20161124102529.20212-4-stephen.boyd@linaro.org>
On Thu, Nov 24, 2016 at 4:25 AM, Stephen Boyd <stephen.boyd@linaro.org> wrote:
> Platforms like 96boards have a standardized connector/expansion
> slot that exposes signals like GPIOs to expansion boards in an
> SoC agnostic way. We'd like the DT overlays for the expansion
> boards to be written once without knowledge of the SoC on the
> other side of the connector. This avoids the unscalable
> combinatorial explosion of a different DT overlay for each
> expansion board and SoC pair.
>
> Now that we have nexus support in the OF core let's change the
> function call here that parses the phandle lists of gpios to use
> the nexus variant. This allows us to remap phandles and their
> arguments through any number of nexus nodes and end up with the
> actual gpio provider being used.
>
> Cc: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: Mark Brown <broonie@kernel.org>
> Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
> ---
>
> TODO: Document gpio-map and gpio-map-mask in GPIO devicetree binding
>
> drivers/gpio/gpiolib-of.c | 5 +++--
> 1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
> index ecad3f0e3b77..3117397c4c41 100644
> --- a/drivers/gpio/gpiolib-of.c
> +++ b/drivers/gpio/gpiolib-of.c
> @@ -71,8 +71,9 @@ struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
> struct gpio_desc *desc;
> int ret;
>
> - ret = of_parse_phandle_with_args(np, propname, "#gpio-cells", index,
> - &gpiospec);
> + ret = of_parse_phandle_with_args_map(np, propname, "#gpio-cells",
> + "gpio-map", "gpio-map-mask",
> + index, &gpiospec);
> if (ret) {
> pr_debug("%s: can't parse '%s' property of node '%s[%d]'\n",
> __func__, propname, np->full_name, index);
> --
> 2.10.0.297.gf6727b0
>
^ permalink raw reply
* Re: [PATCH 0/5] Meson GXL and GXM USB support
From: Martin Blumenstingl @ 2016-11-30 22:49 UTC (permalink / raw)
To: Rob Herring
Cc: linux-amlogic-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, kishon-l0cyMroinI0,
khilman-rdvid1DuHRBWk0Htik3J/w, carlo-KA+7E9HrN00dnm+yROfE0A,
mark.rutland-5wv7dgnIgG8, catalin.marinas-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, narmstrong-rdvid1DuHRBWk0Htik3J/w
In-Reply-To: <20161130222228.zu6ampaajg3gkdz4@rob-hp-laptop>
On Wed, Nov 30, 2016 at 11:22 PM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On Sun, Nov 27, 2016 at 11:42:02PM +0100, Martin Blumenstingl wrote:
>> Hello Kishon,
>>
>> On Sat, Nov 26, 2016 at 3:56 PM, Martin Blumenstingl
>> <martin.blumenstingl-gM/Ye1E23mwN+BqQ9rBEUg@public.gmane.org> wrote:
>> > USB support on GXL and GXM differs a lot from Meson8b and GXBB:
>> > The most obvious change is that GXL and GXM now have one dwc3
>> > controller and one dwc2 controller (instead of two dwc2 controllers).
>> > With that there are also new USB PHYs.
>> >
>> > Due to lack of hardware I was only able to test this on a board with
>> > GXM, but as far as I understand the hardware my preparations should be
>> > correct (so it should also work on GXL).
>> >
>> > dwc2 will probably stay unused on most GXM devices since it's limited
>> > to device mode via some dwc2 hardware configuration register.
>> >
>> > dwc3 is probably used on all devices, even if there is more than just
>> > one USB port. dwc3 has a built-in USB2 hub - on GXL this hub has two
>> > ports enabled, while on GXM there are three ports enabled (see below
>
> This hub is an actual USB hub? If so, then you should probably model the
> USB bus topology (which we have a binding definition for).
(the following explanation is based on a) what I found is going on in
the hardware registers b) reading the vendor drivers - unfortunately
there are no datasheets available which could give more details).
lsusb on my GXM gives:
...
Hub Port Status:
Port 1: 0000.0100 power
Port 2: 0000.0100 power
Port 3: 0000.0100 power
The layout looks like this:
dwc3 provides a USB hub with 2 (on GXL) or 3 (on GXM) USB ports.
Each of the port is driven by a PHY (port 1 = abp@0x78000, port2 =
abp@0x78020, etc...).
On GXM USB2 PHY port 3 = abp@0x78040 is connected to the third dwc3 hub port.
On GXL PHY port 3 = abp@0x78040 is connected to the dwc2 (I could not
prove this yet as I don't have access to any GXL hardware).
So the answer is: we don't have an actual USB hub here (as this hub is
provided by dwc3), but rather a set of PHYs which is assigned to
dwc3's hub (if we don't configure *all* PHYs then none of the USB
ports provided by the dwc3 hub works).
Could you please point me to the USB bus topology binding (is it the
one described in usb-device.txt)?
>> > for lsusb output). There are no USB3 ports enabled in the dwc3 hardware
>> > configuration, meaning that the SoC is limited to high-speed mode.
>> > On my GXM device the dwc3 hardware configuration forces it into "host
>> > only" mode.
>> >
>> > The SoCs contain two PHY blocks: one USB3 PHY and up to four USB2 PHYs
>> > (on GXM there are only three enabled, but the registers should support
>> > up to four).
>> > The USB3 PHY also handles the OTG interrupts, but since dwc3's hardware
>> > configuration enforces "host only" mode I was not able to test this. It
>> > simply takes care of an interrupt and then notifies all related PHYs
>> > about the new mode.
>> > The USB2 PHY block is a bit different: I created one PHY driver which
>> > spans all "PHY ports" because the handling is a bit tricky. It turns
>> > out that for each available USB port in dwc3's hub the corresponding
>> > PHY must be enabled (even if there is no physical port - in my case
>> > port 3 is not connected to anything, but disabling the PHY breaks
>> > ports 1 and 2 as well).
>> > I decided not not pass the USB2 PHYs directly to dwc3 due to three
>> > reasons: 1. the USB3 PHY (which holds a reference to all relevant
>> > USB2 PHY ports) controls the mode of the USB2 PHY ports (since both
>> > are used with the same controller and thus it makes sense to keep the
>> > mode consistent across all ports) 2. the dwc3 driver does not support
>> > passing multiple USB2 PHYs (only one USB2 and one USB3 PHY can be
>> > passed to it) 3. it is similar to how the vendor reference driver
>> > manages the PHYs. Please note that this coupling is not a fixed, this
>> > is all configurable via devicetree (so if the third USB2 PHY has to
>> > be passed two the dwc2 controller then this is still possible by
>> > just moving on PHY reference in the .dts).
>> after not staring at my own code for 24 hours I realized this:
>> (I went through quite a few iterations before getting these drivers to work)
>> I'm basically re-modelling an "USB PHY hub" with my USB3 PHY driver
>> (there's one "upstream" PHY interface which is passed to dwc3 and
>> multiple downstream PHYs, each for one port on dwc3's internal hub).
>> With this approach I could split each of the the USB2s into separate
>> nodes again (instead of one devicetree node with #phy-cells = <1>) as
>> the USB3 PHY is taking care of that special "we have to enable all
>> ports or no port will be usable".
>>
>> We could go even one step further: why implement this in the Meson GXL
>> specific PHY driver - why not implement a generic "phy-hub" driver
>> (which would be valid whenever the PHY controller has to manage
>> multiple PHYs at once, but wants to keep them all in a consistent
>> state).
>> The devicetree could look like this:
>> usb2_phy_hub: phy@0 {
>> compatible = "phy-hub";
>> phys = <&other_phy1>, <&other_phy 2>;
>> };
>>
>> &dwc3 {
>> phys = <&usb2_phy_hub>, <&usb3_phy0>;
>> phy-names = "usb2-phy", "usb3-phy";
>> };
>
> I'm okay with a hub if it is modeled as a USB hub. Here though, it
> looks like you are just trying to group things which doesn't need to be
> in DT.
I hope my answer above makes things more clear
>> The generic phy-hub driver would then implement all phy_ops callbacks
>> and pass then to each of it's downstream PHYs.
>
> You can have generic drivers without a generic binding.
So you'd rather implement a generic driver which would provide
functions like of_create_grouped_phy(struct device_node *np) which
would implement the grouping logic as described (but has no binding
itself, but rather relies on the actual platform driver taking care of
creating that binding and re-using generic code)?
>> That's just what came into my head - please let me know what you think
>> of this or share your ideas on how to approach this!
>>
>> > The coupling of the USB2 and USB3 PHYs is the reason why I sent the
>> > two drivers in one patch, even though they are handling different IP
>> > blocks (different registers, etc.).
>> >
>> > Unfortunately there are no datasheets available for any of these PHYs.
>> > Both drivers were written by reading the reference drivers provided by
>> > Amlogic and analyzing the registers on the kernel that was shipped with
>> > my board.
>> >
>> > As a last note: the dwc3 driver currently only explicitly enables the
>> > first USB port "DWC3_GUSB2PHYCFG(0)" in the internal hub. The hardware
>> > seems to enable the other two (DWC3_GUSB2PHYCFG(1) and
>> > DWC3_GUSB2PHYCFG(2)) automatically. I will ask the dwc3 maintainers if
>> > changes to dwc3 are desired any how these should look like, but for now
>> > it's working fine even without changes there.
>> >
>> > lsusb output on GXM for the dwc3 hub:
>> > Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
>> > ...
>> > Hub Port Status:
>> > Port 1: 0000.0100 power
>> > Port 2: 0000.0100 power
>> > Port 3: 0000.0100 power
>> >
>> > NOTE: The devicetree changes depend on my previous series:
>> > "[PATCH 0/2] minor GXL and GXM improvements" - see [0]
>> >
>> > NOTE2: This series depends on an upstream dwc3/xhci-plat DMA fix
>> > (special thanks to Arnd Bergmann and Sriram Dash for fixing that):
>> > "[PATCH v5 0/6] inherit dma configuration from parent dev" - see [1]
>> >
>> > I have a tree with all dependencies applied available at [2] if
>> > someone wants a quick way to test this (I don't take any responsibility
>> > if anything explodes though).
>> >
>> > [0] http://lists.infradead.org/pipermail/linux-amlogic/2016-November/001665.html
>> > [1] http://marc.info/?l=linux-usb&m=147938307209685&w=2
>> > [2] https://github.com/xdarklight/linux/commits/meson-gx-integration-4.10-20161126
>> >
>> > Martin Blumenstingl (5):
>> > Documentation: dt-bindings: Add documentation for Meson GXL USB2/3
>> > PHYs
>> > phy: meson: add USB2 and USB3 PHY support for Meson GXL
>> > arm64: dts: meson-gxl: add USB support
>> > ARM64: dts: meson-gxm: add GXM specific USB configuration
>> > ARM64: dts: meson-gx-p23x-q20x: enable USB on P23x and Q20x boards
>> >
>> > .../devicetree/bindings/phy/meson-gxl-usb2-phy.txt | 25 ++
>> > .../devicetree/bindings/phy/meson-gxl-usb3-phy.txt | 27 ++
>> > .../arm64/boot/dts/amlogic/meson-gx-p23x-q20x.dtsi | 12 +
>> > arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 49 +++
>> > .../arm64/boot/dts/amlogic/meson-gxm-s912-q200.dts | 17 +
>> > arch/arm64/boot/dts/amlogic/meson-gxm.dtsi | 10 +
>> > drivers/phy/Kconfig | 13 +
>> > drivers/phy/Makefile | 2 +
>> > drivers/phy/phy-meson-gxl-usb2.c | 374 ++++++++++++++++++++
>> > drivers/phy/phy-meson-gxl-usb3.c | 377 +++++++++++++++++++++
>> > 10 files changed, 906 insertions(+)
>> > create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt
>> > create mode 100644 Documentation/devicetree/bindings/phy/meson-gxl-usb3-phy.txt
>> > create mode 100644 drivers/phy/phy-meson-gxl-usb2.c
>> > create mode 100644 drivers/phy/phy-meson-gxl-usb3.c
>> >
>> > --
>> > 2.10.2
>> >
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] arm64: dts: juno: Correct PCI IO window
From: Arnd Bergmann @ 2016-11-30 22:51 UTC (permalink / raw)
To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: Sudeep Holla, Jeremy Linton, devicetree-u79uwXL29TY76Z2rM5mHXA,
mark.rutland-5wv7dgnIgG8, lorenzo.pieralisi-5wv7dgnIgG8,
catalin.marinas-5wv7dgnIgG8, liviu.dudau-5wv7dgnIgG8,
will.deacon-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <92ac8013-b88e-2f74-9a49-7d5f38a4e7a5-5wv7dgnIgG8@public.gmane.org>
On Wednesday, November 30, 2016 4:29:35 PM CET Sudeep Holla wrote:
> Hi Jeremy,
>
> On 29/11/16 20:45, Jeremy Linton wrote:
> > The PCIe root complex on Juno translates the MMIO mapped
> > at 0x5f800000 to the PIO address range starting at 0
> > (which is common because PIO addresses are generally < 64k).
> > Correct the DT to reflect this.
> >
>
> I have another DT fix that I have asked ARM-SoC guys to pick up directly
> from the list. If that doesn't happen, I will send PR including both.
>
> If that happens then we need to send this to them to be picked directly.
> At this point I want to wait for couple of days to avoid confusion.
I ended up taking the other one for v4.10, but this one seems more
important so I applied it for v4.9.
Let me know if you disagree with the priorities, as I plan to send out
the last 4.9 fixes pull request to Linus tomorrow.
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 v3 3/4] [media] davinci: vpif_capture: get subdevs from DT
From: Sakari Ailus @ 2016-11-30 22:51 UTC (permalink / raw)
To: Kevin Hilman
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sekhar Nori, Axel Haslam,
Bartosz Gołaszewski, Alexandre Bailon, David Lechner,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw
In-Reply-To: <m2a8cpvkwj.fsf-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
Hi Kevin,
On Wed, Nov 23, 2016 at 03:25:32PM -0800, Kevin Hilman wrote:
> Hi Sakari,
>
> Sakari Ailus <sakari.ailus-X3B1VOXEql0@public.gmane.org> writes:
>
> > On Tue, Nov 22, 2016 at 07:52:43AM -0800, Kevin Hilman wrote:
> >> Allow getting of subdevs from DT ports and endpoints.
> >>
> >> The _get_pdata() function was larely inspired by (i.e. stolen from)
> >
> > vpif_capture_get_pdata and "largely"?
>
> Yes, thanks.
>
> >> am437x-vpfe.c
> >>
> >> Signed-off-by: Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
> >> ---
> >> drivers/media/platform/davinci/vpif_capture.c | 130 +++++++++++++++++++++++++-
> >> include/media/davinci/vpif_types.h | 9 +-
> >> 2 files changed, 133 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
> >> index 94ee6cf03f02..47a4699157e7 100644
> >> --- a/drivers/media/platform/davinci/vpif_capture.c
> >> +++ b/drivers/media/platform/davinci/vpif_capture.c
> >> @@ -26,6 +26,8 @@
> >> #include <linux/slab.h>
> >>
> >> #include <media/v4l2-ioctl.h>
> >> +#include <media/v4l2-of.h>
> >> +#include <media/i2c/tvp514x.h>
> >
> > Do you need this header?
> >
>
> Yes, based on discussion with Hans, since there is no DT binding for
> selecting the input pins of the TVP514x, I have to select it in the
> driver, so I need the defines from this header. More on this below...
>
> >>
> >> #include "vpif.h"
> >> #include "vpif_capture.h"
> >> @@ -650,6 +652,10 @@ static int vpif_input_to_subdev(
> >>
> >> vpif_dbg(2, debug, "vpif_input_to_subdev\n");
> >>
> >> + if (!chan_cfg)
> >> + return -1;
> >> + if (input_index >= chan_cfg->input_count)
> >> + return -1;
> >> subdev_name = chan_cfg->inputs[input_index].subdev_name;
> >> if (subdev_name == NULL)
> >> return -1;
> >> @@ -657,7 +663,7 @@ static int vpif_input_to_subdev(
> >> /* loop through the sub device list to get the sub device info */
> >> for (i = 0; i < vpif_cfg->subdev_count; i++) {
> >> subdev_info = &vpif_cfg->subdev_info[i];
> >> - if (!strcmp(subdev_info->name, subdev_name))
> >> + if (subdev_info && !strcmp(subdev_info->name, subdev_name))
> >> return i;
> >> }
> >> return -1;
> >> @@ -1327,6 +1333,21 @@ static int vpif_async_bound(struct v4l2_async_notifier *notifier,
> >> {
> >> int i;
> >>
> >> + for (i = 0; i < vpif_obj.config->asd_sizes[0]; i++) {
> >> + struct v4l2_async_subdev *_asd = vpif_obj.config->asd[i];
> >> + const struct device_node *node = _asd->match.of.node;
> >> +
> >> + if (node == subdev->of_node) {
> >> + vpif_obj.sd[i] = subdev;
> >> + vpif_obj.config->chan_config->inputs[i].subdev_name =
> >> + (char *)subdev->of_node->full_name;
> >> + vpif_dbg(2, debug,
> >> + "%s: setting input %d subdev_name = %s\n",
> >> + __func__, i, subdev->of_node->full_name);
> >> + return 0;
> >> + }
> >> + }
> >> +
> >> for (i = 0; i < vpif_obj.config->subdev_count; i++)
> >> if (!strcmp(vpif_obj.config->subdev_info[i].name,
> >> subdev->name)) {
> >> @@ -1422,6 +1443,110 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
> >> return vpif_probe_complete();
> >> }
> >>
> >> +static struct vpif_capture_config *
> >> +vpif_capture_get_pdata(struct platform_device *pdev)
> >> +{
> >> + struct device_node *endpoint = NULL;
> >> + struct v4l2_of_endpoint bus_cfg;
> >> + struct vpif_capture_config *pdata;
> >> + struct vpif_subdev_info *sdinfo;
> >> + struct vpif_capture_chan_config *chan;
> >> + unsigned int i;
> >> +
> >> + dev_dbg(&pdev->dev, "vpif_get_pdata\n");
> >> +
> >> + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
> >> + return pdev->dev.platform_data;
> >> +
> >> + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
> >> + if (!pdata)
> >> + return NULL;
> >> + pdata->subdev_info =
> >> + devm_kzalloc(&pdev->dev, sizeof(*pdata->subdev_info) *
> >> + VPIF_CAPTURE_MAX_CHANNELS, GFP_KERNEL);
> >> +
> >> + if (!pdata->subdev_info)
> >> + return NULL;
> >> + dev_dbg(&pdev->dev, "%s\n", __func__);
> >> +
> >> + for (i = 0; ; i++) {
> >> + struct device_node *rem;
> >> + unsigned int flags;
> >> + int err;
> >> +
> >> + endpoint = of_graph_get_next_endpoint(pdev->dev.of_node,
> >> + endpoint);
> >> + if (!endpoint)
> >> + break;
> >> +
> >> + sdinfo = &pdata->subdev_info[i];
> >
> > subdev_info[] has got VPIF_CAPTURE_MAX_CHANNELS entries only.
> >
>
> Right, I need to make the loop only go for a max of
> VPIF_CAPTURE_MAX_CHANNELS iterations.
>
> >> + chan = &pdata->chan_config[i];
> >> + chan->inputs = devm_kzalloc(&pdev->dev,
> >> + sizeof(*chan->inputs) *
> >> + VPIF_DISPLAY_MAX_CHANNELS,
> >> + GFP_KERNEL);
> >> +
> >> + chan->input_count++;
> >> + chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA;
> >
> > I wonder what's the purpose of using index i on this array as well.
>
> The number of endpoints in DT is the number of input channels configured
> (up to a max of VPIF_CAPTURE_MAX_CHANNELS.)
>
> > If you use that to access a corresponding entry in a different array, I'd
> > just create a struct that contains the port configuration and the async
> > sub-device. The omap3isp driver does that, for instance; see
> > isp_of_parse_nodes() in drivers/media/platform/omap3isp/isp.c if you're
> > interested. Up to you.
>
> OK, I'll have a look at that driver. The goal here with this series is
> just to get this working with DT, but also not break the existing legacy
> platform_device support, so I'm trying not to mess with the
> driver-interal data structures too much.
Ack.
>
> >> + chan->inputs[i].input.std = V4L2_STD_ALL;
> >> + chan->inputs[i].input.capabilities = V4L2_IN_CAP_STD;
> >> +
> >> + /* FIXME: need a new property? ch0:composite ch1: s-video */
> >> + if (i == 0)
> >
> > Can you assume that the first endopoint has got a particular kind of input?
> > What if it's not connected?
>
> On all the boards I know of (there aren't many using this SoC), it's a
> safe assumption.
>
> > If this is a different physical port (not in the meaning another) in the
> > device, I'd use the reg property for this. Please see
> > Documentation/devicetree/bindings/media/video-interfaces.txt .
>
> My understanding (which is admittedly somewhat fuzzy) of the TVP514x is
> that it's not physically a different port. Instead, it's just telling
> the TVP514x which pin(s) will be active inputs (and what kind of signal
> will be present.)
>
> I'm open to a better way to describe this input select from DT, but
> based on what I heard from Hans, there isn't currently a good way to do
> that except for in the driver:
> (c.f. https://marc.info/?l=linux-arm-kernel&m=147887871615788)
>
> Based on further discussion in that thread, it sounds like there may be
> a way forward coming soon, and I'll be glad to switch to that when it
> arrives.
I'm not sure that properly supporting connectors will provide any help here.
Looking at the s_routing() API, it's the calling driver that has to be aware
of sub-device specific function parameters. As such it's not a very good
idea to require that a driver is aware of the value range of another
driver's parameter. I wonder if a simple enumeration interface would help
here --- if I understand correctly, the purpose is just to provide a way to
choose the input using VIDIOC_S_INPUT.
I guess that's somehow ok as long as you have no other combinations of these
devices but this is hardly future-proof. (And certainly not a problem
created by this patch.)
It'd be still nice to fix that as presumably we don't have the option of
reworking how we expect the device tree to look like.
Cc Laurent.
--
Kind regards,
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org XMPP: sailus-PCDdDYkjdNMDXYZnReoRVg@public.gmane.org
--
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/3] of: Support parsing phandle argument lists through a nexus node
From: Rob Herring @ 2016-11-30 23:30 UTC (permalink / raw)
To: Stephen Boyd
Cc: Frank Rowand, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
linux-gpio@vger.kernel.org, Pantelis Antoniou, Linus Walleij,
Mark Brown
In-Reply-To: <20161124102529.20212-2-stephen.boyd@linaro.org>
On Thu, Nov 24, 2016 at 4:25 AM, Stephen Boyd <stephen.boyd@linaro.org> wrote:
> Platforms like 96boards have a standardized connector/expansion
> slot that exposes signals like GPIOs to expansion boards in an
> SoC agnostic way. We'd like the DT overlays for the expansion
> boards to be written once without knowledge of the SoC on the
> other side of the connector. This avoids the unscalable
> combinatorial explosion of a different DT overlay for each
> expansion board and SoC pair.
>
> We need a way to describe the GPIOs routed through the connector
> in an SoC agnostic way. Let's introduce nexus property parsing
> into the OF core to do this. This is largely based on the
> interrupt nexus support we already have. This allows us to remap
> a phandle list in a consumer node (e.g. reset-gpios) through a
> connector in a generic way (e.g. via gpio-map). Do this in a
> generic routine so that we can remap any sort of variable length
> phandle list.
>
> Taking GPIOs as an example, the connector would be a GPIO nexus,
> supporting the remapping of a GPIO specifier space to multiple
> GPIO providers on the SoC. DT would look as shown below, where
> 'soc_gpio1' and 'soc_gpio2' are inside the SoC, 'connector' is an
> expansion port where boards can be plugged in, and
> 'expansion_device' is a device on the expansion board.
>
> soc {
> soc_gpio1: gpio-controller1 {
> #gpio-cells = <2>;
> };
>
> soc_gpio2: gpio-controller2 {
> #gpio-cells = <2>;
> };
> };
>
> connector: connector {
> #gpio-cells = <2>;
> gpio-map = <0 GPIO_ACTIVE_LOW &soc_gpio1 1 GPIO_ACTIVE_LOW>,
> <1 GPIO_ACTIVE_LOW &soc_gpio2 4 GPIO_ACTIVE_LOW>,
> <2 GPIO_ACTIVE_LOW &soc_gpio1 3 GPIO_ACTIVE_LOW>,
> <3 GPIO_ACTIVE_LOW &soc_gpio2 2 GPIO_ACTIVE_LOW>;
> gpio-map-mask = <0xf 0x1>;
I think the common case is something more like this:
gpio-map = <0 0 &soc_gpio1 1 0>,
<1 0 &soc_gpio2 4 0>,
<2 0 &soc_gpio1 3 0>,
<3 0 &soc_gpio2 2 0>;
gpio-map-mask = <0xf 0>;
where we want to pass the 2nd cell of the consumer (e.g. reset-gpios)
thru. So here the GPIO_ACTIVE_LOW flag below needs to pass thru to
&soc_gpio1. Otherwise, the gpio-map is has to enumerate every possible
combination or it will be specific to the daughterboard's usage.
Also, GPIO cells are pretty well standardized, but some cases may need
a translation function which I guess would be part of a connector
driver. I don't think that affects the binding nor needs to be solved
now, but just want to raise that possibility.
> };
>
> expansion_device {
> reset-gpios = <&connector 2 GPIO_ACTIVE_LOW>;
> };
>
> The GPIO core would use of_parse_phandle_with_args_map() instead
> of of_parse_phandle_with_args() and arrive at the same type of
> result, a phandle and argument list. The difference is that the
> phandle and arguments will be remapped through the nexus node to
> the underlying SoC GPIO controller node. In the example above,
> we would remap 'reset-gpios' from <&connector 2 GPIO_ACTIVE_LOW>
> to <&soc_gpio1 3 GPIO_ACTIVE_LOW>.
GPIOs also are interrupts frequently, so we need to make sure
interrupt translation works too. It's a bit tricky as interrupt-map
depends on #address-cells and #interrupt-cells. I think we just set
the #address-cells to 0 on the connector node and it will be fine. We
may need the same pass thru of flags though.
>
> Cc: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Cc: Mark Brown <broonie@kernel.org>
> Signed-off-by: Stephen Boyd <stephen.boyd@linaro.org>
> ---
> drivers/of/base.c | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> include/linux/of.h | 14 +++++
> 2 files changed, 160 insertions(+)
>
> diff --git a/drivers/of/base.c b/drivers/of/base.c
> index d687e6de24a0..693b73f33675 100644
> --- a/drivers/of/base.c
> +++ b/drivers/of/base.c
> @@ -1772,6 +1772,152 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
> EXPORT_SYMBOL(of_parse_phandle_with_args);
>
> /**
> + * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it
> + * @np: pointer to a device tree node containing a list
> + * @list_name: property name that contains a list
> + * @cells_name: property name that specifies phandles' arguments count
> + * @index: index of a phandle to parse out
> + * @out_args: optional pointer to output arguments structure (will be filled)
> + *
> + * This function is useful to parse lists of phandles and their arguments.
> + * Returns 0 on success and fills out_args, on error returns appropriate
> + * errno value.
> + *
> + * Caller is responsible to call of_node_put() on the returned out_args->np
> + * pointer.
> + *
> + * Example:
> + *
> + * phandle1: node1 {
> + * #list-cells = <2>;
> + * }
> + *
> + * phandle2: node2 {
> + * #list-cells = <1>;
> + * }
> + *
> + * phandle3: node3 {
> + * #list-cells = <1>;
> + * list-map = <0 &phandle2 3>,
> + * <1 &phandle2 2>,
> + * <2 &phandle1 5 1>;
> + * list-map-mask = <0x3>;
> + * };
> + *
> + * node4 {
> + * list = <&phandle1 1 2 &phandle3 0>;
> + * }
> + *
> + * To get a device_node of the `node2' node you may call this:
> + * of_parse_phandle_with_args(node4, "list", "#list-cells", "list-map",
> + * "list-map-mask", 1, &args);
> + */
> +int of_parse_phandle_with_args_map(const struct device_node *np,
> + const char *list_name,
> + const char *cells_name,
> + const char *map_name,
> + const char *mask_name,
Perhaps these 3 could be just a single base name (e.g. "gpio")?
Doesn't really buy much other than enforce we don't mix 'gpios' and
'gpio'. That could never happen. ;)
> + int index, struct of_phandle_args *out_args)
> +{
Rob
^ permalink raw reply
* Re: [PATCH v3 4/4] [media] dt-bindings: add TI VPIF documentation
From: Kevin Hilman @ 2016-11-30 23:48 UTC (permalink / raw)
To: Sakari Ailus
Cc: Rob Herring, linux-media@vger.kernel.org, Hans Verkuil,
devicetree@vger.kernel.org, Sekhar Nori, Axel Haslam,
Bartosz Gołaszewski, Alexandre Bailon, David Lechner,
g.liakhovetski-Mmb7MZpHnFY,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw
In-Reply-To: <20161130214835.GN16630-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
Sakari Ailus <sakari.ailus-X3B1VOXEql0@public.gmane.org> writes:
> Hi Rob and Kevin,
>
> On Tue, Nov 29, 2016 at 08:41:44AM -0600, Rob Herring wrote:
>> On Mon, Nov 28, 2016 at 4:30 PM, Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org> wrote:
>> > Hi Rob,
>> >
>> > Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> writes:
>> >
>> >> On Tue, Nov 22, 2016 at 07:52:44AM -0800, Kevin Hilman wrote:
>> >>> Signed-off-by: Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> >>> ---
>> >>> .../bindings/media/ti,da850-vpif-capture.txt | 65 ++++++++++++++++++++++
>> >>> .../devicetree/bindings/media/ti,da850-vpif.txt | 8 +++
>> >>> 2 files changed, 73 insertions(+)
>> >>> create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> >>> create mode 100644 Documentation/devicetree/bindings/media/ti,da850-vpif.txt
>> >>>
>> >>> diff --git a/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt b/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> >>> new file mode 100644
>> >>> index 000000000000..c447ac482c1d
>> >>> --- /dev/null
>> >>> +++ b/Documentation/devicetree/bindings/media/ti,da850-vpif-capture.txt
>> >>> @@ -0,0 +1,65 @@
>> >>> +Texas Instruments VPIF Capture
>> >>> +------------------------------
>> >>> +
>> >>> +The TI Video Port InterFace (VPIF) capture component is the primary
>> >>> +component for video capture on the DA850 family of TI DaVinci SoCs.
>> >>> +
>> >>> +TI Document number reference: SPRUH82C
>> >>> +
>> >>> +Required properties:
>> >>> +- compatible: must be "ti,da850-vpif-capture"
>> >>> +- reg: physical base address and length of the registers set for the device;
>> >>> +- interrupts: should contain IRQ line for the VPIF
>> >>> +
>> >>> +VPIF capture has a 16-bit parallel bus input, supporting 2 8-bit
>> >>> +channels or a single 16-bit channel. It should contain at least one
>> >>> +port child node with child 'endpoint' node. Please refer to the
>> >>> +bindings defined in
>> >>> +Documentation/devicetree/bindings/media/video-interfaces.txt.
>> >>> +
>> >>> +Example using 2 8-bit input channels, one of which is connected to an
>> >>> +I2C-connected TVP5147 decoder:
>> >>> +
>> >>> + vpif_capture: video-capture@0x00217000 {
>> >>> + reg = <0x00217000 0x1000>;
>> >>> + interrupts = <92>;
>> >>> +
>> >>> + port {
>> >>> + vpif_ch0: endpoint@0 {
>> >>> + reg = <0>;
>> >>> + bus-width = <8>;
>> >>> + remote-endpoint = <&composite>;
>> >>> + };
>> >>> +
>> >>> + vpif_ch1: endpoint@1 {
>> >>
>> >> I think probably channels here should be ports rather than endpoints.
>> >> AIUI, having multiple endpoints is for cases like a mux or 1 to many
>> >> connections. There's only one data flow, but multiple sources or sinks.
>> >
>> > Looking at this closer... , I used an endpoint because it's bascially a
>> > 16-bit parallel bus, that can be configured as (up to) 2 8-bit
>> > "channels. So, based on the video-interfaces.txt doc, I configured this
>> > as a single port, with (up to) 2 endpoints. That also allows me to
>> > connect output of the decoder directly, using the remote-endpoint
>> > property.
>> >
>> > So I guess I'm not fully understanding your suggestion.
>>
>> NM, looks like video-interfaces.txt actually spells out this case and
>> defines doing it as you did.
>
> It's actually the first time I read that portion (at least so that I could
> remember) of video-interfaces.txt. I'm not sure if anyone has implemented
> that previously, nor how we ended up with the text. The list archive could
> probably tell. Cc Guennadi who wrote it. :-) I couldn't immediately find DT
> source with this arrangement.
>
> In case of splitting the port into two parallel interfaces, how do you
> determine which wires belong to which endpoint? I guess they'd be particular
> sets of wires but as there's just a single port it isn't defined by the
> port.
Isn't that the point of data-shift?
e.g. it's a single 16-bit parallel bus, where the lower 8 bits are for
channel 0 and the upper 8 bits are for channel 1. Alternately, the port
can also be configured as a single 16-bit channel (e.g. for raw
capture.)
If you want more details on this hardware, it's pretty well described in
Chapter 35 of http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf.
FWIW, I'm not really picky about how to do this. I'm trying to learn
"the right way" and am happy to do that, but the feedback so far has
been confusing (at least for someone relatively new to the DT side of
the media framework.)
Kevin
--
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 3/4] [media] davinci: vpif_capture: get subdevs from DT
From: Kevin Hilman @ 2016-12-01 0:14 UTC (permalink / raw)
To: Sakari Ailus
Cc: linux-media-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil,
devicetree-u79uwXL29TY76Z2rM5mHXA, Sekhar Nori, Axel Haslam,
Bartosz Gołaszewski, Alexandre Bailon, David Lechner,
laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw
In-Reply-To: <20161130225136.GO16630-S+BSfZ9RZZmRSg0ZkenSGLdO1Tsj/99ntUK59QYPAWc@public.gmane.org>
Sakari Ailus <sakari.ailus-X3B1VOXEql0@public.gmane.org> writes:
> Hi Kevin,
>
> On Wed, Nov 23, 2016 at 03:25:32PM -0800, Kevin Hilman wrote:
>> Hi Sakari,
>>
>> Sakari Ailus <sakari.ailus-X3B1VOXEql0@public.gmane.org> writes:
>>
>> > On Tue, Nov 22, 2016 at 07:52:43AM -0800, Kevin Hilman wrote:
>> >> Allow getting of subdevs from DT ports and endpoints.
>> >>
>> >> The _get_pdata() function was larely inspired by (i.e. stolen from)
>> >
>> > vpif_capture_get_pdata and "largely"?
>>
>> Yes, thanks.
>>
>> >> am437x-vpfe.c
>> >>
>> >> Signed-off-by: Kevin Hilman <khilman-rdvid1DuHRBWk0Htik3J/w@public.gmane.org>
>> >> ---
>> >> drivers/media/platform/davinci/vpif_capture.c | 130 +++++++++++++++++++++++++-
>> >> include/media/davinci/vpif_types.h | 9 +-
>> >> 2 files changed, 133 insertions(+), 6 deletions(-)
>> >>
>> >> diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
>> >> index 94ee6cf03f02..47a4699157e7 100644
>> >> --- a/drivers/media/platform/davinci/vpif_capture.c
>> >> +++ b/drivers/media/platform/davinci/vpif_capture.c
>> >> @@ -26,6 +26,8 @@
>> >> #include <linux/slab.h>
>> >>
>> >> #include <media/v4l2-ioctl.h>
>> >> +#include <media/v4l2-of.h>
>> >> +#include <media/i2c/tvp514x.h>
>> >
>> > Do you need this header?
>> >
>>
>> Yes, based on discussion with Hans, since there is no DT binding for
>> selecting the input pins of the TVP514x, I have to select it in the
>> driver, so I need the defines from this header. More on this below...
>>
>> >>
>> >> #include "vpif.h"
>> >> #include "vpif_capture.h"
>> >> @@ -650,6 +652,10 @@ static int vpif_input_to_subdev(
>> >>
>> >> vpif_dbg(2, debug, "vpif_input_to_subdev\n");
>> >>
>> >> + if (!chan_cfg)
>> >> + return -1;
>> >> + if (input_index >= chan_cfg->input_count)
>> >> + return -1;
>> >> subdev_name = chan_cfg->inputs[input_index].subdev_name;
>> >> if (subdev_name == NULL)
>> >> return -1;
>> >> @@ -657,7 +663,7 @@ static int vpif_input_to_subdev(
>> >> /* loop through the sub device list to get the sub device info */
>> >> for (i = 0; i < vpif_cfg->subdev_count; i++) {
>> >> subdev_info = &vpif_cfg->subdev_info[i];
>> >> - if (!strcmp(subdev_info->name, subdev_name))
>> >> + if (subdev_info && !strcmp(subdev_info->name, subdev_name))
>> >> return i;
>> >> }
>> >> return -1;
>> >> @@ -1327,6 +1333,21 @@ static int vpif_async_bound(struct v4l2_async_notifier *notifier,
>> >> {
>> >> int i;
>> >>
>> >> + for (i = 0; i < vpif_obj.config->asd_sizes[0]; i++) {
>> >> + struct v4l2_async_subdev *_asd = vpif_obj.config->asd[i];
>> >> + const struct device_node *node = _asd->match.of.node;
>> >> +
>> >> + if (node == subdev->of_node) {
>> >> + vpif_obj.sd[i] = subdev;
>> >> + vpif_obj.config->chan_config->inputs[i].subdev_name =
>> >> + (char *)subdev->of_node->full_name;
>> >> + vpif_dbg(2, debug,
>> >> + "%s: setting input %d subdev_name = %s\n",
>> >> + __func__, i, subdev->of_node->full_name);
>> >> + return 0;
>> >> + }
>> >> + }
>> >> +
>> >> for (i = 0; i < vpif_obj.config->subdev_count; i++)
>> >> if (!strcmp(vpif_obj.config->subdev_info[i].name,
>> >> subdev->name)) {
>> >> @@ -1422,6 +1443,110 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
>> >> return vpif_probe_complete();
>> >> }
>> >>
>> >> +static struct vpif_capture_config *
>> >> +vpif_capture_get_pdata(struct platform_device *pdev)
>> >> +{
>> >> + struct device_node *endpoint = NULL;
>> >> + struct v4l2_of_endpoint bus_cfg;
>> >> + struct vpif_capture_config *pdata;
>> >> + struct vpif_subdev_info *sdinfo;
>> >> + struct vpif_capture_chan_config *chan;
>> >> + unsigned int i;
>> >> +
>> >> + dev_dbg(&pdev->dev, "vpif_get_pdata\n");
>> >> +
>> >> + if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
>> >> + return pdev->dev.platform_data;
>> >> +
>> >> + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
>> >> + if (!pdata)
>> >> + return NULL;
>> >> + pdata->subdev_info =
>> >> + devm_kzalloc(&pdev->dev, sizeof(*pdata->subdev_info) *
>> >> + VPIF_CAPTURE_MAX_CHANNELS, GFP_KERNEL);
>> >> +
>> >> + if (!pdata->subdev_info)
>> >> + return NULL;
>> >> + dev_dbg(&pdev->dev, "%s\n", __func__);
>> >> +
>> >> + for (i = 0; ; i++) {
>> >> + struct device_node *rem;
>> >> + unsigned int flags;
>> >> + int err;
>> >> +
>> >> + endpoint = of_graph_get_next_endpoint(pdev->dev.of_node,
>> >> + endpoint);
>> >> + if (!endpoint)
>> >> + break;
>> >> +
>> >> + sdinfo = &pdata->subdev_info[i];
>> >
>> > subdev_info[] has got VPIF_CAPTURE_MAX_CHANNELS entries only.
>> >
>>
>> Right, I need to make the loop only go for a max of
>> VPIF_CAPTURE_MAX_CHANNELS iterations.
>>
>> >> + chan = &pdata->chan_config[i];
>> >> + chan->inputs = devm_kzalloc(&pdev->dev,
>> >> + sizeof(*chan->inputs) *
>> >> + VPIF_DISPLAY_MAX_CHANNELS,
>> >> + GFP_KERNEL);
>> >> +
>> >> + chan->input_count++;
>> >> + chan->inputs[i].input.type = V4L2_INPUT_TYPE_CAMERA;
>> >
>> > I wonder what's the purpose of using index i on this array as well.
>>
>> The number of endpoints in DT is the number of input channels configured
>> (up to a max of VPIF_CAPTURE_MAX_CHANNELS.)
>>
>> > If you use that to access a corresponding entry in a different array, I'd
>> > just create a struct that contains the port configuration and the async
>> > sub-device. The omap3isp driver does that, for instance; see
>> > isp_of_parse_nodes() in drivers/media/platform/omap3isp/isp.c if you're
>> > interested. Up to you.
>>
>> OK, I'll have a look at that driver. The goal here with this series is
>> just to get this working with DT, but also not break the existing legacy
>> platform_device support, so I'm trying not to mess with the
>> driver-interal data structures too much.
>
> Ack.
>
>>
>> >> + chan->inputs[i].input.std = V4L2_STD_ALL;
>> >> + chan->inputs[i].input.capabilities = V4L2_IN_CAP_STD;
>> >> +
>> >> + /* FIXME: need a new property? ch0:composite ch1: s-video */
>> >> + if (i == 0)
>> >
>> > Can you assume that the first endopoint has got a particular kind of input?
>> > What if it's not connected?
>>
>> On all the boards I know of (there aren't many using this SoC), it's a
>> safe assumption.
>>
>> > If this is a different physical port (not in the meaning another) in the
>> > device, I'd use the reg property for this. Please see
>> > Documentation/devicetree/bindings/media/video-interfaces.txt .
>>
>> My understanding (which is admittedly somewhat fuzzy) of the TVP514x is
>> that it's not physically a different port. Instead, it's just telling
>> the TVP514x which pin(s) will be active inputs (and what kind of signal
>> will be present.)
>>
>> I'm open to a better way to describe this input select from DT, but
>> based on what I heard from Hans, there isn't currently a good way to do
>> that except for in the driver:
>> (c.f. https://marc.info/?l=linux-arm-kernel&m=147887871615788)
>>
>> Based on further discussion in that thread, it sounds like there may be
>> a way forward coming soon, and I'll be glad to switch to that when it
>> arrives.
>
> I'm not sure that properly supporting connectors will provide any help here.
>
> Looking at the s_routing() API, it's the calling driver that has to be aware
> of sub-device specific function parameters. As such it's not a very good
> idea to require that a driver is aware of the value range of another
> driver's parameter. I wonder if a simple enumeration interface would help
> here --- if I understand correctly, the purpose is just to provide a way to
> choose the input using VIDIOC_S_INPUT.
>
> I guess that's somehow ok as long as you have no other combinations of these
> devices but this is hardly future-proof. (And certainly not a problem
> created by this patch.)
Yeah, this is far from future proof.
> It'd be still nice to fix that as presumably we don't have the option of
> reworking how we expect the device tree to look like.
Agreed.
I'm just hoping someone can shed som light on "how we expect the device
tree to look". ;)
Kevin
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH V6 08/10] PM / OPP: Allow platform specific custom set_opp() callbacks
From: Viresh Kumar @ 2016-12-01 0:27 UTC (permalink / raw)
To: Stephen Boyd
Cc: Rafael Wysocki, Viresh Kumar, Nishanth Menon,
linaro-kernel-cunTk1MwBs8s++Sfvej+rw,
linux-pm-u79uwXL29TY76Z2rM5mHXA, Vincent Guittot,
robh-DgEjT+Ai2ygdnm+yROfE0A, d-gerlach-l0cyMroinI0,
broonie-DgEjT+Ai2ygdnm+yROfE0A, devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20161130220419.GL6095-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On 30-11-16, 14:04, Stephen Boyd wrote:
> On 11/30, Viresh Kumar wrote:
> > The generic set_opp() handler isn't sufficient for platforms with
> > complex DVFS. For example, some TI platforms have multiple regulators
> > for a CPU device. The order in which various supplies need to be
> > programmed is only known to the platform code and its best to leave it
> > to it.
> >
> > This patch implements APIs to register platform specific set_opp()
> > callback.
> >
> > Signed-off-by: Viresh Kumar <viresh.kumar-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> > Tested-by: Dave Gerlach <d-gerlach-l0cyMroinI0@public.gmane.org>
> >
> > ---
>
> Reviewed-by: Stephen Boyd <sboyd-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
Thanks.
> So this one has the same set/put problem the other APIs has?
Yes.
> Presumably we're going to need to fix and change the API that is
> introduced here. Wouldn't it be better to do that first though?
Returning opp_table is one of the solutions and I am not sure if it is
the best one. I am working on the cleanup series and will modify all
the routine the same way very soon.
--
viresh
--
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 6/6] pinctrl: mt8173: set GPIO16 to usb iddig mode
From: Hongzhou Yang @ 2016-12-01 0:43 UTC (permalink / raw)
To: Matthias Brugger
Cc: Mark Rutland, Maoguang Meng, Linus Walleij, Mathias Nyman,
Alan Stern, chunfeng yun, Yingjoe Chen, Felipe Balbi,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Pawel Moll,
Ian Campbell, Biao Huang, Sascha Hauer,
linux-gpio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Rob Herring,
moderated list:ARM/Mediatek SoC support,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
Sergei Shtylyov, Greg Kroah-Hartman <gregkh>
In-Reply-To: <42f5df18-2edd-08f2-a833-9c92ac85e87c-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Wed, 2016-11-23 at 19:32 +0100, Matthias Brugger wrote:
> Hi Hongzhou,
>
> On 12/05/16 04:55, Hongzhou Yang wrote:
> > On Wed, 2016-05-11 at 19:09 -0700, Hongzhou Yang wrote:
> >> On Thu, 2016-05-12 at 09:41 +0800, chunfeng yun wrote:
> >>> Hi,
> >>>
> >>> On Wed, 2016-05-11 at 11:32 -0700, Hongzhou Yang wrote:
> >>>> On Wed, 2016-05-11 at 13:56 +0200, Linus Walleij wrote:
> >>>>> On Tue, May 10, 2016 at 10:23 AM, Chunfeng Yun
> >>>>> <chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org> wrote:
> >>>>>
> >>>>>> the default mode of GPIO16 pin is gpio, when set EINT16 to
> >>>>>> IRQ_TYPE_LEVEL_HIGH, no interrupt is triggered, it can be
> >>>>>> fixed when set its default mode as usb iddig.
> >>>>>>
> >>>>>> Signed-off-by: Chunfeng Yun <chunfeng.yun-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> >>>>>
> >>>>
> >>>> Chunfeng, GPIO16 can be used as EINT16 mode, but the pinmux should be 0.
> >>>> If you want to set its default mode to iddig, you should set it in dts.
> >>>>
> >>> I set it in DTS, but it didn't work, because when usb driver requested
> >>> IRQ, pinmux was switched back to default mode set by
> >>> MTK_EINT_FUNCTION().
> >>>
> >>
> >> After confirmed, there are something wrong with data sheet and pinmux
> >> table, and GPIO16 can only receive interrupt by mode 1. So
> >>
> >> Acked-by: Hongzhou Yang <hongzhou.yang-NuS5LvNUpcJWk0Htik3J/w@public.gmane.org>
> >>
> >
> > Linus,
> >
> > We find there are some other pins still have the same problem, so please
> > hold on it. Sorry for so much noise.
> >
>
> Did you made any progress on this? I didn't see any patch on the mailing
> list.
>
> Regards,
> Matthias
Hi Matthias,
Sorry for the late reply.
I have double confirmed with HW designer, other special EINTs are
built-in and they are using internal signal, they are not triggered
by GPIO, only GPIO16 should set to mode 1.
And, Chunfeng already re-sent this patch.
Thank you very much.
Yours,
Hongzhou
^ permalink raw reply
* [resend V2:PATCH 0/2] add reset-hi3660
From: Zhangfei Gao @ 2016-12-01 0:48 UTC (permalink / raw)
To: Rob Herring, Philipp Zabel, Arnd Bergmann
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Zhangfei Gao
Considering Arnd and Philipp suggestions,
move reset register to dts as table instead of dts header in case of ABI issue
Zhangfei Gao (2):
dt-bindings: Document the hi3660 reset bindings
reset: hisilicon: add reset-hi3660
.../bindings/reset/hisilicon,hi3660-reset.txt | 51 ++++++++
drivers/reset/hisilicon/Kconfig | 7 +
drivers/reset/hisilicon/Makefile | 1 +
drivers/reset/hisilicon/reset-hi3660.c | 144 +++++++++++++++++++++
4 files changed, 203 insertions(+)
create mode 100644 Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
create mode 100644 drivers/reset/hisilicon/reset-hi3660.c
--
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
* [resend v2: PATCH 1/2] dt-bindings: Document the hi3660 reset bindings
From: Zhangfei Gao @ 2016-12-01 0:48 UTC (permalink / raw)
To: Rob Herring, Philipp Zabel, Arnd Bergmann
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Zhangfei Gao
In-Reply-To: <1480553321-17400-1-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Add DT bindings documentation for hi3660 SoC reset controller.
Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
.../bindings/reset/hisilicon,hi3660-reset.txt | 51 ++++++++++++++++++++++
1 file changed, 51 insertions(+)
create mode 100644 Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
diff --git a/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
new file mode 100644
index 0000000..250daf2
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/hisilicon,hi3660-reset.txt
@@ -0,0 +1,51 @@
+Hisilicon System Reset Controller
+======================================
+
+Please also refer to reset.txt in this directory for common reset
+controller binding usage.
+
+The reset controller registers are part of the system-ctl block on
+hi3660 SoC.
+
+Required properties:
+- compatible: should be
+ "hisilicon,hi3660-reset"
+- #reset-cells: 1, see below
+- hisi,rst-syscon: phandle of the reset's syscon.
+- hisi,reset-bits: Contains the reset control register information
+ Should contain 2 cells for each reset exposed to
+ consumers, defined as:
+ Cell #1 : offset from the syscon register base
+ Cell #2 : bits position of the control register
+
+Example:
+ iomcu: iomcu@ffd7e000 {
+ compatible = "hisilicon,hi3660-iomcu", "syscon";
+ reg = <0x0 0xffd7e000 0x0 0x1000>;
+ };
+
+ iomcu_rst: iomcu_rst_controller {
+ compatible = "hisilicon,hi3660-reset";
+ #reset-cells = <1>;
+ hisi,rst-syscon = <&iomcu>;
+ 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>;
+ ...
+ };
+
+ i2c1: i2c@..... {
+ ...
+ resets = <&iomcu_rst 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 V2: PATCH 2/2] reset: hisilicon: add reset-hi3660
From: Zhangfei Gao @ 2016-12-01 0:48 UTC (permalink / raw)
To: Rob Herring, Philipp Zabel, Arnd Bergmann
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Zhangfei Gao
In-Reply-To: <1480553321-17400-1-git-send-email-zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Add hi3660 reset driver
Reset offset & bits should be listed in dts
Like:
iomcu_rst: iomcu_rst_controller {
compatible = "hisilicon,hi3660-reset";
#reset-cells = <1>;
hisi,rst-syscon = <&iomcu>;
hisi,reset-bits = <0x20 0x8 /* 0: i2c0 */
0x20 0x10 /* 1: i2c1 */
0x20 0x20 /* 2: i2c2 */
0x20 0x8000000>; /* 3: i2c6 */
};
Signed-off-by: Zhangfei Gao <zhangfei.gao-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
drivers/reset/hisilicon/Kconfig | 7 ++
drivers/reset/hisilicon/Makefile | 1 +
drivers/reset/hisilicon/reset-hi3660.c | 144 +++++++++++++++++++++++++++++++++
3 files changed, 152 insertions(+)
create mode 100644 drivers/reset/hisilicon/reset-hi3660.c
diff --git a/drivers/reset/hisilicon/Kconfig b/drivers/reset/hisilicon/Kconfig
index 1ff8b0c..10134dc 100644
--- a/drivers/reset/hisilicon/Kconfig
+++ b/drivers/reset/hisilicon/Kconfig
@@ -1,3 +1,10 @@
+config COMMON_RESET_HI3660
+ tristate "Hi3660 Reset Driver"
+ depends on ARCH_HISI || COMPILE_TEST
+ default ARCH_HISI
+ help
+ Build the Hisilicon Hi3660 reset driver.
+
config COMMON_RESET_HI6220
tristate "Hi6220 Reset Driver"
depends on ARCH_HISI || COMPILE_TEST
diff --git a/drivers/reset/hisilicon/Makefile b/drivers/reset/hisilicon/Makefile
index c932f86..ab8a7bf 100644
--- a/drivers/reset/hisilicon/Makefile
+++ b/drivers/reset/hisilicon/Makefile
@@ -1 +1,2 @@
obj-$(CONFIG_COMMON_RESET_HI6220) += hi6220_reset.o
+obj-$(CONFIG_COMMON_RESET_HI3660) += reset-hi3660.o
diff --git a/drivers/reset/hisilicon/reset-hi3660.c b/drivers/reset/hisilicon/reset-hi3660.c
new file mode 100644
index 0000000..3307252
--- /dev/null
+++ b/drivers/reset/hisilicon/reset-hi3660.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2016-2017 Linaro Ltd.
+ * Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/reset-controller.h>
+
+struct hi3660_reset_data {
+ unsigned int off;
+ unsigned int bits;
+};
+
+struct hi3660_reset_controller {
+ struct reset_controller_dev rst;
+ struct regmap *map;
+ const struct hi3660_reset_data *datas;
+};
+
+#define to_hi3660_reset_controller(_rst) \
+ container_of(_rst, struct hi3660_reset_controller, rst)
+
+static int hi3660_reset_program_hw(struct reset_controller_dev *rcdev,
+ unsigned long idx, bool assert)
+{
+ struct hi3660_reset_controller *rc = to_hi3660_reset_controller(rcdev);
+ const struct hi3660_reset_data *d;
+
+ if (idx >= rcdev->nr_resets)
+ return -EINVAL;
+
+ d = &rc->datas[idx];
+
+ if (assert)
+ return regmap_write(rc->map, d->off, d->bits);
+ else
+ return regmap_write(rc->map, d->off + 4, d->bits);
+}
+
+static int hi3660_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ return hi3660_reset_program_hw(rcdev, idx, true);
+}
+
+static int hi3660_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ return hi3660_reset_program_hw(rcdev, idx, false);
+}
+
+static int hi3660_reset_dev(struct reset_controller_dev *rcdev,
+ unsigned long idx)
+{
+ int err;
+
+ err = hi3660_reset_assert(rcdev, idx);
+ if (err)
+ return err;
+
+ return hi3660_reset_deassert(rcdev, idx);
+}
+
+static struct reset_control_ops hi3660_reset_ops = {
+ .reset = hi3660_reset_dev,
+ .assert = hi3660_reset_assert,
+ .deassert = hi3660_reset_deassert,
+};
+
+static int hi3660_reset_probe(struct platform_device *pdev)
+{
+ struct hi3660_reset_controller *rc;
+ struct device_node *np = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct hi3660_reset_data *datas;
+ const __be32 *list;
+ int size, nr, i;
+
+ rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL);
+ if (!rc)
+ return -ENOMEM;
+
+ rc->map = syscon_regmap_lookup_by_phandle(np, "hisi,rst-syscon");
+ if (IS_ERR(rc->map)) {
+ dev_err(dev, "failed to get hi3660,rst-syscon\n");
+ return PTR_ERR(rc->map);
+ }
+
+ list = of_get_property(np, "hisi,reset-bits", &size);
+ if (!list || (size / sizeof(*list)) % 2 != 0) {
+ dev_err(dev, "invalid DT reset description\n");
+ return -EINVAL;
+ }
+
+ nr = (size / sizeof(*list)) / 2;
+ datas = devm_kzalloc(dev, nr * sizeof(*datas), GFP_KERNEL);
+ if (!datas)
+ return -ENOMEM;
+
+ for (i = 0; i < nr; i++) {
+ datas[i].off = be32_to_cpup(list++);
+ datas[i].bits = be32_to_cpup(list++);
+ }
+
+ rc->rst.ops = &hi3660_reset_ops,
+ rc->rst.of_node = np;
+ rc->rst.nr_resets = nr;
+ rc->datas = datas;
+
+ return reset_controller_register(&rc->rst);
+}
+
+static const struct of_device_id hi3660_reset_match[] = {
+ { .compatible = "hisilicon,hi3660-reset", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, hi3660_reset_match);
+
+static struct platform_driver hi3660_reset_driver = {
+ .probe = hi3660_reset_probe,
+ .driver = {
+ .name = "hi3660-reset",
+ .of_match_table = hi3660_reset_match,
+ },
+};
+
+static int __init hi3660_reset_init(void)
+{
+ return platform_driver_register(&hi3660_reset_driver);
+}
+arch_initcall(hi3660_reset_init);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hi3660-reset");
+MODULE_DESCRIPTION("HiSilicon Hi3660 Reset Driver");
--
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 V6 06/10] PM / OPP: Add infrastructure to manage multiple regulators
From: Viresh Kumar @ 2016-12-01 0:51 UTC (permalink / raw)
To: Stephen Boyd
Cc: Rafael Wysocki, Viresh Kumar, Nishanth Menon, linaro-kernel,
linux-pm, Vincent Guittot, robh, d-gerlach, broonie, devicetree
In-Reply-To: <20161130223712.GM6095@codeaurora.org>
On 30-11-16, 14:37, Stephen Boyd wrote:
> > +static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
> > + struct opp_table *opp_table,
> > + struct dentry *pdentry)
> > +{
> > + struct dentry *d;
> > + int i = 0;
> > + char *name;
> > +
> > + /* Always create at least supply-0 directory */
> > + do {
> > + name = kasprintf(GFP_KERNEL, "supply-%d", i);
>
> Sorry I haven't noticed this before. Wouldn't we want to put the
> supply name here instead of a number?
The OPP core provides a way for platforms to use the set-OPP
functionality, but that is not compulsory for its user. Which makes it
very much possible that the OPP core wouldn't know the names of the
supplies at all. And so I used the numbers here. Anyway, the numbers
matches the order in which they are passed from DT, so that should be
readable.
Here is the new rebased version of the patch. I will send the complete
series again later on. Please see if it looks fine.
-------------------------8<-------------------------
From: Viresh Kumar <viresh.kumar@linaro.org>
Date: Tue, 4 Oct 2016 17:07:28 +0530
Subject: [PATCH] PM / OPP: Add infrastructure to manage multiple regulators
This patch adds infrastructure to manage multiple regulators and updates
the only user (cpufreq-dt) of dev_pm_opp_set{put}_regulator().
This is preparatory work for adding full support for devices with
multiple regulators.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Tested-by: Dave Gerlach <d-gerlach@ti.com>
---
drivers/base/power/opp/core.c | 248 +++++++++++++++++++++++++++------------
drivers/base/power/opp/debugfs.c | 52 ++++++--
drivers/base/power/opp/of.c | 103 +++++++++++-----
drivers/base/power/opp/opp.h | 10 +-
drivers/cpufreq/cpufreq-dt.c | 9 +-
include/linux/pm_opp.h | 8 +-
6 files changed, 303 insertions(+), 127 deletions(-)
diff --git a/drivers/base/power/opp/core.c b/drivers/base/power/opp/core.c
index 46ad8470c438..b4da31c5a5eb 100644
--- a/drivers/base/power/opp/core.c
+++ b/drivers/base/power/opp/core.c
@@ -93,6 +93,8 @@ struct opp_table *_find_opp_table(struct device *dev)
* Return: voltage in micro volt corresponding to the opp, else
* return 0
*
+ * This is useful only for devices with single power supply.
+ *
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
* protected pointer. This means that opp which could have been fetched by
* opp_find_freq_{exact,ceil,floor} functions is valid as long as we are
@@ -112,7 +114,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
if (IS_ERR_OR_NULL(tmp_opp))
pr_err("%s: Invalid parameters\n", __func__);
else
- v = tmp_opp->supply.u_volt;
+ v = tmp_opp->supplies[0].u_volt;
return v;
}
@@ -210,6 +212,24 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency);
+static int _get_regulator_count(struct device *dev)
+{
+ struct opp_table *opp_table;
+ int count;
+
+ rcu_read_lock();
+
+ opp_table = _find_opp_table(dev);
+ if (!IS_ERR(opp_table))
+ count = opp_table->regulator_count;
+ else
+ count = 0;
+
+ rcu_read_unlock();
+
+ return count;
+}
+
/**
* dev_pm_opp_get_max_volt_latency() - Get max voltage latency in nanoseconds
* @dev: device for which we do this operation
@@ -222,34 +242,51 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
{
struct opp_table *opp_table;
struct dev_pm_opp *opp;
- struct regulator *reg;
+ struct regulator *reg, **regulators;
unsigned long latency_ns = 0;
- unsigned long min_uV = ~0, max_uV = 0;
- int ret;
+ int ret, i, count;
+ struct {
+ unsigned long min;
+ unsigned long max;
+ } *uV;
+
+ count = _get_regulator_count(dev);
+
+ /* Regulator may not be required for the device */
+ if (!count)
+ return 0;
+
+ regulators = kmalloc_array(count, sizeof(*regulators), GFP_KERNEL);
+ if (!regulators)
+ return 0;
+
+ uV = kmalloc_array(count, sizeof(*uV), GFP_KERNEL);
+ if (!uV)
+ goto free_regulators;
rcu_read_lock();
opp_table = _find_opp_table(dev);
if (IS_ERR(opp_table)) {
rcu_read_unlock();
- return 0;
+ goto free_uV;
}
- reg = opp_table->regulator;
- if (IS_ERR(reg)) {
- /* Regulator may not be required for device */
- rcu_read_unlock();
- return 0;
- }
+ memcpy(regulators, opp_table->regulators, count * sizeof(*regulators));
- list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
- if (!opp->available)
- continue;
+ for (i = 0; i < count; i++) {
+ uV[i].min = ~0;
+ uV[i].max = 0;
- if (opp->supply.u_volt_min < min_uV)
- min_uV = opp->supply.u_volt_min;
- if (opp->supply.u_volt_max > max_uV)
- max_uV = opp->supply.u_volt_max;
+ list_for_each_entry_rcu(opp, &opp_table->opp_list, node) {
+ if (!opp->available)
+ continue;
+
+ if (opp->supplies[i].u_volt_min < uV[i].min)
+ uV[i].min = opp->supplies[i].u_volt_min;
+ if (opp->supplies[i].u_volt_max > uV[i].max)
+ uV[i].max = opp->supplies[i].u_volt_max;
+ }
}
rcu_read_unlock();
@@ -258,9 +295,16 @@ unsigned long dev_pm_opp_get_max_volt_latency(struct device *dev)
* The caller needs to ensure that opp_table (and hence the regulator)
* isn't freed, while we are executing this routine.
*/
- ret = regulator_set_voltage_time(reg, min_uV, max_uV);
- if (ret > 0)
- latency_ns = ret * 1000;
+ for (i = 0; reg = regulators[i], i < count; i++) {
+ ret = regulator_set_voltage_time(reg, uV[i].min, uV[i].max);
+ if (ret > 0)
+ latency_ns += ret * 1000;
+ }
+
+free_uV:
+ kfree(uV);
+free_regulators:
+ kfree(regulators);
return latency_ns;
}
@@ -580,7 +624,7 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
struct opp_table *opp_table;
struct dev_pm_opp *old_opp, *opp;
- struct regulator *reg;
+ struct regulator *reg = ERR_PTR(-ENXIO);
struct clk *clk;
unsigned long freq, old_freq;
struct dev_pm_opp_supply old_supply, new_supply;
@@ -633,14 +677,23 @@ int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
return ret;
}
+ if (opp_table->regulators) {
+ /* This function only supports single regulator per device */
+ if (WARN_ON(opp_table->regulator_count > 1)) {
+ dev_err(dev, "multiple regulators not supported\n");
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ reg = opp_table->regulators[0];
+ }
+
if (IS_ERR(old_opp))
old_supply.u_volt = 0;
else
- memcpy(&old_supply, &old_opp->supply, sizeof(old_supply));
-
- memcpy(&new_supply, &opp->supply, sizeof(new_supply));
+ memcpy(&old_supply, old_opp->supplies, sizeof(old_supply));
- reg = opp_table->regulator;
+ memcpy(&new_supply, opp->supplies, sizeof(new_supply));
rcu_read_unlock();
@@ -764,9 +817,6 @@ static struct opp_table *_add_opp_table(struct device *dev)
_of_init_opp_table(opp_table, dev);
- /* Set regulator to a non-NULL error value */
- opp_table->regulator = ERR_PTR(-ENXIO);
-
/* Find clk for the device */
opp_table->clk = clk_get(dev, NULL);
if (IS_ERR(opp_table->clk)) {
@@ -815,7 +865,7 @@ static void _remove_opp_table(struct opp_table *opp_table)
if (opp_table->prop_name)
return;
- if (!IS_ERR(opp_table->regulator))
+ if (opp_table->regulators)
return;
/* Release clk */
@@ -924,35 +974,50 @@ struct dev_pm_opp *_allocate_opp(struct device *dev,
struct opp_table **opp_table)
{
struct dev_pm_opp *opp;
+ int count, supply_size;
+ struct opp_table *table;
- /* allocate new OPP node */
- opp = kzalloc(sizeof(*opp), GFP_KERNEL);
- if (!opp)
+ table = _add_opp_table(dev);
+ if (!table)
return NULL;
- INIT_LIST_HEAD(&opp->node);
+ /* Allocate space for at least one supply */
+ count = table->regulator_count ? table->regulator_count : 1;
+ supply_size = sizeof(*opp->supplies) * count;
- *opp_table = _add_opp_table(dev);
- if (!*opp_table) {
- kfree(opp);
+ /* allocate new OPP node and supplies structures */
+ opp = kzalloc(sizeof(*opp) + supply_size, GFP_KERNEL);
+ if (!opp) {
+ kfree(table);
return NULL;
}
+ /* Put the supplies at the end of the OPP structure as an empty array */
+ opp->supplies = (struct dev_pm_opp_supply *)(opp + 1);
+ INIT_LIST_HEAD(&opp->node);
+
+ *opp_table = table;
+
return opp;
}
static bool _opp_supported_by_regulators(struct dev_pm_opp *opp,
struct opp_table *opp_table)
{
- struct regulator *reg = opp_table->regulator;
-
- if (!IS_ERR(reg) &&
- !regulator_is_supported_voltage(reg, opp->supply.u_volt_min,
- opp->supply.u_volt_max)) {
- pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
- __func__, opp->supply.u_volt_min,
- opp->supply.u_volt_max);
- return false;
+ struct regulator *reg;
+ int i;
+
+ for (i = 0; i < opp_table->regulator_count; i++) {
+ reg = opp_table->regulators[i];
+
+ if (!regulator_is_supported_voltage(reg,
+ opp->supplies[i].u_volt_min,
+ opp->supplies[i].u_volt_max)) {
+ pr_warn("%s: OPP minuV: %lu maxuV: %lu, not supported by regulator\n",
+ __func__, opp->supplies[i].u_volt_min,
+ opp->supplies[i].u_volt_max);
+ return false;
+ }
}
return true;
@@ -984,12 +1049,13 @@ int _opp_add(struct device *dev, struct dev_pm_opp *new_opp,
/* Duplicate OPPs */
dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
- __func__, opp->rate, opp->supply.u_volt,
- opp->available, new_opp->rate, new_opp->supply.u_volt,
- new_opp->available);
+ __func__, opp->rate, opp->supplies[0].u_volt,
+ opp->available, new_opp->rate,
+ new_opp->supplies[0].u_volt, new_opp->available);
+ /* Should we compare voltages for all regulators here ? */
return opp->available &&
- new_opp->supply.u_volt == opp->supply.u_volt ? 0 : -EEXIST;
+ new_opp->supplies[0].u_volt == opp->supplies[0].u_volt ? 0 : -EEXIST;
}
new_opp->opp_table = opp_table;
@@ -1056,9 +1122,9 @@ int _opp_add_v1(struct device *dev, unsigned long freq, long u_volt,
/* populate the opp table */
new_opp->rate = freq;
tol = u_volt * opp_table->voltage_tolerance_v1 / 100;
- new_opp->supply.u_volt = u_volt;
- new_opp->supply.u_volt_min = u_volt - tol;
- new_opp->supply.u_volt_max = u_volt + tol;
+ new_opp->supplies[0].u_volt = u_volt;
+ new_opp->supplies[0].u_volt_min = u_volt - tol;
+ new_opp->supplies[0].u_volt_max = u_volt + tol;
new_opp->available = true;
new_opp->dynamic = dynamic;
@@ -1303,12 +1369,14 @@ void dev_pm_opp_put_prop_name(struct device *dev)
EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
/**
- * dev_pm_opp_set_regulator() - Set regulator name for the device
+ * dev_pm_opp_set_regulators() - Set regulator names for the device
* @dev: Device for which regulator name is being set.
- * @name: Name of the regulator.
+ * @names: Array of pointers to the names of the regulator.
+ * @count: Number of regulators.
*
* In order to support OPP switching, OPP layer needs to know the name of the
- * device's regulator, as the core would be required to switch voltages as well.
+ * device's regulators, as the core would be required to switch voltages as
+ * well.
*
* This must be called before any OPPs are initialized for the device.
*
@@ -1318,11 +1386,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_put_prop_name);
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/
-struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
+struct opp_table *dev_pm_opp_set_regulators(struct device *dev,
+ const char * const names[],
+ unsigned int count)
{
struct opp_table *opp_table;
struct regulator *reg;
- int ret;
+ int ret, i;
mutex_lock(&opp_table_lock);
@@ -1338,26 +1408,44 @@ struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
goto err;
}
- /* Already have a regulator set */
- if (WARN_ON(!IS_ERR(opp_table->regulator))) {
+ /* Already have regulators set */
+ if (WARN_ON(opp_table->regulators)) {
ret = -EBUSY;
goto err;
}
- /* Allocate the regulator */
- reg = regulator_get_optional(dev, name);
- if (IS_ERR(reg)) {
- ret = PTR_ERR(reg);
- if (ret != -EPROBE_DEFER)
- dev_err(dev, "%s: no regulator (%s) found: %d\n",
- __func__, name, ret);
+
+ opp_table->regulators = kmalloc_array(count,
+ sizeof(*opp_table->regulators),
+ GFP_KERNEL);
+ if (!opp_table->regulators) {
+ ret = -ENOMEM;
goto err;
}
- opp_table->regulator = reg;
+ for (i = 0; i < count; i++) {
+ reg = regulator_get_optional(dev, names[i]);
+ if (IS_ERR(reg)) {
+ ret = PTR_ERR(reg);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "%s: no regulator (%s) found: %d\n",
+ __func__, names[i], ret);
+ goto free_regulators;
+ }
+
+ opp_table->regulators[i] = reg;
+ }
+
+ opp_table->regulator_count = count;
mutex_unlock(&opp_table_lock);
return opp_table;
+free_regulators:
+ while (i != 0)
+ regulator_put(opp_table->regulators[--i]);
+
+ kfree(opp_table->regulators);
+ opp_table->regulators = NULL;
err:
_remove_opp_table(opp_table);
unlock:
@@ -1365,11 +1453,11 @@ struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
+EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulators);
/**
- * dev_pm_opp_put_regulator() - Releases resources blocked for regulator
- * @opp_table: OPP table returned from dev_pm_opp_set_regulator().
+ * dev_pm_opp_put_regulators() - Releases resources blocked for regulator
+ * @opp_table: OPP table returned from dev_pm_opp_set_regulators().
*
* Locking: The internal opp_table and opp structures are RCU protected.
* Hence this function internally uses RCU updater strategy with mutex locks
@@ -1377,20 +1465,26 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_set_regulator);
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
*/
-void dev_pm_opp_put_regulator(struct opp_table *opp_table)
+void dev_pm_opp_put_regulators(struct opp_table *opp_table)
{
+ int i;
+
mutex_lock(&opp_table_lock);
- if (IS_ERR(opp_table->regulator)) {
- pr_err("%s: Doesn't have regulator set\n", __func__);
+ if (!opp_table->regulators) {
+ pr_err("%s: Doesn't have regulators set\n", __func__);
goto unlock;
}
/* Make sure there are no concurrent readers while updating opp_table */
WARN_ON(!list_empty(&opp_table->opp_list));
- regulator_put(opp_table->regulator);
- opp_table->regulator = ERR_PTR(-ENXIO);
+ for (i = opp_table->regulator_count - 1; i >= 0; i--)
+ regulator_put(opp_table->regulators[i]);
+
+ kfree(opp_table->regulators);
+ opp_table->regulators = NULL;
+ opp_table->regulator_count = 0;
/* Try freeing opp_table if this was the last blocking resource */
_remove_opp_table(opp_table);
@@ -1398,7 +1492,7 @@ void dev_pm_opp_put_regulator(struct opp_table *opp_table)
unlock:
mutex_unlock(&opp_table_lock);
}
-EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulator);
+EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
/**
* dev_pm_opp_add() - Add an OPP table from a table definitions
diff --git a/drivers/base/power/opp/debugfs.c b/drivers/base/power/opp/debugfs.c
index c897676ca35f..95f433db4ac7 100644
--- a/drivers/base/power/opp/debugfs.c
+++ b/drivers/base/power/opp/debugfs.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/limits.h>
+#include <linux/slab.h>
#include "opp.h"
@@ -34,6 +35,46 @@ void opp_debug_remove_one(struct dev_pm_opp *opp)
debugfs_remove_recursive(opp->dentry);
}
+static bool opp_debug_create_supplies(struct dev_pm_opp *opp,
+ struct opp_table *opp_table,
+ struct dentry *pdentry)
+{
+ struct dentry *d;
+ int i = 0;
+ char *name;
+
+ /* Always create at least supply-0 directory */
+ do {
+ name = kasprintf(GFP_KERNEL, "supply-%d", i);
+
+ /* Create per-opp directory */
+ d = debugfs_create_dir(name, pdentry);
+
+ kfree(name);
+
+ if (!d)
+ return false;
+
+ if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d,
+ &opp->supplies[i].u_volt))
+ return false;
+
+ if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d,
+ &opp->supplies[i].u_volt_min))
+ return false;
+
+ if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d,
+ &opp->supplies[i].u_volt_max))
+ return false;
+
+ if (!debugfs_create_ulong("u_amp", S_IRUGO, d,
+ &opp->supplies[i].u_amp))
+ return false;
+ } while (++i < opp_table->regulator_count);
+
+ return true;
+}
+
int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
{
struct dentry *pdentry = opp_table->dentry;
@@ -63,16 +104,7 @@ int opp_debug_create_one(struct dev_pm_opp *opp, struct opp_table *opp_table)
if (!debugfs_create_ulong("rate_hz", S_IRUGO, d, &opp->rate))
return -ENOMEM;
- if (!debugfs_create_ulong("u_volt_target", S_IRUGO, d, &opp->supply.u_volt))
- return -ENOMEM;
-
- if (!debugfs_create_ulong("u_volt_min", S_IRUGO, d, &opp->supply.u_volt_min))
- return -ENOMEM;
-
- if (!debugfs_create_ulong("u_volt_max", S_IRUGO, d, &opp->supply.u_volt_max))
- return -ENOMEM;
-
- if (!debugfs_create_ulong("u_amp", S_IRUGO, d, &opp->supply.u_amp))
+ if (!opp_debug_create_supplies(opp, opp_table, d))
return -ENOMEM;
if (!debugfs_create_ulong("clock_latency_ns", S_IRUGO, d,
diff --git a/drivers/base/power/opp/of.c b/drivers/base/power/opp/of.c
index bdf409d42126..3f7d2591b173 100644
--- a/drivers/base/power/opp/of.c
+++ b/drivers/base/power/opp/of.c
@@ -17,6 +17,7 @@
#include <linux/errno.h>
#include <linux/device.h>
#include <linux/of.h>
+#include <linux/slab.h>
#include <linux/export.h>
#include "opp.h"
@@ -101,16 +102,16 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
return true;
}
-/* TODO: Support multiple regulators */
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table)
{
- u32 microvolt[3] = {0};
- u32 val;
- int count, ret;
+ u32 *microvolt, *microamp = NULL;
+ int supplies, vcount, icount, ret, i, j;
struct property *prop = NULL;
char name[NAME_MAX];
+ supplies = opp_table->regulator_count ? opp_table->regulator_count : 1;
+
/* Search for "opp-microvolt-<name>" */
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microvolt-%s",
@@ -128,34 +129,29 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
return 0;
}
- count = of_property_count_u32_elems(opp->np, name);
- if (count < 0) {
+ vcount = of_property_count_u32_elems(opp->np, name);
+ if (vcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n",
- __func__, name, count);
- return count;
+ __func__, name, vcount);
+ return vcount;
}
- /* There can be one or three elements here */
- if (count != 1 && count != 3) {
- dev_err(dev, "%s: Invalid number of elements in %s property (%d)\n",
- __func__, name, count);
+ /* There can be one or three elements per supply */
+ if (vcount != supplies && vcount != supplies * 3) {
+ dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
+ __func__, name, vcount, supplies);
return -EINVAL;
}
- ret = of_property_read_u32_array(opp->np, name, microvolt, count);
+ microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
+ if (!microvolt)
+ return -ENOMEM;
+
+ ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
- return -EINVAL;
- }
-
- opp->supply.u_volt = microvolt[0];
-
- if (count == 1) {
- opp->supply.u_volt_min = opp->supply.u_volt;
- opp->supply.u_volt_max = opp->supply.u_volt;
- } else {
- opp->supply.u_volt_min = microvolt[1];
- opp->supply.u_volt_max = microvolt[2];
+ ret = -EINVAL;
+ goto free_microvolt;
}
/* Search for "opp-microamp-<name>" */
@@ -172,10 +168,59 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
prop = of_find_property(opp->np, name, NULL);
}
- if (prop && !of_property_read_u32(opp->np, name, &val))
- opp->supply.u_amp = val;
+ if (prop) {
+ icount = of_property_count_u32_elems(opp->np, name);
+ if (icount < 0) {
+ dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
+ name, icount);
+ ret = icount;
+ goto free_microvolt;
+ }
- return 0;
+ if (icount != supplies) {
+ dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
+ __func__, name, icount, supplies);
+ ret = -EINVAL;
+ goto free_microvolt;
+ }
+
+ microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
+ if (!microamp) {
+ ret = -EINVAL;
+ goto free_microvolt;
+ }
+
+ ret = of_property_read_u32_array(opp->np, name, microamp,
+ icount);
+ if (ret) {
+ dev_err(dev, "%s: error parsing %s: %d\n", __func__,
+ name, ret);
+ ret = -EINVAL;
+ goto free_microamp;
+ }
+ }
+
+ for (i = 0, j = 0; i < supplies; i++) {
+ opp->supplies[i].u_volt = microvolt[j++];
+
+ if (vcount == supplies) {
+ opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
+ opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
+ } else {
+ opp->supplies[i].u_volt_min = microvolt[j++];
+ opp->supplies[i].u_volt_max = microvolt[j++];
+ }
+
+ if (microamp)
+ opp->supplies[i].u_amp = microamp[i];
+ }
+
+free_microamp:
+ kfree(microamp);
+free_microvolt:
+ kfree(microvolt);
+
+ return ret;
}
/**
@@ -304,8 +349,8 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np)
pr_debug("%s: turbo:%d rate:%lu uv:%lu uvmin:%lu uvmax:%lu latency:%lu\n",
__func__, new_opp->turbo, new_opp->rate,
- new_opp->supply.u_volt, new_opp->supply.u_volt_min,
- new_opp->supply.u_volt_max, new_opp->clock_latency_ns);
+ new_opp->supplies[0].u_volt, new_opp->supplies[0].u_volt_min,
+ new_opp->supplies[0].u_volt_max, new_opp->clock_latency_ns);
/*
* Notify the changes in the availability of the operable
diff --git a/drivers/base/power/opp/opp.h b/drivers/base/power/opp/opp.h
index 8a02516542c2..5b0f7e53bede 100644
--- a/drivers/base/power/opp/opp.h
+++ b/drivers/base/power/opp/opp.h
@@ -61,7 +61,7 @@ extern struct list_head opp_tables;
* @turbo: true if turbo (boost) OPP
* @suspend: true if suspend OPP
* @rate: Frequency in hertz
- * @supply: Power supply voltage/current values
+ * @supplies: Power supplies voltage/current values
* @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
* frequency from any other OPP's frequency.
* @opp_table: points back to the opp_table struct this opp belongs to
@@ -80,7 +80,7 @@ struct dev_pm_opp {
bool suspend;
unsigned long rate;
- struct dev_pm_opp_supply supply;
+ struct dev_pm_opp_supply *supplies;
unsigned long clock_latency_ns;
@@ -139,7 +139,8 @@ enum opp_table_access {
* @supported_hw_count: Number of elements in supported_hw array.
* @prop_name: A name to postfix to many DT properties, while parsing them.
* @clk: Device's clock handle
- * @regulator: Supply regulator
+ * @regulators: Supply regulators
+ * @regulator_count: Number of power supply regulators
* @dentry: debugfs dentry pointer of the real device directory (not links).
* @dentry_name: Name of the real dentry.
*
@@ -174,7 +175,8 @@ struct opp_table {
unsigned int supported_hw_count;
const char *prop_name;
struct clk *clk;
- struct regulator *regulator;
+ struct regulator **regulators;
+ unsigned int regulator_count;
#ifdef CONFIG_DEBUG_FS
struct dentry *dentry;
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index 4d3ec92cbabf..50669e0466c8 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -188,7 +188,10 @@ static int cpufreq_init(struct cpufreq_policy *policy)
*/
name = find_supply_name(cpu_dev);
if (name) {
- opp_table = dev_pm_opp_set_regulator(cpu_dev, name);
+ const char *names[] = {name};
+
+ opp_table = dev_pm_opp_set_regulators(cpu_dev, &name,
+ ARRAY_SIZE(names));
if (IS_ERR(opp_table)) {
ret = PTR_ERR(opp_table);
dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
@@ -289,7 +292,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
out_free_opp:
dev_pm_opp_of_cpumask_remove_table(policy->cpus);
if (name)
- dev_pm_opp_put_regulator(opp_table);
+ dev_pm_opp_put_regulators(opp_table);
out_put_clk:
clk_put(cpu_clk);
@@ -304,7 +307,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
if (priv->reg_name)
- dev_pm_opp_put_regulator(priv->opp_table);
+ dev_pm_opp_put_regulators(priv->opp_table);
clk_put(policy->clk);
kfree(priv);
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 824f7268f687..9a825ae78653 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -79,8 +79,8 @@ int dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
void dev_pm_opp_put_supported_hw(struct device *dev);
int dev_pm_opp_set_prop_name(struct device *dev, const char *name);
void dev_pm_opp_put_prop_name(struct device *dev);
-struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name);
-void dev_pm_opp_put_regulator(struct opp_table *opp_table);
+struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
+void dev_pm_opp_put_regulators(struct opp_table *opp_table);
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask);
int dev_pm_opp_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
@@ -187,12 +187,12 @@ static inline int dev_pm_opp_set_prop_name(struct device *dev, const char *name)
static inline void dev_pm_opp_put_prop_name(struct device *dev) {}
-static inline struct opp_table *dev_pm_opp_set_regulator(struct device *dev, const char *name)
+static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count)
{
return ERR_PTR(-ENOTSUPP);
}
-static inline void dev_pm_opp_put_regulator(struct opp_table *opp_table) {}
+static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
static inline int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq)
{
^ permalink raw reply related
* Re: [PATCH 2/2] Synopsys USB 2.0 Device Controller (UDC) Driver
From: John Youn @ 2016-12-01 0:54 UTC (permalink / raw)
To: Felipe Balbi, Raviteja Garimella
Cc: Rob Herring, Mark Rutland, Greg Kroah-Hartman, devicetree,
linux-kernel, BCM Kernel Feedback, linux-usb, John Youn
In-Reply-To: <87k2blm8yx.fsf@linux.intel.com>
On 11/30/2016 4:47 AM, Felipe Balbi wrote:
>
> Hi,
>
> Raviteja Garimella <raviteja.garimella@broadcom.com> writes:
>> Hi Balbi,
>>
>> On Wed, Nov 30, 2016 at 4:10 PM, Felipe Balbi <balbi@kernel.org> wrote:
>>>
>>> Hi,
>>>
>>> Raviteja Garimella <raviteja.garimella@broadcom.com> writes:
>>>> This is driver for Synopsys Designware Cores USB Device
>>>> Controller (UDC) Subsystem with the AMBA Advanced High-Performance
>>>> Bus (AHB). This driver works with Synopsys UDC20 products.
>>>>
>>>> Signed-off-by: Raviteja Garimella <raviteja.garimella@broadcom.com>
>>>
>>> use drivers/usb/dwc2 instead of duplicating it.
>>
>> The ones we have in drivers/usb/dwc2 is for Designware high speed OTG
>> controller IP. The one that I submitted for review is for USB Device
>> controller IP (UDC). The IPs are different.
>
> I'll wait for John's confirmation that this really isn't compatible with
> dwc2. John?
>
Hi Felipe,
This is our older UDC IP, not compatible with HSOTG.
It is also no longer supported by Synopsys and considered EOL.
Regards,
John
^ permalink raw reply
* [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Brian Norris @ 2016-12-01 1:21 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Caesar Wang, linux-rockchip, Rob Herring, linux-input, devicetree,
linux-kernel, Dmitry Torokhov, Mark Rutland, Doug Anderson,
Brian Norris
From: Caesar Wang <wxt@rock-chips.com>
Add a compatible string and regulator property for Wacom W9103
digitizer. Its VDD supply may need to be enabled before using it.
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: linux-input@vger.kernel.org
Signed-off-by: Brian Norris <briannorris@chromium.org>
---
v1 was a few months back. I finally got around to rewriting it based on
DT binding feedback.
v2:
* add compatible property for wacom
* name the regulator property specifically (VDD)
Documentation/devicetree/bindings/input/hid-over-i2c.txt | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
index 488edcb264c4..eb98054e60c9 100644
--- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
+++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
@@ -11,12 +11,16 @@ If this binding is used, the kernel module i2c-hid will handle the communication
with the device and the generic hid core layer will handle the protocol.
Required properties:
-- compatible: must be "hid-over-i2c"
+- compatible: must be "hid-over-i2c", or a device-specific string like:
+ * "wacom,w9013"
- reg: i2c slave address
- hid-descr-addr: HID descriptor address
- interrupt-parent: the phandle for the interrupt controller
- interrupts: interrupt line
+Optional properties:
+- vdd-supply: phandle of the regulator that provides the supply voltage.
+
Example:
i2c-hid-dev@2c {
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* [PATCH v2 2/2] HID: i2c-hid: support Wacom digitizer + regulator
From: Brian Norris @ 2016-12-01 1:21 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires
Cc: Caesar Wang, linux-rockchip, Rob Herring, linux-input, devicetree,
linux-kernel, Dmitry Torokhov, Mark Rutland, Doug Anderson,
Brian Norris
In-Reply-To: <1480555288-142791-1-git-send-email-briannorris@chromium.org>
We need to power on the digitizer before using it, and it's also nice to
save power in suspend by disabling it. Support an optional "vdd-supply"
and wire it up for the new Wacom device.
Wacom recommended waiting up to 100ms after powering on before trying to
access this device.
Signed-off-by: Brian Norris <briannorris@chromium.org>
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
Cc: Jiri Kosina <jikos@kernel.org>
Cc: linux-input@vger.kernel.org
---
v1 was a few months back. I finally got around to rewriting it based on
DT binding feedback.
v2:
* support compatible property for wacom, with specific "vdd-supply" name
* support the 100ms delay needed for this digitizer
* target regulator support only at specific device
Documentation/devicetree/bindings/input/hid-over-i2c.txt | 6 +++++-
drivers/hid/i2c-hid/i2c-hid.c | 70 ++++++++++++++++++++++++++++++++++++++++++-
include/linux/i2c/i2c-hid.h | 6 ++++
2 files changed, 75 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index b3ec4f2de875..1bc174f3a788 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -37,7 +37,9 @@
#include <linux/mutex.h>
#include <linux/acpi.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
#include <linux/i2c/i2c-hid.h>
@@ -918,10 +920,25 @@ static inline int i2c_hid_acpi_pdata(struct i2c_client *client,
#endif
#ifdef CONFIG_OF
+
+/* of_device_id match data */
+struct i2c_hid_of_data {
+ /* Name of supply regulator. */
+ const char *supply_name;
+ /* Delay required after powering on device before it is usable. */
+ int init_delay_ms;
+};
+
+static const struct i2c_hid_of_data wacom_w9013_data = {
+ .supply_name = "vdd",
+ .init_delay_ms = 100,
+};
+
static int i2c_hid_of_probe(struct i2c_client *client,
struct i2c_hid_platform_data *pdata)
{
struct device *dev = &client->dev;
+ const struct i2c_hid_of_data *data = of_device_get_match_data(dev);
u32 val;
int ret;
@@ -937,10 +954,33 @@ static int i2c_hid_of_probe(struct i2c_client *client,
}
pdata->hid_descriptor_address = val;
+ if (data) {
+ pdata->init_delay_ms = data->init_delay_ms;
+ if (data->supply_name) {
+ pdata->supply = devm_regulator_get_optional(&client->dev,
+ data->supply_name);
+ if (IS_ERR(pdata->supply)) {
+ ret = PTR_ERR(pdata->supply);
+ pdata->supply = NULL;
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ if (ret == -ENODEV)
+ return 0;
+ dev_err(dev, "Failed to get %s regulator: %d\n",
+ data->supply_name, ret);
+ return ret;
+ }
+ }
+ }
+
return 0;
}
static const struct of_device_id i2c_hid_of_match[] = {
+ {
+ .compatible = "wacom,w9013",
+ .data = &wacom_w9013_data,
+ },
{ .compatible = "hid-over-i2c" },
{},
};
@@ -983,6 +1023,17 @@ static int i2c_hid_probe(struct i2c_client *client,
ihid->pdata = *platform_data;
}
+ if (ihid->pdata.supply) {
+ ret = regulator_enable(ihid->pdata.supply);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to enable regulator: %d\n",
+ ret);
+ return ret;
+ }
+ if (ihid->pdata.init_delay_ms)
+ msleep(ihid->pdata.init_delay_ms);
+ }
+
if (client->irq > 0) {
ihid->irq = client->irq;
} else if (ACPI_COMPANION(&client->dev)) {
@@ -1100,6 +1151,9 @@ static int i2c_hid_remove(struct i2c_client *client)
if (ihid->desc)
gpiod_put(ihid->desc);
+ if (ihid->pdata.supply)
+ regulator_disable(ihid->pdata.supply);
+
kfree(ihid);
acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev));
@@ -1152,6 +1206,11 @@ static int i2c_hid_suspend(struct device *dev)
else
hid_warn(hid, "Failed to enable irq wake: %d\n",
wake_status);
+ } else if (ihid->pdata.supply) {
+ ret = regulator_disable(ihid->pdata.supply);
+ if (ret < 0)
+ hid_warn(hid, "Failed to disable supply: %d\n",
+ ret);
}
return 0;
@@ -1165,7 +1224,16 @@ static int i2c_hid_resume(struct device *dev)
struct hid_device *hid = ihid->hid;
int wake_status;
- if (device_may_wakeup(&client->dev) && ihid->irq_wake_enabled) {
+ if (!device_may_wakeup(&client->dev)) {
+ if (ihid->pdata.supply) {
+ ret = regulator_enable(ihid->pdata.supply);
+ if (ret < 0)
+ hid_warn(hid, "Failed to enable supply: %d\n",
+ ret);
+ if (ihid->pdata.init_delay_ms)
+ msleep(ihid->pdata.init_delay_ms);
+ }
+ } else if (ihid->irq_wake_enabled) {
wake_status = disable_irq_wake(ihid->irq);
if (!wake_status)
ihid->irq_wake_enabled = false;
diff --git a/include/linux/i2c/i2c-hid.h b/include/linux/i2c/i2c-hid.h
index 7aa901d92058..97688cde4a91 100644
--- a/include/linux/i2c/i2c-hid.h
+++ b/include/linux/i2c/i2c-hid.h
@@ -14,9 +14,13 @@
#include <linux/types.h>
+struct regulator;
+
/**
* struct i2chid_platform_data - used by hid over i2c implementation.
* @hid_descriptor_address: i2c register where the HID descriptor is stored.
+ * @supply: regulator for powering on the device.
+ * @init_delay_ms: delay after powering on before device is usable.
*
* Note that it is the responsibility of the platform driver (or the acpi 5.0
* driver, or the flattened device tree) to setup the irq related to the gpio in
@@ -31,6 +35,8 @@
*/
struct i2c_hid_platform_data {
u16 hid_descriptor_address;
+ struct regulator *supply;
+ int init_delay_ms;
};
#endif /* __LINUX_I2C_HID_H */
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related
* Re: [PATCH v6 1/5] mmc: dt-bindings: add ZTE ZX296718 MMC bindings
From: Jun Nie @ 2016-12-01 1:34 UTC (permalink / raw)
To: Shawn Guo, xie.baoyou, Rob Herring, mark.rutland
Cc: Ulf Hansson, Jaehoon Chung, Jason Liu, chen.chaokai, lai.binz,
linux-mmc, Jun Nie, devicetree
In-Reply-To: <CABymUCOvpQv7D2fi7EhWUZb_B8iwvQQ7-uW0gPrSdsFabMcPbA@mail.gmail.com>
2016-11-24 10:17 GMT+08:00 Jun Nie <jun.nie@linaro.org>:
> 2016-11-18 14:29 GMT+08:00 Jun Nie <jun.nie@linaro.org>:
>> Document the device-tree binding of ZTE MMC host on
>> ZX296718 SoC.
>>
>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>> ---
>> .../devicetree/bindings/mmc/zx-dw-mshc.txt | 35 ++++++++++++++++++++++
>> 1 file changed, 35 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>> new file mode 100644
>> index 0000000..c175c4b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>> @@ -0,0 +1,35 @@
>> +* ZTE specific extensions to the Synopsys Designware Mobile Storage
>> + Host Controller
>> +
>> +The Synopsys designware mobile storage host controller is used to interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
>> +differences between the core Synopsys dw mshc controller properties described
>> +by synopsys-dw-mshc.txt and the properties used by the ZTE specific
>> +extensions to the Synopsys Designware Mobile Storage Host Controller.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be
>> + - "zte,zx296718-dw-mshc": for ZX SoCs
>> +
>> +Example:
>> +
>> + mmc1: mmc@1110000 {
>> + compatible = "zte,zx296718-dw-mshc";
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + reg = <0x01110000 0x1000>;
>> + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
>> + fifo-depth = <32>;
>> + data-addr = <0x200>;
>> + fifo-watermark-aligned;
>> + bus-width = <4>;
>> + clock-frequency = <50000000>;
>> + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
>> + clock-names = "biu", "ciu";
>> + num-slots = <1>;
>> + max-frequency = <50000000>;
>> + cap-sdio-irq;
>> + cap-sd-highspeed;
>> + status = "disabled";
>> + };
>> --
>> 1.9.1
>>
>
> Hi Rob & Mark,
>
> Could you help review and act this patch if you think it is OK? Thank you!
>
> Jun
Hi Rob & Mark,
Could you help comment or act on this patch? Thank you!
Jun
^ permalink raw reply
* Re: [PATCH v6 3/5] Documentation: synopsys-dw-mshc: add binding for fifo quirks
From: Jun Nie @ 2016-12-01 1:35 UTC (permalink / raw)
To: Shawn Guo, xie.baoyou, Rob Herring, mark.rutland-5wv7dgnIgG8
Cc: Ulf Hansson, Jaehoon Chung, Jason Liu,
chen.chaokai-Th6q7B73Y6EnDS1+zs4M5A,
lai.binz-Th6q7B73Y6EnDS1+zs4M5A, linux-mmc, Jun Nie,
devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CABymUCN_+kJC2NZaPuqOg1C_Q2ASmiGwbwWCtfiLjGwSqPjgkQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-11-24 10:19 GMT+08:00 Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
> 2016-11-18 14:29 GMT+08:00 Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>:
>> Add fifo-addr property and fifo-watermark-quirk property to
>> synopsys-dw-mshc bindings. It is intended to provide more
>> dt interface to support SoCs specific configuration.
>>
>> Signed-off-by: Jun Nie <jun.nie-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> ---
>> Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt | 13 +++++++++++++
>> 1 file changed, 13 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
>> index 4e00e85..8bf2e41 100644
>> --- a/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
>> @@ -76,6 +76,17 @@ Optional properties:
>>
>> * broken-cd: as documented in mmc core bindings.
>>
>> +* data-addr: Override fifo address with value provided by DT. The default FIFO reg
>> + offset is assumed as 0x100 (version < 0x240A) and 0x200(version >= 0x240A) by
>> + driver. If the controller does not follow this rule, please use this property
>> + to set fifo address in device tree.
>> +
>> +* fifo-watermark-aligned: Data done irq is expected if data length is less than
>> + watermark in PIO mode. But fifo watermark is requested to be aligned with data
>> + length in some SoC so that TX/RX irq can be generated with data done irq. Add this
>> + watermark quirk to mark this requirement and force fifo watermark setting
>> + accordingly.
>> +
>> * vmmc-supply: The phandle to the regulator to use for vmmc. If this is
>> specified we'll defer probe until we can find this regulator.
>>
>> @@ -103,6 +114,8 @@ board specific portions as listed below.
>> interrupts = <0 75 0>;
>> #address-cells = <1>;
>> #size-cells = <0>;
>> + data-addr = <0x200>;
>> + fifo-watermark-aligned;
>> };
>>
>> [board specific internal DMA resources]
>> --
>> 1.9.1
>>
> Hi Rob & Mark,
>
> Could you help review and act this patch if you think it is OK? Thank you!
>
> Jun
Hi Rob & Mark,
Could you help comment or act on this patch in revsion 6? Thank you!
Jun
--
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: [alsa-devel] [PATCH v2] clkdev: add devm_of_clk_get()
From: Kuninori Morimoto @ 2016-12-01 1:43 UTC (permalink / raw)
To: Stephen Boyd
Cc: Rob Herring, Linux-ALSA, Linux-DT, Michael Turquette,
Russell King, Linux-Kernel, Mark Brown,
linux-clk-u79uwXL29TY76Z2rM5mHXA, Linux-ARM
In-Reply-To: <874m2pbwsn.wl%kuninori.morimoto.gx-zM6kxYcvzFBBDgjK7y7TUQ@public.gmane.org>
Hi Stephen, again
Can I confirm ??
Was I misunderstanding ??
> I understand your point, but I think devm_get_clk_from_child()
> needs new DT setings, and it can't keep compatibility, or
> it makes driver complex.
> I think it is nice to have. but, I want to keep current style.
> Thus, I will try to use current of_clk_get() as-is, and
> call clk_free() somehow in this driver.
------ Pattern1 -----------
sound_soc {
clocks = <&xxx>, <&xxx>;
clock-names = "cpu", "codec";
...
cpu { /* of_cpu_node */
...
};
codec { /* of_codec_node */
...
};
};
----------------------------
Do you mean, this case we can use
devm_get_clk_from_child(dev, of_cpu_node, "cpu");
devm_get_clk_from_child(dev, of_codec_node, "codec");
------ Pattern2 -----------
sound_soc {
...
cpu { /* of_cpu_node */
clocks = <&xxx>;
...
};
codec { /* of_codec_node */
clocks = <&xxx>;
...
};
};
----------------------------
And, this case, we can use
devm_get_clk_from_child(dev, of_cpu_node, NULL);
devm_get_clk_from_child(dev, of_codec_node, NULL);
If so, I can use it without DT change.
--
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 v8] mtd: nand: add tango NAND flash controller support
From: Brian Norris @ 2016-12-01 1:44 UTC (permalink / raw)
To: Marc Gonzalez
Cc: linux-mtd, Boris Brezillon, Richard Weinberger, Mark Rutland, DT,
Rob Herring, Sebastian Frias, Mason
In-Reply-To: <580F8407.5070706-y1yR0Z3OICC7zZZRDBGcUA@public.gmane.org>
Hi,
On Tue, Oct 25, 2016 at 06:10:47PM +0200, Marc Gonzalez wrote:
> This driver supports the NAND Flash controller embedded in recent
> Tango chips, such as SMP8758 and SMP8759.
>
> Signed-off-by: Marc Gonzalez <marc_gonzalez-y1yR0Z3OICC7zZZRDBGcUA@public.gmane.org>
> ---
...
> diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c
> new file mode 100644
> index 000000000000..74e39a92771c
> --- /dev/null
> +++ b/drivers/mtd/nand/tango_nand.c
> @@ -0,0 +1,654 @@
This driver is being introduced with no copyright or license header. At
least it has an appropriate MODULE_LICENSE().
Can the original author(s) please provide a follow-up patch with one?
Thanks.
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/clk.h>
> +#include <linux/iopoll.h>
> +#include <linux/module.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/platform_device.h>
...
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Sigma Designs");
> +MODULE_DESCRIPTION("Tango4 NAND Flash controller driver");
Brian
--
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
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