blob: a73bcee5345538c0d3f205162f06707138766378 [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0+
/*************************************************
* FILE NAME: air_en8811h_api.c
* PURPOSE:
* EN8811H PHY Driver for Linux
* NOTES:
*
* Copyright (C) 2023 Airoha Technology Corp.
*************************************************/
/* INCLUDE FILE DECLARATIONS
*/
#include <linux/uaccess.h>
#include <linux/trace_seq.h>
#include <linux/seq_file.h>
#include <linux/u64_stats_sync.h>
#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/ctype.h>
#include <linux/of_mdio.h>
#include <linux/of_address.h>
#include <linux/mii.h>
#include <linux/phy.h>
#include <linux/debugfs.h>
#include "air_en8811h.h"
#include "air_en8811h_api.h"
/*
struct air_phy_debug {
struct dentry *root;
};
struct air_phy_debug air_debug;
*/
static const char * const tx_rx_string[32] = {
"Tx Reverse, Rx Normal",
"Tx Normal, Rx Normal",
"Tx Reverse, Rx Reverse",
"Tx Normal, Rx Reverse",
};
/* Airoha MII read function */
static int __air_mii_cl22_read(struct mii_bus *ebus,
int addr, unsigned int phy_register)
{
int read_data;
#if (KERNEL_VERSION(4, 16, 0) < LINUX_VERSION_CODE)
read_data = __mdiobus_read(ebus, addr, phy_register);
#else
read_data = ebus->read(ebus, addr, phy_register);
#endif
return read_data;
}
/* Airoha MII write function */
static int __air_mii_cl22_write(struct mii_bus *ebus, int addr,
unsigned int phy_register, unsigned int write_data)
{
int ret = 0;
#if (KERNEL_VERSION(4, 16, 0) < LINUX_VERSION_CODE)
ret = __mdiobus_write(ebus, addr, phy_register, write_data);
#else
ret = ebus->write(ebus, addr, phy_register, write_data);
#endif
return ret;
}
/* Airoha MII read function */
int air_mii_cl22_read(struct mii_bus *ebus, int addr, unsigned int phy_register)
{
int read_data;
mutex_lock(&ebus->mdio_lock);
read_data = __air_mii_cl22_read(ebus, addr, phy_register);
mutex_unlock(&ebus->mdio_lock);
return read_data;
}
/* Airoha MII write function */
int air_mii_cl22_write(struct mii_bus *ebus, int addr,
unsigned int phy_register, unsigned int write_data)
{
int ret = 0;
mutex_lock(&ebus->mdio_lock);
ret = __air_mii_cl22_write(ebus, addr, phy_register, write_data);
mutex_unlock(&ebus->mdio_lock);
return ret;
}
int __air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
{
int ret = 0;
int data;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ACC_CTL_REG, devad);
ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ADDR_DATA_REG, reg);
ret |= __air_mii_cl22_write(mbus, addr,
MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
if (ret) {
dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
return INVALID_DATA;
}
data = __air_mii_cl22_read(mbus, addr, MII_MMD_ADDR_DATA_REG);
return data;
}
int __air_mii_cl45_write(struct phy_device *phydev,
int devad, u16 reg, u16 write_data)
{
int ret = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ACC_CTL_REG, devad);
ret |= __air_mii_cl22_write(mbus, addr, MII_MMD_ADDR_DATA_REG, reg);
ret |= __air_mii_cl22_write(mbus, addr,
MII_MMD_ACC_CTL_REG, MMD_OP_MODE_DATA | devad);
ret |= __air_mii_cl22_write(mbus, addr,
MII_MMD_ADDR_DATA_REG, write_data);
if (ret) {
dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
return ret;
}
return 0;
}
int air_mii_cl45_read(struct phy_device *phydev, int devad, u16 reg)
{
int data;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
mutex_lock(&mbus->mdio_lock);
data = __air_mii_cl45_read(phydev, devad, reg);
mutex_unlock(&mbus->mdio_lock);
if (data == INVALID_DATA) {
dev_err(dev, "__airoha_cl45_read fail\n");
return INVALID_DATA;
}
return data;
}
int air_mii_cl45_write(struct phy_device *phydev,
int devad, u16 reg, u16 write_data)
{
int ret = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
mutex_lock(&mbus->mdio_lock);
ret |= __air_mii_cl45_write(phydev, devad, reg, write_data);
mutex_unlock(&mbus->mdio_lock);
if (ret) {
dev_err(dev, "__airoha_cl45_write, ret: %d\n", ret);
return ret;
}
return ret;
}
/* EN8811H PBUS read function */
static unsigned int __air_pbus_reg_read(struct phy_device *phydev,
unsigned int pbus_address)
{
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
struct device *dev = phydev_dev(phydev);
unsigned int pbus_data_low, pbus_data_high;
unsigned int pbus_data;
int ret = 0;
ret |= __air_mii_cl22_write(mbus, (addr + 8),
0x1F, (pbus_address >> 6));
pbus_data_low = __air_mii_cl22_read(mbus, (addr + 8),
((pbus_address >> 2) & 0xf));
pbus_data_high = __air_mii_cl22_read(mbus, (addr + 8), 0x10);
pbus_data = (pbus_data_high << 16) + pbus_data_low;
if (ret) {
dev_err(dev, "%s: ret: %d\n", __func__, ret);
return ret;
}
return pbus_data;
}
unsigned int air_pbus_reg_read(struct phy_device *phydev,
unsigned int pbus_address)
{
struct mii_bus *mbus = phydev_mdio_bus(phydev);
struct device *dev = phydev_dev(phydev);
int ret = 0;
unsigned int data;
mutex_lock(&mbus->mdio_lock);
data = __air_pbus_reg_read(phydev, pbus_address);
mutex_unlock(&mbus->mdio_lock);
if (ret) {
dev_err(dev, "%s: ret: %d\n", __func__, ret);
return ret;
}
return data;
}
/* EN8811H PBUS write function */
static int __air_pbus_reg_write(struct phy_device *phydev,
unsigned int pbus_address, unsigned long pbus_data)
{
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
struct device *dev = phydev_dev(phydev);
int ret = 0;
ret |= __air_mii_cl22_write(mbus, (addr + 8),
0x1F, (pbus_address >> 6));
ret |= __air_mii_cl22_write(mbus, (addr + 8),
((pbus_address >> 2) & 0xf), (pbus_data & 0xFFFF));
ret |= __air_mii_cl22_write(mbus, (addr + 8),
0x10, (pbus_data >> 16));
if (ret) {
dev_err(dev, "%s: ret: %d\n", __func__, ret);
return ret;
}
return 0;
}
int air_pbus_reg_write(struct phy_device *phydev,
unsigned int pbus_address, unsigned int pbus_data)
{
struct mii_bus *mbus = phydev_mdio_bus(phydev);
struct device *dev = phydev_dev(phydev);
int ret = 0;
mutex_lock(&mbus->mdio_lock);
ret |= __air_pbus_reg_write(phydev, pbus_address, pbus_data);
mutex_unlock(&mbus->mdio_lock);
if (ret) {
dev_err(dev, "%s: ret: %d\n", __func__, ret);
return ret;
}
return 0;
}
/* EN8811H BUCK write function */
static int __air_buckpbus_reg_write(struct phy_device *phydev,
unsigned int pbus_address, unsigned int pbus_data)
{
int ret = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
/* page 4 */
ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 4);
ret |= __air_mii_cl22_write(mbus, addr, 0x10, 0);
ret |= __air_mii_cl22_write(mbus, addr,
0x11, ((pbus_address >> 16) & 0xffff));
ret |= __air_mii_cl22_write(mbus, addr,
0x12, (pbus_address & 0xffff));
ret |= __air_mii_cl22_write(mbus, addr,
0x13, ((pbus_data >> 16) & 0xffff));
ret |= __air_mii_cl22_write(mbus, addr, 0x14, (pbus_data & 0xffff));
ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 0);
if (ret < 0) {
dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
return ret;
}
return 0;
}
/* EN8811H BUCK read function */
static unsigned int __air_buckpbus_reg_read(struct phy_device *phydev,
unsigned int pbus_address)
{
unsigned int pbus_data = 0, pbus_data_low, pbus_data_high;
int ret = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
/* page 4 */
ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 4);
ret |= __air_mii_cl22_write(mbus, addr, 0x10, 0);
ret |= __air_mii_cl22_write(mbus, addr,
0x15, ((pbus_address >> 16) & 0xffff));
ret |= __air_mii_cl22_write(mbus, addr,
0x16, (pbus_address & 0xffff));
if (ret) {
dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
return PBUS_INVALID_DATA;
}
pbus_data_high = __air_mii_cl22_read(mbus, addr, 0x17);
pbus_data_low = __air_mii_cl22_read(mbus, addr, 0x18);
pbus_data = (pbus_data_high << 16) + pbus_data_low;
ret |= __air_mii_cl22_write(mbus, addr, 0x1F, 0);
if (ret) {
dev_err(dev, "__air_mii_cl22_write, ret: %d\n", ret);
return ret;
}
return pbus_data;
}
unsigned int air_buckpbus_reg_read(struct phy_device *phydev,
unsigned int pbus_address)
{
unsigned int data;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
mutex_lock(&mbus->mdio_lock);
data = __air_buckpbus_reg_read(phydev, pbus_address);
mutex_unlock(&mbus->mdio_lock);
if (data == INVALID_DATA) {
dev_err(dev, "__air_buckpbus_reg_read fail\n");
return INVALID_DATA;
}
return data;
}
int air_buckpbus_reg_write(struct phy_device *phydev,
unsigned int pbus_address, unsigned int pbus_data)
{
int ret = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
mutex_lock(&mbus->mdio_lock);
ret |= __air_buckpbus_reg_write(phydev, pbus_address, pbus_data);
mutex_unlock(&mbus->mdio_lock);
if (ret) {
dev_err(dev, "__air_buckpbus_reg_write, ret: %d\n", ret);
return ret;
}
return ret;
}
#if defined(CONFIG_OF)
int en8811h_of_init(struct phy_device *phydev)
{
struct device *dev = phydev_dev(phydev);
struct device_node *of_node = dev->of_node;
struct en8811h_priv *priv = phydev->priv;
u32 val = 0;
dev_info(dev, "%s: start\n", __func__);
if (of_find_property(of_node, "airoha,polarity", NULL)) {
if (of_property_read_u32(of_node, "airoha,polarity",
&val) != 0) {
phydev_err(phydev, "airoha,polarity value is invalid.");
return -EINVAL;
}
if (val < AIR_POL_TX_REV_RX_NOR ||
val > AIR_POL_TX_NOR_RX_REV) {
phydev_err(phydev,
"airoha,polarity value %u out of range.",
val);
return -EINVAL;
}
priv->pol = val;
} else
priv->pol = AIR_POL_TX_NOR_RX_NOR;
return 0;
}
#else
int en8811h_of_init(struct phy_device *phydev)
{
return -ESRCH;
}
#endif /* CONFIG_OF */
static int air_resolve_an_speed(struct phy_device *phydev)
{
int lpagb = 0, advgb = 0, common_adv_gb = 0;
int lpa = 0, adv = 0, common_adv = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
dev_dbg(dev, "AN mode!\n");
dev_dbg(dev, "SPEED 1000/100!\n");
lpagb = air_mii_cl22_read(mbus,
addr, MII_STAT1000);
if (lpagb < 0)
return lpagb;
advgb = air_mii_cl22_read(mbus,
addr, MII_CTRL1000);
if (adv < 0)
return adv;
common_adv_gb = (lpagb & (advgb << 2));
lpa = air_mii_cl22_read(mbus, addr, MII_LPA);
if (lpa < 0)
return lpa;
adv = air_mii_cl22_read(mbus,
addr, MII_ADVERTISE);
if (adv < 0)
return adv;
phydev->pause = GET_BIT(adv, 10);
phydev->asym_pause = GET_BIT(adv, 11);
common_adv = (lpa & adv);
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_HALF;
if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) {
phydev->speed = SPEED_1000;
if (common_adv_gb & LPA_1000FULL)
phydev->duplex = DUPLEX_FULL;
} else if (common_adv & (LPA_100FULL | LPA_100HALF)) {
phydev->speed = SPEED_100;
if (common_adv & LPA_100FULL)
phydev->duplex = DUPLEX_FULL;
} else {
if (common_adv & LPA_10FULL)
phydev->duplex = DUPLEX_FULL;
}
return 0;
}
int air_get_autonego(struct phy_device *phydev, int *an)
{
int reg;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
reg = air_mii_cl22_read(mbus, addr, MII_BMCR);
if (reg < 0)
return -EINVAL;
if (reg & BMCR_ANENABLE)
*an = AUTONEG_ENABLE;
else
*an = AUTONEG_DISABLE;
return 0;
}
static int air_read_status(struct phy_device *phydev)
{
int ret = 0, reg = 0, an = AUTONEG_DISABLE, bmcr = 0;
u32 pbus_value = 0;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
phydev->link = 0;
phydev->autoneg = AUTONEG_DISABLE;
reg = air_mii_cl22_read(mbus, addr, MII_BMSR);
if (reg < 0) {
dev_err(dev, "MII_BMSR reg %d!\n", reg);
return reg;
}
reg = air_mii_cl22_read(mbus, addr, MII_BMSR);
if (reg < 0) {
dev_err(dev, "MII_BMSR reg %d!\n", reg);
return reg;
}
if (reg & BMSR_LSTATUS) {
phydev->link = 1;
ret = air_get_autonego(phydev, &an);
if (ret < 0)
return ret;
phydev->autoneg = an;
pbus_value = air_buckpbus_reg_read(phydev, 0x109D4);
if (0x10 & pbus_value) {
phydev->speed = SPEED_2500;
phydev->duplex = DUPLEX_FULL;
} else {
ret = air_get_autonego(phydev, &an);
if (phydev->autoneg == AUTONEG_ENABLE) {
ret = air_resolve_an_speed(phydev);
if (ret < 0)
return ret;
} else {
dev_dbg(dev, "Force mode!\n");
bmcr = air_mii_cl22_read(mbus, addr, MII_BMCR);
if (bmcr < 0)
return bmcr;
if (bmcr & BMCR_FULLDPLX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (bmcr & BMCR_SPEED1000)
phydev->speed = SPEED_1000;
else if (bmcr & BMCR_SPEED100)
phydev->speed = SPEED_100;
else
phydev->speed = SPEED_UNKNOWN;
}
}
}
return ret;
}
#ifdef CONFIG_AIROHA_EN8811H_PHY_DEBUGFS
static void air_polarity_help(void)
{
pr_notice("\nUsage:\n"
"[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
"echo [tx polarity] [rx polarity] > /[debugfs]/polarity\n"
"option: tx_normal, tx_reverse, rx_normal, rx_revers\n");
}
static int air_set_polarity(struct phy_device *phydev, int tx_rx)
{
int ret = 0;
unsigned int pbus_data = 0;
pr_debug("\nPolarit %s\n", tx_rx_string[tx_rx]);
pbus_data = air_buckpbus_reg_read(phydev, 0xca0f8) & ~(BIT(0) | BIT(1));
pbus_data |= tx_rx;
ret = air_buckpbus_reg_write(phydev, 0xca0f8, pbus_data);
if (ret < 0)
pr_notice("\n%s:air_buckpbus_reg_write fail\n", __func__);
pbus_data = air_buckpbus_reg_read(phydev, 0xca0f8);
pr_notice("\nPolarity %s confirm....(%02lx)\n",
tx_rx_string[tx_rx], pbus_data & (BIT(0) | BIT(1)));
return ret;
}
static int air_set_mode(struct phy_device *phydev, int dbg_mode)
{
int ret = 0, val = 0;
unsigned int pbus_data = 0;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
switch (dbg_mode) {
case AIR_PORT_MODE_FORCE_100:
pr_notice("\nForce 100M\n");
val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) | BIT(8);
ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) & ~BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl45_read(phydev, 0x7, 0x20) & ~BIT(7);
ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_FORCE_1000:
pr_notice("\nForce 1000M\n");
val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) & ~BIT(8);
ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl45_read(phydev, 0x7, 0x20) & ~BIT(7);
ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_FORCE_2500:
pr_notice("\nForce 2500M\n");
val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) & ~BIT(8);
ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) & ~BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl45_read(phydev, 0x7, 0x20) | BIT(7);
ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_AUTONEGO:
pr_notice("\nAutonego mode\n");
val = air_mii_cl22_read(mbus, addr, MII_ADVERTISE) | BIT(8);
ret = air_mii_cl22_write(mbus, addr, MII_ADVERTISE, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_CTRL1000) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_CTRL1000, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl45_read(phydev, 0x7, 0x20) | BIT(7);
ret = air_mii_cl45_write(phydev, 0x7, 0x20, val);
if (unlikely(ret < 0))
break;
val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_POWER_DOWN:
pr_notice("\nPower Down\n");
val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(11);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_POWER_UP:
pr_notice("\nPower Up\n");
val = air_mii_cl22_read(mbus, addr, MII_BMCR) & ~BIT(11);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_SSC_DISABLE:
pr_notice("\nSSC Disabled\n");
pbus_data = air_buckpbus_reg_read(phydev, 0xca000);
pbus_data &= ~BIT(21);
ret = air_buckpbus_reg_write(phydev, 0xca000, pbus_data);
if (unlikely(ret < 0))
break;
break;
case AIR_PORT_MODE_SSC_ENABLE:
pr_notice("\nSSC Enabled\n");
pbus_data = air_buckpbus_reg_read(phydev, 0xca000);
pbus_data |= BIT(21);
ret = air_buckpbus_reg_write(phydev, 0xca000, pbus_data);
if (unlikely(ret < 0))
break;
break;
default:
pr_notice("\nWrong Port mode\n");
break;
}
return ret;
}
static int airphy_info_show(struct seq_file *seq, void *v)
{
struct phy_device *phydev = seq->private;
struct en8811h_priv *priv = phydev->priv;
unsigned int val = 0;
seq_puts(seq, "<<AIR EN8811H Driver info>>\n");
seq_printf(seq, "| Driver Version : %s\n",
EN8811H_DRIVER_VERSION);
val = air_buckpbus_reg_read(phydev, 0xcf914);
seq_printf(seq, "| Boot mode : %s\n",
((val & BIT(24)) >> 24) ? "Flash" : "Download Code");
seq_printf(seq, "| EthMD32.dm.bin CRC32: %08x\n",
priv->dm_crc32);
seq_printf(seq, "| EthMD32.DSP.bin CRC32: %08x\n",
priv->dsp_crc32);
val = air_buckpbus_reg_read(phydev, 0x3b3c);
seq_printf(seq, "| MD32 FW Version : %08x\n", val);
val = air_mii_cl45_read(phydev, 0x1e, 0x8009);
seq_printf(seq, "| MD32 FW Status : %08x\n",
air_mii_cl45_read(phydev, 0x1e, 0x8009));
val = (air_buckpbus_reg_read(phydev, 0xca0f8) & 0x3);
seq_printf(seq, "| Tx, Rx Polarity : %s(%02d)\n",
tx_rx_string[val], val);
seq_puts(seq, "\n");
return 0;
}
static int airphy_info_open(struct inode *inode, struct file *file)
{
return single_open(file, airphy_info_show, inode->i_private);
}
static int airphy_fcm_counter_show(struct phy_device *phydev,
struct seq_file *seq)
{
int ret = 0;
u32 pkt_cnt = 0;
seq_puts(seq, "|\t<<FCM Counter>>\n");
seq_puts(seq, "| Rx from Line side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0090);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0094);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx to System side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe009c);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx to System side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe00A0);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from System side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0078);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from System side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe007C);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx to Line side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0084);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx to Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xe0088);
seq_printf(seq, "%010u |\n", pkt_cnt);
ret = air_buckpbus_reg_write(phydev, 0xe0074, 0xf);
if (ret < 0)
return ret;
return 0;
}
static int airphy_ss_counter_show(struct phy_device *phydev,
struct seq_file *seq)
{
int ret = 0;
u32 pkt_cnt = 0;
seq_puts(seq, "|\t<<SS Counter>>\n");
ret = air_buckpbus_reg_write(phydev, 0xC602C, 0x3);
if (ret < 0)
return ret;
seq_puts(seq, "| TX Start :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60B0);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| TX Terminal :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60B4);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| RX Start :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60BC);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| RX Terminal :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0xC60C0);
seq_printf(seq, "%010u |\n", pkt_cnt);
ret = air_buckpbus_reg_write(phydev, 0xC602C, 0x4);
if (ret < 0)
return ret;
return 0;
}
static int airphy_counter_show(struct seq_file *seq, void *v)
{
struct phy_device *phydev = seq->private;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int ret = 0, addr = phydev_addr(phydev);
u32 pkt_cnt = 0;
ret = air_read_status(phydev);
if (ret < 0)
return ret;
seq_puts(seq, "==========AIR PHY COUNTER==========\n");
if (phydev->link) {
ret = airphy_ss_counter_show(phydev, seq);
if (ret < 0)
return ret;
}
ret = airphy_fcm_counter_show(phydev, seq);
if (ret < 0)
return ret;
if (phydev->link) {
seq_puts(seq, "|\t<<MAC Counter>>\n");
seq_puts(seq, "| Tx Error from System side:");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x131000);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx Error to System side :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x132000);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx from System side :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x131004);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx to System Side :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x132004);
seq_printf(seq, "%010u |\n", pkt_cnt);
}
if (phydev->link && phydev->speed == SPEED_2500) {
seq_puts(seq, "|\t<<LS Counter>>\n");
ret = air_buckpbus_reg_write(phydev, 0x30718, 0x10);
if (ret < 0)
return ret;
ret = air_buckpbus_reg_write(phydev, 0x30718, 0x0);
if (ret < 0)
return ret;
seq_puts(seq, "|\tBefore EF\n");
seq_puts(seq, "| Tx to Line side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x3071c);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx to Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30720);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx_ENC :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30724);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from Line side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x3072c);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30730);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx_DEC :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30728);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "|\tAfter EF\n");
seq_puts(seq, "| Tx to Line side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30734);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx to Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30738);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from Line side_S :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30764);
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx from Line side_T :");
pkt_cnt = air_buckpbus_reg_read(phydev, 0x30768);
seq_printf(seq, "%010u |\n\n", pkt_cnt);
ret = air_buckpbus_reg_write(phydev, 0x30718, 0x13);
if (ret < 0)
return ret;
ret = air_buckpbus_reg_write(phydev, 0x30718, 0x3);
if (ret < 0)
return ret;
ret = air_buckpbus_reg_write(phydev, 0x30718, 0x10);
if (ret < 0)
return ret;
ret = air_buckpbus_reg_write(phydev, 0x30718, 0x0);
if (ret < 0)
return ret;
}
if (phydev->link && ((phydev->speed != SPEED_2500))) {
seq_puts(seq, "|\t<<LS Counter>>\n");
ret = air_mii_cl22_write(mbus, addr, 0x1f, 1);
if (ret < 0)
return ret;
seq_puts(seq, "| Rx from Line side :");
pkt_cnt = air_mii_cl22_read(mbus, addr, 0x12) & 0x7fff;
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Rx Error from Line side :");
pkt_cnt = air_mii_cl22_read(mbus, addr, 0x17) & 0xff;
seq_printf(seq, "%010u |\n", pkt_cnt);
ret = air_mii_cl22_write(mbus, addr, 0x1f, 0);
if (ret < 0)
return ret;
ret = air_mii_cl22_write(mbus, addr, 0x1f, 0x52B5);
if (ret < 0)
return ret;
ret = air_mii_cl22_write(mbus, addr, 0x10, 0xBF92);
if (ret < 0)
return ret;
seq_puts(seq, "| Tx to Line side :");
pkt_cnt = (air_mii_cl22_read(mbus, addr, 0x11) & 0x7ffe) >> 1;
seq_printf(seq, "%010u |\n", pkt_cnt);
seq_puts(seq, "| Tx Error to Line side :");
pkt_cnt = air_mii_cl22_read(mbus, addr, 0x12);
pkt_cnt &= 0x7f;
seq_printf(seq, "%010u |\n\n", pkt_cnt);
ret = air_mii_cl22_write(mbus, addr, 0x1f, 0);
if (ret < 0)
return ret;
}
return ret;
}
static int airphy_counter_open(struct inode *inode, struct file *file)
{
return single_open(file, airphy_counter_show, inode->i_private);
}
static ssize_t airphy_polarity_write(struct file *file, const char __user *ptr,
size_t len, loff_t *off)
{
struct phy_device *phydev = file->private_data;
char buf[32], param1[32], param2[32];
int count = len, ret = 0, tx_rx = 0;
memset(buf, 0, 32);
memset(param1, 0, 32);
memset(param2, 0, 32);
if (count > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, ptr, len))
return -EFAULT;
if (sscanf(buf, "%s %s", param1, param2) == -1)
return -EFAULT;
if (!strncmp("tx_normal", param1, strlen("tx_normal"))) {
if (!strncmp("rx_normal", param2, strlen("rx_normal")))
tx_rx = AIR_POL_TX_NOR_RX_NOR;
else if (!strncmp("rx_reverse", param2, strlen("rx_reverse")))
tx_rx = AIR_POL_TX_NOR_RX_REV;
else {
pr_notice("\nRx param is not correct.\n");
return -EINVAL;
}
} else if (!strncmp("tx_reverse", param1, strlen("tx_reverse"))) {
if (!strncmp("rx_normal", param2, strlen("rx_normal")))
tx_rx = AIR_POL_TX_REV_RX_NOR;
else if (!strncmp("rx_reverse", param2, strlen("rx_reverse")))
tx_rx = AIR_POL_TX_REV_RX_REV;
else {
pr_notice("\nRx param is not correct.\n");
return -EINVAL;
}
} else {
air_polarity_help();
return count;
}
pr_notice("\nSet Polarity %s\n", tx_rx_string[tx_rx]);
ret = air_set_polarity(phydev, tx_rx);
if (ret < 0)
return ret;
return count;
}
static void airphy_port_mode_help(void)
{
pr_notice("\nUsage:\n"
"[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
"echo [mode] [para] > /[debugfs]/port_mode\n"
"echo re-an > /[debugfs]/port_mode\n"
"echo auto > /[debugfs]/port_mode\n"
"echo 2500 > /[debugfs]/port_mode\n"
"echo 1000 > /[debugfs]/port_mode\n"
"echo 100 > /[debugfs]/port_mode\n"
"echo ssc ena/dis > /[debugfs]/port_mode\n"
"echo power up/down > /[debugfs]/port_mode\n");
}
static ssize_t airphy_port_mode(struct file *file, const char __user *ptr,
size_t len, loff_t *off)
{
struct phy_device *phydev = file->private_data;
char buf[32], cmd[32], param[32];
int count = len, ret = 0;
int num = 0, val = 0;
memset(buf, 0, 32);
memset(cmd, 0, 32);
memset(param, 0, 32);
if (count > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, ptr, len))
return -EFAULT;
num = sscanf(buf, "%s %s", cmd, param);
if (num < 1 || num > 3)
return -EFAULT;
if (!strncmp("auto", cmd, strlen("auto")))
ret = air_set_mode(phydev, AIR_PORT_MODE_AUTONEGO);
else if (!strncmp("2500", cmd, strlen("2500")))
ret = air_set_mode(phydev, AIR_PORT_MODE_FORCE_2500);
else if (!strncmp("1000", cmd, strlen("1000")))
ret = air_set_mode(phydev, AIR_PORT_MODE_FORCE_1000);
else if (!strncmp("100", cmd, strlen("100")))
ret = air_set_mode(phydev, AIR_PORT_MODE_FORCE_100);
else if (!strncmp("re-an", cmd, strlen("re-an"))) {
val = phy_read(phydev, MII_BMCR) | BIT(9);
ret = phy_write(phydev, MII_BMCR, val);
} else if (!strncmp("power", cmd, strlen("power"))) {
if (!strncmp("down", param, strlen("down")))
ret = air_set_mode(phydev, AIR_PORT_MODE_POWER_DOWN);
else if (!strncmp("up", param, strlen("up")))
ret = air_set_mode(phydev, AIR_PORT_MODE_POWER_UP);
} else if (!strncmp("ssc", cmd, strlen("ssc"))) {
if (!strncmp("dis", param, strlen("dis")))
ret = air_set_mode(phydev, AIR_PORT_MODE_SSC_DISABLE);
else if (!strncmp("ena", param, strlen("ena")))
ret = air_set_mode(phydev, AIR_PORT_MODE_SSC_ENABLE);
} else if (!strncmp("help", cmd, strlen("help"))) {
airphy_port_mode_help();
}
if (ret < 0)
return ret;
return count;
}
static void airphy_debugfs_buckpbus_help(void)
{
pr_notice("\nUsage:\n"
"[debugfs] = /sys/kernel/debug/mdio-bus\':[phy_addr]\n"
"Read:\n"
"echo r [buckpbus_register] > /[debugfs]/buckpbus_op\n"
"Write:\n"
"echo w [buckpbus_register] [value] > /[debugfs]/buckpbus_op\n");
}
static ssize_t airphy_debugfs_buckpbus(struct file *file,
const char __user *buffer, size_t count,
loff_t *data)
{
struct phy_device *phydev = file->private_data;
char buf[64];
int ret = 0;
unsigned int reg, val;
memset(buf, 0, 64);
if (count > sizeof(buf) - 1)
return -EINVAL;
if (copy_from_user(buf, buffer, count))
return -EFAULT;
if (buf[0] == 'w') {
if (sscanf(buf, "w %x %x", &reg, &val) == -1)
return -EFAULT;
pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), reg, val);
ret = air_buckpbus_reg_write(phydev, reg, val);
if (ret < 0) {
pr_notice("\nbuckpbus_reg_write fail\n");
return -EIO;
}
val = air_buckpbus_reg_read(phydev, reg);
pr_notice("\nphy=%d, reg=0x%x, val=0x%x confirm..\n",
phydev_addr(phydev), reg, val);
} else if (buf[0] == 'r') {
if (sscanf(buf, "r %x", &reg) == -1)
return -EFAULT;
val = air_buckpbus_reg_read(phydev, reg);
pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), reg, val);
} else
airphy_debugfs_buckpbus_help();
return count;
}
static ssize_t airphy_debugfs_pbus(struct file *file,
const char __user *buffer, size_t count,
loff_t *data)
{
struct phy_device *phydev = file->private_data;
char buf[64];
int ret = 0;
unsigned int reg, val;
memset(buf, 0, 64);
if (copy_from_user(buf, buffer, count))
return -EFAULT;
if (buf[0] == 'w') {
if (sscanf(buf, "w %x %x", &reg, &val) == -1)
return -EFAULT;
pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), reg, val);
ret = air_pbus_reg_write(phydev, reg, val);
if (ret < 0) {
pr_notice("\npbus_reg_write fail\n");
return -EIO;
}
val = air_pbus_reg_read(phydev, reg);
pr_notice("\nphy=%d, reg=0x%x, val=0x%x confirm..\n",
phydev_addr(phydev), reg, val);
} else if (buf[0] == 'r') {
if (sscanf(buf, "r %x", &reg) == -1)
return -EFAULT;
val = air_pbus_reg_read(phydev, reg);
pr_notice("\nphy=%d, reg=0x%x, val=0x%x\n",
phydev_addr(phydev), reg, val);
} else
airphy_debugfs_buckpbus_help();
return count;
}
static int airphy_link_status(struct seq_file *seq, void *v)
{
int ret = 0;
struct phy_device *phydev = seq->private;
ret = air_read_status(phydev);
if (ret < 0)
return ret;
seq_printf(seq, "%s Information:\n", dev_name(phydev_dev(phydev)));
seq_printf(seq, "\tPHYAD: %02d\n", phydev_addr(phydev));
seq_printf(seq, "\tLink Status: %s\n", phydev->link ? "UP" : "DOWN");
if (phydev->link) {
seq_printf(seq, "\tAuto-Nego: %s\n",
phydev->autoneg ? "on" : "off");
seq_puts(seq, "\tSpeed: ");
if (phydev->speed == SPEED_UNKNOWN)
seq_printf(seq, "Unknown! (%i)\n", phydev->speed);
else
seq_printf(seq, "%uMb/s\n", phydev->speed);
seq_printf(seq, "\tDuplex: %s\n",
phydev->duplex ? "Full" : "Half");
seq_puts(seq, "\n");
}
return ret;
}
static int airphy_link_status_open(struct inode *inode, struct file *file)
{
return single_open(file, airphy_link_status, inode->i_private);
}
static int dbg_regs_show(struct seq_file *seq, void *v)
{
struct phy_device *phydev = seq->private;
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
seq_puts(seq, "\t<<DEBUG REG DUMP>>\n");
seq_printf(seq, "| RG_MII_BMCR : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, MII_BMCR));
seq_printf(seq, "| RG_MII_BMSR : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, MII_BMSR));
seq_printf(seq, "| RG_MII_ADVERTISE : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, MII_ADVERTISE));
seq_printf(seq, "| RG_MII_LPA : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, MII_LPA));
seq_printf(seq, "| RG_MII_CTRL1000 : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, MII_CTRL1000));
seq_printf(seq, "| RG_MII_STAT1000 : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, MII_STAT1000));
seq_printf(seq, "| RG_MII_REF_CLK : 0x%08x |\n",
air_mii_cl22_read(mbus, addr, 0x1d));
seq_printf(seq, "| RG_HW_STRAP1 : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xcf910));
seq_printf(seq, "| RG_HW_STRAP2 : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xcf914));
seq_printf(seq, "| RG_SYS_LINK_MODE : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xe0004));
seq_printf(seq, "| RG_FCM_CTRL : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xe000C));
seq_printf(seq, "| RG_SS_PAUSE_TIME : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xe0020));
seq_printf(seq, "| RG_MIN_IPG_NUM : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xe002C));
seq_printf(seq, "| RG_CTROL_0 : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xc0000));
seq_printf(seq, "| RG_LINK_STATUS : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xc0b04));
seq_printf(seq, "| RG_LINK_PARTNER_AN : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0xc0014));
seq_printf(seq, "| RG_FN_PWR_CTRL_STATUS : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0x1020c));
seq_printf(seq, "| RG_WHILE_LOOP_COUNT : 0x%08x |\n",
air_buckpbus_reg_read(phydev, 0x3A48));
return 0;
}
static int airphy_dbg_regs_show_open(struct inode *inode, struct file *file)
{
return single_open(file, dbg_regs_show, inode->i_private);
}
static int airphy_temp_show(struct seq_file *seq, void *v)
{
struct phy_device *phydev = seq->private;
int ret = 0;
u32 pbus_value = 0;
seq_puts(seq, "<<AIR EN8811H Temp>>\n");
air_mii_cl45_write(phydev, 0x1e, 0x800e, 0x1100);
air_mii_cl45_write(phydev, 0x1e, 0x800f, 0xe5);
pbus_value = air_buckpbus_reg_read(phydev, 0x3B38);
seq_printf(seq, "| Temperature : %dC |\n",
pbus_value);
seq_puts(seq, "\n");
return 0;
}
static int airphy_temp_show_open(struct inode *inode, struct file *file)
{
return single_open(file, airphy_temp_show, inode->i_private);
}
static unsigned int air_read_lp_speed(struct phy_device *phydev)
{
int val = 0, an = AUTONEG_DISABLE;
unsigned int ret = 0;
int count = 15, i, lpa, lpagb;
struct air_lp_speed *m;
struct device *dev = phydev_dev(phydev);
struct mii_bus *mbus = phydev_mdio_bus(phydev);
int addr = phydev_addr(phydev);
val = air_mii_cl22_read(mbus, addr, MII_BMCR) | BIT(9);
ret = air_mii_cl22_write(mbus, addr, MII_BMCR, val);
if (unlikely(ret < 0))
return ret;
msleep(1500);
do {
msleep(100);
ret = air_mii_cl45_read(phydev, MDIO_MMD_AN, 0x21);
ret &= BIT(5);
if (ret)
break;
count--;
} while (count);
count = 10;
do {
msleep(500);
val = air_mii_cl22_read(mbus, addr, MII_BMSR);
if (val < 0) {
dev_err(dev, "MII_BMSR reg 0x%x!\n", val);
return val;
}
val = air_mii_cl22_read(mbus, addr, MII_BMSR);
if (val < 0) {
dev_err(dev, "MII_BMSR reg 0x%x!\n", val);
return val;
}
dev_dbg(dev, "val 0x%x\n", val);
if (val & BMSR_LSTATUS) {
val = air_mii_cl22_read(mbus, addr, MII_LPA);
if (val < 0)
return val;
lpa = (val & (BIT(5) | BIT(6) | BIT(7) | BIT(8))) >> 5;
val = air_mii_cl22_read(mbus, addr, MII_STAT1000);
if (val < 0)
return val;
lpagb = GET_BIT(val, 11) << 4;
ret |= (lpagb | lpa);
return ret;
}
} while (count--);
return 0;
}
static int airphy_lp_speed(struct seq_file *seq, void *v)
{
unsigned int ret = 0, val = 0, did1 = 0, i;
struct phy_device *phydev = seq->private;
static const struct {
unsigned int bit_index;
const char *name;
} mode_defs[] = {
{ AIR_LINK_MODE_10baseT_Half_BIT,
"10baseT/Half" },
{ AIR_LINK_MODE_10baseT_Full_BIT,
"10baseT/Full" },
{ AIR_LINK_MODE_100baseT_Half_BIT,
"100baseT/Half" },
{ AIR_LINK_MODE_100baseT_Full_BIT,
"100baseT/Full" },
{ AIR_LINK_MODE_1000baseT_Full_BIT,
"1000baseT/Full" },
{ AIR_LINK_MODE_2500baseT_Full_BIT,
"2500baseT/Full" }
};
seq_printf(seq, "%s Link Partner Ability:\n",
dev_name(phydev_dev(phydev)));
ret = air_read_lp_speed(phydev);
if (val < 0)
return val;
for (i = 0; i < ARRAY_SIZE(mode_defs); i++) {
if (ret & BIT(mode_defs[i].bit_index)) {
seq_printf(seq, "\t\t\t %s\n",
mode_defs[i].name);
did1++;
}
}
if (did1 == 0)
seq_puts(seq, "\t\t\t Not reported\n");
return 0;
}
static int airphy_lp_speed_open(struct inode *inode, struct file *file)
{
return single_open(file, airphy_lp_speed, inode->i_private);
}
static const struct file_operations airphy_lp_speed_fops = {
.owner = THIS_MODULE,
.open = airphy_lp_speed_open,
.read = seq_read,
.llseek = noop_llseek,
.release = single_release,
};
static const struct file_operations airphy_info_fops = {
.owner = THIS_MODULE,
.open = airphy_info_open,
.read = seq_read,
.llseek = noop_llseek,
.release = single_release,
};
static const struct file_operations airphy_counter_fops = {
.owner = THIS_MODULE,
.open = airphy_counter_open,
.read = seq_read,
.llseek = noop_llseek,
.release = single_release,
};
static const struct file_operations airphy_debugfs_buckpbus_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = airphy_debugfs_buckpbus,
.llseek = noop_llseek,
};
static const struct file_operations airphy_debugfs_pbus_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = airphy_debugfs_pbus,
.llseek = noop_llseek,
};
static const struct file_operations airphy_port_mode_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = airphy_port_mode,
.llseek = noop_llseek,
};
static const struct file_operations airphy_polarity_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.write = airphy_polarity_write,
.llseek = noop_llseek,
};
static const struct file_operations airphy_link_status_fops = {
.owner = THIS_MODULE,
.open = airphy_link_status_open,
.read = seq_read,
.llseek = noop_llseek,
.release = single_release,
};
static const struct file_operations airphy_dbg_reg_show_fops = {
.owner = THIS_MODULE,
.open = airphy_dbg_regs_show_open,
.read = seq_read,
.llseek = noop_llseek,
.release = single_release,
};
static const struct file_operations airphy_temp_fops = {
.owner = THIS_MODULE,
.open = airphy_temp_show_open,
.read = seq_read,
.llseek = noop_llseek,
.release = single_release,
};
int airphy_debugfs_init(struct phy_device *phydev)
{
int ret = 0;
struct en8811h_priv *priv = phydev->priv;
struct dentry *dir = priv->debugfs_root;
dev_dbg(phydev_dev(phydev), "%s: start\n", __func__);
dir = debugfs_create_dir(dev_name(phydev_dev(phydev)), NULL);
if (!dir) {
dev_err(phydev_dev(phydev), "%s:err at %d\n",
__func__, __LINE__);
ret = -ENOMEM;
}
debugfs_create_file(DEBUGFS_DRIVER_INFO, S_IFREG | 0444,
dir, phydev,
&airphy_info_fops);
debugfs_create_file(DEBUGFS_COUNTER, S_IFREG | 0444,
dir, phydev,
&airphy_counter_fops);
debugfs_create_file(DEBUGFS_BUCKPBUS_OP, S_IFREG | 0200,
dir, phydev,
&airphy_debugfs_buckpbus_fops);
debugfs_create_file(DEBUGFS_PBUS_OP, S_IFREG | 0200,
dir, phydev,
&airphy_debugfs_pbus_fops);
debugfs_create_file(DEBUGFS_PORT_MODE, S_IFREG | 0200,
dir, phydev,
&airphy_port_mode_fops);
debugfs_create_file(DEBUGFS_POLARITY, S_IFREG | 0200,
dir, phydev,
&airphy_polarity_fops);
debugfs_create_file(DEBUGFS_LINK_STATUS, S_IFREG | 0444,
dir, phydev,
&airphy_link_status_fops);
debugfs_create_file(DEBUGFS_DBG_REG_SHOW, S_IFREG | 0444,
dir, phydev,
&airphy_dbg_reg_show_fops);
debugfs_create_file(DEBUGFS_TEMPERATURE, S_IFREG | 0444,
dir, phydev,
&airphy_temp_fops);
debugfs_create_file(DEBUGFS_LP_SPEED, S_IFREG | 0444,
dir, phydev,
&airphy_lp_speed_fops);
priv->debugfs_root = dir;
return ret;
}
void airphy_debugfs_remove(struct phy_device *phydev)
{
struct en8811h_priv *priv = phydev->priv;
debugfs_remove_recursive(priv->debugfs_root);
priv->debugfs_root = NULL;
}
#endif /*CONFIG_AIROHA_EN8811H_PHY_DEBUGFS*/