| /* |
| * arch/metag/kernel/clock.c |
| * |
| * Copyright (C) 2012 Imagination Technologies Ltd. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2 as |
| * published by the Free Software Foundation. |
| */ |
| |
| #include <linux/clk.h> |
| #include <linux/delay.h> |
| #include <linux/io.h> |
| #include <linux/of.h> |
| |
| #include <asm/param.h> |
| #include <asm/clock.h> |
| |
| struct meta_clock_desc _meta_clock; |
| |
| /* Default machine get_core_freq callback. */ |
| static unsigned long get_core_freq_default(void) |
| { |
| #ifdef CONFIG_METAG_META21 |
| /* |
| * Meta 2 cores divide down the core clock for the Meta timers, so we |
| * can estimate the core clock from the divider. |
| */ |
| return (metag_in32(EXPAND_TIMER_DIV) + 1) * 1000000; |
| #else |
| /* |
| * On Meta 1 we don't know the core clock, but assuming the Meta timer |
| * is correct it can be estimated based on loops_per_jiffy. |
| */ |
| return (loops_per_jiffy * HZ * 5) >> 1; |
| #endif |
| } |
| |
| static struct clk *clk_core; |
| |
| /* Clk based get_core_freq callback. */ |
| static unsigned long get_core_freq_clk(void) |
| { |
| return clk_get_rate(clk_core); |
| } |
| |
| /** |
| * init_metag_core_clock() - Set up core clock from devicetree. |
| * |
| * Checks to see if a "core" clock is provided in the device tree, and overrides |
| * the get_core_freq callback to use it. |
| */ |
| static void __init init_metag_core_clock(void) |
| { |
| /* |
| * See if a core clock is provided by the devicetree (and |
| * registered by the init callback above). |
| */ |
| struct device_node *node; |
| node = of_find_compatible_node(NULL, NULL, "img,meta"); |
| if (!node) { |
| pr_warn("%s: no compatible img,meta DT node found\n", |
| __func__); |
| return; |
| } |
| |
| clk_core = of_clk_get_by_name(node, "core"); |
| if (IS_ERR(clk_core)) { |
| pr_warn("%s: no core clock found in DT\n", |
| __func__); |
| return; |
| } |
| |
| /* |
| * Override the core frequency callback to use |
| * this clk. |
| */ |
| _meta_clock.get_core_freq = get_core_freq_clk; |
| } |
| |
| /** |
| * init_metag_clocks() - Set up clocks from devicetree. |
| * |
| * Set up important clocks from device tree. In particular any needed for clock |
| * sources. |
| */ |
| void __init init_metag_clocks(void) |
| { |
| init_metag_core_clock(); |
| |
| pr_info("Core clock frequency: %lu Hz\n", get_coreclock()); |
| } |
| |
| /** |
| * setup_meta_clocks() - Early set up of the Meta clock. |
| * @desc: Clock descriptor usually provided by machine description |
| * |
| * Ensures all callbacks are valid. |
| */ |
| void __init setup_meta_clocks(struct meta_clock_desc *desc) |
| { |
| /* copy callbacks */ |
| if (desc) |
| _meta_clock = *desc; |
| |
| /* set fallback functions */ |
| if (!_meta_clock.get_core_freq) |
| _meta_clock.get_core_freq = get_core_freq_default; |
| } |
| |