Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a1c0a6ad authored by Robert Jarzmik's avatar Robert Jarzmik
Browse files

ARM: pxa: Transition pxa25x, pxa27x, pxa3xx to clk framework



Transition the PXA25x, PXA27x and PXA3xx CPUs to the clock framework.
This transition still enables legacy platforms to run without device
tree as before, ie relying on platform data encoded in board specific
files.

This is the last step of clock framework transition for pxa
platforms. It was tested on lubbock (pxa25x), mioa701 (pxa27x) and
zylonite (pxa3xx).

Signed-off-by: default avatarRobert Jarzmik <robert.jarzmik@free.fr>
parent 8e3afafe
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -606,7 +606,7 @@ config ARCH_PXA
	select ARCH_REQUIRE_GPIOLIB
	select ARM_CPU_SUSPEND if PM
	select AUTO_ZRELADDR
	select COMMON_CLK if PXA27x || PXA25x
	select COMMON_CLK
	select CLKDEV_LOOKUP
	select CLKSRC_MMIO
	select CLKSRC_OF
+1 −1
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@ obj-$(CONFIG_PM) += pm.o sleep.o standby.o
# SoC-specific code
obj-$(CONFIG_PXA25x)		+= mfp-pxa2xx.o pxa2xx.o pxa25x.o
obj-$(CONFIG_PXA27x)		+= mfp-pxa2xx.o pxa2xx.o pxa27x.o
obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o clock.o clock-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
obj-$(CONFIG_PXA3xx)		+= mfp-pxa3xx.o pxa3xx.o smemc.o pxa3xx-ulpi.o
obj-$(CONFIG_CPU_PXA300)	+= pxa300.o
obj-$(CONFIG_CPU_PXA320)	+= pxa320.o
obj-$(CONFIG_CPU_PXA930)	+= pxa930.o

arch/arm/mach-pxa/clock-pxa2xx.c

deleted100644 → 0
+0 −55
Original line number Diff line number Diff line
/*
 * linux/arch/arm/mach-pxa/clock-pxa2xx.c
 *
 * 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/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>

#include <mach/pxa2xx-regs.h>

#include "clock.h"

void clk_pxa2xx_cken_enable(struct clk *clk)
{
	CKEN |= 1 << clk->cken;
}

void clk_pxa2xx_cken_disable(struct clk *clk)
{
	CKEN &= ~(1 << clk->cken);
}

const struct clkops clk_pxa2xx_cken_ops = {
	.enable		= clk_pxa2xx_cken_enable,
	.disable	= clk_pxa2xx_cken_disable,
};

#ifdef CONFIG_PM
static uint32_t saved_cken;

static int pxa2xx_clock_suspend(void)
{
	saved_cken = CKEN;
	return 0;
}

static void pxa2xx_clock_resume(void)
{
	CKEN = saved_cken;
}
#else
#define pxa2xx_clock_suspend	NULL
#define pxa2xx_clock_resume	NULL
#endif

struct syscore_ops pxa2xx_clock_syscore_ops = {
	.suspend	= pxa2xx_clock_suspend,
	.resume		= pxa2xx_clock_resume,
};

arch/arm/mach-pxa/clock-pxa3xx.c

deleted100644 → 0
+0 −212
Original line number Diff line number Diff line
/*
 * linux/arch/arm/mach-pxa/clock-pxa3xx.c
 *
 * 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/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>

#include <mach/smemc.h>
#include <mach/pxa3xx-regs.h>

#include "clock.h"

/* Crystal clock: 13MHz */
#define BASE_CLK	13000000

/* Ring Oscillator Clock: 60MHz */
#define RO_CLK		60000000

#define ACCR_D0CS	(1 << 26)
#define ACCR_PCCE	(1 << 11)

/* crystal frequency to HSIO bus frequency multiplier (HSS) */
static unsigned char hss_mult[4] = { 8, 12, 16, 24 };

/*
 * Get the clock frequency as reflected by CCSR and the turbo flag.
 * We assume these values have been applied via a fcs.
 * If info is not 0 we also display the current settings.
 */
unsigned int pxa3xx_get_clk_frequency_khz(int info)
{
	unsigned long acsr, xclkcfg;
	unsigned int t, xl, xn, hss, ro, XL, XN, CLK, HSS;

	/* Read XCLKCFG register turbo bit */
	__asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
	t = xclkcfg & 0x1;

	acsr = ACSR;

	xl  = acsr & 0x1f;
	xn  = (acsr >> 8) & 0x7;
	hss = (acsr >> 14) & 0x3;

	XL = xl * BASE_CLK;
	XN = xn * XL;

	ro = acsr & ACCR_D0CS;

	CLK = (ro) ? RO_CLK : ((t) ? XN : XL);
	HSS = (ro) ? RO_CLK : hss_mult[hss] * BASE_CLK;

	if (info) {
		pr_info("RO Mode clock: %d.%02dMHz (%sactive)\n",
			RO_CLK / 1000000, (RO_CLK % 1000000) / 10000,
			(ro) ? "" : "in");
		pr_info("Run Mode clock: %d.%02dMHz (*%d)\n",
			XL / 1000000, (XL % 1000000) / 10000, xl);
		pr_info("Turbo Mode clock: %d.%02dMHz (*%d, %sactive)\n",
			XN / 1000000, (XN % 1000000) / 10000, xn,
			(t) ? "" : "in");
		pr_info("HSIO bus clock: %d.%02dMHz\n",
			HSS / 1000000, (HSS % 1000000) / 10000);
	}

	return CLK / 1000;
}

/*
 * Return the current AC97 clock frequency.
 */
static unsigned long clk_pxa3xx_ac97_getrate(struct clk *clk)
{
	unsigned long rate = 312000000;
	unsigned long ac97_div;

	ac97_div = AC97_DIV;

	/* This may loose precision for some rates but won't for the
	 * standard 24.576MHz.
	 */
	rate /= (ac97_div >> 12) & 0x7fff;
	rate *= (ac97_div & 0xfff);

	return rate;
}

/*
 * Return the current HSIO bus clock frequency
 */
static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk)
{
	unsigned long acsr;
	unsigned int hss, hsio_clk;

	acsr = ACSR;

	hss = (acsr >> 14) & 0x3;
	hsio_clk = (acsr & ACCR_D0CS) ? RO_CLK : hss_mult[hss] * BASE_CLK;

	return hsio_clk;
}

/* crystal frequency to static memory controller multiplier (SMCFS) */
static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };

static unsigned long clk_pxa3xx_smemc_getrate(struct clk *clk)
{
	unsigned long acsr = ACSR;
	unsigned long memclkcfg = __raw_readl(MEMCLKCFG);

	return BASE_CLK * smcfs_mult[(acsr >> 23) & 0x7] /
			df_clkdiv[(memclkcfg >> 16) & 0x3];
}

void clk_pxa3xx_cken_enable(struct clk *clk)
{
	unsigned long mask = 1ul << (clk->cken & 0x1f);

	if (clk->cken < 32)
		CKENA |= mask;
	else if (clk->cken < 64)
		CKENB |= mask;
	else
		CKENC |= mask;
}

void clk_pxa3xx_cken_disable(struct clk *clk)
{
	unsigned long mask = 1ul << (clk->cken & 0x1f);

	if (clk->cken < 32)
		CKENA &= ~mask;
	else if (clk->cken < 64)
		CKENB &= ~mask;
	else
		CKENC &= ~mask;
}

const struct clkops clk_pxa3xx_cken_ops = {
	.enable		= clk_pxa3xx_cken_enable,
	.disable	= clk_pxa3xx_cken_disable,
};

const struct clkops clk_pxa3xx_hsio_ops = {
	.enable		= clk_pxa3xx_cken_enable,
	.disable	= clk_pxa3xx_cken_disable,
	.getrate	= clk_pxa3xx_hsio_getrate,
};

const struct clkops clk_pxa3xx_ac97_ops = {
	.enable		= clk_pxa3xx_cken_enable,
	.disable	= clk_pxa3xx_cken_disable,
	.getrate	= clk_pxa3xx_ac97_getrate,
};

const struct clkops clk_pxa3xx_smemc_ops = {
	.enable		= clk_pxa3xx_cken_enable,
	.disable	= clk_pxa3xx_cken_disable,
	.getrate	= clk_pxa3xx_smemc_getrate,
};

static void clk_pout_enable(struct clk *clk)
{
	OSCC |= OSCC_PEN;
}

static void clk_pout_disable(struct clk *clk)
{
	OSCC &= ~OSCC_PEN;
}

const struct clkops clk_pxa3xx_pout_ops = {
	.enable		= clk_pout_enable,
	.disable	= clk_pout_disable,
};

#ifdef CONFIG_PM
static uint32_t cken[2];
static uint32_t accr;

static int pxa3xx_clock_suspend(void)
{
	cken[0] = CKENA;
	cken[1] = CKENB;
	accr = ACCR;
	return 0;
}

static void pxa3xx_clock_resume(void)
{
	ACCR = accr;
	CKENA = cken[0];
	CKENB = cken[1];
}
#else
#define pxa3xx_clock_suspend	NULL
#define pxa3xx_clock_resume	NULL
#endif

struct syscore_ops pxa3xx_clock_syscore_ops = {
	.suspend	= pxa3xx_clock_suspend,
	.resume		= pxa3xx_clock_resume,
};

arch/arm/mach-pxa/clock.c

deleted100644 → 0
+0 −86
Original line number Diff line number Diff line
/*
 *  linux/arch/arm/mach-sa1100/clock.c
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/clkdev.h>

#include "clock.h"

static DEFINE_SPINLOCK(clocks_lock);

int clk_enable(struct clk *clk)
{
	unsigned long flags;

	spin_lock_irqsave(&clocks_lock, flags);
	if (clk->enabled++ == 0)
		clk->ops->enable(clk);
	spin_unlock_irqrestore(&clocks_lock, flags);

	if (clk->delay)
		udelay(clk->delay);

	return 0;
}
EXPORT_SYMBOL(clk_enable);

void clk_disable(struct clk *clk)
{
	unsigned long flags;

	WARN_ON(clk->enabled == 0);

	spin_lock_irqsave(&clocks_lock, flags);
	if (--clk->enabled == 0)
		clk->ops->disable(clk);
	spin_unlock_irqrestore(&clocks_lock, flags);
}
EXPORT_SYMBOL(clk_disable);

unsigned long clk_get_rate(struct clk *clk)
{
	unsigned long rate;

	rate = clk->rate;
	if (clk->ops->getrate)
		rate = clk->ops->getrate(clk);

	return rate;
}
EXPORT_SYMBOL(clk_get_rate);

int clk_set_rate(struct clk *clk, unsigned long rate)
{
	unsigned long flags;
	int ret = -EINVAL;

	if (clk->ops->setrate) {
		spin_lock_irqsave(&clocks_lock, flags);
		ret = clk->ops->setrate(clk, rate);
		spin_unlock_irqrestore(&clocks_lock, flags);
	}

	return ret;
}
EXPORT_SYMBOL(clk_set_rate);

void clk_dummy_enable(struct clk *clk)
{
}

void clk_dummy_disable(struct clk *clk)
{
}

const struct clkops clk_dummy_ops = {
	.enable		= clk_dummy_enable,
	.disable	= clk_dummy_disable,
};

struct clk clk_dummy = {
	.ops		= &clk_dummy_ops,
};
Loading