brintos

brintos / linux-shallow public Read only

0
0
Text · 7.4 KiB · e3bf827 Raw
359 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/lxt.c4 *5 * Driver for Intel LXT PHYs6 *7 * Author: Andy Fleming8 *9 * Copyright (c) 2004 Freescale Semiconductor, Inc.10 */11#include <linux/kernel.h>12#include <linux/string.h>13#include <linux/errno.h>14#include <linux/unistd.h>15#include <linux/interrupt.h>16#include <linux/init.h>17#include <linux/delay.h>18#include <linux/netdevice.h>19#include <linux/etherdevice.h>20#include <linux/skbuff.h>21#include <linux/spinlock.h>22#include <linux/mm.h>23#include <linux/module.h>24#include <linux/mii.h>25#include <linux/ethtool.h>26#include <linux/phy.h>27 28#include <asm/io.h>29#include <asm/irq.h>30#include <linux/uaccess.h>31 32/* The Level one LXT970 is used by many boards				     */33 34#define MII_LXT970_IER       17  /* Interrupt Enable Register */35 36#define MII_LXT970_IER_IEN	0x000237 38#define MII_LXT970_ISR       18  /* Interrupt Status Register */39 40#define MII_LXT970_IRS_MINT  BIT(15)41 42#define MII_LXT970_CONFIG    19  /* Configuration Register    */43 44/* ------------------------------------------------------------------------- */45/* The Level one LXT971 is used on some of my custom boards                  */46 47/* register definitions for the 971 */48#define MII_LXT971_IER		18  /* Interrupt Enable Register */49#define MII_LXT971_IER_IEN	0x00f250 51#define MII_LXT971_ISR		19  /* Interrupt Status Register */52#define MII_LXT971_ISR_MASK	0x00f053 54/* register definitions for the 973 */55#define MII_LXT973_PCR 16 /* Port Configuration Register */56#define PCR_FIBER_SELECT 157 58MODULE_DESCRIPTION("Intel LXT PHY driver");59MODULE_AUTHOR("Andy Fleming");60MODULE_LICENSE("GPL");61 62static int lxt970_ack_interrupt(struct phy_device *phydev)63{64	int err;65 66	err = phy_read(phydev, MII_BMSR);67 68	if (err < 0)69		return err;70 71	err = phy_read(phydev, MII_LXT970_ISR);72 73	if (err < 0)74		return err;75 76	return 0;77}78 79static int lxt970_config_intr(struct phy_device *phydev)80{81	int err;82 83	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {84		err = lxt970_ack_interrupt(phydev);85		if (err)86			return err;87 88		err = phy_write(phydev, MII_LXT970_IER, MII_LXT970_IER_IEN);89	} else {90		err = phy_write(phydev, MII_LXT970_IER, 0);91		if (err)92			return err;93 94		err = lxt970_ack_interrupt(phydev);95	}96 97	return err;98}99 100static irqreturn_t lxt970_handle_interrupt(struct phy_device *phydev)101{102	int irq_status;103 104	/* The interrupt status register is cleared by reading BMSR105	 * followed by MII_LXT970_ISR106	 */107	irq_status = phy_read(phydev, MII_BMSR);108	if (irq_status < 0) {109		phy_error(phydev);110		return IRQ_NONE;111	}112 113	irq_status = phy_read(phydev, MII_LXT970_ISR);114	if (irq_status < 0) {115		phy_error(phydev);116		return IRQ_NONE;117	}118 119	if (!(irq_status & MII_LXT970_IRS_MINT))120		return IRQ_NONE;121 122	phy_trigger_machine(phydev);123 124	return IRQ_HANDLED;125}126 127static int lxt970_config_init(struct phy_device *phydev)128{129	return phy_write(phydev, MII_LXT970_CONFIG, 0);130}131 132 133static int lxt971_ack_interrupt(struct phy_device *phydev)134{135	int err = phy_read(phydev, MII_LXT971_ISR);136 137	if (err < 0)138		return err;139 140	return 0;141}142 143static int lxt971_config_intr(struct phy_device *phydev)144{145	int err;146 147	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {148		err = lxt971_ack_interrupt(phydev);149		if (err)150			return err;151 152		err = phy_write(phydev, MII_LXT971_IER, MII_LXT971_IER_IEN);153	} else {154		err = phy_write(phydev, MII_LXT971_IER, 0);155		if (err)156			return err;157 158		err = lxt971_ack_interrupt(phydev);159	}160 161	return err;162}163 164static irqreturn_t lxt971_handle_interrupt(struct phy_device *phydev)165{166	int irq_status;167 168	irq_status = phy_read(phydev, MII_LXT971_ISR);169	if (irq_status < 0) {170		phy_error(phydev);171		return IRQ_NONE;172	}173 174	if (!(irq_status & MII_LXT971_ISR_MASK))175		return IRQ_NONE;176 177	phy_trigger_machine(phydev);178 179	return IRQ_HANDLED;180}181 182/*183 * A2 version of LXT973 chip has an ERRATA: it randomly return the contents184 * of the previous even register when you read a odd register regularly185 */186 187static int lxt973a2_update_link(struct phy_device *phydev)188{189	int status;190	int control;191	int retry = 8; /* we try 8 times */192 193	/* Do a fake read */194	status = phy_read(phydev, MII_BMSR);195 196	if (status < 0)197		return status;198 199	control = phy_read(phydev, MII_BMCR);200	if (control < 0)201		return control;202 203	do {204		/* Read link and autonegotiation status */205		status = phy_read(phydev, MII_BMSR);206	} while (status >= 0 && retry-- && status == control);207 208	if (status < 0)209		return status;210 211	if ((status & BMSR_LSTATUS) == 0)212		phydev->link = 0;213	else214		phydev->link = 1;215 216	return 0;217}218 219static int lxt973a2_read_status(struct phy_device *phydev)220{221	int adv;222	int err;223	int lpa;224 225	/* Update the link, but return if there was an error */226	err = lxt973a2_update_link(phydev);227	if (err)228		return err;229 230	if (AUTONEG_ENABLE == phydev->autoneg) {231		int retry = 1;232 233		adv = phy_read(phydev, MII_ADVERTISE);234 235		if (adv < 0)236			return adv;237 238		do {239			lpa = phy_read(phydev, MII_LPA);240 241			if (lpa < 0)242				return lpa;243 244			/* If both registers are equal, it is suspect but not245			 * impossible, hence a new try246			 */247		} while (lpa == adv && retry--);248 249		mii_lpa_to_linkmode_lpa_t(phydev->lp_advertising, lpa);250 251		lpa &= adv;252 253		phydev->speed = SPEED_10;254		phydev->duplex = DUPLEX_HALF;255		phydev->pause = phydev->asym_pause = 0;256 257		if (lpa & (LPA_100FULL | LPA_100HALF)) {258			phydev->speed = SPEED_100;259 260			if (lpa & LPA_100FULL)261				phydev->duplex = DUPLEX_FULL;262		} else {263			if (lpa & LPA_10FULL)264				phydev->duplex = DUPLEX_FULL;265		}266 267		phy_resolve_aneg_pause(phydev);268	} else {269		err = genphy_read_status_fixed(phydev);270		if (err < 0)271			return err;272 273		phydev->pause = phydev->asym_pause = 0;274		linkmode_zero(phydev->lp_advertising);275	}276 277	return 0;278}279 280static int lxt973_probe(struct phy_device *phydev)281{282	int val = phy_read(phydev, MII_LXT973_PCR);283 284	if (val & PCR_FIBER_SELECT) {285		/*286		 * If fiber is selected, then the only correct setting287		 * is 100Mbps, full duplex, and auto negotiation off.288		 */289		val = phy_read(phydev, MII_BMCR);290		val |= (BMCR_SPEED100 | BMCR_FULLDPLX);291		val &= ~BMCR_ANENABLE;292		phy_write(phydev, MII_BMCR, val);293		/* Remember that the port is in fiber mode. */294		phydev->priv = lxt973_probe;295		phydev->port = PORT_FIBRE;296	} else {297		phydev->priv = NULL;298	}299	return 0;300}301 302static int lxt973_config_aneg(struct phy_device *phydev)303{304	/* Do nothing if port is in fiber mode. */305	return phydev->priv ? 0 : genphy_config_aneg(phydev);306}307 308static struct phy_driver lxt97x_driver[] = {309{310	.phy_id		= 0x78100000,311	.name		= "LXT970",312	.phy_id_mask	= 0xfffffff0,313	/* PHY_BASIC_FEATURES */314	.config_init	= lxt970_config_init,315	.config_intr	= lxt970_config_intr,316	.handle_interrupt = lxt970_handle_interrupt,317}, {318	.phy_id		= 0x001378e0,319	.name		= "LXT971",320	.phy_id_mask	= 0xfffffff0,321	/* PHY_BASIC_FEATURES */322	.config_intr	= lxt971_config_intr,323	.handle_interrupt = lxt971_handle_interrupt,324	.suspend	= genphy_suspend,325	.resume		= genphy_resume,326}, {327	.phy_id		= 0x00137a10,328	.name		= "LXT973-A2",329	.phy_id_mask	= 0xffffffff,330	/* PHY_BASIC_FEATURES */331	.flags		= 0,332	.probe		= lxt973_probe,333	.config_aneg	= lxt973_config_aneg,334	.read_status	= lxt973a2_read_status,335	.suspend	= genphy_suspend,336	.resume		= genphy_resume,337}, {338	.phy_id		= 0x00137a10,339	.name		= "LXT973",340	.phy_id_mask	= 0xfffffff0,341	/* PHY_BASIC_FEATURES */342	.flags		= 0,343	.probe		= lxt973_probe,344	.config_aneg	= lxt973_config_aneg,345	.suspend	= genphy_suspend,346	.resume		= genphy_resume,347} };348 349module_phy_driver(lxt97x_driver);350 351static struct mdio_device_id __maybe_unused lxt_tbl[] = {352	{ 0x78100000, 0xfffffff0 },353	{ 0x001378e0, 0xfffffff0 },354	{ 0x00137a10, 0xfffffff0 },355	{ }356};357 358MODULE_DEVICE_TABLE(mdio, lxt_tbl);359