-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'sunxi-clk-for-3.16-2' of https://github.com/mripard/linux …
…into clk-next Rebase of Emilio's clk-sunxi-for-3.16 on top of clk-next Fixed a few compilation warnings exposed by a patch introduced during the 3.16 merge window. Original tag message: Allwinner sunXi SoCs clock changes This pull contains some new code to add support for A31 clocks by Maxime and Boris. It also reworks the driver a bit to avoid having a huge single file when we have a full folder for ourselves, and separating different functional units makes sense.
- Loading branch information
Showing
8 changed files
with
661 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
* Copyright 2013 Emilio López | ||
* | ||
* Emilio López <emilio@elopez.com.ar> | ||
* | ||
* 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-provider.h> | ||
#include <linux/clkdev.h> | ||
#include <linux/of.h> | ||
#include <linux/of_address.h> | ||
|
||
#define SUNXI_OSC24M_GATE 0 | ||
|
||
static DEFINE_SPINLOCK(hosc_lock); | ||
|
||
static void __init sun4i_osc_clk_setup(struct device_node *node) | ||
{ | ||
struct clk *clk; | ||
struct clk_fixed_rate *fixed; | ||
struct clk_gate *gate; | ||
const char *clk_name = node->name; | ||
u32 rate; | ||
|
||
if (of_property_read_u32(node, "clock-frequency", &rate)) | ||
return; | ||
|
||
/* allocate fixed-rate and gate clock structs */ | ||
fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); | ||
if (!fixed) | ||
return; | ||
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
if (!gate) | ||
goto err_free_fixed; | ||
|
||
of_property_read_string(node, "clock-output-names", &clk_name); | ||
|
||
/* set up gate and fixed rate properties */ | ||
gate->reg = of_iomap(node, 0); | ||
gate->bit_idx = SUNXI_OSC24M_GATE; | ||
gate->lock = &hosc_lock; | ||
fixed->fixed_rate = rate; | ||
|
||
clk = clk_register_composite(NULL, clk_name, | ||
NULL, 0, | ||
NULL, NULL, | ||
&fixed->hw, &clk_fixed_rate_ops, | ||
&gate->hw, &clk_gate_ops, | ||
CLK_IS_ROOT); | ||
|
||
if (IS_ERR(clk)) | ||
goto err_free_gate; | ||
|
||
of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
clk_register_clkdev(clk, clk_name, NULL); | ||
|
||
return; | ||
|
||
err_free_gate: | ||
kfree(gate); | ||
err_free_fixed: | ||
kfree(fixed); | ||
} | ||
CLK_OF_DECLARE(sun4i_osc, "allwinner,sun4i-a10-osc-clk", sun4i_osc_clk_setup); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
/* | ||
* Copyright 2013 Emilio López | ||
* Emilio López <emilio@elopez.com.ar> | ||
* | ||
* Copyright 2013 Chen-Yu Tsai | ||
* Chen-Yu Tsai <wens@csie.org> | ||
* | ||
* 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-provider.h> | ||
#include <linux/clkdev.h> | ||
#include <linux/of.h> | ||
#include <linux/of_address.h> | ||
#include <linux/slab.h> | ||
|
||
static DEFINE_SPINLOCK(gmac_lock); | ||
|
||
/** | ||
* sun7i_a20_gmac_clk_setup - Setup function for A20/A31 GMAC clock module | ||
* | ||
* This clock looks something like this | ||
* ________________________ | ||
* MII TX clock from PHY >-----|___________ _________|----> to GMAC core | ||
* GMAC Int. RGMII TX clk >----|___________\__/__gate---|----> to PHY | ||
* Ext. 125MHz RGMII TX clk >--|__divider__/ | | ||
* |________________________| | ||
* | ||
* The external 125 MHz reference is optional, i.e. GMAC can use its | ||
* internal TX clock just fine. The A31 GMAC clock module does not have | ||
* the divider controls for the external reference. | ||
* | ||
* To keep it simple, let the GMAC use either the MII TX clock for MII mode, | ||
* and its internal TX clock for GMII and RGMII modes. The GMAC driver should | ||
* select the appropriate source and gate/ungate the output to the PHY. | ||
* | ||
* Only the GMAC should use this clock. Altering the clock so that it doesn't | ||
* match the GMAC's operation parameters will result in the GMAC not being | ||
* able to send traffic out. The GMAC driver should set the clock rate and | ||
* enable/disable this clock to configure the required state. The clock | ||
* driver then responds by auto-reparenting the clock. | ||
*/ | ||
|
||
#define SUN7I_A20_GMAC_GPIT 2 | ||
#define SUN7I_A20_GMAC_MASK 0x3 | ||
#define SUN7I_A20_GMAC_PARENTS 2 | ||
|
||
static void __init sun7i_a20_gmac_clk_setup(struct device_node *node) | ||
{ | ||
struct clk *clk; | ||
struct clk_mux *mux; | ||
struct clk_gate *gate; | ||
const char *clk_name = node->name; | ||
const char *parents[SUN7I_A20_GMAC_PARENTS]; | ||
void *reg; | ||
|
||
if (of_property_read_string(node, "clock-output-names", &clk_name)) | ||
return; | ||
|
||
/* allocate mux and gate clock structs */ | ||
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); | ||
if (!mux) | ||
return; | ||
|
||
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); | ||
if (!gate) | ||
goto free_mux; | ||
|
||
/* gmac clock requires exactly 2 parents */ | ||
parents[0] = of_clk_get_parent_name(node, 0); | ||
parents[1] = of_clk_get_parent_name(node, 1); | ||
if (!parents[0] || !parents[1]) | ||
goto free_gate; | ||
|
||
reg = of_iomap(node, 0); | ||
if (!reg) | ||
goto free_gate; | ||
|
||
/* set up gate and fixed rate properties */ | ||
gate->reg = reg; | ||
gate->bit_idx = SUN7I_A20_GMAC_GPIT; | ||
gate->lock = &gmac_lock; | ||
mux->reg = reg; | ||
mux->mask = SUN7I_A20_GMAC_MASK; | ||
mux->flags = CLK_MUX_INDEX_BIT; | ||
mux->lock = &gmac_lock; | ||
|
||
clk = clk_register_composite(NULL, clk_name, | ||
parents, SUN7I_A20_GMAC_PARENTS, | ||
&mux->hw, &clk_mux_ops, | ||
NULL, NULL, | ||
&gate->hw, &clk_gate_ops, | ||
0); | ||
|
||
if (IS_ERR(clk)) | ||
goto iounmap_reg; | ||
|
||
of_clk_add_provider(node, of_clk_src_simple_get, clk); | ||
clk_register_clkdev(clk, clk_name, NULL); | ||
|
||
return; | ||
|
||
iounmap_reg: | ||
iounmap(reg); | ||
free_gate: | ||
kfree(gate); | ||
free_mux: | ||
kfree(mux); | ||
} | ||
CLK_OF_DECLARE(sun7i_a20_gmac, "allwinner,sun7i-a20-gmac-clk", | ||
sun7i_a20_gmac_clk_setup); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
/* | ||
* Copyright (C) 2014 Free Electrons | ||
* | ||
* License Terms: GNU General Public License v2 | ||
* Author: Boris BREZILLON <boris.brezillon@free-electrons.com> | ||
* | ||
* Allwinner A31 APB0 clock gates driver | ||
* | ||
*/ | ||
|
||
#include <linux/clk-provider.h> | ||
#include <linux/module.h> | ||
#include <linux/of.h> | ||
#include <linux/platform_device.h> | ||
|
||
#define SUN6I_APB0_GATES_MAX_SIZE 32 | ||
|
||
static int sun6i_a31_apb0_gates_clk_probe(struct platform_device *pdev) | ||
{ | ||
struct device_node *np = pdev->dev.of_node; | ||
struct clk_onecell_data *clk_data; | ||
const char *clk_parent; | ||
const char *clk_name; | ||
struct resource *r; | ||
void __iomem *reg; | ||
int gate_id; | ||
int ngates; | ||
int i; | ||
|
||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
reg = devm_ioremap_resource(&pdev->dev, r); | ||
if (!reg) | ||
return PTR_ERR(reg); | ||
|
||
clk_parent = of_clk_get_parent_name(np, 0); | ||
if (!clk_parent) | ||
return -EINVAL; | ||
|
||
ngates = of_property_count_strings(np, "clock-output-names"); | ||
if (ngates < 0) | ||
return ngates; | ||
|
||
if (!ngates || ngates > SUN6I_APB0_GATES_MAX_SIZE) | ||
return -EINVAL; | ||
|
||
clk_data = devm_kzalloc(&pdev->dev, sizeof(struct clk_onecell_data), | ||
GFP_KERNEL); | ||
if (!clk_data) | ||
return -ENOMEM; | ||
|
||
clk_data->clks = devm_kzalloc(&pdev->dev, | ||
SUN6I_APB0_GATES_MAX_SIZE * | ||
sizeof(struct clk *), | ||
GFP_KERNEL); | ||
if (!clk_data->clks) | ||
return -ENOMEM; | ||
|
||
for (i = 0; i < ngates; i++) { | ||
of_property_read_string_index(np, "clock-output-names", | ||
i, &clk_name); | ||
|
||
gate_id = i; | ||
of_property_read_u32_index(np, "clock-indices", i, &gate_id); | ||
|
||
WARN_ON(gate_id >= SUN6I_APB0_GATES_MAX_SIZE); | ||
if (gate_id >= SUN6I_APB0_GATES_MAX_SIZE) | ||
continue; | ||
|
||
clk_data->clks[gate_id] = clk_register_gate(&pdev->dev, | ||
clk_name, | ||
clk_parent, 0, | ||
reg, gate_id, | ||
0, NULL); | ||
WARN_ON(IS_ERR(clk_data->clks[gate_id])); | ||
} | ||
|
||
clk_data->clk_num = ngates; | ||
|
||
return of_clk_add_provider(np, of_clk_src_onecell_get, clk_data); | ||
} | ||
|
||
const struct of_device_id sun6i_a31_apb0_gates_clk_dt_ids[] = { | ||
{ .compatible = "allwinner,sun6i-a31-apb0-gates-clk" }, | ||
{ /* sentinel */ } | ||
}; | ||
|
||
static struct platform_driver sun6i_a31_apb0_gates_clk_driver = { | ||
.driver = { | ||
.name = "sun6i-a31-apb0-gates-clk", | ||
.owner = THIS_MODULE, | ||
.of_match_table = sun6i_a31_apb0_gates_clk_dt_ids, | ||
}, | ||
.probe = sun6i_a31_apb0_gates_clk_probe, | ||
}; | ||
module_platform_driver(sun6i_a31_apb0_gates_clk_driver); | ||
|
||
MODULE_AUTHOR("Boris BREZILLON <boris.brezillon@free-electrons.com>"); | ||
MODULE_DESCRIPTION("Allwinner A31 APB0 gate clocks driver"); | ||
MODULE_LICENSE("GPL v2"); |
Oops, something went wrong.