Lines Matching +full:clock +full:- +full:frequency

1 // SPDX-License-Identifier: GPL-2.0-or-later
7 * Copyright (C) 2011 - 2021 Xilinx Inc.
14 #include <linux/clk-provider.h>
54 * @max_freq: Maximum frequency for this device
64 * @hw: Clock hw struct
68 * @fxtal: Factory xtal frequency
69 * @n1: Clock divider N1
70 * @hs_div: Clock divider HSDIV
71 * @rfreq: Clock multiplier RFREQ
72 * @frequency: Current output frequency
84 u64 frequency;
90 * si570_get_divs() - Read clock dividers from HW
97 * Retrieve clock dividers and multipliers from the HW.
106 err = regmap_bulk_read(data->regmap, SI570_REG_HS_N1 + data->div_offset,
128 * si570_get_defaults() - Get default values
130 * @fout: Factory frequency output
141 regmap_write(data->regmap, SI570_REG_CONTROL,
144 err = si570_get_divs(data, &data->rfreq, &data->n1, &data->hs_div);
152 fdco = fout * data->n1 * data->hs_div;
154 data->fxtal = div64_u64(fdco << 24, data->rfreq >> 4);
156 data->fxtal = div64_u64(fdco << 28, data->rfreq);
158 data->frequency = fout;
164 * si570_update_rfreq() - Update clock multiplier
172 reg[0] = ((data->n1 - 1) << 6) |
173 ((data->rfreq >> 32) & RFREQ_37_32_MASK);
174 reg[1] = (data->rfreq >> 24) & 0xff;
175 reg[2] = (data->rfreq >> 16) & 0xff;
176 reg[3] = (data->rfreq >> 8) & 0xff;
177 reg[4] = data->rfreq & 0xff;
179 return regmap_bulk_write(data->regmap, SI570_REG_N1_RFREQ0 +
180 data->div_offset, reg, ARRAY_SIZE(reg));
184 * si570_calc_divs() - Caluclate clock dividers
185 * @frequency: Target frequency
188 * @out_n1: Clock divider N1 (output)
189 * @out_hs_div: Clock divider HSDIV (output)
192 * Calculate the clock dividers (@out_hs_div, @out_n1) and clock multiplier
193 * (@out_rfreq) for a given target @frequency.
195 static int si570_calc_divs(unsigned long frequency, struct clk_si570 *data,
206 n1 = div_u64(div_u64(FDCO_MIN, hs_div), frequency);
210 fdco = (u64)frequency * (u64)hs_div * (u64)n1;
216 *out_rfreq = div64_u64(fdco << 28, data->fxtal);
224 return -EINVAL;
239 dev_err(&data->i2c_client->dev, "unable to recalc rate\n");
240 return data->frequency;
244 rate = (data->fxtal * rfreq) >> 28;
260 if (div64_u64(abs(rate - data->frequency) * 10000LL,
261 data->frequency) < 35) {
262 rfreq = div64_u64((data->rfreq * rate) +
263 div64_u64(data->frequency, 2), data->frequency);
264 n1 = data->n1;
265 hs_div = data->hs_div;
270 dev_err(&data->i2c_client->dev,
280 * si570_set_frequency() - Adjust output frequency
282 * @frequency: Target frequency
285 * Update output frequency for big frequency changes (> 3,500 ppm).
287 static int si570_set_frequency(struct clk_si570 *data, unsigned long frequency)
291 err = si570_calc_divs(frequency, data, &data->rfreq, &data->n1,
292 &data->hs_div);
297 * The DCO reg should be accessed with a read-modify-write operation
300 regmap_write(data->regmap, SI570_REG_FREEZE_DCO, SI570_FREEZE_DCO);
301 regmap_write(data->regmap, SI570_REG_HS_N1 + data->div_offset,
302 ((data->hs_div - HS_DIV_OFFSET) << HS_DIV_SHIFT) |
303 (((data->n1 - 1) >> 2) & N1_6_2_MASK));
305 regmap_write(data->regmap, SI570_REG_FREEZE_DCO, 0);
306 regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_NEWFREQ);
308 /* Applying a new frequency can take up to 10ms */
315 * si570_set_frequency_small() - Adjust output frequency
317 * @frequency: Target frequency
320 * Update output frequency for small frequency changes (< 3,500 ppm).
323 unsigned long frequency)
326 * This is a re-implementation of DIV_ROUND_CLOSEST
330 data->rfreq = div64_u64((data->rfreq * frequency) +
331 div_u64(data->frequency, 2), data->frequency);
332 regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_FREEZE_M);
334 regmap_write(data->regmap, SI570_REG_CONTROL, 0);
336 /* Applying a new frequency (small change) can take up to 100us */
346 struct i2c_client *client = data->i2c_client;
349 if (rate < SI570_MIN_FREQ || rate > data->info->max_freq) {
350 dev_err(&client->dev,
351 "requested frequency %lu Hz is out of range\n", rate);
352 return -EINVAL;
355 if (div64_u64(abs(rate - data->frequency) * 10000LL,
356 data->frequency) < 35)
364 data->frequency = rate;
414 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
416 return -ENOMEM;
421 data->hw.init = &init;
422 data->i2c_client = client;
424 data->info = i2c_get_match_data(client);
425 if (data->info->has_temperature_stability) {
426 err = of_property_read_u32(client->dev.of_node,
427 "temperature-stability", &stability);
429 dev_err(&client->dev,
430 "'temperature-stability' property missing\n");
435 data->div_offset = SI570_DIV_OFFSET_7PPM;
438 if (of_property_read_string(client->dev.of_node, "clock-output-names",
440 init.name = client->dev.of_node->name;
442 err = of_property_read_u32(client->dev.of_node, "factory-fout",
445 dev_err(&client->dev, "'factory-fout' property missing\n");
449 skip_recall = of_property_read_bool(client->dev.of_node,
450 "silabs,skip-recall");
452 data->regmap = devm_regmap_init_i2c(client, &si570_regmap_config);
453 if (IS_ERR(data->regmap)) {
454 dev_err(&client->dev, "failed to allocate register map\n");
455 return PTR_ERR(data->regmap);
463 err = devm_clk_hw_register(&client->dev, &data->hw);
465 dev_err(&client->dev, "clock registration failed\n");
468 err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get,
469 &data->hw);
471 dev_err(&client->dev, "unable to add clk provider\n");
475 /* Read the requested initial output frequency from device tree */
476 if (!of_property_read_u32(client->dev.of_node, "clock-frequency",
478 err = clk_set_rate(data->hw.clk, initial_fout);
484 dev_info(&client->dev, "registered, current frequency %llu Hz\n",
485 data->frequency);