diff options
author | Boris Brezillon <boris.brezillon@collabora.com> | 2020-06-03 15:49:20 +0200 |
---|---|---|
committer | Miquel Raynal <miquel.raynal@bootlin.com> | 2020-06-26 08:35:09 +0200 |
commit | 54309d65776755bcdb9dcf3744cd764fc1e254ea (patch) | |
tree | e0ff69ab3609abf8439720c543e3d1f8f66a3158 /drivers | |
parent | abc846afda664b7f229f32b40bbef738c3511801 (diff) |
mtd: rawnand: fsl_upm: Implement exec_op()
Implement exec_op() so we can get rid of the legacy interface
implementation.
Signed-off-by: Boris Brezillon <boris.brezillon@collabora.com>
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200603134922.1352340-9-boris.brezillon@collabora.com
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/nand/raw/fsl_upm.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c index 9a63e36825d8..03ca20930274 100644 --- a/drivers/mtd/nand/raw/fsl_upm.c +++ b/drivers/mtd/nand/raw/fsl_upm.c @@ -194,6 +194,91 @@ err: return ret; } +static int func_exec_instr(struct nand_chip *chip, + const struct nand_op_instr *instr) +{ + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); + u32 mar, reg_offs = fun->mchip_offsets[fun->mchip_number]; + unsigned int i; + const u8 *out; + u8 *in; + + switch (instr->type) { + case NAND_OP_CMD_INSTR: + fsl_upm_start_pattern(&fun->upm, fun->upm_cmd_offset); + mar = (instr->ctx.cmd.opcode << (32 - fun->upm.width)) | + reg_offs; + fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar); + fsl_upm_end_pattern(&fun->upm); + return 0; + + case NAND_OP_ADDR_INSTR: + fsl_upm_start_pattern(&fun->upm, fun->upm_addr_offset); + for (i = 0; i < instr->ctx.addr.naddrs; i++) { + mar = (instr->ctx.addr.addrs[i] << (32 - fun->upm.width)) | + reg_offs; + fsl_upm_run_pattern(&fun->upm, fun->io_base + reg_offs, mar); + } + fsl_upm_end_pattern(&fun->upm); + return 0; + + case NAND_OP_DATA_IN_INSTR: + in = instr->ctx.data.buf.in; + for (i = 0; i < instr->ctx.data.len; i++) + in[i] = in_8(fun->io_base + reg_offs); + return 0; + + case NAND_OP_DATA_OUT_INSTR: + out = instr->ctx.data.buf.out; + for (i = 0; i < instr->ctx.data.len; i++) + out_8(fun->io_base + reg_offs, out[i]); + return 0; + + case NAND_OP_WAITRDY_INSTR: + if (!fun->rnb_gpio[fun->mchip_number]) + return nand_soft_waitrdy(chip, instr->ctx.waitrdy.timeout_ms); + + return nand_gpio_waitrdy(chip, fun->rnb_gpio[fun->mchip_number], + instr->ctx.waitrdy.timeout_ms); + + default: + return -EINVAL; + } + + return 0; +} + +static int fun_exec_op(struct nand_chip *chip, const struct nand_operation *op, + bool check_only) +{ + struct fsl_upm_nand *fun = to_fsl_upm_nand(nand_to_mtd(chip)); + unsigned int i; + int ret; + + if (op->cs > NAND_MAX_CHIPS) + return -EINVAL; + + if (check_only) + return 0; + + fun->mchip_number = op->cs; + + for (i = 0; i < op->ninstrs; i++) { + ret = func_exec_instr(chip, &op->instrs[i]); + if (ret) + return ret; + + if (op->instrs[i].delay_ns) + ndelay(op->instrs[i].delay_ns); + } + + return 0; +} + +static const struct nand_controller_ops fun_ops = { + .exec_op = fun_exec_op, +}; + static int fun_probe(struct platform_device *ofdev) { struct fsl_upm_nand *fun; @@ -271,6 +356,7 @@ static int fun_probe(struct platform_device *ofdev) FSL_UPM_WAIT_WRITE_BYTE; nand_controller_init(&fun->base); + fun->base.ops = &fun_ops; fun->dev = &ofdev->dev; fun->last_ctrl = NAND_CLE; |