xref: /openbmc/linux/drivers/mtd/devices/mchp48l640.c (revision 3ddc8b84)
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 
27 struct mchp48_caps {
28 	unsigned int size;
29 	unsigned int page_size;
30 };
31 
32 struct 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 
60 static 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 
69 static 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 
86 static 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 
115 static 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 
141 static 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 
162 static int mchp48l640_wait_rdy(struct mchp48l640_flash *flash)
163 {
164 	return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_RDY, false);
165 };
166 
167 static 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;
203 fail:
204 	kfree(cmd);
205 	dev_err(&flash->spi->dev, "write fail with: %d", ret);
206 	return ret;
207 };
208 
209 static 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 
235 static 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 
261 fail:
262 	kfree(cmd);
263 	dev_err(&flash->spi->dev, "read fail with: %d", ret);
264 	return ret;
265 }
266 
267 static 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 
293 static const struct mchp48_caps mchp48l640_caps = {
294 	.size = SZ_8K,
295 	.page_size = 32,
296 };
297 
298 static 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 
344 static 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 
351 static const struct of_device_id mchp48l640_of_table[] = {
352 	{
353 		.compatible = "microchip,48l640",
354 		.data = &mchp48l640_caps,
355 	},
356 	{}
357 };
358 MODULE_DEVICE_TABLE(of, mchp48l640_of_table);
359 
360 static const struct spi_device_id mchp48l640_spi_ids[] = {
361 	{
362 		.name = "48l640",
363 		.driver_data = (kernel_ulong_t)&mchp48l640_caps,
364 	},
365 	{}
366 };
367 MODULE_DEVICE_TABLE(spi, mchp48l640_spi_ids);
368 
369 static 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 
379 module_spi_driver(mchp48l640_driver);
380 
381 MODULE_DESCRIPTION("MTD SPI driver for Microchip 48l640 EERAM chips");
382 MODULE_AUTHOR("Heiko Schocher <hs@denx.de>");
383 MODULE_LICENSE("GPL v2");
384 MODULE_ALIAS("spi:mchp48l640");
385