cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/mt29f_spinand/mt29f_spinand.c

/*
 * Copyright (c) 2003-2013 Broadcom Corporation
 *
 * Copyright (c) 2009-2010 Micron Technology, Inc.
 *
 * 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; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
#include <linux/spi/spi.h>

#include "mt29f_spinand.h"


#define BUFSIZE (10 * 64 * 2048)

#define CACHE_BUF 2112
/*
 * OOB area specification layout:  Total 32 available free bytes.
 */


static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd) { struct nand_chip *chip = mtd_to_nand(mtd); struct spinand_info *info = nand_get_controller_data(chip); struct spinand_state *state = info->priv; return state; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel4086.96%133.33%
Boris Brezillon613.04%266.67%
Total46100.00%3100.00%

#ifdef CONFIG_MTD_SPINAND_ONDIEECC static int enable_hw_ecc; static int enable_read_hw_ecc;
static int spinand_ooblayout_64_ecc(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { if (section > 3) return -ERANGE; oobregion->offset = (section * 16) + 1; oobregion->length = 6; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Boris Brezillon4182.00%150.00%
Kamlakant Patel918.00%150.00%
Total50100.00%2100.00%


static int spinand_ooblayout_64_free(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion) { if (section > 3) return -ERANGE; oobregion->offset = (section * 16) + 8; oobregion->length = 8; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Boris Brezillon4284.00%150.00%
Kamlakant Patel816.00%150.00%
Total50100.00%2100.00%

static const struct mtd_ooblayout_ops spinand_oob_64_ops = { .ecc = spinand_ooblayout_64_ecc, .free = spinand_ooblayout_64_free, }; #endif /** * spinand_cmd - process a command to send to the SPI Nand * Description: * Set up the command buffer to send to the SPI controller. * The command buffer has to initialized to 0. */
static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd) { struct spi_message message; struct spi_transfer x[4]; u8 dummy = 0xff; spi_message_init(&message); memset(x, 0, sizeof(x)); x[0].len = 1; x[0].tx_buf = &cmd->cmd; spi_message_add_tail(&x[0], &message); if (cmd->n_addr) { x[1].len = cmd->n_addr; x[1].tx_buf = cmd->addr; spi_message_add_tail(&x[1], &message); } if (cmd->n_dummy) { x[2].len = cmd->n_dummy; x[2].tx_buf = &dummy; spi_message_add_tail(&x[2], &message); } if (cmd->n_tx) { x[3].len = cmd->n_tx; x[3].tx_buf = cmd->tx_buf; spi_message_add_tail(&x[3], &message); } if (cmd->n_rx) { x[3].len = cmd->n_rx; x[3].rx_buf = cmd->rx_buf; spi_message_add_tail(&x[3], &message); } return spi_sync(spi, &message); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel259100.00%1100.00%
Total259100.00%1100.00%

/** * spinand_read_id - Read SPI Nand ID * Description: * read two ID bytes from the SPI Nand device */
static int spinand_read_id(struct spi_device *spi_nand, u8 *id) { int retval; u8 nand_id[3]; struct spinand_cmd cmd = {0}; cmd.cmd = CMD_READ_ID; cmd.n_rx = 3; cmd.rx_buf = &nand_id[0]; retval = spinand_cmd(spi_nand, &cmd); if (retval < 0) { dev_err(&spi_nand->dev, "error %d reading id\n", retval); return retval; } id[0] = nand_id[1]; id[1] = nand_id[2]; return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel110100.00%1100.00%
Total110100.00%1100.00%

/** * spinand_read_status - send command 0xf to the SPI Nand status register * Description: * After read, write, or erase, the Nand device is expected to set the * busy status. * This function is to allow reading the status of the command: read, * write, and erase. * Once the status turns to be ready, the other status bits also are * valid status bits. */
static int spinand_read_status(struct spi_device *spi_nand, u8 *status) { struct spinand_cmd cmd = {0}; int ret; cmd.cmd = CMD_READ_REG; cmd.n_addr = 1; cmd.addr[0] = REG_STATUS; cmd.n_rx = 1; cmd.rx_buf = status; ret = spinand_cmd(spi_nand, &cmd); if (ret < 0) dev_err(&spi_nand->dev, "err: %d read status register\n", ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel8998.89%150.00%
Eva Rachel Retuya11.11%150.00%
Total90100.00%2100.00%

#define MAX_WAIT_JIFFIES (40 * HZ)
static int wait_till_ready(struct spi_device *spi_nand) { unsigned long deadline; int retval; u8 stat = 0; deadline = jiffies + MAX_WAIT_JIFFIES; do { retval = spinand_read_status(spi_nand, &stat); if (retval < 0) return -1; if (!(stat & 0x1)) break; cond_resched(); } while (!time_after_eq(jiffies, deadline)); if ((stat & 0x1) == 0) return 0; return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel93100.00%1100.00%
Total93100.00%1100.00%

/** * spinand_get_otp - send command 0xf to read the SPI Nand OTP register * Description: * There is one bit( bit 0x10 ) to set or to clear the internal ECC. * Enable chip internal ECC, set the bit to 1 * Disable chip internal ECC, clear the bit to 0 */
static int spinand_get_otp(struct spi_device *spi_nand, u8 *otp) { struct spinand_cmd cmd = {0}; int retval; cmd.cmd = CMD_READ_REG; cmd.n_addr = 1; cmd.addr[0] = REG_OTP; cmd.n_rx = 1; cmd.rx_buf = otp; retval = spinand_cmd(spi_nand, &cmd); if (retval < 0) dev_err(&spi_nand->dev, "error %d get otp\n", retval); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel90100.00%1100.00%
Total90100.00%1100.00%

/** * spinand_set_otp - send command 0x1f to write the SPI Nand OTP register * Description: * There is one bit( bit 0x10 ) to set or to clear the internal ECC. * Enable chip internal ECC, set the bit to 1 * Disable chip internal ECC, clear the bit to 0 */
static int spinand_set_otp(struct spi_device *spi_nand, u8 *otp) { int retval; struct spinand_cmd cmd = {0}; cmd.cmd = CMD_WRITE_REG; cmd.n_addr = 1; cmd.addr[0] = REG_OTP; cmd.n_tx = 1; cmd.tx_buf = otp; retval = spinand_cmd(spi_nand, &cmd); if (retval < 0) dev_err(&spi_nand->dev, "error %d set otp\n", retval); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel8594.44%150.00%
Manuel Pégourié-Gonnard55.56%150.00%
Total90100.00%2100.00%

#ifdef CONFIG_MTD_SPINAND_ONDIEECC /** * spinand_enable_ecc - send command 0x1f to write the SPI Nand OTP register * Description: * There is one bit( bit 0x10 ) to set or to clear the internal ECC. * Enable chip internal ECC, set the bit to 1 * Disable chip internal ECC, clear the bit to 0 */
static int spinand_enable_ecc(struct spi_device *spi_nand) { int retval; u8 otp = 0; retval = spinand_get_otp(spi_nand, &otp); if (retval < 0) return retval; if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) return 0; otp |= OTP_ECC_MASK; retval = spinand_set_otp(spi_nand, &otp); if (retval < 0) return retval; return spinand_get_otp(spi_nand, &otp); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel83100.00%1100.00%
Total83100.00%1100.00%

#endif
static int spinand_disable_ecc(struct spi_device *spi_nand) { int retval; u8 otp = 0; retval = spinand_get_otp(spi_nand, &otp); if (retval < 0) return retval; if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) { otp &= ~OTP_ECC_MASK; retval = spinand_set_otp(spi_nand, &otp); if (retval < 0) return retval; return spinand_get_otp(spi_nand, &otp); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel86100.00%1100.00%
Total86100.00%1100.00%

/** * spinand_write_enable - send command 0x06 to enable write or erase the * Nand cells * Description: * Before write and erase the Nand cells, the write enable has to be set. * After the write or erase, the write enable bit is automatically * cleared (status register bit 2) * Set the bit 2 of the status register has the same effect */
static int spinand_write_enable(struct spi_device *spi_nand) { struct spinand_cmd cmd = {0}; cmd.cmd = CMD_WR_ENABLE; return spinand_cmd(spi_nand, &cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel34100.00%1100.00%
Total34100.00%1100.00%


static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id) { struct spinand_cmd cmd = {0}; u16 row; row = page_id; cmd.cmd = CMD_READ; cmd.n_addr = 3; cmd.addr[1] = (u8)((row & 0xff00) >> 8); cmd.addr[2] = (u8)(row & 0x00ff); return spinand_cmd(spi_nand, &cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel86100.00%1100.00%
Total86100.00%1100.00%

/** * spinand_read_from_cache - send command 0x03 to read out the data from the * cache register (2112 bytes max) * Description: * The read can specify 1 to 2112 bytes of data read at the corresponding * locations. * No tRd delay. */
static int spinand_read_from_cache(struct spi_device *spi_nand, u16 page_id, u16 byte_id, u16 len, u8 *rbuf) { struct spinand_cmd cmd = {0}; u16 column; column = byte_id; cmd.cmd = CMD_READ_RDM; cmd.n_addr = 3; cmd.addr[0] = (u8)((column & 0xff00) >> 8); cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4); cmd.addr[1] = (u8)(column & 0x00ff); cmd.addr[2] = (u8)(0xff); cmd.n_dummy = 0; cmd.n_rx = len; cmd.rx_buf = rbuf; return spinand_cmd(spi_nand, &cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel152100.00%1100.00%
Total152100.00%1100.00%

/** * spinand_read_page - read a page * @page_id: the physical page number * @offset: the location from 0 to 2111 * @len: number of bytes to read * @rbuf: read buffer to hold @len bytes * * Description: * The read includes two commands to the Nand - 0x13 and 0x03 commands * Poll to read status to wait for tRD time. */
static int spinand_read_page(struct spi_device *spi_nand, u16 page_id, u16 offset, u16 len, u8 *rbuf) { int ret; u8 status = 0; #ifdef CONFIG_MTD_SPINAND_ONDIEECC if (enable_read_hw_ecc) { if (spinand_enable_ecc(spi_nand) < 0) dev_err(&spi_nand->dev, "enable HW ECC failed!"); } #endif ret = spinand_read_page_to_cache(spi_nand, page_id); if (ret < 0) return ret; if (wait_till_ready(spi_nand)) dev_err(&spi_nand->dev, "WAIT timedout!!!\n"); while (1) { ret = spinand_read_status(spi_nand, &status); if (ret < 0) { dev_err(&spi_nand->dev, "err %d read status register\n", ret); return ret; } if ((status & STATUS_OIP_MASK) == STATUS_READY) { if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) { dev_err(&spi_nand->dev, "ecc error, page=%d\n", page_id); return 0; } break; } } ret = spinand_read_from_cache(spi_nand, page_id, offset, len, rbuf); if (ret < 0) { dev_err(&spi_nand->dev, "read from cache failed!!\n"); return ret; } #ifdef CONFIG_MTD_SPINAND_ONDIEECC if (enable_read_hw_ecc) { ret = spinand_disable_ecc(spi_nand); if (ret < 0) { dev_err(&spi_nand->dev, "disable ecc failed!!\n"); return ret; } enable_read_hw_ecc = 0; } #endif return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel258100.00%1100.00%
Total258100.00%1100.00%

/** * spinand_program_data_to_cache - write a page to cache * @byte_id: the location to write to the cache * @len: number of bytes to write * @wbuf: write buffer holding @len bytes * * Description: * The write command used here is 0x84--indicating that the cache is * not cleared first. * Since it is writing the data to cache, there is no tPROG time. */
static int spinand_program_data_to_cache(struct spi_device *spi_nand, u16 page_id, u16 byte_id, u16 len, u8 *wbuf) { struct spinand_cmd cmd = {0}; u16 column; column = byte_id; cmd.cmd = CMD_PROG_PAGE_CLRCACHE; cmd.n_addr = 2; cmd.addr[0] = (u8)((column & 0xff00) >> 8); cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4); cmd.addr[1] = (u8)(column & 0x00ff); cmd.n_tx = len; cmd.tx_buf = wbuf; return spinand_cmd(spi_nand, &cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel132100.00%1100.00%
Total132100.00%1100.00%

/** * spinand_program_execute - write a page from cache to the Nand array * @page_id: the physical page location to write the page. * * Description: * The write command used here is 0x10--indicating the cache is writing to * the Nand array. * Need to wait for tPROG time to finish the transaction. */
static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id) { struct spinand_cmd cmd = {0}; u16 row; row = page_id; cmd.cmd = CMD_PROG_PAGE_EXC; cmd.n_addr = 3; cmd.addr[1] = (u8)((row & 0xff00) >> 8); cmd.addr[2] = (u8)(row & 0x00ff); return spinand_cmd(spi_nand, &cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel86100.00%1100.00%
Total86100.00%1100.00%

/** * spinand_program_page - write a page * @page_id: the physical page location to write the page. * @offset: the location from the cache starting from 0 to 2111 * @len: the number of bytes to write * @buf: the buffer holding @len bytes * * Description: * The commands used here are 0x06, 0x84, and 0x10--indicating that * the write enable is first sent, the write cache command, and the * write execute command. * Poll to wait for the tPROG time to finish the transaction. */
static int spinand_program_page(struct spi_device *spi_nand, u16 page_id, u16 offset, u16 len, u8 *buf) { int retval; u8 status = 0; u8 *wbuf; #ifdef CONFIG_MTD_SPINAND_ONDIEECC unsigned int i, j; wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL); if (!wbuf) return -ENOMEM; enable_read_hw_ecc = 0; spinand_read_page(spi_nand, page_id, 0, CACHE_BUF, wbuf); for (i = offset, j = 0; i < len; i++, j++) wbuf[i] &= buf[j]; if (enable_hw_ecc) { retval = spinand_enable_ecc(spi_nand); if (retval < 0) { dev_err(&spi_nand->dev, "enable ecc failed!!\n"); return retval; } } #else wbuf = buf; #endif retval = spinand_write_enable(spi_nand); if (retval < 0) { dev_err(&spi_nand->dev, "write enable failed!!\n"); return retval; } if (wait_till_ready(spi_nand)) dev_err(&spi_nand->dev, "wait timedout!!!\n"); retval = spinand_program_data_to_cache(spi_nand, page_id, offset, len, wbuf); if (retval < 0) return retval; retval = spinand_program_execute(spi_nand, page_id); if (retval < 0) return retval; while (1) { retval = spinand_read_status(spi_nand, &status); if (retval < 0) { dev_err(&spi_nand->dev, "error %d reading status register\n", retval); return retval; } if ((status & STATUS_OIP_MASK) == STATUS_READY) { if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) { dev_err(&spi_nand->dev, "program error, page %d\n", page_id); return -1; } break; } } #ifdef CONFIG_MTD_SPINAND_ONDIEECC if (enable_hw_ecc) { retval = spinand_disable_ecc(spi_nand); if (retval < 0) { dev_err(&spi_nand->dev, "disable ecc failed!!\n"); return retval; } enable_hw_ecc = 0; } #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel35696.22%133.33%
Manuel Pégourié-Gonnard133.51%133.33%
Eva Rachel Retuya10.27%133.33%
Total370100.00%3100.00%

/** * spinand_erase_block_erase - erase a page * @block_id: the physical block location to erase. * * Description: * The command used here is 0xd8--indicating an erase command to erase * one block--64 pages * Need to wait for tERS. */
static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id) { struct spinand_cmd cmd = {0}; u16 row; row = block_id; cmd.cmd = CMD_ERASE_BLK; cmd.n_addr = 3; cmd.addr[1] = (u8)((row & 0xff00) >> 8); cmd.addr[2] = (u8)(row & 0x00ff); return spinand_cmd(spi_nand, &cmd); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel86100.00%1100.00%
Total86100.00%1100.00%

/** * spinand_erase_block - erase a page * @block_id: the physical block location to erase. * * Description: * The commands used here are 0x06 and 0xd8--indicating an erase * command to erase one block--64 pages * It will first to enable the write enable bit (0x06 command), * and then send the 0xd8 erase command * Poll to wait for the tERS time to complete the tranaction. */
static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id) { int retval; u8 status = 0; retval = spinand_write_enable(spi_nand); if (wait_till_ready(spi_nand)) dev_err(&spi_nand->dev, "wait timedout!!!\n"); retval = spinand_erase_block_erase(spi_nand, block_id); while (1) { retval = spinand_read_status(spi_nand, &status); if (retval < 0) { dev_err(&spi_nand->dev, "error %d reading status register\n", retval); return retval; } if ((status & STATUS_OIP_MASK) == STATUS_READY) { if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) { dev_err(&spi_nand->dev, "erase error, block %d\n", block_id); return -1; } break; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel138100.00%1100.00%
Total138100.00%1100.00%

#ifdef CONFIG_MTD_SPINAND_ONDIEECC
static int spinand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, const u8 *buf, int oob_required, int page) { const u8 *p = buf; int eccsize = chip->ecc.size; int eccsteps = chip->ecc.steps; enable_hw_ecc = 1; chip->write_buf(mtd, p, eccsize * eccsteps); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel6793.06%133.33%
Boris Brezillon34.17%133.33%
Eva Rachel Retuya22.78%133.33%
Total72100.00%3100.00%


static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, int oob_required, int page) { int retval; u8 status; u8 *p = buf; int eccsize = chip->ecc.size; int eccsteps = chip->ecc.steps; struct spinand_info *info = nand_get_controller_data(chip); enable_read_hw_ecc = 1; chip->read_buf(mtd, p, eccsize * eccsteps); if (oob_required) chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); while (1) { retval = spinand_read_status(info->spi, &status); if (retval < 0) { dev_err(&mtd->dev, "error %d reading status register\n", retval); return retval; } if ((status & STATUS_OIP_MASK) == STATUS_READY) { if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) { pr_info("spinand: ECC error\n"); mtd->ecc_stats.failed++; } else if ((status & STATUS_ECC_MASK) == STATUS_ECC_1BIT_CORRECTED) mtd->ecc_stats.corrected++; break; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel17084.58%125.00%
Devendra Naga2612.94%125.00%
Boris Brezillon31.49%125.00%
Eva Rachel Retuya21.00%125.00%
Total201100.00%4100.00%

#endif
static void spinand_select_chip(struct mtd_info *mtd, int dev) { }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel13100.00%1100.00%
Total13100.00%1100.00%


static u8 spinand_read_byte(struct mtd_info *mtd) { struct spinand_state *state = mtd_to_state(mtd); u8 data; data = state->buf[state->buf_ptr]; state->buf_ptr++; return data; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel4297.67%150.00%
Eva Rachel Retuya12.33%150.00%
Total43100.00%2100.00%


static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip) { struct spinand_info *info = nand_get_controller_data(chip); unsigned long timeo = jiffies; int retval, state = chip->state; u8 status; if (state == FL_ERASING) timeo += (HZ * 400) / 1000; else timeo += (HZ * 20) / 1000; while (time_before(jiffies, timeo)) { retval = spinand_read_status(info->spi, &status); if (retval < 0) { dev_err(&mtd->dev, "error %d reading status register\n", retval); return retval; } if ((status & STATUS_OIP_MASK) == STATUS_READY) return 0; cond_resched(); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel11080.88%133.33%
Devendra Naga2316.91%133.33%
Boris Brezillon32.21%133.33%
Total136100.00%3100.00%


static void spinand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) { struct spinand_state *state = mtd_to_state(mtd); memcpy(state->buf + state->buf_ptr, buf, len); state->buf_ptr += len; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel4998.00%150.00%
Eva Rachel Retuya12.00%150.00%
Total50100.00%2100.00%


static void spinand_read_buf(struct mtd_info *mtd, u8 *buf, int len) { struct spinand_state *state = mtd_to_state(mtd); memcpy(buf, state->buf + state->buf_ptr, len); state->buf_ptr += len; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel4897.96%150.00%
Eva Rachel Retuya12.04%150.00%
Total49100.00%2100.00%

/* * spinand_reset- send RESET command "0xff" to the Nand device. */
static void spinand_reset(struct spi_device *spi_nand) { struct spinand_cmd cmd = {0}; cmd.cmd = CMD_RESET; if (spinand_cmd(spi_nand, &cmd) < 0) pr_info("spinand reset failed!\n"); /* elapse 1ms before issuing any other command */ usleep_range(1000, 2000); if (wait_till_ready(spi_nand)) dev_err(&spi_nand->dev, "wait timedout!\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel6495.52%150.00%
Eva Rachel Retuya34.48%150.00%
Total67100.00%2100.00%


static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command, int column, int page) { struct nand_chip *chip = mtd_to_nand(mtd); struct spinand_info *info = nand_get_controller_data(chip); struct spinand_state *state = info->priv; switch (command) { /* * READ0 - read in first 0x800 bytes */ case NAND_CMD_READ1: case NAND_CMD_READ0: state->buf_ptr = 0; spinand_read_page(info->spi, page, 0x0, 0x840, state->buf); break; /* READOOB reads only the OOB because no ECC is performed. */ case NAND_CMD_READOOB: state->buf_ptr = 0; spinand_read_page(info->spi, page, 0x800, 0x40, state->buf); break; case NAND_CMD_RNDOUT: state->buf_ptr = column; break; case NAND_CMD_READID: state->buf_ptr = 0; spinand_read_id(info->spi, state->buf); break; case NAND_CMD_PARAM: state->buf_ptr = 0; break; /* ERASE1 stores the block and page address */ case NAND_CMD_ERASE1: spinand_erase_block(info->spi, page); break; /* ERASE2 uses the block and page address from ERASE1 */ case NAND_CMD_ERASE2: break; /* SEQIN sets up the addr buffer and all registers except the length */ case NAND_CMD_SEQIN: state->col = column; state->row = page; state->buf_ptr = 0; break; /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ case NAND_CMD_PAGEPROG: spinand_program_page(info->spi, state->row, state->col, state->buf_ptr, state->buf); break; case NAND_CMD_STATUS: spinand_get_otp(info->spi, state->buf); if (!(state->buf[0] & 0x80)) state->buf[0] = 0x80; state->buf_ptr = 0; break; /* RESET command */ case NAND_CMD_RESET: if (wait_till_ready(info->spi)) dev_err(&info->spi->dev, "WAIT timedout!!!\n"); /* a minimum of 250us must elapse before issuing RESET cmd*/ usleep_range(250, 1000); spinand_reset(info->spi); break; default: dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command); } }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel31597.22%125.00%
Boris Brezillon61.85%250.00%
Eva Rachel Retuya30.93%125.00%
Total324100.00%4100.00%

/** * spinand_lock_block - send write register 0x1f command to the Nand device * * Description: * After power up, all the Nand blocks are locked. This function allows * one to unlock the blocks, and so it can be written or erased. */
static int spinand_lock_block(struct spi_device *spi_nand, u8 lock) { struct spinand_cmd cmd = {0}; int ret; u8 otp = 0; ret = spinand_get_otp(spi_nand, &otp); cmd.cmd = CMD_WRITE_REG; cmd.n_addr = 1; cmd.addr[0] = REG_BLOCK_LOCK; cmd.n_tx = 1; cmd.tx_buf = &lock; ret = spinand_cmd(spi_nand, &cmd); if (ret < 0) dev_err(&spi_nand->dev, "error %d lock block\n", ret); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel105100.00%1100.00%
Total105100.00%1100.00%

/** * spinand_probe - [spinand Interface] * @spi_nand: registered device driver. * * Description: * Set up the device driver parameters to make the device available. */
static int spinand_probe(struct spi_device *spi_nand) { struct mtd_info *mtd; struct nand_chip *chip; struct spinand_info *info; struct spinand_state *state; info = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info), GFP_KERNEL); if (!info) return -ENOMEM; info->spi = spi_nand; spinand_lock_block(spi_nand, BL_ALL_UNLOCKED); state = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_state), GFP_KERNEL); if (!state) return -ENOMEM; info->priv = state; state->buf_ptr = 0; state->buf = devm_kzalloc(&spi_nand->dev, BUFSIZE, GFP_KERNEL); if (!state->buf) return -ENOMEM; chip = devm_kzalloc(&spi_nand->dev, sizeof(struct nand_chip), GFP_KERNEL); if (!chip) return -ENOMEM; #ifdef CONFIG_MTD_SPINAND_ONDIEECC chip->ecc.mode = NAND_ECC_HW; chip->ecc.size = 0x200; chip->ecc.bytes = 0x6; chip->ecc.steps = 0x4; chip->ecc.strength = 1; chip->ecc.total = chip->ecc.steps * chip->ecc.bytes; chip->ecc.read_page = spinand_read_page_hwecc; chip->ecc.write_page = spinand_write_page_hwecc; #else chip->ecc.mode = NAND_ECC_SOFT; chip->ecc.algo = NAND_ECC_HAMMING; if (spinand_disable_ecc(spi_nand) < 0) dev_info(&spi_nand->dev, "%s: disable ecc failed!\n", __func__); #endif nand_set_flash_node(chip, spi_nand->dev.of_node); nand_set_controller_data(chip, info); chip->read_buf = spinand_read_buf; chip->write_buf = spinand_write_buf; chip->read_byte = spinand_read_byte; chip->cmdfunc = spinand_cmdfunc; chip->waitfunc = spinand_wait; chip->options |= NAND_CACHEPRG; chip->select_chip = spinand_select_chip; mtd = nand_to_mtd(chip); dev_set_drvdata(&spi_nand->dev, mtd); mtd->dev.parent = &spi_nand->dev; mtd->oobsize = 64; #ifdef CONFIG_MTD_SPINAND_ONDIEECC mtd_set_ooblayout(mtd, &spinand_oob_64_ops); #endif if (nand_scan(mtd, 1)) return -ENXIO; return mtd_device_register(mtd, NULL, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel36488.35%112.50%
Boris Brezillon194.61%337.50%
Brian Norris122.91%112.50%
Rafał Miłecki81.94%112.50%
G Pooja Shamili61.46%112.50%
Frans Klaver30.73%112.50%
Total412100.00%8100.00%

/** * spinand_remove - remove the device driver * @spi: the spi device. * * Description: * Remove the device driver parameters and free up allocated memories. */
static int spinand_remove(struct spi_device *spi) { mtd_device_unregister(dev_get_drvdata(&spi->dev)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel25100.00%1100.00%
Total25100.00%1100.00%

static const struct of_device_id spinand_dt[] = { { .compatible = "spinand,mt29f", }, {} }; MODULE_DEVICE_TABLE(of, spinand_dt); /* * Device name structure description */ static struct spi_driver spinand_driver = { .driver = { .name = "mt29f", .of_match_table = spinand_dt, }, .probe = spinand_probe, .remove = spinand_remove, }; module_spi_driver(spinand_driver); MODULE_DESCRIPTION("SPI NAND driver for Micron"); MODULE_AUTHOR("Henry Pan <hspan@micron.com>, Kamlakant Patel <kamlakant.patel@broadcom.com>"); MODULE_LICENSE("GPL v2");

Overall Contributors

PersonTokensPropCommitsCommitProp
Kamlakant Patel377392.98%15.00%
Boris Brezillon1343.30%525.00%
Devendra Naga491.21%15.00%
Manuel Pégourié-Gonnard350.86%315.00%
Eva Rachel Retuya150.37%210.00%
Brian Norris120.30%15.00%
Randy Dunlap110.27%15.00%
Rafał Miłecki80.20%15.00%
Javier Martinez Canillas70.17%15.00%
G Pooja Shamili60.15%15.00%
Stephen Boyd30.07%15.00%
Frans Klaver30.07%15.00%
Sachin Kamat20.05%15.00%
Total4058100.00%20100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.