root/drivers/clk/clk-cs2000-cp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cs2000_bset
  2. cs2000_enable_dev_config
  3. cs2000_clk_in_bound_rate
  4. cs2000_wait_pll_lock
  5. cs2000_clk_out_enable
  6. cs2000_rate_to_ratio
  7. cs2000_ratio_to_rate
  8. cs2000_ratio_set
  9. cs2000_ratio_get
  10. cs2000_ratio_select
  11. cs2000_recalc_rate
  12. cs2000_round_rate
  13. __cs2000_set_rate
  14. cs2000_set_rate
  15. cs2000_set_saved_rate
  16. cs2000_enable
  17. cs2000_disable
  18. cs2000_get_parent
  19. cs2000_clk_get
  20. cs2000_clk_register
  21. cs2000_version_print
  22. cs2000_remove
  23. cs2000_probe
  24. cs2000_resume

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

/* [<][>][^][v][top][bottom][index][help] */