Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

phy: cadence-torrent: Model reference clock driver as a clock to enable derived refclk

When reference clock driver is enabled, either derived or received refclk
is output on cmn_refclk_p/m. Update the reference clock driver
implementation by modelling reference clock driver as a "clock" with
derived reference clock set as its default parent. The support for
received reference clock will be added in a separate patch.

Signed-off-by: Swapnil Jakhade <sjakhade@cadence.com>
Link: https://lore.kernel.org/r/20210922123735.21927-4-sjakhade@cadence.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Swapnil Jakhade and committed by
Vinod Koul
235bde4f f9aec164

+139 -32
+139 -32
drivers/phy/cadence/phy-cadence-torrent.c
··· 235 235 #define PHY_PMA_CMN_CTRL2 0x0001U 236 236 #define PHY_PMA_PLL_RAW_CTRL 0x0003U 237 237 238 - #define CDNS_TORRENT_OUTPUT_CLOCKS 1 238 + #define CDNS_TORRENT_OUTPUT_CLOCKS 2 239 239 240 240 static const char * const clk_names[] = { 241 241 [CDNS_TORRENT_REFCLK_DRIVER] = "refclk-driver", 242 + [CDNS_TORRENT_DERIVED_REFCLK] = "refclk-der", 242 243 }; 243 244 244 245 static const struct reg_field phy_pll_cfg = ··· 262 261 263 262 static const struct reg_field phy_pipe_cmn_ctrl1_0 = REG_FIELD(PHY_PIPE_CMN_CTRL1, 0, 0); 264 263 265 - #define REFCLK_OUT_NUM_CMN_CONFIG 5 264 + static const struct reg_field cmn_cdiag_refclk_ovrd_4 = 265 + REG_FIELD(CMN_CDIAG_REFCLK_OVRD, 4, 4); 266 + 267 + #define REFCLK_OUT_NUM_CMN_CONFIG 4 266 268 267 269 enum cdns_torrent_refclk_out_cmn { 268 - CMN_CDIAG_REFCLK_OVRD_4, 269 270 CMN_CDIAG_REFCLK_DRV0_CTRL_1, 270 271 CMN_CDIAG_REFCLK_DRV0_CTRL_4, 271 272 CMN_CDIAG_REFCLK_DRV0_CTRL_5, ··· 275 272 }; 276 273 277 274 static const struct reg_field refclk_out_cmn_cfg[] = { 278 - [CMN_CDIAG_REFCLK_OVRD_4] = REG_FIELD(CMN_CDIAG_REFCLK_OVRD, 4, 4), 279 275 [CMN_CDIAG_REFCLK_DRV0_CTRL_1] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 1, 1), 280 276 [CMN_CDIAG_REFCLK_DRV0_CTRL_4] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 4, 4), 281 277 [CMN_CDIAG_REFCLK_DRV0_CTRL_5] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 5, 5), ··· 332 330 struct regmap *regmap_phy_pcs_lane_cdb[MAX_NUM_LANES]; 333 331 struct regmap *regmap_dptx_phy_reg; 334 332 struct regmap_field *phy_pll_cfg; 333 + struct regmap_field *phy_pipe_cmn_ctrl1_0; 334 + struct regmap_field *cmn_cdiag_refclk_ovrd_4; 335 335 struct regmap_field *phy_pma_cmn_ctrl_1; 336 336 struct regmap_field *phy_pma_cmn_ctrl_2; 337 337 struct regmap_field *phy_pma_pll_raw_ctrl; ··· 349 345 POWERSTATE_A3 = 3, 350 346 }; 351 347 348 + struct cdns_torrent_refclk_driver { 349 + struct clk_hw hw; 350 + struct regmap_field *cmn_fields[REFCLK_OUT_NUM_CMN_CONFIG]; 351 + struct clk_init_data clk_data; 352 + }; 353 + 354 + #define to_cdns_torrent_refclk_driver(_hw) \ 355 + container_of(_hw, struct cdns_torrent_refclk_driver, hw) 356 + 352 357 struct cdns_torrent_derived_refclk { 353 358 struct clk_hw hw; 354 359 struct regmap_field *phy_pipe_cmn_ctrl1_0; 355 - struct regmap_field *cmn_fields[REFCLK_OUT_NUM_CMN_CONFIG]; 360 + struct regmap_field *cmn_cdiag_refclk_ovrd_4; 356 361 struct clk_init_data clk_data; 357 362 }; 358 363 ··· 1631 1618 { 1632 1619 struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); 1633 1620 1634 - regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_6], 0); 1635 - regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1); 1636 - regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_5], 1); 1637 - regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 0); 1638 - regmap_field_write(derived_refclk->cmn_fields[CMN_CDIAG_REFCLK_OVRD_4], 1); 1621 + regmap_field_write(derived_refclk->cmn_cdiag_refclk_ovrd_4, 1); 1639 1622 regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 1); 1640 1623 1641 1624 return 0; ··· 1642 1633 struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); 1643 1634 1644 1635 regmap_field_write(derived_refclk->phy_pipe_cmn_ctrl1_0, 0); 1636 + regmap_field_write(derived_refclk->cmn_cdiag_refclk_ovrd_4, 0); 1645 1637 } 1646 1638 1647 1639 static int cdns_torrent_derived_refclk_is_enabled(struct clk_hw *hw) ··· 1650 1640 struct cdns_torrent_derived_refclk *derived_refclk = to_cdns_torrent_derived_refclk(hw); 1651 1641 int val; 1652 1642 1653 - regmap_field_read(derived_refclk->phy_pipe_cmn_ctrl1_0, &val); 1643 + regmap_field_read(derived_refclk->cmn_cdiag_refclk_ovrd_4, &val); 1654 1644 1655 1645 return !!val; 1656 1646 } ··· 1665 1655 { 1666 1656 struct cdns_torrent_derived_refclk *derived_refclk; 1667 1657 struct device *dev = cdns_phy->dev; 1668 - struct regmap_field *field; 1669 1658 struct clk_init_data *init; 1670 1659 const char *parent_name; 1671 - struct regmap *regmap; 1672 1660 char clk_name[100]; 1673 1661 struct clk_hw *hw; 1674 1662 struct clk *clk; 1675 - int i, ret; 1663 + int ret; 1676 1664 1677 1665 derived_refclk = devm_kzalloc(dev, sizeof(*derived_refclk), GFP_KERNEL); 1678 1666 if (!derived_refclk) 1679 1667 return -ENOMEM; 1680 1668 1681 1669 snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), 1682 - clk_names[CDNS_TORRENT_REFCLK_DRIVER]); 1670 + clk_names[CDNS_TORRENT_DERIVED_REFCLK]); 1683 1671 1684 1672 clk = devm_clk_get_optional(dev, "phy_en_refclk"); 1685 1673 if (IS_ERR(clk)) { ··· 1696 1688 init->flags = 0; 1697 1689 init->name = clk_name; 1698 1690 1699 - regmap = cdns_phy->regmap_phy_pcs_common_cdb; 1700 - field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0); 1701 - if (IS_ERR(field)) { 1702 - dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n"); 1703 - return PTR_ERR(field); 1704 - } 1705 - derived_refclk->phy_pipe_cmn_ctrl1_0 = field; 1706 - 1707 - regmap = cdns_phy->regmap_common_cdb; 1708 - for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) { 1709 - field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]); 1710 - if (IS_ERR(field)) { 1711 - dev_err(dev, "CMN reg field init failed\n"); 1712 - return PTR_ERR(field); 1713 - } 1714 - derived_refclk->cmn_fields[i] = field; 1715 - } 1691 + derived_refclk->phy_pipe_cmn_ctrl1_0 = cdns_phy->phy_pipe_cmn_ctrl1_0; 1692 + derived_refclk->cmn_cdiag_refclk_ovrd_4 = cdns_phy->cmn_cdiag_refclk_ovrd_4; 1716 1693 1717 1694 derived_refclk->hw.init = init; 1718 1695 1719 1696 hw = &derived_refclk->hw; 1697 + ret = devm_clk_hw_register(dev, hw); 1698 + if (ret) 1699 + return ret; 1700 + 1701 + cdns_phy->clk_hw_data->hws[CDNS_TORRENT_DERIVED_REFCLK] = hw; 1702 + 1703 + return 0; 1704 + } 1705 + 1706 + static int cdns_torrent_refclk_driver_enable(struct clk_hw *hw) 1707 + { 1708 + struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw); 1709 + 1710 + regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_6], 0); 1711 + regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1); 1712 + regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_5], 1); 1713 + regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 0); 1714 + 1715 + return 0; 1716 + } 1717 + 1718 + static void cdns_torrent_refclk_driver_disable(struct clk_hw *hw) 1719 + { 1720 + struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw); 1721 + 1722 + regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 1); 1723 + } 1724 + 1725 + static int cdns_torrent_refclk_driver_is_enabled(struct clk_hw *hw) 1726 + { 1727 + struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw); 1728 + int val; 1729 + 1730 + regmap_field_read(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], &val); 1731 + 1732 + return !val; 1733 + } 1734 + 1735 + static const struct clk_ops cdns_torrent_refclk_driver_ops = { 1736 + .enable = cdns_torrent_refclk_driver_enable, 1737 + .disable = cdns_torrent_refclk_driver_disable, 1738 + .is_enabled = cdns_torrent_refclk_driver_is_enabled, 1739 + }; 1740 + 1741 + static int cdns_torrent_refclk_driver_register(struct cdns_torrent_phy *cdns_phy) 1742 + { 1743 + struct cdns_torrent_refclk_driver *refclk_driver; 1744 + struct device *dev = cdns_phy->dev; 1745 + struct regmap_field *field; 1746 + struct clk_init_data *init; 1747 + const char *parent_name; 1748 + struct regmap *regmap; 1749 + char clk_name[100]; 1750 + struct clk_hw *hw; 1751 + int i, ret; 1752 + 1753 + refclk_driver = devm_kzalloc(dev, sizeof(*refclk_driver), GFP_KERNEL); 1754 + if (!refclk_driver) 1755 + return -ENOMEM; 1756 + 1757 + hw = cdns_phy->clk_hw_data->hws[CDNS_TORRENT_DERIVED_REFCLK]; 1758 + if (IS_ERR_OR_NULL(hw)) { 1759 + dev_err(dev, "No parent clock for refclk driver clock\n"); 1760 + return IS_ERR(hw) ? PTR_ERR(hw) : -ENOENT; 1761 + } 1762 + parent_name = clk_hw_get_name(hw); 1763 + 1764 + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), 1765 + clk_names[CDNS_TORRENT_REFCLK_DRIVER]); 1766 + 1767 + init = &refclk_driver->clk_data; 1768 + 1769 + init->ops = &cdns_torrent_refclk_driver_ops; 1770 + init->flags = 0; 1771 + init->parent_names = &parent_name; 1772 + init->num_parents = 1; 1773 + init->name = clk_name; 1774 + 1775 + regmap = cdns_phy->regmap_common_cdb; 1776 + 1777 + for (i = 0; i < REFCLK_OUT_NUM_CMN_CONFIG; i++) { 1778 + field = devm_regmap_field_alloc(dev, regmap, refclk_out_cmn_cfg[i]); 1779 + if (IS_ERR(field)) { 1780 + dev_err(dev, "Refclk driver CMN reg field init failed\n"); 1781 + return PTR_ERR(field); 1782 + } 1783 + refclk_driver->cmn_fields[i] = field; 1784 + } 1785 + 1786 + refclk_driver->hw.init = init; 1787 + 1788 + hw = &refclk_driver->hw; 1720 1789 ret = devm_clk_hw_register(dev, hw); 1721 1790 if (ret) 1722 1791 return ret; ··· 1852 1767 return PTR_ERR(field); 1853 1768 } 1854 1769 cdns_phy->phy_pll_cfg = field; 1770 + 1771 + regmap = cdns_phy->regmap_phy_pcs_common_cdb; 1772 + field = devm_regmap_field_alloc(dev, regmap, phy_pipe_cmn_ctrl1_0); 1773 + if (IS_ERR(field)) { 1774 + dev_err(dev, "phy_pipe_cmn_ctrl1_0 reg field init failed\n"); 1775 + return PTR_ERR(field); 1776 + } 1777 + cdns_phy->phy_pipe_cmn_ctrl1_0 = field; 1778 + 1779 + regmap = cdns_phy->regmap_common_cdb; 1780 + field = devm_regmap_field_alloc(dev, regmap, cmn_cdiag_refclk_ovrd_4); 1781 + if (IS_ERR(field)) { 1782 + dev_err(dev, "cmn_cdiag_refclk_ovrd_4 reg field init failed\n"); 1783 + return PTR_ERR(field); 1784 + } 1785 + cdns_phy->cmn_cdiag_refclk_ovrd_4 = field; 1855 1786 1856 1787 regmap = cdns_phy->regmap_phy_pma_common_cdb; 1857 1788 field = devm_regmap_field_alloc(dev, regmap, phy_pma_cmn_ctrl_1); ··· 2305 2204 ret = cdns_torrent_derived_refclk_register(cdns_phy); 2306 2205 if (ret) { 2307 2206 dev_err(dev, "failed to register derived refclk\n"); 2207 + return ret; 2208 + } 2209 + 2210 + ret = cdns_torrent_refclk_driver_register(cdns_phy); 2211 + if (ret) { 2212 + dev_err(dev, "failed to register refclk driver\n"); 2308 2213 return ret; 2309 2214 } 2310 2215