162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/net/phy/et1011c.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Driver for LSI ET1011C PHYs
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Author: Chaithrika U S
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Copyright (c) 2008 Texas Instruments
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci#include <linux/errno.h>
1462306a36Sopenharmony_ci#include <linux/unistd.h>
1562306a36Sopenharmony_ci#include <linux/interrupt.h>
1662306a36Sopenharmony_ci#include <linux/init.h>
1762306a36Sopenharmony_ci#include <linux/delay.h>
1862306a36Sopenharmony_ci#include <linux/netdevice.h>
1962306a36Sopenharmony_ci#include <linux/etherdevice.h>
2062306a36Sopenharmony_ci#include <linux/skbuff.h>
2162306a36Sopenharmony_ci#include <linux/spinlock.h>
2262306a36Sopenharmony_ci#include <linux/mm.h>
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci#include <linux/mii.h>
2562306a36Sopenharmony_ci#include <linux/ethtool.h>
2662306a36Sopenharmony_ci#include <linux/phy.h>
2762306a36Sopenharmony_ci#include <linux/io.h>
2862306a36Sopenharmony_ci#include <linux/uaccess.h>
2962306a36Sopenharmony_ci#include <asm/irq.h>
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define ET1011C_STATUS_REG	(0x1A)
3262306a36Sopenharmony_ci#define ET1011C_CONFIG_REG	(0x16)
3362306a36Sopenharmony_ci#define ET1011C_SPEED_MASK		(0x0300)
3462306a36Sopenharmony_ci#define ET1011C_GIGABIT_SPEED		(0x0200)
3562306a36Sopenharmony_ci#define ET1011C_TX_FIFO_MASK		(0x3000)
3662306a36Sopenharmony_ci#define ET1011C_TX_FIFO_DEPTH_8		(0x0000)
3762306a36Sopenharmony_ci#define ET1011C_TX_FIFO_DEPTH_16	(0x1000)
3862306a36Sopenharmony_ci#define ET1011C_INTERFACE_MASK		(0x0007)
3962306a36Sopenharmony_ci#define ET1011C_GMII_INTERFACE		(0x0002)
4062306a36Sopenharmony_ci#define ET1011C_SYS_CLK_EN		(0x01 << 4)
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciMODULE_DESCRIPTION("LSI ET1011C PHY driver");
4462306a36Sopenharmony_ciMODULE_AUTHOR("Chaithrika U S");
4562306a36Sopenharmony_ciMODULE_LICENSE("GPL");
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int et1011c_config_aneg(struct phy_device *phydev)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	int ctl = phy_read(phydev, MII_BMCR);
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (ctl < 0)
5262306a36Sopenharmony_ci		return ctl;
5362306a36Sopenharmony_ci	ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
5462306a36Sopenharmony_ci		 BMCR_ANENABLE);
5562306a36Sopenharmony_ci	/* First clear the PHY */
5662306a36Sopenharmony_ci	phy_write(phydev, MII_BMCR, ctl | BMCR_RESET);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	return genphy_config_aneg(phydev);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cistatic int et1011c_read_status(struct phy_device *phydev)
6262306a36Sopenharmony_ci{
6362306a36Sopenharmony_ci	static int speed;
6462306a36Sopenharmony_ci	int ret;
6562306a36Sopenharmony_ci	u32 val;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	ret = genphy_read_status(phydev);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (speed != phydev->speed) {
7062306a36Sopenharmony_ci		speed = phydev->speed;
7162306a36Sopenharmony_ci		val = phy_read(phydev, ET1011C_STATUS_REG);
7262306a36Sopenharmony_ci		if ((val & ET1011C_SPEED_MASK) ==
7362306a36Sopenharmony_ci					ET1011C_GIGABIT_SPEED) {
7462306a36Sopenharmony_ci			val = phy_read(phydev, ET1011C_CONFIG_REG);
7562306a36Sopenharmony_ci			val &= ~ET1011C_TX_FIFO_MASK;
7662306a36Sopenharmony_ci			phy_write(phydev, ET1011C_CONFIG_REG, val |
7762306a36Sopenharmony_ci					  ET1011C_GMII_INTERFACE |
7862306a36Sopenharmony_ci					  ET1011C_SYS_CLK_EN |
7962306a36Sopenharmony_ci					  ET1011C_TX_FIFO_DEPTH_16);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		}
8262306a36Sopenharmony_ci	}
8362306a36Sopenharmony_ci	return ret;
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic struct phy_driver et1011c_driver[] = { {
8762306a36Sopenharmony_ci	.phy_id		= 0x0282f014,
8862306a36Sopenharmony_ci	.name		= "ET1011C",
8962306a36Sopenharmony_ci	.phy_id_mask	= 0xfffffff0,
9062306a36Sopenharmony_ci	/* PHY_GBIT_FEATURES */
9162306a36Sopenharmony_ci	.config_aneg	= et1011c_config_aneg,
9262306a36Sopenharmony_ci	.read_status	= et1011c_read_status,
9362306a36Sopenharmony_ci} };
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cimodule_phy_driver(et1011c_driver);
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic struct mdio_device_id __maybe_unused et1011c_tbl[] = {
9862306a36Sopenharmony_ci	{ 0x0282f014, 0xfffffff0 },
9962306a36Sopenharmony_ci	{ }
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, et1011c_tbl);
103