diff options
author | Hubert Chaumette <hchaumette@adeneo-embedded.com> | 2014-05-06 03:40:17 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-07 16:51:09 -0400 |
commit | 6e4b82730c7525504fc485b370c7f09e594e2e96 (patch) | |
tree | ade90e43e866c92f4dc09594a13115d1511c2af4 | |
parent | 4b405efbe12de28b26289282b431323d73992381 (diff) |
ARM: i.MX6: Add OF configuration support for ksz9031
Adds support for ksz9031 PAD skew configuration over devicetree.
Signed-off-by: Hubert Chaumette <hchaumette@adeneo-embedded.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/phy/micrel.c | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index d849684231c1..bc7c7d2f75f2 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c | |||
@@ -283,6 +283,110 @@ static int ksz9021_config_init(struct phy_device *phydev) | |||
283 | return 0; | 283 | return 0; |
284 | } | 284 | } |
285 | 285 | ||
286 | #define MII_KSZ9031RN_MMD_CTRL_REG 0x0d | ||
287 | #define MII_KSZ9031RN_MMD_REGDATA_REG 0x0e | ||
288 | #define OP_DATA 1 | ||
289 | #define KSZ9031_PS_TO_REG 60 | ||
290 | |||
291 | /* Extended registers */ | ||
292 | #define MII_KSZ9031RN_CONTROL_PAD_SKEW 4 | ||
293 | #define MII_KSZ9031RN_RX_DATA_PAD_SKEW 5 | ||
294 | #define MII_KSZ9031RN_TX_DATA_PAD_SKEW 6 | ||
295 | #define MII_KSZ9031RN_CLK_PAD_SKEW 8 | ||
296 | |||
297 | static int ksz9031_extended_write(struct phy_device *phydev, | ||
298 | u8 mode, u32 dev_addr, u32 regnum, u16 val) | ||
299 | { | ||
300 | phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr); | ||
301 | phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum); | ||
302 | phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr); | ||
303 | return phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, val); | ||
304 | } | ||
305 | |||
306 | static int ksz9031_extended_read(struct phy_device *phydev, | ||
307 | u8 mode, u32 dev_addr, u32 regnum) | ||
308 | { | ||
309 | phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr); | ||
310 | phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum); | ||
311 | phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr); | ||
312 | return phy_read(phydev, MII_KSZ9031RN_MMD_REGDATA_REG); | ||
313 | } | ||
314 | |||
315 | static int ksz9031_of_load_skew_values(struct phy_device *phydev, | ||
316 | struct device_node *of_node, | ||
317 | u16 reg, size_t field_sz, | ||
318 | char *field[], u8 numfields) | ||
319 | { | ||
320 | int val[4] = {-1, -2, -3, -4}; | ||
321 | int matches = 0; | ||
322 | u16 mask; | ||
323 | u16 maxval; | ||
324 | u16 newval; | ||
325 | int i; | ||
326 | |||
327 | for (i = 0; i < numfields; i++) | ||
328 | if (!of_property_read_u32(of_node, field[i], val + i)) | ||
329 | matches++; | ||
330 | |||
331 | if (!matches) | ||
332 | return 0; | ||
333 | |||
334 | if (matches < numfields) | ||
335 | newval = ksz9031_extended_read(phydev, OP_DATA, 2, reg); | ||
336 | else | ||
337 | newval = 0; | ||
338 | |||
339 | maxval = (field_sz == 4) ? 0xf : 0x1f; | ||
340 | for (i = 0; i < numfields; i++) | ||
341 | if (val[i] != -(i + 1)) { | ||
342 | mask = 0xffff; | ||
343 | mask ^= maxval << (field_sz * i); | ||
344 | newval = (newval & mask) | | ||
345 | (((val[i] / KSZ9031_PS_TO_REG) & maxval) | ||
346 | << (field_sz * i)); | ||
347 | } | ||
348 | |||
349 | return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval); | ||
350 | } | ||
351 | |||
352 | static int ksz9031_config_init(struct phy_device *phydev) | ||
353 | { | ||
354 | struct device *dev = &phydev->dev; | ||
355 | struct device_node *of_node = dev->of_node; | ||
356 | char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"}; | ||
357 | char *rx_data_skews[4] = { | ||
358 | "rxd0-skew-ps", "rxd1-skew-ps", | ||
359 | "rxd2-skew-ps", "rxd3-skew-ps" | ||
360 | }; | ||
361 | char *tx_data_skews[4] = { | ||
362 | "txd0-skew-ps", "txd1-skew-ps", | ||
363 | "txd2-skew-ps", "txd3-skew-ps" | ||
364 | }; | ||
365 | char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"}; | ||
366 | |||
367 | if (!of_node && dev->parent->of_node) | ||
368 | of_node = dev->parent->of_node; | ||
369 | |||
370 | if (of_node) { | ||
371 | ksz9031_of_load_skew_values(phydev, of_node, | ||
372 | MII_KSZ9031RN_CLK_PAD_SKEW, 5, | ||
373 | clk_skews, 2); | ||
374 | |||
375 | ksz9031_of_load_skew_values(phydev, of_node, | ||
376 | MII_KSZ9031RN_CONTROL_PAD_SKEW, 4, | ||
377 | control_skews, 2); | ||
378 | |||
379 | ksz9031_of_load_skew_values(phydev, of_node, | ||
380 | MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4, | ||
381 | rx_data_skews, 4); | ||
382 | |||
383 | ksz9031_of_load_skew_values(phydev, of_node, | ||
384 | MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4, | ||
385 | tx_data_skews, 4); | ||
386 | } | ||
387 | return 0; | ||
388 | } | ||
389 | |||
286 | #define KSZ8873MLL_GLOBAL_CONTROL_4 0x06 | 390 | #define KSZ8873MLL_GLOBAL_CONTROL_4 0x06 |
287 | #define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6) | 391 | #define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX (1 << 6) |
288 | #define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4) | 392 | #define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED (1 << 4) |
@@ -469,7 +573,7 @@ static struct phy_driver ksphy_driver[] = { | |||
469 | .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause | 573 | .features = (PHY_GBIT_FEATURES | SUPPORTED_Pause |
470 | | SUPPORTED_Asym_Pause), | 574 | | SUPPORTED_Asym_Pause), |
471 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, | 575 | .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, |
472 | .config_init = kszphy_config_init, | 576 | .config_init = ksz9031_config_init, |
473 | .config_aneg = genphy_config_aneg, | 577 | .config_aneg = genphy_config_aneg, |
474 | .read_status = genphy_read_status, | 578 | .read_status = genphy_read_status, |
475 | .ack_interrupt = kszphy_ack_interrupt, | 579 | .ack_interrupt = kszphy_ack_interrupt, |