Linux Audio

Check our new training course

Loading...
Note: File does not exist in v5.9.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for Microchip 48L640 64 Kb SPI Serial EERAM
  4 *
  5 * Copyright Heiko Schocher <hs@denx.de>
  6 *
  7 * datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/20006055B.pdf
  8 *
  9 * we set continuous mode but reading/writing more bytes than
 10 * pagesize seems to bring chip into state where readden values
 11 * are wrong ... no idea why.
 12 *
 13 */
 14#include <linux/delay.h>
 15#include <linux/device.h>
 16#include <linux/jiffies.h>
 17#include <linux/module.h>
 18#include <linux/mtd/mtd.h>
 19#include <linux/mtd/partitions.h>
 20#include <linux/mutex.h>
 21#include <linux/sched.h>
 22#include <linux/sizes.h>
 23#include <linux/spi/flash.h>
 24#include <linux/spi/spi.h>
 25#include <linux/of.h>
 26
 27struct mchp48_caps {
 28	unsigned int size;
 29	unsigned int page_size;
 30};
 31
 32struct mchp48l640_flash {
 33	struct spi_device	*spi;
 34	struct mutex		lock;
 35	struct mtd_info		mtd;
 36	const struct mchp48_caps	*caps;
 37};
 38
 39#define MCHP48L640_CMD_WREN		0x06
 40#define MCHP48L640_CMD_WRDI		0x04
 41#define MCHP48L640_CMD_WRITE		0x02
 42#define MCHP48L640_CMD_READ		0x03
 43#define MCHP48L640_CMD_WRSR		0x01
 44#define MCHP48L640_CMD_RDSR		0x05
 45
 46#define MCHP48L640_STATUS_RDY		0x01
 47#define MCHP48L640_STATUS_WEL		0x02
 48#define MCHP48L640_STATUS_BP0		0x04
 49#define MCHP48L640_STATUS_BP1		0x08
 50#define MCHP48L640_STATUS_SWM		0x10
 51#define MCHP48L640_STATUS_PRO		0x20
 52#define MCHP48L640_STATUS_ASE		0x40
 53
 54#define MCHP48L640_TIMEOUT		100
 55
 56#define MAX_CMD_SIZE			0x10
 57
 58#define to_mchp48l640_flash(x) container_of(x, struct mchp48l640_flash, mtd)
 59
 60static int mchp48l640_mkcmd(struct mchp48l640_flash *flash, u8 cmd, loff_t addr, char *buf)
 61{
 62	buf[0] = cmd;
 63	buf[1] = addr >> 8;
 64	buf[2] = addr;
 65
 66	return 3;
 67}
 68
 69static int mchp48l640_read_status(struct mchp48l640_flash *flash, int *status)
 70{
 71	unsigned char cmd[2];
 72	int ret;
 73
 74	cmd[0] = MCHP48L640_CMD_RDSR;
 75	cmd[1] = 0x00;
 76	mutex_lock(&flash->lock);
 77	ret = spi_write_then_read(flash->spi, &cmd[0], 1, &cmd[1], 1);
 78	mutex_unlock(&flash->lock);
 79	if (!ret)
 80		*status = cmd[1];
 81	dev_dbg(&flash->spi->dev, "read status ret: %d status: %x", ret, *status);
 82
 83	return ret;
 84}
 85
 86static int mchp48l640_waitforbit(struct mchp48l640_flash *flash, int bit, bool set)
 87{
 88	int ret, status;
 89	unsigned long deadline;
 90
 91	deadline = jiffies + msecs_to_jiffies(MCHP48L640_TIMEOUT);
 92	do {
 93		ret = mchp48l640_read_status(flash, &status);
 94		dev_dbg(&flash->spi->dev, "read status ret: %d bit: %x %sset status: %x",
 95			ret, bit, (set ? "" : "not"), status);
 96		if (ret)
 97			return ret;
 98
 99		if (set) {
100			if ((status & bit) == bit)
101				return 0;
102		} else {
103			if ((status & bit) == 0)
104				return 0;
105		}
106
107		usleep_range(1000, 2000);
108	} while (!time_after_eq(jiffies, deadline));
109
110	dev_err(&flash->spi->dev, "Timeout waiting for bit %x %s set in status register.",
111		bit, (set ? "" : "not"));
112	return -ETIMEDOUT;
113}
114
115static int mchp48l640_write_prepare(struct mchp48l640_flash *flash, bool enable)
116{
117	unsigned char cmd[2];
118	int ret;
119
120	if (enable)
121		cmd[0] = MCHP48L640_CMD_WREN;
122	else
123		cmd[0] = MCHP48L640_CMD_WRDI;
124
125	mutex_lock(&flash->lock);
126	ret = spi_write(flash->spi, cmd, 1);
127	mutex_unlock(&flash->lock);
128
129	if (ret)
130		dev_err(&flash->spi->dev, "write %sable failed ret: %d",
131			(enable ? "en" : "dis"), ret);
132
133	dev_dbg(&flash->spi->dev, "write %sable success ret: %d",
134		(enable ? "en" : "dis"), ret);
135	if (enable)
136		return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, true);
137
138	return ret;
139}
140
141static int mchp48l640_set_mode(struct mchp48l640_flash *flash)
142{
143	unsigned char cmd[2];
144	int ret;
145
146	ret = mchp48l640_write_prepare(flash, true);
147	if (ret)
148		return ret;
149
150	cmd[0] = MCHP48L640_CMD_WRSR;
151	cmd[1] = MCHP48L640_STATUS_PRO;
152
153	mutex_lock(&flash->lock);
154	ret = spi_write(flash->spi, cmd, 2);
155	mutex_unlock(&flash->lock);
156	if (ret)
157		dev_err(&flash->spi->dev, "Could not set continuous mode ret: %d", ret);
158
159	return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_PRO, true);
160}
161
162static int mchp48l640_wait_rdy(struct mchp48l640_flash *flash)
163{
164	return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_RDY, false);
165};
166
167static int mchp48l640_write_page(struct mtd_info *mtd, loff_t to, size_t len,
168			    size_t *retlen, const unsigned char *buf)
169{
170	struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
171	unsigned char *cmd;
172	int ret;
173	int cmdlen;
174
175	cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA);
176	if (!cmd)
177		return -ENOMEM;
178
179	ret = mchp48l640_wait_rdy(flash);
180	if (ret)
181		goto fail;
182
183	ret = mchp48l640_write_prepare(flash, true);
184	if (ret)
185		goto fail;
186
187	mutex_lock(&flash->lock);
188	cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_WRITE, to, cmd);
189	memcpy(&cmd[cmdlen], buf, len);
190	ret = spi_write(flash->spi, cmd, cmdlen + len);
191	mutex_unlock(&flash->lock);
192	if (!ret)
193		*retlen += len;
194	else
195		goto fail;
196
197	ret = mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, false);
198	if (ret)
199		goto fail;
200
201	kfree(cmd);
202	return 0;
203fail:
204	kfree(cmd);
205	dev_err(&flash->spi->dev, "write fail with: %d", ret);
206	return ret;
207};
208
209static int mchp48l640_write(struct mtd_info *mtd, loff_t to, size_t len,
210			    size_t *retlen, const unsigned char *buf)
211{
212	struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
213	int ret;
214	size_t wlen = 0;
215	loff_t woff = to;
216	size_t ws;
217	size_t page_sz = flash->caps->page_size;
218
219	/*
220	 * we set PRO bit (page rollover), but writing length > page size
221	 * does result in total chaos, so write in 32 byte chunks.
222	 */
223	while (wlen < len) {
224		ws = min((len - wlen), page_sz);
225		ret = mchp48l640_write_page(mtd, woff, ws, retlen, &buf[wlen]);
226		if (ret)
227			return ret;
228		wlen += ws;
229		woff += ws;
230	}
231
232	return 0;
233}
234
235static int mchp48l640_read_page(struct mtd_info *mtd, loff_t from, size_t len,
236			   size_t *retlen, unsigned char *buf)
237{
238	struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
239	unsigned char *cmd;
240	int ret;
241	int cmdlen;
242
243	cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA);
244	if (!cmd)
245		return -ENOMEM;
246
247	ret = mchp48l640_wait_rdy(flash);
248	if (ret)
249		goto fail;
250
251	mutex_lock(&flash->lock);
252	cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_READ, from, cmd);
253	ret = spi_write_then_read(flash->spi, cmd, cmdlen, buf, len);
254	mutex_unlock(&flash->lock);
255	if (!ret)
256		*retlen += len;
257
258	kfree(cmd);
259	return ret;
260
261fail:
262	kfree(cmd);
263	dev_err(&flash->spi->dev, "read fail with: %d", ret);
264	return ret;
265}
266
267static int mchp48l640_read(struct mtd_info *mtd, loff_t from, size_t len,
268			   size_t *retlen, unsigned char *buf)
269{
270	struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
271	int ret;
272	size_t wlen = 0;
273	loff_t woff = from;
274	size_t ws;
275	size_t page_sz = flash->caps->page_size;
276
277	/*
278	 * we set PRO bit (page rollover), but if read length > page size
279	 * does result in total chaos in result ...
280	 */
281	while (wlen < len) {
282		ws = min((len - wlen), page_sz);
283		ret = mchp48l640_read_page(mtd, woff, ws, retlen, &buf[wlen]);
284		if (ret)
285			return ret;
286		wlen += ws;
287		woff += ws;
288	}
289
290	return 0;
291};
292
293static const struct mchp48_caps mchp48l640_caps = {
294	.size = SZ_8K,
295	.page_size = 32,
296};
297
298static int mchp48l640_probe(struct spi_device *spi)
299{
300	struct mchp48l640_flash *flash;
301	struct flash_platform_data *data;
302	int err;
303	int status;
304
305	flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
306	if (!flash)
307		return -ENOMEM;
308
309	flash->spi = spi;
310	mutex_init(&flash->lock);
311	spi_set_drvdata(spi, flash);
312
313	err = mchp48l640_read_status(flash, &status);
314	if (err)
315		return err;
316
317	err = mchp48l640_set_mode(flash);
318	if (err)
319		return err;
320
321	data = dev_get_platdata(&spi->dev);
322
323	flash->caps = of_device_get_match_data(&spi->dev);
324	if (!flash->caps)
325		flash->caps = &mchp48l640_caps;
326
327	mtd_set_of_node(&flash->mtd, spi->dev.of_node);
328	flash->mtd.dev.parent	= &spi->dev;
329	flash->mtd.type		= MTD_RAM;
330	flash->mtd.flags	= MTD_CAP_RAM;
331	flash->mtd.writesize	= flash->caps->page_size;
332	flash->mtd.size		= flash->caps->size;
333	flash->mtd._read	= mchp48l640_read;
334	flash->mtd._write	= mchp48l640_write;
335
336	err = mtd_device_register(&flash->mtd, data ? data->parts : NULL,
337				  data ? data->nr_parts : 0);
338	if (err)
339		return err;
340
341	return 0;
342}
343
344static void mchp48l640_remove(struct spi_device *spi)
345{
346	struct mchp48l640_flash *flash = spi_get_drvdata(spi);
347
348	WARN_ON(mtd_device_unregister(&flash->mtd));
349}
350
351static const struct of_device_id mchp48l640_of_table[] = {
352	{
353		.compatible = "microchip,48l640",
354		.data = &mchp48l640_caps,
355	},
356	{}
357};
358MODULE_DEVICE_TABLE(of, mchp48l640_of_table);
359
360static const struct spi_device_id mchp48l640_spi_ids[] = {
361	{
362		.name = "48l640",
363		.driver_data = (kernel_ulong_t)&mchp48l640_caps,
364	},
365	{}
366};
367MODULE_DEVICE_TABLE(spi, mchp48l640_spi_ids);
368
369static struct spi_driver mchp48l640_driver = {
370	.driver = {
371		.name	= "mchp48l640",
372		.of_match_table = mchp48l640_of_table,
373	},
374	.probe		= mchp48l640_probe,
375	.remove		= mchp48l640_remove,
376	.id_table	= mchp48l640_spi_ids,
377};
378
379module_spi_driver(mchp48l640_driver);
380
381MODULE_DESCRIPTION("MTD SPI driver for Microchip 48l640 EERAM chips");
382MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
383MODULE_LICENSE("GPL v2");
384MODULE_ALIAS("spi:mchp48l640");