12f207cbfSStefan Wahren // SPDX-License-Identifier: GPL-2.0-only
22f207cbfSStefan Wahren /* Copyright (C) 2021 in-tech smart charging GmbH
32f207cbfSStefan Wahren  *
42f207cbfSStefan Wahren  * driver is based on micrel/ks8851_spi.c
52f207cbfSStefan Wahren  */
62f207cbfSStefan Wahren 
72f207cbfSStefan Wahren #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
82f207cbfSStefan Wahren 
92f207cbfSStefan Wahren #include <linux/interrupt.h>
102f207cbfSStefan Wahren #include <linux/module.h>
112f207cbfSStefan Wahren #include <linux/kernel.h>
122f207cbfSStefan Wahren #include <linux/netdevice.h>
132f207cbfSStefan Wahren #include <linux/etherdevice.h>
142f207cbfSStefan Wahren #include <linux/ethtool.h>
152f207cbfSStefan Wahren #include <linux/cache.h>
162f207cbfSStefan Wahren #include <linux/debugfs.h>
172f207cbfSStefan Wahren #include <linux/seq_file.h>
182f207cbfSStefan Wahren 
192f207cbfSStefan Wahren #include <linux/spi/spi.h>
202f207cbfSStefan Wahren #include <linux/of_net.h>
212f207cbfSStefan Wahren 
222f207cbfSStefan Wahren #define MSG_DEFAULT	(NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
232f207cbfSStefan Wahren 			 NETIF_MSG_TIMER)
242f207cbfSStefan Wahren 
252f207cbfSStefan Wahren #define DRV_NAME	"mse102x"
262f207cbfSStefan Wahren 
272f207cbfSStefan Wahren #define DET_CMD		0x0001
282f207cbfSStefan Wahren #define DET_SOF		0x0002
292f207cbfSStefan Wahren #define DET_DFT		0x55AA
302f207cbfSStefan Wahren 
312f207cbfSStefan Wahren #define CMD_SHIFT	12
322f207cbfSStefan Wahren #define CMD_RTS		(0x1 << CMD_SHIFT)
332f207cbfSStefan Wahren #define CMD_CTR		(0x2 << CMD_SHIFT)
342f207cbfSStefan Wahren 
352f207cbfSStefan Wahren #define CMD_MASK	GENMASK(15, CMD_SHIFT)
362f207cbfSStefan Wahren #define LEN_MASK	GENMASK(CMD_SHIFT - 1, 0)
372f207cbfSStefan Wahren 
382f207cbfSStefan Wahren #define DET_CMD_LEN	4
392f207cbfSStefan Wahren #define DET_SOF_LEN	2
402f207cbfSStefan Wahren #define DET_DFT_LEN	2
412f207cbfSStefan Wahren 
422f207cbfSStefan Wahren #define MIN_FREQ_HZ	6000000
432f207cbfSStefan Wahren #define MAX_FREQ_HZ	7142857
442f207cbfSStefan Wahren 
452f207cbfSStefan Wahren struct mse102x_stats {
462f207cbfSStefan Wahren 	u64 xfer_err;
472f207cbfSStefan Wahren 	u64 invalid_cmd;
482f207cbfSStefan Wahren 	u64 invalid_ctr;
492f207cbfSStefan Wahren 	u64 invalid_dft;
502f207cbfSStefan Wahren 	u64 invalid_len;
512f207cbfSStefan Wahren 	u64 invalid_rts;
522f207cbfSStefan Wahren 	u64 invalid_sof;
532f207cbfSStefan Wahren 	u64 tx_timeout;
542f207cbfSStefan Wahren };
552f207cbfSStefan Wahren 
562f207cbfSStefan Wahren static const char mse102x_gstrings_stats[][ETH_GSTRING_LEN] = {
572f207cbfSStefan Wahren 	"SPI transfer errors",
582f207cbfSStefan Wahren 	"Invalid command",
592f207cbfSStefan Wahren 	"Invalid CTR",
602f207cbfSStefan Wahren 	"Invalid DFT",
612f207cbfSStefan Wahren 	"Invalid frame length",
622f207cbfSStefan Wahren 	"Invalid RTS",
632f207cbfSStefan Wahren 	"Invalid SOF",
642f207cbfSStefan Wahren 	"TX timeout",
652f207cbfSStefan Wahren };
662f207cbfSStefan Wahren 
672f207cbfSStefan Wahren struct mse102x_net {
682f207cbfSStefan Wahren 	struct net_device	*ndev;
692f207cbfSStefan Wahren 
702f207cbfSStefan Wahren 	u8			rxd[8];
712f207cbfSStefan Wahren 	u8			txd[8];
722f207cbfSStefan Wahren 
732f207cbfSStefan Wahren 	u32			msg_enable ____cacheline_aligned;
742f207cbfSStefan Wahren 
752f207cbfSStefan Wahren 	struct sk_buff_head	txq;
762f207cbfSStefan Wahren 	struct mse102x_stats	stats;
772f207cbfSStefan Wahren };
782f207cbfSStefan Wahren 
792f207cbfSStefan Wahren struct mse102x_net_spi {
802f207cbfSStefan Wahren 	struct mse102x_net	mse102x;
812f207cbfSStefan Wahren 	struct mutex		lock;		/* Protect SPI frame transfer */
822f207cbfSStefan Wahren 	struct work_struct	tx_work;
832f207cbfSStefan Wahren 	struct spi_device	*spidev;
842f207cbfSStefan Wahren 	struct spi_message	spi_msg;
852f207cbfSStefan Wahren 	struct spi_transfer	spi_xfer;
862f207cbfSStefan Wahren 
872f207cbfSStefan Wahren #ifdef CONFIG_DEBUG_FS
882f207cbfSStefan Wahren 	struct dentry		*device_root;
892f207cbfSStefan Wahren #endif
902f207cbfSStefan Wahren };
912f207cbfSStefan Wahren 
922f207cbfSStefan Wahren #define to_mse102x_spi(mse) container_of((mse), struct mse102x_net_spi, mse102x)
932f207cbfSStefan Wahren 
942f207cbfSStefan Wahren #ifdef CONFIG_DEBUG_FS
952f207cbfSStefan Wahren 
mse102x_info_show(struct seq_file * s,void * what)962f207cbfSStefan Wahren static int mse102x_info_show(struct seq_file *s, void *what)
972f207cbfSStefan Wahren {
982f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = s->private;
992f207cbfSStefan Wahren 
1002f207cbfSStefan Wahren 	seq_printf(s, "TX ring size        : %u\n",
1012f207cbfSStefan Wahren 		   skb_queue_len(&mses->mse102x.txq));
1022f207cbfSStefan Wahren 
1032f207cbfSStefan Wahren 	seq_printf(s, "IRQ                 : %d\n",
1042f207cbfSStefan Wahren 		   mses->spidev->irq);
1052f207cbfSStefan Wahren 
1062f207cbfSStefan Wahren 	seq_printf(s, "SPI effective speed : %lu\n",
1072f207cbfSStefan Wahren 		   (unsigned long)mses->spi_xfer.effective_speed_hz);
1082f207cbfSStefan Wahren 	seq_printf(s, "SPI mode            : %x\n",
1092f207cbfSStefan Wahren 		   mses->spidev->mode);
1102f207cbfSStefan Wahren 
1112f207cbfSStefan Wahren 	return 0;
1122f207cbfSStefan Wahren }
1132f207cbfSStefan Wahren DEFINE_SHOW_ATTRIBUTE(mse102x_info);
1142f207cbfSStefan Wahren 
mse102x_init_device_debugfs(struct mse102x_net_spi * mses)1152f207cbfSStefan Wahren static void mse102x_init_device_debugfs(struct mse102x_net_spi *mses)
1162f207cbfSStefan Wahren {
1172f207cbfSStefan Wahren 	mses->device_root = debugfs_create_dir(dev_name(&mses->mse102x.ndev->dev),
1182f207cbfSStefan Wahren 					       NULL);
1192f207cbfSStefan Wahren 
1202f207cbfSStefan Wahren 	debugfs_create_file("info", S_IFREG | 0444, mses->device_root, mses,
1212f207cbfSStefan Wahren 			    &mse102x_info_fops);
1222f207cbfSStefan Wahren }
1232f207cbfSStefan Wahren 
mse102x_remove_device_debugfs(struct mse102x_net_spi * mses)1242f207cbfSStefan Wahren static void mse102x_remove_device_debugfs(struct mse102x_net_spi *mses)
1252f207cbfSStefan Wahren {
1262f207cbfSStefan Wahren 	debugfs_remove_recursive(mses->device_root);
1272f207cbfSStefan Wahren }
1282f207cbfSStefan Wahren 
1292f207cbfSStefan Wahren #else /* CONFIG_DEBUG_FS */
1302f207cbfSStefan Wahren 
mse102x_init_device_debugfs(struct mse102x_net_spi * mses)1312f207cbfSStefan Wahren static void mse102x_init_device_debugfs(struct mse102x_net_spi *mses)
1322f207cbfSStefan Wahren {
1332f207cbfSStefan Wahren }
1342f207cbfSStefan Wahren 
mse102x_remove_device_debugfs(struct mse102x_net_spi * mses)1352f207cbfSStefan Wahren static void mse102x_remove_device_debugfs(struct mse102x_net_spi *mses)
1362f207cbfSStefan Wahren {
1372f207cbfSStefan Wahren }
1382f207cbfSStefan Wahren 
1392f207cbfSStefan Wahren #endif
1402f207cbfSStefan Wahren 
1412f207cbfSStefan Wahren /* SPI register read/write calls.
1422f207cbfSStefan Wahren  *
1432f207cbfSStefan Wahren  * All these calls issue SPI transactions to access the chip's registers. They
1442f207cbfSStefan Wahren  * all require that the necessary lock is held to prevent accesses when the
1452f207cbfSStefan Wahren  * chip is busy transferring packet data.
1462f207cbfSStefan Wahren  */
1472f207cbfSStefan Wahren 
mse102x_tx_cmd_spi(struct mse102x_net * mse,u16 cmd)1482f207cbfSStefan Wahren static void mse102x_tx_cmd_spi(struct mse102x_net *mse, u16 cmd)
1492f207cbfSStefan Wahren {
1502f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
1512f207cbfSStefan Wahren 	struct spi_transfer *xfer = &mses->spi_xfer;
1522f207cbfSStefan Wahren 	struct spi_message *msg = &mses->spi_msg;
1532f207cbfSStefan Wahren 	__be16 txb[2];
1542f207cbfSStefan Wahren 	int ret;
1552f207cbfSStefan Wahren 
1562f207cbfSStefan Wahren 	txb[0] = cpu_to_be16(DET_CMD);
1572f207cbfSStefan Wahren 	txb[1] = cpu_to_be16(cmd);
1582f207cbfSStefan Wahren 
1592f207cbfSStefan Wahren 	xfer->tx_buf = txb;
1602f207cbfSStefan Wahren 	xfer->rx_buf = NULL;
1612f207cbfSStefan Wahren 	xfer->len = DET_CMD_LEN;
1622f207cbfSStefan Wahren 
1632f207cbfSStefan Wahren 	ret = spi_sync(mses->spidev, msg);
1642f207cbfSStefan Wahren 	if (ret < 0) {
1652f207cbfSStefan Wahren 		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
1662f207cbfSStefan Wahren 			   __func__, ret);
1672f207cbfSStefan Wahren 		mse->stats.xfer_err++;
1682f207cbfSStefan Wahren 	}
1692f207cbfSStefan Wahren }
1702f207cbfSStefan Wahren 
mse102x_rx_cmd_spi(struct mse102x_net * mse,u8 * rxb)1712f207cbfSStefan Wahren static int mse102x_rx_cmd_spi(struct mse102x_net *mse, u8 *rxb)
1722f207cbfSStefan Wahren {
1732f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
1742f207cbfSStefan Wahren 	struct spi_transfer *xfer = &mses->spi_xfer;
1752f207cbfSStefan Wahren 	struct spi_message *msg = &mses->spi_msg;
1762f207cbfSStefan Wahren 	__be16 *txb = (__be16 *)mse->txd;
1772f207cbfSStefan Wahren 	__be16 *cmd = (__be16 *)mse->rxd;
1782f207cbfSStefan Wahren 	u8 *trx = mse->rxd;
1792f207cbfSStefan Wahren 	int ret;
1802f207cbfSStefan Wahren 
1812f207cbfSStefan Wahren 	txb[0] = 0;
1822f207cbfSStefan Wahren 	txb[1] = 0;
1832f207cbfSStefan Wahren 
1842f207cbfSStefan Wahren 	xfer->tx_buf = txb;
1852f207cbfSStefan Wahren 	xfer->rx_buf = trx;
1862f207cbfSStefan Wahren 	xfer->len = DET_CMD_LEN;
1872f207cbfSStefan Wahren 
1882f207cbfSStefan Wahren 	ret = spi_sync(mses->spidev, msg);
1892f207cbfSStefan Wahren 	if (ret < 0) {
1902f207cbfSStefan Wahren 		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
1912f207cbfSStefan Wahren 			   __func__, ret);
1922f207cbfSStefan Wahren 		mse->stats.xfer_err++;
1932f207cbfSStefan Wahren 	} else if (*cmd != cpu_to_be16(DET_CMD)) {
1942f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
1952f207cbfSStefan Wahren 				    __func__, *cmd);
1962f207cbfSStefan Wahren 		mse->stats.invalid_cmd++;
1972f207cbfSStefan Wahren 		ret = -EIO;
1982f207cbfSStefan Wahren 	} else {
1992f207cbfSStefan Wahren 		memcpy(rxb, trx + 2, 2);
2002f207cbfSStefan Wahren 	}
2012f207cbfSStefan Wahren 
2022f207cbfSStefan Wahren 	return ret;
2032f207cbfSStefan Wahren }
2042f207cbfSStefan Wahren 
mse102x_push_header(struct sk_buff * skb)2052f207cbfSStefan Wahren static inline void mse102x_push_header(struct sk_buff *skb)
2062f207cbfSStefan Wahren {
2072f207cbfSStefan Wahren 	__be16 *header = skb_push(skb, DET_SOF_LEN);
2082f207cbfSStefan Wahren 
2092f207cbfSStefan Wahren 	*header = cpu_to_be16(DET_SOF);
2102f207cbfSStefan Wahren }
2112f207cbfSStefan Wahren 
mse102x_put_footer(struct sk_buff * skb)2122f207cbfSStefan Wahren static inline void mse102x_put_footer(struct sk_buff *skb)
2132f207cbfSStefan Wahren {
2142f207cbfSStefan Wahren 	__be16 *footer = skb_put(skb, DET_DFT_LEN);
2152f207cbfSStefan Wahren 
2162f207cbfSStefan Wahren 	*footer = cpu_to_be16(DET_DFT);
2172f207cbfSStefan Wahren }
2182f207cbfSStefan Wahren 
mse102x_tx_frame_spi(struct mse102x_net * mse,struct sk_buff * txp,unsigned int pad)2192f207cbfSStefan Wahren static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp,
2202f207cbfSStefan Wahren 				unsigned int pad)
2212f207cbfSStefan Wahren {
2222f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
2232f207cbfSStefan Wahren 	struct spi_transfer *xfer = &mses->spi_xfer;
2242f207cbfSStefan Wahren 	struct spi_message *msg = &mses->spi_msg;
2252f207cbfSStefan Wahren 	struct sk_buff *tskb;
2262f207cbfSStefan Wahren 	int ret;
2272f207cbfSStefan Wahren 
2282f207cbfSStefan Wahren 	netif_dbg(mse, tx_queued, mse->ndev, "%s: skb %p, %d@%p\n",
2292f207cbfSStefan Wahren 		  __func__, txp, txp->len, txp->data);
2302f207cbfSStefan Wahren 
2312f207cbfSStefan Wahren 	if ((skb_headroom(txp) < DET_SOF_LEN) ||
2322f207cbfSStefan Wahren 	    (skb_tailroom(txp) < DET_DFT_LEN + pad)) {
2332f207cbfSStefan Wahren 		tskb = skb_copy_expand(txp, DET_SOF_LEN, DET_DFT_LEN + pad,
2342f207cbfSStefan Wahren 				       GFP_KERNEL);
2352f207cbfSStefan Wahren 		if (!tskb)
2362f207cbfSStefan Wahren 			return -ENOMEM;
2372f207cbfSStefan Wahren 
2382f207cbfSStefan Wahren 		dev_kfree_skb(txp);
2392f207cbfSStefan Wahren 		txp = tskb;
2402f207cbfSStefan Wahren 	}
2412f207cbfSStefan Wahren 
2422f207cbfSStefan Wahren 	mse102x_push_header(txp);
2432f207cbfSStefan Wahren 
2442f207cbfSStefan Wahren 	if (pad)
2452f207cbfSStefan Wahren 		skb_put_zero(txp, pad);
2462f207cbfSStefan Wahren 
2472f207cbfSStefan Wahren 	mse102x_put_footer(txp);
2482f207cbfSStefan Wahren 
2492f207cbfSStefan Wahren 	xfer->tx_buf = txp->data;
2502f207cbfSStefan Wahren 	xfer->rx_buf = NULL;
2512f207cbfSStefan Wahren 	xfer->len = txp->len;
2522f207cbfSStefan Wahren 
2532f207cbfSStefan Wahren 	ret = spi_sync(mses->spidev, msg);
2542f207cbfSStefan Wahren 	if (ret < 0) {
2552f207cbfSStefan Wahren 		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
2562f207cbfSStefan Wahren 			   __func__, ret);
2572f207cbfSStefan Wahren 		mse->stats.xfer_err++;
2582f207cbfSStefan Wahren 	}
2592f207cbfSStefan Wahren 
2602f207cbfSStefan Wahren 	return ret;
2612f207cbfSStefan Wahren }
2622f207cbfSStefan Wahren 
mse102x_rx_frame_spi(struct mse102x_net * mse,u8 * buff,unsigned int frame_len)2632f207cbfSStefan Wahren static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff,
2642f207cbfSStefan Wahren 				unsigned int frame_len)
2652f207cbfSStefan Wahren {
2662f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
2672f207cbfSStefan Wahren 	struct spi_transfer *xfer = &mses->spi_xfer;
2682f207cbfSStefan Wahren 	struct spi_message *msg = &mses->spi_msg;
2692f207cbfSStefan Wahren 	__be16 *sof = (__be16 *)buff;
2702f207cbfSStefan Wahren 	__be16 *dft = (__be16 *)(buff + DET_SOF_LEN + frame_len);
2712f207cbfSStefan Wahren 	int ret;
2722f207cbfSStefan Wahren 
2732f207cbfSStefan Wahren 	xfer->rx_buf = buff;
2742f207cbfSStefan Wahren 	xfer->tx_buf = NULL;
2752f207cbfSStefan Wahren 	xfer->len = DET_SOF_LEN + frame_len + DET_DFT_LEN;
2762f207cbfSStefan Wahren 
2772f207cbfSStefan Wahren 	ret = spi_sync(mses->spidev, msg);
2782f207cbfSStefan Wahren 	if (ret < 0) {
2792f207cbfSStefan Wahren 		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
2802f207cbfSStefan Wahren 			   __func__, ret);
2812f207cbfSStefan Wahren 		mse->stats.xfer_err++;
2822f207cbfSStefan Wahren 	} else if (*sof != cpu_to_be16(DET_SOF)) {
2832f207cbfSStefan Wahren 		netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n",
2842f207cbfSStefan Wahren 			   __func__, *sof);
2852f207cbfSStefan Wahren 		mse->stats.invalid_sof++;
2862f207cbfSStefan Wahren 		ret = -EIO;
2872f207cbfSStefan Wahren 	} else if (*dft != cpu_to_be16(DET_DFT)) {
2882f207cbfSStefan Wahren 		netdev_dbg(mse->ndev, "%s: SPI frame tail is invalid (0x%04x)\n",
2892f207cbfSStefan Wahren 			   __func__, *dft);
2902f207cbfSStefan Wahren 		mse->stats.invalid_dft++;
2912f207cbfSStefan Wahren 		ret = -EIO;
2922f207cbfSStefan Wahren 	}
2932f207cbfSStefan Wahren 
2942f207cbfSStefan Wahren 	return ret;
2952f207cbfSStefan Wahren }
2962f207cbfSStefan Wahren 
mse102x_dump_packet(const char * msg,int len,const char * data)2972f207cbfSStefan Wahren static void mse102x_dump_packet(const char *msg, int len, const char *data)
2982f207cbfSStefan Wahren {
2992f207cbfSStefan Wahren 	printk(KERN_DEBUG ": %s - packet len:%d\n", msg, len);
3002f207cbfSStefan Wahren 	print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1,
3012f207cbfSStefan Wahren 		       data, len, true);
3022f207cbfSStefan Wahren }
3032f207cbfSStefan Wahren 
mse102x_rx_pkt_spi(struct mse102x_net * mse)3042f207cbfSStefan Wahren static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
3052f207cbfSStefan Wahren {
3062f207cbfSStefan Wahren 	struct sk_buff *skb;
3072f207cbfSStefan Wahren 	unsigned int rxalign;
3082f207cbfSStefan Wahren 	unsigned int rxlen;
3092f207cbfSStefan Wahren 	__be16 rx = 0;
3102f207cbfSStefan Wahren 	u16 cmd_resp;
3112f207cbfSStefan Wahren 	u8 *rxpkt;
3122f207cbfSStefan Wahren 	int ret;
3132f207cbfSStefan Wahren 
3142f207cbfSStefan Wahren 	mse102x_tx_cmd_spi(mse, CMD_CTR);
3152f207cbfSStefan Wahren 	ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
3162f207cbfSStefan Wahren 	cmd_resp = be16_to_cpu(rx);
3172f207cbfSStefan Wahren 
3182f207cbfSStefan Wahren 	if (ret || ((cmd_resp & CMD_MASK) != CMD_RTS)) {
3192f207cbfSStefan Wahren 		usleep_range(50, 100);
3202f207cbfSStefan Wahren 
3212f207cbfSStefan Wahren 		mse102x_tx_cmd_spi(mse, CMD_CTR);
3222f207cbfSStefan Wahren 		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
3232f207cbfSStefan Wahren 		if (ret)
3242f207cbfSStefan Wahren 			return;
3252f207cbfSStefan Wahren 
3262f207cbfSStefan Wahren 		cmd_resp = be16_to_cpu(rx);
3272f207cbfSStefan Wahren 		if ((cmd_resp & CMD_MASK) != CMD_RTS) {
3282f207cbfSStefan Wahren 			net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
3292f207cbfSStefan Wahren 					    __func__, cmd_resp);
3302f207cbfSStefan Wahren 			mse->stats.invalid_rts++;
3312f207cbfSStefan Wahren 			return;
3322f207cbfSStefan Wahren 		}
3332f207cbfSStefan Wahren 
3342f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: Unexpected response to first CMD\n",
3352f207cbfSStefan Wahren 				    __func__);
3362f207cbfSStefan Wahren 	}
3372f207cbfSStefan Wahren 
3382f207cbfSStefan Wahren 	rxlen = cmd_resp & LEN_MASK;
3392f207cbfSStefan Wahren 	if (!rxlen) {
3402f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: No frame length defined\n", __func__);
3412f207cbfSStefan Wahren 		mse->stats.invalid_len++;
3422f207cbfSStefan Wahren 		return;
3432f207cbfSStefan Wahren 	}
3442f207cbfSStefan Wahren 
3452f207cbfSStefan Wahren 	rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4);
3462f207cbfSStefan Wahren 	skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign);
3472f207cbfSStefan Wahren 	if (!skb)
3482f207cbfSStefan Wahren 		return;
3492f207cbfSStefan Wahren 
3502f207cbfSStefan Wahren 	/* 2 bytes Start of frame (before ethernet header)
3512f207cbfSStefan Wahren 	 * 2 bytes Data frame tail (after ethernet frame)
3522f207cbfSStefan Wahren 	 * They are copied, but ignored.
3532f207cbfSStefan Wahren 	 */
3542f207cbfSStefan Wahren 	rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN;
3552f207cbfSStefan Wahren 	if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) {
3562f207cbfSStefan Wahren 		mse->ndev->stats.rx_errors++;
3572f207cbfSStefan Wahren 		dev_kfree_skb(skb);
3582f207cbfSStefan Wahren 		return;
3592f207cbfSStefan Wahren 	}
3602f207cbfSStefan Wahren 
3612f207cbfSStefan Wahren 	if (netif_msg_pktdata(mse))
3622f207cbfSStefan Wahren 		mse102x_dump_packet(__func__, skb->len, skb->data);
3632f207cbfSStefan Wahren 
3642f207cbfSStefan Wahren 	skb->protocol = eth_type_trans(skb, mse->ndev);
36590f77c1cSSebastian Andrzej Siewior 	netif_rx(skb);
3662f207cbfSStefan Wahren 
3672f207cbfSStefan Wahren 	mse->ndev->stats.rx_packets++;
3682f207cbfSStefan Wahren 	mse->ndev->stats.rx_bytes += rxlen;
3692f207cbfSStefan Wahren }
3702f207cbfSStefan Wahren 
mse102x_tx_pkt_spi(struct mse102x_net * mse,struct sk_buff * txb,unsigned long work_timeout)3712f207cbfSStefan Wahren static int mse102x_tx_pkt_spi(struct mse102x_net *mse, struct sk_buff *txb,
3722f207cbfSStefan Wahren 			      unsigned long work_timeout)
3732f207cbfSStefan Wahren {
3742f207cbfSStefan Wahren 	unsigned int pad = 0;
3752f207cbfSStefan Wahren 	__be16 rx = 0;
3762f207cbfSStefan Wahren 	u16 cmd_resp;
3772f207cbfSStefan Wahren 	int ret;
3782f207cbfSStefan Wahren 	bool first = true;
3792f207cbfSStefan Wahren 
3802f207cbfSStefan Wahren 	if (txb->len < 60)
3812f207cbfSStefan Wahren 		pad = 60 - txb->len;
3822f207cbfSStefan Wahren 
3832f207cbfSStefan Wahren 	while (1) {
3842f207cbfSStefan Wahren 		mse102x_tx_cmd_spi(mse, CMD_RTS | (txb->len + pad));
3852f207cbfSStefan Wahren 		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
3862f207cbfSStefan Wahren 		cmd_resp = be16_to_cpu(rx);
3872f207cbfSStefan Wahren 
3882f207cbfSStefan Wahren 		if (!ret) {
3892f207cbfSStefan Wahren 			/* ready to send frame ? */
3902f207cbfSStefan Wahren 			if (cmd_resp == CMD_CTR)
3912f207cbfSStefan Wahren 				break;
3922f207cbfSStefan Wahren 
3932f207cbfSStefan Wahren 			net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
3942f207cbfSStefan Wahren 					    __func__, cmd_resp);
3952f207cbfSStefan Wahren 			mse->stats.invalid_ctr++;
3962f207cbfSStefan Wahren 		}
3972f207cbfSStefan Wahren 
3982f207cbfSStefan Wahren 		/* It's not predictable how long / many retries it takes to
3992f207cbfSStefan Wahren 		 * send at least one packet, so TX timeouts are possible.
4002f207cbfSStefan Wahren 		 * That's the reason why the netdev watchdog is not used here.
4012f207cbfSStefan Wahren 		 */
4022f207cbfSStefan Wahren 		if (time_after(jiffies, work_timeout))
4032f207cbfSStefan Wahren 			return -ETIMEDOUT;
4042f207cbfSStefan Wahren 
4052f207cbfSStefan Wahren 		if (first) {
4062f207cbfSStefan Wahren 			/* throttle at first issue */
4072f207cbfSStefan Wahren 			netif_stop_queue(mse->ndev);
4082f207cbfSStefan Wahren 			/* fast retry */
4092f207cbfSStefan Wahren 			usleep_range(50, 100);
4102f207cbfSStefan Wahren 			first = false;
4112f207cbfSStefan Wahren 		} else {
4122f207cbfSStefan Wahren 			msleep(20);
4132f207cbfSStefan Wahren 		}
414431b9b4dSYang Li 	}
4152f207cbfSStefan Wahren 
4162f207cbfSStefan Wahren 	ret = mse102x_tx_frame_spi(mse, txb, pad);
4172f207cbfSStefan Wahren 	if (ret)
4182f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: Failed to send (%d), drop frame\n",
4192f207cbfSStefan Wahren 				    __func__, ret);
4202f207cbfSStefan Wahren 
4212f207cbfSStefan Wahren 	return ret;
4222f207cbfSStefan Wahren }
4232f207cbfSStefan Wahren 
4242f207cbfSStefan Wahren #define TX_QUEUE_MAX 10
4252f207cbfSStefan Wahren 
mse102x_tx_work(struct work_struct * work)4262f207cbfSStefan Wahren static void mse102x_tx_work(struct work_struct *work)
4272f207cbfSStefan Wahren {
4282f207cbfSStefan Wahren 	/* Make sure timeout is sufficient to transfer TX_QUEUE_MAX frames */
4292f207cbfSStefan Wahren 	unsigned long work_timeout = jiffies + msecs_to_jiffies(1000);
4302f207cbfSStefan Wahren 	struct mse102x_net_spi *mses;
4312f207cbfSStefan Wahren 	struct mse102x_net *mse;
4322f207cbfSStefan Wahren 	struct sk_buff *txb;
4332f207cbfSStefan Wahren 	int ret = 0;
4342f207cbfSStefan Wahren 
4352f207cbfSStefan Wahren 	mses = container_of(work, struct mse102x_net_spi, tx_work);
4362f207cbfSStefan Wahren 	mse = &mses->mse102x;
4372f207cbfSStefan Wahren 
4382f207cbfSStefan Wahren 	while ((txb = skb_dequeue(&mse->txq))) {
4392f207cbfSStefan Wahren 		mutex_lock(&mses->lock);
4402f207cbfSStefan Wahren 		ret = mse102x_tx_pkt_spi(mse, txb, work_timeout);
4412f207cbfSStefan Wahren 		mutex_unlock(&mses->lock);
4422f207cbfSStefan Wahren 		if (ret) {
4432f207cbfSStefan Wahren 			mse->ndev->stats.tx_dropped++;
4442f207cbfSStefan Wahren 		} else {
4452f207cbfSStefan Wahren 			mse->ndev->stats.tx_bytes += txb->len;
4462f207cbfSStefan Wahren 			mse->ndev->stats.tx_packets++;
4472f207cbfSStefan Wahren 		}
4482f207cbfSStefan Wahren 
4492f207cbfSStefan Wahren 		dev_kfree_skb(txb);
4502f207cbfSStefan Wahren 	}
4512f207cbfSStefan Wahren 
4522f207cbfSStefan Wahren 	if (ret == -ETIMEDOUT) {
4532f207cbfSStefan Wahren 		if (netif_msg_timer(mse))
4542f207cbfSStefan Wahren 			netdev_err(mse->ndev, "tx work timeout\n");
4552f207cbfSStefan Wahren 
4562f207cbfSStefan Wahren 		mse->stats.tx_timeout++;
4572f207cbfSStefan Wahren 	}
4582f207cbfSStefan Wahren 
4592f207cbfSStefan Wahren 	netif_wake_queue(mse->ndev);
4602f207cbfSStefan Wahren }
4612f207cbfSStefan Wahren 
mse102x_start_xmit_spi(struct sk_buff * skb,struct net_device * ndev)4622f207cbfSStefan Wahren static netdev_tx_t mse102x_start_xmit_spi(struct sk_buff *skb,
4632f207cbfSStefan Wahren 					  struct net_device *ndev)
4642f207cbfSStefan Wahren {
4652f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
4662f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
4672f207cbfSStefan Wahren 
4682f207cbfSStefan Wahren 	netif_dbg(mse, tx_queued, ndev,
4692f207cbfSStefan Wahren 		  "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data);
4702f207cbfSStefan Wahren 
4712f207cbfSStefan Wahren 	skb_queue_tail(&mse->txq, skb);
4722f207cbfSStefan Wahren 
4732f207cbfSStefan Wahren 	if (skb_queue_len(&mse->txq) >= TX_QUEUE_MAX)
4742f207cbfSStefan Wahren 		netif_stop_queue(ndev);
4752f207cbfSStefan Wahren 
4762f207cbfSStefan Wahren 	schedule_work(&mses->tx_work);
4772f207cbfSStefan Wahren 
4782f207cbfSStefan Wahren 	return NETDEV_TX_OK;
4792f207cbfSStefan Wahren }
4802f207cbfSStefan Wahren 
mse102x_init_mac(struct mse102x_net * mse,struct device_node * np)4812f207cbfSStefan Wahren static void mse102x_init_mac(struct mse102x_net *mse, struct device_node *np)
4822f207cbfSStefan Wahren {
4832f207cbfSStefan Wahren 	struct net_device *ndev = mse->ndev;
4842f207cbfSStefan Wahren 	int ret = of_get_ethdev_address(np, ndev);
4852f207cbfSStefan Wahren 
4862f207cbfSStefan Wahren 	if (ret) {
4872f207cbfSStefan Wahren 		eth_hw_addr_random(ndev);
4882f207cbfSStefan Wahren 		netdev_err(ndev, "Using random MAC address: %pM\n",
4892f207cbfSStefan Wahren 			   ndev->dev_addr);
4902f207cbfSStefan Wahren 	}
4912f207cbfSStefan Wahren }
4922f207cbfSStefan Wahren 
4932f207cbfSStefan Wahren /* Assumption: this is called for every incoming packet */
mse102x_irq(int irq,void * _mse)4942f207cbfSStefan Wahren static irqreturn_t mse102x_irq(int irq, void *_mse)
4952f207cbfSStefan Wahren {
4962f207cbfSStefan Wahren 	struct mse102x_net *mse = _mse;
4972f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
4982f207cbfSStefan Wahren 
4992f207cbfSStefan Wahren 	mutex_lock(&mses->lock);
5002f207cbfSStefan Wahren 	mse102x_rx_pkt_spi(mse);
5012f207cbfSStefan Wahren 	mutex_unlock(&mses->lock);
5022f207cbfSStefan Wahren 
5032f207cbfSStefan Wahren 	return IRQ_HANDLED;
5042f207cbfSStefan Wahren }
5052f207cbfSStefan Wahren 
mse102x_net_open(struct net_device * ndev)5062f207cbfSStefan Wahren static int mse102x_net_open(struct net_device *ndev)
5072f207cbfSStefan Wahren {
5082f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5092f207cbfSStefan Wahren 	int ret;
5102f207cbfSStefan Wahren 
5112f207cbfSStefan Wahren 	ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT,
5122f207cbfSStefan Wahren 				   ndev->name, mse);
5132f207cbfSStefan Wahren 	if (ret < 0) {
5142f207cbfSStefan Wahren 		netdev_err(ndev, "Failed to get irq: %d\n", ret);
5152f207cbfSStefan Wahren 		return ret;
5162f207cbfSStefan Wahren 	}
5172f207cbfSStefan Wahren 
5182f207cbfSStefan Wahren 	netif_dbg(mse, ifup, ndev, "opening\n");
5192f207cbfSStefan Wahren 
5202f207cbfSStefan Wahren 	netif_start_queue(ndev);
5212f207cbfSStefan Wahren 
5222f207cbfSStefan Wahren 	netif_carrier_on(ndev);
5232f207cbfSStefan Wahren 
5242f207cbfSStefan Wahren 	netif_dbg(mse, ifup, ndev, "network device up\n");
5252f207cbfSStefan Wahren 
5262f207cbfSStefan Wahren 	return 0;
5272f207cbfSStefan Wahren }
5282f207cbfSStefan Wahren 
mse102x_net_stop(struct net_device * ndev)5292f207cbfSStefan Wahren static int mse102x_net_stop(struct net_device *ndev)
5302f207cbfSStefan Wahren {
5312f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5322f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
5332f207cbfSStefan Wahren 
5342f207cbfSStefan Wahren 	netif_info(mse, ifdown, ndev, "shutting down\n");
5352f207cbfSStefan Wahren 
5362f207cbfSStefan Wahren 	netif_carrier_off(mse->ndev);
5372f207cbfSStefan Wahren 
5382f207cbfSStefan Wahren 	/* stop any outstanding work */
5392f207cbfSStefan Wahren 	flush_work(&mses->tx_work);
5402f207cbfSStefan Wahren 
5412f207cbfSStefan Wahren 	netif_stop_queue(ndev);
5422f207cbfSStefan Wahren 
5432f207cbfSStefan Wahren 	skb_queue_purge(&mse->txq);
5442f207cbfSStefan Wahren 
5452f207cbfSStefan Wahren 	free_irq(ndev->irq, mse);
5462f207cbfSStefan Wahren 
5472f207cbfSStefan Wahren 	return 0;
5482f207cbfSStefan Wahren }
5492f207cbfSStefan Wahren 
5502f207cbfSStefan Wahren static const struct net_device_ops mse102x_netdev_ops = {
5512f207cbfSStefan Wahren 	.ndo_open		= mse102x_net_open,
5522f207cbfSStefan Wahren 	.ndo_stop		= mse102x_net_stop,
5532f207cbfSStefan Wahren 	.ndo_start_xmit		= mse102x_start_xmit_spi,
5542f207cbfSStefan Wahren 	.ndo_set_mac_address	= eth_mac_addr,
5552f207cbfSStefan Wahren 	.ndo_validate_addr	= eth_validate_addr,
5562f207cbfSStefan Wahren };
5572f207cbfSStefan Wahren 
5582f207cbfSStefan Wahren /* ethtool support */
5592f207cbfSStefan Wahren 
mse102x_get_drvinfo(struct net_device * ndev,struct ethtool_drvinfo * di)5602f207cbfSStefan Wahren static void mse102x_get_drvinfo(struct net_device *ndev,
5612f207cbfSStefan Wahren 				struct ethtool_drvinfo *di)
5622f207cbfSStefan Wahren {
5632f207cbfSStefan Wahren 	strscpy(di->driver, DRV_NAME, sizeof(di->driver));
5642f207cbfSStefan Wahren 	strscpy(di->bus_info, dev_name(ndev->dev.parent), sizeof(di->bus_info));
5652f207cbfSStefan Wahren }
5662f207cbfSStefan Wahren 
mse102x_get_msglevel(struct net_device * ndev)5672f207cbfSStefan Wahren static u32 mse102x_get_msglevel(struct net_device *ndev)
5682f207cbfSStefan Wahren {
5692f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5702f207cbfSStefan Wahren 
5712f207cbfSStefan Wahren 	return mse->msg_enable;
5722f207cbfSStefan Wahren }
5732f207cbfSStefan Wahren 
mse102x_set_msglevel(struct net_device * ndev,u32 to)5742f207cbfSStefan Wahren static void mse102x_set_msglevel(struct net_device *ndev, u32 to)
5752f207cbfSStefan Wahren {
5762f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5772f207cbfSStefan Wahren 
5782f207cbfSStefan Wahren 	mse->msg_enable = to;
5792f207cbfSStefan Wahren }
5802f207cbfSStefan Wahren 
mse102x_get_ethtool_stats(struct net_device * ndev,struct ethtool_stats * estats,u64 * data)5812f207cbfSStefan Wahren static void mse102x_get_ethtool_stats(struct net_device *ndev,
5822f207cbfSStefan Wahren 				      struct ethtool_stats *estats, u64 *data)
5832f207cbfSStefan Wahren {
5842f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5852f207cbfSStefan Wahren 	struct mse102x_stats *st = &mse->stats;
5862f207cbfSStefan Wahren 
5872f207cbfSStefan Wahren 	memcpy(data, st, ARRAY_SIZE(mse102x_gstrings_stats) * sizeof(u64));
5882f207cbfSStefan Wahren }
5892f207cbfSStefan Wahren 
mse102x_get_strings(struct net_device * ndev,u32 stringset,u8 * buf)5902f207cbfSStefan Wahren static void mse102x_get_strings(struct net_device *ndev, u32 stringset, u8 *buf)
5912f207cbfSStefan Wahren {
5922f207cbfSStefan Wahren 	switch (stringset) {
5932f207cbfSStefan Wahren 	case ETH_SS_STATS:
5942f207cbfSStefan Wahren 		memcpy(buf, &mse102x_gstrings_stats,
5952f207cbfSStefan Wahren 		       sizeof(mse102x_gstrings_stats));
5962f207cbfSStefan Wahren 		break;
5972f207cbfSStefan Wahren 	default:
5982f207cbfSStefan Wahren 		WARN_ON(1);
5992f207cbfSStefan Wahren 		break;
6002f207cbfSStefan Wahren 	}
6012f207cbfSStefan Wahren }
6022f207cbfSStefan Wahren 
mse102x_get_sset_count(struct net_device * ndev,int sset)6032f207cbfSStefan Wahren static int mse102x_get_sset_count(struct net_device *ndev, int sset)
6042f207cbfSStefan Wahren {
6052f207cbfSStefan Wahren 	switch (sset) {
6062f207cbfSStefan Wahren 	case ETH_SS_STATS:
6072f207cbfSStefan Wahren 		return ARRAY_SIZE(mse102x_gstrings_stats);
6082f207cbfSStefan Wahren 	default:
6092f207cbfSStefan Wahren 		return -EINVAL;
6102f207cbfSStefan Wahren 	}
6112f207cbfSStefan Wahren }
6122f207cbfSStefan Wahren 
6132f207cbfSStefan Wahren static const struct ethtool_ops mse102x_ethtool_ops = {
6142f207cbfSStefan Wahren 	.get_drvinfo		= mse102x_get_drvinfo,
6152f207cbfSStefan Wahren 	.get_link		= ethtool_op_get_link,
6162f207cbfSStefan Wahren 	.get_msglevel		= mse102x_get_msglevel,
6172f207cbfSStefan Wahren 	.set_msglevel		= mse102x_set_msglevel,
6182f207cbfSStefan Wahren 	.get_ethtool_stats	= mse102x_get_ethtool_stats,
6192f207cbfSStefan Wahren 	.get_strings		= mse102x_get_strings,
6202f207cbfSStefan Wahren 	.get_sset_count		= mse102x_get_sset_count,
6212f207cbfSStefan Wahren };
6222f207cbfSStefan Wahren 
6232f207cbfSStefan Wahren /* driver bus management functions */
6242f207cbfSStefan Wahren 
6252f207cbfSStefan Wahren #ifdef CONFIG_PM_SLEEP
6262f207cbfSStefan Wahren 
mse102x_suspend(struct device * dev)6272f207cbfSStefan Wahren static int mse102x_suspend(struct device *dev)
6282f207cbfSStefan Wahren {
6292f207cbfSStefan Wahren 	struct mse102x_net *mse = dev_get_drvdata(dev);
6302f207cbfSStefan Wahren 	struct net_device *ndev = mse->ndev;
6312f207cbfSStefan Wahren 
6322f207cbfSStefan Wahren 	if (netif_running(ndev)) {
6332f207cbfSStefan Wahren 		netif_device_detach(ndev);
6342f207cbfSStefan Wahren 		mse102x_net_stop(ndev);
6352f207cbfSStefan Wahren 	}
6362f207cbfSStefan Wahren 
6372f207cbfSStefan Wahren 	return 0;
6382f207cbfSStefan Wahren }
6392f207cbfSStefan Wahren 
mse102x_resume(struct device * dev)6402f207cbfSStefan Wahren static int mse102x_resume(struct device *dev)
6412f207cbfSStefan Wahren {
6422f207cbfSStefan Wahren 	struct mse102x_net *mse = dev_get_drvdata(dev);
6432f207cbfSStefan Wahren 	struct net_device *ndev = mse->ndev;
6442f207cbfSStefan Wahren 
6452f207cbfSStefan Wahren 	if (netif_running(ndev)) {
6462f207cbfSStefan Wahren 		mse102x_net_open(ndev);
6472f207cbfSStefan Wahren 		netif_device_attach(ndev);
6482f207cbfSStefan Wahren 	}
6492f207cbfSStefan Wahren 
6502f207cbfSStefan Wahren 	return 0;
6512f207cbfSStefan Wahren }
6522f207cbfSStefan Wahren #endif
6532f207cbfSStefan Wahren 
6542f207cbfSStefan Wahren static SIMPLE_DEV_PM_OPS(mse102x_pm_ops, mse102x_suspend, mse102x_resume);
6552f207cbfSStefan Wahren 
mse102x_probe_spi(struct spi_device * spi)6562f207cbfSStefan Wahren static int mse102x_probe_spi(struct spi_device *spi)
6572f207cbfSStefan Wahren {
6582f207cbfSStefan Wahren 	struct device *dev = &spi->dev;
6592f207cbfSStefan Wahren 	struct mse102x_net_spi *mses;
6602f207cbfSStefan Wahren 	struct net_device *ndev;
6612f207cbfSStefan Wahren 	struct mse102x_net *mse;
6622f207cbfSStefan Wahren 	int ret;
6632f207cbfSStefan Wahren 
6642f207cbfSStefan Wahren 	spi->bits_per_word = 8;
6652f207cbfSStefan Wahren 	spi->mode |= SPI_MODE_3;
6662f207cbfSStefan Wahren 	/* enforce minimum speed to ensure device functionality */
6672f207cbfSStefan Wahren 	spi->master->min_speed_hz = MIN_FREQ_HZ;
6682f207cbfSStefan Wahren 
6692f207cbfSStefan Wahren 	if (!spi->max_speed_hz)
6702f207cbfSStefan Wahren 		spi->max_speed_hz = MAX_FREQ_HZ;
6712f207cbfSStefan Wahren 
6722f207cbfSStefan Wahren 	if (spi->max_speed_hz < MIN_FREQ_HZ ||
6732f207cbfSStefan Wahren 	    spi->max_speed_hz > MAX_FREQ_HZ) {
6742f207cbfSStefan Wahren 		dev_err(&spi->dev, "SPI max frequency out of range (min: %u, max: %u)\n",
6752f207cbfSStefan Wahren 			MIN_FREQ_HZ, MAX_FREQ_HZ);
6762f207cbfSStefan Wahren 		return -EINVAL;
6772f207cbfSStefan Wahren 	}
6782f207cbfSStefan Wahren 
6792f207cbfSStefan Wahren 	ret = spi_setup(spi);
6802f207cbfSStefan Wahren 	if (ret < 0) {
6812f207cbfSStefan Wahren 		dev_err(&spi->dev, "Unable to setup SPI device: %d\n", ret);
6822f207cbfSStefan Wahren 		return ret;
6832f207cbfSStefan Wahren 	}
6842f207cbfSStefan Wahren 
6852f207cbfSStefan Wahren 	ndev = devm_alloc_etherdev(dev, sizeof(struct mse102x_net_spi));
6862f207cbfSStefan Wahren 	if (!ndev)
6872f207cbfSStefan Wahren 		return -ENOMEM;
6882f207cbfSStefan Wahren 
6892f207cbfSStefan Wahren 	ndev->needed_tailroom += ALIGN(DET_DFT_LEN, 4);
6902f207cbfSStefan Wahren 	ndev->needed_headroom += ALIGN(DET_SOF_LEN, 4);
6912f207cbfSStefan Wahren 	ndev->priv_flags &= ~IFF_TX_SKB_SHARING;
6922f207cbfSStefan Wahren 	ndev->tx_queue_len = 100;
6932f207cbfSStefan Wahren 
6942f207cbfSStefan Wahren 	mse = netdev_priv(ndev);
6952f207cbfSStefan Wahren 	mses = to_mse102x_spi(mse);
6962f207cbfSStefan Wahren 
6972f207cbfSStefan Wahren 	mses->spidev = spi;
6982f207cbfSStefan Wahren 	mutex_init(&mses->lock);
6992f207cbfSStefan Wahren 	INIT_WORK(&mses->tx_work, mse102x_tx_work);
7002f207cbfSStefan Wahren 
7012f207cbfSStefan Wahren 	/* initialise pre-made spi transfer messages */
7022f207cbfSStefan Wahren 	spi_message_init(&mses->spi_msg);
7032f207cbfSStefan Wahren 	spi_message_add_tail(&mses->spi_xfer, &mses->spi_msg);
7042f207cbfSStefan Wahren 
7052f207cbfSStefan Wahren 	ndev->irq = spi->irq;
7062f207cbfSStefan Wahren 	mse->ndev = ndev;
7072f207cbfSStefan Wahren 
7082f207cbfSStefan Wahren 	/* set the default message enable */
7092f207cbfSStefan Wahren 	mse->msg_enable = netif_msg_init(-1, MSG_DEFAULT);
7102f207cbfSStefan Wahren 
7112f207cbfSStefan Wahren 	skb_queue_head_init(&mse->txq);
7122f207cbfSStefan Wahren 
7132f207cbfSStefan Wahren 	SET_NETDEV_DEV(ndev, dev);
7142f207cbfSStefan Wahren 
7152f207cbfSStefan Wahren 	dev_set_drvdata(dev, mse);
7162f207cbfSStefan Wahren 
7172f207cbfSStefan Wahren 	netif_carrier_off(mse->ndev);
7182f207cbfSStefan Wahren 	ndev->netdev_ops = &mse102x_netdev_ops;
7192f207cbfSStefan Wahren 	ndev->ethtool_ops = &mse102x_ethtool_ops;
7202f207cbfSStefan Wahren 
7212f207cbfSStefan Wahren 	mse102x_init_mac(mse, dev->of_node);
7222f207cbfSStefan Wahren 
7232f207cbfSStefan Wahren 	ret = register_netdev(ndev);
7242f207cbfSStefan Wahren 	if (ret) {
7252f207cbfSStefan Wahren 		dev_err(dev, "failed to register network device: %d\n", ret);
7262f207cbfSStefan Wahren 		return ret;
7272f207cbfSStefan Wahren 	}
7282f207cbfSStefan Wahren 
7292f207cbfSStefan Wahren 	mse102x_init_device_debugfs(mses);
7302f207cbfSStefan Wahren 
7312f207cbfSStefan Wahren 	return 0;
7322f207cbfSStefan Wahren }
7332f207cbfSStefan Wahren 
mse102x_remove_spi(struct spi_device * spi)734a0386bbaSUwe Kleine-König static void mse102x_remove_spi(struct spi_device *spi)
7352f207cbfSStefan Wahren {
7362f207cbfSStefan Wahren 	struct mse102x_net *mse = dev_get_drvdata(&spi->dev);
7372f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
7382f207cbfSStefan Wahren 
7392f207cbfSStefan Wahren 	if (netif_msg_drv(mse))
7402f207cbfSStefan Wahren 		dev_info(&spi->dev, "remove\n");
7412f207cbfSStefan Wahren 
7422f207cbfSStefan Wahren 	mse102x_remove_device_debugfs(mses);
7432f207cbfSStefan Wahren 	unregister_netdev(mse->ndev);
7442f207cbfSStefan Wahren }
7452f207cbfSStefan Wahren 
7462f207cbfSStefan Wahren static const struct of_device_id mse102x_match_table[] = {
7472f207cbfSStefan Wahren 	{ .compatible = "vertexcom,mse1021" },
7482f207cbfSStefan Wahren 	{ .compatible = "vertexcom,mse1022" },
7492f207cbfSStefan Wahren 	{ }
7502f207cbfSStefan Wahren };
7512f207cbfSStefan Wahren MODULE_DEVICE_TABLE(of, mse102x_match_table);
7522f207cbfSStefan Wahren 
753*1bba1998SWei Yongjun static const struct spi_device_id mse102x_ids[] = {
754*1bba1998SWei Yongjun 	{ "mse1021" },
755*1bba1998SWei Yongjun 	{ "mse1022" },
756*1bba1998SWei Yongjun 	{ }
757*1bba1998SWei Yongjun };
758*1bba1998SWei Yongjun MODULE_DEVICE_TABLE(spi, mse102x_ids);
759*1bba1998SWei Yongjun 
7602f207cbfSStefan Wahren static struct spi_driver mse102x_driver = {
7612f207cbfSStefan Wahren 	.driver = {
7622f207cbfSStefan Wahren 		.name = DRV_NAME,
7632f207cbfSStefan Wahren 		.of_match_table = mse102x_match_table,
7642f207cbfSStefan Wahren 		.pm = &mse102x_pm_ops,
7652f207cbfSStefan Wahren 	},
7662f207cbfSStefan Wahren 	.probe = mse102x_probe_spi,
7672f207cbfSStefan Wahren 	.remove = mse102x_remove_spi,
768*1bba1998SWei Yongjun 	.id_table = mse102x_ids,
7692f207cbfSStefan Wahren };
7702f207cbfSStefan Wahren module_spi_driver(mse102x_driver);
7712f207cbfSStefan Wahren 
7722f207cbfSStefan Wahren MODULE_DESCRIPTION("MSE102x Network driver");
77356cb6a59SStefan Wahren MODULE_AUTHOR("Stefan Wahren <stefan.wahren@chargebyte.com>");
7742f207cbfSStefan Wahren MODULE_LICENSE("GPL");
7752f207cbfSStefan Wahren MODULE_ALIAS("spi:" DRV_NAME);
776