0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
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
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
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
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
0086
0087
0088
0089
0090
0091
0092
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
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
0124
0125
0126
0127
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
0145
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
0160
0161
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
0180
0181
0182
0183
0184
0185
0186
0187
0188
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
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
0276
0277
0278
0279
0280
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
0293
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
0304 usleep_range(10000, 12000);
0305
0306 return 0;
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317 static int si570_set_frequency_small(struct clk_si570 *data,
0318 unsigned long frequency)
0319 {
0320
0321
0322
0323
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
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
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
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
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");