kernel: add missing patch
[oweals/openwrt.git] / target / linux / generic / pending-4.9 / 734-net-phy-at803x-allow-to-configure-via-pdata.patch
1 From: Gabor Juhos <juhosg@openwrt.org>
2 Subject: net: phy: allow to configure AR803x PHYs via platform data
3
4 Add a patch for the at803x phy driver, in order to be able
5 to configure some register settings via platform data.
6
7 Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
8 ---
9  drivers/net/phy/at803x.c                 | 56 ++++++++++++++++++++++++++++++++
10  include/linux/platform_data/phy-at803x.h | 11 +++++++
11  2 files changed, 67 insertions(+)
12  create mode 100644 include/linux/platform_data/phy-at803x.h
13
14 diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
15 index c0f45dde60aa..4a55130dcb1c 100644
16 --- a/drivers/net/phy/at803x.c
17 +++ b/drivers/net/phy/at803x.c
18 @@ -12,12 +12,14 @@
19   */
20  
21  #include <linux/phy.h>
22 +#include <linux/mdio.h>
23  #include <linux/module.h>
24  #include <linux/string.h>
25  #include <linux/netdevice.h>
26  #include <linux/etherdevice.h>
27  #include <linux/of_gpio.h>
28  #include <linux/gpio/consumer.h>
29 +#include <linux/platform_data/phy-at803x.h>
30  
31  #define AT803X_INTR_ENABLE                     0x12
32  #define AT803X_INTR_ENABLE_AUTONEG_ERR         BIT(15)
33 @@ -45,6 +47,11 @@
34  #define AT803X_REG_CHIP_CONFIG                 0x1f
35  #define AT803X_BT_BX_REG_SEL                   0x8000
36  
37 +#define AT803X_PCS_SMART_EEE_CTRL3                     0x805D
38 +#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK   0x3
39 +#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT  12
40 +#define AT803X_SMART_EEE_CTRL3_LPI_EN                  BIT(8)
41 +
42  #define AT803X_DEBUG_ADDR                      0x1D
43  #define AT803X_DEBUG_DATA                      0x1E
44  
45 @@ -72,6 +79,7 @@ MODULE_LICENSE("GPL");
46  struct at803x_priv {
47         bool phy_reset:1;
48         struct gpio_desc *gpiod_reset;
49 +       int prev_speed;
50  };
51  
52  struct at803x_context {
53 @@ -276,8 +284,16 @@ static int at803x_probe(struct phy_device *phydev)
54         return 0;
55  }
56  
57 +static void at803x_disable_smarteee(struct phy_device *phydev)
58 +{
59 +       phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
60 +               1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
61 +       phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
62 +}
63 +
64  static int at803x_config_init(struct phy_device *phydev)
65  {
66 +       struct at803x_platform_data *pdata;
67         int ret;
68  
69         ret = genphy_config_init(phydev);
70 @@ -298,6 +314,26 @@ static int at803x_config_init(struct phy_device *phydev)
71                         return ret;
72         }
73  
74 +       pdata = dev_get_platdata(&phydev->mdio.dev);
75 +       if (pdata) {
76 +               if (pdata->disable_smarteee)
77 +                       at803x_disable_smarteee(phydev);
78 +
79 +               if (pdata->enable_rgmii_rx_delay)
80 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
81 +                               AT803X_DEBUG_RX_CLK_DLY_EN);
82 +               else
83 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
84 +                               AT803X_DEBUG_RX_CLK_DLY_EN, 0);
85 +
86 +               if (pdata->enable_rgmii_tx_delay)
87 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
88 +                               AT803X_DEBUG_TX_CLK_DLY_EN);
89 +               else
90 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
91 +                               AT803X_DEBUG_TX_CLK_DLY_EN, 0);
92 +       }
93 +
94         return 0;
95  }
96  
97 @@ -335,6 +371,8 @@ static int at803x_config_intr(struct phy_device *phydev)
98  static void at803x_link_change_notify(struct phy_device *phydev)
99  {
100         struct at803x_priv *priv = phydev->priv;
101 +       struct at803x_platform_data *pdata;
102 +       pdata = dev_get_platdata(&phydev->mdio.dev);
103  
104         /*
105          * Conduct a hardware reset for AT8030/2 every time a link loss is
106 @@ -363,6 +401,24 @@ static void at803x_link_change_notify(struct phy_device *phydev)
107         } else {
108                 priv->phy_reset = false;
109         }
110 +       if (pdata && pdata->fixup_rgmii_tx_delay &&
111 +           phydev->speed != priv->prev_speed) {
112 +               switch (phydev->speed) {
113 +               case SPEED_10:
114 +               case SPEED_100:
115 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
116 +                               AT803X_DEBUG_TX_CLK_DLY_EN);
117 +                       break;
118 +               case SPEED_1000:
119 +                       at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
120 +                               AT803X_DEBUG_TX_CLK_DLY_EN, 0);
121 +                       break;
122 +               default:
123 +                       break;
124 +               }
125 +
126 +               priv->prev_speed = phydev->speed;
127 +       }
128  }
129  
130  static int at803x_aneg_done(struct phy_device *phydev)
131 diff --git a/include/linux/platform_data/phy-at803x.h b/include/linux/platform_data/phy-at803x.h
132 new file mode 100644
133 index 000000000000..a5df74b4f38d
134 --- /dev/null
135 +++ b/include/linux/platform_data/phy-at803x.h
136 @@ -0,0 +1,11 @@
137 +#ifndef _PHY_AT803X_PDATA_H
138 +#define _PHY_AT803X_PDATA_H
139 +
140 +struct at803x_platform_data {
141 +       int disable_smarteee:1;
142 +       int enable_rgmii_tx_delay:1;
143 +       int enable_rgmii_rx_delay:1;
144 +       int fixup_rgmii_tx_delay:1;
145 +};
146 +
147 +#endif /* _PHY_AT803X_PDATA_H */
148 -- 
149 2.11.0
150