1/* 2 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx. 3 * 4 * Copyright (c) 2003 Intracom S.A. 5 * by Pantelis Antoniou <panto@intracom.gr> 6 * 7 * 2005 (c) MontaVista Software, Inc. 8 * Vitaly Bordug <vbordug@ru.mvista.com> 9 * 10 * This file is licensed under the terms of the GNU General Public License 11 * version 2. This program is licensed "as is" without any warranty of any 12 * kind, whether express or implied. 13 */ 14 15#include <linux/module.h> 16#include <linux/ioport.h> 17#include <linux/slab.h> 18#include <linux/init.h> 19#include <linux/interrupt.h> 20#include <linux/netdevice.h> 21#include <linux/etherdevice.h> 22#include <linux/mii.h> 23#include <linux/platform_device.h> 24#include <linux/mdio-bitbang.h> 25#include <linux/of_mdio.h> 26#include <linux/of_platform.h> 27 28#include "fs_enet.h" 29 30struct bb_info { 31 struct mdiobb_ctrl ctrl; 32 __be32 __iomem *dir; 33 __be32 __iomem *dat; 34 u32 mdio_msk; 35 u32 mdc_msk; 36}; 37 38static inline void bb_set(u32 __iomem *p, u32 m) 39{ 40 out_be32(p, in_be32(p) | m); 41} 42 43static inline void bb_clr(u32 __iomem *p, u32 m) 44{ 45 out_be32(p, in_be32(p) & ~m); 46} 47 48static inline int bb_read(u32 __iomem *p, u32 m) 49{ 50 return (in_be32(p) & m) != 0; 51} 52 53static inline void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) 54{ 55 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 56 57 if (dir) 58 bb_set(bitbang->dir, bitbang->mdio_msk); 59 else 60 bb_clr(bitbang->dir, bitbang->mdio_msk); 61 62 /* Read back to flush the write. */ 63 in_be32(bitbang->dir); 64} 65 66static inline int mdio_read(struct mdiobb_ctrl *ctrl) 67{ 68 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 69 return bb_read(bitbang->dat, bitbang->mdio_msk); 70} 71 72static inline void mdio(struct mdiobb_ctrl *ctrl, int what) 73{ 74 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 75 76 if (what) 77 bb_set(bitbang->dat, bitbang->mdio_msk); 78 else 79 bb_clr(bitbang->dat, bitbang->mdio_msk); 80 81 /* Read back to flush the write. */ 82 in_be32(bitbang->dat); 83} 84 85static inline void mdc(struct mdiobb_ctrl *ctrl, int what) 86{ 87 struct bb_info *bitbang = container_of(ctrl, struct bb_info, ctrl); 88 89 if (what) 90 bb_set(bitbang->dat, bitbang->mdc_msk); 91 else 92 bb_clr(bitbang->dat, bitbang->mdc_msk); 93 94 /* Read back to flush the write. */ 95 in_be32(bitbang->dat); 96} 97 98static struct mdiobb_ops bb_ops = { 99 .owner = THIS_MODULE, 100 .set_mdc = mdc, 101 .set_mdio_dir = mdio_dir, 102 .set_mdio_data = mdio, 103 .get_mdio_data = mdio_read, 104}; 105 106static int __devinit fs_mii_bitbang_init(struct mii_bus *bus, 107 struct device_node *np) 108{ 109 struct resource res; 110 const u32 *data; 111 int mdio_pin, mdc_pin, len; 112 struct bb_info *bitbang = bus->priv; 113 114 int ret = of_address_to_resource(np, 0, &res); 115 if (ret) 116 return ret; 117 118 if (res.end - res.start < 13) 119 return -ENODEV; 120 121 /* This should really encode the pin number as well, but all 122 * we get is an int, and the odds of multiple bitbang mdio buses 123 * is low enough that it's not worth going too crazy. 124 */ 125 snprintf(bus->id, MII_BUS_ID_SIZE, "%x", res.start); 126 127 data = of_get_property(np, "fsl,mdio-pin", &len); 128 if (!data || len != 4) 129 return -ENODEV; 130 mdio_pin = *data; 131 132 data = of_get_property(np, "fsl,mdc-pin", &len); 133 if (!data || len != 4) 134 return -ENODEV; 135 mdc_pin = *data; 136 137 bitbang->dir = ioremap(res.start, res.end - res.start + 1); 138 if (!bitbang->dir) 139 return -ENOMEM; 140 141 bitbang->dat = bitbang->dir + 4; 142 bitbang->mdio_msk = 1 << (31 - mdio_pin); 143 bitbang->mdc_msk = 1 << (31 - mdc_pin); 144 145 return 0; 146} 147 148static int __devinit fs_enet_mdio_probe(struct platform_device *ofdev, 149 const struct of_device_id *match) 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 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 173 if (!new_bus->irq) 174 goto out_unmap_regs; 175 176 new_bus->parent = &ofdev->dev; 177 dev_set_drvdata(&ofdev->dev, new_bus); 178 179 ret = of_mdiobus_register(new_bus, ofdev->dev.of_node); 180 if (ret) 181 goto out_free_irqs; 182 183 return 0; 184 185out_free_irqs: 186 dev_set_drvdata(&ofdev->dev, NULL); 187 kfree(new_bus->irq); 188out_unmap_regs: 189 iounmap(bitbang->dir); 190out_free_bus: 191 free_mdio_bitbang(new_bus); 192out_free_priv: 193 kfree(bitbang); 194out: 195 return ret; 196} 197 198static int fs_enet_mdio_remove(struct platform_device *ofdev) 199{ 200 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); 201 struct bb_info *bitbang = bus->priv; 202 203 mdiobus_unregister(bus); 204 dev_set_drvdata(&ofdev->dev, NULL); 205 kfree(bus->irq); 206 free_mdio_bitbang(bus); 207 iounmap(bitbang->dir); 208 kfree(bitbang); 209 210 return 0; 211} 212 213static struct of_device_id fs_enet_mdio_bb_match[] = { 214 { 215 .compatible = "fsl,cpm2-mdio-bitbang", 216 }, 217 {}, 218}; 219MODULE_DEVICE_TABLE(of, fs_enet_mdio_bb_match); 220 221static struct of_platform_driver fs_enet_bb_mdio_driver = { 222 .driver = { 223 .name = "fsl-bb-mdio", 224 .owner = THIS_MODULE, 225 .of_match_table = fs_enet_mdio_bb_match, 226 }, 227 .probe = fs_enet_mdio_probe, 228 .remove = fs_enet_mdio_remove, 229}; 230 231static int fs_enet_mdio_bb_init(void) 232{ 233 return of_register_platform_driver(&fs_enet_bb_mdio_driver); 234} 235 236static void fs_enet_mdio_bb_exit(void) 237{ 238 of_unregister_platform_driver(&fs_enet_bb_mdio_driver); 239} 240 241module_init(fs_enet_mdio_bb_init); 242module_exit(fs_enet_mdio_bb_exit); 243