FILE
mii-bitbang.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/ethernet/freescale/fs_enet/mii-bitbang.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. 4 * 5 * Copyright (c) 2003 Intracom S.A. 6 * by Pantelis Antoniou <panto@intracom.gr> 7 * 8 * 2005 (c) MontaVista Software, Inc. 9 * Vitaly Bordug <vbordug@ru.mvista.com> 10 */ 11 12#include <linux/module.h> 13#include <linux/ioport.h> 14#include <linux/slab.h> 15#include <linux/interrupt.h> 16#include <linux/netdevice.h> 17#include <linux/etherdevice.h> 18#include <linux/mii.h> 19#include <linux/platform_device.h> 20#include <linux/mdio-bitbang.h> 21#include <linux/of_address.h> 22#include <linux/of_mdio.h> 23#include <linux/of_platform.h> 24 25#include "fs_enet.h" 26 27struct bb_info { 28 struct mdiobb_ctrl ctrl; 29 u32 __iomem *dir; 30 u32 __iomem *dat; 31 u32 mdio_msk; 32 u32 mdc_msk; 33}; 34 35/* FIXME: If any other users of GPIO crop up, then these will have to 36 * have some sort of global synchronization to avoid races with other 37 * pins on the same port. The ideal solution would probably be to 38 * bind the ports to a GPIO driver, and have this be a client of it. 39 */ 40static inline void bb_set(u32 __iomem *p, u32 m) 41{ 42 out_be32(p, in_be32(p) | m); 43} 44 45static inline void bb_clr(u32 __iomem *p, u32 m) 46{ 47 out_be32(p, in_be32(p) & ~m); 48} 49 50static inline int bb_read(u32 __iomem *p, u32 m) 51{ 52 return (in_be32(p) & m) != 0; 53} 54 55static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) 56{ 57 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 58 59 if (dir) 60 bb_set(bitbang->dir, bitbang->mdio_msk); 61 else 62 bb_clr(bitbang->dir, bitbang->mdio_msk); 63 64 /* Read back to flush the write. */ 65 in_be32(bitbang->dir); 66} 67 68static inline int mdio_read(struct mdiobb_ctrl *ctrl) 69{ 70 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 71 return bb_read(bitbang->dat, bitbang->mdio_msk); 72} 73 74static inline void mdio(struct mdiobb_ctrl *ctrl, int what) 75{ 76 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 77 78 if (what) 79 bb_set(bitbang->dat, bitbang->mdio_msk); 80 else 81 bb_clr(bitbang->dat, bitbang->mdio_msk); 82 83 /* Read back to flush the write. */ 84 in_be32(bitbang->dat); 85} 86 87static inline void mdc(struct mdiobb_ctrl *ctrl, int what) 88{ 89 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 90 91 if (what) 92 bb_set(bitbang->dat, bitbang->mdc_msk); 93 else 94 bb_clr(bitbang->dat, bitbang->mdc_msk); 95 96 /* Read back to flush the write. */ 97 in_be32(bitbang->dat); 98} 99 100static const struct mdiobb_ops bb_ops = { 101 .owner = THIS_MODULE, 102 .set_mdc = mdc, 103 .set_mdio_dir = mdio_dir, 104 .set_mdio_data = mdio, 105 .get_mdio_data = mdio_read, 106}; 107 108static int fs_mii_bitbang_init(struct mii_bus *bus, struct device_node *np) 109{ 110 struct resource res; 111 const u32 *data; 112 int mdio_pin, mdc_pin, len; 113 struct bb_info *bitbang = bus->priv; 114 115 int ret = of_address_to_resource(np, 0, &res); 116 if (ret) 117 return ret; 118 119 if (resource_size(&res) <= 13) 120 return -ENODEV; 121 122 /* This should really encode the pin number as well, but all 123 * we get is an int, and the odds of multiple bitbang mdio buses 124 * is low enough that it's not worth going too crazy. 125 */ 126 snprintf(bus->id, MII_BUS_ID_SIZE, "%pa", &res.start); 127 128 data = of_get_property(np, "fsl,mdio-pin", &len); 129 if (!data || len != 4) 130 return -ENODEV; 131 mdio_pin = *data; 132 133 data = of_get_property(np, "fsl,mdc-pin", &len); 134 if (!data || len != 4) 135 return -ENODEV; 136 mdc_pin = *data; 137 138 bitbang->dir = ioremap(res.start, resource_size(&res)); 139 if (!bitbang->dir) 140 return -ENOMEM; 141 142 bitbang->dat = bitbang->dir + 4; 143 bitbang->mdio_msk = 1 << (31 - mdio_pin); 144 bitbang->mdc_msk = 1 << (31 - mdc_pin); 145 146 return 0; 147} 148 149static int fs_enet_mdio_probe(struct platform_device *ofdev) 150{ 151 struct mii_bus *new_bus; 152 struct bb_info *bitbang; 153 int ret = -ENOMEM; 154 155 bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL); 156 if (!bitbang) 157 goto out; 158 159 bitbang->ctrl.ops = &bb_ops; 160 161 new_bus = alloc_mdio_bitbang(&bitbang->ctrl); 162 if (!new_bus) 163 goto out_free_priv; 164 165 new_bus->name = "CPM2 Bitbanged MII", 166 167 ret = fs_mii_bitbang_init(new_bus, ofdev->dev.of_node); 168 if (ret) 169 goto out_free_bus; 170 171 new_bus->phy_mask = ~0; 172 173 new_bus->parent = &ofdev->dev; 174 platform_set_drvdata(ofdev, new_bus); 175 176 ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); 177 if (ret) 178 goto out_unmap_regs; 179 180 return 0; 181 182out_unmap_regs: 183 iounmap(bitbang->dir); 184out_free_bus: 185 free_mdio_bitbang(new_bus); 186out_free_priv: 187 kfree(bitbang); 188out: 189 return ret; 190} 191 192static void fs_enet_mdio_remove(struct platform_device *ofdev) 193{ 194 struct mii_bus *bus = platform_get_drvdata(ofdev); 195 struct bb_info *bitbang = bus->priv; 196 197 mdiobus_unregister(bus); 198 free_mdio_bitbang(bus); 199 iounmap(bitbang->dir); 200 kfree(bitbang); 201} 202 203static const struct of_device_id fs_enet_mdio_bb_match[] = { 204 { 205 .compatible = "fsl,cpm2-mdio-bitbang", 206 }, 207 {}, 208}; 209MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match); 210 211static struct platform_driver fs_enet_bb_mdio_driver = { 212 .driver = { 213 .name = "fsl-bb-mdio", 214 .of_match_table = fs_enet_mdio_bb_match, 215 }, 216 .probe = fs_enet_mdio_probe, 217 .remove = fs_enet_mdio_remove, 218}; 219 220module_platform_driver(fs_enet_bb_mdio_driver); 221MODULE_LICENSE("GPL");
~/
Read-only file preview.