コード例 #1
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
{
	u32 control;
	unsigned long parent_rate, child_div, actual_rate, div;

	parent_rate = clk->parent->get_rate(clk->parent);
	control = pm_readl(CKSEL);

	if (control & PM_BIT(HSBDIV))
		child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
	else
		child_div = 1;

	if (rate > 3 * (parent_rate / 4) || child_div == 1) {
		actual_rate = parent_rate;
		control &= ~PM_BIT(CPUDIV);
	} else {
		unsigned int cpusel;
		div = (parent_rate + rate / 2) / rate;
		if (div > child_div)
			div = child_div;
		cpusel = (div > 1) ? (fls(div) - 2) : 0;
		control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
		actual_rate = parent_rate / (1 << (cpusel + 1));
	}

	pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
			clk->name, rate, actual_rate);

	if (apply)
		pm_writel(CKSEL, control);

	return actual_rate;
}
コード例 #2
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
int genclk_set_parent(struct clk *clk, struct clk *parent)
{
	u32 control;

	dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
		clk->name, parent->name, clk->parent->name);

	control = pm_readl(GCCTRL(clk->index));

	if (parent == &osc1 || parent == &pll1)
		control |= PM_BIT(OSCSEL);
	else if (parent == &osc0 || parent == &pll0)
		control &= ~PM_BIT(OSCSEL);
	else
		return -EINVAL;

	if (parent == &pll0 || parent == &pll1)
		control |= PM_BIT(PLLSEL);
	else
		control &= ~PM_BIT(PLLSEL);

	pm_writel(GCCTRL(clk->index), control);
	clk->parent = parent;

	return 0;
}
コード例 #3
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static void pll1_mode(struct clk *clk, int enabled)
{
	unsigned long timeout;
	u32 status;
	u32 ctrl;

	ctrl = pm_readl(PLL1);

	if (enabled) {
		if (!PM_BFEXT(PLLMUL, ctrl) && !PM_BFEXT(PLLDIV, ctrl)) {
			pr_debug("clk %s: failed to enable, rate not set\n",
					clk->name);
			return;
		}

		ctrl |= PM_BIT(PLLEN);
		pm_writel(PLL1, ctrl);

		/* Wait for PLL lock. */
		for (timeout = 10000; timeout; timeout--) {
			status = pm_readl(ISR);
			if (status & PM_BIT(LOCK1))
				break;
			udelay(10);
		}

		if (!(status & PM_BIT(LOCK1)))
			printk(KERN_ERR "clk %s: timeout waiting for lock\n",
					clk->name);
	} else {
		ctrl &= ~PM_BIT(PLLEN);
		pm_writel(PLL1, ctrl);
	}
}
コード例 #4
0
ファイル: at32ap7000.c プロジェクト: PennPanda/linux-repo
void __init at32_clock_init(void)
{
	u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
	int i;

	if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
		main_clock = &pll0;
		cpu_clk.parent = &pll0;
	} else {
		main_clock = &osc0;
		cpu_clk.parent = &osc0;
	}

	if (pm_readl(PLL0) & PM_BIT(PLLOSC))
		pll0.parent = &osc1;
	if (pm_readl(PLL1) & PM_BIT(PLLOSC))
		pll1.parent = &osc1;

	genclk_init_parent(&gclk0);
	genclk_init_parent(&gclk1);
	genclk_init_parent(&gclk2);
	genclk_init_parent(&gclk3);
	genclk_init_parent(&gclk4);
	genclk_init_parent(&atmel_lcdfb0_pixclk);
	genclk_init_parent(&abdac0_sample_clk);

	/*
	 * Turn on all clocks that have at least one user already, and
	 * turn off everything else. We only do this for module
	 * clocks, and even though it isn't particularly pretty to
	 * check the address of the mode function, it should do the
	 * trick...
	 */
	for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
		struct clk *clk = at32_clock_list[i];

		if (clk->users == 0)
			continue;

		if (clk->mode == &cpu_clk_mode)
			cpu_mask |= 1 << clk->index;
		else if (clk->mode == &hsb_clk_mode)
			hsb_mask |= 1 << clk->index;
		else if (clk->mode == &pba_clk_mode)
			pba_mask |= 1 << clk->index;
		else if (clk->mode == &pbb_clk_mode)
			pbb_mask |= 1 << clk->index;
	}

	pm_writel(CPU_MASK, cpu_mask);
	pm_writel(HSB_MASK, hsb_mask);
	pm_writel(PBA_MASK, pba_mask);
	pm_writel(PBB_MASK, pbb_mask);
}
コード例 #5
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static void __init genclk_init_parent(struct clk *clk)
{
	u32 control;
	struct clk *parent;

	BUG_ON(clk->index > 7);

	control = pm_readl(GCCTRL(clk->index));
	if (control & PM_BIT(OSCSEL))
		parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
	else
		parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;

	clk->parent = parent;
}
コード例 #6
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
{
	u32 control;
	unsigned long parent_rate, actual_rate, div;

	parent_rate = clk->parent->get_rate(clk->parent);
	control = pm_readl(GCCTRL(clk->index));

	if (rate > 3 * parent_rate / 4) {
		actual_rate = parent_rate;
		control &= ~PM_BIT(DIVEN);
	} else {
		div = (parent_rate + rate) / (2 * rate) - 1;
		control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
		actual_rate = parent_rate / (2 * (div + 1));
	}

	dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
		clk->name, rate, actual_rate);

	if (apply)
		pm_writel(GCCTRL(clk->index), control);

	return actual_rate;
}
コード例 #7
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static unsigned long pbb_clk_get_rate(struct clk *clk)
{
	unsigned long cksel, shift = 0;

	cksel = pm_readl(CKSEL);
	if (cksel & PM_BIT(PBBDIV))
		shift = PM_BFEXT(PBBSEL, cksel) + 1;

	return bus_clk_get_rate(clk, shift);
}
コード例 #8
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static unsigned long genclk_get_rate(struct clk *clk)
{
	u32 control;
	unsigned long div = 1;

	control = pm_readl(GCCTRL(clk->index));
	if (control & PM_BIT(DIVEN))
		div = 2 * (PM_BFEXT(DIV, control) + 1);

	return clk->parent->get_rate(clk->parent) / div;
}
コード例 #9
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static void genclk_mode(struct clk *clk, int enabled)
{
	u32 control;

	control = pm_readl(GCCTRL(clk->index));
	if (enabled)
		control |= PM_BIT(CEN);
	else
		control &= ~PM_BIT(CEN);
	pm_writel(GCCTRL(clk->index), control);
}
コード例 #10
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static int pll1_set_parent(struct clk *clk, struct clk *parent)
{
	u32 ctrl;

	if (clk->users > 0)
		return -EBUSY;

	ctrl = pm_readl(PLL1);
	WARN_ON(ctrl & PM_BIT(PLLEN));

	if (parent == &osc0)
		ctrl &= ~PM_BIT(PLLOSC);
	else if (parent == &osc1)
		ctrl |= PM_BIT(PLLOSC);
	else
		return -EINVAL;

	pm_writel(PLL1, ctrl);
	clk->parent = parent;

	return 0;
}
コード例 #11
0
ファイル: at32ap7000.c プロジェクト: PennPanda/linux-repo
static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
{
	unsigned long div, mul, rate;

	if (!(control & PM_BIT(PLLEN)))
		return 0;

	div = PM_BFEXT(PLLDIV, control) + 1;
	mul = PM_BFEXT(PLLMUL, control) + 1;

	rate = clk->parent->get_rate(clk->parent);
	rate = (rate + div / 2) / div;
	rate *= mul;

	return rate;
}
コード例 #12
0
ファイル: at32ap700x.c プロジェクト: LeonMagnus/linux
static long pll_set_rate(struct clk *clk, unsigned long rate,
			 u32 *pll_ctrl)
{
	unsigned long mul;
	unsigned long mul_best_fit = 0;
	unsigned long div;
	unsigned long div_min;
	unsigned long div_max;
	unsigned long div_best_fit = 0;
	unsigned long base;
	unsigned long pll_in;
	unsigned long actual = 0;
	unsigned long rate_error;
	unsigned long rate_error_prev = ~0UL;
	u32 ctrl;

	/* Rate must be between 80 MHz and 200 Mhz. */
	if (rate < 80000000UL || rate > 200000000UL)
		return -EINVAL;

	ctrl = PM_BF(PLLOPT, 4);
	base = clk->parent->get_rate(clk->parent);

	/* PLL input frequency must be between 6 MHz and 32 MHz. */
	div_min = DIV_ROUND_UP(base, 32000000UL);
	div_max = base / 6000000UL;

	if (div_max < div_min)
		return -EINVAL;

	for (div = div_min; div <= div_max; div++) {
		pll_in = (base + div / 2) / div;
		mul = (rate + pll_in / 2) / pll_in;

		if (mul == 0)
			continue;

		actual = pll_in * mul;
		rate_error = abs(actual - rate);

		if (rate_error < rate_error_prev) {
			mul_best_fit = mul;
			div_best_fit = div;
			rate_error_prev = rate_error;
		}

		if (rate_error == 0)
			break;
	}

	if (div_best_fit == 0)
		return -EINVAL;

	ctrl |= PM_BF(PLLMUL, mul_best_fit - 1);
	ctrl |= PM_BF(PLLDIV, div_best_fit - 1);
	ctrl |= PM_BF(PLLCOUNT, 16);

	if (clk->parent == &osc1)
		ctrl |= PM_BIT(PLLOSC);

	*pll_ctrl = ctrl;

	return actual;
}