summaryrefslogtreecommitdiff
path: root/drivers/staging/cg2900/clock-cg2900.c
blob: cc763f8c548d75ca8c207de5a9eafcef3cba085c (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
/*
 * Copyright (C) ST-Ericsson SA 2011
 *
 * Author: Hemant Gupta <hemant.gupta@stericsson.com>
 * Author: Tomasz Hliwiak <tomasz.hliwiak@tieto.com>
 *
 * 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 <asm/mach-types.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/skbuff.h>
#include "clock.h"
#include "cg2900.h"

static DEFINE_MUTEX(cg2900_clk_mutex);

static struct cg2900_user_data *pf_data;
static struct clk_lookup *cg2900_clk_lookup;

/**
 * cg2900_clk_enable() - Enables CG2900 Clock
 *
 * Enables CG2900 Clock by starting CG2900.
 *
 * Returns:
 *  0 if success.
 *  -EINVAL if stored pf_data is NULL.
 *  Error codes generated by open.
 */

static int cg2900_clk_enable(struct clk *clk)
{
	int err = -EINVAL;
	if (pf_data)
		err = pf_data->open(pf_data);

	return err;
}

/**
 * cg2900_clk_disable() - Disables CG2900 Clock
 *
 * Disables CG2900 Clock by switching off CG2900.
 */
static void cg2900_clk_disable(struct clk *clk)
{
	if (pf_data)
		pf_data->close(pf_data);
}

static struct clkops cg2900_clk_ops = {
	.enable		= cg2900_clk_enable,
	.disable	= cg2900_clk_disable,
};

static struct clk cg2900_clk = {
	.name	= "cg2900_clk",
	.ops	= &cg2900_clk_ops,
	.mutex	= &cg2900_clk_mutex,
};

/**
 * cg2900_read_cb() - Dummy callback for cg2900 core read.
 *
 * Function is required by cg2900_core->open().
 */
static void cg2900_read_cb(struct cg2900_user_data *user, struct sk_buff *skb)
{
	kfree_skb(skb);
}

/**
 * cg2900_core_probe() - Initialize resources.
 *
 * Function initializes pf_data structure and also adds the cg2900
 * clock source.
 */
static int __devinit cg2900_core_probe(struct platform_device *pdev)
{
	cg2900_clk_lookup = clkdev_alloc(&cg2900_clk, "sys_clk_out",
			"cw1200_wlan");

	if (!cg2900_clk_lookup)
		return -ENOMEM;

	clkdev_add(cg2900_clk_lookup);
	pf_data = dev_get_platdata(&pdev->dev);
	pf_data->dev = &pdev->dev;
	pf_data->read_cb = cg2900_read_cb;

	return 0;
}

/**
 * cg2900_core_remove() - Clean resources.
 *
 * Function cleans pf_data structure and removes the clock source.
 */
static int __devexit cg2900_core_remove(struct platform_device *pdev)
{
	clkdev_drop(cg2900_clk_lookup);
	pf_data = NULL;

	return 0;
}

static struct platform_driver cg2900_core_ctrl_driver = {
	.driver = {
		.name      = "cg2900-core",
		.owner     = THIS_MODULE,
	},
	.probe     = cg2900_core_probe,
	.remove    = __devexit_p(cg2900_core_remove),
};

/**
 * clock_cg2900_init() - Register Platform Data
 *
 * Registers the platform data.
 */
static int __init clock_cg2900_init(void)
{
	return platform_driver_register(&cg2900_core_ctrl_driver);
}

/**
 * clock_cg2900_exit() - Unregister Platform Data
 *
 * Unregister Platform Data
 */
static void __exit clock_cg2900_exit(void)
{
	platform_driver_unregister(&cg2900_core_ctrl_driver);
}

module_init(clock_cg2900_init);
module_exit(clock_cg2900_exit);