0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/clk-provider.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/regmap.h>
0013 #include <linux/slab.h>
0014 #include <linux/mfd/core.h>
0015 #include <linux/mfd/hi655x-pmic.h>
0016
0017 #define HI655X_CLK_BASE HI655X_BUS_ADDR(0x1c)
0018 #define HI655X_CLK_SET BIT(6)
0019
0020 struct hi655x_clk {
0021 struct hi655x_pmic *hi655x;
0022 struct clk_hw clk_hw;
0023 };
0024
0025 static unsigned long hi655x_clk_recalc_rate(struct clk_hw *hw,
0026 unsigned long parent_rate)
0027 {
0028 return 32768;
0029 }
0030
0031 static int hi655x_clk_enable(struct clk_hw *hw, bool enable)
0032 {
0033 struct hi655x_clk *hi655x_clk =
0034 container_of(hw, struct hi655x_clk, clk_hw);
0035
0036 struct hi655x_pmic *hi655x = hi655x_clk->hi655x;
0037
0038 return regmap_update_bits(hi655x->regmap, HI655X_CLK_BASE,
0039 HI655X_CLK_SET, enable ? HI655X_CLK_SET : 0);
0040 }
0041
0042 static int hi655x_clk_prepare(struct clk_hw *hw)
0043 {
0044 return hi655x_clk_enable(hw, true);
0045 }
0046
0047 static void hi655x_clk_unprepare(struct clk_hw *hw)
0048 {
0049 hi655x_clk_enable(hw, false);
0050 }
0051
0052 static int hi655x_clk_is_prepared(struct clk_hw *hw)
0053 {
0054 struct hi655x_clk *hi655x_clk =
0055 container_of(hw, struct hi655x_clk, clk_hw);
0056 struct hi655x_pmic *hi655x = hi655x_clk->hi655x;
0057 int ret;
0058 uint32_t val;
0059
0060 ret = regmap_read(hi655x->regmap, HI655X_CLK_BASE, &val);
0061 if (ret < 0)
0062 return ret;
0063
0064 return val & HI655X_CLK_BASE;
0065 }
0066
0067 static const struct clk_ops hi655x_clk_ops = {
0068 .prepare = hi655x_clk_prepare,
0069 .unprepare = hi655x_clk_unprepare,
0070 .is_prepared = hi655x_clk_is_prepared,
0071 .recalc_rate = hi655x_clk_recalc_rate,
0072 };
0073
0074 static int hi655x_clk_probe(struct platform_device *pdev)
0075 {
0076 struct device *parent = pdev->dev.parent;
0077 struct hi655x_pmic *hi655x = dev_get_drvdata(parent);
0078 struct hi655x_clk *hi655x_clk;
0079 const char *clk_name = "hi655x-clk";
0080 struct clk_init_data init = {
0081 .name = clk_name,
0082 .ops = &hi655x_clk_ops
0083 };
0084 int ret;
0085
0086 hi655x_clk = devm_kzalloc(&pdev->dev, sizeof(*hi655x_clk), GFP_KERNEL);
0087 if (!hi655x_clk)
0088 return -ENOMEM;
0089
0090 of_property_read_string_index(parent->of_node, "clock-output-names",
0091 0, &clk_name);
0092
0093 hi655x_clk->clk_hw.init = &init;
0094 hi655x_clk->hi655x = hi655x;
0095
0096 platform_set_drvdata(pdev, hi655x_clk);
0097
0098 ret = devm_clk_hw_register(&pdev->dev, &hi655x_clk->clk_hw);
0099 if (ret)
0100 return ret;
0101
0102 return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get,
0103 &hi655x_clk->clk_hw);
0104 }
0105
0106 static struct platform_driver hi655x_clk_driver = {
0107 .probe = hi655x_clk_probe,
0108 .driver = {
0109 .name = "hi655x-clk",
0110 },
0111 };
0112
0113 module_platform_driver(hi655x_clk_driver);
0114
0115 MODULE_DESCRIPTION("Clk driver for the hi655x series PMICs");
0116 MODULE_AUTHOR("Daniel Lezcano <daniel.lezcano@linaro.org>");
0117 MODULE_LICENSE("GPL");
0118 MODULE_ALIAS("platform:hi655x-clk");