WIP FPC-III support
[linux/fpc-iii.git] / drivers / clk / hisilicon / clk-hi3660-stub.c
blob3a653d54bee0562d26d0de1dd31525786d05d40d
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Hisilicon clock driver
5 * Copyright (c) 2013-2017 Hisilicon Limited.
6 * Copyright (c) 2017 Linaro Limited.
8 * Author: Kai Zhao <zhaokai1@hisilicon.com>
9 * Tao Wang <kevin.wangtao@hisilicon.com>
10 * Leo Yan <leo.yan@linaro.org>
13 #include <linux/clk-provider.h>
14 #include <linux/device.h>
15 #include <linux/err.h>
16 #include <linux/init.h>
17 #include <linux/io.h>
18 #include <linux/mailbox_client.h>
19 #include <linux/module.h>
20 #include <linux/of.h>
21 #include <linux/platform_device.h>
22 #include <dt-bindings/clock/hi3660-clock.h>
24 #define HI3660_STUB_CLOCK_DATA (0x70)
25 #define MHZ (1000 * 1000)
27 #define DEFINE_CLK_STUB(_id, _cmd, _name) \
28 { \
29 .id = (_id), \
30 .cmd = (_cmd), \
31 .hw.init = &(struct clk_init_data) { \
32 .name = #_name, \
33 .ops = &hi3660_stub_clk_ops, \
34 .num_parents = 0, \
35 .flags = CLK_GET_RATE_NOCACHE, \
36 }, \
39 #define to_stub_clk(_hw) container_of(_hw, struct hi3660_stub_clk, hw)
41 struct hi3660_stub_clk_chan {
42 struct mbox_client cl;
43 struct mbox_chan *mbox;
46 struct hi3660_stub_clk {
47 unsigned int id;
48 struct clk_hw hw;
49 unsigned int cmd;
50 unsigned int msg[8];
51 unsigned int rate;
54 static void __iomem *freq_reg;
55 static struct hi3660_stub_clk_chan stub_clk_chan;
57 static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw,
58 unsigned long parent_rate)
60 struct hi3660_stub_clk *stub_clk = to_stub_clk(hw);
63 * LPM3 writes back the CPU frequency in shared SRAM so read
64 * back the frequency.
66 stub_clk->rate = readl(freq_reg + (stub_clk->id << 2)) * MHZ;
67 return stub_clk->rate;
70 static long hi3660_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
71 unsigned long *prate)
74 * LPM3 handles rate rounding so just return whatever
75 * rate is requested.
77 return rate;
80 static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
81 unsigned long parent_rate)
83 struct hi3660_stub_clk *stub_clk = to_stub_clk(hw);
85 stub_clk->msg[0] = stub_clk->cmd;
86 stub_clk->msg[1] = rate / MHZ;
88 dev_dbg(stub_clk_chan.cl.dev, "set rate msg[0]=0x%x msg[1]=0x%x\n",
89 stub_clk->msg[0], stub_clk->msg[1]);
91 mbox_send_message(stub_clk_chan.mbox, stub_clk->msg);
92 mbox_client_txdone(stub_clk_chan.mbox, 0);
94 stub_clk->rate = rate;
95 return 0;
98 static const struct clk_ops hi3660_stub_clk_ops = {
99 .recalc_rate = hi3660_stub_clk_recalc_rate,
100 .round_rate = hi3660_stub_clk_round_rate,
101 .set_rate = hi3660_stub_clk_set_rate,
104 static struct hi3660_stub_clk hi3660_stub_clks[HI3660_CLK_STUB_NUM] = {
105 DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0")
106 DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1")
107 DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d")
108 DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc")
111 static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec,
112 void *data)
114 unsigned int idx = clkspec->args[0];
116 if (idx >= HI3660_CLK_STUB_NUM) {
117 pr_err("%s: invalid index %u\n", __func__, idx);
118 return ERR_PTR(-EINVAL);
121 return &hi3660_stub_clks[idx].hw;
124 static int hi3660_stub_clk_probe(struct platform_device *pdev)
126 struct device *dev = &pdev->dev;
127 struct resource *res;
128 unsigned int i;
129 int ret;
131 /* Use mailbox client without blocking */
132 stub_clk_chan.cl.dev = dev;
133 stub_clk_chan.cl.tx_done = NULL;
134 stub_clk_chan.cl.tx_block = false;
135 stub_clk_chan.cl.knows_txdone = false;
137 /* Allocate mailbox channel */
138 stub_clk_chan.mbox = mbox_request_channel(&stub_clk_chan.cl, 0);
139 if (IS_ERR(stub_clk_chan.mbox))
140 return PTR_ERR(stub_clk_chan.mbox);
142 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
143 if (!res)
144 return -EINVAL;
145 freq_reg = devm_ioremap(dev, res->start, resource_size(res));
146 if (!freq_reg)
147 return -ENOMEM;
149 freq_reg += HI3660_STUB_CLOCK_DATA;
151 for (i = 0; i < HI3660_CLK_STUB_NUM; i++) {
152 ret = devm_clk_hw_register(&pdev->dev, &hi3660_stub_clks[i].hw);
153 if (ret)
154 return ret;
157 return devm_of_clk_add_hw_provider(&pdev->dev, hi3660_stub_clk_hw_get,
158 hi3660_stub_clks);
161 static const struct of_device_id hi3660_stub_clk_of_match[] = {
162 { .compatible = "hisilicon,hi3660-stub-clk", },
166 static struct platform_driver hi3660_stub_clk_driver = {
167 .probe = hi3660_stub_clk_probe,
168 .driver = {
169 .name = "hi3660-stub-clk",
170 .of_match_table = hi3660_stub_clk_of_match,
174 static int __init hi3660_stub_clk_init(void)
176 return platform_driver_register(&hi3660_stub_clk_driver);
178 subsys_initcall(hi3660_stub_clk_init);