^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2004 Richard Purdie
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2008 Dmitry Baryshkov
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Based on Sharp's NAND driver sharp_sl.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/genhd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/mtd/mtd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/mtd/rawnand.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mtd/nand_ecc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/mtd/partitions.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/mtd/sharpsl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct sharpsl_nand {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) struct nand_controller controller;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) struct nand_chip chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) void __iomem *io;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) static inline struct sharpsl_nand *mtd_to_sharpsl(struct mtd_info *mtd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return container_of(mtd_to_nand(mtd), struct sharpsl_nand, chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) /* register offset */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define ECCLPLB 0x00 /* line parity 7 - 0 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define ECCLPUB 0x04 /* line parity 15 - 8 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define ECCCP 0x08 /* column parity 5 - 0 bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define ECCCNTR 0x0C /* ECC byte counter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define ECCCLRR 0x10 /* cleare ECC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define FLASHIO 0x14 /* Flash I/O */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define FLASHCTL 0x18 /* Flash Control */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) /* Flash control bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define FLRYBY (1 << 5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #define FLCE1 (1 << 4)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define FLWP (1 << 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define FLALE (1 << 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define FLCLE (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) #define FLCE0 (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * hardware specific access to control-lines
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * ctrl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) * NAND_CNE: bit 0 -> ! bit 0 & 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * NAND_CLE: bit 1 -> bit 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * NAND_ALE: bit 2 -> bit 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) static void sharpsl_nand_hwcontrol(struct nand_chip *chip, int cmd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) unsigned int ctrl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if (ctrl & NAND_CTRL_CHANGE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) unsigned char bits = ctrl & 0x07;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) bits |= (ctrl & 0x01) << 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) bits ^= 0x11;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) writeb((readb(sharpsl->io + FLASHCTL) & ~0x17) | bits, sharpsl->io + FLASHCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (cmd != NAND_CMD_NONE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) writeb(cmd, chip->legacy.IO_ADDR_W);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) static int sharpsl_nand_dev_ready(struct nand_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return !((readb(sharpsl->io + FLASHCTL) & FLRYBY) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) static void sharpsl_nand_enable_hwecc(struct nand_chip *chip, int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) writeb(0, sharpsl->io + ECCCLRR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int sharpsl_nand_calculate_ecc(struct nand_chip *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) const u_char * dat, u_char * ecc_code)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) struct sharpsl_nand *sharpsl = mtd_to_sharpsl(nand_to_mtd(chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) ecc_code[0] = ~readb(sharpsl->io + ECCLPUB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) ecc_code[1] = ~readb(sharpsl->io + ECCLPLB);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ecc_code[2] = (~readb(sharpsl->io + ECCCP) << 2) | 0x03;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return readb(sharpsl->io + ECCCNTR) != 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int sharpsl_attach_chip(struct nand_chip *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) if (chip->ecc.engine_type != NAND_ECC_ENGINE_TYPE_ON_HOST)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) chip->ecc.size = 256;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) chip->ecc.bytes = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) chip->ecc.strength = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) chip->ecc.hwctl = sharpsl_nand_enable_hwecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) chip->ecc.calculate = sharpsl_nand_calculate_ecc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) chip->ecc.correct = nand_correct_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) static const struct nand_controller_ops sharpsl_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) .attach_chip = sharpsl_attach_chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * Main initialization routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) static int sharpsl_nand_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) struct nand_chip *this;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct mtd_info *mtd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct resource *r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) struct sharpsl_nand *sharpsl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) struct sharpsl_nand_platform_data *data = dev_get_platdata(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (!data) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) dev_err(&pdev->dev, "no platform data!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /* Allocate memory for MTD device structure and private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!sharpsl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (!r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) dev_err(&pdev->dev, "no io memory resource defined!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) goto err_get_res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) /* map physical address */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) sharpsl->io = ioremap(r->start, resource_size(r));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (!sharpsl->io) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) err = -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) goto err_ioremap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* Get pointer to private data */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) this = (struct nand_chip *)(&sharpsl->chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) nand_controller_init(&sharpsl->controller);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) sharpsl->controller.ops = &sharpsl_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) this->controller = &sharpsl->controller;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /* Link the private data with the MTD structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) mtd = nand_to_mtd(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) mtd->dev.parent = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) mtd_set_ooblayout(mtd, data->ecc_layout);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) platform_set_drvdata(pdev, sharpsl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) * PXA initialize
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) writeb(readb(sharpsl->io + FLASHCTL) | FLWP, sharpsl->io + FLASHCTL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) /* Set address of NAND IO lines */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) this->legacy.IO_ADDR_R = sharpsl->io + FLASHIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) this->legacy.IO_ADDR_W = sharpsl->io + FLASHIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) /* Set address of hardware control function */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) this->legacy.cmd_ctrl = sharpsl_nand_hwcontrol;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) this->legacy.dev_ready = sharpsl_nand_dev_ready;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* 15 us command delay time */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) this->legacy.chip_delay = 15;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) this->badblock_pattern = data->badblock_pattern;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) /* Scan to find existence of the device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) err = nand_scan(this, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) goto err_scan;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) /* Register the partitions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) mtd->name = "sharpsl-nand";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) err = mtd_device_parse_register(mtd, data->part_parsers, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) data->partitions, data->nr_partitions);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) goto err_add;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) /* Return happy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) err_add:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) nand_cleanup(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) err_scan:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) iounmap(sharpsl->io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) err_ioremap:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) err_get_res:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) kfree(sharpsl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) * Clean up routine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) static int sharpsl_nand_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) struct sharpsl_nand *sharpsl = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct nand_chip *chip = &sharpsl->chip;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) /* Unregister device */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) ret = mtd_device_unregister(nand_to_mtd(chip));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) WARN_ON(ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) /* Release resources */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) nand_cleanup(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) iounmap(sharpsl->io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) /* Free the driver's structure */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) kfree(sharpsl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static struct platform_driver sharpsl_nand_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .name = "sharpsl-nand",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .probe = sharpsl_nand_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .remove = sharpsl_nand_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) module_platform_driver(sharpsl_nand_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) MODULE_DESCRIPTION("Device specific logic for NAND flash on Sharp SL-C7xx Series");