| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | /* | 
|  | 2 | * Driver for AMD am79c PHYs | 
|  | 3 | * | 
|  | 4 | * Author: Heiko Schocher <hs@denx.de> | 
|  | 5 | * | 
|  | 6 | * Copyright (c) 2011 DENX Software Engineering GmbH | 
|  | 7 | * | 
|  | 8 | * This program is free software; you can redistribute  it and/or modify it | 
|  | 9 | * under  the terms of  the GNU General  Public License as published by the | 
|  | 10 | * Free Software Foundation;  either version 2 of the  License, or (at your | 
|  | 11 | * option) any later version. | 
|  | 12 | * | 
|  | 13 | */ | 
|  | 14 | #include <linux/kernel.h> | 
|  | 15 | #include <linux/errno.h> | 
|  | 16 | #include <linux/init.h> | 
|  | 17 | #include <linux/module.h> | 
|  | 18 | #include <linux/mii.h> | 
|  | 19 | #include <linux/phy.h> | 
|  | 20 |  | 
|  | 21 | #define PHY_ID_AM79C874		0x0022561b | 
|  | 22 |  | 
|  | 23 | #define MII_AM79C_IR		17	/* Interrupt Status/Control Register */ | 
|  | 24 | #define MII_AM79C_IR_EN_LINK	0x0400	/* IR enable Linkstate */ | 
|  | 25 | #define MII_AM79C_IR_EN_ANEG	0x0100	/* IR enable Aneg Complete */ | 
|  | 26 | #define MII_AM79C_IR_IMASK_INIT	(MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG) | 
|  | 27 |  | 
|  | 28 | MODULE_DESCRIPTION("AMD PHY driver"); | 
|  | 29 | MODULE_AUTHOR("Heiko Schocher <hs@denx.de>"); | 
|  | 30 | MODULE_LICENSE("GPL"); | 
|  | 31 |  | 
|  | 32 | static 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 |  | 
|  | 47 | static int am79c_config_init(struct phy_device *phydev) | 
|  | 48 | { | 
|  | 49 | return 0; | 
|  | 50 | } | 
|  | 51 |  | 
|  | 52 | static int am79c_config_intr(struct phy_device *phydev) | 
|  | 53 | { | 
|  | 54 | int err; | 
|  | 55 |  | 
|  | 56 | if (phydev->interrupts == PHY_INTERRUPT_ENABLED) | 
|  | 57 | err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT); | 
|  | 58 | else | 
|  | 59 | err = phy_write(phydev, MII_AM79C_IR, 0); | 
|  | 60 |  | 
|  | 61 | return err; | 
|  | 62 | } | 
|  | 63 |  | 
|  | 64 | static struct phy_driver am79c_driver[] = { { | 
|  | 65 | .phy_id		= PHY_ID_AM79C874, | 
|  | 66 | .name		= "AM79C874", | 
|  | 67 | .phy_id_mask	= 0xfffffff0, | 
|  | 68 | .features	= PHY_BASIC_FEATURES, | 
|  | 69 | .flags		= PHY_HAS_INTERRUPT, | 
|  | 70 | .config_init	= am79c_config_init, | 
|  | 71 | .ack_interrupt	= am79c_ack_interrupt, | 
|  | 72 | .config_intr	= am79c_config_intr, | 
|  | 73 | } }; | 
|  | 74 |  | 
|  | 75 | module_phy_driver(am79c_driver); | 
|  | 76 |  | 
|  | 77 | static struct mdio_device_id __maybe_unused amd_tbl[] = { | 
|  | 78 | { PHY_ID_AM79C874, 0xfffffff0 }, | 
|  | 79 | { } | 
|  | 80 | }; | 
|  | 81 |  | 
|  | 82 | MODULE_DEVICE_TABLE(mdio, amd_tbl); |