0001
0002
0003
0004
0005
0006 #include <linux/clk-provider.h>
0007 #include <linux/clkdev.h>
0008 #include <linux/clk/at91_pmc.h>
0009 #include <linux/of.h>
0010 #include <linux/mfd/syscon.h>
0011 #include <linux/regmap.h>
0012
0013 #include "pmc.h"
0014
0015 #define SYSTEM_MAX_ID 31
0016
0017 #define SYSTEM_MAX_NAME_SZ 32
0018
0019 #define to_clk_system(hw) container_of(hw, struct clk_system, hw)
0020 struct clk_system {
0021 struct clk_hw hw;
0022 struct regmap *regmap;
0023 struct at91_clk_pms pms;
0024 u8 id;
0025 };
0026
0027 static inline int is_pck(int id)
0028 {
0029 return (id >= 8) && (id <= 15);
0030 }
0031
0032 static inline bool clk_system_ready(struct regmap *regmap, int id)
0033 {
0034 unsigned int status;
0035
0036 regmap_read(regmap, AT91_PMC_SR, &status);
0037
0038 return !!(status & (1 << id));
0039 }
0040
0041 static int clk_system_prepare(struct clk_hw *hw)
0042 {
0043 struct clk_system *sys = to_clk_system(hw);
0044
0045 regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
0046
0047 if (!is_pck(sys->id))
0048 return 0;
0049
0050 while (!clk_system_ready(sys->regmap, sys->id))
0051 cpu_relax();
0052
0053 return 0;
0054 }
0055
0056 static void clk_system_unprepare(struct clk_hw *hw)
0057 {
0058 struct clk_system *sys = to_clk_system(hw);
0059
0060 regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
0061 }
0062
0063 static int clk_system_is_prepared(struct clk_hw *hw)
0064 {
0065 struct clk_system *sys = to_clk_system(hw);
0066 unsigned int status;
0067
0068 regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
0069
0070 if (!(status & (1 << sys->id)))
0071 return 0;
0072
0073 if (!is_pck(sys->id))
0074 return 1;
0075
0076 regmap_read(sys->regmap, AT91_PMC_SR, &status);
0077
0078 return !!(status & (1 << sys->id));
0079 }
0080
0081 static int clk_system_save_context(struct clk_hw *hw)
0082 {
0083 struct clk_system *sys = to_clk_system(hw);
0084
0085 sys->pms.status = clk_system_is_prepared(hw);
0086
0087 return 0;
0088 }
0089
0090 static void clk_system_restore_context(struct clk_hw *hw)
0091 {
0092 struct clk_system *sys = to_clk_system(hw);
0093
0094 if (sys->pms.status)
0095 clk_system_prepare(&sys->hw);
0096 }
0097
0098 static const struct clk_ops system_ops = {
0099 .prepare = clk_system_prepare,
0100 .unprepare = clk_system_unprepare,
0101 .is_prepared = clk_system_is_prepared,
0102 .save_context = clk_system_save_context,
0103 .restore_context = clk_system_restore_context,
0104 };
0105
0106 struct clk_hw * __init
0107 at91_clk_register_system(struct regmap *regmap, const char *name,
0108 const char *parent_name, u8 id)
0109 {
0110 struct clk_system *sys;
0111 struct clk_hw *hw;
0112 struct clk_init_data init;
0113 int ret;
0114
0115 if (!parent_name || id > SYSTEM_MAX_ID)
0116 return ERR_PTR(-EINVAL);
0117
0118 sys = kzalloc(sizeof(*sys), GFP_KERNEL);
0119 if (!sys)
0120 return ERR_PTR(-ENOMEM);
0121
0122 init.name = name;
0123 init.ops = &system_ops;
0124 init.parent_names = &parent_name;
0125 init.num_parents = 1;
0126 init.flags = CLK_SET_RATE_PARENT;
0127
0128 sys->id = id;
0129 sys->hw.init = &init;
0130 sys->regmap = regmap;
0131
0132 hw = &sys->hw;
0133 ret = clk_hw_register(NULL, &sys->hw);
0134 if (ret) {
0135 kfree(sys);
0136 hw = ERR_PTR(ret);
0137 }
0138
0139 return hw;
0140 }