/*
* Ethernet driver for the WIZnet W5100 chip.
*
* Copyright (C) 2006-2008 WIZnet Co.,Ltd.
* Copyright (C) 2012 Mike Sinkovsky <msink@permonline.ru>
*
* Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kconfig.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/platform_data/wiznet.h>
#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include "w5100.h"
#define DRV_NAME "w5100"
#define DRV_VERSION "2012-04-04"
MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver v"DRV_VERSION);
MODULE_AUTHOR("Mike Sinkovsky <msink@permonline.ru>");
MODULE_ALIAS("platform:"DRV_NAME);
MODULE_LICENSE("GPL");
/*
* Registers
*/
#define W5100_COMMON_REGS 0x0000
#define W5100_MR 0x0000 /* Mode Register */
#define MR_RST 0x80 /* S/W reset */
#define MR_PB 0x10 /* Ping block */
#define MR_AI 0x02 /* Address Auto-Increment */
#define MR_IND 0x01 /* Indirect mode */
#define W5100_SHAR 0x0009 /* Source MAC address */
#define W5100_IR 0x0015 /* Interrupt Register */
#define W5100_IMR 0x0016 /* Interrupt Mask Register */
#define IR_S0 0x01 /* S0 interrupt */
#define W5100_RTR 0x0017 /* Retry Time-value Register */
#define RTR_DEFAULT 2000 /* =0x07d0 (2000) */
#define W5100_RMSR 0x001a /* Receive Memory Size */
#define W5100_TMSR 0x001b /* Transmit Memory Size */
#define W5100_COMMON_REGS_LEN 0x0040
#define W5100_S0_REGS 0x0400
#define W5100_S0_MR 0x0400 /* S0 Mode Register */
#define S0_MR_MACRAW 0x04 /* MAC RAW mode (promiscuous) */
#define S0_MR_MACRAW_MF 0x44 /* MAC RAW mode (filtered) */
#define W5100_S0_CR 0x0401 /* S0 Command Register */
#define S0_CR_OPEN 0x01 /* OPEN command */
#define S0_CR_CLOSE 0x10 /* CLOSE command */
#define S0_CR_SEND 0x20 /* SEND command */
#define S0_CR_RECV 0x40 /* RECV command */
#define W5100_S0_IR 0x0402 /* S0 Interrupt Register */
#define S0_IR_SENDOK 0x10 /* complete sending */
#define S0_IR_RECV 0x04 /* receiving data */
#define W5100_S0_SR 0x0403 /* S0 Status Register */
#define S0_SR_MACRAW 0x42 /* mac raw mode */
#define W5100_S0_TX_FSR 0x0420 /* S0 Transmit free memory size */
#define W5100_S0_TX_RD 0x0422 /* S0 Transmit memory read pointer */
#define W5100_S0_TX_WR 0x0424 /* S0 Transmit memory write pointer */
#define W5100_S0_RX_RSR 0x0426 /* S0 Receive free memory size */
#define W5100_S0_RX_RD 0x0428 /* S0 Receive memory read pointer */
#define W5100_S0_REGS_LEN 0x0040
#define W5100_TX_MEM_START 0x4000
#define W5100_TX_MEM_SIZE 0x2000
#define W5100_RX_MEM_START 0x6000
#define W5100_RX_MEM_SIZE 0x2000
/*
* Device driver private data structure
*/
struct w5100_priv {
const struct w5100_ops *ops;
int irq;
int link_irq;
int link_gpio;
struct napi_struct napi;
struct net_device *ndev;
bool promisc;
u32 msg_enable;
struct workqueue_struct *xfer_wq;
struct work_struct rx_work;
struct sk_buff *tx_skb;
struct work_struct tx_work;
struct work_struct setrx_work;
struct work_struct restart_work;
};
/************************************************************************
*
* Lowlevel I/O functions
*
***********************************************************************/
struct w5100_mmio_priv {
void __iomem *base;
/* Serialize access in indirect address mode */
spinlock_t reg_lock;
};
static inline struct w5100_mmio_priv *w5100_mmio_priv(struct net_device *dev)
{
return w5100_ops_priv(dev);
}
static inline void __iomem *w5100_mmio(struct net_device *ndev)
{
struct w5100_mmio_priv *mmio_priv = w5100_mmio_priv(ndev);
return mmio_priv->base;
}
/*
* In direct address mode host system can directly access W5100 registers
* after mapping to Memory-Mapped I/O space.
*
* 0x8000 bytes are required for memory space.
*/
static inline int w5100_read_direct(struct net_device *ndev, u16 addr)
{
return ioread8(w5100_mmio(ndev) + (addr << CONFIG_WIZNET_BUS_SHIFT));
}
static inline int __w5100_write_direct(struct net_device *ndev, u16 addr,
u8 data)
{
iowrite8(data, w5100_mmio(ndev) + (addr << CONFIG_WIZNET_BUS_SHIFT));
return 0;
}
static inline int w5100_write_direct(struct net_device *ndev, u16 addr, u8 data)
{
__w5100_write_direct(ndev, addr, data);
mmiowb();
return 0;
}
static int w5100_read16_direct(struct net_device *ndev, u16 addr)
{
u16 data;
data = w5100_read_direct(ndev, addr) << 8;
data |= w5100_read_direct(ndev, addr + 1);
return data;
}
static int w5100_write16_direct(struct net_device *ndev, u16 addr, u16 data)
{
__w5100_write_direct(ndev, addr,