| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Generic NAND driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Author: Vitaly Wool <vitalywool@gmail.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/err.h> |
|---|
| .. | .. |
|---|
| 15 | 11 | #include <linux/platform_device.h> |
|---|
| 16 | 12 | #include <linux/slab.h> |
|---|
| 17 | 13 | #include <linux/mtd/mtd.h> |
|---|
| 18 | | -#include <linux/mtd/rawnand.h> |
|---|
| 19 | | -#include <linux/mtd/partitions.h> |
|---|
| 14 | +#include <linux/mtd/platnand.h> |
|---|
| 20 | 15 | |
|---|
| 21 | 16 | struct plat_nand_data { |
|---|
| 17 | + struct nand_controller controller; |
|---|
| 22 | 18 | struct nand_chip chip; |
|---|
| 23 | 19 | void __iomem *io_base; |
|---|
| 20 | +}; |
|---|
| 21 | + |
|---|
| 22 | +static int plat_nand_attach_chip(struct nand_chip *chip) |
|---|
| 23 | +{ |
|---|
| 24 | + if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT && |
|---|
| 25 | + chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN) |
|---|
| 26 | + chip->ecc.algo = NAND_ECC_ALGO_HAMMING; |
|---|
| 27 | + |
|---|
| 28 | + return 0; |
|---|
| 29 | +} |
|---|
| 30 | + |
|---|
| 31 | +static const struct nand_controller_ops plat_nand_ops = { |
|---|
| 32 | + .attach_chip = plat_nand_attach_chip, |
|---|
| 24 | 33 | }; |
|---|
| 25 | 34 | |
|---|
| 26 | 35 | /* |
|---|
| .. | .. |
|---|
| 51 | 60 | if (!data) |
|---|
| 52 | 61 | return -ENOMEM; |
|---|
| 53 | 62 | |
|---|
| 63 | + data->controller.ops = &plat_nand_ops; |
|---|
| 64 | + nand_controller_init(&data->controller); |
|---|
| 65 | + data->chip.controller = &data->controller; |
|---|
| 66 | + |
|---|
| 54 | 67 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 55 | 68 | data->io_base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 56 | 69 | if (IS_ERR(data->io_base)) |
|---|
| .. | .. |
|---|
| 60 | 73 | mtd = nand_to_mtd(&data->chip); |
|---|
| 61 | 74 | mtd->dev.parent = &pdev->dev; |
|---|
| 62 | 75 | |
|---|
| 63 | | - data->chip.IO_ADDR_R = data->io_base; |
|---|
| 64 | | - data->chip.IO_ADDR_W = data->io_base; |
|---|
| 65 | | - data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl; |
|---|
| 66 | | - data->chip.dev_ready = pdata->ctrl.dev_ready; |
|---|
| 67 | | - data->chip.select_chip = pdata->ctrl.select_chip; |
|---|
| 68 | | - data->chip.write_buf = pdata->ctrl.write_buf; |
|---|
| 69 | | - data->chip.read_buf = pdata->ctrl.read_buf; |
|---|
| 70 | | - data->chip.chip_delay = pdata->chip.chip_delay; |
|---|
| 76 | + data->chip.legacy.IO_ADDR_R = data->io_base; |
|---|
| 77 | + data->chip.legacy.IO_ADDR_W = data->io_base; |
|---|
| 78 | + data->chip.legacy.cmd_ctrl = pdata->ctrl.cmd_ctrl; |
|---|
| 79 | + data->chip.legacy.dev_ready = pdata->ctrl.dev_ready; |
|---|
| 80 | + data->chip.legacy.select_chip = pdata->ctrl.select_chip; |
|---|
| 81 | + data->chip.legacy.write_buf = pdata->ctrl.write_buf; |
|---|
| 82 | + data->chip.legacy.read_buf = pdata->ctrl.read_buf; |
|---|
| 83 | + data->chip.legacy.chip_delay = pdata->chip.chip_delay; |
|---|
| 71 | 84 | data->chip.options |= pdata->chip.options; |
|---|
| 72 | 85 | data->chip.bbt_options |= pdata->chip.bbt_options; |
|---|
| 73 | | - |
|---|
| 74 | | - data->chip.ecc.mode = NAND_ECC_SOFT; |
|---|
| 75 | | - data->chip.ecc.algo = NAND_ECC_HAMMING; |
|---|
| 76 | 86 | |
|---|
| 77 | 87 | platform_set_drvdata(pdev, data); |
|---|
| 78 | 88 | |
|---|
| .. | .. |
|---|
| 82 | 92 | if (err) |
|---|
| 83 | 93 | goto out; |
|---|
| 84 | 94 | } |
|---|
| 95 | + |
|---|
| 96 | + /* |
|---|
| 97 | + * This driver assumes that the default ECC engine should be TYPE_SOFT. |
|---|
| 98 | + * Set ->engine_type before registering the NAND devices in order to |
|---|
| 99 | + * provide a driver specific default value. |
|---|
| 100 | + */ |
|---|
| 101 | + data->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; |
|---|
| 85 | 102 | |
|---|
| 86 | 103 | /* Scan to find existence of the device */ |
|---|
| 87 | 104 | err = nand_scan(&data->chip, pdata->chip.nr_chips); |
|---|
| .. | .. |
|---|
| 111 | 128 | { |
|---|
| 112 | 129 | struct plat_nand_data *data = platform_get_drvdata(pdev); |
|---|
| 113 | 130 | struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev); |
|---|
| 131 | + struct nand_chip *chip = &data->chip; |
|---|
| 132 | + int ret; |
|---|
| 114 | 133 | |
|---|
| 115 | | - nand_release(&data->chip); |
|---|
| 134 | + ret = mtd_device_unregister(nand_to_mtd(chip)); |
|---|
| 135 | + WARN_ON(ret); |
|---|
| 136 | + nand_cleanup(chip); |
|---|
| 116 | 137 | if (pdata->ctrl.remove) |
|---|
| 117 | 138 | pdata->ctrl.remove(pdev); |
|---|
| 118 | 139 | |
|---|