blob: 23d2d7ea1beb1df955fc550ed6a4785b41fa4122 [file] [log] [blame]
Linus Walleij91b87a42012-06-11 17:29:54 +02001/*
2 * Driver for the ICST307 VCO clock found in the ARM Reference designs.
3 * We wrap the custom interface from <asm/hardware/icst.h> into the generic
4 * clock framework.
5 *
Linus Walleij401301c2012-11-20 22:39:31 +01006 * Copyright (C) 2012 Linus Walleij
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 *
Linus Walleij91b87a42012-06-11 17:29:54 +020012 * TODO: when all ARM reference designs are migrated to generic clocks, the
13 * ICST clock code from the ARM tree should probably be merged into this
14 * file.
15 */
16#include <linux/clk.h>
17#include <linux/clkdev.h>
18#include <linux/err.h>
19#include <linux/clk-provider.h>
20
21#include "clk-icst.h"
22
23/**
24 * struct clk_icst - ICST VCO clock wrapper
25 * @hw: corresponding clock hardware entry
26 * @params: parameters for this ICST instance
27 * @rate: current rate
28 * @setvco: function to commit ICST settings to hardware
29 */
30struct clk_icst {
31 struct clk_hw hw;
32 const struct icst_params *params;
33 unsigned long rate;
34 struct icst_vco (*getvco)(void);
35 void (*setvco)(struct icst_vco);
36};
37
38#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
39
40static unsigned long icst_recalc_rate(struct clk_hw *hw,
41 unsigned long parent_rate)
42{
43 struct clk_icst *icst = to_icst(hw);
44 struct icst_vco vco;
45
46 vco = icst->getvco();
47 icst->rate = icst_hz(icst->params, vco);
48 return icst->rate;
49}
50
51static long icst_round_rate(struct clk_hw *hw, unsigned long rate,
52 unsigned long *prate)
53{
54 struct clk_icst *icst = to_icst(hw);
55 struct icst_vco vco;
56
57 vco = icst_hz_to_vco(icst->params, rate);
58 return icst_hz(icst->params, vco);
59}
60
61static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
62 unsigned long parent_rate)
63{
64 struct clk_icst *icst = to_icst(hw);
65 struct icst_vco vco;
66
67 vco = icst_hz_to_vco(icst->params, rate);
68 icst->rate = icst_hz(icst->params, vco);
69 icst->setvco(vco);
70 return 0;
71}
72
73static const struct clk_ops icst_ops = {
74 .recalc_rate = icst_recalc_rate,
75 .round_rate = icst_round_rate,
76 .set_rate = icst_set_rate,
77};
78
79struct clk * __init icst_clk_register(struct device *dev,
80 const struct clk_icst_desc *desc)
81{
82 struct clk *clk;
83 struct clk_icst *icst;
84 struct clk_init_data init;
85
86 icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
87 if (!icst) {
88 pr_err("could not allocate ICST clock!\n");
89 return ERR_PTR(-ENOMEM);
90 }
91 init.name = "icst";
92 init.ops = &icst_ops;
93 init.flags = CLK_IS_ROOT;
94 init.parent_names = NULL;
95 init.num_parents = 0;
96 icst->hw.init = &init;
97 icst->params = desc->params;
98 icst->getvco = desc->getvco;
99 icst->setvco = desc->setvco;
100
101 clk = clk_register(dev, &icst->hw);
102 if (IS_ERR(clk))
103 kfree(icst);
104
105 return clk;
106}