* [PATCH v3 0/2] Add a new Rockchip usb2 phy driver @ 2016-06-06 9:20 Frank Wang 2016-06-06 9:20 ` [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY Frank Wang 2016-06-06 9:20 ` [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy Frank Wang 0 siblings, 2 replies; 14+ messages in thread From: Frank Wang @ 2016-06-06 9:20 UTC (permalink / raw) To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu, frank.wang The newer SoCs (rk3366, rk3399) of Rock-chip take a different usb-phy IP block than rk3288 and before, and most of phy-related registers are also different from the past, so a new phy driver is required necessarily. These series patches add phy-rockchip-inno-usb2.c and the corresponding documentation. Changes in v3: - Supplemented some hardware-description into the devicetree bindings. - Resolved the mapping defect between fixed value in driver and the property in devicetree. - Code cleanup. Changes in v2: - Specified more hardware-description into the devicetree bindings. - Optimized some process of driver. Frank Wang (2): Documentation: bindings: add DT documentation for Rockchip USB2PHY phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 ++ drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-rockchip-inno-usb2.c | 630 ++++++++++++++++++++ 4 files changed, 698 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c -- 1.7.9.5 ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-06 9:20 [PATCH v3 0/2] Add a new Rockchip usb2 phy driver Frank Wang @ 2016-06-06 9:20 ` Frank Wang 2016-06-06 11:27 ` Mark Rutland 2016-06-06 9:20 ` [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy Frank Wang 1 sibling, 1 reply; 14+ messages in thread From: Frank Wang @ 2016-06-06 9:20 UTC (permalink / raw) To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu, frank.wang Signed-off-by: Frank Wang <frank.wang@rock-chips.com> --- Changes in v3: - Added 'clocks' and 'clock-names' optional properties. - Specified 'otg-port' and 'host-port' as the sub-node name. Changes in v2: - Changed vbus_host optional property from gpio to regulator. - Specified vbus_otg-supply optional property. - Specified otg_id and otg_bvalid property. .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 ++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new file mode 100644 index 0000000..0b4bbbb --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt @@ -0,0 +1,60 @@ +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK + +Required properties (phy (parent) node): + - compatible : should be one of the listed compatibles: + * "rockchip,rk3366-usb2phy" + * "rockchip,rk3399-usb2phy" + - #clock-cells : should be 0. + - clock-output-names : specify the 480m output clock name. + +Optional properties: + - clocks : phandle + phy specifier pair, for the input clock of phy. + - clock-names : input clock name of phy, must be "phyclk". + - vbus_host-supply : phandle to a regulator that supplies host vbus. + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. + +Required nodes : a sub-node is required for each port the phy provides. + The sub-node name is used to identify host or otg port, + and shall be the following entries: + * "otg-port" : the name of otg port. + * "host-port" : the name of host port. + +Required properties (port (child) node): + - #phy-cells : must be 0. See ./phy-bindings.txt for details. + - interrupts : specify an interrupt for each entry in interrupt-names. + - interrupt-names : a list which shall be the following entries: + * "otg_id" : for the otg id interrupt. + * "otg_bvalid" : for the otg vbus interrupt. + * "linestate" : for the host/otg linestate interrupt. + +Example: + +grf: syscon@ff770000 { + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; + #address-cells = <1>; + #size-cells = <1>; + +... + + u2phy: usb2-phy { + compatible = "rockchip,rk3366-usb2phy"; + #clock-cells = <0>; + clock-output-names = "sclk_otgphy0_480m"; + + u2phy_otg: otg-port { + #phy-cells = <0>; + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "otg_id", "otg_bvalid", "linestate"; + status = "okay"; + }; + + u2phy_host: host-port { + #phy-cells = <0>; + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; + interrupt-names = "linestate"; + status = "okay"; + }; + }; +}; -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-06 9:20 ` [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY Frank Wang @ 2016-06-06 11:27 ` Mark Rutland 2016-06-06 12:33 ` Heiko Stübner 0 siblings, 1 reply; 14+ messages in thread From: Mark Rutland @ 2016-06-06 11:27 UTC (permalink / raw) To: Frank Wang Cc: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: > Signed-off-by: Frank Wang <frank.wang@rock-chips.com> > --- > > Changes in v3: > - Added 'clocks' and 'clock-names' optional properties. > - Specified 'otg-port' and 'host-port' as the sub-node name. > > Changes in v2: > - Changed vbus_host optional property from gpio to regulator. > - Specified vbus_otg-supply optional property. > - Specified otg_id and otg_bvalid property. > > .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 ++++++++++++++++++++ > 1 file changed, 60 insertions(+) > create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > > diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > new file mode 100644 > index 0000000..0b4bbbb > --- /dev/null > +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > @@ -0,0 +1,60 @@ > +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK > + > +Required properties (phy (parent) node): > + - compatible : should be one of the listed compatibles: > + * "rockchip,rk3366-usb2phy" > + * "rockchip,rk3399-usb2phy" > + - #clock-cells : should be 0. > + - clock-output-names : specify the 480m output clock name. > + > +Optional properties: > + - clocks : phandle + phy specifier pair, for the input clock of phy. > + - clock-names : input clock name of phy, must be "phyclk". > + - vbus_host-supply : phandle to a regulator that supplies host vbus. > + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. Nit: s/_/-/ here. Otherwise the rest of this looks generally fine, though I'm confused as to how you address the programming interface(s), given none are described. Thanks, Mark. > + > +Required nodes : a sub-node is required for each port the phy provides. > + The sub-node name is used to identify host or otg port, > + and shall be the following entries: > + * "otg-port" : the name of otg port. > + * "host-port" : the name of host port. > + > +Required properties (port (child) node): > + - #phy-cells : must be 0. See ./phy-bindings.txt for details. > + - interrupts : specify an interrupt for each entry in interrupt-names. > + - interrupt-names : a list which shall be the following entries: > + * "otg_id" : for the otg id interrupt. > + * "otg_bvalid" : for the otg vbus interrupt. > + * "linestate" : for the host/otg linestate interrupt. > + > +Example: > + > +grf: syscon@ff770000 { > + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; > + #address-cells = <1>; > + #size-cells = <1>; > + > +... > + > + u2phy: usb2-phy { > + compatible = "rockchip,rk3366-usb2phy"; > + #clock-cells = <0>; > + clock-output-names = "sclk_otgphy0_480m"; > + > + u2phy_otg: otg-port { > + #phy-cells = <0>; > + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, > + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; > + interrupt-names = "otg_id", "otg_bvalid", "linestate"; > + status = "okay"; > + }; > + > + u2phy_host: host-port { > + #phy-cells = <0>; > + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; > + interrupt-names = "linestate"; > + status = "okay"; > + }; > + }; > +}; > -- > 1.7.9.5 > > ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-06 11:27 ` Mark Rutland @ 2016-06-06 12:33 ` Heiko Stübner 2016-06-07 2:59 ` Frank Wang 0 siblings, 1 reply; 14+ messages in thread From: Heiko Stübner @ 2016-06-06 12:33 UTC (permalink / raw) To: Mark Rutland Cc: Frank Wang, dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu Am Montag, 6. Juni 2016, 12:27:54 schrieb Mark Rutland: > On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: > > Signed-off-by: Frank Wang <frank.wang@rock-chips.com> > > --- > > > > Changes in v3: > > - Added 'clocks' and 'clock-names' optional properties. > > - Specified 'otg-port' and 'host-port' as the sub-node name. > > > > Changes in v2: > > - Changed vbus_host optional property from gpio to regulator. > > - Specified vbus_otg-supply optional property. > > - Specified otg_id and otg_bvalid property. > > > > .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 > > ++++++++++++++++++++ 1 file changed, 60 insertions(+) > > create mode 100644 > > Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt> > > diff --git > > a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > > b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new > > file mode 100644 > > index 0000000..0b4bbbb > > --- /dev/null > > +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > > @@ -0,0 +1,60 @@ > > +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK > > + > > +Required properties (phy (parent) node): > > + - compatible : should be one of the listed compatibles: > > + * "rockchip,rk3366-usb2phy" > > + * "rockchip,rk3399-usb2phy" > > + - #clock-cells : should be 0. > > + - clock-output-names : specify the 480m output clock name. > > + > > +Optional properties: > > + - clocks : phandle + phy specifier pair, for the input clock of phy. > > + - clock-names : input clock name of phy, must be "phyclk". > > + - vbus_host-supply : phandle to a regulator that supplies host vbus. > > + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. > > Nit: s/_/-/ here. Something I only stumbled over yesterday for the first time on my rk3288- popmetal: The phy subnodes seem to be able to use a generic phy-supply property from inside the phy-core itself, see: https://github.com/mmind/linux-rockchip/commit/93739f521fc65f44524b00c9aaf6db46bca94e02#diff-ddf3e45ebb753d6debf57022003a1a57R597 for my WIP code for that other board. > Otherwise the rest of this looks generally fine, though I'm confused as > to how you address the programming interface(s), given none are > described. I think that comes generally down to phy_power_on and phy_power_off from the host driver (ehci / dwc2 / whatever) using the generic phy interface. The usb2 phys on Rockchip SoCs seem always pretty easy to handle, while the new additional typeC phy seems to require more work Heiko > > + > > +Required nodes : a sub-node is required for each port the phy provides. > > + The sub-node name is used to identify host or otg port, > > + and shall be the following entries: > > + * "otg-port" : the name of otg port. > > + * "host-port" : the name of host port. > > + > > +Required properties (port (child) node): > > + - #phy-cells : must be 0. See ./phy-bindings.txt for details. > > + - interrupts : specify an interrupt for each entry in interrupt-names. > > + - interrupt-names : a list which shall be the following entries: > > + * "otg_id" : for the otg id interrupt. > > + * "otg_bvalid" : for the otg vbus interrupt. > > + * "linestate" : for the host/otg linestate interrupt. > > + > > +Example: > > + > > +grf: syscon@ff770000 { > > + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; > > + #address-cells = <1>; > > + #size-cells = <1>; > > + > > +... > > + > > + u2phy: usb2-phy { > > + compatible = "rockchip,rk3366-usb2phy"; > > + #clock-cells = <0>; > > + clock-output-names = "sclk_otgphy0_480m"; > > + > > + u2phy_otg: otg-port { > > + #phy-cells = <0>; > > + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, > > + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, > > + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; > > + interrupt-names = "otg_id", "otg_bvalid", "linestate"; > > + status = "okay"; > > + }; > > + > > + u2phy_host: host-port { > > + #phy-cells = <0>; > > + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; > > + interrupt-names = "linestate"; > > + status = "okay"; > > + }; > > + }; > > +}; ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-06 12:33 ` Heiko Stübner @ 2016-06-07 2:59 ` Frank Wang 2016-06-07 3:31 ` Frank Wang 0 siblings, 1 reply; 14+ messages in thread From: Frank Wang @ 2016-06-07 2:59 UTC (permalink / raw) To: Heiko Stübner, Mark Rutland Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu, frank.wang Hi Heiko & Mark, On 2016/6/6 20:33, Heiko Stübner wrote: > Am Montag, 6. Juni 2016, 12:27:54 schrieb Mark Rutland: >> On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: >>> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> >>> --- >>> >>> Changes in v3: >>> - Added 'clocks' and 'clock-names' optional properties. >>> - Specified 'otg-port' and 'host-port' as the sub-node name. >>> >>> Changes in v2: >>> - Changed vbus_host optional property from gpio to regulator. >>> - Specified vbus_otg-supply optional property. >>> - Specified otg_id and otg_bvalid property. >>> >>> .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 >>> ++++++++++++++++++++ 1 file changed, 60 insertions(+) >>> create mode 100644 >>> Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt> >>> diff --git >>> a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>> b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new >>> file mode 100644 >>> index 0000000..0b4bbbb >>> --- /dev/null >>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>> @@ -0,0 +1,60 @@ >>> +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK >>> + >>> +Required properties (phy (parent) node): >>> + - compatible : should be one of the listed compatibles: >>> + * "rockchip,rk3366-usb2phy" >>> + * "rockchip,rk3399-usb2phy" >>> + - #clock-cells : should be 0. >>> + - clock-output-names : specify the 480m output clock name. >>> + >>> +Optional properties: >>> + - clocks : phandle + phy specifier pair, for the input clock of phy. >>> + - clock-names : input clock name of phy, must be "phyclk". >>> + - vbus_host-supply : phandle to a regulator that supplies host vbus. >>> + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. >> Nit: s/_/-/ here. > Something I only stumbled over yesterday for the first time on my rk3288- > popmetal: The phy subnodes seem to be able to use a generic phy-supply > property from inside the phy-core itself, see: > > https://github.com/mmind/linux-rockchip/commit/93739f521fc65f44524b00c9aaf6db46bca94e02#diff-ddf3e45ebb753d6debf57022003a1a57R597 > > for my WIP code for that other board. > Ah, good comments! I will try later, if it is practicable, I shall correct it into the next patches (patch v4). >> Otherwise the rest of this looks generally fine, though I'm confused as >> to how you address the programming interface(s), given none are >> described. > I think that comes generally down to phy_power_on and phy_power_off from the > host driver (ehci / dwc2 / whatever) using the generic phy interface. The usb2 > phys on Rockchip SoCs seem always pretty easy to handle, while the new > additional typeC phy seems to require more work > Yeah, just like that. > > >>> + >>> +Required nodes : a sub-node is required for each port the phy provides. >>> + The sub-node name is used to identify host or otg port, >>> + and shall be the following entries: >>> + * "otg-port" : the name of otg port. >>> + * "host-port" : the name of host port. >>> + >>> +Required properties (port (child) node): >>> + - #phy-cells : must be 0. See ./phy-bindings.txt for details. >>> + - interrupts : specify an interrupt for each entry in interrupt-names. >>> + - interrupt-names : a list which shall be the following entries: >>> + * "otg_id" : for the otg id interrupt. >>> + * "otg_bvalid" : for the otg vbus interrupt. >>> + * "linestate" : for the host/otg linestate interrupt. >>> + >>> +Example: >>> + >>> +grf: syscon@ff770000 { >>> + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; >>> + #address-cells = <1>; >>> + #size-cells = <1>; >>> + >>> +... >>> + >>> + u2phy: usb2-phy { >>> + compatible = "rockchip,rk3366-usb2phy"; >>> + #clock-cells = <0>; >>> + clock-output-names = "sclk_otgphy0_480m"; >>> + >>> + u2phy_otg: otg-port { >>> + #phy-cells = <0>; >>> + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, >>> + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, >>> + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; >>> + interrupt-names = "otg_id", "otg_bvalid", "linestate"; >>> + status = "okay"; >>> + }; >>> + >>> + u2phy_host: host-port { >>> + #phy-cells = <0>; >>> + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; >>> + interrupt-names = "linestate"; >>> + status = "okay"; >>> + }; >>> + }; >>> +}; ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-07 2:59 ` Frank Wang @ 2016-06-07 3:31 ` Frank Wang 2016-06-07 7:45 ` Kishon Vijay Abraham I 2016-06-07 7:59 ` Heiko Stübner 0 siblings, 2 replies; 14+ messages in thread From: Frank Wang @ 2016-06-07 3:31 UTC (permalink / raw) To: Heiko Stübner, Mark Rutland Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu, frank.wang Hi Heiko, On 2016/6/7 10:59, Frank Wang wrote: > Hi Heiko & Mark, > > On 2016/6/6 20:33, Heiko Stübner wrote: >> Am Montag, 6. Juni 2016, 12:27:54 schrieb Mark Rutland: >>> On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: >>>> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> >>>> --- >>>> >>>> Changes in v3: >>>> - Added 'clocks' and 'clock-names' optional properties. >>>> - Specified 'otg-port' and 'host-port' as the sub-node name. >>>> >>>> Changes in v2: >>>> - Changed vbus_host optional property from gpio to regulator. >>>> - Specified vbus_otg-supply optional property. >>>> - Specified otg_id and otg_bvalid property. >>>> .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 >>>> ++++++++++++++++++++ 1 file changed, 60 insertions(+) >>>> create mode 100644 >>>> Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt> >>>> diff --git >>>> a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>>> b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new >>>> file mode 100644 >>>> index 0000000..0b4bbbb >>>> --- /dev/null >>>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>>> @@ -0,0 +1,60 @@ >>>> +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK >>>> + >>>> +Required properties (phy (parent) node): >>>> + - compatible : should be one of the listed compatibles: >>>> + * "rockchip,rk3366-usb2phy" >>>> + * "rockchip,rk3399-usb2phy" >>>> + - #clock-cells : should be 0. >>>> + - clock-output-names : specify the 480m output clock name. >>>> + >>>> +Optional properties: >>>> + - clocks : phandle + phy specifier pair, for the input clock of phy. >>>> + - clock-names : input clock name of phy, must be "phyclk". >>>> + - vbus_host-supply : phandle to a regulator that supplies host vbus. >>>> + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. >>> Nit: s/_/-/ here. >> Something I only stumbled over yesterday for the first time on my >> rk3288- >> popmetal: The phy subnodes seem to be able to use a generic phy-supply >> property from inside the phy-core itself, see: >> >> https://github.com/mmind/linux-rockchip/commit/93739f521fc65f44524b00c9aaf6db46bca94e02#diff-ddf3e45ebb753d6debf57022003a1a57R597 >> >> >> for my WIP code for that other board. >> > > Ah, good comments! I will try later, if it is practicable, I shall > correct it into the next patches (patch v4). > I am sorry to tell you that seems unworkable, because we have two sub-nodes (phy-ports) in one parent-node (phy), what is more, the 'phy-supply' property can only put into parent-node, I believe it can not be differentiated types of ports. I mean vbus for host and otg are separately. >>> Otherwise the rest of this looks generally fine, though I'm confused as >>> to how you address the programming interface(s), given none are >>> described. >> I think that comes generally down to phy_power_on and phy_power_off >> from the >> host driver (ehci / dwc2 / whatever) using the generic phy interface. >> The usb2 >> phys on Rockchip SoCs seem always pretty easy to handle, while the new >> additional typeC phy seems to require more work >> > > Yeah, just like that. > >> >> >>>> + >>>> +Required nodes : a sub-node is required for each port the phy >>>> provides. >>>> + The sub-node name is used to identify host or otg port, >>>> + and shall be the following entries: >>>> + * "otg-port" : the name of otg port. >>>> + * "host-port" : the name of host port. >>>> + >>>> +Required properties (port (child) node): >>>> + - #phy-cells : must be 0. See ./phy-bindings.txt for details. >>>> + - interrupts : specify an interrupt for each entry in >>>> interrupt-names. >>>> + - interrupt-names : a list which shall be the following entries: >>>> + * "otg_id" : for the otg id interrupt. >>>> + * "otg_bvalid" : for the otg vbus interrupt. >>>> + * "linestate" : for the host/otg linestate interrupt. >>>> + >>>> +Example: >>>> + >>>> +grf: syscon@ff770000 { >>>> + compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; >>>> + #address-cells = <1>; >>>> + #size-cells = <1>; >>>> + >>>> +... >>>> + >>>> + u2phy: usb2-phy { >>>> + compatible = "rockchip,rk3366-usb2phy"; >>>> + #clock-cells = <0>; >>>> + clock-output-names = "sclk_otgphy0_480m"; >>>> + >>>> + u2phy_otg: otg-port { >>>> + #phy-cells = <0>; >>>> + interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>, >>>> + <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>, >>>> + <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>; >>>> + interrupt-names = "otg_id", "otg_bvalid", "linestate"; >>>> + status = "okay"; >>>> + }; >>>> + >>>> + u2phy_host: host-port { >>>> + #phy-cells = <0>; >>>> + interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>; >>>> + interrupt-names = "linestate"; >>>> + status = "okay"; >>>> + }; >>>> + }; >>>> +}; ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-07 3:31 ` Frank Wang @ 2016-06-07 7:45 ` Kishon Vijay Abraham I 2016-06-07 8:23 ` Frank Wang 2016-06-07 7:59 ` Heiko Stübner 1 sibling, 1 reply; 14+ messages in thread From: Kishon Vijay Abraham I @ 2016-06-07 7:45 UTC (permalink / raw) To: Frank Wang, Heiko Stübner, Mark Rutland Cc: dianders, linux, groeck, jwerner, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu Hi, On Tuesday 07 June 2016 09:01 AM, Frank Wang wrote: > Hi Heiko, > > On 2016/6/7 10:59, Frank Wang wrote: >> Hi Heiko & Mark, >> >> On 2016/6/6 20:33, Heiko Stübner wrote: >>> Am Montag, 6. Juni 2016, 12:27:54 schrieb Mark Rutland: >>>> On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: >>>>> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> >>>>> --- >>>>> >>>>> Changes in v3: >>>>> - Added 'clocks' and 'clock-names' optional properties. >>>>> - Specified 'otg-port' and 'host-port' as the sub-node name. >>>>> >>>>> Changes in v2: >>>>> - Changed vbus_host optional property from gpio to regulator. >>>>> - Specified vbus_otg-supply optional property. >>>>> - Specified otg_id and otg_bvalid property. >>>>> .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 >>>>> ++++++++++++++++++++ 1 file changed, 60 insertions(+) >>>>> create mode 100644 >>>>> Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt> >>>>> diff --git >>>>> a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>>>> b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new >>>>> file mode 100644 >>>>> index 0000000..0b4bbbb >>>>> --- /dev/null >>>>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>>>> @@ -0,0 +1,60 @@ >>>>> +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK >>>>> + >>>>> +Required properties (phy (parent) node): >>>>> + - compatible : should be one of the listed compatibles: >>>>> + * "rockchip,rk3366-usb2phy" >>>>> + * "rockchip,rk3399-usb2phy" >>>>> + - #clock-cells : should be 0. >>>>> + - clock-output-names : specify the 480m output clock name. >>>>> + >>>>> +Optional properties: >>>>> + - clocks : phandle + phy specifier pair, for the input clock of phy. >>>>> + - clock-names : input clock name of phy, must be "phyclk". >>>>> + - vbus_host-supply : phandle to a regulator that supplies host vbus. >>>>> + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. >>>> Nit: s/_/-/ here. >>> Something I only stumbled over yesterday for the first time on my rk3288- >>> popmetal: The phy subnodes seem to be able to use a generic phy-supply >>> property from inside the phy-core itself, see: >>> >>> https://github.com/mmind/linux-rockchip/commit/93739f521fc65f44524b00c9aaf6db46bca94e02#diff-ddf3e45ebb753d6debf57022003a1a57R597 >>> >>> >>> for my WIP code for that other board. >>> >> >> Ah, good comments! I will try later, if it is practicable, I shall correct it >> into the next patches (patch v4). >> > > I am sorry to tell you that seems unworkable, because we have two sub-nodes > (phy-ports) in one parent-node (phy), > what is more, the 'phy-supply' property can only put into parent-node, I > believe it can not be differentiated types of ports. 'phy-supply' is a property of the phy node and not the 'phy-provider' node. So IMO this should work. What problem do you see? Thanks Kishon ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-07 7:45 ` Kishon Vijay Abraham I @ 2016-06-07 8:23 ` Frank Wang 0 siblings, 0 replies; 14+ messages in thread From: Frank Wang @ 2016-06-07 8:23 UTC (permalink / raw) To: Kishon Vijay Abraham I, Heiko Stübner, Mark Rutland Cc: dianders, linux, groeck, jwerner, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu, frank.wang Hi Kishon & Heiko, On 2016/6/7 15:45, Kishon Vijay Abraham I wrote: > Hi, > > On Tuesday 07 June 2016 09:01 AM, Frank Wang wrote: >> Hi Heiko, >> >> On 2016/6/7 10:59, Frank Wang wrote: >>> Hi Heiko & Mark, >>> >>> On 2016/6/6 20:33, Heiko Stübner wrote: >>>> Am Montag, 6. Juni 2016, 12:27:54 schrieb Mark Rutland: >>>>> On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: >>>>>> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> >>>>>> --- >>>>>> >>>>>> Changes in v3: >>>>>> - Added 'clocks' and 'clock-names' optional properties. >>>>>> - Specified 'otg-port' and 'host-port' as the sub-node name. >>>>>> >>>>>> Changes in v2: >>>>>> - Changed vbus_host optional property from gpio to regulator. >>>>>> - Specified vbus_otg-supply optional property. >>>>>> - Specified otg_id and otg_bvalid property. >>>>>> .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 >>>>>> ++++++++++++++++++++ 1 file changed, 60 insertions(+) >>>>>> create mode 100644 >>>>>> Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt> >>>>>> diff --git >>>>>> a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>>>>> b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new >>>>>> file mode 100644 >>>>>> index 0000000..0b4bbbb >>>>>> --- /dev/null >>>>>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt >>>>>> @@ -0,0 +1,60 @@ >>>>>> +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK >>>>>> + >>>>>> +Required properties (phy (parent) node): >>>>>> + - compatible : should be one of the listed compatibles: >>>>>> + * "rockchip,rk3366-usb2phy" >>>>>> + * "rockchip,rk3399-usb2phy" >>>>>> + - #clock-cells : should be 0. >>>>>> + - clock-output-names : specify the 480m output clock name. >>>>>> + >>>>>> +Optional properties: >>>>>> + - clocks : phandle + phy specifier pair, for the input clock of phy. >>>>>> + - clock-names : input clock name of phy, must be "phyclk". >>>>>> + - vbus_host-supply : phandle to a regulator that supplies host vbus. >>>>>> + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. >>>>> Nit: s/_/-/ here. >>>> Something I only stumbled over yesterday for the first time on my rk3288- >>>> popmetal: The phy subnodes seem to be able to use a generic phy-supply >>>> property from inside the phy-core itself, see: >>>> >>>> https://github.com/mmind/linux-rockchip/commit/93739f521fc65f44524b00c9aaf6db46bca94e02#diff-ddf3e45ebb753d6debf57022003a1a57R597 >>>> >>>> >>>> for my WIP code for that other board. >>>> >>> Ah, good comments! I will try later, if it is practicable, I shall correct it >>> into the next patches (patch v4). >>> >> I am sorry to tell you that seems unworkable, because we have two sub-nodes >> (phy-ports) in one parent-node (phy), >> what is more, the 'phy-supply' property can only put into parent-node, I >> believe it can not be differentiated types of ports. > 'phy-supply' is a property of the phy node and not the 'phy-provider' node. So > IMO this should work. What problem do you see? Sorry, I think I must have made a wrong phandle of phy-port name in *.dts before. Yes, It works now, thanks for your reminding. @Heiko, I have just received your another mail, thanks again for your detail explanation. I will correct it in the next patches (patch v4). BR. Frank ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY 2016-06-07 3:31 ` Frank Wang 2016-06-07 7:45 ` Kishon Vijay Abraham I @ 2016-06-07 7:59 ` Heiko Stübner 1 sibling, 0 replies; 14+ messages in thread From: Heiko Stübner @ 2016-06-07 7:59 UTC (permalink / raw) To: Frank Wang Cc: Mark Rutland, dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu Hi Frank, Am Dienstag, 7. Juni 2016, 11:31:59 schrieb Frank Wang: > On 2016/6/7 10:59, Frank Wang wrote: > > On 2016/6/6 20:33, Heiko Stübner wrote: > >> Am Montag, 6. Juni 2016, 12:27:54 schrieb Mark Rutland: > >>> On Mon, Jun 06, 2016 at 05:20:03PM +0800, Frank Wang wrote: > >>>> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> > >>>> --- > >>>> > >>>> Changes in v3: > >>>> - Added 'clocks' and 'clock-names' optional properties. > >>>> - Specified 'otg-port' and 'host-port' as the sub-node name. > >>>> > >>>> Changes in v2: > >>>> - Changed vbus_host optional property from gpio to regulator. > >>>> - Specified vbus_otg-supply optional property. > >>>> - Specified otg_id and otg_bvalid property. > >>>> > >>>> .../bindings/phy/phy-rockchip-inno-usb2.txt | 60 > >>>> > >>>> ++++++++++++++++++++ 1 file changed, 60 insertions(+) > >>>> create mode 100644 > >>>> > >>>> Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt> > >>>> diff --git > >>>> a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > >>>> b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new > >>>> file mode 100644 > >>>> index 0000000..0b4bbbb > >>>> --- /dev/null > >>>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt > >>>> @@ -0,0 +1,60 @@ > >>>> +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK > >>>> + > >>>> +Required properties (phy (parent) node): > >>>> + - compatible : should be one of the listed compatibles: > >>>> + * "rockchip,rk3366-usb2phy" > >>>> + * "rockchip,rk3399-usb2phy" > >>>> + - #clock-cells : should be 0. > >>>> + - clock-output-names : specify the 480m output clock name. > >>>> + > >>>> +Optional properties: > >>>> + - clocks : phandle + phy specifier pair, for the input clock of phy. > >>>> + - clock-names : input clock name of phy, must be "phyclk". > >>>> + - vbus_host-supply : phandle to a regulator that supplies host vbus. > >>>> + - vbus_otg-supply : phandle to a regulator that supplies otg vbus. > >>> > >>> Nit: s/_/-/ here. > >> > >> Something I only stumbled over yesterday for the first time on my > >> rk3288- > >> popmetal: The phy subnodes seem to be able to use a generic phy-supply > >> property from inside the phy-core itself, see: > >> > >> https://github.com/mmind/linux-rockchip/commit/93739f521fc65f44524b00c9aa > >> f6db46bca94e02#diff-ddf3e45ebb753d6debf57022003a1a57R597 > >> > >> > >> for my WIP code for that other board. > > > > Ah, good comments! I will try later, if it is practicable, I shall > > correct it into the next patches (patch v4). > > I am sorry to tell you that seems unworkable, because we have two > sub-nodes (phy-ports) in one parent-node (phy), > what is more, the 'phy-supply' property can only put into parent-node, I > believe it can not be differentiated types of ports. > I mean vbus for host and otg are separately. I would disagree ;-) If you look in phy-core.c phy_create(), you can see that the struct phy that gets created, contains its own struct device instance, which then gets the phys of_node (the host+otg subnodes in this context) attached to it. The regulator_get_optional then runs on this struct device, thus making lookup on the subnode. And that works just nicely on my rk3288-popmetal, with its 3 phy subnodes and debugfs/regulator/regulator_summary prints that nicely: vcc_sys 0 12 0 5000mV 0mA 5000mV 5000mV vcc_host_5v 1 1 0 5000mV 0mA 5000mV 5000mV phy-phy.2 0mV 0mV vcc_otg_5v 1 1 0 5000mV 0mA 5000mV 5000mV phy-phy.0 0mV 0mV vcc_sata_5v 2 1 0 5000mV 0mA 5000mV 5000mV phy-phy.1 0mV 0mV Heiko ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy 2016-06-06 9:20 [PATCH v3 0/2] Add a new Rockchip usb2 phy driver Frank Wang 2016-06-06 9:20 ` [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY Frank Wang @ 2016-06-06 9:20 ` Frank Wang 2016-06-07 9:54 ` Heiko Stübner 1 sibling, 1 reply; 14+ messages in thread From: Frank Wang @ 2016-06-06 9:20 UTC (permalink / raw) To: heiko, dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak Cc: linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu, frank.wang The newer SoCs (rk3366, rk3399) take a different usb-phy IP block than rk3288 and before, and most of phy-related registers are also different from the past, so a new phy driver is required necessarily. Signed-off-by: Frank Wang <frank.wang@rock-chips.com> --- Changes in v3: - Resolved the mapping defect between fixed value in driver and the property in devicetree. - Optimized 480m output clock register function. - Code cleanup. Changes in v2: - Changed vbus_host operation from gpio to regulator in *_probe. - Improved the fault treatment relate to 480m clock register. - Cleaned up some meaningless codes in *_clk480m_disable. - made more clear the comment of *_sm_work. drivers/phy/Kconfig | 7 + drivers/phy/Makefile | 1 + drivers/phy/phy-rockchip-inno-usb2.c | 630 ++++++++++++++++++++++++++++++++++ 3 files changed, 638 insertions(+) create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index b869b98..29ef15c 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -347,6 +347,13 @@ config PHY_ROCKCHIP_USB help Enable this to support the Rockchip USB 2.0 PHY. +config PHY_ROCKCHIP_INNO_USB2 + tristate "Rockchip INNO USB2PHY Driver" + depends on ARCH_ROCKCHIP && OF + select GENERIC_PHY + help + Support for Rockchip USB2.0 PHY with Innosilicon IP block. + config PHY_ROCKCHIP_EMMC tristate "Rockchip EMMC PHY Driver" depends on ARCH_ROCKCHIP && OF diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 9c3e73c..4963fbc 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -38,6 +38,7 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o +obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c new file mode 100644 index 0000000..a2c4f96 --- /dev/null +++ b/drivers/phy/phy-rockchip-inno-usb2.c @@ -0,0 +1,630 @@ +/* + * Rockchip USB2.0 PHY with Innosilicon IP block driver + * + * Copyright (C) 2016 Fuzhou Rockchip Electronics 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/gpio/consumer.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_platform.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> + +#define BIT_WRITEABLE_SHIFT 16 +#define SCHEDULE_DELAY (60 * HZ) + +enum rockchip_usb2phy_port_id { + USB2PHY_PORT_OTG, + USB2PHY_PORT_HOST, + USB2PHY_NUM_PORTS, +}; + +enum rockchip_usb2phy_host_state { + PHY_STATE_HS_ONLINE = 0, + PHY_STATE_DISCONNECT = 1, + PHY_STATE_HS_CONNECT = 2, + PHY_STATE_FS_CONNECT = 4, +}; + +struct usb2phy_reg { + unsigned int offset; + unsigned int bitend; + unsigned int bitstart; + unsigned int disable; + unsigned int enable; +}; + +/** + * struct rockchip_usb2phy_port_cfg: usb-phy port configuration. + * @phy_sus: phy suspend register. + * @ls_det_en: linestate detection enable register. + * @ls_det_st: linestate detection state register. + * @ls_det_clr: linestate detection clear register. + * @utmi_ls: utmi linestate state register. + * @utmi_hstdet: utmi host disconnect register. + */ +struct rockchip_usb2phy_port_cfg { + struct usb2phy_reg phy_sus; + struct usb2phy_reg ls_det_en; + struct usb2phy_reg ls_det_st; + struct usb2phy_reg ls_det_clr; + struct usb2phy_reg utmi_ls; + struct usb2phy_reg utmi_hstdet; +}; + +/** + * struct rockchip_usb2phy_cfg: usb-phy configuration. + * @num_ports: specify how many ports that the phy has. + * @clkout_ctl: keep on/turn off output clk of phy. + */ +struct rockchip_usb2phy_cfg { + unsigned int num_ports; + struct usb2phy_reg clkout_ctl; + const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS]; +}; + +/** + * struct rockchip_usb2phy_port: usb-phy port data. + * @port_id: flag for otg port or host port. + * @suspended: phy suspended flag. + * @ls_irq: IRQ number assigned for linestate detection. + * @mutex: for register updating in sm_work. + * @sm_work: OTG state machine work. + * @phy_cfg: port register configuration, assigned by driver data. + */ +struct rockchip_usb2phy_port { + struct phy *phy; + unsigned int port_id; + bool suspended; + int ls_irq; + struct mutex mutex; + struct delayed_work sm_work; + const struct rockchip_usb2phy_port_cfg *port_cfg; +}; + +/** + * struct rockchip_usb2phy: usb2.0 phy driver data. + * @grf: General Register Files regmap. + * @clk: clock struct of phy input clk. + * @clk480m: clock struct of phy output clk. + * @clk_hw: clock struct of phy output clk management. + * @vbus_host: the regulator for vbus_host supply. + * @phy_cfg: phy register configuration, assigned by driver data. + * @ports: phy port instance. + */ +struct rockchip_usb2phy { + struct device *dev; + struct regmap *grf; + struct clk *clk; + struct clk *clk480m; + struct clk_hw clk480m_hw; + struct regulator *vbus_host; + const struct rockchip_usb2phy_cfg *phy_cfg; + struct rockchip_usb2phy_port ports[USB2PHY_NUM_PORTS]; +}; + +static inline int property_enable(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *reg, bool en) +{ + unsigned int val, mask, tmp; + + tmp = en ? reg->enable : reg->disable; + mask = GENMASK(reg->bitend, reg->bitstart); + val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); + + return regmap_write(rphy->grf, reg->offset, val); +} + +static inline bool property_enabled(struct rockchip_usb2phy *rphy, + const struct usb2phy_reg *reg) +{ + int ret; + unsigned int tmp, orig; + unsigned int mask = GENMASK(reg->bitend, reg->bitstart); + + ret = regmap_read(rphy->grf, reg->offset, &orig); + if (ret) + return false; + + tmp = (orig & mask) >> reg->bitstart; + return tmp == reg->enable; +} + +static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw) +{ + struct rockchip_usb2phy *rphy = + container_of(hw, struct rockchip_usb2phy, clk480m_hw); + int ret; + + /* turn on 480m clk output if it is off */ + if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) { + ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true); + if (ret) + return ret; + + /* waitting for the clk become stable */ + mdelay(1); + } + + return 0; +} + +static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw) +{ + struct rockchip_usb2phy *rphy = + container_of(hw, struct rockchip_usb2phy, clk480m_hw); + + /* turn off 480m clk output */ + property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false); +} + +static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw) +{ + struct rockchip_usb2phy *rphy = + container_of(hw, struct rockchip_usb2phy, clk480m_hw); + + return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl); +} + +static unsigned long +rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 480000000; +} + +static const struct clk_ops rockchip_usb2phy_clkout_ops = { + .enable = rockchip_usb2phy_clk480m_enable, + .disable = rockchip_usb2phy_clk480m_disable, + .is_enabled = rockchip_usb2phy_clk480m_enabled, + .recalc_rate = rockchip_usb2phy_clk480m_recalc_rate, +}; + +static void rockchip_usb2phy_clk480m_unregister(void *data) +{ + struct rockchip_usb2phy *rphy = data; + + of_clk_del_provider(rphy->dev->of_node); + clk_unregister(rphy->clk480m); + + if (rphy->clk) + clk_put(rphy->clk); +} + +static int +rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy) +{ + struct device_node *node = rphy->dev->of_node; + struct clk_init_data init; + const char *clk_name; + int ret; + + init.flags = 0; + init.name = "clk_usbphy_480m"; + init.ops = &rockchip_usb2phy_clkout_ops; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + rphy->clk = of_clk_get_by_name(node, "phyclk"); + if (IS_ERR(rphy->clk)) { + rphy->clk = NULL; + init.parent_names = NULL; + init.num_parents = 0; + } else { + clk_name = __clk_get_name(rphy->clk); + init.parent_names = &clk_name; + init.num_parents = 1; + } + + rphy->clk480m_hw.init = &init; + + /* register the clock */ + rphy->clk480m = clk_register(rphy->dev, &rphy->clk480m_hw); + if (IS_ERR(rphy->clk480m)) { + ret = PTR_ERR(rphy->clk480m); + goto err_register; + } + + ret = of_clk_add_provider(node, of_clk_src_simple_get, rphy->clk480m); + if (ret < 0) + goto err_clk_provider; + + ret = devm_add_action(rphy->dev, rockchip_usb2phy_clk480m_unregister, + rphy); + if (ret < 0) + goto err_unreg_action; + + return 0; + +err_unreg_action: + of_clk_del_provider(node); +err_clk_provider: + clk_unregister(rphy->clk480m); +err_register: + if (rphy->clk) + clk_put(rphy->clk); + return ret; +} + +static int rockchip_usb2phy_init(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + int ret; + + if (rport->port_id == USB2PHY_PORT_HOST) { + /* clear linestate and enable linestate detect irq */ + mutex_lock(&rport->mutex); + + ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + if (ret) { + mutex_unlock(&rport->mutex); + return ret; + } + + ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true); + if (ret) { + mutex_unlock(&rport->mutex); + return ret; + } + + mutex_unlock(&rport->mutex); + schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); + } + + return 0; +} + +static int rockchip_usb2phy_resume(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + int ret; + + dev_dbg(&rport->phy->dev, "port resume\n"); + + ret = clk_prepare_enable(rphy->clk480m); + if (ret) + return ret; + + ret = property_enable(rphy, &rport->port_cfg->phy_sus, false); + if (ret) + return ret; + + rport->suspended = false; + return 0; +} + +static int rockchip_usb2phy_suspend(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); + int ret; + + dev_dbg(&rport->phy->dev, "port suspend\n"); + + ret = property_enable(rphy, &rport->port_cfg->phy_sus, true); + if (ret) + return ret; + + rport->suspended = true; + clk_disable_unprepare(rphy->clk480m); + return 0; +} + +static int rockchip_usb2phy_exit(struct phy *phy) +{ + struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); + + if (rport->port_id == USB2PHY_PORT_HOST) + cancel_delayed_work_sync(&rport->sm_work); + + return 0; +} + +static const struct phy_ops rockchip_usb2phy_ops = { + .init = rockchip_usb2phy_init, + .exit = rockchip_usb2phy_exit, + .power_on = rockchip_usb2phy_resume, + .power_off = rockchip_usb2phy_suspend, + .owner = THIS_MODULE, +}; + +/* + * The function manage host-phy port state and suspend/resume phy port + * to save power. + * + * we rely on utmi_linestate and utmi_hostdisconnect to identify whether + * FS/HS is disconnect or not. Besides, we do not need care it is FS + * disconnected or HS disconnected, actually, we just only need get the + * device is disconnected at last through rearm the delayed work, + * to suspend the phy port in _PHY_STATE_DISCONNECT_ case. + * + * NOTE: It may invoke *phy_suspend or *phy_resume which will invoke some + * clk related APIs, so do not invoke it from interrupt context directly. + */ +static void rockchip_usb2phy_sm_work(struct work_struct *work) +{ + struct rockchip_usb2phy_port *rport = + container_of(work, struct rockchip_usb2phy_port, sm_work.work); + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); + unsigned int sh = rport->port_cfg->utmi_hstdet.bitend - + rport->port_cfg->utmi_hstdet.bitstart + 1; + unsigned int ul, uhd, state; + unsigned int ul_mask, uhd_mask; + int ret; + + mutex_lock(&rport->mutex); + + ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul); + if (ret < 0) + goto next_schedule; + + ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, + &uhd); + if (ret < 0) + goto next_schedule; + + uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend, + rport->port_cfg->utmi_hstdet.bitstart); + ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend, + rport->port_cfg->utmi_ls.bitstart); + + /* stitch on utmi_ls and utmi_hstdet as phy state */ + state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) | + (((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh); + + switch (state) { + case PHY_STATE_HS_ONLINE: + dev_dbg(&rport->phy->dev, "HS online\n"); + break; + case PHY_STATE_FS_CONNECT: + /* + * For FS device, the online state share with connect state + * from utmi_ls and utmi_hstdet register, so we distinguish + * them via suspended flag. + */ + if (!rport->suspended) { + dev_dbg(&rport->phy->dev, "FS online\n"); + break; + } + /* fall through */ + case PHY_STATE_HS_CONNECT: + if (rport->suspended) { + dev_dbg(&rport->phy->dev, "HS/FS connected\n"); + rockchip_usb2phy_resume(rport->phy); + rport->suspended = false; + } + break; + case PHY_STATE_DISCONNECT: + if (!rport->suspended) { + dev_dbg(&rport->phy->dev, "HS/FS disconnected\n"); + rockchip_usb2phy_suspend(rport->phy); + rport->suspended = true; + } + + /* + * activate the linestate detection to get the next device + * plug-in irq. + */ + property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + property_enable(rphy, &rport->port_cfg->ls_det_en, true); + + /* + * we don't need to rearm the delayed work when the phy port + * is suspended. + */ + mutex_unlock(&rport->mutex); + return; + default: + dev_dbg(&rport->phy->dev, "unknown phy state\n"); + break; + } + +next_schedule: + mutex_unlock(&rport->mutex); + schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY); +} + +static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data) +{ + struct rockchip_usb2phy_port *rport = data; + struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); + + if (!property_enabled(rphy, &rport->port_cfg->ls_det_st)) + return IRQ_NONE; + + mutex_lock(&rport->mutex); + + /* disable linestate detect irq and clear its status */ + property_enable(rphy, &rport->port_cfg->ls_det_en, false); + property_enable(rphy, &rport->port_cfg->ls_det_clr, true); + + mutex_unlock(&rport->mutex); + + /* + * In this case for host phy port, a new device is plugged in, + * meanwhile, if the phy port is suspended, we need rearm the work to + * resume it and mange its states; otherwise, we do nothing about that. + */ + if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST) + rockchip_usb2phy_sm_work(&rport->sm_work.work); + + return IRQ_HANDLED; +} + +static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy, + struct rockchip_usb2phy_port *rport, + struct device_node *child_np) +{ + int ret; + + rport->port_id = USB2PHY_PORT_HOST; + rport->port_cfg = &rphy->phy_cfg->port_cfgs[USB2PHY_PORT_HOST]; + + mutex_init(&rport->mutex); + INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work); + + rport->ls_irq = of_irq_get_byname(child_np, "linestate"); + if (rport->ls_irq < 0) { + dev_err(rphy->dev, "no linestate irq provided\n"); + return rport->ls_irq; + } + + ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL, + rockchip_usb2phy_linestate_irq, + IRQF_ONESHOT, + "rockchip_usb2phy", rport); + if (ret) { + dev_err(rphy->dev, "failed to request irq handle\n"); + return ret; + } + + return 0; +} + +static int rockchip_usb2phy_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child_np; + struct phy_provider *provider; + struct rockchip_usb2phy *rphy; + const struct of_device_id *match; + int index, ret; + + rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); + if (!rphy) + return -ENOMEM; + + match = of_match_device(dev->driver->of_match_table, dev); + if (!match || !match->data) { + dev_err(dev, "phy configs are not assigned!\n"); + return -EINVAL; + } + + if (!dev->parent || !dev->parent->of_node) + return -EINVAL; + + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(rphy->grf)) + return PTR_ERR(rphy->grf); + + rphy->dev = dev; + rphy->phy_cfg = match->data; + platform_set_drvdata(pdev, rphy); + + ret = rockchip_usb2phy_clk480m_register(rphy); + if (ret) { + dev_err(dev, "failed to register 480m output clock\n"); + return ret; + } + + rphy->vbus_host = devm_regulator_get_optional(dev, "vbus_host"); + if (IS_ERR(rphy->vbus_host)) { + ret = PTR_ERR(rphy->vbus_host); + if (ret == -EPROBE_DEFER) + return ret; + + dev_info(dev, "vbus_host regulator is not assigned!\n"); + rphy->vbus_host = NULL; + } else { + ret = regulator_enable(rphy->vbus_host); + if (ret) + return ret; + } + + index = 0; + for_each_available_child_of_node(np, child_np) { + struct rockchip_usb2phy_port *rport = &rphy->ports[index]; + struct phy *phy; + + phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create phy\n"); + ret = PTR_ERR(phy); + goto put_child; + } + + rport->phy = phy; + + /* initialize otg/host port separately */ + if (!of_node_cmp(child_np->name, "host-port")) { + ret = rockchip_usb2phy_host_port_init(rphy, rport, + child_np); + if (ret) + goto put_child; + } + + phy_set_drvdata(rport->phy, rport); + + /* to prevent out of boundary */ + if (++index >= rphy->phy_cfg->num_ports) + break; + } + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(provider); + +put_child: + of_node_put(child_np); + return ret; +} + +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs = { + .num_ports = 2, + .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, + .utmi_ls = { 0x049c, 14, 13, 0, 1 }, + .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } + } + }, +}; + +static const struct of_device_id rockchip_usb2phy_dt_match[] = { + { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, + {} +}; +MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match); + +static struct platform_driver rockchip_usb2phy_driver = { + .probe = rockchip_usb2phy_probe, + .driver = { + .name = "rockchip-usb2phy", + .of_match_table = rockchip_usb2phy_dt_match, + }, +}; +module_platform_driver(rockchip_usb2phy_driver); + +MODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>"); +MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver"); +MODULE_LICENSE("GPL v2"); -- 1.7.9.5 ^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy 2016-06-06 9:20 ` [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy Frank Wang @ 2016-06-07 9:54 ` Heiko Stübner 2016-06-07 13:19 ` Guenter Roeck 0 siblings, 1 reply; 14+ messages in thread From: Heiko Stübner @ 2016-06-07 9:54 UTC (permalink / raw) To: Frank Wang Cc: dianders, linux, groeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, kever.yang, huangtao, william.wu Hi Frank, Am Montag, 6. Juni 2016, 17:20:04 schrieb Frank Wang: > The newer SoCs (rk3366, rk3399) take a different usb-phy IP block > than rk3288 and before, and most of phy-related registers are also > different from the past, so a new phy driver is required necessarily. > > Signed-off-by: Frank Wang <frank.wang@rock-chips.com> > --- [...] > +static int rockchip_usb2phy_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct device_node *np = dev->of_node; > + struct device_node *child_np; > + struct phy_provider *provider; > + struct rockchip_usb2phy *rphy; > + const struct of_device_id *match; > + int index, ret; > + > + rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); > + if (!rphy) > + return -ENOMEM; > + > + match = of_match_device(dev->driver->of_match_table, dev); > + if (!match || !match->data) { > + dev_err(dev, "phy configs are not assigned!\n"); > + return -EINVAL; > + } > + > + if (!dev->parent || !dev->parent->of_node) > + return -EINVAL; > + > + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); > + if (IS_ERR(rphy->grf)) > + return PTR_ERR(rphy->grf); > + > + rphy->dev = dev; > + rphy->phy_cfg = match->data; > + platform_set_drvdata(pdev, rphy); > + > + ret = rockchip_usb2phy_clk480m_register(rphy); > + if (ret) { > + dev_err(dev, "failed to register 480m output clock\n"); > + return ret; > + } > + > + rphy->vbus_host = devm_regulator_get_optional(dev, "vbus_host"); > + if (IS_ERR(rphy->vbus_host)) { > + ret = PTR_ERR(rphy->vbus_host); > + if (ret == -EPROBE_DEFER) > + return ret; > + > + dev_info(dev, "vbus_host regulator is not assigned!\n"); > + rphy->vbus_host = NULL; > + } else { > + ret = regulator_enable(rphy->vbus_host); > + if (ret) > + return ret; > + } > + > + index = 0; > + for_each_available_child_of_node(np, child_np) { > + struct rockchip_usb2phy_port *rport = &rphy->ports[index]; > + struct phy *phy; > + > + phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); > + if (IS_ERR(phy)) { > + dev_err(dev, "failed to create phy\n"); > + ret = PTR_ERR(phy); > + goto put_child; > + } > + > + rport->phy = phy; > + > + /* initialize otg/host port separately */ > + if (!of_node_cmp(child_np->name, "host-port")) { > + ret = rockchip_usb2phy_host_port_init(rphy, rport, > + child_np); > + if (ret) > + goto put_child; > + } > + > + phy_set_drvdata(rport->phy, rport); > + > + /* to prevent out of boundary */ > + if (++index >= rphy->phy_cfg->num_ports) > + break; > + } > + > + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > + return PTR_ERR_OR_ZERO(provider); > + > +put_child: > + of_node_put(child_np); > + return ret; > +} > + > +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs = { > + .num_ports = 2, > + .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, > + .port_cfgs = { > + [USB2PHY_PORT_HOST] = { > + .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, > + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, > + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, > + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, > + .utmi_ls = { 0x049c, 14, 13, 0, 1 }, > + .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } > + } > + }, > +}; I also realized that the rk3399 has two of those phy-blocks, so I think we'll need to adapt your data storage mechanism a tiny bit. Maybe something like the following: In the dts: grf: syscon@ff770000 { compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; ... u2phy: usb2-phy@700 { compatible = "rockchip,rk3366-usb2phy"; reg = <0x700 0x2c>; ... }; }; In the driver static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = { { .reg = 0x700, .num_ports = 2, .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, .port_cfgs = { [USB2PHY_PORT_HOST] = { .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, ... } }, }, }; and in _probe then simply use the correct array entry matching the dts reg property. On the rk3399 this would then probably be u2phy0: phy@e450 { compatible = "rockchip,rk3366-usb2phy"; reg = <0xe450 0x10>; ... }; u2phy1: phy@e460 { compatible = "rockchip,rk3366-usb2phy"; reg = <0xe460 0x10>; ... }; This is slightly similar to what we do with the emmc-phy. But also as the usbphys differ in a lot of way, this is really only used to match to the data block. This only affects the match-data selection and the rest of the driver does not need to be changed for this. Heiko > +static const struct of_device_id rockchip_usb2phy_dt_match[] = { > + { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, > + {} > +}; > +MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match); > + > +static struct platform_driver rockchip_usb2phy_driver = { > + .probe = rockchip_usb2phy_probe, > + .driver = { > + .name = "rockchip-usb2phy", > + .of_match_table = rockchip_usb2phy_dt_match, > + }, > +}; > +module_platform_driver(rockchip_usb2phy_driver); > + > +MODULE_AUTHOR("Frank Wang <frank.wang@rock-chips.com>"); > +MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver"); > +MODULE_LICENSE("GPL v2"); ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy 2016-06-07 9:54 ` Heiko Stübner @ 2016-06-07 13:19 ` Guenter Roeck 2016-06-07 14:12 ` Heiko Stübner 0 siblings, 1 reply; 14+ messages in thread From: Guenter Roeck @ 2016-06-07 13:19 UTC (permalink / raw) To: Heiko Stübner Cc: Frank Wang, Douglas Anderson, Guenter Roeck, Guenter Roeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, Kever Yang, huangtao, william.wu On Tue, Jun 7, 2016 at 2:54 AM, Heiko Stübner <heiko@sntech.de> wrote: > Hi Frank, > > Am Montag, 6. Juni 2016, 17:20:04 schrieb Frank Wang: >> The newer SoCs (rk3366, rk3399) take a different usb-phy IP block >> than rk3288 and before, and most of phy-related registers are also >> different from the past, so a new phy driver is required necessarily. >> >> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> >> --- > > [...] > >> +static int rockchip_usb2phy_probe(struct platform_device *pdev) >> +{ >> + struct device *dev = &pdev->dev; >> + struct device_node *np = dev->of_node; >> + struct device_node *child_np; >> + struct phy_provider *provider; >> + struct rockchip_usb2phy *rphy; >> + const struct of_device_id *match; >> + int index, ret; >> + >> + rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); >> + if (!rphy) >> + return -ENOMEM; >> + >> + match = of_match_device(dev->driver->of_match_table, dev); >> + if (!match || !match->data) { >> + dev_err(dev, "phy configs are not assigned!\n"); >> + return -EINVAL; >> + } >> + >> + if (!dev->parent || !dev->parent->of_node) >> + return -EINVAL; >> + >> + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); >> + if (IS_ERR(rphy->grf)) >> + return PTR_ERR(rphy->grf); >> + >> + rphy->dev = dev; >> + rphy->phy_cfg = match->data; >> + platform_set_drvdata(pdev, rphy); >> + >> + ret = rockchip_usb2phy_clk480m_register(rphy); >> + if (ret) { >> + dev_err(dev, "failed to register 480m output clock\n"); >> + return ret; >> + } >> + >> + rphy->vbus_host = devm_regulator_get_optional(dev, "vbus_host"); >> + if (IS_ERR(rphy->vbus_host)) { >> + ret = PTR_ERR(rphy->vbus_host); >> + if (ret == -EPROBE_DEFER) >> + return ret; >> + >> + dev_info(dev, "vbus_host regulator is not assigned!\n"); >> + rphy->vbus_host = NULL; >> + } else { >> + ret = regulator_enable(rphy->vbus_host); >> + if (ret) >> + return ret; >> + } >> + >> + index = 0; >> + for_each_available_child_of_node(np, child_np) { >> + struct rockchip_usb2phy_port *rport = &rphy->ports[index]; >> + struct phy *phy; >> + >> + phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops); >> + if (IS_ERR(phy)) { >> + dev_err(dev, "failed to create phy\n"); >> + ret = PTR_ERR(phy); >> + goto put_child; >> + } >> + >> + rport->phy = phy; >> + >> + /* initialize otg/host port separately */ >> + if (!of_node_cmp(child_np->name, "host-port")) { >> + ret = rockchip_usb2phy_host_port_init(rphy, rport, >> + child_np); >> + if (ret) >> + goto put_child; >> + } >> + >> + phy_set_drvdata(rport->phy, rport); >> + >> + /* to prevent out of boundary */ >> + if (++index >= rphy->phy_cfg->num_ports) >> + break; >> + } >> + >> + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); >> + return PTR_ERR_OR_ZERO(provider); >> + >> +put_child: >> + of_node_put(child_np); >> + return ret; >> +} >> + >> +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs = { >> + .num_ports = 2, >> + .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, >> + .port_cfgs = { >> + [USB2PHY_PORT_HOST] = { >> + .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, >> + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, >> + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, >> + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, >> + .utmi_ls = { 0x049c, 14, 13, 0, 1 }, >> + .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } >> + } >> + }, >> +}; > > I also realized that the rk3399 has two of those phy-blocks, so I think we'll > need to adapt your data storage mechanism a tiny bit. Maybe something like > the following: > > In the dts: > > grf: syscon@ff770000 { > compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; > ... > u2phy: usb2-phy@700 { > compatible = "rockchip,rk3366-usb2phy"; > reg = <0x700 0x2c>; > ... > }; > }; > > In the driver > > static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = { > { > .reg = 0x700, > .num_ports = 2, > .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, > .port_cfgs = { > [USB2PHY_PORT_HOST] = { > .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, > ... > } > }, > }, > }; > > and in _probe then simply use the correct array entry matching the dts reg > property. > > On the rk3399 this would then probably be > > u2phy0: phy@e450 { > compatible = "rockchip,rk3366-usb2phy"; > reg = <0xe450 0x10>; > ... > }; > > u2phy1: phy@e460 { > compatible = "rockchip,rk3366-usb2phy"; > reg = <0xe460 0x10>; > ... > }; > > > This is slightly similar to what we do with the emmc-phy. But also as the > usbphys differ in a lot of way, this is really only used to match to the data > block. > > This only affects the match-data selection and the rest of the driver does not > need to be changed for this. > Would this replace the host-port property ? Thanks, Guenter ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy 2016-06-07 13:19 ` Guenter Roeck @ 2016-06-07 14:12 ` Heiko Stübner 2016-06-07 17:19 ` Guenter Roeck 0 siblings, 1 reply; 14+ messages in thread From: Heiko Stübner @ 2016-06-07 14:12 UTC (permalink / raw) To: Guenter Roeck Cc: Frank Wang, Douglas Anderson, Guenter Roeck, Guenter Roeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, Kever Yang, huangtao, william.wu Hi Guenter, Am Dienstag, 7. Juni 2016, 06:19:45 schrieb Guenter Roeck: > On Tue, Jun 7, 2016 at 2:54 AM, Heiko Stübner <heiko@sntech.de> wrote: > > Hi Frank, > > > > Am Montag, 6. Juni 2016, 17:20:04 schrieb Frank Wang: > >> The newer SoCs (rk3366, rk3399) take a different usb-phy IP block > >> than rk3288 and before, and most of phy-related registers are also > >> different from the past, so a new phy driver is required necessarily. > >> > >> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> > >> --- > > > > [...] > > > >> +static int rockchip_usb2phy_probe(struct platform_device *pdev) > >> +{ > >> + struct device *dev = &pdev->dev; > >> + struct device_node *np = dev->of_node; > >> + struct device_node *child_np; > >> + struct phy_provider *provider; > >> + struct rockchip_usb2phy *rphy; > >> + const struct of_device_id *match; > >> + int index, ret; > >> + > >> + rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); > >> + if (!rphy) > >> + return -ENOMEM; > >> + > >> + match = of_match_device(dev->driver->of_match_table, dev); > >> + if (!match || !match->data) { > >> + dev_err(dev, "phy configs are not assigned!\n"); > >> + return -EINVAL; > >> + } > >> + > >> + if (!dev->parent || !dev->parent->of_node) > >> + return -EINVAL; > >> + > >> + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); > >> + if (IS_ERR(rphy->grf)) > >> + return PTR_ERR(rphy->grf); > >> + > >> + rphy->dev = dev; > >> + rphy->phy_cfg = match->data; > >> + platform_set_drvdata(pdev, rphy); > >> + > >> + ret = rockchip_usb2phy_clk480m_register(rphy); > >> + if (ret) { > >> + dev_err(dev, "failed to register 480m output clock\n"); > >> + return ret; > >> + } > >> + > >> + rphy->vbus_host = devm_regulator_get_optional(dev, "vbus_host"); > >> + if (IS_ERR(rphy->vbus_host)) { > >> + ret = PTR_ERR(rphy->vbus_host); > >> + if (ret == -EPROBE_DEFER) > >> + return ret; > >> + > >> + dev_info(dev, "vbus_host regulator is not assigned!\n"); > >> + rphy->vbus_host = NULL; > >> + } else { > >> + ret = regulator_enable(rphy->vbus_host); > >> + if (ret) > >> + return ret; > >> + } > >> + > >> + index = 0; > >> + for_each_available_child_of_node(np, child_np) { > >> + struct rockchip_usb2phy_port *rport = &rphy->ports[index]; > >> + struct phy *phy; > >> + > >> + phy = devm_phy_create(dev, child_np, > >> &rockchip_usb2phy_ops); > >> + if (IS_ERR(phy)) { > >> + dev_err(dev, "failed to create phy\n"); > >> + ret = PTR_ERR(phy); > >> + goto put_child; > >> + } > >> + > >> + rport->phy = phy; > >> + > >> + /* initialize otg/host port separately */ > >> + if (!of_node_cmp(child_np->name, "host-port")) { > >> + ret = rockchip_usb2phy_host_port_init(rphy, rport, > >> + child_np); > >> + if (ret) > >> + goto put_child; > >> + } > >> + > >> + phy_set_drvdata(rport->phy, rport); > >> + > >> + /* to prevent out of boundary */ > >> + if (++index >= rphy->phy_cfg->num_ports) > >> + break; > >> + } > >> + > >> + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > >> + return PTR_ERR_OR_ZERO(provider); > >> + > >> +put_child: > >> + of_node_put(child_np); > >> + return ret; > >> +} > >> + > >> +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs = { > >> + .num_ports = 2, > >> + .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, > >> + .port_cfgs = { > >> + [USB2PHY_PORT_HOST] = { > >> + .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, > >> + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, > >> + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, > >> + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, > >> + .utmi_ls = { 0x049c, 14, 13, 0, 1 }, > >> + .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } > >> + } > >> + }, > >> +}; > > > > I also realized that the rk3399 has two of those phy-blocks, so I think > > we'll need to adapt your data storage mechanism a tiny bit. Maybe > > something like the following: > > > > In the dts: > > > > grf: syscon@ff770000 { > > > > compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; > > > > ... > > > > u2phy: usb2-phy@700 { > > > > compatible = "rockchip,rk3366-usb2phy"; > > > > reg = <0x700 0x2c>; > > ... > > > > }; > > > > }; > > > > In the driver > > > > static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = { > > > > { > > > > .reg = 0x700, > > .num_ports = 2, > > .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, > > .port_cfgs = { > > > > [USB2PHY_PORT_HOST] = { > > > > .phy_sus = { 0x0728, 15, 0, 0, > > 0x1d1 }, > > ... > > > > } > > > > }, > > > > }, > > > > }; > > > > and in _probe then simply use the correct array entry matching the dts reg > > property. > > > > On the rk3399 this would then probably be > > > > u2phy0: phy@e450 { > > > > compatible = "rockchip,rk3366-usb2phy"; > > > > reg = <0xe450 0x10>; > > ... > > > > }; > > > > u2phy1: phy@e460 { > > > > compatible = "rockchip,rk3366-usb2phy"; > > > > reg = <0xe460 0x10>; > > ... > > > > }; > > > > This is slightly similar to what we do with the emmc-phy. But also as the > > usbphys differ in a lot of way, this is really only used to match to the > > data block. > > > > This only affects the match-data selection and the rest of the driver does > > not need to be changed for this. > > Would this replace the host-port property ? nope ... each phy-block has two ports (host + otg). Franks rk3366 has one phy- block while the rk3399 has two phy blocks (with two ports on each). Heiko ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy 2016-06-07 14:12 ` Heiko Stübner @ 2016-06-07 17:19 ` Guenter Roeck 0 siblings, 0 replies; 14+ messages in thread From: Guenter Roeck @ 2016-06-07 17:19 UTC (permalink / raw) To: Heiko Stübner Cc: Guenter Roeck, Frank Wang, Douglas Anderson, Guenter Roeck, jwerner, kishon, robh+dt, pawel.moll, mark.rutland, ijc+devicetree, galak, linux-kernel, devicetree, linux-usb, linux-rockchip, xzy.xu, Kever Yang, huangtao, william.wu On Tue, Jun 07, 2016 at 04:12:29PM +0200, Heiko Stübner wrote: > Hi Guenter, > > Am Dienstag, 7. Juni 2016, 06:19:45 schrieb Guenter Roeck: > > On Tue, Jun 7, 2016 at 2:54 AM, Heiko Stübner <heiko@sntech.de> wrote: > > > Hi Frank, > > > > > > Am Montag, 6. Juni 2016, 17:20:04 schrieb Frank Wang: > > >> The newer SoCs (rk3366, rk3399) take a different usb-phy IP block > > >> than rk3288 and before, and most of phy-related registers are also > > >> different from the past, so a new phy driver is required necessarily. > > >> > > >> Signed-off-by: Frank Wang <frank.wang@rock-chips.com> > > >> --- > > > > > > [...] > > > > > >> +static int rockchip_usb2phy_probe(struct platform_device *pdev) > > >> +{ > > >> + struct device *dev = &pdev->dev; > > >> + struct device_node *np = dev->of_node; > > >> + struct device_node *child_np; > > >> + struct phy_provider *provider; > > >> + struct rockchip_usb2phy *rphy; > > >> + const struct of_device_id *match; > > >> + int index, ret; > > >> + > > >> + rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL); > > >> + if (!rphy) > > >> + return -ENOMEM; > > >> + > > >> + match = of_match_device(dev->driver->of_match_table, dev); > > >> + if (!match || !match->data) { > > >> + dev_err(dev, "phy configs are not assigned!\n"); > > >> + return -EINVAL; > > >> + } > > >> + > > >> + if (!dev->parent || !dev->parent->of_node) > > >> + return -EINVAL; > > >> + > > >> + rphy->grf = syscon_node_to_regmap(dev->parent->of_node); > > >> + if (IS_ERR(rphy->grf)) > > >> + return PTR_ERR(rphy->grf); > > >> + > > >> + rphy->dev = dev; > > >> + rphy->phy_cfg = match->data; > > >> + platform_set_drvdata(pdev, rphy); > > >> + > > >> + ret = rockchip_usb2phy_clk480m_register(rphy); > > >> + if (ret) { > > >> + dev_err(dev, "failed to register 480m output clock\n"); > > >> + return ret; > > >> + } > > >> + > > >> + rphy->vbus_host = devm_regulator_get_optional(dev, "vbus_host"); > > >> + if (IS_ERR(rphy->vbus_host)) { > > >> + ret = PTR_ERR(rphy->vbus_host); > > >> + if (ret == -EPROBE_DEFER) > > >> + return ret; > > >> + > > >> + dev_info(dev, "vbus_host regulator is not assigned!\n"); > > >> + rphy->vbus_host = NULL; > > >> + } else { > > >> + ret = regulator_enable(rphy->vbus_host); > > >> + if (ret) > > >> + return ret; > > >> + } > > >> + > > >> + index = 0; > > >> + for_each_available_child_of_node(np, child_np) { > > >> + struct rockchip_usb2phy_port *rport = &rphy->ports[index]; > > >> + struct phy *phy; > > >> + > > >> + phy = devm_phy_create(dev, child_np, > > >> &rockchip_usb2phy_ops); > > >> + if (IS_ERR(phy)) { > > >> + dev_err(dev, "failed to create phy\n"); > > >> + ret = PTR_ERR(phy); > > >> + goto put_child; > > >> + } > > >> + > > >> + rport->phy = phy; > > >> + > > >> + /* initialize otg/host port separately */ > > >> + if (!of_node_cmp(child_np->name, "host-port")) { > > >> + ret = rockchip_usb2phy_host_port_init(rphy, rport, > > >> + child_np); > > >> + if (ret) > > >> + goto put_child; > > >> + } > > >> + > > >> + phy_set_drvdata(rport->phy, rport); > > >> + > > >> + /* to prevent out of boundary */ > > >> + if (++index >= rphy->phy_cfg->num_ports) > > >> + break; > > >> + } > > >> + > > >> + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > > >> + return PTR_ERR_OR_ZERO(provider); > > >> + > > >> +put_child: > > >> + of_node_put(child_np); > > >> + return ret; > > >> +} > > >> + > > >> +static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs = { > > >> + .num_ports = 2, > > >> + .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, > > >> + .port_cfgs = { > > >> + [USB2PHY_PORT_HOST] = { > > >> + .phy_sus = { 0x0728, 15, 0, 0, 0x1d1 }, > > >> + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, > > >> + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, > > >> + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 }, > > >> + .utmi_ls = { 0x049c, 14, 13, 0, 1 }, > > >> + .utmi_hstdet = { 0x049c, 12, 12, 0, 1 } > > >> + } > > >> + }, > > >> +}; > > > > > > I also realized that the rk3399 has two of those phy-blocks, so I think > > > we'll need to adapt your data storage mechanism a tiny bit. Maybe > > > something like the following: > > > > > > In the dts: > > > > > > grf: syscon@ff770000 { > > > > > > compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd"; > > > > > > ... > > > > > > u2phy: usb2-phy@700 { > > > > > > compatible = "rockchip,rk3366-usb2phy"; > > > > > > reg = <0x700 0x2c>; > > > ... > > > > > > }; > > > > > > }; > > > > > > In the driver > > > > > > static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = { > > > > > > { > > > > > > .reg = 0x700, > > > .num_ports = 2, > > > .clkout_ctl = { 0x0724, 15, 15, 1, 0 }, > > > .port_cfgs = { > > > > > > [USB2PHY_PORT_HOST] = { > > > > > > .phy_sus = { 0x0728, 15, 0, 0, > > > 0x1d1 }, > > > ... > > > > > > } > > > > > > }, > > > > > > }, > > > > > > }; > > > > > > and in _probe then simply use the correct array entry matching the dts reg > > > property. > > > > > > On the rk3399 this would then probably be > > > > > > u2phy0: phy@e450 { > > > > > > compatible = "rockchip,rk3366-usb2phy"; > > > > > > reg = <0xe450 0x10>; > > > ... > > > > > > }; > > > > > > u2phy1: phy@e460 { > > > > > > compatible = "rockchip,rk3366-usb2phy"; > > > > > > reg = <0xe460 0x10>; > > > ... > > > > > > }; > > > > > > This is slightly similar to what we do with the emmc-phy. But also as the > > > usbphys differ in a lot of way, this is really only used to match to the > > > data block. > > > > > > This only affects the match-data selection and the rest of the driver does > > > not need to be changed for this. > > > > Would this replace the host-port property ? > > nope ... each phy-block has two ports (host + otg). Franks rk3366 has one phy- > block while the rk3399 has two phy blocks (with two ports on each). > Ah, now I understand. Yes, I think you are right, it would make sense to add this now. Guenter ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2016-06-07 17:20 UTC | newest] Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2016-06-06 9:20 [PATCH v3 0/2] Add a new Rockchip usb2 phy driver Frank Wang 2016-06-06 9:20 ` [PATCH v3 1/2] Documentation: bindings: add DT documentation for Rockchip USB2PHY Frank Wang 2016-06-06 11:27 ` Mark Rutland 2016-06-06 12:33 ` Heiko Stübner 2016-06-07 2:59 ` Frank Wang 2016-06-07 3:31 ` Frank Wang 2016-06-07 7:45 ` Kishon Vijay Abraham I 2016-06-07 8:23 ` Frank Wang 2016-06-07 7:59 ` Heiko Stübner 2016-06-06 9:20 ` [PATCH v3 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy Frank Wang 2016-06-07 9:54 ` Heiko Stübner 2016-06-07 13:19 ` Guenter Roeck 2016-06-07 14:12 ` Heiko Stübner 2016-06-07 17:19 ` Guenter Roeck
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).