Commit a6dba20c authored by Russell King's avatar Russell King Committed by Russell King
Browse files

[ARM] pxa: introduce clk support for PXA SoC clocks

parent 00dc4f94
Loading
Loading
Loading
Loading
+50 −29
Original line number Diff line number Diff line
@@ -9,19 +9,15 @@
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
#include <linux/delay.h>

#include <asm/arch/pxa-regs.h>
#include <asm/hardware.h>

struct clk {
	struct list_head	node;
	unsigned long		rate;
	struct module		*owner;
	const char		*name;
	unsigned int		enabled;
	void			(*enable)(void);
	void			(*disable)(void);
};
#include "devices.h"
#include "generic.h"
#include "clock.h"

static LIST_HEAD(clocks);
static DEFINE_MUTEX(clocks_mutex);
@@ -33,7 +29,8 @@ struct clk *clk_get(struct device *dev, const char *id)

	mutex_lock(&clocks_mutex);
	list_for_each_entry(p, &clocks, node) {
		if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
		if (strcmp(id, p->name) == 0 &&
		    (p->dev == NULL || p->dev == dev)) {
			clk = p;
			break;
		}
@@ -46,7 +43,6 @@ EXPORT_SYMBOL(clk_get);

void clk_put(struct clk *clk)
{
	module_put(clk->owner);
}
EXPORT_SYMBOL(clk_put);

@@ -56,8 +52,12 @@ int clk_enable(struct clk *clk)

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

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

	return 0;
}
EXPORT_SYMBOL(clk_enable);
@@ -70,54 +70,75 @@ void clk_disable(struct clk *clk)

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

unsigned long clk_get_rate(struct clk *clk)
{
	return clk->rate;
	unsigned long rate;

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

	return rate;
}
EXPORT_SYMBOL(clk_get_rate);


static void clk_gpio27_enable(void)
static void clk_gpio27_enable(struct clk *clk)
{
	pxa_gpio_mode(GPIO11_3_6MHz_MD);
}

static void clk_gpio27_disable(void)
static void clk_gpio27_disable(struct clk *clk)
{
}

static struct clk clk_gpio27 = {
	.name		= "GPIO27_CLK",
	.rate		= 3686400,
static const struct clkops clk_gpio27_ops = {
	.enable		= clk_gpio27_enable,
	.disable	= clk_gpio27_disable,
};

int clk_register(struct clk *clk)

void clk_cken_enable(struct clk *clk)
{
	mutex_lock(&clocks_mutex);
	list_add(&clk->node, &clocks);
	mutex_unlock(&clocks_mutex);
	return 0;
	CKEN |= 1 << clk->cken;
}

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

void clk_unregister(struct clk *clk)
const struct clkops clk_cken_ops = {
	.enable		= clk_cken_enable,
	.disable	= clk_cken_disable,
};

static struct clk common_clks[] = {
	{
		.name		= "GPIO27_CLK",
		.ops		= &clk_gpio27_ops,
		.rate		= 3686400,
	},
};

void clks_register(struct clk *clks, size_t num)
{
	int i;

	mutex_lock(&clocks_mutex);
	list_del(&clk->node);
	for (i = 0; i < num; i++)
		list_add(&clks[i].node, &clocks);
	mutex_unlock(&clocks_mutex);
}
EXPORT_SYMBOL(clk_unregister);

static int __init clk_init(void)
{
	clk_register(&clk_gpio27);
	clks_register(common_clks, ARRAY_SIZE(common_clks));
	return 0;
}
arch_initcall(clk_init);
+43 −0
Original line number Diff line number Diff line
struct clk;

struct clkops {
	void			(*enable)(struct clk *);
	void			(*disable)(struct clk *);
	unsigned long		(*getrate)(struct clk *);
};

struct clk {
	struct list_head	node;
	const char		*name;
	struct device		*dev;
	const struct clkops	*ops;
	unsigned long		rate;
	unsigned int		cken;
	unsigned int		delay;
	unsigned int		enabled;
};

#define INIT_CKEN(_name, _cken, _rate, _delay, _dev)	\
	{						\
		.name	= _name,			\
		.dev	= _dev,				\
		.ops	= &clk_cken_ops,		\
		.rate	= _rate,			\
		.cken	= CKEN_##_cken,			\
		.delay	= _delay,			\
	}

#define INIT_CK(_name, _cken, _ops, _dev)		\
	{						\
		.name	= _name,			\
		.dev	= _dev,				\
		.ops	= _ops,				\
		.cken	= CKEN_##_cken,			\
	}

extern const struct clkops clk_cken_ops;

void clk_cken_enable(struct clk *clk);
void clk_cken_disable(struct clk *clk);

void clks_register(struct clk *clks, size_t num);
+38 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

#include "generic.h"
#include "devices.h"
#include "clock.h"

/*
 * Various clock factors driven by the CCCR register.
@@ -94,6 +95,41 @@ unsigned int pxa25x_get_memclk_frequency_10khz(void)
	return L_clk_mult[(CCCR >> 0) & 0x1f] * BASE_CLK / 10000;
}

static unsigned long clk_pxa25x_lcd_getrate(struct clk *clk)
{
	return pxa25x_get_memclk_frequency_10khz() * 10000;
}

static const struct clkops clk_pxa25x_lcd_ops = {
	.enable		= clk_cken_enable,
	.disable	= clk_cken_disable,
	.getrate	= clk_pxa25x_lcd_getrate,
};

/*
 * 3.6864MHz -> OST, GPIO, SSP, PWM, PLLs (95.842MHz, 147.456MHz)
 * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
 * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
 */
static struct clk pxa25x_clks[] = {
	INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev),
	INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev),
	INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
	INIT_CKEN("UARTCLK", STUART, 14745600, 1, &pxa_device_stuart.dev),
	INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
	INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev),
	INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
	INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev),
	/*
	INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
	INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
	INIT_CKEN("SSPCLK",  SSP,  3686400,  0, NULL),
	INIT_CKEN("I2SCLK",  I2S,  14745600, 0, NULL),
	INIT_CKEN("NSSPCLK", NSSP, 3686400,  0, NULL),
	INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL),
	*/
};

#ifdef CONFIG_PM

#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
@@ -215,6 +251,8 @@ static int __init pxa25x_init(void)
	int ret = 0;

	if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
		clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks));

		if ((ret = pxa_init_dma(16)))
			return ret;
#ifdef CONFIG_PM
+45 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@

#include "generic.h"
#include "devices.h"
#include "clock.h"

/* Crystal clock: 13MHz */
#define BASE_CLK	13000000
@@ -120,6 +121,48 @@ unsigned int pxa27x_get_lcdclk_frequency_10khz(void)
	return (K / 10000);
}

static unsigned long clk_pxa27x_lcd_getrate(struct clk *clk)
{
	return pxa27x_get_lcdclk_frequency_10khz() * 10000;
}

static const struct clkops clk_pxa27x_lcd_ops = {
	.enable		= clk_cken_enable,
	.disable	= clk_cken_disable,
	.getrate	= clk_pxa27x_lcd_getrate,
};

static struct clk pxa27x_clks[] = {
	INIT_CK("LCDCLK", LCD,    &clk_pxa27x_lcd_ops, &pxa_device_fb.dev),
	INIT_CK("CAMCLK", CAMERA, &clk_pxa27x_lcd_ops, NULL),

	INIT_CKEN("UARTCLK", STUART, 14857000, 1, &pxa_device_stuart.dev),
	INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
	INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),

	INIT_CKEN("I2SCLK",  I2S,  14682000, 0, &pxa_device_i2s.dev),
	INIT_CKEN("I2CCLK",  I2C,  32842000, 0, &pxa_device_i2c.dev),
	INIT_CKEN("UDCCLK",  USB,  48000000, 5, &pxa_device_udc.dev),
	INIT_CKEN("MMCCLK",  MMC,  19500000, 0, &pxa_device_mci.dev),
	INIT_CKEN("FICPCLK", FICP, 48000000, 0, &pxa_device_ficp.dev),

	INIT_CKEN("USBCLK", USB,    48000000, 0, &pxa27x_device_ohci.dev),
	INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
	INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL),

	/*
	INIT_CKEN("PWMCLK",  PWM0, 13000000, 0, NULL),
	INIT_CKEN("SSPCLK",  SSP1, 13000000, 0, NULL),
	INIT_CKEN("SSPCLK",  SSP2, 13000000, 0, NULL),
	INIT_CKEN("SSPCLK",  SSP3, 13000000, 0, NULL),
	INIT_CKEN("MSLCLK",  MSL,  48000000, 0, NULL),
	INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL),
	INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL),
	INIT_CKEN("IMCLK",   IM,   0, 0, NULL),
	INIT_CKEN("MEMCLK",  MEMC, 0, 0, NULL),
	*/
};

#ifdef CONFIG_PM

#define SAVE(x)		sleep_save[SLEEP_SAVE_##x] = x
@@ -343,6 +386,8 @@ static int __init pxa27x_init(void)
{
	int ret = 0;
	if (cpu_is_pxa27x()) {
		clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));

		if ((ret = pxa_init_dma(32)))
			return ret;
#ifdef CONFIG_PM