summaryrefslogtreecommitdiff
path: root/arch/arm/mach-sa1100/clock.c
blob: 6199e87447ca600bb38f66f14bc017c97e529958 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// SPDX-License-Identifier: GPL-2.0
/*
 *  linux/arch/arm/mach-sa1100/clock.c
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/clk.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/clkdev.h>

#include <mach/hardware.h>
#include <mach/generic.h>

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

struct clk {
	const struct clkops	*ops;
	unsigned int		enabled;
};

#define DEFINE_CLK(_name, _ops)				\
struct clk clk_##_name = {				\
		.ops	= _ops,				\
	}

static DEFINE_SPINLOCK(clocks_lock);

/* Dummy clk routine to build generic kernel parts that may be using them */
long clk_round_rate(struct clk *clk, unsigned long rate)
{
	return clk_get_rate(clk);
}
EXPORT_SYMBOL(clk_round_rate);

int clk_set_rate(struct clk *clk, unsigned long rate)
{
	return 0;
}
EXPORT_SYMBOL(clk_set_rate);

int clk_set_parent(struct clk *clk, struct clk *parent)
{
	return 0;
}
EXPORT_SYMBOL(clk_set_parent);

struct clk *clk_get_parent(struct clk *clk)
{
	return NULL;
}
EXPORT_SYMBOL(clk_get_parent);

static void clk_gpio27_enable(struct clk *clk)
{
	/*
	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
	 * (SA-1110 Developer's Manual, section 9.1.2.1)
	 */
	GAFR |= GPIO_32_768kHz;
	GPDR |= GPIO_32_768kHz;
	TUCR = TUCR_3_6864MHz;
}

static void clk_gpio27_disable(struct clk *clk)
{
	TUCR = 0;
	GPDR &= ~GPIO_32_768kHz;
	GAFR &= ~GPIO_32_768kHz;
}

static void clk_cpu_enable(struct clk *clk)
{
}

static void clk_cpu_disable(struct clk *clk)
{
}

static unsigned long clk_cpu_get_rate(struct clk *clk)
{
	return sa11x0_getspeed(0) * 1000;
}

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

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

	return 0;
}
EXPORT_SYMBOL(clk_enable);

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

	if (clk) {
		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)
{
	if (clk && clk->ops && clk->ops->get_rate)
		return clk->ops->get_rate(clk);

	return 0;
}
EXPORT_SYMBOL(clk_get_rate);

const struct clkops clk_gpio27_ops = {
	.enable		= clk_gpio27_enable,
	.disable	= clk_gpio27_disable,
};

const struct clkops clk_cpu_ops = {
	.enable		= clk_cpu_enable,
	.disable	= clk_cpu_disable,
	.get_rate	= clk_cpu_get_rate,
};

static DEFINE_CLK(gpio27, &clk_gpio27_ops);

static DEFINE_CLK(cpu, &clk_cpu_ops);

static unsigned long clk_36864_get_rate(struct clk *clk)
{
	return 3686400;
}

static struct clkops clk_36864_ops = {
	.enable		= clk_cpu_enable,
	.disable	= clk_cpu_disable,
	.get_rate	= clk_36864_get_rate,
};

static DEFINE_CLK(36864, &clk_36864_ops);

static struct clk_lookup sa11xx_clkregs[] = {
	CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
	CLKDEV_INIT("sa1100-rtc", NULL, NULL),
	CLKDEV_INIT("sa11x0-fb", NULL, &clk_cpu),
	CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
	CLKDEV_INIT("sa11x0-pcmcia.0", NULL, &clk_cpu),
	CLKDEV_INIT("sa11x0-pcmcia.1", NULL, &clk_cpu),
	/* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */
	CLKDEV_INIT("1800", NULL, &clk_cpu),
	CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864),
};

int __init sa11xx_clk_init(void)
{
	clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
	return 0;
}