Skip to content

Commit d1abe52

Browse files
committed
1 parent d24bcd1 commit d1abe52

2 files changed

Lines changed: 249 additions & 0 deletions

File tree

drivers/net/dsa/mxl862xx/mxl862xx.c

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <net/dsa.h>
2020
#include <linux/dsa/8021q.h>
2121
#include <linux/stddef.h>
22+
#include <linux/gpio/consumer.h>
23+
#include <linux/of_net.h>
2224

2325
#include "mxl862xx.h"
2426
#include "mxl862xx-api.h"
@@ -3712,12 +3714,221 @@ static const struct dsa_switch_ops mxl862xx_switch_ops = {
37123714
.setup = mxl862xx_setup,
37133715
};
37143716

3717+
static void sfp_monitor_work_func(struct work_struct *work)
3718+
{
3719+
struct combo_port_mux *mux = container_of(work, struct combo_port_mux, sfp_monitor_work.work);
3720+
struct dsa_switch *ds = mux->dp->ds;
3721+
struct dsa_port *dp = mux->dp;
3722+
struct net_device *dev = mux->dp->user;
3723+
unsigned int new_channel;
3724+
int sfp_present;
3725+
3726+
if (IS_ERR(mux->mod_def0_gpio) || IS_ERR(mux->chan_sel_gpio))
3727+
goto reschedule;
3728+
3729+
if (!netif_running(dev))
3730+
goto reschedule;
3731+
3732+
sfp_present = gpiod_get_value_cansleep(mux->mod_def0_gpio);
3733+
new_channel = sfp_present ? mux->sfp_present_channel : !mux->sfp_present_channel;
3734+
3735+
if (mux->initialized && mux->channel == new_channel)
3736+
goto reschedule;
3737+
3738+
rtnl_lock();
3739+
3740+
phylink_stop(dp->pl);
3741+
phylink_disconnect_phy(dp->pl);
3742+
3743+
dp->dn = mux->data[new_channel]->of_node;
3744+
dp->pl = mux->data[new_channel]->phylink;
3745+
3746+
phylink_of_phy_connect(dp->pl, dp->dn, 0);
3747+
phylink_start(dp->pl);
3748+
3749+
dev_info(ds->dev, "dsa mux: switch to channel%d\n", new_channel);
3750+
3751+
gpiod_set_value_cansleep(mux->chan_sel_gpio, new_channel);
3752+
3753+
rtnl_unlock();
3754+
3755+
mux->channel = new_channel;
3756+
mux->initialized = true;
3757+
3758+
reschedule:
3759+
mod_delayed_work(system_wq, &mux->sfp_monitor_work, msecs_to_jiffies(100));
3760+
}
3761+
3762+
static int ds_add_mux_channel(struct combo_port_mux *mux, struct device_node *np)
3763+
{
3764+
const __be32 *_id = of_get_property(np, "reg", NULL);
3765+
struct dsa_switch *ds = mux->dp->ds;
3766+
struct dp_mux_data *data;
3767+
struct phylink *phylink;
3768+
phy_interface_t phy_mode;
3769+
int id, err;
3770+
3771+
if (!_id) {
3772+
dev_err(ds->dev, "missing mux channel id\n");
3773+
return -EINVAL;
3774+
}
3775+
3776+
id = be32_to_cpup(_id);
3777+
if (id < 0 || id > 1) {
3778+
dev_err(ds->dev, "%d is not a valid mux channel id\n", id);
3779+
return -EINVAL;
3780+
}
3781+
3782+
data = kmalloc(sizeof(*data), GFP_KERNEL);
3783+
if (unlikely(!data)) {
3784+
dev_err(ds->dev, "failed to create mux data structure\n");
3785+
return -ENOMEM;
3786+
}
3787+
3788+
err = of_get_phy_mode(np, &phy_mode);
3789+
if (err) {
3790+
dev_err(ds->dev, "incorrect phy-mode\n");
3791+
goto err_free_data;
3792+
}
3793+
3794+
phylink = phylink_create(&mux->dp->pl_config,
3795+
of_fwnode_handle(np),
3796+
phy_mode, ds->phylink_mac_ops);
3797+
if (IS_ERR(phylink)) {
3798+
dev_err(ds->dev, "failed to create phylink structure\n");
3799+
err = PTR_ERR(phylink);
3800+
goto err_free_data;
3801+
}
3802+
3803+
data->of_node = np;
3804+
data->phylink = phylink;
3805+
mux->data[id] = data;
3806+
3807+
return 0;
3808+
3809+
err_free_data:
3810+
kfree(data);
3811+
return err;
3812+
}
3813+
3814+
static int ds_add_mux(struct mxl862xx_priv *priv, struct device_node *np)
3815+
{
3816+
const __be32 *_id = of_get_property(np, "reg", NULL);
3817+
struct device_node *child;
3818+
struct combo_port_mux *mux;
3819+
unsigned int id;
3820+
int err;
3821+
3822+
if (!_id) {
3823+
dev_err(priv->dev, "missing attach dp id\n");
3824+
return -EINVAL;
3825+
}
3826+
3827+
id = be32_to_cpup(_id);
3828+
if (id < 0 || id >= MAX_PORTS) {
3829+
dev_err(priv->dev, "%d is not a valid attach dp id\n", id);
3830+
return -EINVAL;
3831+
}
3832+
3833+
mux = kmalloc(sizeof(struct combo_port_mux), GFP_KERNEL);
3834+
if (unlikely(!mux)) {
3835+
dev_err(priv->dev, "failed to create mux structure\n");
3836+
return -ENOMEM;
3837+
}
3838+
3839+
mux->mod_def0_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np),
3840+
"mod-def0", 0, GPIOD_IN |
3841+
GPIOD_FLAGS_BIT_NONEXCLUSIVE, "?");
3842+
3843+
if (IS_ERR(mux->mod_def0_gpio)) {
3844+
dev_err(priv->dev, "failed to requset gpio for mod-def0\n");
3845+
err = PTR_ERR(mux->mod_def0_gpio);
3846+
goto err_free_mux;
3847+
}
3848+
3849+
mux->chan_sel_gpio = fwnode_gpiod_get_index(of_fwnode_handle(np),
3850+
"chan-sel", 0, GPIOD_OUT_LOW, "?");
3851+
3852+
if (IS_ERR(mux->chan_sel_gpio)) {
3853+
dev_err(priv->dev, "failed to requset gpio for chan-sel\n");
3854+
err = PTR_ERR(mux->chan_sel_gpio);
3855+
goto err_put_mod_def0;
3856+
}
3857+
3858+
of_property_read_u32(np, "sfp-present-channel",
3859+
&mux->sfp_present_channel);
3860+
3861+
priv->ds_mux[id] = mux;
3862+
mux->dp = dsa_to_port(priv->ds, id);
3863+
/* configure default channel to 10G PHY */
3864+
mux->channel = !mux->sfp_present_channel;
3865+
mux->initialized = false;
3866+
3867+
for_each_child_of_node(np, child) {
3868+
err = ds_add_mux_channel(mux, child);
3869+
if (err) {
3870+
dev_err(priv->dev, "failed to add ds_mux\n");
3871+
of_node_put(child);
3872+
goto err_put_chan_sel;
3873+
}
3874+
}
3875+
3876+
INIT_DELAYED_WORK(&mux->sfp_monitor_work, sfp_monitor_work_func);
3877+
mod_delayed_work(system_wq, &mux->sfp_monitor_work, msecs_to_jiffies(3000));
3878+
3879+
return 0;
3880+
3881+
err_put_chan_sel:
3882+
gpiod_put(mux->chan_sel_gpio);
3883+
err_put_mod_def0:
3884+
gpiod_put(mux->mod_def0_gpio);
3885+
err_free_mux:
3886+
kfree(mux);
3887+
priv->ds_mux[id] = NULL;
3888+
return err;
3889+
}
3890+
3891+
static void mxl862xx_release_mux(struct mxl862xx_priv *priv, int id)
3892+
{
3893+
struct combo_port_mux *mux = priv->ds_mux[id];
3894+
int i;
3895+
3896+
if (!mux)
3897+
return;
3898+
3899+
cancel_delayed_work_sync(&mux->sfp_monitor_work);
3900+
3901+
if (!IS_ERR_OR_NULL(mux->mod_def0_gpio))
3902+
gpiod_put(mux->mod_def0_gpio);
3903+
3904+
if (!IS_ERR_OR_NULL(mux->chan_sel_gpio))
3905+
gpiod_put(mux->chan_sel_gpio);
3906+
3907+
for (i = 0; i < 2; i++) {
3908+
if (mux->data[i]) {
3909+
if (mux->data[i]->phylink)
3910+
phylink_destroy(mux->data[i]->phylink);
3911+
kfree(mux->data[i]);
3912+
}
3913+
}
3914+
kfree(mux);
3915+
priv->ds_mux[id] = NULL;
3916+
}
3917+
3918+
static void mxl862xx_release_all_muxes(struct mxl862xx_priv *priv)
3919+
{
3920+
int i;
3921+
for (i = 0; i < MAX_PORTS; i++)
3922+
mxl862xx_release_mux(priv, i);
3923+
}
3924+
37153925
static int mxl862xx_probe(struct mdio_device *mdiodev)
37163926
{
37173927
struct mxl862xx_sys_fw_image_version fw_version;
37183928
struct device *dev = &mdiodev->dev;
37193929
struct mxl862xx_priv *priv;
37203930
struct dsa_switch *ds;
3931+
struct device_node *mux_np;
37213932
int ret;
37223933

37233934
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -3782,13 +3993,34 @@ static int mxl862xx_probe(struct mdio_device *mdiodev)
37823993
dev_info(dev, "%s:%u: Enable force isolate", __func__, __LINE__);
37833994
}
37843995

3996+
mux_np = of_get_child_by_name(priv->ds->dev->of_node, "ds-mux-bus");
3997+
if (mux_np) {
3998+
struct device_node *child;
3999+
4000+
for_each_available_child_of_node(mux_np, child) {
4001+
if (!of_device_is_compatible(child,
4002+
"mxl862xx,ds-mux"))
4003+
continue;
4004+
4005+
if (!of_device_is_available(child))
4006+
continue;
4007+
4008+
ret = ds_add_mux(priv, child);
4009+
if (ret)
4010+
dev_err(dev, "failed to add mux\n");
4011+
4012+
of_node_put(mux_np);
4013+
};
4014+
}
4015+
37854016
return 0;
37864017
}
37874018

37884019
static void mxl862xx_remove(struct mdio_device *mdiodev)
37894020
{
37904021
struct dsa_switch *ds = dev_get_drvdata(&mdiodev->dev);
37914022

4023+
mxl862xx_release_all_muxes(ds->priv);
37924024
dsa_unregister_switch(ds);
37934025
}
37944026

drivers/net/dsa/mxl862xx/mxl862xx.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,22 @@ struct mxl862xx_pcs {
8787
int port;
8888
};
8989

90+
struct dp_mux_data {
91+
struct device_node *of_node;
92+
struct phylink *phylink;
93+
};
94+
95+
struct combo_port_mux {
96+
struct dsa_port *dp;
97+
struct gpio_desc *mod_def0_gpio;
98+
struct gpio_desc *chan_sel_gpio;
99+
struct dp_mux_data *data[2];
100+
unsigned int channel;
101+
unsigned int sfp_present_channel;
102+
struct delayed_work sfp_monitor_work;
103+
bool initialized;
104+
};
105+
90106
struct mxl862xx_priv {
91107
struct dsa_switch *ds;
92108
struct mii_bus *bus;
@@ -107,4 +123,5 @@ struct mxl862xx_priv {
107123
bool force_isolate;
108124
bool c22_extended;
109125
struct mxl862xx_pcs pcs_port_1;
126+
struct combo_port_mux *ds_mux[MAX_PORTS];
110127
};

0 commit comments

Comments
 (0)