18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for AMD am79c PHYs
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Heiko Schocher <hs@denx.de>
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (c) 2011 DENX Software Engineering GmbH
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/errno.h>
118c2ecf20Sopenharmony_ci#include <linux/init.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/mii.h>
148c2ecf20Sopenharmony_ci#include <linux/phy.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define PHY_ID_AM79C874		0x0022561b
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define MII_AM79C_IR		17	/* Interrupt Status/Control Register */
198c2ecf20Sopenharmony_ci#define MII_AM79C_IR_EN_LINK	0x0400	/* IR enable Linkstate */
208c2ecf20Sopenharmony_ci#define MII_AM79C_IR_EN_ANEG	0x0100	/* IR enable Aneg Complete */
218c2ecf20Sopenharmony_ci#define MII_AM79C_IR_IMASK_INIT	(MII_AM79C_IR_EN_LINK | MII_AM79C_IR_EN_ANEG)
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD PHY driver");
248c2ecf20Sopenharmony_ciMODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
258c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic int am79c_ack_interrupt(struct phy_device *phydev)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	int err;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	err = phy_read(phydev, MII_BMSR);
328c2ecf20Sopenharmony_ci	if (err < 0)
338c2ecf20Sopenharmony_ci		return err;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	err = phy_read(phydev, MII_AM79C_IR);
368c2ecf20Sopenharmony_ci	if (err < 0)
378c2ecf20Sopenharmony_ci		return err;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return 0;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int am79c_config_init(struct phy_device *phydev)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	return 0;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int am79c_config_intr(struct phy_device *phydev)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	int err;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
528c2ecf20Sopenharmony_ci		err = phy_write(phydev, MII_AM79C_IR, MII_AM79C_IR_IMASK_INIT);
538c2ecf20Sopenharmony_ci	else
548c2ecf20Sopenharmony_ci		err = phy_write(phydev, MII_AM79C_IR, 0);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	return err;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic struct phy_driver am79c_driver[] = { {
608c2ecf20Sopenharmony_ci	.phy_id		= PHY_ID_AM79C874,
618c2ecf20Sopenharmony_ci	.name		= "AM79C874",
628c2ecf20Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
638c2ecf20Sopenharmony_ci	/* PHY_BASIC_FEATURES */
648c2ecf20Sopenharmony_ci	.config_init	= am79c_config_init,
658c2ecf20Sopenharmony_ci	.ack_interrupt	= am79c_ack_interrupt,
668c2ecf20Sopenharmony_ci	.config_intr	= am79c_config_intr,
678c2ecf20Sopenharmony_ci} };
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cimodule_phy_driver(am79c_driver);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic struct mdio_device_id __maybe_unused amd_tbl[] = {
728c2ecf20Sopenharmony_ci	{ PHY_ID_AM79C874, 0xfffffff0 },
738c2ecf20Sopenharmony_ci	{ }
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, amd_tbl);
77