1/*
2 *  linux/arch/arm/mach-mmp/clock.c
3 *
4 *  This program is free software; you can redistribute it and/or modify
5 *  it under the terms of the GNU General Public License version 2 as
6 *  published by the Free Software Foundation.
7 */
8
9#include <linux/module.h>
10#include <linux/kernel.h>
11#include <linux/list.h>
12#include <linux/spinlock.h>
13#include <linux/clk.h>
14#include <linux/io.h>
15
16#include <mach/regs-apbc.h>
17#include "clock.h"
18
19static void apbc_clk_enable(struct clk *clk)
20{
21	uint32_t clk_rst;
22
23	clk_rst = APBC_APBCLK | APBC_FNCLK | APBC_FNCLKSEL(clk->fnclksel);
24	__raw_writel(clk_rst, clk->clk_rst);
25}
26
27static void apbc_clk_disable(struct clk *clk)
28{
29	__raw_writel(0, clk->clk_rst);
30}
31
32struct clkops apbc_clk_ops = {
33	.enable		= apbc_clk_enable,
34	.disable	= apbc_clk_disable,
35};
36
37static void apmu_clk_enable(struct clk *clk)
38{
39	__raw_writel(clk->enable_val, clk->clk_rst);
40}
41
42static void apmu_clk_disable(struct clk *clk)
43{
44	__raw_writel(0, clk->clk_rst);
45}
46
47struct clkops apmu_clk_ops = {
48	.enable		= apmu_clk_enable,
49	.disable	= apmu_clk_disable,
50};
51
52static DEFINE_SPINLOCK(clocks_lock);
53
54int clk_enable(struct clk *clk)
55{
56	unsigned long flags;
57
58	spin_lock_irqsave(&clocks_lock, flags);
59	if (clk->enabled++ == 0)
60		clk->ops->enable(clk);
61	spin_unlock_irqrestore(&clocks_lock, flags);
62	return 0;
63}
64EXPORT_SYMBOL(clk_enable);
65
66void clk_disable(struct clk *clk)
67{
68	unsigned long flags;
69
70	WARN_ON(clk->enabled == 0);
71
72	spin_lock_irqsave(&clocks_lock, flags);
73	if (--clk->enabled == 0)
74		clk->ops->disable(clk);
75	spin_unlock_irqrestore(&clocks_lock, flags);
76}
77EXPORT_SYMBOL(clk_disable);
78
79unsigned long clk_get_rate(struct clk *clk)
80{
81	unsigned long rate;
82
83	if (clk->ops->getrate)
84		rate = clk->ops->getrate(clk);
85	else
86		rate = clk->rate;
87
88	return rate;
89}
90EXPORT_SYMBOL(clk_get_rate);
91
92int clk_set_rate(struct clk *clk, unsigned long rate)
93{
94	unsigned long flags;
95	int ret = -EINVAL;
96
97	if (clk->ops->setrate) {
98		spin_lock_irqsave(&clocks_lock, flags);
99		ret = clk->ops->setrate(clk, rate);
100		spin_unlock_irqrestore(&clocks_lock, flags);
101	}
102
103	return ret;
104}
105EXPORT_SYMBOL(clk_set_rate);
106