0001
0002
0003
0004
0005
0006
0007 #include <linux/mdio-mux.h>
0008 #include <linux/module.h>
0009 #include <linux/mux/consumer.h>
0010 #include <linux/platform_device.h>
0011
0012 struct mdio_mux_multiplexer_state {
0013 struct mux_control *muxc;
0014 bool do_deselect;
0015 void *mux_handle;
0016 };
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 static int mdio_mux_multiplexer_switch_fn(int current_child, int desired_child,
0032 void *data)
0033 {
0034 struct platform_device *pdev;
0035 struct mdio_mux_multiplexer_state *s;
0036 int ret = 0;
0037
0038 pdev = (struct platform_device *)data;
0039 s = platform_get_drvdata(pdev);
0040
0041 if (!(current_child ^ desired_child))
0042 return 0;
0043
0044 if (s->do_deselect)
0045 ret = mux_control_deselect(s->muxc);
0046 if (ret) {
0047 dev_err(&pdev->dev, "mux_control_deselect failed in %s: %d\n",
0048 __func__, ret);
0049 return ret;
0050 }
0051
0052 ret = mux_control_select(s->muxc, desired_child);
0053 if (!ret) {
0054 dev_dbg(&pdev->dev, "%s %d -> %d\n", __func__, current_child,
0055 desired_child);
0056 s->do_deselect = true;
0057 } else {
0058 s->do_deselect = false;
0059 }
0060
0061 return ret;
0062 }
0063
0064 static int mdio_mux_multiplexer_probe(struct platform_device *pdev)
0065 {
0066 struct device *dev = &pdev->dev;
0067 struct mdio_mux_multiplexer_state *s;
0068 int ret = 0;
0069
0070 s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
0071 if (!s)
0072 return -ENOMEM;
0073
0074 s->muxc = devm_mux_control_get(dev, NULL);
0075 if (IS_ERR(s->muxc)) {
0076 ret = PTR_ERR(s->muxc);
0077 if (ret != -EPROBE_DEFER)
0078 dev_err(&pdev->dev, "Failed to get mux: %d\n", ret);
0079 return ret;
0080 }
0081
0082 platform_set_drvdata(pdev, s);
0083
0084 ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node,
0085 mdio_mux_multiplexer_switch_fn, &s->mux_handle,
0086 pdev, NULL);
0087
0088 return ret;
0089 }
0090
0091 static int mdio_mux_multiplexer_remove(struct platform_device *pdev)
0092 {
0093 struct mdio_mux_multiplexer_state *s = platform_get_drvdata(pdev);
0094
0095 mdio_mux_uninit(s->mux_handle);
0096
0097 if (s->do_deselect)
0098 mux_control_deselect(s->muxc);
0099
0100 return 0;
0101 }
0102
0103 static const struct of_device_id mdio_mux_multiplexer_match[] = {
0104 { .compatible = "mdio-mux-multiplexer", },
0105 {},
0106 };
0107 MODULE_DEVICE_TABLE(of, mdio_mux_multiplexer_match);
0108
0109 static struct platform_driver mdio_mux_multiplexer_driver = {
0110 .driver = {
0111 .name = "mdio-mux-multiplexer",
0112 .of_match_table = mdio_mux_multiplexer_match,
0113 },
0114 .probe = mdio_mux_multiplexer_probe,
0115 .remove = mdio_mux_multiplexer_remove,
0116 };
0117
0118 module_platform_driver(mdio_mux_multiplexer_driver);
0119
0120 MODULE_DESCRIPTION("MDIO bus multiplexer using kernel multiplexer subsystem");
0121 MODULE_AUTHOR("Pankaj Bansal <pankaj.bansal@nxp.com>");
0122 MODULE_LICENSE("GPL");