• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-WNDR4500-V1.0.1.40_1.0.68/src/linux/linux-2.6/arch/powerpc/platforms/pasemi/
1/*
2 * Copyright (C) 2006-2007 PA Semi, Inc
3 *
4 * Author: Olof Johansson, PA Semi
5 *
6 * Maintained by: Olof Johansson <olof@lixom.net>
7 *
8 * Based on drivers/net/fs_enet/mii-bitbang.c.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
22 */
23
24#include <linux/io.h>
25#include <linux/module.h>
26#include <linux/types.h>
27#include <linux/sched.h>
28#include <linux/errno.h>
29#include <linux/ioport.h>
30#include <linux/interrupt.h>
31#include <linux/phy.h>
32#include <linux/platform_device.h>
33#include <asm/of_platform.h>
34
35#define DELAY 1
36
37static void __iomem *gpio_regs;
38
39struct gpio_priv {
40	int mdc_pin;
41	int mdio_pin;
42};
43
44#define MDC_PIN(bus)	(((struct gpio_priv *)bus->priv)->mdc_pin)
45#define MDIO_PIN(bus)	(((struct gpio_priv *)bus->priv)->mdio_pin)
46
47static inline void mdio_lo(struct mii_bus *bus)
48{
49	out_le32(gpio_regs+0x10, 1 << MDIO_PIN(bus));
50}
51
52static inline void mdio_hi(struct mii_bus *bus)
53{
54	out_le32(gpio_regs, 1 << MDIO_PIN(bus));
55}
56
57static inline void mdc_lo(struct mii_bus *bus)
58{
59	out_le32(gpio_regs+0x10, 1 << MDC_PIN(bus));
60}
61
62static inline void mdc_hi(struct mii_bus *bus)
63{
64	out_le32(gpio_regs, 1 << MDC_PIN(bus));
65}
66
67static inline void mdio_active(struct mii_bus *bus)
68{
69	out_le32(gpio_regs+0x20, (1 << MDC_PIN(bus)) | (1 << MDIO_PIN(bus)));
70}
71
72static inline void mdio_tristate(struct mii_bus *bus)
73{
74	out_le32(gpio_regs+0x30, (1 << MDIO_PIN(bus)));
75}
76
77static inline int mdio_read(struct mii_bus *bus)
78{
79	return !!(in_le32(gpio_regs+0x40) & (1 << MDIO_PIN(bus)));
80}
81
82static void clock_out(struct mii_bus *bus, int bit)
83{
84	if (bit)
85		mdio_hi(bus);
86	else
87		mdio_lo(bus);
88	udelay(DELAY);
89	mdc_hi(bus);
90	udelay(DELAY);
91	mdc_lo(bus);
92}
93
94/* Utility to send the preamble, address, and register (common to read and write). */
95static void bitbang_pre(struct mii_bus *bus, int read, u8 addr, u8 reg)
96{
97	int i;
98
99	/* CFE uses a really long preamble (40 bits). We'll do the same. */
100	mdio_active(bus);
101	for (i = 0; i < 40; i++) {
102		clock_out(bus, 1);
103	}
104
105	/* send the start bit (01) and the read opcode (10) or write (10) */
106	clock_out(bus, 0);
107	clock_out(bus, 1);
108
109	clock_out(bus, read);
110	clock_out(bus, !read);
111
112	/* send the PHY address */
113	for (i = 0; i < 5; i++) {
114		clock_out(bus, (addr & 0x10) != 0);
115		addr <<= 1;
116	}
117
118	/* send the register address */
119	for (i = 0; i < 5; i++) {
120		clock_out(bus, (reg & 0x10) != 0);
121		reg <<= 1;
122	}
123}
124
125static int gpio_mdio_read(struct mii_bus *bus, int phy_id, int location)
126{
127	u16 rdreg;
128	int ret, i;
129	u8 addr = phy_id & 0xff;
130	u8 reg = location & 0xff;
131
132	bitbang_pre(bus, 1, addr, reg);
133
134	/* tri-state our MDIO I/O pin so we can read */
135	mdio_tristate(bus);
136	udelay(DELAY);
137	mdc_hi(bus);
138	udelay(DELAY);
139	mdc_lo(bus);
140
141	/* read 16 bits of register data, MSB first */
142	rdreg = 0;
143	for (i = 0; i < 16; i++) {
144		mdc_lo(bus);
145		udelay(DELAY);
146		mdc_hi(bus);
147		udelay(DELAY);
148		mdc_lo(bus);
149		udelay(DELAY);
150		rdreg <<= 1;
151		rdreg |= mdio_read(bus);
152	}
153
154	mdc_hi(bus);
155	udelay(DELAY);
156	mdc_lo(bus);
157	udelay(DELAY);
158
159	ret = rdreg;
160
161	return ret;
162}
163
164static int gpio_mdio_write(struct mii_bus *bus, int phy_id, int location, u16 val)
165{
166	int i;
167
168	u8 addr = phy_id & 0xff;
169	u8 reg = location & 0xff;
170	u16 value = val & 0xffff;
171
172	bitbang_pre(bus, 0, addr, reg);
173
174	/* send the turnaround (10) */
175	mdc_lo(bus);
176	mdio_hi(bus);
177	udelay(DELAY);
178	mdc_hi(bus);
179	udelay(DELAY);
180	mdc_lo(bus);
181	mdio_lo(bus);
182	udelay(DELAY);
183	mdc_hi(bus);
184	udelay(DELAY);
185
186	/* write 16 bits of register data, MSB first */
187	for (i = 0; i < 16; i++) {
188		mdc_lo(bus);
189		if (value & 0x8000)
190			mdio_hi(bus);
191		else
192			mdio_lo(bus);
193		udelay(DELAY);
194		mdc_hi(bus);
195		udelay(DELAY);
196		value <<= 1;
197	}
198
199	/*
200	 * Tri-state the MDIO line.
201	 */
202	mdio_tristate(bus);
203	mdc_lo(bus);
204	udelay(DELAY);
205	mdc_hi(bus);
206	udelay(DELAY);
207	return 0;
208}
209
210static int gpio_mdio_reset(struct mii_bus *bus)
211{
212	/*nothing here - dunno how to reset it*/
213	return 0;
214}
215
216
217static int __devinit gpio_mdio_probe(struct of_device *ofdev,
218				     const struct of_device_id *match)
219{
220	struct device *dev = &ofdev->dev;
221	struct device_node *np = ofdev->node;
222	struct device_node *gpio_np;
223	struct mii_bus *new_bus;
224	struct resource res;
225	struct gpio_priv *priv;
226	const unsigned int *prop;
227	int err = 0;
228	int i;
229
230	gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio");
231
232	if (!gpio_np)
233		return -ENODEV;
234
235	err = of_address_to_resource(gpio_np, 0, &res);
236	of_node_put(gpio_np);
237
238	if (err)
239		return -EINVAL;
240
241	if (!gpio_regs)
242		gpio_regs = ioremap(res.start, 0x100);
243
244	if (!gpio_regs)
245		return -EPERM;
246
247	priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL);
248	if (priv == NULL)
249		return -ENOMEM;
250
251	new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
252
253	if (new_bus == NULL)
254		return -ENOMEM;
255
256	new_bus->name = "pasemi gpio mdio bus",
257	new_bus->read = &gpio_mdio_read,
258	new_bus->write = &gpio_mdio_write,
259	new_bus->reset = &gpio_mdio_reset,
260
261	prop = of_get_property(np, "reg", NULL);
262	new_bus->id = *prop;
263	new_bus->priv = priv;
264
265	new_bus->phy_mask = 0;
266
267	new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
268	for(i = 0; i < PHY_MAX_ADDR; ++i)
269		new_bus->irq[i] = irq_create_mapping(NULL, 10);
270
271
272	prop = of_get_property(np, "mdc-pin", NULL);
273	priv->mdc_pin = *prop;
274
275	prop = of_get_property(np, "mdio-pin", NULL);
276	priv->mdio_pin = *prop;
277
278	new_bus->dev = dev;
279	dev_set_drvdata(dev, new_bus);
280
281	err = mdiobus_register(new_bus);
282
283	if (0 != err) {
284		printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n",
285				new_bus->name, err);
286		goto bus_register_fail;
287	}
288
289	return 0;
290
291bus_register_fail:
292	kfree(new_bus);
293
294	return err;
295}
296
297
298static int gpio_mdio_remove(struct of_device *dev)
299{
300	struct mii_bus *bus = dev_get_drvdata(&dev->dev);
301
302	mdiobus_unregister(bus);
303
304	dev_set_drvdata(&dev->dev, NULL);
305
306	kfree(bus->priv);
307	bus->priv = NULL;
308	kfree(bus);
309
310	return 0;
311}
312
313static struct of_device_id gpio_mdio_match[] =
314{
315	{
316		.compatible      = "gpio-mdio",
317	},
318	{},
319};
320
321static struct of_platform_driver gpio_mdio_driver =
322{
323	.name		= "gpio-mdio-bitbang",
324	.match_table	= gpio_mdio_match,
325	.probe		= gpio_mdio_probe,
326	.remove		= gpio_mdio_remove,
327};
328
329int gpio_mdio_init(void)
330{
331	return of_register_platform_driver(&gpio_mdio_driver);
332}
333
334void gpio_mdio_exit(void)
335{
336	of_unregister_platform_driver(&gpio_mdio_driver);
337}
338device_initcall(gpio_mdio_init);
339