0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/device.h>
0011 #include <linux/mdio-mux.h>
0012 #include <linux/module.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_mdio.h>
0015 #include <linux/phy.h>
0016 #include <linux/platform_device.h>
0017
0018 struct mdio_mux_mmioreg_state {
0019 void *mux_handle;
0020 phys_addr_t phys;
0021 unsigned int iosize;
0022 unsigned int mask;
0023 };
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 static int mdio_mux_mmioreg_switch_fn(int current_child, int desired_child,
0043 void *data)
0044 {
0045 struct mdio_mux_mmioreg_state *s = data;
0046
0047 if (current_child ^ desired_child) {
0048 void __iomem *p = ioremap(s->phys, s->iosize);
0049 if (!p)
0050 return -ENOMEM;
0051
0052 switch (s->iosize) {
0053 case sizeof(uint8_t): {
0054 uint8_t x, y;
0055
0056 x = ioread8(p);
0057 y = (x & ~s->mask) | desired_child;
0058 if (x != y) {
0059 iowrite8((x & ~s->mask) | desired_child, p);
0060 pr_debug("%s: %02x -> %02x\n", __func__, x, y);
0061 }
0062
0063 break;
0064 }
0065 case sizeof(uint16_t): {
0066 uint16_t x, y;
0067
0068 x = ioread16(p);
0069 y = (x & ~s->mask) | desired_child;
0070 if (x != y) {
0071 iowrite16((x & ~s->mask) | desired_child, p);
0072 pr_debug("%s: %04x -> %04x\n", __func__, x, y);
0073 }
0074
0075 break;
0076 }
0077 case sizeof(uint32_t): {
0078 uint32_t x, y;
0079
0080 x = ioread32(p);
0081 y = (x & ~s->mask) | desired_child;
0082 if (x != y) {
0083 iowrite32((x & ~s->mask) | desired_child, p);
0084 pr_debug("%s: %08x -> %08x\n", __func__, x, y);
0085 }
0086
0087 break;
0088 }
0089 }
0090
0091 iounmap(p);
0092 }
0093
0094 return 0;
0095 }
0096
0097 static int mdio_mux_mmioreg_probe(struct platform_device *pdev)
0098 {
0099 struct device_node *np2, *np = pdev->dev.of_node;
0100 struct mdio_mux_mmioreg_state *s;
0101 struct resource res;
0102 const __be32 *iprop;
0103 int len, ret;
0104
0105 dev_dbg(&pdev->dev, "probing node %pOF\n", np);
0106
0107 s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
0108 if (!s)
0109 return -ENOMEM;
0110
0111 ret = of_address_to_resource(np, 0, &res);
0112 if (ret) {
0113 dev_err(&pdev->dev, "could not obtain memory map for node %pOF\n",
0114 np);
0115 return ret;
0116 }
0117 s->phys = res.start;
0118
0119 s->iosize = resource_size(&res);
0120 if (s->iosize != sizeof(uint8_t) &&
0121 s->iosize != sizeof(uint16_t) &&
0122 s->iosize != sizeof(uint32_t)) {
0123 dev_err(&pdev->dev, "only 8/16/32-bit registers are supported\n");
0124 return -EINVAL;
0125 }
0126
0127 iprop = of_get_property(np, "mux-mask", &len);
0128 if (!iprop || len != sizeof(uint32_t)) {
0129 dev_err(&pdev->dev, "missing or invalid mux-mask property\n");
0130 return -ENODEV;
0131 }
0132 if (be32_to_cpup(iprop) >= BIT(s->iosize * 8)) {
0133 dev_err(&pdev->dev, "only 8/16/32-bit registers are supported\n");
0134 return -EINVAL;
0135 }
0136 s->mask = be32_to_cpup(iprop);
0137
0138
0139
0140
0141
0142 for_each_available_child_of_node(np, np2) {
0143 iprop = of_get_property(np2, "reg", &len);
0144 if (!iprop || len != sizeof(uint32_t)) {
0145 dev_err(&pdev->dev, "mdio-mux child node %pOF is "
0146 "missing a 'reg' property\n", np2);
0147 of_node_put(np2);
0148 return -ENODEV;
0149 }
0150 if (be32_to_cpup(iprop) & ~s->mask) {
0151 dev_err(&pdev->dev, "mdio-mux child node %pOF has "
0152 "a 'reg' value with unmasked bits\n",
0153 np2);
0154 of_node_put(np2);
0155 return -ENODEV;
0156 }
0157 }
0158
0159 ret = mdio_mux_init(&pdev->dev, pdev->dev.of_node,
0160 mdio_mux_mmioreg_switch_fn,
0161 &s->mux_handle, s, NULL);
0162 if (ret) {
0163 if (ret != -EPROBE_DEFER)
0164 dev_err(&pdev->dev,
0165 "failed to register mdio-mux bus %pOF\n", np);
0166 return ret;
0167 }
0168
0169 pdev->dev.platform_data = s;
0170
0171 return 0;
0172 }
0173
0174 static int mdio_mux_mmioreg_remove(struct platform_device *pdev)
0175 {
0176 struct mdio_mux_mmioreg_state *s = dev_get_platdata(&pdev->dev);
0177
0178 mdio_mux_uninit(s->mux_handle);
0179
0180 return 0;
0181 }
0182
0183 static const struct of_device_id mdio_mux_mmioreg_match[] = {
0184 {
0185 .compatible = "mdio-mux-mmioreg",
0186 },
0187 {},
0188 };
0189 MODULE_DEVICE_TABLE(of, mdio_mux_mmioreg_match);
0190
0191 static struct platform_driver mdio_mux_mmioreg_driver = {
0192 .driver = {
0193 .name = "mdio-mux-mmioreg",
0194 .of_match_table = mdio_mux_mmioreg_match,
0195 },
0196 .probe = mdio_mux_mmioreg_probe,
0197 .remove = mdio_mux_mmioreg_remove,
0198 };
0199
0200 module_platform_driver(mdio_mux_mmioreg_driver);
0201
0202 MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
0203 MODULE_DESCRIPTION("Memory-mapped device MDIO MUX driver");
0204 MODULE_LICENSE("GPL v2");