linux/drivers/clk/clk-cs2000-cp.c
<<
>>
Prefs
   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
  74struct 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
  85static const struct of_device_id cs2000_of_match[] = {
  86        { .compatible = "cirrus,cs2000-cp", },
  87        {},
  88};
  89MODULE_DEVICE_TABLE(of, cs2000_of_match);
  90
  91static const struct i2c_device_id cs2000_id[] = {
  92        { "cs2000-cp", },
  93        {}
  94};
  95MODULE_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
 102static 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
 116static 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
 144static 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
 163static 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
 183static 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
 192static 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
 208static 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
 223static 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
 245static 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
 263static 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
 288static 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
 300static 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
 310static 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
 334static 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
 343static 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
 352static 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
 372static 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
 381static u8 cs2000_get_parent(struct clk_hw *hw)
 382{
 383        /* always return REF_CLK */
 384        return REF_CLK;
 385}
 386
 387static 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
 396static 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
 417static 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
 464static 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
 494static 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
 507static 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
 535probe_err:
 536        cs2000_remove(client);
 537
 538        return ret;
 539}
 540
 541static 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
 548static const struct dev_pm_ops cs2000_pm_ops = {
 549        SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, cs2000_resume)
 550};
 551
 552static 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
 563module_i2c_driver(cs2000_driver);
 564
 565MODULE_DESCRIPTION("CS2000-CP driver");
 566MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 567MODULE_LICENSE("GPL v2");
 568