mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
phy: lynx-28g: common probe() and remove()
Factor the device-agnostic logic from lynx_28g_probe() and lynx_28g_remove() into lynx_probe() and lynx_remove() inside phy-fsl-lynx-core.c. These will be shared with the 10G Lynx driver. Since the PLL configuration, lane configuration and CDR lock detection procedure are going to be different, introduce lynx_info function pointers so that this code remains in the 28G Lynx driver. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Link: https://patch.msgid.link/20260610151952.2141019-11-vladimir.oltean@nxp.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
This commit is contained in:
parent
b1c4d866ed
commit
719a2da392
|
|
@ -12,7 +12,6 @@
|
|||
#include "phy-fsl-lynx-core.h"
|
||||
|
||||
#define LYNX_28G_NUM_LANE 8
|
||||
#define LYNX_28G_NUM_PLL LYNX_NUM_PLL
|
||||
|
||||
/* SoC IP wrapper for protocol converters */
|
||||
#define PCC8 0x10a0
|
||||
|
|
@ -781,6 +780,30 @@ static bool lynx_28g_compat_lane_supports_mode(int lane,
|
|||
}
|
||||
}
|
||||
|
||||
static void lynx_28g_cdr_lock_check(struct lynx_lane *lane)
|
||||
{
|
||||
u32 rrstctl;
|
||||
int err;
|
||||
|
||||
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
|
||||
if (!!(rrstctl & LNaRRSTCTL_CDR_LOCK))
|
||||
return;
|
||||
|
||||
lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
|
||||
LNaRRSTCTL_RST_REQ);
|
||||
|
||||
err = read_poll_timeout(lynx_28g_lane_read, rrstctl,
|
||||
!!(rrstctl & LNaRRSTCTL_RST_DONE),
|
||||
LYNX_28G_LANE_RESET_SLEEP_US,
|
||||
LYNX_28G_LANE_RESET_TIMEOUT_US,
|
||||
false, lane, LNaRRSTCTL);
|
||||
if (err) {
|
||||
dev_warn_once(&lane->phy->dev,
|
||||
"Lane %c receiver reset failed: %pe\n",
|
||||
'A' + lane->id, ERR_PTR(err));
|
||||
}
|
||||
}
|
||||
|
||||
static void lynx_28g_lane_remap_pll(struct lynx_lane *lane,
|
||||
enum lynx_lane_mode lane_mode)
|
||||
{
|
||||
|
|
@ -1088,50 +1111,6 @@ static void lynx_28g_pll_read_configuration(struct lynx_pll *pll)
|
|||
}
|
||||
}
|
||||
|
||||
#define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)
|
||||
|
||||
static void lynx_28g_cdr_lock_check(struct work_struct *work)
|
||||
{
|
||||
struct lynx_28g_priv *priv = work_to_lynx(work);
|
||||
struct lynx_28g_lane *lane;
|
||||
u32 rrstctl;
|
||||
int err, i;
|
||||
|
||||
for (i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
|
||||
lane = &priv->lane[i];
|
||||
if (!lane->phy)
|
||||
continue;
|
||||
|
||||
mutex_lock(&lane->phy->mutex);
|
||||
|
||||
if (!lane->init || !lane->powered_up) {
|
||||
mutex_unlock(&lane->phy->mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
|
||||
if (!(rrstctl & LNaRRSTCTL_CDR_LOCK)) {
|
||||
lynx_28g_lane_rmw(lane, LNaRRSTCTL, LNaRRSTCTL_RST_REQ,
|
||||
LNaRRSTCTL_RST_REQ);
|
||||
|
||||
err = read_poll_timeout(lynx_28g_lane_read, rrstctl,
|
||||
!!(rrstctl & LNaRRSTCTL_RST_DONE),
|
||||
LYNX_28G_LANE_RESET_SLEEP_US,
|
||||
LYNX_28G_LANE_RESET_TIMEOUT_US,
|
||||
false, lane, LNaRRSTCTL);
|
||||
if (err) {
|
||||
dev_warn_once(&lane->phy->dev,
|
||||
"Lane %c receiver reset failed: %pe\n",
|
||||
'A' + lane->id, ERR_PTR(err));
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&lane->phy->mutex);
|
||||
}
|
||||
queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
|
||||
msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
|
||||
{
|
||||
u32 pccr, pss, protocol;
|
||||
|
|
@ -1157,49 +1136,13 @@ static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
|
|||
}
|
||||
}
|
||||
|
||||
static struct phy *lynx_28g_xlate(struct device *dev,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
struct lynx_28g_priv *priv = dev_get_drvdata(dev);
|
||||
int idx;
|
||||
|
||||
if (args->args_count == 0)
|
||||
return of_phy_simple_xlate(dev, args);
|
||||
else if (args->args_count != 1)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
idx = args->args[0];
|
||||
|
||||
if (WARN_ON(idx >= LYNX_28G_NUM_LANE ||
|
||||
idx < priv->info->first_lane))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return priv->lane[idx].phy ?: ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static int lynx_28g_probe_lane(struct lynx_28g_priv *priv, int id,
|
||||
struct device_node *dn)
|
||||
{
|
||||
struct lynx_28g_lane *lane = &priv->lane[id];
|
||||
struct phy *phy;
|
||||
|
||||
phy = devm_phy_create(priv->dev, dn, &lynx_28g_ops);
|
||||
if (IS_ERR(phy))
|
||||
return PTR_ERR(phy);
|
||||
|
||||
lane->priv = priv;
|
||||
lane->phy = phy;
|
||||
lane->id = id;
|
||||
phy_set_drvdata(phy, lane);
|
||||
lynx_28g_lane_read_configuration(lane);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lynx_info lynx_info_compat = {
|
||||
.get_pccr = lynx_28g_get_pccr,
|
||||
.get_pcvt_offset = lynx_28g_get_pcvt_offset,
|
||||
.lane_supports_mode = lynx_28g_compat_lane_supports_mode,
|
||||
.pll_read_configuration = lynx_28g_pll_read_configuration,
|
||||
.lane_read_configuration = lynx_28g_lane_read_configuration,
|
||||
.cdr_lock_check = lynx_28g_cdr_lock_check,
|
||||
.num_lanes = LYNX_28G_NUM_LANE,
|
||||
};
|
||||
|
||||
|
|
@ -1207,6 +1150,9 @@ static const struct lynx_info lynx_info_lx2160a_serdes1 = {
|
|||
.get_pccr = lynx_28g_get_pccr,
|
||||
.get_pcvt_offset = lynx_28g_get_pcvt_offset,
|
||||
.lane_supports_mode = lx2160a_serdes1_lane_supports_mode,
|
||||
.pll_read_configuration = lynx_28g_pll_read_configuration,
|
||||
.lane_read_configuration = lynx_28g_lane_read_configuration,
|
||||
.cdr_lock_check = lynx_28g_cdr_lock_check,
|
||||
.num_lanes = LYNX_28G_NUM_LANE,
|
||||
};
|
||||
|
||||
|
|
@ -1214,6 +1160,9 @@ static const struct lynx_info lynx_info_lx2160a_serdes2 = {
|
|||
.get_pccr = lynx_28g_get_pccr,
|
||||
.get_pcvt_offset = lynx_28g_get_pcvt_offset,
|
||||
.lane_supports_mode = lx2160a_serdes2_lane_supports_mode,
|
||||
.pll_read_configuration = lynx_28g_pll_read_configuration,
|
||||
.lane_read_configuration = lynx_28g_lane_read_configuration,
|
||||
.cdr_lock_check = lynx_28g_cdr_lock_check,
|
||||
.num_lanes = LYNX_28G_NUM_LANE,
|
||||
};
|
||||
|
||||
|
|
@ -1221,6 +1170,9 @@ static const struct lynx_info lynx_info_lx2160a_serdes3 = {
|
|||
.get_pccr = lynx_28g_get_pccr,
|
||||
.get_pcvt_offset = lynx_28g_get_pcvt_offset,
|
||||
.lane_supports_mode = lx2160a_serdes3_lane_supports_mode,
|
||||
.pll_read_configuration = lynx_28g_pll_read_configuration,
|
||||
.lane_read_configuration = lynx_28g_lane_read_configuration,
|
||||
.cdr_lock_check = lynx_28g_cdr_lock_check,
|
||||
.num_lanes = LYNX_28G_NUM_LANE,
|
||||
};
|
||||
|
||||
|
|
@ -1228,6 +1180,9 @@ static const struct lynx_info lynx_info_lx2162a_serdes1 = {
|
|||
.get_pccr = lynx_28g_get_pccr,
|
||||
.get_pcvt_offset = lynx_28g_get_pcvt_offset,
|
||||
.lane_supports_mode = lx2162a_serdes1_lane_supports_mode,
|
||||
.pll_read_configuration = lynx_28g_pll_read_configuration,
|
||||
.lane_read_configuration = lynx_28g_lane_read_configuration,
|
||||
.cdr_lock_check = lynx_28g_cdr_lock_check,
|
||||
.first_lane = 4,
|
||||
.num_lanes = LYNX_28G_NUM_LANE,
|
||||
};
|
||||
|
|
@ -1236,112 +1191,26 @@ static const struct lynx_info lynx_info_lx2162a_serdes2 = {
|
|||
.get_pccr = lynx_28g_get_pccr,
|
||||
.get_pcvt_offset = lynx_28g_get_pcvt_offset,
|
||||
.lane_supports_mode = lx2162a_serdes2_lane_supports_mode,
|
||||
.pll_read_configuration = lynx_28g_pll_read_configuration,
|
||||
.lane_read_configuration = lynx_28g_lane_read_configuration,
|
||||
.cdr_lock_check = lynx_28g_cdr_lock_check,
|
||||
.num_lanes = LYNX_28G_NUM_LANE,
|
||||
};
|
||||
|
||||
static int lynx_28g_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy_provider *provider;
|
||||
struct lynx_28g_priv *priv;
|
||||
struct device_node *dn;
|
||||
int err;
|
||||
|
||||
dn = dev_of_node(dev);
|
||||
if (!dn) {
|
||||
dev_err(dev, "Device requires an OF node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->info = of_device_get_match_data(dev);
|
||||
if (!priv->info)
|
||||
return -ENODEV;
|
||||
|
||||
dev_set_drvdata(dev, priv);
|
||||
spin_lock_init(&priv->pcc_lock);
|
||||
INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
|
||||
const struct lynx_info *info;
|
||||
|
||||
/*
|
||||
* If we get here it means we probed on a device tree where
|
||||
* "fsl,lynx-28g" wasn't the fallback, but the sole compatible string.
|
||||
*/
|
||||
if (priv->info == &lynx_info_compat)
|
||||
info = of_device_get_match_data(dev);
|
||||
if (info == &lynx_info_compat)
|
||||
dev_warn(dev, "Please update device tree to use per-device compatible strings\n");
|
||||
|
||||
priv->lane = devm_kcalloc(dev, priv->info->num_lanes,
|
||||
sizeof(*priv->lane), GFP_KERNEL);
|
||||
if (!priv->lane)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
for (int i = 0; i < LYNX_28G_NUM_PLL; i++) {
|
||||
struct lynx_28g_pll *pll = &priv->pll[i];
|
||||
|
||||
pll->priv = priv;
|
||||
pll->id = i;
|
||||
lynx_28g_pll_read_configuration(pll);
|
||||
}
|
||||
|
||||
if (of_get_child_count(dn)) {
|
||||
struct device_node *child;
|
||||
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
u32 reg;
|
||||
|
||||
/* PHY subnode name must be 'phy'. */
|
||||
if (!(of_node_name_eq(child, "phy")))
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(child, "reg", ®)) {
|
||||
dev_err(dev, "No \"reg\" property for %pOF\n", child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reg < priv->info->first_lane || reg >= LYNX_28G_NUM_LANE) {
|
||||
dev_err(dev, "\"reg\" property out of range for %pOF\n", child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = lynx_28g_probe_lane(priv, reg, child);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = priv->info->first_lane; i < LYNX_28G_NUM_LANE; i++) {
|
||||
err = lynx_28g_probe_lane(priv, i, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, lynx_28g_xlate);
|
||||
if (IS_ERR(provider))
|
||||
return PTR_ERR(provider);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void lynx_28g_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct lynx_28g_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
cancel_delayed_work_sync(&priv->cdr_check);
|
||||
return lynx_probe(pdev, info, &lynx_28g_ops);
|
||||
}
|
||||
|
||||
static const struct of_device_id lynx_28g_of_match_table[] = {
|
||||
|
|
@ -1357,7 +1226,7 @@ MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
|
|||
|
||||
static struct platform_driver lynx_28g_driver = {
|
||||
.probe = lynx_28g_probe,
|
||||
.remove = lynx_28g_remove,
|
||||
.remove = lynx_remove,
|
||||
.driver = {
|
||||
.name = "lynx-28g",
|
||||
.of_match_table = lynx_28g_of_match_table,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
/* Copyright 2025-2026 NXP */
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include "phy-fsl-lynx-core.h"
|
||||
|
||||
|
|
@ -202,5 +203,174 @@ int lynx_pcvt_rmw(struct lynx_lane *lane, enum lynx_lane_mode mode, int cr,
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(lynx_pcvt_rmw, "PHY_FSL_LYNX");
|
||||
|
||||
#define work_to_lynx(w) container_of((w), struct lynx_priv, cdr_check.work)
|
||||
|
||||
static void lynx_cdr_lock_check(struct work_struct *work)
|
||||
{
|
||||
struct lynx_priv *priv = work_to_lynx(work);
|
||||
struct lynx_lane *lane;
|
||||
|
||||
for (int i = priv->info->first_lane; i < priv->info->num_lanes; i++) {
|
||||
lane = &priv->lane[i];
|
||||
if (!lane->phy)
|
||||
continue;
|
||||
|
||||
mutex_lock(&lane->phy->mutex);
|
||||
|
||||
if (!lane->init || !lane->powered_up) {
|
||||
mutex_unlock(&lane->phy->mutex);
|
||||
continue;
|
||||
}
|
||||
|
||||
priv->info->cdr_lock_check(lane);
|
||||
|
||||
mutex_unlock(&lane->phy->mutex);
|
||||
}
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
|
||||
msecs_to_jiffies(1000));
|
||||
}
|
||||
|
||||
static struct phy *lynx_xlate(struct device *dev,
|
||||
const struct of_phandle_args *args)
|
||||
{
|
||||
struct lynx_priv *priv = dev_get_drvdata(dev);
|
||||
int idx;
|
||||
|
||||
if (args->args_count == 0)
|
||||
return of_phy_simple_xlate(dev, args);
|
||||
else if (args->args_count != 1)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
idx = args->args[0];
|
||||
|
||||
if (WARN_ON(idx >= priv->info->num_lanes ||
|
||||
idx < priv->info->first_lane))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
return priv->lane[idx].phy ?: ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
static int lynx_probe_lane(struct lynx_priv *priv, int id,
|
||||
struct device_node *dn,
|
||||
const struct phy_ops *phy_ops)
|
||||
{
|
||||
struct lynx_lane *lane = &priv->lane[id];
|
||||
struct phy *phy;
|
||||
|
||||
phy = devm_phy_create(priv->dev, dn, phy_ops);
|
||||
if (IS_ERR(phy))
|
||||
return PTR_ERR(phy);
|
||||
|
||||
lane->priv = priv;
|
||||
lane->phy = phy;
|
||||
lane->id = id;
|
||||
phy_set_drvdata(phy, lane);
|
||||
priv->info->lane_read_configuration(lane);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lynx_probe(struct platform_device *pdev, const struct lynx_info *info,
|
||||
const struct phy_ops *phy_ops)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy_provider *provider;
|
||||
struct device_node *dn;
|
||||
struct lynx_priv *priv;
|
||||
int err;
|
||||
|
||||
dn = dev_of_node(dev);
|
||||
if (!dn) {
|
||||
dev_err(dev, "Device requires an OF node\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!info)
|
||||
return -ENODEV;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->info = info;
|
||||
dev_set_drvdata(dev, priv);
|
||||
spin_lock_init(&priv->pcc_lock);
|
||||
INIT_DELAYED_WORK(&priv->cdr_check, lynx_cdr_lock_check);
|
||||
|
||||
priv->lane = devm_kcalloc(dev, priv->info->num_lanes,
|
||||
sizeof(*priv->lane), GFP_KERNEL);
|
||||
if (!priv->lane)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
for (int i = 0; i < LYNX_NUM_PLL; i++) {
|
||||
struct lynx_pll *pll = &priv->pll[i];
|
||||
|
||||
pll->priv = priv;
|
||||
pll->id = i;
|
||||
priv->info->pll_read_configuration(pll);
|
||||
}
|
||||
|
||||
if (of_get_child_count(dn)) {
|
||||
struct device_node *child;
|
||||
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
u32 reg;
|
||||
|
||||
/* PHY subnode name must be 'phy'. */
|
||||
if (!(of_node_name_eq(child, "phy")))
|
||||
continue;
|
||||
|
||||
if (of_property_read_u32(child, "reg", ®)) {
|
||||
dev_err(dev, "No \"reg\" property for %pOF\n", child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reg < priv->info->first_lane || reg >= priv->info->num_lanes) {
|
||||
dev_err(dev, "\"reg\" property out of range for %pOF\n", child);
|
||||
of_node_put(child);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = lynx_probe_lane(priv, reg, child, phy_ops);
|
||||
if (err) {
|
||||
of_node_put(child);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = priv->info->first_lane; i < priv->info->num_lanes; i++) {
|
||||
err = lynx_probe_lane(priv, i, NULL, phy_ops);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, lynx_xlate);
|
||||
if (IS_ERR(provider))
|
||||
return PTR_ERR(provider);
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
|
||||
msecs_to_jiffies(1000));
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(lynx_probe, "PHY_FSL_LYNX");
|
||||
|
||||
void lynx_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct lynx_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
cancel_delayed_work_sync(&priv->cdr_check);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(lynx_remove, "PHY_FSL_LYNX");
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Freescale Lynx SerDes core functionality");
|
||||
|
|
|
|||
|
|
@ -10,14 +10,15 @@
|
|||
|
||||
#define LYNX_NUM_PLL 2
|
||||
|
||||
struct lynx_priv;
|
||||
struct lynx_lane;
|
||||
|
||||
struct lynx_pccr {
|
||||
int offset;
|
||||
int width;
|
||||
int shift;
|
||||
};
|
||||
|
||||
struct lynx_priv;
|
||||
|
||||
struct lynx_pll {
|
||||
struct lynx_priv *priv;
|
||||
int id;
|
||||
|
|
@ -42,6 +43,9 @@ struct lynx_info {
|
|||
struct lynx_pccr *pccr);
|
||||
int (*get_pcvt_offset)(int lane, enum lynx_lane_mode mode);
|
||||
bool (*lane_supports_mode)(int lane, enum lynx_lane_mode mode);
|
||||
void (*pll_read_configuration)(struct lynx_pll *pll);
|
||||
void (*lane_read_configuration)(struct lynx_lane *lane);
|
||||
void (*cdr_lock_check)(struct lynx_lane *lane);
|
||||
int first_lane;
|
||||
int num_lanes;
|
||||
};
|
||||
|
|
@ -85,6 +89,10 @@ static inline void lynx_rmw(struct lynx_priv *priv, unsigned long off, u32 val,
|
|||
#define lynx_pll_read(pll, reg) \
|
||||
ioread32((pll)->priv->base + reg((pll)->id))
|
||||
|
||||
int lynx_probe(struct platform_device *pdev, const struct lynx_info *info,
|
||||
const struct phy_ops *phy_ops);
|
||||
void lynx_remove(struct platform_device *pdev);
|
||||
|
||||
const char *lynx_lane_mode_str(enum lynx_lane_mode lane_mode);
|
||||
enum lynx_lane_mode phy_interface_to_lane_mode(phy_interface_t intf);
|
||||
bool lynx_lane_supports_mode(struct lynx_lane *lane, enum lynx_lane_mode mode);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user