]>
Commit | Line | Data |
---|---|---|
a2443fd1 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
49099122 HS |
2 | /* |
3 | * Driver for AMD am79c PHYs | |
4 | * | |
5 | * Author: Heiko Schocher <hs@denx.de> | |
6 | * | |
7 | * Copyright (c) 2011 DENX Software Engineering GmbH | |
49099122 HS |
8 | */ |
9 | #include <linux/kernel.h> | |
10 | #include <linux/errno.h> | |
11 | #include <linux/init.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/mii.h> | |
14 | #include <linux/phy.h> | |
15 | ||
16 | #define PHY_ID_AM79C874 0x0022561b | |
17 | ||
18 | #define MII_AM79C_IR 17 /* Interrupt Status/Control Register */ | |
19 | #define MII_AM79C_IR_EN_LINK 0x0400 /* IR enable Linkstate */ | |
20 | #define MII_AM79C_IR_EN_ANEG 0x0100 /* IR enable Aneg Complete */ | |
21 | #define MII_AM79C_IR_IMASK_INIT (MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG) | |
22 | ||
d995a36b IC |
23 | #define MII_AM79C_IR_LINK_DOWN BIT(2) |
24 | #define MII_AM79C_IR_ANEG_DONE BIT(0) | |
25 | #define MII_AM79C_IR_IMASK_STAT (MII_AM79C_IR_LINK_DOWN | MII_AM79C_IR_ANEG_DONE) | |
26 | ||
49099122 HS |
27 | MODULE_DESCRIPTION("AMD PHY driver"); |
28 | MODULE_AUTHOR("Heiko Schocher <hs@denx.de>"); | |
29 | MODULE_LICENSE("GPL"); | |
30 | ||
31 | static int am79c_ack_interrupt(struct phy_device *phydev) | |
32 | { | |
33 | int err; | |
34 | ||
35 | err = phy_read(phydev, MII_BMSR); | |
36 | if (err < 0) | |
37 | return err; | |
38 | ||
39 | err = phy_read(phydev, MII_AM79C_IR); | |
40 | if (err < 0) | |
41 | return err; | |
42 | ||
43 | return 0; | |
44 | } | |
45 | ||
46 | static int am79c_config_init(struct phy_device *phydev) | |
47 | { | |
48 | return 0; | |
49 | } | |
50 | ||
51 | static int am79c_config_intr(struct phy_device *phydev) | |
52 | { | |
53 | int err; | |
54 | ||
347917c7 IC |
55 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { |
56 | err = am79c_ack_interrupt(phydev); | |
57 | if (err) | |
58 | return err; | |
59 | ||
49099122 | 60 | err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT); |
347917c7 | 61 | } else { |
49099122 | 62 | err = phy_write(phydev, MII_AM79C_IR, 0); |
347917c7 IC |
63 | if (err) |
64 | return err; | |
65 | ||
66 | err = am79c_ack_interrupt(phydev); | |
67 | } | |
49099122 HS |
68 | |
69 | return err; | |
70 | } | |
71 | ||
d995a36b IC |
72 | static irqreturn_t am79c_handle_interrupt(struct phy_device *phydev) |
73 | { | |
74 | int irq_status; | |
75 | ||
76 | irq_status = phy_read(phydev, MII_AM79C_IR); | |
77 | if (irq_status < 0) { | |
78 | phy_error(phydev); | |
79 | return IRQ_NONE; | |
80 | } | |
81 | ||
82 | if (!(irq_status & MII_AM79C_IR_IMASK_STAT)) | |
83 | return IRQ_NONE; | |
84 | ||
85 | phy_trigger_machine(phydev); | |
86 | ||
87 | return IRQ_HANDLED; | |
88 | } | |
89 | ||
116dffa0 | 90 | static struct phy_driver am79c_driver[] = { { |
49099122 HS |
91 | .phy_id = PHY_ID_AM79C874, |
92 | .name = "AM79C874", | |
93 | .phy_id_mask = 0xfffffff0, | |
dcdecdcf | 94 | /* PHY_BASIC_FEATURES */ |
49099122 | 95 | .config_init = am79c_config_init, |
49099122 | 96 | .config_intr = am79c_config_intr, |
d995a36b | 97 | .handle_interrupt = am79c_handle_interrupt, |
116dffa0 | 98 | } }; |
49099122 | 99 | |
116dffa0 | 100 | module_phy_driver(am79c_driver); |
49099122 HS |
101 | |
102 | static struct mdio_device_id __maybe_unused amd_tbl[] = { | |
103 | { PHY_ID_AM79C874, 0xfffffff0 }, | |
104 | { } | |
105 | }; | |
106 | ||
107 | MODULE_DEVICE_TABLE(mdio, amd_tbl); |