121 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Driver for AMD am79c PHYs4 *5 * Author: Heiko Schocher <hs@denx.de>6 *7 * Copyright (c) 2011 DENX Software Engineering GmbH8 */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_AC101L 0x0022552017#define PHY_ID_AM79C874 0x0022561b18 19#define MII_AM79C_IR 17 /* Interrupt Status/Control Register */20#define MII_AM79C_IR_EN_LINK 0x0400 /* IR enable Linkstate */21#define MII_AM79C_IR_EN_ANEG 0x0100 /* IR enable Aneg Complete */22#define MII_AM79C_IR_IMASK_INIT (MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG)23 24#define MII_AM79C_IR_LINK_DOWN BIT(2)25#define MII_AM79C_IR_ANEG_DONE BIT(0)26#define MII_AM79C_IR_IMASK_STAT (MII_AM79C_IR_LINK_DOWN | MII_AM79C_IR_ANEG_DONE)27 28MODULE_DESCRIPTION("AMD PHY driver");29MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");30MODULE_LICENSE("GPL");31 32static int am79c_ack_interrupt(struct phy_device *phydev)33{34 int err;35 36 err = phy_read(phydev, MII_BMSR);37 if (err < 0)38 return err;39 40 err = phy_read(phydev, MII_AM79C_IR);41 if (err < 0)42 return err;43 44 return 0;45}46 47static int am79c_config_init(struct phy_device *phydev)48{49 return 0;50}51 52static int am79c_config_intr(struct phy_device *phydev)53{54 int err;55 56 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {57 err = am79c_ack_interrupt(phydev);58 if (err)59 return err;60 61 err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT);62 } else {63 err = phy_write(phydev, MII_AM79C_IR, 0);64 if (err)65 return err;66 67 err = am79c_ack_interrupt(phydev);68 }69 70 return err;71}72 73static irqreturn_t am79c_handle_interrupt(struct phy_device *phydev)74{75 int irq_status;76 77 irq_status = phy_read(phydev, MII_AM79C_IR);78 if (irq_status < 0) {79 phy_error(phydev);80 return IRQ_NONE;81 }82 83 if (!(irq_status & MII_AM79C_IR_IMASK_STAT))84 return IRQ_NONE;85 86 phy_trigger_machine(phydev);87 88 return IRQ_HANDLED;89}90 91static struct phy_driver am79c_drivers[] = {92 {93 .phy_id = PHY_ID_AM79C874,94 .name = "AM79C874",95 .phy_id_mask = 0xfffffff0,96 /* PHY_BASIC_FEATURES */97 .config_init = am79c_config_init,98 .config_intr = am79c_config_intr,99 .handle_interrupt = am79c_handle_interrupt,100 },101 {102 .phy_id = PHY_ID_AC101L,103 .name = "AC101L",104 .phy_id_mask = 0xfffffff0,105 /* PHY_BASIC_FEATURES */106 .config_init = am79c_config_init,107 .config_intr = am79c_config_intr,108 .handle_interrupt = am79c_handle_interrupt,109 },110};111 112module_phy_driver(am79c_drivers);113 114static struct mdio_device_id __maybe_unused amd_tbl[] = {115 { PHY_ID_AC101L, 0xfffffff0 },116 { PHY_ID_AM79C874, 0xfffffff0 },117 { }118};119 120MODULE_DEVICE_TABLE(mdio, amd_tbl);121