2 * Copyright (C) 2015 Broadcom Corporation
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation version 2.
8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
9 * kind, whether express or implied; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include "bcm-phy-lib.h"
15 #include <linux/brcmphy.h>
16 #include <linux/export.h>
17 #include <linux/mdio.h>
18 #include <linux/module.h>
19 #include <linux/phy.h>
21 #define MII_BCM_CHANNEL_WIDTH 0x2000
22 #define BCM_CL45VEN_EEE_ADV 0x3c
24 int bcm_phy_write_exp(struct phy_device
*phydev
, u16 reg
, u16 val
)
28 rc
= phy_write(phydev
, MII_BCM54XX_EXP_SEL
, reg
);
32 return phy_write(phydev
, MII_BCM54XX_EXP_DATA
, val
);
34 EXPORT_SYMBOL_GPL(bcm_phy_write_exp
);
36 int bcm_phy_read_exp(struct phy_device
*phydev
, u16 reg
)
40 val
= phy_write(phydev
, MII_BCM54XX_EXP_SEL
, reg
);
44 val
= phy_read(phydev
, MII_BCM54XX_EXP_DATA
);
46 /* Restore default value. It's O.K. if this write fails. */
47 phy_write(phydev
, MII_BCM54XX_EXP_SEL
, 0);
51 EXPORT_SYMBOL_GPL(bcm_phy_read_exp
);
53 int bcm_phy_write_misc(struct phy_device
*phydev
,
54 u16 reg
, u16 chl
, u16 val
)
59 rc
= phy_write(phydev
, MII_BCM54XX_AUX_CTL
,
60 MII_BCM54XX_AUXCTL_SHDWSEL_MISC
);
64 tmp
= phy_read(phydev
, MII_BCM54XX_AUX_CTL
);
65 tmp
|= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA
;
66 rc
= phy_write(phydev
, MII_BCM54XX_AUX_CTL
, tmp
);
70 tmp
= (chl
* MII_BCM_CHANNEL_WIDTH
) | reg
;
71 rc
= bcm_phy_write_exp(phydev
, tmp
, val
);
75 EXPORT_SYMBOL_GPL(bcm_phy_write_misc
);
77 int bcm_phy_read_misc(struct phy_device
*phydev
,
83 rc
= phy_write(phydev
, MII_BCM54XX_AUX_CTL
,
84 MII_BCM54XX_AUXCTL_SHDWSEL_MISC
);
88 tmp
= phy_read(phydev
, MII_BCM54XX_AUX_CTL
);
89 tmp
|= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA
;
90 rc
= phy_write(phydev
, MII_BCM54XX_AUX_CTL
, tmp
);
94 tmp
= (chl
* MII_BCM_CHANNEL_WIDTH
) | reg
;
95 rc
= bcm_phy_read_exp(phydev
, tmp
);
99 EXPORT_SYMBOL_GPL(bcm_phy_read_misc
);
101 int bcm_phy_ack_intr(struct phy_device
*phydev
)
105 /* Clear pending interrupts. */
106 reg
= phy_read(phydev
, MII_BCM54XX_ISR
);
112 EXPORT_SYMBOL_GPL(bcm_phy_ack_intr
);
114 int bcm_phy_config_intr(struct phy_device
*phydev
)
118 reg
= phy_read(phydev
, MII_BCM54XX_ECR
);
122 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
)
123 reg
&= ~MII_BCM54XX_ECR_IM
;
125 reg
|= MII_BCM54XX_ECR_IM
;
127 return phy_write(phydev
, MII_BCM54XX_ECR
, reg
);
129 EXPORT_SYMBOL_GPL(bcm_phy_config_intr
);
131 int bcm_phy_read_shadow(struct phy_device
*phydev
, u16 shadow
)
133 phy_write(phydev
, MII_BCM54XX_SHD
, MII_BCM54XX_SHD_VAL(shadow
));
134 return MII_BCM54XX_SHD_DATA(phy_read(phydev
, MII_BCM54XX_SHD
));
136 EXPORT_SYMBOL_GPL(bcm_phy_read_shadow
);
138 int bcm_phy_write_shadow(struct phy_device
*phydev
, u16 shadow
,
141 return phy_write(phydev
, MII_BCM54XX_SHD
,
142 MII_BCM54XX_SHD_WRITE
|
143 MII_BCM54XX_SHD_VAL(shadow
) |
144 MII_BCM54XX_SHD_DATA(val
));
146 EXPORT_SYMBOL_GPL(bcm_phy_write_shadow
);
148 int bcm_phy_enable_apd(struct phy_device
*phydev
, bool dll_pwr_down
)
153 val
= bcm_phy_read_shadow(phydev
, BCM54XX_SHD_SCR3
);
157 val
|= BCM54XX_SHD_SCR3_DLLAPD_DIS
;
158 bcm_phy_write_shadow(phydev
, BCM54XX_SHD_SCR3
, val
);
161 val
= bcm_phy_read_shadow(phydev
, BCM54XX_SHD_APD
);
166 val
&= BCM_APD_CLR_MASK
;
168 if (phydev
->autoneg
== AUTONEG_ENABLE
)
169 val
|= BCM54XX_SHD_APD_EN
;
171 val
|= BCM_NO_ANEG_APD_EN
;
173 /* Enable energy detect single link pulse for easy wakeup */
174 val
|= BCM_APD_SINGLELP_EN
;
176 /* Enable Auto Power-Down (APD) for the PHY */
177 return bcm_phy_write_shadow(phydev
, BCM54XX_SHD_APD
, val
);
179 EXPORT_SYMBOL_GPL(bcm_phy_enable_apd
);
181 int bcm_phy_enable_eee(struct phy_device
*phydev
)
185 /* Enable EEE at PHY level */
186 val
= phy_read_mmd_indirect(phydev
, BRCM_CL45VEN_EEE_CONTROL
,
191 val
|= LPI_FEATURE_EN
| LPI_FEATURE_EN_DIG1000X
;
193 phy_write_mmd_indirect(phydev
, BRCM_CL45VEN_EEE_CONTROL
,
194 MDIO_MMD_AN
, (u32
)val
);
197 val
= phy_read_mmd_indirect(phydev
, BCM_CL45VEN_EEE_ADV
,
202 val
|= (MDIO_AN_EEE_ADV_100TX
| MDIO_AN_EEE_ADV_1000T
);
204 phy_write_mmd_indirect(phydev
, BCM_CL45VEN_EEE_ADV
,
205 MDIO_MMD_AN
, (u32
)val
);
209 EXPORT_SYMBOL_GPL(bcm_phy_enable_eee
);
211 MODULE_DESCRIPTION("Broadcom PHY Library");
212 MODULE_LICENSE("GPL v2");
213 MODULE_AUTHOR("Broadcom Corporation");