2 * Bitbanged MDIO support.
4 * Author: Scott Wood <scottwood@freescale.com>
5 * Copyright (c) 2007 Freescale Semiconductor
7 * Based on CPM2 MDIO code which is:
9 * Copyright (c) 2003 Intracom S.A.
10 * by Pantelis Antoniou <panto@intracom.gr>
12 * 2005 (c) MontaVista Software, Inc.
13 * Vitaly Bordug <vbordug@ru.mvista.com>
15 * This file is licensed under the terms of the GNU General Public License
16 * version 2. This program is licensed "as is" without any warranty of any
17 * kind, whether express or implied.
20 #include <linux/module.h>
21 #include <linux/mdio-bitbang.h>
22 #include <linux/slab.h>
23 #include <linux/types.h>
24 #include <linux/delay.h>
29 #define MDIO_SETUP_TIME 10
30 #define MDIO_HOLD_TIME 10
32 /* Minimum MDC period is 400 ns, plus some margin for error. MDIO_DELAY
33 * is done twice per period.
35 #define MDIO_DELAY 250
37 /* The PHY may take up to 300 ns to produce data, plus some margin
40 #define MDIO_READ_DELAY 350
42 /* MDIO must already be configured as output. */
43 static void mdiobb_send_bit(struct mdiobb_ctrl
*ctrl
, int val
)
45 const struct mdiobb_ops
*ops
= ctrl
->ops
;
47 ops
->set_mdio_data(ctrl
, val
);
49 ops
->set_mdc(ctrl
, 1);
51 ops
->set_mdc(ctrl
, 0);
54 /* MDIO must already be configured as input. */
55 static int mdiobb_get_bit(struct mdiobb_ctrl
*ctrl
)
57 const struct mdiobb_ops
*ops
= ctrl
->ops
;
60 ops
->set_mdc(ctrl
, 1);
61 ndelay(MDIO_READ_DELAY
);
62 ops
->set_mdc(ctrl
, 0);
64 return ops
->get_mdio_data(ctrl
);
67 /* MDIO must already be configured as output. */
68 static void mdiobb_send_num(struct mdiobb_ctrl
*ctrl
, u16 val
, int bits
)
72 for (i
= bits
- 1; i
>= 0; i
--)
73 mdiobb_send_bit(ctrl
, (val
>> i
) & 1);
76 /* MDIO must already be configured as input. */
77 static u16
mdiobb_get_num(struct mdiobb_ctrl
*ctrl
, int bits
)
82 for (i
= bits
- 1; i
>= 0; i
--) {
84 ret
|= mdiobb_get_bit(ctrl
);
90 /* Utility to send the preamble, address, and
91 * register (common to read and write).
93 static void mdiobb_cmd(struct mdiobb_ctrl
*ctrl
, int read
, u8 phy
, u8 reg
)
95 const struct mdiobb_ops
*ops
= ctrl
->ops
;
98 ops
->set_mdio_dir(ctrl
, 1);
101 * Send a 32 bit preamble ('1's) with an extra '1' bit for good
102 * measure. The IEEE spec says this is a PHY optional
103 * requirement. The AMD 79C874 requires one after power up and
104 * one after a MII communications error. This means that we are
105 * doing more preambles than we need, but it is safer and will be
109 for (i
= 0; i
< 32; i
++)
110 mdiobb_send_bit(ctrl
, 1);
112 /* send the start bit (01) and the read opcode (10) or write (10) */
113 mdiobb_send_bit(ctrl
, 0);
114 mdiobb_send_bit(ctrl
, 1);
115 mdiobb_send_bit(ctrl
, read
);
116 mdiobb_send_bit(ctrl
, !read
);
118 mdiobb_send_num(ctrl
, phy
, 5);
119 mdiobb_send_num(ctrl
, reg
, 5);
123 static int mdiobb_read(struct mii_bus
*bus
, int phy
, int reg
)
125 struct mdiobb_ctrl
*ctrl
= bus
->priv
;
128 mdiobb_cmd(ctrl
, MDIO_READ
, phy
, reg
);
129 ctrl
->ops
->set_mdio_dir(ctrl
, 0);
131 /* check the turnaround bit: the PHY should be driving it to zero */
132 if (mdiobb_get_bit(ctrl
) != 0) {
133 /* PHY didn't drive TA low -- flush any bits it
134 * may be trying to send.
136 for (i
= 0; i
< 32; i
++)
137 mdiobb_get_bit(ctrl
);
142 ret
= mdiobb_get_num(ctrl
, 16);
143 mdiobb_get_bit(ctrl
);
147 static int mdiobb_write(struct mii_bus
*bus
, int phy
, int reg
, u16 val
)
149 struct mdiobb_ctrl
*ctrl
= bus
->priv
;
151 mdiobb_cmd(ctrl
, MDIO_WRITE
, phy
, reg
);
153 /* send the turnaround (10) */
154 mdiobb_send_bit(ctrl
, 1);
155 mdiobb_send_bit(ctrl
, 0);
157 mdiobb_send_num(ctrl
, val
, 16);
159 ctrl
->ops
->set_mdio_dir(ctrl
, 0);
160 mdiobb_get_bit(ctrl
);
164 struct mii_bus
*alloc_mdio_bitbang(struct mdiobb_ctrl
*ctrl
)
168 bus
= mdiobus_alloc();
172 __module_get(ctrl
->ops
->owner
);
174 bus
->read
= mdiobb_read
;
175 bus
->write
= mdiobb_write
;
180 EXPORT_SYMBOL(alloc_mdio_bitbang
);
182 void free_mdio_bitbang(struct mii_bus
*bus
)
184 struct mdiobb_ctrl
*ctrl
= bus
->priv
;
186 module_put(ctrl
->ops
->owner
);
189 EXPORT_SYMBOL(free_mdio_bitbang
);
191 MODULE_LICENSE("GPL");