clk: sunxi: mmc: Last bits of phase handling
Subsystems (5)
v3 cover clk: sunxi: mmc: Last bits of phase handling
Hi,
These are the last patches of the serie converting the custom phase API to the proper common clock framework API.
These patches have already been discussed in length, only the patch 1 is new and should ease the handling of our MMC clocks.
Thanks,
Maxime
Changes from v2:
- Rebased on top of v3.19
Changes from v1:
- Fixed memory leak when a phase clock registration fails
- Moved the spinlock declaration
- Updated the DT bindings docs
Maxime Ripard (4):
clk: sunxi: Rework MMC phase clocks
ARM: sunxi: dt: Add sample and output mmc clocks
mmc: sunxi: Convert MMC driver to the standard clock phase API
clk: sunxi: Remove custom phase function
Documentation/devicetree/bindings/clock/sunxi.txt | 13 +- .../devicetree/bindings/mmc/sunxi-mmc.txt | 8 +- arch/arm/boot/dts/sun4i-a10.dtsi | 72 +++++++---- arch/arm/boot/dts/sun5i-a10s.dtsi | 54 ++++++--- arch/arm/boot/dts/sun5i-a13.dtsi | 44 +++++-- arch/arm/boot/dts/sun6i-a31.dtsi | 72 +++++++---- arch/arm/boot/dts/sun7i-a20.dtsi | 72 +++++++---- arch/arm/boot/dts/sun8i-a23.dtsi | 54 ++++++--- drivers/clk/sunxi/clk-mod0.c | 131 +++++++++++---------- drivers/clk/sunxi/clk-sunxi.c | 37 ------ drivers/mmc/host/sunxi-mmc.c | 73 ++++++++---- include/linux/clk/sunxi.h | 22 ---- 12 files changed, 395 insertions(+), 257 deletions(-) delete mode 100644 include/linux/clk/sunxi.h
Signature · 1 line
2.2.1
PATCH v3 1/4 clk: sunxi: Rework MMC phase clocks
Instead of having three different clocks for the main MMC clock and the two phase sub-clocks, which involved having three different drivers sharing the same register, rework it to have the same single driver registering three different clocks.
--- Documentation/devicetree/bindings/clock/sunxi.txt | 13 ++- drivers/clk/sunxi/clk-mod0.c | 131 ++++++++++++---------- 2 files changed, 77 insertions(+), 67 deletions(-)
Documentation/devicetree/bindings/clock/sunxi.txt +8 -5
@@ -55,8 +55,7 @@ Required properties: "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 - "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10 - "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10 + "allwinner,sun4i-a10-mmc-clk" - for the MMC clock "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 "allwinner,sun7i-a20-out-clk" - for the external output clocks
@@ -95,6 +94,10 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output is the normal PLL6 output, or "pll6". The second output is rate doubled PLL6, or "pll6x2". +The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the +main clock, with the ID 0, and the output and sample clocks, with the +IDs 1 and 2, respectively. + For example: osc24M: clk at 01c20050 {
@@ -138,11 +141,11 @@ cpu: cpu at 01c20054 { }; mmc0_clk: clk at 01c20088 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-mod0-clk"; + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; - clock-output-names = "mmc0"; + clock-output-names = "mmc0", "mmc0_output", "mmc0_sample"; }; mii_phy_tx_clk: clk at 2 {
drivers/clk/sunxi/clk-mod0.c +69 -62
164 lines not on this page · raw message
Signature · 1 line
2.2.1
PATCH v3 1/4 clk: sunxi: Rework MMC phase clocks
Quoting Maxime Ripard (2015-01-11 12:00:54)
Quoted 8 lines
Instead of having three different clocks for the main MMC clock and the two phase sub-clocks, which involved having three different drivers sharing the same register, rework it to have the same single driver registering three different clocks.
Signed-off-by Maxime Ripard <[email protected]>Reviewed-by Chen-Yu Tsai <[email protected]>Tested-by Chen-Yu Tsai <[email protected]>
Looks good to me.
Regards,
Mike
Quoted 220 lines
--- Documentation/devicetree/bindings/clock/sunxi.txt | 13 ++- drivers/clk/sunxi/clk-mod0.c | 131 ++++++++++++---------- 2 files changed, 77 insertions(+), 67 deletions(-)Documentation/devicetree/bindings/clock/sunxi.txt +8
-5@@ -55,8 +55,7 @@ Required properties: "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 - "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10 - "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10 + "allwinner,sun4i-a10-mmc-clk" - for the MMC clock "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 "allwinner,sun7i-a20-out-clk" - for the external output clocks@@ -95,6 +94,10 @@ For "allwinner,sun6i-a31-pll6-clk", there are 2 outputs. The first output is the normal PLL6 output, or "pll6". The second output is rate doubled PLL6, or "pll6x2". +The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the +main clock, with the ID 0, and the output and sample clocks, with the +IDs 1 and 2, respectively. + For example: osc24M: clk at 01c20050 {@@ -138,11 +141,11 @@ cpu: cpu at 01c20054 { }; mmc0_clk: clk at 01c20088 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-mod0-clk"; + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; - clock-output-names = "mmc0"; + clock-output-names = "mmc0", "mmc0_output", "mmc0_sample"; }; mii_phy_tx_clk: clk at 2 {drivers/clk/sunxi/clk-mod0.c +69
-62@@ -152,14 +152,10 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node) }CLK_OF_DECLARE (sun5i_a13_mbus,"allwinner,sun5i-a13-mbus-clk" , sun5i_a13_mbus_setup); -struct mmc_phase_data { -u8 offset; -}; -struct mmc_phase {struct clk_hw hw; +u8 offset;void __iomem *reg; -struct mmc_phase_data *data;spinlock_t *lock; };@@ -175,7 +171,7 @@ static int mmc_get_phase(struct clk_hw *hw)u8 delay; value =readl (phase->reg); - delay = (value >> phase->data->offset) &0x3 ; + delay = (value >> phase->offset) &0x3 ;if (!delay)return 180 ;@@ -263,8 +259,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)spin_lock_irqsave (phase->lock, flags); value =readl (phase->reg); - value &= ~GENMASK (phase->data->offset +3 , phase->data->offset); - value |= delay << phase->data->offset; + value &= ~GENMASK (phase->offset +3 , phase->offset); + value |= delay << phase->offset;writel (value, phase->reg);spin_unlock_irqrestore (phase->lock, flags);@@ -276,66 +272,77 @@ static const struct clk_ops mmc_clk_ops = { .set_phase = mmc_set_phase, }; -static void __init sun4i_a10_mmc_phase_setup (struct device_node *node, -struct mmc_phase_data *data) -{ -const char *parent_names[1 ] = {of_clk_get_parent_name (node,0 ) }; -struct clk_init_data init = { - .num_parents =1 , - .parent_names = parent_names, - .ops = &mmc_clk_ops, - }; - -struct mmc_phase *phase; -struct clk *clk; - - phase =kmalloc (sizeof (*phase),GFP_KERNEL ); -if (!phase) -return ; - - phase->hw.init = &init; +static DEFINE_SPINLOCK (sun4i_a10_mmc_lock); - phase->reg =of_iomap (node,0 ); -if (!phase->reg) - goto err_free; +static void __init sun4i_a10_mmc_setup (struct device_node *node) +{ +struct clk_onecell_data *clk_data; +const char *parent; +void __iomem *reg; +int i; - phase->data = data; - phase->lock = &sun4i_a10_mod0_lock; + reg =of_io_request_and_map (node,0 ,of_node_full_name (node)); +if (IS_ERR (reg)) { +pr_err ("Couldn't map the %s clock registers\n" , node->name); +return ; + } -if (of_property_read_string (node,"clock-output-names" , &init.name)) - init.name = node->name; + clk_data =kmalloc (sizeof (*clk_data),GFP_KERNEL ); +if (!clk_data) +return ; - clk =clk_register (NULL , &phase->hw); -if (IS_ERR (clk)) - goto err_unmap; + clk_data->clks =kcalloc (3 ,sizeof (*clk_data->clks),GFP_KERNEL ); +if (!clk_data->clks) + goto err_free_data; + + clk_data->clk_num =3 ; + clk_data->clks[0 ] =sunxi_factors_register (node, + &sun4i_a10_mod0_data, + &sun4i_a10_mmc_lock, reg); +if (!clk_data->clks[0 ]) + goto err_free_clks; + + parent =__clk_get_name (clk_data->clks[0 ]); + +for (i =1 ; i <3 ; i++) { +struct clk_init_data init = { + .num_parents =1 , + .parent_names = &parent, + .ops = &mmc_clk_ops, + }; +struct mmc_phase *phase; + + phase =kmalloc (sizeof (*phase),GFP_KERNEL ); +if (!phase) +continue ; + + phase->hw.init = &init; + phase->reg = reg; + phase->lock = &sun4i_a10_mmc_lock; + +if (i ==1 ) + phase->offset =8 ; +else + phase->offset =20 ; + +if (of_property_read_string_index (node,"clock-output-names" , + i, &init.name)) + init.name = node->name; + + clk_data->clks[i] =clk_register (NULL , &phase->hw); +if (IS_ERR (clk_data->clks[i])) { +kfree (phase); +continue ; + } + } -of_clk_add_provider (node, of_clk_src_simple_get, clk); +of_clk_add_provider (node, of_clk_src_onecell_get, clk_data);return ; -err_unmap: -iounmap (phase->reg); -err_free: -kfree (phase); -} - - -static struct mmc_phase_data mmc_output_clk = { - .offset =8 , -}; - -static struct mmc_phase_data mmc_sample_clk = { - .offset =20 , -}; - -static void __init sun4i_a10_mmc_output_setup (struct device_node *node) -{ -sun4i_a10_mmc_phase_setup (node, &mmc_output_clk); -} -CLK_OF_DECLARE (sun4i_a10_mmc_output,"allwinner,sun4i-a10-mmc-output-clk" , sun4i_a10_mmc_output_setup); - -static void __init sun4i_a10_mmc_sample_setup (struct device_node *node) -{ -sun4i_a10_mmc_phase_setup (node, &mmc_sample_clk); +err_free_clks: +kfree (clk_data->clks); +err_free_data: +kfree (clk_data); } -CLK_OF_DECLARE (sun4i_a10_mmc_sample,"allwinner,sun4i-a10-mmc-sample-clk" , sun4i_a10_mmc_sample_setup); +CLK_OF_DECLARE (sun4i_a10_mmc,"allwinner,sun4i-a10-mmc-clk" , sun4i_a10_mmc_setup);Signature · 1 line
2.2.1
PATCH v3 2/4 ARM: sunxi: dt: Add sample and output mmc clocks
In reply to Maxime RipardAdd the sample and output clocks for the MMC phase support.
--- arch/arm/boot/dts/sun4i-a10.dtsi | 72 ++++++++++++++++++++++++++++----------- arch/arm/boot/dts/sun5i-a10s.dtsi | 54 +++++++++++++++++++++-------- arch/arm/boot/dts/sun5i-a13.dtsi | 44 +++++++++++++++++------- arch/arm/boot/dts/sun6i-a31.dtsi | 72 ++++++++++++++++++++++++++++----------- arch/arm/boot/dts/sun7i-a20.dtsi | 72 ++++++++++++++++++++++++++++----------- arch/arm/boot/dts/sun8i-a23.dtsi | 54 +++++++++++++++++++++-------- 6 files changed, 265 insertions(+), 103 deletions(-)
arch/arm/boot/dts/sun4i-a10.dtsi +52 -20
@@ -242,35 +242,43 @@ }; mmc0_clk: clk at 01c20088 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-mod0-clk"; + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; reg = <0x01c20088 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; - clock-output-names = "mmc0"; + clock-output-names = "mmc0", + "mmc0_output", + "mmc0_sample"; }; mmc1_clk: clk at 01c2008c { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-mod0-clk"; + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; reg = <0x01c2008c 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; - clock-output-names = "mmc1"; + clock-output-names = "mmc1", + "mmc1_output", + "mmc1_sample"; }; mmc2_clk: clk at 01c20090 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-mod0-clk"; + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; reg = <0x01c20090 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; - clock-output-names = "mmc2"; + clock-output-names = "mmc2", + "mmc2_output", + "mmc2_sample"; }; mmc3_clk: clk at 01c20094 { - #clock-cells = <0>; - compatible = "allwinner,sun4i-a10-mod0-clk"; + #clock-cells = <1>; + compatible = "allwinner,sun4i-a10-mmc-clk"; reg = <0x01c20094 0x4>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; - clock-output-names = "mmc3"; + clock-output-names = "mmc3", + "mmc3_output", + "mmc3_sample"; }; ts_clk: clk at 01c20098 {
@@ -416,8 +424,14 @@ mmc0: mmc at 01c0f000 { compatible = "allwinner,sun4i-a10-mmc"; reg = <0x01c0f000 0x1000>; - clocks = <&ahb_gates 8>, <&mmc0_clk>; - clock-names = "ahb", "mmc"; + clocks = <&ahb_gates 8>, + <&mmc0_clk 0>, + <&mmc0_clk 1>, + <&mmc0_clk 2>; + clock-names = "ahb", + "mmc", + "output", + "sample"; interrupts = <32>; status = "disabled"; };
@@ -425,8 +439,14 @@ mmc1: mmc at 01c10000 { compatible = "allwinner,sun4i-a10-mmc"; reg = <0x01c10000 0x1000>; - clocks = <&ahb_gates 9>, <&mmc1_clk>; - clock-names = "ahb", "mmc"; + clocks = <&ahb_gates 9>, + <&mmc1_clk 0>, + <&mmc1_clk 1>, + <&mmc1_clk 2>; + clock-names = "ahb", + "mmc", + "output", + "sample"; interrupts = <33>; status = "disabled"; };
@@ -434,8 +454,14 @@ mmc2: mmc at 01c11000 { compatible = "allwinner,sun4i-a10-mmc"; reg = <0x01c11000 0x1000>; - clocks = <&ahb_gates 10>, <&mmc2_clk>; - clock-names = "ahb", "mmc"; + clocks = <&ahb_gates 10>, + <&mmc2_clk 0>, + <&mmc2_clk 1>, + <&mmc2_clk 2>; + clock-names = "ahb", + "mmc", + "output", + "sample"; interrupts = <34>; status = "disabled"; };
@@ -443,8 +469,14 @@ mmc3: mmc at 01c12000 { compatible = "allwinner,sun4i-a10-mmc"; reg = <0x01c12000 0x1000>; - clocks = <&ahb_gates 11>, <&mmc3_clk>; - clock-names = "ahb", "mmc"; + clocks = <&ahb_gates 11>, + <&mmc3_clk 0>, + <&mmc3_clk 1>, + <&mmc3_clk 2>; + clock-names = "ahb", + "mmc", + "output", + "sample"; interrupts = <35>; status = "disabled"; };
arch/arm/boot/dts/sun5i-a10s.dtsi +39 -15
90 lines not on this page · raw message
arch/arm/boot/dts/sun5i-a13.dtsi +31 -13
74 lines not on this page · raw message
arch/arm/boot/dts/sun6i-a31.dtsi +52 -20
119 lines not on this page · raw message
arch/arm/boot/dts/sun7i-a20.dtsi +52 -20
119 lines not on this page · raw message
arch/arm/boot/dts/sun8i-a23.dtsi +39 -15
90 lines not on this page · raw message
Signature · 1 line
2.2.1
PATCH v3 3/4 mmc: sunxi: Convert MMC driver to the standard clock phase API
In reply to Maxime RipardNow that we have proper support to use the generic phase API in our clock driver, switch the MMC driver to use it.
--- .../devicetree/bindings/mmc/sunxi-mmc.txt | 8 +-- drivers/mmc/host/sunxi-mmc.c | 73 +++++++++++++++------- 2 files changed, 53 insertions(+), 28 deletions(-)
Documentation/devicetree/bindings/mmc/sunxi-mmc.txt +4 -4
@@ -10,8 +10,8 @@ Absolute maximum transfer rate is 200MB/s Required properties: - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc" - reg : mmc controller base registers - - clocks : a list with 2 phandle + clock specifier pairs - - clock-names : must contain "ahb" and "mmc" + - clocks : a list with 4 phandle + clock specifier pairs + - clock-names : must contain "ahb", "mmc", "output" and "sample" - interrupts : mmc controller interrupt Optional properties:
@@ -25,8 +25,8 @@ Examples: mmc0: mmc at 01c0f000 { compatible = "allwinner,sun5i-a13-mmc"; reg = <0x01c0f000 0x1000>; - clocks = <&ahb_gates 8>, <&mmc0_clk>; - clock-names = "ahb", "mod"; + clocks = <&ahb_gates 8>, <&mmc0_clk>, <&mmc0_output_clk>, <&mmc0_sample_clk>; + clock-names = "ahb", "mod", "output", "sample"; interrupts = <0 32 4>; status = "disabled"; };
drivers/mmc/host/sunxi-mmc.c +49 -24
127 lines not on this page · raw message
Signature · 1 line
2.2.1
PATCH v3 4/4 clk: sunxi: Remove custom phase function
In reply to Maxime RipardNow that we don't have any user left for our custom phase function, we can safely remove this hack from the code.
--- drivers/clk/sunxi/clk-sunxi.c | 37 ------------------------------------- include/linux/clk/sunxi.h | 22 ---------------------- 2 files changed, 59 deletions(-) delete mode 100644 include/linux/clk/sunxi.h
drivers/clk/sunxi/clk-sunxi.c +0 -37
@@ -563,43 +563,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate, }/** -* clk_sunxi_mmc_phase_control() - configures MMC clock phase control -*/ - -void clk_sunxi_mmc_phase_control (struct clk *clk,u8 sample,u8 output) -{ -#define to_clk_composite (_hw) container_of(_hw, struct clk_composite, hw) -#define to_clk_factors (_hw) container_of(_hw, struct clk_factors, hw) - -struct clk_hw *hw =__clk_get_hw (clk); -struct clk_composite *composite =to_clk_composite (hw); -struct clk_hw *rate_hw = composite->rate_hw; -struct clk_factors *factors =to_clk_factors (rate_hw); -unsigned long flags =0 ; -u32 reg; - -if (factors->lock) -spin_lock_irqsave (factors->lock, flags); - - reg =readl (factors->reg); - -/* set sample clock phase control */ - reg &= ~(0x7 <<20 ); - reg |= ((sample &0x7 ) <<20 ); - -/* set output clock phase control */ - reg &= ~(0x7 <<8 ); - reg |= ((output &0x7 ) <<8 ); - -writel (reg, factors->reg); - -if (factors->lock) -spin_unlock_irqrestore (factors->lock, flags); -} -EXPORT_SYMBOL (clk_sunxi_mmc_phase_control); - - -/** * sunxi_factors_clk_setup() - Setup function for factor clocks */
include/linux/clk/sunxi.h deleted +0 -22
@@ -1,22 +0,0 @@ -/* -* Copyright 2013 - Hans de Goede <[email protected]> -* -* 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. -*/ - -#ifndef __LINUX_CLK_SUNXI_H_ -#define __LINUX_CLK_SUNXI_H_ - -#include <linux/clk.h> - -void clk_sunxi_mmc_phase_control (struct clk *clk,u8 sample,u8 output); - -#endif
Signature · 1 line
2.2.1
v3 cover clk: sunxi: mmc: Last bits of phase handling
In reply to Maxime RipardQuoted 10 lines · Maxime Ripard
Hi,
These are the last patches of the serie converting the custom phase API to the proper common clock framework API.
These patches have already been discussed in length, only the patch 1 is new and should ease the handling of our MMC clocks.
Thanks,
Maxime
Merged the 4 patches with Mike's Acked-by on the first one.
Thanks!
Maxime
Signature · 10 lines
Maxime Ripard, Free Electrons Embedded Linux, Kernel and Android engineering http://free-electrons.com -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 819 bytes Desc: Digital signature URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20150114/f1a071d2/attachment.sig>