rpcd: iwinfo plugin fixes
[openwrt.git] / target / linux / bcm53xx / files / drivers / mtd / spi-nor / bcm53xxspiflash.c
1 #include <linux/module.h>
2 #include <linux/delay.h>
3 #include <linux/spi/spi.h>
4 #include <linux/mtd/spi-nor.h>
5 #include <linux/mtd/mtd.h>
6 #include <linux/mtd/cfi.h>
7 #include <linux/mtd/partitions.h>
8
9 static const char * const probes[] = { "ofpart", "bcm47xxpart", NULL };
10
11 struct bcm53xxsf {
12         struct spi_device *spi;
13         struct spi_nor nor;
14 };
15
16 /**************************************************
17  * spi-nor API
18  **************************************************/
19
20 static int bcm53xxspiflash_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
21                                    int len)
22 {
23         struct bcm53xxsf *b53sf = nor->priv;
24
25         return spi_write_then_read(b53sf->spi, &opcode, 1, buf, len);
26 }
27
28 static int bcm53xxspiflash_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
29                                      int len)
30 {
31         struct bcm53xxsf *b53sf = nor->priv;
32         u8 *cmd = kzalloc(len + 1, GFP_KERNEL);
33         int err;
34
35         if (!cmd)
36                 return -ENOMEM;
37
38         cmd[0] = opcode;
39         memcpy(&cmd[1], buf, len);
40         err = spi_write(b53sf->spi, cmd, len + 1);
41
42         kfree(cmd);
43
44         return err;
45 }
46
47 static int bcm53xxspiflash_read(struct spi_nor *nor, loff_t from, size_t len,
48                                 size_t *retlen, u_char *buf)
49 {
50         struct bcm53xxsf *b53sf = nor->priv;
51         struct spi_message m;
52         struct spi_transfer t[2] = { { 0 }, { 0 } };
53         unsigned char cmd[5];
54         int cmd_len = 0;
55         int err;
56
57         spi_message_init(&m);
58
59         cmd[cmd_len++] = SPINOR_OP_READ;
60         if (nor->mtd.size > 0x1000000)
61                 cmd[cmd_len++] = (from & 0xFF000000) >> 24;
62         cmd[cmd_len++] = (from & 0x00FF0000) >> 16;
63         cmd[cmd_len++] = (from & 0x0000FF00) >> 8;
64         cmd[cmd_len++] = (from & 0x000000FF) >> 0;
65
66         t[0].tx_buf = cmd;
67         t[0].len = cmd_len;
68         spi_message_add_tail(&t[0], &m);
69
70         t[1].rx_buf = buf;
71         t[1].len = len;
72         spi_message_add_tail(&t[1], &m);
73
74         err = spi_sync(b53sf->spi, &m);
75         if (err)
76                 return err;
77
78         if (retlen && m.actual_length > cmd_len)
79                 *retlen = m.actual_length - cmd_len;
80
81         return 0;
82 }
83
84 static void bcm53xxspiflash_write(struct spi_nor *nor, loff_t to, size_t len,
85                                   size_t *retlen, const u_char *buf)
86 {
87         struct bcm53xxsf *b53sf = nor->priv;
88         struct spi_message m;
89         struct spi_transfer t = { 0 };
90         u8 *cmd = kzalloc(len + 5, GFP_KERNEL);
91         int cmd_len = 0;
92         int err;
93
94         if (!cmd)
95                 return;
96
97         spi_message_init(&m);
98
99         cmd[cmd_len++] = nor->program_opcode;
100         if (nor->mtd.size > 0x1000000)
101                 cmd[cmd_len++] = (to & 0xFF000000) >> 24;
102         cmd[cmd_len++] = (to & 0x00FF0000) >> 16;
103         cmd[cmd_len++] = (to & 0x0000FF00) >> 8;
104         cmd[cmd_len++] = (to & 0x000000FF) >> 0;
105         memcpy(&cmd[cmd_len], buf, len);
106
107         t.tx_buf = cmd;
108         t.len = cmd_len + len;
109         spi_message_add_tail(&t, &m);
110
111         err = spi_sync(b53sf->spi, &m);
112         if (err)
113                 goto out;
114
115         if (retlen && m.actual_length > cmd_len)
116                 *retlen += m.actual_length - cmd_len;
117
118 out:
119         kfree(cmd);
120 }
121
122 static int bcm53xxspiflash_erase(struct spi_nor *nor, loff_t offs)
123 {
124         struct bcm53xxsf *b53sf = nor->priv;
125         unsigned char cmd[5];
126         int i;
127
128         i = 0;
129         cmd[i++] = nor->erase_opcode;
130         if (nor->mtd.size > 0x1000000)
131                 cmd[i++] = (offs & 0xFF000000) >> 24;
132         cmd[i++] = ((offs & 0x00FF0000) >> 16);
133         cmd[i++] = ((offs & 0x0000FF00) >> 8);
134         cmd[i++] = ((offs & 0x000000FF) >> 0);
135
136         return spi_write(b53sf->spi, cmd, i);
137 }
138
139 static const char *bcm53xxspiflash_chip_name(struct spi_nor *nor)
140 {
141         struct bcm53xxsf *b53sf = nor->priv;
142         struct device *dev = &b53sf->spi->dev;
143         unsigned char cmd[4];
144         unsigned char resp[2];
145         int err;
146
147         /* SST and Winbond/NexFlash specific command */
148         cmd[0] = 0x90; /* Read Manufacturer / Device ID */
149         cmd[1] = 0;
150         cmd[2] = 0;
151         cmd[3] = 0;
152         err = spi_write_then_read(b53sf->spi, cmd, 4, resp, 2);
153         if (err < 0) {
154                 dev_err(dev, "error reading SPI flash id\n");
155                 return ERR_PTR(-EBUSY);
156         }
157         switch (resp[0]) {
158         case 0xef: /* Winbond/NexFlash */
159                 switch (resp[1]) {
160                 case 0x17:
161                         return "w25q128";
162                 }
163                 dev_err(dev, "Unknown Winbond/NexFlash flash: %02X %02X\n",
164                         resp[0], resp[1]);
165                 return NULL;
166         }
167
168         /* TODO: Try more ID commands */
169
170         return NULL;
171 }
172
173 /**************************************************
174  * SPI driver
175  **************************************************/
176
177 static int bcm53xxspiflash_probe(struct spi_device *spi)
178 {
179         struct mtd_part_parser_data parser_data = {};
180         struct bcm53xxsf *b53sf;
181         struct spi_nor *nor;
182         int err;
183
184         b53sf = devm_kzalloc(&spi->dev, sizeof(*b53sf), GFP_KERNEL);
185         if (!b53sf)
186                 return -ENOMEM;
187         spi_set_drvdata(spi, b53sf);
188
189         nor = &b53sf->nor;
190         b53sf->spi = spi;
191
192         nor->dev = &spi->dev;
193         nor->read_reg = bcm53xxspiflash_read_reg;
194         nor->write_reg = bcm53xxspiflash_write_reg;
195         nor->read = bcm53xxspiflash_read;
196         nor->write = bcm53xxspiflash_write;
197         nor->erase = bcm53xxspiflash_erase;
198         nor->priv = b53sf;
199
200         err = spi_nor_scan(&b53sf->nor, bcm53xxspiflash_chip_name(nor),
201                            SPI_NOR_NORMAL);
202         if (err)
203                 return err;
204
205         parser_data.of_node = spi->master->dev.parent->of_node;
206         err = mtd_device_parse_register(&nor->mtd, probes, &parser_data,
207                                         NULL, 0);
208         if (err)
209                 return err;
210
211         return 0;
212 }
213
214 static int bcm53xxspiflash_remove(struct spi_device *spi)
215 {
216         return 0;
217 }
218
219 static struct spi_driver bcm53xxspiflash_driver = {
220         .driver = {
221                 .name   = "bcm53xxspiflash",
222                 .owner  = THIS_MODULE,
223         },
224         .probe          = bcm53xxspiflash_probe,
225         .remove         = bcm53xxspiflash_remove,
226 };
227
228 module_spi_driver(bcm53xxspiflash_driver);