Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
net
phy
mdio-mux.c
Go to the documentation of this file.
1
/*
2
* This file is subject to the terms and conditions of the GNU General Public
3
* License. See the file "COPYING" in the main directory of this archive
4
* for more details.
5
*
6
* Copyright (C) 2011, 2012 Cavium, Inc.
7
*/
8
9
#include <
linux/platform_device.h
>
10
#include <
linux/mdio-mux.h
>
11
#include <
linux/of_mdio.h
>
12
#include <linux/device.h>
13
#include <linux/module.h>
14
#include <
linux/phy.h
>
15
16
#define DRV_VERSION "1.0"
17
#define DRV_DESCRIPTION "MDIO bus multiplexer driver"
18
19
struct
mdio_mux_child_bus
;
20
21
struct
mdio_mux_parent_bus
{
22
struct
mii_bus
*
mii_bus
;
23
int
current_child
;
24
int
parent_id
;
25
void
*
switch_data
;
26
int
(*
switch_fn
)(
int
current_child
,
int
desired_child,
void
*
data
);
27
28
/* List of our children linked through their next fields. */
29
struct
mdio_mux_child_bus
*
children
;
30
};
31
32
struct
mdio_mux_child_bus
{
33
struct
mii_bus
*
mii_bus
;
34
struct
mdio_mux_parent_bus
*
parent
;
35
struct
mdio_mux_child_bus
*
next
;
36
int
bus_number
;
37
int
phy_irq
[
PHY_MAX_ADDR
];
38
};
39
40
/*
41
* The parent bus' lock is used to order access to the switch_fn.
42
*/
43
static
int
mdio_mux_read(
struct
mii_bus
*
bus
,
int
phy_id
,
int
regnum)
44
{
45
struct
mdio_mux_child_bus
*
cb
= bus->
priv
;
46
struct
mdio_mux_parent_bus
*pb = cb->
parent
;
47
int
r
;
48
49
/* In theory multiple mdio_mux could be stacked, thus creating
50
* more than a single level of nesting. But in practice,
51
* SINGLE_DEPTH_NESTING will cover the vast majority of use
52
* cases. We use it, instead of trying to handle the general
53
* case.
54
*/
55
mutex_lock_nested
(&pb->
mii_bus
->mdio_lock,
SINGLE_DEPTH_NESTING
);
56
r = pb->
switch_fn
(pb->
current_child
, cb->
bus_number
, pb->
switch_data
);
57
if
(r)
58
goto
out
;
59
60
pb->
current_child
= cb->
bus_number
;
61
62
r = pb->
mii_bus
->read(pb->
mii_bus
, phy_id, regnum);
63
out
:
64
mutex_unlock
(&pb->
mii_bus
->mdio_lock);
65
66
return
r
;
67
}
68
69
/*
70
* The parent bus' lock is used to order access to the switch_fn.
71
*/
72
static
int
mdio_mux_write(
struct
mii_bus
*
bus
,
int
phy_id
,
73
int
regnum,
u16
val
)
74
{
75
struct
mdio_mux_child_bus
*
cb
= bus->
priv
;
76
struct
mdio_mux_parent_bus
*pb = cb->
parent
;
77
78
int
r
;
79
80
mutex_lock_nested
(&pb->
mii_bus
->mdio_lock,
SINGLE_DEPTH_NESTING
);
81
r = pb->
switch_fn
(pb->
current_child
, cb->
bus_number
, pb->
switch_data
);
82
if
(r)
83
goto
out
;
84
85
pb->
current_child
= cb->
bus_number
;
86
87
r = pb->
mii_bus
->write(pb->
mii_bus
, phy_id, regnum, val);
88
out
:
89
mutex_unlock
(&pb->
mii_bus
->mdio_lock);
90
91
return
r
;
92
}
93
94
static
int
parent_count;
95
96
int
mdio_mux_init
(
struct
device
*
dev
,
97
int
(*
switch_fn
)(
int
cur
,
int
desired,
void
*
data
),
98
void
**mux_handle,
99
void
*data)
100
{
101
struct
device_node
*parent_bus_node;
102
struct
device_node
*child_bus_node;
103
int
r
, ret_val;
104
struct
mii_bus
*parent_bus;
105
struct
mdio_mux_parent_bus
*pb;
106
struct
mdio_mux_child_bus
*cb;
107
108
if
(!dev->
of_node
)
109
return
-
ENODEV
;
110
111
parent_bus_node =
of_parse_phandle
(dev->
of_node
,
"mdio-parent-bus"
, 0);
112
113
if
(!parent_bus_node)
114
return
-
ENODEV
;
115
116
parent_bus = of_mdio_find_bus(parent_bus_node);
117
if
(parent_bus ==
NULL
) {
118
ret_val = -
EPROBE_DEFER
;
119
goto
err_parent_bus;
120
}
121
122
pb =
devm_kzalloc
(dev,
sizeof
(*pb),
GFP_KERNEL
);
123
if
(pb ==
NULL
) {
124
ret_val = -
ENOMEM
;
125
goto
err_parent_bus;
126
}
127
128
pb->
switch_data
=
data
;
129
pb->
switch_fn
= switch_fn;
130
pb->
current_child
= -1;
131
pb->
parent_id
= parent_count++;
132
pb->
mii_bus
= parent_bus;
133
134
ret_val = -
ENODEV
;
135
for_each_available_child_of_node(dev->
of_node
, child_bus_node) {
136
u32
v
;
137
138
r = of_property_read_u32(child_bus_node,
"reg"
, &v);
139
if
(r)
140
continue
;
141
142
cb =
devm_kzalloc
(dev,
sizeof
(*cb),
GFP_KERNEL
);
143
if
(cb ==
NULL
) {
144
dev_err
(dev,
145
"Error: Failed to allocate memory for child\n"
);
146
ret_val = -
ENOMEM
;
147
break
;
148
}
149
cb->
bus_number
=
v
;
150
cb->
parent
= pb;
151
cb->
mii_bus
= mdiobus_alloc();
152
cb->
mii_bus
->priv = cb;
153
154
cb->
mii_bus
->irq = cb->
phy_irq
;
155
cb->
mii_bus
->name =
"mdio_mux"
;
156
snprintf
(cb->
mii_bus
->id,
MII_BUS_ID_SIZE
,
"%x.%x"
,
157
pb->
parent_id
, v);
158
cb->
mii_bus
->parent =
dev
;
159
cb->
mii_bus
->read = mdio_mux_read;
160
cb->
mii_bus
->write = mdio_mux_write;
161
r =
of_mdiobus_register
(cb->
mii_bus
, child_bus_node);
162
if
(r) {
163
mdiobus_free
(cb->
mii_bus
);
164
devm_kfree
(dev, cb);
165
}
else
{
166
of_node_get(child_bus_node);
167
cb->
next
= pb->
children
;
168
pb->
children
= cb;
169
}
170
}
171
if
(pb->
children
) {
172
*mux_handle = pb;
173
dev_info
(dev,
"Version "
DRV_VERSION
"\n"
);
174
return
0;
175
}
176
err_parent_bus:
177
of_node_put(parent_bus_node);
178
return
ret_val;
179
}
180
EXPORT_SYMBOL_GPL
(
mdio_mux_init
);
181
182
void
mdio_mux_uninit
(
void
*mux_handle)
183
{
184
struct
mdio_mux_parent_bus
*pb = mux_handle;
185
struct
mdio_mux_child_bus
*cb = pb->
children
;
186
187
while
(cb) {
188
mdiobus_unregister
(cb->
mii_bus
);
189
mdiobus_free
(cb->
mii_bus
);
190
cb = cb->
next
;
191
}
192
}
193
EXPORT_SYMBOL_GPL
(
mdio_mux_uninit
);
194
195
MODULE_DESCRIPTION
(
DRV_DESCRIPTION
);
196
MODULE_VERSION
(
DRV_VERSION
);
197
MODULE_AUTHOR
(
"David Daney"
);
198
MODULE_LICENSE
(
"GPL"
);
Generated on Thu Jan 10 2013 14:07:10 for Linux Kernel by
1.8.2