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.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Chen-Yu Tsai <wens@csie.org>
Tested-by: Chen-Yu Tsai <wens@csie.org>
Acked-by: Mike Turquette <mturquette@linaro.org>
This commit is contained in:
Maxime Ripard 2014-12-07 17:43:04 +01:00
parent 3ec72fabcc
commit 6b0b8ccff0
2 changed files with 72 additions and 62 deletions

View file

@ -55,8 +55,7 @@ Required properties:
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 "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,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23
"allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 "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-clk" - for the MMC clock
"allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10
"allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks
"allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23
"allwinner,sun7i-a20-out-clk" - for the external output clocks "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 is the normal PLL6 output, or "pll6". The second output is rate doubled
PLL6, or "pll6x2". 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: For example:
osc24M: clk@01c20050 { osc24M: clk@01c20050 {
@ -138,11 +141,11 @@ cpu: cpu@01c20054 {
}; };
mmc0_clk: clk@01c20088 { mmc0_clk: clk@01c20088 {
#clock-cells = <0>; #clock-cells = <1>;
compatible = "allwinner,sun4i-mod0-clk"; compatible = "allwinner,sun4i-a10-mmc-clk";
reg = <0x01c20088 0x4>; reg = <0x01c20088 0x4>;
clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; clocks = <&osc24M>, <&pll6 1>, <&pll5 1>;
clock-output-names = "mmc0"; clock-output-names = "mmc0", "mmc0_output", "mmc0_sample";
}; };
mii_phy_tx_clk: clk@2 { mii_phy_tx_clk: clk@2 {

View file

@ -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); 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 mmc_phase {
struct clk_hw hw; struct clk_hw hw;
u8 offset;
void __iomem *reg; void __iomem *reg;
struct mmc_phase_data *data;
spinlock_t *lock; spinlock_t *lock;
}; };
@ -175,7 +171,7 @@ static int mmc_get_phase(struct clk_hw *hw)
u8 delay; u8 delay;
value = readl(phase->reg); value = readl(phase->reg);
delay = (value >> phase->data->offset) & 0x3; delay = (value >> phase->offset) & 0x3;
if (!delay) if (!delay)
return 180; return 180;
@ -263,8 +259,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
spin_lock_irqsave(phase->lock, flags); spin_lock_irqsave(phase->lock, flags);
value = readl(phase->reg); value = readl(phase->reg);
value &= ~GENMASK(phase->data->offset + 3, phase->data->offset); value &= ~GENMASK(phase->offset + 3, phase->offset);
value |= delay << phase->data->offset; value |= delay << phase->offset;
writel(value, phase->reg); writel(value, phase->reg);
spin_unlock_irqrestore(phase->lock, flags); spin_unlock_irqrestore(phase->lock, flags);
@ -276,66 +272,77 @@ static const struct clk_ops mmc_clk_ops = {
.set_phase = mmc_set_phase, .set_phase = mmc_set_phase,
}; };
static void __init sun4i_a10_mmc_phase_setup(struct device_node *node, static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
struct mmc_phase_data *data)
static void __init sun4i_a10_mmc_setup(struct device_node *node)
{ {
const char *parent_names[1] = { of_clk_get_parent_name(node, 0) }; struct clk_onecell_data *clk_data;
struct clk_init_data init = { const char *parent;
.num_parents = 1, void __iomem *reg;
.parent_names = parent_names, int i;
.ops = &mmc_clk_ops,
};
struct mmc_phase *phase; reg = of_io_request_and_map(node, 0, of_node_full_name(node));
struct clk *clk; if (IS_ERR(reg)) {
pr_err("Couldn't map the %s clock registers\n", node->name);
return;
}
phase = kmalloc(sizeof(*phase), GFP_KERNEL); clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
if (!phase) if (!clk_data)
return; return;
phase->hw.init = &init; clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
if (!clk_data->clks)
goto err_free_data;
phase->reg = of_iomap(node, 0); clk_data->clk_num = 3;
if (!phase->reg) clk_data->clks[0] = sunxi_factors_register(node,
goto err_free; &sun4i_a10_mod0_data,
&sun4i_a10_mmc_lock, reg);
if (!clk_data->clks[0])
goto err_free_clks;
phase->data = data; parent = __clk_get_name(clk_data->clks[0]);
phase->lock = &sun4i_a10_mod0_lock;
if (of_property_read_string(node, "clock-output-names", &init.name)) for (i = 1; i < 3; i++) {
init.name = node->name; struct clk_init_data init = {
.num_parents = 1,
.parent_names = &parent,
.ops = &mmc_clk_ops,
};
struct mmc_phase *phase;
clk = clk_register(NULL, &phase->hw); phase = kmalloc(sizeof(*phase), GFP_KERNEL);
if (IS_ERR(clk)) if (!phase)
goto err_unmap; continue;
of_clk_add_provider(node, of_clk_src_simple_get, clk); 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_onecell_get, clk_data);
return; return;
err_unmap: err_free_clks:
iounmap(phase->reg); kfree(clk_data->clks);
err_free: err_free_data:
kfree(phase); kfree(clk_data);
} }
CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
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);
}
CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);