Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.11 125 lines 3.0 kB view raw
1/* 2 * This file is subject to the terms and conditions of the GNU General Public 3 * License. See the file "COPYING" in the main directory of this archive 4 * for more details. 5 * 6 * Copyright (C) 2009-2015 Cavium, Inc. 7 */ 8 9#include <linux/platform_device.h> 10#include <linux/of_address.h> 11#include <linux/of_mdio.h> 12#include <linux/module.h> 13#include <linux/gfp.h> 14#include <linux/phy.h> 15#include <linux/io.h> 16 17#include "mdio-cavium.h" 18 19static int octeon_mdiobus_probe(struct platform_device *pdev) 20{ 21 struct cavium_mdiobus *bus; 22 struct mii_bus *mii_bus; 23 struct resource *res_mem; 24 resource_size_t mdio_phys; 25 resource_size_t regsize; 26 union cvmx_smix_en smi_en; 27 int err = -ENOENT; 28 29 mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus)); 30 if (!mii_bus) 31 return -ENOMEM; 32 33 res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 34 if (res_mem == NULL) { 35 dev_err(&pdev->dev, "found no memory resource\n"); 36 return -ENXIO; 37 } 38 39 bus = mii_bus->priv; 40 bus->mii_bus = mii_bus; 41 mdio_phys = res_mem->start; 42 regsize = resource_size(res_mem); 43 44 if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize, 45 res_mem->name)) { 46 dev_err(&pdev->dev, "request_mem_region failed\n"); 47 return -ENXIO; 48 } 49 50 bus->register_base = 51 (u64)devm_ioremap(&pdev->dev, mdio_phys, regsize); 52 if (!bus->register_base) { 53 dev_err(&pdev->dev, "dev_ioremap failed\n"); 54 return -ENOMEM; 55 } 56 57 smi_en.u64 = 0; 58 smi_en.s.en = 1; 59 oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); 60 61 bus->mii_bus->name = KBUILD_MODNAME; 62 snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%llx", bus->register_base); 63 bus->mii_bus->parent = &pdev->dev; 64 65 bus->mii_bus->read = cavium_mdiobus_read; 66 bus->mii_bus->write = cavium_mdiobus_write; 67 68 platform_set_drvdata(pdev, bus); 69 70 err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node); 71 if (err) 72 goto fail_register; 73 74 dev_info(&pdev->dev, "Probed\n"); 75 76 return 0; 77fail_register: 78 mdiobus_free(bus->mii_bus); 79 smi_en.u64 = 0; 80 oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); 81 return err; 82} 83 84static int octeon_mdiobus_remove(struct platform_device *pdev) 85{ 86 struct cavium_mdiobus *bus; 87 union cvmx_smix_en smi_en; 88 89 bus = platform_get_drvdata(pdev); 90 91 mdiobus_unregister(bus->mii_bus); 92 mdiobus_free(bus->mii_bus); 93 smi_en.u64 = 0; 94 oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN); 95 return 0; 96} 97 98static const struct of_device_id octeon_mdiobus_match[] = { 99 { 100 .compatible = "cavium,octeon-3860-mdio", 101 }, 102 {}, 103}; 104MODULE_DEVICE_TABLE(of, octeon_mdiobus_match); 105 106static struct platform_driver octeon_mdiobus_driver = { 107 .driver = { 108 .name = KBUILD_MODNAME, 109 .of_match_table = octeon_mdiobus_match, 110 }, 111 .probe = octeon_mdiobus_probe, 112 .remove = octeon_mdiobus_remove, 113}; 114 115void octeon_mdiobus_force_mod_depencency(void) 116{ 117 /* Let ethernet drivers force us to be loaded. */ 118} 119EXPORT_SYMBOL(octeon_mdiobus_force_mod_depencency); 120 121module_platform_driver(octeon_mdiobus_driver); 122 123MODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver"); 124MODULE_AUTHOR("David Daney"); 125MODULE_LICENSE("GPL");