diff options
| author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2014-12-07 11:43:04 -0500 |
|---|---|---|
| committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2015-01-14 04:39:16 -0500 |
| commit | 6b0b8ccff002414fab08a080c7a8a6ee3db22c0d (patch) | |
| tree | 608d0cc1f59c46ae0f6afbe88eb0d368a88a606d | |
| parent | 3ec72fabcc6f4f5c786c50e08b59e1251d0fdfeb (diff) | |
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>
| -rw-r--r-- | Documentation/devicetree/bindings/clock/sunxi.txt | 13 | ||||
| -rw-r--r-- | drivers/clk/sunxi/clk-mod0.c | 131 |
2 files changed, 77 insertions, 67 deletions
diff --git a/Documentation/devicetree/bindings/clock/sunxi.txt b/Documentation/devicetree/bindings/clock/sunxi.txt index 9dc4f55a04ad..e4c42276c577 100644 --- a/Documentation/devicetree/bindings/clock/sunxi.txt +++ b/Documentation/devicetree/bindings/clock/sunxi.txt | |||
| @@ -55,8 +55,7 @@ Required properties: | |||
| 55 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 | 55 | "allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31 |
| 56 | "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 | 56 | "allwinner,sun8i-a23-apb2-gates-clk" - for the APB2 gates on A23 |
| 57 | "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 | 57 | "allwinner,sun5i-a13-mbus-clk" - for the MBUS clock on A13 |
| 58 | "allwinner,sun4i-a10-mmc-output-clk" - for the MMC output clock on A10 | 58 | "allwinner,sun4i-a10-mmc-clk" - for the MMC clock |
| 59 | "allwinner,sun4i-a10-mmc-sample-clk" - for the MMC sample clock on A10 | ||
| 60 | "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks | 59 | "allwinner,sun4i-a10-mod0-clk" - for the module 0 family of clocks |
| 61 | "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 | 60 | "allwinner,sun8i-a23-mbus-clk" - for the MBUS clock on A23 |
| 62 | "allwinner,sun7i-a20-out-clk" - for the external output clocks | 61 | "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 | |||
| 95 | is the normal PLL6 output, or "pll6". The second output is rate doubled | 94 | is the normal PLL6 output, or "pll6". The second output is rate doubled |
| 96 | PLL6, or "pll6x2". | 95 | PLL6, or "pll6x2". |
| 97 | 96 | ||
| 97 | The "allwinner,sun4i-a10-mmc-clk" has three different outputs: the | ||
| 98 | main clock, with the ID 0, and the output and sample clocks, with the | ||
| 99 | IDs 1 and 2, respectively. | ||
| 100 | |||
| 98 | For example: | 101 | For example: |
| 99 | 102 | ||
| 100 | osc24M: clk@01c20050 { | 103 | osc24M: clk@01c20050 { |
| @@ -138,11 +141,11 @@ cpu: cpu@01c20054 { | |||
| 138 | }; | 141 | }; |
| 139 | 142 | ||
| 140 | mmc0_clk: clk@01c20088 { | 143 | mmc0_clk: clk@01c20088 { |
| 141 | #clock-cells = <0>; | 144 | #clock-cells = <1>; |
| 142 | compatible = "allwinner,sun4i-mod0-clk"; | 145 | compatible = "allwinner,sun4i-a10-mmc-clk"; |
| 143 | reg = <0x01c20088 0x4>; | 146 | reg = <0x01c20088 0x4>; |
| 144 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; | 147 | clocks = <&osc24M>, <&pll6 1>, <&pll5 1>; |
| 145 | clock-output-names = "mmc0"; | 148 | clock-output-names = "mmc0", "mmc0_output", "mmc0_sample"; |
| 146 | }; | 149 | }; |
| 147 | 150 | ||
| 148 | mii_phy_tx_clk: clk@2 { | 151 | mii_phy_tx_clk: clk@2 { |
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c index bf8fcd8c940e..e37eb6fe19e8 100644 --- a/drivers/clk/sunxi/clk-mod0.c +++ b/drivers/clk/sunxi/clk-mod0.c | |||
| @@ -152,14 +152,10 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node) | |||
| 152 | } | 152 | } |
| 153 | CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup); | 153 | CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup); |
| 154 | 154 | ||
| 155 | struct mmc_phase_data { | ||
| 156 | u8 offset; | ||
| 157 | }; | ||
| 158 | |||
| 159 | struct mmc_phase { | 155 | struct mmc_phase { |
| 160 | struct clk_hw hw; | 156 | struct clk_hw hw; |
| 157 | u8 offset; | ||
| 161 | void __iomem *reg; | 158 | void __iomem *reg; |
| 162 | struct mmc_phase_data *data; | ||
| 163 | spinlock_t *lock; | 159 | spinlock_t *lock; |
| 164 | }; | 160 | }; |
| 165 | 161 | ||
| @@ -175,7 +171,7 @@ static int mmc_get_phase(struct clk_hw *hw) | |||
| 175 | u8 delay; | 171 | u8 delay; |
| 176 | 172 | ||
| 177 | value = readl(phase->reg); | 173 | value = readl(phase->reg); |
| 178 | delay = (value >> phase->data->offset) & 0x3; | 174 | delay = (value >> phase->offset) & 0x3; |
| 179 | 175 | ||
| 180 | if (!delay) | 176 | if (!delay) |
| 181 | return 180; | 177 | return 180; |
| @@ -263,8 +259,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees) | |||
| 263 | 259 | ||
| 264 | spin_lock_irqsave(phase->lock, flags); | 260 | spin_lock_irqsave(phase->lock, flags); |
| 265 | value = readl(phase->reg); | 261 | value = readl(phase->reg); |
| 266 | value &= ~GENMASK(phase->data->offset + 3, phase->data->offset); | 262 | value &= ~GENMASK(phase->offset + 3, phase->offset); |
| 267 | value |= delay << phase->data->offset; | 263 | value |= delay << phase->offset; |
| 268 | writel(value, phase->reg); | 264 | writel(value, phase->reg); |
| 269 | spin_unlock_irqrestore(phase->lock, flags); | 265 | spin_unlock_irqrestore(phase->lock, flags); |
| 270 | 266 | ||
| @@ -276,66 +272,77 @@ static const struct clk_ops mmc_clk_ops = { | |||
| 276 | .set_phase = mmc_set_phase, | 272 | .set_phase = mmc_set_phase, |
| 277 | }; | 273 | }; |
| 278 | 274 | ||
| 279 | static void __init sun4i_a10_mmc_phase_setup(struct device_node *node, | 275 | static DEFINE_SPINLOCK(sun4i_a10_mmc_lock); |
| 280 | struct mmc_phase_data *data) | ||
| 281 | { | ||
| 282 | const char *parent_names[1] = { of_clk_get_parent_name(node, 0) }; | ||
| 283 | struct clk_init_data init = { | ||
| 284 | .num_parents = 1, | ||
| 285 | .parent_names = parent_names, | ||
| 286 | .ops = &mmc_clk_ops, | ||
| 287 | }; | ||
| 288 | |||
| 289 | struct mmc_phase *phase; | ||
| 290 | struct clk *clk; | ||
| 291 | |||
| 292 | phase = kmalloc(sizeof(*phase), GFP_KERNEL); | ||
| 293 | if (!phase) | ||
| 294 | return; | ||
| 295 | |||
| 296 | phase->hw.init = &init; | ||
| 297 | 276 | ||
| 298 | phase->reg = of_iomap(node, 0); | 277 | static void __init sun4i_a10_mmc_setup(struct device_node *node) |
| 299 | if (!phase->reg) | 278 | { |
| 300 | goto err_free; | 279 | struct clk_onecell_data *clk_data; |
| 280 | const char *parent; | ||
| 281 | void __iomem *reg; | ||
| 282 | int i; | ||
| 301 | 283 | ||
| 302 | phase->data = data; | 284 | reg = of_io_request_and_map(node, 0, of_node_full_name(node)); |
| 303 | phase->lock = &sun4i_a10_mod0_lock; | 285 | if (IS_ERR(reg)) { |
| 286 | pr_err("Couldn't map the %s clock registers\n", node->name); | ||
| 287 | return; | ||
| 288 | } | ||
| 304 | 289 | ||
| 305 | if (of_property_read_string(node, "clock-output-names", &init.name)) | 290 | clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL); |
| 306 | init.name = node->name; | 291 | if (!clk_data) |
| 292 | return; | ||
| 307 | 293 | ||
| 308 | clk = clk_register(NULL, &phase->hw); | 294 | clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL); |
| 309 | if (IS_ERR(clk)) | 295 | if (!clk_data->clks) |
| 310 | goto err_unmap; | 296 | goto err_free_data; |
| 297 | |||
| 298 | clk_data->clk_num = 3; | ||
| 299 | clk_data->clks[0] = sunxi_factors_register(node, | ||
| 300 | &sun4i_a10_mod0_data, | ||
| 301 | &sun4i_a10_mmc_lock, reg); | ||
| 302 | if (!clk_data->clks[0]) | ||
| 303 | goto err_free_clks; | ||
| 304 | |||
| 305 | parent = __clk_get_name(clk_data->clks[0]); | ||
| 306 | |||
| 307 | for (i = 1; i < 3; i++) { | ||
| 308 | struct clk_init_data init = { | ||
| 309 | .num_parents = 1, | ||
| 310 | .parent_names = &parent, | ||
| 311 | .ops = &mmc_clk_ops, | ||
| 312 | }; | ||
| 313 | struct mmc_phase *phase; | ||
| 314 | |||
| 315 | phase = kmalloc(sizeof(*phase), GFP_KERNEL); | ||
| 316 | if (!phase) | ||
| 317 | continue; | ||
| 318 | |||
| 319 | phase->hw.init = &init; | ||
| 320 | phase->reg = reg; | ||
| 321 | phase->lock = &sun4i_a10_mmc_lock; | ||
| 322 | |||
| 323 | if (i == 1) | ||
| 324 | phase->offset = 8; | ||
| 325 | else | ||
| 326 | phase->offset = 20; | ||
| 327 | |||
| 328 | if (of_property_read_string_index(node, "clock-output-names", | ||
| 329 | i, &init.name)) | ||
| 330 | init.name = node->name; | ||
| 331 | |||
| 332 | clk_data->clks[i] = clk_register(NULL, &phase->hw); | ||
| 333 | if (IS_ERR(clk_data->clks[i])) { | ||
| 334 | kfree(phase); | ||
| 335 | continue; | ||
| 336 | } | ||
| 337 | } | ||
| 311 | 338 | ||
| 312 | of_clk_add_provider(node, of_clk_src_simple_get, clk); | 339 | of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); |
| 313 | 340 | ||
| 314 | return; | 341 | return; |
| 315 | 342 | ||
| 316 | err_unmap: | 343 | err_free_clks: |
| 317 | iounmap(phase->reg); | 344 | kfree(clk_data->clks); |
| 318 | err_free: | 345 | err_free_data: |
| 319 | kfree(phase); | 346 | kfree(clk_data); |
| 320 | } | ||
| 321 | |||
| 322 | |||
| 323 | static struct mmc_phase_data mmc_output_clk = { | ||
| 324 | .offset = 8, | ||
| 325 | }; | ||
| 326 | |||
| 327 | static struct mmc_phase_data mmc_sample_clk = { | ||
| 328 | .offset = 20, | ||
| 329 | }; | ||
| 330 | |||
| 331 | static void __init sun4i_a10_mmc_output_setup(struct device_node *node) | ||
| 332 | { | ||
| 333 | sun4i_a10_mmc_phase_setup(node, &mmc_output_clk); | ||
| 334 | } | ||
| 335 | CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup); | ||
| 336 | |||
| 337 | static void __init sun4i_a10_mmc_sample_setup(struct device_node *node) | ||
| 338 | { | ||
| 339 | sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk); | ||
| 340 | } | 347 | } |
| 341 | CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup); | 348 | CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup); |
