brintos

brintos / linux-shallow public Read only

0
0
Text · 4.0 KiB · 30d15f7 Raw
164 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/qsemi.c4 *5 * Driver for Quality Semiconductor 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/* ------------------------------------------------------------------------- */33/* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */34 35/* register definitions */36 37#define MII_QS6612_MCR		17  /* Mode Control Register      */38#define MII_QS6612_FTR		27  /* Factory Test Register      */39#define MII_QS6612_MCO		28  /* Misc. Control Register     */40#define MII_QS6612_ISR		29  /* Interrupt Source Register  */41#define MII_QS6612_IMR		30  /* Interrupt Mask Register    */42#define MII_QS6612_IMR_INIT	0x003a43#define MII_QS6612_PCR		31  /* 100BaseTx PHY Control Reg. */44 45#define QS6612_PCR_AN_COMPLETE	0x100046#define QS6612_PCR_RLBEN	0x020047#define QS6612_PCR_DCREN	0x010048#define QS6612_PCR_4B5BEN	0x004049#define QS6612_PCR_TX_ISOLATE	0x002050#define QS6612_PCR_MLT3_DIS	0x000251#define QS6612_PCR_SCRM_DESCRM	0x000152 53MODULE_DESCRIPTION("Quality Semiconductor PHY driver");54MODULE_AUTHOR("Andy Fleming");55MODULE_LICENSE("GPL");56 57/* Returns 0, unless there's a write error */58static int qs6612_config_init(struct phy_device *phydev)59{60	/* The PHY powers up isolated on the RPX,61	 * so send a command to allow operation.62	 * XXX - My docs indicate this should be 0x094063	 * ...or something.  The current value sets three64	 * reserved bits, bit 11, which specifies it should be65	 * set to one, bit 10, which specifies it should be set66	 * to 0, and bit 7, which doesn't specify.  However, my67	 * docs are preliminary, and I will leave it like this68	 * until someone more knowledgable corrects me or it.69	 * -- Andy Fleming70	 */71	return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);72}73 74static int qs6612_ack_interrupt(struct phy_device *phydev)75{76	int err;77 78	/* The Interrupt Source register is not self-clearing, bits 4 and 5 are79	 * cleared when MII_BMSR is read and bits 1 and 3 are cleared when80	 * MII_EXPANSION is read81	 */82	err = phy_read(phydev, MII_QS6612_ISR);83 84	if (err < 0)85		return err;86 87	err = phy_read(phydev, MII_BMSR);88 89	if (err < 0)90		return err;91 92	err = phy_read(phydev, MII_EXPANSION);93 94	if (err < 0)95		return err;96 97	return 0;98}99 100static int qs6612_config_intr(struct phy_device *phydev)101{102	int err;103 104	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {105		/* clear any interrupts before enabling them */106		err = qs6612_ack_interrupt(phydev);107		if (err)108			return err;109 110		err = phy_write(phydev, MII_QS6612_IMR,111				MII_QS6612_IMR_INIT);112	} else {113		err = phy_write(phydev, MII_QS6612_IMR, 0);114		if (err)115			return err;116 117		/* clear any leftover interrupts */118		err = qs6612_ack_interrupt(phydev);119	}120 121	return err;122 123}124 125static irqreturn_t qs6612_handle_interrupt(struct phy_device *phydev)126{127	int irq_status;128 129	irq_status = phy_read(phydev, MII_QS6612_ISR);130	if (irq_status < 0) {131		phy_error(phydev);132		return IRQ_NONE;133	}134 135	if (!(irq_status & MII_QS6612_IMR_INIT))136		return IRQ_NONE;137 138	/* the interrupt source register is not self-clearing */139	qs6612_ack_interrupt(phydev);140 141	phy_trigger_machine(phydev);142 143	return IRQ_HANDLED;144}145 146static struct phy_driver qs6612_driver[] = { {147	.phy_id		= 0x00181440,148	.name		= "QS6612",149	.phy_id_mask	= 0xfffffff0,150	/* PHY_BASIC_FEATURES */151	.config_init	= qs6612_config_init,152	.config_intr	= qs6612_config_intr,153	.handle_interrupt = qs6612_handle_interrupt,154} };155 156module_phy_driver(qs6612_driver);157 158static struct mdio_device_id __maybe_unused qs6612_tbl[] = {159	{ 0x00181440, 0xfffffff0 },160	{ }161};162 163MODULE_DEVICE_TABLE(mdio, qs6612_tbl);164