brintos

brintos / linux-shallow public Read only

0
0
Text · 4.3 KiB · 9ae9cc6 Raw
182 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/national.c4 *5 * Driver for National Semiconductor PHYs6 *7 * Author: Stuart Menefy <stuart.menefy@st.com>8 * Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>9 *10 * Copyright (c) 2008 STMicroelectronics Limited11 */12 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt14 15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/mii.h>18#include <linux/ethtool.h>19#include <linux/phy.h>20#include <linux/netdevice.h>21 22/* DP83865 phy identifier values */23#define DP83865_PHY_ID	0x20005c7a24 25#define DP83865_INT_STATUS	0x1426#define DP83865_INT_MASK	0x1527#define DP83865_INT_CLEAR	0x1728 29#define DP83865_INT_REMOTE_FAULT 0x000830#define DP83865_INT_ANE_COMPLETED 0x001031#define DP83865_INT_LINK_CHANGE	0xe00032#define DP83865_INT_MASK_DEFAULT (DP83865_INT_REMOTE_FAULT | \33				DP83865_INT_ANE_COMPLETED | \34				DP83865_INT_LINK_CHANGE)35 36/* Advanced proprietary configuration */37#define NS_EXP_MEM_CTL	0x1638#define NS_EXP_MEM_DATA	0x1d39#define NS_EXP_MEM_ADD	0x1e40 41#define LED_CTRL_REG 0x1342#define AN_FALLBACK_AN 0x000143#define AN_FALLBACK_CRC 0x000244#define AN_FALLBACK_IE 0x000445#define ALL_FALLBACK_ON (AN_FALLBACK_AN |  AN_FALLBACK_CRC | AN_FALLBACK_IE)46 47enum hdx_loopback {48	hdx_loopback_on = 0,49	hdx_loopback_off = 1,50};51 52static u8 ns_exp_read(struct phy_device *phydev, u16 reg)53{54	phy_write(phydev, NS_EXP_MEM_ADD, reg);55	return phy_read(phydev, NS_EXP_MEM_DATA);56}57 58static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data)59{60	phy_write(phydev, NS_EXP_MEM_ADD, reg);61	phy_write(phydev, NS_EXP_MEM_DATA, data);62}63 64static int ns_ack_interrupt(struct phy_device *phydev)65{66	int ret = phy_read(phydev, DP83865_INT_STATUS);67	if (ret < 0)68		return ret;69 70	/* Clear the interrupt status bit by writing a “1”71	 * to the corresponding bit in INT_CLEAR (2:0 are reserved)72	 */73	ret = phy_write(phydev, DP83865_INT_CLEAR, ret & ~0x7);74 75	return ret;76}77 78static irqreturn_t ns_handle_interrupt(struct phy_device *phydev)79{80	int irq_status;81 82	irq_status = phy_read(phydev, DP83865_INT_STATUS);83	if (irq_status < 0) {84		phy_error(phydev);85		return IRQ_NONE;86	}87 88	if (!(irq_status & DP83865_INT_MASK_DEFAULT))89		return IRQ_NONE;90 91	/* clear the interrupt */92	phy_write(phydev, DP83865_INT_CLEAR, irq_status & ~0x7);93 94	phy_trigger_machine(phydev);95 96	return IRQ_HANDLED;97}98 99static int ns_config_intr(struct phy_device *phydev)100{101	int err;102 103	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {104		err = ns_ack_interrupt(phydev);105		if (err)106			return err;107 108		err = phy_write(phydev, DP83865_INT_MASK,109				DP83865_INT_MASK_DEFAULT);110	} else {111		err = phy_write(phydev, DP83865_INT_MASK, 0);112		if (err)113			return err;114 115		err = ns_ack_interrupt(phydev);116	}117 118	return err;119}120 121static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)122{123	int bmcr = phy_read(phydev, MII_BMCR);124 125	phy_write(phydev, MII_BMCR, (bmcr | BMCR_PDOWN));126 127	/* Enable 8 bit expended memory read/write (no auto increment) */128	phy_write(phydev, NS_EXP_MEM_CTL, 0);129	phy_write(phydev, NS_EXP_MEM_ADD, 0x1C0);130	phy_write(phydev, NS_EXP_MEM_DATA, 0x0008);131	phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN));132	phy_write(phydev, LED_CTRL_REG, mode);133}134 135static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)136{137	u16 lb_dis = BIT(1);138 139	if (disable)140		ns_exp_write(phydev, 0x1c0,141			     ns_exp_read(phydev, 0x1c0) | lb_dis);142	else143		ns_exp_write(phydev, 0x1c0,144			     ns_exp_read(phydev, 0x1c0) & ~lb_dis);145 146	pr_debug("10BASE-T HDX loopback %s\n",147		 (ns_exp_read(phydev, 0x1c0) & lb_dis) ? "off" : "on");148}149 150static int ns_config_init(struct phy_device *phydev)151{152	ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON);153	/* In the latest MAC or switches design, the 10 Mbps loopback154	 * is desired to be turned off.155	 */156	ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off);157	return ns_ack_interrupt(phydev);158}159 160static struct phy_driver dp83865_driver[] = { {161	.phy_id = DP83865_PHY_ID,162	.phy_id_mask = 0xfffffff0,163	.name = "NatSemi DP83865",164	/* PHY_GBIT_FEATURES */165	.config_init = ns_config_init,166	.config_intr = ns_config_intr,167	.handle_interrupt = ns_handle_interrupt,168} };169 170module_phy_driver(dp83865_driver);171 172MODULE_DESCRIPTION("NatSemi PHY driver");173MODULE_AUTHOR("Stuart Menefy");174MODULE_LICENSE("GPL");175 176static struct mdio_device_id __maybe_unused ns_tbl[] = {177	{ DP83865_PHY_ID, 0xfffffff0 },178	{ }179};180 181MODULE_DEVICE_TABLE(mdio, ns_tbl);182