root/drivers/net/dsa/mv88e6xxx/phy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mv88e6165_phy_read
  2. mv88e6165_phy_write
  3. mv88e6xxx_phy_read
  4. mv88e6xxx_phy_write
  5. mv88e6xxx_phy_page_get
  6. mv88e6xxx_phy_page_put
  7. mv88e6xxx_phy_page_read
  8. mv88e6xxx_phy_page_write
  9. mv88e6xxx_phy_ppu_disable
  10. mv88e6xxx_phy_ppu_enable
  11. mv88e6xxx_phy_ppu_reenable_work
  12. mv88e6xxx_phy_ppu_reenable_timer
  13. mv88e6xxx_phy_ppu_access_get
  14. mv88e6xxx_phy_ppu_access_put
  15. mv88e6xxx_phy_ppu_state_init
  16. mv88e6xxx_phy_ppu_state_destroy
  17. mv88e6185_phy_ppu_read
  18. mv88e6185_phy_ppu_write
  19. mv88e6xxx_phy_init
  20. mv88e6xxx_phy_destroy
  21. mv88e6xxx_phy_setup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Marvell 88e6xxx Ethernet switch PHY and PPU support
   4  *
   5  * Copyright (c) 2008 Marvell Semiconductor
   6  *
   7  * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
   8  */
   9 
  10 #include <linux/mdio.h>
  11 #include <linux/module.h>
  12 
  13 #include "chip.h"
  14 #include "phy.h"
  15 
  16 int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
  17                        int addr, int reg, u16 *val)
  18 {
  19         return mv88e6xxx_read(chip, addr, reg, val);
  20 }
  21 
  22 int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
  23                         int addr, int reg, u16 val)
  24 {
  25         return mv88e6xxx_write(chip, addr, reg, val);
  26 }
  27 
  28 int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, int reg, u16 *val)
  29 {
  30         int addr = phy; /* PHY devices addresses start at 0x0 */
  31         struct mii_bus *bus;
  32 
  33         bus = mv88e6xxx_default_mdio_bus(chip);
  34         if (!bus)
  35                 return -EOPNOTSUPP;
  36 
  37         if (!chip->info->ops->phy_read)
  38                 return -EOPNOTSUPP;
  39 
  40         return chip->info->ops->phy_read(chip, bus, addr, reg, val);
  41 }
  42 
  43 int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val)
  44 {
  45         int addr = phy; /* PHY devices addresses start at 0x0 */
  46         struct mii_bus *bus;
  47 
  48         bus = mv88e6xxx_default_mdio_bus(chip);
  49         if (!bus)
  50                 return -EOPNOTSUPP;
  51 
  52         if (!chip->info->ops->phy_write)
  53                 return -EOPNOTSUPP;
  54 
  55         return chip->info->ops->phy_write(chip, bus, addr, reg, val);
  56 }
  57 
  58 static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
  59 {
  60         return mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page);
  61 }
  62 
  63 static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
  64 {
  65         int err;
  66 
  67         /* Restore PHY page Copper 0x0 for access via the registered
  68          * MDIO bus
  69          */
  70         err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE,
  71                                   MV88E6XXX_PHY_PAGE_COPPER);
  72         if (unlikely(err)) {
  73                 dev_err(chip->dev,
  74                         "failed to restore PHY %d page Copper (%d)\n",
  75                         phy, err);
  76         }
  77 }
  78 
  79 int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
  80                             u8 page, int reg, u16 *val)
  81 {
  82         int err;
  83 
  84         /* There is no paging for registers 22 */
  85         if (reg == MV88E6XXX_PHY_PAGE)
  86                 return -EINVAL;
  87 
  88         err = mv88e6xxx_phy_page_get(chip, phy, page);
  89         if (!err) {
  90                 err = mv88e6xxx_phy_read(chip, phy, reg, val);
  91                 mv88e6xxx_phy_page_put(chip, phy);
  92         }
  93 
  94         return err;
  95 }
  96 
  97 int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
  98                              u8 page, int reg, u16 val)
  99 {
 100         int err;
 101 
 102         /* There is no paging for registers 22 */
 103         if (reg == MV88E6XXX_PHY_PAGE)
 104                 return -EINVAL;
 105 
 106         err = mv88e6xxx_phy_page_get(chip, phy, page);
 107         if (!err) {
 108                 err = mv88e6xxx_phy_write(chip, phy, MV88E6XXX_PHY_PAGE, page);
 109                 if (!err)
 110                         err = mv88e6xxx_phy_write(chip, phy, reg, val);
 111 
 112                 mv88e6xxx_phy_page_put(chip, phy);
 113         }
 114 
 115         return err;
 116 }
 117 
 118 static int mv88e6xxx_phy_ppu_disable(struct mv88e6xxx_chip *chip)
 119 {
 120         if (!chip->info->ops->ppu_disable)
 121                 return 0;
 122 
 123         return chip->info->ops->ppu_disable(chip);
 124 }
 125 
 126 static int mv88e6xxx_phy_ppu_enable(struct mv88e6xxx_chip *chip)
 127 {
 128         if (!chip->info->ops->ppu_enable)
 129                 return 0;
 130 
 131         return chip->info->ops->ppu_enable(chip);
 132 }
 133 
 134 static void mv88e6xxx_phy_ppu_reenable_work(struct work_struct *ugly)
 135 {
 136         struct mv88e6xxx_chip *chip;
 137 
 138         chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
 139 
 140         mv88e6xxx_reg_lock(chip);
 141 
 142         if (mutex_trylock(&chip->ppu_mutex)) {
 143                 if (mv88e6xxx_phy_ppu_enable(chip) == 0)
 144                         chip->ppu_disabled = 0;
 145                 mutex_unlock(&chip->ppu_mutex);
 146         }
 147 
 148         mv88e6xxx_reg_unlock(chip);
 149 }
 150 
 151 static void mv88e6xxx_phy_ppu_reenable_timer(struct timer_list *t)
 152 {
 153         struct mv88e6xxx_chip *chip = from_timer(chip, t, ppu_timer);
 154 
 155         schedule_work(&chip->ppu_work);
 156 }
 157 
 158 static int mv88e6xxx_phy_ppu_access_get(struct mv88e6xxx_chip *chip)
 159 {
 160         int ret;
 161 
 162         mutex_lock(&chip->ppu_mutex);
 163 
 164         /* If the PHY polling unit is enabled, disable it so that
 165          * we can access the PHY registers.  If it was already
 166          * disabled, cancel the timer that is going to re-enable
 167          * it.
 168          */
 169         if (!chip->ppu_disabled) {
 170                 ret = mv88e6xxx_phy_ppu_disable(chip);
 171                 if (ret < 0) {
 172                         mutex_unlock(&chip->ppu_mutex);
 173                         return ret;
 174                 }
 175                 chip->ppu_disabled = 1;
 176         } else {
 177                 del_timer(&chip->ppu_timer);
 178                 ret = 0;
 179         }
 180 
 181         return ret;
 182 }
 183 
 184 static void mv88e6xxx_phy_ppu_access_put(struct mv88e6xxx_chip *chip)
 185 {
 186         /* Schedule a timer to re-enable the PHY polling unit. */
 187         mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
 188         mutex_unlock(&chip->ppu_mutex);
 189 }
 190 
 191 static void mv88e6xxx_phy_ppu_state_init(struct mv88e6xxx_chip *chip)
 192 {
 193         mutex_init(&chip->ppu_mutex);
 194         INIT_WORK(&chip->ppu_work, mv88e6xxx_phy_ppu_reenable_work);
 195         timer_setup(&chip->ppu_timer, mv88e6xxx_phy_ppu_reenable_timer, 0);
 196 }
 197 
 198 static void mv88e6xxx_phy_ppu_state_destroy(struct mv88e6xxx_chip *chip)
 199 {
 200         del_timer_sync(&chip->ppu_timer);
 201 }
 202 
 203 int mv88e6185_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
 204                            int addr, int reg, u16 *val)
 205 {
 206         int err;
 207 
 208         err = mv88e6xxx_phy_ppu_access_get(chip);
 209         if (!err) {
 210                 err = mv88e6xxx_read(chip, addr, reg, val);
 211                 mv88e6xxx_phy_ppu_access_put(chip);
 212         }
 213 
 214         return err;
 215 }
 216 
 217 int mv88e6185_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
 218                             int addr, int reg, u16 val)
 219 {
 220         int err;
 221 
 222         err = mv88e6xxx_phy_ppu_access_get(chip);
 223         if (!err) {
 224                 err = mv88e6xxx_write(chip, addr, reg, val);
 225                 mv88e6xxx_phy_ppu_access_put(chip);
 226         }
 227 
 228         return err;
 229 }
 230 
 231 void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
 232 {
 233         if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
 234                 mv88e6xxx_phy_ppu_state_init(chip);
 235 }
 236 
 237 void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
 238 {
 239         if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
 240                 mv88e6xxx_phy_ppu_state_destroy(chip);
 241 }
 242 
 243 int mv88e6xxx_phy_setup(struct mv88e6xxx_chip *chip)
 244 {
 245         return mv88e6xxx_phy_ppu_enable(chip);
 246 }

/* [<][>][^][v][top][bottom][index][help] */