xref: /OK3568_Linux_fs/kernel/drivers/net/phy/qsemi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * drivers/net/phy/qsemi.c
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Driver for Quality Semiconductor PHYs
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Andy Fleming
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * Copyright (c) 2004 Freescale Semiconductor, Inc.
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/string.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/unistd.h>
15*4882a593Smuzhiyun #include <linux/interrupt.h>
16*4882a593Smuzhiyun #include <linux/init.h>
17*4882a593Smuzhiyun #include <linux/delay.h>
18*4882a593Smuzhiyun #include <linux/netdevice.h>
19*4882a593Smuzhiyun #include <linux/etherdevice.h>
20*4882a593Smuzhiyun #include <linux/skbuff.h>
21*4882a593Smuzhiyun #include <linux/spinlock.h>
22*4882a593Smuzhiyun #include <linux/mm.h>
23*4882a593Smuzhiyun #include <linux/module.h>
24*4882a593Smuzhiyun #include <linux/mii.h>
25*4882a593Smuzhiyun #include <linux/ethtool.h>
26*4882a593Smuzhiyun #include <linux/phy.h>
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #include <asm/io.h>
29*4882a593Smuzhiyun #include <asm/irq.h>
30*4882a593Smuzhiyun #include <linux/uaccess.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
33*4882a593Smuzhiyun /* The Quality Semiconductor QS6612 is used on the RPX CLLF                  */
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* register definitions */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #define MII_QS6612_MCR		17  /* Mode Control Register      */
38*4882a593Smuzhiyun #define MII_QS6612_FTR		27  /* Factory Test Register      */
39*4882a593Smuzhiyun #define MII_QS6612_MCO		28  /* Misc. Control Register     */
40*4882a593Smuzhiyun #define MII_QS6612_ISR		29  /* Interrupt Source Register  */
41*4882a593Smuzhiyun #define MII_QS6612_IMR		30  /* Interrupt Mask Register    */
42*4882a593Smuzhiyun #define MII_QS6612_IMR_INIT	0x003a
43*4882a593Smuzhiyun #define MII_QS6612_PCR		31  /* 100BaseTx PHY Control Reg. */
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define QS6612_PCR_AN_COMPLETE	0x1000
46*4882a593Smuzhiyun #define QS6612_PCR_RLBEN	0x0200
47*4882a593Smuzhiyun #define QS6612_PCR_DCREN	0x0100
48*4882a593Smuzhiyun #define QS6612_PCR_4B5BEN	0x0040
49*4882a593Smuzhiyun #define QS6612_PCR_TX_ISOLATE	0x0020
50*4882a593Smuzhiyun #define QS6612_PCR_MLT3_DIS	0x0002
51*4882a593Smuzhiyun #define QS6612_PCR_SCRM_DESCRM	0x0001
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun MODULE_DESCRIPTION("Quality Semiconductor PHY driver");
54*4882a593Smuzhiyun MODULE_AUTHOR("Andy Fleming");
55*4882a593Smuzhiyun MODULE_LICENSE("GPL");
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun /* Returns 0, unless there's a write error */
qs6612_config_init(struct phy_device * phydev)58*4882a593Smuzhiyun static int qs6612_config_init(struct phy_device *phydev)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	/* The PHY powers up isolated on the RPX,
61*4882a593Smuzhiyun 	 * so send a command to allow operation.
62*4882a593Smuzhiyun 	 * XXX - My docs indicate this should be 0x0940
63*4882a593Smuzhiyun 	 * ...or something.  The current value sets three
64*4882a593Smuzhiyun 	 * reserved bits, bit 11, which specifies it should be
65*4882a593Smuzhiyun 	 * set to one, bit 10, which specifies it should be set
66*4882a593Smuzhiyun 	 * to 0, and bit 7, which doesn't specify.  However, my
67*4882a593Smuzhiyun 	 * docs are preliminary, and I will leave it like this
68*4882a593Smuzhiyun 	 * until someone more knowledgable corrects me or it.
69*4882a593Smuzhiyun 	 * -- Andy Fleming
70*4882a593Smuzhiyun 	 */
71*4882a593Smuzhiyun 	return phy_write(phydev, MII_QS6612_PCR, 0x0dc0);
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
qs6612_ack_interrupt(struct phy_device * phydev)74*4882a593Smuzhiyun static int qs6612_ack_interrupt(struct phy_device *phydev)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	int err;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	err = phy_read(phydev, MII_QS6612_ISR);
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun 	if (err < 0)
81*4882a593Smuzhiyun 		return err;
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	err = phy_read(phydev, MII_BMSR);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	if (err < 0)
86*4882a593Smuzhiyun 		return err;
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	err = phy_read(phydev, MII_EXPANSION);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	if (err < 0)
91*4882a593Smuzhiyun 		return err;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun 
qs6612_config_intr(struct phy_device * phydev)96*4882a593Smuzhiyun static int qs6612_config_intr(struct phy_device *phydev)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	int err;
99*4882a593Smuzhiyun 	if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
100*4882a593Smuzhiyun 		err = phy_write(phydev, MII_QS6612_IMR,
101*4882a593Smuzhiyun 				MII_QS6612_IMR_INIT);
102*4882a593Smuzhiyun 	else
103*4882a593Smuzhiyun 		err = phy_write(phydev, MII_QS6612_IMR, 0);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	return err;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static struct phy_driver qs6612_driver[] = { {
110*4882a593Smuzhiyun 	.phy_id		= 0x00181440,
111*4882a593Smuzhiyun 	.name		= "QS6612",
112*4882a593Smuzhiyun 	.phy_id_mask	= 0xfffffff0,
113*4882a593Smuzhiyun 	/* PHY_BASIC_FEATURES */
114*4882a593Smuzhiyun 	.config_init	= qs6612_config_init,
115*4882a593Smuzhiyun 	.ack_interrupt	= qs6612_ack_interrupt,
116*4882a593Smuzhiyun 	.config_intr	= qs6612_config_intr,
117*4882a593Smuzhiyun } };
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun module_phy_driver(qs6612_driver);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun static struct mdio_device_id __maybe_unused qs6612_tbl[] = {
122*4882a593Smuzhiyun 	{ 0x00181440, 0xfffffff0 },
123*4882a593Smuzhiyun 	{ }
124*4882a593Smuzhiyun };
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun MODULE_DEVICE_TABLE(mdio, qs6612_tbl);
127