aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/coldfire/files-2.6.31/drivers/net/phy/broadcom522x.c
blob: f20a519e5d77e17817a8d48a9ec9de858cfbcd7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
 *Copyright (C) 2009 Freescale Semiconductor, Inc. All rights reserved.
 *	Chenghu Wu <b16972@freescale.com>
 *
 * Driver for broadcom PHYs 522x
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/netdevice.h>

/* DP83865 phy identifier values */
#define BCM5222_PHY_ID	0x00406320

/* PHY Register */
#define BCM5222_TIMEOUT                 0x100

/* MII Registers */
#define BCM5222_CTRL                    0x00
#define BCM5222_STATUS                  0x01
#define BCM5222_ID_HIGH                 0x02
#define BCM5222_ID_LOW                  0x03
#define BCM5222_AN_ADV                  0x04
#define BCM5222_AN_LP                   0x05
#define BCM5222_AN_EXP                  0x06
#define BCM5222_AN_NEXTPG               0x07
#define BCM5222_AN_LP_NPTX              0x08
#define BCM5222_AUX_CS                  0x18
#define BCM5222_AUX_STATUS              0x19

/* CONTROL Bits */
#define BCM5222_CTRL_RESET              0x8000
#define BCM5222_CTRL_LOOPBACK           0x4000
#define BCM5222_CTRL_FORCE              0x2000
#define BCM5222_CTRL_AUTOEN             0x1000
#define BCM5222_CTRL_PWRDN              0x0800
#define BCM5222_CTRL_ISOLATE            0x0400
#define BCM5222_CTRL_RESTART            0x0200
#define BCM5222_CTRL_DUPLEX             0x0100
#define BCM5222_CTRL_COLLEN             0x0080

/* STATUS Bits */
#define BCM5222_STATUS_100T4            0x8000
#define BCM5222_STATUS_100TXFDX         0x4000
#define BCM5222_STATUS_100TX            0x2000
#define BCM5222_STATUS_10FDX            0x1000
#define BCM5222_STATUS_10               0x0800
#define BCM5222_STATUS_MF_PREAMBLE      0x0040
#define BCM5222_STATUS_AN_COMPLETE      0x0020
#define BCM5222_STATUS_REMOTE_FAULT     0x0010
#define BCM5222_STATUS_AN_CAPABLE       0x0008
#define BCM5222_STATUS_LINK             0x0004
#define BCM5222_STATUS_JABBER           0x0002
#define BCM5222_STATUS_EXT_CAP          0x0001

/* ID Values */
#define BCM5222_ID_HIGH_VAL             0x0040
#define BCM5222_ID_LOW_VAL              0x6320

/* Advertise Bits */
#define BCM5222_AN_ADV_NEXTPG           0x8000
#define BCM5222_AN_ADV_REMOTE_FAULT     0x2000
#define BCM5222_AN_ADV_PAUSE            0x0400
#define BCM5222_AN_ADV_100T4            0x0200
#define BCM5222_AN_ADV_100TXFDX         0x0100
#define BCM5222_AN_ADV_100TX            0x0080
#define BCM5222_AN_ADV_10FDX            0x0040
#define BCM5222_AN_ADV_10               0x0020
#define BCM5222_AN_ADV_8023             0x0001
#define BCM5222_AN_ADV_ALL              \
	(BCM5222_AN_ADV_100TXFDX | \
	BCM5222_AN_ADV_100TXFDX | \
	BCM5222_AN_ADV_100TX | \
	BCM5222_AN_ADV_10FDX | \
	BCM5222_AN_ADV_10 |    \
	BCM5222_AN_ADV_8023)

/* AUX CTRL/STATUS Bits */
#define BCM5222_AUX_CS_JABBER_DIS       0x8000
#define BCM5222_AUX_CS_FORCE_LINK       0x4000
#define BCM5222_AUX_CS_10M_TX_PWR       0x0100
#define BCM5222_AUX_CS_HSQ_LSQ_MASK     0x00c0
#define BCM5222_AUX_CS_EDGE_RATE_MASK   0x0030
#define BCM5222_AUX_CS_AN_IND           0x0008
#define BCM5222_AUX_CS_SPEED_FORCE      0x0004
#define BCM5222_AUX_CS_SPEED            0x0002
#define BCM5222_AUX_CS_DUPLEX           0x0001

/* AUX STATUS Bits */
#define BCM5222_AUX_STATUS_AN_COMP      0x8000
#define BCM5222_AUX_STATUS_AN_COMPACK   0x4000
#define BCM5222_AUX_STATUS_AN_ACKDET    0x2000
#define BCM5222_AUX_STATUS_AN_ABDET     0x1000
#define BCM5222_AUX_STATUS_AN_PAUSE     0x0800
#define BCM5222_AUX_STATUS_AN_HCDMASK   0x0700
#define BCM5222_AUX_STATUS_AN_PDFAULT   0x0080
#define BCM5222_AUX_STATUS_LP_RMTFAULT  0x0040
#define BCM5222_AUX_STATUS_LP_PGRX      0x0020
#define BCM5222_AUX_STATUS_LP_NEGABLE   0x0010
#define BCM5222_AUX_STATUS_SPEED        0x0008
#define BCM5222_AUX_STATUS_LINK         0x0004
#define BCM5222_AUX_STATUS_AN_EN        0x0002
#define BCM5222_AUX_STATUS_JABBER       0x0001

static int bcm5222_config_intr(struct phy_device *phydev)
{
	int err = 0;
	printk(KERN_INFO "%s PHY_INTERRUPT %x\n",
			__func__, phydev->interrupts);

	return err;
}

static int bcm5222_ack_interrupt(struct phy_device *phydev)
{
	return 0;
}

static int bcm5222_config_init(struct phy_device *phydev)
{
	return  bcm5222_ack_interrupt(phydev);
}

static int bcm5222_config_init_old(struct phy_device *phydev)
{
	int timeout;
	int flag = 1;
	int ret = phy_read(phydev, BCM5222_AUX_STATUS);
	if (ret < 0) {
		printk(KERN_INFO "%s MII_BCM5222_ISR %x\n",
			__func__, ret);
	}
	/*
	* reset
	*/
	phy_write(phydev, BCM5222_CTRL, BCM5222_CTRL_RESET);

	/* check that it cleared */
	ret = phy_read(phydev, BCM5222_CTRL);
	printk(KERN_INFO "%s BCM5222_CTRL %x\n",
		__func__, ret);
	/*if reset bit is set, return */
	if (ret & BCM5222_CTRL_RESET) {
		printk(KERN_ERR "%s %x = BCM5222_CTRL_RESET(%x)\n",
			__func__, ret, BCM5222_CTRL_RESET);
		return -ETIME;
	}

	/*
	* setup auto-negotiation
	*/

	/* disable */
	phy_write(phydev, BCM5222_CTRL, 0);
	ret = phy_read(phydev, BCM5222_CTRL);
	printk(KERN_INFO "%s BCM5222_CTRL %x\n",
		__func__, ret);
	/* set the auto-negotiation advertisement register */
	phy_write(phydev, BCM5222_AN_ADV, BCM5222_AN_ADV_ALL);
	ret = phy_read(phydev, BCM5222_AN_ADV);
	printk(KERN_INFO "%s BCM5222_AN_ADV %x, BCM5222_AN_ADV_ALL %x\n",
		__func__, ret, BCM5222_AN_ADV_ALL);
	/* enable */
	phy_write(phydev, BCM5222_CTRL, BCM5222_CTRL_AUTOEN);
	ret = phy_read(phydev, BCM5222_CTRL);
	printk(KERN_INFO "%s BCM5222_CTRL %x\n",
			__func__, ret);
	printk(KERN_INFO "** wait for complete\n");

	/* read aux status reg */
	ret = phy_read(phydev, BCM5222_AUX_STATUS);
	/* Wait for the auto-negotiation completion */
	timeout = BCM5222_TIMEOUT;
	while (!(ret & BCM5222_AUX_STATUS_AN_COMP)) {
		if (!timeout--) {
			flag = 0;
			printk(KERN_INFO "BCM5222: TIMEOUT\n");
			break;
		}

		mdelay(10);
		/* Read PHY status register */
		ret = phy_read(phydev, BCM5222_AUX_STATUS);
	}

	ret = phy_read(phydev, BCM5222_AUX_STATUS);
	ret = phy_read(phydev, BCM5222_AN_ADV);
	return 0;
}

static int bcm5222_read_status(struct phy_device *phydev)
{
	int ret;
	ret = phy_read(phydev, BCM5222_AUX_STATUS);
	printk(KERN_INFO "%s ret %x\n", __func__, ret);

	if (ret & BCM5222_AUX_STATUS_LINK)
		phydev->link = 1;
	else
		phydev->link = 0;

	if (ret & BCM5222_AUX_STATUS_SPEED)
		phydev->speed = SPEED_100;
	else
		phydev->speed = SPEED_10;

	ret = phy_read(phydev, BCM5222_AUX_CS);
	printk(KERN_INFO "%s ret %x\n", __func__, ret);
	if (ret & BCM5222_AUX_CS_DUPLEX)
		phydev->duplex = DUPLEX_FULL;
	else
		phydev->duplex = DUPLEX_HALF;
	return 0;
}

static int bcm5222_config_aneg(struct phy_device *phydev)
{
	phy_read(phydev, BCM5222_AUX_STATUS);
	phy_read(phydev, BCM5222_AN_ADV);
	return 0;
}

static struct phy_driver bcm5222_driver = {
	.phy_id = BCM5222_PHY_ID,
	.phy_id_mask = 0xfffffff0,
	.name = "Broadcom BCM5222",
	.features = PHY_BASIC_FEATURES,
	.flags = PHY_HAS_INTERRUPT,
	.config_init = bcm5222_config_init,
	.config_aneg = genphy_config_aneg,
	.read_status = genphy_read_status,
	.ack_interrupt = bcm5222_ack_interrupt,
	.config_intr = bcm5222_config_intr,
	.driver = {.owner = THIS_MODULE,}
};

static int __init bcm5222_init(void)
{
	int ret;

	ret = phy_driver_register(&bcm5222_driver);
	if (ret)
		goto err1;

	return 0;
err1:
	printk(KERN_INFO "register bcm5222 PHY driver fail\n");
	return ret;
}

static void __exit bcm5222_exit(void)
{
	phy_driver_unregister(&bcm5222_driver);
}

MODULE_DESCRIPTION("Broadcom PHY driver");
MODULE_LICENSE("GPL v2");

module_init(bcm5222_init);
module_exit(bcm5222_exit);