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