Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: mchp23k256: Add driver for this SPI SRAM device

The Microchip 23k256 is a 32K Byte SRAM connected via SPI.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Reviewed-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
[Brian: fixed copyright to be in this millenium]
Signed-off-by: Brian Norris <computersforpeace@gmail.com>

authored by

Andrew Lunn and committed by
Brian Norris
5dc17fa6 67e4145e

+193
+10
drivers/mtd/devices/Kconfig
··· 95 95 if you want to specify device partitioning or to use a device which 96 96 doesn't support the JEDEC ID instruction. 97 97 98 + config MTD_MCHP23K256 99 + tristate "Microchip 23K256 SRAM" 100 + depends on SPI_MASTER 101 + help 102 + This enables access to Microchip 23K256 SRAM chips, using SPI. 103 + 104 + Set up your spi devices with the right board-specific 105 + platform data, or a device tree description if you want to 106 + specify device partitioning 107 + 98 108 config MTD_SPEAR_SMI 99 109 tristate "SPEAR MTD NOR Support through SMI controller" 100 110 depends on PLAT_SPEAR
+1
drivers/mtd/devices/Makefile
··· 12 12 obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o 13 13 obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o 14 14 obj-$(CONFIG_MTD_M25P80) += m25p80.o 15 + obj-$(CONFIG_MTD_MCHP23K256) += mchp23k256.o 15 16 obj-$(CONFIG_MTD_SPEAR_SMI) += spear_smi.o 16 17 obj-$(CONFIG_MTD_SST25L) += sst25l.o 17 18 obj-$(CONFIG_MTD_BCM47XXSFLASH) += bcm47xxsflash.o
+182
drivers/mtd/devices/mchp23k256.c
··· 1 + /* 2 + * mchp23k256.c 3 + * 4 + * Driver for Microchip 23k256 SPI RAM chips 5 + * 6 + * Copyright © 2016 Andrew Lunn <andrew@lunn.ch> 7 + * 8 + * This code is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License version 2 as 10 + * published by the Free Software Foundation. 11 + * 12 + */ 13 + #include <linux/device.h> 14 + #include <linux/module.h> 15 + #include <linux/mtd/mtd.h> 16 + #include <linux/mtd/partitions.h> 17 + #include <linux/mutex.h> 18 + #include <linux/sched.h> 19 + #include <linux/sizes.h> 20 + #include <linux/spi/flash.h> 21 + #include <linux/spi/spi.h> 22 + 23 + struct mchp23k256_flash { 24 + struct spi_device *spi; 25 + struct mutex lock; 26 + struct mtd_info mtd; 27 + }; 28 + 29 + #define MCHP23K256_CMD_WRITE_STATUS 0x01 30 + #define MCHP23K256_CMD_WRITE 0x02 31 + #define MCHP23K256_CMD_READ 0x03 32 + #define MCHP23K256_MODE_SEQ BIT(6) 33 + 34 + #define to_mchp23k256_flash(x) container_of(x, struct mchp23k256_flash, mtd) 35 + 36 + static int mchp23k256_write(struct mtd_info *mtd, loff_t to, size_t len, 37 + size_t *retlen, const unsigned char *buf) 38 + { 39 + struct mchp23k256_flash *flash = to_mchp23k256_flash(mtd); 40 + struct spi_transfer transfer[2] = {}; 41 + struct spi_message message; 42 + unsigned char command[3]; 43 + 44 + spi_message_init(&message); 45 + 46 + command[0] = MCHP23K256_CMD_WRITE; 47 + command[1] = to >> 8; 48 + command[2] = to; 49 + 50 + transfer[0].tx_buf = command; 51 + transfer[0].len = sizeof(command); 52 + spi_message_add_tail(&transfer[0], &message); 53 + 54 + transfer[1].tx_buf = buf; 55 + transfer[1].len = len; 56 + spi_message_add_tail(&transfer[1], &message); 57 + 58 + mutex_lock(&flash->lock); 59 + 60 + spi_sync(flash->spi, &message); 61 + 62 + if (retlen && message.actual_length > sizeof(command)) 63 + *retlen += message.actual_length - sizeof(command); 64 + 65 + mutex_unlock(&flash->lock); 66 + return 0; 67 + } 68 + 69 + static int mchp23k256_read(struct mtd_info *mtd, loff_t from, size_t len, 70 + size_t *retlen, unsigned char *buf) 71 + { 72 + struct mchp23k256_flash *flash = to_mchp23k256_flash(mtd); 73 + struct spi_transfer transfer[2] = {}; 74 + struct spi_message message; 75 + unsigned char command[3]; 76 + 77 + spi_message_init(&message); 78 + 79 + memset(&transfer, 0, sizeof(transfer)); 80 + command[0] = MCHP23K256_CMD_READ; 81 + command[1] = from >> 8; 82 + command[2] = from; 83 + 84 + transfer[0].tx_buf = command; 85 + transfer[0].len = sizeof(command); 86 + spi_message_add_tail(&transfer[0], &message); 87 + 88 + transfer[1].rx_buf = buf; 89 + transfer[1].len = len; 90 + spi_message_add_tail(&transfer[1], &message); 91 + 92 + mutex_lock(&flash->lock); 93 + 94 + spi_sync(flash->spi, &message); 95 + 96 + if (retlen && message.actual_length > sizeof(command)) 97 + *retlen += message.actual_length - sizeof(command); 98 + 99 + mutex_unlock(&flash->lock); 100 + return 0; 101 + } 102 + 103 + /* 104 + * Set the device into sequential mode. This allows read/writes to the 105 + * entire SRAM in a single operation 106 + */ 107 + static int mchp23k256_set_mode(struct spi_device *spi) 108 + { 109 + struct spi_transfer transfer = {}; 110 + struct spi_message message; 111 + unsigned char command[2]; 112 + 113 + spi_message_init(&message); 114 + 115 + command[0] = MCHP23K256_CMD_WRITE_STATUS; 116 + command[1] = MCHP23K256_MODE_SEQ; 117 + 118 + transfer.tx_buf = command; 119 + transfer.len = sizeof(command); 120 + spi_message_add_tail(&transfer, &message); 121 + 122 + return spi_sync(spi, &message); 123 + } 124 + 125 + static int mchp23k256_probe(struct spi_device *spi) 126 + { 127 + struct mchp23k256_flash *flash; 128 + struct flash_platform_data *data; 129 + int err; 130 + 131 + flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL); 132 + if (!flash) 133 + return -ENOMEM; 134 + 135 + flash->spi = spi; 136 + mutex_init(&flash->lock); 137 + spi_set_drvdata(spi, flash); 138 + 139 + err = mchp23k256_set_mode(spi); 140 + if (err) 141 + return err; 142 + 143 + data = dev_get_platdata(&spi->dev); 144 + 145 + flash->mtd.dev.parent = &spi->dev; 146 + flash->mtd.type = MTD_RAM; 147 + flash->mtd.flags = MTD_CAP_RAM; 148 + flash->mtd.writesize = 1; 149 + flash->mtd.size = SZ_32K; 150 + flash->mtd._read = mchp23k256_read; 151 + flash->mtd._write = mchp23k256_write; 152 + 153 + err = mtd_device_parse_register(&flash->mtd, NULL, NULL, 154 + data ? data->parts : NULL, 155 + data ? data->nr_parts : 0); 156 + if (err) 157 + return err; 158 + 159 + return 0; 160 + } 161 + 162 + static int mchp23k256_remove(struct spi_device *spi) 163 + { 164 + struct mchp23k256_flash *flash = spi_get_drvdata(spi); 165 + 166 + return mtd_device_unregister(&flash->mtd); 167 + } 168 + 169 + static struct spi_driver mchp23k256_driver = { 170 + .driver = { 171 + .name = "mchp23k256", 172 + }, 173 + .probe = mchp23k256_probe, 174 + .remove = mchp23k256_remove, 175 + }; 176 + 177 + module_spi_driver(mchp23k256_driver); 178 + 179 + MODULE_DESCRIPTION("MTD SPI driver for MCHP23K256 RAM chips"); 180 + MODULE_AUTHOR("Andrew Lunn <andre@lunn.ch>"); 181 + MODULE_LICENSE("GPL v2"); 182 + MODULE_ALIAS("spi:mchp23k256");