18e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg/* 28e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * drivers/mtd/devices/goldfish_nand.c 38e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * 48e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * Copyright (C) 2007 Google, Inc. 58e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * Copyright (C) 2012 Intel, Inc. 68e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * Copyright (C) 2013 Intel, Inc. 78e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * 88e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * This software is licensed under the terms of the GNU General Public 98e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * License version 2, as published by the Free Software Foundation, and 108e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * may be copied, distributed, and modified under those terms. 118e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * 128e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * This program is distributed in the hope that it will be useful, 138e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * but WITHOUT ANY WARRANTY; without even the implied warranty of 148e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 158e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * GNU General Public License for more details. 168e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg * 178e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg */ 188e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 198e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/io.h> 208e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/device.h> 218e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/module.h> 228e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/slab.h> 238e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/ioport.h> 248e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/vmalloc.h> 258e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/mtd/mtd.h> 268e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <linux/platform_device.h> 2767c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko#include <linux/mutex.h> 28f6279717bbb20bf90ec414af17d2a31d843f5eb5Alan#include <linux/goldfish.h> 298e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include <asm/div64.h> 308e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 318e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg#include "goldfish_nand_reg.h" 328e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 338e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstruct goldfish_nand { 342c50741597b60284c4142808429fa94f3e516c23Loic Pefferkorn /* lock protects access to the device registers */ 3567c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko struct mutex lock; 368e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg unsigned char __iomem *base; 378e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct cmd_params *cmd_params; 388e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg size_t mtd_count; 398e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct mtd_info mtd[0]; 408e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg}; 418e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 428e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic u32 goldfish_nand_cmd_with_params(struct mtd_info *mtd, 438f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn enum nand_cmd cmd, u64 addr, u32 len, 448f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn void *ptr, u32 *rv) 458e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 468e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 cmdp; 478e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct goldfish_nand *nand = mtd->priv; 488e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct cmd_params *cps = nand->cmd_params; 498e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg unsigned char __iomem *base = nand->base; 508e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 518e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (cps == NULL) 528e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -1; 538e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 548e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg switch (cmd) { 558e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg case NAND_CMD_ERASE: 568e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cmdp = NAND_CMD_ERASE_WITH_PARAMS; 578e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg break; 588e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg case NAND_CMD_READ: 598e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cmdp = NAND_CMD_READ_WITH_PARAMS; 608e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg break; 618e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg case NAND_CMD_WRITE: 628e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cmdp = NAND_CMD_WRITE_WITH_PARAMS; 638e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg break; 648e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg default: 658e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -1; 668e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 678e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cps->dev = mtd - nand->mtd; 688e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cps->addr_high = (u32)(addr >> 32); 698e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cps->addr_low = (u32)addr; 708e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg cps->transfer_size = len; 717f09d4a00cc85ca43b2a7f491f9b3f8498413f1bJun Tian cps->data = (unsigned long)ptr; 728e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel(cmdp, base + NAND_COMMAND); 738e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg *rv = cps->result; 748e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 758e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 768e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 778e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic u32 goldfish_nand_cmd(struct mtd_info *mtd, enum nand_cmd cmd, 788f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn u64 addr, u32 len, void *ptr) 798e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 808e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct goldfish_nand *nand = mtd->priv; 818e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rv; 828e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg unsigned char __iomem *base = nand->base; 838e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 8467c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko mutex_lock(&nand->lock); 858e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (goldfish_nand_cmd_with_params(mtd, cmd, addr, len, ptr, &rv)) { 868e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel(mtd - nand->mtd, base + NAND_DEV); 878e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel((u32)(addr >> 32), base + NAND_ADDR_HIGH); 888e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel((u32)addr, base + NAND_ADDR_LOW); 898e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel(len, base + NAND_TRANSFER_SIZE); 90f6279717bbb20bf90ec414af17d2a31d843f5eb5Alan gf_write64((u64)ptr, base + NAND_DATA, base + NAND_DATA_HIGH); 918e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel(cmd, base + NAND_COMMAND); 928e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rv = readl(base + NAND_RESULT); 938e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 9467c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko mutex_unlock(&nand->lock); 958e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return rv; 968e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 978e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 988e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_erase(struct mtd_info *mtd, struct erase_info *instr) 998e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 1008e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg loff_t ofs = instr->addr; 1018e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 len = instr->len; 1028e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 1038e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1048e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ofs + len > mtd->size) 1058e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1068e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(ofs, mtd->writesize); 1078e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 1088e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1098e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= (mtd->writesize + mtd->oobsize); 1108e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1118e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (len % mtd->writesize) 1128e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1138e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg len = len / mtd->writesize * (mtd->writesize + mtd->oobsize); 1148e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1158e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (goldfish_nand_cmd(mtd, NAND_CMD_ERASE, ofs, len, NULL) != len) { 1168e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg pr_err("goldfish_nand_erase: erase failed, start %llx, len %x, dev_size %llx, erase_size %x\n", 1178f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn ofs, len, mtd->size, mtd->erasesize); 1188e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EIO; 1198e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 1208e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1218e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg instr->state = MTD_ERASE_DONE; 1228e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd_erase_callback(instr); 1238e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1248e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 1258e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1268e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 1278e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg pr_err("goldfish_nand_erase: invalid erase, start %llx, len %x, dev_size %llx, erase_size %x\n", 1288f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn ofs, len, mtd->size, mtd->erasesize); 1298e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 1308e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 1318e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1328e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_read_oob(struct mtd_info *mtd, loff_t ofs, 1338f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn struct mtd_oob_ops *ops) 1348e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 1358e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 1368e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1378e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ofs + ops->len > mtd->size) 1388e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1398e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->datbuf && ops->len && ops->len != mtd->writesize) 1408e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1418e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->ooblen + ops->ooboffs > mtd->oobsize) 1428e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1438e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1448e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(ofs, mtd->writesize); 1458e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 1468e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1478e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= (mtd->writesize + mtd->oobsize); 1488e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1498e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->datbuf) 1508e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->retlen = goldfish_nand_cmd(mtd, NAND_CMD_READ, ofs, 1518e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->len, ops->datbuf); 1528e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs += mtd->writesize + ops->ooboffs; 1538e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->oobbuf) 1548e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->oobretlen = goldfish_nand_cmd(mtd, NAND_CMD_READ, ofs, 1558e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->ooblen, ops->oobbuf); 1568e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 1578e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1588e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 159b4fcf48a740fde8e5acb8e64ad0845fb2500dde4Peter Huewe pr_err("goldfish_nand_read_oob: invalid read, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n", 1608f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn ofs, ops->len, ops->ooblen, mtd->size, mtd->writesize); 1618e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 1628e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 1638e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1648e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_write_oob(struct mtd_info *mtd, loff_t ofs, 1658f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn struct mtd_oob_ops *ops) 1668e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 1678e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 1688e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1698e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ofs + ops->len > mtd->size) 1708e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1718e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->len && ops->len != mtd->writesize) 1728e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1738e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->ooblen + ops->ooboffs > mtd->oobsize) 1748e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1758e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1768e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(ofs, mtd->writesize); 1778e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 1788e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 1798e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= (mtd->writesize + mtd->oobsize); 1808e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1818e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->datbuf) 1828e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->retlen = goldfish_nand_cmd(mtd, NAND_CMD_WRITE, ofs, 1838e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->len, ops->datbuf); 1848e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs += mtd->writesize + ops->ooboffs; 1858e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ops->oobbuf) 1868e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->oobretlen = goldfish_nand_cmd(mtd, NAND_CMD_WRITE, ofs, 1878e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ops->ooblen, ops->oobbuf); 1888e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 1898e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1908e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 191b4fcf48a740fde8e5acb8e64ad0845fb2500dde4Peter Huewe pr_err("goldfish_nand_write_oob: invalid write, start %llx, len %zx, ooblen %zx, dev_size %llx, write_size %x\n", 1928f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn ofs, ops->len, ops->ooblen, mtd->size, mtd->writesize); 1938e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 1948e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 1958e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 1968e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_read(struct mtd_info *mtd, loff_t from, size_t len, 1978f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn size_t *retlen, u_char *buf) 1988e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 1998e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 2008e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2018e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (from + len > mtd->size) 2028e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2038e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2048e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(from, mtd->writesize); 2058e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 2068e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2078e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg from *= (mtd->writesize + mtd->oobsize); 2088e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2098e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg *retlen = goldfish_nand_cmd(mtd, NAND_CMD_READ, from, len, buf); 2108e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 2118e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2128e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 213b4fcf48a740fde8e5acb8e64ad0845fb2500dde4Peter Huewe pr_err("goldfish_nand_read: invalid read, start %llx, len %zx, dev_size %llx, write_size %x\n", 2148f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn from, len, mtd->size, mtd->writesize); 2158e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 2168e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 2178e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2188e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_write(struct mtd_info *mtd, loff_t to, size_t len, 2198f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn size_t *retlen, const u_char *buf) 2208e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 2218e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 2228e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2238e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (to + len > mtd->size) 2248e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2258e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2268e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(to, mtd->writesize); 2278e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 2288e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2298e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg to *= (mtd->writesize + mtd->oobsize); 2308e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2318e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg *retlen = goldfish_nand_cmd(mtd, NAND_CMD_WRITE, to, len, (void *)buf); 2328e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 2338e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2348e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 235b4fcf48a740fde8e5acb8e64ad0845fb2500dde4Peter Huewe pr_err("goldfish_nand_write: invalid write, start %llx, len %zx, dev_size %llx, write_size %x\n", 2368f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn to, len, mtd->size, mtd->writesize); 2378e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 2388e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 2398e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2408e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_block_isbad(struct mtd_info *mtd, loff_t ofs) 2418e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 2428e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 2438e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2448e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ofs >= mtd->size) 2458e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2468e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2478e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(ofs, mtd->erasesize); 2488e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 2498e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2508e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= mtd->erasesize / mtd->writesize; 2518e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= (mtd->writesize + mtd->oobsize); 2528e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2538e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return goldfish_nand_cmd(mtd, NAND_CMD_BLOCK_BAD_GET, ofs, 0, NULL); 2548e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2558e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 2568e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg pr_err("goldfish_nand_block_isbad: invalid arg, ofs %llx, dev_size %llx, write_size %x\n", 2578f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn ofs, mtd->size, mtd->writesize); 2588e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 2598e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 2608e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2618e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_block_markbad(struct mtd_info *mtd, loff_t ofs) 2628e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 2638e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 rem; 2648e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2658e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (ofs >= mtd->size) 2668e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2678e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2688e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg rem = do_div(ofs, mtd->erasesize); 2698e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (rem) 2708e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg goto invalid_arg; 2718e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= mtd->erasesize / mtd->writesize; 2728e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg ofs *= (mtd->writesize + mtd->oobsize); 2738e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2748e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (goldfish_nand_cmd(mtd, NAND_CMD_BLOCK_BAD_SET, ofs, 0, NULL) != 1) 2758e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EIO; 2768e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 2778e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2788e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåginvalid_arg: 2798e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg pr_err("goldfish_nand_block_markbad: invalid arg, ofs %llx, dev_size %llx, write_size %x\n", 2808f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn ofs, mtd->size, mtd->writesize); 2818e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EINVAL; 2828e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 2838e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2848e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int nand_setup_cmd_params(struct platform_device *pdev, 2858f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn struct goldfish_nand *nand) 2868e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 2878e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u64 paddr; 2888e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg unsigned char __iomem *base = nand->base; 2898e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2908e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg nand->cmd_params = devm_kzalloc(&pdev->dev, 2918e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg sizeof(struct cmd_params), GFP_KERNEL); 2928e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (!nand->cmd_params) 2938e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -1; 2948e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 2958e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg paddr = __pa(nand->cmd_params); 2968e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel((u32)(paddr >> 32), base + NAND_CMD_PARAMS_ADDR_HIGH); 2978e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel((u32)paddr, base + NAND_CMD_PARAMS_ADDR_LOW); 2988e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 2998e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 3008e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3018e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_init_device(struct platform_device *pdev, 3028f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn struct goldfish_nand *nand, int id) 3038e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 3048e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 name_len; 3058e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 result; 3068e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 flags; 3078e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg unsigned char __iomem *base = nand->base; 3088e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct mtd_info *mtd = &nand->mtd[id]; 3098e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg char *name; 3108e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 31167c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko mutex_lock(&nand->lock); 3128e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg writel(id, base + NAND_DEV); 3138e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg flags = readl(base + NAND_DEV_FLAGS); 3148e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg name_len = readl(base + NAND_DEV_NAME_LEN); 3158e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->writesize = readl(base + NAND_DEV_PAGE_SIZE); 3168e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->size = readl(base + NAND_DEV_SIZE_LOW); 3178e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->size |= (u64)readl(base + NAND_DEV_SIZE_HIGH) << 32; 3188e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->oobsize = readl(base + NAND_DEV_EXTRA_SIZE); 3198e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->oobavail = mtd->oobsize; 3208e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->erasesize = readl(base + NAND_DEV_ERASE_SIZE) / 3218e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg (mtd->writesize + mtd->oobsize) * mtd->writesize; 3228e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg do_div(mtd->size, mtd->writesize + mtd->oobsize); 3238e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->size *= mtd->writesize; 32436270be3b7a1541b98d8a2356b113493d98c98deHema Prathaban dev_dbg(&pdev->dev, 3258e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg "goldfish nand dev%d: size %llx, page %d, extra %d, erase %d\n", 32613aa4016e8a8006a228716a6b099acaf21b96b2bHema Prathaban id, mtd->size, mtd->writesize, 32713aa4016e8a8006a228716a6b099acaf21b96b2bHema Prathaban mtd->oobsize, mtd->erasesize); 32867c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko mutex_unlock(&nand->lock); 3298e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3308e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->priv = nand; 3318e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3321f11b38ca8b8f1ed6a70b518dabcb4cd96db8996Loic Pefferkorn name = devm_kzalloc(&pdev->dev, name_len + 1, GFP_KERNEL); 3338e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (name == NULL) 3348e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENOMEM; 3351f11b38ca8b8f1ed6a70b518dabcb4cd96db8996Loic Pefferkorn mtd->name = name; 3368e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3378e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg result = goldfish_nand_cmd(mtd, NAND_CMD_GET_DEV_NAME, 0, name_len, 3388f52e264e80e500a24f565d3cb4dc37ec6d1b289Loic Pefferkorn name); 3398e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (result != name_len) { 34036270be3b7a1541b98d8a2356b113493d98c98deHema Prathaban dev_err(&pdev->dev, 3418e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg "goldfish_nand_init_device failed to get dev name %d != %d\n", 3428e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg result, name_len); 3438e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENODEV; 3448e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 3451977533a3f425cb9b7633d59e30459e048ce681fLoic Pefferkorn ((char *)mtd->name)[name_len] = '\0'; 3468e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3478e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg /* Setup the MTD structure */ 3488e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->type = MTD_NANDFLASH; 3498e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->flags = MTD_CAP_NANDFLASH; 3508e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (flags & NAND_DEV_FLAG_READ_ONLY) 3518e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->flags &= ~MTD_WRITEABLE; 3528e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (flags & NAND_DEV_FLAG_CMD_PARAMS_CAP) 3538e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg nand_setup_cmd_params(pdev, nand); 3548e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3558e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->owner = THIS_MODULE; 3568e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_erase = goldfish_nand_erase; 3578e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_read = goldfish_nand_read; 3588e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_write = goldfish_nand_write; 3598e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_read_oob = goldfish_nand_read_oob; 3608e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_write_oob = goldfish_nand_write_oob; 3618e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_block_isbad = goldfish_nand_block_isbad; 3628e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd->_block_markbad = goldfish_nand_block_markbad; 3638e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3648e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (mtd_device_register(mtd, NULL, 0)) 3658e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -EIO; 3668e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3678e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 3688e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 3698e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3708e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_probe(struct platform_device *pdev) 3718e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 3728e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 num_dev; 3738e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg int i; 3748e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg int err; 3758e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 num_dev_working; 3768e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg u32 version; 3778e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct resource *r; 3788e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct goldfish_nand *nand; 3798e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg unsigned char __iomem *base; 3808e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3818e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 3828e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (r == NULL) 3838e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENODEV; 3848e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3858e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg base = devm_ioremap(&pdev->dev, r->start, PAGE_SIZE); 3868e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (base == NULL) 3878e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENOMEM; 3888e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 3898e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg version = readl(base + NAND_VERSION); 3908e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (version != NAND_VERSION_CURRENT) { 39136270be3b7a1541b98d8a2356b113493d98c98deHema Prathaban dev_err(&pdev->dev, 3928e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg "goldfish_nand_init: version mismatch, got %d, expected %d\n", 3938e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg version, NAND_VERSION_CURRENT); 3948e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENODEV; 3958e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 3968e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg num_dev = readl(base + NAND_NUM_DEV); 3978e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (num_dev == 0) 3988e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENODEV; 3998e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 40036270be3b7a1541b98d8a2356b113493d98c98deHema Prathaban nand = devm_kzalloc(&pdev->dev, sizeof(*nand) + 4018e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg sizeof(struct mtd_info) * num_dev, GFP_KERNEL); 4028e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (nand == NULL) 4038e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENOMEM; 4048e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 40567c20cfbce53cf6df28681939d9a9621d2a85dfcKristina Martšenko mutex_init(&nand->lock); 4068e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg nand->base = base; 4078e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg nand->mtd_count = num_dev; 4088e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg platform_set_drvdata(pdev, nand); 4098e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 4108e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg num_dev_working = 0; 4118e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg for (i = 0; i < num_dev; i++) { 4128e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg err = goldfish_nand_init_device(pdev, nand, i); 4138e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (err == 0) 4148e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg num_dev_working++; 4158e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 4168e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (num_dev_working == 0) 4178e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return -ENODEV; 4188e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 4198e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 4208e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 4218e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic int goldfish_nand_remove(struct platform_device *pdev) 4228e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg{ 4238e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg struct goldfish_nand *nand = platform_get_drvdata(pdev); 4248e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg int i; 425ef323812c9cfd5837afab13dde846bf208eb4cc3Garret Kelly 4268e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg for (i = 0; i < nand->mtd_count; i++) { 4278e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg if (nand->mtd[i].name) 4288e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg mtd_device_unregister(&nand->mtd[i]); 4298e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 4308e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg return 0; 4318e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg} 4328e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 4338e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågstatic struct platform_driver goldfish_nand_driver = { 4348e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg .probe = goldfish_nand_probe, 4358e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg .remove = goldfish_nand_remove, 4368e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg .driver = { 4378e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg .name = "goldfish_nand" 4388e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg } 4398e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg}; 4408e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevåg 4418e404fffeac7d3985b193edbf860d9d73dec5b6aArve Hjønnevågmodule_platform_driver(goldfish_nand_driver); 4428e404fffeac7d3985b193edbf860d9d73dec5b6aArve HjønnevågMODULE_LICENSE("GPL"); 443