brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 76d50eb Raw
242 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  Copyright © 2008 Ilya Yanok, Emcraft Systems4 */5 6#include <linux/slab.h>7#include <linux/module.h>8#include <linux/mtd/mtd.h>9#include <linux/mtd/rawnand.h>10#include <linux/mtd/partitions.h>11#include <linux/of.h>12#include <linux/of_address.h>13#include <linux/platform_device.h>14#include <linux/io.h>15 16#define FPGA_NAND_CMD_MASK		(0x7 << 28)17#define FPGA_NAND_CMD_COMMAND		(0x0 << 28)18#define FPGA_NAND_CMD_ADDR		(0x1 << 28)19#define FPGA_NAND_CMD_READ		(0x2 << 28)20#define FPGA_NAND_CMD_WRITE		(0x3 << 28)21#define FPGA_NAND_BUSY			(0x1 << 15)22#define FPGA_NAND_ENABLE		(0x1 << 31)23#define FPGA_NAND_DATA_SHIFT		1624 25struct socrates_nand_host {26	struct nand_controller	controller;27	struct nand_chip	nand_chip;28	void __iomem		*io_base;29	struct device		*dev;30};31 32/**33 * socrates_nand_write_buf -  write buffer to chip34 * @this:	NAND chip object35 * @buf:	data buffer36 * @len:	number of bytes to write37 */38static void socrates_nand_write_buf(struct nand_chip *this, const uint8_t *buf,39				    int len)40{41	int i;42	struct socrates_nand_host *host = nand_get_controller_data(this);43 44	for (i = 0; i < len; i++) {45		out_be32(host->io_base, FPGA_NAND_ENABLE |46				FPGA_NAND_CMD_WRITE |47				(buf[i] << FPGA_NAND_DATA_SHIFT));48	}49}50 51/**52 * socrates_nand_read_buf -  read chip data into buffer53 * @this:	NAND chip object54 * @buf:	buffer to store date55 * @len:	number of bytes to read56 */57static void socrates_nand_read_buf(struct nand_chip *this, uint8_t *buf,58				   int len)59{60	int i;61	struct socrates_nand_host *host = nand_get_controller_data(this);62	uint32_t val;63 64	val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ;65 66	out_be32(host->io_base, val);67	for (i = 0; i < len; i++) {68		buf[i] = (in_be32(host->io_base) >>69				FPGA_NAND_DATA_SHIFT) & 0xff;70	}71}72 73/**74 * socrates_nand_read_byte -  read one byte from the chip75 * @mtd:	MTD device structure76 */77static uint8_t socrates_nand_read_byte(struct nand_chip *this)78{79	uint8_t byte;80	socrates_nand_read_buf(this, &byte, sizeof(byte));81	return byte;82}83 84/*85 * Hardware specific access to control-lines86 */87static void socrates_nand_cmd_ctrl(struct nand_chip *nand_chip, int cmd,88				   unsigned int ctrl)89{90	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);91	uint32_t val;92 93	if (cmd == NAND_CMD_NONE)94		return;95 96	if (ctrl & NAND_CLE)97		val = FPGA_NAND_CMD_COMMAND;98	else99		val = FPGA_NAND_CMD_ADDR;100 101	if (ctrl & NAND_NCE)102		val |= FPGA_NAND_ENABLE;103 104	val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT;105 106	out_be32(host->io_base, val);107}108 109/*110 * Read the Device Ready pin.111 */112static int socrates_nand_device_ready(struct nand_chip *nand_chip)113{114	struct socrates_nand_host *host = nand_get_controller_data(nand_chip);115 116	if (in_be32(host->io_base) & FPGA_NAND_BUSY)117		return 0; /* busy */118	return 1;119}120 121static int socrates_attach_chip(struct nand_chip *chip)122{123	if (chip->ecc.engine_type == NAND_ECC_ENGINE_TYPE_SOFT &&124	    chip->ecc.algo == NAND_ECC_ALGO_UNKNOWN)125		chip->ecc.algo = NAND_ECC_ALGO_HAMMING;126 127	return 0;128}129 130static const struct nand_controller_ops socrates_ops = {131	.attach_chip = socrates_attach_chip,132};133 134/*135 * Probe for the NAND device.136 */137static int socrates_nand_probe(struct platform_device *ofdev)138{139	struct socrates_nand_host *host;140	struct mtd_info *mtd;141	struct nand_chip *nand_chip;142	int res;143 144	/* Allocate memory for the device structure (and zero it) */145	host = devm_kzalloc(&ofdev->dev, sizeof(*host), GFP_KERNEL);146	if (!host)147		return -ENOMEM;148 149	host->io_base = of_iomap(ofdev->dev.of_node, 0);150	if (host->io_base == NULL) {151		dev_err(&ofdev->dev, "ioremap failed\n");152		return -EIO;153	}154 155	nand_chip = &host->nand_chip;156	mtd = nand_to_mtd(nand_chip);157	host->dev = &ofdev->dev;158 159	nand_controller_init(&host->controller);160	host->controller.ops = &socrates_ops;161	nand_chip->controller = &host->controller;162 163	/* link the private data structures */164	nand_set_controller_data(nand_chip, host);165	nand_set_flash_node(nand_chip, ofdev->dev.of_node);166	mtd->name = "socrates_nand";167	mtd->dev.parent = &ofdev->dev;168 169	nand_chip->legacy.cmd_ctrl = socrates_nand_cmd_ctrl;170	nand_chip->legacy.read_byte = socrates_nand_read_byte;171	nand_chip->legacy.write_buf = socrates_nand_write_buf;172	nand_chip->legacy.read_buf = socrates_nand_read_buf;173	nand_chip->legacy.dev_ready = socrates_nand_device_ready;174 175	/* TODO: I have no idea what real delay is. */176	nand_chip->legacy.chip_delay = 20;	/* 20us command delay time */177 178	/*179	 * This driver assumes that the default ECC engine should be TYPE_SOFT.180	 * Set ->engine_type before registering the NAND devices in order to181	 * provide a driver specific default value.182	 */183	nand_chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;184 185	dev_set_drvdata(&ofdev->dev, host);186 187	res = nand_scan(nand_chip, 1);188	if (res)189		goto out;190 191	res = mtd_device_register(mtd, NULL, 0);192	if (!res)193		return res;194 195	nand_cleanup(nand_chip);196 197out:198	iounmap(host->io_base);199	return res;200}201 202/*203 * Remove a NAND device.204 */205static void socrates_nand_remove(struct platform_device *ofdev)206{207	struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev);208	struct nand_chip *chip = &host->nand_chip;209	int ret;210 211	ret = mtd_device_unregister(nand_to_mtd(chip));212	WARN_ON(ret);213	nand_cleanup(chip);214 215	iounmap(host->io_base);216}217 218static const struct of_device_id socrates_nand_match[] =219{220	{221		.compatible   = "abb,socrates-nand",222	},223	{},224};225 226MODULE_DEVICE_TABLE(of, socrates_nand_match);227 228static struct platform_driver socrates_nand_driver = {229	.driver = {230		.name = "socrates_nand",231		.of_match_table = socrates_nand_match,232	},233	.probe		= socrates_nand_probe,234	.remove_new	= socrates_nand_remove,235};236 237module_platform_driver(socrates_nand_driver);238 239MODULE_LICENSE("GPL");240MODULE_AUTHOR("Ilya Yanok");241MODULE_DESCRIPTION("NAND driver for Socrates board");242