ar71xx: allow to configure AR803x PHYs via platform data
[openwrt.git] / target / linux / ar71xx / patches-3.10 / 425-net-phy-at803x-allow-to-configure-via-pdata.patch
1 --- a/drivers/net/phy/at803x.c
2 +++ b/drivers/net/phy/at803x.c
3 @@ -12,10 +12,12 @@
4   */
5  
6  #include <linux/phy.h>
7 +#include <linux/mdio.h>
8  #include <linux/module.h>
9  #include <linux/string.h>
10  #include <linux/netdevice.h>
11  #include <linux/etherdevice.h>
12 +#include <linux/platform_data/phy-at803x.h>
13  
14  #define AT803X_INTR_ENABLE                     0x12
15  #define AT803X_INTR_STATUS                     0x13
16 @@ -28,10 +30,61 @@
17  #define AT803X_MMD_ACCESS_CONTROL_DATA         0x0E
18  #define AT803X_FUNC_DATA                       0x4003
19  
20 +#define AT803X_PCS_SMART_EEE_CTRL3             0x805D
21 +
22 +#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK   0x3
23 +#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT  12
24 +#define AT803X_SMART_EEE_CTRL3_LPI_EN                  BIT(8)
25 +
26 +#define AT803X_DEBUG_PORT_ACCESS_OFFSET                0x1D
27 +#define AT803X_DEBUG_PORT_ACCESS_DATA          0x1E
28 +
29 +#define AT803X_DBG0_REG                                0x00
30 +#define AT803X_DBG0_RGMII_RX_CLK_DELAY_EN      BIT(8)
31 +
32 +#define AT803X_DBG5_REG                                0x05
33 +#define AT803X_DBG5_RGMII_TX_CLK_DELAY_EN      BIT(8)
34 +
35  MODULE_DESCRIPTION("Atheros 803x PHY driver");
36  MODULE_AUTHOR("Matus Ujhelyi");
37  MODULE_LICENSE("GPL");
38  
39 +static u16
40 +at803x_dbg_reg_rmw(struct phy_device *phydev, u16 reg, u16 clear, u16 set)
41 +{
42 +       struct mii_bus *bus = phydev->bus;
43 +       int val;
44 +
45 +       mutex_lock(&bus->mdio_lock);
46 +
47 +       bus->write(bus, phydev->addr, AT803X_DEBUG_PORT_ACCESS_OFFSET, reg);
48 +       val = bus->read(bus, phydev->addr, AT803X_DEBUG_PORT_ACCESS_DATA);
49 +       if (val < 0) {
50 +               val = 0xffff;
51 +               goto out;
52 +       }
53 +
54 +       val &= ~clear;
55 +       val |= set;
56 +       bus->write(bus, phydev->addr, AT803X_DEBUG_PORT_ACCESS_DATA, val);
57 +
58 +out:
59 +       mutex_unlock(&bus->mdio_lock);
60 +       return val;
61 +}
62 +
63 +static inline void
64 +at803x_dbg_reg_set(struct phy_device *phydev, u16 reg, u16 set)
65 +{
66 +       at803x_dbg_reg_rmw(phydev, reg, 0, set);
67 +}
68 +
69 +static inline void
70 +at803x_dbg_reg_clr(struct phy_device *phydev, u16 reg, u16 clear)
71 +{
72 +       at803x_dbg_reg_rmw(phydev, reg, clear, 0);
73 +}
74 +
75  static void at803x_set_wol_mac_addr(struct phy_device *phydev)
76  {
77         struct net_device *ndev = phydev->attached_dev;
78 @@ -62,8 +115,16 @@ static void at803x_set_wol_mac_addr(stru
79         }
80  }
81  
82 +static void at803x_disable_smarteee(struct phy_device *phydev)
83 +{
84 +       phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
85 +                     1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
86 +       phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
87 +}
88 +
89  static int at803x_config_init(struct phy_device *phydev)
90  {
91 +       struct at803x_platform_data *pdata;
92         int val;
93         u32 features;
94         int status;
95 @@ -105,6 +166,26 @@ static int at803x_config_init(struct phy
96         status = phy_write(phydev, AT803X_INTR_ENABLE, AT803X_WOL_ENABLE);
97         status = phy_read(phydev, AT803X_INTR_STATUS);
98  
99 +       pdata = dev_get_platdata(&phydev->dev);
100 +       if (pdata) {
101 +               if (pdata->disable_smarteee)
102 +                       at803x_disable_smarteee(phydev);
103 +
104 +               if (pdata->enable_rgmii_rx_delay)
105 +                       at803x_dbg_reg_set(phydev, AT803X_DBG0_REG,
106 +                                          AT803X_DBG0_RGMII_RX_CLK_DELAY_EN);
107 +               else
108 +                       at803x_dbg_reg_clr(phydev, AT803X_DBG0_REG,
109 +                                          AT803X_DBG0_RGMII_RX_CLK_DELAY_EN);
110 +
111 +               if (pdata->enable_rgmii_tx_delay)
112 +                       at803x_dbg_reg_set(phydev, AT803X_DBG5_REG,
113 +                                          AT803X_DBG5_RGMII_TX_CLK_DELAY_EN);
114 +               else
115 +                       at803x_dbg_reg_clr(phydev, AT803X_DBG5_REG,
116 +                                          AT803X_DBG5_RGMII_TX_CLK_DELAY_EN);
117 +       }
118 +
119         return 0;
120  }
121  
122 --- /dev/null
123 +++ b/include/linux/platform_data/phy-at803x.h
124 @@ -0,0 +1,10 @@
125 +#ifndef _PHY_AT803X_PDATA_H
126 +#define _PHY_AT803X_PDATA_H
127 +
128 +struct at803x_platform_data {
129 +       int disable_smarteee:1;
130 +       int enable_rgmii_tx_delay:1;
131 +       int enable_rgmii_rx_delay:1;
132 +};
133 +
134 +#endif /* _PHY_AT803X_PDATA_H */