|  | @@ -0,0 +1,92 @@
 | 
	
		
			
				|  |  | +/*
 | 
	
		
			
				|  |  | + * 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 <r-woodruff2@ti.com>
 | 
	
		
			
				|  |  | + * 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 <linux/kernel.h>
 | 
	
		
			
				|  |  | +#include <linux/errno.h>
 | 
	
		
			
				|  |  | +#include <linux/clk-provider.h>
 | 
	
		
			
				|  |  | +#include <linux/io.h>
 | 
	
		
			
				|  |  | +#include <linux/bug.h>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +#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
 |