207 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Toshiba Visconti clock controller4 *5 * Copyright (c) 2021 TOSHIBA CORPORATION6 * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation7 *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 23static 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 28static 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 38static 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 55static 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 68static 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 74static 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 124int 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 != NO_RESET) {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 187struct 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