Merge tag 's390-5.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
[platform/kernel/linux-rpi.git] / drivers / net / phy / aquantia.c
1 /*
2  * Driver for Aquantia PHY
3  *
4  * Author: Shaohui Xie <Shaohui.Xie@freescale.com>
5  *
6  * Copyright 2015 Freescale Semiconductor, Inc.
7  *
8  * This file is licensed under the terms of the GNU General Public License
9  * version 2.  This program is licensed "as is" without any warranty of any
10  * kind, whether express or implied.
11  */
12
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/delay.h>
16 #include <linux/mii.h>
17 #include <linux/ethtool.h>
18 #include <linux/phy.h>
19 #include <linux/mdio.h>
20
21 #define PHY_ID_AQ1202   0x03a1b445
22 #define PHY_ID_AQ2104   0x03a1b460
23 #define PHY_ID_AQR105   0x03a1b4a2
24 #define PHY_ID_AQR106   0x03a1b4d0
25 #define PHY_ID_AQR107   0x03a1b4e0
26 #define PHY_ID_AQR405   0x03a1b4b0
27
28 static int aquantia_config_aneg(struct phy_device *phydev)
29 {
30         linkmode_copy(phydev->supported, phy_10gbit_features);
31         linkmode_copy(phydev->advertising, phydev->supported);
32
33         return 0;
34 }
35
36 static int aquantia_config_intr(struct phy_device *phydev)
37 {
38         int err;
39
40         if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
41                 err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1);
42                 if (err < 0)
43                         return err;
44
45                 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1);
46                 if (err < 0)
47                         return err;
48
49                 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001);
50         } else {
51                 err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0);
52                 if (err < 0)
53                         return err;
54
55                 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0);
56                 if (err < 0)
57                         return err;
58
59                 err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0);
60         }
61
62         return err;
63 }
64
65 static int aquantia_ack_interrupt(struct phy_device *phydev)
66 {
67         int reg;
68
69         reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01);
70         return (reg < 0) ? reg : 0;
71 }
72
73 static int aquantia_read_status(struct phy_device *phydev)
74 {
75         int reg;
76
77         reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
78         reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
79         if (reg & MDIO_STAT1_LSTATUS)
80                 phydev->link = 1;
81         else
82                 phydev->link = 0;
83
84         reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
85         mdelay(10);
86         reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
87
88         switch (reg) {
89         case 0x9:
90                 phydev->speed = SPEED_2500;
91                 break;
92         case 0x5:
93                 phydev->speed = SPEED_1000;
94                 break;
95         case 0x3:
96                 phydev->speed = SPEED_100;
97                 break;
98         case 0x7:
99         default:
100                 phydev->speed = SPEED_10000;
101                 break;
102         }
103         phydev->duplex = DUPLEX_FULL;
104
105         return 0;
106 }
107
108 static struct phy_driver aquantia_driver[] = {
109 {
110         .phy_id         = PHY_ID_AQ1202,
111         .phy_id_mask    = 0xfffffff0,
112         .name           = "Aquantia AQ1202",
113         .features       = PHY_10GBIT_FULL_FEATURES,
114         .aneg_done      = genphy_c45_aneg_done,
115         .config_aneg    = aquantia_config_aneg,
116         .config_intr    = aquantia_config_intr,
117         .ack_interrupt  = aquantia_ack_interrupt,
118         .read_status    = aquantia_read_status,
119 },
120 {
121         .phy_id         = PHY_ID_AQ2104,
122         .phy_id_mask    = 0xfffffff0,
123         .name           = "Aquantia AQ2104",
124         .features       = PHY_10GBIT_FULL_FEATURES,
125         .aneg_done      = genphy_c45_aneg_done,
126         .config_aneg    = aquantia_config_aneg,
127         .config_intr    = aquantia_config_intr,
128         .ack_interrupt  = aquantia_ack_interrupt,
129         .read_status    = aquantia_read_status,
130 },
131 {
132         .phy_id         = PHY_ID_AQR105,
133         .phy_id_mask    = 0xfffffff0,
134         .name           = "Aquantia AQR105",
135         .features       = PHY_10GBIT_FULL_FEATURES,
136         .aneg_done      = genphy_c45_aneg_done,
137         .config_aneg    = aquantia_config_aneg,
138         .config_intr    = aquantia_config_intr,
139         .ack_interrupt  = aquantia_ack_interrupt,
140         .read_status    = aquantia_read_status,
141 },
142 {
143         .phy_id         = PHY_ID_AQR106,
144         .phy_id_mask    = 0xfffffff0,
145         .name           = "Aquantia AQR106",
146         .features       = PHY_10GBIT_FULL_FEATURES,
147         .aneg_done      = genphy_c45_aneg_done,
148         .config_aneg    = aquantia_config_aneg,
149         .config_intr    = aquantia_config_intr,
150         .ack_interrupt  = aquantia_ack_interrupt,
151         .read_status    = aquantia_read_status,
152 },
153 {
154         .phy_id         = PHY_ID_AQR107,
155         .phy_id_mask    = 0xfffffff0,
156         .name           = "Aquantia AQR107",
157         .features       = PHY_10GBIT_FULL_FEATURES,
158         .aneg_done      = genphy_c45_aneg_done,
159         .config_aneg    = aquantia_config_aneg,
160         .config_intr    = aquantia_config_intr,
161         .ack_interrupt  = aquantia_ack_interrupt,
162         .read_status    = aquantia_read_status,
163 },
164 {
165         .phy_id         = PHY_ID_AQR405,
166         .phy_id_mask    = 0xfffffff0,
167         .name           = "Aquantia AQR405",
168         .features       = PHY_10GBIT_FULL_FEATURES,
169         .aneg_done      = genphy_c45_aneg_done,
170         .config_aneg    = aquantia_config_aneg,
171         .config_intr    = aquantia_config_intr,
172         .ack_interrupt  = aquantia_ack_interrupt,
173         .read_status    = aquantia_read_status,
174 },
175 };
176
177 module_phy_driver(aquantia_driver);
178
179 static struct mdio_device_id __maybe_unused aquantia_tbl[] = {
180         { PHY_ID_AQ1202, 0xfffffff0 },
181         { PHY_ID_AQ2104, 0xfffffff0 },
182         { PHY_ID_AQR105, 0xfffffff0 },
183         { PHY_ID_AQR106, 0xfffffff0 },
184         { PHY_ID_AQR107, 0xfffffff0 },
185         { PHY_ID_AQR405, 0xfffffff0 },
186         { }
187 };
188
189 MODULE_DEVICE_TABLE(mdio, aquantia_tbl);
190
191 MODULE_DESCRIPTION("Aquantia PHY driver");
192 MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>");
193 MODULE_LICENSE("GPL v2");