diff mbox series

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

Message ID 20250408150118.54478-1-lucienx123@gmail.com (mailing list archive)
State Under Review
Headers show
Series [v7,net-next,1/1] net: phy: air_en8811h: Add clk provider for CKO pin | expand

Commit Message

Lucien.Jheng April 8, 2025, 3:01 p.m. UTC
EN8811H outputs 25MHz or 50MHz clocks on CKO, selected by GPIO3.
CKO clock operates continuously from power-up through md32 loading.
Implement clk provider driver so we can disable the clock output in case
it isn't needed, which also helps to reduce EMF noise

Signed-off-by: Lucien.Jheng <lucienx123@gmail.com>
---
Change in PATCH v7:
air_en8811h.c:
 * Fix: Correct various code style inconsistencies and remove unnecessary initialization.

 drivers/net/phy/air_en8811h.c | 103 +++++++++++++++++++++++++++++++++-
 1 file changed, 100 insertions(+), 3 deletions(-)

--
2.34.1

Comments

Andrew Lunn April 8, 2025, 3:18 p.m. UTC | #1
On Tue, Apr 08, 2025 at 11:01:18PM +0800, Lucien.Jheng wrote:
> EN8811H outputs 25MHz or 50MHz clocks on CKO, selected by GPIO3.
> CKO clock operates continuously from power-up through md32 loading.
> Implement clk provider driver so we can disable the clock output in case
> it isn't needed, which also helps to reduce EMF noise
> 
> Signed-off-by: Lucien.Jheng <lucienx123@gmail.com>
>  #include <linux/property.h>
>  #include <linux/wordpart.h>
>  #include <linux/unaligned.h>
> +#include <linux/clk-provider.h>

We try to keep thinks sorted in order. The includes are not quite
correct, but still clk-provider.h should be first.

>  #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))

and registers should be in order, so 0xcf958 goes after 0xcf8b8.

> +static int en8811h_clk_is_enabled(struct clk_hw *hw)
> +{
> +	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
> +	struct phy_device *phydev = priv->phydev;
> +	int ret;
> +	u32 pbus_value;

Reverse Christmas tree please. Sort them longest to shortest.

	Andrew
diff mbox series

Patch

diff --git a/drivers/net/phy/air_en8811h.c b/drivers/net/phy/air_en8811h.c
index e9fd24cb7270..4eebc6e24ce5 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];
+	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,86 @@  static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
 	return 0;
 };

+static unsigned long en8811h_clk_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_clk_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_clk_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_clk_is_enabled(struct clk_hw *hw)
+{
+	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
+	struct phy_device *phydev = priv->phydev;
+	int ret;
+	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_clk_recalc_rate,
+	.enable		= en8811h_clk_enable,
+	.disable	= en8811h_clk_disable,
+	.is_enabled	= en8811h_clk_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 +929,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,