Files
wlan-ap/feeds/qca-wifi-7/ipq53xx/files-6.1/drivers/net/phy/rtl8221d.c
Justin.Guo a9f47c9e1e qca-wifi-7: CIG WiFi7 WF-672A bring up
* bring up wf672a
* add drivers lsm303agr rtl8221d ilps22qs
* add cig-wifi-mode-sw for switching radio to 2 bands or 3 bands

Fixes: WIFI-14509
Signed-off-by: Justin.Guo <guoxijun@actiontec.com>
2025-05-26 16:23:17 +02:00

229 lines
4.9 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Driver for Rtl PHY
*
* Author: Huang Yunxiang <huangyunxiang@cigtech.com>
*
* Copyright 2024 cig, Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/bitfield.h>
#include <linux/phy.h>
#define PHY_ID_RTL8221D 0x001CC841
#define BIT_0 0x0001
#define BIT_1 0x0002
#define BIT_2 0x0004
#define BIT_3 0x0008
#define BIT_4 0x0010
#define BIT_5 0x0020
#define BIT_6 0x0040
#define BIT_7 0x0080
#define BIT_8 0x0100
#define BIT_9 0x0200
#define BIT_10 0x0400
#define BIT_11 0x0800
#define BIT_12 0x1000
#define BIT_13 0x2000
#define BIT_14 0x4000
#define BIT_15 0x8000
static int rtl8221d_config_aneg(struct phy_device *phydev)
{
return 0;
}
static u32 Rtl8226b_is_link(struct phy_device *phydev)
{
int phydata = 0;
int i = 0;
// must read twice
for(i=0;i<2;i++)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA402);
}
phydev->link = (phydata & BIT_2) ? (1) : (0);
return 0;
}
static int rtl8221d_read_status(struct phy_device *phydev)
{
int phydata, speed_grp, speed;
Rtl8226b_is_link(phydev);
if (phydev->link)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
speed_grp = (phydata & (BIT_9 | BIT_10)) >> 9;
speed = (phydata & (BIT_4 | BIT_5)) >> 4;
switch(speed_grp)
{
case 0:
{
switch(speed)
{
case 1:
phydev->speed = SPEED_100;
break;
case 2:
phydev->speed = SPEED_1000;
break;
default:
phydev->speed = SPEED_10;
break;
}
break;
}
case 1:
{
switch(speed)
{
case 1:
phydev->speed = SPEED_2500;
break;
case 3:
phydev->speed = SPEED_1000; // 2.5G lite
break;
default:
phydev->speed = SPEED_10;
break;
}
break;
}
default:
phydev->speed = SPEED_10;
break;
}
}
else
{
phydev->speed = SPEED_10;
}
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
phydev->duplex = (phydata & BIT_3) ? (DUPLEX_FULL) : (DUPLEX_HALF);
return 0;
}
static int rtl8221d_config_init(struct phy_device *phydev)
{
int err;
int phydata;
u16 timeoutms = 100;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
if (err < 0)
return err;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0);
if (err < 0)
return err;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3);
if (err < 0)
return err;
while(--timeoutms)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x7587);
if((phydata & 0x01) == 0)
break;
mdelay(10);
}
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x75F3);
phydata &= ~BIT_0;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75F3, phydata);
if (err < 0)
return err;
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x697A);
phydata &= (~(BIT_0 | BIT_1 | BIT_2 | BIT_3 | BIT_4 | BIT_5));
phydata |= 2;
phydata |=0x8000;
err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x697A, phydata);
if (err < 0)
return err;
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND1, 0x697A);
Rtl8226b_is_link(phydev);
if (phydev->link)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0x0);
phydata |= BIT_15;
err = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x0, phydata);
if (err < 0)
return err;
while(--timeoutms)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, 0x0);
if (!(phydata & BIT_15))
break;
mdelay(10);
}
err = phy_write_mmd(phydev, MDIO_MMD_PMAPMD, 0x0, phydata);
if (err < 0)
return err;
}
else
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa400);
phydata |= BIT_14;
err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa400, phydata);
if (err < 0)
return err;
while(--timeoutms)
{
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xA434);
if (phydata & BIT_2)
break;
mdelay(10);
}
phydata = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa400);
phydata &= ~BIT_14;
err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa400, phydata);
if (err < 0)
return err;
}
return 0;
}
static int rtl8221d_probe(struct phy_device *phydev)
{
printk("rtl8221d probe");
return 0;
}
static struct phy_driver aqr_driver[] = {
{
PHY_ID_MATCH_MODEL(PHY_ID_RTL8221D),
.name = "Rtl 8221D",
.features = PHY_GBIT_FEATURES,
.probe = rtl8221d_probe,
.config_init = rtl8221d_config_init,
.config_aneg = rtl8221d_config_aneg,
.read_status = rtl8221d_read_status,
},
};
module_phy_driver(aqr_driver);
static struct mdio_device_id __maybe_unused rtl_tbl[] = {
{ PHY_ID_MATCH_MODEL(PHY_ID_RTL8221D) },
{ }
};
MODULE_DEVICE_TABLE(mdio, rtl_tbl);
MODULE_DESCRIPTION("rtl8221d PHY driver");
MODULE_AUTHOR("haungyunxiang huangyunxiang@cigtech.com>");
MODULE_LICENSE("GPL v2");