diff options
Diffstat (limited to 'drivers/net/dsa/realtek/realtek-smi.c')
-rw-r--r-- | drivers/net/dsa/realtek/realtek-smi.c | 166 |
1 files changed, 33 insertions, 133 deletions
diff --git a/drivers/net/dsa/realtek/realtek-smi.c b/drivers/net/dsa/realtek/realtek-smi.c index ad3b57311015..d676cc44d517 100644 --- a/drivers/net/dsa/realtek/realtek-smi.c +++ b/drivers/net/dsa/realtek/realtek-smi.c @@ -41,6 +41,7 @@ #include "realtek.h" #include "realtek-smi.h" +#include "rtl83xx.h" #define REALTEK_SMI_ACK_RETRY_COUNT 5 @@ -311,47 +312,6 @@ static int realtek_smi_read(void *ctx, u32 reg, u32 *val) return realtek_smi_read_reg(priv, reg, val); } -static void realtek_smi_lock(void *ctx) -{ - struct realtek_priv *priv = ctx; - - mutex_lock(&priv->map_lock); -} - -static void realtek_smi_unlock(void *ctx) -{ - struct realtek_priv *priv = ctx; - - mutex_unlock(&priv->map_lock); -} - -static const struct regmap_config realtek_smi_regmap_config = { - .reg_bits = 10, /* A4..A0 R4..R0 */ - .val_bits = 16, - .reg_stride = 1, - /* PHY regs are at 0x8000 */ - .max_register = 0xffff, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .reg_read = realtek_smi_read, - .reg_write = realtek_smi_write, - .cache_type = REGCACHE_NONE, - .lock = realtek_smi_lock, - .unlock = realtek_smi_unlock, -}; - -static const struct regmap_config realtek_smi_nolock_regmap_config = { - .reg_bits = 10, /* A4..A0 R4..R0 */ - .val_bits = 16, - .reg_stride = 1, - /* PHY regs are at 0x8000 */ - .max_register = 0xffff, - .reg_format_endian = REGMAP_ENDIAN_BIG, - .reg_read = realtek_smi_read, - .reg_write = realtek_smi_write, - .cache_type = REGCACHE_NONE, - .disable_locking = true, -}; - static int realtek_smi_mdio_read(struct mii_bus *bus, int addr, int regnum) { struct realtek_priv *priv = bus->priv; @@ -409,111 +369,56 @@ err_put_node: return ret; } +static const struct realtek_interface_info realtek_smi_info = { + .reg_read = realtek_smi_read, + .reg_write = realtek_smi_write, +}; + /** * realtek_smi_probe() - Probe a platform device for an SMI-connected switch * @pdev: platform_device to probe on. * - * This function should be used as the .probe in a platform_driver. It - * initializes realtek_priv and read data from the device-tree node. The switch - * is hard reset if a method is provided. It checks the switch chip ID and, - * finally, a DSA switch is registered. + * This function should be used as the .probe in a platform_driver. After + * calling the common probe function for both interfaces, it initializes the + * values specific for SMI-connected devices. Finally, it calls a common + * function to register the DSA switch. * * Context: Can sleep. Takes and releases priv->map_lock. * Return: Returns 0 on success, a negative error on failure. */ int realtek_smi_probe(struct platform_device *pdev) { - const struct realtek_variant *var; struct device *dev = &pdev->dev; struct realtek_priv *priv; - struct regmap_config rc; - struct device_node *np; int ret; - var = of_device_get_match_data(dev); - np = dev->of_node; - - priv = devm_kzalloc(dev, sizeof(*priv) + var->chip_data_sz, GFP_KERNEL); - if (!priv) - return -ENOMEM; - priv->chip_data = (void *)priv + sizeof(*priv); - - mutex_init(&priv->map_lock); - - rc = realtek_smi_regmap_config; - rc.lock_arg = priv; - priv->map = devm_regmap_init(dev, NULL, priv, &rc); - if (IS_ERR(priv->map)) { - ret = PTR_ERR(priv->map); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - rc = realtek_smi_nolock_regmap_config; - priv->map_nolock = devm_regmap_init(dev, NULL, priv, &rc); - if (IS_ERR(priv->map_nolock)) { - ret = PTR_ERR(priv->map_nolock); - dev_err(dev, "regmap init failed: %d\n", ret); - return ret; - } - - /* Link forward and backward */ - priv->dev = dev; - priv->variant = var; - priv->ops = var->ops; - - priv->setup_interface = realtek_smi_setup_mdio; - priv->write_reg_noack = realtek_smi_write_reg_noack; - - dev_set_drvdata(dev, priv); - spin_lock_init(&priv->lock); - - /* TODO: if power is software controlled, set up any regulators here */ - - priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(priv->reset)) { - dev_err(dev, "failed to get RESET GPIO\n"); - return PTR_ERR(priv->reset); - } - if (priv->reset) { - gpiod_set_value(priv->reset, 1); - dev_dbg(dev, "asserted RESET\n"); - msleep(REALTEK_HW_STOP_DELAY); - gpiod_set_value(priv->reset, 0); - msleep(REALTEK_HW_START_DELAY); - dev_dbg(dev, "deasserted RESET\n"); - } + priv = rtl83xx_probe(dev, &realtek_smi_info); + if (IS_ERR(priv)) + return PTR_ERR(priv); /* Fetch MDIO pins */ priv->mdc = devm_gpiod_get_optional(dev, "mdc", GPIOD_OUT_LOW); - if (IS_ERR(priv->mdc)) + if (IS_ERR(priv->mdc)) { + rtl83xx_remove(priv); return PTR_ERR(priv->mdc); + } + priv->mdio = devm_gpiod_get_optional(dev, "mdio", GPIOD_OUT_LOW); - if (IS_ERR(priv->mdio)) + if (IS_ERR(priv->mdio)) { + rtl83xx_remove(priv); return PTR_ERR(priv->mdio); - - priv->leds_disabled = of_property_read_bool(np, "realtek,disable-leds"); - - ret = priv->ops->detect(priv); - if (ret) { - dev_err(dev, "unable to detect switch\n"); - return ret; } - priv->ds = devm_kzalloc(dev, sizeof(*priv->ds), GFP_KERNEL); - if (!priv->ds) - return -ENOMEM; - - priv->ds->dev = dev; - priv->ds->num_ports = priv->num_ports; - priv->ds->priv = priv; + priv->write_reg_noack = realtek_smi_write_reg_noack; + priv->setup_interface = realtek_smi_setup_mdio; + priv->ds_ops = priv->variant->ds_ops_smi; - priv->ds->ops = var->ds_ops_smi; - ret = dsa_register_switch(priv->ds); + ret = rtl83xx_register_switch(priv); if (ret) { - dev_err_probe(dev, ret, "unable to register switch\n"); + rtl83xx_remove(priv); return ret; } + return 0; } EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); @@ -523,8 +428,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_probe, REALTEK_DSA); * @pdev: platform_device to be removed. * * This function should be used as the .remove_new in a platform_driver. First - * it unregisters the DSA switch and cleans internal data. If a method is - * provided, the hard reset is asserted to avoid traffic leakage. + * it unregisters the DSA switch and cleans internal data. Finally, it calls + * the common remove function. * * Context: Can sleep. * Return: Nothing. @@ -536,13 +441,12 @@ void realtek_smi_remove(struct platform_device *pdev) if (!priv) return; - dsa_unregister_switch(priv->ds); + rtl83xx_unregister_switch(priv); + if (priv->user_mii_bus) of_node_put(priv->user_mii_bus->dev.of_node); - /* leave the device reset asserted */ - if (priv->reset) - gpiod_set_value(priv->reset, 1); + rtl83xx_remove(priv); } EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); @@ -550,10 +454,8 @@ EXPORT_SYMBOL_NS_GPL(realtek_smi_remove, REALTEK_DSA); * realtek_smi_shutdown() - Shutdown the driver of a SMI-connected switch * @pdev: platform_device shutting down. * - * This function should be used as the .shutdown in a platform_driver. It shuts - * down the DSA switch and cleans the platform driver data, to prevent - * realtek_smi_remove() from running afterwards, which is possible if the - * parent bus implements its own .shutdown() as .remove(). + * This function should be used as the .shutdown in a platform_driver. It calls + * the common shutdown function. * * Context: Can sleep. * Return: Nothing. @@ -565,9 +467,7 @@ void realtek_smi_shutdown(struct platform_device *pdev) if (!priv) return; - dsa_switch_shutdown(priv->ds); - - platform_set_drvdata(pdev, NULL); + rtl83xx_shutdown(priv); } EXPORT_SYMBOL_NS_GPL(realtek_smi_shutdown, REALTEK_DSA); |