Created
October 26, 2014 19:23
-
-
Save Mm7/350f7499b9bd2cdd39f3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* linux/drivers/mtd/onenand/msm.c | |
* | |
* OneNAND driver for MSM | |
* | |
* Copyright © 2014 androidarmv6 project | |
* | |
* This program is free software; you can redistribute it and/or modify it | |
* under the terms of the GNU General Public License version 2 as published by | |
* the Free Software Foundation. | |
* | |
* 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. | |
* | |
* You should have received a copy of the GNU General Public License along with | |
* this program; see the file COPYING. If not, write to the Free Software | |
* Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
* | |
*/ | |
#include <linux/io.h> | |
#include <linux/module.h> | |
#include <linux/mtd/mtd.h> | |
#include <linux/mtd/onenand.h> | |
#include <linux/mtd/onenand_regs.h> | |
#include <linux/mtd/partitions.h> | |
#include <linux/platform_device.h> | |
#include <linux/slab.h> | |
#include <asm/io.h> | |
#include "msm.h" | |
#define SFLASH_PREPCMD(numxfr, offval, delval, trnstp, mode, opcode) \ | |
((numxfr<<20)|(offval<<12)|(delval<<6)|(trnstp<<5)|(mode<<4)|opcode) | |
#define DRIVER_NAME "msm-onenand" | |
struct msm_onenand { | |
struct onenand_chip *this; | |
unsigned long phys_base; | |
unsigned long size; | |
volatile uint32_t *base; | |
struct mtd_info *mtd; | |
struct mtd_partition *parts; | |
}; | |
static struct msm_onenand *onenand; | |
#ifdef CONFIG_MTD_PARTITIONS | |
static const char *part_probes[] = { "cmdlinepart", NULL, }; | |
#endif | |
extern void FSR_PAM_InitNANDController(void); | |
extern void FSR_PAM_WriteToOneNANDRegister(uint32_t addr, uint16_t value); | |
extern uint16_t FSR_PAM_ReadOneNANDRegister(uint32_t addr); | |
extern void FSR_PAM_TransToNAND(volatile void *pDst, void *pSrc, uint32_t nSize); | |
extern void FSR_PAM_TransFromNAND(volatile void *pDst, void *pSrc, uint32_t nSize); | |
static void msm_onenand_writew(unsigned short value, void __iomem *addr) | |
{ | |
FSR_PAM_WriteToOneNANDRegister((uint32_t)addr, value); | |
} | |
static unsigned short msm_onenand_readw(void __iomem *addr) | |
{ | |
return FSR_PAM_ReadOneNANDRegister((uint32_t)addr); | |
} | |
static int msm_onenand_write_bufferram(struct mtd_info *mtd, int area, const unsigned char *buffer, int offset, size_t count) | |
{ | |
FSR_PAM_TransToNAND((volatile void *)(area+offset), (void *)buffer, count); | |
return 0; | |
} | |
static int msm_onenand_read_bufferram(struct mtd_info *mtd, int area, unsigned char *buffer, int offset, size_t count) | |
{ | |
FSR_PAM_TransFromNAND(buffer, (void *)(area+offset), count); | |
return 0; | |
} | |
static int __devinit msm_onenand_probe(struct platform_device *pdev) | |
{ | |
struct onenand_platform_data *pdata; | |
int err; | |
int i, nr_parts; | |
pdata = pdev->dev.platform_data; | |
onenand = kzalloc(sizeof(struct msm_onenand), GFP_KERNEL); | |
if (!onenand) { | |
dev_err(&pdev->dev, "msm-onenand: Failed to allocate memory\n"); | |
return -ENOMEM; | |
} | |
onenand->mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL); | |
if (!onenand->mtd) { | |
dev_err(&pdev->dev, "msm-onenand: Failed to allocate memory\n"); | |
err = -ENOMEM; | |
goto free_onenand; | |
} | |
onenand->this = kzalloc(sizeof(struct onenand_chip), GFP_KERNEL); | |
if (!onenand->this) { | |
dev_err(&pdev->dev, "msm-onenand: Failed to allocate memory\n"); | |
err = -ENOMEM; | |
goto free_mtd; | |
} | |
onenand->this->base = 0; | |
onenand->mtd->name = dev_name(&pdev->dev); | |
onenand->mtd->priv = onenand->this; | |
onenand->mtd->dev.parent = &pdev->dev; | |
onenand->mtd->owner = THIS_MODULE; | |
onenand->this->read_word = msm_onenand_readw; | |
onenand->this->write_word = msm_onenand_writew; | |
onenand->this->read_bufferram = msm_onenand_read_bufferram; | |
onenand->this->write_bufferram = msm_onenand_write_bufferram; | |
FSR_PAM_InitNANDController(); | |
if (onenand_scan(onenand->mtd, 1)) { | |
printk("msm-onenand: OneNAND scan failed\n"); | |
err = -EFAULT; | |
goto unmap_onenand; | |
} | |
#ifdef CONFIG_MTD_PARTITIONS | |
for (i = 0; i < pdata->nr_parts; i++) { | |
pdata->parts[i].offset = pdata->parts[i].offset * onenand->mtd->erasesize; | |
pdata->parts[i].size = pdata->parts[i].size * onenand->mtd->erasesize; | |
} | |
nr_parts = parse_mtd_partitions(onenand->mtd, part_probes, &onenand->parts, 0); | |
if (nr_parts > 0) | |
add_mtd_partitions(onenand->mtd, onenand->parts, nr_parts); | |
else if (nr_parts <= 0 && pdata && pdata->parts) | |
add_mtd_partitions(onenand->mtd, pdata->parts, pdata->nr_parts); | |
else | |
add_mtd_device(onenand->mtd); | |
#else | |
add_mtd_device(onenand->mtd); | |
#endif | |
platform_set_drvdata(pdev, onenand); | |
return 0; | |
unmap_onenand: | |
kfree(onenand->this); | |
free_mtd: | |
kfree(onenand->mtd); | |
free_onenand: | |
kfree(onenand); | |
return err; | |
} | |
static int __devexit msm_onenand_remove(struct platform_device *pdev) | |
{ | |
#ifdef CONFIG_MTD_PARTITIONS | |
if (onenand->parts) | |
del_mtd_partitions(onenand->mtd); | |
else | |
del_mtd_device(onenand->mtd); | |
#else | |
del_mtd_device(onenand->mtd); | |
#endif | |
kfree(onenand->this); | |
kfree(onenand->mtd); | |
kfree(onenand); | |
return 0; | |
} | |
static struct platform_driver msm_onenand_driver = { | |
.probe = msm_onenand_probe, | |
.remove = __devexit_p(msm_onenand_remove), | |
.driver = { | |
.name = DRIVER_NAME, | |
.owner = THIS_MODULE, | |
}, | |
}; | |
static int __init msm_onenand_init(void) | |
{ | |
printk(KERN_INFO "OneNAND driver initializing\n"); | |
return platform_driver_register(&msm_onenand_driver); | |
} | |
static void __exit msm_onenand_exit(void) | |
{ | |
platform_driver_unregister(&msm_onenand_driver); | |
} | |
module_init(msm_onenand_init); | |
module_exit(msm_onenand_exit); | |
MODULE_ALIAS(DRIVER_NAME); | |
MODULE_LICENSE("GPL"); | |
MODULE_AUTHOR("Marco Milanese <marcomilanese7@gmail.com>"); | |
MODULE_DESCRIPTION("Glue layer for OneNAND flash on MSM"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment