Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for Silicon Labs Si570/Si571 Programmable XO/VCXO
0004  *
0005  * Copyright (C) 2010, 2011 Ericsson AB.
0006  * Copyright (C) 2011 Guenter Roeck.
0007  * Copyright (C) 2011 - 2021 Xilinx Inc.
0008  *
0009  * Author: Guenter Roeck <guenter.roeck@ericsson.com>
0010  *     Sören Brinkmann <soren.brinkmann@xilinx.com>
0011  */
0012 
0013 #include <linux/clk.h>
0014 #include <linux/clk-provider.h>
0015 #include <linux/delay.h>
0016 #include <linux/module.h>
0017 #include <linux/i2c.h>
0018 #include <linux/regmap.h>
0019 #include <linux/slab.h>
0020 
0021 /* Si570 registers */
0022 #define SI570_REG_HS_N1     7
0023 #define SI570_REG_N1_RFREQ0 8
0024 #define SI570_REG_RFREQ1    9
0025 #define SI570_REG_RFREQ2    10
0026 #define SI570_REG_RFREQ3    11
0027 #define SI570_REG_RFREQ4    12
0028 #define SI570_REG_CONTROL   135
0029 #define SI570_REG_FREEZE_DCO    137
0030 #define SI570_DIV_OFFSET_7PPM   6
0031 
0032 #define HS_DIV_SHIFT        5
0033 #define HS_DIV_MASK     0xe0
0034 #define HS_DIV_OFFSET       4
0035 #define N1_6_2_MASK     0x1f
0036 #define N1_1_0_MASK     0xc0
0037 #define RFREQ_37_32_MASK    0x3f
0038 
0039 #define SI570_MIN_FREQ      10000000L
0040 #define SI570_MAX_FREQ      1417500000L
0041 #define SI598_MAX_FREQ      525000000L
0042 
0043 #define FDCO_MIN        4850000000LL
0044 #define FDCO_MAX        5670000000LL
0045 
0046 #define SI570_CNTRL_RECALL  (1 << 0)
0047 #define SI570_CNTRL_FREEZE_M    (1 << 5)
0048 #define SI570_CNTRL_NEWFREQ (1 << 6)
0049 
0050 #define SI570_FREEZE_DCO    (1 << 4)
0051 
0052 /**
0053  * struct clk_si570:
0054  * @hw: Clock hw struct
0055  * @regmap: Device's regmap
0056  * @div_offset: Rgister offset for dividers
0057  * @max_freq:   Maximum frequency for this device
0058  * @fxtal:  Factory xtal frequency
0059  * @n1:     Clock divider N1
0060  * @hs_div: Clock divider HSDIV
0061  * @rfreq:  Clock multiplier RFREQ
0062  * @frequency:  Current output frequency
0063  * @i2c_client: I2C client pointer
0064  */
0065 struct clk_si570 {
0066     struct clk_hw hw;
0067     struct regmap *regmap;
0068     unsigned int div_offset;
0069     u64 max_freq;
0070     u64 fxtal;
0071     unsigned int n1;
0072     unsigned int hs_div;
0073     u64 rfreq;
0074     u64 frequency;
0075     struct i2c_client *i2c_client;
0076 };
0077 #define to_clk_si570(_hw)   container_of(_hw, struct clk_si570, hw)
0078 
0079 enum clk_si570_variant {
0080     si57x,
0081     si59x
0082 };
0083 
0084 /**
0085  * si570_get_divs() - Read clock dividers from HW
0086  * @data:   Pointer to struct clk_si570
0087  * @rfreq:  Fractional multiplier (output)
0088  * @n1:     Divider N1 (output)
0089  * @hs_div: Divider HSDIV (output)
0090  * Returns 0 on success, negative errno otherwise.
0091  *
0092  * Retrieve clock dividers and multipliers from the HW.
0093  */
0094 static int si570_get_divs(struct clk_si570 *data, u64 *rfreq,
0095         unsigned int *n1, unsigned int *hs_div)
0096 {
0097     int err;
0098     u8 reg[6];
0099     u64 tmp;
0100 
0101     err = regmap_bulk_read(data->regmap, SI570_REG_HS_N1 + data->div_offset,
0102             reg, ARRAY_SIZE(reg));
0103     if (err)
0104         return err;
0105 
0106     *hs_div = ((reg[0] & HS_DIV_MASK) >> HS_DIV_SHIFT) + HS_DIV_OFFSET;
0107     *n1 = ((reg[0] & N1_6_2_MASK) << 2) + ((reg[1] & N1_1_0_MASK) >> 6) + 1;
0108     /* Handle invalid cases */
0109     if (*n1 > 1)
0110         *n1 &= ~1;
0111 
0112     tmp = reg[1] & RFREQ_37_32_MASK;
0113     tmp = (tmp << 8) + reg[2];
0114     tmp = (tmp << 8) + reg[3];
0115     tmp = (tmp << 8) + reg[4];
0116     tmp = (tmp << 8) + reg[5];
0117     *rfreq = tmp;
0118 
0119     return 0;
0120 }
0121 
0122 /**
0123  * si570_get_defaults() - Get default values
0124  * @data:   Driver data structure
0125  * @fout:   Factory frequency output
0126  * @skip_recall:    If true, don't recall NVM into RAM
0127  * Returns 0 on success, negative errno otherwise.
0128  */
0129 static int si570_get_defaults(struct clk_si570 *data, u64 fout,
0130                   bool skip_recall)
0131 {
0132     int err;
0133     u64 fdco;
0134 
0135     if (!skip_recall)
0136         regmap_write(data->regmap, SI570_REG_CONTROL,
0137                  SI570_CNTRL_RECALL);
0138 
0139     err = si570_get_divs(data, &data->rfreq, &data->n1, &data->hs_div);
0140     if (err)
0141         return err;
0142 
0143     /*
0144      * Accept optional precision loss to avoid arithmetic overflows.
0145      * Acceptable per Silicon Labs Application Note AN334.
0146      */
0147     fdco = fout * data->n1 * data->hs_div;
0148     if (fdco >= (1LL << 36))
0149         data->fxtal = div64_u64(fdco << 24, data->rfreq >> 4);
0150     else
0151         data->fxtal = div64_u64(fdco << 28, data->rfreq);
0152 
0153     data->frequency = fout;
0154 
0155     return 0;
0156 }
0157 
0158 /**
0159  * si570_update_rfreq() - Update clock multiplier
0160  * @data:   Driver data structure
0161  * Passes on regmap_bulk_write() return value.
0162  */
0163 static int si570_update_rfreq(struct clk_si570 *data)
0164 {
0165     u8 reg[5];
0166 
0167     reg[0] = ((data->n1 - 1) << 6) |
0168         ((data->rfreq >> 32) & RFREQ_37_32_MASK);
0169     reg[1] = (data->rfreq >> 24) & 0xff;
0170     reg[2] = (data->rfreq >> 16) & 0xff;
0171     reg[3] = (data->rfreq >> 8) & 0xff;
0172     reg[4] = data->rfreq & 0xff;
0173 
0174     return regmap_bulk_write(data->regmap, SI570_REG_N1_RFREQ0 +
0175             data->div_offset, reg, ARRAY_SIZE(reg));
0176 }
0177 
0178 /**
0179  * si570_calc_divs() - Caluclate clock dividers
0180  * @frequency:  Target frequency
0181  * @data:   Driver data structure
0182  * @out_rfreq:  RFREG fractional multiplier (output)
0183  * @out_n1: Clock divider N1 (output)
0184  * @out_hs_div: Clock divider HSDIV (output)
0185  * Returns 0 on success, negative errno otherwise.
0186  *
0187  * Calculate the clock dividers (@out_hs_div, @out_n1) and clock multiplier
0188  * (@out_rfreq) for a given target @frequency.
0189  */
0190 static int si570_calc_divs(unsigned long frequency, struct clk_si570 *data,
0191         u64 *out_rfreq, unsigned int *out_n1, unsigned int *out_hs_div)
0192 {
0193     int i;
0194     unsigned int n1, hs_div;
0195     u64 fdco, best_fdco = ULLONG_MAX;
0196     static const uint8_t si570_hs_div_values[] = { 11, 9, 7, 6, 5, 4 };
0197 
0198     for (i = 0; i < ARRAY_SIZE(si570_hs_div_values); i++) {
0199         hs_div = si570_hs_div_values[i];
0200         /* Calculate lowest possible value for n1 */
0201         n1 = div_u64(div_u64(FDCO_MIN, hs_div), frequency);
0202         if (!n1 || (n1 & 1))
0203             n1++;
0204         while (n1 <= 128) {
0205             fdco = (u64)frequency * (u64)hs_div * (u64)n1;
0206             if (fdco > FDCO_MAX)
0207                 break;
0208             if (fdco >= FDCO_MIN && fdco < best_fdco) {
0209                 *out_n1 = n1;
0210                 *out_hs_div = hs_div;
0211                 *out_rfreq = div64_u64(fdco << 28, data->fxtal);
0212                 best_fdco = fdco;
0213             }
0214             n1 += (n1 == 1 ? 1 : 2);
0215         }
0216     }
0217 
0218     if (best_fdco == ULLONG_MAX)
0219         return -EINVAL;
0220 
0221     return 0;
0222 }
0223 
0224 static unsigned long si570_recalc_rate(struct clk_hw *hw,
0225         unsigned long parent_rate)
0226 {
0227     int err;
0228     u64 rfreq, rate;
0229     unsigned int n1, hs_div;
0230     struct clk_si570 *data = to_clk_si570(hw);
0231 
0232     err = si570_get_divs(data, &rfreq, &n1, &hs_div);
0233     if (err) {
0234         dev_err(&data->i2c_client->dev, "unable to recalc rate\n");
0235         return data->frequency;
0236     }
0237 
0238     rfreq = div_u64(rfreq, hs_div * n1);
0239     rate = (data->fxtal * rfreq) >> 28;
0240 
0241     return rate;
0242 }
0243 
0244 static long si570_round_rate(struct clk_hw *hw, unsigned long rate,
0245         unsigned long *parent_rate)
0246 {
0247     int err;
0248     u64 rfreq;
0249     unsigned int n1, hs_div;
0250     struct clk_si570 *data = to_clk_si570(hw);
0251 
0252     if (!rate)
0253         return 0;
0254 
0255     if (div64_u64(abs(rate - data->frequency) * 10000LL,
0256                 data->frequency) < 35) {
0257         rfreq = div64_u64((data->rfreq * rate) +
0258                 div64_u64(data->frequency, 2), data->frequency);
0259         n1 = data->n1;
0260         hs_div = data->hs_div;
0261 
0262     } else {
0263         err = si570_calc_divs(rate, data, &rfreq, &n1, &hs_div);
0264         if (err) {
0265             dev_err(&data->i2c_client->dev,
0266                     "unable to round rate\n");
0267             return 0;
0268         }
0269     }
0270 
0271     return rate;
0272 }
0273 
0274 /**
0275  * si570_set_frequency() - Adjust output frequency
0276  * @data:   Driver data structure
0277  * @frequency:  Target frequency
0278  * Returns 0 on success.
0279  *
0280  * Update output frequency for big frequency changes (> 3,500 ppm).
0281  */
0282 static int si570_set_frequency(struct clk_si570 *data, unsigned long frequency)
0283 {
0284     int err;
0285 
0286     err = si570_calc_divs(frequency, data, &data->rfreq, &data->n1,
0287             &data->hs_div);
0288     if (err)
0289         return err;
0290 
0291     /*
0292      * The DCO reg should be accessed with a read-modify-write operation
0293      * per AN334
0294      */
0295     regmap_write(data->regmap, SI570_REG_FREEZE_DCO, SI570_FREEZE_DCO);
0296     regmap_write(data->regmap, SI570_REG_HS_N1 + data->div_offset,
0297             ((data->hs_div - HS_DIV_OFFSET) << HS_DIV_SHIFT) |
0298             (((data->n1 - 1) >> 2) & N1_6_2_MASK));
0299     si570_update_rfreq(data);
0300     regmap_write(data->regmap, SI570_REG_FREEZE_DCO, 0);
0301     regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_NEWFREQ);
0302 
0303     /* Applying a new frequency can take up to 10ms */
0304     usleep_range(10000, 12000);
0305 
0306     return 0;
0307 }
0308 
0309 /**
0310  * si570_set_frequency_small() - Adjust output frequency
0311  * @data:   Driver data structure
0312  * @frequency:  Target frequency
0313  * Returns 0 on success.
0314  *
0315  * Update output frequency for small frequency changes (< 3,500 ppm).
0316  */
0317 static int si570_set_frequency_small(struct clk_si570 *data,
0318                      unsigned long frequency)
0319 {
0320     /*
0321      * This is a re-implementation of DIV_ROUND_CLOSEST
0322      * using the div64_u64 function lieu of letting the compiler
0323      * insert EABI calls
0324      */
0325     data->rfreq = div64_u64((data->rfreq * frequency) +
0326             div_u64(data->frequency, 2), data->frequency);
0327     regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_FREEZE_M);
0328     si570_update_rfreq(data);
0329     regmap_write(data->regmap, SI570_REG_CONTROL, 0);
0330 
0331     /* Applying a new frequency (small change) can take up to 100us */
0332     usleep_range(100, 200);
0333 
0334     return 0;
0335 }
0336 
0337 static int si570_set_rate(struct clk_hw *hw, unsigned long rate,
0338         unsigned long parent_rate)
0339 {
0340     struct clk_si570 *data = to_clk_si570(hw);
0341     struct i2c_client *client = data->i2c_client;
0342     int err;
0343 
0344     if (rate < SI570_MIN_FREQ || rate > data->max_freq) {
0345         dev_err(&client->dev,
0346             "requested frequency %lu Hz is out of range\n", rate);
0347         return -EINVAL;
0348     }
0349 
0350     if (div64_u64(abs(rate - data->frequency) * 10000LL,
0351                 data->frequency) < 35)
0352         err = si570_set_frequency_small(data, rate);
0353     else
0354         err = si570_set_frequency(data, rate);
0355 
0356     if (err)
0357         return err;
0358 
0359     data->frequency = rate;
0360 
0361     return 0;
0362 }
0363 
0364 static const struct clk_ops si570_clk_ops = {
0365     .recalc_rate = si570_recalc_rate,
0366     .round_rate = si570_round_rate,
0367     .set_rate = si570_set_rate,
0368 };
0369 
0370 static bool si570_regmap_is_volatile(struct device *dev, unsigned int reg)
0371 {
0372     switch (reg) {
0373     case SI570_REG_CONTROL:
0374         return true;
0375     default:
0376         return false;
0377     }
0378 }
0379 
0380 static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg)
0381 {
0382     switch (reg) {
0383     case SI570_REG_HS_N1 ... (SI570_REG_RFREQ4 + SI570_DIV_OFFSET_7PPM):
0384     case SI570_REG_CONTROL:
0385     case SI570_REG_FREEZE_DCO:
0386         return true;
0387     default:
0388         return false;
0389     }
0390 }
0391 
0392 static const struct regmap_config si570_regmap_config = {
0393     .reg_bits = 8,
0394     .val_bits = 8,
0395     .cache_type = REGCACHE_RBTREE,
0396     .max_register = 137,
0397     .writeable_reg = si570_regmap_is_writeable,
0398     .volatile_reg = si570_regmap_is_volatile,
0399 };
0400 
0401 static const struct i2c_device_id si570_id[] = {
0402     { "si570", si57x },
0403     { "si571", si57x },
0404     { "si598", si59x },
0405     { "si599", si59x },
0406     { }
0407 };
0408 MODULE_DEVICE_TABLE(i2c, si570_id);
0409 
0410 static int si570_probe(struct i2c_client *client)
0411 {
0412     struct clk_si570 *data;
0413     struct clk_init_data init;
0414     const struct i2c_device_id *id = i2c_match_id(si570_id, client);
0415     u32 initial_fout, factory_fout, stability;
0416     bool skip_recall;
0417     int err;
0418     enum clk_si570_variant variant = id->driver_data;
0419 
0420     data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
0421     if (!data)
0422         return -ENOMEM;
0423 
0424     init.ops = &si570_clk_ops;
0425     init.flags = 0;
0426     init.num_parents = 0;
0427     data->hw.init = &init;
0428     data->i2c_client = client;
0429 
0430     if (variant == si57x) {
0431         err = of_property_read_u32(client->dev.of_node,
0432                 "temperature-stability", &stability);
0433         if (err) {
0434             dev_err(&client->dev,
0435                   "'temperature-stability' property missing\n");
0436             return err;
0437         }
0438         /* adjust register offsets for 7ppm devices */
0439         if (stability == 7)
0440             data->div_offset = SI570_DIV_OFFSET_7PPM;
0441 
0442         data->max_freq = SI570_MAX_FREQ;
0443     } else {
0444         data->max_freq = SI598_MAX_FREQ;
0445     }
0446 
0447     if (of_property_read_string(client->dev.of_node, "clock-output-names",
0448             &init.name))
0449         init.name = client->dev.of_node->name;
0450 
0451     err = of_property_read_u32(client->dev.of_node, "factory-fout",
0452             &factory_fout);
0453     if (err) {
0454         dev_err(&client->dev, "'factory-fout' property missing\n");
0455         return err;
0456     }
0457 
0458     skip_recall = of_property_read_bool(client->dev.of_node,
0459                         "silabs,skip-recall");
0460 
0461     data->regmap = devm_regmap_init_i2c(client, &si570_regmap_config);
0462     if (IS_ERR(data->regmap)) {
0463         dev_err(&client->dev, "failed to allocate register map\n");
0464         return PTR_ERR(data->regmap);
0465     }
0466 
0467     i2c_set_clientdata(client, data);
0468     err = si570_get_defaults(data, factory_fout, skip_recall);
0469     if (err)
0470         return err;
0471 
0472     err = devm_clk_hw_register(&client->dev, &data->hw);
0473     if (err) {
0474         dev_err(&client->dev, "clock registration failed\n");
0475         return err;
0476     }
0477     err = of_clk_add_hw_provider(client->dev.of_node, of_clk_hw_simple_get,
0478                      &data->hw);
0479     if (err) {
0480         dev_err(&client->dev, "unable to add clk provider\n");
0481         return err;
0482     }
0483 
0484     /* Read the requested initial output frequency from device tree */
0485     if (!of_property_read_u32(client->dev.of_node, "clock-frequency",
0486                 &initial_fout)) {
0487         err = clk_set_rate(data->hw.clk, initial_fout);
0488         if (err) {
0489             of_clk_del_provider(client->dev.of_node);
0490             return err;
0491         }
0492     }
0493 
0494     /* Display a message indicating that we've successfully registered */
0495     dev_info(&client->dev, "registered, current frequency %llu Hz\n",
0496             data->frequency);
0497 
0498     return 0;
0499 }
0500 
0501 static int si570_remove(struct i2c_client *client)
0502 {
0503     of_clk_del_provider(client->dev.of_node);
0504     return 0;
0505 }
0506 
0507 static const struct of_device_id clk_si570_of_match[] = {
0508     { .compatible = "silabs,si570" },
0509     { .compatible = "silabs,si571" },
0510     { .compatible = "silabs,si598" },
0511     { .compatible = "silabs,si599" },
0512     { },
0513 };
0514 MODULE_DEVICE_TABLE(of, clk_si570_of_match);
0515 
0516 static struct i2c_driver si570_driver = {
0517     .driver = {
0518         .name = "si570",
0519         .of_match_table = clk_si570_of_match,
0520     },
0521     .probe_new  = si570_probe,
0522     .remove     = si570_remove,
0523     .id_table   = si570_id,
0524 };
0525 module_i2c_driver(si570_driver);
0526 
0527 MODULE_AUTHOR("Guenter Roeck <guenter.roeck@ericsson.com>");
0528 MODULE_AUTHOR("Soeren Brinkmann <soren.brinkmann@xilinx.com>");
0529 MODULE_DESCRIPTION("Si570 driver");
0530 MODULE_LICENSE("GPL");