Lines Matching +full:clkin +full:- +full:diff

1 // SPDX-License-Identifier: GPL-2.0-only
3 * TI CDCE706 programmable 3-PLL clock synthesizer driver
11 #include <linux/clk-provider.h>
50 #define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4))
82 struct cdce706_hw_data clkin[1]; member
115 int rc = regmap_read(dev_data->regmap, reg | 0x80, val); in cdce706_reg_read()
118 dev_err(&dev_data->client->dev, "error reading reg %u", reg); in cdce706_reg_read()
125 int rc = regmap_write(dev_data->regmap, reg | 0x80, val); in cdce706_reg_write()
128 dev_err(&dev_data->client->dev, "error writing reg %u", reg); in cdce706_reg_write()
135 int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val); in cdce706_reg_update()
138 dev_err(&dev_data->client->dev, "error updating reg %u", reg); in cdce706_reg_update()
146 hwd->parent = index; in cdce706_clkin_set_parent()
154 return hwd->parent; in cdce706_clkin_get_parent()
168 dev_dbg(&hwd->dev_data->client->dev, in cdce706_pll_recalc_rate()
170 __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div); in cdce706_pll_recalc_rate()
172 if (!hwd->mux) { in cdce706_pll_recalc_rate()
173 if (hwd->div && hwd->mul) { in cdce706_pll_recalc_rate()
174 u64 res = (u64)parent_rate * hwd->mul; in cdce706_pll_recalc_rate()
176 do_div(res, hwd->div); in cdce706_pll_recalc_rate()
180 if (hwd->div) in cdce706_pll_recalc_rate()
181 return parent_rate / hwd->div; in cdce706_pll_recalc_rate()
193 dev_dbg(&hwd->dev_data->client->dev, in cdce706_pll_determine_rate()
195 __func__, req->rate, req->best_parent_rate); in cdce706_pll_determine_rate()
197 rational_best_approximation(req->rate, req->best_parent_rate, in cdce706_pll_determine_rate()
200 hwd->mul = mul; in cdce706_pll_determine_rate()
201 hwd->div = div; in cdce706_pll_determine_rate()
203 dev_dbg(&hwd->dev_data->client->dev, in cdce706_pll_determine_rate()
205 __func__, hwd->idx, mul, div); in cdce706_pll_determine_rate()
207 res = (u64)req->best_parent_rate * hwd->mul; in cdce706_pll_determine_rate()
208 do_div(res, hwd->div); in cdce706_pll_determine_rate()
209 req->rate = res; in cdce706_pll_determine_rate()
218 unsigned long mul = hwd->mul, div = hwd->div; in cdce706_pll_set_rate()
221 dev_dbg(&hwd->dev_data->client->dev, in cdce706_pll_set_rate()
223 __func__, hwd->idx, mul, div); in cdce706_pll_set_rate()
225 err = cdce706_reg_update(hwd->dev_data, in cdce706_pll_set_rate()
226 CDCE706_PLL_HI(hwd->idx), in cdce706_pll_set_rate()
229 ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) & in cdce706_pll_set_rate()
234 err = cdce706_reg_write(hwd->dev_data, in cdce706_pll_set_rate()
235 CDCE706_PLL_M_LOW(hwd->idx), in cdce706_pll_set_rate()
240 err = cdce706_reg_write(hwd->dev_data, in cdce706_pll_set_rate()
241 CDCE706_PLL_N_LOW(hwd->idx), in cdce706_pll_set_rate()
246 err = cdce706_reg_update(hwd->dev_data, in cdce706_pll_set_rate()
248 CDCE706_PLL_FVCO_MASK(hwd->idx), in cdce706_pll_set_rate()
250 CDCE706_PLL_FVCO_MASK(hwd->idx) : 0); in cdce706_pll_set_rate()
264 if (hwd->parent == index) in cdce706_divider_set_parent()
266 hwd->parent = index; in cdce706_divider_set_parent()
267 return cdce706_reg_update(hwd->dev_data, in cdce706_divider_set_parent()
268 CDCE706_DIVIDER_PLL(hwd->idx), in cdce706_divider_set_parent()
269 CDCE706_DIVIDER_PLL_MASK(hwd->idx), in cdce706_divider_set_parent()
270 index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx)); in cdce706_divider_set_parent()
277 return hwd->parent; in cdce706_divider_get_parent()
285 dev_dbg(&hwd->dev_data->client->dev, in cdce706_divider_recalc_rate()
287 __func__, hwd->idx, hwd->div); in cdce706_divider_recalc_rate()
288 if (hwd->div) in cdce706_divider_recalc_rate()
289 return parent_rate / hwd->div; in cdce706_divider_recalc_rate()
297 struct cdce706_dev_data *cdce = hwd->dev_data; in cdce706_divider_determine_rate()
298 unsigned long rate = req->rate; in cdce706_divider_determine_rate()
301 dev_dbg(&hwd->dev_data->client->dev, in cdce706_divider_determine_rate()
303 __func__, rate, req->best_parent_rate); in cdce706_divider_determine_rate()
305 rational_best_approximation(rate, req->best_parent_rate, in cdce706_divider_determine_rate()
314 struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent]; in cdce706_divider_determine_rate()
320 unsigned long diff; in cdce706_divider_determine_rate() local
335 diff = max(div_rate, rate) - min(div_rate, rate); in cdce706_divider_determine_rate()
337 if (diff < best_diff) { in cdce706_divider_determine_rate()
338 best_diff = diff; in cdce706_divider_determine_rate()
340 dev_dbg(&hwd->dev_data->client->dev, in cdce706_divider_determine_rate()
348 dev_dbg(&hwd->dev_data->client->dev, in cdce706_divider_determine_rate()
349 "%s, altering parent rate: %lu -> %lu\n", in cdce706_divider_determine_rate()
350 __func__, req->best_parent_rate, rate * div); in cdce706_divider_determine_rate()
351 req->best_parent_rate = rate * div; in cdce706_divider_determine_rate()
353 hwd->div = div; in cdce706_divider_determine_rate()
355 dev_dbg(&hwd->dev_data->client->dev, in cdce706_divider_determine_rate()
357 __func__, hwd->idx, div); in cdce706_divider_determine_rate()
359 req->rate = req->best_parent_rate / div; in cdce706_divider_determine_rate()
368 dev_dbg(&hwd->dev_data->client->dev, in cdce706_divider_set_rate()
370 __func__, hwd->idx, hwd->div); in cdce706_divider_set_rate()
372 return cdce706_reg_update(hwd->dev_data, in cdce706_divider_set_rate()
373 CDCE706_DIVIDER(hwd->idx), in cdce706_divider_set_rate()
375 hwd->div); in cdce706_divider_set_rate()
390 return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx), in cdce706_clkout_prepare()
399 cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx), in cdce706_clkout_unprepare()
407 if (hwd->parent == index) in cdce706_clkout_set_parent()
409 hwd->parent = index; in cdce706_clkout_set_parent()
410 return cdce706_reg_update(hwd->dev_data, in cdce706_clkout_set_parent()
411 CDCE706_CLKOUT(hwd->idx), in cdce706_clkout_set_parent()
419 return hwd->parent; in cdce706_clkout_get_parent()
431 req->best_parent_rate = req->rate; in cdce706_clkout_determine_rate()
461 init->name = clk_names[i]; in cdce706_register_hw()
462 hw->dev_data = cdce; in cdce706_register_hw()
463 hw->idx = i; in cdce706_register_hw()
464 hw->hw.init = init; in cdce706_register_hw()
465 ret = devm_clk_hw_register(&cdce->client->dev, in cdce706_register_hw()
466 &hw->hw); in cdce706_register_hw()
468 dev_err(&cdce->client->dev, "Failed to register %s\n", in cdce706_register_hw()
480 .parent_names = cdce->clkin_name, in cdce706_register_clkin()
481 .num_parents = ARRAY_SIZE(cdce->clkin_name), in cdce706_register_clkin()
487 for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) { in cdce706_register_clkin()
488 struct clk *parent = devm_clk_get(&cdce->client->dev, in cdce706_register_clkin()
492 cdce->clkin_name[i] = cdce706_source_name[i]; in cdce706_register_clkin()
494 cdce->clkin_name[i] = __clk_get_name(parent); in cdce706_register_clkin()
495 cdce->clkin_clk[i] = parent; in cdce706_register_clkin()
507 cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK); in cdce706_register_clkin()
510 ret = cdce706_register_hw(cdce, cdce->clkin, in cdce706_register_clkin()
511 ARRAY_SIZE(cdce->clkin), in cdce706_register_clkin()
531 for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) { in cdce706_register_plls()
543 cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8); in cdce706_register_plls()
544 cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) << in cdce706_register_plls()
545 (8 - CDCE706_PLL_HI_N_SHIFT)); in cdce706_register_plls()
546 cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i); in cdce706_register_plls()
547 dev_dbg(&cdce->client->dev, in cdce706_register_plls()
549 cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux); in cdce706_register_plls()
552 ret = cdce706_register_hw(cdce, cdce->pll, in cdce706_register_plls()
553 ARRAY_SIZE(cdce->pll), in cdce706_register_plls()
569 for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) { in cdce706_register_dividers()
575 cdce->divider[i].parent = in cdce706_register_dividers()
582 cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK; in cdce706_register_dividers()
583 dev_dbg(&cdce->client->dev, in cdce706_register_dividers()
585 cdce->divider[i].parent, cdce->divider[i].div); in cdce706_register_dividers()
588 ret = cdce706_register_hw(cdce, cdce->divider, in cdce706_register_dividers()
589 ARRAY_SIZE(cdce->divider), in cdce706_register_dividers()
605 for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) { in cdce706_register_clkouts()
611 cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK; in cdce706_register_clkouts()
612 dev_dbg(&cdce->client->dev, in cdce706_register_clkouts()
614 cdce->clkout[i].parent); in cdce706_register_clkouts()
617 return cdce706_register_hw(cdce, cdce->clkout, in cdce706_register_clkouts()
618 ARRAY_SIZE(cdce->clkout), in cdce706_register_clkouts()
626 unsigned int idx = clkspec->args[0]; in of_clk_cdce_get()
628 if (idx >= ARRAY_SIZE(cdce->clkout)) { in of_clk_cdce_get()
630 return ERR_PTR(-EINVAL); in of_clk_cdce_get()
633 return &cdce->clkout[idx].hw; in of_clk_cdce_get()
638 struct i2c_adapter *adapter = client->adapter; in cdce706_probe()
643 return -EIO; in cdce706_probe()
645 cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL); in cdce706_probe()
647 return -ENOMEM; in cdce706_probe()
649 cdce->client = client; in cdce706_probe()
650 cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config); in cdce706_probe()
651 if (IS_ERR(cdce->regmap)) { in cdce706_probe()
652 dev_err(&client->dev, "Failed to initialize regmap\n"); in cdce706_probe()
653 return -EINVAL; in cdce706_probe()
670 return devm_of_clk_add_hw_provider(&client->dev, of_clk_cdce_get, in cdce706_probe()