root/drivers/clk/clk-si544.c

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

DEFINITIONS

This source file includes following definitions.
  1. si544_enable_output
  2. si544_prepare
  3. si544_unprepare
  4. si544_is_prepared
  5. si544_get_muldiv
  6. si544_set_delta_m
  7. si544_set_muldiv
  8. is_valid_frequency
  9. si544_calc_muldiv
  10. si544_calc_center_rate
  11. si544_calc_rate
  12. si544_recalc_rate
  13. si544_round_rate
  14. si544_max_delta
  15. si544_calc_delta
  16. si544_set_rate
  17. si544_regmap_is_volatile
  18. si544_probe

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Driver for Silicon Labs Si544 Programmable Oscillator
   4  * Copyright (C) 2018 Topic Embedded Products
   5  * Author: Mike Looijmans <mike.looijmans@topic.nl>
   6  */
   7 
   8 #include <linux/clk-provider.h>
   9 #include <linux/delay.h>
  10 #include <linux/math64.h>
  11 #include <linux/module.h>
  12 #include <linux/i2c.h>
  13 #include <linux/regmap.h>
  14 #include <linux/slab.h>
  15 
  16 /* I2C registers (decimal as in datasheet) */
  17 #define SI544_REG_CONTROL       7
  18 #define SI544_REG_OE_STATE      17
  19 #define SI544_REG_HS_DIV        23
  20 #define SI544_REG_LS_HS_DIV     24
  21 #define SI544_REG_FBDIV0        26
  22 #define SI544_REG_FBDIV8        27
  23 #define SI544_REG_FBDIV16       28
  24 #define SI544_REG_FBDIV24       29
  25 #define SI544_REG_FBDIV32       30
  26 #define SI544_REG_FBDIV40       31
  27 #define SI544_REG_FCAL_OVR      69
  28 #define SI544_REG_ADPLL_DELTA_M0        231
  29 #define SI544_REG_ADPLL_DELTA_M8        232
  30 #define SI544_REG_ADPLL_DELTA_M16       233
  31 #define SI544_REG_PAGE_SELECT   255
  32 
  33 /* Register values */
  34 #define SI544_CONTROL_RESET     BIT(7)
  35 #define SI544_CONTROL_MS_ICAL2  BIT(3)
  36 
  37 #define SI544_OE_STATE_ODC_OE   BIT(0)
  38 
  39 /* Max freq depends on speed grade */
  40 #define SI544_MIN_FREQ      200000U
  41 
  42 /* Si544 Internal oscilator runs at 55.05 MHz */
  43 #define FXO               55050000U
  44 
  45 /* VCO range is 10.8 .. 12.1 GHz, max depends on speed grade */
  46 #define FVCO_MIN       10800000000ULL
  47 
  48 #define HS_DIV_MAX      2046
  49 #define HS_DIV_MAX_ODD  33
  50 
  51 /* Lowest frequency synthesizeable using only the HS divider */
  52 #define MIN_HSDIV_FREQ  (FVCO_MIN / HS_DIV_MAX)
  53 
  54 /* Range and interpretation of the adjustment value */
  55 #define DELTA_M_MAX     8161512
  56 #define DELTA_M_FRAC_NUM        19
  57 #define DELTA_M_FRAC_DEN        20000
  58 
  59 enum si544_speed_grade {
  60         si544a,
  61         si544b,
  62         si544c,
  63 };
  64 
  65 struct clk_si544 {
  66         struct clk_hw hw;
  67         struct regmap *regmap;
  68         struct i2c_client *i2c_client;
  69         enum si544_speed_grade speed_grade;
  70 };
  71 #define to_clk_si544(_hw)       container_of(_hw, struct clk_si544, hw)
  72 
  73 /**
  74  * struct clk_si544_muldiv - Multiplier/divider settings
  75  * @fb_div_frac:        integer part of feedback divider (32 bits)
  76  * @fb_div_int:         fractional part of feedback divider (11 bits)
  77  * @hs_div:             1st divider, 5..2046, must be even when >33
  78  * @ls_div_bits:        2nd divider, as 2^x, range 0..5
  79  *                      If ls_div_bits is non-zero, hs_div must be even
  80  * @delta_m:            Frequency shift for small -950..+950 ppm changes, 24 bit
  81  */
  82 struct clk_si544_muldiv {
  83         u32 fb_div_frac;
  84         u16 fb_div_int;
  85         u16 hs_div;
  86         u8 ls_div_bits;
  87         s32 delta_m;
  88 };
  89 
  90 /* Enables or disables the output driver */
  91 static int si544_enable_output(struct clk_si544 *data, bool enable)
  92 {
  93         return regmap_update_bits(data->regmap, SI544_REG_OE_STATE,
  94                 SI544_OE_STATE_ODC_OE, enable ? SI544_OE_STATE_ODC_OE : 0);
  95 }
  96 
  97 static int si544_prepare(struct clk_hw *hw)
  98 {
  99         struct clk_si544 *data = to_clk_si544(hw);
 100 
 101         return si544_enable_output(data, true);
 102 }
 103 
 104 static void si544_unprepare(struct clk_hw *hw)
 105 {
 106         struct clk_si544 *data = to_clk_si544(hw);
 107 
 108         si544_enable_output(data, false);
 109 }
 110 
 111 static int si544_is_prepared(struct clk_hw *hw)
 112 {
 113         struct clk_si544 *data = to_clk_si544(hw);
 114         unsigned int val;
 115         int err;
 116 
 117         err = regmap_read(data->regmap, SI544_REG_OE_STATE, &val);
 118         if (err < 0)
 119                 return err;
 120 
 121         return !!(val & SI544_OE_STATE_ODC_OE);
 122 }
 123 
 124 /* Retrieve clock multiplier and dividers from hardware */
 125 static int si544_get_muldiv(struct clk_si544 *data,
 126         struct clk_si544_muldiv *settings)
 127 {
 128         int err;
 129         u8 reg[6];
 130 
 131         err = regmap_bulk_read(data->regmap, SI544_REG_HS_DIV, reg, 2);
 132         if (err)
 133                 return err;
 134 
 135         settings->ls_div_bits = (reg[1] >> 4) & 0x07;
 136         settings->hs_div = (reg[1] & 0x07) << 8 | reg[0];
 137 
 138         err = regmap_bulk_read(data->regmap, SI544_REG_FBDIV0, reg, 6);
 139         if (err)
 140                 return err;
 141 
 142         settings->fb_div_int = reg[4] | (reg[5] & 0x07) << 8;
 143         settings->fb_div_frac = reg[0] | reg[1] << 8 | reg[2] << 16 |
 144                                 reg[3] << 24;
 145 
 146         err = regmap_bulk_read(data->regmap, SI544_REG_ADPLL_DELTA_M0, reg, 3);
 147         if (err)
 148                 return err;
 149 
 150         /* Interpret as 24-bit signed number */
 151         settings->delta_m = reg[0] << 8 | reg[1] << 16 | reg[2] << 24;
 152         settings->delta_m >>= 8;
 153 
 154         return 0;
 155 }
 156 
 157 static int si544_set_delta_m(struct clk_si544 *data, s32 delta_m)
 158 {
 159         u8 reg[3];
 160 
 161         reg[0] = delta_m;
 162         reg[1] = delta_m >> 8;
 163         reg[2] = delta_m >> 16;
 164 
 165         return regmap_bulk_write(data->regmap, SI544_REG_ADPLL_DELTA_M0,
 166                                  reg, 3);
 167 }
 168 
 169 static int si544_set_muldiv(struct clk_si544 *data,
 170         struct clk_si544_muldiv *settings)
 171 {
 172         int err;
 173         u8 reg[6];
 174 
 175         reg[0] = settings->hs_div;
 176         reg[1] = settings->hs_div >> 8 | settings->ls_div_bits << 4;
 177 
 178         err = regmap_bulk_write(data->regmap, SI544_REG_HS_DIV, reg, 2);
 179         if (err < 0)
 180                 return err;
 181 
 182         reg[0] = settings->fb_div_frac;
 183         reg[1] = settings->fb_div_frac >> 8;
 184         reg[2] = settings->fb_div_frac >> 16;
 185         reg[3] = settings->fb_div_frac >> 24;
 186         reg[4] = settings->fb_div_int;
 187         reg[5] = settings->fb_div_int >> 8;
 188 
 189         /*
 190          * Writing to SI544_REG_FBDIV40 triggers the clock change, so that
 191          * must be written last
 192          */
 193         return regmap_bulk_write(data->regmap, SI544_REG_FBDIV0, reg, 6);
 194 }
 195 
 196 static bool is_valid_frequency(const struct clk_si544 *data,
 197         unsigned long frequency)
 198 {
 199         unsigned long max_freq = 0;
 200 
 201         if (frequency < SI544_MIN_FREQ)
 202                 return false;
 203 
 204         switch (data->speed_grade) {
 205         case si544a:
 206                 max_freq = 1500000000;
 207                 break;
 208         case si544b:
 209                 max_freq = 800000000;
 210                 break;
 211         case si544c:
 212                 max_freq = 350000000;
 213                 break;
 214         }
 215 
 216         return frequency <= max_freq;
 217 }
 218 
 219 /* Calculate divider settings for a given frequency */
 220 static int si544_calc_muldiv(struct clk_si544_muldiv *settings,
 221         unsigned long frequency)
 222 {
 223         u64 vco;
 224         u32 ls_freq;
 225         u32 tmp;
 226         u8 res;
 227 
 228         /* Determine the minimum value of LS_DIV and resulting target freq. */
 229         ls_freq = frequency;
 230         settings->ls_div_bits = 0;
 231 
 232         if (frequency >= MIN_HSDIV_FREQ) {
 233                 settings->ls_div_bits = 0;
 234         } else {
 235                 res = 1;
 236                 tmp = 2 * HS_DIV_MAX;
 237                 while (tmp <= (HS_DIV_MAX * 32)) {
 238                         if (((u64)frequency * tmp) >= FVCO_MIN)
 239                                 break;
 240                         ++res;
 241                         tmp <<= 1;
 242                 }
 243                 settings->ls_div_bits = res;
 244                 ls_freq = frequency << res;
 245         }
 246 
 247         /* Determine minimum HS_DIV by rounding up */
 248         vco = FVCO_MIN + ls_freq - 1;
 249         do_div(vco, ls_freq);
 250         settings->hs_div = vco;
 251 
 252         /* round up to even number when required */
 253         if ((settings->hs_div & 1) &&
 254             (settings->hs_div > HS_DIV_MAX_ODD || settings->ls_div_bits))
 255                 ++settings->hs_div;
 256 
 257         /* Calculate VCO frequency (in 10..12GHz range) */
 258         vco = (u64)ls_freq * settings->hs_div;
 259 
 260         /* Calculate the integer part of the feedback divider */
 261         tmp = do_div(vco, FXO);
 262         settings->fb_div_int = vco;
 263 
 264         /* And the fractional bits using the remainder */
 265         vco = (u64)tmp << 32;
 266         vco += FXO / 2; /* Round to nearest multiple */
 267         do_div(vco, FXO);
 268         settings->fb_div_frac = vco;
 269 
 270         /* Reset the frequency adjustment */
 271         settings->delta_m = 0;
 272 
 273         return 0;
 274 }
 275 
 276 /* Calculate resulting frequency given the register settings */
 277 static unsigned long si544_calc_center_rate(
 278                 const struct clk_si544_muldiv *settings)
 279 {
 280         u32 d = settings->hs_div * BIT(settings->ls_div_bits);
 281         u64 vco;
 282 
 283         /* Calculate VCO from the fractional part */
 284         vco = (u64)settings->fb_div_frac * FXO;
 285         vco += (FXO / 2);
 286         vco >>= 32;
 287 
 288         /* Add the integer part of the VCO frequency */
 289         vco += (u64)settings->fb_div_int * FXO;
 290 
 291         /* Apply divider to obtain the generated frequency */
 292         do_div(vco, d);
 293 
 294         return vco;
 295 }
 296 
 297 static unsigned long si544_calc_rate(const struct clk_si544_muldiv *settings)
 298 {
 299         unsigned long rate = si544_calc_center_rate(settings);
 300         s64 delta = (s64)rate * (DELTA_M_FRAC_NUM * settings->delta_m);
 301 
 302         /*
 303          * The clock adjustment is much smaller than 1 Hz, round to the
 304          * nearest multiple. Apparently div64_s64 rounds towards zero, hence
 305          * check the sign and adjust into the proper direction.
 306          */
 307         if (settings->delta_m < 0)
 308                 delta -= ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
 309         else
 310                 delta += ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN) / 2;
 311         delta = div64_s64(delta, ((s64)DELTA_M_MAX * DELTA_M_FRAC_DEN));
 312 
 313         return rate + delta;
 314 }
 315 
 316 static unsigned long si544_recalc_rate(struct clk_hw *hw,
 317                 unsigned long parent_rate)
 318 {
 319         struct clk_si544 *data = to_clk_si544(hw);
 320         struct clk_si544_muldiv settings;
 321         int err;
 322 
 323         err = si544_get_muldiv(data, &settings);
 324         if (err)
 325                 return 0;
 326 
 327         return si544_calc_rate(&settings);
 328 }
 329 
 330 static long si544_round_rate(struct clk_hw *hw, unsigned long rate,
 331                 unsigned long *parent_rate)
 332 {
 333         struct clk_si544 *data = to_clk_si544(hw);
 334 
 335         if (!is_valid_frequency(data, rate))
 336                 return -EINVAL;
 337 
 338         /* The accuracy is less than 1 Hz, so any rate is possible */
 339         return rate;
 340 }
 341 
 342 /* Calculates the maximum "small" change, 950 * rate / 1000000 */
 343 static unsigned long si544_max_delta(unsigned long rate)
 344 {
 345         u64 num = rate;
 346 
 347         num *= DELTA_M_FRAC_NUM;
 348         do_div(num, DELTA_M_FRAC_DEN);
 349 
 350         return num;
 351 }
 352 
 353 static s32 si544_calc_delta(s32 delta, s32 max_delta)
 354 {
 355         s64 n = (s64)delta * DELTA_M_MAX;
 356 
 357         return div_s64(n, max_delta);
 358 }
 359 
 360 static int si544_set_rate(struct clk_hw *hw, unsigned long rate,
 361                 unsigned long parent_rate)
 362 {
 363         struct clk_si544 *data = to_clk_si544(hw);
 364         struct clk_si544_muldiv settings;
 365         unsigned long center;
 366         long max_delta;
 367         long delta;
 368         unsigned int old_oe_state;
 369         int err;
 370 
 371         if (!is_valid_frequency(data, rate))
 372                 return -EINVAL;
 373 
 374         /* Try using the frequency adjustment feature for a <= 950ppm change */
 375         err = si544_get_muldiv(data, &settings);
 376         if (err)
 377                 return err;
 378 
 379         center = si544_calc_center_rate(&settings);
 380         max_delta = si544_max_delta(center);
 381         delta = rate - center;
 382 
 383         if (abs(delta) <= max_delta)
 384                 return si544_set_delta_m(data,
 385                                          si544_calc_delta(delta, max_delta));
 386 
 387         /* Too big for the delta adjustment, need to reprogram */
 388         err = si544_calc_muldiv(&settings, rate);
 389         if (err)
 390                 return err;
 391 
 392         err = regmap_read(data->regmap, SI544_REG_OE_STATE, &old_oe_state);
 393         if (err)
 394                 return err;
 395 
 396         si544_enable_output(data, false);
 397 
 398         /* Allow FCAL for this frequency update */
 399         err = regmap_write(data->regmap, SI544_REG_FCAL_OVR, 0);
 400         if (err < 0)
 401                 return err;
 402 
 403         err = si544_set_delta_m(data, settings.delta_m);
 404         if (err < 0)
 405                 return err;
 406 
 407         err = si544_set_muldiv(data, &settings);
 408         if (err < 0)
 409                 return err; /* Undefined state now, best to leave disabled */
 410 
 411         /* Trigger calibration */
 412         err = regmap_write(data->regmap, SI544_REG_CONTROL,
 413                            SI544_CONTROL_MS_ICAL2);
 414         if (err < 0)
 415                 return err;
 416 
 417         /* Applying a new frequency can take up to 10ms */
 418         usleep_range(10000, 12000);
 419 
 420         if (old_oe_state & SI544_OE_STATE_ODC_OE)
 421                 si544_enable_output(data, true);
 422 
 423         return err;
 424 }
 425 
 426 static const struct clk_ops si544_clk_ops = {
 427         .prepare = si544_prepare,
 428         .unprepare = si544_unprepare,
 429         .is_prepared = si544_is_prepared,
 430         .recalc_rate = si544_recalc_rate,
 431         .round_rate = si544_round_rate,
 432         .set_rate = si544_set_rate,
 433 };
 434 
 435 static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg)
 436 {
 437         switch (reg) {
 438         case SI544_REG_CONTROL:
 439         case SI544_REG_FCAL_OVR:
 440                 return true;
 441         default:
 442                 return false;
 443         }
 444 }
 445 
 446 static const struct regmap_config si544_regmap_config = {
 447         .reg_bits = 8,
 448         .val_bits = 8,
 449         .cache_type = REGCACHE_RBTREE,
 450         .max_register = SI544_REG_PAGE_SELECT,
 451         .volatile_reg = si544_regmap_is_volatile,
 452 };
 453 
 454 static int si544_probe(struct i2c_client *client,
 455                 const struct i2c_device_id *id)
 456 {
 457         struct clk_si544 *data;
 458         struct clk_init_data init;
 459         int err;
 460 
 461         data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
 462         if (!data)
 463                 return -ENOMEM;
 464 
 465         init.ops = &si544_clk_ops;
 466         init.flags = 0;
 467         init.num_parents = 0;
 468         data->hw.init = &init;
 469         data->i2c_client = client;
 470         data->speed_grade = id->driver_data;
 471 
 472         if (of_property_read_string(client->dev.of_node, "clock-output-names",
 473                         &init.name))
 474                 init.name = client->dev.of_node->name;
 475 
 476         data->regmap = devm_regmap_init_i2c(client, &si544_regmap_config);
 477         if (IS_ERR(data->regmap))
 478                 return PTR_ERR(data->regmap);
 479 
 480         i2c_set_clientdata(client, data);
 481 
 482         /* Select page 0, just to be sure, there appear to be no more */
 483         err = regmap_write(data->regmap, SI544_REG_PAGE_SELECT, 0);
 484         if (err < 0)
 485                 return err;
 486 
 487         err = devm_clk_hw_register(&client->dev, &data->hw);
 488         if (err) {
 489                 dev_err(&client->dev, "clock registration failed\n");
 490                 return err;
 491         }
 492         err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get,
 493                                           &data->hw);
 494         if (err) {
 495                 dev_err(&client->dev, "unable to add clk provider\n");
 496                 return err;
 497         }
 498 
 499         return 0;
 500 }
 501 
 502 static const struct i2c_device_id si544_id[] = {
 503         { "si544a", si544a },
 504         { "si544b", si544b },
 505         { "si544c", si544c },
 506         { }
 507 };
 508 MODULE_DEVICE_TABLE(i2c, si544_id);
 509 
 510 static const struct of_device_id clk_si544_of_match[] = {
 511         { .compatible = "silabs,si544a" },
 512         { .compatible = "silabs,si544b" },
 513         { .compatible = "silabs,si544c" },
 514         { },
 515 };
 516 MODULE_DEVICE_TABLE(of, clk_si544_of_match);
 517 
 518 static struct i2c_driver si544_driver = {
 519         .driver = {
 520                 .name = "si544",
 521                 .of_match_table = clk_si544_of_match,
 522         },
 523         .probe          = si544_probe,
 524         .id_table       = si544_id,
 525 };
 526 module_i2c_driver(si544_driver);
 527 
 528 MODULE_AUTHOR("Mike Looijmans <mike.looijmans@topic.nl>");
 529 MODULE_DESCRIPTION("Si544 driver");
 530 MODULE_LICENSE("GPL");

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