/* * clkt_clksel.c - OMAP2/3/4 clksel clock functions * * Copyright (C) 2005-2008 Texas Instruments, Inc. * Copyright (C) 2004-2010 Nokia Corporation * * Contacts: * Richard Woodruff * Paul Walmsley * * 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. * * * clksel clocks are clocks that do not have a fixed parent, or that * can divide their parent's rate, or possibly both at the same time, based * on the contents of a hardware register bitfield. * * All of the various mux and divider settings can be encoded into * struct clksel* data structures, and then these can be autogenerated * from some hardware database for each new chip generation. This * should avoid the need to write, review, and validate a lot of new * clock code for each new chip, since it can be exported from the SoC * design flow. This is now done on OMAP4. * * The fusion of mux and divider clocks is a software creation. In * hardware reality, the multiplexer (parent selection) and the * divider exist separately. XXX At some point these clksel clocks * should be split into "divider" clocks and "mux" clocks to better * match the hardware. * * (The name "clksel" comes from the name of the corresponding * register field in the OMAP2/3 family of SoCs.) * * XXX Currently these clocks are only used in the OMAP2/3/4 code, but * many of the OMAP1 clocks should be convertible to use this * mechanism. */ #undef DEBUG #include #include #include #include #include #include "clock.h" /* Private functions */ /** * _get_clksel_by_parent() - return clksel struct for a given clk & parent * @clk: OMAP struct clk ptr to inspect * @src_clk: OMAP struct clk ptr of the parent clk to search for * * Scan the struct clksel array associated with the clock to find * the element associated with the supplied parent clock address. * Returns a pointer to the struct clksel on success or NULL on error. */ static const struct clksel *_get_clksel_by_parent(struct clk_hw_omap *clk, struct clk *src_clk) { const struct clksel *clks; if (!src_clk) return NULL; for (clks = clk->clksel; clks->parent; clks++) if (clks->parent == src_clk) break; /* Found the requested parent */ if (!clks->parent) { /* This indicates a data problem */ WARN(1, "clock: %s: could not find parent clock %s in clksel array\n", __clk_get_name(clk->hw.clk), __clk_get_name(src_clk)); return NULL; } return clks; } /** * _write_clksel_reg() - program a clock's clksel register in hardware * @clk: struct clk * to program * @v: clksel bitfield value to program (with LSB at bit 0) * * Shift the clksel register bitfield value @v to its appropriate * location in the clksel register and write it in. This function * will ensure that the write to the clksel_reg reaches its * destination before returning -- important since PRM and CM register * accesses can be quite slow compared to ARM cycles -- but does not