diff options
author | David S. Miller <davem@davemloft.net> | 2015-08-31 17:48:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-08-31 17:48:03 -0400 |
commit | 684511ac2eeb015b7a9a46c575543566e1b1fb7c (patch) | |
tree | e755ec8c049139469d67a5f239002ec68c743113 /drivers/net/phy/fixed_phy.c | |
parent | 6ea3c9d5b042edf14eac1e21af21c41f81f3491e (diff) | |
parent | bc0f4a87fc7e45642455682f281de2131cde9695 (diff) |
Merge branch 'dsa-port-config'
Andrew Lunn says:
====================
DSA port configuration and status
This patchset allows various switch port settings to be configured and
port status to be sampled. Some of these patches have been posted
before.
The first three patches provide infrastructure for configuring a
switch ports link speed and duplex from a fixed_link phy.
Patch four then uses this infrastructure to allow the CPU and DSA
ports of a switch to be configured using a fixed-link property in the
device tree.
Patches five and six allow a phy-mode property to be specified in the
device tree, and allow this to be used for configuring RGMII delays.
Patches seven through nine allow link status, for example that of an
SFP module, to be read from a gpio.
Changes since v1:
Rewrite 9/9 so that it hopefully does not regression on
868a4215be9a6d80 ("net: phy: fixed_phy: handle link-down case")
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy/fixed_phy.c')
-rw-r--r-- | drivers/net/phy/fixed_phy.c | 110 |
1 files changed, 83 insertions, 27 deletions
diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 99d9bc19c94a..12c7eb2c604e 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/err.h> | 22 | #include <linux/err.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/of.h> | 24 | #include <linux/of.h> |
25 | #include <linux/gpio.h> | ||
25 | 26 | ||
26 | #define MII_REGS_NUM 29 | 27 | #define MII_REGS_NUM 29 |
27 | 28 | ||
@@ -38,6 +39,7 @@ struct fixed_phy { | |||
38 | struct fixed_phy_status status; | 39 | struct fixed_phy_status status; |
39 | int (*link_update)(struct net_device *, struct fixed_phy_status *); | 40 | int (*link_update)(struct net_device *, struct fixed_phy_status *); |
40 | struct list_head node; | 41 | struct list_head node; |
42 | int link_gpio; | ||
41 | }; | 43 | }; |
42 | 44 | ||
43 | static struct platform_device *pdev; | 45 | static struct platform_device *pdev; |
@@ -52,61 +54,87 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) | |||
52 | u16 lpagb = 0; | 54 | u16 lpagb = 0; |
53 | u16 lpa = 0; | 55 | u16 lpa = 0; |
54 | 56 | ||
55 | if (!fp->status.link) | 57 | if (gpio_is_valid(fp->link_gpio)) |
56 | goto done; | 58 | fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio); |
57 | bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; | ||
58 | 59 | ||
59 | if (fp->status.duplex) { | 60 | if (fp->status.duplex) { |
60 | bmcr |= BMCR_FULLDPLX; | ||
61 | |||
62 | switch (fp->status.speed) { | 61 | switch (fp->status.speed) { |
63 | case 1000: | 62 | case 1000: |
64 | bmsr |= BMSR_ESTATEN; | 63 | bmsr |= BMSR_ESTATEN; |
65 | bmcr |= BMCR_SPEED1000; | ||
66 | lpagb |= LPA_1000FULL; | ||
67 | break; | 64 | break; |
68 | case 100: | 65 | case 100: |
69 | bmsr |= BMSR_100FULL; | 66 | bmsr |= BMSR_100FULL; |
70 | bmcr |= BMCR_SPEED100; | ||
71 | lpa |= LPA_100FULL; | ||
72 | break; | 67 | break; |
73 | case 10: | 68 | case 10: |
74 | bmsr |= BMSR_10FULL; | 69 | bmsr |= BMSR_10FULL; |
75 | lpa |= LPA_10FULL; | ||
76 | break; | 70 | break; |
77 | default: | 71 | default: |
78 | pr_warn("fixed phy: unknown speed\n"); | 72 | break; |
79 | return -EINVAL; | ||
80 | } | 73 | } |
81 | } else { | 74 | } else { |
82 | switch (fp->status.speed) { | 75 | switch (fp->status.speed) { |
83 | case 1000: | 76 | case 1000: |
84 | bmsr |= BMSR_ESTATEN; | 77 | bmsr |= BMSR_ESTATEN; |
85 | bmcr |= BMCR_SPEED1000; | ||
86 | lpagb |= LPA_1000HALF; | ||
87 | break; | 78 | break; |
88 | case 100: | 79 | case 100: |
89 | bmsr |= BMSR_100HALF; | 80 | bmsr |= BMSR_100HALF; |
90 | bmcr |= BMCR_SPEED100; | ||
91 | lpa |= LPA_100HALF; | ||
92 | break; | 81 | break; |
93 | case 10: | 82 | case 10: |
94 | bmsr |= BMSR_10HALF; | 83 | bmsr |= BMSR_10HALF; |
95 | lpa |= LPA_10HALF; | ||
96 | break; | 84 | break; |
97 | default: | 85 | default: |
98 | pr_warn("fixed phy: unknown speed\n"); | 86 | break; |
99 | return -EINVAL; | ||
100 | } | 87 | } |
101 | } | 88 | } |
102 | 89 | ||
103 | if (fp->status.pause) | 90 | if (fp->status.link) { |
104 | lpa |= LPA_PAUSE_CAP; | 91 | bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; |
92 | |||
93 | if (fp->status.duplex) { | ||
94 | bmcr |= BMCR_FULLDPLX; | ||
95 | |||
96 | switch (fp->status.speed) { | ||
97 | case 1000: | ||
98 | bmcr |= BMCR_SPEED1000; | ||
99 | lpagb |= LPA_1000FULL; | ||
100 | break; | ||
101 | case 100: | ||
102 | bmcr |= BMCR_SPEED100; | ||
103 | lpa |= LPA_100FULL; | ||
104 | break; | ||
105 | case 10: | ||
106 | lpa |= LPA_10FULL; | ||
107 | break; | ||
108 | default: | ||
109 | pr_warn("fixed phy: unknown speed\n"); | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | } else { | ||
113 | switch (fp->status.speed) { | ||
114 | case 1000: | ||
115 | bmcr |= BMCR_SPEED1000; | ||
116 | lpagb |= LPA_1000HALF; | ||
117 | break; | ||
118 | case 100: | ||
119 | bmcr |= BMCR_SPEED100; | ||
120 | lpa |= LPA_100HALF; | ||
121 | break; | ||
122 | case 10: | ||
123 | lpa |= LPA_10HALF; | ||
124 | break; | ||
125 | default: | ||
126 | pr_warn("fixed phy: unknown speed\n"); | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (fp->status.pause) | ||
132 | lpa |= LPA_PAUSE_CAP; | ||
105 | 133 | ||
106 | if (fp->status.asym_pause) | 134 | if (fp->status.asym_pause) |
107 | lpa |= LPA_PAUSE_ASYM; | 135 | lpa |= LPA_PAUSE_ASYM; |
136 | } | ||
108 | 137 | ||
109 | done: | ||
110 | fp->regs[MII_PHYSID1] = 0; | 138 | fp->regs[MII_PHYSID1] = 0; |
111 | fp->regs[MII_PHYSID2] = 0; | 139 | fp->regs[MII_PHYSID2] = 0; |
112 | 140 | ||
@@ -215,7 +243,8 @@ int fixed_phy_update_state(struct phy_device *phydev, | |||
215 | EXPORT_SYMBOL(fixed_phy_update_state); | 243 | EXPORT_SYMBOL(fixed_phy_update_state); |
216 | 244 | ||
217 | int fixed_phy_add(unsigned int irq, int phy_addr, | 245 | int fixed_phy_add(unsigned int irq, int phy_addr, |
218 | struct fixed_phy_status *status) | 246 | struct fixed_phy_status *status, |
247 | int link_gpio) | ||
219 | { | 248 | { |
220 | int ret; | 249 | int ret; |
221 | struct fixed_mdio_bus *fmb = &platform_fmb; | 250 | struct fixed_mdio_bus *fmb = &platform_fmb; |
@@ -231,15 +260,26 @@ int fixed_phy_add(unsigned int irq, int phy_addr, | |||
231 | 260 | ||
232 | fp->addr = phy_addr; | 261 | fp->addr = phy_addr; |
233 | fp->status = *status; | 262 | fp->status = *status; |
263 | fp->link_gpio = link_gpio; | ||
264 | |||
265 | if (gpio_is_valid(fp->link_gpio)) { | ||
266 | ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN, | ||
267 | "fixed-link-gpio-link"); | ||
268 | if (ret) | ||
269 | goto err_regs; | ||
270 | } | ||
234 | 271 | ||
235 | ret = fixed_phy_update_regs(fp); | 272 | ret = fixed_phy_update_regs(fp); |
236 | if (ret) | 273 | if (ret) |
237 | goto err_regs; | 274 | goto err_gpio; |
238 | 275 | ||
239 | list_add_tail(&fp->node, &fmb->phys); | 276 | list_add_tail(&fp->node, &fmb->phys); |
240 | 277 | ||
241 | return 0; | 278 | return 0; |
242 | 279 | ||
280 | err_gpio: | ||
281 | if (gpio_is_valid(fp->link_gpio)) | ||
282 | gpio_free(fp->link_gpio); | ||
243 | err_regs: | 283 | err_regs: |
244 | kfree(fp); | 284 | kfree(fp); |
245 | return ret; | 285 | return ret; |
@@ -254,6 +294,8 @@ void fixed_phy_del(int phy_addr) | |||
254 | list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { | 294 | list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { |
255 | if (fp->addr == phy_addr) { | 295 | if (fp->addr == phy_addr) { |
256 | list_del(&fp->node); | 296 | list_del(&fp->node); |
297 | if (gpio_is_valid(fp->link_gpio)) | ||
298 | gpio_free(fp->link_gpio); | ||
257 | kfree(fp); | 299 | kfree(fp); |
258 | return; | 300 | return; |
259 | } | 301 | } |
@@ -266,6 +308,7 @@ static DEFINE_SPINLOCK(phy_fixed_addr_lock); | |||
266 | 308 | ||
267 | struct phy_device *fixed_phy_register(unsigned int irq, | 309 | struct phy_device *fixed_phy_register(unsigned int irq, |
268 | struct fixed_phy_status *status, | 310 | struct fixed_phy_status *status, |
311 | int link_gpio, | ||
269 | struct device_node *np) | 312 | struct device_node *np) |
270 | { | 313 | { |
271 | struct fixed_mdio_bus *fmb = &platform_fmb; | 314 | struct fixed_mdio_bus *fmb = &platform_fmb; |
@@ -282,7 +325,7 @@ struct phy_device *fixed_phy_register(unsigned int irq, | |||
282 | phy_addr = phy_fixed_addr++; | 325 | phy_addr = phy_fixed_addr++; |
283 | spin_unlock(&phy_fixed_addr_lock); | 326 | spin_unlock(&phy_fixed_addr_lock); |
284 | 327 | ||
285 | ret = fixed_phy_add(PHY_POLL, phy_addr, status); | 328 | ret = fixed_phy_add(PHY_POLL, phy_addr, status, link_gpio); |
286 | if (ret < 0) | 329 | if (ret < 0) |
287 | return ERR_PTR(ret); | 330 | return ERR_PTR(ret); |
288 | 331 | ||
@@ -303,6 +346,19 @@ struct phy_device *fixed_phy_register(unsigned int irq, | |||
303 | 346 | ||
304 | of_node_get(np); | 347 | of_node_get(np); |
305 | phy->dev.of_node = np; | 348 | phy->dev.of_node = np; |
349 | phy->is_pseudo_fixed_link = true; | ||
350 | |||
351 | switch (status->speed) { | ||
352 | case SPEED_1000: | ||
353 | phy->supported = PHY_1000BT_FEATURES; | ||
354 | break; | ||
355 | case SPEED_100: | ||
356 | phy->supported = PHY_100BT_FEATURES; | ||
357 | break; | ||
358 | case SPEED_10: | ||
359 | default: | ||
360 | phy->supported = PHY_10BT_FEATURES; | ||
361 | } | ||
306 | 362 | ||
307 | ret = phy_device_register(phy); | 363 | ret = phy_device_register(phy); |
308 | if (ret) { | 364 | if (ret) { |