xref: /openbmc/linux/drivers/net/ethernet/vertexcom/mse102x.c (revision f6d73b12ca9fd3b1c29a6a725cd751b972c740cf)
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;
2251325e838SStefan Wahren 	struct sk_buff *tskb = NULL;
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 		txp = tskb;
2392f207cbfSStefan Wahren 	}
2402f207cbfSStefan Wahren 
2412f207cbfSStefan Wahren 	mse102x_push_header(txp);
2422f207cbfSStefan Wahren 
2432f207cbfSStefan Wahren 	if (pad)
2442f207cbfSStefan Wahren 		skb_put_zero(txp, pad);
2452f207cbfSStefan Wahren 
2462f207cbfSStefan Wahren 	mse102x_put_footer(txp);
2472f207cbfSStefan Wahren 
2482f207cbfSStefan Wahren 	xfer->tx_buf = txp->data;
2492f207cbfSStefan Wahren 	xfer->rx_buf = NULL;
2502f207cbfSStefan Wahren 	xfer->len = txp->len;
2512f207cbfSStefan Wahren 
2522f207cbfSStefan Wahren 	ret = spi_sync(mses->spidev, msg);
2532f207cbfSStefan Wahren 	if (ret < 0) {
2542f207cbfSStefan Wahren 		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
2552f207cbfSStefan Wahren 			   __func__, ret);
2562f207cbfSStefan Wahren 		mse->stats.xfer_err++;
2572f207cbfSStefan Wahren 	}
2582f207cbfSStefan Wahren 
2591325e838SStefan Wahren 	dev_kfree_skb(tskb);
2601325e838SStefan Wahren 
2612f207cbfSStefan Wahren 	return ret;
2622f207cbfSStefan Wahren }
2632f207cbfSStefan Wahren 
mse102x_rx_frame_spi(struct mse102x_net * mse,u8 * buff,unsigned int frame_len)2642f207cbfSStefan Wahren static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff,
2652f207cbfSStefan Wahren 				unsigned int frame_len)
2662f207cbfSStefan Wahren {
2672f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
2682f207cbfSStefan Wahren 	struct spi_transfer *xfer = &mses->spi_xfer;
2692f207cbfSStefan Wahren 	struct spi_message *msg = &mses->spi_msg;
2702f207cbfSStefan Wahren 	__be16 *sof = (__be16 *)buff;
2712f207cbfSStefan Wahren 	__be16 *dft = (__be16 *)(buff + DET_SOF_LEN + frame_len);
2722f207cbfSStefan Wahren 	int ret;
2732f207cbfSStefan Wahren 
2742f207cbfSStefan Wahren 	xfer->rx_buf = buff;
2752f207cbfSStefan Wahren 	xfer->tx_buf = NULL;
2762f207cbfSStefan Wahren 	xfer->len = DET_SOF_LEN + frame_len + DET_DFT_LEN;
2772f207cbfSStefan Wahren 
2782f207cbfSStefan Wahren 	ret = spi_sync(mses->spidev, msg);
2792f207cbfSStefan Wahren 	if (ret < 0) {
2802f207cbfSStefan Wahren 		netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n",
2812f207cbfSStefan Wahren 			   __func__, ret);
2822f207cbfSStefan Wahren 		mse->stats.xfer_err++;
2832f207cbfSStefan Wahren 	} else if (*sof != cpu_to_be16(DET_SOF)) {
2842f207cbfSStefan Wahren 		netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n",
2852f207cbfSStefan Wahren 			   __func__, *sof);
2862f207cbfSStefan Wahren 		mse->stats.invalid_sof++;
2872f207cbfSStefan Wahren 		ret = -EIO;
2882f207cbfSStefan Wahren 	} else if (*dft != cpu_to_be16(DET_DFT)) {
2892f207cbfSStefan Wahren 		netdev_dbg(mse->ndev, "%s: SPI frame tail is invalid (0x%04x)\n",
2902f207cbfSStefan Wahren 			   __func__, *dft);
2912f207cbfSStefan Wahren 		mse->stats.invalid_dft++;
2922f207cbfSStefan Wahren 		ret = -EIO;
2932f207cbfSStefan Wahren 	}
2942f207cbfSStefan Wahren 
2952f207cbfSStefan Wahren 	return ret;
2962f207cbfSStefan Wahren }
2972f207cbfSStefan Wahren 
mse102x_dump_packet(const char * msg,int len,const char * data)2982f207cbfSStefan Wahren static void mse102x_dump_packet(const char *msg, int len, const char *data)
2992f207cbfSStefan Wahren {
3002f207cbfSStefan Wahren 	printk(KERN_DEBUG ": %s - packet len:%d\n", msg, len);
3012f207cbfSStefan Wahren 	print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1,
3022f207cbfSStefan Wahren 		       data, len, true);
3032f207cbfSStefan Wahren }
3042f207cbfSStefan Wahren 
mse102x_rx_pkt_spi(struct mse102x_net * mse)3052f207cbfSStefan Wahren static void mse102x_rx_pkt_spi(struct mse102x_net *mse)
3062f207cbfSStefan Wahren {
3072f207cbfSStefan Wahren 	struct sk_buff *skb;
3082f207cbfSStefan Wahren 	unsigned int rxalign;
3092f207cbfSStefan Wahren 	unsigned int rxlen;
3102f207cbfSStefan Wahren 	__be16 rx = 0;
3112f207cbfSStefan Wahren 	u16 cmd_resp;
3122f207cbfSStefan Wahren 	u8 *rxpkt;
3132f207cbfSStefan Wahren 	int ret;
3142f207cbfSStefan Wahren 
3152f207cbfSStefan Wahren 	mse102x_tx_cmd_spi(mse, CMD_CTR);
3162f207cbfSStefan Wahren 	ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
3172f207cbfSStefan Wahren 	cmd_resp = be16_to_cpu(rx);
3182f207cbfSStefan Wahren 
3192f207cbfSStefan Wahren 	if (ret || ((cmd_resp & CMD_MASK) != CMD_RTS)) {
3202f207cbfSStefan Wahren 		usleep_range(50, 100);
3212f207cbfSStefan Wahren 
3222f207cbfSStefan Wahren 		mse102x_tx_cmd_spi(mse, CMD_CTR);
3232f207cbfSStefan Wahren 		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
3242f207cbfSStefan Wahren 		if (ret)
3252f207cbfSStefan Wahren 			return;
3262f207cbfSStefan Wahren 
3272f207cbfSStefan Wahren 		cmd_resp = be16_to_cpu(rx);
3282f207cbfSStefan Wahren 		if ((cmd_resp & CMD_MASK) != CMD_RTS) {
3292f207cbfSStefan Wahren 			net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
3302f207cbfSStefan Wahren 					    __func__, cmd_resp);
3312f207cbfSStefan Wahren 			mse->stats.invalid_rts++;
3322f207cbfSStefan Wahren 			return;
3332f207cbfSStefan Wahren 		}
3342f207cbfSStefan Wahren 
3352f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: Unexpected response to first CMD\n",
3362f207cbfSStefan Wahren 				    __func__);
3372f207cbfSStefan Wahren 	}
3382f207cbfSStefan Wahren 
3392f207cbfSStefan Wahren 	rxlen = cmd_resp & LEN_MASK;
3402f207cbfSStefan Wahren 	if (!rxlen) {
3412f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: No frame length defined\n", __func__);
3422f207cbfSStefan Wahren 		mse->stats.invalid_len++;
3432f207cbfSStefan Wahren 		return;
3442f207cbfSStefan Wahren 	}
3452f207cbfSStefan Wahren 
3462f207cbfSStefan Wahren 	rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4);
3472f207cbfSStefan Wahren 	skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign);
3482f207cbfSStefan Wahren 	if (!skb)
3492f207cbfSStefan Wahren 		return;
3502f207cbfSStefan Wahren 
3512f207cbfSStefan Wahren 	/* 2 bytes Start of frame (before ethernet header)
3522f207cbfSStefan Wahren 	 * 2 bytes Data frame tail (after ethernet frame)
3532f207cbfSStefan Wahren 	 * They are copied, but ignored.
3542f207cbfSStefan Wahren 	 */
3552f207cbfSStefan Wahren 	rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN;
3562f207cbfSStefan Wahren 	if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) {
3572f207cbfSStefan Wahren 		mse->ndev->stats.rx_errors++;
3582f207cbfSStefan Wahren 		dev_kfree_skb(skb);
3592f207cbfSStefan Wahren 		return;
3602f207cbfSStefan Wahren 	}
3612f207cbfSStefan Wahren 
3622f207cbfSStefan Wahren 	if (netif_msg_pktdata(mse))
3632f207cbfSStefan Wahren 		mse102x_dump_packet(__func__, skb->len, skb->data);
3642f207cbfSStefan Wahren 
3652f207cbfSStefan Wahren 	skb->protocol = eth_type_trans(skb, mse->ndev);
36690f77c1cSSebastian Andrzej Siewior 	netif_rx(skb);
3672f207cbfSStefan Wahren 
3682f207cbfSStefan Wahren 	mse->ndev->stats.rx_packets++;
3692f207cbfSStefan Wahren 	mse->ndev->stats.rx_bytes += rxlen;
3702f207cbfSStefan Wahren }
3712f207cbfSStefan Wahren 
mse102x_tx_pkt_spi(struct mse102x_net * mse,struct sk_buff * txb,unsigned long work_timeout)3722f207cbfSStefan Wahren static int mse102x_tx_pkt_spi(struct mse102x_net *mse, struct sk_buff *txb,
3732f207cbfSStefan Wahren 			      unsigned long work_timeout)
3742f207cbfSStefan Wahren {
3752f207cbfSStefan Wahren 	unsigned int pad = 0;
3762f207cbfSStefan Wahren 	__be16 rx = 0;
3772f207cbfSStefan Wahren 	u16 cmd_resp;
3782f207cbfSStefan Wahren 	int ret;
3792f207cbfSStefan Wahren 	bool first = true;
3802f207cbfSStefan Wahren 
3812f207cbfSStefan Wahren 	if (txb->len < 60)
3822f207cbfSStefan Wahren 		pad = 60 - txb->len;
3832f207cbfSStefan Wahren 
3842f207cbfSStefan Wahren 	while (1) {
3852f207cbfSStefan Wahren 		mse102x_tx_cmd_spi(mse, CMD_RTS | (txb->len + pad));
3862f207cbfSStefan Wahren 		ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx);
3872f207cbfSStefan Wahren 		cmd_resp = be16_to_cpu(rx);
3882f207cbfSStefan Wahren 
3892f207cbfSStefan Wahren 		if (!ret) {
3902f207cbfSStefan Wahren 			/* ready to send frame ? */
3912f207cbfSStefan Wahren 			if (cmd_resp == CMD_CTR)
3922f207cbfSStefan Wahren 				break;
3932f207cbfSStefan Wahren 
3942f207cbfSStefan Wahren 			net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n",
3952f207cbfSStefan Wahren 					    __func__, cmd_resp);
3962f207cbfSStefan Wahren 			mse->stats.invalid_ctr++;
3972f207cbfSStefan Wahren 		}
3982f207cbfSStefan Wahren 
3992f207cbfSStefan Wahren 		/* It's not predictable how long / many retries it takes to
4002f207cbfSStefan Wahren 		 * send at least one packet, so TX timeouts are possible.
4012f207cbfSStefan Wahren 		 * That's the reason why the netdev watchdog is not used here.
4022f207cbfSStefan Wahren 		 */
4032f207cbfSStefan Wahren 		if (time_after(jiffies, work_timeout))
4042f207cbfSStefan Wahren 			return -ETIMEDOUT;
4052f207cbfSStefan Wahren 
4062f207cbfSStefan Wahren 		if (first) {
4072f207cbfSStefan Wahren 			/* throttle at first issue */
4082f207cbfSStefan Wahren 			netif_stop_queue(mse->ndev);
4092f207cbfSStefan Wahren 			/* fast retry */
4102f207cbfSStefan Wahren 			usleep_range(50, 100);
4112f207cbfSStefan Wahren 			first = false;
4122f207cbfSStefan Wahren 		} else {
4132f207cbfSStefan Wahren 			msleep(20);
4142f207cbfSStefan Wahren 		}
415431b9b4dSYang Li 	}
4162f207cbfSStefan Wahren 
4172f207cbfSStefan Wahren 	ret = mse102x_tx_frame_spi(mse, txb, pad);
4182f207cbfSStefan Wahren 	if (ret)
4192f207cbfSStefan Wahren 		net_dbg_ratelimited("%s: Failed to send (%d), drop frame\n",
4202f207cbfSStefan Wahren 				    __func__, ret);
4212f207cbfSStefan Wahren 
4222f207cbfSStefan Wahren 	return ret;
4232f207cbfSStefan Wahren }
4242f207cbfSStefan Wahren 
4252f207cbfSStefan Wahren #define TX_QUEUE_MAX 10
4262f207cbfSStefan Wahren 
mse102x_tx_work(struct work_struct * work)4272f207cbfSStefan Wahren static void mse102x_tx_work(struct work_struct *work)
4282f207cbfSStefan Wahren {
4292f207cbfSStefan Wahren 	/* Make sure timeout is sufficient to transfer TX_QUEUE_MAX frames */
4302f207cbfSStefan Wahren 	unsigned long work_timeout = jiffies + msecs_to_jiffies(1000);
4312f207cbfSStefan Wahren 	struct mse102x_net_spi *mses;
4322f207cbfSStefan Wahren 	struct mse102x_net *mse;
4332f207cbfSStefan Wahren 	struct sk_buff *txb;
4342f207cbfSStefan Wahren 	int ret = 0;
4352f207cbfSStefan Wahren 
4362f207cbfSStefan Wahren 	mses = container_of(work, struct mse102x_net_spi, tx_work);
4372f207cbfSStefan Wahren 	mse = &mses->mse102x;
4382f207cbfSStefan Wahren 
4392f207cbfSStefan Wahren 	while ((txb = skb_dequeue(&mse->txq))) {
440*fa8d2d14SStefan Wahren 		unsigned int len = max_t(unsigned int, txb->len, ETH_ZLEN);
441*fa8d2d14SStefan Wahren 
4422f207cbfSStefan Wahren 		mutex_lock(&mses->lock);
4432f207cbfSStefan Wahren 		ret = mse102x_tx_pkt_spi(mse, txb, work_timeout);
4442f207cbfSStefan Wahren 		mutex_unlock(&mses->lock);
4452f207cbfSStefan Wahren 		if (ret) {
4462f207cbfSStefan Wahren 			mse->ndev->stats.tx_dropped++;
4472f207cbfSStefan Wahren 		} else {
448*fa8d2d14SStefan Wahren 			mse->ndev->stats.tx_bytes += len;
4492f207cbfSStefan Wahren 			mse->ndev->stats.tx_packets++;
4502f207cbfSStefan Wahren 		}
4512f207cbfSStefan Wahren 
4522f207cbfSStefan Wahren 		dev_kfree_skb(txb);
4532f207cbfSStefan Wahren 	}
4542f207cbfSStefan Wahren 
4552f207cbfSStefan Wahren 	if (ret == -ETIMEDOUT) {
4562f207cbfSStefan Wahren 		if (netif_msg_timer(mse))
4572f207cbfSStefan Wahren 			netdev_err(mse->ndev, "tx work timeout\n");
4582f207cbfSStefan Wahren 
4592f207cbfSStefan Wahren 		mse->stats.tx_timeout++;
4602f207cbfSStefan Wahren 	}
4612f207cbfSStefan Wahren 
4622f207cbfSStefan Wahren 	netif_wake_queue(mse->ndev);
4632f207cbfSStefan Wahren }
4642f207cbfSStefan Wahren 
mse102x_start_xmit_spi(struct sk_buff * skb,struct net_device * ndev)4652f207cbfSStefan Wahren static netdev_tx_t mse102x_start_xmit_spi(struct sk_buff *skb,
4662f207cbfSStefan Wahren 					  struct net_device *ndev)
4672f207cbfSStefan Wahren {
4682f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
4692f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
4702f207cbfSStefan Wahren 
4712f207cbfSStefan Wahren 	netif_dbg(mse, tx_queued, ndev,
4722f207cbfSStefan Wahren 		  "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data);
4732f207cbfSStefan Wahren 
4742f207cbfSStefan Wahren 	skb_queue_tail(&mse->txq, skb);
4752f207cbfSStefan Wahren 
4762f207cbfSStefan Wahren 	if (skb_queue_len(&mse->txq) >= TX_QUEUE_MAX)
4772f207cbfSStefan Wahren 		netif_stop_queue(ndev);
4782f207cbfSStefan Wahren 
4792f207cbfSStefan Wahren 	schedule_work(&mses->tx_work);
4802f207cbfSStefan Wahren 
4812f207cbfSStefan Wahren 	return NETDEV_TX_OK;
4822f207cbfSStefan Wahren }
4832f207cbfSStefan Wahren 
mse102x_init_mac(struct mse102x_net * mse,struct device_node * np)4842f207cbfSStefan Wahren static void mse102x_init_mac(struct mse102x_net *mse, struct device_node *np)
4852f207cbfSStefan Wahren {
4862f207cbfSStefan Wahren 	struct net_device *ndev = mse->ndev;
4872f207cbfSStefan Wahren 	int ret = of_get_ethdev_address(np, ndev);
4882f207cbfSStefan Wahren 
4892f207cbfSStefan Wahren 	if (ret) {
4902f207cbfSStefan Wahren 		eth_hw_addr_random(ndev);
4912f207cbfSStefan Wahren 		netdev_err(ndev, "Using random MAC address: %pM\n",
4922f207cbfSStefan Wahren 			   ndev->dev_addr);
4932f207cbfSStefan Wahren 	}
4942f207cbfSStefan Wahren }
4952f207cbfSStefan Wahren 
4962f207cbfSStefan Wahren /* Assumption: this is called for every incoming packet */
mse102x_irq(int irq,void * _mse)4972f207cbfSStefan Wahren static irqreturn_t mse102x_irq(int irq, void *_mse)
4982f207cbfSStefan Wahren {
4992f207cbfSStefan Wahren 	struct mse102x_net *mse = _mse;
5002f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
5012f207cbfSStefan Wahren 
5022f207cbfSStefan Wahren 	mutex_lock(&mses->lock);
5032f207cbfSStefan Wahren 	mse102x_rx_pkt_spi(mse);
5042f207cbfSStefan Wahren 	mutex_unlock(&mses->lock);
5052f207cbfSStefan Wahren 
5062f207cbfSStefan Wahren 	return IRQ_HANDLED;
5072f207cbfSStefan Wahren }
5082f207cbfSStefan Wahren 
mse102x_net_open(struct net_device * ndev)5092f207cbfSStefan Wahren static int mse102x_net_open(struct net_device *ndev)
5102f207cbfSStefan Wahren {
5112f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5122f207cbfSStefan Wahren 	int ret;
5132f207cbfSStefan Wahren 
5142f207cbfSStefan Wahren 	ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT,
5152f207cbfSStefan Wahren 				   ndev->name, mse);
5162f207cbfSStefan Wahren 	if (ret < 0) {
5172f207cbfSStefan Wahren 		netdev_err(ndev, "Failed to get irq: %d\n", ret);
5182f207cbfSStefan Wahren 		return ret;
5192f207cbfSStefan Wahren 	}
5202f207cbfSStefan Wahren 
5212f207cbfSStefan Wahren 	netif_dbg(mse, ifup, ndev, "opening\n");
5222f207cbfSStefan Wahren 
5232f207cbfSStefan Wahren 	netif_start_queue(ndev);
5242f207cbfSStefan Wahren 
5252f207cbfSStefan Wahren 	netif_carrier_on(ndev);
5262f207cbfSStefan Wahren 
5272f207cbfSStefan Wahren 	netif_dbg(mse, ifup, ndev, "network device up\n");
5282f207cbfSStefan Wahren 
5292f207cbfSStefan Wahren 	return 0;
5302f207cbfSStefan Wahren }
5312f207cbfSStefan Wahren 
mse102x_net_stop(struct net_device * ndev)5322f207cbfSStefan Wahren static int mse102x_net_stop(struct net_device *ndev)
5332f207cbfSStefan Wahren {
5342f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5352f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
5362f207cbfSStefan Wahren 
5372f207cbfSStefan Wahren 	netif_info(mse, ifdown, ndev, "shutting down\n");
5382f207cbfSStefan Wahren 
5392f207cbfSStefan Wahren 	netif_carrier_off(mse->ndev);
5402f207cbfSStefan Wahren 
5412f207cbfSStefan Wahren 	/* stop any outstanding work */
5422f207cbfSStefan Wahren 	flush_work(&mses->tx_work);
5432f207cbfSStefan Wahren 
5442f207cbfSStefan Wahren 	netif_stop_queue(ndev);
5452f207cbfSStefan Wahren 
5462f207cbfSStefan Wahren 	skb_queue_purge(&mse->txq);
5472f207cbfSStefan Wahren 
5482f207cbfSStefan Wahren 	free_irq(ndev->irq, mse);
5492f207cbfSStefan Wahren 
5502f207cbfSStefan Wahren 	return 0;
5512f207cbfSStefan Wahren }
5522f207cbfSStefan Wahren 
5532f207cbfSStefan Wahren static const struct net_device_ops mse102x_netdev_ops = {
5542f207cbfSStefan Wahren 	.ndo_open		= mse102x_net_open,
5552f207cbfSStefan Wahren 	.ndo_stop		= mse102x_net_stop,
5562f207cbfSStefan Wahren 	.ndo_start_xmit		= mse102x_start_xmit_spi,
5572f207cbfSStefan Wahren 	.ndo_set_mac_address	= eth_mac_addr,
5582f207cbfSStefan Wahren 	.ndo_validate_addr	= eth_validate_addr,
5592f207cbfSStefan Wahren };
5602f207cbfSStefan Wahren 
5612f207cbfSStefan Wahren /* ethtool support */
5622f207cbfSStefan Wahren 
mse102x_get_drvinfo(struct net_device * ndev,struct ethtool_drvinfo * di)5632f207cbfSStefan Wahren static void mse102x_get_drvinfo(struct net_device *ndev,
5642f207cbfSStefan Wahren 				struct ethtool_drvinfo *di)
5652f207cbfSStefan Wahren {
5662f207cbfSStefan Wahren 	strscpy(di->driver, DRV_NAME, sizeof(di->driver));
5672f207cbfSStefan Wahren 	strscpy(di->bus_info, dev_name(ndev->dev.parent), sizeof(di->bus_info));
5682f207cbfSStefan Wahren }
5692f207cbfSStefan Wahren 
mse102x_get_msglevel(struct net_device * ndev)5702f207cbfSStefan Wahren static u32 mse102x_get_msglevel(struct net_device *ndev)
5712f207cbfSStefan Wahren {
5722f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5732f207cbfSStefan Wahren 
5742f207cbfSStefan Wahren 	return mse->msg_enable;
5752f207cbfSStefan Wahren }
5762f207cbfSStefan Wahren 
mse102x_set_msglevel(struct net_device * ndev,u32 to)5772f207cbfSStefan Wahren static void mse102x_set_msglevel(struct net_device *ndev, u32 to)
5782f207cbfSStefan Wahren {
5792f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5802f207cbfSStefan Wahren 
5812f207cbfSStefan Wahren 	mse->msg_enable = to;
5822f207cbfSStefan Wahren }
5832f207cbfSStefan Wahren 
mse102x_get_ethtool_stats(struct net_device * ndev,struct ethtool_stats * estats,u64 * data)5842f207cbfSStefan Wahren static void mse102x_get_ethtool_stats(struct net_device *ndev,
5852f207cbfSStefan Wahren 				      struct ethtool_stats *estats, u64 *data)
5862f207cbfSStefan Wahren {
5872f207cbfSStefan Wahren 	struct mse102x_net *mse = netdev_priv(ndev);
5882f207cbfSStefan Wahren 	struct mse102x_stats *st = &mse->stats;
5892f207cbfSStefan Wahren 
5902f207cbfSStefan Wahren 	memcpy(data, st, ARRAY_SIZE(mse102x_gstrings_stats) * sizeof(u64));
5912f207cbfSStefan Wahren }
5922f207cbfSStefan Wahren 
mse102x_get_strings(struct net_device * ndev,u32 stringset,u8 * buf)5932f207cbfSStefan Wahren static void mse102x_get_strings(struct net_device *ndev, u32 stringset, u8 *buf)
5942f207cbfSStefan Wahren {
5952f207cbfSStefan Wahren 	switch (stringset) {
5962f207cbfSStefan Wahren 	case ETH_SS_STATS:
5972f207cbfSStefan Wahren 		memcpy(buf, &mse102x_gstrings_stats,
5982f207cbfSStefan Wahren 		       sizeof(mse102x_gstrings_stats));
5992f207cbfSStefan Wahren 		break;
6002f207cbfSStefan Wahren 	default:
6012f207cbfSStefan Wahren 		WARN_ON(1);
6022f207cbfSStefan Wahren 		break;
6032f207cbfSStefan Wahren 	}
6042f207cbfSStefan Wahren }
6052f207cbfSStefan Wahren 
mse102x_get_sset_count(struct net_device * ndev,int sset)6062f207cbfSStefan Wahren static int mse102x_get_sset_count(struct net_device *ndev, int sset)
6072f207cbfSStefan Wahren {
6082f207cbfSStefan Wahren 	switch (sset) {
6092f207cbfSStefan Wahren 	case ETH_SS_STATS:
6102f207cbfSStefan Wahren 		return ARRAY_SIZE(mse102x_gstrings_stats);
6112f207cbfSStefan Wahren 	default:
6122f207cbfSStefan Wahren 		return -EINVAL;
6132f207cbfSStefan Wahren 	}
6142f207cbfSStefan Wahren }
6152f207cbfSStefan Wahren 
6162f207cbfSStefan Wahren static const struct ethtool_ops mse102x_ethtool_ops = {
6172f207cbfSStefan Wahren 	.get_drvinfo		= mse102x_get_drvinfo,
6182f207cbfSStefan Wahren 	.get_link		= ethtool_op_get_link,
6192f207cbfSStefan Wahren 	.get_msglevel		= mse102x_get_msglevel,
6202f207cbfSStefan Wahren 	.set_msglevel		= mse102x_set_msglevel,
6212f207cbfSStefan Wahren 	.get_ethtool_stats	= mse102x_get_ethtool_stats,
6222f207cbfSStefan Wahren 	.get_strings		= mse102x_get_strings,
6232f207cbfSStefan Wahren 	.get_sset_count		= mse102x_get_sset_count,
6242f207cbfSStefan Wahren };
6252f207cbfSStefan Wahren 
6262f207cbfSStefan Wahren /* driver bus management functions */
6272f207cbfSStefan Wahren 
6282f207cbfSStefan Wahren #ifdef CONFIG_PM_SLEEP
6292f207cbfSStefan Wahren 
mse102x_suspend(struct device * dev)6302f207cbfSStefan Wahren static int mse102x_suspend(struct device *dev)
6312f207cbfSStefan Wahren {
6322f207cbfSStefan Wahren 	struct mse102x_net *mse = dev_get_drvdata(dev);
6332f207cbfSStefan Wahren 	struct net_device *ndev = mse->ndev;
6342f207cbfSStefan Wahren 
6352f207cbfSStefan Wahren 	if (netif_running(ndev)) {
6362f207cbfSStefan Wahren 		netif_device_detach(ndev);
6372f207cbfSStefan Wahren 		mse102x_net_stop(ndev);
6382f207cbfSStefan Wahren 	}
6392f207cbfSStefan Wahren 
6402f207cbfSStefan Wahren 	return 0;
6412f207cbfSStefan Wahren }
6422f207cbfSStefan Wahren 
mse102x_resume(struct device * dev)6432f207cbfSStefan Wahren static int mse102x_resume(struct device *dev)
6442f207cbfSStefan Wahren {
6452f207cbfSStefan Wahren 	struct mse102x_net *mse = dev_get_drvdata(dev);
6462f207cbfSStefan Wahren 	struct net_device *ndev = mse->ndev;
6472f207cbfSStefan Wahren 
6482f207cbfSStefan Wahren 	if (netif_running(ndev)) {
6492f207cbfSStefan Wahren 		mse102x_net_open(ndev);
6502f207cbfSStefan Wahren 		netif_device_attach(ndev);
6512f207cbfSStefan Wahren 	}
6522f207cbfSStefan Wahren 
6532f207cbfSStefan Wahren 	return 0;
6542f207cbfSStefan Wahren }
6552f207cbfSStefan Wahren #endif
6562f207cbfSStefan Wahren 
6572f207cbfSStefan Wahren static SIMPLE_DEV_PM_OPS(mse102x_pm_ops, mse102x_suspend, mse102x_resume);
6582f207cbfSStefan Wahren 
mse102x_probe_spi(struct spi_device * spi)6592f207cbfSStefan Wahren static int mse102x_probe_spi(struct spi_device *spi)
6602f207cbfSStefan Wahren {
6612f207cbfSStefan Wahren 	struct device *dev = &spi->dev;
6622f207cbfSStefan Wahren 	struct mse102x_net_spi *mses;
6632f207cbfSStefan Wahren 	struct net_device *ndev;
6642f207cbfSStefan Wahren 	struct mse102x_net *mse;
6652f207cbfSStefan Wahren 	int ret;
6662f207cbfSStefan Wahren 
6672f207cbfSStefan Wahren 	spi->bits_per_word = 8;
6682f207cbfSStefan Wahren 	spi->mode |= SPI_MODE_3;
6692f207cbfSStefan Wahren 	/* enforce minimum speed to ensure device functionality */
6702f207cbfSStefan Wahren 	spi->master->min_speed_hz = MIN_FREQ_HZ;
6712f207cbfSStefan Wahren 
6722f207cbfSStefan Wahren 	if (!spi->max_speed_hz)
6732f207cbfSStefan Wahren 		spi->max_speed_hz = MAX_FREQ_HZ;
6742f207cbfSStefan Wahren 
6752f207cbfSStefan Wahren 	if (spi->max_speed_hz < MIN_FREQ_HZ ||
6762f207cbfSStefan Wahren 	    spi->max_speed_hz > MAX_FREQ_HZ) {
6772f207cbfSStefan Wahren 		dev_err(&spi->dev, "SPI max frequency out of range (min: %u, max: %u)\n",
6782f207cbfSStefan Wahren 			MIN_FREQ_HZ, MAX_FREQ_HZ);
6792f207cbfSStefan Wahren 		return -EINVAL;
6802f207cbfSStefan Wahren 	}
6812f207cbfSStefan Wahren 
6822f207cbfSStefan Wahren 	ret = spi_setup(spi);
6832f207cbfSStefan Wahren 	if (ret < 0) {
6842f207cbfSStefan Wahren 		dev_err(&spi->dev, "Unable to setup SPI device: %d\n", ret);
6852f207cbfSStefan Wahren 		return ret;
6862f207cbfSStefan Wahren 	}
6872f207cbfSStefan Wahren 
6882f207cbfSStefan Wahren 	ndev = devm_alloc_etherdev(dev, sizeof(struct mse102x_net_spi));
6892f207cbfSStefan Wahren 	if (!ndev)
6902f207cbfSStefan Wahren 		return -ENOMEM;
6912f207cbfSStefan Wahren 
6922f207cbfSStefan Wahren 	ndev->needed_tailroom += ALIGN(DET_DFT_LEN, 4);
6932f207cbfSStefan Wahren 	ndev->needed_headroom += ALIGN(DET_SOF_LEN, 4);
6942f207cbfSStefan Wahren 	ndev->priv_flags &= ~IFF_TX_SKB_SHARING;
6952f207cbfSStefan Wahren 	ndev->tx_queue_len = 100;
6962f207cbfSStefan Wahren 
6972f207cbfSStefan Wahren 	mse = netdev_priv(ndev);
6982f207cbfSStefan Wahren 	mses = to_mse102x_spi(mse);
6992f207cbfSStefan Wahren 
7002f207cbfSStefan Wahren 	mses->spidev = spi;
7012f207cbfSStefan Wahren 	mutex_init(&mses->lock);
7022f207cbfSStefan Wahren 	INIT_WORK(&mses->tx_work, mse102x_tx_work);
7032f207cbfSStefan Wahren 
7042f207cbfSStefan Wahren 	/* initialise pre-made spi transfer messages */
7052f207cbfSStefan Wahren 	spi_message_init(&mses->spi_msg);
7062f207cbfSStefan Wahren 	spi_message_add_tail(&mses->spi_xfer, &mses->spi_msg);
7072f207cbfSStefan Wahren 
7082f207cbfSStefan Wahren 	ndev->irq = spi->irq;
7092f207cbfSStefan Wahren 	mse->ndev = ndev;
7102f207cbfSStefan Wahren 
7112f207cbfSStefan Wahren 	/* set the default message enable */
7122f207cbfSStefan Wahren 	mse->msg_enable = netif_msg_init(-1, MSG_DEFAULT);
7132f207cbfSStefan Wahren 
7142f207cbfSStefan Wahren 	skb_queue_head_init(&mse->txq);
7152f207cbfSStefan Wahren 
7162f207cbfSStefan Wahren 	SET_NETDEV_DEV(ndev, dev);
7172f207cbfSStefan Wahren 
7182f207cbfSStefan Wahren 	dev_set_drvdata(dev, mse);
7192f207cbfSStefan Wahren 
7202f207cbfSStefan Wahren 	netif_carrier_off(mse->ndev);
7212f207cbfSStefan Wahren 	ndev->netdev_ops = &mse102x_netdev_ops;
7222f207cbfSStefan Wahren 	ndev->ethtool_ops = &mse102x_ethtool_ops;
7232f207cbfSStefan Wahren 
7242f207cbfSStefan Wahren 	mse102x_init_mac(mse, dev->of_node);
7252f207cbfSStefan Wahren 
7262f207cbfSStefan Wahren 	ret = register_netdev(ndev);
7272f207cbfSStefan Wahren 	if (ret) {
7282f207cbfSStefan Wahren 		dev_err(dev, "failed to register network device: %d\n", ret);
7292f207cbfSStefan Wahren 		return ret;
7302f207cbfSStefan Wahren 	}
7312f207cbfSStefan Wahren 
7322f207cbfSStefan Wahren 	mse102x_init_device_debugfs(mses);
7332f207cbfSStefan Wahren 
7342f207cbfSStefan Wahren 	return 0;
7352f207cbfSStefan Wahren }
7362f207cbfSStefan Wahren 
mse102x_remove_spi(struct spi_device * spi)737a0386bbaSUwe Kleine-König static void mse102x_remove_spi(struct spi_device *spi)
7382f207cbfSStefan Wahren {
7392f207cbfSStefan Wahren 	struct mse102x_net *mse = dev_get_drvdata(&spi->dev);
7402f207cbfSStefan Wahren 	struct mse102x_net_spi *mses = to_mse102x_spi(mse);
7412f207cbfSStefan Wahren 
7422f207cbfSStefan Wahren 	if (netif_msg_drv(mse))
7432f207cbfSStefan Wahren 		dev_info(&spi->dev, "remove\n");
7442f207cbfSStefan Wahren 
7452f207cbfSStefan Wahren 	mse102x_remove_device_debugfs(mses);
7462f207cbfSStefan Wahren 	unregister_netdev(mse->ndev);
7472f207cbfSStefan Wahren }
7482f207cbfSStefan Wahren 
7492f207cbfSStefan Wahren static const struct of_device_id mse102x_match_table[] = {
7502f207cbfSStefan Wahren 	{ .compatible = "vertexcom,mse1021" },
7512f207cbfSStefan Wahren 	{ .compatible = "vertexcom,mse1022" },
7522f207cbfSStefan Wahren 	{ }
7532f207cbfSStefan Wahren };
7542f207cbfSStefan Wahren MODULE_DEVICE_TABLE(of, mse102x_match_table);
7552f207cbfSStefan Wahren 
7561bba1998SWei Yongjun static const struct spi_device_id mse102x_ids[] = {
7571bba1998SWei Yongjun 	{ "mse1021" },
7581bba1998SWei Yongjun 	{ "mse1022" },
7591bba1998SWei Yongjun 	{ }
7601bba1998SWei Yongjun };
7611bba1998SWei Yongjun MODULE_DEVICE_TABLE(spi, mse102x_ids);
7621bba1998SWei Yongjun 
7632f207cbfSStefan Wahren static struct spi_driver mse102x_driver = {
7642f207cbfSStefan Wahren 	.driver = {
7652f207cbfSStefan Wahren 		.name = DRV_NAME,
7662f207cbfSStefan Wahren 		.of_match_table = mse102x_match_table,
7672f207cbfSStefan Wahren 		.pm = &mse102x_pm_ops,
7682f207cbfSStefan Wahren 	},
7692f207cbfSStefan Wahren 	.probe = mse102x_probe_spi,
7702f207cbfSStefan Wahren 	.remove = mse102x_remove_spi,
7711bba1998SWei Yongjun 	.id_table = mse102x_ids,
7722f207cbfSStefan Wahren };
7732f207cbfSStefan Wahren module_spi_driver(mse102x_driver);
7742f207cbfSStefan Wahren 
7752f207cbfSStefan Wahren MODULE_DESCRIPTION("MSE102x Network driver");
77656cb6a59SStefan Wahren MODULE_AUTHOR("Stefan Wahren <stefan.wahren@chargebyte.com>");
7772f207cbfSStefan Wahren MODULE_LICENSE("GPL");
7782f207cbfSStefan Wahren MODULE_ALIAS("spi:" DRV_NAME);
779