#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/of_device.h>
+#include <linux/of_mdio.h>
#include <linux/bitops.h>
#include <net/genetlink.h>
#include <linux/switch.h>
}
};
-module_phy_driver(ar8xxx_phy_driver);
+static const struct of_device_id ar8xxx_mdiodev_of_match[] = {
+ {
+ .compatible = "qca,ar8236",
+ .data = &ar8236_chip,
+ }, {
+ .compatible = "qca,ar8327",
+ .data = &ar8327_chip,
+ },
+ { /* sentinel */ },
+};
+
+static int
+ar8xxx_mdiodev_probe(struct mdio_device *mdiodev)
+{
+ const struct of_device_id *match;
+ struct ar8xxx_priv *priv;
+ struct switch_dev *swdev;
+ int ret;
+
+ match = of_match_device(ar8xxx_mdiodev_of_match, &mdiodev->dev);
+ if (!match)
+ return -EINVAL;
+
+ priv = ar8xxx_create();
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->mii_bus = mdiodev->bus;
+ priv->pdev = &mdiodev->dev;
+ priv->chip = (const struct ar8xxx_chip *) match->data;
+
+ ret = ar8xxx_read_id(priv);
+ if (ret)
+ goto free_priv;
+
+ ret = ar8xxx_probe_switch(priv);
+ if (ret)
+ goto free_priv;
+
+ swdev = &priv->dev;
+ swdev->alias = dev_name(&mdiodev->dev);
+ ret = register_switch(swdev, NULL);
+ if (ret)
+ goto free_priv;
+
+ pr_info("%s: %s rev. %u switch registered on %s\n",
+ swdev->devname, swdev->name, priv->chip_rev,
+ dev_name(&priv->mii_bus->dev));
+
+ mutex_lock(&ar8xxx_dev_list_lock);
+ list_add(&priv->list, &ar8xxx_dev_list);
+ mutex_unlock(&ar8xxx_dev_list_lock);
+
+ priv->use_count++;
+
+ ret = ar8xxx_start(priv);
+ if (ret)
+ goto err_unregister_switch;
+
+ dev_set_drvdata(&mdiodev->dev, priv);
+
+ return 0;
+
+err_unregister_switch:
+ if (--priv->use_count)
+ return ret;
+
+ unregister_switch(&priv->dev);
+
+free_priv:
+ ar8xxx_free(priv);
+ return ret;
+}
+
+static void
+ar8xxx_mdiodev_remove(struct mdio_device *mdiodev)
+{
+ struct ar8xxx_priv *priv = dev_get_drvdata(&mdiodev->dev);
+
+ if (WARN_ON(!priv))
+ return;
+
+ mutex_lock(&ar8xxx_dev_list_lock);
+
+ if (--priv->use_count > 0) {
+ mutex_unlock(&ar8xxx_dev_list_lock);
+ return;
+ }
+
+ list_del(&priv->list);
+ mutex_unlock(&ar8xxx_dev_list_lock);
+
+ unregister_switch(&priv->dev);
+ ar8xxx_mib_stop(priv);
+ ar8xxx_free(priv);
+}
+
+static struct mdio_driver ar8xxx_mdio_driver = {
+ .probe = ar8xxx_mdiodev_probe,
+ .remove = ar8xxx_mdiodev_remove,
+ .mdiodrv.driver = {
+ .name = "ar8xxx-switch",
+ .of_match_table = ar8xxx_mdiodev_of_match,
+ },
+};
+
+static int __init ar8216_init(void)
+{
+ int ret;
+
+ ret = phy_drivers_register(ar8xxx_phy_driver,
+ ARRAY_SIZE(ar8xxx_phy_driver),
+ THIS_MODULE);
+ if (ret)
+ return ret;
+
+ ret = mdio_driver_register(&ar8xxx_mdio_driver);
+ if (ret)
+ phy_drivers_unregister(ar8xxx_phy_driver,
+ ARRAY_SIZE(ar8xxx_phy_driver));
+
+ return ret;
+}
+module_init(ar8216_init);
+
+static void __exit ar8216_exit(void)
+{
+ mdio_driver_unregister(&ar8xxx_mdio_driver);
+ phy_drivers_unregister(ar8xxx_phy_driver,
+ ARRAY_SIZE(ar8xxx_phy_driver));
+}
+module_exit(ar8216_exit);
+
MODULE_LICENSE("GPL");