Most machine classes want some way to register a block of clk_lookup structures, and most do it by implementing a clks_register() type function which walks an array, or by open-coding a loop. Consolidate all this into clkdev_add_table(). Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com> Reviewed-by: Kevin Hilman <khilman@deeprootsystems.com> Acked-by: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
		
			
				
	
	
		
			640 lines
		
	
	
	
		
			14 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			640 lines
		
	
	
	
		
			14 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
#include <linux/clk.h>
 | 
						|
#include <linux/kernel.h>
 | 
						|
#include <linux/init.h>
 | 
						|
#include <linux/io.h>
 | 
						|
 | 
						|
#include <mach/clock.h>
 | 
						|
#include <mach/hardware.h>
 | 
						|
#include <mach/common.h>
 | 
						|
 | 
						|
#include <asm/clkdev.h>
 | 
						|
#include <asm/bug.h>
 | 
						|
#include <asm/div64.h>
 | 
						|
 | 
						|
#include "crm_regs.h"
 | 
						|
 | 
						|
#define CRM_SMALL_DIVIDER(base, name) \
 | 
						|
	crm_small_divider(base, \
 | 
						|
			  base ## _ ## name ## _OFFSET, \
 | 
						|
			  base ## _ ## name ## _MASK)
 | 
						|
#define CRM_1DIVIDER(base, name) \
 | 
						|
	crm_divider(base, \
 | 
						|
		    base ## _ ## name ## _OFFSET, \
 | 
						|
		    base ## _ ## name ## _MASK, 1)
 | 
						|
#define CRM_16DIVIDER(base, name) \
 | 
						|
	crm_divider(base, \
 | 
						|
		    base ## _ ## name ## _OFFSET, \
 | 
						|
		    base ## _ ## name ## _MASK, 16)
 | 
						|
 | 
						|
static u32 crm_small_divider(void __iomem *reg, u8 offset, u32 mask)
 | 
						|
{
 | 
						|
	static const u32 crm_small_dividers[] = {
 | 
						|
		2, 3, 4, 5, 6, 8, 10, 12
 | 
						|
	};
 | 
						|
	u8 idx;
 | 
						|
 | 
						|
	idx = (__raw_readl(reg) & mask) >> offset;
 | 
						|
	if (idx > 7)
 | 
						|
		return 1;
 | 
						|
 | 
						|
	return crm_small_dividers[idx];
 | 
						|
}
 | 
						|
 | 
						|
static u32 crm_divider(void __iomem *reg, u8 offset, u32 mask, u32 z)
 | 
						|
{
 | 
						|
	u32 div;
 | 
						|
	div = (__raw_readl(reg) & mask) >> offset;
 | 
						|
	return div ? div : z;
 | 
						|
}
 | 
						|
 | 
						|
static int _clk_1bit_enable(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 reg;
 | 
						|
 | 
						|
	reg = __raw_readl(clk->enable_reg);
 | 
						|
	reg |= 1 << clk->enable_shift;
 | 
						|
	__raw_writel(reg, clk->enable_reg);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void _clk_1bit_disable(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 reg;
 | 
						|
 | 
						|
	reg = __raw_readl(clk->enable_reg);
 | 
						|
	reg &= ~(1 << clk->enable_shift);
 | 
						|
	__raw_writel(reg, clk->enable_reg);
 | 
						|
}
 | 
						|
 | 
						|
static int _clk_3bit_enable(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 reg;
 | 
						|
 | 
						|
	reg = __raw_readl(clk->enable_reg);
 | 
						|
	reg |= 0x7 << clk->enable_shift;
 | 
						|
	__raw_writel(reg, clk->enable_reg);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void _clk_3bit_disable(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 reg;
 | 
						|
 | 
						|
	reg = __raw_readl(clk->enable_reg);
 | 
						|
	reg &= ~(0x7 << clk->enable_shift);
 | 
						|
	__raw_writel(reg, clk->enable_reg);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned long ckih_rate;
 | 
						|
 | 
						|
static unsigned long clk_ckih_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return ckih_rate;
 | 
						|
}
 | 
						|
 | 
						|
static struct clk ckih_clk = {
 | 
						|
	.get_rate = clk_ckih_get_rate,
 | 
						|
};
 | 
						|
 | 
						|
static unsigned long clk_ckih_x2_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return 2 * clk_get_rate(clk->parent);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk ckih_x2_clk = {
 | 
						|
	.parent = &ckih_clk,
 | 
						|
	.get_rate = clk_ckih_x2_get_rate,
 | 
						|
};
 | 
						|
 | 
						|
static unsigned long clk_ckil_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return CKIL_CLK_FREQ;
 | 
						|
}
 | 
						|
 | 
						|
static struct clk ckil_clk = {
 | 
						|
	.get_rate = clk_ckil_get_rate,
 | 
						|
};
 | 
						|
 | 
						|
/* plls stuff */
 | 
						|
static struct clk mcu_pll_clk;
 | 
						|
static struct clk dsp_pll_clk;
 | 
						|
static struct clk usb_pll_clk;
 | 
						|
 | 
						|
static struct clk *pll_clk(u8 sel)
 | 
						|
{
 | 
						|
	switch (sel) {
 | 
						|
	case 0:
 | 
						|
		return &mcu_pll_clk;
 | 
						|
	case 1:
 | 
						|
		return &dsp_pll_clk;
 | 
						|
	case 2:
 | 
						|
		return &usb_pll_clk;
 | 
						|
	}
 | 
						|
	BUG();
 | 
						|
}
 | 
						|
 | 
						|
static void __iomem *pll_base(struct clk *clk)
 | 
						|
{
 | 
						|
	if (clk == &mcu_pll_clk)
 | 
						|
		return MXC_PLL0_BASE;
 | 
						|
	else if (clk == &dsp_pll_clk)
 | 
						|
		return MXC_PLL1_BASE;
 | 
						|
	else if (clk == &usb_pll_clk)
 | 
						|
		return MXC_PLL2_BASE;
 | 
						|
	BUG();
 | 
						|
}
 | 
						|
 | 
						|
static unsigned long clk_pll_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	const void __iomem *pllbase;
 | 
						|
	unsigned long dp_op, dp_mfd, dp_mfn, pll_hfsm, ref_clk, mfi;
 | 
						|
	long mfn, mfn_abs, mfd, pdf;
 | 
						|
	s64 temp;
 | 
						|
	pllbase = pll_base(clk);
 | 
						|
 | 
						|
	pll_hfsm = __raw_readl(pllbase + MXC_PLL_DP_CTL) & MXC_PLL_DP_CTL_HFSM;
 | 
						|
	if (pll_hfsm == 0) {
 | 
						|
		dp_op = __raw_readl(pllbase + MXC_PLL_DP_OP);
 | 
						|
		dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_MFD);
 | 
						|
		dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_MFN);
 | 
						|
	} else {
 | 
						|
		dp_op = __raw_readl(pllbase + MXC_PLL_DP_HFS_OP);
 | 
						|
		dp_mfd = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFD);
 | 
						|
		dp_mfn = __raw_readl(pllbase + MXC_PLL_DP_HFS_MFN);
 | 
						|
	}
 | 
						|
 | 
						|
	pdf = dp_op & MXC_PLL_DP_OP_PDF_MASK;
 | 
						|
	mfi = (dp_op >> MXC_PLL_DP_OP_MFI_OFFSET) & MXC_PLL_DP_OP_PDF_MASK;
 | 
						|
	mfi = (mfi <= 5) ? 5 : mfi;
 | 
						|
	mfd = dp_mfd & MXC_PLL_DP_MFD_MASK;
 | 
						|
	mfn = dp_mfn & MXC_PLL_DP_MFN_MASK;
 | 
						|
	mfn = (mfn <= 0x4000000) ? mfn : (mfn - 0x10000000);
 | 
						|
 | 
						|
	if (mfn < 0)
 | 
						|
		mfn_abs = -mfn;
 | 
						|
	else
 | 
						|
		mfn_abs = mfn;
 | 
						|
 | 
						|
/* XXX: actually this asumes that ckih is fed to pll, but spec says
 | 
						|
 * that ckih_x2 is also possible. need to check this out.
 | 
						|
 */
 | 
						|
	ref_clk = clk_get_rate(&ckih_clk);
 | 
						|
 | 
						|
	ref_clk *= 2;
 | 
						|
	ref_clk /= pdf + 1;
 | 
						|
 | 
						|
	temp = (u64) ref_clk * mfn_abs;
 | 
						|
	do_div(temp, mfd);
 | 
						|
	if (mfn < 0)
 | 
						|
		temp = -temp;
 | 
						|
	temp += ref_clk * mfi;
 | 
						|
 | 
						|
	return temp;
 | 
						|
}
 | 
						|
 | 
						|
static int clk_pll_enable(struct clk *clk)
 | 
						|
{
 | 
						|
	void __iomem *ctl;
 | 
						|
	u32 reg;
 | 
						|
 | 
						|
	ctl = pll_base(clk);
 | 
						|
	reg = __raw_readl(ctl);
 | 
						|
	reg |= (MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN);
 | 
						|
	__raw_writel(reg, ctl);
 | 
						|
	do {
 | 
						|
		reg = __raw_readl(ctl);
 | 
						|
	} while ((reg & MXC_PLL_DP_CTL_LRF) != MXC_PLL_DP_CTL_LRF);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void clk_pll_disable(struct clk *clk)
 | 
						|
{
 | 
						|
	void __iomem *ctl;
 | 
						|
	u32 reg;
 | 
						|
 | 
						|
	ctl = pll_base(clk);
 | 
						|
	reg = __raw_readl(ctl);
 | 
						|
	reg &= ~(MXC_PLL_DP_CTL_RST | MXC_PLL_DP_CTL_UPEN);
 | 
						|
	__raw_writel(reg, ctl);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk mcu_pll_clk = {
 | 
						|
	.parent = &ckih_clk,
 | 
						|
	.get_rate = clk_pll_get_rate,
 | 
						|
	.enable = clk_pll_enable,
 | 
						|
	.disable = clk_pll_disable,
 | 
						|
};
 | 
						|
 | 
						|
static struct clk dsp_pll_clk = {
 | 
						|
	.parent = &ckih_clk,
 | 
						|
	.get_rate = clk_pll_get_rate,
 | 
						|
	.enable = clk_pll_enable,
 | 
						|
	.disable = clk_pll_disable,
 | 
						|
};
 | 
						|
 | 
						|
static struct clk usb_pll_clk = {
 | 
						|
	.parent = &ckih_clk,
 | 
						|
	.get_rate = clk_pll_get_rate,
 | 
						|
	.enable = clk_pll_enable,
 | 
						|
	.disable = clk_pll_disable,
 | 
						|
};
 | 
						|
/* plls stuff end */
 | 
						|
 | 
						|
/* ap_ref_clk stuff */
 | 
						|
static struct clk ap_ref_clk;
 | 
						|
 | 
						|
static unsigned long clk_ap_ref_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 ascsr, acsr;
 | 
						|
	u8 ap_pat_ref_div_2, ap_isel, acs, ads;
 | 
						|
 | 
						|
	ascsr = __raw_readl(MXC_CRMAP_ASCSR);
 | 
						|
	acsr = __raw_readl(MXC_CRMAP_ACSR);
 | 
						|
 | 
						|
	/* 0 for ckih, 1 for ckih*2 */
 | 
						|
	ap_isel = ascsr & MXC_CRMAP_ASCSR_APISEL;
 | 
						|
	/* reg divider */
 | 
						|
	ap_pat_ref_div_2 = (ascsr >> MXC_CRMAP_ASCSR_AP_PATDIV2_OFFSET) & 0x1;
 | 
						|
	/* undocumented, 1 for disabling divider */
 | 
						|
	ads = (acsr >> MXC_CRMAP_ACSR_ADS_OFFSET) & 0x1;
 | 
						|
	/* 0 for pat_ref, 1 for divider out */
 | 
						|
	acs = acsr & MXC_CRMAP_ACSR_ACS;
 | 
						|
 | 
						|
	if (acs & !ads)
 | 
						|
		/* use divided clock */
 | 
						|
		return clk_get_rate(clk->parent) / (ap_pat_ref_div_2 ? 2 : 1);
 | 
						|
 | 
						|
	return clk_get_rate(clk->parent) * (ap_isel ? 2 : 1);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk ap_ref_clk = {
 | 
						|
	.parent = &ckih_clk,
 | 
						|
	.get_rate = clk_ap_ref_get_rate,
 | 
						|
};
 | 
						|
/* ap_ref_clk stuff end */
 | 
						|
 | 
						|
/* ap_pre_dfs_clk stuff */
 | 
						|
static struct clk ap_pre_dfs_clk;
 | 
						|
 | 
						|
static unsigned long clk_ap_pre_dfs_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 acsr, ascsr;
 | 
						|
 | 
						|
	acsr = __raw_readl(MXC_CRMAP_ACSR);
 | 
						|
	ascsr = __raw_readl(MXC_CRMAP_ASCSR);
 | 
						|
 | 
						|
	if (acsr & MXC_CRMAP_ACSR_ACS) {
 | 
						|
		u8 sel;
 | 
						|
		sel = (ascsr & MXC_CRMAP_ASCSR_APSEL_MASK) >>
 | 
						|
			MXC_CRMAP_ASCSR_APSEL_OFFSET;
 | 
						|
		return clk_get_rate(pll_clk(sel)) /
 | 
						|
			CRM_SMALL_DIVIDER(MXC_CRMAP_ACDR, ARMDIV);
 | 
						|
	}
 | 
						|
	return clk_get_rate(&ap_ref_clk);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk ap_pre_dfs_clk = {
 | 
						|
	.get_rate = clk_ap_pre_dfs_get_rate,
 | 
						|
};
 | 
						|
/* ap_pre_dfs_clk stuff end */
 | 
						|
 | 
						|
/* usb_clk stuff */
 | 
						|
static struct clk usb_clk;
 | 
						|
 | 
						|
static struct clk *clk_usb_parent(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 acsr, ascsr;
 | 
						|
 | 
						|
	acsr = __raw_readl(MXC_CRMAP_ACSR);
 | 
						|
	ascsr = __raw_readl(MXC_CRMAP_ASCSR);
 | 
						|
 | 
						|
	if (acsr & MXC_CRMAP_ACSR_ACS) {
 | 
						|
		u8 sel;
 | 
						|
		sel = (ascsr & MXC_CRMAP_ASCSR_USBSEL_MASK) >>
 | 
						|
			MXC_CRMAP_ASCSR_USBSEL_OFFSET;
 | 
						|
		return pll_clk(sel);
 | 
						|
	}
 | 
						|
	return &ap_ref_clk;
 | 
						|
}
 | 
						|
 | 
						|
static unsigned long clk_usb_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return clk_get_rate(clk->parent) /
 | 
						|
		CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, USBDIV);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk usb_clk = {
 | 
						|
	.enable_reg = MXC_CRMAP_ACDER2,
 | 
						|
	.enable_shift = MXC_CRMAP_ACDER2_USBEN_OFFSET,
 | 
						|
	.get_rate = clk_usb_get_rate,
 | 
						|
	.enable = _clk_1bit_enable,
 | 
						|
	.disable = _clk_1bit_disable,
 | 
						|
};
 | 
						|
/* usb_clk stuff end */
 | 
						|
 | 
						|
static unsigned long clk_ipg_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return clk_get_rate(clk->parent) / CRM_16DIVIDER(MXC_CRMAP_ACDR, IPDIV);
 | 
						|
}
 | 
						|
 | 
						|
static unsigned long clk_ahb_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return clk_get_rate(clk->parent) /
 | 
						|
		CRM_16DIVIDER(MXC_CRMAP_ACDR, AHBDIV);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk ipg_clk = {
 | 
						|
	.parent = &ap_pre_dfs_clk,
 | 
						|
	.get_rate = clk_ipg_get_rate,
 | 
						|
};
 | 
						|
 | 
						|
static struct clk ahb_clk = {
 | 
						|
	.parent = &ap_pre_dfs_clk,
 | 
						|
	.get_rate = clk_ahb_get_rate,
 | 
						|
};
 | 
						|
 | 
						|
/* perclk_clk stuff */
 | 
						|
static struct clk perclk_clk;
 | 
						|
 | 
						|
static unsigned long clk_perclk_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 acder2;
 | 
						|
 | 
						|
	acder2 = __raw_readl(MXC_CRMAP_ACDER2);
 | 
						|
	if (acder2 & MXC_CRMAP_ACDER2_BAUD_ISEL_MASK)
 | 
						|
		return 2 * clk_get_rate(clk->parent);
 | 
						|
 | 
						|
	return clk_get_rate(clk->parent);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk perclk_clk = {
 | 
						|
	.parent = &ckih_clk,
 | 
						|
	.get_rate = clk_perclk_get_rate,
 | 
						|
};
 | 
						|
/* perclk_clk stuff end */
 | 
						|
 | 
						|
/* uart_clk stuff */
 | 
						|
static struct clk uart_clk[];
 | 
						|
 | 
						|
static unsigned long clk_uart_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 div;
 | 
						|
 | 
						|
	switch (clk->id) {
 | 
						|
	case 0:
 | 
						|
	case 1:
 | 
						|
		div = CRM_SMALL_DIVIDER(MXC_CRMAP_ACDER2, BAUDDIV);
 | 
						|
		break;
 | 
						|
	case 2:
 | 
						|
		div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRA, UART3DIV);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		BUG();
 | 
						|
	}
 | 
						|
	return clk_get_rate(clk->parent) / div;
 | 
						|
}
 | 
						|
 | 
						|
static struct clk uart_clk[] = {
 | 
						|
	{
 | 
						|
		.id = 0,
 | 
						|
		.parent = &perclk_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_APRA,
 | 
						|
		.enable_shift = MXC_CRMAP_APRA_UART1EN_OFFSET,
 | 
						|
		.get_rate = clk_uart_get_rate,
 | 
						|
		.enable = _clk_1bit_enable,
 | 
						|
		.disable = _clk_1bit_disable,
 | 
						|
	}, {
 | 
						|
		.id = 1,
 | 
						|
		.parent = &perclk_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_APRA,
 | 
						|
		.enable_shift = MXC_CRMAP_APRA_UART2EN_OFFSET,
 | 
						|
		.get_rate = clk_uart_get_rate,
 | 
						|
		.enable = _clk_1bit_enable,
 | 
						|
		.disable = _clk_1bit_disable,
 | 
						|
	}, {
 | 
						|
		.id = 2,
 | 
						|
		.parent = &perclk_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_APRA,
 | 
						|
		.enable_shift = MXC_CRMAP_APRA_UART3EN_OFFSET,
 | 
						|
		.get_rate = clk_uart_get_rate,
 | 
						|
		.enable = _clk_1bit_enable,
 | 
						|
		.disable = _clk_1bit_disable,
 | 
						|
	},
 | 
						|
};
 | 
						|
/* uart_clk stuff end */
 | 
						|
 | 
						|
/* sdhc_clk stuff */
 | 
						|
static struct clk nfc_clk;
 | 
						|
 | 
						|
static unsigned long clk_nfc_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	return clk_get_rate(clk->parent) /
 | 
						|
		CRM_1DIVIDER(MXC_CRMAP_ACDER2, NFCDIV);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk nfc_clk = {
 | 
						|
	.parent = &ahb_clk,
 | 
						|
	.enable_reg = MXC_CRMAP_ACDER2,
 | 
						|
	.enable_shift = MXC_CRMAP_ACDER2_NFCEN_OFFSET,
 | 
						|
	.get_rate = clk_nfc_get_rate,
 | 
						|
	.enable = _clk_1bit_enable,
 | 
						|
	.disable = _clk_1bit_disable,
 | 
						|
};
 | 
						|
/* sdhc_clk stuff end */
 | 
						|
 | 
						|
/* sdhc_clk stuff */
 | 
						|
static struct clk sdhc_clk[];
 | 
						|
 | 
						|
static struct clk *clk_sdhc_parent(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 aprb;
 | 
						|
	u8 sel;
 | 
						|
	u32 mask;
 | 
						|
	int offset;
 | 
						|
 | 
						|
	aprb = __raw_readl(MXC_CRMAP_APRB);
 | 
						|
 | 
						|
	switch (clk->id) {
 | 
						|
	case 0:
 | 
						|
		mask = MXC_CRMAP_APRB_SDHC1_ISEL_MASK;
 | 
						|
		offset = MXC_CRMAP_APRB_SDHC1_ISEL_OFFSET;
 | 
						|
		break;
 | 
						|
	case 1:
 | 
						|
		mask = MXC_CRMAP_APRB_SDHC2_ISEL_MASK;
 | 
						|
		offset = MXC_CRMAP_APRB_SDHC2_ISEL_OFFSET;
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		BUG();
 | 
						|
	}
 | 
						|
	sel = (aprb & mask) >> offset;
 | 
						|
 | 
						|
	switch (sel) {
 | 
						|
	case 0:
 | 
						|
		return &ckih_clk;
 | 
						|
	case 1:
 | 
						|
		return &ckih_x2_clk;
 | 
						|
	}
 | 
						|
	return &usb_clk;
 | 
						|
}
 | 
						|
 | 
						|
static unsigned long clk_sdhc_get_rate(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 div;
 | 
						|
 | 
						|
	switch (clk->id) {
 | 
						|
	case 0:
 | 
						|
		div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC1_DIV);
 | 
						|
		break;
 | 
						|
	case 1:
 | 
						|
		div = CRM_SMALL_DIVIDER(MXC_CRMAP_APRB, SDHC2_DIV);
 | 
						|
		break;
 | 
						|
	default:
 | 
						|
		BUG();
 | 
						|
	}
 | 
						|
 | 
						|
	return clk_get_rate(clk->parent) / div;
 | 
						|
}
 | 
						|
 | 
						|
static int clk_sdhc_enable(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 amlpmre1, aprb;
 | 
						|
 | 
						|
	amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
 | 
						|
	aprb = __raw_readl(MXC_CRMAP_APRB);
 | 
						|
	switch (clk->id) {
 | 
						|
	case 0:
 | 
						|
		amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
 | 
						|
		aprb |= (0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
 | 
						|
		break;
 | 
						|
	case 1:
 | 
						|
		amlpmre1 |= (0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
 | 
						|
		aprb |= (0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	__raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
 | 
						|
	__raw_writel(aprb, MXC_CRMAP_APRB);
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
static void clk_sdhc_disable(struct clk *clk)
 | 
						|
{
 | 
						|
	u32 amlpmre1, aprb;
 | 
						|
 | 
						|
	amlpmre1 = __raw_readl(MXC_CRMAP_AMLPMRE1);
 | 
						|
	aprb = __raw_readl(MXC_CRMAP_APRB);
 | 
						|
	switch (clk->id) {
 | 
						|
	case 0:
 | 
						|
		amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME4_OFFSET);
 | 
						|
		aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC1EN_OFFSET);
 | 
						|
		break;
 | 
						|
	case 1:
 | 
						|
		amlpmre1 &= ~(0x7 << MXC_CRMAP_AMLPMRE1_MLPME5_OFFSET);
 | 
						|
		aprb &= ~(0x1 << MXC_CRMAP_APRB_SDHC2EN_OFFSET);
 | 
						|
		break;
 | 
						|
	}
 | 
						|
	__raw_writel(amlpmre1, MXC_CRMAP_AMLPMRE1);
 | 
						|
	__raw_writel(aprb, MXC_CRMAP_APRB);
 | 
						|
}
 | 
						|
 | 
						|
static struct clk sdhc_clk[] = {
 | 
						|
	{
 | 
						|
		.id = 0,
 | 
						|
		.get_rate = clk_sdhc_get_rate,
 | 
						|
		.enable = clk_sdhc_enable,
 | 
						|
		.disable = clk_sdhc_disable,
 | 
						|
	}, {
 | 
						|
		.id = 1,
 | 
						|
		.get_rate = clk_sdhc_get_rate,
 | 
						|
		.enable = clk_sdhc_enable,
 | 
						|
		.disable = clk_sdhc_disable,
 | 
						|
	},
 | 
						|
};
 | 
						|
/* sdhc_clk stuff end */
 | 
						|
 | 
						|
/* wdog_clk stuff */
 | 
						|
static struct clk wdog_clk[] = {
 | 
						|
	{
 | 
						|
		.id = 0,
 | 
						|
		.parent = &ipg_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_AMLPMRD,
 | 
						|
		.enable_shift = MXC_CRMAP_AMLPMRD_MLPMD7_OFFSET,
 | 
						|
		.enable = _clk_3bit_enable,
 | 
						|
		.disable = _clk_3bit_disable,
 | 
						|
	}, {
 | 
						|
		.id = 1,
 | 
						|
		.parent = &ipg_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_AMLPMRD,
 | 
						|
		.enable_shift = MXC_CRMAP_AMLPMRD_MLPMD3_OFFSET,
 | 
						|
		.enable = _clk_3bit_enable,
 | 
						|
		.disable = _clk_3bit_disable,
 | 
						|
	},
 | 
						|
};
 | 
						|
/* wdog_clk stuff end */
 | 
						|
 | 
						|
/* gpt_clk stuff */
 | 
						|
static struct clk gpt_clk = {
 | 
						|
	.parent = &ipg_clk,
 | 
						|
	.enable_reg = MXC_CRMAP_AMLPMRC,
 | 
						|
	.enable_shift = MXC_CRMAP_AMLPMRC_MLPMC4_OFFSET,
 | 
						|
	.enable = _clk_3bit_enable,
 | 
						|
	.disable = _clk_3bit_disable,
 | 
						|
};
 | 
						|
/* gpt_clk stuff end */
 | 
						|
 | 
						|
/* cspi_clk stuff */
 | 
						|
static struct clk cspi_clk[] = {
 | 
						|
	{
 | 
						|
		.id = 0,
 | 
						|
		.parent = &ipg_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_AMLPMRE2,
 | 
						|
		.enable_shift = MXC_CRMAP_AMLPMRE2_MLPME0_OFFSET,
 | 
						|
		.enable = _clk_3bit_enable,
 | 
						|
		.disable = _clk_3bit_disable,
 | 
						|
	}, {
 | 
						|
		.id = 1,
 | 
						|
		.parent = &ipg_clk,
 | 
						|
		.enable_reg = MXC_CRMAP_AMLPMRE1,
 | 
						|
		.enable_shift = MXC_CRMAP_AMLPMRE1_MLPME6_OFFSET,
 | 
						|
		.enable = _clk_3bit_enable,
 | 
						|
		.disable = _clk_3bit_disable,
 | 
						|
	},
 | 
						|
};
 | 
						|
/* cspi_clk stuff end */
 | 
						|
 | 
						|
#define _REGISTER_CLOCK(d, n, c) \
 | 
						|
	{ \
 | 
						|
		.dev_id = d, \
 | 
						|
		.con_id = n, \
 | 
						|
		.clk = &c, \
 | 
						|
	},
 | 
						|
 | 
						|
static struct clk_lookup lookups[] = {
 | 
						|
	_REGISTER_CLOCK("imx-uart.0", NULL, uart_clk[0])
 | 
						|
	_REGISTER_CLOCK("imx-uart.1", NULL, uart_clk[1])
 | 
						|
	_REGISTER_CLOCK("imx-uart.2", NULL, uart_clk[2])
 | 
						|
	_REGISTER_CLOCK("mxc-mmc.0", NULL, sdhc_clk[0])
 | 
						|
	_REGISTER_CLOCK("mxc-mmc.1", NULL, sdhc_clk[1])
 | 
						|
	_REGISTER_CLOCK("mxc-wdt.0", NULL, wdog_clk[0])
 | 
						|
	_REGISTER_CLOCK("spi_imx.0", NULL, cspi_clk[0])
 | 
						|
	_REGISTER_CLOCK("spi_imx.1", NULL, cspi_clk[1])
 | 
						|
};
 | 
						|
 | 
						|
int __init mxc91231_clocks_init(unsigned long fref)
 | 
						|
{
 | 
						|
	void __iomem *gpt_base;
 | 
						|
 | 
						|
	ckih_rate = fref;
 | 
						|
 | 
						|
	usb_clk.parent = clk_usb_parent(&usb_clk);
 | 
						|
	sdhc_clk[0].parent = clk_sdhc_parent(&sdhc_clk[0]);
 | 
						|
	sdhc_clk[1].parent = clk_sdhc_parent(&sdhc_clk[1]);
 | 
						|
 | 
						|
	clkdev_add_table(lookups, ARRAY_SIZE(lookups));
 | 
						|
 | 
						|
	gpt_base = MXC91231_IO_ADDRESS(MXC91231_GPT1_BASE_ADDR);
 | 
						|
	mxc_timer_init(&gpt_clk, gpt_base, MXC91231_INT_GPT);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 |