Thread (10 messages) 10 messages, 4 authors, 2020-10-29

Re: [PATCH v4 3/5] net: ax88796c: ASIX AX88796C SPI Ethernet Adapter Driver

flat view

From: Marc Kleine-Budde <mkl@pengutronix.de>
Date: 2020-10-29 17:36:01
Also in: linux-arm-kernel, linux-devicetree, linux-samsung-soc, lkml

Possibly related (same subject, not in this thread)

On 10/28/20 10:40 PM, Łukasz Stelmach wrote:
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.

[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 <l.stelmach@samsung.com>
---
 MAINTAINERS                                |    6 +
 drivers/net/ethernet/Kconfig               |    1 +
 drivers/net/ethernet/Makefile              |    1 +
 drivers/net/ethernet/asix/Kconfig          |   22 +
 drivers/net/ethernet/asix/Makefile         |    6 +
 drivers/net/ethernet/asix/ax88796c_ioctl.c |  197 ++++
 drivers/net/ethernet/asix/ax88796c_ioctl.h |   26 +
 drivers/net/ethernet/asix/ax88796c_main.c  | 1144 ++++++++++++++++++++
 drivers/net/ethernet/asix/ax88796c_main.h  |  578 ++++++++++
 drivers/net/ethernet/asix/ax88796c_spi.c   |  111 ++
 drivers/net/ethernet/asix/ax88796c_spi.h   |   69 ++
 11 files changed, 2161 insertions(+)
 create mode 100644 drivers/net/ethernet/asix/Kconfig
 create mode 100644 drivers/net/ethernet/asix/Makefile
 create mode 100644 drivers/net/ethernet/asix/ax88796c_ioctl.c
 create mode 100644 drivers/net/ethernet/asix/ax88796c_ioctl.h
 create mode 100644 drivers/net/ethernet/asix/ax88796c_main.c
 create mode 100644 drivers/net/ethernet/asix/ax88796c_main.h
 create mode 100644 drivers/net/ethernet/asix/ax88796c_spi.c
 create mode 100644 drivers/net/ethernet/asix/ax88796c_spi.h
[...]
quoted hunk ↗ jump to hunk
+enum watchdog_state {
+	chk_link = 0,
+	chk_cable,
+	ax_nop,
+};
+
+struct ax88796c_device {
+	struct resource		*addr_res;   /* resources found */
+	struct resource		*addr_req;   /* resources requested */
+	struct resource		*irq_res;
+
+	struct spi_device	*spi;
+	struct net_device	*ndev;
+	struct net_device_stats	stats;
+
+	struct timer_list	watchdog;
+	enum watchdog_state	w_state;
+	size_t			w_ticks;
are these used?
quoted hunk ↗ jump to hunk
+
+	struct work_struct	ax_work;
+
+	struct mutex		spi_lock; /* device access */
+
+	struct sk_buff_head	tx_wait_q;
+
+	struct axspi_data	ax_spi;
+
+	struct mii_bus		*mdiobus;
+	struct phy_device	*phydev;
+
+	int			msg_enable;
+
+	u16			seq_num;
+
+	u8			multi_filter[AX_MCAST_FILTER_SIZE];
+
+	int			link;
+	int			speed;
+	int			duplex;
+	int			pause;
+	int			asym_pause;
+	int			flowctrl;
+		#define AX_FC_NONE		0
+		#define AX_FC_RX		BIT(0)
+		#define AX_FC_TX		BIT(1)
+		#define AX_FC_ANEG		BIT(2)
+
+	unsigned long		capabilities;
+		#define AX_CAP_DMA		BIT(0)
+		#define AX_CAP_COMP		BIT(1)
+		#define AX_CAP_BIDIR		BIT(2)
+
+	u8			plat_endian;
+		#define PLAT_LITTLE_ENDIAN	0
+		#define PLAT_BIG_ENDIAN		1
+
+	unsigned long		flags;
+		#define EVENT_INTR		BIT(0)
+		#define EVENT_TX		BIT(1)
+		#define EVENT_SET_MULTI		BIT(2)
+
+};
+
+#define to_ax88796c_device(ndev) ((struct ax88796c_device *)netdev_priv(ndev))
+
+enum skb_state {
+	illegal = 0,
+	tx_done,
+	rx_done,
+	rx_err,
+};
+
+struct skb_data {
+	enum skb_state state;
+	struct net_device *ndev;
+	struct sk_buff *skb;
+	size_t len;
+	dma_addr_t phy_addr;
unused?

[...]
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/ethernet/asix/ax88796c_spi.c b/drivers/net/ethernet/asix/ax88796c_spi.c
new file mode 100644
index 000000000000..1a20bbeb4dc1
--- /dev/null
+++ b/drivers/net/ethernet/asix/ax88796c_spi.c
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2010 ASIX Electronics Corporation
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * ASIX AX88796C SPI Fast Ethernet Linux driver
+ */
+
+#define pr_fmt(fmt)	"ax88796c: " fmt
+
+#include <linux/string.h>
+#include <linux/spi/spi.h>
+
+#include "ax88796c_spi.h"
+
+/* driver bus management functions */
+int axspi_wakeup(const struct axspi_data *ax_spi)
+{
+	u8 tx_buf;
+	int ret;
+
+	tx_buf = AX_SPICMD_EXIT_PWD;	/* OP */
+	ret = spi_write(ax_spi->spi, &tx_buf, 1);
spi_write() needs a DMA safe buffer.
quoted hunk ↗ jump to hunk
+	if (ret)
+		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
+	return ret;
+}
+
+int axspi_read_status(const struct axspi_data *ax_spi, struct spi_status *status)
+{
+	u8 tx_buf;
+	int ret;
+
+	/* OP */
+	tx_buf = AX_SPICMD_READ_STATUS;
+	ret = spi_write_then_read(ax_spi->spi, &tx_buf, 1, (u8 *)&status, 3);
+	if (ret)
+		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
+	else
+		le16_to_cpus(&status->isr);
+
+	return ret;
+}
+
+int axspi_read_rxq(struct axspi_data *ax_spi, void *data, int len)
+{
+	struct spi_transfer *xfer = ax_spi->spi_rx_xfer;
+	int ret;
+
+	memcpy(ax_spi->cmd_buf, rx_cmd_buf, 5);
+
+	xfer->tx_buf = ax_spi->cmd_buf;
+	xfer->rx_buf = NULL;
+	xfer->len = ax_spi->comp ? 2 : 5;
+	xfer->bits_per_word = 8;
+	spi_message_add_tail(xfer, &ax_spi->rx_msg);
+
+	xfer++;
+	xfer->rx_buf = data;
+	xfer->tx_buf = NULL;
+	xfer->len = len;
+	xfer->bits_per_word = 8;
+	spi_message_add_tail(xfer, &ax_spi->rx_msg);
+	ret = spi_sync(ax_spi->spi, &ax_spi->rx_msg);
+	if (ret)
+		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
+
+	return ret;
+}
+
+int axspi_write_txq(const struct axspi_data *ax_spi, void *data, int len)
+{
+	return spi_write(ax_spi->spi, data, len);
+}
+
+u16 axspi_read_reg(const struct axspi_data *ax_spi, u8 reg)
+{
+	u8 tx_buf[4];
+	u16 rx_buf = 0;
+	int ret;
+	int len = ax_spi->comp ? 3 : 4;
+
+	tx_buf[0] = 0x03;	/* OP code read register */
+	tx_buf[1] = reg;	/* register address */
+	tx_buf[2] = 0xFF;	/* dumy cycle */
+	tx_buf[3] = 0xFF;	/* dumy cycle */
+	ret = spi_write_then_read(ax_spi->spi, tx_buf, len, (u8 *)&rx_buf, 2);
+	if (ret)
+		dev_err(&ax_spi->spi->dev, "%s() failed: ret = %d\n", __func__, ret);
+	else
+		le16_to_cpus(&rx_buf);
+
+	return rx_buf;
+}
+
+int axspi_write_reg(const struct axspi_data *ax_spi, u8 reg, u16 value)
+{
+	u8 tx_buf[4];
+	int ret;
+
+	tx_buf[0] = AX_SPICMD_WRITE_REG;	/* OP code read register */
+	tx_buf[1] = reg;			/* register address */
+	tx_buf[2] = value;
+	tx_buf[3] = value >> 8;
+
+	ret = spi_write(ax_spi->spi, tx_buf, 4);
I think you need DMA safe mem for spi_write().

Marc

-- 
Pengutronix e.K.                 | Marc Kleine-Budde           |
Embedded Linux                   | https://www.pengutronix.de  |
Vertretung West/Dortmund         | Phone: +49-231-2826-924     |
Amtsgericht Hildesheim, HRA 2686 | Fax:   +49-5121-206917-5555 |

Attachments

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help