📄 k9f5608.c
字号:
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
#include <asm/io.h>
/*
* MTD structure for s3c44b0 board
*/
static struct mtd_info *s3c44b0_mtd = NULL;
/*
* Values specific to the s3c44b0 board (used with s3c44b0 processor)
*/
#define S3C44B0_IO_BASE 0x01d20000 /* Start of s3c44b0 IO address space */
#define S3C44B0_FIO_BASE 0x04400000 /* Address where flash is mapped */
#define S3C44B0_PBDR 0x000c
#define S3C44B0_PCDR 0x0014
/*
* IO offset to Port C data register
* where the CLE, ALE and NCE pins
* are wired to.
*/
#define S3C44B0_PBDDR 0x0008
#define S3C44B0_PCDDR 0x0010
#define S3C44B0_PFDDR 0x0034 /*
* IO offset to Port F data direction
* register so we can control the IO
* lines.
*/
/*
* Module stuff
*/
static int s3c44b0_io_base = S3C44B0_IO_BASE;
static int s3c44b0_fio_base = S3C44B0_FIO_BASE;
static int s3c44b0_pbdr = S3C44B0_PBDR;
static int s3c44b0_pcdr = S3C44B0_PCDR;
static int s3c44b0_pbddr = S3C44B0_PBDDR;
static int s3c44b0_pcddr = S3C44B0_PCDDR;
static int s3c44b0_pfddr = S3C44B0_PFDDR;
#ifdef MODULE
MODULE_PARM(s3c44b0_io_base, "i");
MODULE_PARM(s3c44b0_fio_base, "i");
MODULE_PARM(s3c44b0_pbdr, "i");
MODULE_PARM(s3c44b0_pcdr, "i");
MODULE_PARM(s3c44b0_pbddr, "i");
MODULE_PARM(s3c44b0_pcddr, "i");
MODULE_PARM(s3c44b0_pfddr, "i");
__setup("s3c44b0_io_base = ", s3c44b0_io_base);
__setup("s3c44b0_fio_base = ", s3c44b0_fio_base);
__setup("s3c44b0_pbdr = ", s3c44b0_pbdr);
__setup("s3c44b0_pcdr = ", s3c44b0_pcdr);
__setup("s3c44b0_pbddr = ", s3c44b0_pbddr);
__setup("s3c44b0_pcddr = ", s3c44b0_pcddr);
__setup("s3c44b0_pfddr = ", s3c44b0_pfddr);
#endif
/*
* Define partitions for flash device
*/
const static struct mtd_partition partition_info[] = {
{ name: "S3C44B0 jffs2 partition",
offset: 0,
size: 32*1024*1024 },
};
#define NUM_PARTITIONS 1
/*
* hardware specific access to control-lines
*/
void s3c44b0_hwcontrol(int cmd) {
switch(cmd){
case NAND_CTL_SETCLE: (*(volatile unsigned char *)(s3c44b0_io_base + s3c44b0_pcdr)) |= 0x0200; break;
case NAND_CTL_CLRCLE: (*(volatile unsigned char *)(s3c44b0_io_base + s3c44b0_pcdr)) &= ~0x0200; break;
case NAND_CTL_SETALE: (*(volatile unsigned char *)(s3c44b0_io_base + s3c44b0_pcdr)) |= 0x0100; break;
case NAND_CTL_CLRALE: (*(volatile unsigned char *)(s3c44b0_io_base + s3c44b0_pcdr)) &= ~0x0100; break;
case NAND_CTL_SETNCE: (*(volatile unsigned char *)(s3c44b0_io_base + s3c44b0_pbdr)) &= ~0x200; break;
case NAND_CTL_CLRNCE: (*(volatile unsigned char *)(s3c44b0_io_base + s3c44b0_pbdr)) |= 0x200; break;
}
}
/*
* Main initialization routine
*/
int __init s3c44b0_init (void)
{
int i;
struct nand_chip *this;
/* Allocate memory for MTD device structure and private data */
s3c44b0_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
GFP_KERNEL);
if (!s3c44b0_mtd) {
printk ("Unable to allocate s3c44b0 NAND MTD device structure.\n");
return -ENOMEM;
}
/* Get pointer to private data */
this = (struct nand_chip *) (&s3c44b0_mtd[1]);
/* Initialize structures */
memset((char *) s3c44b0_mtd, 0, sizeof(struct mtd_info));
memset((char *) this, 0, sizeof(struct nand_chip));
/* Link the private data with the MTD structure */
s3c44b0_mtd->priv = this;
/*
* Set GPIO Port F control register so that the pins are configured
* to be outputs for controlling the NAND flash.
*/
(*(volatile unsigned *)(s3c44b0_io_base + s3c44b0_pbddr)) &= 0x5ff;//bit [9] set 0; or set 1 |0x200
(*(volatile unsigned *)(s3c44b0_io_base + s3c44b0_pcddr)) = 0x0ff5ffff;//[16,17]=01, [18,19]=01
(*(volatile unsigned *)(s3c44b0_io_base + s3c44b0_pfddr)) &= 0x3ffcf;//[4,5] set 0
//for (i=0;i<3000;i++);
/* Set address of NAND IO lines */
this->IO_ADDR_R = s3c44b0_fio_base;
this->IO_ADDR_W = s3c44b0_fio_base;
/* Set address of hardware control function */
this->hwcontrol = s3c44b0_hwcontrol;
/* 15 us command delay time */
this->chip_delay = 15;
/* Scan to find existence of the device */
if (nand_scan (s3c44b0_mtd)) {
kfree (s3c44b0_mtd);
return -ENXIO;
}
/* Allocate memory for internal data buffer */
this->data_buf = kmalloc (sizeof(u_char) * (s3c44b0_mtd->oobblock + s3c44b0_mtd->oobsize), GFP_KERNEL);
if (!this->data_buf) {
printk ("Unable to allocate NAND data buffer for s3c44b0.\n");
kfree (s3c44b0_mtd);
return -ENOMEM;
}
/* Allocate memory for internal data buffer */
this->data_cache = kmalloc (sizeof(u_char) * (s3c44b0_mtd->oobblock + s3c44b0_mtd->oobsize), GFP_KERNEL);
if (!this->data_cache) {
printk ("Unable to allocate NAND data cache for s3c44b0.\n");
kfree (this->data_buf);
kfree (s3c44b0_mtd);
return -ENOMEM;
}
this->cache_page = -1;
/* Register the partitions */
add_mtd_partitions(s3c44b0_mtd, (struct mtd_partition *)partition_info, NUM_PARTITIONS);
/* Return happy */
return 0;
}
module_init(s3c44b0_init);
/*
* Clean up routine
*/
#ifdef MODULE
static void __exit s3c44b0_cleanup (void)
{
struct nand_chip *this = (struct nand_chip *) &s3c44b0_mtd[1];
/* Unregister the device */
del_mtd_device (s3c44b0_mtd);
/* Free internal data buffer */
kfree (this->data_buf);
kfree (this->page_cache);
/* Free the MTD device structure */
kfree (s3c44b0_mtd);
}
module_exit(s3c44b0_cleanup);
#endif
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com");
MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on s3c44b0 board");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -