197d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King/*
297d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King *  linux/arch/arm/mach-sa1100/clock.c
397d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King */
497d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/module.h>
597d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/kernel.h>
65e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King#include <linux/device.h>
797d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/list.h>
897d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/errno.h>
997d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/err.h>
1097d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/string.h>
1197d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/clk.h>
1297d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King#include <linux/spinlock.h>
13d0a9d75b9cd9cc8097c746611cc57cc8438b94beRussell King#include <linux/mutex.h>
144a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou#include <linux/io.h>
154a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou#include <linux/clkdev.h>
1697d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
17a09e64fbc0094e3073dbb09c3b4bfe4ab669244bRussell King#include <mach/hardware.h>
1897d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
194a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustruct clkops {
204a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	void			(*enable)(struct clk *);
214a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	void			(*disable)(struct clk *);
224a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou};
234a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
2497d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell Kingstruct clk {
254a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	const struct clkops	*ops;
2697d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King	unsigned int		enabled;
2797d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King};
2897d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
294a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou#define DEFINE_CLK(_name, _ops)				\
304a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustruct clk clk_##_name = {				\
314a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		.ops	= _ops,				\
324a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	}
334a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
344a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustatic DEFINE_SPINLOCK(clocks_lock);
354a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
364a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustatic void clk_gpio27_enable(struct clk *clk)
375e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King{
385e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	/*
395e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
405e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	 * (SA-1110 Developer's Manual, section 9.1.2.1)
415e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	 */
425e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	GAFR |= GPIO_32_768kHz;
435e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	GPDR |= GPIO_32_768kHz;
445e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	TUCR = TUCR_3_6864MHz;
455e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King}
465e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King
474a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustatic void clk_gpio27_disable(struct clk *clk)
485e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King{
495e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	TUCR = 0;
505e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	GPDR &= ~GPIO_32_768kHz;
515e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King	GAFR &= ~GPIO_32_768kHz;
525e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King}
535e1dbdb458ada37f7e97265cb2ea87c55fd5d034Russell King
5497d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell Kingint clk_enable(struct clk *clk)
5597d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King{
5697d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King	unsigned long flags;
5797d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
584a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	if (clk) {
594a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		spin_lock_irqsave(&clocks_lock, flags);
604a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		if (clk->enabled++ == 0)
614a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou			clk->ops->enable(clk);
624a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		spin_unlock_irqrestore(&clocks_lock, flags);
634a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	}
644a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
6597d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King	return 0;
6697d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King}
6797d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell KingEXPORT_SYMBOL(clk_enable);
6897d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
6997d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell Kingvoid clk_disable(struct clk *clk)
7097d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King{
7197d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King	unsigned long flags;
7297d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
734a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	if (clk) {
744a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		WARN_ON(clk->enabled == 0);
754a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		spin_lock_irqsave(&clocks_lock, flags);
764a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		if (--clk->enabled == 0)
774a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou			clk->ops->disable(clk);
784a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou		spin_unlock_irqrestore(&clocks_lock, flags);
794a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	}
8097d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King}
8197d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell KingEXPORT_SYMBOL(clk_disable);
8297d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King
834a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhouconst struct clkops clk_gpio27_ops = {
844a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	.enable		= clk_gpio27_enable,
854a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	.disable	= clk_gpio27_disable,
864a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou};
874a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
884a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustatic DEFINE_CLK(gpio27, &clk_gpio27_ops);
894a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
904a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustatic struct clk_lookup sa11xx_clkregs[] = {
914a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
924a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	CLKDEV_INIT("sa1100-rtc", NULL, NULL),
934a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou};
944a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou
954a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoustatic int __init sa11xx_clk_init(void)
9697d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King{
974a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
984a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhou	return 0;
9997d654f8eb4b8fbb6e1afef076429a4235a3a3adRussell King}
1004a8f83409da6be1085b3c8f52538c1427ef2c0f1Jett.Zhoucore_initcall(sa11xx_clk_init);
101