]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/net/ethernet/wiznet/w5100-spi.c
net: w5100: support SPI interface mode
[karo-tx-linux.git] / drivers / net / ethernet / wiznet / w5100-spi.c
1 /*
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
20 static 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
32 static 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
40 static 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
54 static 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
65 static 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
81 static 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
96 static 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
106 static 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
112 static int w5100_spi_remove(struct spi_device *spi)
113 {
114         return w5100_remove(&spi->dev);
115 }
116
117 static const struct spi_device_id w5100_spi_ids[] = {
118         { "w5100", 0 },
119         {}
120 };
121 MODULE_DEVICE_TABLE(spi, w5100_spi_ids);
122
123 static 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 };
132 module_spi_driver(w5100_spi_driver);
133
134 MODULE_DESCRIPTION("WIZnet W5100 Ethernet driver for SPI mode");
135 MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>");
136 MODULE_LICENSE("GPL");