162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Copyright (C) 2021 in-tech smart charging GmbH
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * driver is based on micrel/ks8851_spi.c
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/interrupt.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/netdevice.h>
1362306a36Sopenharmony_ci#include <linux/etherdevice.h>
1462306a36Sopenharmony_ci#include <linux/ethtool.h>
1562306a36Sopenharmony_ci#include <linux/cache.h>
1662306a36Sopenharmony_ci#include <linux/debugfs.h>
1762306a36Sopenharmony_ci#include <linux/seq_file.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/spi/spi.h>
2062306a36Sopenharmony_ci#include <linux/of_net.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define MSG_DEFAULT	(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
2362306a36Sopenharmony_ci			 NETIF_MSG_TIMER)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define DRV_NAME	"mse102x"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define DET_CMD		0x0001
2862306a36Sopenharmony_ci#define DET_SOF		0x0002
2962306a36Sopenharmony_ci#define DET_DFT		0x55AA
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define CMD_SHIFT	12
3262306a36Sopenharmony_ci#define CMD_RTS		(0x1 << CMD_SHIFT)
3362306a36Sopenharmony_ci#define CMD_CTR		(0x2 << CMD_SHIFT)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define CMD_MASK	GENMASK(15, CMD_SHIFT)
3662306a36Sopenharmony_ci#define LEN_MASK	GENMASK(CMD_SHIFT - 1, 0)
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci#define DET_CMD_LEN	4
3962306a36Sopenharmony_ci#define DET_SOF_LEN	2
4062306a36Sopenharmony_ci#define DET_DFT_LEN	2
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define MIN_FREQ_HZ	6000000
4362306a36Sopenharmony_ci#define MAX_FREQ_HZ	7142857
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cistruct mse102x_stats {
4662306a36Sopenharmony_ci	u64 xfer_err;
4762306a36Sopenharmony_ci	u64 invalid_cmd;
4862306a36Sopenharmony_ci	u64 invalid_ctr;
4962306a36Sopenharmony_ci	u64 invalid_dft;
5062306a36Sopenharmony_ci	u64 invalid_len;
5162306a36Sopenharmony_ci	u64 invalid_rts;
5262306a36Sopenharmony_ci	u64 invalid_sof;
5362306a36Sopenharmony_ci	u64 tx_timeout;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic const char mse102x_gstrings_stats[][ETH_GSTRING_LEN] = {
5762306a36Sopenharmony_ci	"SPI transfer errors",
5862306a36Sopenharmony_ci	"Invalid command",
5962306a36Sopenharmony_ci	"Invalid CTR",
6062306a36Sopenharmony_ci	"Invalid DFT",
6162306a36Sopenharmony_ci	"Invalid frame length",
6262306a36Sopenharmony_ci	"Invalid RTS",
6362306a36Sopenharmony_ci	"Invalid SOF",
6462306a36Sopenharmony_ci	"TX timeout",
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct mse102x_net {
6862306a36Sopenharmony_ci	struct net_device	*ndev;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	u8			rxd[8];
7162306a36Sopenharmony_ci	u8			txd[8];
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	u32			msg_enable ____cacheline_aligned;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	struct sk_buff_head	txq;
7662306a36Sopenharmony_ci	struct mse102x_stats	stats;
7762306a36Sopenharmony_ci};
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistruct mse102x_net_spi {
8062306a36Sopenharmony_ci	struct mse102x_net	mse102x;
8162306a36Sopenharmony_ci	struct mutex		lock;		/* Protect SPI frame transfer */
8262306a36Sopenharmony_ci	struct work_struct	tx_work;
8362306a36Sopenharmony_ci	struct spi_device	*spidev;
8462306a36Sopenharmony_ci	struct spi_message	spi_msg;
8562306a36Sopenharmony_ci	struct spi_transfer	spi_xfer;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
8862306a36Sopenharmony_ci	struct dentry		*device_root;
8962306a36Sopenharmony_ci#endif
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define to_mse102x_spi(mse) container_of((mse), struct mse102x_net_spi, mse102x)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic int mse102x_info_show(struct seq_file *s, void *what)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct mse102x_net_spi *mses = s->private;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	seq_printf(s, "TX ring size        : %u\n",
10162306a36Sopenharmony_ci		   skb_queue_len(&mses->mse102x.txq));
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	seq_printf(s, "IRQ                 : %d\n",
10462306a36Sopenharmony_ci		   mses->spidev->irq);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	seq_printf(s, "SPI effective speed : %lu\n",
10762306a36Sopenharmony_ci		   (unsigned long)mses->spi_xfer.effective_speed_hz);
10862306a36Sopenharmony_ci	seq_printf(s, "SPI mode            : %x\n",
10962306a36Sopenharmony_ci		   mses->spidev->mode);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	return 0;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(mse102x_info);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_cistatic void mse102x_init_device_debugfs(struct mse102x_net_spi *mses)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	mses->device_root = debugfs_create_dir(dev_name(&mses->mse102x.ndev->dev),
11862306a36Sopenharmony_ci					       NULL);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	debugfs_create_file("info", S_IFREG | 0444, mses->device_root, mses,
12162306a36Sopenharmony_ci			    &mse102x_info_fops);
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void mse102x_remove_device_debugfs(struct mse102x_net_spi *mses)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	debugfs_remove_recursive(mses->device_root);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci#else /* CONFIG_DEBUG_FS */
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic void mse102x_init_device_debugfs(struct mse102x_net_spi *mses)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic void mse102x_remove_device_debugfs(struct mse102x_net_spi *mses)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#endif
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/* SPI register read/write calls.
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * All these calls issue SPI transactions to access the chip's registers. They
14462306a36Sopenharmony_ci * all require that the necessary lock is held to prevent accesses when the
14562306a36Sopenharmony_ci * chip is busy transferring packet data.
14662306a36Sopenharmony_ci */
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic void mse102x_tx_cmd_spi(struct mse102x_net *mse, u16 cmd)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
15162306a36Sopenharmony_ci	struct spi_transfer *xfer = &mses->spi_xfer;
15262306a36Sopenharmony_ci	struct spi_message *msg = &mses->spi_msg;
15362306a36Sopenharmony_ci	__be16 txb[2];
15462306a36Sopenharmony_ci	int ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	txb[0] = cpu_to_be16(DET_CMD);
15762306a36Sopenharmony_ci	txb[1] = cpu_to_be16(cmd);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	xfer->tx_buf = txb;
16062306a36Sopenharmony_ci	xfer->rx_buf = NULL;
16162306a36Sopenharmony_ci	xfer->len = DET_CMD_LEN;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	ret = spi_sync(mses->spidev, msg);
16462306a36Sopenharmony_ci	if (ret < 0) {
16562306a36Sopenharmony_ci		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
16662306a36Sopenharmony_ci			   __func__, ret);
16762306a36Sopenharmony_ci		mse->stats.xfer_err++;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int mse102x_rx_cmd_spi(struct mse102x_net *mse, u8 *rxb)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
17462306a36Sopenharmony_ci	struct spi_transfer *xfer = &mses->spi_xfer;
17562306a36Sopenharmony_ci	struct spi_message *msg = &mses->spi_msg;
17662306a36Sopenharmony_ci	__be16 *txb = (__be16 *)mse->txd;
17762306a36Sopenharmony_ci	__be16 *cmd = (__be16 *)mse->rxd;
17862306a36Sopenharmony_ci	u8 *trx = mse->rxd;
17962306a36Sopenharmony_ci	int ret;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	txb[0] = 0;
18262306a36Sopenharmony_ci	txb[1] = 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	xfer->tx_buf = txb;
18562306a36Sopenharmony_ci	xfer->rx_buf = trx;
18662306a36Sopenharmony_ci	xfer->len = DET_CMD_LEN;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	ret = spi_sync(mses->spidev, msg);
18962306a36Sopenharmony_ci	if (ret < 0) {
19062306a36Sopenharmony_ci		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
19162306a36Sopenharmony_ci			   __func__, ret);
19262306a36Sopenharmony_ci		mse->stats.xfer_err++;
19362306a36Sopenharmony_ci	} else if (*cmd != cpu_to_be16(DET_CMD)) {
19462306a36Sopenharmony_ci		net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
19562306a36Sopenharmony_ci				    __func__, *cmd);
19662306a36Sopenharmony_ci		mse->stats.invalid_cmd++;
19762306a36Sopenharmony_ci		ret = -EIO;
19862306a36Sopenharmony_ci	} else {
19962306a36Sopenharmony_ci		memcpy(rxb, trx + 2, 2);
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return ret;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic inline void mse102x_push_header(struct sk_buff *skb)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	__be16 *header = skb_push(skb, DET_SOF_LEN);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	*header = cpu_to_be16(DET_SOF);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic inline void mse102x_put_footer(struct sk_buff *skb)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	__be16 *footer = skb_put(skb, DET_DFT_LEN);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	*footer = cpu_to_be16(DET_DFT);
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp,
22062306a36Sopenharmony_ci				unsigned int pad)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
22362306a36Sopenharmony_ci	struct spi_transfer *xfer = &mses->spi_xfer;
22462306a36Sopenharmony_ci	struct spi_message *msg = &mses->spi_msg;
22562306a36Sopenharmony_ci	struct sk_buff *tskb;
22662306a36Sopenharmony_ci	int ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	netif_dbg(mse, tx_queued, mse->ndev, "%s: skb %p, %d@%p\n",
22962306a36Sopenharmony_ci		  __func__, txp, txp->len, txp->data);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if ((skb_headroom(txp) < DET_SOF_LEN) ||
23262306a36Sopenharmony_ci	    (skb_tailroom(txp) < DET_DFT_LEN + pad)) {
23362306a36Sopenharmony_ci		tskb = skb_copy_expand(txp, DET_SOF_LEN, DET_DFT_LEN + pad,
23462306a36Sopenharmony_ci				       GFP_KERNEL);
23562306a36Sopenharmony_ci		if (!tskb)
23662306a36Sopenharmony_ci			return -ENOMEM;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci		dev_kfree_skb(txp);
23962306a36Sopenharmony_ci		txp = tskb;
24062306a36Sopenharmony_ci	}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	mse102x_push_header(txp);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	if (pad)
24562306a36Sopenharmony_ci		skb_put_zero(txp, pad);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	mse102x_put_footer(txp);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	xfer->tx_buf = txp->data;
25062306a36Sopenharmony_ci	xfer->rx_buf = NULL;
25162306a36Sopenharmony_ci	xfer->len = txp->len;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	ret = spi_sync(mses->spidev, msg);
25462306a36Sopenharmony_ci	if (ret < 0) {
25562306a36Sopenharmony_ci		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
25662306a36Sopenharmony_ci			   __func__, ret);
25762306a36Sopenharmony_ci		mse->stats.xfer_err++;
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	return ret;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_cistatic int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff,
26462306a36Sopenharmony_ci				unsigned int frame_len)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
26762306a36Sopenharmony_ci	struct spi_transfer *xfer = &mses->spi_xfer;
26862306a36Sopenharmony_ci	struct spi_message *msg = &mses->spi_msg;
26962306a36Sopenharmony_ci	__be16 *sof = (__be16 *)buff;
27062306a36Sopenharmony_ci	__be16 *dft = (__be16 *)(buff + DET_SOF_LEN + frame_len);
27162306a36Sopenharmony_ci	int ret;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	xfer->rx_buf = buff;
27462306a36Sopenharmony_ci	xfer->tx_buf = NULL;
27562306a36Sopenharmony_ci	xfer->len = DET_SOF_LEN + frame_len + DET_DFT_LEN;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	ret = spi_sync(mses->spidev, msg);
27862306a36Sopenharmony_ci	if (ret < 0) {
27962306a36Sopenharmony_ci		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
28062306a36Sopenharmony_ci			   __func__, ret);
28162306a36Sopenharmony_ci		mse->stats.xfer_err++;
28262306a36Sopenharmony_ci	} else if (*sof != cpu_to_be16(DET_SOF)) {
28362306a36Sopenharmony_ci		netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n",
28462306a36Sopenharmony_ci			   __func__, *sof);
28562306a36Sopenharmony_ci		mse->stats.invalid_sof++;
28662306a36Sopenharmony_ci		ret = -EIO;
28762306a36Sopenharmony_ci	} else if (*dft != cpu_to_be16(DET_DFT)) {
28862306a36Sopenharmony_ci		netdev_dbg(mse->ndev, "%s: SPI frame tail is invalid (0x%04x)\n",
28962306a36Sopenharmony_ci			   __func__, *dft);
29062306a36Sopenharmony_ci		mse->stats.invalid_dft++;
29162306a36Sopenharmony_ci		ret = -EIO;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	return ret;
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_cistatic void mse102x_dump_packet(const char *msg, int len, const char *data)
29862306a36Sopenharmony_ci{
29962306a36Sopenharmony_ci	printk(KERN_DEBUG ": %s - packet len:%d\n", msg, len);
30062306a36Sopenharmony_ci	print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1,
30162306a36Sopenharmony_ci		       data, len, true);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic void mse102x_rx_pkt_spi(struct mse102x_net *mse)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct sk_buff *skb;
30762306a36Sopenharmony_ci	unsigned int rxalign;
30862306a36Sopenharmony_ci	unsigned int rxlen;
30962306a36Sopenharmony_ci	__be16 rx = 0;
31062306a36Sopenharmony_ci	u16 cmd_resp;
31162306a36Sopenharmony_ci	u8 *rxpkt;
31262306a36Sopenharmony_ci	int ret;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	mse102x_tx_cmd_spi(mse, CMD_CTR);
31562306a36Sopenharmony_ci	ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
31662306a36Sopenharmony_ci	cmd_resp = be16_to_cpu(rx);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (ret || ((cmd_resp & CMD_MASK) != CMD_RTS)) {
31962306a36Sopenharmony_ci		usleep_range(50, 100);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci		mse102x_tx_cmd_spi(mse, CMD_CTR);
32262306a36Sopenharmony_ci		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
32362306a36Sopenharmony_ci		if (ret)
32462306a36Sopenharmony_ci			return;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		cmd_resp = be16_to_cpu(rx);
32762306a36Sopenharmony_ci		if ((cmd_resp & CMD_MASK) != CMD_RTS) {
32862306a36Sopenharmony_ci			net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
32962306a36Sopenharmony_ci					    __func__, cmd_resp);
33062306a36Sopenharmony_ci			mse->stats.invalid_rts++;
33162306a36Sopenharmony_ci			return;
33262306a36Sopenharmony_ci		}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci		net_dbg_ratelimited("%s: Unexpected response to first CMD\n",
33562306a36Sopenharmony_ci				    __func__);
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	rxlen = cmd_resp & LEN_MASK;
33962306a36Sopenharmony_ci	if (!rxlen) {
34062306a36Sopenharmony_ci		net_dbg_ratelimited("%s: No frame length defined\n", __func__);
34162306a36Sopenharmony_ci		mse->stats.invalid_len++;
34262306a36Sopenharmony_ci		return;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4);
34662306a36Sopenharmony_ci	skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign);
34762306a36Sopenharmony_ci	if (!skb)
34862306a36Sopenharmony_ci		return;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/* 2 bytes Start of frame (before ethernet header)
35162306a36Sopenharmony_ci	 * 2 bytes Data frame tail (after ethernet frame)
35262306a36Sopenharmony_ci	 * They are copied, but ignored.
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN;
35562306a36Sopenharmony_ci	if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) {
35662306a36Sopenharmony_ci		mse->ndev->stats.rx_errors++;
35762306a36Sopenharmony_ci		dev_kfree_skb(skb);
35862306a36Sopenharmony_ci		return;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	if (netif_msg_pktdata(mse))
36262306a36Sopenharmony_ci		mse102x_dump_packet(__func__, skb->len, skb->data);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	skb->protocol = eth_type_trans(skb, mse->ndev);
36562306a36Sopenharmony_ci	netif_rx(skb);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	mse->ndev->stats.rx_packets++;
36862306a36Sopenharmony_ci	mse->ndev->stats.rx_bytes += rxlen;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_cistatic int mse102x_tx_pkt_spi(struct mse102x_net *mse, struct sk_buff *txb,
37262306a36Sopenharmony_ci			      unsigned long work_timeout)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	unsigned int pad = 0;
37562306a36Sopenharmony_ci	__be16 rx = 0;
37662306a36Sopenharmony_ci	u16 cmd_resp;
37762306a36Sopenharmony_ci	int ret;
37862306a36Sopenharmony_ci	bool first = true;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (txb->len < 60)
38162306a36Sopenharmony_ci		pad = 60 - txb->len;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	while (1) {
38462306a36Sopenharmony_ci		mse102x_tx_cmd_spi(mse, CMD_RTS | (txb->len + pad));
38562306a36Sopenharmony_ci		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
38662306a36Sopenharmony_ci		cmd_resp = be16_to_cpu(rx);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		if (!ret) {
38962306a36Sopenharmony_ci			/* ready to send frame ? */
39062306a36Sopenharmony_ci			if (cmd_resp == CMD_CTR)
39162306a36Sopenharmony_ci				break;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci			net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
39462306a36Sopenharmony_ci					    __func__, cmd_resp);
39562306a36Sopenharmony_ci			mse->stats.invalid_ctr++;
39662306a36Sopenharmony_ci		}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		/* It's not predictable how long / many retries it takes to
39962306a36Sopenharmony_ci		 * send at least one packet, so TX timeouts are possible.
40062306a36Sopenharmony_ci		 * That's the reason why the netdev watchdog is not used here.
40162306a36Sopenharmony_ci		 */
40262306a36Sopenharmony_ci		if (time_after(jiffies, work_timeout))
40362306a36Sopenharmony_ci			return -ETIMEDOUT;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		if (first) {
40662306a36Sopenharmony_ci			/* throttle at first issue */
40762306a36Sopenharmony_ci			netif_stop_queue(mse->ndev);
40862306a36Sopenharmony_ci			/* fast retry */
40962306a36Sopenharmony_ci			usleep_range(50, 100);
41062306a36Sopenharmony_ci			first = false;
41162306a36Sopenharmony_ci		} else {
41262306a36Sopenharmony_ci			msleep(20);
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	ret = mse102x_tx_frame_spi(mse, txb, pad);
41762306a36Sopenharmony_ci	if (ret)
41862306a36Sopenharmony_ci		net_dbg_ratelimited("%s: Failed to send (%d), drop frame\n",
41962306a36Sopenharmony_ci				    __func__, ret);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return ret;
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci#define TX_QUEUE_MAX 10
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic void mse102x_tx_work(struct work_struct *work)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	/* Make sure timeout is sufficient to transfer TX_QUEUE_MAX frames */
42962306a36Sopenharmony_ci	unsigned long work_timeout = jiffies + msecs_to_jiffies(1000);
43062306a36Sopenharmony_ci	struct mse102x_net_spi *mses;
43162306a36Sopenharmony_ci	struct mse102x_net *mse;
43262306a36Sopenharmony_ci	struct sk_buff *txb;
43362306a36Sopenharmony_ci	int ret = 0;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	mses = container_of(work, struct mse102x_net_spi, tx_work);
43662306a36Sopenharmony_ci	mse = &mses->mse102x;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	while ((txb = skb_dequeue(&mse->txq))) {
43962306a36Sopenharmony_ci		mutex_lock(&mses->lock);
44062306a36Sopenharmony_ci		ret = mse102x_tx_pkt_spi(mse, txb, work_timeout);
44162306a36Sopenharmony_ci		mutex_unlock(&mses->lock);
44262306a36Sopenharmony_ci		if (ret) {
44362306a36Sopenharmony_ci			mse->ndev->stats.tx_dropped++;
44462306a36Sopenharmony_ci		} else {
44562306a36Sopenharmony_ci			mse->ndev->stats.tx_bytes += txb->len;
44662306a36Sopenharmony_ci			mse->ndev->stats.tx_packets++;
44762306a36Sopenharmony_ci		}
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		dev_kfree_skb(txb);
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
45362306a36Sopenharmony_ci		if (netif_msg_timer(mse))
45462306a36Sopenharmony_ci			netdev_err(mse->ndev, "tx work timeout\n");
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci		mse->stats.tx_timeout++;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	netif_wake_queue(mse->ndev);
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic netdev_tx_t mse102x_start_xmit_spi(struct sk_buff *skb,
46362306a36Sopenharmony_ci					  struct net_device *ndev)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct mse102x_net *mse = netdev_priv(ndev);
46662306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	netif_dbg(mse, tx_queued, ndev,
46962306a36Sopenharmony_ci		  "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data);
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	skb_queue_tail(&mse->txq, skb);
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (skb_queue_len(&mse->txq) >= TX_QUEUE_MAX)
47462306a36Sopenharmony_ci		netif_stop_queue(ndev);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	schedule_work(&mses->tx_work);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	return NETDEV_TX_OK;
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_cistatic void mse102x_init_mac(struct mse102x_net *mse, struct device_node *np)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct net_device *ndev = mse->ndev;
48462306a36Sopenharmony_ci	int ret = of_get_ethdev_address(np, ndev);
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	if (ret) {
48762306a36Sopenharmony_ci		eth_hw_addr_random(ndev);
48862306a36Sopenharmony_ci		netdev_err(ndev, "Using random MAC address: %pM\n",
48962306a36Sopenharmony_ci			   ndev->dev_addr);
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci/* Assumption: this is called for every incoming packet */
49462306a36Sopenharmony_cistatic irqreturn_t mse102x_irq(int irq, void *_mse)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct mse102x_net *mse = _mse;
49762306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	mutex_lock(&mses->lock);
50062306a36Sopenharmony_ci	mse102x_rx_pkt_spi(mse);
50162306a36Sopenharmony_ci	mutex_unlock(&mses->lock);
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	return IRQ_HANDLED;
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_cistatic int mse102x_net_open(struct net_device *ndev)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct mse102x_net *mse = netdev_priv(ndev);
50962306a36Sopenharmony_ci	int ret;
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT,
51262306a36Sopenharmony_ci				   ndev->name, mse);
51362306a36Sopenharmony_ci	if (ret < 0) {
51462306a36Sopenharmony_ci		netdev_err(ndev, "Failed to get irq: %d\n", ret);
51562306a36Sopenharmony_ci		return ret;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	netif_dbg(mse, ifup, ndev, "opening\n");
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	netif_start_queue(ndev);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	netif_carrier_on(ndev);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	netif_dbg(mse, ifup, ndev, "network device up\n");
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return 0;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic int mse102x_net_stop(struct net_device *ndev)
53062306a36Sopenharmony_ci{
53162306a36Sopenharmony_ci	struct mse102x_net *mse = netdev_priv(ndev);
53262306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	netif_info(mse, ifdown, ndev, "shutting down\n");
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	netif_carrier_off(mse->ndev);
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	/* stop any outstanding work */
53962306a36Sopenharmony_ci	flush_work(&mses->tx_work);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	netif_stop_queue(ndev);
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	skb_queue_purge(&mse->txq);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	free_irq(ndev->irq, mse);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	return 0;
54862306a36Sopenharmony_ci}
54962306a36Sopenharmony_ci
55062306a36Sopenharmony_cistatic const struct net_device_ops mse102x_netdev_ops = {
55162306a36Sopenharmony_ci	.ndo_open		= mse102x_net_open,
55262306a36Sopenharmony_ci	.ndo_stop		= mse102x_net_stop,
55362306a36Sopenharmony_ci	.ndo_start_xmit		= mse102x_start_xmit_spi,
55462306a36Sopenharmony_ci	.ndo_set_mac_address	= eth_mac_addr,
55562306a36Sopenharmony_ci	.ndo_validate_addr	= eth_validate_addr,
55662306a36Sopenharmony_ci};
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/* ethtool support */
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void mse102x_get_drvinfo(struct net_device *ndev,
56162306a36Sopenharmony_ci				struct ethtool_drvinfo *di)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	strscpy(di->driver, DRV_NAME, sizeof(di->driver));
56462306a36Sopenharmony_ci	strscpy(di->bus_info, dev_name(ndev->dev.parent), sizeof(di->bus_info));
56562306a36Sopenharmony_ci}
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_cistatic u32 mse102x_get_msglevel(struct net_device *ndev)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct mse102x_net *mse = netdev_priv(ndev);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	return mse->msg_enable;
57262306a36Sopenharmony_ci}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_cistatic void mse102x_set_msglevel(struct net_device *ndev, u32 to)
57562306a36Sopenharmony_ci{
57662306a36Sopenharmony_ci	struct mse102x_net *mse = netdev_priv(ndev);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	mse->msg_enable = to;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic void mse102x_get_ethtool_stats(struct net_device *ndev,
58262306a36Sopenharmony_ci				      struct ethtool_stats *estats, u64 *data)
58362306a36Sopenharmony_ci{
58462306a36Sopenharmony_ci	struct mse102x_net *mse = netdev_priv(ndev);
58562306a36Sopenharmony_ci	struct mse102x_stats *st = &mse->stats;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	memcpy(data, st, ARRAY_SIZE(mse102x_gstrings_stats) * sizeof(u64));
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_cistatic void mse102x_get_strings(struct net_device *ndev, u32 stringset, u8 *buf)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	switch (stringset) {
59362306a36Sopenharmony_ci	case ETH_SS_STATS:
59462306a36Sopenharmony_ci		memcpy(buf, &mse102x_gstrings_stats,
59562306a36Sopenharmony_ci		       sizeof(mse102x_gstrings_stats));
59662306a36Sopenharmony_ci		break;
59762306a36Sopenharmony_ci	default:
59862306a36Sopenharmony_ci		WARN_ON(1);
59962306a36Sopenharmony_ci		break;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_cistatic int mse102x_get_sset_count(struct net_device *ndev, int sset)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	switch (sset) {
60662306a36Sopenharmony_ci	case ETH_SS_STATS:
60762306a36Sopenharmony_ci		return ARRAY_SIZE(mse102x_gstrings_stats);
60862306a36Sopenharmony_ci	default:
60962306a36Sopenharmony_ci		return -EINVAL;
61062306a36Sopenharmony_ci	}
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_cistatic const struct ethtool_ops mse102x_ethtool_ops = {
61462306a36Sopenharmony_ci	.get_drvinfo		= mse102x_get_drvinfo,
61562306a36Sopenharmony_ci	.get_link		= ethtool_op_get_link,
61662306a36Sopenharmony_ci	.get_msglevel		= mse102x_get_msglevel,
61762306a36Sopenharmony_ci	.set_msglevel		= mse102x_set_msglevel,
61862306a36Sopenharmony_ci	.get_ethtool_stats	= mse102x_get_ethtool_stats,
61962306a36Sopenharmony_ci	.get_strings		= mse102x_get_strings,
62062306a36Sopenharmony_ci	.get_sset_count		= mse102x_get_sset_count,
62162306a36Sopenharmony_ci};
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci/* driver bus management functions */
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic int mse102x_suspend(struct device *dev)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	struct mse102x_net *mse = dev_get_drvdata(dev);
63062306a36Sopenharmony_ci	struct net_device *ndev = mse->ndev;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (netif_running(ndev)) {
63362306a36Sopenharmony_ci		netif_device_detach(ndev);
63462306a36Sopenharmony_ci		mse102x_net_stop(ndev);
63562306a36Sopenharmony_ci	}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	return 0;
63862306a36Sopenharmony_ci}
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_cistatic int mse102x_resume(struct device *dev)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct mse102x_net *mse = dev_get_drvdata(dev);
64362306a36Sopenharmony_ci	struct net_device *ndev = mse->ndev;
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci	if (netif_running(ndev)) {
64662306a36Sopenharmony_ci		mse102x_net_open(ndev);
64762306a36Sopenharmony_ci		netif_device_attach(ndev);
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	return 0;
65162306a36Sopenharmony_ci}
65262306a36Sopenharmony_ci#endif
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mse102x_pm_ops, mse102x_suspend, mse102x_resume);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic int mse102x_probe_spi(struct spi_device *spi)
65762306a36Sopenharmony_ci{
65862306a36Sopenharmony_ci	struct device *dev = &spi->dev;
65962306a36Sopenharmony_ci	struct mse102x_net_spi *mses;
66062306a36Sopenharmony_ci	struct net_device *ndev;
66162306a36Sopenharmony_ci	struct mse102x_net *mse;
66262306a36Sopenharmony_ci	int ret;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	spi->bits_per_word = 8;
66562306a36Sopenharmony_ci	spi->mode |= SPI_MODE_3;
66662306a36Sopenharmony_ci	/* enforce minimum speed to ensure device functionality */
66762306a36Sopenharmony_ci	spi->master->min_speed_hz = MIN_FREQ_HZ;
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	if (!spi->max_speed_hz)
67062306a36Sopenharmony_ci		spi->max_speed_hz = MAX_FREQ_HZ;
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	if (spi->max_speed_hz < MIN_FREQ_HZ ||
67362306a36Sopenharmony_ci	    spi->max_speed_hz > MAX_FREQ_HZ) {
67462306a36Sopenharmony_ci		dev_err(&spi->dev, "SPI max frequency out of range (min: %u, max: %u)\n",
67562306a36Sopenharmony_ci			MIN_FREQ_HZ, MAX_FREQ_HZ);
67662306a36Sopenharmony_ci		return -EINVAL;
67762306a36Sopenharmony_ci	}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	ret = spi_setup(spi);
68062306a36Sopenharmony_ci	if (ret < 0) {
68162306a36Sopenharmony_ci		dev_err(&spi->dev, "Unable to setup SPI device: %d\n", ret);
68262306a36Sopenharmony_ci		return ret;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	ndev = devm_alloc_etherdev(dev, sizeof(struct mse102x_net_spi));
68662306a36Sopenharmony_ci	if (!ndev)
68762306a36Sopenharmony_ci		return -ENOMEM;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	ndev->needed_tailroom += ALIGN(DET_DFT_LEN, 4);
69062306a36Sopenharmony_ci	ndev->needed_headroom += ALIGN(DET_SOF_LEN, 4);
69162306a36Sopenharmony_ci	ndev->priv_flags &= ~IFF_TX_SKB_SHARING;
69262306a36Sopenharmony_ci	ndev->tx_queue_len = 100;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	mse = netdev_priv(ndev);
69562306a36Sopenharmony_ci	mses = to_mse102x_spi(mse);
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	mses->spidev = spi;
69862306a36Sopenharmony_ci	mutex_init(&mses->lock);
69962306a36Sopenharmony_ci	INIT_WORK(&mses->tx_work, mse102x_tx_work);
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	/* initialise pre-made spi transfer messages */
70262306a36Sopenharmony_ci	spi_message_init(&mses->spi_msg);
70362306a36Sopenharmony_ci	spi_message_add_tail(&mses->spi_xfer, &mses->spi_msg);
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	ndev->irq = spi->irq;
70662306a36Sopenharmony_ci	mse->ndev = ndev;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	/* set the default message enable */
70962306a36Sopenharmony_ci	mse->msg_enable = netif_msg_init(-1, MSG_DEFAULT);
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	skb_queue_head_init(&mse->txq);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	SET_NETDEV_DEV(ndev, dev);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	dev_set_drvdata(dev, mse);
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	netif_carrier_off(mse->ndev);
71862306a36Sopenharmony_ci	ndev->netdev_ops = &mse102x_netdev_ops;
71962306a36Sopenharmony_ci	ndev->ethtool_ops = &mse102x_ethtool_ops;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	mse102x_init_mac(mse, dev->of_node);
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	ret = register_netdev(ndev);
72462306a36Sopenharmony_ci	if (ret) {
72562306a36Sopenharmony_ci		dev_err(dev, "failed to register network device: %d\n", ret);
72662306a36Sopenharmony_ci		return ret;
72762306a36Sopenharmony_ci	}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	mse102x_init_device_debugfs(mses);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	return 0;
73262306a36Sopenharmony_ci}
73362306a36Sopenharmony_ci
73462306a36Sopenharmony_cistatic void mse102x_remove_spi(struct spi_device *spi)
73562306a36Sopenharmony_ci{
73662306a36Sopenharmony_ci	struct mse102x_net *mse = dev_get_drvdata(&spi->dev);
73762306a36Sopenharmony_ci	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (netif_msg_drv(mse))
74062306a36Sopenharmony_ci		dev_info(&spi->dev, "remove\n");
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	mse102x_remove_device_debugfs(mses);
74362306a36Sopenharmony_ci	unregister_netdev(mse->ndev);
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_cistatic const struct of_device_id mse102x_match_table[] = {
74762306a36Sopenharmony_ci	{ .compatible = "vertexcom,mse1021" },
74862306a36Sopenharmony_ci	{ .compatible = "vertexcom,mse1022" },
74962306a36Sopenharmony_ci	{ }
75062306a36Sopenharmony_ci};
75162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, mse102x_match_table);
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_cistatic const struct spi_device_id mse102x_ids[] = {
75462306a36Sopenharmony_ci	{ "mse1021" },
75562306a36Sopenharmony_ci	{ "mse1022" },
75662306a36Sopenharmony_ci	{ }
75762306a36Sopenharmony_ci};
75862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, mse102x_ids);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic struct spi_driver mse102x_driver = {
76162306a36Sopenharmony_ci	.driver = {
76262306a36Sopenharmony_ci		.name = DRV_NAME,
76362306a36Sopenharmony_ci		.of_match_table = mse102x_match_table,
76462306a36Sopenharmony_ci		.pm = &mse102x_pm_ops,
76562306a36Sopenharmony_ci	},
76662306a36Sopenharmony_ci	.probe = mse102x_probe_spi,
76762306a36Sopenharmony_ci	.remove = mse102x_remove_spi,
76862306a36Sopenharmony_ci	.id_table = mse102x_ids,
76962306a36Sopenharmony_ci};
77062306a36Sopenharmony_cimodule_spi_driver(mse102x_driver);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ciMODULE_DESCRIPTION("MSE102x Network driver");
77362306a36Sopenharmony_ciMODULE_AUTHOR("Stefan Wahren <stefan.wahren@chargebyte.com>");
77462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
77562306a36Sopenharmony_ciMODULE_ALIAS("spi:" DRV_NAME);
776