18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2009-2015 Cavium, Inc.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/gfp.h>
78c2ecf20Sopenharmony_ci#include <linux/io.h>
88c2ecf20Sopenharmony_ci#include <linux/module.h>
98c2ecf20Sopenharmony_ci#include <linux/of_address.h>
108c2ecf20Sopenharmony_ci#include <linux/of_mdio.h>
118c2ecf20Sopenharmony_ci#include <linux/phy.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "mdio-cavium.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistatic int octeon_mdiobus_probe(struct platform_device *pdev)
178c2ecf20Sopenharmony_ci{
188c2ecf20Sopenharmony_ci	struct cavium_mdiobus *bus;
198c2ecf20Sopenharmony_ci	struct mii_bus *mii_bus;
208c2ecf20Sopenharmony_ci	struct resource *res_mem;
218c2ecf20Sopenharmony_ci	resource_size_t mdio_phys;
228c2ecf20Sopenharmony_ci	resource_size_t regsize;
238c2ecf20Sopenharmony_ci	union cvmx_smix_en smi_en;
248c2ecf20Sopenharmony_ci	int err = -ENOENT;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	mii_bus = devm_mdiobus_alloc_size(&pdev->dev, sizeof(*bus));
278c2ecf20Sopenharmony_ci	if (!mii_bus)
288c2ecf20Sopenharmony_ci		return -ENOMEM;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
318c2ecf20Sopenharmony_ci	if (res_mem == NULL) {
328c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "found no memory resource\n");
338c2ecf20Sopenharmony_ci		return -ENXIO;
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	bus = mii_bus->priv;
378c2ecf20Sopenharmony_ci	bus->mii_bus = mii_bus;
388c2ecf20Sopenharmony_ci	mdio_phys = res_mem->start;
398c2ecf20Sopenharmony_ci	regsize = resource_size(res_mem);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci	if (!devm_request_mem_region(&pdev->dev, mdio_phys, regsize,
428c2ecf20Sopenharmony_ci				     res_mem->name)) {
438c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "request_mem_region failed\n");
448c2ecf20Sopenharmony_ci		return -ENXIO;
458c2ecf20Sopenharmony_ci	}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	bus->register_base = devm_ioremap(&pdev->dev, mdio_phys, regsize);
488c2ecf20Sopenharmony_ci	if (!bus->register_base) {
498c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "dev_ioremap failed\n");
508c2ecf20Sopenharmony_ci		return -ENOMEM;
518c2ecf20Sopenharmony_ci	}
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	smi_en.u64 = 0;
548c2ecf20Sopenharmony_ci	smi_en.s.en = 1;
558c2ecf20Sopenharmony_ci	oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	bus->mii_bus->name = KBUILD_MODNAME;
588c2ecf20Sopenharmony_ci	snprintf(bus->mii_bus->id, MII_BUS_ID_SIZE, "%px", bus->register_base);
598c2ecf20Sopenharmony_ci	bus->mii_bus->parent = &pdev->dev;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	bus->mii_bus->read = cavium_mdiobus_read;
628c2ecf20Sopenharmony_ci	bus->mii_bus->write = cavium_mdiobus_write;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, bus);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	err = of_mdiobus_register(bus->mii_bus, pdev->dev.of_node);
678c2ecf20Sopenharmony_ci	if (err)
688c2ecf20Sopenharmony_ci		goto fail_register;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	dev_info(&pdev->dev, "Probed\n");
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	return 0;
738c2ecf20Sopenharmony_cifail_register:
748c2ecf20Sopenharmony_ci	smi_en.u64 = 0;
758c2ecf20Sopenharmony_ci	oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
768c2ecf20Sopenharmony_ci	return err;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic int octeon_mdiobus_remove(struct platform_device *pdev)
808c2ecf20Sopenharmony_ci{
818c2ecf20Sopenharmony_ci	struct cavium_mdiobus *bus;
828c2ecf20Sopenharmony_ci	union cvmx_smix_en smi_en;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	bus = platform_get_drvdata(pdev);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	mdiobus_unregister(bus->mii_bus);
878c2ecf20Sopenharmony_ci	smi_en.u64 = 0;
888c2ecf20Sopenharmony_ci	oct_mdio_writeq(smi_en.u64, bus->register_base + SMI_EN);
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic const struct of_device_id octeon_mdiobus_match[] = {
938c2ecf20Sopenharmony_ci	{
948c2ecf20Sopenharmony_ci		.compatible = "cavium,octeon-3860-mdio",
958c2ecf20Sopenharmony_ci	},
968c2ecf20Sopenharmony_ci	{},
978c2ecf20Sopenharmony_ci};
988c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, octeon_mdiobus_match);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic struct platform_driver octeon_mdiobus_driver = {
1018c2ecf20Sopenharmony_ci	.driver = {
1028c2ecf20Sopenharmony_ci		.name		= KBUILD_MODNAME,
1038c2ecf20Sopenharmony_ci		.of_match_table = octeon_mdiobus_match,
1048c2ecf20Sopenharmony_ci	},
1058c2ecf20Sopenharmony_ci	.probe		= octeon_mdiobus_probe,
1068c2ecf20Sopenharmony_ci	.remove		= octeon_mdiobus_remove,
1078c2ecf20Sopenharmony_ci};
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cimodule_platform_driver(octeon_mdiobus_driver);
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Cavium OCTEON MDIO bus driver");
1128c2ecf20Sopenharmony_ciMODULE_AUTHOR("David Daney");
1138c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
114