From 02ea5b9e560255ae07686fe1a55721691b106e9e Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Sun, 13 Apr 2014 20:41:50 +0000
Subject: ar71xx: allow to configure AR803x PHYs via platform data

Add a patch for the at803x phy driver, in order to be able
to configure some register settings via platform data.

Signed-off-by: Gabor Juhos <juhosg@openwrt.org>

SVN-Revision: 40507
---
 ...t-phy-at803x-allow-to-configure-via-pdata.patch | 134 +++++++++++++++++++++
 1 file changed, 134 insertions(+)
 create mode 100644 target/linux/ar71xx/patches-3.10/425-net-phy-at803x-allow-to-configure-via-pdata.patch

(limited to 'target')

diff --git a/target/linux/ar71xx/patches-3.10/425-net-phy-at803x-allow-to-configure-via-pdata.patch b/target/linux/ar71xx/patches-3.10/425-net-phy-at803x-allow-to-configure-via-pdata.patch
new file mode 100644
index 0000000000..788653fc5f
--- /dev/null
+++ b/target/linux/ar71xx/patches-3.10/425-net-phy-at803x-allow-to-configure-via-pdata.patch
@@ -0,0 +1,134 @@
+--- a/drivers/net/phy/at803x.c
++++ b/drivers/net/phy/at803x.c
+@@ -12,10 +12,12 @@
+  */
+ 
+ #include <linux/phy.h>
++#include <linux/mdio.h>
+ #include <linux/module.h>
+ #include <linux/string.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
++#include <linux/platform_data/phy-at803x.h>
+ 
+ #define AT803X_INTR_ENABLE			0x12
+ #define AT803X_INTR_STATUS			0x13
+@@ -28,10 +30,61 @@
+ #define AT803X_MMD_ACCESS_CONTROL_DATA		0x0E
+ #define AT803X_FUNC_DATA			0x4003
+ 
++#define AT803X_PCS_SMART_EEE_CTRL3		0x805D
++
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK   0x3
++#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT  12
++#define AT803X_SMART_EEE_CTRL3_LPI_EN                  BIT(8)
++
++#define AT803X_DEBUG_PORT_ACCESS_OFFSET		0x1D
++#define AT803X_DEBUG_PORT_ACCESS_DATA		0x1E
++
++#define AT803X_DBG0_REG				0x00
++#define AT803X_DBG0_RGMII_RX_CLK_DELAY_EN	BIT(8)
++
++#define AT803X_DBG5_REG				0x05
++#define AT803X_DBG5_RGMII_TX_CLK_DELAY_EN	BIT(8)
++
+ MODULE_DESCRIPTION("Atheros 803x PHY driver");
+ MODULE_AUTHOR("Matus Ujhelyi");
+ MODULE_LICENSE("GPL");
+ 
++static u16
++at803x_dbg_reg_rmw(struct phy_device *phydev, u16 reg, u16 clear, u16 set)
++{
++	struct mii_bus *bus = phydev->bus;
++	int val;
++
++	mutex_lock(&bus->mdio_lock);
++
++	bus->write(bus, phydev->addr, AT803X_DEBUG_PORT_ACCESS_OFFSET, reg);
++	val = bus->read(bus, phydev->addr, AT803X_DEBUG_PORT_ACCESS_DATA);
++	if (val < 0) {
++		val = 0xffff;
++		goto out;
++	}
++
++	val &= ~clear;
++	val |= set;
++	bus->write(bus, phydev->addr, AT803X_DEBUG_PORT_ACCESS_DATA, val);
++
++out:
++	mutex_unlock(&bus->mdio_lock);
++	return val;
++}
++
++static inline void
++at803x_dbg_reg_set(struct phy_device *phydev, u16 reg, u16 set)
++{
++	at803x_dbg_reg_rmw(phydev, reg, 0, set);
++}
++
++static inline void
++at803x_dbg_reg_clr(struct phy_device *phydev, u16 reg, u16 clear)
++{
++	at803x_dbg_reg_rmw(phydev, reg, clear, 0);
++}
++
+ static void at803x_set_wol_mac_addr(struct phy_device *phydev)
+ {
+ 	struct net_device *ndev = phydev->attached_dev;
+@@ -62,8 +115,16 @@ static void at803x_set_wol_mac_addr(stru
+ 	}
+ }
+ 
++static void at803x_disable_smarteee(struct phy_device *phydev)
++{
++	phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
++		      1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
++	phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
++}
++
+ static int at803x_config_init(struct phy_device *phydev)
+ {
++	struct at803x_platform_data *pdata;
+ 	int val;
+ 	u32 features;
+ 	int status;
+@@ -105,6 +166,26 @@ static int at803x_config_init(struct phy
+ 	status = phy_write(phydev, AT803X_INTR_ENABLE, AT803X_WOL_ENABLE);
+ 	status = phy_read(phydev, AT803X_INTR_STATUS);
+ 
++	pdata = dev_get_platdata(&phydev->dev);
++	if (pdata) {
++		if (pdata->disable_smarteee)
++			at803x_disable_smarteee(phydev);
++
++		if (pdata->enable_rgmii_rx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DBG0_REG,
++					   AT803X_DBG0_RGMII_RX_CLK_DELAY_EN);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DBG0_REG,
++					   AT803X_DBG0_RGMII_RX_CLK_DELAY_EN);
++
++		if (pdata->enable_rgmii_tx_delay)
++			at803x_dbg_reg_set(phydev, AT803X_DBG5_REG,
++					   AT803X_DBG5_RGMII_TX_CLK_DELAY_EN);
++		else
++			at803x_dbg_reg_clr(phydev, AT803X_DBG5_REG,
++					   AT803X_DBG5_RGMII_TX_CLK_DELAY_EN);
++	}
++
+ 	return 0;
+ }
+ 
+--- /dev/null
++++ b/include/linux/platform_data/phy-at803x.h
+@@ -0,0 +1,10 @@
++#ifndef _PHY_AT803X_PDATA_H
++#define _PHY_AT803X_PDATA_H
++
++struct at803x_platform_data {
++	int disable_smarteee:1;
++	int enable_rgmii_tx_delay:1;
++	int enable_rgmii_rx_delay:1;
++};
++
++#endif /* _PHY_AT803X_PDATA_H */
-- 
cgit v1.2.3