1*2f207cbfSStefan Wahren // SPDX-License-Identifier: GPL-2.0-only 2*2f207cbfSStefan Wahren /* Copyright (C) 2021 in-tech smart charging GmbH 3*2f207cbfSStefan Wahren * 4*2f207cbfSStefan Wahren * driver is based on micrel/ks8851_spi.c 5*2f207cbfSStefan Wahren */ 6*2f207cbfSStefan Wahren 7*2f207cbfSStefan Wahren #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8*2f207cbfSStefan Wahren 9*2f207cbfSStefan Wahren #include <linux/interrupt.h> 10*2f207cbfSStefan Wahren #include <linux/module.h> 11*2f207cbfSStefan Wahren #include <linux/kernel.h> 12*2f207cbfSStefan Wahren #include <linux/netdevice.h> 13*2f207cbfSStefan Wahren #include <linux/etherdevice.h> 14*2f207cbfSStefan Wahren #include <linux/ethtool.h> 15*2f207cbfSStefan Wahren #include <linux/cache.h> 16*2f207cbfSStefan Wahren #include <linux/debugfs.h> 17*2f207cbfSStefan Wahren #include <linux/seq_file.h> 18*2f207cbfSStefan Wahren 19*2f207cbfSStefan Wahren #include <linux/spi/spi.h> 20*2f207cbfSStefan Wahren #include <linux/of_net.h> 21*2f207cbfSStefan Wahren 22*2f207cbfSStefan Wahren #define MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \ 23*2f207cbfSStefan Wahren NETIF_MSG_TIMER) 24*2f207cbfSStefan Wahren 25*2f207cbfSStefan Wahren #define DRV_NAME "mse102x" 26*2f207cbfSStefan Wahren 27*2f207cbfSStefan Wahren #define DET_CMD 0x0001 28*2f207cbfSStefan Wahren #define DET_SOF 0x0002 29*2f207cbfSStefan Wahren #define DET_DFT 0x55AA 30*2f207cbfSStefan Wahren 31*2f207cbfSStefan Wahren #define CMD_SHIFT 12 32*2f207cbfSStefan Wahren #define CMD_RTS (0x1 << CMD_SHIFT) 33*2f207cbfSStefan Wahren #define CMD_CTR (0x2 << CMD_SHIFT) 34*2f207cbfSStefan Wahren 35*2f207cbfSStefan Wahren #define CMD_MASK GENMASK(15, CMD_SHIFT) 36*2f207cbfSStefan Wahren #define LEN_MASK GENMASK(CMD_SHIFT - 1, 0) 37*2f207cbfSStefan Wahren 38*2f207cbfSStefan Wahren #define DET_CMD_LEN 4 39*2f207cbfSStefan Wahren #define DET_SOF_LEN 2 40*2f207cbfSStefan Wahren #define DET_DFT_LEN 2 41*2f207cbfSStefan Wahren 42*2f207cbfSStefan Wahren #define MIN_FREQ_HZ 6000000 43*2f207cbfSStefan Wahren #define MAX_FREQ_HZ 7142857 44*2f207cbfSStefan Wahren 45*2f207cbfSStefan Wahren struct mse102x_stats { 46*2f207cbfSStefan Wahren u64 xfer_err; 47*2f207cbfSStefan Wahren u64 invalid_cmd; 48*2f207cbfSStefan Wahren u64 invalid_ctr; 49*2f207cbfSStefan Wahren u64 invalid_dft; 50*2f207cbfSStefan Wahren u64 invalid_len; 51*2f207cbfSStefan Wahren u64 invalid_rts; 52*2f207cbfSStefan Wahren u64 invalid_sof; 53*2f207cbfSStefan Wahren u64 tx_timeout; 54*2f207cbfSStefan Wahren }; 55*2f207cbfSStefan Wahren 56*2f207cbfSStefan Wahren static const char mse102x_gstrings_stats[][ETH_GSTRING_LEN] = { 57*2f207cbfSStefan Wahren "SPI transfer errors", 58*2f207cbfSStefan Wahren "Invalid command", 59*2f207cbfSStefan Wahren "Invalid CTR", 60*2f207cbfSStefan Wahren "Invalid DFT", 61*2f207cbfSStefan Wahren "Invalid frame length", 62*2f207cbfSStefan Wahren "Invalid RTS", 63*2f207cbfSStefan Wahren "Invalid SOF", 64*2f207cbfSStefan Wahren "TX timeout", 65*2f207cbfSStefan Wahren }; 66*2f207cbfSStefan Wahren 67*2f207cbfSStefan Wahren struct mse102x_net { 68*2f207cbfSStefan Wahren struct net_device *ndev; 69*2f207cbfSStefan Wahren 70*2f207cbfSStefan Wahren u8 rxd[8]; 71*2f207cbfSStefan Wahren u8 txd[8]; 72*2f207cbfSStefan Wahren 73*2f207cbfSStefan Wahren u32 msg_enable ____cacheline_aligned; 74*2f207cbfSStefan Wahren 75*2f207cbfSStefan Wahren struct sk_buff_head txq; 76*2f207cbfSStefan Wahren struct mse102x_stats stats; 77*2f207cbfSStefan Wahren }; 78*2f207cbfSStefan Wahren 79*2f207cbfSStefan Wahren struct mse102x_net_spi { 80*2f207cbfSStefan Wahren struct mse102x_net mse102x; 81*2f207cbfSStefan Wahren struct mutex lock; /* Protect SPI frame transfer */ 82*2f207cbfSStefan Wahren struct work_struct tx_work; 83*2f207cbfSStefan Wahren struct spi_device *spidev; 84*2f207cbfSStefan Wahren struct spi_message spi_msg; 85*2f207cbfSStefan Wahren struct spi_transfer spi_xfer; 86*2f207cbfSStefan Wahren 87*2f207cbfSStefan Wahren #ifdef CONFIG_DEBUG_FS 88*2f207cbfSStefan Wahren struct dentry *device_root; 89*2f207cbfSStefan Wahren #endif 90*2f207cbfSStefan Wahren }; 91*2f207cbfSStefan Wahren 92*2f207cbfSStefan Wahren #define to_mse102x_spi(mse) container_of((mse), struct mse102x_net_spi, mse102x) 93*2f207cbfSStefan Wahren 94*2f207cbfSStefan Wahren #ifdef CONFIG_DEBUG_FS 95*2f207cbfSStefan Wahren 96*2f207cbfSStefan Wahren static int mse102x_info_show(struct seq_file *s, void *what) 97*2f207cbfSStefan Wahren { 98*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = s->private; 99*2f207cbfSStefan Wahren 100*2f207cbfSStefan Wahren seq_printf(s, "TX ring size : %u\n", 101*2f207cbfSStefan Wahren skb_queue_len(&mses->mse102x.txq)); 102*2f207cbfSStefan Wahren 103*2f207cbfSStefan Wahren seq_printf(s, "IRQ : %d\n", 104*2f207cbfSStefan Wahren mses->spidev->irq); 105*2f207cbfSStefan Wahren 106*2f207cbfSStefan Wahren seq_printf(s, "SPI effective speed : %lu\n", 107*2f207cbfSStefan Wahren (unsigned long)mses->spi_xfer.effective_speed_hz); 108*2f207cbfSStefan Wahren seq_printf(s, "SPI mode : %x\n", 109*2f207cbfSStefan Wahren mses->spidev->mode); 110*2f207cbfSStefan Wahren 111*2f207cbfSStefan Wahren return 0; 112*2f207cbfSStefan Wahren } 113*2f207cbfSStefan Wahren DEFINE_SHOW_ATTRIBUTE(mse102x_info); 114*2f207cbfSStefan Wahren 115*2f207cbfSStefan Wahren static void mse102x_init_device_debugfs(struct mse102x_net_spi *mses) 116*2f207cbfSStefan Wahren { 117*2f207cbfSStefan Wahren mses->device_root = debugfs_create_dir(dev_name(&mses->mse102x.ndev->dev), 118*2f207cbfSStefan Wahren NULL); 119*2f207cbfSStefan Wahren 120*2f207cbfSStefan Wahren debugfs_create_file("info", S_IFREG | 0444, mses->device_root, mses, 121*2f207cbfSStefan Wahren &mse102x_info_fops); 122*2f207cbfSStefan Wahren } 123*2f207cbfSStefan Wahren 124*2f207cbfSStefan Wahren static void mse102x_remove_device_debugfs(struct mse102x_net_spi *mses) 125*2f207cbfSStefan Wahren { 126*2f207cbfSStefan Wahren debugfs_remove_recursive(mses->device_root); 127*2f207cbfSStefan Wahren } 128*2f207cbfSStefan Wahren 129*2f207cbfSStefan Wahren #else /* CONFIG_DEBUG_FS */ 130*2f207cbfSStefan Wahren 131*2f207cbfSStefan Wahren static void mse102x_init_device_debugfs(struct mse102x_net_spi *mses) 132*2f207cbfSStefan Wahren { 133*2f207cbfSStefan Wahren } 134*2f207cbfSStefan Wahren 135*2f207cbfSStefan Wahren static void mse102x_remove_device_debugfs(struct mse102x_net_spi *mses) 136*2f207cbfSStefan Wahren { 137*2f207cbfSStefan Wahren } 138*2f207cbfSStefan Wahren 139*2f207cbfSStefan Wahren #endif 140*2f207cbfSStefan Wahren 141*2f207cbfSStefan Wahren /* SPI register read/write calls. 142*2f207cbfSStefan Wahren * 143*2f207cbfSStefan Wahren * All these calls issue SPI transactions to access the chip's registers. They 144*2f207cbfSStefan Wahren * all require that the necessary lock is held to prevent accesses when the 145*2f207cbfSStefan Wahren * chip is busy transferring packet data. 146*2f207cbfSStefan Wahren */ 147*2f207cbfSStefan Wahren 148*2f207cbfSStefan Wahren static void mse102x_tx_cmd_spi(struct mse102x_net *mse, u16 cmd) 149*2f207cbfSStefan Wahren { 150*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 151*2f207cbfSStefan Wahren struct spi_transfer *xfer = &mses->spi_xfer; 152*2f207cbfSStefan Wahren struct spi_message *msg = &mses->spi_msg; 153*2f207cbfSStefan Wahren __be16 txb[2]; 154*2f207cbfSStefan Wahren int ret; 155*2f207cbfSStefan Wahren 156*2f207cbfSStefan Wahren txb[0] = cpu_to_be16(DET_CMD); 157*2f207cbfSStefan Wahren txb[1] = cpu_to_be16(cmd); 158*2f207cbfSStefan Wahren 159*2f207cbfSStefan Wahren xfer->tx_buf = txb; 160*2f207cbfSStefan Wahren xfer->rx_buf = NULL; 161*2f207cbfSStefan Wahren xfer->len = DET_CMD_LEN; 162*2f207cbfSStefan Wahren 163*2f207cbfSStefan Wahren ret = spi_sync(mses->spidev, msg); 164*2f207cbfSStefan Wahren if (ret < 0) { 165*2f207cbfSStefan Wahren netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n", 166*2f207cbfSStefan Wahren __func__, ret); 167*2f207cbfSStefan Wahren mse->stats.xfer_err++; 168*2f207cbfSStefan Wahren } 169*2f207cbfSStefan Wahren } 170*2f207cbfSStefan Wahren 171*2f207cbfSStefan Wahren static int mse102x_rx_cmd_spi(struct mse102x_net *mse, u8 *rxb) 172*2f207cbfSStefan Wahren { 173*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 174*2f207cbfSStefan Wahren struct spi_transfer *xfer = &mses->spi_xfer; 175*2f207cbfSStefan Wahren struct spi_message *msg = &mses->spi_msg; 176*2f207cbfSStefan Wahren __be16 *txb = (__be16 *)mse->txd; 177*2f207cbfSStefan Wahren __be16 *cmd = (__be16 *)mse->rxd; 178*2f207cbfSStefan Wahren u8 *trx = mse->rxd; 179*2f207cbfSStefan Wahren int ret; 180*2f207cbfSStefan Wahren 181*2f207cbfSStefan Wahren txb[0] = 0; 182*2f207cbfSStefan Wahren txb[1] = 0; 183*2f207cbfSStefan Wahren 184*2f207cbfSStefan Wahren xfer->tx_buf = txb; 185*2f207cbfSStefan Wahren xfer->rx_buf = trx; 186*2f207cbfSStefan Wahren xfer->len = DET_CMD_LEN; 187*2f207cbfSStefan Wahren 188*2f207cbfSStefan Wahren ret = spi_sync(mses->spidev, msg); 189*2f207cbfSStefan Wahren if (ret < 0) { 190*2f207cbfSStefan Wahren netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n", 191*2f207cbfSStefan Wahren __func__, ret); 192*2f207cbfSStefan Wahren mse->stats.xfer_err++; 193*2f207cbfSStefan Wahren } else if (*cmd != cpu_to_be16(DET_CMD)) { 194*2f207cbfSStefan Wahren net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n", 195*2f207cbfSStefan Wahren __func__, *cmd); 196*2f207cbfSStefan Wahren mse->stats.invalid_cmd++; 197*2f207cbfSStefan Wahren ret = -EIO; 198*2f207cbfSStefan Wahren } else { 199*2f207cbfSStefan Wahren memcpy(rxb, trx + 2, 2); 200*2f207cbfSStefan Wahren } 201*2f207cbfSStefan Wahren 202*2f207cbfSStefan Wahren return ret; 203*2f207cbfSStefan Wahren } 204*2f207cbfSStefan Wahren 205*2f207cbfSStefan Wahren static inline void mse102x_push_header(struct sk_buff *skb) 206*2f207cbfSStefan Wahren { 207*2f207cbfSStefan Wahren __be16 *header = skb_push(skb, DET_SOF_LEN); 208*2f207cbfSStefan Wahren 209*2f207cbfSStefan Wahren *header = cpu_to_be16(DET_SOF); 210*2f207cbfSStefan Wahren } 211*2f207cbfSStefan Wahren 212*2f207cbfSStefan Wahren static inline void mse102x_put_footer(struct sk_buff *skb) 213*2f207cbfSStefan Wahren { 214*2f207cbfSStefan Wahren __be16 *footer = skb_put(skb, DET_DFT_LEN); 215*2f207cbfSStefan Wahren 216*2f207cbfSStefan Wahren *footer = cpu_to_be16(DET_DFT); 217*2f207cbfSStefan Wahren } 218*2f207cbfSStefan Wahren 219*2f207cbfSStefan Wahren static int mse102x_tx_frame_spi(struct mse102x_net *mse, struct sk_buff *txp, 220*2f207cbfSStefan Wahren unsigned int pad) 221*2f207cbfSStefan Wahren { 222*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 223*2f207cbfSStefan Wahren struct spi_transfer *xfer = &mses->spi_xfer; 224*2f207cbfSStefan Wahren struct spi_message *msg = &mses->spi_msg; 225*2f207cbfSStefan Wahren struct sk_buff *tskb; 226*2f207cbfSStefan Wahren int ret; 227*2f207cbfSStefan Wahren 228*2f207cbfSStefan Wahren netif_dbg(mse, tx_queued, mse->ndev, "%s: skb %p, %d@%p\n", 229*2f207cbfSStefan Wahren __func__, txp, txp->len, txp->data); 230*2f207cbfSStefan Wahren 231*2f207cbfSStefan Wahren if ((skb_headroom(txp) < DET_SOF_LEN) || 232*2f207cbfSStefan Wahren (skb_tailroom(txp) < DET_DFT_LEN + pad)) { 233*2f207cbfSStefan Wahren tskb = skb_copy_expand(txp, DET_SOF_LEN, DET_DFT_LEN + pad, 234*2f207cbfSStefan Wahren GFP_KERNEL); 235*2f207cbfSStefan Wahren if (!tskb) 236*2f207cbfSStefan Wahren return -ENOMEM; 237*2f207cbfSStefan Wahren 238*2f207cbfSStefan Wahren dev_kfree_skb(txp); 239*2f207cbfSStefan Wahren txp = tskb; 240*2f207cbfSStefan Wahren } 241*2f207cbfSStefan Wahren 242*2f207cbfSStefan Wahren mse102x_push_header(txp); 243*2f207cbfSStefan Wahren 244*2f207cbfSStefan Wahren if (pad) 245*2f207cbfSStefan Wahren skb_put_zero(txp, pad); 246*2f207cbfSStefan Wahren 247*2f207cbfSStefan Wahren mse102x_put_footer(txp); 248*2f207cbfSStefan Wahren 249*2f207cbfSStefan Wahren xfer->tx_buf = txp->data; 250*2f207cbfSStefan Wahren xfer->rx_buf = NULL; 251*2f207cbfSStefan Wahren xfer->len = txp->len; 252*2f207cbfSStefan Wahren 253*2f207cbfSStefan Wahren ret = spi_sync(mses->spidev, msg); 254*2f207cbfSStefan Wahren if (ret < 0) { 255*2f207cbfSStefan Wahren netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n", 256*2f207cbfSStefan Wahren __func__, ret); 257*2f207cbfSStefan Wahren mse->stats.xfer_err++; 258*2f207cbfSStefan Wahren } 259*2f207cbfSStefan Wahren 260*2f207cbfSStefan Wahren return ret; 261*2f207cbfSStefan Wahren } 262*2f207cbfSStefan Wahren 263*2f207cbfSStefan Wahren static int mse102x_rx_frame_spi(struct mse102x_net *mse, u8 *buff, 264*2f207cbfSStefan Wahren unsigned int frame_len) 265*2f207cbfSStefan Wahren { 266*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 267*2f207cbfSStefan Wahren struct spi_transfer *xfer = &mses->spi_xfer; 268*2f207cbfSStefan Wahren struct spi_message *msg = &mses->spi_msg; 269*2f207cbfSStefan Wahren __be16 *sof = (__be16 *)buff; 270*2f207cbfSStefan Wahren __be16 *dft = (__be16 *)(buff + DET_SOF_LEN + frame_len); 271*2f207cbfSStefan Wahren int ret; 272*2f207cbfSStefan Wahren 273*2f207cbfSStefan Wahren xfer->rx_buf = buff; 274*2f207cbfSStefan Wahren xfer->tx_buf = NULL; 275*2f207cbfSStefan Wahren xfer->len = DET_SOF_LEN + frame_len + DET_DFT_LEN; 276*2f207cbfSStefan Wahren 277*2f207cbfSStefan Wahren ret = spi_sync(mses->spidev, msg); 278*2f207cbfSStefan Wahren if (ret < 0) { 279*2f207cbfSStefan Wahren netdev_err(mse->ndev, "%s: spi_sync() failed: %d\n", 280*2f207cbfSStefan Wahren __func__, ret); 281*2f207cbfSStefan Wahren mse->stats.xfer_err++; 282*2f207cbfSStefan Wahren } else if (*sof != cpu_to_be16(DET_SOF)) { 283*2f207cbfSStefan Wahren netdev_dbg(mse->ndev, "%s: SPI start of frame is invalid (0x%04x)\n", 284*2f207cbfSStefan Wahren __func__, *sof); 285*2f207cbfSStefan Wahren mse->stats.invalid_sof++; 286*2f207cbfSStefan Wahren ret = -EIO; 287*2f207cbfSStefan Wahren } else if (*dft != cpu_to_be16(DET_DFT)) { 288*2f207cbfSStefan Wahren netdev_dbg(mse->ndev, "%s: SPI frame tail is invalid (0x%04x)\n", 289*2f207cbfSStefan Wahren __func__, *dft); 290*2f207cbfSStefan Wahren mse->stats.invalid_dft++; 291*2f207cbfSStefan Wahren ret = -EIO; 292*2f207cbfSStefan Wahren } 293*2f207cbfSStefan Wahren 294*2f207cbfSStefan Wahren return ret; 295*2f207cbfSStefan Wahren } 296*2f207cbfSStefan Wahren 297*2f207cbfSStefan Wahren static void mse102x_dump_packet(const char *msg, int len, const char *data) 298*2f207cbfSStefan Wahren { 299*2f207cbfSStefan Wahren printk(KERN_DEBUG ": %s - packet len:%d\n", msg, len); 300*2f207cbfSStefan Wahren print_hex_dump(KERN_DEBUG, "pk data: ", DUMP_PREFIX_OFFSET, 16, 1, 301*2f207cbfSStefan Wahren data, len, true); 302*2f207cbfSStefan Wahren } 303*2f207cbfSStefan Wahren 304*2f207cbfSStefan Wahren static void mse102x_rx_pkt_spi(struct mse102x_net *mse) 305*2f207cbfSStefan Wahren { 306*2f207cbfSStefan Wahren struct sk_buff *skb; 307*2f207cbfSStefan Wahren unsigned int rxalign; 308*2f207cbfSStefan Wahren unsigned int rxlen; 309*2f207cbfSStefan Wahren __be16 rx = 0; 310*2f207cbfSStefan Wahren u16 cmd_resp; 311*2f207cbfSStefan Wahren u8 *rxpkt; 312*2f207cbfSStefan Wahren int ret; 313*2f207cbfSStefan Wahren 314*2f207cbfSStefan Wahren mse102x_tx_cmd_spi(mse, CMD_CTR); 315*2f207cbfSStefan Wahren ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx); 316*2f207cbfSStefan Wahren cmd_resp = be16_to_cpu(rx); 317*2f207cbfSStefan Wahren 318*2f207cbfSStefan Wahren if (ret || ((cmd_resp & CMD_MASK) != CMD_RTS)) { 319*2f207cbfSStefan Wahren usleep_range(50, 100); 320*2f207cbfSStefan Wahren 321*2f207cbfSStefan Wahren mse102x_tx_cmd_spi(mse, CMD_CTR); 322*2f207cbfSStefan Wahren ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx); 323*2f207cbfSStefan Wahren if (ret) 324*2f207cbfSStefan Wahren return; 325*2f207cbfSStefan Wahren 326*2f207cbfSStefan Wahren cmd_resp = be16_to_cpu(rx); 327*2f207cbfSStefan Wahren if ((cmd_resp & CMD_MASK) != CMD_RTS) { 328*2f207cbfSStefan Wahren net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n", 329*2f207cbfSStefan Wahren __func__, cmd_resp); 330*2f207cbfSStefan Wahren mse->stats.invalid_rts++; 331*2f207cbfSStefan Wahren return; 332*2f207cbfSStefan Wahren } 333*2f207cbfSStefan Wahren 334*2f207cbfSStefan Wahren net_dbg_ratelimited("%s: Unexpected response to first CMD\n", 335*2f207cbfSStefan Wahren __func__); 336*2f207cbfSStefan Wahren } 337*2f207cbfSStefan Wahren 338*2f207cbfSStefan Wahren rxlen = cmd_resp & LEN_MASK; 339*2f207cbfSStefan Wahren if (!rxlen) { 340*2f207cbfSStefan Wahren net_dbg_ratelimited("%s: No frame length defined\n", __func__); 341*2f207cbfSStefan Wahren mse->stats.invalid_len++; 342*2f207cbfSStefan Wahren return; 343*2f207cbfSStefan Wahren } 344*2f207cbfSStefan Wahren 345*2f207cbfSStefan Wahren rxalign = ALIGN(rxlen + DET_SOF_LEN + DET_DFT_LEN, 4); 346*2f207cbfSStefan Wahren skb = netdev_alloc_skb_ip_align(mse->ndev, rxalign); 347*2f207cbfSStefan Wahren if (!skb) 348*2f207cbfSStefan Wahren return; 349*2f207cbfSStefan Wahren 350*2f207cbfSStefan Wahren /* 2 bytes Start of frame (before ethernet header) 351*2f207cbfSStefan Wahren * 2 bytes Data frame tail (after ethernet frame) 352*2f207cbfSStefan Wahren * They are copied, but ignored. 353*2f207cbfSStefan Wahren */ 354*2f207cbfSStefan Wahren rxpkt = skb_put(skb, rxlen) - DET_SOF_LEN; 355*2f207cbfSStefan Wahren if (mse102x_rx_frame_spi(mse, rxpkt, rxlen)) { 356*2f207cbfSStefan Wahren mse->ndev->stats.rx_errors++; 357*2f207cbfSStefan Wahren dev_kfree_skb(skb); 358*2f207cbfSStefan Wahren return; 359*2f207cbfSStefan Wahren } 360*2f207cbfSStefan Wahren 361*2f207cbfSStefan Wahren if (netif_msg_pktdata(mse)) 362*2f207cbfSStefan Wahren mse102x_dump_packet(__func__, skb->len, skb->data); 363*2f207cbfSStefan Wahren 364*2f207cbfSStefan Wahren skb->protocol = eth_type_trans(skb, mse->ndev); 365*2f207cbfSStefan Wahren netif_rx_ni(skb); 366*2f207cbfSStefan Wahren 367*2f207cbfSStefan Wahren mse->ndev->stats.rx_packets++; 368*2f207cbfSStefan Wahren mse->ndev->stats.rx_bytes += rxlen; 369*2f207cbfSStefan Wahren } 370*2f207cbfSStefan Wahren 371*2f207cbfSStefan Wahren static int mse102x_tx_pkt_spi(struct mse102x_net *mse, struct sk_buff *txb, 372*2f207cbfSStefan Wahren unsigned long work_timeout) 373*2f207cbfSStefan Wahren { 374*2f207cbfSStefan Wahren unsigned int pad = 0; 375*2f207cbfSStefan Wahren __be16 rx = 0; 376*2f207cbfSStefan Wahren u16 cmd_resp; 377*2f207cbfSStefan Wahren int ret; 378*2f207cbfSStefan Wahren bool first = true; 379*2f207cbfSStefan Wahren 380*2f207cbfSStefan Wahren if (txb->len < 60) 381*2f207cbfSStefan Wahren pad = 60 - txb->len; 382*2f207cbfSStefan Wahren 383*2f207cbfSStefan Wahren while (1) { 384*2f207cbfSStefan Wahren mse102x_tx_cmd_spi(mse, CMD_RTS | (txb->len + pad)); 385*2f207cbfSStefan Wahren ret = mse102x_rx_cmd_spi(mse, (u8 *)&rx); 386*2f207cbfSStefan Wahren cmd_resp = be16_to_cpu(rx); 387*2f207cbfSStefan Wahren 388*2f207cbfSStefan Wahren if (!ret) { 389*2f207cbfSStefan Wahren /* ready to send frame ? */ 390*2f207cbfSStefan Wahren if (cmd_resp == CMD_CTR) 391*2f207cbfSStefan Wahren break; 392*2f207cbfSStefan Wahren 393*2f207cbfSStefan Wahren net_dbg_ratelimited("%s: Unexpected response (0x%04x)\n", 394*2f207cbfSStefan Wahren __func__, cmd_resp); 395*2f207cbfSStefan Wahren mse->stats.invalid_ctr++; 396*2f207cbfSStefan Wahren } 397*2f207cbfSStefan Wahren 398*2f207cbfSStefan Wahren /* It's not predictable how long / many retries it takes to 399*2f207cbfSStefan Wahren * send at least one packet, so TX timeouts are possible. 400*2f207cbfSStefan Wahren * That's the reason why the netdev watchdog is not used here. 401*2f207cbfSStefan Wahren */ 402*2f207cbfSStefan Wahren if (time_after(jiffies, work_timeout)) 403*2f207cbfSStefan Wahren return -ETIMEDOUT; 404*2f207cbfSStefan Wahren 405*2f207cbfSStefan Wahren if (first) { 406*2f207cbfSStefan Wahren /* throttle at first issue */ 407*2f207cbfSStefan Wahren netif_stop_queue(mse->ndev); 408*2f207cbfSStefan Wahren /* fast retry */ 409*2f207cbfSStefan Wahren usleep_range(50, 100); 410*2f207cbfSStefan Wahren first = false; 411*2f207cbfSStefan Wahren } else { 412*2f207cbfSStefan Wahren msleep(20); 413*2f207cbfSStefan Wahren } 414*2f207cbfSStefan Wahren }; 415*2f207cbfSStefan Wahren 416*2f207cbfSStefan Wahren ret = mse102x_tx_frame_spi(mse, txb, pad); 417*2f207cbfSStefan Wahren if (ret) 418*2f207cbfSStefan Wahren net_dbg_ratelimited("%s: Failed to send (%d), drop frame\n", 419*2f207cbfSStefan Wahren __func__, ret); 420*2f207cbfSStefan Wahren 421*2f207cbfSStefan Wahren return ret; 422*2f207cbfSStefan Wahren } 423*2f207cbfSStefan Wahren 424*2f207cbfSStefan Wahren #define TX_QUEUE_MAX 10 425*2f207cbfSStefan Wahren 426*2f207cbfSStefan Wahren static void mse102x_tx_work(struct work_struct *work) 427*2f207cbfSStefan Wahren { 428*2f207cbfSStefan Wahren /* Make sure timeout is sufficient to transfer TX_QUEUE_MAX frames */ 429*2f207cbfSStefan Wahren unsigned long work_timeout = jiffies + msecs_to_jiffies(1000); 430*2f207cbfSStefan Wahren struct mse102x_net_spi *mses; 431*2f207cbfSStefan Wahren struct mse102x_net *mse; 432*2f207cbfSStefan Wahren struct sk_buff *txb; 433*2f207cbfSStefan Wahren int ret = 0; 434*2f207cbfSStefan Wahren 435*2f207cbfSStefan Wahren mses = container_of(work, struct mse102x_net_spi, tx_work); 436*2f207cbfSStefan Wahren mse = &mses->mse102x; 437*2f207cbfSStefan Wahren 438*2f207cbfSStefan Wahren while ((txb = skb_dequeue(&mse->txq))) { 439*2f207cbfSStefan Wahren mutex_lock(&mses->lock); 440*2f207cbfSStefan Wahren ret = mse102x_tx_pkt_spi(mse, txb, work_timeout); 441*2f207cbfSStefan Wahren mutex_unlock(&mses->lock); 442*2f207cbfSStefan Wahren if (ret) { 443*2f207cbfSStefan Wahren mse->ndev->stats.tx_dropped++; 444*2f207cbfSStefan Wahren } else { 445*2f207cbfSStefan Wahren mse->ndev->stats.tx_bytes += txb->len; 446*2f207cbfSStefan Wahren mse->ndev->stats.tx_packets++; 447*2f207cbfSStefan Wahren } 448*2f207cbfSStefan Wahren 449*2f207cbfSStefan Wahren dev_kfree_skb(txb); 450*2f207cbfSStefan Wahren } 451*2f207cbfSStefan Wahren 452*2f207cbfSStefan Wahren if (ret == -ETIMEDOUT) { 453*2f207cbfSStefan Wahren if (netif_msg_timer(mse)) 454*2f207cbfSStefan Wahren netdev_err(mse->ndev, "tx work timeout\n"); 455*2f207cbfSStefan Wahren 456*2f207cbfSStefan Wahren mse->stats.tx_timeout++; 457*2f207cbfSStefan Wahren } 458*2f207cbfSStefan Wahren 459*2f207cbfSStefan Wahren netif_wake_queue(mse->ndev); 460*2f207cbfSStefan Wahren } 461*2f207cbfSStefan Wahren 462*2f207cbfSStefan Wahren static netdev_tx_t mse102x_start_xmit_spi(struct sk_buff *skb, 463*2f207cbfSStefan Wahren struct net_device *ndev) 464*2f207cbfSStefan Wahren { 465*2f207cbfSStefan Wahren struct mse102x_net *mse = netdev_priv(ndev); 466*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 467*2f207cbfSStefan Wahren 468*2f207cbfSStefan Wahren netif_dbg(mse, tx_queued, ndev, 469*2f207cbfSStefan Wahren "%s: skb %p, %d@%p\n", __func__, skb, skb->len, skb->data); 470*2f207cbfSStefan Wahren 471*2f207cbfSStefan Wahren skb_queue_tail(&mse->txq, skb); 472*2f207cbfSStefan Wahren 473*2f207cbfSStefan Wahren if (skb_queue_len(&mse->txq) >= TX_QUEUE_MAX) 474*2f207cbfSStefan Wahren netif_stop_queue(ndev); 475*2f207cbfSStefan Wahren 476*2f207cbfSStefan Wahren schedule_work(&mses->tx_work); 477*2f207cbfSStefan Wahren 478*2f207cbfSStefan Wahren return NETDEV_TX_OK; 479*2f207cbfSStefan Wahren } 480*2f207cbfSStefan Wahren 481*2f207cbfSStefan Wahren static void mse102x_init_mac(struct mse102x_net *mse, struct device_node *np) 482*2f207cbfSStefan Wahren { 483*2f207cbfSStefan Wahren struct net_device *ndev = mse->ndev; 484*2f207cbfSStefan Wahren int ret = of_get_ethdev_address(np, ndev); 485*2f207cbfSStefan Wahren 486*2f207cbfSStefan Wahren if (ret) { 487*2f207cbfSStefan Wahren eth_hw_addr_random(ndev); 488*2f207cbfSStefan Wahren netdev_err(ndev, "Using random MAC address: %pM\n", 489*2f207cbfSStefan Wahren ndev->dev_addr); 490*2f207cbfSStefan Wahren } 491*2f207cbfSStefan Wahren } 492*2f207cbfSStefan Wahren 493*2f207cbfSStefan Wahren /* Assumption: this is called for every incoming packet */ 494*2f207cbfSStefan Wahren static irqreturn_t mse102x_irq(int irq, void *_mse) 495*2f207cbfSStefan Wahren { 496*2f207cbfSStefan Wahren struct mse102x_net *mse = _mse; 497*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 498*2f207cbfSStefan Wahren 499*2f207cbfSStefan Wahren mutex_lock(&mses->lock); 500*2f207cbfSStefan Wahren mse102x_rx_pkt_spi(mse); 501*2f207cbfSStefan Wahren mutex_unlock(&mses->lock); 502*2f207cbfSStefan Wahren 503*2f207cbfSStefan Wahren return IRQ_HANDLED; 504*2f207cbfSStefan Wahren } 505*2f207cbfSStefan Wahren 506*2f207cbfSStefan Wahren static int mse102x_net_open(struct net_device *ndev) 507*2f207cbfSStefan Wahren { 508*2f207cbfSStefan Wahren struct mse102x_net *mse = netdev_priv(ndev); 509*2f207cbfSStefan Wahren int ret; 510*2f207cbfSStefan Wahren 511*2f207cbfSStefan Wahren ret = request_threaded_irq(ndev->irq, NULL, mse102x_irq, IRQF_ONESHOT, 512*2f207cbfSStefan Wahren ndev->name, mse); 513*2f207cbfSStefan Wahren if (ret < 0) { 514*2f207cbfSStefan Wahren netdev_err(ndev, "Failed to get irq: %d\n", ret); 515*2f207cbfSStefan Wahren return ret; 516*2f207cbfSStefan Wahren } 517*2f207cbfSStefan Wahren 518*2f207cbfSStefan Wahren netif_dbg(mse, ifup, ndev, "opening\n"); 519*2f207cbfSStefan Wahren 520*2f207cbfSStefan Wahren netif_start_queue(ndev); 521*2f207cbfSStefan Wahren 522*2f207cbfSStefan Wahren netif_carrier_on(ndev); 523*2f207cbfSStefan Wahren 524*2f207cbfSStefan Wahren netif_dbg(mse, ifup, ndev, "network device up\n"); 525*2f207cbfSStefan Wahren 526*2f207cbfSStefan Wahren return 0; 527*2f207cbfSStefan Wahren } 528*2f207cbfSStefan Wahren 529*2f207cbfSStefan Wahren static int mse102x_net_stop(struct net_device *ndev) 530*2f207cbfSStefan Wahren { 531*2f207cbfSStefan Wahren struct mse102x_net *mse = netdev_priv(ndev); 532*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 533*2f207cbfSStefan Wahren 534*2f207cbfSStefan Wahren netif_info(mse, ifdown, ndev, "shutting down\n"); 535*2f207cbfSStefan Wahren 536*2f207cbfSStefan Wahren netif_carrier_off(mse->ndev); 537*2f207cbfSStefan Wahren 538*2f207cbfSStefan Wahren /* stop any outstanding work */ 539*2f207cbfSStefan Wahren flush_work(&mses->tx_work); 540*2f207cbfSStefan Wahren 541*2f207cbfSStefan Wahren netif_stop_queue(ndev); 542*2f207cbfSStefan Wahren 543*2f207cbfSStefan Wahren skb_queue_purge(&mse->txq); 544*2f207cbfSStefan Wahren 545*2f207cbfSStefan Wahren free_irq(ndev->irq, mse); 546*2f207cbfSStefan Wahren 547*2f207cbfSStefan Wahren return 0; 548*2f207cbfSStefan Wahren } 549*2f207cbfSStefan Wahren 550*2f207cbfSStefan Wahren static const struct net_device_ops mse102x_netdev_ops = { 551*2f207cbfSStefan Wahren .ndo_open = mse102x_net_open, 552*2f207cbfSStefan Wahren .ndo_stop = mse102x_net_stop, 553*2f207cbfSStefan Wahren .ndo_start_xmit = mse102x_start_xmit_spi, 554*2f207cbfSStefan Wahren .ndo_set_mac_address = eth_mac_addr, 555*2f207cbfSStefan Wahren .ndo_validate_addr = eth_validate_addr, 556*2f207cbfSStefan Wahren }; 557*2f207cbfSStefan Wahren 558*2f207cbfSStefan Wahren /* ethtool support */ 559*2f207cbfSStefan Wahren 560*2f207cbfSStefan Wahren static void mse102x_get_drvinfo(struct net_device *ndev, 561*2f207cbfSStefan Wahren struct ethtool_drvinfo *di) 562*2f207cbfSStefan Wahren { 563*2f207cbfSStefan Wahren strscpy(di->driver, DRV_NAME, sizeof(di->driver)); 564*2f207cbfSStefan Wahren strscpy(di->bus_info, dev_name(ndev->dev.parent), sizeof(di->bus_info)); 565*2f207cbfSStefan Wahren } 566*2f207cbfSStefan Wahren 567*2f207cbfSStefan Wahren static u32 mse102x_get_msglevel(struct net_device *ndev) 568*2f207cbfSStefan Wahren { 569*2f207cbfSStefan Wahren struct mse102x_net *mse = netdev_priv(ndev); 570*2f207cbfSStefan Wahren 571*2f207cbfSStefan Wahren return mse->msg_enable; 572*2f207cbfSStefan Wahren } 573*2f207cbfSStefan Wahren 574*2f207cbfSStefan Wahren static void mse102x_set_msglevel(struct net_device *ndev, u32 to) 575*2f207cbfSStefan Wahren { 576*2f207cbfSStefan Wahren struct mse102x_net *mse = netdev_priv(ndev); 577*2f207cbfSStefan Wahren 578*2f207cbfSStefan Wahren mse->msg_enable = to; 579*2f207cbfSStefan Wahren } 580*2f207cbfSStefan Wahren 581*2f207cbfSStefan Wahren static void mse102x_get_ethtool_stats(struct net_device *ndev, 582*2f207cbfSStefan Wahren struct ethtool_stats *estats, u64 *data) 583*2f207cbfSStefan Wahren { 584*2f207cbfSStefan Wahren struct mse102x_net *mse = netdev_priv(ndev); 585*2f207cbfSStefan Wahren struct mse102x_stats *st = &mse->stats; 586*2f207cbfSStefan Wahren 587*2f207cbfSStefan Wahren memcpy(data, st, ARRAY_SIZE(mse102x_gstrings_stats) * sizeof(u64)); 588*2f207cbfSStefan Wahren } 589*2f207cbfSStefan Wahren 590*2f207cbfSStefan Wahren static void mse102x_get_strings(struct net_device *ndev, u32 stringset, u8 *buf) 591*2f207cbfSStefan Wahren { 592*2f207cbfSStefan Wahren switch (stringset) { 593*2f207cbfSStefan Wahren case ETH_SS_STATS: 594*2f207cbfSStefan Wahren memcpy(buf, &mse102x_gstrings_stats, 595*2f207cbfSStefan Wahren sizeof(mse102x_gstrings_stats)); 596*2f207cbfSStefan Wahren break; 597*2f207cbfSStefan Wahren default: 598*2f207cbfSStefan Wahren WARN_ON(1); 599*2f207cbfSStefan Wahren break; 600*2f207cbfSStefan Wahren } 601*2f207cbfSStefan Wahren } 602*2f207cbfSStefan Wahren 603*2f207cbfSStefan Wahren static int mse102x_get_sset_count(struct net_device *ndev, int sset) 604*2f207cbfSStefan Wahren { 605*2f207cbfSStefan Wahren switch (sset) { 606*2f207cbfSStefan Wahren case ETH_SS_STATS: 607*2f207cbfSStefan Wahren return ARRAY_SIZE(mse102x_gstrings_stats); 608*2f207cbfSStefan Wahren default: 609*2f207cbfSStefan Wahren return -EINVAL; 610*2f207cbfSStefan Wahren } 611*2f207cbfSStefan Wahren } 612*2f207cbfSStefan Wahren 613*2f207cbfSStefan Wahren static const struct ethtool_ops mse102x_ethtool_ops = { 614*2f207cbfSStefan Wahren .get_drvinfo = mse102x_get_drvinfo, 615*2f207cbfSStefan Wahren .get_link = ethtool_op_get_link, 616*2f207cbfSStefan Wahren .get_msglevel = mse102x_get_msglevel, 617*2f207cbfSStefan Wahren .set_msglevel = mse102x_set_msglevel, 618*2f207cbfSStefan Wahren .get_ethtool_stats = mse102x_get_ethtool_stats, 619*2f207cbfSStefan Wahren .get_strings = mse102x_get_strings, 620*2f207cbfSStefan Wahren .get_sset_count = mse102x_get_sset_count, 621*2f207cbfSStefan Wahren }; 622*2f207cbfSStefan Wahren 623*2f207cbfSStefan Wahren /* driver bus management functions */ 624*2f207cbfSStefan Wahren 625*2f207cbfSStefan Wahren #ifdef CONFIG_PM_SLEEP 626*2f207cbfSStefan Wahren 627*2f207cbfSStefan Wahren static int mse102x_suspend(struct device *dev) 628*2f207cbfSStefan Wahren { 629*2f207cbfSStefan Wahren struct mse102x_net *mse = dev_get_drvdata(dev); 630*2f207cbfSStefan Wahren struct net_device *ndev = mse->ndev; 631*2f207cbfSStefan Wahren 632*2f207cbfSStefan Wahren if (netif_running(ndev)) { 633*2f207cbfSStefan Wahren netif_device_detach(ndev); 634*2f207cbfSStefan Wahren mse102x_net_stop(ndev); 635*2f207cbfSStefan Wahren } 636*2f207cbfSStefan Wahren 637*2f207cbfSStefan Wahren return 0; 638*2f207cbfSStefan Wahren } 639*2f207cbfSStefan Wahren 640*2f207cbfSStefan Wahren static int mse102x_resume(struct device *dev) 641*2f207cbfSStefan Wahren { 642*2f207cbfSStefan Wahren struct mse102x_net *mse = dev_get_drvdata(dev); 643*2f207cbfSStefan Wahren struct net_device *ndev = mse->ndev; 644*2f207cbfSStefan Wahren 645*2f207cbfSStefan Wahren if (netif_running(ndev)) { 646*2f207cbfSStefan Wahren mse102x_net_open(ndev); 647*2f207cbfSStefan Wahren netif_device_attach(ndev); 648*2f207cbfSStefan Wahren } 649*2f207cbfSStefan Wahren 650*2f207cbfSStefan Wahren return 0; 651*2f207cbfSStefan Wahren } 652*2f207cbfSStefan Wahren #endif 653*2f207cbfSStefan Wahren 654*2f207cbfSStefan Wahren static SIMPLE_DEV_PM_OPS(mse102x_pm_ops, mse102x_suspend, mse102x_resume); 655*2f207cbfSStefan Wahren 656*2f207cbfSStefan Wahren static int mse102x_probe_spi(struct spi_device *spi) 657*2f207cbfSStefan Wahren { 658*2f207cbfSStefan Wahren struct device *dev = &spi->dev; 659*2f207cbfSStefan Wahren struct mse102x_net_spi *mses; 660*2f207cbfSStefan Wahren struct net_device *ndev; 661*2f207cbfSStefan Wahren struct mse102x_net *mse; 662*2f207cbfSStefan Wahren int ret; 663*2f207cbfSStefan Wahren 664*2f207cbfSStefan Wahren spi->bits_per_word = 8; 665*2f207cbfSStefan Wahren spi->mode |= SPI_MODE_3; 666*2f207cbfSStefan Wahren /* enforce minimum speed to ensure device functionality */ 667*2f207cbfSStefan Wahren spi->master->min_speed_hz = MIN_FREQ_HZ; 668*2f207cbfSStefan Wahren 669*2f207cbfSStefan Wahren if (!spi->max_speed_hz) 670*2f207cbfSStefan Wahren spi->max_speed_hz = MAX_FREQ_HZ; 671*2f207cbfSStefan Wahren 672*2f207cbfSStefan Wahren if (spi->max_speed_hz < MIN_FREQ_HZ || 673*2f207cbfSStefan Wahren spi->max_speed_hz > MAX_FREQ_HZ) { 674*2f207cbfSStefan Wahren dev_err(&spi->dev, "SPI max frequency out of range (min: %u, max: %u)\n", 675*2f207cbfSStefan Wahren MIN_FREQ_HZ, MAX_FREQ_HZ); 676*2f207cbfSStefan Wahren return -EINVAL; 677*2f207cbfSStefan Wahren } 678*2f207cbfSStefan Wahren 679*2f207cbfSStefan Wahren ret = spi_setup(spi); 680*2f207cbfSStefan Wahren if (ret < 0) { 681*2f207cbfSStefan Wahren dev_err(&spi->dev, "Unable to setup SPI device: %d\n", ret); 682*2f207cbfSStefan Wahren return ret; 683*2f207cbfSStefan Wahren } 684*2f207cbfSStefan Wahren 685*2f207cbfSStefan Wahren ndev = devm_alloc_etherdev(dev, sizeof(struct mse102x_net_spi)); 686*2f207cbfSStefan Wahren if (!ndev) 687*2f207cbfSStefan Wahren return -ENOMEM; 688*2f207cbfSStefan Wahren 689*2f207cbfSStefan Wahren ndev->needed_tailroom += ALIGN(DET_DFT_LEN, 4); 690*2f207cbfSStefan Wahren ndev->needed_headroom += ALIGN(DET_SOF_LEN, 4); 691*2f207cbfSStefan Wahren ndev->priv_flags &= ~IFF_TX_SKB_SHARING; 692*2f207cbfSStefan Wahren ndev->tx_queue_len = 100; 693*2f207cbfSStefan Wahren 694*2f207cbfSStefan Wahren mse = netdev_priv(ndev); 695*2f207cbfSStefan Wahren mses = to_mse102x_spi(mse); 696*2f207cbfSStefan Wahren 697*2f207cbfSStefan Wahren mses->spidev = spi; 698*2f207cbfSStefan Wahren mutex_init(&mses->lock); 699*2f207cbfSStefan Wahren INIT_WORK(&mses->tx_work, mse102x_tx_work); 700*2f207cbfSStefan Wahren 701*2f207cbfSStefan Wahren /* initialise pre-made spi transfer messages */ 702*2f207cbfSStefan Wahren spi_message_init(&mses->spi_msg); 703*2f207cbfSStefan Wahren spi_message_add_tail(&mses->spi_xfer, &mses->spi_msg); 704*2f207cbfSStefan Wahren 705*2f207cbfSStefan Wahren ndev->irq = spi->irq; 706*2f207cbfSStefan Wahren mse->ndev = ndev; 707*2f207cbfSStefan Wahren 708*2f207cbfSStefan Wahren /* set the default message enable */ 709*2f207cbfSStefan Wahren mse->msg_enable = netif_msg_init(-1, MSG_DEFAULT); 710*2f207cbfSStefan Wahren 711*2f207cbfSStefan Wahren skb_queue_head_init(&mse->txq); 712*2f207cbfSStefan Wahren 713*2f207cbfSStefan Wahren SET_NETDEV_DEV(ndev, dev); 714*2f207cbfSStefan Wahren 715*2f207cbfSStefan Wahren dev_set_drvdata(dev, mse); 716*2f207cbfSStefan Wahren 717*2f207cbfSStefan Wahren netif_carrier_off(mse->ndev); 718*2f207cbfSStefan Wahren ndev->netdev_ops = &mse102x_netdev_ops; 719*2f207cbfSStefan Wahren ndev->ethtool_ops = &mse102x_ethtool_ops; 720*2f207cbfSStefan Wahren 721*2f207cbfSStefan Wahren mse102x_init_mac(mse, dev->of_node); 722*2f207cbfSStefan Wahren 723*2f207cbfSStefan Wahren ret = register_netdev(ndev); 724*2f207cbfSStefan Wahren if (ret) { 725*2f207cbfSStefan Wahren dev_err(dev, "failed to register network device: %d\n", ret); 726*2f207cbfSStefan Wahren return ret; 727*2f207cbfSStefan Wahren } 728*2f207cbfSStefan Wahren 729*2f207cbfSStefan Wahren mse102x_init_device_debugfs(mses); 730*2f207cbfSStefan Wahren 731*2f207cbfSStefan Wahren return 0; 732*2f207cbfSStefan Wahren } 733*2f207cbfSStefan Wahren 734*2f207cbfSStefan Wahren static int mse102x_remove_spi(struct spi_device *spi) 735*2f207cbfSStefan Wahren { 736*2f207cbfSStefan Wahren struct mse102x_net *mse = dev_get_drvdata(&spi->dev); 737*2f207cbfSStefan Wahren struct mse102x_net_spi *mses = to_mse102x_spi(mse); 738*2f207cbfSStefan Wahren 739*2f207cbfSStefan Wahren if (netif_msg_drv(mse)) 740*2f207cbfSStefan Wahren dev_info(&spi->dev, "remove\n"); 741*2f207cbfSStefan Wahren 742*2f207cbfSStefan Wahren mse102x_remove_device_debugfs(mses); 743*2f207cbfSStefan Wahren unregister_netdev(mse->ndev); 744*2f207cbfSStefan Wahren 745*2f207cbfSStefan Wahren return 0; 746*2f207cbfSStefan Wahren } 747*2f207cbfSStefan Wahren 748*2f207cbfSStefan Wahren static const struct of_device_id mse102x_match_table[] = { 749*2f207cbfSStefan Wahren { .compatible = "vertexcom,mse1021" }, 750*2f207cbfSStefan Wahren { .compatible = "vertexcom,mse1022" }, 751*2f207cbfSStefan Wahren { } 752*2f207cbfSStefan Wahren }; 753*2f207cbfSStefan Wahren MODULE_DEVICE_TABLE(of, mse102x_match_table); 754*2f207cbfSStefan Wahren 755*2f207cbfSStefan Wahren static struct spi_driver mse102x_driver = { 756*2f207cbfSStefan Wahren .driver = { 757*2f207cbfSStefan Wahren .name = DRV_NAME, 758*2f207cbfSStefan Wahren .of_match_table = mse102x_match_table, 759*2f207cbfSStefan Wahren .pm = &mse102x_pm_ops, 760*2f207cbfSStefan Wahren }, 761*2f207cbfSStefan Wahren .probe = mse102x_probe_spi, 762*2f207cbfSStefan Wahren .remove = mse102x_remove_spi, 763*2f207cbfSStefan Wahren }; 764*2f207cbfSStefan Wahren module_spi_driver(mse102x_driver); 765*2f207cbfSStefan Wahren 766*2f207cbfSStefan Wahren MODULE_DESCRIPTION("MSE102x Network driver"); 767*2f207cbfSStefan Wahren MODULE_AUTHOR("Stefan Wahren <stefan.wahren@in-tech.com>"); 768*2f207cbfSStefan Wahren MODULE_LICENSE("GPL"); 769*2f207cbfSStefan Wahren MODULE_ALIAS("spi:" DRV_NAME); 770