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