Skip to content

Commit a97c69b

Browse files
Łukasz Stelmachkuba-moo
authored andcommitted
net: ax88796c: ASIX AX88796C SPI Ethernet Adapter Driver
ASIX AX88796[1] is a versatile ethernet adapter chip, that can be connected to a CPU with a 8/16-bit bus or with an SPI. This driver supports SPI connection. The driver has been ported from the vendor kernel for ARTIK5[2] boards. Several changes were made to adapt it to the current kernel which include: + updated DT configuration, + clock configuration moved to DT, + new timer, ethtool and gpio APIs, + dev_* instead of pr_* and custom printk() wrappers, + removed awkward vendor power managemtn. + introduced ethtool tunable to control SPI compression [1] https://www.asix.com.tw/products.php?op=pItemdetail&PItemID=104;65;86&PLine=65 [2] https://git.tizen.org/cgit/profile/common/platform/kernel/linux-3.10-artik/ The other ax88796 driver is for NE2000 compatible AX88796L chip. These chips are not compatible. Hence, two separate drivers are required. Signed-off-by: Łukasz Stelmach <[email protected]> Signed-off-by: Jakub Kicinski <[email protected]>
1 parent b13c7a8 commit a97c69b

File tree

11 files changed

+2229
-0
lines changed

11 files changed

+2229
-0
lines changed

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2899,6 +2899,12 @@ S: Maintained
28992899
F: Documentation/hwmon/asc7621.rst
29002900
F: drivers/hwmon/asc7621.c
29012901

2902+
ASIX AX88796C SPI ETHERNET ADAPTER
2903+
M: Łukasz Stelmach <[email protected]>
2904+
S: Maintained
2905+
F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml
2906+
F: drivers/net/ethernet/asix/ax88796c_*
2907+
29022908
ASPEED PINCTRL DRIVERS
29032909
M: Andrew Jeffery <[email protected]>
29042910
L: [email protected] (moderated for non-subscribers)

drivers/net/ethernet/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ source "drivers/net/ethernet/apm/Kconfig"
3333
source "drivers/net/ethernet/apple/Kconfig"
3434
source "drivers/net/ethernet/aquantia/Kconfig"
3535
source "drivers/net/ethernet/arc/Kconfig"
36+
source "drivers/net/ethernet/asix/Kconfig"
3637
source "drivers/net/ethernet/atheros/Kconfig"
3738
source "drivers/net/ethernet/broadcom/Kconfig"
3839
source "drivers/net/ethernet/brocade/Kconfig"

drivers/net/ethernet/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ obj-$(CONFIG_NET_XGENE) += apm/
1919
obj-$(CONFIG_NET_VENDOR_APPLE) += apple/
2020
obj-$(CONFIG_NET_VENDOR_AQUANTIA) += aquantia/
2121
obj-$(CONFIG_NET_VENDOR_ARC) += arc/
22+
obj-$(CONFIG_NET_VENDOR_ASIX) += asix/
2223
obj-$(CONFIG_NET_VENDOR_ATHEROS) += atheros/
2324
obj-$(CONFIG_NET_VENDOR_CADENCE) += cadence/
2425
obj-$(CONFIG_NET_VENDOR_BROADCOM) += broadcom/

drivers/net/ethernet/asix/Kconfig

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#
2+
# Asix network device configuration
3+
#
4+
5+
config NET_VENDOR_ASIX
6+
bool "Asix devices"
7+
default y
8+
help
9+
If you have a network (Ethernet, non-USB, not NE2000 compatible)
10+
interface based on a chip from ASIX, say Y.
11+
12+
if NET_VENDOR_ASIX
13+
14+
config SPI_AX88796C
15+
tristate "Asix AX88796C-SPI support"
16+
select PHYLIB
17+
depends on SPI
18+
depends on GPIOLIB
19+
help
20+
Say Y here if you intend to use ASIX AX88796C attached in SPI mode.
21+
22+
config SPI_AX88796C_COMPRESSION
23+
bool "SPI transfer compression"
24+
default n
25+
depends on SPI_AX88796C
26+
help
27+
Say Y here to enable SPI transfer compression. It saves up
28+
to 24 dummy cycles during each transfer which may noticeably
29+
speed up short transfers. This sets the default value that is
30+
inherited by network interfaces during probe. It can be
31+
changed at run time via spi-compression ethtool tunable.
32+
33+
If unsure say N.
34+
35+
endif # NET_VENDOR_ASIX

drivers/net/ethernet/asix/Makefile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#
2+
# Makefile for the Asix network device drivers.
3+
#
4+
5+
obj-$(CONFIG_SPI_AX88796C) += ax88796c.o
6+
ax88796c-y := ax88796c_main.o ax88796c_ioctl.o ax88796c_spi.o
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (c) 2010 ASIX Electronics Corporation
4+
* Copyright (c) 2020 Samsung Electronics Co., Ltd.
5+
*
6+
* ASIX AX88796C SPI Fast Ethernet Linux driver
7+
*/
8+
9+
#define pr_fmt(fmt) "ax88796c: " fmt
10+
11+
#include <linux/bitmap.h>
12+
#include <linux/iopoll.h>
13+
#include <linux/phy.h>
14+
#include <linux/netdevice.h>
15+
16+
#include "ax88796c_main.h"
17+
#include "ax88796c_ioctl.h"
18+
19+
static const char ax88796c_priv_flag_names[][ETH_GSTRING_LEN] = {
20+
"SPICompression",
21+
};
22+
23+
static void
24+
ax88796c_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
25+
{
26+
/* Inherit standard device info */
27+
strncpy(info->driver, DRV_NAME, sizeof(info->driver));
28+
}
29+
30+
static u32 ax88796c_get_msglevel(struct net_device *ndev)
31+
{
32+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
33+
34+
return ax_local->msg_enable;
35+
}
36+
37+
static void ax88796c_set_msglevel(struct net_device *ndev, u32 level)
38+
{
39+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
40+
41+
ax_local->msg_enable = level;
42+
}
43+
44+
static void
45+
ax88796c_get_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause)
46+
{
47+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
48+
49+
pause->tx_pause = !!(ax_local->flowctrl & AX_FC_TX);
50+
pause->rx_pause = !!(ax_local->flowctrl & AX_FC_RX);
51+
pause->autoneg = (ax_local->flowctrl & AX_FC_ANEG) ?
52+
AUTONEG_ENABLE :
53+
AUTONEG_DISABLE;
54+
}
55+
56+
static int
57+
ax88796c_set_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause)
58+
{
59+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
60+
int fc;
61+
62+
/* The following logic comes from phylink_ethtool_set_pauseparam() */
63+
fc = pause->tx_pause ? AX_FC_TX : 0;
64+
fc |= pause->rx_pause ? AX_FC_RX : 0;
65+
fc |= pause->autoneg ? AX_FC_ANEG : 0;
66+
67+
ax_local->flowctrl = fc;
68+
69+
if (pause->autoneg) {
70+
phy_set_asym_pause(ax_local->phydev, pause->tx_pause,
71+
pause->rx_pause);
72+
} else {
73+
int maccr = 0;
74+
75+
phy_set_asym_pause(ax_local->phydev, 0, 0);
76+
maccr |= (ax_local->flowctrl & AX_FC_RX) ? MACCR_RXFC_ENABLE : 0;
77+
maccr |= (ax_local->flowctrl & AX_FC_TX) ? MACCR_TXFC_ENABLE : 0;
78+
79+
mutex_lock(&ax_local->spi_lock);
80+
81+
maccr |= AX_READ(&ax_local->ax_spi, P0_MACCR) &
82+
~(MACCR_TXFC_ENABLE | MACCR_RXFC_ENABLE);
83+
AX_WRITE(&ax_local->ax_spi, maccr, P0_MACCR);
84+
85+
mutex_unlock(&ax_local->spi_lock);
86+
}
87+
88+
return 0;
89+
}
90+
91+
static int ax88796c_get_regs_len(struct net_device *ndev)
92+
{
93+
return AX88796C_REGDUMP_LEN + AX88796C_PHY_REGDUMP_LEN;
94+
}
95+
96+
static void
97+
ax88796c_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *_p)
98+
{
99+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
100+
int offset, i;
101+
u16 *p = _p;
102+
103+
memset(p, 0, ax88796c_get_regs_len(ndev));
104+
105+
mutex_lock(&ax_local->spi_lock);
106+
107+
for (offset = 0; offset < AX88796C_REGDUMP_LEN; offset += 2) {
108+
if (!test_bit(offset / 2, ax88796c_no_regs_mask))
109+
*p = AX_READ(&ax_local->ax_spi, offset);
110+
p++;
111+
}
112+
113+
mutex_unlock(&ax_local->spi_lock);
114+
115+
for (i = 0; i < AX88796C_PHY_REGDUMP_LEN / 2; i++) {
116+
*p = phy_read(ax_local->phydev, i);
117+
p++;
118+
}
119+
}
120+
121+
static void
122+
ax88796c_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
123+
{
124+
switch (stringset) {
125+
case ETH_SS_PRIV_FLAGS:
126+
memcpy(data, ax88796c_priv_flag_names,
127+
sizeof(ax88796c_priv_flag_names));
128+
break;
129+
}
130+
}
131+
132+
static int
133+
ax88796c_get_sset_count(struct net_device *ndev, int stringset)
134+
{
135+
int ret = 0;
136+
137+
switch (stringset) {
138+
case ETH_SS_PRIV_FLAGS:
139+
ret = ARRAY_SIZE(ax88796c_priv_flag_names);
140+
break;
141+
default:
142+
ret = -EOPNOTSUPP;
143+
}
144+
145+
return ret;
146+
}
147+
148+
static int ax88796c_set_priv_flags(struct net_device *ndev, u32 flags)
149+
{
150+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
151+
152+
if (flags & ~AX_PRIV_FLAGS_MASK)
153+
return -EOPNOTSUPP;
154+
155+
if ((ax_local->priv_flags ^ flags) & AX_CAP_COMP)
156+
if (netif_running(ndev))
157+
return -EBUSY;
158+
159+
ax_local->priv_flags = flags;
160+
161+
return 0;
162+
}
163+
164+
static u32 ax88796c_get_priv_flags(struct net_device *ndev)
165+
{
166+
struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
167+
168+
return ax_local->priv_flags;
169+
}
170+
171+
int ax88796c_mdio_read(struct mii_bus *mdiobus, int phy_id, int loc)
172+
{
173+
struct ax88796c_device *ax_local = mdiobus->priv;
174+
int ret;
175+
176+
mutex_lock(&ax_local->spi_lock);
177+
AX_WRITE(&ax_local->ax_spi, MDIOCR_RADDR(loc)
178+
| MDIOCR_FADDR(phy_id) | MDIOCR_READ, P2_MDIOCR);
179+
180+
ret = read_poll_timeout(AX_READ, ret,
181+
(ret != 0),
182+
0, jiffies_to_usecs(HZ / 100), false,
183+
&ax_local->ax_spi, P2_MDIOCR);
184+
if (!ret)
185+
ret = AX_READ(&ax_local->ax_spi, P2_MDIODR);
186+
187+
mutex_unlock(&ax_local->spi_lock);
188+
189+
return ret;
190+
}
191+
192+
int
193+
ax88796c_mdio_write(struct mii_bus *mdiobus, int phy_id, int loc, u16 val)
194+
{
195+
struct ax88796c_device *ax_local = mdiobus->priv;
196+
int ret;
197+
198+
mutex_lock(&ax_local->spi_lock);
199+
AX_WRITE(&ax_local->ax_spi, val, P2_MDIODR);
200+
201+
AX_WRITE(&ax_local->ax_spi,
202+
MDIOCR_RADDR(loc) | MDIOCR_FADDR(phy_id)
203+
| MDIOCR_WRITE, P2_MDIOCR);
204+
205+
ret = read_poll_timeout(AX_READ, ret,
206+
((ret & MDIOCR_VALID) != 0), 0,
207+
jiffies_to_usecs(HZ / 100), false,
208+
&ax_local->ax_spi, P2_MDIOCR);
209+
mutex_unlock(&ax_local->spi_lock);
210+
211+
return ret;
212+
}
213+
214+
const struct ethtool_ops ax88796c_ethtool_ops = {
215+
.get_drvinfo = ax88796c_get_drvinfo,
216+
.get_link = ethtool_op_get_link,
217+
.get_msglevel = ax88796c_get_msglevel,
218+
.set_msglevel = ax88796c_set_msglevel,
219+
.get_link_ksettings = phy_ethtool_get_link_ksettings,
220+
.set_link_ksettings = phy_ethtool_set_link_ksettings,
221+
.nway_reset = phy_ethtool_nway_reset,
222+
.get_pauseparam = ax88796c_get_pauseparam,
223+
.set_pauseparam = ax88796c_set_pauseparam,
224+
.get_regs_len = ax88796c_get_regs_len,
225+
.get_regs = ax88796c_get_regs,
226+
.get_strings = ax88796c_get_strings,
227+
.get_sset_count = ax88796c_get_sset_count,
228+
.get_priv_flags = ax88796c_get_priv_flags,
229+
.set_priv_flags = ax88796c_set_priv_flags,
230+
};
231+
232+
int ax88796c_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
233+
{
234+
int ret;
235+
236+
ret = phy_mii_ioctl(ndev->phydev, ifr, cmd);
237+
238+
return ret;
239+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (c) 2010 ASIX Electronics Corporation
4+
* Copyright (c) 2020 Samsung Electronics Co., Ltd.
5+
*
6+
* ASIX AX88796C SPI Fast Ethernet Linux driver
7+
*/
8+
9+
#ifndef _AX88796C_IOCTL_H
10+
#define _AX88796C_IOCTL_H
11+
12+
#include <linux/ethtool.h>
13+
#include <linux/netdevice.h>
14+
15+
#include "ax88796c_main.h"
16+
17+
extern const struct ethtool_ops ax88796c_ethtool_ops;
18+
19+
bool ax88796c_check_power(const struct ax88796c_device *ax_local);
20+
bool ax88796c_check_power_and_wake(struct ax88796c_device *ax_local);
21+
void ax88796c_set_power_saving(struct ax88796c_device *ax_local, u8 ps_level);
22+
int ax88796c_mdio_read(struct mii_bus *mdiobus, int phy_id, int loc);
23+
int ax88796c_mdio_write(struct mii_bus *mdiobus, int phy_id, int loc, u16 val);
24+
int ax88796c_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
25+
26+
#endif

0 commit comments

Comments
 (0)