|
@@ -26,6 +26,8 @@
|
|
#include "clk.h"
|
|
#include "clk.h"
|
|
#include "clk-id.h"
|
|
#include "clk-id.h"
|
|
|
|
|
|
|
|
+#define MISC_CLK_ENB 0x48
|
|
|
|
+
|
|
#define OSC_CTRL 0x50
|
|
#define OSC_CTRL 0x50
|
|
#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
|
|
#define OSC_CTRL_OSC_FREQ_MASK (3<<30)
|
|
#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
|
|
#define OSC_CTRL_OSC_FREQ_13MHZ (0<<30)
|
|
@@ -831,15 +833,25 @@ static void __init tegra20_periph_clk_init(void)
|
|
periph_clk_enb_refcnt);
|
|
periph_clk_enb_refcnt);
|
|
clks[TEGRA20_CLK_PEX] = clk;
|
|
clks[TEGRA20_CLK_PEX] = clk;
|
|
|
|
|
|
|
|
+ /* dev1 OSC divider */
|
|
|
|
+ clk_register_divider(NULL, "dev1_osc_div", "clk_m",
|
|
|
|
+ 0, clk_base + MISC_CLK_ENB, 22, 2,
|
|
|
|
+ CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_READ_ONLY,
|
|
|
|
+ NULL);
|
|
|
|
+
|
|
|
|
+ /* dev2 OSC divider */
|
|
|
|
+ clk_register_divider(NULL, "dev2_osc_div", "clk_m",
|
|
|
|
+ 0, clk_base + MISC_CLK_ENB, 20, 2,
|
|
|
|
+ CLK_DIVIDER_POWER_OF_TWO | CLK_DIVIDER_READ_ONLY,
|
|
|
|
+ NULL);
|
|
|
|
+
|
|
/* cdev1 */
|
|
/* cdev1 */
|
|
- clk = clk_register_fixed_rate(NULL, "cdev1_fixed", NULL, 0, 26000000);
|
|
|
|
- clk = tegra_clk_register_periph_gate("cdev1", "cdev1_fixed", 0,
|
|
|
|
|
|
+ clk = tegra_clk_register_periph_gate("cdev1", "cdev1_mux", 0,
|
|
clk_base, 0, 94, periph_clk_enb_refcnt);
|
|
clk_base, 0, 94, periph_clk_enb_refcnt);
|
|
clks[TEGRA20_CLK_CDEV1] = clk;
|
|
clks[TEGRA20_CLK_CDEV1] = clk;
|
|
|
|
|
|
/* cdev2 */
|
|
/* cdev2 */
|
|
- clk = clk_register_fixed_rate(NULL, "cdev2_fixed", NULL, 0, 26000000);
|
|
|
|
- clk = tegra_clk_register_periph_gate("cdev2", "cdev2_fixed", 0,
|
|
|
|
|
|
+ clk = tegra_clk_register_periph_gate("cdev2", "cdev2_mux", 0,
|
|
clk_base, 0, 93, periph_clk_enb_refcnt);
|
|
clk_base, 0, 93, periph_clk_enb_refcnt);
|
|
clks[TEGRA20_CLK_CDEV2] = clk;
|
|
clks[TEGRA20_CLK_CDEV2] = clk;
|
|
|
|
|
|
@@ -1077,6 +1089,36 @@ static const struct of_device_id pmc_match[] __initconst = {
|
|
{ },
|
|
{ },
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static struct clk *tegra20_clk_src_onecell_get(struct of_phandle_args *clkspec,
|
|
|
|
+ void *data)
|
|
|
|
+{
|
|
|
|
+ struct clk_hw *parent_hw;
|
|
|
|
+ struct clk_hw *hw;
|
|
|
|
+ struct clk *clk;
|
|
|
|
+
|
|
|
|
+ clk = of_clk_src_onecell_get(clkspec, data);
|
|
|
|
+ if (IS_ERR(clk))
|
|
|
|
+ return clk;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Tegra20 CDEV1 and CDEV2 clocks are a bit special case, their parent
|
|
|
|
+ * clock is created by the pinctrl driver. It is possible for clk user
|
|
|
|
+ * to request these clocks before pinctrl driver got probed and hence
|
|
|
|
+ * user will get an orphaned clock. That might be undesirable because
|
|
|
|
+ * user may expect parent clock to be enabled by the child.
|
|
|
|
+ */
|
|
|
|
+ if (clkspec->args[0] == TEGRA20_CLK_CDEV1 ||
|
|
|
|
+ clkspec->args[0] == TEGRA20_CLK_CDEV2) {
|
|
|
|
+ hw = __clk_get_hw(clk);
|
|
|
|
+
|
|
|
|
+ parent_hw = clk_hw_get_parent(hw);
|
|
|
|
+ if (!parent_hw)
|
|
|
|
+ return ERR_PTR(-EPROBE_DEFER);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return clk;
|
|
|
|
+}
|
|
|
|
+
|
|
static void __init tegra20_clock_init(struct device_node *np)
|
|
static void __init tegra20_clock_init(struct device_node *np)
|
|
{
|
|
{
|
|
struct device_node *node;
|
|
struct device_node *node;
|
|
@@ -1115,7 +1157,7 @@ static void __init tegra20_clock_init(struct device_node *np)
|
|
|
|
|
|
tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX);
|
|
tegra_init_dup_clks(tegra_clk_duplicates, clks, TEGRA20_CLK_CLK_MAX);
|
|
|
|
|
|
- tegra_add_of_provider(np);
|
|
|
|
|
|
+ tegra_add_of_provider(np, tegra20_clk_src_onecell_get);
|
|
tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
|
|
tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
|
|
|
|
|
|
tegra_clk_apply_init_table = tegra20_clock_apply_init_table;
|
|
tegra_clk_apply_init_table = tegra20_clock_apply_init_table;
|