Blame view

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