1*00db8189SAndy Fleming /* 2*00db8189SAndy Fleming * drivers/net/phy/qsemi.c 3*00db8189SAndy Fleming * 4*00db8189SAndy Fleming * Driver for Quality Semiconductor PHYs 5*00db8189SAndy Fleming * 6*00db8189SAndy Fleming * Author: Andy Fleming 7*00db8189SAndy Fleming * 8*00db8189SAndy Fleming * Copyright (c) 2004 Freescale Semiconductor, Inc. 9*00db8189SAndy Fleming * 10*00db8189SAndy Fleming * This program is free software; you can redistribute it and/or modify it 11*00db8189SAndy Fleming * under the terms of the GNU General Public License as published by the 12*00db8189SAndy Fleming * Free Software Foundation; either version 2 of the License, or (at your 13*00db8189SAndy Fleming * option) any later version. 14*00db8189SAndy Fleming * 15*00db8189SAndy Fleming */ 16*00db8189SAndy Fleming #include <linux/config.h> 17*00db8189SAndy Fleming #include <linux/kernel.h> 18*00db8189SAndy Fleming #include <linux/sched.h> 19*00db8189SAndy Fleming #include <linux/string.h> 20*00db8189SAndy Fleming #include <linux/errno.h> 21*00db8189SAndy Fleming #include <linux/unistd.h> 22*00db8189SAndy Fleming #include <linux/slab.h> 23*00db8189SAndy Fleming #include <linux/interrupt.h> 24*00db8189SAndy Fleming #include <linux/init.h> 25*00db8189SAndy Fleming #include <linux/delay.h> 26*00db8189SAndy Fleming #include <linux/netdevice.h> 27*00db8189SAndy Fleming #include <linux/etherdevice.h> 28*00db8189SAndy Fleming #include <linux/skbuff.h> 29*00db8189SAndy Fleming #include <linux/spinlock.h> 30*00db8189SAndy Fleming #include <linux/mm.h> 31*00db8189SAndy Fleming #include <linux/module.h> 32*00db8189SAndy Fleming #include <linux/version.h> 33*00db8189SAndy Fleming #include <linux/mii.h> 34*00db8189SAndy Fleming #include <linux/ethtool.h> 35*00db8189SAndy Fleming #include <linux/phy.h> 36*00db8189SAndy Fleming 37*00db8189SAndy Fleming #include <asm/io.h> 38*00db8189SAndy Fleming #include <asm/irq.h> 39*00db8189SAndy Fleming #include <asm/uaccess.h> 40*00db8189SAndy Fleming 41*00db8189SAndy Fleming /* ------------------------------------------------------------------------- */ 42*00db8189SAndy Fleming /* The Quality Semiconductor QS6612 is used on the RPX CLLF */ 43*00db8189SAndy Fleming 44*00db8189SAndy Fleming /* register definitions */ 45*00db8189SAndy Fleming 46*00db8189SAndy Fleming #define MII_QS6612_MCR 17 /* Mode Control Register */ 47*00db8189SAndy Fleming #define MII_QS6612_FTR 27 /* Factory Test Register */ 48*00db8189SAndy Fleming #define MII_QS6612_MCO 28 /* Misc. Control Register */ 49*00db8189SAndy Fleming #define MII_QS6612_ISR 29 /* Interrupt Source Register */ 50*00db8189SAndy Fleming #define MII_QS6612_IMR 30 /* Interrupt Mask Register */ 51*00db8189SAndy Fleming #define MII_QS6612_IMR_INIT 0x003a 52*00db8189SAndy Fleming #define MII_QS6612_PCR 31 /* 100BaseTx PHY Control Reg. */ 53*00db8189SAndy Fleming 54*00db8189SAndy Fleming #define QS6612_PCR_AN_COMPLETE 0x1000 55*00db8189SAndy Fleming #define QS6612_PCR_RLBEN 0x0200 56*00db8189SAndy Fleming #define QS6612_PCR_DCREN 0x0100 57*00db8189SAndy Fleming #define QS6612_PCR_4B5BEN 0x0040 58*00db8189SAndy Fleming #define QS6612_PCR_TX_ISOLATE 0x0020 59*00db8189SAndy Fleming #define QS6612_PCR_MLT3_DIS 0x0002 60*00db8189SAndy Fleming #define QS6612_PCR_SCRM_DESCRM 0x0001 61*00db8189SAndy Fleming 62*00db8189SAndy Fleming MODULE_DESCRIPTION("Quality Semiconductor PHY driver"); 63*00db8189SAndy Fleming MODULE_AUTHOR("Andy Fleming"); 64*00db8189SAndy Fleming MODULE_LICENSE("GPL"); 65*00db8189SAndy Fleming 66*00db8189SAndy Fleming /* Returns 0, unless there's a write error */ 67*00db8189SAndy Fleming static int qs6612_config_init(struct phy_device *phydev) 68*00db8189SAndy Fleming { 69*00db8189SAndy Fleming /* The PHY powers up isolated on the RPX, 70*00db8189SAndy Fleming * so send a command to allow operation. 71*00db8189SAndy Fleming * XXX - My docs indicate this should be 0x0940 72*00db8189SAndy Fleming * ...or something. The current value sets three 73*00db8189SAndy Fleming * reserved bits, bit 11, which specifies it should be 74*00db8189SAndy Fleming * set to one, bit 10, which specifies it should be set 75*00db8189SAndy Fleming * to 0, and bit 7, which doesn't specify. However, my 76*00db8189SAndy Fleming * docs are preliminary, and I will leave it like this 77*00db8189SAndy Fleming * until someone more knowledgable corrects me or it. 78*00db8189SAndy Fleming * -- Andy Fleming 79*00db8189SAndy Fleming */ 80*00db8189SAndy Fleming return phy_write(phydev, MII_QS6612_PCR, 0x0dc0); 81*00db8189SAndy Fleming } 82*00db8189SAndy Fleming 83*00db8189SAndy Fleming static int qs6612_ack_interrupt(struct phy_device *phydev) 84*00db8189SAndy Fleming { 85*00db8189SAndy Fleming int err; 86*00db8189SAndy Fleming 87*00db8189SAndy Fleming err = phy_read(phydev, MII_QS6612_ISR); 88*00db8189SAndy Fleming 89*00db8189SAndy Fleming if (err < 0) 90*00db8189SAndy Fleming return err; 91*00db8189SAndy Fleming 92*00db8189SAndy Fleming err = phy_read(phydev, MII_BMSR); 93*00db8189SAndy Fleming 94*00db8189SAndy Fleming if (err < 0) 95*00db8189SAndy Fleming return err; 96*00db8189SAndy Fleming 97*00db8189SAndy Fleming err = phy_read(phydev, MII_EXPANSION); 98*00db8189SAndy Fleming 99*00db8189SAndy Fleming if (err < 0) 100*00db8189SAndy Fleming return err; 101*00db8189SAndy Fleming 102*00db8189SAndy Fleming return 0; 103*00db8189SAndy Fleming } 104*00db8189SAndy Fleming 105*00db8189SAndy Fleming static int qs6612_config_intr(struct phy_device *phydev) 106*00db8189SAndy Fleming { 107*00db8189SAndy Fleming int err; 108*00db8189SAndy Fleming if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 109*00db8189SAndy Fleming err = phy_write(phydev, MII_QS6612_IMR, 110*00db8189SAndy Fleming MII_QS6612_IMR_INIT); 111*00db8189SAndy Fleming else 112*00db8189SAndy Fleming err = phy_write(phydev, MII_QS6612_IMR, 0); 113*00db8189SAndy Fleming 114*00db8189SAndy Fleming return err; 115*00db8189SAndy Fleming 116*00db8189SAndy Fleming } 117*00db8189SAndy Fleming 118*00db8189SAndy Fleming static struct phy_driver qs6612_driver = { 119*00db8189SAndy Fleming .phy_id = 0x00181440, 120*00db8189SAndy Fleming .name = "QS6612", 121*00db8189SAndy Fleming .phy_id_mask = 0xfffffff0, 122*00db8189SAndy Fleming .features = PHY_BASIC_FEATURES, 123*00db8189SAndy Fleming .flags = PHY_HAS_INTERRUPT, 124*00db8189SAndy Fleming .config_init = qs6612_config_init, 125*00db8189SAndy Fleming .config_aneg = genphy_config_aneg, 126*00db8189SAndy Fleming .read_status = genphy_read_status, 127*00db8189SAndy Fleming .ack_interrupt = qs6612_ack_interrupt, 128*00db8189SAndy Fleming .config_intr = qs6612_config_intr, 129*00db8189SAndy Fleming .driver = { .owner = THIS_MODULE,}, 130*00db8189SAndy Fleming }; 131*00db8189SAndy Fleming 132*00db8189SAndy Fleming static int __init qs6612_init(void) 133*00db8189SAndy Fleming { 134*00db8189SAndy Fleming return phy_driver_register(&qs6612_driver); 135*00db8189SAndy Fleming } 136*00db8189SAndy Fleming 137*00db8189SAndy Fleming static void __exit qs6612_exit(void) 138*00db8189SAndy Fleming { 139*00db8189SAndy Fleming phy_driver_unregister(&qs6612_driver); 140*00db8189SAndy Fleming } 141*00db8189SAndy Fleming 142*00db8189SAndy Fleming module_init(qs6612_init); 143*00db8189SAndy Fleming module_exit(qs6612_exit); 144