Lines Matching +full:clock +full:- +full:output +full:- +full:name

1 // SPDX-License-Identifier: GPL-2.0-or-later
7 * Copyright (C) 2011 - 2021 Xilinx Inc.
14 #include <linux/clk-provider.h>
64 * @hw: Clock hw struct
69 * @n1: Clock divider N1
70 * @hs_div: Clock divider HSDIV
71 * @rfreq: Clock multiplier RFREQ
72 * @frequency: Current output frequency
90 * si570_get_divs() - Read clock dividers from HW
92 * @rfreq: Fractional multiplier (output)
93 * @n1: Divider N1 (output)
94 * @hs_div: Divider HSDIV (output)
97 * Retrieve clock dividers and multipliers from the HW.
106 err = regmap_bulk_read(data->regmap, SI570_REG_HS_N1 + data->div_offset, in si570_get_divs()
128 * si570_get_defaults() - Get default values
130 * @fout: Factory frequency output
141 regmap_write(data->regmap, SI570_REG_CONTROL, in si570_get_defaults()
144 err = si570_get_divs(data, &data->rfreq, &data->n1, &data->hs_div); in si570_get_defaults()
152 fdco = fout * data->n1 * data->hs_div; in si570_get_defaults()
154 data->fxtal = div64_u64(fdco << 24, data->rfreq >> 4); in si570_get_defaults()
156 data->fxtal = div64_u64(fdco << 28, data->rfreq); in si570_get_defaults()
158 data->frequency = fout; in si570_get_defaults()
164 * si570_update_rfreq() - Update clock multiplier
172 reg[0] = ((data->n1 - 1) << 6) | in si570_update_rfreq()
173 ((data->rfreq >> 32) & RFREQ_37_32_MASK); in si570_update_rfreq()
174 reg[1] = (data->rfreq >> 24) & 0xff; in si570_update_rfreq()
175 reg[2] = (data->rfreq >> 16) & 0xff; in si570_update_rfreq()
176 reg[3] = (data->rfreq >> 8) & 0xff; in si570_update_rfreq()
177 reg[4] = data->rfreq & 0xff; in si570_update_rfreq()
179 return regmap_bulk_write(data->regmap, SI570_REG_N1_RFREQ0 + in si570_update_rfreq()
180 data->div_offset, reg, ARRAY_SIZE(reg)); in si570_update_rfreq()
184 * si570_calc_divs() - Calculate clock dividers
187 * @out_rfreq: RFREG fractional multiplier (output)
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
216 *out_rfreq = div64_u64(fdco << 28, data->fxtal); in si570_calc_divs()
224 return -EINVAL; in si570_calc_divs()
239 dev_err(&data->i2c_client->dev, "unable to recalc rate\n"); in si570_recalc_rate()
240 return data->frequency; in si570_recalc_rate()
244 rate = (data->fxtal * rfreq) >> 28; in si570_recalc_rate()
257 if (!req->rate) { in si570_determine_rate()
258 req->rate = 0; in si570_determine_rate()
263 if (div64_u64(abs(req->rate - data->frequency) * 10000LL, in si570_determine_rate()
264 data->frequency) < 35) { in si570_determine_rate()
265 rfreq = div64_u64((data->rfreq * req->rate) + in si570_determine_rate()
266 div64_u64(data->frequency, 2), in si570_determine_rate()
267 data->frequency); in si570_determine_rate()
268 n1 = data->n1; in si570_determine_rate()
269 hs_div = data->hs_div; in si570_determine_rate()
272 err = si570_calc_divs(req->rate, data, &rfreq, &n1, &hs_div); in si570_determine_rate()
274 dev_err(&data->i2c_client->dev, in si570_determine_rate()
276 req->rate = 0; in si570_determine_rate()
286 * si570_set_frequency() - Adjust output frequency
291 * Update output frequency for big frequency changes (> 3,500 ppm).
297 err = si570_calc_divs(frequency, data, &data->rfreq, &data->n1, in si570_set_frequency()
298 &data->hs_div); in si570_set_frequency()
303 * The DCO reg should be accessed with a read-modify-write operation in si570_set_frequency()
306 regmap_write(data->regmap, SI570_REG_FREEZE_DCO, SI570_FREEZE_DCO); in si570_set_frequency()
307 regmap_write(data->regmap, SI570_REG_HS_N1 + data->div_offset, in si570_set_frequency()
308 ((data->hs_div - HS_DIV_OFFSET) << HS_DIV_SHIFT) | in si570_set_frequency()
309 (((data->n1 - 1) >> 2) & N1_6_2_MASK)); in si570_set_frequency()
311 regmap_write(data->regmap, SI570_REG_FREEZE_DCO, 0); in si570_set_frequency()
312 regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_NEWFREQ); in si570_set_frequency()
321 * si570_set_frequency_small() - Adjust output frequency
326 * Update output frequency for small frequency changes (< 3,500 ppm).
332 * This is a re-implementation of DIV_ROUND_CLOSEST in si570_set_frequency_small()
336 data->rfreq = div64_u64((data->rfreq * frequency) + in si570_set_frequency_small()
337 div_u64(data->frequency, 2), data->frequency); in si570_set_frequency_small()
338 regmap_write(data->regmap, SI570_REG_CONTROL, SI570_CNTRL_FREEZE_M); in si570_set_frequency_small()
340 regmap_write(data->regmap, SI570_REG_CONTROL, 0); in si570_set_frequency_small()
352 struct i2c_client *client = data->i2c_client; in si570_set_rate()
355 if (rate < SI570_MIN_FREQ || rate > data->info->max_freq) { in si570_set_rate()
356 dev_err(&client->dev, in si570_set_rate()
358 return -EINVAL; in si570_set_rate()
361 if (div64_u64(abs(rate - data->frequency) * 10000LL, in si570_set_rate()
362 data->frequency) < 35) in si570_set_rate()
370 data->frequency = rate; in si570_set_rate()
420 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); in si570_probe()
422 return -ENOMEM; in si570_probe()
427 data->hw.init = &init; in si570_probe()
428 data->i2c_client = client; in si570_probe()
430 data->info = i2c_get_match_data(client); in si570_probe()
431 if (data->info->has_temperature_stability) { in si570_probe()
432 err = of_property_read_u32(client->dev.of_node, in si570_probe()
433 "temperature-stability", &stability); in si570_probe()
435 dev_err(&client->dev, in si570_probe()
436 "'temperature-stability' property missing\n"); in si570_probe()
441 data->div_offset = SI570_DIV_OFFSET_7PPM; in si570_probe()
444 if (of_property_read_string(client->dev.of_node, "clock-output-names", in si570_probe()
445 &init.name)) in si570_probe()
446 init.name = client->dev.of_node->name; in si570_probe()
448 err = of_property_read_u32(client->dev.of_node, "factory-fout", in si570_probe()
451 dev_err(&client->dev, "'factory-fout' property missing\n"); in si570_probe()
455 skip_recall = of_property_read_bool(client->dev.of_node, in si570_probe()
456 "silabs,skip-recall"); in si570_probe()
458 data->regmap = devm_regmap_init_i2c(client, &si570_regmap_config); in si570_probe()
459 if (IS_ERR(data->regmap)) { in si570_probe()
460 dev_err(&client->dev, "failed to allocate register map\n"); in si570_probe()
461 return PTR_ERR(data->regmap); in si570_probe()
469 err = devm_clk_hw_register(&client->dev, &data->hw); in si570_probe()
471 dev_err(&client->dev, "clock registration failed\n"); in si570_probe()
474 err = devm_of_clk_add_hw_provider(&client->dev, of_clk_hw_simple_get, in si570_probe()
475 &data->hw); in si570_probe()
477 dev_err(&client->dev, "unable to add clk provider\n"); in si570_probe()
481 /* Read the requested initial output frequency from device tree */ in si570_probe()
482 if (!of_property_read_u32(client->dev.of_node, "clock-frequency", in si570_probe()
484 err = clk_set_rate(data->hw.clk, initial_fout); in si570_probe()
490 dev_info(&client->dev, "registered, current frequency %llu Hz\n", in si570_probe()
491 data->frequency); in si570_probe()
525 .name = "si570",