Root/drivers/clk/versatile/clk-icst.c

1/*
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 *
6 * TODO: when all ARM reference designs are migrated to generic clocks, the
7 * ICST clock code from the ARM tree should probably be merged into this
8 * file.
9 */
10#include <linux/clk.h>
11#include <linux/clkdev.h>
12#include <linux/err.h>
13#include <linux/clk-provider.h>
14
15#include "clk-icst.h"
16
17/**
18 * struct clk_icst - ICST VCO clock wrapper
19 * @hw: corresponding clock hardware entry
20 * @params: parameters for this ICST instance
21 * @rate: current rate
22 * @setvco: function to commit ICST settings to hardware
23 */
24struct clk_icst {
25    struct clk_hw hw;
26    const struct icst_params *params;
27    unsigned long rate;
28    struct icst_vco (*getvco)(void);
29    void (*setvco)(struct icst_vco);
30};
31
32#define to_icst(_hw) container_of(_hw, struct clk_icst, hw)
33
34static unsigned long icst_recalc_rate(struct clk_hw *hw,
35                      unsigned long parent_rate)
36{
37    struct clk_icst *icst = to_icst(hw);
38    struct icst_vco vco;
39
40    vco = icst->getvco();
41    icst->rate = icst_hz(icst->params, vco);
42    return icst->rate;
43}
44
45static long icst_round_rate(struct clk_hw *hw, unsigned long rate,
46                unsigned long *prate)
47{
48    struct clk_icst *icst = to_icst(hw);
49    struct icst_vco vco;
50
51    vco = icst_hz_to_vco(icst->params, rate);
52    return icst_hz(icst->params, vco);
53}
54
55static int icst_set_rate(struct clk_hw *hw, unsigned long rate,
56             unsigned long parent_rate)
57{
58    struct clk_icst *icst = to_icst(hw);
59    struct icst_vco vco;
60
61    vco = icst_hz_to_vco(icst->params, rate);
62    icst->rate = icst_hz(icst->params, vco);
63    icst->setvco(vco);
64    return 0;
65}
66
67static const struct clk_ops icst_ops = {
68    .recalc_rate = icst_recalc_rate,
69    .round_rate = icst_round_rate,
70    .set_rate = icst_set_rate,
71};
72
73struct clk * __init icst_clk_register(struct device *dev,
74                      const struct clk_icst_desc *desc)
75{
76    struct clk *clk;
77    struct clk_icst *icst;
78    struct clk_init_data init;
79
80    icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL);
81    if (!icst) {
82        pr_err("could not allocate ICST clock!\n");
83        return ERR_PTR(-ENOMEM);
84    }
85    init.name = "icst";
86    init.ops = &icst_ops;
87    init.flags = CLK_IS_ROOT;
88    init.parent_names = NULL;
89    init.num_parents = 0;
90    icst->hw.init = &init;
91    icst->params = desc->params;
92    icst->getvco = desc->getvco;
93    icst->setvco = desc->setvco;
94
95    clk = clk_register(dev, &icst->hw);
96    if (IS_ERR(clk))
97        kfree(icst);
98
99    return clk;
100}
101

Archive Download this file



interactive