--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <net/dsa.h>
+
+#include "mt7530.h"
+
+static const struct of_device_id mt7988_of_match[] = {
+       { .compatible = "mediatek,mt7988-switch", .data = &mt753x_table[ID_MT7988], },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mt7988_of_match);
+
+static int
+mt7988_probe(struct platform_device *pdev)
+{
+       static struct regmap_config *sw_regmap_config;
+       struct mt7530_priv *priv;
+       void __iomem *base_addr;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->bus = NULL;
+       priv->dev = &pdev->dev;
+
+       ret = mt7530_probe_common(priv);
+       if (ret)
+               return ret;
+
+       priv->rstc = devm_reset_control_get(&pdev->dev, NULL);
+       if (IS_ERR(priv->rstc)) {
+               dev_err(&pdev->dev, "Couldn't get our reset line\n");
+               return PTR_ERR(priv->rstc);
+       }
+
+       base_addr = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(base_addr)) {
+               dev_err(&pdev->dev, "cannot request I/O memory space\n");
+               return -ENXIO;
+       }
+
+       sw_regmap_config = devm_kzalloc(&pdev->dev, sizeof(*sw_regmap_config), GFP_KERNEL);
+       if (!sw_regmap_config)
+               return -ENOMEM;
+
+       sw_regmap_config->name = "switch";
+       sw_regmap_config->reg_bits = 16;
+       sw_regmap_config->val_bits = 32;
+       sw_regmap_config->reg_stride = 4;
+       sw_regmap_config->max_register = MT7530_CREV;
+       priv->regmap = devm_regmap_init_mmio(&pdev->dev, base_addr, sw_regmap_config);
+       if (IS_ERR(priv->regmap))
+               return PTR_ERR(priv->regmap);
+
+       return dsa_register_switch(priv->ds);
+}
+
+static int
+mt7988_remove(struct platform_device *pdev)
+{
+       struct mt7530_priv *priv = platform_get_drvdata(pdev);
+
+       if (priv)
+               mt7530_remove_common(priv);
+
+       return 0;
+}
+
+static void mt7988_shutdown(struct platform_device *pdev)
+{
+       struct mt7530_priv *priv = platform_get_drvdata(pdev);
+
+       if (!priv)
+               return;
+
+       dsa_switch_shutdown(priv->ds);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+}
+
+static struct platform_driver mt7988_platform_driver = {
+       .probe  = mt7988_probe,
+       .remove = mt7988_remove,
+       .shutdown = mt7988_shutdown,
+       .driver = {
+               .name = "mt7530-mmio",
+               .of_match_table = mt7988_of_match,
+       },
+};
+module_platform_driver(mt7988_platform_driver);
+
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
+MODULE_DESCRIPTION("Driver for Mediatek MT7530 Switch (MMIO)");
+MODULE_LICENSE("GPL");
 
        .xlate = irq_domain_xlate_onecell,
 };
 
+static void
+mt7988_irq_mask(struct irq_data *d)
+{
+       struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+       priv->irq_enable &= ~BIT(d->hwirq);
+       mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
+}
+
+static void
+mt7988_irq_unmask(struct irq_data *d)
+{
+       struct mt7530_priv *priv = irq_data_get_irq_chip_data(d);
+
+       priv->irq_enable |= BIT(d->hwirq);
+       mt7530_mii_write(priv, MT7530_SYS_INT_EN, priv->irq_enable);
+}
+
+static struct irq_chip mt7988_irq_chip = {
+       .name = KBUILD_MODNAME,
+       .irq_mask = mt7988_irq_mask,
+       .irq_unmask = mt7988_irq_unmask,
+};
+
+static int
+mt7988_irq_map(struct irq_domain *domain, unsigned int irq,
+              irq_hw_number_t hwirq)
+{
+       irq_set_chip_data(irq, domain->host_data);
+       irq_set_chip_and_handler(irq, &mt7988_irq_chip, handle_simple_irq);
+       irq_set_nested_thread(irq, true);
+       irq_set_noprobe(irq);
+
+       return 0;
+}
+
+static const struct irq_domain_ops mt7988_irq_domain_ops = {
+       .map = mt7988_irq_map,
+       .xlate = irq_domain_xlate_onecell,
+};
+
 static void
 mt7530_setup_mdio_irq(struct mt7530_priv *priv)
 {
                return priv->irq ? : -EINVAL;
        }
 
-       priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
-                                                &mt7530_irq_domain_ops, priv);
+       if (priv->id == ID_MT7988)
+               priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
+                                                        &mt7988_irq_domain_ops,
+                                                        priv);
+       else
+               priv->irq_domain = irq_domain_add_linear(np, MT7530_NUM_PHYS,
+                                                        &mt7530_irq_domain_ops,
+                                                        priv);
+
        if (!priv->irq_domain) {
                dev_err(dev, "failed to create IRQ domain\n");
                return -ENOMEM;
        }
 }
 
+static void mt7988_mac_port_get_caps(struct dsa_switch *ds, int port,
+                                    struct phylink_config *config)
+{
+       phy_interface_zero(config->supported_interfaces);
+
+       switch (port) {
+       case 0 ... 4: /* Internal phy */
+               __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+                         config->supported_interfaces);
+               break;
+
+       case 6:
+               __set_bit(PHY_INTERFACE_MODE_INTERNAL,
+                         config->supported_interfaces);
+               config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
+                                          MAC_10000FD;
+       }
+}
+
 static int
 mt753x_pad_setup(struct dsa_switch *ds, const struct phylink_link_state *state)
 {
        return (port == 5 || port == 6);
 }
 
+static int
+mt7988_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
+                 phy_interface_t interface)
+{
+       if (dsa_is_cpu_port(ds, port) &&
+           interface == PHY_INTERFACE_MODE_INTERNAL)
+               return 0;
+
+       return -EINVAL;
+}
+
 static int
 mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
                  phy_interface_t interface)
 
        switch (port) {
        case 0 ... 4: /* Internal phy */
-               if (state->interface != PHY_INTERFACE_MODE_GMII)
+               if (state->interface != PHY_INTERFACE_MODE_GMII &&
+                   state->interface != PHY_INTERFACE_MODE_INTERNAL)
                        goto unsupported;
                break;
        case 5: /* 2nd cpu port with phy of port 0 or 4 / external phy */
        /* MT753x MAC works in 1G full duplex mode for all up-clocked
         * variants.
         */
-       if (interface == PHY_INTERFACE_MODE_TRGMII ||
+       if (interface == PHY_INTERFACE_MODE_INTERNAL ||
+           interface == PHY_INTERFACE_MODE_TRGMII ||
            (phy_interface_mode_is_8023z(interface))) {
                speed = SPEED_1000;
                duplex = DUPLEX_FULL;
        return 0;
 }
 
+static int
+mt7988_cpu_port_config(struct dsa_switch *ds, int port)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       mt7530_write(priv, MT7530_PMCR_P(port),
+                    PMCR_CPU_PORT_SETTING(priv->id));
+
+       mt753x_phylink_mac_link_up(ds, port, MLO_AN_FIXED,
+                                  PHY_INTERFACE_MODE_INTERNAL, NULL,
+                                  SPEED_10000, DUPLEX_FULL, true, true);
+
+       return 0;
+}
+
 static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
                                    struct phylink_config *config)
 {
        return 0;
 }
 
+static int mt7988_pad_setup(struct dsa_switch *ds, phy_interface_t interface)
+{
+       return 0;
+}
+
+static int mt7988_setup(struct dsa_switch *ds)
+{
+       struct mt7530_priv *priv = ds->priv;
+
+       /* Reset the switch */
+       reset_control_assert(priv->rstc);
+       usleep_range(20, 50);
+       reset_control_deassert(priv->rstc);
+       usleep_range(20, 50);
+
+       /* Reset the switch PHYs */
+       mt7530_write(priv, MT7530_SYS_CTRL, SYS_CTRL_PHY_RST);
+
+       return mt7531_setup_common(ds);
+}
+
 const struct dsa_switch_ops mt7530_switch_ops = {
        .get_tag_protocol       = mtk_get_tag_protocol,
        .setup                  = mt753x_setup,
                .mac_port_get_caps = mt7531_mac_port_get_caps,
                .mac_port_config = mt7531_mac_config,
        },
+       [ID_MT7988] = {
+               .id = ID_MT7988,
+               .pcs_ops = &mt7530_pcs_ops,
+               .sw_setup = mt7988_setup,
+               .phy_read_c22 = mt7531_ind_c22_phy_read,
+               .phy_write_c22 = mt7531_ind_c22_phy_write,
+               .phy_read_c45 = mt7531_ind_c45_phy_read,
+               .phy_write_c45 = mt7531_ind_c45_phy_write,
+               .pad_setup = mt7988_pad_setup,
+               .cpu_port_config = mt7988_cpu_port_config,
+               .mac_port_get_caps = mt7988_mac_port_get_caps,
+               .mac_port_config = mt7988_mac_config,
+       },
 };
 EXPORT_SYMBOL_GPL(mt753x_table);