diff mbox series

[v4,net-next,1/1] net: phy: air_en8811h: Add clk provider for CKO pin

Message ID 20250317143111.28824-2-lucienX123@gmail.com (mailing list archive)
State New
Delegated to: Netdev Maintainers
Headers show
Series net: phy: air_en8811h: Add clk provider for CKO pin | expand

Commit Message

Lucien.Jheng March 17, 2025, 2:31 p.m. UTC
EN8811H outputs 25MHz or 50MHz clocks on CKO, selected by GPIO3.
CKO clock activates on power-up and continues through md32 firmware loading.

Signed-off-by: Lucien.Jheng <lucienX123@gmail.com>
---
 drivers/net/phy/air_en8811h.c | 95 +++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

Comments

Daniel Golle March 17, 2025, 6:37 p.m. UTC | #1
On Mon, Mar 17, 2025 at 10:31:11PM +0800, Lucien.Jheng wrote:
> EN8811H outputs 25MHz or 50MHz clocks on CKO, selected by GPIO3.
> CKO clock activates on power-up and continues through md32 firmware loading.

Maybe add here:
"Implement clk provider driver so we can disable the clock output in case
it isn't needed, which also helps to reduce EMF noise"

Ie. the description you had was fine and good to have, just the lines had to
be shorter (ie. just insert linebreaks at 70~75 chars).

See more comments inline below:

> ...
> @@ -806,6 +817,84 @@ static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
>  	return 0;
>  };
>  
> +static unsigned long en8811h_recalc_rate(struct clk_hw *hw, unsigned long parent)

calling this en8811h_clk_recalc_rate() would be better imho.

> +{
> +	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
> +	struct phy_device *phydev = priv->phydev;
> +	u32 pbus_value;
> +	int ret;
> +
> +	ret = air_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value);
> +	if (ret < 0)
> +		return ret;
> +
> +	return (pbus_value & EN8811H_HWTRAP1_CKO) ? 50000000 : 25000000;
> +}
> +
> +static int en8811h_enable(struct clk_hw *hw)

call this en8811h_clk_enable()

> +{
> +	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
> +	struct phy_device *phydev = priv->phydev;
> +
> +	return air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
> +				EN8811H_CLK_CGM_CKO, EN8811H_CLK_CGM_CKO);
> +}
> +
> +static void en8811h_disable(struct clk_hw *hw)

call this en8811h_clk_disable()

> +{
> +	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
> +	struct phy_device *phydev = priv->phydev;
> +
> +	air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
> +				EN8811H_CLK_CGM_CKO, 0);
> +}
> +
> +static int en8811h_is_enabled(struct clk_hw *hw)

call this en8811h_clk_is_enabled()
diff mbox series

Patch

diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
index e9fd24cb7270..eb349b4ff327 100644
--- a/drivers/net/phy/air_en8811h.c
+++ b/drivers/net/phy/air_en8811h.c
@@ -16,6 +16,7 @@ 
 #include <linux/property.h>
 #include <linux/wordpart.h>
 #include <linux/unaligned.h>
+#include <linux/clk-provider.h>
 
 #define EN8811H_PHY_ID		0x03a2a411
 
@@ -112,6 +113,11 @@ 
 #define   EN8811H_POLARITY_TX_NORMAL		BIT(0)
 #define   EN8811H_POLARITY_RX_REVERSE		BIT(1)
 
+#define EN8811H_CLK_CGM     0xcf958
+#define EN8811H_CLK_CGM_CKO     BIT(26)
+#define EN8811H_HWTRAP1     0xcf914
+#define EN8811H_HWTRAP1_CKO     BIT(12)
+
 #define EN8811H_GPIO_OUTPUT		0xcf8b8
 #define   EN8811H_GPIO_OUTPUT_345		(BIT(3) | BIT(4) | BIT(5))
 
@@ -142,10 +148,15 @@  struct led {
 	unsigned long state;
 };
 
+#define clk_hw_to_en8811h_priv(_hw)			\
+	container_of(_hw, struct en8811h_priv, hw)
+
 struct en8811h_priv {
 	u32		firmware_version;
 	bool		mcu_needs_restart;
 	struct led	led[EN8811H_LED_COUNT];
+	struct clk_hw        hw;
+	struct phy_device *phydev;
 };
 
 enum {
@@ -806,6 +817,84 @@  static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
 	return 0;
 };
 
+static unsigned long en8811h_recalc_rate(struct clk_hw *hw, unsigned long parent)
+{
+	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
+	struct phy_device *phydev = priv->phydev;
+	u32 pbus_value;
+	int ret;
+
+	ret = air_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value);
+	if (ret < 0)
+		return ret;
+
+	return (pbus_value & EN8811H_HWTRAP1_CKO) ? 50000000 : 25000000;
+}
+
+static int en8811h_enable(struct clk_hw *hw)
+{
+	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
+	struct phy_device *phydev = priv->phydev;
+
+	return air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
+				EN8811H_CLK_CGM_CKO, EN8811H_CLK_CGM_CKO);
+}
+
+static void en8811h_disable(struct clk_hw *hw)
+{
+	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
+	struct phy_device *phydev = priv->phydev;
+
+	air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
+				EN8811H_CLK_CGM_CKO, 0);
+}
+
+static int en8811h_is_enabled(struct clk_hw *hw)
+{
+	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
+	struct phy_device *phydev = priv->phydev;
+	int ret = 0;
+	u32 pbus_value;
+
+	ret = air_buckpbus_reg_read(phydev, EN8811H_CLK_CGM, &pbus_value);
+	if (ret < 0)
+		return ret;
+
+	return (pbus_value & EN8811H_CLK_CGM_CKO);
+}
+
+static const struct clk_ops en8811h_clk_ops = {
+	.recalc_rate = en8811h_recalc_rate,
+	.enable = en8811h_enable,
+	.disable = en8811h_disable,
+	.is_enabled	= en8811h_is_enabled,
+};
+
+static int en8811h_clk_provider_setup(struct device *dev, struct clk_hw *hw)
+{
+	struct clk_init_data init;
+	int ret;
+
+	if (!IS_ENABLED(CONFIG_COMMON_CLK))
+		return 0;
+
+	init.name =  devm_kasprintf(dev, GFP_KERNEL, "%s-cko",
+				    fwnode_get_name(dev_fwnode(dev)));
+	if (!init.name)
+		return -ENOMEM;
+
+	init.ops = &en8811h_clk_ops;
+	init.flags = 0;
+	init.num_parents = 0;
+	hw->init = &init;
+
+	ret = devm_clk_hw_register(dev, hw);
+	if (ret)
+		return ret;
+
+	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
+}
+
 static int en8811h_probe(struct phy_device *phydev)
 {
 	struct en8811h_priv *priv;
@@ -838,6 +927,12 @@  static int en8811h_probe(struct phy_device *phydev)
 		return ret;
 	}
 
+	priv->phydev = phydev;
+	/* Co-Clock Output */
+	ret = en8811h_clk_provider_setup(&phydev->mdio.dev, &priv->hw);
+	if (ret)
+		return ret;
+
 	/* Configure led gpio pins as output */
 	ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
 				      EN8811H_GPIO_OUTPUT_345,