0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/clk-provider.h>
0014 #include <linux/device.h>
0015 #include <linux/err.h>
0016 #include <linux/init.h>
0017 #include <linux/io.h>
0018 #include <linux/mailbox_client.h>
0019 #include <linux/module.h>
0020 #include <linux/of.h>
0021 #include <linux/platform_device.h>
0022 #include <dt-bindings/clock/hi3660-clock.h>
0023
0024 #define HI3660_STUB_CLOCK_DATA (0x70)
0025 #define MHZ (1000 * 1000)
0026
0027 #define DEFINE_CLK_STUB(_id, _cmd, _name) \
0028 { \
0029 .id = (_id), \
0030 .cmd = (_cmd), \
0031 .hw.init = &(struct clk_init_data) { \
0032 .name = #_name, \
0033 .ops = &hi3660_stub_clk_ops, \
0034 .num_parents = 0, \
0035 .flags = CLK_GET_RATE_NOCACHE, \
0036 }, \
0037 },
0038
0039 #define to_stub_clk(_hw) container_of(_hw, struct hi3660_stub_clk, hw)
0040
0041 struct hi3660_stub_clk_chan {
0042 struct mbox_client cl;
0043 struct mbox_chan *mbox;
0044 };
0045
0046 struct hi3660_stub_clk {
0047 unsigned int id;
0048 struct clk_hw hw;
0049 unsigned int cmd;
0050 unsigned int msg[8];
0051 unsigned int rate;
0052 };
0053
0054 static void __iomem *freq_reg;
0055 static struct hi3660_stub_clk_chan stub_clk_chan;
0056
0057 static unsigned long hi3660_stub_clk_recalc_rate(struct clk_hw *hw,
0058 unsigned long parent_rate)
0059 {
0060 struct hi3660_stub_clk *stub_clk = to_stub_clk(hw);
0061
0062
0063
0064
0065
0066 stub_clk->rate = readl(freq_reg + (stub_clk->id << 2)) * MHZ;
0067 return stub_clk->rate;
0068 }
0069
0070 static long hi3660_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
0071 unsigned long *prate)
0072 {
0073
0074
0075
0076
0077 return rate;
0078 }
0079
0080 static int hi3660_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
0081 unsigned long parent_rate)
0082 {
0083 struct hi3660_stub_clk *stub_clk = to_stub_clk(hw);
0084
0085 stub_clk->msg[0] = stub_clk->cmd;
0086 stub_clk->msg[1] = rate / MHZ;
0087
0088 dev_dbg(stub_clk_chan.cl.dev, "set rate msg[0]=0x%x msg[1]=0x%x\n",
0089 stub_clk->msg[0], stub_clk->msg[1]);
0090
0091 mbox_send_message(stub_clk_chan.mbox, stub_clk->msg);
0092 mbox_client_txdone(stub_clk_chan.mbox, 0);
0093
0094 stub_clk->rate = rate;
0095 return 0;
0096 }
0097
0098 static const struct clk_ops hi3660_stub_clk_ops = {
0099 .recalc_rate = hi3660_stub_clk_recalc_rate,
0100 .round_rate = hi3660_stub_clk_round_rate,
0101 .set_rate = hi3660_stub_clk_set_rate,
0102 };
0103
0104 static struct hi3660_stub_clk hi3660_stub_clks[HI3660_CLK_STUB_NUM] = {
0105 DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER0, 0x0001030A, "cpu-cluster.0")
0106 DEFINE_CLK_STUB(HI3660_CLK_STUB_CLUSTER1, 0x0002030A, "cpu-cluster.1")
0107 DEFINE_CLK_STUB(HI3660_CLK_STUB_GPU, 0x0003030A, "clk-g3d")
0108 DEFINE_CLK_STUB(HI3660_CLK_STUB_DDR, 0x00040309, "clk-ddrc")
0109 };
0110
0111 static struct clk_hw *hi3660_stub_clk_hw_get(struct of_phandle_args *clkspec,
0112 void *data)
0113 {
0114 unsigned int idx = clkspec->args[0];
0115
0116 if (idx >= HI3660_CLK_STUB_NUM) {
0117 pr_err("%s: invalid index %u\n", __func__, idx);
0118 return ERR_PTR(-EINVAL);
0119 }
0120
0121 return &hi3660_stub_clks[idx].hw;
0122 }
0123
0124 static int hi3660_stub_clk_probe(struct platform_device *pdev)
0125 {
0126 struct device *dev = &pdev->dev;
0127 struct resource *res;
0128 unsigned int i;
0129 int ret;
0130
0131
0132 stub_clk_chan.cl.dev = dev;
0133 stub_clk_chan.cl.tx_done = NULL;
0134 stub_clk_chan.cl.tx_block = false;
0135 stub_clk_chan.cl.knows_txdone = false;
0136
0137
0138 stub_clk_chan.mbox = mbox_request_channel(&stub_clk_chan.cl, 0);
0139 if (IS_ERR(stub_clk_chan.mbox))
0140 return PTR_ERR(stub_clk_chan.mbox);
0141
0142 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0143 if (!res)
0144 return -EINVAL;
0145 freq_reg = devm_ioremap(dev, res->start, resource_size(res));
0146 if (!freq_reg)
0147 return -ENOMEM;
0148
0149 freq_reg += HI3660_STUB_CLOCK_DATA;
0150
0151 for (i = 0; i < HI3660_CLK_STUB_NUM; i++) {
0152 ret = devm_clk_hw_register(&pdev->dev, &hi3660_stub_clks[i].hw);
0153 if (ret)
0154 return ret;
0155 }
0156
0157 return devm_of_clk_add_hw_provider(&pdev->dev, hi3660_stub_clk_hw_get,
0158 hi3660_stub_clks);
0159 }
0160
0161 static const struct of_device_id hi3660_stub_clk_of_match[] = {
0162 { .compatible = "hisilicon,hi3660-stub-clk", },
0163 {}
0164 };
0165
0166 static struct platform_driver hi3660_stub_clk_driver = {
0167 .probe = hi3660_stub_clk_probe,
0168 .driver = {
0169 .name = "hi3660-stub-clk",
0170 .of_match_table = hi3660_stub_clk_of_match,
0171 },
0172 };
0173
0174 static int __init hi3660_stub_clk_init(void)
0175 {
0176 return platform_driver_register(&hi3660_stub_clk_driver);
0177 }
0178 subsys_initcall(hi3660_stub_clk_init);