Linux Audio

Check our new training course

Loading...
v3.1
  1/*
  2 * Driver for Vitesse PHYs
  3 *
  4 * Author: Kriston Carson
  5 *
  6 * Copyright (c) 2005 Freescale Semiconductor, Inc.
  7 *
  8 * This program is free software; you can redistribute  it and/or modify it
  9 * under  the terms of  the GNU General  Public License as published by the
 10 * Free Software Foundation;  either version 2 of the  License, or (at your
 11 * option) any later version.
 12 *
 13 */
 14
 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
 21/* Vitesse Extended Control Register 1 */
 22#define MII_VSC8244_EXT_CON1           0x17
 23#define MII_VSC8244_EXTCON1_INIT       0x0000
 24#define MII_VSC8244_EXTCON1_TX_SKEW_MASK	0x0c00
 25#define MII_VSC8244_EXTCON1_RX_SKEW_MASK	0x0300
 26#define MII_VSC8244_EXTCON1_TX_SKEW	0x0800
 27#define MII_VSC8244_EXTCON1_RX_SKEW	0x0200
 28
 29/* Vitesse Interrupt Mask Register */
 30#define MII_VSC8244_IMASK		0x19
 31#define MII_VSC8244_IMASK_IEN		0x8000
 32#define MII_VSC8244_IMASK_SPEED		0x4000
 33#define MII_VSC8244_IMASK_LINK		0x2000
 34#define MII_VSC8244_IMASK_DUPLEX	0x1000
 35#define MII_VSC8244_IMASK_MASK		0xf000
 36
 37#define MII_VSC8221_IMASK_MASK		0xa000
 38
 39/* Vitesse Interrupt Status Register */
 40#define MII_VSC8244_ISTAT		0x1a
 41#define MII_VSC8244_ISTAT_STATUS	0x8000
 42#define MII_VSC8244_ISTAT_SPEED		0x4000
 43#define MII_VSC8244_ISTAT_LINK		0x2000
 44#define MII_VSC8244_ISTAT_DUPLEX	0x1000
 45
 46/* Vitesse Auxiliary Control/Status Register */
 47#define MII_VSC8244_AUX_CONSTAT        	0x1c
 48#define MII_VSC8244_AUXCONSTAT_INIT    	0x0000
 49#define MII_VSC8244_AUXCONSTAT_DUPLEX  	0x0020
 50#define MII_VSC8244_AUXCONSTAT_SPEED   	0x0018
 51#define MII_VSC8244_AUXCONSTAT_GBIT    	0x0010
 52#define MII_VSC8244_AUXCONSTAT_100     	0x0008
 53
 54#define MII_VSC8221_AUXCONSTAT_INIT	0x0004 /* need to set this bit? */
 55#define MII_VSC8221_AUXCONSTAT_RESERVED	0x0004
 56
 57#define PHY_ID_VSC8244			0x000fc6c0
 58#define PHY_ID_VSC8221			0x000fc550
 59
 60MODULE_DESCRIPTION("Vitesse PHY driver");
 61MODULE_AUTHOR("Kriston Carson");
 62MODULE_LICENSE("GPL");
 63
 64static int vsc824x_config_init(struct phy_device *phydev)
 65{
 66	int extcon;
 67	int err;
 68
 69	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
 70			MII_VSC8244_AUXCONSTAT_INIT);
 71	if (err < 0)
 72		return err;
 73
 74	extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
 75
 76	if (extcon < 0)
 77		return err;
 78
 79	extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
 80			MII_VSC8244_EXTCON1_RX_SKEW_MASK);
 81
 82	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
 83		extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
 84				MII_VSC8244_EXTCON1_RX_SKEW);
 85
 86	err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 87
 88	return err;
 89}
 90
 91static int vsc824x_ack_interrupt(struct phy_device *phydev)
 92{
 93	int err = 0;
 94	
 95	/*
 96	 * Don't bother to ACK the interrupts if interrupts
 97	 * are disabled.  The 824x cannot clear the interrupts
 98	 * if they are disabled.
 99	 */
100	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
101		err = phy_read(phydev, MII_VSC8244_ISTAT);
102
103	return (err < 0) ? err : 0;
104}
105
106static int vsc82xx_config_intr(struct phy_device *phydev)
107{
108	int err;
109
110	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
111		err = phy_write(phydev, MII_VSC8244_IMASK,
112			phydev->drv->phy_id == PHY_ID_VSC8244 ?
113				MII_VSC8244_IMASK_MASK :
114				MII_VSC8221_IMASK_MASK);
115	else {
116		/*
117		 * The Vitesse PHY cannot clear the interrupt
118		 * once it has disabled them, so we clear them first
119		 */
120		err = phy_read(phydev, MII_VSC8244_ISTAT);
121
122		if (err < 0)
123			return err;
124
125		err = phy_write(phydev, MII_VSC8244_IMASK, 0);
126	}
127
128	return err;
129}
130
131/* Vitesse 824x */
132static struct phy_driver vsc8244_driver = {
133	.phy_id		= PHY_ID_VSC8244,
134	.name		= "Vitesse VSC8244",
135	.phy_id_mask	= 0x000fffc0,
136	.features	= PHY_GBIT_FEATURES,
137	.flags		= PHY_HAS_INTERRUPT,
138	.config_init	= &vsc824x_config_init,
139	.config_aneg	= &genphy_config_aneg,
140	.read_status	= &genphy_read_status,
141	.ack_interrupt	= &vsc824x_ack_interrupt,
142	.config_intr	= &vsc82xx_config_intr,
143	.driver 	= { .owner = THIS_MODULE,},
144};
145
146static int vsc8221_config_init(struct phy_device *phydev)
147{
148	int err;
149
150	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
151			MII_VSC8221_AUXCONSTAT_INIT);
152	return err;
153
154	/* Perhaps we should set EXT_CON1 based on the interface?
155	   Options are 802.3Z SerDes or SGMII */
156}
157
158/* Vitesse 8221 */
159static struct phy_driver vsc8221_driver = {
160	.phy_id		= PHY_ID_VSC8221,
161	.phy_id_mask	= 0x000ffff0,
162	.name		= "Vitesse VSC8221",
163	.features	= PHY_GBIT_FEATURES,
164	.flags		= PHY_HAS_INTERRUPT,
165	.config_init	= &vsc8221_config_init,
166	.config_aneg	= &genphy_config_aneg,
167	.read_status	= &genphy_read_status,
168	.ack_interrupt	= &vsc824x_ack_interrupt,
169	.config_intr	= &vsc82xx_config_intr,
170	.driver 	= { .owner = THIS_MODULE,},
171};
172
173static int __init vsc82xx_init(void)
174{
175	int err;
176
177	err = phy_driver_register(&vsc8244_driver);
178	if (err < 0)
179		return err;
180	err = phy_driver_register(&vsc8221_driver);
181	if (err < 0)
182		phy_driver_unregister(&vsc8244_driver);
183	return err;
184}
185
186static void __exit vsc82xx_exit(void)
187{
188	phy_driver_unregister(&vsc8244_driver);
189	phy_driver_unregister(&vsc8221_driver);
190}
191
192module_init(vsc82xx_init);
193module_exit(vsc82xx_exit);
194
195static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
196	{ PHY_ID_VSC8244, 0x000fffc0 },
197	{ PHY_ID_VSC8221, 0x000ffff0 },
198	{ }
199};
200
201MODULE_DEVICE_TABLE(mdio, vitesse_tbl);
v3.5.6
  1/*
  2 * Driver for Vitesse PHYs
  3 *
  4 * Author: Kriston Carson
  5 *
  6 * Copyright (c) 2005, 2009 Freescale Semiconductor, Inc.
  7 *
  8 * This program is free software; you can redistribute  it and/or modify it
  9 * under  the terms of  the GNU General  Public License as published by the
 10 * Free Software Foundation;  either version 2 of the  License, or (at your
 11 * option) any later version.
 12 *
 13 */
 14
 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
 21/* Vitesse Extended Control Register 1 */
 22#define MII_VSC8244_EXT_CON1           0x17
 23#define MII_VSC8244_EXTCON1_INIT       0x0000
 24#define MII_VSC8244_EXTCON1_TX_SKEW_MASK	0x0c00
 25#define MII_VSC8244_EXTCON1_RX_SKEW_MASK	0x0300
 26#define MII_VSC8244_EXTCON1_TX_SKEW	0x0800
 27#define MII_VSC8244_EXTCON1_RX_SKEW	0x0200
 28
 29/* Vitesse Interrupt Mask Register */
 30#define MII_VSC8244_IMASK		0x19
 31#define MII_VSC8244_IMASK_IEN		0x8000
 32#define MII_VSC8244_IMASK_SPEED		0x4000
 33#define MII_VSC8244_IMASK_LINK		0x2000
 34#define MII_VSC8244_IMASK_DUPLEX	0x1000
 35#define MII_VSC8244_IMASK_MASK		0xf000
 36
 37#define MII_VSC8221_IMASK_MASK		0xa000
 38
 39/* Vitesse Interrupt Status Register */
 40#define MII_VSC8244_ISTAT		0x1a
 41#define MII_VSC8244_ISTAT_STATUS	0x8000
 42#define MII_VSC8244_ISTAT_SPEED		0x4000
 43#define MII_VSC8244_ISTAT_LINK		0x2000
 44#define MII_VSC8244_ISTAT_DUPLEX	0x1000
 45
 46/* Vitesse Auxiliary Control/Status Register */
 47#define MII_VSC8244_AUX_CONSTAT        	0x1c
 48#define MII_VSC8244_AUXCONSTAT_INIT    	0x0000
 49#define MII_VSC8244_AUXCONSTAT_DUPLEX  	0x0020
 50#define MII_VSC8244_AUXCONSTAT_SPEED   	0x0018
 51#define MII_VSC8244_AUXCONSTAT_GBIT    	0x0010
 52#define MII_VSC8244_AUXCONSTAT_100     	0x0008
 53
 54#define MII_VSC8221_AUXCONSTAT_INIT	0x0004 /* need to set this bit? */
 55#define MII_VSC8221_AUXCONSTAT_RESERVED	0x0004
 56
 57#define PHY_ID_VSC8244			0x000fc6c0
 58#define PHY_ID_VSC8221			0x000fc550
 59
 60MODULE_DESCRIPTION("Vitesse PHY driver");
 61MODULE_AUTHOR("Kriston Carson");
 62MODULE_LICENSE("GPL");
 63
 64int vsc824x_add_skew(struct phy_device *phydev)
 65{
 
 66	int err;
 67	int extcon;
 
 
 
 
 68
 69	extcon = phy_read(phydev, MII_VSC8244_EXT_CON1);
 70
 71	if (extcon < 0)
 72		return extcon;
 73
 74	extcon &= ~(MII_VSC8244_EXTCON1_TX_SKEW_MASK |
 75			MII_VSC8244_EXTCON1_RX_SKEW_MASK);
 76
 77	extcon |= (MII_VSC8244_EXTCON1_TX_SKEW |
 78			MII_VSC8244_EXTCON1_RX_SKEW);
 
 79
 80	err = phy_write(phydev, MII_VSC8244_EXT_CON1, extcon);
 81
 82	return err;
 83}
 84EXPORT_SYMBOL(vsc824x_add_skew);
 85
 86static int vsc824x_config_init(struct phy_device *phydev)
 87{
 88	int err;
 89
 90	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
 91			MII_VSC8244_AUXCONSTAT_INIT);
 92	if (err < 0)
 93		return err;
 94
 95	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
 96		err = vsc824x_add_skew(phydev);
 97
 98	return err;
 99}
100
101static int vsc824x_ack_interrupt(struct phy_device *phydev)
102{
103	int err = 0;
104	
105	/*
106	 * Don't bother to ACK the interrupts if interrupts
107	 * are disabled.  The 824x cannot clear the interrupts
108	 * if they are disabled.
109	 */
110	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
111		err = phy_read(phydev, MII_VSC8244_ISTAT);
112
113	return (err < 0) ? err : 0;
114}
115
116static int vsc82xx_config_intr(struct phy_device *phydev)
117{
118	int err;
119
120	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
121		err = phy_write(phydev, MII_VSC8244_IMASK,
122			phydev->drv->phy_id == PHY_ID_VSC8244 ?
123				MII_VSC8244_IMASK_MASK :
124				MII_VSC8221_IMASK_MASK);
125	else {
126		/*
127		 * The Vitesse PHY cannot clear the interrupt
128		 * once it has disabled them, so we clear them first
129		 */
130		err = phy_read(phydev, MII_VSC8244_ISTAT);
131
132		if (err < 0)
133			return err;
134
135		err = phy_write(phydev, MII_VSC8244_IMASK, 0);
136	}
137
138	return err;
139}
140
141/* Vitesse 824x */
142static struct phy_driver vsc8244_driver = {
143	.phy_id		= PHY_ID_VSC8244,
144	.name		= "Vitesse VSC8244",
145	.phy_id_mask	= 0x000fffc0,
146	.features	= PHY_GBIT_FEATURES,
147	.flags		= PHY_HAS_INTERRUPT,
148	.config_init	= &vsc824x_config_init,
149	.config_aneg	= &genphy_config_aneg,
150	.read_status	= &genphy_read_status,
151	.ack_interrupt	= &vsc824x_ack_interrupt,
152	.config_intr	= &vsc82xx_config_intr,
153	.driver 	= { .owner = THIS_MODULE,},
154};
155
156static int vsc8221_config_init(struct phy_device *phydev)
157{
158	int err;
159
160	err = phy_write(phydev, MII_VSC8244_AUX_CONSTAT,
161			MII_VSC8221_AUXCONSTAT_INIT);
162	return err;
163
164	/* Perhaps we should set EXT_CON1 based on the interface?
165	   Options are 802.3Z SerDes or SGMII */
166}
167
168/* Vitesse 8221 */
169static struct phy_driver vsc8221_driver = {
170	.phy_id		= PHY_ID_VSC8221,
171	.phy_id_mask	= 0x000ffff0,
172	.name		= "Vitesse VSC8221",
173	.features	= PHY_GBIT_FEATURES,
174	.flags		= PHY_HAS_INTERRUPT,
175	.config_init	= &vsc8221_config_init,
176	.config_aneg	= &genphy_config_aneg,
177	.read_status	= &genphy_read_status,
178	.ack_interrupt	= &vsc824x_ack_interrupt,
179	.config_intr	= &vsc82xx_config_intr,
180	.driver 	= { .owner = THIS_MODULE,},
181};
182
183static int __init vsc82xx_init(void)
184{
185	int err;
186
187	err = phy_driver_register(&vsc8244_driver);
188	if (err < 0)
189		return err;
190	err = phy_driver_register(&vsc8221_driver);
191	if (err < 0)
192		phy_driver_unregister(&vsc8244_driver);
193	return err;
194}
195
196static void __exit vsc82xx_exit(void)
197{
198	phy_driver_unregister(&vsc8244_driver);
199	phy_driver_unregister(&vsc8221_driver);
200}
201
202module_init(vsc82xx_init);
203module_exit(vsc82xx_exit);
204
205static struct mdio_device_id __maybe_unused vitesse_tbl[] = {
206	{ PHY_ID_VSC8244, 0x000fffc0 },
207	{ PHY_ID_VSC8221, 0x000ffff0 },
208	{ }
209};
210
211MODULE_DEVICE_TABLE(mdio, vitesse_tbl);