Skip to content

Commit 67ac229

Browse files
bjxlucX123NipaLocal
authored and
NipaLocal
committed
net: phy: air_en8811h: Add clk provider for CKO pin
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 <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Signed-off-by: NipaLocal <nipa@local>
1 parent b182fbb commit 67ac229

File tree

1 file changed

+100
-3
lines changed

1 file changed

+100
-3
lines changed

drivers/net/phy/air_en8811h.c

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
* Copyright (C) 2023 Airoha Technology Corp.
1212
*/
1313

14+
#include <linux/clk-provider.h>
1415
#include <linux/phy.h>
1516
#include <linux/firmware.h>
1617
#include <linux/property.h>
@@ -115,6 +116,11 @@
115116
#define EN8811H_GPIO_OUTPUT 0xcf8b8
116117
#define EN8811H_GPIO_OUTPUT_345 (BIT(3) | BIT(4) | BIT(5))
117118

119+
#define EN8811H_HWTRAP1 0xcf914
120+
#define EN8811H_HWTRAP1_CKO BIT(12)
121+
#define EN8811H_CLK_CGM 0xcf958
122+
#define EN8811H_CLK_CGM_CKO BIT(26)
123+
118124
#define EN8811H_FW_CTRL_1 0x0f0018
119125
#define EN8811H_FW_CTRL_1_START 0x0
120126
#define EN8811H_FW_CTRL_1_FINISH 0x1
@@ -142,10 +148,15 @@ struct led {
142148
unsigned long state;
143149
};
144150

151+
#define clk_hw_to_en8811h_priv(_hw) \
152+
container_of(_hw, struct en8811h_priv, hw)
153+
145154
struct en8811h_priv {
146-
u32 firmware_version;
147-
bool mcu_needs_restart;
148-
struct led led[EN8811H_LED_COUNT];
155+
u32 firmware_version;
156+
bool mcu_needs_restart;
157+
struct led led[EN8811H_LED_COUNT];
158+
struct clk_hw hw;
159+
struct phy_device *phydev;
149160
};
150161

151162
enum {
@@ -806,6 +817,86 @@ static int en8811h_led_hw_is_supported(struct phy_device *phydev, u8 index,
806817
return 0;
807818
};
808819

820+
static unsigned long en8811h_clk_recalc_rate(struct clk_hw *hw,
821+
unsigned long parent)
822+
{
823+
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
824+
struct phy_device *phydev = priv->phydev;
825+
u32 pbus_value;
826+
int ret;
827+
828+
ret = air_buckpbus_reg_read(phydev, EN8811H_HWTRAP1, &pbus_value);
829+
if (ret < 0)
830+
return ret;
831+
832+
return (pbus_value & EN8811H_HWTRAP1_CKO) ? 50000000 : 25000000;
833+
}
834+
835+
static int en8811h_clk_enable(struct clk_hw *hw)
836+
{
837+
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
838+
struct phy_device *phydev = priv->phydev;
839+
840+
return air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
841+
EN8811H_CLK_CGM_CKO,
842+
EN8811H_CLK_CGM_CKO);
843+
}
844+
845+
static void en8811h_clk_disable(struct clk_hw *hw)
846+
{
847+
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
848+
struct phy_device *phydev = priv->phydev;
849+
850+
air_buckpbus_reg_modify(phydev, EN8811H_CLK_CGM,
851+
EN8811H_CLK_CGM_CKO, 0);
852+
}
853+
854+
static int en8811h_clk_is_enabled(struct clk_hw *hw)
855+
{
856+
struct en8811h_priv *priv = clk_hw_to_en8811h_priv(hw);
857+
struct phy_device *phydev = priv->phydev;
858+
u32 pbus_value;
859+
int ret;
860+
861+
ret = air_buckpbus_reg_read(phydev, EN8811H_CLK_CGM, &pbus_value);
862+
if (ret < 0)
863+
return ret;
864+
865+
return (pbus_value & EN8811H_CLK_CGM_CKO);
866+
}
867+
868+
static const struct clk_ops en8811h_clk_ops = {
869+
.recalc_rate = en8811h_clk_recalc_rate,
870+
.enable = en8811h_clk_enable,
871+
.disable = en8811h_clk_disable,
872+
.is_enabled = en8811h_clk_is_enabled,
873+
};
874+
875+
static int en8811h_clk_provider_setup(struct device *dev, struct clk_hw *hw)
876+
{
877+
struct clk_init_data init;
878+
int ret;
879+
880+
if (!IS_ENABLED(CONFIG_COMMON_CLK))
881+
return 0;
882+
883+
init.name = devm_kasprintf(dev, GFP_KERNEL, "%s-cko",
884+
fwnode_get_name(dev_fwnode(dev)));
885+
if (!init.name)
886+
return -ENOMEM;
887+
888+
init.ops = &en8811h_clk_ops;
889+
init.flags = 0;
890+
init.num_parents = 0;
891+
hw->init = &init;
892+
893+
ret = devm_clk_hw_register(dev, hw);
894+
if (ret)
895+
return ret;
896+
897+
return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
898+
}
899+
809900
static int en8811h_probe(struct phy_device *phydev)
810901
{
811902
struct en8811h_priv *priv;
@@ -838,6 +929,12 @@ static int en8811h_probe(struct phy_device *phydev)
838929
return ret;
839930
}
840931

932+
priv->phydev = phydev;
933+
/* Co-Clock Output */
934+
ret = en8811h_clk_provider_setup(&phydev->mdio.dev, &priv->hw);
935+
if (ret)
936+
return ret;
937+
841938
/* Configure led gpio pins as output */
842939
ret = air_buckpbus_reg_modify(phydev, EN8811H_GPIO_OUTPUT,
843940
EN8811H_GPIO_OUTPUT_345,

0 commit comments

Comments
 (0)