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_chip chip
;
18 void __iomem
*io_base
;
22 * Probe for the NAND device.
24 static int plat_nand_probe(struct platform_device
*pdev
)
26 struct platform_nand_data
*pdata
= dev_get_platdata(&pdev
->dev
);
27 struct plat_nand_data
*data
;
30 const char **part_types
;
34 dev_err(&pdev
->dev
, "platform_nand_data is missing\n");
38 if (pdata
->chip
.nr_chips
< 1) {
39 dev_err(&pdev
->dev
, "invalid number of chips specified\n");
43 /* Allocate memory for the device structure (and zero it) */
44 data
= devm_kzalloc(&pdev
->dev
, sizeof(struct plat_nand_data
),
49 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
50 data
->io_base
= devm_ioremap_resource(&pdev
->dev
, res
);
51 if (IS_ERR(data
->io_base
))
52 return PTR_ERR(data
->io_base
);
54 nand_set_flash_node(&data
->chip
, pdev
->dev
.of_node
);
55 mtd
= nand_to_mtd(&data
->chip
);
56 mtd
->dev
.parent
= &pdev
->dev
;
58 data
->chip
.legacy
.IO_ADDR_R
= data
->io_base
;
59 data
->chip
.legacy
.IO_ADDR_W
= data
->io_base
;
60 data
->chip
.legacy
.cmd_ctrl
= pdata
->ctrl
.cmd_ctrl
;
61 data
->chip
.legacy
.dev_ready
= pdata
->ctrl
.dev_ready
;
62 data
->chip
.legacy
.select_chip
= pdata
->ctrl
.select_chip
;
63 data
->chip
.legacy
.write_buf
= pdata
->ctrl
.write_buf
;
64 data
->chip
.legacy
.read_buf
= pdata
->ctrl
.read_buf
;
65 data
->chip
.legacy
.chip_delay
= pdata
->chip
.chip_delay
;
66 data
->chip
.options
|= pdata
->chip
.options
;
67 data
->chip
.bbt_options
|= pdata
->chip
.bbt_options
;
69 data
->chip
.ecc
.mode
= NAND_ECC_SOFT
;
70 data
->chip
.ecc
.algo
= NAND_ECC_HAMMING
;
72 platform_set_drvdata(pdev
, data
);
74 /* Handle any platform specific setup */
75 if (pdata
->ctrl
.probe
) {
76 err
= pdata
->ctrl
.probe(pdev
);
81 /* Scan to find existence of the device */
82 err
= nand_scan(&data
->chip
, pdata
->chip
.nr_chips
);
86 part_types
= pdata
->chip
.part_probe_types
;
88 err
= mtd_device_parse_register(mtd
, part_types
, NULL
,
89 pdata
->chip
.partitions
,
90 pdata
->chip
.nr_partitions
);
95 nand_release(&data
->chip
);
97 if (pdata
->ctrl
.remove
)
98 pdata
->ctrl
.remove(pdev
);
103 * Remove a NAND device.
105 static int plat_nand_remove(struct platform_device
*pdev
)
107 struct plat_nand_data
*data
= platform_get_drvdata(pdev
);
108 struct platform_nand_data
*pdata
= dev_get_platdata(&pdev
->dev
);
110 nand_release(&data
->chip
);
111 if (pdata
->ctrl
.remove
)
112 pdata
->ctrl
.remove(pdev
);
117 static const struct of_device_id plat_nand_match
[] = {
118 { .compatible
= "gen_nand" },
121 MODULE_DEVICE_TABLE(of
, plat_nand_match
);
123 static struct platform_driver plat_nand_driver
= {
124 .probe
= plat_nand_probe
,
125 .remove
= plat_nand_remove
,
128 .of_match_table
= plat_nand_match
,
132 module_platform_driver(plat_nand_driver
);
134 MODULE_LICENSE("GPL");
135 MODULE_AUTHOR("Vitaly Wool");
136 MODULE_DESCRIPTION("Simple generic NAND driver");
137 MODULE_ALIAS("platform:gen_nand");