100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* 200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * drivers/net/phy/davicom.c 300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Driver for Davicom PHYs 500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Author: Andy Fleming 700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Copyright (c) 2004 Freescale Semiconductor, Inc. 900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 1000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * This program is free software; you can redistribute it and/or modify it 1100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * under the terms of the GNU General Public License as published by the 1200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * Free Software Foundation; either version 2 of the License, or (at your 1300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * option) any later version. 1400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming * 1500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming */ 1600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/kernel.h> 1700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/string.h> 1800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/errno.h> 1900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/unistd.h> 2000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/interrupt.h> 2100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/init.h> 2200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/delay.h> 2300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/netdevice.h> 2400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/etherdevice.h> 2500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/skbuff.h> 2600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/spinlock.h> 2700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/mm.h> 2800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/module.h> 2900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/mii.h> 3000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/ethtool.h> 3100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <linux/phy.h> 3200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 3300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <asm/io.h> 3400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <asm/irq.h> 3500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#include <asm/uaccess.h> 3600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 3700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_SCR 0x10 3800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_SCR_INIT 0x0610 398b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo#define MII_DM9161_SCR_RMII 0x0100 4000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 4100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* DM9161 Interrupt Register */ 4200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR 0x15 4300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_PEND 0x8000 4400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_DPLX_MASK 0x0800 4500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_SPD_MASK 0x0400 4600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_LINK_MASK 0x0200 4700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_MASK 0x0100 4800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_DPLX_CHANGE 0x0010 4900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_SPD_CHANGE 0x0008 5000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_LINK_CHANGE 0x0004 5100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_INIT 0x0000 5200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_INTR_STOP \ 5300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming(MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ 5400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) 5500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 5600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming/* DM9161 10BT Configuration/Status */ 5700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_10BTCSR 0x12 5800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define MII_DM9161_10BTCSR_INIT 0x7800 5900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 6000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingMODULE_DESCRIPTION("Davicom PHY driver"); 6100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingMODULE_AUTHOR("Andy Fleming"); 6200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy FlemingMODULE_LICENSE("GPL"); 6300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 6400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 6500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming#define DM9161_DELAY 1 6600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic int dm9161_config_intr(struct phy_device *phydev) 6700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 6800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int temp; 6900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 7000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming temp = phy_read(phydev, MII_DM9161_INTR); 7100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 7200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (temp < 0) 7300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return temp; 7400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 75a60e7e1e657b9458c3f44681fe81f03a85acfc20Florian Fainelli if (PHY_INTERRUPT_ENABLED == phydev->interrupts) 7600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming temp &= ~(MII_DM9161_INTR_STOP); 7700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming else 7800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming temp |= MII_DM9161_INTR_STOP; 7900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 8000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming temp = phy_write(phydev, MII_DM9161_INTR, temp); 8100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 8200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return temp; 8300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 8400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 8500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic int dm9161_config_aneg(struct phy_device *phydev) 8600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 8700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err; 8800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 8900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Isolate the PHY */ 9000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); 9100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 9300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 9400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Configure the new settings */ 9600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = genphy_config_aneg(phydev); 9700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 9800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 9900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 10000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 10100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return 0; 10200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 10300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 10400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic int dm9161_config_init(struct phy_device *phydev) 10500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 1068b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo int err, temp; 10700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 10800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Isolate the PHY */ 10900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_write(phydev, MII_BMCR, BMCR_ISOLATE); 11000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 11100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 11200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 11300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 1148b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo switch (phydev->interface) { 1158b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo case PHY_INTERFACE_MODE_MII: 1168b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo temp = MII_DM9161_SCR_INIT; 1178b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo break; 1188b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo case PHY_INTERFACE_MODE_RMII: 1198b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo temp = MII_DM9161_SCR_INIT | MII_DM9161_SCR_RMII; 1208b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo break; 1218b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo default: 1228b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo return -EINVAL; 1238b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo } 12400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 1258b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo /* Do not bypass the scrambler/descrambler */ 1268b7c1664405a1262bb78e80011ec10aa6b79df81frederic Rodo err = phy_write(phydev, MII_DM9161_SCR, temp); 12700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 12800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 12900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 13000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Clear 10BTCSR to default */ 13100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming err = phy_write(phydev, MII_DM9161_10BTCSR, MII_DM9161_10BTCSR_INIT); 13200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 13300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming if (err < 0) 13400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return err; 13500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 13600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming /* Reconnect the PHY, and enable Autonegotiation */ 1378bc47ec6efd4d447f3502d9f9d41fe440cd5854dSrinivas Kandagatla return phy_write(phydev, MII_BMCR, BMCR_ANENABLE); 13800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 13900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 14000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic int dm9161_ack_interrupt(struct phy_device *phydev) 14100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 14200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming int err = phy_read(phydev, MII_DM9161_INTR); 14300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 14400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming return (err < 0) ? err : 0; 14500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 14600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 147d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedtstatic struct phy_driver dm91xx_driver[] = { 148d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt{ 14900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .phy_id = 0x0181b880, 15000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .name = "Davicom DM9161E", 15100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .phy_id_mask = 0x0ffffff0, 15200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .features = PHY_BASIC_FEATURES, 15363f71dd026cc6b2cc1cc26299720d763269f65b6Joachim Eastwood .flags = PHY_HAS_INTERRUPT, 15400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .config_init = dm9161_config_init, 15500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .config_aneg = dm9161_config_aneg, 15600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .read_status = genphy_read_status, 15763f71dd026cc6b2cc1cc26299720d763269f65b6Joachim Eastwood .ack_interrupt = dm9161_ack_interrupt, 15863f71dd026cc6b2cc1cc26299720d763269f65b6Joachim Eastwood .config_intr = dm9161_config_intr, 15912414db11da8789d9a6b549c4899250f6e116630Kim Phillips .driver = { .owner = THIS_MODULE,}, 160d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt}, { 16112414db11da8789d9a6b549c4899250f6e116630Kim Phillips .phy_id = 0x0181b8a0, 16212414db11da8789d9a6b549c4899250f6e116630Kim Phillips .name = "Davicom DM9161A", 16312414db11da8789d9a6b549c4899250f6e116630Kim Phillips .phy_id_mask = 0x0ffffff0, 16412414db11da8789d9a6b549c4899250f6e116630Kim Phillips .features = PHY_BASIC_FEATURES, 16563f71dd026cc6b2cc1cc26299720d763269f65b6Joachim Eastwood .flags = PHY_HAS_INTERRUPT, 16612414db11da8789d9a6b549c4899250f6e116630Kim Phillips .config_init = dm9161_config_init, 16712414db11da8789d9a6b549c4899250f6e116630Kim Phillips .config_aneg = dm9161_config_aneg, 16812414db11da8789d9a6b549c4899250f6e116630Kim Phillips .read_status = genphy_read_status, 16963f71dd026cc6b2cc1cc26299720d763269f65b6Joachim Eastwood .ack_interrupt = dm9161_ack_interrupt, 17063f71dd026cc6b2cc1cc26299720d763269f65b6Joachim Eastwood .config_intr = dm9161_config_intr, 17112414db11da8789d9a6b549c4899250f6e116630Kim Phillips .driver = { .owner = THIS_MODULE,}, 172d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt}, { 17300db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .phy_id = 0x00181b80, 17400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .name = "Davicom DM9131", 17500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .phy_id_mask = 0x0ffffff0, 17600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .features = PHY_BASIC_FEATURES, 17700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .flags = PHY_HAS_INTERRUPT, 17800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .config_aneg = genphy_config_aneg, 17900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .read_status = genphy_read_status, 18000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .ack_interrupt = dm9161_ack_interrupt, 18100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming .config_intr = dm9161_config_intr, 18212414db11da8789d9a6b549c4899250f6e116630Kim Phillips .driver = { .owner = THIS_MODULE,}, 183d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt} }; 18400db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 18500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic int __init davicom_init(void) 18600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 187d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt return phy_drivers_register(dm91xx_driver, 188d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt ARRAY_SIZE(dm91xx_driver)); 18900db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 19000db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 19100db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingstatic void __exit davicom_exit(void) 19200db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming{ 193d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt phy_drivers_unregister(dm91xx_driver, 194d5bf9071e71a4db85a0eea6236ef94a29fc3eec9Christian Hohnstaedt ARRAY_SIZE(dm91xx_driver)); 19500db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming} 19600db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Fleming 19700db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingmodule_init(davicom_init); 19800db8189d984d6c51226dafbbe4a667ce9b7d5daAndy Flemingmodule_exit(davicom_exit); 1994e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse 200cf93c94581bab447a5634c6d737c1cf38c080261Uwe Kleine-Königstatic struct mdio_device_id __maybe_unused davicom_tbl[] = { 2014e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse { 0x0181b880, 0x0ffffff0 }, 2024e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse { 0x0181b8a0, 0x0ffffff0 }, 2034e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse { 0x00181b80, 0x0ffffff0 }, 2044e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse { } 2054e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse}; 2064e4f10f6498bc5038c0a110b5f21682fcb5578d7David Woodhouse 2074e4f10f6498bc5038c0a110b5f21682fcb5578d7David WoodhouseMODULE_DEVICE_TABLE(mdio, davicom_tbl); 208