bcm53xx: initial support for kernel 3.18
[15.05/openwrt.git] / target / linux / bcm53xx / patches-3.18 / 404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch
1 --- a/drivers/mtd/spi-nor/Kconfig
2 +++ b/drivers/mtd/spi-nor/Kconfig
3 @@ -28,4 +28,10 @@ config SPI_FSL_QUADSPI
4           This enables support for the Quad SPI controller in master mode.
5           We only connect the NOR to this controller now.
6  
7 +config MTD_SPI_BCM53XXSPIFLASH
8 +       tristate "SPI-NOR flashes connected to the Broadcom ARM SoC"
9 +       depends on MTD_SPI_NOR
10 +       help
11 +         SPI driver for flashes used on Broadcom ARM SoCs.
12 +
13  endif # MTD_SPI_NOR
14 --- a/drivers/mtd/spi-nor/Makefile
15 +++ b/drivers/mtd/spi-nor/Makefile
16 @@ -1,2 +1,3 @@
17  obj-$(CONFIG_MTD_SPI_NOR)      += spi-nor.o
18  obj-$(CONFIG_SPI_FSL_QUADSPI)  += fsl-quadspi.o
19 +obj-$(CONFIG_MTD_SPI_BCM53XXSPIFLASH)  += bcm53xxspiflash.o
20 --- /dev/null
21 +++ b/drivers/mtd/spi-nor/bcm53xxspiflash.c
22 @@ -0,0 +1,241 @@
23 +#include <linux/module.h>
24 +#include <linux/delay.h>
25 +#include <linux/spi/spi.h>
26 +#include <linux/mtd/spi-nor.h>
27 +#include <linux/mtd/mtd.h>
28 +#include <linux/mtd/cfi.h>
29 +
30 +static const char * const probes[] = { "bcm47xxpart", NULL };
31 +
32 +struct bcm53xxsf {
33 +       struct spi_device *spi;
34 +       struct mtd_info mtd;
35 +       struct spi_nor nor;
36 +};
37 +
38 +/**************************************************
39 + * spi-nor API
40 + **************************************************/
41 +
42 +static int bcm53xxspiflash_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
43 +                                  int len)
44 +{
45 +       struct bcm53xxsf *b53sf = nor->priv;
46 +
47 +       return spi_write_then_read(b53sf->spi, &opcode, 1, buf, len);
48 +}
49 +
50 +static int bcm53xxspiflash_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
51 +                                    int len, int write_enable)
52 +{
53 +       struct bcm53xxsf *b53sf = nor->priv;
54 +       u8 *cmd = kzalloc(len + 1, GFP_KERNEL);
55 +       int err;
56 +
57 +       if (!cmd)
58 +               return -ENOMEM;
59 +
60 +       cmd[0] = opcode;
61 +       memcpy(&cmd[1], buf, len);
62 +       err = spi_write(b53sf->spi, cmd, len + 1);
63 +
64 +       kfree(cmd);
65 +
66 +       return err;
67 +}
68 +
69 +static int bcm53xxspiflash_read(struct spi_nor *nor, loff_t from, size_t len,
70 +                               size_t *retlen, u_char *buf)
71 +{
72 +       struct bcm53xxsf *b53sf = nor->priv;
73 +       struct spi_message m;
74 +       struct spi_transfer t[2] = { { 0 }, { 0 } };
75 +       unsigned char cmd[5];
76 +       int cmd_len = 0;
77 +       int err;
78 +
79 +       spi_message_init(&m);
80 +
81 +       cmd[cmd_len++] = SPINOR_OP_READ;
82 +       if (b53sf->mtd.size > 0x1000000)
83 +               cmd[cmd_len++] = (from & 0xFF000000) >> 24;
84 +       cmd[cmd_len++] = (from & 0x00FF0000) >> 16;
85 +       cmd[cmd_len++] = (from & 0x0000FF00) >> 8;
86 +       cmd[cmd_len++] = (from & 0x000000FF) >> 0;
87 +
88 +       t[0].tx_buf = cmd;
89 +       t[0].len = cmd_len;
90 +       spi_message_add_tail(&t[0], &m);
91 +
92 +       t[1].rx_buf = buf;
93 +       t[1].len = len;
94 +       spi_message_add_tail(&t[1], &m);
95 +
96 +       err = spi_sync(b53sf->spi, &m);
97 +       if (err)
98 +               return err;
99 +
100 +       if (retlen && m.actual_length > cmd_len)
101 +               *retlen = m.actual_length - cmd_len;
102 +
103 +       return 0;
104 +}
105 +
106 +static void bcm53xxspiflash_write(struct spi_nor *nor, loff_t to, size_t len,
107 +                                 size_t *retlen, const u_char *buf)
108 +{
109 +       struct bcm53xxsf *b53sf = nor->priv;
110 +       struct spi_message m;
111 +       struct spi_transfer t = { 0 };
112 +       u8 *cmd = kzalloc(len + 5, GFP_KERNEL);
113 +       int cmd_len = 0;
114 +       int err;
115 +
116 +       if (!cmd)
117 +               return;
118 +
119 +       spi_message_init(&m);
120 +
121 +       cmd[cmd_len++] = nor->program_opcode;
122 +       if (b53sf->mtd.size > 0x1000000)
123 +               cmd[cmd_len++] = (to & 0xFF000000) >> 24;
124 +       cmd[cmd_len++] = (to & 0x00FF0000) >> 16;
125 +       cmd[cmd_len++] = (to & 0x0000FF00) >> 8;
126 +       cmd[cmd_len++] = (to & 0x000000FF) >> 0;
127 +       memcpy(&cmd[cmd_len], buf, len);
128 +
129 +       t.tx_buf = cmd;
130 +       t.len = cmd_len + len;
131 +       spi_message_add_tail(&t, &m);
132 +
133 +       err = spi_sync(b53sf->spi, &m);
134 +       if (err)
135 +               goto out;
136 +
137 +       if (retlen && m.actual_length > cmd_len)
138 +               *retlen += m.actual_length - cmd_len;
139 +
140 +out:
141 +       kfree(cmd);
142 +}
143 +
144 +static int bcm53xxspiflash_erase(struct spi_nor *nor, loff_t offs)
145 +{
146 +       struct bcm53xxsf *b53sf = nor->priv;
147 +       unsigned char cmd[5];
148 +       int i;
149 +
150 +       i = 0;
151 +       cmd[i++] = nor->erase_opcode;
152 +       if (b53sf->mtd.size > 0x1000000)
153 +               cmd[i++] = (offs & 0xFF000000) >> 24;
154 +       cmd[i++] = ((offs & 0x00FF0000) >> 16);
155 +       cmd[i++] = ((offs & 0x0000FF00) >> 8);
156 +       cmd[i++] = ((offs & 0x000000FF) >> 0);
157 +
158 +       return spi_write(b53sf->spi, cmd, i);
159 +}
160 +
161 +static const struct spi_device_id *bcm53xxspiflash_read_id(struct spi_nor *nor)
162 +{
163 +       struct bcm53xxsf *b53sf = nor->priv;
164 +       struct device *dev = &b53sf->spi->dev;
165 +       const struct spi_device_id *id;
166 +       unsigned char cmd[4];
167 +       unsigned char resp[2];
168 +       char *name = NULL;
169 +       int err;
170 +
171 +       /* SST and Winbond/NexFlash specific command */
172 +       cmd[0] = 0x90; /* Read Manufacturer / Device ID */
173 +       cmd[1] = 0;
174 +       cmd[2] = 0;
175 +       cmd[3] = 0;
176 +       err = spi_write_then_read(b53sf->spi, cmd, 4, resp, 2);
177 +       if (err < 0) {
178 +               dev_err(dev, "error reading SPI flash id\n");
179 +               return ERR_PTR(-EBUSY);
180 +       }
181 +       switch (resp[0]) {
182 +       case 0xef: /* Winbond/NexFlash */
183 +               switch (resp[1]) {
184 +               case 0x17:
185 +                       name = "w25q128";
186 +                       break;
187 +               }
188 +               if (!name) {
189 +                       dev_err(dev, "Unknown Winbond/NexFlash flash: %02X %02X\n",
190 +                               resp[0], resp[1]);
191 +                       return ERR_PTR(-ENOTSUPP);
192 +               }
193 +               goto found_name;
194 +       }
195 +
196 +       /* TODO: Try more ID commands */
197 +
198 +       return ERR_PTR(-ENODEV);
199 +
200 +found_name:
201 +       id = spi_nor_match_id(name);
202 +       if (!id) {
203 +               dev_err(dev, "No matching entry for %s flash\n", name);
204 +               return ERR_PTR(-ENOENT);
205 +       }
206 +
207 +       return id;
208 +}
209 +
210 +/**************************************************
211 + * SPI driver
212 + **************************************************/
213 +
214 +static int bcm53xxspiflash_probe(struct spi_device *spi)
215 +{
216 +       struct bcm53xxsf *b53sf;
217 +       int err;
218 +
219 +       b53sf = devm_kzalloc(&spi->dev, sizeof(*b53sf), GFP_KERNEL);
220 +       if (!b53sf)
221 +               return -ENOMEM;
222 +       spi_set_drvdata(spi, b53sf);
223 +
224 +       b53sf->spi = spi;
225 +
226 +       b53sf->mtd.priv = &b53sf->nor;
227 +
228 +       b53sf->nor.mtd = &b53sf->mtd;
229 +       b53sf->nor.dev = &spi->dev;
230 +       b53sf->nor.read_reg = bcm53xxspiflash_read_reg;
231 +       b53sf->nor.write_reg = bcm53xxspiflash_write_reg;
232 +       b53sf->nor.read = bcm53xxspiflash_read;
233 +       b53sf->nor.write = bcm53xxspiflash_write;
234 +       b53sf->nor.erase = bcm53xxspiflash_erase;
235 +       b53sf->nor.read_id = bcm53xxspiflash_read_id;
236 +       b53sf->nor.priv = b53sf;
237 +
238 +       err = spi_nor_scan(&b53sf->nor, NULL, SPI_NOR_NORMAL);
239 +       if (err)
240 +               return err;
241 +
242 +       err = mtd_device_parse_register(&b53sf->mtd, probes, NULL, NULL, 0);
243 +       if (err)
244 +               return err;
245 +
246 +       return 0;
247 +}
248 +
249 +static int bcm53xxspiflash_remove(struct spi_device *spi)
250 +{
251 +       return 0;
252 +}
253 +
254 +static struct spi_driver bcm53xxspiflash_driver = {
255 +       .driver = {
256 +               .name   = "bcm53xxspiflash",
257 +               .owner  = THIS_MODULE,
258 +       },
259 +       .probe          = bcm53xxspiflash_probe,
260 +       .remove         = bcm53xxspiflash_remove,
261 +};
262 +
263 +module_spi_driver(bcm53xxspiflash_driver);