diff options
author | Rafał Miłecki <zajec5@gmail.com> | 2014-12-17 14:53:25 +0000 |
---|---|---|
committer | Rafał Miłecki <zajec5@gmail.com> | 2014-12-17 14:53:25 +0000 |
commit | e21e9c55484762a3bc4fe6521d5b1fc84bfa1a1e (patch) | |
tree | 9fced2f084635096d5d48098385ea49590f36f4f /target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch | |
parent | d27c682def7cdaa887e06b0edb1b4a29c0130eb4 (diff) | |
download | upstream-e21e9c55484762a3bc4fe6521d5b1fc84bfa1a1e.tar.gz upstream-e21e9c55484762a3bc4fe6521d5b1fc84bfa1a1e.tar.bz2 upstream-e21e9c55484762a3bc4fe6521d5b1fc84bfa1a1e.zip |
bcm53xx: backport spi-nor changes and update bcm53xxspiflash
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
SVN-Revision: 43738
Diffstat (limited to 'target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch')
-rw-r--r-- | target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch | 244 |
1 files changed, 0 insertions, 244 deletions
diff --git a/target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch b/target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch index 9a9d903f82..41ef3b300e 100644 --- a/target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch +++ b/target/linux/bcm53xx/patches-3.14/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch @@ -17,247 +17,3 @@ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o +obj-$(CONFIG_MTD_SPI_BCM53XXSPIFLASH) += bcm53xxspiflash.o ---- /dev/null -+++ b/drivers/mtd/spi-nor/bcm53xxspiflash.c -@@ -0,0 +1,241 @@ -+#include <linux/module.h> -+#include <linux/delay.h> -+#include <linux/spi/spi.h> -+#include <linux/mtd/spi-nor.h> -+#include <linux/mtd/mtd.h> -+#include <linux/mtd/cfi.h> -+ -+static const char * const probes[] = { "bcm47xxpart", NULL }; -+ -+struct bcm53xxsf { -+ struct spi_device *spi; -+ struct mtd_info mtd; -+ struct spi_nor nor; -+}; -+ -+/************************************************** -+ * spi-nor API -+ **************************************************/ -+ -+static int bcm53xxspiflash_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, -+ int len) -+{ -+ struct bcm53xxsf *b53sf = nor->priv; -+ -+ return spi_write_then_read(b53sf->spi, &opcode, 1, buf, len); -+} -+ -+static int bcm53xxspiflash_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, -+ int len, int write_enable) -+{ -+ struct bcm53xxsf *b53sf = nor->priv; -+ u8 *cmd = kzalloc(len + 1, GFP_KERNEL); -+ int err; -+ -+ if (!cmd) -+ return -ENOMEM; -+ -+ cmd[0] = opcode; -+ memcpy(&cmd[1], buf, len); -+ err = spi_write(b53sf->spi, cmd, len + 1); -+ -+ kfree(cmd); -+ -+ return err; -+} -+ -+static int bcm53xxspiflash_read(struct spi_nor *nor, loff_t from, size_t len, -+ size_t *retlen, u_char *buf) -+{ -+ struct bcm53xxsf *b53sf = nor->priv; -+ struct spi_message m; -+ struct spi_transfer t[2] = { { 0 }, { 0 } }; -+ unsigned char cmd[5]; -+ int cmd_len = 0; -+ int err; -+ -+ spi_message_init(&m); -+ -+ cmd[cmd_len++] = SPINOR_OP_READ; -+ if (b53sf->mtd.size > 0x1000000) -+ cmd[cmd_len++] = (from & 0xFF000000) >> 24; -+ cmd[cmd_len++] = (from & 0x00FF0000) >> 16; -+ cmd[cmd_len++] = (from & 0x0000FF00) >> 8; -+ cmd[cmd_len++] = (from & 0x000000FF) >> 0; -+ -+ t[0].tx_buf = cmd; -+ t[0].len = cmd_len; -+ spi_message_add_tail(&t[0], &m); -+ -+ t[1].rx_buf = buf; -+ t[1].len = len; -+ spi_message_add_tail(&t[1], &m); -+ -+ err = spi_sync(b53sf->spi, &m); -+ if (err) -+ return err; -+ -+ if (retlen && m.actual_length > cmd_len) -+ *retlen = m.actual_length - cmd_len; -+ -+ return 0; -+} -+ -+static void bcm53xxspiflash_write(struct spi_nor *nor, loff_t to, size_t len, -+ size_t *retlen, const u_char *buf) -+{ -+ struct bcm53xxsf *b53sf = nor->priv; -+ struct spi_message m; -+ struct spi_transfer t = { 0 }; -+ u8 *cmd = kzalloc(len + 5, GFP_KERNEL); -+ int cmd_len = 0; -+ int err; -+ -+ if (!cmd) -+ return; -+ -+ spi_message_init(&m); -+ -+ cmd[cmd_len++] = nor->program_opcode; -+ if (b53sf->mtd.size > 0x1000000) -+ cmd[cmd_len++] = (to & 0xFF000000) >> 24; -+ cmd[cmd_len++] = (to & 0x00FF0000) >> 16; -+ cmd[cmd_len++] = (to & 0x0000FF00) >> 8; -+ cmd[cmd_len++] = (to & 0x000000FF) >> 0; -+ memcpy(&cmd[cmd_len], buf, len); -+ -+ t.tx_buf = cmd; -+ t.len = cmd_len + len; -+ spi_message_add_tail(&t, &m); -+ -+ err = spi_sync(b53sf->spi, &m); -+ if (err) -+ goto out; -+ -+ if (retlen && m.actual_length > cmd_len) -+ *retlen += m.actual_length - cmd_len; -+ -+out: -+ kfree(cmd); -+} -+ -+static int bcm53xxspiflash_erase(struct spi_nor *nor, loff_t offs) -+{ -+ struct bcm53xxsf *b53sf = nor->priv; -+ unsigned char cmd[5]; -+ int i; -+ -+ i = 0; -+ cmd[i++] = nor->erase_opcode; -+ if (b53sf->mtd.size > 0x1000000) -+ cmd[i++] = (offs & 0xFF000000) >> 24; -+ cmd[i++] = ((offs & 0x00FF0000) >> 16); -+ cmd[i++] = ((offs & 0x0000FF00) >> 8); -+ cmd[i++] = ((offs & 0x000000FF) >> 0); -+ -+ return spi_write(b53sf->spi, cmd, i); -+} -+ -+static const struct spi_device_id *bcm53xxspiflash_read_id(struct spi_nor *nor) -+{ -+ struct bcm53xxsf *b53sf = nor->priv; -+ struct device *dev = &b53sf->spi->dev; -+ const struct spi_device_id *id; -+ unsigned char cmd[4]; -+ unsigned char resp[2]; -+ char *name = NULL; -+ int err; -+ -+ /* SST and Winbond/NexFlash specific command */ -+ cmd[0] = 0x90; /* Read Manufacturer / Device ID */ -+ cmd[1] = 0; -+ cmd[2] = 0; -+ cmd[3] = 0; -+ err = spi_write_then_read(b53sf->spi, cmd, 4, resp, 2); -+ if (err < 0) { -+ dev_err(dev, "error reading SPI flash id\n"); -+ return ERR_PTR(-EBUSY); -+ } -+ switch (resp[0]) { -+ case 0xef: /* Winbond/NexFlash */ -+ switch (resp[1]) { -+ case 0x17: -+ name = "w25q128"; -+ break; -+ } -+ if (!name) { -+ dev_err(dev, "Unknown Winbond/NexFlash flash: %02X %02X\n", -+ resp[0], resp[1]); -+ return ERR_PTR(-ENOTSUPP); -+ } -+ goto found_name; -+ } -+ -+ /* TODO: Try more ID commands */ -+ -+ return ERR_PTR(-ENODEV); -+ -+found_name: -+ id = spi_nor_match_id(name); -+ if (!id) { -+ dev_err(dev, "No matching entry for %s flash\n", name); -+ return ERR_PTR(-ENOENT); -+ } -+ -+ return id; -+} -+ -+/************************************************** -+ * SPI driver -+ **************************************************/ -+ -+static int bcm53xxspiflash_probe(struct spi_device *spi) -+{ -+ struct bcm53xxsf *b53sf; -+ int err; -+ -+ b53sf = devm_kzalloc(&spi->dev, sizeof(*b53sf), GFP_KERNEL); -+ if (!b53sf) -+ return -ENOMEM; -+ spi_set_drvdata(spi, b53sf); -+ -+ b53sf->spi = spi; -+ -+ b53sf->mtd.priv = &b53sf->nor; -+ -+ b53sf->nor.mtd = &b53sf->mtd; -+ b53sf->nor.dev = &spi->dev; -+ b53sf->nor.read_reg = bcm53xxspiflash_read_reg; -+ b53sf->nor.write_reg = bcm53xxspiflash_write_reg; -+ b53sf->nor.read = bcm53xxspiflash_read; -+ b53sf->nor.write = bcm53xxspiflash_write; -+ b53sf->nor.erase = bcm53xxspiflash_erase; -+ b53sf->nor.read_id = bcm53xxspiflash_read_id; -+ b53sf->nor.priv = b53sf; -+ -+ err = spi_nor_scan(&b53sf->nor, NULL, SPI_NOR_NORMAL); -+ if (err) -+ return err; -+ -+ err = mtd_device_parse_register(&b53sf->mtd, probes, NULL, NULL, 0); -+ if (err) -+ return err; -+ -+ return 0; -+} -+ -+static int bcm53xxspiflash_remove(struct spi_device *spi) -+{ -+ return 0; -+} -+ -+static struct spi_driver bcm53xxspiflash_driver = { -+ .driver = { -+ .name = "bcm53xxspiflash", -+ .owner = THIS_MODULE, -+ }, -+ .probe = bcm53xxspiflash_probe, -+ .remove = bcm53xxspiflash_remove, -+}; -+ -+module_spi_driver(bcm53xxspiflash_driver); |