qca: ipq40xx: Add support for MDIO driver

Change-Id: I404a264f53ef333f0b4b137f7a79f089b4d3d0bf
Signed-off-by: Balamurugan Selvarajan <bselvara@codeaurora.org>
This commit is contained in:
Balamurugan Selvarajan 2016-03-21 20:29:20 +05:30 committed by Akila N
parent 3522c2faad
commit 788ce2c5ce
2 changed files with 153 additions and 0 deletions

View file

@ -0,0 +1,124 @@
/*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <common.h>
#include <miiphy.h>
#include <phy.h>
#include <asm/io.h>
#include <errno.h>
#include "ipq40xx_mdio.h"
struct ipq40xx_mdio_data {
struct mii_bus *bus;
int phy_irq[PHY_MAX_ADDR];
};
static int ipq40xx_mdio_wait_busy(void)
{
int i;
u32 busy;
for (i = 0; i < IPQ40XX_MDIO_RETRY; i++) {
udelay(IPQ40XX_MDIO_DELAY);
busy = readl(IPQ40XX_MDIO_BASE +
MDIO_CTRL_4_REG) &
MDIO_CTRL_4_ACCESS_BUSY;
if (!busy)
return 0;
udelay(IPQ40XX_MDIO_DELAY);
}
printf("%s: MDIO operation timed out\n",
__func__);
return -ETIMEDOUT;
}
int ipq40xx_mdio_write(int mii_id, int regnum, u16 value)
{
if (ipq40xx_mdio_wait_busy())
return -ETIMEDOUT;
/* Issue the phy addreass and reg */
writel((mii_id << 8 | regnum),
IPQ40XX_MDIO_BASE + MDIO_CTRL_1_REG);
/* Issue a write data */
writel(value, IPQ40XX_MDIO_BASE + MDIO_CTRL_2_REG);
/* Issue write command */
writel((MDIO_CTRL_4_ACCESS_START |
MDIO_CTRL_4_ACCESS_CODE_WRITE),
(IPQ40XX_MDIO_BASE + MDIO_CTRL_4_REG));
/* Wait for write complete */
if (ipq40xx_mdio_wait_busy())
return -ETIMEDOUT;
return 0;
}
int ipq40xx_mdio_read(int mii_id, int regnum, ushort *data)
{
u32 val;
if (ipq40xx_mdio_wait_busy())
return -ETIMEDOUT;
/* Issue the phy address and reg */
writel((mii_id << 8) | regnum,
IPQ40XX_MDIO_BASE + MDIO_CTRL_1_REG);
/* issue read command */
writel((MDIO_CTRL_4_ACCESS_START |
MDIO_CTRL_4_ACCESS_CODE_READ),
(IPQ40XX_MDIO_BASE + MDIO_CTRL_4_REG));
if (ipq40xx_mdio_wait_busy())
return -ETIMEDOUT;
/* Read data */
val = readl(IPQ40XX_MDIO_BASE + MDIO_CTRL_3_REG);
if (data != NULL)
*data = val;
return val;
}
int ipq40xx_phy_write(struct mii_dev *bus,
int addr, int dev_addr,
int regnum, ushort value)
{
return ipq40xx_mdio_write(
addr, regnum, value);
}
int ipq40xx_phy_read(struct mii_dev *bus,
int addr, int dev_addr, int regnum)
{
return ipq40xx_mdio_read(
addr, regnum, NULL);
}
int ipq40xx_sw_mdio_init(const char *name)
{
struct mii_dev *bus = mdio_alloc();
if(!bus) {
printf("Failed to allocate IPQ MDIO bus\n");
return -1;
}
bus->read = ipq40xx_phy_read;
bus->write = ipq40xx_phy_write;
bus->reset = NULL;
sprintf(bus->name, name);
return mdio_register(bus);
}

View file

@ -0,0 +1,29 @@
/*
* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _IPQ40XX_MDIO_H
#define _IPQ40XX_MDIO_H
#define IPQ40XX_MDIO_BASE 0x90000
#define MDIO_CTRL_0_REG 0x40
#define MDIO_CTRL_1_REG 0x44
#define MDIO_CTRL_2_REG 0x48
#define MDIO_CTRL_3_REG 0x4c
#define MDIO_CTRL_4_REG 0x50
#define MDIO_CTRL_4_ACCESS_BUSY (1 << 16)
#define MDIO_CTRL_4_ACCESS_START (1 << 8)
#define MDIO_CTRL_4_ACCESS_CODE_READ 0
#define MDIO_CTRL_4_ACCESS_CODE_WRITE 1
#define IPQ40XX_MDIO_RETRY 1000
#define IPQ40XX_MDIO_DELAY 5
#endif /* End _IPQ40XX_MDIO_H */