Lines Matching +full:phy +full:- +full:ref +full:- +full:clk

1 // SPDX-License-Identifier: GPL-2.0+
9 #include <linux/clk.h>
10 #include <linux/clk-provider.h>
32 * REG33 does not match the ref manual. According to Sandor Yu from NXP,
286 /* PHY_REG(1-7) pix clk specific */
314 struct clk *apbclk;
315 struct clk *refclk;
317 /* clk provider */
329 fsl_samsung_hdmi_phy_configure_pll_lock_det(struct fsl_samsung_hdmi_phy *phy, in fsl_samsung_hdmi_phy_configure_pll_lock_det() argument
332 u32 pclk = cfg->pixclk; in fsl_samsung_hdmi_phy_configure_pll_lock_det()
345 return -EINVAL; in fsl_samsung_hdmi_phy_configure_pll_lock_det()
347 writeb(FIELD_PREP(REG12_CK_DIV_MASK, div), phy->regs + PHY_REG(12)); in fsl_samsung_hdmi_phy_configure_pll_lock_det()
365 phy->regs + PHY_REG(13)); in fsl_samsung_hdmi_phy_configure_pll_lock_det()
369 phy->regs + PHY_REG(14)); in fsl_samsung_hdmi_phy_configure_pll_lock_det()
383 * Figure 13-78 of the reference manual states the PLL should be TMDS x 5 in fsl_samsung_hdmi_phy_find_pms()
389 /* The ref manual states the values of 'P' range from 1 to 11 */ in fsl_samsung_hdmi_phy_find_pms()
404 * The Ref manual doesn't explicitly state the range of M, in fsl_samsung_hdmi_phy_find_pms()
405 * but it does show it as an 8-bit value, so reject in fsl_samsung_hdmi_phy_find_pms()
415 * Rev 2 of the Ref Manual states the in fsl_samsung_hdmi_phy_find_pms()
426 /* Final frequency after post-divider */ in fsl_samsung_hdmi_phy_find_pms()
429 delta = abs(fout - tmp); in fsl_samsung_hdmi_phy_find_pms()
453 static int fsl_samsung_hdmi_phy_configure(struct fsl_samsung_hdmi_phy *phy, in fsl_samsung_hdmi_phy_configure() argument
459 phy->cur_cfg = cfg; in fsl_samsung_hdmi_phy_configure()
461 /* HDMI PHY init */ in fsl_samsung_hdmi_phy_configure()
462 writeb(REG33_FIX_DA, phy->regs + PHY_REG(33)); in fsl_samsung_hdmi_phy_configure()
464 /* common PHY registers */ in fsl_samsung_hdmi_phy_configure()
466 writeb(common_phy_cfg[i].val, phy->regs + common_phy_cfg[i].reg); in fsl_samsung_hdmi_phy_configure()
470 writeb(cfg->pll_div_regs[i], phy->regs + PHY_REG(1) + i * 4); in fsl_samsung_hdmi_phy_configure()
474 cfg->pll_div_regs[2] >> 4), phy->regs + PHY_REG(21)); in fsl_samsung_hdmi_phy_configure()
476 ret = fsl_samsung_hdmi_phy_configure_pll_lock_det(phy, cfg); in fsl_samsung_hdmi_phy_configure()
478 dev_err(phy->dev, "pixclock too large\n"); in fsl_samsung_hdmi_phy_configure()
482 writeb(REG33_FIX_DA | REG33_MODE_SET_DONE, phy->regs + PHY_REG(33)); in fsl_samsung_hdmi_phy_configure()
484 ret = readb_poll_timeout(phy->regs + PHY_REG(34), val, in fsl_samsung_hdmi_phy_configure()
487 dev_err(phy->dev, "PLL failed to lock\n"); in fsl_samsung_hdmi_phy_configure()
495 struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); in phy_clk_recalc_rate() local
497 if (!phy->cur_cfg) in phy_clk_recalc_rate()
500 return phy->cur_cfg->pixclk; in phy_clk_recalc_rate()
503 /* Helper function to lookup the available fractional-divider rate */
509 for (i = ARRAY_SIZE(phy_pll_cfg) - 1; i >= 0; i--) in fsl_samsung_hdmi_phy_lookup_rate()
514 if (phy_pll_cfg[i].pixclk == rate || i + 1 > ARRAY_SIZE(phy_pll_cfg) - 1) in fsl_samsung_hdmi_phy_lookup_rate()
518 return (abs((long) rate - (long) phy_pll_cfg[i].pixclk) < in fsl_samsung_hdmi_phy_lookup_rate()
519 abs((long) rate - (long) phy_pll_cfg[i+1].pixclk) ? in fsl_samsung_hdmi_phy_lookup_rate()
526 cal_phy->pixclk = rate; in fsl_samsung_hdmi_calculate_phy()
527 cal_phy->pll_div_regs[0] = FIELD_PREP(REG01_PMS_P_MASK, p); in fsl_samsung_hdmi_calculate_phy()
528 cal_phy->pll_div_regs[1] = m; in fsl_samsung_hdmi_calculate_phy()
529 cal_phy->pll_div_regs[2] = FIELD_PREP(REG03_PMS_S_MASK, s-1); in fsl_samsung_hdmi_calculate_phy()
530 /* pll_div_regs 3-6 are fixed and pre-defined already */ in fsl_samsung_hdmi_calculate_phy()
534 const struct phy_config *fsl_samsung_hdmi_phy_find_settings(struct fsl_samsung_hdmi_phy *phy, in fsl_samsung_hdmi_phy_find_settings() argument
548 if (fract_div_phy->pixclk == rate) { in fsl_samsung_hdmi_phy_find_settings()
549 dev_dbg(phy->dev, "fractional divider match = %u\n", fract_div_phy->pixclk); in fsl_samsung_hdmi_phy_find_settings()
557 dev_dbg(phy->dev, "integer divider match = %u\n", calculated_phy_pll_cfg.pixclk); in fsl_samsung_hdmi_phy_find_settings()
562 if (abs((long)rate - (long)int_div_clk) < in fsl_samsung_hdmi_phy_find_settings()
563 abs((long)rate - (long)fract_div_phy->pixclk)) { in fsl_samsung_hdmi_phy_find_settings()
564 dev_dbg(phy->dev, "integer divider = %u\n", calculated_phy_pll_cfg.pixclk); in fsl_samsung_hdmi_phy_find_settings()
568 dev_dbg(phy->dev, "fractional divider = %u\n", phy->cur_cfg->pixclk); in fsl_samsung_hdmi_phy_find_settings()
576 struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); in fsl_samsung_hdmi_phy_clk_round_rate() local
577 const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate); in fsl_samsung_hdmi_phy_clk_round_rate()
580 return -EINVAL; in fsl_samsung_hdmi_phy_clk_round_rate()
582 dev_dbg(phy->dev, "round_rate, closest rate = %u\n", target_settings->pixclk); in fsl_samsung_hdmi_phy_clk_round_rate()
583 return target_settings->pixclk; in fsl_samsung_hdmi_phy_clk_round_rate()
589 struct fsl_samsung_hdmi_phy *phy = to_fsl_samsung_hdmi_phy(hw); in fsl_samsung_hdmi_phy_clk_set_rate() local
590 const struct phy_config *target_settings = fsl_samsung_hdmi_phy_find_settings(phy, rate); in fsl_samsung_hdmi_phy_clk_set_rate()
593 return -EINVAL; in fsl_samsung_hdmi_phy_clk_set_rate()
595 dev_dbg(phy->dev, "set_rate, closest rate = %u\n", target_settings->pixclk); in fsl_samsung_hdmi_phy_clk_set_rate()
597 return fsl_samsung_hdmi_phy_configure(phy, target_settings); in fsl_samsung_hdmi_phy_clk_set_rate()
606 static int phy_clk_register(struct fsl_samsung_hdmi_phy *phy) in phy_clk_register() argument
608 struct device *dev = phy->dev; in phy_clk_register()
609 struct device_node *np = dev->of_node; in phy_clk_register()
612 struct clk *phyclk; in phy_clk_register()
615 parent_name = __clk_get_name(phy->refclk); in phy_clk_register()
623 phy->hw.init = &init; in phy_clk_register()
625 phyclk = devm_clk_register(dev, &phy->hw); in phy_clk_register()
640 struct fsl_samsung_hdmi_phy *phy; in fsl_samsung_hdmi_phy_probe() local
643 phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); in fsl_samsung_hdmi_phy_probe()
644 if (!phy) in fsl_samsung_hdmi_phy_probe()
645 return -ENOMEM; in fsl_samsung_hdmi_phy_probe()
647 platform_set_drvdata(pdev, phy); in fsl_samsung_hdmi_phy_probe()
648 phy->dev = &pdev->dev; in fsl_samsung_hdmi_phy_probe()
650 phy->regs = devm_platform_ioremap_resource(pdev, 0); in fsl_samsung_hdmi_phy_probe()
651 if (IS_ERR(phy->regs)) in fsl_samsung_hdmi_phy_probe()
652 return PTR_ERR(phy->regs); in fsl_samsung_hdmi_phy_probe()
654 phy->apbclk = devm_clk_get_enabled(phy->dev, "apb"); in fsl_samsung_hdmi_phy_probe()
655 if (IS_ERR(phy->apbclk)) in fsl_samsung_hdmi_phy_probe()
656 return dev_err_probe(phy->dev, PTR_ERR(phy->apbclk), in fsl_samsung_hdmi_phy_probe()
657 "failed to get apb clk\n"); in fsl_samsung_hdmi_phy_probe()
659 phy->refclk = devm_clk_get(phy->dev, "ref"); in fsl_samsung_hdmi_phy_probe()
660 if (IS_ERR(phy->refclk)) in fsl_samsung_hdmi_phy_probe()
661 return dev_err_probe(phy->dev, PTR_ERR(phy->refclk), in fsl_samsung_hdmi_phy_probe()
662 "failed to get ref clk\n"); in fsl_samsung_hdmi_phy_probe()
664 pm_runtime_get_noresume(phy->dev); in fsl_samsung_hdmi_phy_probe()
665 pm_runtime_set_active(phy->dev); in fsl_samsung_hdmi_phy_probe()
666 pm_runtime_enable(phy->dev); in fsl_samsung_hdmi_phy_probe()
668 ret = phy_clk_register(phy); in fsl_samsung_hdmi_phy_probe()
670 dev_err(&pdev->dev, "register clk failed\n"); in fsl_samsung_hdmi_phy_probe()
674 pm_runtime_put(phy->dev); in fsl_samsung_hdmi_phy_probe()
684 of_clk_del_provider(pdev->dev.of_node); in fsl_samsung_hdmi_phy_remove()
689 struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); in fsl_samsung_hdmi_phy_suspend() local
691 clk_disable_unprepare(phy->apbclk); in fsl_samsung_hdmi_phy_suspend()
698 struct fsl_samsung_hdmi_phy *phy = dev_get_drvdata(dev); in fsl_samsung_hdmi_phy_resume() local
701 ret = clk_prepare_enable(phy->apbclk); in fsl_samsung_hdmi_phy_resume()
703 dev_err(phy->dev, "failed to enable apbclk\n"); in fsl_samsung_hdmi_phy_resume()
707 if (phy->cur_cfg) in fsl_samsung_hdmi_phy_resume()
708 ret = fsl_samsung_hdmi_phy_configure(phy, phy->cur_cfg); in fsl_samsung_hdmi_phy_resume()
720 .compatible = "fsl,imx8mp-hdmi-phy",
731 .name = "fsl-samsung-hdmi-phy",
739 MODULE_DESCRIPTION("SAMSUNG HDMI 2.0 Transmitter PHY Driver");