2 * Marvell 88e6xxx Ethernet switch PHY and PPU support
4 * Copyright (c) 2008 Marvell Semiconductor
6 * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
14 #include <linux/mdio.h>
15 #include <linux/module.h>
20 int mv88e6165_phy_read(struct mv88e6xxx_chip
*chip
, struct mii_bus
*bus
,
21 int addr
, int reg
, u16
*val
)
23 return mv88e6xxx_read(chip
, addr
, reg
, val
);
26 int mv88e6165_phy_write(struct mv88e6xxx_chip
*chip
, struct mii_bus
*bus
,
27 int addr
, int reg
, u16 val
)
29 return mv88e6xxx_write(chip
, addr
, reg
, val
);
32 int mv88e6xxx_phy_read(struct mv88e6xxx_chip
*chip
, int phy
, int reg
, u16
*val
)
34 int addr
= phy
; /* PHY devices addresses start at 0x0 */
37 bus
= mv88e6xxx_default_mdio_bus(chip
);
41 if (!chip
->info
->ops
->phy_read
)
44 return chip
->info
->ops
->phy_read(chip
, bus
, addr
, reg
, val
);
47 int mv88e6xxx_phy_write(struct mv88e6xxx_chip
*chip
, int phy
, int reg
, u16 val
)
49 int addr
= phy
; /* PHY devices addresses start at 0x0 */
52 bus
= mv88e6xxx_default_mdio_bus(chip
);
56 if (!chip
->info
->ops
->phy_write
)
59 return chip
->info
->ops
->phy_write(chip
, bus
, addr
, reg
, val
);
62 static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip
*chip
, int phy
, u8 page
)
64 return mv88e6xxx_phy_write(chip
, phy
, MV88E6XXX_PHY_PAGE
, page
);
67 static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip
*chip
, int phy
)
71 /* Restore PHY page Copper 0x0 for access via the registered
74 err
= mv88e6xxx_phy_write(chip
, phy
, MV88E6XXX_PHY_PAGE
,
75 MV88E6XXX_PHY_PAGE_COPPER
);
78 "failed to restore PHY %d page Copper (%d)\n",
83 int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip
*chip
, int phy
,
84 u8 page
, int reg
, u16
*val
)
88 /* There is no paging for registers 22 */
89 if (reg
== MV88E6XXX_PHY_PAGE
)
92 err
= mv88e6xxx_phy_page_get(chip
, phy
, page
);
94 err
= mv88e6xxx_phy_read(chip
, phy
, reg
, val
);
95 mv88e6xxx_phy_page_put(chip
, phy
);
101 int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip
*chip
, int phy
,
102 u8 page
, int reg
, u16 val
)
106 /* There is no paging for registers 22 */
107 if (reg
== MV88E6XXX_PHY_PAGE
)
110 err
= mv88e6xxx_phy_page_get(chip
, phy
, page
);
112 err
= mv88e6xxx_phy_write(chip
, phy
, MV88E6XXX_PHY_PAGE
, page
);
113 mv88e6xxx_phy_page_put(chip
, phy
);
119 static int mv88e6xxx_phy_ppu_disable(struct mv88e6xxx_chip
*chip
)
121 if (!chip
->info
->ops
->ppu_disable
)
124 return chip
->info
->ops
->ppu_disable(chip
);
127 static int mv88e6xxx_phy_ppu_enable(struct mv88e6xxx_chip
*chip
)
129 if (!chip
->info
->ops
->ppu_enable
)
132 return chip
->info
->ops
->ppu_enable(chip
);
135 static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct
*ugly
)
137 struct mv88e6xxx_chip
*chip
;
139 chip
= container_of(ugly
, struct mv88e6xxx_chip
, ppu_work
);
141 mutex_lock(&chip
->reg_lock
);
143 if (mutex_trylock(&chip
->ppu_mutex
)) {
144 if (mv88e6xxx_phy_ppu_enable(chip
) == 0)
145 chip
->ppu_disabled
= 0;
146 mutex_unlock(&chip
->ppu_mutex
);
149 mutex_unlock(&chip
->reg_lock
);
152 static void mv88e6xxx_phy_ppu_reenable_timer(struct timer_list
*t
)
154 struct mv88e6xxx_chip
*chip
= from_timer(chip
, t
, ppu_timer
);
156 schedule_work(&chip
->ppu_work
);
159 static int mv88e6xxx_phy_ppu_access_get(struct mv88e6xxx_chip
*chip
)
163 mutex_lock(&chip
->ppu_mutex
);
165 /* If the PHY polling unit is enabled, disable it so that
166 * we can access the PHY registers. If it was already
167 * disabled, cancel the timer that is going to re-enable
170 if (!chip
->ppu_disabled
) {
171 ret
= mv88e6xxx_phy_ppu_disable(chip
);
173 mutex_unlock(&chip
->ppu_mutex
);
176 chip
->ppu_disabled
= 1;
178 del_timer(&chip
->ppu_timer
);
185 static void mv88e6xxx_phy_ppu_access_put(struct mv88e6xxx_chip
*chip
)
187 /* Schedule a timer to re-enable the PHY polling unit. */
188 mod_timer(&chip
->ppu_timer
, jiffies
+ msecs_to_jiffies(10));
189 mutex_unlock(&chip
->ppu_mutex
);
192 static void mv88e6xxx_phy_ppu_state_init(struct mv88e6xxx_chip
*chip
)
194 mutex_init(&chip
->ppu_mutex
);
195 INIT_WORK(&chip
->ppu_work
, mv88e6xxx_phy_ppu_reenable_work
);
196 timer_setup(&chip
->ppu_timer
, mv88e6xxx_phy_ppu_reenable_timer
, 0);
199 static void mv88e6xxx_phy_ppu_state_destroy(struct mv88e6xxx_chip
*chip
)
201 del_timer_sync(&chip
->ppu_timer
);
204 int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip
*chip
, struct mii_bus
*bus
,
205 int addr
, int reg
, u16
*val
)
209 err
= mv88e6xxx_phy_ppu_access_get(chip
);
211 err
= mv88e6xxx_read(chip
, addr
, reg
, val
);
212 mv88e6xxx_phy_ppu_access_put(chip
);
218 int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip
*chip
, struct mii_bus
*bus
,
219 int addr
, int reg
, u16 val
)
223 err
= mv88e6xxx_phy_ppu_access_get(chip
);
225 err
= mv88e6xxx_write(chip
, addr
, reg
, val
);
226 mv88e6xxx_phy_ppu_access_put(chip
);
232 void mv88e6xxx_phy_init(struct mv88e6xxx_chip
*chip
)
234 if (chip
->info
->ops
->ppu_enable
&& chip
->info
->ops
->ppu_disable
)
235 mv88e6xxx_phy_ppu_state_init(chip
);
238 void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip
*chip
)
240 if (chip
->info
->ops
->ppu_enable
&& chip
->info
->ops
->ppu_disable
)
241 mv88e6xxx_phy_ppu_state_destroy(chip
);
244 int mv88e6xxx_phy_setup(struct mv88e6xxx_chip
*chip
)
246 return mv88e6xxx_phy_ppu_enable(chip
);