Commit 6b9c9def authored by Lucien.Jheng's avatar Lucien.Jheng Committed by Jakub Kicinski
Browse files

net: phy: air_en8811h: Introduce resume/suspend and clk_restore_context to...


net: phy: air_en8811h: Introduce resume/suspend and clk_restore_context to ensure correct CKO settings after network interface reinitialization.

If the user reinitializes the network interface, the PHY will reinitialize,
and the CKO settings will revert to their initial configuration(be enabled).
To prevent CKO from being re-enabled,
en8811h_clk_restore_context and en8811h_resume were added
to ensure the CKO settings remain correct.

Signed-off-by: default avatarLucien.Jheng <lucienzx159@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20250630154147.80388-1-lucienzx159@gmail.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 10c38949
Loading
Loading
Loading
Loading
+41 −4
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
 * Copyright (C) 2023 Airoha Technology Corp.
 */

#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/phy.h>
#include <linux/firmware.h>
@@ -157,6 +158,7 @@ struct en8811h_priv {
	struct led		led[EN8811H_LED_COUNT];
	struct clk_hw		hw;
	struct phy_device	*phydev;
	unsigned int		cko_is_enabled;
};

enum {
@@ -865,11 +867,30 @@ static int en8811h_clk_is_enabled(struct clk_hw *hw)
	return (pbus_value & EN8811H_CLK_CGM_CKO);
}

static int en8811h_clk_save_context(struct clk_hw *hw)
{
	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);

	priv->cko_is_enabled = en8811h_clk_is_enabled(hw);

	return 0;
}

static void en8811h_clk_restore_context(struct clk_hw *hw)
{
	struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);

	if (!priv->cko_is_enabled)
		en8811h_clk_disable(hw);
}

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,
	.save_context		= en8811h_clk_save_context,
	.restore_context	= en8811h_clk_restore_context,
};

static int en8811h_clk_provider_setup(struct device *dev, struct clk_hw *hw)
@@ -1149,6 +1170,20 @@ static irqreturn_t en8811h_handle_interrupt(struct phy_device *phydev)
	return IRQ_HANDLED;
}

static int en8811h_resume(struct phy_device *phydev)
{
	clk_restore_context();

	return genphy_resume(phydev);
}

static int en8811h_suspend(struct phy_device *phydev)
{
	clk_save_context();

	return genphy_suspend(phydev);
}

static struct phy_driver en8811h_driver[] = {
{
	PHY_ID_MATCH_MODEL(EN8811H_PHY_ID),
@@ -1159,6 +1194,8 @@ static struct phy_driver en8811h_driver[] = {
	.get_rate_matching	= en8811h_get_rate_matching,
	.config_aneg		= en8811h_config_aneg,
	.read_status		= en8811h_read_status,
	.resume			= en8811h_resume,
	.suspend		= en8811h_suspend,
	.config_intr		= en8811h_clear_intr,
	.handle_interrupt	= en8811h_handle_interrupt,
	.led_hw_is_supported	= en8811h_led_hw_is_supported,