2007-05-06 19:31:18 +04:00
/*
* Generic NAND driver
*
* Author : Vitaly Wool < vitalywool @ gmail . 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 .
*
*/
# include <linux/io.h>
# include <linux/module.h>
# include <linux/platform_device.h>
# include <linux/slab.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/partitions.h>
struct plat_nand_data {
struct nand_chip chip ;
struct mtd_info mtd ;
void __iomem * io_base ;
} ;
2012-03-28 11:13:05 -07:00
static const char * part_probe_types [ ] = { " cmdlinepart " , NULL } ;
2007-05-06 19:31:18 +04:00
/*
* Probe for the NAND device .
*/
2009-03-28 00:26:58 +01:00
static int __devinit plat_nand_probe ( struct platform_device * pdev )
2007-05-06 19:31:18 +04:00
{
struct platform_nand_data * pdata = pdev - > dev . platform_data ;
2012-04-30 19:30:46 +02:00
struct mtd_part_parser_data ppdata ;
2007-05-06 19:31:18 +04:00
struct plat_nand_data * data ;
2009-10-19 19:45:29 -04:00
struct resource * res ;
2012-03-28 11:13:05 -07:00
const char * * part_types ;
2009-10-19 19:45:29 -04:00
int err = 0 ;
2012-07-22 08:59:57 +02:00
if ( ! pdata ) {
dev_err ( & pdev - > dev , " platform_nand_data is missing \n " ) ;
return - EINVAL ;
}
2010-08-12 03:53:55 +01:00
if ( pdata - > chip . nr_chips < 1 ) {
dev_err ( & pdev - > dev , " invalid number of chips specified \n " ) ;
return - EINVAL ;
}
2009-10-19 19:45:29 -04:00
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! res )
return - ENXIO ;
2007-05-06 19:31:18 +04:00
/* Allocate memory for the device structure (and zero it) */
data = kzalloc ( sizeof ( struct plat_nand_data ) , GFP_KERNEL ) ;
if ( ! data ) {
dev_err ( & pdev - > dev , " failed to allocate device structure. \n " ) ;
return - ENOMEM ;
}
2009-10-19 19:45:29 -04:00
if ( ! request_mem_region ( res - > start , resource_size ( res ) ,
dev_name ( & pdev - > dev ) ) ) {
dev_err ( & pdev - > dev , " request_mem_region failed \n " ) ;
err = - EBUSY ;
goto out_free ;
}
data - > io_base = ioremap ( res - > start , resource_size ( res ) ) ;
2007-05-06 19:31:18 +04:00
if ( data - > io_base = = NULL ) {
dev_err ( & pdev - > dev , " ioremap failed \n " ) ;
2009-10-19 19:45:29 -04:00
err = - EIO ;
goto out_release_io ;
2007-05-06 19:31:18 +04:00
}
data - > chip . priv = & data ;
data - > mtd . priv = & data - > chip ;
data - > mtd . owner = THIS_MODULE ;
2009-01-06 10:44:38 -08:00
data - > mtd . name = dev_name ( & pdev - > dev ) ;
2007-05-06 19:31:18 +04:00
data - > chip . IO_ADDR_R = data - > io_base ;
data - > chip . IO_ADDR_W = data - > io_base ;
data - > chip . cmd_ctrl = pdata - > ctrl . cmd_ctrl ;
data - > chip . dev_ready = pdata - > ctrl . dev_ready ;
data - > chip . select_chip = pdata - > ctrl . select_chip ;
2009-05-11 19:28:01 +01:00
data - > chip . write_buf = pdata - > ctrl . write_buf ;
data - > chip . read_buf = pdata - > ctrl . read_buf ;
2012-04-30 19:30:47 +02:00
data - > chip . read_byte = pdata - > ctrl . read_byte ;
2007-05-06 19:31:18 +04:00
data - > chip . chip_delay = pdata - > chip . chip_delay ;
data - > chip . options | = pdata - > chip . options ;
2011-05-31 16:31:22 -07:00
data - > chip . bbt_options | = pdata - > chip . bbt_options ;
2007-05-06 19:31:18 +04:00
data - > chip . ecc . hwctl = pdata - > ctrl . hwcontrol ;
data - > chip . ecc . layout = pdata - > chip . ecclayout ;
data - > chip . ecc . mode = NAND_ECC_SOFT ;
platform_set_drvdata ( pdev , data ) ;
2009-05-12 13:46:58 -07:00
/* Handle any platform specific setup */
if ( pdata - > ctrl . probe ) {
2009-10-19 19:45:29 -04:00
err = pdata - > ctrl . probe ( pdev ) ;
if ( err )
2009-05-12 13:46:58 -07:00
goto out ;
}
2011-03-30 22:57:33 -03:00
/* Scan to find existence of the device */
2010-07-28 07:36:54 +02:00
if ( nand_scan ( & data - > mtd , pdata - > chip . nr_chips ) ) {
2009-10-19 19:45:29 -04:00
err = - ENXIO ;
2007-05-06 19:31:18 +04:00
goto out ;
}
2012-03-28 11:13:05 -07:00
part_types = pdata - > chip . part_probe_types ? : part_probe_types ;
2012-04-30 19:30:46 +02:00
ppdata . of_node = pdev - > dev . of_node ;
err = mtd_device_parse_register ( & data - > mtd , part_types , & ppdata ,
mtd: do not use plain 0 as NULL
The first 3 arguments of 'mtd_device_parse_register()' are pointers,
but many callers pass '0' instead of 'NULL'. Fix this globally. Thanks
to coccinelle for making it easy to do with the following semantic patch:
@@
expression mtd, types, parser_data, parts, nr_parts;
@@
(
-mtd_device_parse_register(mtd, 0, parser_data, parts, nr_parts)
+mtd_device_parse_register(mtd, NULL, parser_data, parts, nr_parts)
|
-mtd_device_parse_register(mtd, types, 0, parts, nr_parts)
+mtd_device_parse_register(mtd, types, NULL, parts, nr_parts)
|
-mtd_device_parse_register(mtd, types, parser_data, 0, nr_parts)
+mtd_device_parse_register(mtd, types, parser_data, NULL, nr_parts)
)
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
2012-03-09 19:24:26 +02:00
pdata - > chip . partitions ,
pdata - > chip . nr_partitions ) ;
2007-05-06 19:31:18 +04:00
2009-10-19 19:45:29 -04:00
if ( ! err )
return err ;
2007-05-06 19:31:18 +04:00
nand_release ( & data - > mtd ) ;
out :
2009-05-12 13:46:58 -07:00
if ( pdata - > ctrl . remove )
pdata - > ctrl . remove ( pdev ) ;
2007-05-06 19:31:18 +04:00
platform_set_drvdata ( pdev , NULL ) ;
iounmap ( data - > io_base ) ;
2009-10-19 19:45:29 -04:00
out_release_io :
release_mem_region ( res - > start , resource_size ( res ) ) ;
out_free :
2007-05-06 19:31:18 +04:00
kfree ( data ) ;
2009-10-19 19:45:29 -04:00
return err ;
2007-05-06 19:31:18 +04:00
}
/*
* Remove a NAND device .
*/
static int __devexit plat_nand_remove ( struct platform_device * pdev )
{
struct plat_nand_data * data = platform_get_drvdata ( pdev ) ;
struct platform_nand_data * pdata = pdev - > dev . platform_data ;
2009-10-19 19:45:29 -04:00
struct resource * res ;
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2007-05-06 19:31:18 +04:00
nand_release ( & data - > mtd ) ;
2009-05-12 13:46:58 -07:00
if ( pdata - > ctrl . remove )
pdata - > ctrl . remove ( pdev ) ;
2007-05-06 19:31:18 +04:00
iounmap ( data - > io_base ) ;
2009-10-19 19:45:29 -04:00
release_mem_region ( res - > start , resource_size ( res ) ) ;
2007-05-06 19:31:18 +04:00
kfree ( data ) ;
return 0 ;
}
2012-04-30 19:30:46 +02:00
static const struct of_device_id plat_nand_match [ ] = {
{ . compatible = " gen_nand " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , plat_nand_match ) ;
2007-05-06 19:31:18 +04:00
static struct platform_driver plat_nand_driver = {
2012-04-30 19:30:46 +02:00
. probe = plat_nand_probe ,
2012-11-19 13:21:24 -05:00
. remove = plat_nand_remove ,
2012-04-30 19:30:46 +02:00
. driver = {
. name = " gen_nand " ,
. owner = THIS_MODULE ,
. of_match_table = plat_nand_match ,
2007-05-06 19:31:18 +04:00
} ,
} ;
2011-11-27 20:45:03 +08:00
module_platform_driver ( plat_nand_driver ) ;
2007-05-06 19:31:18 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Vitaly Wool " ) ;
MODULE_DESCRIPTION ( " Simple generic NAND driver " ) ;
2008-04-18 13:44:27 -07:00
MODULE_ALIAS ( " platform:gen_nand " ) ;