1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2017 Pengutronix, Juergen Borleis <kernel@pengutronix.de> 4 * 5 * Partially based on a patch from 6 * Copyright (c) 2014 Stefan Roese <sr@denx.de> 7 */ 8 #include <linux/kernel.h> 9 #include <linux/module.h> 10 #include <linux/mdio.h> 11 #include <linux/phy.h> 12 #include <linux/of.h> 13 14 #include "lan9303.h" 15 16 /* Generate phy-addr and -reg from the input address */ 17 #define PHY_ADDR(x) ((((x) >> 6) + 0x10) & 0x1f) 18 #define PHY_REG(x) (((x) >> 1) & 0x1f) 19 20 struct lan9303_mdio { 21 struct mdio_device *device; 22 struct lan9303 chip; 23 }; 24 25 static void lan9303_mdio_real_write(struct mdio_device *mdio, int reg, u16 val) 26 { 27 mdio->bus->write(mdio->bus, PHY_ADDR(reg), PHY_REG(reg), val); 28 } 29 30 static int lan9303_mdio_write(void *ctx, uint32_t reg, uint32_t val) 31 { 32 struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx; 33 34 reg <<= 2; /* reg num to offset */ 35 mutex_lock(&sw_dev->device->bus->mdio_lock); 36 lan9303_mdio_real_write(sw_dev->device, reg, val & 0xffff); 37 lan9303_mdio_real_write(sw_dev->device, reg + 2, (val >> 16) & 0xffff); 38 mutex_unlock(&sw_dev->device->bus->mdio_lock); 39 40 return 0; 41 } 42 43 static u16 lan9303_mdio_real_read(struct mdio_device *mdio, int reg) 44 { 45 return mdio->bus->read(mdio->bus, PHY_ADDR(reg), PHY_REG(reg)); 46 } 47 48 static int lan9303_mdio_read(void *ctx, uint32_t reg, uint32_t *val) 49 { 50 struct lan9303_mdio *sw_dev = (struct lan9303_mdio *)ctx; 51 52 reg <<= 2; /* reg num to offset */ 53 mutex_lock(&sw_dev->device->bus->mdio_lock); 54 *val = lan9303_mdio_real_read(sw_dev->device, reg); 55 *val |= (lan9303_mdio_real_read(sw_dev->device, reg + 2) << 16); 56 mutex_unlock(&sw_dev->device->bus->mdio_lock); 57 58 return 0; 59 } 60 61 static int lan9303_mdio_phy_write(struct lan9303 *chip, int phy, int reg, 62 u16 val) 63 { 64 struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev); 65 66 return mdiobus_write_nested(sw_dev->device->bus, phy, reg, val); 67 } 68 69 static int lan9303_mdio_phy_read(struct lan9303 *chip, int phy, int reg) 70 { 71 struct lan9303_mdio *sw_dev = dev_get_drvdata(chip->dev); 72 73 return mdiobus_read_nested(sw_dev->device->bus, phy, reg); 74 } 75 76 static const struct lan9303_phy_ops lan9303_mdio_phy_ops = { 77 .phy_read = lan9303_mdio_phy_read, 78 .phy_write = lan9303_mdio_phy_write, 79 }; 80 81 static const struct regmap_config lan9303_mdio_regmap_config = { 82 .reg_bits = 8, 83 .val_bits = 32, 84 .reg_stride = 1, 85 .can_multi_write = true, 86 .max_register = 0x0ff, /* address bits 0..1 are not used */ 87 .reg_format_endian = REGMAP_ENDIAN_LITTLE, 88 89 .volatile_table = &lan9303_register_set, 90 .wr_table = &lan9303_register_set, 91 .rd_table = &lan9303_register_set, 92 93 .reg_read = lan9303_mdio_read, 94 .reg_write = lan9303_mdio_write, 95 96 .cache_type = REGCACHE_NONE, 97 }; 98 99 static int lan9303_mdio_probe(struct mdio_device *mdiodev) 100 { 101 struct lan9303_mdio *sw_dev; 102 int ret; 103 104 sw_dev = devm_kzalloc(&mdiodev->dev, sizeof(struct lan9303_mdio), 105 GFP_KERNEL); 106 if (!sw_dev) 107 return -ENOMEM; 108 109 sw_dev->chip.regmap = devm_regmap_init(&mdiodev->dev, NULL, sw_dev, 110 &lan9303_mdio_regmap_config); 111 if (IS_ERR(sw_dev->chip.regmap)) { 112 ret = PTR_ERR(sw_dev->chip.regmap); 113 dev_err(&mdiodev->dev, "regmap init failed: %d\n", ret); 114 return ret; 115 } 116 117 /* link forward and backward */ 118 sw_dev->device = mdiodev; 119 dev_set_drvdata(&mdiodev->dev, sw_dev); 120 sw_dev->chip.dev = &mdiodev->dev; 121 122 sw_dev->chip.ops = &lan9303_mdio_phy_ops; 123 124 ret = lan9303_probe(&sw_dev->chip, mdiodev->dev.of_node); 125 if (ret != 0) 126 return ret; 127 128 dev_info(&mdiodev->dev, "LAN9303 MDIO driver loaded successfully\n"); 129 130 return 0; 131 } 132 133 static void lan9303_mdio_remove(struct mdio_device *mdiodev) 134 { 135 struct lan9303_mdio *sw_dev = dev_get_drvdata(&mdiodev->dev); 136 137 if (!sw_dev) 138 return; 139 140 lan9303_remove(&sw_dev->chip); 141 } 142 143 static void lan9303_mdio_shutdown(struct mdio_device *mdiodev) 144 { 145 struct lan9303_mdio *sw_dev = dev_get_drvdata(&mdiodev->dev); 146 147 if (!sw_dev) 148 return; 149 150 lan9303_shutdown(&sw_dev->chip); 151 152 dev_set_drvdata(&mdiodev->dev, NULL); 153 } 154 155 /*-------------------------------------------------------------------------*/ 156 157 static const struct of_device_id lan9303_mdio_of_match[] = { 158 { .compatible = "smsc,lan9303-mdio" }, 159 { .compatible = "microchip,lan9354-mdio" }, 160 { /* sentinel */ }, 161 }; 162 MODULE_DEVICE_TABLE(of, lan9303_mdio_of_match); 163 164 static struct mdio_driver lan9303_mdio_driver = { 165 .mdiodrv.driver = { 166 .name = "LAN9303_MDIO", 167 .of_match_table = lan9303_mdio_of_match, 168 }, 169 .probe = lan9303_mdio_probe, 170 .remove = lan9303_mdio_remove, 171 .shutdown = lan9303_mdio_shutdown, 172 }; 173 mdio_module_driver(lan9303_mdio_driver); 174 175 MODULE_AUTHOR("Stefan Roese <sr@denx.de>, Juergen Borleis <kernel@pengutronix.de>"); 176 MODULE_DESCRIPTION("Driver for SMSC/Microchip LAN9303 three port ethernet switch in MDIO managed mode"); 177 MODULE_LICENSE("GPL v2"); 178