@@ -21,6 +21,8 @@
#include <linux/phylink.h>
#include <linux/sfp.h>
#include <dt-bindings/net/qca-ar803x.h>
+#include <linux/clk.h>
+#include <linux/reset.h>
#define AT803X_SPECIFIC_FUNCTION_CONTROL 0x10
#define AT803X_SFC_ASSERT_CRS BIT(11)
@@ -337,6 +339,31 @@ static struct at803x_hw_stat at803x_hw_stats[] = {
{ "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
};
+enum {
+ SRDS0_SYS_CLK,
+ SRDS1_SYS_CLK,
+ GEPHY0_SYS_CLK,
+ GEPHY1_SYS_CLK,
+ GEPHY2_SYS_CLK,
+ GEPHY3_SYS_CLK,
+ QCA8084_CLK_CNT
+};
+
+enum {
+ SRDS0_SYS_RESET,
+ SRDS1_SYS_RESET,
+ GEPHY0_SYS_RESET,
+ GEPHY1_SYS_RESET,
+ GEPHY2_SYS_RESET,
+ GEPHY3_SYS_RESET,
+ GEPHY0_RESET,
+ GEPHY1_RESET,
+ GEPHY2_RESET,
+ GEPHY3_RESET,
+ GEPHY_DSP_RESET,
+ QCA8084_RESET_CNT,
+};
+
struct at803x_priv {
int flags;
u16 clk_25m_reg;
@@ -348,6 +375,8 @@ struct at803x_priv {
struct regulator_dev *vddio_rdev;
struct regulator_dev *vddh_rdev;
u64 stats[ARRAY_SIZE(at803x_hw_stats)];
+ struct clk *clk[QCA8084_CLK_CNT];
+ struct reset_control *reset[QCA8084_RESET_CNT];
};
struct at803x_context {
@@ -359,6 +388,29 @@ struct at803x_context {
u16 led_control;
};
+static const char *const qca8084_clock_name[QCA8084_CLK_CNT] = {
+ "srds0_sys",
+ "srds1_sys",
+ "gephy0_sys",
+ "gephy1_sys",
+ "gephy2_sys",
+ "gephy3_sys",
+};
+
+static const char *const qca8084_reset_name[QCA8084_RESET_CNT] = {
+ "srds0_sys",
+ "srds1_sys",
+ "gephy0_sys",
+ "gephy1_sys",
+ "gephy2_sys",
+ "gephy3_sys",
+ "gephy0_soft",
+ "gephy1_soft",
+ "gephy2_soft",
+ "gephy3_soft",
+ "gephy_dsp",
+};
+
static int at803x_debug_reg_write(struct phy_device *phydev, u16 reg, u16 data)
{
int ret;
@@ -1007,8 +1059,45 @@ static int qca8084_parse_and_set_phyaddr(struct phy_device *phydev)
FIELD_PREP(QCA8084_PCS_ADDR2_MASK, addr[6]));
}
+static int qca8084_parse_dt(struct phy_device *phydev)
+{
+ struct at803x_priv *priv;
+ int i;
+
+ priv = phydev->priv;
+ for (i = 0; i < QCA8084_CLK_CNT; i++) {
+ priv->clk[i] = devm_clk_get_optional(&phydev->mdio.dev,
+ qca8084_clock_name[i]);
+ if (IS_ERR(priv->clk[i])) {
+ phydev_err(phydev, "failed to get the clock ID %s!\n",
+ qca8084_clock_name[i]);
+
+ return PTR_ERR(priv->clk[i]);
+ }
+ }
+
+ for (i = 0; i < QCA8084_RESET_CNT; i++) {
+ priv->reset[i] = devm_reset_control_get_optional_exclusive(&phydev->mdio.dev,
+ qca8084_reset_name[i]);
+ if (IS_ERR(priv->reset[i])) {
+ phydev_err(phydev, "failed to get the reset ID %s!\n",
+ qca8084_reset_name[i]);
+
+ return PTR_ERR(priv->reset[i]);
+ }
+ }
+
+ return 0;
+}
+
static int qca8084_probe(struct phy_device *phydev)
{
+ int ret;
+
+ ret = qca8084_parse_dt(phydev);
+ if (ret)
+ return ret;
+
return qca8084_parse_and_set_phyaddr(phydev);
}