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

phy: cadence-torrent: Add support to output received reference clock

Add support to output received reference clock. Model the received
reference clock as an alternate parent of reference clock driver
clock. When received refclk is selected to output on cmn_refclk_p/m,
this is the internal reference clock driven on the pma_cmn_refclk_int.

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

authored by

Swapnil Jakhade and committed by
Vinod Koul
785a4e68 235bde4f

+148 -11
+148 -11
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 2 238 + #define CDNS_TORRENT_OUTPUT_CLOCKS 3 239 239 240 240 static const char * const clk_names[] = { 241 241 [CDNS_TORRENT_REFCLK_DRIVER] = "refclk-driver", 242 242 [CDNS_TORRENT_DERIVED_REFCLK] = "refclk-der", 243 + [CDNS_TORRENT_RECEIVED_REFCLK] = "refclk-rec", 243 244 }; 244 245 245 246 static const struct reg_field phy_pll_cfg = ··· 281 280 [CMN_CDIAG_REFCLK_DRV0_CTRL_5] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 5, 5), 282 281 [CMN_CDIAG_REFCLK_DRV0_CTRL_6] = REG_FIELD(CMN_CDIAG_REFCLK_DRV0_CTRL, 6, 6), 283 282 }; 283 + 284 + static const int refclk_driver_parent_index[] = { 285 + CDNS_TORRENT_DERIVED_REFCLK, 286 + CDNS_TORRENT_RECEIVED_REFCLK 287 + }; 288 + 289 + static u32 cdns_torrent_refclk_driver_mux_table[] = { 1, 0 }; 284 290 285 291 enum cdns_torrent_phy_type { 286 292 TYPE_NONE, ··· 375 367 376 368 #define to_cdns_torrent_derived_refclk(_hw) \ 377 369 container_of(_hw, struct cdns_torrent_derived_refclk, hw) 370 + 371 + struct cdns_torrent_received_refclk { 372 + struct clk_hw hw; 373 + struct regmap_field *phy_pipe_cmn_ctrl1_0; 374 + struct regmap_field *cmn_cdiag_refclk_ovrd_4; 375 + struct clk_init_data clk_data; 376 + }; 377 + 378 + #define to_cdns_torrent_received_refclk(_hw) \ 379 + container_of(_hw, struct cdns_torrent_received_refclk, hw) 378 380 379 381 struct cdns_reg_pairs { 380 382 u32 val; ··· 1729 1711 return 0; 1730 1712 } 1731 1713 1714 + static int cdns_torrent_received_refclk_enable(struct clk_hw *hw) 1715 + { 1716 + struct cdns_torrent_received_refclk *received_refclk = to_cdns_torrent_received_refclk(hw); 1717 + 1718 + regmap_field_write(received_refclk->phy_pipe_cmn_ctrl1_0, 1); 1719 + 1720 + return 0; 1721 + } 1722 + 1723 + static void cdns_torrent_received_refclk_disable(struct clk_hw *hw) 1724 + { 1725 + struct cdns_torrent_received_refclk *received_refclk = to_cdns_torrent_received_refclk(hw); 1726 + 1727 + regmap_field_write(received_refclk->phy_pipe_cmn_ctrl1_0, 0); 1728 + } 1729 + 1730 + static int cdns_torrent_received_refclk_is_enabled(struct clk_hw *hw) 1731 + { 1732 + struct cdns_torrent_received_refclk *received_refclk = to_cdns_torrent_received_refclk(hw); 1733 + int val, cmn_val; 1734 + 1735 + regmap_field_read(received_refclk->phy_pipe_cmn_ctrl1_0, &val); 1736 + regmap_field_read(received_refclk->cmn_cdiag_refclk_ovrd_4, &cmn_val); 1737 + 1738 + return val && !cmn_val; 1739 + } 1740 + 1741 + static const struct clk_ops cdns_torrent_received_refclk_ops = { 1742 + .enable = cdns_torrent_received_refclk_enable, 1743 + .disable = cdns_torrent_received_refclk_disable, 1744 + .is_enabled = cdns_torrent_received_refclk_is_enabled, 1745 + }; 1746 + 1747 + static int cdns_torrent_received_refclk_register(struct cdns_torrent_phy *cdns_phy) 1748 + { 1749 + struct cdns_torrent_received_refclk *received_refclk; 1750 + struct device *dev = cdns_phy->dev; 1751 + struct clk_init_data *init; 1752 + const char *parent_name; 1753 + char clk_name[100]; 1754 + struct clk_hw *hw; 1755 + struct clk *clk; 1756 + int ret; 1757 + 1758 + received_refclk = devm_kzalloc(dev, sizeof(*received_refclk), GFP_KERNEL); 1759 + if (!received_refclk) 1760 + return -ENOMEM; 1761 + 1762 + snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), 1763 + clk_names[CDNS_TORRENT_RECEIVED_REFCLK]); 1764 + 1765 + clk = devm_clk_get_optional(dev, "phy_en_refclk"); 1766 + if (IS_ERR(clk)) { 1767 + dev_err(dev, "No parent clock for received_refclk\n"); 1768 + return PTR_ERR(clk); 1769 + } 1770 + 1771 + init = &received_refclk->clk_data; 1772 + 1773 + if (clk) { 1774 + parent_name = __clk_get_name(clk); 1775 + init->parent_names = &parent_name; 1776 + init->num_parents = 1; 1777 + } 1778 + init->ops = &cdns_torrent_received_refclk_ops; 1779 + init->flags = 0; 1780 + init->name = clk_name; 1781 + 1782 + received_refclk->phy_pipe_cmn_ctrl1_0 = cdns_phy->phy_pipe_cmn_ctrl1_0; 1783 + received_refclk->cmn_cdiag_refclk_ovrd_4 = cdns_phy->cmn_cdiag_refclk_ovrd_4; 1784 + 1785 + received_refclk->hw.init = init; 1786 + 1787 + hw = &received_refclk->hw; 1788 + ret = devm_clk_hw_register(dev, hw); 1789 + if (ret) 1790 + return ret; 1791 + 1792 + cdns_phy->clk_hw_data->hws[CDNS_TORRENT_RECEIVED_REFCLK] = hw; 1793 + 1794 + return 0; 1795 + } 1796 + 1732 1797 static int cdns_torrent_refclk_driver_enable(struct clk_hw *hw) 1733 1798 { 1734 1799 struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw); 1735 1800 1736 1801 regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_6], 0); 1737 - regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1); 1738 1802 regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_5], 1); 1739 1803 regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_1], 0); 1740 1804 ··· 1840 1740 return !val; 1841 1741 } 1842 1742 1743 + static u8 cdns_torrent_refclk_driver_get_parent(struct clk_hw *hw) 1744 + { 1745 + struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw); 1746 + unsigned int val; 1747 + 1748 + regmap_field_read(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], &val); 1749 + return clk_mux_val_to_index(hw, cdns_torrent_refclk_driver_mux_table, 0, val); 1750 + } 1751 + 1752 + static int cdns_torrent_refclk_driver_set_parent(struct clk_hw *hw, u8 index) 1753 + { 1754 + struct cdns_torrent_refclk_driver *refclk_driver = to_cdns_torrent_refclk_driver(hw); 1755 + unsigned int val; 1756 + 1757 + val = cdns_torrent_refclk_driver_mux_table[index]; 1758 + return regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], val); 1759 + } 1760 + 1843 1761 static const struct clk_ops cdns_torrent_refclk_driver_ops = { 1844 1762 .enable = cdns_torrent_refclk_driver_enable, 1845 1763 .disable = cdns_torrent_refclk_driver_disable, 1846 1764 .is_enabled = cdns_torrent_refclk_driver_is_enabled, 1765 + .set_parent = cdns_torrent_refclk_driver_set_parent, 1766 + .get_parent = cdns_torrent_refclk_driver_get_parent, 1847 1767 }; 1848 1768 1849 1769 static int cdns_torrent_refclk_driver_register(struct cdns_torrent_phy *cdns_phy) ··· 1872 1752 struct device *dev = cdns_phy->dev; 1873 1753 struct regmap_field *field; 1874 1754 struct clk_init_data *init; 1875 - const char *parent_name; 1755 + const char **parent_names; 1756 + unsigned int num_parents; 1876 1757 struct regmap *regmap; 1877 1758 char clk_name[100]; 1878 1759 struct clk_hw *hw; ··· 1883 1762 if (!refclk_driver) 1884 1763 return -ENOMEM; 1885 1764 1886 - hw = cdns_phy->clk_hw_data->hws[CDNS_TORRENT_DERIVED_REFCLK]; 1887 - if (IS_ERR_OR_NULL(hw)) { 1888 - dev_err(dev, "No parent clock for refclk driver clock\n"); 1889 - return IS_ERR(hw) ? PTR_ERR(hw) : -ENOENT; 1765 + num_parents = ARRAY_SIZE(refclk_driver_parent_index); 1766 + parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), GFP_KERNEL); 1767 + if (!parent_names) 1768 + return -ENOMEM; 1769 + 1770 + for (i = 0; i < num_parents; i++) { 1771 + hw = cdns_phy->clk_hw_data->hws[refclk_driver_parent_index[i]]; 1772 + if (IS_ERR_OR_NULL(hw)) { 1773 + dev_err(dev, "No parent clock for refclk driver clock\n"); 1774 + return IS_ERR(hw) ? PTR_ERR(hw) : -ENOENT; 1775 + } 1776 + parent_names[i] = clk_hw_get_name(hw); 1890 1777 } 1891 - parent_name = clk_hw_get_name(hw); 1892 1778 1893 1779 snprintf(clk_name, sizeof(clk_name), "%s_%s", dev_name(dev), 1894 1780 clk_names[CDNS_TORRENT_REFCLK_DRIVER]); ··· 1903 1775 init = &refclk_driver->clk_data; 1904 1776 1905 1777 init->ops = &cdns_torrent_refclk_driver_ops; 1906 - init->flags = 0; 1907 - init->parent_names = &parent_name; 1908 - init->num_parents = 1; 1778 + init->flags = CLK_SET_RATE_NO_REPARENT; 1779 + init->parent_names = parent_names; 1780 + init->num_parents = num_parents; 1909 1781 init->name = clk_name; 1910 1782 1911 1783 regmap = cdns_phy->regmap_common_cdb; ··· 1918 1790 } 1919 1791 refclk_driver->cmn_fields[i] = field; 1920 1792 } 1793 + 1794 + /* Enable Derived reference clock as default */ 1795 + regmap_field_write(refclk_driver->cmn_fields[CMN_CDIAG_REFCLK_DRV0_CTRL_4], 1); 1921 1796 1922 1797 refclk_driver->hw.init = init; 1923 1798 ··· 2436 2305 ret = cdns_torrent_derived_refclk_register(cdns_phy); 2437 2306 if (ret) { 2438 2307 dev_err(dev, "failed to register derived refclk\n"); 2308 + return ret; 2309 + } 2310 + 2311 + ret = cdns_torrent_received_refclk_register(cdns_phy); 2312 + if (ret) { 2313 + dev_err(dev, "failed to register received refclk\n"); 2439 2314 return ret; 2440 2315 } 2441 2316