1 // SPDX-License-Identifier: GPL-2.0-only
5 * Author: Vitaly Wool <vitalywool@gmail.com>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
12 #include <linux/slab.h>
13 #include <linux/mtd/mtd.h>
14 #include <linux/mtd/platnand.h>
16 struct plat_nand_data
{
17 struct nand_controller controller
;
18 struct nand_chip chip
;
19 void __iomem
*io_base
;
22 static int plat_nand_attach_chip(struct nand_chip
*chip
)
24 chip
->ecc
.engine_type
= NAND_ECC_ENGINE_TYPE_SOFT
;
26 if (chip
->ecc
.algo
== NAND_ECC_ALGO_UNKNOWN
)
27 chip
->ecc
.algo
= NAND_ECC_ALGO_HAMMING
;
32 static const struct nand_controller_ops plat_nand_ops
= {
33 .attach_chip
= plat_nand_attach_chip
,
37 * Probe for the NAND device.
39 static int plat_nand_probe(struct platform_device
*pdev
)
41 struct platform_nand_data
*pdata
= dev_get_platdata(&pdev
->dev
);
42 struct plat_nand_data
*data
;
45 const char **part_types
;
49 dev_err(&pdev
->dev
, "platform_nand_data is missing\n");
53 if (pdata
->chip
.nr_chips
< 1) {
54 dev_err(&pdev
->dev
, "invalid number of chips specified\n");
58 /* Allocate memory for the device structure (and zero it) */
59 data
= devm_kzalloc(&pdev
->dev
, sizeof(struct plat_nand_data
),
64 data
->controller
.ops
= &plat_nand_ops
;
65 nand_controller_init(&data
->controller
);
66 data
->chip
.controller
= &data
->controller
;
68 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
69 data
->io_base
= devm_ioremap_resource(&pdev
->dev
, res
);
70 if (IS_ERR(data
->io_base
))
71 return PTR_ERR(data
->io_base
);
73 nand_set_flash_node(&data
->chip
, pdev
->dev
.of_node
);
74 mtd
= nand_to_mtd(&data
->chip
);
75 mtd
->dev
.parent
= &pdev
->dev
;
77 data
->chip
.legacy
.IO_ADDR_R
= data
->io_base
;
78 data
->chip
.legacy
.IO_ADDR_W
= data
->io_base
;
79 data
->chip
.legacy
.cmd_ctrl
= pdata
->ctrl
.cmd_ctrl
;
80 data
->chip
.legacy
.dev_ready
= pdata
->ctrl
.dev_ready
;
81 data
->chip
.legacy
.select_chip
= pdata
->ctrl
.select_chip
;
82 data
->chip
.legacy
.write_buf
= pdata
->ctrl
.write_buf
;
83 data
->chip
.legacy
.read_buf
= pdata
->ctrl
.read_buf
;
84 data
->chip
.legacy
.chip_delay
= pdata
->chip
.chip_delay
;
85 data
->chip
.options
|= pdata
->chip
.options
;
86 data
->chip
.bbt_options
|= pdata
->chip
.bbt_options
;
88 platform_set_drvdata(pdev
, data
);
90 /* Handle any platform specific setup */
91 if (pdata
->ctrl
.probe
) {
92 err
= pdata
->ctrl
.probe(pdev
);
97 /* Scan to find existence of the device */
98 err
= nand_scan(&data
->chip
, pdata
->chip
.nr_chips
);
102 part_types
= pdata
->chip
.part_probe_types
;
104 err
= mtd_device_parse_register(mtd
, part_types
, NULL
,
105 pdata
->chip
.partitions
,
106 pdata
->chip
.nr_partitions
);
111 nand_cleanup(&data
->chip
);
113 if (pdata
->ctrl
.remove
)
114 pdata
->ctrl
.remove(pdev
);
119 * Remove a NAND device.
121 static int plat_nand_remove(struct platform_device
*pdev
)
123 struct plat_nand_data
*data
= platform_get_drvdata(pdev
);
124 struct platform_nand_data
*pdata
= dev_get_platdata(&pdev
->dev
);
125 struct nand_chip
*chip
= &data
->chip
;
128 ret
= mtd_device_unregister(nand_to_mtd(chip
));
131 if (pdata
->ctrl
.remove
)
132 pdata
->ctrl
.remove(pdev
);
137 static const struct of_device_id plat_nand_match
[] = {
138 { .compatible
= "gen_nand" },
141 MODULE_DEVICE_TABLE(of
, plat_nand_match
);
143 static struct platform_driver plat_nand_driver
= {
144 .probe
= plat_nand_probe
,
145 .remove
= plat_nand_remove
,
148 .of_match_table
= plat_nand_match
,
152 module_platform_driver(plat_nand_driver
);
154 MODULE_LICENSE("GPL");
155 MODULE_AUTHOR("Vitaly Wool");
156 MODULE_DESCRIPTION("Simple generic NAND driver");
157 MODULE_ALIAS("platform:gen_nand");