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