1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
5 * Derived from drivers/mtd/nand/toto.c (removed in v2.6.28)
6 * Copyright (c) 2003 Texas Instruments
7 * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
9 * Converted to platform driver by Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
10 * Partially stolen from plat_nand.c
13 * This is a device driver for the NAND flash device found on the
17 #include <linux/slab.h>
18 #include <linux/module.h>
19 #include <linux/delay.h>
20 #include <linux/gpio/consumer.h>
21 #include <linux/mtd/mtd.h>
22 #include <linux/mtd/rawnand.h>
23 #include <linux/mtd/partitions.h>
24 #include <linux/platform_device.h>
25 #include <linux/sizes.h>
28 * MTD structure for E3 (Delta)
30 struct ams_delta_nand
{
31 struct nand_controller base
;
32 struct nand_chip nand_chip
;
33 struct gpio_desc
*gpiod_rdy
;
34 struct gpio_desc
*gpiod_nce
;
35 struct gpio_desc
*gpiod_nre
;
36 struct gpio_desc
*gpiod_nwp
;
37 struct gpio_desc
*gpiod_nwe
;
38 struct gpio_desc
*gpiod_ale
;
39 struct gpio_desc
*gpiod_cle
;
40 struct gpio_descs
*data_gpiods
;
45 * Define partitions for flash devices
48 static const struct mtd_partition partition_info
[] = {
51 .size
= 3 * SZ_1M
+ SZ_512K
},
53 .offset
= 3 * SZ_1M
+ SZ_512K
,
55 { .name
= "u-boot params",
56 .offset
= 3 * SZ_1M
+ SZ_512K
+ SZ_256K
,
58 { .name
= "Amstrad LDR",
61 { .name
= "File system",
62 .offset
= 4 * SZ_1M
+ 1 * SZ_256K
,
64 { .name
= "PBL reserved",
65 .offset
= 32 * SZ_1M
- 3 * SZ_256K
,
66 .size
= 3 * SZ_256K
},
69 static void ams_delta_write_commit(struct ams_delta_nand
*priv
)
71 gpiod_set_value(priv
->gpiod_nwe
, 0);
73 gpiod_set_value(priv
->gpiod_nwe
, 1);
76 static void ams_delta_io_write(struct ams_delta_nand
*priv
, u8 byte
)
78 struct gpio_descs
*data_gpiods
= priv
->data_gpiods
;
79 DECLARE_BITMAP(values
, BITS_PER_TYPE(byte
)) = { byte
, };
81 gpiod_set_raw_array_value(data_gpiods
->ndescs
, data_gpiods
->desc
,
82 data_gpiods
->info
, values
);
84 ams_delta_write_commit(priv
);
87 static void ams_delta_dir_output(struct ams_delta_nand
*priv
, u8 byte
)
89 struct gpio_descs
*data_gpiods
= priv
->data_gpiods
;
90 DECLARE_BITMAP(values
, BITS_PER_TYPE(byte
)) = { byte
, };
93 for (i
= 0; i
< data_gpiods
->ndescs
; i
++)
94 gpiod_direction_output_raw(data_gpiods
->desc
[i
],
97 ams_delta_write_commit(priv
);
99 priv
->data_in
= false;
102 static u8
ams_delta_io_read(struct ams_delta_nand
*priv
)
105 struct gpio_descs
*data_gpiods
= priv
->data_gpiods
;
106 DECLARE_BITMAP(values
, BITS_PER_TYPE(res
)) = { 0, };
108 gpiod_set_value(priv
->gpiod_nre
, 0);
111 gpiod_get_raw_array_value(data_gpiods
->ndescs
, data_gpiods
->desc
,
112 data_gpiods
->info
, values
);
114 gpiod_set_value(priv
->gpiod_nre
, 1);
120 static void ams_delta_dir_input(struct ams_delta_nand
*priv
)
122 struct gpio_descs
*data_gpiods
= priv
->data_gpiods
;
125 for (i
= 0; i
< data_gpiods
->ndescs
; i
++)
126 gpiod_direction_input(data_gpiods
->desc
[i
]);
128 priv
->data_in
= true;
131 static void ams_delta_write_buf(struct ams_delta_nand
*priv
, const u8
*buf
,
136 if (len
> 0 && priv
->data_in
)
137 ams_delta_dir_output(priv
, buf
[i
++]);
140 ams_delta_io_write(priv
, buf
[i
++]);
143 static void ams_delta_read_buf(struct ams_delta_nand
*priv
, u8
*buf
, int len
)
148 ams_delta_dir_input(priv
);
150 for (i
= 0; i
< len
; i
++)
151 buf
[i
] = ams_delta_io_read(priv
);
154 static void ams_delta_ctrl_cs(struct ams_delta_nand
*priv
, bool assert)
156 gpiod_set_value(priv
->gpiod_nce
, assert ? 0 : 1);
159 static int ams_delta_exec_op(struct nand_chip
*this,
160 const struct nand_operation
*op
, bool check_only
)
162 struct ams_delta_nand
*priv
= nand_get_controller_data(this);
163 const struct nand_op_instr
*instr
;
169 ams_delta_ctrl_cs(priv
, 1);
171 for (instr
= op
->instrs
; instr
< op
->instrs
+ op
->ninstrs
; instr
++) {
172 switch (instr
->type
) {
173 case NAND_OP_CMD_INSTR
:
174 gpiod_set_value(priv
->gpiod_cle
, 1);
175 ams_delta_write_buf(priv
, &instr
->ctx
.cmd
.opcode
, 1);
176 gpiod_set_value(priv
->gpiod_cle
, 0);
179 case NAND_OP_ADDR_INSTR
:
180 gpiod_set_value(priv
->gpiod_ale
, 1);
181 ams_delta_write_buf(priv
, instr
->ctx
.addr
.addrs
,
182 instr
->ctx
.addr
.naddrs
);
183 gpiod_set_value(priv
->gpiod_ale
, 0);
186 case NAND_OP_DATA_IN_INSTR
:
187 ams_delta_read_buf(priv
, instr
->ctx
.data
.buf
.in
,
188 instr
->ctx
.data
.len
);
191 case NAND_OP_DATA_OUT_INSTR
:
192 ams_delta_write_buf(priv
, instr
->ctx
.data
.buf
.out
,
193 instr
->ctx
.data
.len
);
196 case NAND_OP_WAITRDY_INSTR
:
197 ret
= priv
->gpiod_rdy
?
198 nand_gpio_waitrdy(this, priv
->gpiod_rdy
,
199 instr
->ctx
.waitrdy
.timeout_ms
) :
200 nand_soft_waitrdy(this,
201 instr
->ctx
.waitrdy
.timeout_ms
);
209 ams_delta_ctrl_cs(priv
, 0);
214 static const struct nand_controller_ops ams_delta_ops
= {
215 .exec_op
= ams_delta_exec_op
,
219 * Main initialization routine
221 static int ams_delta_init(struct platform_device
*pdev
)
223 struct ams_delta_nand
*priv
;
224 struct nand_chip
*this;
225 struct mtd_info
*mtd
;
226 struct gpio_descs
*data_gpiods
;
229 /* Allocate memory for MTD device structure and private data */
230 priv
= devm_kzalloc(&pdev
->dev
, sizeof(struct ams_delta_nand
),
235 this = &priv
->nand_chip
;
237 mtd
= nand_to_mtd(this);
238 mtd
->dev
.parent
= &pdev
->dev
;
240 nand_set_controller_data(this, priv
);
242 priv
->gpiod_rdy
= devm_gpiod_get_optional(&pdev
->dev
, "rdy", GPIOD_IN
);
243 if (IS_ERR(priv
->gpiod_rdy
)) {
244 err
= PTR_ERR(priv
->gpiod_rdy
);
245 dev_warn(&pdev
->dev
, "RDY GPIO request failed (%d)\n", err
);
249 this->ecc
.mode
= NAND_ECC_SOFT
;
250 this->ecc
.algo
= NAND_ECC_HAMMING
;
252 platform_set_drvdata(pdev
, priv
);
254 /* Set chip enabled, but */
255 priv
->gpiod_nwp
= devm_gpiod_get(&pdev
->dev
, "nwp", GPIOD_OUT_HIGH
);
256 if (IS_ERR(priv
->gpiod_nwp
)) {
257 err
= PTR_ERR(priv
->gpiod_nwp
);
258 dev_err(&pdev
->dev
, "NWP GPIO request failed (%d)\n", err
);
262 priv
->gpiod_nce
= devm_gpiod_get(&pdev
->dev
, "nce", GPIOD_OUT_HIGH
);
263 if (IS_ERR(priv
->gpiod_nce
)) {
264 err
= PTR_ERR(priv
->gpiod_nce
);
265 dev_err(&pdev
->dev
, "NCE GPIO request failed (%d)\n", err
);
269 priv
->gpiod_nre
= devm_gpiod_get(&pdev
->dev
, "nre", GPIOD_OUT_HIGH
);
270 if (IS_ERR(priv
->gpiod_nre
)) {
271 err
= PTR_ERR(priv
->gpiod_nre
);
272 dev_err(&pdev
->dev
, "NRE GPIO request failed (%d)\n", err
);
276 priv
->gpiod_nwe
= devm_gpiod_get(&pdev
->dev
, "nwe", GPIOD_OUT_HIGH
);
277 if (IS_ERR(priv
->gpiod_nwe
)) {
278 err
= PTR_ERR(priv
->gpiod_nwe
);
279 dev_err(&pdev
->dev
, "NWE GPIO request failed (%d)\n", err
);
283 priv
->gpiod_ale
= devm_gpiod_get(&pdev
->dev
, "ale", GPIOD_OUT_LOW
);
284 if (IS_ERR(priv
->gpiod_ale
)) {
285 err
= PTR_ERR(priv
->gpiod_ale
);
286 dev_err(&pdev
->dev
, "ALE GPIO request failed (%d)\n", err
);
290 priv
->gpiod_cle
= devm_gpiod_get(&pdev
->dev
, "cle", GPIOD_OUT_LOW
);
291 if (IS_ERR(priv
->gpiod_cle
)) {
292 err
= PTR_ERR(priv
->gpiod_cle
);
293 dev_err(&pdev
->dev
, "CLE GPIO request failed (%d)\n", err
);
297 /* Request array of data pins, initialize them as input */
298 data_gpiods
= devm_gpiod_get_array(&pdev
->dev
, "data", GPIOD_IN
);
299 if (IS_ERR(data_gpiods
)) {
300 err
= PTR_ERR(data_gpiods
);
301 dev_err(&pdev
->dev
, "data GPIO request failed: %d\n", err
);
304 priv
->data_gpiods
= data_gpiods
;
305 priv
->data_in
= true;
307 /* Initialize the NAND controller object embedded in ams_delta_nand. */
308 priv
->base
.ops
= &ams_delta_ops
;
309 nand_controller_init(&priv
->base
);
310 this->controller
= &priv
->base
;
312 /* Scan to find existence of the device */
313 err
= nand_scan(this, 1);
317 /* Register the partitions */
318 err
= mtd_device_register(mtd
, partition_info
,
319 ARRAY_SIZE(partition_info
));
321 goto err_nand_cleanup
;
334 static int ams_delta_cleanup(struct platform_device
*pdev
)
336 struct ams_delta_nand
*priv
= platform_get_drvdata(pdev
);
337 struct mtd_info
*mtd
= nand_to_mtd(&priv
->nand_chip
);
339 /* Unregister device */
340 nand_release(mtd_to_nand(mtd
));
345 static struct platform_driver ams_delta_nand_driver
= {
346 .probe
= ams_delta_init
,
347 .remove
= ams_delta_cleanup
,
349 .name
= "ams-delta-nand",
353 module_platform_driver(ams_delta_nand_driver
);
355 MODULE_LICENSE("GPL v2");
356 MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
357 MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");