|
17 | 17 | #include <linux/delay.h>
|
18 | 18 | #include <linux/device.h>
|
19 | 19 | #include <linux/init.h>
|
| 20 | +#include <linux/iopoll.h> |
20 | 21 | #include <linux/mod_devicetable.h>
|
21 | 22 | #include <linux/module.h>
|
22 | 23 | #include <linux/of_address.h>
|
|
55 | 56 | #define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff)
|
56 | 57 | #define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff)
|
57 | 58 |
|
| 59 | +struct sd_hw_data { |
| 60 | + struct clk_hw hw; |
| 61 | + u32 conf; |
| 62 | + struct rzg2l_cpg_priv *priv; |
| 63 | +}; |
| 64 | + |
| 65 | +#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw) |
| 66 | + |
58 | 67 | /**
|
59 | 68 | * struct rzg2l_cpg_priv - Clock Pulse Generator Private Data
|
60 | 69 | *
|
@@ -150,6 +159,112 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core,
|
150 | 159 | return clk_hw->clk;
|
151 | 160 | }
|
152 | 161 |
|
| 162 | +static int rzg2l_cpg_sd_clk_mux_determine_rate(struct clk_hw *hw, |
| 163 | + struct clk_rate_request *req) |
| 164 | +{ |
| 165 | + return clk_mux_determine_rate_flags(hw, req, 0); |
| 166 | +} |
| 167 | + |
| 168 | +static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index) |
| 169 | +{ |
| 170 | + struct sd_hw_data *hwdata = to_sd_hw_data(hw); |
| 171 | + struct rzg2l_cpg_priv *priv = hwdata->priv; |
| 172 | + u32 off = GET_REG_OFFSET(hwdata->conf); |
| 173 | + u32 shift = GET_SHIFT(hwdata->conf); |
| 174 | + const u32 clk_src_266 = 2; |
| 175 | + u32 bitmask; |
| 176 | + |
| 177 | + /* |
| 178 | + * As per the HW manual, we should not directly switch from 533 MHz to |
| 179 | + * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz) |
| 180 | + * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first, |
| 181 | + * and then switch to the target setting (2’b01 (533 MHz) or 2’b10 |
| 182 | + * (400 MHz)). |
| 183 | + * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock |
| 184 | + * switching register is prohibited. |
| 185 | + * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and |
| 186 | + * the index to value mapping is done by adding 1 to the index. |
| 187 | + */ |
| 188 | + bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16; |
| 189 | + if (index != clk_src_266) { |
| 190 | + u32 msk, val; |
| 191 | + int ret; |
| 192 | + |
| 193 | + writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off); |
| 194 | + |
| 195 | + msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS; |
| 196 | + |
| 197 | + ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val, |
| 198 | + !(val & msk), 100, |
| 199 | + CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US); |
| 200 | + if (ret) { |
| 201 | + dev_err(priv->dev, "failed to switch clk source\n"); |
| 202 | + return ret; |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + writel(bitmask | ((index + 1) << shift), priv->base + off); |
| 207 | + |
| 208 | + return 0; |
| 209 | +} |
| 210 | + |
| 211 | +static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw) |
| 212 | +{ |
| 213 | + struct sd_hw_data *hwdata = to_sd_hw_data(hw); |
| 214 | + struct rzg2l_cpg_priv *priv = hwdata->priv; |
| 215 | + u32 val = readl(priv->base + GET_REG_OFFSET(hwdata->conf)); |
| 216 | + |
| 217 | + val >>= GET_SHIFT(hwdata->conf); |
| 218 | + val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0); |
| 219 | + if (val) { |
| 220 | + val--; |
| 221 | + } else { |
| 222 | + /* Prohibited clk source, change it to 533 MHz(reset value) */ |
| 223 | + rzg2l_cpg_sd_clk_mux_set_parent(hw, 0); |
| 224 | + } |
| 225 | + |
| 226 | + return val; |
| 227 | +} |
| 228 | + |
| 229 | +static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = { |
| 230 | + .determine_rate = rzg2l_cpg_sd_clk_mux_determine_rate, |
| 231 | + .set_parent = rzg2l_cpg_sd_clk_mux_set_parent, |
| 232 | + .get_parent = rzg2l_cpg_sd_clk_mux_get_parent, |
| 233 | +}; |
| 234 | + |
| 235 | +static struct clk * __init |
| 236 | +rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core, |
| 237 | + void __iomem *base, |
| 238 | + struct rzg2l_cpg_priv *priv) |
| 239 | +{ |
| 240 | + struct sd_hw_data *clk_hw_data; |
| 241 | + struct clk_init_data init; |
| 242 | + struct clk_hw *clk_hw; |
| 243 | + int ret; |
| 244 | + |
| 245 | + clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL); |
| 246 | + if (!clk_hw_data) |
| 247 | + return ERR_PTR(-ENOMEM); |
| 248 | + |
| 249 | + clk_hw_data->priv = priv; |
| 250 | + clk_hw_data->conf = core->conf; |
| 251 | + |
| 252 | + init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0"; |
| 253 | + init.ops = &rzg2l_cpg_sd_clk_mux_ops; |
| 254 | + init.flags = 0; |
| 255 | + init.num_parents = core->num_parents; |
| 256 | + init.parent_names = core->parent_names; |
| 257 | + |
| 258 | + clk_hw = &clk_hw_data->hw; |
| 259 | + clk_hw->init = &init; |
| 260 | + |
| 261 | + ret = devm_clk_hw_register(priv->dev, clk_hw); |
| 262 | + if (ret) |
| 263 | + return ERR_PTR(ret); |
| 264 | + |
| 265 | + return clk_hw->clk; |
| 266 | +} |
| 267 | + |
153 | 268 | struct pll_clk {
|
154 | 269 | struct clk_hw hw;
|
155 | 270 | unsigned int conf;
|
@@ -311,6 +426,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
|
311 | 426 | case CLK_TYPE_MUX:
|
312 | 427 | clk = rzg2l_cpg_mux_clk_register(core, priv->base, priv);
|
313 | 428 | break;
|
| 429 | + case CLK_TYPE_SD_MUX: |
| 430 | + clk = rzg2l_cpg_sd_mux_clk_register(core, priv->base, priv); |
| 431 | + break; |
314 | 432 | default:
|
315 | 433 | goto fail;
|
316 | 434 | }
|
|
0 commit comments