123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638 |
- From 2e45d404d99d43bb7127b74b5dea8818df64996c Mon Sep 17 00:00:00 2001
- From: Christian Marangi <[email protected]>
- Date: Mon, 29 Jan 2024 15:15:21 +0100
- Subject: [PATCH 3/5] net: phy: qcom: deatch qca83xx PHY driver from at803x
- Deatch qca83xx PHY driver from at803x.
- The QCA83xx PHYs implement specific function and doesn't use generic
- at803x so it can be detached from the driver and moved to a dedicated
- one.
- Probe function and priv struct is reimplemented to allocate and use
- only the qca83xx specific data. Unused data from at803x PHY driver
- are dropped from at803x priv struct.
- This is to make slimmer PHY drivers instead of including lots of bloat
- that would never be used in specific SoC.
- A new Kconfig flag QCA83XX_PHY is introduced to compile the new
- introduced PHY driver.
- As the Kconfig name starts with Qualcomm the same order is kept.
- Signed-off-by: Christian Marangi <[email protected]>
- Reviewed-by: Andrew Lunn <[email protected]>
- Link: https://lore.kernel.org/r/[email protected]
- Signed-off-by: Jakub Kicinski <[email protected]>
- ---
- drivers/net/phy/qcom/Kconfig | 11 +-
- drivers/net/phy/qcom/Makefile | 1 +
- drivers/net/phy/qcom/at803x.c | 235 ----------------------------
- drivers/net/phy/qcom/qca83xx.c | 275 +++++++++++++++++++++++++++++++++
- 4 files changed, 284 insertions(+), 238 deletions(-)
- create mode 100644 drivers/net/phy/qcom/qca83xx.c
- --- a/drivers/net/phy/qcom/Kconfig
- +++ b/drivers/net/phy/qcom/Kconfig
- @@ -3,9 +3,14 @@ config QCOM_NET_PHYLIB
- tristate
-
- config AT803X_PHY
- - tristate "Qualcomm Atheros AR803X PHYs and QCA833x PHYs"
- + tristate "Qualcomm Atheros AR803X PHYs"
- select QCOM_NET_PHYLIB
- depends on REGULATOR
- help
- - Currently supports the AR8030, AR8031, AR8033, AR8035 and internal
- - QCA8337(Internal qca8k PHY) model
- + Currently supports the AR8030, AR8031, AR8033, AR8035 model
- +
- +config QCA83XX_PHY
- + tristate "Qualcomm Atheros QCA833x PHYs"
- + select QCOM_NET_PHYLIB
- + help
- + Currently supports the internal QCA8337(Internal qca8k PHY) model
- --- a/drivers/net/phy/qcom/Makefile
- +++ b/drivers/net/phy/qcom/Makefile
- @@ -1,3 +1,4 @@
- # SPDX-License-Identifier: GPL-2.0
- obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o
- obj-$(CONFIG_AT803X_PHY) += at803x.o
- +obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
- --- a/drivers/net/phy/qcom/at803x.c
- +++ b/drivers/net/phy/qcom/at803x.c
- @@ -102,17 +102,10 @@
- #define AT803X_PSSR 0x11 /*PHY-Specific Status Register*/
- #define AT803X_PSSR_MR_AN_COMPLETE 0x0200
-
- -#define AT803X_DEBUG_REG_3C 0x3C
- -
- -#define AT803X_DEBUG_REG_GREEN 0x3D
- -#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
- -
- #define AT803X_DEBUG_REG_1F 0x1F
- #define AT803X_DEBUG_PLL_ON BIT(2)
- #define AT803X_DEBUG_RGMII_1V8 BIT(3)
-
- -#define MDIO_AZ_DEBUG 0x800D
- -
- /* AT803x supports either the XTAL input pad, an internal PLL or the
- * DSP as clock reference for the clock output pad. The XTAL reference
- * is only used for 25 MHz output, all other frequencies need the PLL.
- @@ -163,13 +156,7 @@
-
- #define QCA8081_PHY_ID 0x004dd101
-
- -#define QCA8327_A_PHY_ID 0x004dd033
- -#define QCA8327_B_PHY_ID 0x004dd034
- -#define QCA8337_PHY_ID 0x004dd036
- #define QCA9561_PHY_ID 0x004dd042
- -#define QCA8K_PHY_ID_MASK 0xffffffff
- -
- -#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
-
- #define AT803X_PAGE_FIBER 0
- #define AT803X_PAGE_COPPER 1
- @@ -379,12 +366,6 @@ MODULE_DESCRIPTION("Qualcomm Atheros AR8
- MODULE_AUTHOR("Matus Ujhelyi");
- MODULE_LICENSE("GPL");
-
- -static struct at803x_hw_stat qca83xx_hw_stats[] = {
- - { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
- - { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
- - { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
- -};
- -
- struct at803x_ss_mask {
- u16 speed_mask;
- u8 speed_shift;
- @@ -400,7 +381,6 @@ struct at803x_priv {
- bool is_1000basex;
- struct regulator_dev *vddio_rdev;
- struct regulator_dev *vddh_rdev;
- - u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
- int led_polarity_mode;
- };
-
- @@ -564,53 +544,6 @@ static void at803x_get_wol(struct phy_de
- wol->wolopts |= WAKE_MAGIC;
- }
-
- -static int qca83xx_get_sset_count(struct phy_device *phydev)
- -{
- - return ARRAY_SIZE(qca83xx_hw_stats);
- -}
- -
- -static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
- -{
- - int i;
- -
- - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
- - strscpy(data + i * ETH_GSTRING_LEN,
- - qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
- - }
- -}
- -
- -static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
- -{
- - struct at803x_hw_stat stat = qca83xx_hw_stats[i];
- - struct at803x_priv *priv = phydev->priv;
- - int val;
- - u64 ret;
- -
- - if (stat.access_type == MMD)
- - val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
- - else
- - val = phy_read(phydev, stat.reg);
- -
- - if (val < 0) {
- - ret = U64_MAX;
- - } else {
- - val = val & stat.mask;
- - priv->stats[i] += val;
- - ret = priv->stats[i];
- - }
- -
- - return ret;
- -}
- -
- -static void qca83xx_get_stats(struct phy_device *phydev,
- - struct ethtool_stats *stats, u64 *data)
- -{
- - int i;
- -
- - for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
- - data[i] = qca83xx_get_stat(phydev, i);
- -}
- -
- static int at803x_suspend(struct phy_device *phydev)
- {
- int value;
- @@ -1707,124 +1640,6 @@ static int at8035_probe(struct phy_devic
- return at8035_parse_dt(phydev);
- }
-
- -static int qca83xx_config_init(struct phy_device *phydev)
- -{
- - u8 switch_revision;
- -
- - switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
- -
- - switch (switch_revision) {
- - case 1:
- - /* For 100M waveform */
- - at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
- - /* Turn on Gigabit clock */
- - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
- - break;
- -
- - case 2:
- - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
- - fallthrough;
- - case 4:
- - phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
- - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
- - at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
- - at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
- - break;
- - }
- -
- - /* Following original QCA sourcecode set port to prefer master */
- - phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
- -
- - return 0;
- -}
- -
- -static int qca8327_config_init(struct phy_device *phydev)
- -{
- - /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
- - * Disable on init and enable only with 100m speed following
- - * qca original source code.
- - */
- - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- - QCA8327_DEBUG_MANU_CTRL_EN, 0);
- -
- - return qca83xx_config_init(phydev);
- -}
- -
- -static void qca83xx_link_change_notify(struct phy_device *phydev)
- -{
- - /* Set DAC Amplitude adjustment to +6% for 100m on link running */
- - if (phydev->state == PHY_RUNNING) {
- - if (phydev->speed == SPEED_100)
- - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- - QCA8327_DEBUG_MANU_CTRL_EN,
- - QCA8327_DEBUG_MANU_CTRL_EN);
- - } else {
- - /* Reset DAC Amplitude adjustment */
- - at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- - QCA8327_DEBUG_MANU_CTRL_EN, 0);
- - }
- -}
- -
- -static int qca83xx_resume(struct phy_device *phydev)
- -{
- - int ret, val;
- -
- - /* Skip reset if not suspended */
- - if (!phydev->suspended)
- - return 0;
- -
- - /* Reinit the port, reset values set by suspend */
- - qca83xx_config_init(phydev);
- -
- - /* Reset the port on port resume */
- - phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
- -
- - /* On resume from suspend the switch execute a reset and
- - * restart auto-negotiation. Wait for reset to complete.
- - */
- - ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
- - 50000, 600000, true);
- - if (ret)
- - return ret;
- -
- - usleep_range(1000, 2000);
- -
- - return 0;
- -}
- -
- -static int qca83xx_suspend(struct phy_device *phydev)
- -{
- - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
- - AT803X_DEBUG_GATE_CLK_IN1000, 0);
- -
- - at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
- - AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
- - AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
- -
- - return 0;
- -}
- -
- -static int qca8337_suspend(struct phy_device *phydev)
- -{
- - /* Only QCA8337 support actual suspend. */
- - genphy_suspend(phydev);
- -
- - return qca83xx_suspend(phydev);
- -}
- -
- -static int qca8327_suspend(struct phy_device *phydev)
- -{
- - u16 mask = 0;
- -
- - /* QCA8327 cause port unreliability when phy suspend
- - * is set.
- - */
- - mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
- - phy_modify(phydev, MII_BMCR, mask, 0);
- -
- - return qca83xx_suspend(phydev);
- -}
- -
- static int qca808x_phy_fast_retrain_config(struct phy_device *phydev)
- {
- int ret;
- @@ -2599,53 +2414,6 @@ static struct phy_driver at803x_driver[]
- .soft_reset = genphy_soft_reset,
- .config_aneg = at803x_config_aneg,
- }, {
- - /* QCA8337 */
- - .phy_id = QCA8337_PHY_ID,
- - .phy_id_mask = QCA8K_PHY_ID_MASK,
- - .name = "Qualcomm Atheros 8337 internal PHY",
- - /* PHY_GBIT_FEATURES */
- - .probe = at803x_probe,
- - .flags = PHY_IS_INTERNAL,
- - .config_init = qca83xx_config_init,
- - .soft_reset = genphy_soft_reset,
- - .get_sset_count = qca83xx_get_sset_count,
- - .get_strings = qca83xx_get_strings,
- - .get_stats = qca83xx_get_stats,
- - .suspend = qca8337_suspend,
- - .resume = qca83xx_resume,
- -}, {
- - /* QCA8327-A from switch QCA8327-AL1A */
- - .phy_id = QCA8327_A_PHY_ID,
- - .phy_id_mask = QCA8K_PHY_ID_MASK,
- - .name = "Qualcomm Atheros 8327-A internal PHY",
- - /* PHY_GBIT_FEATURES */
- - .link_change_notify = qca83xx_link_change_notify,
- - .probe = at803x_probe,
- - .flags = PHY_IS_INTERNAL,
- - .config_init = qca8327_config_init,
- - .soft_reset = genphy_soft_reset,
- - .get_sset_count = qca83xx_get_sset_count,
- - .get_strings = qca83xx_get_strings,
- - .get_stats = qca83xx_get_stats,
- - .suspend = qca8327_suspend,
- - .resume = qca83xx_resume,
- -}, {
- - /* QCA8327-B from switch QCA8327-BL1A */
- - .phy_id = QCA8327_B_PHY_ID,
- - .phy_id_mask = QCA8K_PHY_ID_MASK,
- - .name = "Qualcomm Atheros 8327-B internal PHY",
- - /* PHY_GBIT_FEATURES */
- - .link_change_notify = qca83xx_link_change_notify,
- - .probe = at803x_probe,
- - .flags = PHY_IS_INTERNAL,
- - .config_init = qca8327_config_init,
- - .soft_reset = genphy_soft_reset,
- - .get_sset_count = qca83xx_get_sset_count,
- - .get_strings = qca83xx_get_strings,
- - .get_stats = qca83xx_get_stats,
- - .suspend = qca8327_suspend,
- - .resume = qca83xx_resume,
- -}, {
- /* Qualcomm QCA8081 */
- PHY_ID_MATCH_EXACT(QCA8081_PHY_ID),
- .name = "Qualcomm QCA8081",
- @@ -2683,9 +2451,6 @@ static struct mdio_device_id __maybe_unu
- { PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
- { PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
- { PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
- - { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
- - { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
- - { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA9561_PHY_ID) },
- { PHY_ID_MATCH_EXACT(QCA8081_PHY_ID) },
- { }
- --- /dev/null
- +++ b/drivers/net/phy/qcom/qca83xx.c
- @@ -0,0 +1,275 @@
- +// SPDX-License-Identifier: GPL-2.0+
- +
- +#include <linux/phy.h>
- +#include <linux/module.h>
- +
- +#include "qcom.h"
- +
- +#define AT803X_DEBUG_REG_3C 0x3C
- +
- +#define AT803X_DEBUG_REG_GREEN 0x3D
- +#define AT803X_DEBUG_GATE_CLK_IN1000 BIT(6)
- +
- +#define MDIO_AZ_DEBUG 0x800D
- +
- +#define QCA8327_A_PHY_ID 0x004dd033
- +#define QCA8327_B_PHY_ID 0x004dd034
- +#define QCA8337_PHY_ID 0x004dd036
- +#define QCA8K_PHY_ID_MASK 0xffffffff
- +
- +#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
- +
- +static struct at803x_hw_stat qca83xx_hw_stats[] = {
- + { "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
- + { "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
- + { "eee_wake_errors", 0x16, GENMASK(15, 0), MMD},
- +};
- +
- +struct qca83xx_priv {
- + u64 stats[ARRAY_SIZE(qca83xx_hw_stats)];
- +};
- +
- +MODULE_DESCRIPTION("Qualcomm Atheros QCA83XX PHY driver");
- +MODULE_AUTHOR("Matus Ujhelyi");
- +MODULE_AUTHOR("Christian Marangi <[email protected]>");
- +MODULE_LICENSE("GPL");
- +
- +static int qca83xx_get_sset_count(struct phy_device *phydev)
- +{
- + return ARRAY_SIZE(qca83xx_hw_stats);
- +}
- +
- +static void qca83xx_get_strings(struct phy_device *phydev, u8 *data)
- +{
- + int i;
- +
- + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++) {
- + strscpy(data + i * ETH_GSTRING_LEN,
- + qca83xx_hw_stats[i].string, ETH_GSTRING_LEN);
- + }
- +}
- +
- +static u64 qca83xx_get_stat(struct phy_device *phydev, int i)
- +{
- + struct at803x_hw_stat stat = qca83xx_hw_stats[i];
- + struct qca83xx_priv *priv = phydev->priv;
- + int val;
- + u64 ret;
- +
- + if (stat.access_type == MMD)
- + val = phy_read_mmd(phydev, MDIO_MMD_PCS, stat.reg);
- + else
- + val = phy_read(phydev, stat.reg);
- +
- + if (val < 0) {
- + ret = U64_MAX;
- + } else {
- + val = val & stat.mask;
- + priv->stats[i] += val;
- + ret = priv->stats[i];
- + }
- +
- + return ret;
- +}
- +
- +static void qca83xx_get_stats(struct phy_device *phydev,
- + struct ethtool_stats *stats, u64 *data)
- +{
- + int i;
- +
- + for (i = 0; i < ARRAY_SIZE(qca83xx_hw_stats); i++)
- + data[i] = qca83xx_get_stat(phydev, i);
- +}
- +
- +static int qca83xx_probe(struct phy_device *phydev)
- +{
- + struct device *dev = &phydev->mdio.dev;
- + struct qca83xx_priv *priv;
- +
- + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- + if (!priv)
- + return -ENOMEM;
- +
- + phydev->priv = priv;
- +
- + return 0;
- +}
- +
- +static int qca83xx_config_init(struct phy_device *phydev)
- +{
- + u8 switch_revision;
- +
- + switch_revision = phydev->dev_flags & QCA8K_DEVFLAGS_REVISION_MASK;
- +
- + switch (switch_revision) {
- + case 1:
- + /* For 100M waveform */
- + at803x_debug_reg_write(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL, 0x02ea);
- + /* Turn on Gigabit clock */
- + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x68a0);
- + break;
- +
- + case 2:
- + phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0x0);
- + fallthrough;
- + case 4:
- + phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
- + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_GREEN, 0x6860);
- + at803x_debug_reg_write(phydev, AT803X_DEBUG_SYSTEM_CTRL_MODE, 0x2c46);
- + at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
- + break;
- + }
- +
- + /* Following original QCA sourcecode set port to prefer master */
- + phy_set_bits(phydev, MII_CTRL1000, CTL1000_PREFER_MASTER);
- +
- + return 0;
- +}
- +
- +static int qca8327_config_init(struct phy_device *phydev)
- +{
- + /* QCA8327 require DAC amplitude adjustment for 100m set to +6%.
- + * Disable on init and enable only with 100m speed following
- + * qca original source code.
- + */
- + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- + QCA8327_DEBUG_MANU_CTRL_EN, 0);
- +
- + return qca83xx_config_init(phydev);
- +}
- +
- +static void qca83xx_link_change_notify(struct phy_device *phydev)
- +{
- + /* Set DAC Amplitude adjustment to +6% for 100m on link running */
- + if (phydev->state == PHY_RUNNING) {
- + if (phydev->speed == SPEED_100)
- + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- + QCA8327_DEBUG_MANU_CTRL_EN,
- + QCA8327_DEBUG_MANU_CTRL_EN);
- + } else {
- + /* Reset DAC Amplitude adjustment */
- + at803x_debug_reg_mask(phydev, AT803X_DEBUG_ANALOG_TEST_CTRL,
- + QCA8327_DEBUG_MANU_CTRL_EN, 0);
- + }
- +}
- +
- +static int qca83xx_resume(struct phy_device *phydev)
- +{
- + int ret, val;
- +
- + /* Skip reset if not suspended */
- + if (!phydev->suspended)
- + return 0;
- +
- + /* Reinit the port, reset values set by suspend */
- + qca83xx_config_init(phydev);
- +
- + /* Reset the port on port resume */
- + phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
- +
- + /* On resume from suspend the switch execute a reset and
- + * restart auto-negotiation. Wait for reset to complete.
- + */
- + ret = phy_read_poll_timeout(phydev, MII_BMCR, val, !(val & BMCR_RESET),
- + 50000, 600000, true);
- + if (ret)
- + return ret;
- +
- + usleep_range(1000, 2000);
- +
- + return 0;
- +}
- +
- +static int qca83xx_suspend(struct phy_device *phydev)
- +{
- + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_GREEN,
- + AT803X_DEBUG_GATE_CLK_IN1000, 0);
- +
- + at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_HIB_CTRL,
- + AT803X_DEBUG_HIB_CTRL_EN_ANY_CHANGE |
- + AT803X_DEBUG_HIB_CTRL_SEL_RST_80U, 0);
- +
- + return 0;
- +}
- +
- +static int qca8337_suspend(struct phy_device *phydev)
- +{
- + /* Only QCA8337 support actual suspend. */
- + genphy_suspend(phydev);
- +
- + return qca83xx_suspend(phydev);
- +}
- +
- +static int qca8327_suspend(struct phy_device *phydev)
- +{
- + u16 mask = 0;
- +
- + /* QCA8327 cause port unreliability when phy suspend
- + * is set.
- + */
- + mask |= ~(BMCR_SPEED1000 | BMCR_FULLDPLX);
- + phy_modify(phydev, MII_BMCR, mask, 0);
- +
- + return qca83xx_suspend(phydev);
- +}
- +
- +static struct phy_driver qca83xx_driver[] = {
- +{
- + /* QCA8337 */
- + .phy_id = QCA8337_PHY_ID,
- + .phy_id_mask = QCA8K_PHY_ID_MASK,
- + .name = "Qualcomm Atheros 8337 internal PHY",
- + /* PHY_GBIT_FEATURES */
- + .probe = qca83xx_probe,
- + .flags = PHY_IS_INTERNAL,
- + .config_init = qca83xx_config_init,
- + .soft_reset = genphy_soft_reset,
- + .get_sset_count = qca83xx_get_sset_count,
- + .get_strings = qca83xx_get_strings,
- + .get_stats = qca83xx_get_stats,
- + .suspend = qca8337_suspend,
- + .resume = qca83xx_resume,
- +}, {
- + /* QCA8327-A from switch QCA8327-AL1A */
- + .phy_id = QCA8327_A_PHY_ID,
- + .phy_id_mask = QCA8K_PHY_ID_MASK,
- + .name = "Qualcomm Atheros 8327-A internal PHY",
- + /* PHY_GBIT_FEATURES */
- + .link_change_notify = qca83xx_link_change_notify,
- + .probe = qca83xx_probe,
- + .flags = PHY_IS_INTERNAL,
- + .config_init = qca8327_config_init,
- + .soft_reset = genphy_soft_reset,
- + .get_sset_count = qca83xx_get_sset_count,
- + .get_strings = qca83xx_get_strings,
- + .get_stats = qca83xx_get_stats,
- + .suspend = qca8327_suspend,
- + .resume = qca83xx_resume,
- +}, {
- + /* QCA8327-B from switch QCA8327-BL1A */
- + .phy_id = QCA8327_B_PHY_ID,
- + .phy_id_mask = QCA8K_PHY_ID_MASK,
- + .name = "Qualcomm Atheros 8327-B internal PHY",
- + /* PHY_GBIT_FEATURES */
- + .link_change_notify = qca83xx_link_change_notify,
- + .probe = qca83xx_probe,
- + .flags = PHY_IS_INTERNAL,
- + .config_init = qca8327_config_init,
- + .soft_reset = genphy_soft_reset,
- + .get_sset_count = qca83xx_get_sset_count,
- + .get_strings = qca83xx_get_strings,
- + .get_stats = qca83xx_get_stats,
- + .suspend = qca8327_suspend,
- + .resume = qca83xx_resume,
- +}, };
- +
- +module_phy_driver(qca83xx_driver);
- +
- +static struct mdio_device_id __maybe_unused qca83xx_tbl[] = {
- + { PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
- + { PHY_ID_MATCH_EXACT(QCA8327_A_PHY_ID) },
- + { PHY_ID_MATCH_EXACT(QCA8327_B_PHY_ID) },
- + { }
- +};
- +
- +MODULE_DEVICE_TABLE(mdio, qca83xx_tbl);
|