| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Freescale UPM NAND driver. |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright © 2007-2008 MontaVista Software, Inc. |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 9 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 10 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | | - * (at your option) any later version. |
|---|
| 12 | 8 | */ |
|---|
| 13 | 9 | |
|---|
| 14 | 10 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 18 | 14 | #include <linux/mtd/nand_ecc.h> |
|---|
| 19 | 15 | #include <linux/mtd/partitions.h> |
|---|
| 20 | 16 | #include <linux/mtd/mtd.h> |
|---|
| 21 | | -#include <linux/of_address.h> |
|---|
| 22 | 17 | #include <linux/of_platform.h> |
|---|
| 23 | | -#include <linux/of_gpio.h> |
|---|
| 24 | 18 | #include <linux/io.h> |
|---|
| 25 | 19 | #include <linux/slab.h> |
|---|
| 26 | 20 | #include <asm/fsl_lbc.h> |
|---|
| 27 | 21 | |
|---|
| 28 | | -#define FSL_UPM_WAIT_RUN_PATTERN 0x1 |
|---|
| 29 | | -#define FSL_UPM_WAIT_WRITE_BYTE 0x2 |
|---|
| 30 | | -#define FSL_UPM_WAIT_WRITE_BUFFER 0x4 |
|---|
| 31 | | - |
|---|
| 32 | 22 | struct fsl_upm_nand { |
|---|
| 23 | + struct nand_controller base; |
|---|
| 33 | 24 | struct device *dev; |
|---|
| 34 | 25 | struct nand_chip chip; |
|---|
| 35 | | - int last_ctrl; |
|---|
| 36 | | - struct mtd_partition *parts; |
|---|
| 37 | 26 | struct fsl_upm upm; |
|---|
| 38 | 27 | uint8_t upm_addr_offset; |
|---|
| 39 | 28 | uint8_t upm_cmd_offset; |
|---|
| 40 | 29 | void __iomem *io_base; |
|---|
| 41 | | - int rnb_gpio[NAND_MAX_CHIPS]; |
|---|
| 30 | + struct gpio_desc *rnb_gpio[NAND_MAX_CHIPS]; |
|---|
| 42 | 31 | uint32_t mchip_offsets[NAND_MAX_CHIPS]; |
|---|
| 43 | 32 | uint32_t mchip_count; |
|---|
| 44 | 33 | uint32_t mchip_number; |
|---|
| 45 | | - int chip_delay; |
|---|
| 46 | | - uint32_t wait_flags; |
|---|
| 47 | 34 | }; |
|---|
| 48 | 35 | |
|---|
| 49 | 36 | static inline struct fsl_upm_nand *to_fsl_upm_nand(struct mtd_info *mtdinfo) |
|---|
| 50 | 37 | { |
|---|
| 51 | 38 | return container_of(mtd_to_nand(mtdinfo), struct fsl_upm_nand, |
|---|
| 52 | 39 | chip); |
|---|
| 53 | | -} |
|---|
| 54 | | - |
|---|
| 55 | | -static int fun_chip_ready(struct mtd_info *mtd) |
|---|
| 56 | | -{ |
|---|
| 57 | | - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); |
|---|
| 58 | | - |
|---|
| 59 | | - if (gpio_get_value(fun->rnb_gpio[fun->mchip_number])) |
|---|
| 60 | | - return 1; |
|---|
| 61 | | - |
|---|
| 62 | | - dev_vdbg(fun->dev, "busy\n"); |
|---|
| 63 | | - return 0; |
|---|
| 64 | | -} |
|---|
| 65 | | - |
|---|
| 66 | | -static void fun_wait_rnb(struct fsl_upm_nand *fun) |
|---|
| 67 | | -{ |
|---|
| 68 | | - if (fun->rnb_gpio[fun->mchip_number] >= 0) { |
|---|
| 69 | | - struct mtd_info *mtd = nand_to_mtd(&fun->chip); |
|---|
| 70 | | - int cnt = 1000000; |
|---|
| 71 | | - |
|---|
| 72 | | - while (--cnt && !fun_chip_ready(mtd)) |
|---|
| 73 | | - cpu_relax(); |
|---|
| 74 | | - if (!cnt) |
|---|
| 75 | | - dev_err(fun->dev, "tired waiting for RNB\n"); |
|---|
| 76 | | - } else { |
|---|
| 77 | | - ndelay(100); |
|---|
| 78 | | - } |
|---|
| 79 | | -} |
|---|
| 80 | | - |
|---|
| 81 | | -static void fun_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) |
|---|
| 82 | | -{ |
|---|
| 83 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 84 | | - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); |
|---|
| 85 | | - u32 mar; |
|---|
| 86 | | - |
|---|
| 87 | | - if (!(ctrl & fun->last_ctrl)) { |
|---|
| 88 | | - fsl_upm_end_pattern(&fun->upm); |
|---|
| 89 | | - |
|---|
| 90 | | - if (cmd == NAND_CMD_NONE) |
|---|
| 91 | | - return; |
|---|
| 92 | | - |
|---|
| 93 | | - fun->last_ctrl = ctrl & (NAND_ALE | NAND_CLE); |
|---|
| 94 | | - } |
|---|
| 95 | | - |
|---|
| 96 | | - if (ctrl & NAND_CTRL_CHANGE) { |
|---|
| 97 | | - if (ctrl & NAND_ALE) |
|---|
| 98 | | - fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); |
|---|
| 99 | | - else if (ctrl & NAND_CLE) |
|---|
| 100 | | - fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); |
|---|
| 101 | | - } |
|---|
| 102 | | - |
|---|
| 103 | | - mar = (cmd << (32 - fun->upm.width)) | |
|---|
| 104 | | - fun->mchip_offsets[fun->mchip_number]; |
|---|
| 105 | | - fsl_upm_run_pattern(&fun->upm, chip->IO_ADDR_R, mar); |
|---|
| 106 | | - |
|---|
| 107 | | - if (fun->wait_flags & FSL_UPM_WAIT_RUN_PATTERN) |
|---|
| 108 | | - fun_wait_rnb(fun); |
|---|
| 109 | | -} |
|---|
| 110 | | - |
|---|
| 111 | | -static void fun_select_chip(struct mtd_info *mtd, int mchip_nr) |
|---|
| 112 | | -{ |
|---|
| 113 | | - struct nand_chip *chip = mtd_to_nand(mtd); |
|---|
| 114 | | - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); |
|---|
| 115 | | - |
|---|
| 116 | | - if (mchip_nr == -1) { |
|---|
| 117 | | - chip->cmd_ctrl(mtd, NAND_CMD_NONE, 0 | NAND_CTRL_CHANGE); |
|---|
| 118 | | - } else if (mchip_nr >= 0 && mchip_nr < NAND_MAX_CHIPS) { |
|---|
| 119 | | - fun->mchip_number = mchip_nr; |
|---|
| 120 | | - chip->IO_ADDR_R = fun->io_base + fun->mchip_offsets[mchip_nr]; |
|---|
| 121 | | - chip->IO_ADDR_W = chip->IO_ADDR_R; |
|---|
| 122 | | - } else { |
|---|
| 123 | | - BUG(); |
|---|
| 124 | | - } |
|---|
| 125 | | -} |
|---|
| 126 | | - |
|---|
| 127 | | -static uint8_t fun_read_byte(struct mtd_info *mtd) |
|---|
| 128 | | -{ |
|---|
| 129 | | - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); |
|---|
| 130 | | - |
|---|
| 131 | | - return in_8(fun->chip.IO_ADDR_R); |
|---|
| 132 | | -} |
|---|
| 133 | | - |
|---|
| 134 | | -static void fun_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) |
|---|
| 135 | | -{ |
|---|
| 136 | | - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); |
|---|
| 137 | | - int i; |
|---|
| 138 | | - |
|---|
| 139 | | - for (i = 0; i < len; i++) |
|---|
| 140 | | - buf[i] = in_8(fun->chip.IO_ADDR_R); |
|---|
| 141 | | -} |
|---|
| 142 | | - |
|---|
| 143 | | -static void fun_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len) |
|---|
| 144 | | -{ |
|---|
| 145 | | - struct fsl_upm_nand *fun = to_fsl_upm_nand(mtd); |
|---|
| 146 | | - int i; |
|---|
| 147 | | - |
|---|
| 148 | | - for (i = 0; i < len; i++) { |
|---|
| 149 | | - out_8(fun->chip.IO_ADDR_W, buf[i]); |
|---|
| 150 | | - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BYTE) |
|---|
| 151 | | - fun_wait_rnb(fun); |
|---|
| 152 | | - } |
|---|
| 153 | | - if (fun->wait_flags & FSL_UPM_WAIT_WRITE_BUFFER) |
|---|
| 154 | | - fun_wait_rnb(fun); |
|---|
| 155 | 40 | } |
|---|
| 156 | 41 | |
|---|
| 157 | 42 | static int fun_chip_init(struct fsl_upm_nand *fun, |
|---|
| .. | .. |
|---|
| 162 | 47 | int ret; |
|---|
| 163 | 48 | struct device_node *flash_np; |
|---|
| 164 | 49 | |
|---|
| 165 | | - fun->chip.IO_ADDR_R = fun->io_base; |
|---|
| 166 | | - fun->chip.IO_ADDR_W = fun->io_base; |
|---|
| 167 | | - fun->chip.cmd_ctrl = fun_cmd_ctrl; |
|---|
| 168 | | - fun->chip.chip_delay = fun->chip_delay; |
|---|
| 169 | | - fun->chip.read_byte = fun_read_byte; |
|---|
| 170 | | - fun->chip.read_buf = fun_read_buf; |
|---|
| 171 | | - fun->chip.write_buf = fun_write_buf; |
|---|
| 172 | | - fun->chip.ecc.mode = NAND_ECC_SOFT; |
|---|
| 173 | | - fun->chip.ecc.algo = NAND_ECC_HAMMING; |
|---|
| 174 | | - if (fun->mchip_count > 1) |
|---|
| 175 | | - fun->chip.select_chip = fun_select_chip; |
|---|
| 176 | | - |
|---|
| 177 | | - if (fun->rnb_gpio[0] >= 0) |
|---|
| 178 | | - fun->chip.dev_ready = fun_chip_ready; |
|---|
| 179 | | - |
|---|
| 50 | + fun->chip.ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT; |
|---|
| 51 | + fun->chip.ecc.algo = NAND_ECC_ALGO_HAMMING; |
|---|
| 52 | + fun->chip.controller = &fun->base; |
|---|
| 180 | 53 | mtd->dev.parent = fun->dev; |
|---|
| 181 | 54 | |
|---|
| 182 | 55 | flash_np = of_get_next_child(upm_np, NULL); |
|---|
| .. | .. |
|---|
| 184 | 57 | return -ENODEV; |
|---|
| 185 | 58 | |
|---|
| 186 | 59 | nand_set_flash_node(&fun->chip, flash_np); |
|---|
| 187 | | - mtd->name = kasprintf(GFP_KERNEL, "0x%llx.%s", (u64)io_res->start, |
|---|
| 188 | | - flash_np->name); |
|---|
| 60 | + mtd->name = devm_kasprintf(fun->dev, GFP_KERNEL, "0x%llx.%pOFn", |
|---|
| 61 | + (u64)io_res->start, |
|---|
| 62 | + flash_np); |
|---|
| 189 | 63 | if (!mtd->name) { |
|---|
| 190 | 64 | ret = -ENOMEM; |
|---|
| 191 | 65 | goto err; |
|---|
| .. | .. |
|---|
| 198 | 72 | ret = mtd_device_register(mtd, NULL, 0); |
|---|
| 199 | 73 | err: |
|---|
| 200 | 74 | of_node_put(flash_np); |
|---|
| 201 | | - if (ret) |
|---|
| 202 | | - kfree(mtd->name); |
|---|
| 203 | 75 | return ret; |
|---|
| 204 | 76 | } |
|---|
| 77 | + |
|---|
| 78 | +static int func_exec_instr(struct nand_chip *chip, |
|---|
| 79 | + const struct nand_op_instr *instr) |
|---|
| 80 | +{ |
|---|
| 81 | + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); |
|---|
| 82 | + u32 mar, reg_offs = fun->mchip_offsets[fun->mchip_number]; |
|---|
| 83 | + unsigned int i; |
|---|
| 84 | + const u8 *out; |
|---|
| 85 | + u8 *in; |
|---|
| 86 | + |
|---|
| 87 | + switch (instr->type) { |
|---|
| 88 | + case NAND_OP_CMD_INSTR: |
|---|
| 89 | + fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); |
|---|
| 90 | + mar = (instr->ctx.cmd.opcode << (32 - fun->upm.width)) | |
|---|
| 91 | + reg_offs; |
|---|
| 92 | + fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar); |
|---|
| 93 | + fsl_upm_end_pattern(&fun->upm); |
|---|
| 94 | + return 0; |
|---|
| 95 | + |
|---|
| 96 | + case NAND_OP_ADDR_INSTR: |
|---|
| 97 | + fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); |
|---|
| 98 | + for (i = 0; i < instr->ctx.addr.naddrs; i++) { |
|---|
| 99 | + mar = (instr->ctx.addr.addrs[i] << (32 - fun->upm.width)) | |
|---|
| 100 | + reg_offs; |
|---|
| 101 | + fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar); |
|---|
| 102 | + } |
|---|
| 103 | + fsl_upm_end_pattern(&fun->upm); |
|---|
| 104 | + return 0; |
|---|
| 105 | + |
|---|
| 106 | + case NAND_OP_DATA_IN_INSTR: |
|---|
| 107 | + in = instr->ctx.data.buf.in; |
|---|
| 108 | + for (i = 0; i < instr->ctx.data.len; i++) |
|---|
| 109 | + in[i] = in_8(fun->io_base + reg_offs); |
|---|
| 110 | + return 0; |
|---|
| 111 | + |
|---|
| 112 | + case NAND_OP_DATA_OUT_INSTR: |
|---|
| 113 | + out = instr->ctx.data.buf.out; |
|---|
| 114 | + for (i = 0; i < instr->ctx.data.len; i++) |
|---|
| 115 | + out_8(fun->io_base + reg_offs, out[i]); |
|---|
| 116 | + return 0; |
|---|
| 117 | + |
|---|
| 118 | + case NAND_OP_WAITRDY_INSTR: |
|---|
| 119 | + if (!fun->rnb_gpio[fun->mchip_number]) |
|---|
| 120 | + return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms); |
|---|
| 121 | + |
|---|
| 122 | + return nand_gpio_waitrdy(chip, fun->rnb_gpio[fun->mchip_number], |
|---|
| 123 | + instr->ctx.waitrdy.timeout_ms); |
|---|
| 124 | + |
|---|
| 125 | + default: |
|---|
| 126 | + return -EINVAL; |
|---|
| 127 | + } |
|---|
| 128 | + |
|---|
| 129 | + return 0; |
|---|
| 130 | +} |
|---|
| 131 | + |
|---|
| 132 | +static int fun_exec_op(struct nand_chip *chip, const struct nand_operation *op, |
|---|
| 133 | + bool check_only) |
|---|
| 134 | +{ |
|---|
| 135 | + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); |
|---|
| 136 | + unsigned int i; |
|---|
| 137 | + int ret; |
|---|
| 138 | + |
|---|
| 139 | + if (op->cs > NAND_MAX_CHIPS) |
|---|
| 140 | + return -EINVAL; |
|---|
| 141 | + |
|---|
| 142 | + if (check_only) |
|---|
| 143 | + return 0; |
|---|
| 144 | + |
|---|
| 145 | + fun->mchip_number = op->cs; |
|---|
| 146 | + |
|---|
| 147 | + for (i = 0; i < op->ninstrs; i++) { |
|---|
| 148 | + ret = func_exec_instr(chip, &op->instrs[i]); |
|---|
| 149 | + if (ret) |
|---|
| 150 | + return ret; |
|---|
| 151 | + |
|---|
| 152 | + if (op->instrs[i].delay_ns) |
|---|
| 153 | + ndelay(op->instrs[i].delay_ns); |
|---|
| 154 | + } |
|---|
| 155 | + |
|---|
| 156 | + return 0; |
|---|
| 157 | +} |
|---|
| 158 | + |
|---|
| 159 | +static const struct nand_controller_ops fun_ops = { |
|---|
| 160 | + .exec_op = fun_exec_op, |
|---|
| 161 | +}; |
|---|
| 205 | 162 | |
|---|
| 206 | 163 | static int fun_probe(struct platform_device *ofdev) |
|---|
| 207 | 164 | { |
|---|
| 208 | 165 | struct fsl_upm_nand *fun; |
|---|
| 209 | | - struct resource io_res; |
|---|
| 166 | + struct resource *io_res; |
|---|
| 210 | 167 | const __be32 *prop; |
|---|
| 211 | | - int rnb_gpio; |
|---|
| 212 | 168 | int ret; |
|---|
| 213 | 169 | int size; |
|---|
| 214 | 170 | int i; |
|---|
| 215 | 171 | |
|---|
| 216 | | - fun = kzalloc(sizeof(*fun), GFP_KERNEL); |
|---|
| 172 | + fun = devm_kzalloc(&ofdev->dev, sizeof(*fun), GFP_KERNEL); |
|---|
| 217 | 173 | if (!fun) |
|---|
| 218 | 174 | return -ENOMEM; |
|---|
| 219 | 175 | |
|---|
| 220 | | - ret = of_address_to_resource(ofdev->dev.of_node, 0, &io_res); |
|---|
| 221 | | - if (ret) { |
|---|
| 222 | | - dev_err(&ofdev->dev, "can't get IO base\n"); |
|---|
| 223 | | - goto err1; |
|---|
| 224 | | - } |
|---|
| 176 | + io_res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); |
|---|
| 177 | + fun->io_base = devm_ioremap_resource(&ofdev->dev, io_res); |
|---|
| 178 | + if (IS_ERR(fun->io_base)) |
|---|
| 179 | + return PTR_ERR(fun->io_base); |
|---|
| 225 | 180 | |
|---|
| 226 | | - ret = fsl_upm_find(io_res.start, &fun->upm); |
|---|
| 181 | + ret = fsl_upm_find(io_res->start, &fun->upm); |
|---|
| 227 | 182 | if (ret) { |
|---|
| 228 | 183 | dev_err(&ofdev->dev, "can't find UPM\n"); |
|---|
| 229 | | - goto err1; |
|---|
| 184 | + return ret; |
|---|
| 230 | 185 | } |
|---|
| 231 | 186 | |
|---|
| 232 | 187 | prop = of_get_property(ofdev->dev.of_node, "fsl,upm-addr-offset", |
|---|
| 233 | 188 | &size); |
|---|
| 234 | 189 | if (!prop || size != sizeof(uint32_t)) { |
|---|
| 235 | 190 | dev_err(&ofdev->dev, "can't get UPM address offset\n"); |
|---|
| 236 | | - ret = -EINVAL; |
|---|
| 237 | | - goto err1; |
|---|
| 191 | + return -EINVAL; |
|---|
| 238 | 192 | } |
|---|
| 239 | 193 | fun->upm_addr_offset = *prop; |
|---|
| 240 | 194 | |
|---|
| 241 | 195 | prop = of_get_property(ofdev->dev.of_node, "fsl,upm-cmd-offset", &size); |
|---|
| 242 | 196 | if (!prop || size != sizeof(uint32_t)) { |
|---|
| 243 | 197 | dev_err(&ofdev->dev, "can't get UPM command offset\n"); |
|---|
| 244 | | - ret = -EINVAL; |
|---|
| 245 | | - goto err1; |
|---|
| 198 | + return -EINVAL; |
|---|
| 246 | 199 | } |
|---|
| 247 | 200 | fun->upm_cmd_offset = *prop; |
|---|
| 248 | 201 | |
|---|
| .. | .. |
|---|
| 252 | 205 | fun->mchip_count = size / sizeof(uint32_t); |
|---|
| 253 | 206 | if (fun->mchip_count >= NAND_MAX_CHIPS) { |
|---|
| 254 | 207 | dev_err(&ofdev->dev, "too much multiple chips\n"); |
|---|
| 255 | | - goto err1; |
|---|
| 208 | + return -EINVAL; |
|---|
| 256 | 209 | } |
|---|
| 257 | 210 | for (i = 0; i < fun->mchip_count; i++) |
|---|
| 258 | 211 | fun->mchip_offsets[i] = be32_to_cpu(prop[i]); |
|---|
| .. | .. |
|---|
| 261 | 214 | } |
|---|
| 262 | 215 | |
|---|
| 263 | 216 | for (i = 0; i < fun->mchip_count; i++) { |
|---|
| 264 | | - fun->rnb_gpio[i] = -1; |
|---|
| 265 | | - rnb_gpio = of_get_gpio(ofdev->dev.of_node, i); |
|---|
| 266 | | - if (rnb_gpio >= 0) { |
|---|
| 267 | | - ret = gpio_request(rnb_gpio, dev_name(&ofdev->dev)); |
|---|
| 268 | | - if (ret) { |
|---|
| 269 | | - dev_err(&ofdev->dev, |
|---|
| 270 | | - "can't request RNB gpio #%d\n", i); |
|---|
| 271 | | - goto err2; |
|---|
| 272 | | - } |
|---|
| 273 | | - gpio_direction_input(rnb_gpio); |
|---|
| 274 | | - fun->rnb_gpio[i] = rnb_gpio; |
|---|
| 275 | | - } else if (rnb_gpio == -EINVAL) { |
|---|
| 217 | + fun->rnb_gpio[i] = devm_gpiod_get_index_optional(&ofdev->dev, |
|---|
| 218 | + NULL, i, |
|---|
| 219 | + GPIOD_IN); |
|---|
| 220 | + if (IS_ERR(fun->rnb_gpio[i])) { |
|---|
| 276 | 221 | dev_err(&ofdev->dev, "RNB gpio #%d is invalid\n", i); |
|---|
| 277 | | - goto err2; |
|---|
| 222 | + return PTR_ERR(fun->rnb_gpio[i]); |
|---|
| 278 | 223 | } |
|---|
| 279 | 224 | } |
|---|
| 280 | 225 | |
|---|
| 281 | | - prop = of_get_property(ofdev->dev.of_node, "chip-delay", NULL); |
|---|
| 282 | | - if (prop) |
|---|
| 283 | | - fun->chip_delay = be32_to_cpup(prop); |
|---|
| 284 | | - else |
|---|
| 285 | | - fun->chip_delay = 50; |
|---|
| 286 | | - |
|---|
| 287 | | - prop = of_get_property(ofdev->dev.of_node, "fsl,upm-wait-flags", &size); |
|---|
| 288 | | - if (prop && size == sizeof(uint32_t)) |
|---|
| 289 | | - fun->wait_flags = be32_to_cpup(prop); |
|---|
| 290 | | - else |
|---|
| 291 | | - fun->wait_flags = FSL_UPM_WAIT_RUN_PATTERN | |
|---|
| 292 | | - FSL_UPM_WAIT_WRITE_BYTE; |
|---|
| 293 | | - |
|---|
| 294 | | - fun->io_base = devm_ioremap_nocache(&ofdev->dev, io_res.start, |
|---|
| 295 | | - resource_size(&io_res)); |
|---|
| 296 | | - if (!fun->io_base) { |
|---|
| 297 | | - ret = -ENOMEM; |
|---|
| 298 | | - goto err2; |
|---|
| 299 | | - } |
|---|
| 300 | | - |
|---|
| 226 | + nand_controller_init(&fun->base); |
|---|
| 227 | + fun->base.ops = &fun_ops; |
|---|
| 301 | 228 | fun->dev = &ofdev->dev; |
|---|
| 302 | | - fun->last_ctrl = NAND_CLE; |
|---|
| 303 | 229 | |
|---|
| 304 | | - ret = fun_chip_init(fun, ofdev->dev.of_node, &io_res); |
|---|
| 230 | + ret = fun_chip_init(fun, ofdev->dev.of_node, io_res); |
|---|
| 305 | 231 | if (ret) |
|---|
| 306 | | - goto err2; |
|---|
| 232 | + return ret; |
|---|
| 307 | 233 | |
|---|
| 308 | 234 | dev_set_drvdata(&ofdev->dev, fun); |
|---|
| 309 | 235 | |
|---|
| 310 | 236 | return 0; |
|---|
| 311 | | -err2: |
|---|
| 312 | | - for (i = 0; i < fun->mchip_count; i++) { |
|---|
| 313 | | - if (fun->rnb_gpio[i] < 0) |
|---|
| 314 | | - break; |
|---|
| 315 | | - gpio_free(fun->rnb_gpio[i]); |
|---|
| 316 | | - } |
|---|
| 317 | | -err1: |
|---|
| 318 | | - kfree(fun); |
|---|
| 319 | | - |
|---|
| 320 | | - return ret; |
|---|
| 321 | 237 | } |
|---|
| 322 | 238 | |
|---|
| 323 | 239 | static int fun_remove(struct platform_device *ofdev) |
|---|
| 324 | 240 | { |
|---|
| 325 | 241 | struct fsl_upm_nand *fun = dev_get_drvdata(&ofdev->dev); |
|---|
| 326 | | - struct mtd_info *mtd = nand_to_mtd(&fun->chip); |
|---|
| 327 | | - int i; |
|---|
| 242 | + struct nand_chip *chip = &fun->chip; |
|---|
| 243 | + struct mtd_info *mtd = nand_to_mtd(chip); |
|---|
| 244 | + int ret; |
|---|
| 328 | 245 | |
|---|
| 329 | | - nand_release(&fun->chip); |
|---|
| 330 | | - kfree(mtd->name); |
|---|
| 331 | | - |
|---|
| 332 | | - for (i = 0; i < fun->mchip_count; i++) { |
|---|
| 333 | | - if (fun->rnb_gpio[i] < 0) |
|---|
| 334 | | - break; |
|---|
| 335 | | - gpio_free(fun->rnb_gpio[i]); |
|---|
| 336 | | - } |
|---|
| 337 | | - |
|---|
| 338 | | - kfree(fun); |
|---|
| 246 | + ret = mtd_device_unregister(mtd); |
|---|
| 247 | + WARN_ON(ret); |
|---|
| 248 | + nand_cleanup(chip); |
|---|
| 339 | 249 | |
|---|
| 340 | 250 | return 0; |
|---|
| 341 | 251 | } |
|---|