cregit-Linux how code gets into the kernel

Release 4.11 drivers/mtd/nand/nuc900_nand.c

Directory: drivers/mtd/nand
/*
 * Copyright © 2009 Nuvoton technology corporation.
 *
 * Wan ZongShun <mcuos.com@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation;version 2 of the License.
 *
 */

#include <linux/slab.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/err.h>

#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>


#define REG_FMICSR   	0x00

#define REG_SMCSR    	0xa0

#define REG_SMISR    	0xac

#define REG_SMCMD    	0xb0

#define REG_SMADDR   	0xb4

#define REG_SMDATA   	0xb8


#define RESET_FMI	0x01

#define NAND_EN		0x08

#define READYBUSY	(0x01 << 18)


#define SWRST		0x01

#define PSIZE		(0x01 << 3)

#define DMARWEN		(0x03 << 1)

#define BUSWID		(0x01 << 4)

#define ECC4EN		(0x01 << 5)

#define WP		(0x01 << 24)

#define NANDCS		(0x01 << 25)

#define ENDADDR		(0x01 << 31)


#define read_data_reg(dev)		\
	__raw_readl((dev)->reg + REG_SMDATA)


#define write_data_reg(dev, val)	\
	__raw_writel((val), (dev)->reg + REG_SMDATA)


#define write_cmd_reg(dev, val)		\
	__raw_writel((val), (dev)->reg + REG_SMCMD)


#define write_addr_reg(dev, val)	\
	__raw_writel((val), (dev)->reg + REG_SMADDR)


struct nuc900_nand {
	
struct nand_chip chip;
	
void __iomem *reg;
	
struct clk *clk;
	
spinlock_t lock;
};


static inline struct nuc900_nand *mtd_to_nuc900(struct mtd_info *mtd) { return container_of(mtd_to_nand(mtd), struct nuc900_nand, chip); }

Contributors

PersonTokensPropCommitsCommitProp
Boris Brezillon28100.00%2100.00%
Total28100.00%2100.00%

static const struct mtd_partition partitions[] = { { .name = "NAND FS 0", .offset = 0, .size = 8 * 1024 * 1024 }, { .name = "NAND FS 1", .offset = MTDPART_OFS_APPEND, .size = MTDPART_SIZ_FULL } };
static unsigned char nuc900_nand_read_byte(struct mtd_info *mtd) { unsigned char ret; struct nuc900_nand *nand = mtd_to_nuc900(mtd); ret = (unsigned char)read_data_reg(nand); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun3587.50%133.33%
Boris Brezillon37.50%133.33%
David Woodhouse25.00%133.33%
Total40100.00%3100.00%


static void nuc900_nand_read_buf(struct mtd_info *mtd, unsigned char *buf, int len) { int i; struct nuc900_nand *nand = mtd_to_nuc900(mtd); for (i = 0; i < len; i++) buf[i] = (unsigned char)read_data_reg(nand); }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun5491.53%133.33%
Boris Brezillon35.08%133.33%
David Woodhouse23.39%133.33%
Total59100.00%3100.00%


static void nuc900_nand_write_buf(struct mtd_info *mtd, const unsigned char *buf, int len) { int i; struct nuc900_nand *nand = mtd_to_nuc900(mtd); for (i = 0; i < len; i++) write_data_reg(nand, buf[i]); }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun5191.07%133.33%
Boris Brezillon35.36%133.33%
David Woodhouse23.57%133.33%
Total56100.00%3100.00%


static int nuc900_check_rb(struct nuc900_nand *nand) { unsigned int val; spin_lock(&nand->lock); val = __raw_readl(nand->reg + REG_SMISR); val &= READYBUSY; spin_unlock(&nand->lock); return val; }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun4387.76%133.33%
Arnd Bergmann48.16%133.33%
David Woodhouse24.08%133.33%
Total49100.00%3100.00%


static int nuc900_nand_devready(struct mtd_info *mtd) { struct nuc900_nand *nand = mtd_to_nuc900(mtd); int ready; ready = (nuc900_check_rb(nand)) ? 1 : 0; return ready; }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun3280.00%133.33%
Boris Brezillon512.50%133.33%
David Woodhouse37.50%133.33%
Total40100.00%3100.00%


static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command, int column, int page_addr) { register struct nand_chip *chip = mtd_to_nand(mtd); struct nuc900_nand *nand = mtd_to_nuc900(mtd); if (command == NAND_CMD_READOOB) { column += mtd->writesize; command = NAND_CMD_READ0; } write_cmd_reg(nand, command & 0xff); if (column != -1 || page_addr != -1) { if (column != -1) { if (chip->options & NAND_BUSWIDTH_16 && !nand_opcode_8bits(command)) column >>= 1; write_addr_reg(nand, column); write_addr_reg(nand, column >> 8 | ENDADDR); } if (page_addr != -1) { write_addr_reg(nand, page_addr); if (chip->chipsize > (128 << 20)) { write_addr_reg(nand, page_addr >> 8); write_addr_reg(nand, page_addr >> 16 | ENDADDR); } else { write_addr_reg(nand, page_addr >> 8 | ENDADDR); } } } switch (command) { case NAND_CMD_CACHEDPROG: case NAND_CMD_PAGEPROG: case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: case NAND_CMD_RNDIN: case NAND_CMD_STATUS: return; case NAND_CMD_RESET: if (chip->dev_ready) break; udelay(chip->chip_delay); write_cmd_reg(nand, NAND_CMD_STATUS); write_cmd_reg(nand, command); while (!nuc900_check_rb(nand)) ; return; case NAND_CMD_RNDOUT: write_cmd_reg(nand, NAND_CMD_RNDOUTSTART); return; case NAND_CMD_READ0: write_cmd_reg(nand, NAND_CMD_READSTART); default: if (!chip->dev_ready) { udelay(chip->chip_delay); return; } } /* Apply this short delay always to ensure that we do wait tWB in * any case on any machine. */ ndelay(100); while (!chip->dev_ready(mtd)) ; }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun30295.27%120.00%
Boris Brezillon61.89%240.00%
Brian Norris61.89%120.00%
David Woodhouse30.95%120.00%
Total317100.00%5100.00%


static void nuc900_nand_enable(struct nuc900_nand *nand) { unsigned int val; spin_lock(&nand->lock); __raw_writel(RESET_FMI, (nand->reg + REG_FMICSR)); val = __raw_readl(nand->reg + REG_FMICSR); if (!(val & NAND_EN)) __raw_writel(val | NAND_EN, nand->reg + REG_FMICSR); val = __raw_readl(nand->reg + REG_SMCSR); val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS); val |= WP; __raw_writel(val, nand->reg + REG_SMCSR); spin_unlock(&nand->lock); }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun11495.00%133.33%
Dan Carpenter43.33%133.33%
David Woodhouse21.67%133.33%
Total120100.00%3100.00%


static int nuc900_nand_probe(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand; struct nand_chip *chip; struct mtd_info *mtd; struct resource *res; nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand), GFP_KERNEL); if (!nuc900_nand) return -ENOMEM; chip = &(nuc900_nand->chip); mtd = nand_to_mtd(chip); mtd->dev.parent = &pdev->dev; spin_lock_init(&nuc900_nand->lock); nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(nuc900_nand->clk)) return -ENOENT; clk_enable(nuc900_nand->clk); chip->cmdfunc = nuc900_nand_command_lp; chip->dev_ready = nuc900_nand_devready; chip->read_byte = nuc900_nand_read_byte; chip->write_buf = nuc900_nand_write_buf; chip->read_buf = nuc900_nand_read_buf; chip->chip_delay = 50; chip->options = 0; chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(nuc900_nand->reg)) return PTR_ERR(nuc900_nand->reg); nuc900_nand_enable(nuc900_nand); if (nand_scan(mtd, 1)) return -ENXIO; mtd_device_register(mtd, partitions, ARRAY_SIZE(partitions)); platform_set_drvdata(pdev, nuc900_nand); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun19472.66%114.29%
Jingoo Han2710.11%114.29%
David Woodhouse217.87%114.29%
Boris Brezillon93.37%114.29%
Rafał Miłecki83.00%114.29%
Frans Klaver72.62%114.29%
Jamie Iles10.37%114.29%
Total267100.00%7100.00%


static int nuc900_nand_remove(struct platform_device *pdev) { struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev); nand_release(nand_to_mtd(&nuc900_nand->chip)); clk_disable(nuc900_nand->clk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun2764.29%125.00%
Axel Lin716.67%125.00%
David Woodhouse49.52%125.00%
Boris Brezillon49.52%125.00%
Total42100.00%4100.00%

static struct platform_driver nuc900_nand_driver = { .probe = nuc900_nand_probe, .remove = nuc900_nand_remove, .driver = { .name = "nuc900-fmi", }, }; module_platform_driver(nuc900_nand_driver); MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); MODULE_DESCRIPTION("w90p910/NUC9xx nand driver!"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:nuc900-fmi");

Overall Contributors

PersonTokensPropCommitsCommitProp
Wan ZongShun110586.40%213.33%
Boris Brezillon614.77%320.00%
David Woodhouse473.67%16.67%
Jingoo Han272.11%16.67%
Axel Lin90.70%213.33%
Rafał Miłecki80.63%16.67%
Frans Klaver70.55%16.67%
Brian Norris60.47%16.67%
Dan Carpenter40.31%16.67%
Arnd Bergmann40.31%16.67%
Jamie Iles10.08%16.67%
Total1279100.00%15100.00%
Directory: drivers/mtd/nand
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.