Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 630cf097 authored by Akinobu Mita's avatar Akinobu Mita Committed by David S. Miller
Browse files

net: w5100: support SPI interface mode



This adds new w5100-spi driver which shares the bus interface
independent code with existing w5100 driver.

Signed-off-by: default avatarAkinobu Mita <akinobu.mita@gmail.com>
Cc: Mike Sinkovsky <msink@permonline.ru>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bf2c6b90
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -69,4 +69,18 @@ config WIZNET_BUS_ANY
	  Performance may decrease compared to explicitly selected bus mode.
endchoice

config WIZNET_W5100_SPI
	tristate "WIZnet W5100 Ethernet support for SPI mode"
	depends on WIZNET_BUS_ANY
	depends on SPI
	---help---
	  In SPI mode host system accesses registers using SPI protocol
	  (mode 0) on the SPI bus.

	  Performance decreases compared to other bus interface mode.
	  In W5100 SPI mode, burst READ/WRITE processing are not provided.

	  To compile this driver as a module, choose M here: the module
	  will be called w5100-spi.

endif # NET_VENDOR_WIZNET
+1 −0
Original line number Diff line number Diff line
obj-$(CONFIG_WIZNET_W5100) += w5100.o
obj-$(CONFIG_WIZNET_W5100_SPI) += w5100-spi.o
obj-$(CONFIG_WIZNET_W5300) += w5300.o
+136 −0
Original line number Diff line number Diff line
/*
 * Ethernet driver for the WIZnet W5100 chip.
 *
 * Copyright (C) 2016 Akinobu Mita <akinobu.mita@gmail.com>
 *
 * Licensed under the GPL-2 or later.
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/spi/spi.h>

#include "w5100.h"

#define W5100_SPI_WRITE_OPCODE 0xf0
#define W5100_SPI_READ_OPCODE 0x0f

static int w5100_spi_read(struct net_device *ndev, u16 addr)
{
	struct spi_device *spi = to_spi_device(ndev->dev.parent);
	u8 cmd[3] = { W5100_SPI_READ_OPCODE, addr >> 8, addr & 0xff };
	u8 data;
	int ret;

	ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, 1);

	return ret ? ret : data;
}

static int w5100_spi_write(struct net_device *ndev, u16 addr, u8 data)
{
	struct spi_device *spi = to_spi_device(ndev->dev.parent);
	u8 cmd[4] = { W5100_SPI_WRITE_OPCODE, addr >> 8, addr & 0xff, data};

	return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);
}

static int w5100_spi_read16(struct net_device *ndev, u16 addr)
{
	u16 data;
	int ret;

	ret = w5100_spi_read(ndev, addr);
	if (ret < 0)
		return ret;
	data = ret << 8;
	ret = w5100_spi_read(ndev, addr + 1);

	return ret < 0 ? ret : data | ret;
}

static int w5100_spi_write16(struct net_device *ndev, u16 addr, u16 data)
{
	int ret;

	ret = w5100_spi_write(ndev, addr, data >> 8);
	if (ret)
		return ret;

	return w5100_spi_write(ndev, addr + 1, data & 0xff);
}

static int w5100_spi_readbulk(struct net_device *ndev, u16 addr, u8 *buf,
			      int len)
{
	int i;

	for (i = 0; i < len; i++) {
		int ret = w5100_spi_read(ndev, addr + i);

		if (ret < 0)
			return ret;
		buf[i] = ret;
	}

	return 0;
}

static int w5100_spi_writebulk(struct net_device *ndev, u16 addr, const u8 *buf,
			       int len)
{
	int i;

	for (i = 0; i < len; i++) {
		int ret = w5100_spi_write(ndev, addr + i, buf[i]);

		if (ret)
			return ret;
	}

	return 0;
}

static const struct w5100_ops w5100_spi_ops = {
	.may_sleep = true,
	.read = w5100_spi_read,
	.write = w5100_spi_write,
	.read16 = w5100_spi_read16,
	.write16 = w5100_spi_write16,
	.readbulk = w5100_spi_readbulk,
	.writebulk = w5100_spi_writebulk,
};

static int w5100_spi_probe(struct spi_device *spi)
{
	return w5100_probe(&spi->dev, &w5100_spi_ops, 0, NULL, spi->irq,
			   -EINVAL);
}

static int w5100_spi_remove(struct spi_device *spi)
{
	return w5100_remove(&spi->dev);
}

static const struct spi_device_id w5100_spi_ids[] = {
	{ "w5100", 0 },
	{}
};
MODULE_DEVICE_TABLE(spi, w5100_spi_ids);

static struct spi_driver w5100_spi_driver = {
	.driver		= {
		.name	= "w5100",
		.pm	= &w5100_pm_ops,
	},
	.probe		= w5100_spi_probe,
	.remove		= w5100_spi_remove,
	.id_table	= w5100_spi_ids,
};
module_spi_driver(w5100_spi_driver);

MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver for SPI mode");
MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
MODULE_LICENSE("GPL");