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_enable(struct clk_hw *hw)
 347{
 348        struct cs2000_priv *priv = hw_to_priv(hw);
 349        int ret;
 350
 351        ret = cs2000_enable_dev_config(priv, true);
 352        if (ret < 0)
 353                return ret;
 354
 355        ret = cs2000_clk_out_enable(priv, true);
 356        if (ret < 0)
 357                return ret;
 358
 359        ret = cs2000_wait_pll_lock(priv);
 360        if (ret < 0)
 361                return ret;
 362
 363        return ret;
 364}
 365
 366static void cs2000_disable(struct clk_hw *hw)
 367{
 368        struct cs2000_priv *priv = hw_to_priv(hw);
 369
 370        cs2000_enable_dev_config(priv, false);
 371
 372        cs2000_clk_out_enable(priv, false);
 373}
 374
 375static u8 cs2000_get_parent(struct clk_hw *hw)
 376{
 377        /* always return REF_CLK */
 378        return REF_CLK;
 379}
 380
 381static const struct clk_ops cs2000_ops = {
 382        .get_parent     = cs2000_get_parent,
 383        .recalc_rate    = cs2000_recalc_rate,
 384        .round_rate     = cs2000_round_rate,
 385        .set_rate       = cs2000_set_rate,
 386        .prepare        = cs2000_enable,
 387        .unprepare      = cs2000_disable,
 388};
 389
 390static int cs2000_clk_get(struct cs2000_priv *priv)
 391{
 392        struct device *dev = priv_to_dev(priv);
 393        struct clk *clk_in, *ref_clk;
 394
 395        clk_in = devm_clk_get(dev, "clk_in");
 396        /* not yet provided */
 397        if (IS_ERR(clk_in))
 398                return -EPROBE_DEFER;
 399
 400        ref_clk = devm_clk_get(dev, "ref_clk");
 401        /* not yet provided */
 402        if (IS_ERR(ref_clk))
 403                return -EPROBE_DEFER;
 404
 405        priv->clk_in    = clk_in;
 406        priv->ref_clk   = ref_clk;
 407
 408        return 0;
 409}
 410
 411static int cs2000_clk_register(struct cs2000_priv *priv)
 412{
 413        struct device *dev = priv_to_dev(priv);
 414        struct device_node *np = dev->of_node;
 415        struct clk_init_data init;
 416        const char *name = np->name;
 417        static const char *parent_names[CLK_MAX];
 418        int ch = 0; /* it uses ch0 only at this point */
 419        int rate;
 420        int ret;
 421
 422        of_property_read_string(np, "clock-output-names", &name);
 423
 424        /*
 425         * set default rate as 1/1.
 426         * otherwise .set_rate which setup ratio
 427         * is never called if user requests 1/1 rate
 428         */
 429        rate = clk_get_rate(priv->ref_clk);
 430        ret = __cs2000_set_rate(priv, ch, rate, rate);
 431        if (ret < 0)
 432                return ret;
 433
 434        parent_names[CLK_IN]    = __clk_get_name(priv->clk_in);
 435        parent_names[REF_CLK]   = __clk_get_name(priv->ref_clk);
 436
 437        init.name               = name;
 438        init.ops                = &cs2000_ops;
 439        init.flags              = CLK_SET_RATE_GATE;
 440        init.parent_names       = parent_names;
 441        init.num_parents        = ARRAY_SIZE(parent_names);
 442
 443        priv->hw.init = &init;
 444
 445        ret = clk_hw_register(dev, &priv->hw);
 446        if (ret)
 447                return ret;
 448
 449        ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &priv->hw);
 450        if (ret < 0) {
 451                clk_hw_unregister(&priv->hw);
 452                return ret;
 453        }
 454
 455        return 0;
 456}
 457
 458static int cs2000_version_print(struct cs2000_priv *priv)
 459{
 460        struct device *dev = priv_to_dev(priv);
 461        s32 val;
 462        const char *revision;
 463
 464        val = cs2000_read(priv, DEVICE_ID);
 465        if (val < 0)
 466                return val;
 467
 468        /* CS2000 should be 0x0 */
 469        if (val >> 3)
 470                return -EIO;
 471
 472        switch (val & REVISION_MASK) {
 473        case REVISION_B2_B3:
 474                revision = "B2 / B3";
 475                break;
 476        case REVISION_C1:
 477                revision = "C1";
 478                break;
 479        default:
 480                return -EIO;
 481        }
 482
 483        dev_info(dev, "revision - %s\n", revision);
 484
 485        return 0;
 486}
 487
 488static int cs2000_remove(struct i2c_client *client)
 489{
 490        struct cs2000_priv *priv = i2c_get_clientdata(client);
 491        struct device *dev = priv_to_dev(priv);
 492        struct device_node *np = dev->of_node;
 493
 494        of_clk_del_provider(np);
 495
 496        clk_hw_unregister(&priv->hw);
 497
 498        return 0;
 499}
 500
 501static int cs2000_probe(struct i2c_client *client,
 502                        const struct i2c_device_id *id)
 503{
 504        struct cs2000_priv *priv;
 505        struct device *dev = &client->dev;
 506        int ret;
 507
 508        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 509        if (!priv)
 510                return -ENOMEM;
 511
 512        priv->client = client;
 513        i2c_set_clientdata(client, priv);
 514
 515        ret = cs2000_clk_get(priv);
 516        if (ret < 0)
 517                return ret;
 518
 519        ret = cs2000_clk_register(priv);
 520        if (ret < 0)
 521                return ret;
 522
 523        ret = cs2000_version_print(priv);
 524        if (ret < 0)
 525                goto probe_err;
 526
 527        return 0;
 528
 529probe_err:
 530        cs2000_remove(client);
 531
 532        return ret;
 533}
 534
 535static int cs2000_resume(struct device *dev)
 536{
 537        struct cs2000_priv *priv = dev_get_drvdata(dev);
 538        int ch = 0; /* it uses ch0 only at this point */
 539
 540        return __cs2000_set_rate(priv, ch,
 541                                 priv->saved_rate,
 542                                 priv->saved_parent_rate);
 543}
 544
 545static const struct dev_pm_ops cs2000_pm_ops = {
 546        .resume_early   = cs2000_resume,
 547};
 548
 549static struct i2c_driver cs2000_driver = {
 550        .driver = {
 551                .name = "cs2000-cp",
 552                .pm     = &cs2000_pm_ops,
 553                .of_match_table = cs2000_of_match,
 554        },
 555        .probe          = cs2000_probe,
 556        .remove         = cs2000_remove,
 557        .id_table       = cs2000_id,
 558};
 559
 560module_i2c_driver(cs2000_driver);
 561
 562MODULE_DESCRIPTION("CS2000-CP driver");
 563MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
 564MODULE_LICENSE("GPL v2");
 565