1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * Copyright 2017 NXP |
4 | * |
5 | * CORTINA is a registered trademark of Cortina Systems, Inc. |
6 | * |
7 | */ |
8 | #include <linux/module.h> |
9 | #include <linux/phy.h> |
10 | |
11 | #define PHY_ID_CS4340 0x13e51002 |
12 | |
13 | #define VILLA_GLOBAL_CHIP_ID_LSB 0x0 |
14 | #define VILLA_GLOBAL_CHIP_ID_MSB 0x1 |
15 | |
16 | #define VILLA_GLOBAL_GPIO_1_INTS 0x017 |
17 | |
18 | static int cortina_read_reg(struct phy_device *phydev, u16 regnum) |
19 | { |
20 | return mdiobus_c45_read(bus: phydev->mdio.bus, addr: phydev->mdio.addr, devad: 0, regnum); |
21 | } |
22 | |
23 | static int cortina_read_status(struct phy_device *phydev) |
24 | { |
25 | int gpio_int_status, ret = 0; |
26 | |
27 | gpio_int_status = cortina_read_reg(phydev, VILLA_GLOBAL_GPIO_1_INTS); |
28 | if (gpio_int_status < 0) { |
29 | ret = gpio_int_status; |
30 | goto err; |
31 | } |
32 | |
33 | if (gpio_int_status & 0x8) { |
34 | /* up when edc_convergedS set */ |
35 | phydev->speed = SPEED_10000; |
36 | phydev->duplex = DUPLEX_FULL; |
37 | phydev->link = 1; |
38 | } else { |
39 | phydev->link = 0; |
40 | } |
41 | |
42 | err: |
43 | return ret; |
44 | } |
45 | |
46 | static int cortina_probe(struct phy_device *phydev) |
47 | { |
48 | u32 phy_id = 0; |
49 | int id_lsb = 0, id_msb = 0; |
50 | |
51 | /* Read device id from phy registers. */ |
52 | id_lsb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_LSB); |
53 | if (id_lsb < 0) |
54 | return -ENXIO; |
55 | |
56 | phy_id = id_lsb << 16; |
57 | |
58 | id_msb = cortina_read_reg(phydev, VILLA_GLOBAL_CHIP_ID_MSB); |
59 | if (id_msb < 0) |
60 | return -ENXIO; |
61 | |
62 | phy_id |= id_msb; |
63 | |
64 | /* Make sure the device tree binding matched the driver with the |
65 | * right device. |
66 | */ |
67 | if (phy_id != phydev->drv->phy_id) { |
68 | phydev_err(phydev, "Error matching phy with %s driver\n" , |
69 | phydev->drv->name); |
70 | return -ENODEV; |
71 | } |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | static struct phy_driver cortina_driver[] = { |
77 | { |
78 | .phy_id = PHY_ID_CS4340, |
79 | .phy_id_mask = 0xffffffff, |
80 | .name = "Cortina CS4340" , |
81 | .features = PHY_10GBIT_FEATURES, |
82 | .config_aneg = gen10g_config_aneg, |
83 | .read_status = cortina_read_status, |
84 | .probe = cortina_probe, |
85 | }, |
86 | }; |
87 | |
88 | module_phy_driver(cortina_driver); |
89 | |
90 | static struct mdio_device_id __maybe_unused cortina_tbl[] = { |
91 | { PHY_ID_CS4340, 0xffffffff}, |
92 | {}, |
93 | }; |
94 | |
95 | MODULE_DEVICE_TABLE(mdio, cortina_tbl); |
96 | |
97 | MODULE_DESCRIPTION("Cortina EDC CDR 10G Ethernet PHY driver" ); |
98 | MODULE_AUTHOR("NXP" ); |
99 | MODULE_LICENSE("GPL" ); |
100 | |