1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Toshiba Visconti clock controller 4 * 5 * Copyright (c) 2021 TOSHIBA CORPORATION 6 * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation 7 * 8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp> 9 */ 10 11 #include <linux/clk-provider.h> 12 #include <linux/delay.h> 13 #include <linux/device.h> 14 #include <linux/io.h> 15 #include <linux/of.h> 16 #include <linux/of_address.h> 17 #include <linux/regmap.h> 18 #include <linux/slab.h> 19 #include <linux/string.h> 20 21 #include "clkc.h" 22 23 static inline struct visconti_clk_gate *to_visconti_clk_gate(struct clk_hw *hw) 24 { 25 return container_of(hw, struct visconti_clk_gate, hw); 26 } 27 28 static int visconti_gate_clk_is_enabled(struct clk_hw *hw) 29 { 30 struct visconti_clk_gate *gate = to_visconti_clk_gate(hw); 31 u32 clk = BIT(gate->ck_idx); 32 u32 val; 33 34 regmap_read(gate->regmap, gate->ckon_offset, &val); 35 return (val & clk) ? 1 : 0; 36 } 37 38 static void visconti_gate_clk_disable(struct clk_hw *hw) 39 { 40 struct visconti_clk_gate *gate = to_visconti_clk_gate(hw); 41 u32 clk = BIT(gate->ck_idx); 42 unsigned long flags; 43 44 spin_lock_irqsave(gate->lock, flags); 45 46 if (!visconti_gate_clk_is_enabled(hw)) { 47 spin_unlock_irqrestore(gate->lock, flags); 48 return; 49 } 50 51 regmap_update_bits(gate->regmap, gate->ckoff_offset, clk, clk); 52 spin_unlock_irqrestore(gate->lock, flags); 53 } 54 55 static int visconti_gate_clk_enable(struct clk_hw *hw) 56 { 57 struct visconti_clk_gate *gate = to_visconti_clk_gate(hw); 58 u32 clk = BIT(gate->ck_idx); 59 unsigned long flags; 60 61 spin_lock_irqsave(gate->lock, flags); 62 regmap_update_bits(gate->regmap, gate->ckon_offset, clk, clk); 63 spin_unlock_irqrestore(gate->lock, flags); 64 65 return 0; 66 } 67 68 static const struct clk_ops visconti_clk_gate_ops = { 69 .enable = visconti_gate_clk_enable, 70 .disable = visconti_gate_clk_disable, 71 .is_enabled = visconti_gate_clk_is_enabled, 72 }; 73 74 static struct clk_hw *visconti_clk_register_gate(struct device *dev, 75 const char *name, 76 const char *parent_name, 77 struct regmap *regmap, 78 const struct visconti_clk_gate_table *clks, 79 u32 rson_offset, 80 u32 rsoff_offset, 81 u8 rs_idx, 82 spinlock_t *lock) 83 { 84 struct visconti_clk_gate *gate; 85 struct clk_parent_data *pdata; 86 struct clk_init_data init; 87 struct clk_hw *hw; 88 int ret; 89 90 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 91 if (!pdata) 92 return ERR_PTR(-ENOMEM); 93 94 pdata->name = pdata->fw_name = parent_name; 95 96 gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL); 97 if (!gate) 98 return ERR_PTR(-ENOMEM); 99 100 init.name = name; 101 init.ops = &visconti_clk_gate_ops; 102 init.flags = clks->flags; 103 init.parent_data = pdata; 104 init.num_parents = 1; 105 106 gate->regmap = regmap; 107 gate->ckon_offset = clks->ckon_offset; 108 gate->ckoff_offset = clks->ckoff_offset; 109 gate->ck_idx = clks->ck_idx; 110 gate->rson_offset = rson_offset; 111 gate->rsoff_offset = rsoff_offset; 112 gate->rs_idx = rs_idx; 113 gate->lock = lock; 114 gate->hw.init = &init; 115 116 hw = &gate->hw; 117 ret = devm_clk_hw_register(dev, hw); 118 if (ret) 119 hw = ERR_PTR(ret); 120 121 return hw; 122 } 123 124 int visconti_clk_register_gates(struct visconti_clk_provider *ctx, 125 const struct visconti_clk_gate_table *clks, 126 int num_gate, 127 const struct visconti_reset_data *reset, 128 spinlock_t *lock) 129 { 130 struct device *dev = ctx->dev; 131 int i; 132 133 for (i = 0; i < num_gate; i++) { 134 const char *parent_div_name = clks[i].parent_data[0].name; 135 struct clk_parent_data *pdata; 136 u32 rson_offset, rsoff_offset; 137 struct clk_hw *gate_clk; 138 struct clk_hw *div_clk; 139 char *dev_name; 140 u8 rs_idx; 141 142 pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); 143 if (!pdata) 144 return -ENOMEM; 145 146 dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s_div", clks[i].name); 147 if (!dev_name) 148 return -ENOMEM; 149 150 if (clks[i].rs_id >= 0) { 151 rson_offset = reset[clks[i].rs_id].rson_offset; 152 rsoff_offset = reset[clks[i].rs_id].rsoff_offset; 153 rs_idx = reset[clks[i].rs_id].rs_idx; 154 } else { 155 rson_offset = rsoff_offset = rs_idx = -1; 156 } 157 158 div_clk = devm_clk_hw_register_fixed_factor(dev, 159 dev_name, 160 parent_div_name, 161 0, 1, 162 clks[i].div); 163 if (IS_ERR(div_clk)) 164 return PTR_ERR(div_clk); 165 166 gate_clk = visconti_clk_register_gate(dev, 167 clks[i].name, 168 dev_name, 169 ctx->regmap, 170 &clks[i], 171 rson_offset, 172 rsoff_offset, 173 rs_idx, 174 lock); 175 if (IS_ERR(gate_clk)) { 176 dev_err(dev, "%s: failed to register clock %s\n", 177 __func__, clks[i].name); 178 return PTR_ERR(gate_clk); 179 } 180 181 ctx->clk_data.hws[clks[i].id] = gate_clk; 182 } 183 184 return 0; 185 } 186 187 struct visconti_clk_provider *visconti_init_clk(struct device *dev, 188 struct regmap *regmap, 189 unsigned long nr_clks) 190 { 191 struct visconti_clk_provider *ctx; 192 int i; 193 194 ctx = devm_kzalloc(dev, struct_size(ctx, clk_data.hws, nr_clks), GFP_KERNEL); 195 if (!ctx) 196 return ERR_PTR(-ENOMEM); 197 198 for (i = 0; i < nr_clks; ++i) 199 ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); 200 ctx->clk_data.num = nr_clks; 201 202 ctx->dev = dev; 203 ctx->regmap = regmap; 204 205 return ctx; 206 } 207