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