> + > + ds->configure_vlan_while_not_filtering = true; Unnecessary, this is the default value, please remove. > + > + /* Flush the FDB table */ > + ret = an8855_fdb_cmd(priv, AN8855_FDB_FLUSH, NULL); > + if (ret < 0) > + return ret; > + > + /* Set min a max ageing value supported */ > + ds->ageing_time_min = AN8855_L2_AGING_MS_CONSTANT; > + ds->ageing_time_max = FIELD_MAX(AN8855_AGE_CNT) * > + FIELD_MAX(AN8855_AGE_UNIT) * > + AN8855_L2_AGING_MS_CONSTANT; > + > + /* Enable assisted learning for fdb isolation */ > + ds->assisted_learning_on_cpu_port = true; What FDB isolation? :) > + > + return 0; > +} > + > +static int an8855_switch_probe(struct platform_device *pdev) > +{ > + struct an8855_priv *priv; > + u32 val; > + int ret; > + > + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); > + if (!priv) > + return -ENOMEM; > + > + priv->dev = &pdev->dev; > + priv->phy_require_calib = of_property_read_bool(priv->dev->of_node, > + "airoha,ext-surge"); Can this be moved to the DT bindings of individual PHYs instead? The switch is just a useless messenger here. > + > + priv->reset_gpio = devm_gpiod_get_optional(priv->dev, "reset", > + GPIOD_OUT_LOW); > + if (IS_ERR(priv->reset_gpio)) > + return PTR_ERR(priv->reset_gpio); > + > + /* Get regmap from MFD */ > + priv->regmap = dev_get_regmap(priv->dev->parent, NULL); > + > + if (priv->reset_gpio) { > + usleep_range(100000, 150000); > + gpiod_set_value_cansleep(priv->reset_gpio, 0); > + usleep_range(100000, 150000); > + gpiod_set_value_cansleep(priv->reset_gpio, 1); > + > + /* Poll HWTRAP reg to wait for Switch to fully Init */ > + ret = regmap_read_poll_timeout(priv->regmap, AN8855_HWTRAP, val, > + val, 20, 200000); > + if (ret) > + return ret; > + } As mentioned in the dt-bindings comment: this sounds like the type of thing which should only run from the context of the top-level MFD driver, in a very controlled manner (child drivers have not started). > + > + ret = an8855_read_switch_id(priv); > + if (ret) > + return ret; > + > + priv->ds = devm_kzalloc(priv->dev, sizeof(*priv->ds), GFP_KERNEL); > + if (!priv->ds) > + return -ENOMEM; > + > + priv->ds->dev = priv->dev; > + priv->ds->num_ports = AN8855_NUM_PORTS; > + priv->ds->priv = priv; > + priv->ds->ops = &an8855_switch_ops; > + devm_mutex_init(priv->dev, &priv->reg_mutex); > + priv->ds->phylink_mac_ops = &an8855_phylink_mac_ops; > + > + priv->pcs.ops = &an8855_pcs_ops; > + priv->pcs.neg_mode = true; > + priv->pcs.poll = true; > + > + dev_set_drvdata(priv->dev, priv); > + > + return dsa_register_switch(priv->ds); > +} > + > +static void an8855_switch_remove(struct platform_device *pdev) > +{ > + struct an8855_priv *priv = dev_get_drvdata(&pdev->dev); > + > + if (!priv) > + return; > + > + dsa_unregister_switch(priv->ds); > +} > + > +static const struct of_device_id an8855_switch_of_match[] = { > + { .compatible = "airoha,an8855-switch" }, > + { /* sentinel */ } > +}; > +MODULE_DEVICE_TABLE(of, an8855_switch_of_match); > + > +static struct platform_driver an8855_switch_driver = { > + .probe = an8855_switch_probe, > + .remove = an8855_switch_remove, dsa_switch_shutdown() is non-optional - see commit 0650bf52b31f ("net: dsa: be compatible with masters which unregister on shutdown") for more details. As a discrete DSA switch, don't get to choose which conduit interface this is paired with. > + .driver = { > + .name = "an8855-switch", > + .of_match_table = an8855_switch_of_match, > + }, > +}; > +module_platform_driver(an8855_switch_driver); > +struct an8855_priv { > + struct device *dev; Nitpick: can retrieve the device as priv->ds->dev already. > + struct dsa_switch *ds; > + struct regmap *regmap; > + struct gpio_desc *reset_gpio; > + /* Protect ATU or VLAN table access */ > + struct mutex reg_mutex; > + > + struct phylink_pcs pcs; > + > + u8 mirror_rx; > + u8 mirror_tx; > + u8 port_isolated_map; > + > + bool phy_require_calib; > +}; > + > +#endif /* __AN8855_H */ > -- > 2.45.2 > This doesn't look bad IMO (sure, still needs work), we should focus on the selftests and make sure they pass.