• Home
  • Raw
  • Download

Lines Matching +full:keep +full:- +full:pll +full:- +full:enabled

1 // SPDX-License-Identifier: GPL-2.0-or-later
10 * - Use spread spectrum
11 * - Use integer divider in FOD if applicable
15 #include <linux/clk-provider.h>
27 #include <dt-bindings/clk/versaclock.h>
32 /* Factory-reserved register block */
126 /* PLL/VCO runs between 2.5 GHz and 3.0 GHz */
141 /* chip has built-in oscilator */
205 /* Factory reserved regs, make them read-only */ in vc5_regmap_is_writeable()
209 /* Factory reserved regs, make them read-only */ in vc5_regmap_is_writeable()
234 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &src); in vc5_mux_get_parent()
243 dev_warn(&vc5->client->dev, in vc5_mux_get_parent()
255 if ((index > 1) || !vc5->clk_mux_ins) in vc5_mux_set_parent()
256 return -EINVAL; in vc5_mux_set_parent()
258 if (vc5->clk_mux_ins == (VC5_MUX_IN_CLKIN | VC5_MUX_IN_XIN)) { in vc5_mux_set_parent()
265 return -EINVAL; in vc5_mux_set_parent()
267 if (vc5->clk_mux_ins == VC5_MUX_IN_XIN) in vc5_mux_set_parent()
269 else if (vc5->clk_mux_ins == VC5_MUX_IN_CLKIN) in vc5_mux_set_parent()
272 return -EINVAL; in vc5_mux_set_parent()
275 return regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, mask, src); in vc5_mux_set_parent()
290 regmap_read(vc5->regmap, VC5_PRIM_SRC_SHDN, &premul); in vc5_dbl_recalc_rate()
303 return -EINVAL; in vc5_dbl_round_rate()
318 regmap_update_bits(vc5->regmap, VC5_PRIM_SRC_SHDN, in vc5_dbl_set_rate()
338 regmap_read(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, &prediv); in vc5_pfd_recalc_rate()
340 /* The bypass_prediv is set, PLL fed from Ref_in directly. */ in vc5_pfd_recalc_rate()
344 regmap_read(vc5->regmap, VC5_REF_DIVIDER, &div); in vc5_pfd_recalc_rate()
346 /* The Sel_prediv2 is set, PLL fed from prediv2 (Ref_in / 2) */ in vc5_pfd_recalc_rate()
358 /* PLL cannot operate with input clock above 50 MHz. */ in vc5_pfd_round_rate()
360 return -EINVAL; in vc5_pfd_round_rate()
362 /* CLKIN within range of PLL input, feed directly to PLL. */ in vc5_pfd_round_rate()
368 return -EINVAL; in vc5_pfd_round_rate()
381 /* CLKIN within range of PLL input, feed directly to PLL. */ in vc5_pfd_set_rate()
383 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, in vc5_pfd_set_rate()
386 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, 0x00); in vc5_pfd_set_rate()
392 /* We have dedicated div-2 predivider. */ in vc5_pfd_set_rate()
398 regmap_update_bits(vc5->regmap, VC5_REF_DIVIDER, 0xff, div); in vc5_pfd_set_rate()
399 regmap_update_bits(vc5->regmap, VC5_VCO_CTRL_AND_PREDIV, in vc5_pfd_set_rate()
412 * VersaClock5 PLL/VCO
418 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_pll_recalc_rate()
422 regmap_bulk_read(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5); in vc5_pll_recalc_rate()
427 /* The PLL divider has 12 integer bits and 24 fractional bits */ in vc5_pll_recalc_rate()
450 div_frc *= BIT(24) - 1; in vc5_pll_round_rate()
453 hwdata->div_int = div_int; in vc5_pll_round_rate()
454 hwdata->div_frc = (u32)div_frc; in vc5_pll_round_rate()
463 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_pll_set_rate()
466 fb[0] = hwdata->div_int >> 4; in vc5_pll_set_rate()
467 fb[1] = hwdata->div_int << 4; in vc5_pll_set_rate()
468 fb[2] = hwdata->div_frc >> 16; in vc5_pll_set_rate()
469 fb[3] = hwdata->div_frc >> 8; in vc5_pll_set_rate()
470 fb[4] = hwdata->div_frc; in vc5_pll_set_rate()
472 return regmap_bulk_write(vc5->regmap, VC5_FEEDBACK_INT_DIV, fb, 5); in vc5_pll_set_rate()
485 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_fod_recalc_rate()
492 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_INT(hwdata->num, 0), in vc5_fod_recalc_rate()
494 regmap_bulk_read(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0), in vc5_fod_recalc_rate()
505 /* The PLL divider has 12 integer bits and 30 fractional bits */ in vc5_fod_recalc_rate()
522 * of the divider is 0xfff and fractional part is non-zero. in vc5_fod_round_rate()
523 * Clamp the divider at 0xffe to keep the code simple. in vc5_fod_round_rate()
535 hwdata->div_int = div_int; in vc5_fod_round_rate()
536 hwdata->div_frc = (u32)div_frc; in vc5_fod_round_rate()
545 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_fod_set_rate()
547 hwdata->div_frc >> 22, hwdata->div_frc >> 14, in vc5_fod_set_rate()
548 hwdata->div_frc >> 6, hwdata->div_frc << 2, in vc5_fod_set_rate()
551 hwdata->div_int >> 4, hwdata->div_int << 4, in vc5_fod_set_rate()
555 regmap_bulk_write(vc5->regmap, VC5_OUT_DIV_FRAC(hwdata->num, 0), in vc5_fod_set_rate()
564 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER, in vc5_fod_set_rate()
566 regmap_update_bits(vc5->regmap, VC5_GLOBAL_REGISTER, in vc5_fod_set_rate()
581 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_clk_out_prepare()
589 * When enabling a FOD, all currently enabled FODs are briefly in vc5_clk_out_prepare()
596 if (vc5->chip_info->flags & VC5_HAS_BYPASS_SYNC_BIT) { in vc5_clk_out_prepare()
597 ret = regmap_update_bits(vc5->regmap, in vc5_clk_out_prepare()
598 VC5_RESERVED_X0(hwdata->num), in vc5_clk_out_prepare()
609 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src); in vc5_clk_out_prepare()
612 ret = regmap_update_bits(vc5->regmap, in vc5_clk_out_prepare()
613 VC5_OUT_DIV_CONTROL(hwdata->num), in vc5_clk_out_prepare()
620 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), in vc5_clk_out_prepare()
623 if (hwdata->clk_output_cfg0_mask) { in vc5_clk_out_prepare()
624 dev_dbg(&vc5->client->dev, "Update output %d mask 0x%0X val 0x%0X\n", in vc5_clk_out_prepare()
625 hwdata->num, hwdata->clk_output_cfg0_mask, in vc5_clk_out_prepare()
626 hwdata->clk_output_cfg0); in vc5_clk_out_prepare()
628 regmap_update_bits(vc5->regmap, in vc5_clk_out_prepare()
629 VC5_CLK_OUTPUT_CFG(hwdata->num, 0), in vc5_clk_out_prepare()
630 hwdata->clk_output_cfg0_mask, in vc5_clk_out_prepare()
631 hwdata->clk_output_cfg0); in vc5_clk_out_prepare()
640 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_clk_out_unprepare()
643 regmap_update_bits(vc5->regmap, VC5_CLK_OUTPUT_CFG(hwdata->num, 1), in vc5_clk_out_unprepare()
650 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_clk_out_get_parent()
660 regmap_read(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), &src); in vc5_clk_out_get_parent()
672 dev_warn(&vc5->client->dev, in vc5_clk_out_get_parent()
680 struct vc5_driver_data *vc5 = hwdata->vc5; in vc5_clk_out_set_parent()
694 return regmap_update_bits(vc5->regmap, VC5_OUT_DIV_CONTROL(hwdata->num), in vc5_clk_out_set_parent()
709 unsigned int idx = clkspec->args[0]; in vc5_of_clk_get()
711 if (idx >= vc5->chip_info->clk_out_cnt) in vc5_of_clk_get()
712 return ERR_PTR(-EINVAL); in vc5_of_clk_get()
714 return &vc5->clk_out[idx].hw; in vc5_of_clk_get()
739 clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_CFG_MASK; in vc5_update_mode()
748 clk_out->clk_output_cfg0 |= in vc5_update_mode()
752 return -EINVAL; in vc5_update_mode()
763 if (!of_property_read_u32(np_output, "idt,voltage-microvolt", in vc5_update_power()
765 clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_PWR_MASK; in vc5_update_power()
768 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_18; in vc5_update_power()
771 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_25; in vc5_update_power()
774 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_PWR_33; in vc5_update_power()
777 return -EINVAL; in vc5_update_power()
788 if (!of_property_read_u32(np_output, "idt,slew-percent", &value)) { in vc5_update_slew()
789 clk_out->clk_output_cfg0_mask |= VC5_CLK_OUTPUT_CFG0_SLEW_MASK; in vc5_update_slew()
792 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_80; in vc5_update_slew()
795 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_85; in vc5_update_slew()
798 clk_out->clk_output_cfg0 |= VC5_CLK_OUTPUT_CFG0_SLEW_90; in vc5_update_slew()
801 clk_out->clk_output_cfg0 |= in vc5_update_slew()
805 return -EINVAL; in vc5_update_slew()
818 child_name = kasprintf(GFP_KERNEL, "OUT%d", clk_out->num + 1); in vc5_get_output_config()
820 return -ENOMEM; in vc5_get_output_config()
822 np_output = of_get_child_by_name(client->dev.of_node, child_name); in vc5_get_output_config()
839 dev_err(&client->dev, in vc5_get_output_config()
841 clk_out->num + 1); in vc5_get_output_config()
859 vc5 = devm_kzalloc(&client->dev, sizeof(*vc5), GFP_KERNEL); in vc5_probe()
861 return -ENOMEM; in vc5_probe()
864 vc5->client = client; in vc5_probe()
865 vc5->chip_info = of_device_get_match_data(&client->dev); in vc5_probe()
867 vc5->pin_xin = devm_clk_get(&client->dev, "xin"); in vc5_probe()
868 if (PTR_ERR(vc5->pin_xin) == -EPROBE_DEFER) in vc5_probe()
869 return -EPROBE_DEFER; in vc5_probe()
871 vc5->pin_clkin = devm_clk_get(&client->dev, "clkin"); in vc5_probe()
872 if (PTR_ERR(vc5->pin_clkin) == -EPROBE_DEFER) in vc5_probe()
873 return -EPROBE_DEFER; in vc5_probe()
875 vc5->regmap = devm_regmap_init_i2c(client, &vc5_regmap_config); in vc5_probe()
876 if (IS_ERR(vc5->regmap)) { in vc5_probe()
877 dev_err(&client->dev, "failed to allocate register map\n"); in vc5_probe()
878 return PTR_ERR(vc5->regmap); in vc5_probe()
884 if (!IS_ERR(vc5->pin_xin)) { in vc5_probe()
885 vc5->clk_mux_ins |= VC5_MUX_IN_XIN; in vc5_probe()
886 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin); in vc5_probe()
887 } else if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) { in vc5_probe()
888 vc5->pin_xin = clk_register_fixed_rate(&client->dev, in vc5_probe()
889 "internal-xtal", NULL, in vc5_probe()
891 if (IS_ERR(vc5->pin_xin)) in vc5_probe()
892 return PTR_ERR(vc5->pin_xin); in vc5_probe()
893 vc5->clk_mux_ins |= VC5_MUX_IN_XIN; in vc5_probe()
894 parent_names[init.num_parents++] = __clk_get_name(vc5->pin_xin); in vc5_probe()
897 if (!IS_ERR(vc5->pin_clkin)) { in vc5_probe()
898 vc5->clk_mux_ins |= VC5_MUX_IN_CLKIN; in vc5_probe()
900 __clk_get_name(vc5->pin_clkin); in vc5_probe()
904 dev_err(&client->dev, "no input clock specified!\n"); in vc5_probe()
905 return -EINVAL; in vc5_probe()
908 init.name = kasprintf(GFP_KERNEL, "%pOFn.mux", client->dev.of_node); in vc5_probe()
912 vc5->clk_mux.init = &init; in vc5_probe()
913 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mux); in vc5_probe()
918 if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) { in vc5_probe()
922 client->dev.of_node); in vc5_probe()
926 parent_names[0] = clk_hw_get_name(&vc5->clk_mux); in vc5_probe()
928 vc5->clk_mul.init = &init; in vc5_probe()
929 ret = devm_clk_hw_register(&client->dev, &vc5->clk_mul); in vc5_probe()
937 init.name = kasprintf(GFP_KERNEL, "%pOFn.pfd", client->dev.of_node); in vc5_probe()
941 if (vc5->chip_info->flags & VC5_HAS_PFD_FREQ_DBL) in vc5_probe()
942 parent_names[0] = clk_hw_get_name(&vc5->clk_mul); in vc5_probe()
944 parent_names[0] = clk_hw_get_name(&vc5->clk_mux); in vc5_probe()
946 vc5->clk_pfd.init = &init; in vc5_probe()
947 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pfd); in vc5_probe()
952 /* Register PLL */ in vc5_probe()
954 init.name = kasprintf(GFP_KERNEL, "%pOFn.pll", client->dev.of_node); in vc5_probe()
958 parent_names[0] = clk_hw_get_name(&vc5->clk_pfd); in vc5_probe()
960 vc5->clk_pll.num = 0; in vc5_probe()
961 vc5->clk_pll.vc5 = vc5; in vc5_probe()
962 vc5->clk_pll.hw.init = &init; in vc5_probe()
963 ret = devm_clk_hw_register(&client->dev, &vc5->clk_pll.hw); in vc5_probe()
969 for (n = 0; n < vc5->chip_info->clk_fod_cnt; n++) { in vc5_probe()
970 idx = vc5_map_index_to_output(vc5->chip_info->model, n); in vc5_probe()
973 client->dev.of_node, idx); in vc5_probe()
977 parent_names[0] = clk_hw_get_name(&vc5->clk_pll.hw); in vc5_probe()
979 vc5->clk_fod[n].num = idx; in vc5_probe()
980 vc5->clk_fod[n].vc5 = vc5; in vc5_probe()
981 vc5->clk_fod[n].hw.init = &init; in vc5_probe()
982 ret = devm_clk_hw_register(&client->dev, &vc5->clk_fod[n].hw); in vc5_probe()
988 /* Register MUX-connected OUT0_I2C_SELB output */ in vc5_probe()
991 client->dev.of_node); in vc5_probe()
995 parent_names[0] = clk_hw_get_name(&vc5->clk_mux); in vc5_probe()
997 vc5->clk_out[0].num = idx; in vc5_probe()
998 vc5->clk_out[0].vc5 = vc5; in vc5_probe()
999 vc5->clk_out[0].hw.init = &init; in vc5_probe()
1000 ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[0].hw); in vc5_probe()
1005 /* Register FOD-connected OUTx outputs */ in vc5_probe()
1006 for (n = 1; n < vc5->chip_info->clk_out_cnt; n++) { in vc5_probe()
1007 idx = vc5_map_index_to_output(vc5->chip_info->model, n - 1); in vc5_probe()
1008 parent_names[0] = clk_hw_get_name(&vc5->clk_fod[idx].hw); in vc5_probe()
1010 parent_names[1] = clk_hw_get_name(&vc5->clk_mux); in vc5_probe()
1013 clk_hw_get_name(&vc5->clk_out[n - 1].hw); in vc5_probe()
1017 client->dev.of_node, idx + 1); in vc5_probe()
1022 vc5->clk_out[n].num = idx; in vc5_probe()
1023 vc5->clk_out[n].vc5 = vc5; in vc5_probe()
1024 vc5->clk_out[n].hw.init = &init; in vc5_probe()
1025 ret = devm_clk_hw_register(&client->dev, &vc5->clk_out[n].hw); in vc5_probe()
1031 ret = vc5_get_output_config(client, &vc5->clk_out[n]); in vc5_probe()
1036 ret = of_clk_add_hw_provider(client->dev.of_node, vc5_of_clk_get, vc5); in vc5_probe()
1038 dev_err(&client->dev, "unable to add clk provider\n"); in vc5_probe()
1045 dev_err(&client->dev, "unable to register %s\n", init.name); in vc5_probe()
1048 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) in vc5_probe()
1049 clk_unregister_fixed_rate(vc5->pin_xin); in vc5_probe()
1057 of_clk_del_provider(client->dev.of_node); in vc5_remove()
1059 if (vc5->chip_info->flags & VC5_HAS_INTERNAL_XTAL) in vc5_remove()
1060 clk_unregister_fixed_rate(vc5->pin_xin); in vc5_remove()
1069 regcache_cache_only(vc5->regmap, true); in vc5_suspend()
1070 regcache_mark_dirty(vc5->regmap); in vc5_suspend()
1080 regcache_cache_only(vc5->regmap, false); in vc5_resume()
1081 ret = regcache_sync(vc5->regmap); in vc5_resume()