.. | .. |
---|
8 | 8 | #include <linux/kernel.h> |
---|
9 | 9 | #include <linux/module.h> |
---|
10 | 10 | #include <linux/netdevice.h> |
---|
| 11 | +#include <linux/of_device.h> |
---|
11 | 12 | #include <linux/phy.h> |
---|
12 | 13 | |
---|
13 | 14 | #define PHY_ID_YT8511 0x0000010a |
---|
| 15 | +#define PHY_ID_YT8512 0x00000118 |
---|
| 16 | +#define PHY_ID_YT8512B 0x00000128 |
---|
14 | 17 | #define PHY_ID_YT8531S 0x4f51e91a |
---|
15 | 18 | #define PHY_ID_YT8531 0x4f51e91b |
---|
16 | 19 | |
---|
.. | .. |
---|
40 | 43 | #define YT8511_DELAY_GE_TX_DIS (0x2 << 4) |
---|
41 | 44 | #define YT8511_DELAY_FE_TX_EN (0xf << 12) |
---|
42 | 45 | #define YT8511_DELAY_FE_TX_DIS (0x2 << 12) |
---|
| 46 | + |
---|
| 47 | +#define YT8512_EXTREG_AFE_PLL 0x50 |
---|
| 48 | +#define YT8512_EXTREG_EXTEND_COMBO 0x4000 |
---|
| 49 | +#define YT8512_EXTREG_LED0 0x40c0 |
---|
| 50 | +#define YT8512_EXTREG_LED1 0x40c3 |
---|
| 51 | + |
---|
| 52 | +#define YT8512_EXTREG_SLEEP_CONTROL1 0x2027 |
---|
| 53 | + |
---|
| 54 | +#define YT_SOFTWARE_RESET 0x8000 |
---|
| 55 | + |
---|
| 56 | +#define YT8512_CONFIG_PLL_REFCLK_SEL_EN 0x0040 |
---|
| 57 | +#define YT8512_CONTROL1_RMII_EN 0x0001 |
---|
| 58 | +#define YT8512_LED0_ACT_BLK_IND 0x1000 |
---|
| 59 | +#define YT8512_LED0_DIS_LED_AN_TRY 0x0001 |
---|
| 60 | +#define YT8512_LED0_BT_BLK_EN 0x0002 |
---|
| 61 | +#define YT8512_LED0_HT_BLK_EN 0x0004 |
---|
| 62 | +#define YT8512_LED0_COL_BLK_EN 0x0008 |
---|
| 63 | +#define YT8512_LED0_BT_ON_EN 0x0010 |
---|
| 64 | +#define YT8512_LED1_BT_ON_EN 0x0010 |
---|
| 65 | +#define YT8512_LED1_TXACT_BLK_EN 0x0100 |
---|
| 66 | +#define YT8512_LED1_RXACT_BLK_EN 0x0200 |
---|
| 67 | +#define YT8512_SPEED_MODE 0xc000 |
---|
| 68 | +#define YT8512_DUPLEX 0x2000 |
---|
| 69 | + |
---|
| 70 | +#define YT8512_SPEED_MODE_BIT 14 |
---|
| 71 | +#define YT8512_DUPLEX_BIT 13 |
---|
| 72 | +#define YT8512_EN_SLEEP_SW_BIT 15 |
---|
43 | 73 | |
---|
44 | 74 | /* if system depends on ethernet packet to restore from sleep, |
---|
45 | 75 | * please define this macro to 1 otherwise, define it to 0. |
---|
.. | .. |
---|
153 | 183 | return phy_restore_page(phydev, oldpage, ret); |
---|
154 | 184 | } |
---|
155 | 185 | |
---|
156 | | -static inline void phy_lock_mdio_bus(struct phy_device *phydev) |
---|
157 | | -{ |
---|
158 | | - mutex_lock(&phydev->mdio.bus->mdio_lock); |
---|
159 | | -} |
---|
160 | | - |
---|
161 | | -static inline void phy_unlock_mdio_bus(struct phy_device *phydev) |
---|
162 | | -{ |
---|
163 | | - mutex_unlock(&phydev->mdio.bus->mdio_lock); |
---|
164 | | -} |
---|
165 | | - |
---|
166 | 186 | static u32 ytphy_read_ext(struct phy_device *phydev, u32 regnum) |
---|
167 | 187 | { |
---|
168 | 188 | int ret; |
---|
.. | .. |
---|
212 | 232 | return ret; |
---|
213 | 233 | |
---|
214 | 234 | return ret; |
---|
| 235 | +} |
---|
| 236 | + |
---|
| 237 | +static int yt8512_clk_init(struct phy_device *phydev) |
---|
| 238 | +{ |
---|
| 239 | + struct device_node *node = phydev->mdio.dev.of_node; |
---|
| 240 | + const char *strings = NULL; |
---|
| 241 | + int ret; |
---|
| 242 | + int val; |
---|
| 243 | + |
---|
| 244 | + if (node && node->parent && node->parent->parent) { |
---|
| 245 | + ret = of_property_read_string(node->parent->parent, |
---|
| 246 | + "clock_in_out", &strings); |
---|
| 247 | + if (!ret) { |
---|
| 248 | + if (!strcmp(strings, "input")) |
---|
| 249 | + return 0; |
---|
| 250 | + } |
---|
| 251 | + } |
---|
| 252 | + |
---|
| 253 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_AFE_PLL); |
---|
| 254 | + if (val < 0) |
---|
| 255 | + return val; |
---|
| 256 | + |
---|
| 257 | + val |= YT8512_CONFIG_PLL_REFCLK_SEL_EN; |
---|
| 258 | + |
---|
| 259 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_AFE_PLL, val); |
---|
| 260 | + if (ret < 0) |
---|
| 261 | + return ret; |
---|
| 262 | + |
---|
| 263 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_EXTEND_COMBO); |
---|
| 264 | + if (val < 0) |
---|
| 265 | + return val; |
---|
| 266 | + |
---|
| 267 | + val |= YT8512_CONTROL1_RMII_EN; |
---|
| 268 | + |
---|
| 269 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_EXTEND_COMBO, val); |
---|
| 270 | + if (ret < 0) |
---|
| 271 | + return ret; |
---|
| 272 | + |
---|
| 273 | + val = phy_read(phydev, MII_BMCR); |
---|
| 274 | + if (val < 0) |
---|
| 275 | + return val; |
---|
| 276 | + |
---|
| 277 | + val |= YT_SOFTWARE_RESET; |
---|
| 278 | + ret = phy_write(phydev, MII_BMCR, val); |
---|
| 279 | + |
---|
| 280 | + return ret; |
---|
| 281 | +} |
---|
| 282 | + |
---|
| 283 | +static int yt8512_led_init(struct phy_device *phydev) |
---|
| 284 | +{ |
---|
| 285 | + int ret; |
---|
| 286 | + int val; |
---|
| 287 | + int mask; |
---|
| 288 | + |
---|
| 289 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0); |
---|
| 290 | + if (val < 0) |
---|
| 291 | + return val; |
---|
| 292 | + |
---|
| 293 | + val |= YT8512_LED0_ACT_BLK_IND; |
---|
| 294 | + |
---|
| 295 | + mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN | |
---|
| 296 | + YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN | |
---|
| 297 | + YT8512_LED0_BT_ON_EN; |
---|
| 298 | + val &= ~mask; |
---|
| 299 | + |
---|
| 300 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val); |
---|
| 301 | + if (ret < 0) |
---|
| 302 | + return ret; |
---|
| 303 | + |
---|
| 304 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1); |
---|
| 305 | + if (val < 0) |
---|
| 306 | + return val; |
---|
| 307 | + |
---|
| 308 | + val |= YT8512_LED1_BT_ON_EN; |
---|
| 309 | + |
---|
| 310 | + mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN; |
---|
| 311 | + val &= ~mask; |
---|
| 312 | + |
---|
| 313 | + ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val); |
---|
| 314 | + |
---|
| 315 | + return ret; |
---|
| 316 | +} |
---|
| 317 | + |
---|
| 318 | +static int yt8512_config_init(struct phy_device *phydev) |
---|
| 319 | +{ |
---|
| 320 | + int ret; |
---|
| 321 | + int val; |
---|
| 322 | + |
---|
| 323 | + ret = yt8512_clk_init(phydev); |
---|
| 324 | + if (ret < 0) |
---|
| 325 | + return ret; |
---|
| 326 | + |
---|
| 327 | + ret = yt8512_led_init(phydev); |
---|
| 328 | + if (ret < 0) |
---|
| 329 | + return ret; |
---|
| 330 | + |
---|
| 331 | + /* disable auto sleep */ |
---|
| 332 | + val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1); |
---|
| 333 | + if (val < 0) |
---|
| 334 | + return val; |
---|
| 335 | + |
---|
| 336 | + val &= (~BIT(YT8512_EN_SLEEP_SW_BIT)); |
---|
| 337 | + |
---|
| 338 | + ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val); |
---|
| 339 | + if (ret < 0) |
---|
| 340 | + return ret; |
---|
| 341 | + |
---|
| 342 | + return ret; |
---|
| 343 | +} |
---|
| 344 | + |
---|
| 345 | +static int yt8512_read_status(struct phy_device *phydev) |
---|
| 346 | +{ |
---|
| 347 | + int ret; |
---|
| 348 | + int val; |
---|
| 349 | + int speed, speed_mode, duplex; |
---|
| 350 | + |
---|
| 351 | + ret = genphy_update_link(phydev); |
---|
| 352 | + if (ret) |
---|
| 353 | + return ret; |
---|
| 354 | + |
---|
| 355 | + val = phy_read(phydev, REG_PHY_SPEC_STATUS); |
---|
| 356 | + if (val < 0) |
---|
| 357 | + return val; |
---|
| 358 | + |
---|
| 359 | + duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT; |
---|
| 360 | + speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT; |
---|
| 361 | + switch (speed_mode) { |
---|
| 362 | + case 0: |
---|
| 363 | + speed = SPEED_10; |
---|
| 364 | + break; |
---|
| 365 | + case 1: |
---|
| 366 | + speed = SPEED_100; |
---|
| 367 | + break; |
---|
| 368 | + case 2: |
---|
| 369 | + case 3: |
---|
| 370 | + default: |
---|
| 371 | + speed = SPEED_UNKNOWN; |
---|
| 372 | + break; |
---|
| 373 | + } |
---|
| 374 | + |
---|
| 375 | + phydev->speed = speed; |
---|
| 376 | + phydev->duplex = duplex; |
---|
| 377 | + |
---|
| 378 | + return 0; |
---|
215 | 379 | } |
---|
216 | 380 | |
---|
217 | 381 | static int yt8521_soft_reset(struct phy_device *phydev) |
---|
.. | .. |
---|
618 | 782 | .read_page = yt8511_read_page, |
---|
619 | 783 | .write_page = yt8511_write_page, |
---|
620 | 784 | }, { |
---|
| 785 | + PHY_ID_MATCH_EXACT(PHY_ID_YT8512), |
---|
| 786 | + .name = "YT8512 Ethernet", |
---|
| 787 | + .config_init = yt8512_config_init, |
---|
| 788 | + .read_status = yt8512_read_status, |
---|
| 789 | + .suspend = genphy_suspend, |
---|
| 790 | + .resume = genphy_resume, |
---|
| 791 | + }, { |
---|
| 792 | + PHY_ID_MATCH_EXACT(PHY_ID_YT8512B), |
---|
| 793 | + .name = "YT8512B Ethernet", |
---|
| 794 | + .config_init = yt8512_config_init, |
---|
| 795 | + .read_status = yt8512_read_status, |
---|
| 796 | + .suspend = genphy_suspend, |
---|
| 797 | + .resume = genphy_resume, |
---|
| 798 | + }, { |
---|
621 | 799 | /* same as 8521 */ |
---|
622 | 800 | PHY_ID_MATCH_EXACT(PHY_ID_YT8531S), |
---|
623 | 801 | .name = "YT8531S Gigabit Ethernet", |
---|
.. | .. |
---|
655 | 833 | |
---|
656 | 834 | static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = { |
---|
657 | 835 | { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) }, |
---|
| 836 | + { PHY_ID_MATCH_EXACT(PHY_ID_YT8512) }, |
---|
| 837 | + { PHY_ID_MATCH_EXACT(PHY_ID_YT8512B) }, |
---|
658 | 838 | { PHY_ID_MATCH_EXACT(PHY_ID_YT8531S) }, |
---|
659 | 839 | { PHY_ID_MATCH_EXACT(PHY_ID_YT8531) }, |
---|
660 | 840 | { /* sentinal */ } |
---|