Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: micrel: add generic clock-mode-select support

Add generic RMII-Reference-Clock-Select support.

Several Micrel PHY have an RMII-Reference-Clock-Select bit to select
25 MHz or 50 MHz clock mode. Recently, support for configuring this
through device tree for KSZ8021 and KSZ8031 was added.

Generalise this support so that it can be configured for other PHY types
as well.

Note that some PHY revisions (of the same type) has this bit inverted.
This should be either configurable through a new device-tree property,
or preferably, determined based on PHY ID if possible.

Also note that this removes support for setting 25 MHz mode from board
files which was also added by the above mentioned commit 45f56cb82e45
("net/phy: micrel: Add clock support for KSZ8021/KSZ8031").

Signed-off-by: Johan Hovold <johan@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Johan Hovold and committed by
David S. Miller
63f44b2b 0f95903e

+50 -44
+50 -43
drivers/net/phy/micrel.c
··· 57 57 #define KSZPHY_CTRL_INT_ACTIVE_HIGH BIT(9) 58 58 #define KSZ9021_CTRL_INT_ACTIVE_HIGH BIT(14) 59 59 #define KS8737_CTRL_INT_ACTIVE_HIGH BIT(14) 60 - #define KSZ8051_RMII_50MHZ_CLK BIT(7) 60 + #define KSZPHY_RMII_REF_CLK_SEL BIT(7) 61 61 62 62 /* Write/read to/from extended registers */ 63 63 #define MII_KSZPHY_EXTREG 0x0b ··· 76 76 struct kszphy_type { 77 77 u32 led_mode_reg; 78 78 bool has_broadcast_disable; 79 + bool has_rmii_ref_clk_sel; 79 80 }; 80 81 81 82 struct kszphy_priv { 82 83 const struct kszphy_type *type; 83 84 int led_mode; 85 + bool rmii_ref_clk_sel; 86 + bool rmii_ref_clk_sel_val; 84 87 }; 85 88 86 89 static const struct kszphy_type ksz8021_type = { 87 90 .led_mode_reg = MII_KSZPHY_CTRL_2, 91 + .has_rmii_ref_clk_sel = true, 88 92 }; 89 93 90 94 static const struct kszphy_type ksz8041_type = { ··· 103 99 .led_mode_reg = MII_KSZPHY_CTRL_2, 104 100 .has_broadcast_disable = true, 105 101 }; 106 - 107 - static int ksz_config_flags(struct phy_device *phydev) 108 - { 109 - int regval; 110 - 111 - if (phydev->dev_flags & (MICREL_PHY_50MHZ_CLK | MICREL_PHY_25MHZ_CLK)) { 112 - regval = phy_read(phydev, MII_KSZPHY_CTRL); 113 - if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) 114 - regval |= KSZ8051_RMII_50MHZ_CLK; 115 - else 116 - regval &= ~KSZ8051_RMII_50MHZ_CLK; 117 - return phy_write(phydev, MII_KSZPHY_CTRL, regval); 118 - } 119 - return 0; 120 - } 121 102 122 103 static int kszphy_extended_write(struct phy_device *phydev, 123 104 u32 regnum, u16 val) ··· 178 189 return rc < 0 ? rc : 0; 179 190 } 180 191 192 + static int kszphy_rmii_clk_sel(struct phy_device *phydev, bool val) 193 + { 194 + int ctrl; 195 + 196 + ctrl = phy_read(phydev, MII_KSZPHY_CTRL); 197 + if (ctrl < 0) 198 + return ctrl; 199 + 200 + if (val) 201 + ctrl |= KSZPHY_RMII_REF_CLK_SEL; 202 + else 203 + ctrl &= ~KSZPHY_RMII_REF_CLK_SEL; 204 + 205 + return phy_write(phydev, MII_KSZPHY_CTRL, ctrl); 206 + } 207 + 181 208 static int kszphy_setup_led(struct phy_device *phydev, u32 reg, int val) 182 209 { 183 210 int rc, temp, shift; ··· 248 243 { 249 244 struct kszphy_priv *priv = phydev->priv; 250 245 const struct kszphy_type *type; 246 + int ret; 251 247 252 248 if (!priv) 253 249 return 0; ··· 257 251 258 252 if (type->has_broadcast_disable) 259 253 kszphy_broadcast_disable(phydev); 254 + 255 + if (priv->rmii_ref_clk_sel) { 256 + ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val); 257 + if (ret) { 258 + dev_err(&phydev->dev, "failed to set rmii reference clock\n"); 259 + return ret; 260 + } 261 + } 260 262 261 263 if (priv->led_mode >= 0) 262 264 kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode); ··· 276 262 { 277 263 int rc; 278 264 279 - kszphy_config_init(phydev); 280 - 281 - rc = ksz_config_flags(phydev); 282 - if (rc < 0) 265 + rc = kszphy_config_init(phydev); 266 + if (rc) 283 267 return rc; 284 268 285 269 rc = kszphy_broadcast_disable(phydev); 286 270 287 - return rc < 0 ? rc : 0; 288 - } 289 - 290 - static int ks8051_config_init(struct phy_device *phydev) 291 - { 292 - int rc; 293 - 294 - kszphy_config_init(phydev); 295 - 296 - rc = ksz_config_flags(phydev); 297 271 return rc < 0 ? rc : 0; 298 272 } 299 273 ··· 519 517 const struct kszphy_type *type = phydev->drv->driver_data; 520 518 struct device_node *np = phydev->dev.of_node; 521 519 struct kszphy_priv *priv; 520 + struct clk *clk; 522 521 int ret; 523 522 524 523 priv = devm_kzalloc(&phydev->dev, sizeof(*priv), GFP_KERNEL); ··· 545 542 priv->led_mode = -1; 546 543 } 547 544 548 - return 0; 549 - } 550 - 551 - static int ksz8021_probe(struct phy_device *phydev) 552 - { 553 - struct clk *clk; 554 - 555 545 clk = devm_clk_get(&phydev->dev, "rmii-ref"); 556 546 if (!IS_ERR(clk)) { 557 547 unsigned long rate = clk_get_rate(clk); 558 548 549 + priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel; 550 + 551 + /* FIXME: add support for PHY revisions that have this bit 552 + * inverted (e.g. through new property or based on PHY ID). 553 + */ 559 554 if (rate > 24500000 && rate < 25500000) { 560 - phydev->dev_flags |= MICREL_PHY_25MHZ_CLK; 555 + priv->rmii_ref_clk_sel_val = false; 561 556 } else if (rate > 49500000 && rate < 50500000) { 562 - phydev->dev_flags |= MICREL_PHY_50MHZ_CLK; 557 + priv->rmii_ref_clk_sel_val = true; 563 558 } else { 564 559 dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate); 565 560 return -EINVAL; 566 561 } 567 562 } 568 563 569 - return kszphy_probe(phydev); 564 + /* Support legacy board-file configuration */ 565 + if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) { 566 + priv->rmii_ref_clk_sel = true; 567 + priv->rmii_ref_clk_sel_val = true; 568 + } 569 + 570 + return 0; 570 571 } 571 572 572 573 static struct phy_driver ksphy_driver[] = { ··· 596 589 SUPPORTED_Asym_Pause), 597 590 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 598 591 .driver_data = &ksz8021_type, 599 - .probe = ksz8021_probe, 592 + .probe = kszphy_probe, 600 593 .config_init = ksz8021_config_init, 601 594 .config_aneg = genphy_config_aneg, 602 595 .read_status = genphy_read_status, ··· 613 606 SUPPORTED_Asym_Pause), 614 607 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 615 608 .driver_data = &ksz8021_type, 616 - .probe = ksz8021_probe, 609 + .probe = kszphy_probe, 617 610 .config_init = ksz8021_config_init, 618 611 .config_aneg = genphy_config_aneg, 619 612 .read_status = genphy_read_status, ··· 665 658 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 666 659 .driver_data = &ksz8051_type, 667 660 .probe = kszphy_probe, 668 - .config_init = ks8051_config_init, 661 + .config_init = kszphy_config_init, 669 662 .config_aneg = genphy_config_aneg, 670 663 .read_status = genphy_read_status, 671 664 .ack_interrupt = kszphy_ack_interrupt,
-1
include/linux/micrel_phy.h
··· 37 37 38 38 /* struct phy_device dev_flags definitions */ 39 39 #define MICREL_PHY_50MHZ_CLK 0x00000001 40 - #define MICREL_PHY_25MHZ_CLK 0x00000002 41 40 42 41 #define MICREL_KSZ9021_EXTREG_CTRL 0xB 43 42 #define MICREL_KSZ9021_EXTREG_DATA_WRITE 0xC