blob: 32f406cfce4b7ef427145b3818ac929e5214982e [file] [log] [blame]
Akinobu Mita630cf092016-04-15 00:11:32 +09001/*
2 * Ethernet driver for the WIZnet W5100 chip.
3 *
4 * Copyright (C) 2016 Akinobu Mita <akinobu.mita@gmail.com>
5 *
6 * Licensed under the GPL-2 or later.
7 */
8
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/delay.h>
12#include <linux/netdevice.h>
13#include <linux/spi/spi.h>
14
15#include "w5100.h"
16
17#define W5100_SPI_WRITE_OPCODE 0xf0
18#define W5100_SPI_READ_OPCODE 0x0f
19
20static int w5100_spi_read(struct net_device *ndev, u16 addr)
21{
22 struct spi_device *spi = to_spi_device(ndev->dev.parent);
23 u8 cmd[3] = { W5100_SPI_READ_OPCODE, addr >> 8, addr & 0xff };
24 u8 data;
25 int ret;
26
27 ret = spi_write_then_read(spi, cmd, sizeof(cmd), &data, 1);
28
29 return ret ? ret : data;
30}
31
32static int w5100_spi_write(struct net_device *ndev, u16 addr, u8 data)
33{
34 struct spi_device *spi = to_spi_device(ndev->dev.parent);
35 u8 cmd[4] = { W5100_SPI_WRITE_OPCODE, addr >> 8, addr & 0xff, data};
36
37 return spi_write_then_read(spi, cmd, sizeof(cmd), NULL, 0);
38}
39
40static int w5100_spi_read16(struct net_device *ndev, u16 addr)
41{
42 u16 data;
43 int ret;
44
45 ret = w5100_spi_read(ndev, addr);
46 if (ret < 0)
47 return ret;
48 data = ret << 8;
49 ret = w5100_spi_read(ndev, addr + 1);
50
51 return ret < 0 ? ret : data | ret;
52}
53
54static int w5100_spi_write16(struct net_device *ndev, u16 addr, u16 data)
55{
56 int ret;
57
58 ret = w5100_spi_write(ndev, addr, data >> 8);
59 if (ret)
60 return ret;
61
62 return w5100_spi_write(ndev, addr + 1, data & 0xff);
63}
64
65static int w5100_spi_readbulk(struct net_device *ndev, u16 addr, u8 *buf,
66 int len)
67{
68 int i;
69
70 for (i = 0; i < len; i++) {
71 int ret = w5100_spi_read(ndev, addr + i);
72
73 if (ret < 0)
74 return ret;
75 buf[i] = ret;
76 }
77
78 return 0;
79}
80
81static int w5100_spi_writebulk(struct net_device *ndev, u16 addr, const u8 *buf,
82 int len)
83{
84 int i;
85
86 for (i = 0; i < len; i++) {
87 int ret = w5100_spi_write(ndev, addr + i, buf[i]);
88
89 if (ret)
90 return ret;
91 }
92
93 return 0;
94}
95
96static const struct w5100_ops w5100_spi_ops = {
97 .may_sleep = true,
98 .read = w5100_spi_read,
99 .write = w5100_spi_write,
100 .read16 = w5100_spi_read16,
101 .write16 = w5100_spi_write16,
102 .readbulk = w5100_spi_readbulk,
103 .writebulk = w5100_spi_writebulk,
104};
105
106static int w5100_spi_probe(struct spi_device *spi)
107{
108 return w5100_probe(&spi->dev, &w5100_spi_ops, 0, NULL, spi->irq,
109 -EINVAL);
110}
111
112static int w5100_spi_remove(struct spi_device *spi)
113{
114 return w5100_remove(&spi->dev);
115}
116
117static const struct spi_device_id w5100_spi_ids[] = {
118 { "w5100", 0 },
119 {}
120};
121MODULE_DEVICE_TABLE(spi, w5100_spi_ids);
122
123static struct spi_driver w5100_spi_driver = {
124 .driver = {
125 .name = "w5100",
126 .pm = &w5100_pm_ops,
127 },
128 .probe = w5100_spi_probe,
129 .remove = w5100_spi_remove,
130 .id_table = w5100_spi_ids,
131};
132module_spi_driver(w5100_spi_driver);
133
134MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver for SPI mode");
135MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
136MODULE_LICENSE("GPL");