Merge tag 'locks-v5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton...
[linux-2.6-microblaze.git] / drivers / net / phy / cortina.c
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(phydev->mdio.bus, phydev->mdio.addr, 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");