|
|
|
@ -24,6 +24,7 @@ |
|
|
|
|
#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> |
|
|
|
@ -2333,5 +2334,137 @@ static struct phy_driver ar8xxx_phy_driver[] = { |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
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"); |
|
|
|
|