2005-09-09 10:39:50 +04:00
/*
* linux / drivers / mtd / onenand / generic . c
*
* Copyright ( c ) 2005 Samsung Electronics
* Kyungmin Park < kyungmin . park @ samsung . com >
*
* 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 .
*
* Overview :
* This is a device driver for the OneNAND flash for generic boards .
*/
# include <linux/module.h>
# include <linux/init.h>
2006-01-08 12:02:05 +03:00
# include <linux/slab.h>
2005-12-16 05:17:29 +03:00
# include <linux/platform_device.h>
2005-09-09 10:39:50 +04:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/onenand.h>
# include <linux/mtd/partitions.h>
# include <asm/io.h>
# include <asm/mach/flash.h>
# define DRIVER_NAME "onenand"
# ifdef CONFIG_MTD_PARTITIONS
static const char * part_probes [ ] = { " cmdlinepart " , NULL , } ;
# endif
struct onenand_info {
struct mtd_info mtd ;
struct mtd_partition * parts ;
struct onenand_chip onenand ;
} ;
static int __devinit generic_onenand_probe ( struct device * dev )
{
struct onenand_info * info ;
struct platform_device * pdev = to_platform_device ( dev ) ;
2005-12-16 05:17:29 +03:00
struct flash_platform_data * pdata = pdev - > dev . platform_data ;
2005-09-09 10:39:50 +04:00
struct resource * res = pdev - > resource ;
unsigned long size = res - > end - res - > start + 1 ;
int err ;
2006-11-15 22:10:29 +03:00
info = kzalloc ( sizeof ( struct onenand_info ) , GFP_KERNEL ) ;
2005-09-09 10:39:50 +04:00
if ( ! info )
return - ENOMEM ;
if ( ! request_mem_region ( res - > start , size , dev - > driver - > name ) ) {
err = - EBUSY ;
goto out_free_info ;
}
info - > onenand . base = ioremap ( res - > start , size ) ;
if ( ! info - > onenand . base ) {
err = - ENOMEM ;
goto out_release_mem_region ;
}
info - > onenand . mmcontrol = pdata - > mmcontrol ;
2006-11-16 05:23:48 +03:00
info - > onenand . irq = platform_get_irq ( pdev , 0 ) ;
2005-09-09 10:39:50 +04:00
info - > mtd . name = pdev - > dev . bus_id ;
info - > mtd . priv = & info - > onenand ;
info - > mtd . owner = THIS_MODULE ;
if ( onenand_scan ( & info - > mtd , 1 ) ) {
err = - ENXIO ;
goto out_iounmap ;
}
# ifdef CONFIG_MTD_PARTITIONS
err = parse_mtd_partitions ( & info - > mtd , part_probes , & info - > parts , 0 ) ;
if ( err > 0 )
add_mtd_partitions ( & info - > mtd , info - > parts , err ) ;
else if ( err < 0 & & pdata - > parts )
add_mtd_partitions ( & info - > mtd , pdata - > parts , pdata - > nr_parts ) ;
else
# endif
err = add_mtd_device ( & info - > mtd ) ;
dev_set_drvdata ( & pdev - > dev , info ) ;
return 0 ;
out_iounmap :
iounmap ( info - > onenand . base ) ;
out_release_mem_region :
release_mem_region ( res - > start , size ) ;
out_free_info :
kfree ( info ) ;
return err ;
}
static int __devexit generic_onenand_remove ( struct device * dev )
{
struct platform_device * pdev = to_platform_device ( dev ) ;
struct onenand_info * info = dev_get_drvdata ( & pdev - > dev ) ;
struct resource * res = pdev - > resource ;
unsigned long size = res - > end - res - > start + 1 ;
dev_set_drvdata ( & pdev - > dev , NULL ) ;
if ( info ) {
if ( info - > parts )
del_mtd_partitions ( & info - > mtd ) ;
else
del_mtd_device ( & info - > mtd ) ;
onenand_release ( & info - > mtd ) ;
release_mem_region ( res - > start , size ) ;
iounmap ( info - > onenand . base ) ;
kfree ( info ) ;
}
return 0 ;
}
static struct device_driver generic_onenand_driver = {
. name = DRIVER_NAME ,
. bus = & platform_bus_type ,
. probe = generic_onenand_probe ,
. remove = __devexit_p ( generic_onenand_remove ) ,
} ;
MODULE_ALIAS ( DRIVER_NAME ) ;
static int __init generic_onenand_init ( void )
{
return driver_register ( & generic_onenand_driver ) ;
}
static void __exit generic_onenand_exit ( void )
{
driver_unregister ( & generic_onenand_driver ) ;
}
module_init ( generic_onenand_init ) ;
module_exit ( generic_onenand_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Kyungmin Park <kyungmin.park@samsung.com> " ) ;
MODULE_DESCRIPTION ( " Glue layer for OneNAND flash on generic boards " ) ;