Linux Audio

Check our new training course

Loading...
v4.17
  1/*
  2 * Driver for Aquantia PHY
  3 *
  4 * Author: Shaohui Xie <Shaohui.Xie@freescale.com>
  5 *
  6 * Copyright 2015 Freescale Semiconductor, Inc.
  7 *
  8 * This file is licensed under the terms of the GNU General Public License
  9 * version 2.  This program is licensed "as is" without any warranty of any
 10 * kind, whether express or implied.
 11 */
 12
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/delay.h>
 16#include <linux/mii.h>
 17#include <linux/ethtool.h>
 18#include <linux/phy.h>
 19#include <linux/mdio.h>
 20
 21#define PHY_ID_AQ1202	0x03a1b445
 22#define PHY_ID_AQ2104	0x03a1b460
 23#define PHY_ID_AQR105	0x03a1b4a2
 24#define PHY_ID_AQR106	0x03a1b4d0
 25#define PHY_ID_AQR107	0x03a1b4e0
 26#define PHY_ID_AQR405	0x03a1b4b0
 27
 28#define PHY_AQUANTIA_FEATURES	(SUPPORTED_10000baseT_Full | \
 29				 SUPPORTED_1000baseT_Full | \
 30				 SUPPORTED_100baseT_Full | \
 31				 PHY_DEFAULT_FEATURES)
 32
 33static int aquantia_config_aneg(struct phy_device *phydev)
 34{
 35	phydev->supported = PHY_AQUANTIA_FEATURES;
 36	phydev->advertising = phydev->supported;
 37
 38	return 0;
 39}
 40
 
 
 
 
 
 
 
 
 41static int aquantia_config_intr(struct phy_device *phydev)
 42{
 43	int err;
 44
 45	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 46		err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1);
 47		if (err < 0)
 48			return err;
 49
 50		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1);
 51		if (err < 0)
 52			return err;
 53
 54		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001);
 55	} else {
 56		err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0);
 57		if (err < 0)
 58			return err;
 59
 60		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0);
 61		if (err < 0)
 62			return err;
 63
 64		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0);
 65	}
 66
 67	return err;
 68}
 69
 70static int aquantia_ack_interrupt(struct phy_device *phydev)
 71{
 72	int reg;
 73
 74	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01);
 75	return (reg < 0) ? reg : 0;
 76}
 77
 78static int aquantia_read_status(struct phy_device *phydev)
 79{
 80	int reg;
 81
 82	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 83	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 84	if (reg & MDIO_STAT1_LSTATUS)
 85		phydev->link = 1;
 86	else
 87		phydev->link = 0;
 88
 89	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
 90	mdelay(10);
 91	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
 92
 93	switch (reg) {
 94	case 0x9:
 95		phydev->speed = SPEED_2500;
 96		break;
 97	case 0x5:
 98		phydev->speed = SPEED_1000;
 99		break;
100	case 0x3:
101		phydev->speed = SPEED_100;
102		break;
103	case 0x7:
104	default:
105		phydev->speed = SPEED_10000;
106		break;
107	}
108	phydev->duplex = DUPLEX_FULL;
109
110	return 0;
111}
112
113static struct phy_driver aquantia_driver[] = {
114{
115	.phy_id		= PHY_ID_AQ1202,
116	.phy_id_mask	= 0xfffffff0,
117	.name		= "Aquantia AQ1202",
118	.features	= PHY_AQUANTIA_FEATURES,
119	.flags		= PHY_HAS_INTERRUPT,
120	.aneg_done	= genphy_c45_aneg_done,
121	.config_aneg    = aquantia_config_aneg,
122	.config_intr	= aquantia_config_intr,
123	.ack_interrupt	= aquantia_ack_interrupt,
124	.read_status	= aquantia_read_status,
125},
126{
127	.phy_id		= PHY_ID_AQ2104,
128	.phy_id_mask	= 0xfffffff0,
129	.name		= "Aquantia AQ2104",
130	.features	= PHY_AQUANTIA_FEATURES,
131	.flags		= PHY_HAS_INTERRUPT,
132	.aneg_done	= genphy_c45_aneg_done,
133	.config_aneg    = aquantia_config_aneg,
134	.config_intr	= aquantia_config_intr,
135	.ack_interrupt	= aquantia_ack_interrupt,
136	.read_status	= aquantia_read_status,
137},
138{
139	.phy_id		= PHY_ID_AQR105,
140	.phy_id_mask	= 0xfffffff0,
141	.name		= "Aquantia AQR105",
142	.features	= PHY_AQUANTIA_FEATURES,
143	.flags		= PHY_HAS_INTERRUPT,
144	.aneg_done	= genphy_c45_aneg_done,
145	.config_aneg    = aquantia_config_aneg,
146	.config_intr	= aquantia_config_intr,
147	.ack_interrupt	= aquantia_ack_interrupt,
148	.read_status	= aquantia_read_status,
149},
150{
151	.phy_id		= PHY_ID_AQR106,
152	.phy_id_mask	= 0xfffffff0,
153	.name		= "Aquantia AQR106",
154	.features	= PHY_AQUANTIA_FEATURES,
155	.flags		= PHY_HAS_INTERRUPT,
156	.aneg_done	= genphy_c45_aneg_done,
157	.config_aneg    = aquantia_config_aneg,
158	.config_intr	= aquantia_config_intr,
159	.ack_interrupt	= aquantia_ack_interrupt,
160	.read_status	= aquantia_read_status,
161},
162{
163	.phy_id		= PHY_ID_AQR107,
164	.phy_id_mask	= 0xfffffff0,
165	.name		= "Aquantia AQR107",
166	.features	= PHY_AQUANTIA_FEATURES,
167	.flags		= PHY_HAS_INTERRUPT,
168	.aneg_done	= genphy_c45_aneg_done,
169	.config_aneg    = aquantia_config_aneg,
170	.config_intr	= aquantia_config_intr,
171	.ack_interrupt	= aquantia_ack_interrupt,
172	.read_status	= aquantia_read_status,
173},
174{
175	.phy_id		= PHY_ID_AQR405,
176	.phy_id_mask	= 0xfffffff0,
177	.name		= "Aquantia AQR405",
178	.features	= PHY_AQUANTIA_FEATURES,
179	.flags		= PHY_HAS_INTERRUPT,
180	.aneg_done	= genphy_c45_aneg_done,
181	.config_aneg    = aquantia_config_aneg,
182	.config_intr	= aquantia_config_intr,
183	.ack_interrupt	= aquantia_ack_interrupt,
184	.read_status	= aquantia_read_status,
185},
186};
187
188module_phy_driver(aquantia_driver);
189
190static struct mdio_device_id __maybe_unused aquantia_tbl[] = {
191	{ PHY_ID_AQ1202, 0xfffffff0 },
192	{ PHY_ID_AQ2104, 0xfffffff0 },
193	{ PHY_ID_AQR105, 0xfffffff0 },
194	{ PHY_ID_AQR106, 0xfffffff0 },
195	{ PHY_ID_AQR107, 0xfffffff0 },
196	{ PHY_ID_AQR405, 0xfffffff0 },
197	{ }
198};
199
200MODULE_DEVICE_TABLE(mdio, aquantia_tbl);
201
202MODULE_DESCRIPTION("Aquantia PHY driver");
203MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>");
204MODULE_LICENSE("GPL v2");
v4.6
  1/*
  2 * Driver for Aquantia PHY
  3 *
  4 * Author: Shaohui Xie <Shaohui.Xie@freescale.com>
  5 *
  6 * Copyright 2015 Freescale Semiconductor, Inc.
  7 *
  8 * This file is licensed under the terms of the GNU General Public License
  9 * version 2.  This program is licensed "as is" without any warranty of any
 10 * kind, whether express or implied.
 11 */
 12
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include <linux/delay.h>
 16#include <linux/mii.h>
 17#include <linux/ethtool.h>
 18#include <linux/phy.h>
 19#include <linux/mdio.h>
 20
 21#define PHY_ID_AQ1202	0x03a1b445
 22#define PHY_ID_AQ2104	0x03a1b460
 23#define PHY_ID_AQR105	0x03a1b4a2
 
 
 24#define PHY_ID_AQR405	0x03a1b4b0
 25
 26#define PHY_AQUANTIA_FEATURES	(SUPPORTED_10000baseT_Full | \
 27				 SUPPORTED_1000baseT_Full | \
 28				 SUPPORTED_100baseT_Full | \
 29				 PHY_DEFAULT_FEATURES)
 30
 31static int aquantia_config_aneg(struct phy_device *phydev)
 32{
 33	phydev->supported = PHY_AQUANTIA_FEATURES;
 34	phydev->advertising = phydev->supported;
 35
 36	return 0;
 37}
 38
 39static int aquantia_aneg_done(struct phy_device *phydev)
 40{
 41	int reg;
 42
 43	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 44	return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE);
 45}
 46
 47static int aquantia_config_intr(struct phy_device *phydev)
 48{
 49	int err;
 50
 51	if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 52		err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1);
 53		if (err < 0)
 54			return err;
 55
 56		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1);
 57		if (err < 0)
 58			return err;
 59
 60		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001);
 61	} else {
 62		err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0);
 63		if (err < 0)
 64			return err;
 65
 66		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0);
 67		if (err < 0)
 68			return err;
 69
 70		err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0);
 71	}
 72
 73	return err;
 74}
 75
 76static int aquantia_ack_interrupt(struct phy_device *phydev)
 77{
 78	int reg;
 79
 80	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01);
 81	return (reg < 0) ? reg : 0;
 82}
 83
 84static int aquantia_read_status(struct phy_device *phydev)
 85{
 86	int reg;
 87
 88	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 89	reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
 90	if (reg & MDIO_STAT1_LSTATUS)
 91		phydev->link = 1;
 92	else
 93		phydev->link = 0;
 94
 95	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
 96	mdelay(10);
 97	reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xc800);
 98
 99	switch (reg) {
100	case 0x9:
101		phydev->speed = SPEED_2500;
102		break;
103	case 0x5:
104		phydev->speed = SPEED_1000;
105		break;
106	case 0x3:
107		phydev->speed = SPEED_100;
108		break;
109	case 0x7:
110	default:
111		phydev->speed = SPEED_10000;
112		break;
113	}
114	phydev->duplex = DUPLEX_FULL;
115
116	return 0;
117}
118
119static struct phy_driver aquantia_driver[] = {
120{
121	.phy_id		= PHY_ID_AQ1202,
122	.phy_id_mask	= 0xfffffff0,
123	.name		= "Aquantia AQ1202",
124	.features	= PHY_AQUANTIA_FEATURES,
125	.flags		= PHY_HAS_INTERRUPT,
126	.aneg_done	= aquantia_aneg_done,
127	.config_aneg    = aquantia_config_aneg,
128	.config_intr	= aquantia_config_intr,
129	.ack_interrupt	= aquantia_ack_interrupt,
130	.read_status	= aquantia_read_status,
131},
132{
133	.phy_id		= PHY_ID_AQ2104,
134	.phy_id_mask	= 0xfffffff0,
135	.name		= "Aquantia AQ2104",
136	.features	= PHY_AQUANTIA_FEATURES,
137	.flags		= PHY_HAS_INTERRUPT,
138	.aneg_done	= aquantia_aneg_done,
139	.config_aneg    = aquantia_config_aneg,
140	.config_intr	= aquantia_config_intr,
141	.ack_interrupt	= aquantia_ack_interrupt,
142	.read_status	= aquantia_read_status,
143},
144{
145	.phy_id		= PHY_ID_AQR105,
146	.phy_id_mask	= 0xfffffff0,
147	.name		= "Aquantia AQR105",
148	.features	= PHY_AQUANTIA_FEATURES,
149	.flags		= PHY_HAS_INTERRUPT,
150	.aneg_done	= aquantia_aneg_done,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151	.config_aneg    = aquantia_config_aneg,
152	.config_intr	= aquantia_config_intr,
153	.ack_interrupt	= aquantia_ack_interrupt,
154	.read_status	= aquantia_read_status,
155},
156{
157	.phy_id		= PHY_ID_AQR405,
158	.phy_id_mask	= 0xfffffff0,
159	.name		= "Aquantia AQR405",
160	.features	= PHY_AQUANTIA_FEATURES,
161	.flags		= PHY_HAS_INTERRUPT,
162	.aneg_done	= aquantia_aneg_done,
163	.config_aneg    = aquantia_config_aneg,
164	.config_intr	= aquantia_config_intr,
165	.ack_interrupt	= aquantia_ack_interrupt,
166	.read_status	= aquantia_read_status,
167},
168};
169
170module_phy_driver(aquantia_driver);
171
172static struct mdio_device_id __maybe_unused aquantia_tbl[] = {
173	{ PHY_ID_AQ1202, 0xfffffff0 },
174	{ PHY_ID_AQ2104, 0xfffffff0 },
175	{ PHY_ID_AQR105, 0xfffffff0 },
 
 
176	{ PHY_ID_AQR405, 0xfffffff0 },
177	{ }
178};
179
180MODULE_DEVICE_TABLE(mdio, aquantia_tbl);
181
182MODULE_DESCRIPTION("Aquantia PHY driver");
183MODULE_AUTHOR("Shaohui Xie <Shaohui.Xie@freescale.com>");
184MODULE_LICENSE("GPL v2");