Part Number: DP83TC812S-Q1
Other Parts Discussed in Thread: DP83TG720S-Q1
Hi,
Can TI provide us with the driver for the DP83TC812S? Our SDK version is ti-processor-sdk-linux-adas-j784s4-evm-09_00_01_03
Thanks!
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Part Number: DP83TC812S-Q1
Other Parts Discussed in Thread: DP83TG720S-Q1
Hi,
Can TI provide us with the driver for the DP83TC812S? Our SDK version is ti-processor-sdk-linux-adas-j784s4-evm-09_00_01_03
Thanks!
Hello Yao,
https://www.ti.com/tool/ETHERNET-SW#downloads
Here you can find our Ethernet PHY Linux drivers & tools including the driver for the DP83TC812.
Regards,
Avtar
I use file dp83tc812.c in https://git.ti.com/gitweb?p=ti-analog-linux-kernel/analog-linux.git;a=blob;f=drivers/net/phy/dp83tc812.c;h=0c594375f188d40299603628a0636947cfea35bf;hb=f973f3deb81b1f44aa4c33b275a342e28fc982fd
It shows build error:
make[1]: Leaving directory '/home/share/test/ethfw_vision/TDA4_J784S4_SDK/linux/board-support/linux-6.1.46+gitAUTOINC+f8110d9ce8-gf8110d9ce8'
make -j 16 -C /home/share/test/ethfw_vision/TDA4_J784S4_SDK/linux/board-support/linux-6.1.46+gitAUTOINC+f8110d9ce8-gf8110d9ce8 ARCH=arm64 CROSS_COMPILE=/home/share/test/ethfw_vision/TDA4_J784S4_SDK/linux/external-toolchain-dir/arm-gnu-toolchain-11.3.rel1-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu- Image
make[1]: Entering directory '/home/share/test/ethfw_vision/TDA4_J784S4_SDK/linux/board-support/linux-6.1.46+gitAUTOINC+f8110d9ce8-gf8110d9ce8'
CALL scripts/checksyscalls.sh
CC drivers/net/phy/dp83tc812.o
drivers/net/phy/dp83tc812.c:524:18: error: ‘struct phy_driver’ has no member named ‘ack_interrupt’; did you mean ‘handle_interrupt’?
524 | .ack_interrupt = dp83812_ack_interrupt, \
| ^~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:534:9: note: in expansion of macro ‘DP83812_PHY_DRIVER’
534 | DP83812_PHY_DRIVER(DP83TC812_CS1_0_PHY_ID, "TI DP83TC812CS1.0"),
| ^~~~~~~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:524:18: error: ‘struct phy_driver’ has no member named ‘ack_interrupt’; did you mean ‘handle_interrupt’?
524 | .ack_interrupt = dp83812_ack_interrupt, \
| ^~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:535:9: note: in expansion of macro ‘DP83812_PHY_DRIVER’
535 | DP83812_PHY_DRIVER(DP83TC812_CS2_0_PHY_ID, "TI DP83TC812CS2.0"),
| ^~~~~~~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:524:18: error: ‘struct phy_driver’ has no member named ‘ack_interrupt’; did you mean ‘handle_interrupt’?
524 | .ack_interrupt = dp83812_ack_interrupt, \
| ^~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:536:9: note: in expansion of macro ‘DP83812_PHY_DRIVER’
536 | DP83812_PHY_DRIVER(DP83TC813_CS2_0_PHY_ID, "TI DP83TC813CS2.0"),
| ^~~~~~~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:524:18: error: ‘struct phy_driver’ has no member named ‘ack_interrupt’; did you mean ‘handle_interrupt’?
524 | .ack_interrupt = dp83812_ack_interrupt, \
| ^~~~~~~~~~~~~
drivers/net/phy/dp83tc812.c:537:9: note: in expansion of macro ‘DP83812_PHY_DRIVER’
537 | DP83812_PHY_DRIVER(DP83TC814_CS2_0_PHY_ID, "TI DP83TC814CS2.0"),
| ^~~~~~~~~~~~~~~~~~
make[5]: *** [scripts/Makefile.build:250: drivers/net/phy/dp83tc812.o] Error 1
make[4]: *** [scripts/Makefile.build:502: drivers/net/phy] Error 2
make[3]: *** [scripts/Makefile.build:502: drivers/net] Error 2
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [scripts/Makefile.build:502: drivers] Error 2
make[1]: *** [Makefile:2012: .] Error 2
make[1]: Leaving directory '/home/share/test/ethfw_vision/TDA4_J784S4_SDK/linux/board-support/linux-6.1.46+gitAUTOINC+f8110d9ce8-gf8110d9ce8'
make: *** [makerules/Makefile_linux:7: linux] Error 2
This driver has an obvious error, lack of 'phydev->priv = dp83720;':
static int dp83812_probe(struct phy_device *phydev)
{
struct dp83812_private *dp83812;
int ret;
dp83812 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83812), GFP_KERNEL);
if (!dp83812)
return -ENOMEM;
phydev->priv = dp83720; //lack of this, it will case coredump.
ret = dp83812_read_straps(phydev);
if (ret)
return ret;
switch (phydev->phy_id) {
case DP83TC812_CS1_0_PHY_ID:
dp83812->chip = DP83812_CS1;
break;
case DP83TC812_CS2_0_PHY_ID:
dp83812->chip = DP83812_CS2;
break;
case DP83TC813_CS2_0_PHY_ID:
dp83812->chip = DP83813_CS2;
break;
case DP83TC814_CS2_0_PHY_ID:
dp83812->chip = DP83814_CS2;
break;
default:
return -EINVAL;
};
/* vikram : above code added to switch between different phy ids */
return dp83812_config_init(phydev);
}Hello,
I see the problem, here is a new driver that we have tested to work on kernel 5.10. Please try and let me know if the same errors are being seen.
// SPDX-License-Identifier: GPL-2.0
/*
* Driver for the Texas Instruments DP83TC812 PHY
*
* Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
*
*/
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
#define DP83TC812_CS1_0_PHY_ID 0x2000a270
#define DP83TC812_CS2_0_PHY_ID 0x2000a271
#define DP83TC813_CS2_0_PHY_ID 0x2000a211
#define DP83TC814_CS2_0_PHY_ID 0x2000a261
#define DP83812_DEVADDR 0x1f
#define DP83812_DEVADDR_MMD1 0x1
#define DP83812_STRAP 0x45d
#define MII_DP83812_SGMII_CTRL 0x608
#define SGMII_CONFIG_VAL 0x027B
#define MII_DP83812_RGMII_CTRL 0x600
#define MII_DP83812_INT_STAT1 0x12
#define MII_DP83812_INT_STAT2 0x13
#define MII_DP83812_INT_STAT3 0x18
#define MII_DP83812_RESET_CTRL 0x1f
#define DP83812_HW_RESET BIT(15)
#define DP83812_SW_RESET BIT(14)
/* INT_STAT1 bits */
#define DP83812_RX_ERR_CNT_HALF_FULL_INT_EN BIT(0)
#define DP83812_TX_ERR_CNT_HALF_FULL_INT_EN BIT(1)
#define DP83812_MS_TRAIN_DONE_INT_EN BIT(2)
#define DP83812_ESD_EVENT_INT_EN BIT(3)
#define DP83812_LINK_STAT_INT_EN BIT(5)
#define DP83812_ENERGY_DET_INT_EN BIT(6)
#define DP83812_LINK_QUAL_INT_EN BIT(7)
/* INT_STAT2 bits */
#define DP83812_JABBER_INT_EN BIT(0)
#define DP83812_POL_INT_EN BIT(1)
#define DP83812_SLEEP_MODE_INT_EN BIT(2)
#define DP83812_OVERTEMP_INT_EN BIT(3)
#define DP83812_FIFO_INT_EN BIT(4)
#define DP83812_PAGE_RXD_INT_EN BIT(5)
#define DP83812_OVERVOLTAGE_INT_EN BIT(6)
#define DP83812_UNDERVOLTAGE_INT_EN BIT(7)
/* INT_STAT3 bits */
#define DP83812_LPS_INT_EN BIT(0)
#define DP83812_WUP_INT_EN BIT(1)
#define DP83812_WAKE_REQ_INT_EN BIT(2)
#define DP83811_NO_FRAME_INT_EN BIT(3)
#define DP83811_POR_DONE_INT_EN BIT(4)
#define DP83812_SLEEP_FAIL_INT_EN BIT(5)
/* RGMII_CTRL bits */
#define DP83812_RGMII_EN BIT(3)
/* SGMII CTRL bits */
#define DP83812_SGMII_AUTO_NEG_EN BIT(0)
#define DP83812_SGMII_EN BIT(9)
/* Strap bits */
#define DP83812_MASTER_MODE BIT(9)
#define DP83812_RGMII_IS_EN BIT(7)
/* RGMII ID CTRL */
#define DP83812_RGMII_ID_CTRL 0x602
#define DP83812_RX_CLK_SHIFT BIT(1)
#define DP83812_TX_CLK_SHIFT BIT(0)
enum dp83812_chip_type {
DP83812_CS1 = 0,
DP83812_CS2,
DP83813_CS2,
DP83814_CS2,
};
struct dp83812_init_reg {
int reg;
int val;
};
static const struct dp83812_init_reg dp83812_master_cs1_0_init[] = {
{0x523, 0x0001},
{0x800, 0xf864},
{0x803, 0x1552},
{0x804, 0x1a66},
{0x805, 0x1f7b},
{0x81f, 0x2a88},
{0x825, 0x40e5},
{0x82b, 0x7f3f},
{0x830, 0x0543},
{0x836, 0x5008},
{0x83a, 0x08e0},
{0x83b, 0x0845},
{0x83e, 0x0445},
{0x855, 0x9b9a},
{0x85f, 0x2010},
{0x860, 0x6040},
{0x86c, 0x1333},
{0x86b, 0x3e10},
{0x872, 0x88c0},
{0x873, 0x0003},
{0x879, 0x000f},
{0x87b, 0x0070},
{0x87c, 0x003f},
{0x89e, 0x00aa},
{0x523, 0x0000},
};
static const struct dp83812_init_reg dp83812_master_cs2_0_init[] = {
{0x523, 0x0001},
{0x81C, 0x0fe2},
{0x872, 0x0300},
{0x879, 0x0f00},
{0x806, 0x2952},
{0x807, 0x3361},
{0x808, 0x3D7B},
{0x83E, 0x045F},
{0x834, 0x8000},
{0x862, 0x00E8},
{0x896, 0x32CB},
{0x03E, 0x0009},
{0x01f, 0x4000},
{0x523, 0x0000},
};
static const struct dp83812_init_reg dp83812_slave_cs1_0_init[] = {
{0x523, 0x0001},
{0x803, 0x1b52},
{0x804, 0x216c},
{0x805, 0x277b},
{0x827, 0x3000},
{0x830, 0x0543},
{0x83a, 0x0020},
{0x83c, 0x0001},
{0x855, 0x9b9a},
{0x85f, 0x2010},
{0x860, 0x6040},
{0x86c, 0x0333},
{0x872, 0x88c0},
{0x873, 0x0021},
{0x879, 0x000f},
{0x87b, 0x0070},
{0x87c, 0x0002},
{0x897, 0x003f},
{0x89e, 0x00a2},
{0x510, 0x000f},
{0x523, 0x0000},
};
static const struct dp83812_init_reg dp83812_slave_cs2_0_init[] = {
{0x523, 0x0001},
{0x873, 0x0821},
{0x896, 0x22ff},
{0x89E, 0x0000},
{0x01f, 0x4000},
{0x523, 0x0000},
};
struct dp83812_private {
int chip;
bool is_master;
bool is_rgmii;
bool is_sgmii;
};
static int dp83812_read_straps(struct phy_device *phydev)
{
struct dp83812_private *dp83812 = phydev->priv;
int strap;
strap = phy_read_mmd(phydev, DP83812_DEVADDR, DP83812_STRAP);
if (strap < 0)
return strap;
printk("%s: Strap is 0x%X\n", __func__, strap);
if (strap & DP83812_MASTER_MODE)
dp83812->is_master = true;
if (strap & DP83812_RGMII_IS_EN)
dp83812->is_rgmii = true;
return 0;
};
static int dp83812_reset(struct phy_device *phydev, bool hw_reset)
{
int ret;
if (hw_reset)
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_RESET_CTRL,
DP83812_HW_RESET);
else
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_RESET_CTRL,
DP83812_SW_RESET);
if (ret)
return ret;
mdelay(100);
return 0;
}
static int dp83812_phy_reset(struct phy_device *phydev)
{
int err;
int ret;
err = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_RESET_CTRL, DP83812_HW_RESET);
if (err < 0)
return err;
ret = dp83812_read_straps(phydev);
if (ret)
return ret;
return 0;
}
static int dp83812_write_seq(struct phy_device *phydev, const struct
dp83812_init_reg *init_data, int size)
{
int ret;
int i;
for (i = 0; i < size; i++) {
ret = phy_write_mmd(phydev, DP83812_DEVADDR, init_data[i].reg,
init_data[i].val);
if (ret)
return ret;
}
return 0;
}
static int dp83812_chip_init(struct phy_device *phydev)
{
struct dp83812_private *dp83812 = phydev->priv;
int ret;
ret = dp83812_reset(phydev, true);
if (ret)
return ret;
phydev->autoneg = AUTONEG_DISABLE;
phydev->speed = SPEED_100;
phydev->duplex = DUPLEX_FULL;
linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
phydev->supported);
if (dp83812->is_master)
ret = phy_write_mmd(phydev, DP83812_DEVADDR_MMD1, 0x0834, 0xc001);
// ret = phy_write_mmd(phydev, DP83812_DEVADDR, 0x0834, 0xc001);
else
ret = phy_write_mmd(phydev, DP83812_DEVADDR_MMD1, 0x0834, 0x8001);
// ret = phy_write_mmd(phydev, DP83812_DEVADDR, 0x0834, 0x8001);
switch (dp83812->chip) {
case DP83812_CS1:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs1_0_init,
ARRAY_SIZE(dp83812_master_cs1_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs1_0_init,
ARRAY_SIZE(dp83812_slave_cs1_0_init));
break;
case DP83812_CS2:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs2_0_init,
ARRAY_SIZE(dp83812_master_cs2_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs2_0_init,
ARRAY_SIZE(dp83812_slave_cs2_0_init));
break;
case DP83813_CS2:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs2_0_init,
ARRAY_SIZE(dp83812_master_cs2_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs2_0_init,
ARRAY_SIZE(dp83812_slave_cs2_0_init));
break;
case DP83814_CS2:
if (dp83812->is_master)
ret = dp83812_write_seq(phydev,
dp83812_master_cs2_0_init,
ARRAY_SIZE(dp83812_master_cs2_0_init));
else
ret = dp83812_write_seq(phydev,
dp83812_slave_cs2_0_init,
ARRAY_SIZE(dp83812_slave_cs2_0_init));
break;
default:
return -EINVAL;
};
if (ret)
return ret;
mdelay(10);
// phy_write_mmd(phydev, DP83812_DEVADDR, 0x523, 0x00);
/* Do a soft reset to restart the PHY with updated values */
return dp83812_reset(phydev, false);
}
static int dp83812_config_init(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
s32 rx_int_delay;
s32 tx_int_delay;
int rgmii_delay;
int value, ret;
ret = dp83812_chip_init(phydev);
if (ret)
return ret;
if (phy_interface_is_rgmii(phydev)) {
rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
true);
if (rx_int_delay <= 0)
rgmii_delay = 0;
else
rgmii_delay = DP83812_RX_CLK_SHIFT;
tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
false);
if (tx_int_delay <= 0)
rgmii_delay &= ~DP83812_TX_CLK_SHIFT;
else
rgmii_delay |= DP83812_TX_CLK_SHIFT;
if (rgmii_delay) {
ret = phy_set_bits_mmd(phydev, DP83812_DEVADDR_MMD1,
DP83812_RGMII_ID_CTRL,
rgmii_delay);
if (ret)
return ret;
}
}
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
value = phy_read(phydev, MII_DP83812_SGMII_CTRL);
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_SGMII_CTRL,
SGMII_CONFIG_VAL);
if (ret < 0)
return ret;
}
return 0;
}
static int dp83812_ack_interrupt(struct phy_device *phydev)
{
int err;
err = phy_read(phydev, MII_DP83812_INT_STAT1);
if (err < 0)
return err;
err = phy_read(phydev, MII_DP83812_INT_STAT2);
if (err < 0)
return err;
err = phy_read(phydev, MII_DP83812_INT_STAT3);
if (err < 0)
return err;
return 0;
}
static int dp83812_config_intr(struct phy_device *phydev)
{
int misr_status, err;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
misr_status = phy_read(phydev, MII_DP83812_INT_STAT1);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83812_ESD_EVENT_INT_EN |
DP83812_LINK_STAT_INT_EN |
DP83812_ENERGY_DET_INT_EN |
DP83812_LINK_QUAL_INT_EN);
err = phy_write(phydev, MII_DP83812_INT_STAT1, misr_status);
if (err < 0)
return err;
misr_status = phy_read(phydev, MII_DP83812_INT_STAT2);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83812_SLEEP_MODE_INT_EN |
DP83812_OVERTEMP_INT_EN |
DP83812_OVERVOLTAGE_INT_EN |
DP83812_UNDERVOLTAGE_INT_EN);
err = phy_write(phydev, MII_DP83812_INT_STAT2, misr_status);
if (err < 0)
return err;
misr_status = phy_read(phydev, MII_DP83812_INT_STAT3);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83812_LPS_INT_EN |
DP83812_WAKE_REQ_INT_EN |
DP83811_NO_FRAME_INT_EN |
DP83811_POR_DONE_INT_EN);
err = phy_write(phydev, MII_DP83812_INT_STAT3, misr_status);
} else {
err = phy_write(phydev, MII_DP83812_INT_STAT1, 0);
if (err < 0)
return err;
err = phy_write(phydev, MII_DP83812_INT_STAT2, 0);
if (err < 0)
return err;
err = phy_write(phydev, MII_DP83812_INT_STAT3, 0);
}
return err;
}
#if 0
static irqreturn_t dp83812_handle_interrupt(struct phy_device *phydev)
{
bool trigger_machine = false;
int irq_status;
/* The INT_STAT registers 1, 2 and 3 are holding the interrupt status
* in the upper half (15:8), while the lower half (7:0) is used for
* controlling the interrupt enable state of those individual interrupt
* sources. To determine the possible interrupt sources, just read the
* INT_STAT* register and use it directly to know which interrupts have
* been enabled previously or not.
*/
irq_status = phy_read(phydev, MII_DP83812_INT_STAT1);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
trigger_machine = true;
irq_status = phy_read(phydev, MII_DP83812_INT_STAT2);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
trigger_machine = true;
irq_status = phy_read(phydev, MII_DP83812_INT_STAT3);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
trigger_machine = true;
if (!trigger_machine)
return IRQ_NONE;
phy_trigger_machine(phydev);
return IRQ_HANDLED;
}
#endif
static int dp83812_config_aneg(struct phy_device *phydev)
{
int value, ret;
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
value = phy_read(phydev, MII_DP83812_SGMII_CTRL);
ret = phy_write_mmd(phydev, DP83812_DEVADDR, MII_DP83812_SGMII_CTRL,
SGMII_CONFIG_VAL);
if (ret < 0)
return ret;
}
return genphy_config_aneg(phydev);
}
static int dp83812_probe(struct phy_device *phydev)
{
struct dp83812_private *dp83812;
int ret;
dp83812 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83812), GFP_KERNEL);
if (!dp83812)
return -ENOMEM;
phydev->priv = dp83812;
ret = dp83812_read_straps(phydev);
if (ret)
return ret;
switch (phydev->phy_id) {
case DP83TC812_CS1_0_PHY_ID:
dp83812->chip = DP83812_CS1;
break;
case DP83TC812_CS2_0_PHY_ID:
dp83812->chip = DP83812_CS2;
break;
case DP83TC813_CS2_0_PHY_ID:
dp83812->chip = DP83813_CS2;
break;
case DP83TC814_CS2_0_PHY_ID:
dp83812->chip = DP83814_CS2;
break;
default:
return -EINVAL;
};
/* vikram : above code added to switch between different phy ids */
return dp83812_config_init(phydev);
}
#define DP83812_PHY_DRIVER(_id, _name) \
{ \
PHY_ID_MATCH_EXACT(_id), \
.name = (_name), \
.probe = dp83812_probe, \
/* PHY_BASIC_FEATURES */ \
.soft_reset = dp83812_phy_reset, \
.config_init = dp83812_config_init, \
.config_aneg = dp83812_config_aneg, \
.ack_interrupt = dp83812_ack_interrupt, \
/*if 0 \
.handle_interrupt = dp83812_handle_interrupt, \
#endif */ \
.config_intr = dp83812_config_intr, \
.suspend = genphy_suspend, \
.resume = genphy_resume, \
}
static struct phy_driver dp83812_driver[] = {
DP83812_PHY_DRIVER(DP83TC812_CS1_0_PHY_ID, "TI DP83TC812CS1.0"),
DP83812_PHY_DRIVER(DP83TC812_CS2_0_PHY_ID, "TI DP83TC812CS2.0"),
DP83812_PHY_DRIVER(DP83TC813_CS2_0_PHY_ID, "TI DP83TC813CS2.0"),
DP83812_PHY_DRIVER(DP83TC814_CS2_0_PHY_ID, "TI DP83TC814CS2.0"),
};
module_phy_driver(dp83812_driver);
static struct mdio_device_id __maybe_unused dp83812_tbl[] = {
{ PHY_ID_MATCH_EXACT(DP83TC812_CS1_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TC812_CS2_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TC813_CS2_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TC814_CS2_0_PHY_ID) },
{ },
};
MODULE_DEVICE_TABLE(mdio, dp83812_tbl);
MODULE_DESCRIPTION("Texas Instruments DP83TC812 PHY driver");
MODULE_AUTHOR("Hari Nagalla <hnagalla@ti.com");
MODULE_LICENSE("GPL");
Regards,
Avtar
1. In my sdk, 'ack_interrupt' does not exsit, and build fail, so I delete it, open the 'handle_interrupt = dp83812_handle_interrupt'. Can I do so?
2.With you latest driver, phy works well, and can you supply 'DP83TG720S-Q1' driver, it has the same issue.
I see the problem, here is a new driver that we have tested to work on kernel 5.10.
Thank you so much to support us.
Hello Zheng,
1. Yes you can do so.
2.
// SPDX-License-Identifier: GPL-2.0-only
/* Driver for the Texas Instruments DP83TG720 PHY
* Copyright (C) 2020 Texas Instruments Incorporated - http://www.ti.com/
*/
#include <linux/ethtool.h>
#include <linux/etherdevice.h>
#include <linux/kernel.h>
#include <linux/mii.h>
#include <linux/module.h>
#include <linux/phy.h>
#include <linux/netdevice.h>
#define DP83TG720ES1_PHY_ID 0x2000a280
#define DP83TG720ES2_PHY_ID 0x2000a281
#define DP83TG720CS_1_0_PHY_ID 0x2000a283
#define DP83TG720CS_1_1_PHY_ID 0x2000a284
#define DP83TG721CS_1_0_PHY_ID 0x2000a290
#define DP83720_DEVADDR 0x1f
#define DP83720_DEVADDR_MMD1 0x1
#define MII_DP83720_INT_STAT1 0x12
#define MII_DP83720_INT_STAT2 0x13
#define MII_DP83720_INT_STAT3 0x18
#define MII_DP83720_RESET_CTRL 0x1f
#define DP83720_HW_RESET BIT(15)
#define DP83720_SW_RESET BIT(14)
#define DP83720_STRAP 0x45d
#define DP83720_SGMII_CTRL 0x608
#define SGMII_CONFIG_VAL 0x027B
/* INT_STAT1 bits */
#define DP83720_ANEG_COMPLETE_INT_EN BIT(2)
#define DP83720_ESD_EVENT_INT_EN BIT(3)
#define DP83720_LINK_STAT_INT_EN BIT(5)
#define DP83720_ENERGY_DET_INT_EN BIT(6)
#define DP83720_LINK_QUAL_INT_EN BIT(7)
/* INT_STAT2 bits */
#define DP83720_SLEEP_MODE_INT_EN BIT(2)
#define DP83720_OVERTEMP_INT_EN BIT(3)
#define DP83720_OVERVOLTAGE_INT_EN BIT(6)
#define DP83720_UNDERVOLTAGE_INT_EN BIT(7)
/* INT_STAT3 bits */
#define DP83720_LPS_INT_EN BIT(0)
#define DP83720_WAKE_REQ_EN BIT(1)
#define DP83720_NO_FRAME_INT_EN BIT(2)
#define DP83720_POR_DONE_INT_EN BIT(3)
/* SGMII CTRL bits */
#define DP83720_SGMII_AUTO_NEG_EN BIT(0)
#define DP83720_SGMII_EN BIT(9)
/* Strap bits */
#define DP83720_MASTER_MODE BIT(5)
#define DP83720_RGMII_IS_EN BIT(12)
#define DP83720_SGMII_IS_EN BIT(13)
#define DP83720_RX_SHIFT_EN BIT(14)
#define DP83720_TX_SHIFT_EN BIT(15)
/* RGMII ID CTRL */
#define DP83720_RGMII_ID_CTRL 0x602
#define DP83720_RX_CLK_SHIFT BIT(1)
#define DP83720_TX_CLK_SHIFT BIT(0)
enum dp83720_chip_type {
DP83720_ES1,
DP83720_ES2,
DP83720_CS1,
DP83720_CS1_1,
DP83721_CS1,
};
struct dp83720_init_reg {
int reg;
int val;
};
static const struct dp83720_init_reg dp83720_es1_init[] = {
{0x182, 0x3000},
{0x56a, 0xfc5},
{0x510, 0x2d51},
{0x408, 0x400},
{0x409, 0x2b},
{0x509, 0x4c04},
{0x8a1, 0xbff},
{0x802, 0x422},
{0x853, 0x632},
{0x824, 0x15e0},
{0x86a, 0x106},
{0x852, 0x3261},
{0x851, 0x5141},
{0x852, 0x327a},
{0x851, 0x6652},
{0x405, 0x1a0},
{0x423, 0x2},
{0x422, 0x0},
{0x420, 0x5510},
{0x421, 0x4077},
{0x412, 0x10},
{0x40f, 0x10},
{0x85d, 0x6405},
{0x894, 0x5557},
{0x892, 0x1b0},
{0x877, 0x55},
{0x80b, 0x16},
{0x864, 0x1fd0},
{0x865, 0xa},
};
static const struct dp83720_init_reg dp83720_es2_master_init[] = {
{0x408, 0x580},
{0x409, 0x2a},
{0x8a1, 0xbff},
{0x802, 0x422},
{0x840, 0x4120},
{0x841, 0x6151},
{0x8a3, 0x24e9},
{0x800, 0x2090},
{0x864, 0x1fd0},
{0x865, 0x2},
{0x405, 0x6800},
{0x420, 0x3310},
{0x412, 0x10},
{0x40f, 0xe4ce},
{0x844, 0x3f10},
{0x8a0, 0x1e7},
{0x843, 0x327a},
{0x842, 0x6652},
{0x50b, 0x7e7c},
{0x56a, 0x7f41},
{0x56b, 0xffb4},
{0x813, 0x3fa0},
{0x88d, 0x3fa0},
{0x899, 0x3fa0},
};
static const struct dp83720_init_reg dp83720_es2_slave_init[] = {
{0x408, 0x580},
{0x409, 0x2a},
{0x8a1, 0xbff},
{0x802, 0x422},
{0x853, 0x632},
{0x824, 0x15e0},
{0x86a, 0x106},
{0x852, 0x327a},
{0x851, 0x6652},
{0x405, 0x6800},
{0x420, 0x3310},
{0x412, 0x10},
{0x40f, 0x10},
{0x85d, 0x6405},
{0x894, 0x5057},
{0x892, 0x1b0},
{0x877, 0x55},
{0x80b, 0x16},
{0x864, 0x1fd0},
{0x865, 0x2},
{0x50b, 0x7e7c},
{0x56a, 0x7f41},
{0x56c, 0xffb4},
{0x813, 0x3fa0},
{0x88d, 0x3fa0},
{0x899, 0x3fa0},
};
static const struct dp83720_init_reg dp83720_cs1_master_init[] = {
{0x408, 0x580},
{0x409, 0x2a},
{0x8a1, 0xbff},
{0x802, 0x422},
{0x864, 0x1fd0},
{0x865, 0x2},
{0x8a3, 0x24e9},
{0x800, 0x2090},
{0x840, 0x4120},
{0x841, 0x6151},
{0x8a0, 0x01e7},
{0x879, 0xe4ce},
{0x89f, 0x1},
{0x844, 0x3f10},
{0x843, 0x327a},
{0x842, 0x6652},
{0x8a8, 0xe080},
{0x8a9, 0x3f0},
{0x88d, 0x3fa0},
{0x889, 0x3fa0},
{0x50b, 0x7e7c},
{0x56a, 0x5f41},
{0x56b, 0xffb4},
{0x56c, 0xffb4},
{0x573, 0x1},
};
static const struct dp83720_init_reg dp83720_cs1_slave_init[] = {
{0x408, 0x580},
{0x409, 0x2a},
{0x8a1, 0xbff},
{0x802, 0x422},
{0x864, 0x1fd0},
{0x865, 0x2},
{0x853, 0x632},
{0x824, 0x15e0},
{0x86a, 0x106},
{0x894, 0x5057},
{0x85d, 0x6405},
{0x892, 0x1b0},
{0x852, 0x327a},
{0x851, 0x6652},
{0x877, 0x55},
{0x80b, 0x16},
{0x8a8, 0xe080},
{0x8a9, 0x3f0},
{0x88d, 0x3fa0},
{0x899, 0x3fa0},
{0x1f, 0x4000},
{0x56a, 0x5f41},
{0x56b, 0xffb4},
{0x56c, 0xffb4},
{0x573, 0x1},
};
static const struct dp83720_init_reg dp83720_cs1_1_master_init[] = {
{0x405, 0x5800},
{0x8ad, 0x3c51},
{0x894, 0x5df7},
{0x8a0, 0x9e7},
{0x8c0, 0x4000},
{0x814, 0x4800},
{0x80d, 0x2ebf},
{0x8c1, 0xb00},
{0x87d, 0x001},
{0x82e, 0x000},
{0x837, 0x0f4},
{0x8be, 0x200},
{0x8c5, 0x4000},
{0x8c7, 0x2000},
{0x8b3, 0x05a},
{0x8b4, 0x05a},
{0x8b0, 0x202},
{0x8b5, 0x0ea},
{0x8ba, 0x2828},
{0x8bb, 0x6828},
{0x8bc, 0x028},
{0x8bf, 0x000},
{0x8b1, 0x014},
{0x8b2, 0x008},
{0x8ec, 0x000},
{0x8c8, 0x003},
{0x8be, 0x201},
{0x18c, 0x001},
};
static const struct dp83720_init_reg dp83720_cs1_1_slave_init[] = {
{0x894, 0x5df7},
{0x56a, 0x5f40},
{0x405, 0x5800},
{0x8ad, 0x3c51},
{0x894, 0x5df7},
{0x8a0, 0x9e7},
{0x8c0, 0x4000},
{0x814, 0x4800},
{0x80d, 0x2ebf},
{0x8c1, 0xb00},
{0x87d, 0x001},
{0x82e, 0x000},
{0x837, 0x0f4},
{0x8be, 0x200},
{0x8c5, 0x4000},
{0x8c7, 0x2000},
{0x8b3, 0x05a},
{0x8b4, 0x05a},
{0x8b0, 0x202},
{0x8b5, 0x0ea},
{0x8ba, 0x2828},
{0x8bb, 0x6828},
{0x8bc, 0x028},
{0x8bf, 0x000},
{0x8b1, 0x014},
{0x8b2, 0x008},
{0x8ec, 0x000},
{0x8c8, 0x003},
{0x8be, 0x201},
{0x56a, 0x5f40},
{0x18c, 0x001},
};
static const struct dp83720_init_reg dp83721_cs1_master_init[] = {
{0x001F,0x8000},
{0x0573,0x0801},
{0x0834,0xC001},
{0x0405,0x6C00},
{0x08AD,0x3C51},
{0x0894,0x5DF7},
{0x08A0,0x09E7},
{0x08C0,0x4000},
{0x0814,0x4800},
{0x080D,0x2EBF},
{0x08C1,0x0B00},
{0x087D,0x0001},
{0x082E,0x0000},
{0x0837,0x00F8},
{0x08BE,0x0200},
{0x08C5,0x4000},
{0x08C7,0x2000},
{0x08B3,0x005A},
{0x08B4,0x005A},
{0x08B0,0x0202},
{0x08B5,0x00EA},
{0x08BA,0x2828},
{0x08BB,0x6828},
{0x08BC,0x0028},
{0x08BF,0x0000},
{0x08B1,0x0014},
{0x08B2,0x0008},
{0x08EC,0x0000},
{0x08FC,0x0091},
{0x08BE,0x0201},
{0x0335,0x0010},
{0x0336,0x0009},
{0x0337,0x0208},
{0x0338,0x0208},
{0x0339,0x02CB},
{0x033A,0x0208},
{0x033B,0x0109},
{0x0418,0x0380},
{0x0420,0xFF10},
{0x0421,0x4033},
{0x0422,0x0800},
{0x0423,0x0002},
{0x0484,0x0003},
{0x055D,0x0008},
{0x042B,0x0018},
{0x087C,0x0080},
{0x08C1,0x0900},
{0x08fc,0x4091},
{0x0881,0x5146},
{0x08be,0x02a1},
{0x0867,0x9999},
{0x0869,0x9666},
{0x086a,0x0009},
{0x0822,0x11e1},
{0x08f9,0x1f11},
{0x08a3,0x24e8},
{0x018C,0x0001},
{0x001F,0x4000},
{0x0573,0x0001},
{0x056A,0x5F41},
};
static const struct dp83720_init_reg dp83721_cs1_slave_init[] = {
{0x405, 0x6C00},
{0x8ad, 0x3c51},
{0x894, 0x5df7},
{0x8a0, 0x9e7},
{0x8c0, 0x4000},
{0x814, 0x4800},
{0x80d, 0x2ebf},
{0x8c1, 0xb00},
{0x87d, 0x001},
{0x82e, 0x000},
{0x837, 0x0f4},
{0x8be, 0x200},
{0x8c5, 0x4000},
{0x8c7, 0x2000},
{0x8b3, 0x05a},
{0x8b4, 0x05a},
{0x8b0, 0x202},
{0x8b5, 0x0ea},
{0x8ba, 0x2828},
{0x8bb, 0x6828},
{0x8bc, 0x028},
{0x8bf, 0x000},
{0x8b1, 0x014},
{0x8b2, 0x008},
{0x8ec, 0x000},
{0x8c8, 0x003},
{0x8be, 0x201},
{0x56a, 0x5f40},
{0x18c, 0x001},
};
struct dp83720_private {
int chip;
bool is_master;
bool is_rgmii;
bool is_sgmii;
bool rx_shift;
bool tx_shift;
};
#if 0
static irqreturn_t dp83720_handle_interrupt(struct phy_device *phydev)
{
int irq_status;
irq_status = phy_read(phydev, MII_DP83720_INT_STAT1);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
goto trigger_machine;
irq_status = phy_read(phydev, MII_DP83720_INT_STAT2);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
goto trigger_machine;
irq_status = phy_read(phydev, MII_DP83720_INT_STAT3);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
goto trigger_machine;
return IRQ_NONE;
trigger_machine:
phy_trigger_machine(phydev);
return IRQ_HANDLED;
}
#endif
static int dp83720_config_intr(struct phy_device *phydev)
{
int misr_status, ret;
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
misr_status = phy_read(phydev, MII_DP83720_INT_STAT1);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83720_ANEG_COMPLETE_INT_EN |
DP83720_ESD_EVENT_INT_EN |
DP83720_LINK_STAT_INT_EN |
DP83720_ENERGY_DET_INT_EN |
DP83720_LINK_QUAL_INT_EN);
ret = phy_write(phydev, MII_DP83720_INT_STAT1, misr_status);
if (ret < 0)
return ret;
misr_status = phy_read(phydev, MII_DP83720_INT_STAT2);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83720_SLEEP_MODE_INT_EN |
DP83720_OVERTEMP_INT_EN |
DP83720_OVERVOLTAGE_INT_EN |
DP83720_UNDERVOLTAGE_INT_EN);
ret = phy_write(phydev, MII_DP83720_INT_STAT2, misr_status);
if (ret < 0)
return ret;
misr_status = phy_read(phydev, MII_DP83720_INT_STAT3);
if (misr_status < 0)
return misr_status;
misr_status |= (DP83720_LPS_INT_EN |
DP83720_WAKE_REQ_EN |
DP83720_NO_FRAME_INT_EN |
DP83720_POR_DONE_INT_EN);
ret = phy_write(phydev, MII_DP83720_INT_STAT3, misr_status);
} else {
ret = phy_write(phydev, MII_DP83720_INT_STAT1, 0);
if (ret < 0)
return ret;
ret = phy_write(phydev, MII_DP83720_INT_STAT2, 0);
if (ret < 0)
return ret;
ret = phy_write(phydev, MII_DP83720_INT_STAT3, 0);
if (ret < 0)
return ret;
ret = phy_read(phydev, MII_DP83720_INT_STAT1);
if (ret < 0)
return ret;
ret = phy_read(phydev, MII_DP83720_INT_STAT2);
if (ret < 0)
return ret;
ret = phy_read(phydev, MII_DP83720_INT_STAT3);
if (ret < 0)
return ret;
ret = 0;
}
return ret;
}
static int dp83720_config_aneg(struct phy_device *phydev)
{
int value, ret;
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
value = phy_read(phydev, DP83720_SGMII_CTRL);
ret = phy_write_mmd(phydev, DP83720_DEVADDR, DP83720_SGMII_CTRL,
SGMII_CONFIG_VAL);
if (ret < 0)
return ret;
}
return genphy_config_aneg(phydev);
}
static int dp83720_read_straps(struct phy_device *phydev)
{
struct dp83720_private *dp83720 = phydev->priv;
int strap;
strap = phy_read_mmd(phydev, DP83720_DEVADDR, DP83720_STRAP);
if (strap < 0)
return strap;
if (strap & DP83720_MASTER_MODE)
dp83720->is_master = true;
if (strap & DP83720_RGMII_IS_EN)
dp83720->is_rgmii = true;
if (strap & DP83720_SGMII_IS_EN)
dp83720->is_sgmii = true;
if (strap & DP83720_RX_SHIFT_EN)
dp83720->rx_shift = true;
if (strap & DP83720_TX_SHIFT_EN)
dp83720->tx_shift = true;
return 0;
};
static int dp83720_reset(struct phy_device *phydev, bool hw_reset)
{
int ret;
if (hw_reset)
ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_DP83720_RESET_CTRL,
DP83720_HW_RESET);
else
ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_DP83720_RESET_CTRL,
DP83720_SW_RESET);
if (ret)
return ret;
mdelay(100);
return 0;
}
static int dp83720_phy_reset(struct phy_device *phydev)
{
int ret;
ret = dp83720_reset(phydev, false);
if (ret)
return ret;
ret = dp83720_read_straps(phydev);
if (ret)
return ret;
return 0;
}
static int dp83720_write_seq(struct phy_device *phydev,
const struct dp83720_init_reg *init_data, int size)
{
int ret;
int i;
for (i = 0; i < size; i++) {
ret = phy_write_mmd(phydev, DP83720_DEVADDR, init_data[i].reg,
init_data[i].val);
if (ret)
return ret;
}
return 0;
}
static int dp83720_chip_init(struct phy_device *phydev)
{
struct dp83720_private *dp83720 = phydev->priv;
int ret;
ret = dp83720_reset(phydev, true);
if (ret)
return ret;
phydev->autoneg = AUTONEG_DISABLE;
phydev->speed = SPEED_1000;
phydev->duplex = DUPLEX_FULL;
linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
phydev->supported);
if (dp83720->chip == DP83720_CS1 && dp83720->is_master) {
ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_BMSR, 0x940);
if (ret)
return ret;
ret = phy_write_mmd(phydev, DP83720_DEVADDR, MII_BMSR, 0x140);
if (ret)
return ret;
}
if (dp83720->is_master)
ret = phy_write_mmd(phydev, DP83720_DEVADDR_MMD1, 0x0834,
0xc001);
else
ret = phy_write_mmd(phydev, DP83720_DEVADDR_MMD1, 0x0834,
0x8001);
if (ret)
return ret;
switch (dp83720->chip) {
case DP83720_ES1:
ret = dp83720_write_seq(phydev, dp83720_es1_init,
ARRAY_SIZE(dp83720_es1_init));
break;
case DP83720_ES2:
if (dp83720->is_master)
ret = dp83720_write_seq(phydev, dp83720_es2_master_init,
ARRAY_SIZE(dp83720_es2_master_init));
else
ret = dp83720_write_seq(phydev, dp83720_es2_slave_init,
ARRAY_SIZE(dp83720_es2_slave_init));
break;
case DP83720_CS1:
ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x101);
if (ret)
return ret;
if (dp83720->is_master)
ret = dp83720_write_seq(phydev, dp83720_cs1_master_init,
ARRAY_SIZE(dp83720_cs1_master_init));
else
ret = dp83720_write_seq(phydev, dp83720_cs1_slave_init,
ARRAY_SIZE(dp83720_cs1_slave_init));
break;
case DP83720_CS1_1:
ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x101);
if (ret)
return ret;
if (dp83720->is_master)
ret = dp83720_write_seq(phydev, dp83720_cs1_1_master_init,
ARRAY_SIZE(dp83720_cs1_1_master_init));
else
ret = dp83720_write_seq(phydev, dp83720_cs1_1_slave_init,
ARRAY_SIZE(dp83720_cs1_1_slave_init));
ret = dp83720_reset(phydev, false);
ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x001);
if (ret)
return ret;
return phy_write_mmd(phydev, DP83720_DEVADDR, 0x56a, 0x5f41);
case DP83721_CS1:
ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x101);
if (ret)
return ret;
if (dp83720->is_master)
ret = dp83720_write_seq(phydev, dp83721_cs1_master_init,
ARRAY_SIZE(dp83721_cs1_master_init));
else
ret = dp83720_write_seq(phydev, dp83721_cs1_slave_init,
ARRAY_SIZE(dp83721_cs1_slave_init));
ret = dp83720_reset(phydev, false);
ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x573, 0x001);
if (ret)
return ret;
return phy_write_mmd(phydev, DP83720_DEVADDR, 0x56a, 0x5f41);
default:
return -EINVAL;
};
if (ret)
return ret;
/* Enable the PHY */
ret = phy_write_mmd(phydev, DP83720_DEVADDR, 0x18c, 0x1);
if (ret)
return ret;
mdelay(10);
/* Do a software reset to restart the PHY with the updated values */
return dp83720_reset(phydev, false);
}
static int dp83720_config_init(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
s32 rx_int_delay;
s32 tx_int_delay;
int rgmii_delay;
int value, ret;
ret = dp83720_chip_init(phydev);
if (ret)
return ret;
if (phy_interface_is_rgmii(phydev)) {
rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
true);
if (rx_int_delay <= 0)
rgmii_delay = 0;
else
rgmii_delay = DP83720_RX_CLK_SHIFT;
tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
false);
if (tx_int_delay <= 0)
rgmii_delay &= ~DP83720_TX_CLK_SHIFT;
else
rgmii_delay |= DP83720_TX_CLK_SHIFT;
if (rgmii_delay) {
ret = phy_set_bits_mmd(phydev, DP83720_DEVADDR_MMD1,
DP83720_RGMII_ID_CTRL,
rgmii_delay);
if (ret)
return ret;
}
}
value = phy_read_mmd(phydev, DP83720_DEVADDR, DP83720_SGMII_CTRL);
if (value < 0)
return value;
if (phydev->interface == PHY_INTERFACE_MODE_SGMII)
value |= DP83720_SGMII_EN;
else
value &= ~DP83720_SGMII_EN;
ret = phy_write_mmd(phydev, DP83720_DEVADDR, DP83720_SGMII_CTRL, value);
if (ret < 0)
return ret;
return 0;
}
static int dp83720_probe(struct phy_device *phydev)
{
struct dp83720_private *dp83720;
int ret;
dp83720 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83720),
GFP_KERNEL);
if (!dp83720)
return -ENOMEM;
phydev->priv = dp83720;
ret = dp83720_read_straps(phydev);
if (ret)
return ret;
switch (phydev->phy_id) {
case DP83TG720ES1_PHY_ID:
dp83720->chip = DP83720_ES1;
break;
case DP83TG720ES2_PHY_ID:
dp83720->chip = DP83720_ES2;
break;
case DP83TG720CS_1_0_PHY_ID:
dp83720->chip = DP83720_CS1;
break;
case DP83TG720CS_1_1_PHY_ID:
dp83720->chip = DP83720_CS1_1;
break;
case DP83TG721CS_1_0_PHY_ID:
dp83720->chip = DP83721_CS1;
break;
default:
return -EINVAL;
};
return dp83720_config_init(phydev);
}
#define DP83720_PHY_DRIVER(_id, _name) \
{ \
PHY_ID_MATCH_EXACT(_id), \
.name = (_name), \
.probe = dp83720_probe, \
/* PHY_GBIT_FEATURES */ \
.soft_reset = dp83720_phy_reset, \
.config_init = dp83720_config_init, \
.config_aneg = dp83720_config_aneg, \
/*if 0 \
.handle_interrupt = dp83720_handle_interrupt, \
#endif */ \
.config_intr = dp83720_config_intr, \
.suspend = genphy_suspend, \
.resume = genphy_resume, \
}
static struct phy_driver dp83720_driver[] = {
DP83720_PHY_DRIVER(DP83TG720ES1_PHY_ID, "TI DP83TG720ES1"),
DP83720_PHY_DRIVER(DP83TG720ES2_PHY_ID, "TI DP83TG720ES2"),
DP83720_PHY_DRIVER(DP83TG720CS_1_0_PHY_ID, "TI DP83TG720CS1.0"),
DP83720_PHY_DRIVER(DP83TG720CS_1_1_PHY_ID, "TI DP83TG720CS1.1"),
DP83720_PHY_DRIVER(DP83TG721CS_1_0_PHY_ID, "TI DP83TG721CS1.0"),
};
module_phy_driver(dp83720_driver);
static struct mdio_device_id __maybe_unused dp83720_tbl[] = {
{ PHY_ID_MATCH_EXACT(DP83TG720ES1_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TG720ES2_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TG720CS_1_0_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TG720CS_1_1_PHY_ID) },
{ PHY_ID_MATCH_EXACT(DP83TG721CS_1_0_PHY_ID) },
{ },
};
MODULE_DEVICE_TABLE(mdio, dp83720_tbl);
MODULE_DESCRIPTION("Texas Instruments DP83TG720 PHY driver");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
MODULE_LICENSE("GPL");
Here is the DP83TG720S-Q1 driver