123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- /*
- *
- * Copyright (C) 2010 Google, Inc.
- * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved.
- *
- * Author:
- * Colin Cross <ccross@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * 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/kernel.h>
- #include <linux/clk.h>
- #include <linux/clkdev.h>
- #include <linux/init.h>
- #include <linux/list.h>
- #include <linux/module.h>
- #include <linux/sched.h>
- #include <linux/seq_file.h>
- #include <linux/slab.h>
- #include "board.h"
- #include "clock.h"
- #include "tegra_cpu_car.h"
- /* Global data of Tegra CPU CAR ops */
- struct tegra_cpu_car_ops *tegra_cpu_car_ops;
- /*
- * Locking:
- *
- * An additional mutex, clock_list_lock, is used to protect the list of all
- * clocks.
- *
- */
- static DEFINE_MUTEX(clock_list_lock);
- static LIST_HEAD(clocks);
- 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;
- }
|