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.
7 +config MTD_SPI_BCM53XXSPIFLASH
8 + tristate "SPI-NOR flashes connected to the Broadcom ARM SoC"
9 + depends on MTD_SPI_NOR
11 + SPI driver for flashes used on Broadcom ARM SoCs.
14 --- a/drivers/mtd/spi-nor/Makefile
15 +++ b/drivers/mtd/spi-nor/Makefile
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
21 +++ b/drivers/mtd/spi-nor/bcm53xxspiflash.c
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>
30 +static const char * const probes[] = { "bcm47xxpart", NULL };
33 + struct spi_device *spi;
34 + struct mtd_info mtd;
38 +/**************************************************
40 + **************************************************/
42 +static int bcm53xxspiflash_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
45 + struct bcm53xxsf *b53sf = nor->priv;
47 + return spi_write_then_read(b53sf->spi, &opcode, 1, buf, len);
50 +static int bcm53xxspiflash_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
51 + int len, int write_enable)
53 + struct bcm53xxsf *b53sf = nor->priv;
54 + u8 *cmd = kzalloc(len + 1, GFP_KERNEL);
61 + memcpy(&cmd[1], buf, len);
62 + err = spi_write(b53sf->spi, cmd, len + 1);
69 +static int bcm53xxspiflash_read(struct spi_nor *nor, loff_t from, size_t len,
70 + size_t *retlen, u_char *buf)
72 + struct bcm53xxsf *b53sf = nor->priv;
73 + struct spi_message m;
74 + struct spi_transfer t[2] = { { 0 }, { 0 } };
75 + unsigned char cmd[5];
79 + spi_message_init(&m);
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;
90 + spi_message_add_tail(&t[0], &m);
94 + spi_message_add_tail(&t[1], &m);
96 + err = spi_sync(b53sf->spi, &m);
100 + if (retlen && m.actual_length > cmd_len)
101 + *retlen = m.actual_length - cmd_len;
106 +static void bcm53xxspiflash_write(struct spi_nor *nor, loff_t to, size_t len,
107 + size_t *retlen, const u_char *buf)
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);
119 + spi_message_init(&m);
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);
130 + t.len = cmd_len + len;
131 + spi_message_add_tail(&t, &m);
133 + err = spi_sync(b53sf->spi, &m);
137 + if (retlen && m.actual_length > cmd_len)
138 + *retlen += m.actual_length - cmd_len;
144 +static int bcm53xxspiflash_erase(struct spi_nor *nor, loff_t offs)
146 + struct bcm53xxsf *b53sf = nor->priv;
147 + unsigned char cmd[5];
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);
158 + return spi_write(b53sf->spi, cmd, i);
161 +static const struct spi_device_id *bcm53xxspiflash_read_id(struct spi_nor *nor)
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];
171 + /* SST and Winbond/NexFlash specific command */
172 + cmd[0] = 0x90; /* Read Manufacturer / Device ID */
176 + err = spi_write_then_read(b53sf->spi, cmd, 4, resp, 2);
178 + dev_err(dev, "error reading SPI flash id\n");
179 + return ERR_PTR(-EBUSY);
182 + case 0xef: /* Winbond/NexFlash */
189 + dev_err(dev, "Unknown Winbond/NexFlash flash: %02X %02X\n",
191 + return ERR_PTR(-ENOTSUPP);
196 + /* TODO: Try more ID commands */
198 + return ERR_PTR(-ENODEV);
201 +// id = spi_nor_match_id(name);
203 +// dev_err(dev, "No matching entry for %s flash\n", name);
204 +// return ERR_PTR(-ENOENT);
210 +/**************************************************
212 + **************************************************/
214 +static int bcm53xxspiflash_probe(struct spi_device *spi)
216 + struct bcm53xxsf *b53sf;
219 + b53sf = devm_kzalloc(&spi->dev, sizeof(*b53sf), GFP_KERNEL);
222 + spi_set_drvdata(spi, b53sf);
226 + b53sf->mtd.priv = &b53sf->nor;
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;
238 + err = spi_nor_scan(&b53sf->nor, "w25q128", SPI_NOR_NORMAL);
242 + err = mtd_device_parse_register(&b53sf->mtd, probes, NULL, NULL, 0);
249 +static int bcm53xxspiflash_remove(struct spi_device *spi)
254 +static struct spi_driver bcm53xxspiflash_driver = {
256 + .name = "bcm53xxspiflash",
257 + .owner = THIS_MODULE,
259 + .probe = bcm53xxspiflash_probe,
260 + .remove = bcm53xxspiflash_remove,
263 +module_spi_driver(bcm53xxspiflash_driver);