diff options
-rw-r--r-- | arch/arm/mach-tegra/clock.c | 126 | ||||
-rw-r--r-- | arch/arm/mach-tegra/clock.h | 90 | ||||
-rw-r--r-- | arch/arm/mach-tegra/common.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-tegra/include/mach/clk.h | 3 |
4 files changed, 210 insertions, 11 deletions
diff --git a/arch/arm/mach-tegra/clock.c b/arch/arm/mach-tegra/clock.c index 58f981c0819..ef9b494f961 100644 --- a/arch/arm/mach-tegra/clock.c +++ b/arch/arm/mach-tegra/clock.c @@ -1,6 +1,7 @@ /* * * Copyright (C) 2010 Google, Inc. + * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -62,6 +63,7 @@ static DEFINE_MUTEX(clock_list_lock); static LIST_HEAD(clocks); +#ifndef CONFIG_COMMON_CLK struct clk *tegra_get_clock_by_name(const char *name) { struct clk *c; @@ -668,5 +670,127 @@ err_out: debugfs_remove_recursive(clk_debugfs_root); return err; } - #endif +#else + +void tegra_clk_add(struct clk *clk) +{ + struct clk_tegra *c = to_clk_tegra(__clk_get_hw(clk)); + + mutex_lock(&clock_list_lock); + list_add(&c->node, &clocks); + mutex_unlock(&clock_list_lock); +} + +struct clk *tegra_get_clock_by_name(const char *name) +{ + struct clk_tegra *c; + struct clk *ret = NULL; + mutex_lock(&clock_list_lock); + list_for_each_entry(c, &clocks, node) { + if (strcmp(__clk_get_name(c->hw.clk), name) == 0) { + ret = c->hw.clk; + break; + } + } + mutex_unlock(&clock_list_lock); + return ret; +} + +static int tegra_clk_init_one_from_table(struct tegra_clk_init_table *table) +{ + struct clk *c; + struct clk *p; + struct clk *parent; + + int ret = 0; + + c = tegra_get_clock_by_name(table->name); + + if (!c) { + pr_warn("Unable to initialize clock %s\n", + table->name); + return -ENODEV; + } + + parent = clk_get_parent(c); + + if (table->parent) { + p = tegra_get_clock_by_name(table->parent); + if (!p) { + pr_warn("Unable to find parent %s of clock %s\n", + table->parent, table->name); + return -ENODEV; + } + + if (parent != p) { + ret = clk_set_parent(c, p); + if (ret) { + pr_warn("Unable to set parent %s of clock %s: %d\n", + table->parent, table->name, ret); + return -EINVAL; + } + } + } + + if (table->rate && table->rate != clk_get_rate(c)) { + ret = clk_set_rate(c, table->rate); + if (ret) { + pr_warn("Unable to set clock %s to rate %lu: %d\n", + table->name, table->rate, ret); + return -EINVAL; + } + } + + if (table->enabled) { + ret = clk_prepare_enable(c); + if (ret) { + pr_warn("Unable to enable clock %s: %d\n", + table->name, ret); + return -EINVAL; + } + } + + return 0; +} + +void tegra_clk_init_from_table(struct tegra_clk_init_table *table) +{ + for (; table->name; table++) + tegra_clk_init_one_from_table(table); +} + +void tegra_periph_reset_deassert(struct clk *c) +{ + struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); + BUG_ON(!clk->reset); + clk->reset(__clk_get_hw(c), false); +} +EXPORT_SYMBOL(tegra_periph_reset_deassert); + +void tegra_periph_reset_assert(struct clk *c) +{ + struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); + BUG_ON(!clk->reset); + clk->reset(__clk_get_hw(c), true); +} +EXPORT_SYMBOL(tegra_periph_reset_assert); + +/* Several extended clock configuration bits (e.g., clock routing, clock + * phase control) are included in PLL and peripheral clock source + * registers. */ +int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting) +{ + int ret = 0; + struct clk_tegra *clk = to_clk_tegra(__clk_get_hw(c)); + + if (!clk->clk_cfg_ex) { + ret = -ENOSYS; + goto out; + } + ret = clk->clk_cfg_ex(__clk_get_hw(c), p, setting); + +out: + return ret; +} +#endif /* !CONFIG_COMMON_CLK */ diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index bc300657deb..f4d32ba5602 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -2,6 +2,7 @@ * arch/arm/mach-tegra/include/mach/clock.h * * Copyright (C) 2010 Google, Inc. + * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. * * Author: * Colin Cross <ccross@google.com> @@ -20,6 +21,7 @@ #ifndef __MACH_TEGRA_CLOCK_H #define __MACH_TEGRA_CLOCK_H +#include <linux/clk-provider.h> #include <linux/clkdev.h> #include <linux/list.h> #include <linux/spinlock.h> @@ -54,6 +56,11 @@ struct clk; +#ifdef CONFIG_COMMON_CLK +struct clk_tegra; +#define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw) +#endif + struct clk_mux_sel { struct clk *input; u32 value; @@ -68,6 +75,13 @@ struct clk_pll_freq_table { u8 cpcon; }; +enum clk_state { + UNINITIALIZED = 0, + ON, + OFF, +}; + +#ifndef CONFIG_COMMON_CLK struct clk_ops { void (*init)(struct clk *); int (*enable)(struct clk *); @@ -80,12 +94,6 @@ struct clk_ops { enum tegra_clk_ex_param, u32); }; -enum clk_state { - UNINITIALIZED = 0, - ON, - OFF, -}; - struct clk { /* node for master clocks list */ struct list_head node; /* node for list of all clocks */ @@ -147,6 +155,65 @@ struct clk { spinlock_t spinlock; }; +#else + +struct clk_tegra { + /* node for master clocks list */ + struct list_head node; /* node for list of all clocks */ + struct clk_lookup lookup; + struct clk_hw hw; + + bool set; + unsigned long fixed_rate; + unsigned long max_rate; + unsigned long min_rate; + u32 flags; + const char *name; + + enum clk_state state; + u32 div; + u32 mul; + + u32 reg; + u32 reg_shift; + + struct list_head shared_bus_list; + + union { + struct { + unsigned int clk_num; + } periph; + struct { + unsigned long input_min; + unsigned long input_max; + unsigned long cf_min; + unsigned long cf_max; + unsigned long vco_min; + unsigned long vco_max; + const struct clk_pll_freq_table *freq_table; + int lock_delay; + unsigned long fixed_rate; + } pll; + struct { + u32 sel; + u32 reg_mask; + } mux; + struct { + struct clk *main; + struct clk *backup; + } cpu; + struct { + struct list_head node; + bool enabled; + unsigned long rate; + } shared_bus_user; + } u; + + void (*reset)(struct clk_hw *, bool); + int (*clk_cfg_ex)(struct clk_hw *, enum tegra_clk_ex_param, u32); +}; +#endif /* !CONFIG_COMMON_CLK */ + struct clk_duplicate { const char *name; struct clk_lookup lookup; @@ -159,13 +226,16 @@ struct tegra_clk_init_table { bool enabled; }; +#ifndef CONFIG_COMMON_CLK +void clk_init(struct clk *clk); +unsigned long clk_get_rate_locked(struct clk *c); +int clk_set_rate_locked(struct clk *c, unsigned long rate); +int clk_reparent(struct clk *c, struct clk *parent); +#endif /* !CONFIG_COMMON_CLK */ + void tegra2_init_clocks(void); void tegra30_init_clocks(void); -void clk_init(struct clk *clk); struct clk *tegra_get_clock_by_name(const char *name); -int clk_reparent(struct clk *c, struct clk *parent); void tegra_clk_init_from_table(struct tegra_clk_init_table *table); -unsigned long clk_get_rate_locked(struct clk *c); -int clk_set_rate_locked(struct clk *c, unsigned long rate); #endif diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c index 96fef6bcc65..ef7d6f3cff8 100644 --- a/arch/arm/mach-tegra/common.c +++ b/arch/arm/mach-tegra/common.c @@ -152,6 +152,8 @@ void __init tegra30_init_early(void) void __init tegra_init_late(void) { +#ifndef CONFIG_COMMON_CLK tegra_clk_debugfs_init(); +#endif tegra_powergate_debugfs_init(); } diff --git a/arch/arm/mach-tegra/include/mach/clk.h b/arch/arm/mach-tegra/include/mach/clk.h index d97e403303a..95f3a547c77 100644 --- a/arch/arm/mach-tegra/include/mach/clk.h +++ b/arch/arm/mach-tegra/include/mach/clk.h @@ -34,7 +34,10 @@ enum tegra_clk_ex_param { void tegra_periph_reset_deassert(struct clk *c); void tegra_periph_reset_assert(struct clk *c); +#ifndef CONFIG_COMMON_CLK unsigned long clk_get_rate_all_locked(struct clk *c); +#endif + void tegra2_sdmmc_tap_delay(struct clk *c, int delay); int tegra_clk_cfg_ex(struct clk *c, enum tegra_clk_ex_param p, u32 setting); |