brintos

brintos / linux-shallow public Read only

0
0
Text · 3.6 KiB · ef5f412 Raw
155 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/cicada.c4 *5 * Driver for Cicada 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 <linux/io.h>29#include <asm/irq.h>30#include <linux/uaccess.h>31 32/* Cicada Extended Control Register 1 */33#define MII_CIS8201_EXT_CON1           0x1734#define MII_CIS8201_EXTCON1_INIT       0x000035 36/* Cicada Interrupt Mask Register */37#define MII_CIS8201_IMASK		0x1938#define MII_CIS8201_IMASK_IEN		0x800039#define MII_CIS8201_IMASK_SPEED	0x400040#define MII_CIS8201_IMASK_LINK		0x200041#define MII_CIS8201_IMASK_DUPLEX	0x100042#define MII_CIS8201_IMASK_MASK		0xf00043 44/* Cicada Interrupt Status Register */45#define MII_CIS8201_ISTAT		0x1a46#define MII_CIS8201_ISTAT_STATUS	0x800047#define MII_CIS8201_ISTAT_SPEED	0x400048#define MII_CIS8201_ISTAT_LINK		0x200049#define MII_CIS8201_ISTAT_DUPLEX	0x100050 51/* Cicada Auxiliary Control/Status Register */52#define MII_CIS8201_AUX_CONSTAT        0x1c53#define MII_CIS8201_AUXCONSTAT_INIT    0x000454#define MII_CIS8201_AUXCONSTAT_DUPLEX  0x002055#define MII_CIS8201_AUXCONSTAT_SPEED   0x001856#define MII_CIS8201_AUXCONSTAT_GBIT    0x001057#define MII_CIS8201_AUXCONSTAT_100     0x000858 59MODULE_DESCRIPTION("Cicadia PHY driver");60MODULE_AUTHOR("Andy Fleming");61MODULE_LICENSE("GPL");62 63static int cis820x_config_init(struct phy_device *phydev)64{65	int err;66 67	err = phy_write(phydev, MII_CIS8201_AUX_CONSTAT,68			MII_CIS8201_AUXCONSTAT_INIT);69 70	if (err < 0)71		return err;72 73	err = phy_write(phydev, MII_CIS8201_EXT_CON1,74			MII_CIS8201_EXTCON1_INIT);75 76	return err;77}78 79static int cis820x_ack_interrupt(struct phy_device *phydev)80{81	int err = phy_read(phydev, MII_CIS8201_ISTAT);82 83	return (err < 0) ? err : 0;84}85 86static int cis820x_config_intr(struct phy_device *phydev)87{88	int err;89 90	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {91		err = cis820x_ack_interrupt(phydev);92		if (err)93			return err;94 95		err = phy_write(phydev, MII_CIS8201_IMASK,96				MII_CIS8201_IMASK_MASK);97	} else {98		err = phy_write(phydev, MII_CIS8201_IMASK, 0);99		if (err)100			return err;101 102		err = cis820x_ack_interrupt(phydev);103	}104 105	return err;106}107 108static irqreturn_t cis820x_handle_interrupt(struct phy_device *phydev)109{110	int irq_status;111 112	irq_status = phy_read(phydev, MII_CIS8201_ISTAT);113	if (irq_status < 0) {114		phy_error(phydev);115		return IRQ_NONE;116	}117 118	if (!(irq_status & MII_CIS8201_IMASK_MASK))119		return IRQ_NONE;120 121	phy_trigger_machine(phydev);122 123	return IRQ_HANDLED;124}125 126/* Cicada 8201, a.k.a Vitesse VSC8201 */127static struct phy_driver cis820x_driver[] = {128{129	.phy_id		= 0x000fc410,130	.name		= "Cicada Cis8201",131	.phy_id_mask	= 0x000ffff0,132	/* PHY_GBIT_FEATURES */133	.config_init	= &cis820x_config_init,134	.config_intr	= &cis820x_config_intr,135	.handle_interrupt = &cis820x_handle_interrupt,136}, {137	.phy_id		= 0x000fc440,138	.name		= "Cicada Cis8204",139	.phy_id_mask	= 0x000fffc0,140	/* PHY_GBIT_FEATURES */141	.config_init	= &cis820x_config_init,142	.config_intr	= &cis820x_config_intr,143	.handle_interrupt = &cis820x_handle_interrupt,144} };145 146module_phy_driver(cis820x_driver);147 148static struct mdio_device_id __maybe_unused cicada_tbl[] = {149	{ 0x000fc410, 0x000ffff0 },150	{ 0x000fc440, 0x000fffc0 },151	{ }152};153 154MODULE_DEVICE_TABLE(mdio, cicada_tbl);155