1/* 2 ************************************************************************** 3 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 ************************************************************************** 17 */ 18/* 19 * @file 20 * IPQ806x MDIO bus support. 21 * 22 * @note Many of the functions other than the device specific functions 23 * changes for operating system other than Linux 2.6.xx 24 *-----------------------------REVISION HISTORY-------------------------------- 25 * Qualcomm Atheros 09/Jun/2013 Created 26 */ 27 28#include <linux/version.h> 29#include <linux/kernel.h> 30#include <linux/bitops.h> 31#include <linux/phy.h> 32#include <linux/device.h> 33 34#ifdef CONFIG_OF 35#include <msm_nss_gmac.h> 36#else 37#include <mach/msm_nss_gmac.h> 38#endif 39 40#include <nss_gmac_dev.h> 41#include <nss_gmac_network_interface.h> 42 43 44static int32_t phy_irq[PHY_MAX_ADDR]; 45 46 47/** 48 * @brief MDIO bus read 49 * @param[in] pointer to struct mii_bus 50 * @param[in] Phy MDIO address 51 * @param[in] Register number 52 * @return Contents of MDIO register 53 */ 54static int32_t nss_gmac_mdiobus_read(struct mii_bus *bus, int32_t phy_id, 55 int32_t regnum) 56{ 57 int32_t status; 58 uint16_t data; 59 struct nss_gmac_dev *gmacdev; 60 61 gmacdev = (struct nss_gmac_dev *)bus->priv; 62 63 status = nss_gmac_read_phy_reg((uint32_t *)gmacdev->mac_base, 64 phy_id, regnum, 65 &data, gmacdev->mdc_clk_div); 66 67 if (status != 0) 68 data = 0; 69 70 return (int32_t)data; 71} 72 73 74/** 75 * @brief MDIO bus write 76 * @param[in] pointer to struct mii_bus 77 * @param[in] Phy MDIO address 78 * @param[in] Register number 79 * @param[in] Value to write 80 * @return 0 on Success 81 */ 82static int32_t nss_gmac_mdiobus_write(struct mii_bus *bus, int32_t phy_id, 83 int32_t regnum, uint16_t val) 84{ 85 struct nss_gmac_dev *gmacdev; 86 87 gmacdev = (struct nss_gmac_dev *)bus->priv; 88 89 nss_gmac_write_phy_reg((uint32_t *)gmacdev->mac_base, phy_id, 90 regnum, val, gmacdev->mdc_clk_div); 91 92 return 0; 93} 94 95 96/** 97 * @brief MDIO bus reset 98 * @param[in] pointer to struct mii_bus 99 * @return 0 on Success 100 */ 101int32_t nss_gmac_mdiobus_reset(struct mii_bus *bus) 102{ 103 struct nss_gmac_dev *gmacdev; 104 105 gmacdev = (struct nss_gmac_dev *)bus->priv; 106 gmacdev->mdc_clk_div = MDC_CLK_DIV; 107 netdev_dbg(gmacdev->netdev, "%s: GMAC%d MDC Clk div set to - 0x%x\n", 108 __func__, gmacdev->macid, gmacdev->mdc_clk_div); 109 110 return 0; 111} 112 113 114/** 115 * @brief Initialize and register MDIO bus 116 * @param[in] pointer to nss_gmac_dev 117 * @return 0 on Success 118 */ 119int32_t nss_gmac_init_mdiobus(struct nss_gmac_dev *gmacdev) 120{ 121 struct mii_bus *miibus = NULL; 122 struct phy_device *phydev = NULL; 123 124 miibus = mdiobus_alloc(); 125 if (miibus == NULL) 126 return -ENOMEM; 127 128 miibus->name = "nss gmac mdio bus"; 129 snprintf(miibus->id, MII_BUS_ID_SIZE, "mdiobus%x", gmacdev->macid); 130 131 miibus->priv = (void *)gmacdev; 132 miibus->read = nss_gmac_mdiobus_read; 133 miibus->write = nss_gmac_mdiobus_write; 134 miibus->reset = nss_gmac_mdiobus_reset; 135 mutex_init(&(miibus->mdio_lock)); 136 miibus->parent = &(gmacdev->pdev->dev); 137 138 phy_irq[gmacdev->phy_base] = PHY_POLL; 139 miibus->irq = phy_irq; 140 miibus->phy_mask = ~((uint32_t)(1 << gmacdev->phy_base)); 141 142 if (mdiobus_register(miibus) != 0) { 143 mdiobus_free(miibus); 144 netdev_dbg(gmacdev->netdev, "%s: mdiobus_reg failed\n", __func__); 145 return -EIO; 146 } 147 148 phydev = miibus->phy_map[gmacdev->phy_base]; 149 if (!phydev) { 150 netdev_dbg(gmacdev->netdev, "%s: No phy device\n", __func__); 151 mdiobus_unregister(miibus); 152 mdiobus_free(miibus); 153 return -ENODEV; 154 } 155 156 phydev->interface = gmacdev->phy_mii_type; 157 158 gmacdev->miibus = miibus; 159 return 0; 160} 161 162 163/** 164 * @brief De-initialize MDIO bus 165 * @param[in] pointer to nss_gmac_dev 166 * @return void 167 */ 168void nss_gmac_deinit_mdiobus(struct nss_gmac_dev *gmacdev) 169{ 170 mdiobus_unregister(gmacdev->miibus); 171 mdiobus_free(gmacdev->miibus); 172 gmacdev->miibus = NULL; 173} 174 175 176