1*a9770eacSAndrew Lunn // SPDX-License-Identifier: GPL-2.0 2*a9770eacSAndrew Lunn /* 3*a9770eacSAndrew Lunn * Copyright (C) 2009-2015 Cavium, Inc. 4*a9770eacSAndrew Lunn */ 5*a9770eacSAndrew Lunn 6*a9770eacSAndrew Lunn #include <linux/platform_device.h> 7*a9770eacSAndrew Lunn #include <linux/of_address.h> 8*a9770eacSAndrew Lunn #include <linux/of_mdio.h> 9*a9770eacSAndrew Lunn #include <linux/module.h> 10*a9770eacSAndrew Lunn #include <linux/gfp.h> 11*a9770eacSAndrew Lunn #include <linux/phy.h> 12*a9770eacSAndrew Lunn #include <linux/io.h> 13*a9770eacSAndrew Lunn 14*a9770eacSAndrew Lunn #include "mdio-cavium.h" 15*a9770eacSAndrew Lunn 16*a9770eacSAndrew Lunn static int octeon_mdiobus_probe(struct platform_device *pdev) 17*a9770eacSAndrew Lunn { 18*a9770eacSAndrew Lunn struct cavium_mdiobus *bus; 19*a9770eacSAndrew Lunn struct mii_bus *mii_bus; 20*a9770eacSAndrew Lunn struct resource *res_mem; 21*a9770eacSAndrew Lunn resource_size_t mdio_phys; 22*a9770eacSAndrew Lunn resource_size_t regsize; 23*a9770eacSAndrew Lunn union cvmx_smix_en smi_en; 24*a9770eacSAndrew Lunn int err = -ENOENT; 25*a9770eacSAndrew Lunn 26*a9770eacSAndrew Lunn mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus)); 27*a9770eacSAndrew Lunn if (!mii_bus) 28*a9770eacSAndrew Lunn return -ENOMEM; 29*a9770eacSAndrew Lunn 30*a9770eacSAndrew Lunn res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 31*a9770eacSAndrew Lunn if (res_mem == NULL) { 32*a9770eacSAndrew Lunn dev_err(&pdev->dev, "found no memory resource\n"); 33*a9770eacSAndrew Lunn return -ENXIO; 34*a9770eacSAndrew Lunn } 35*a9770eacSAndrew Lunn 36*a9770eacSAndrew Lunn bus = mii_bus->priv; 37*a9770eacSAndrew Lunn bus->mii_bus = mii_bus; 38*a9770eacSAndrew Lunn mdio_phys = res_mem->start; 39*a9770eacSAndrew Lunn regsize = resource_size(res_mem); 40*a9770eacSAndrew Lunn 41*a9770eacSAndrew Lunn if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize, 42*a9770eacSAndrew Lunn res_mem->name)) { 43*a9770eacSAndrew Lunn dev_err(&pdev->dev, "request_mem_region failed\n"); 44*a9770eacSAndrew Lunn return -ENXIO; 45*a9770eacSAndrew Lunn } 46*a9770eacSAndrew Lunn 47*a9770eacSAndrew Lunn bus->register_base = devm_ioremap(&pdev->dev, mdio_phys, regsize); 48*a9770eacSAndrew Lunn if (!bus->register_base) { 49*a9770eacSAndrew Lunn dev_err(&pdev->dev, "dev_ioremap failed\n"); 50*a9770eacSAndrew Lunn return -ENOMEM; 51*a9770eacSAndrew Lunn } 52*a9770eacSAndrew Lunn 53*a9770eacSAndrew Lunn smi_en.u64 = 0; 54*a9770eacSAndrew Lunn smi_en.s.en = 1; 55*a9770eacSAndrew Lunn oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); 56*a9770eacSAndrew Lunn 57*a9770eacSAndrew Lunn bus->mii_bus->name = KBUILD_MODNAME; 58*a9770eacSAndrew Lunn snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%px", bus->register_base); 59*a9770eacSAndrew Lunn bus->mii_bus->parent = &pdev->dev; 60*a9770eacSAndrew Lunn 61*a9770eacSAndrew Lunn bus->mii_bus->read = cavium_mdiobus_read; 62*a9770eacSAndrew Lunn bus->mii_bus->write = cavium_mdiobus_write; 63*a9770eacSAndrew Lunn 64*a9770eacSAndrew Lunn platform_set_drvdata(pdev, bus); 65*a9770eacSAndrew Lunn 66*a9770eacSAndrew Lunn err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node); 67*a9770eacSAndrew Lunn if (err) 68*a9770eacSAndrew Lunn goto fail_register; 69*a9770eacSAndrew Lunn 70*a9770eacSAndrew Lunn dev_info(&pdev->dev, "Probed\n"); 71*a9770eacSAndrew Lunn 72*a9770eacSAndrew Lunn return 0; 73*a9770eacSAndrew Lunn fail_register: 74*a9770eacSAndrew Lunn mdiobus_free(bus->mii_bus); 75*a9770eacSAndrew Lunn smi_en.u64 = 0; 76*a9770eacSAndrew Lunn oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); 77*a9770eacSAndrew Lunn return err; 78*a9770eacSAndrew Lunn } 79*a9770eacSAndrew Lunn 80*a9770eacSAndrew Lunn static int octeon_mdiobus_remove(struct platform_device *pdev) 81*a9770eacSAndrew Lunn { 82*a9770eacSAndrew Lunn struct cavium_mdiobus *bus; 83*a9770eacSAndrew Lunn union cvmx_smix_en smi_en; 84*a9770eacSAndrew Lunn 85*a9770eacSAndrew Lunn bus = platform_get_drvdata(pdev); 86*a9770eacSAndrew Lunn 87*a9770eacSAndrew Lunn mdiobus_unregister(bus->mii_bus); 88*a9770eacSAndrew Lunn mdiobus_free(bus->mii_bus); 89*a9770eacSAndrew Lunn smi_en.u64 = 0; 90*a9770eacSAndrew Lunn oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); 91*a9770eacSAndrew Lunn return 0; 92*a9770eacSAndrew Lunn } 93*a9770eacSAndrew Lunn 94*a9770eacSAndrew Lunn static const struct of_device_id octeon_mdiobus_match[] = { 95*a9770eacSAndrew Lunn { 96*a9770eacSAndrew Lunn .compatible = "cavium,octeon-3860-mdio", 97*a9770eacSAndrew Lunn }, 98*a9770eacSAndrew Lunn {}, 99*a9770eacSAndrew Lunn }; 100*a9770eacSAndrew Lunn MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); 101*a9770eacSAndrew Lunn 102*a9770eacSAndrew Lunn static struct platform_driver octeon_mdiobus_driver = { 103*a9770eacSAndrew Lunn .driver = { 104*a9770eacSAndrew Lunn .name = KBUILD_MODNAME, 105*a9770eacSAndrew Lunn .of_match_table = octeon_mdiobus_match, 106*a9770eacSAndrew Lunn }, 107*a9770eacSAndrew Lunn .probe = octeon_mdiobus_probe, 108*a9770eacSAndrew Lunn .remove = octeon_mdiobus_remove, 109*a9770eacSAndrew Lunn }; 110*a9770eacSAndrew Lunn 111*a9770eacSAndrew Lunn module_platform_driver(octeon_mdiobus_driver); 112*a9770eacSAndrew Lunn 113*a9770eacSAndrew Lunn MODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver"); 114*a9770eacSAndrew Lunn MODULE_AUTHOR("David Daney"); 115*a9770eacSAndrew Lunn MODULE_LICENSE("GPL v2"); 116