brintos

brintos / linux-shallow public Read only

0
0
Text · 10.8 KiB · 990a3cc Raw
484 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Ethernet driver for the WIZnet W5100/W5200/W5500 chip.4 *5 * Copyright (C) 2016 Akinobu Mita <akinobu.mita@gmail.com>6 *7 * Datasheet:8 * http://www.wiznet.co.kr/wp-content/uploads/wiznethome/Chip/W5100/Document/W5100_Datasheet_v1.2.6.pdf9 * http://wiznethome.cafe24.com/wp-content/uploads/wiznethome/Chip/W5200/Documents/W5200_DS_V140E.pdf10 * http://wizwiki.net/wiki/lib/exe/fetch.php?media=products:w5500:w5500_ds_v106e_141230.pdf11 */12 13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/delay.h>16#include <linux/netdevice.h>17#include <linux/of.h>18#include <linux/of_net.h>19#include <linux/spi/spi.h>20 21#include "w5100.h"22 23#define W5100_SPI_WRITE_OPCODE 0xf024#define W5100_SPI_READ_OPCODE 0x0f25 26static int w5100_spi_read(struct net_device *ndev, u32 addr)27{28	struct spi_device *spi = to_spi_device(ndev->dev.parent);29	u8 cmd[3] = { W5100_SPI_READ_OPCODE, addr >> 8, addr & 0xff };30	u8 data;31	int ret;32 33	ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, 1);34 35	return ret ? ret : data;36}37 38static int w5100_spi_write(struct net_device *ndev, u32 addr, u8 data)39{40	struct spi_device *spi = to_spi_device(ndev->dev.parent);41	u8 cmd[4] = { W5100_SPI_WRITE_OPCODE, addr >> 8, addr & 0xff, data};42 43	return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);44}45 46static int w5100_spi_read16(struct net_device *ndev, u32 addr)47{48	u16 data;49	int ret;50 51	ret = w5100_spi_read(ndev, addr);52	if (ret < 0)53		return ret;54	data = ret << 8;55	ret = w5100_spi_read(ndev, addr + 1);56 57	return ret < 0 ? ret : data | ret;58}59 60static int w5100_spi_write16(struct net_device *ndev, u32 addr, u16 data)61{62	int ret;63 64	ret = w5100_spi_write(ndev, addr, data >> 8);65	if (ret)66		return ret;67 68	return w5100_spi_write(ndev, addr + 1, data & 0xff);69}70 71static int w5100_spi_readbulk(struct net_device *ndev, u32 addr, u8 *buf,72			      int len)73{74	int i;75 76	for (i = 0; i < len; i++) {77		int ret = w5100_spi_read(ndev, addr + i);78 79		if (ret < 0)80			return ret;81		buf[i] = ret;82	}83 84	return 0;85}86 87static int w5100_spi_writebulk(struct net_device *ndev, u32 addr, const u8 *buf,88			       int len)89{90	int i;91 92	for (i = 0; i < len; i++) {93		int ret = w5100_spi_write(ndev, addr + i, buf[i]);94 95		if (ret)96			return ret;97	}98 99	return 0;100}101 102static const struct w5100_ops w5100_spi_ops = {103	.may_sleep = true,104	.chip_id = W5100,105	.read = w5100_spi_read,106	.write = w5100_spi_write,107	.read16 = w5100_spi_read16,108	.write16 = w5100_spi_write16,109	.readbulk = w5100_spi_readbulk,110	.writebulk = w5100_spi_writebulk,111};112 113#define W5200_SPI_WRITE_OPCODE 0x80114 115struct w5200_spi_priv {116	/* Serialize access to cmd_buf */117	struct mutex cmd_lock;118 119	/* DMA (thus cache coherency maintenance) requires the120	 * transfer buffers to live in their own cache lines.121	 */122	u8 cmd_buf[4] ____cacheline_aligned;123};124 125static struct w5200_spi_priv *w5200_spi_priv(struct net_device *ndev)126{127	return w5100_ops_priv(ndev);128}129 130static int w5200_spi_init(struct net_device *ndev)131{132	struct w5200_spi_priv *spi_priv = w5200_spi_priv(ndev);133 134	mutex_init(&spi_priv->cmd_lock);135 136	return 0;137}138 139static int w5200_spi_read(struct net_device *ndev, u32 addr)140{141	struct spi_device *spi = to_spi_device(ndev->dev.parent);142	u8 cmd[4] = { addr >> 8, addr & 0xff, 0, 1 };143	u8 data;144	int ret;145 146	ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, 1);147 148	return ret ? ret : data;149}150 151static int w5200_spi_write(struct net_device *ndev, u32 addr, u8 data)152{153	struct spi_device *spi = to_spi_device(ndev->dev.parent);154	u8 cmd[5] = { addr >> 8, addr & 0xff, W5200_SPI_WRITE_OPCODE, 1, data };155 156	return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);157}158 159static int w5200_spi_read16(struct net_device *ndev, u32 addr)160{161	struct spi_device *spi = to_spi_device(ndev->dev.parent);162	u8 cmd[4] = { addr >> 8, addr & 0xff, 0, 2 };163	__be16 data;164	int ret;165 166	ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, sizeof(data));167 168	return ret ? ret : be16_to_cpu(data);169}170 171static int w5200_spi_write16(struct net_device *ndev, u32 addr, u16 data)172{173	struct spi_device *spi = to_spi_device(ndev->dev.parent);174	u8 cmd[6] = {175		addr >> 8, addr & 0xff,176		W5200_SPI_WRITE_OPCODE, 2,177		data >> 8, data & 0xff178	};179 180	return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);181}182 183static int w5200_spi_readbulk(struct net_device *ndev, u32 addr, u8 *buf,184			      int len)185{186	struct spi_device *spi = to_spi_device(ndev->dev.parent);187	struct w5200_spi_priv *spi_priv = w5200_spi_priv(ndev);188	struct spi_transfer xfer[] = {189		{190			.tx_buf = spi_priv->cmd_buf,191			.len = sizeof(spi_priv->cmd_buf),192		},193		{194			.rx_buf = buf,195			.len = len,196		},197	};198	int ret;199 200	mutex_lock(&spi_priv->cmd_lock);201 202	spi_priv->cmd_buf[0] = addr >> 8;203	spi_priv->cmd_buf[1] = addr;204	spi_priv->cmd_buf[2] = len >> 8;205	spi_priv->cmd_buf[3] = len;206	ret = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));207 208	mutex_unlock(&spi_priv->cmd_lock);209 210	return ret;211}212 213static int w5200_spi_writebulk(struct net_device *ndev, u32 addr, const u8 *buf,214			       int len)215{216	struct spi_device *spi = to_spi_device(ndev->dev.parent);217	struct w5200_spi_priv *spi_priv = w5200_spi_priv(ndev);218	struct spi_transfer xfer[] = {219		{220			.tx_buf = spi_priv->cmd_buf,221			.len = sizeof(spi_priv->cmd_buf),222		},223		{224			.tx_buf = buf,225			.len = len,226		},227	};228	int ret;229 230	mutex_lock(&spi_priv->cmd_lock);231 232	spi_priv->cmd_buf[0] = addr >> 8;233	spi_priv->cmd_buf[1] = addr;234	spi_priv->cmd_buf[2] = W5200_SPI_WRITE_OPCODE | (len >> 8);235	spi_priv->cmd_buf[3] = len;236	ret = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));237 238	mutex_unlock(&spi_priv->cmd_lock);239 240	return ret;241}242 243static const struct w5100_ops w5200_ops = {244	.may_sleep = true,245	.chip_id = W5200,246	.read = w5200_spi_read,247	.write = w5200_spi_write,248	.read16 = w5200_spi_read16,249	.write16 = w5200_spi_write16,250	.readbulk = w5200_spi_readbulk,251	.writebulk = w5200_spi_writebulk,252	.init = w5200_spi_init,253};254 255#define W5500_SPI_BLOCK_SELECT(addr) (((addr) >> 16) & 0x1f)256#define W5500_SPI_READ_CONTROL(addr) (W5500_SPI_BLOCK_SELECT(addr) << 3)257#define W5500_SPI_WRITE_CONTROL(addr)	\258	((W5500_SPI_BLOCK_SELECT(addr) << 3) | BIT(2))259 260struct w5500_spi_priv {261	/* Serialize access to cmd_buf */262	struct mutex cmd_lock;263 264	/* DMA (thus cache coherency maintenance) requires the265	 * transfer buffers to live in their own cache lines.266	 */267	u8 cmd_buf[3] ____cacheline_aligned;268};269 270static struct w5500_spi_priv *w5500_spi_priv(struct net_device *ndev)271{272	return w5100_ops_priv(ndev);273}274 275static int w5500_spi_init(struct net_device *ndev)276{277	struct w5500_spi_priv *spi_priv = w5500_spi_priv(ndev);278 279	mutex_init(&spi_priv->cmd_lock);280 281	return 0;282}283 284static int w5500_spi_read(struct net_device *ndev, u32 addr)285{286	struct spi_device *spi = to_spi_device(ndev->dev.parent);287	u8 cmd[3] = {288		addr >> 8,289		addr,290		W5500_SPI_READ_CONTROL(addr)291	};292	u8 data;293	int ret;294 295	ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, 1);296 297	return ret ? ret : data;298}299 300static int w5500_spi_write(struct net_device *ndev, u32 addr, u8 data)301{302	struct spi_device *spi = to_spi_device(ndev->dev.parent);303	u8 cmd[4] = {304		addr >> 8,305		addr,306		W5500_SPI_WRITE_CONTROL(addr),307		data308	};309 310	return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);311}312 313static int w5500_spi_read16(struct net_device *ndev, u32 addr)314{315	struct spi_device *spi = to_spi_device(ndev->dev.parent);316	u8 cmd[3] = {317		addr >> 8,318		addr,319		W5500_SPI_READ_CONTROL(addr)320	};321	__be16 data;322	int ret;323 324	ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, sizeof(data));325 326	return ret ? ret : be16_to_cpu(data);327}328 329static int w5500_spi_write16(struct net_device *ndev, u32 addr, u16 data)330{331	struct spi_device *spi = to_spi_device(ndev->dev.parent);332	u8 cmd[5] = {333		addr >> 8,334		addr,335		W5500_SPI_WRITE_CONTROL(addr),336		data >> 8,337		data338	};339 340	return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);341}342 343static int w5500_spi_readbulk(struct net_device *ndev, u32 addr, u8 *buf,344			      int len)345{346	struct spi_device *spi = to_spi_device(ndev->dev.parent);347	struct w5500_spi_priv *spi_priv = w5500_spi_priv(ndev);348	struct spi_transfer xfer[] = {349		{350			.tx_buf = spi_priv->cmd_buf,351			.len = sizeof(spi_priv->cmd_buf),352		},353		{354			.rx_buf = buf,355			.len = len,356		},357	};358	int ret;359 360	mutex_lock(&spi_priv->cmd_lock);361 362	spi_priv->cmd_buf[0] = addr >> 8;363	spi_priv->cmd_buf[1] = addr;364	spi_priv->cmd_buf[2] = W5500_SPI_READ_CONTROL(addr);365	ret = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));366 367	mutex_unlock(&spi_priv->cmd_lock);368 369	return ret;370}371 372static int w5500_spi_writebulk(struct net_device *ndev, u32 addr, const u8 *buf,373			       int len)374{375	struct spi_device *spi = to_spi_device(ndev->dev.parent);376	struct w5500_spi_priv *spi_priv = w5500_spi_priv(ndev);377	struct spi_transfer xfer[] = {378		{379			.tx_buf = spi_priv->cmd_buf,380			.len = sizeof(spi_priv->cmd_buf),381		},382		{383			.tx_buf = buf,384			.len = len,385		},386	};387	int ret;388 389	mutex_lock(&spi_priv->cmd_lock);390 391	spi_priv->cmd_buf[0] = addr >> 8;392	spi_priv->cmd_buf[1] = addr;393	spi_priv->cmd_buf[2] = W5500_SPI_WRITE_CONTROL(addr);394	ret = spi_sync_transfer(spi, xfer, ARRAY_SIZE(xfer));395 396	mutex_unlock(&spi_priv->cmd_lock);397 398	return ret;399}400 401static const struct w5100_ops w5500_ops = {402	.may_sleep = true,403	.chip_id = W5500,404	.read = w5500_spi_read,405	.write = w5500_spi_write,406	.read16 = w5500_spi_read16,407	.write16 = w5500_spi_write16,408	.readbulk = w5500_spi_readbulk,409	.writebulk = w5500_spi_writebulk,410	.init = w5500_spi_init,411};412 413static const struct of_device_id w5100_of_match[] = {414	{ .compatible = "wiznet,w5100", .data = (const void*)W5100, },415	{ .compatible = "wiznet,w5200", .data = (const void*)W5200, },416	{ .compatible = "wiznet,w5500", .data = (const void*)W5500, },417	{ },418};419MODULE_DEVICE_TABLE(of, w5100_of_match);420 421static int w5100_spi_probe(struct spi_device *spi)422{423	const struct w5100_ops *ops;424	kernel_ulong_t driver_data;425	const void *mac = NULL;426	u8 tmpmac[ETH_ALEN];427	int priv_size;428	int ret;429 430	ret = of_get_mac_address(spi->dev.of_node, tmpmac);431	if (!ret)432		mac = tmpmac;433 434	driver_data = (uintptr_t)spi_get_device_match_data(spi);435 436	switch (driver_data) {437	case W5100:438		ops = &w5100_spi_ops;439		priv_size = 0;440		break;441	case W5200:442		ops = &w5200_ops;443		priv_size = sizeof(struct w5200_spi_priv);444		break;445	case W5500:446		ops = &w5500_ops;447		priv_size = sizeof(struct w5500_spi_priv);448		break;449	default:450		return -EINVAL;451	}452 453	return w5100_probe(&spi->dev, ops, priv_size, mac, spi->irq, -EINVAL);454}455 456static void w5100_spi_remove(struct spi_device *spi)457{458	w5100_remove(&spi->dev);459}460 461static const struct spi_device_id w5100_spi_ids[] = {462	{ "w5100", W5100 },463	{ "w5200", W5200 },464	{ "w5500", W5500 },465	{}466};467MODULE_DEVICE_TABLE(spi, w5100_spi_ids);468 469static struct spi_driver w5100_spi_driver = {470	.driver		= {471		.name	= "w5100",472		.pm	= &w5100_pm_ops,473		.of_match_table = w5100_of_match,474	},475	.probe		= w5100_spi_probe,476	.remove		= w5100_spi_remove,477	.id_table	= w5100_spi_ids,478};479module_spi_driver(w5100_spi_driver);480 481MODULE_DESCRIPTION("WIZnet W5100/W5200/W5500 Ethernet driver for SPI mode");482MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");483MODULE_LICENSE("GPL");484