1 /*
2  * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <linux/clk-provider.h>
18 #include <linux/slab.h>
19 #include <linux/err.h>
20 
21 #include "clk.h"
22 
23 static unsigned long clk_sync_source_recalc_rate(struct clk_hw *hw,
24 						 unsigned long parent_rate)
25 {
26 	struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
27 
28 	return sync->rate;
29 }
30 
31 static long clk_sync_source_round_rate(struct clk_hw *hw, unsigned long rate,
32 				       unsigned long *prate)
33 {
34 	struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
35 
36 	if (rate > sync->max_rate)
37 		return -EINVAL;
38 	else
39 		return rate;
40 }
41 
42 static int clk_sync_source_set_rate(struct clk_hw *hw, unsigned long rate,
43 				    unsigned long parent_rate)
44 {
45 	struct tegra_clk_sync_source *sync = to_clk_sync_source(hw);
46 
47 	sync->rate = rate;
48 	return 0;
49 }
50 
51 const struct clk_ops tegra_clk_sync_source_ops = {
52 	.round_rate = clk_sync_source_round_rate,
53 	.set_rate = clk_sync_source_set_rate,
54 	.recalc_rate = clk_sync_source_recalc_rate,
55 };
56 
57 struct clk *tegra_clk_register_sync_source(const char *name,
58 					   unsigned long max_rate)
59 {
60 	struct tegra_clk_sync_source *sync;
61 	struct clk_init_data init;
62 	struct clk *clk;
63 
64 	sync = kzalloc(sizeof(*sync), GFP_KERNEL);
65 	if (!sync) {
66 		pr_err("%s: could not allocate sync source clk\n", __func__);
67 		return ERR_PTR(-ENOMEM);
68 	}
69 
70 	sync->max_rate = max_rate;
71 
72 	init.ops = &tegra_clk_sync_source_ops;
73 	init.name = name;
74 	init.flags = 0;
75 	init.parent_names = NULL;
76 	init.num_parents = 0;
77 
78 	/* Data in .init is copied by clk_register(), so stack variable OK */
79 	sync->hw.init = &init;
80 
81 	clk = clk_register(NULL, &sync->hw);
82 	if (IS_ERR(clk))
83 		kfree(sync);
84 
85 	return clk;
86 }
87