Add support for Generic Mux controls, when Mdio mux node is a consumer of mux produced by some other device.
Signed-off-by: Pankaj Bansal <pankaj.ban...@nxp.com> --- drivers/net/phy/Kconfig | 1 + drivers/net/phy/mdio-mux.c | 81 ++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 3d187cd50eb0..e0e6b2b33d6d 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -47,6 +47,7 @@ config MDIO_BITBANG config MDIO_BUS_MUX tristate depends on OF_MDIO + select MULTIPLEXER help This module provides a driver framework for MDIO bus multiplexers which connect one of several child MDIO busses diff --git a/drivers/net/phy/mdio-mux.c b/drivers/net/phy/mdio-mux.c index 0a86f1e4c02f..c49e4ae9c174 100644 --- a/drivers/net/phy/mdio-mux.c +++ b/drivers/net/phy/mdio-mux.c @@ -11,6 +11,7 @@ #include <linux/of_mdio.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/mux/consumer.h> #include <linux/phy.h> #define DRV_DESCRIPTION "MDIO bus multiplexer driver" @@ -35,6 +36,11 @@ struct mdio_mux_child_bus { int bus_number; }; +struct mdio_mux_state { + struct mux_control *muxc; + void *mux_handle; +}; + /* * The parent bus' lock is used to order access to the switch_fn. */ @@ -208,6 +214,81 @@ void mdio_mux_uninit(void *mux_handle) } EXPORT_SYMBOL_GPL(mdio_mux_uninit); +static int mdio_mux_switch_fn(int current_child, int desired_child, void *data) +{ + struct platform_device *pdev; + struct mdio_mux_state *s; + int ret = 0; + + pdev = (struct platform_device *)data; + s = (struct mdio_mux_state *)platform_get_drvdata(pdev); + if (current_child ^ desired_child) { + if (current_child != -1) + ret = mux_control_deselect(s->muxc); + if (ret) + return ret; + + ret = mux_control_select(s->muxc, desired_child); + if (!ret) + dev_dbg(&pdev->dev, "%s %d -> %d\n", __func__, + current_child, desired_child); + } + + return ret; +} + +static int mdio_mux_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mdio_mux_state *s; + int ret = 0; + + s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + + s->muxc = devm_mux_control_get(dev, NULL); + if (IS_ERR(s->muxc)) { + ret = PTR_ERR(s->muxc); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "Failed to get mux: %d\n", ret); + return ret; + } + + platform_set_drvdata(pdev, s); + + ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node, mdio_mux_switch_fn, + &s->mux_handle, pdev, NULL); + + return ret; +} + +static int mdio_mux_remove(struct platform_device *pdev) +{ + struct mdio_mux_state *s = platform_get_drvdata(pdev); + + mdio_mux_uninit(s->mux_handle); + + return 0; +} + +static const struct of_device_id mdio_mux_match[] = { + { .compatible = "mdio-mux", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mdio_mux_match); + +static struct platform_driver mdio_mux_driver = { + .driver = { + .name = "mdio-mux", + .of_match_table = mdio_mux_match, + }, + .probe = mdio_mux_probe, + .remove = mdio_mux_remove, +}; + +module_platform_driver(mdio_mux_driver); + MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_AUTHOR("David Daney"); MODULE_LICENSE("GPL"); -- 2.17.1