Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: add CS2000 Fractional-N driver

This patch adds CS2000 Fractional-N driver as clock provider.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
[sboyd@codeaurora.org: Fix unsigned checked for < 0 in
cs2000_ratio_get()]
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Kuninori Morimoto and committed by
Stephen Boyd
64dfbe24 198bb594

+539
+22
Documentation/devicetree/bindings/clock/cs2000-cp.txt
··· 1 + CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier 2 + 3 + Required properties: 4 + 5 + - compatible: "cirrus,cs2000-cp" 6 + - reg: The chip select number on the I2C bus 7 + - clocks: common clock binding for CLK_IN, XTI/REF_CLK 8 + - clock-names: CLK_IN : clk_in, XTI/REF_CLK : ref_clk 9 + - #clock-cells: must be <0> 10 + 11 + Example: 12 + 13 + &i2c2 { 14 + ... 15 + cs2000: clk_multiplier@4f { 16 + #clock-cells = <0>; 17 + compatible = "cirrus,cs2000-cp"; 18 + reg = <0x4f>; 19 + clocks = <&rcar_sound 0>, <&x12_clk>; 20 + clock-names = "clk_in", "ref_clk"; 21 + }; 22 + };
+6
drivers/clk/Kconfig
··· 116 116 Given a target output frequency, the driver will set the PLL and 117 117 divider to best approximate the desired output. 118 118 119 + config COMMON_CLK_CS2000_CP 120 + tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier" 121 + depends on I2C 122 + help 123 + If you say yes here you get support for the CS2000 clock multiplier. 124 + 119 125 config COMMON_CLK_S2MPS11 120 126 tristate "Clock driver for S2MPS1X/S5M8767 MFD" 121 127 depends on MFD_SEC_CORE
+1
drivers/clk/Makefile
··· 21 21 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o 22 22 obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o 23 23 obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o 24 + obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o 24 25 obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o 25 26 obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o 26 27 obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
+510
drivers/clk/clk-cs2000-cp.c
··· 1 + /* 2 + * CS2000 -- CIRRUS LOGIC Fractional-N Clock Synthesizer & Clock Multiplier 3 + * 4 + * Copyright (C) 2015 Renesas Electronics Corporation 5 + * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License version 2 as 9 + * published by the Free Software Foundation. 10 + */ 11 + #include <linux/clk-provider.h> 12 + #include <linux/delay.h> 13 + #include <linux/clk.h> 14 + #include <linux/i2c.h> 15 + #include <linux/of_device.h> 16 + #include <linux/module.h> 17 + 18 + #define CH_MAX 4 19 + #define RATIO_REG_SIZE 4 20 + 21 + #define DEVICE_ID 0x1 22 + #define DEVICE_CTRL 0x2 23 + #define DEVICE_CFG1 0x3 24 + #define DEVICE_CFG2 0x4 25 + #define GLOBAL_CFG 0x5 26 + #define Ratio_Add(x, nth) (6 + (x * 4) + (nth)) 27 + #define Ratio_Val(x, nth) ((x >> (24 - (8 * nth))) & 0xFF) 28 + #define Val_Ratio(x, nth) ((x & 0xFF) << (24 - (8 * nth))) 29 + #define FUNC_CFG1 0x16 30 + #define FUNC_CFG2 0x17 31 + 32 + /* DEVICE_ID */ 33 + #define REVISION_MASK (0x7) 34 + #define REVISION_B2_B3 (0x4) 35 + #define REVISION_C1 (0x6) 36 + 37 + /* DEVICE_CTRL */ 38 + #define PLL_UNLOCK (1 << 7) 39 + 40 + /* DEVICE_CFG1 */ 41 + #define RSEL(x) (((x) & 0x3) << 3) 42 + #define RSEL_MASK RSEL(0x3) 43 + #define ENDEV1 (0x1) 44 + 45 + /* GLOBAL_CFG */ 46 + #define ENDEV2 (0x1) 47 + 48 + #define CH_SIZE_ERR(ch) ((ch < 0) || (ch >= CH_MAX)) 49 + #define hw_to_priv(_hw) container_of(_hw, struct cs2000_priv, hw) 50 + #define priv_to_client(priv) (priv->client) 51 + #define priv_to_dev(priv) (&(priv_to_client(priv)->dev)) 52 + 53 + #define CLK_IN 0 54 + #define REF_CLK 1 55 + #define CLK_MAX 2 56 + 57 + struct cs2000_priv { 58 + struct clk_hw hw; 59 + struct i2c_client *client; 60 + struct clk *clk_in; 61 + struct clk *ref_clk; 62 + struct clk *clk_out; 63 + }; 64 + 65 + static const struct of_device_id cs2000_of_match[] = { 66 + { .compatible = "cirrus,cs2000-cp", }, 67 + {}, 68 + }; 69 + MODULE_DEVICE_TABLE(of, cs2000_of_match); 70 + 71 + static const struct i2c_device_id cs2000_id[] = { 72 + { "cs2000-cp", }, 73 + {} 74 + }; 75 + MODULE_DEVICE_TABLE(i2c, cs2000_id); 76 + 77 + #define cs2000_read(priv, addr) \ 78 + i2c_smbus_read_byte_data(priv_to_client(priv), addr) 79 + #define cs2000_write(priv, addr, val) \ 80 + i2c_smbus_write_byte_data(priv_to_client(priv), addr, val) 81 + 82 + static int cs2000_bset(struct cs2000_priv *priv, u8 addr, u8 mask, u8 val) 83 + { 84 + s32 data; 85 + 86 + data = cs2000_read(priv, addr); 87 + if (data < 0) 88 + return data; 89 + 90 + data &= ~mask; 91 + data |= (val & mask); 92 + 93 + return cs2000_write(priv, addr, data); 94 + } 95 + 96 + static int cs2000_enable_dev_config(struct cs2000_priv *priv, bool enable) 97 + { 98 + int ret; 99 + 100 + ret = cs2000_bset(priv, DEVICE_CFG1, ENDEV1, 101 + enable ? ENDEV1 : 0); 102 + if (ret < 0) 103 + return ret; 104 + 105 + ret = cs2000_bset(priv, GLOBAL_CFG, ENDEV2, 106 + enable ? ENDEV2 : 0); 107 + if (ret < 0) 108 + return ret; 109 + 110 + return 0; 111 + } 112 + 113 + static int cs2000_clk_in_bound_rate(struct cs2000_priv *priv, 114 + u32 rate_in) 115 + { 116 + u32 val; 117 + 118 + if (rate_in >= 32000000 && rate_in < 56000000) 119 + val = 0x0; 120 + else if (rate_in >= 16000000 && rate_in < 28000000) 121 + val = 0x1; 122 + else if (rate_in >= 8000000 && rate_in < 14000000) 123 + val = 0x2; 124 + else 125 + return -EINVAL; 126 + 127 + return cs2000_bset(priv, FUNC_CFG1, 0x3 << 3, val << 3); 128 + } 129 + 130 + static int cs2000_wait_pll_lock(struct cs2000_priv *priv) 131 + { 132 + struct device *dev = priv_to_dev(priv); 133 + s32 val; 134 + unsigned int i; 135 + 136 + for (i = 0; i < 256; i++) { 137 + val = cs2000_read(priv, DEVICE_CTRL); 138 + if (val < 0) 139 + return val; 140 + if (!(val & PLL_UNLOCK)) 141 + return 0; 142 + udelay(1); 143 + } 144 + 145 + dev_err(dev, "pll lock failed\n"); 146 + 147 + return -ETIMEDOUT; 148 + } 149 + 150 + static int cs2000_clk_out_enable(struct cs2000_priv *priv, bool enable) 151 + { 152 + /* enable both AUX_OUT, CLK_OUT */ 153 + return cs2000_write(priv, DEVICE_CTRL, enable ? 0 : 0x3); 154 + } 155 + 156 + static u32 cs2000_rate_to_ratio(u32 rate_in, u32 rate_out) 157 + { 158 + u64 ratio; 159 + 160 + /* 161 + * ratio = rate_out / rate_in * 2^20 162 + * 163 + * To avoid over flow, rate_out is u64. 164 + * The result should be u32. 165 + */ 166 + ratio = (u64)rate_out << 20; 167 + do_div(ratio, rate_in); 168 + 169 + return ratio; 170 + } 171 + 172 + static unsigned long cs2000_ratio_to_rate(u32 ratio, u32 rate_in) 173 + { 174 + u64 rate_out; 175 + 176 + /* 177 + * ratio = rate_out / rate_in * 2^20 178 + * 179 + * To avoid over flow, rate_out is u64. 180 + * The result should be u32 or unsigned long. 181 + */ 182 + 183 + rate_out = (u64)ratio * rate_in; 184 + return rate_out >> 20; 185 + } 186 + 187 + static int cs2000_ratio_set(struct cs2000_priv *priv, 188 + int ch, u32 rate_in, u32 rate_out) 189 + { 190 + u32 val; 191 + unsigned int i; 192 + int ret; 193 + 194 + if (CH_SIZE_ERR(ch)) 195 + return -EINVAL; 196 + 197 + val = cs2000_rate_to_ratio(rate_in, rate_out); 198 + for (i = 0; i < RATIO_REG_SIZE; i++) { 199 + ret = cs2000_write(priv, 200 + Ratio_Add(ch, i), 201 + Ratio_Val(val, i)); 202 + if (ret < 0) 203 + return ret; 204 + } 205 + 206 + return 0; 207 + } 208 + 209 + static u32 cs2000_ratio_get(struct cs2000_priv *priv, int ch) 210 + { 211 + s32 tmp; 212 + u32 val; 213 + unsigned int i; 214 + 215 + val = 0; 216 + for (i = 0; i < RATIO_REG_SIZE; i++) { 217 + tmp = cs2000_read(priv, Ratio_Add(ch, i)); 218 + if (tmp < 0) 219 + return 0; 220 + 221 + val |= Val_Ratio(tmp, i); 222 + } 223 + 224 + return val; 225 + } 226 + 227 + static int cs2000_ratio_select(struct cs2000_priv *priv, int ch) 228 + { 229 + int ret; 230 + 231 + if (CH_SIZE_ERR(ch)) 232 + return -EINVAL; 233 + 234 + /* 235 + * FIXME 236 + * 237 + * this driver supports static ratio mode only at this point. 238 + */ 239 + ret = cs2000_bset(priv, DEVICE_CFG1, RSEL_MASK, RSEL(ch)); 240 + if (ret < 0) 241 + return ret; 242 + 243 + ret = cs2000_write(priv, DEVICE_CFG2, 0x0); 244 + if (ret < 0) 245 + return ret; 246 + 247 + return 0; 248 + } 249 + 250 + static unsigned long cs2000_recalc_rate(struct clk_hw *hw, 251 + unsigned long parent_rate) 252 + { 253 + struct cs2000_priv *priv = hw_to_priv(hw); 254 + int ch = 0; /* it uses ch0 only at this point */ 255 + u32 ratio; 256 + 257 + ratio = cs2000_ratio_get(priv, ch); 258 + 259 + return cs2000_ratio_to_rate(ratio, parent_rate); 260 + } 261 + 262 + static long cs2000_round_rate(struct clk_hw *hw, unsigned long rate, 263 + unsigned long *parent_rate) 264 + { 265 + u32 ratio; 266 + 267 + ratio = cs2000_rate_to_ratio(*parent_rate, rate); 268 + 269 + return cs2000_ratio_to_rate(ratio, *parent_rate); 270 + } 271 + 272 + static int __cs2000_set_rate(struct cs2000_priv *priv, int ch, 273 + unsigned long rate, unsigned long parent_rate) 274 + 275 + { 276 + int ret; 277 + 278 + ret = cs2000_clk_in_bound_rate(priv, parent_rate); 279 + if (ret < 0) 280 + return ret; 281 + 282 + ret = cs2000_ratio_set(priv, ch, parent_rate, rate); 283 + if (ret < 0) 284 + return ret; 285 + 286 + ret = cs2000_ratio_select(priv, ch); 287 + if (ret < 0) 288 + return ret; 289 + 290 + return 0; 291 + } 292 + 293 + static int cs2000_set_rate(struct clk_hw *hw, 294 + unsigned long rate, unsigned long parent_rate) 295 + { 296 + struct cs2000_priv *priv = hw_to_priv(hw); 297 + int ch = 0; /* it uses ch0 only at this point */ 298 + 299 + return __cs2000_set_rate(priv, ch, rate, parent_rate); 300 + } 301 + 302 + static int cs2000_enable(struct clk_hw *hw) 303 + { 304 + struct cs2000_priv *priv = hw_to_priv(hw); 305 + int ret; 306 + 307 + ret = cs2000_enable_dev_config(priv, true); 308 + if (ret < 0) 309 + return ret; 310 + 311 + ret = cs2000_clk_out_enable(priv, true); 312 + if (ret < 0) 313 + return ret; 314 + 315 + ret = cs2000_wait_pll_lock(priv); 316 + if (ret < 0) 317 + return ret; 318 + 319 + return ret; 320 + } 321 + 322 + static void cs2000_disable(struct clk_hw *hw) 323 + { 324 + struct cs2000_priv *priv = hw_to_priv(hw); 325 + 326 + cs2000_enable_dev_config(priv, false); 327 + 328 + cs2000_clk_out_enable(priv, false); 329 + } 330 + 331 + static u8 cs2000_get_parent(struct clk_hw *hw) 332 + { 333 + /* always return REF_CLK */ 334 + return REF_CLK; 335 + } 336 + 337 + static const struct clk_ops cs2000_ops = { 338 + .get_parent = cs2000_get_parent, 339 + .recalc_rate = cs2000_recalc_rate, 340 + .round_rate = cs2000_round_rate, 341 + .set_rate = cs2000_set_rate, 342 + .prepare = cs2000_enable, 343 + .unprepare = cs2000_disable, 344 + }; 345 + 346 + static int cs2000_clk_get(struct cs2000_priv *priv) 347 + { 348 + struct i2c_client *client = priv_to_client(priv); 349 + struct device *dev = &client->dev; 350 + struct clk *clk_in, *ref_clk; 351 + 352 + clk_in = devm_clk_get(dev, "clk_in"); 353 + /* not yet provided */ 354 + if (IS_ERR(clk_in)) 355 + return -EPROBE_DEFER; 356 + 357 + ref_clk = devm_clk_get(dev, "ref_clk"); 358 + /* not yet provided */ 359 + if (IS_ERR(ref_clk)) 360 + return -EPROBE_DEFER; 361 + 362 + priv->clk_in = clk_in; 363 + priv->ref_clk = ref_clk; 364 + 365 + return 0; 366 + } 367 + 368 + static int cs2000_clk_register(struct cs2000_priv *priv) 369 + { 370 + struct device *dev = priv_to_dev(priv); 371 + struct device_node *np = dev->of_node; 372 + struct clk_init_data init; 373 + const char *name = np->name; 374 + struct clk *clk; 375 + static const char *parent_names[CLK_MAX]; 376 + int ch = 0; /* it uses ch0 only at this point */ 377 + int rate; 378 + int ret; 379 + 380 + of_property_read_string(np, "clock-output-names", &name); 381 + 382 + /* 383 + * set default rate as 1/1. 384 + * otherwise .set_rate which setup ratio 385 + * is never called if user requests 1/1 rate 386 + */ 387 + rate = clk_get_rate(priv->ref_clk); 388 + ret = __cs2000_set_rate(priv, ch, rate, rate); 389 + if (ret < 0) 390 + return ret; 391 + 392 + parent_names[CLK_IN] = __clk_get_name(priv->clk_in); 393 + parent_names[REF_CLK] = __clk_get_name(priv->ref_clk); 394 + 395 + init.name = name; 396 + init.ops = &cs2000_ops; 397 + init.flags = CLK_SET_RATE_GATE; 398 + init.parent_names = parent_names; 399 + init.num_parents = ARRAY_SIZE(parent_names); 400 + 401 + priv->hw.init = &init; 402 + 403 + clk = clk_register(dev, &priv->hw); 404 + if (IS_ERR(clk)) 405 + return PTR_ERR(clk); 406 + 407 + ret = of_clk_add_provider(np, of_clk_src_simple_get, clk); 408 + if (ret < 0) { 409 + clk_unregister(clk); 410 + return ret; 411 + } 412 + 413 + priv->clk_out = clk; 414 + 415 + return 0; 416 + } 417 + 418 + static int cs2000_version_print(struct cs2000_priv *priv) 419 + { 420 + struct i2c_client *client = priv_to_client(priv); 421 + struct device *dev = &client->dev; 422 + s32 val; 423 + const char *revision; 424 + 425 + val = cs2000_read(priv, DEVICE_ID); 426 + if (val < 0) 427 + return val; 428 + 429 + /* CS2000 should be 0x0 */ 430 + if (val >> 3) 431 + return -EIO; 432 + 433 + switch (val & REVISION_MASK) { 434 + case REVISION_B2_B3: 435 + revision = "B2 / B3"; 436 + break; 437 + case REVISION_C1: 438 + revision = "C1"; 439 + break; 440 + default: 441 + return -EIO; 442 + } 443 + 444 + dev_info(dev, "revision - %s\n", revision); 445 + 446 + return 0; 447 + } 448 + 449 + static int cs2000_remove(struct i2c_client *client) 450 + { 451 + struct cs2000_priv *priv = i2c_get_clientdata(client); 452 + struct device *dev = &client->dev; 453 + struct device_node *np = dev->of_node; 454 + 455 + of_clk_del_provider(np); 456 + 457 + clk_unregister(priv->clk_out); 458 + 459 + return 0; 460 + } 461 + 462 + static int cs2000_probe(struct i2c_client *client, 463 + const struct i2c_device_id *id) 464 + { 465 + struct cs2000_priv *priv; 466 + struct device *dev = &client->dev; 467 + int ret; 468 + 469 + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 470 + if (!priv) 471 + return -ENOMEM; 472 + 473 + priv->client = client; 474 + i2c_set_clientdata(client, priv); 475 + 476 + ret = cs2000_clk_get(priv); 477 + if (ret < 0) 478 + return ret; 479 + 480 + ret = cs2000_clk_register(priv); 481 + if (ret < 0) 482 + return ret; 483 + 484 + ret = cs2000_version_print(priv); 485 + if (ret < 0) 486 + goto probe_err; 487 + 488 + return 0; 489 + 490 + probe_err: 491 + cs2000_remove(client); 492 + 493 + return ret; 494 + } 495 + 496 + static struct i2c_driver cs2000_driver = { 497 + .driver = { 498 + .name = "cs2000-cp", 499 + .of_match_table = cs2000_of_match, 500 + }, 501 + .probe = cs2000_probe, 502 + .remove = cs2000_remove, 503 + .id_table = cs2000_id, 504 + }; 505 + 506 + module_i2c_driver(cs2000_driver); 507 + 508 + MODULE_DESCRIPTION("CS2000-CP driver"); 509 + MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 510 + MODULE_LICENSE("GPL v2");