2005-04-16 15:20:36 -07:00
/*
* drivers / mtd / nand / sharpsl . c
*
* Copyright ( C ) 2004 Richard Purdie
2008-10-16 18:22:28 +04:00
* Copyright ( C ) 2008 Dmitry Baryshkov
2005-04-16 15:20:36 -07:00
*
* Based on Sharp ' s NAND driver sharp_sl . c
*
* 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/genhd.h>
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/delay.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
# include <linux/mtd/nand_ecc.h>
# include <linux/mtd/partitions.h>
2008-10-16 18:43:48 +04:00
# include <linux/mtd/sharpsl.h>
2005-04-16 15:20:36 -07:00
# include <linux/interrupt.h>
2008-10-16 12:08:14 +04:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <asm/io.h>
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2005-04-16 15:20:36 -07:00
# include <asm/mach-types.h>
2008-10-16 17:49:06 +04:00
struct sharpsl_nand {
struct nand_chip chip ;
2008-10-16 17:58:18 +04:00
void __iomem * io ;
2008-10-16 17:49:06 +04:00
} ;
2015-12-10 09:00:24 +01:00
static inline struct sharpsl_nand * mtd_to_sharpsl ( struct mtd_info * mtd )
{
return container_of ( mtd_to_nand ( mtd ) , struct sharpsl_nand , chip ) ;
}
2005-04-16 15:20:36 -07:00
/* register offset */
2008-10-16 17:58:18 +04:00
# define ECCLPLB 0x00 /* line parity 7 - 0 bit */
# define ECCLPUB 0x04 /* line parity 15 - 8 bit */
# define ECCCP 0x08 /* column parity 5 - 0 bit */
# define ECCCNTR 0x0C /* ECC byte counter */
# define ECCCLRR 0x10 /* cleare ECC */
# define FLASHIO 0x14 /* Flash I/O */
# define FLASHCTL 0x18 /* Flash Control */
2005-04-16 15:20:36 -07:00
/* Flash control bit */
# define FLRYBY (1 << 5)
# define FLCE1 (1 << 4)
# define FLWP (1 << 3)
# define FLALE (1 << 2)
# define FLCLE (1 << 1)
# define FLCE0 (1 << 0)
2005-11-07 11:15:49 +00:00
/*
2005-04-16 15:20:36 -07:00
* hardware specific access to control - lines
2006-05-23 23:25:53 +02:00
* ctrl :
2006-07-15 13:05:24 +01:00
* NAND_CNE : bit 0 - > ! bit 0 & 4
2006-05-23 23:25:53 +02:00
* NAND_CLE : bit 1 - > bit 1
* NAND_ALE : bit 2 - > bit 2
*
2005-04-16 15:20:36 -07:00
*/
2006-05-23 23:25:53 +02:00
static void sharpsl_nand_hwcontrol ( struct mtd_info * mtd , int cmd ,
unsigned int ctrl )
2005-04-16 15:20:36 -07:00
{
2008-10-16 17:58:18 +04:00
struct sharpsl_nand * sharpsl = mtd_to_sharpsl ( mtd ) ;
2015-12-01 12:03:04 +01:00
struct nand_chip * chip = mtd_to_nand ( mtd ) ;
2006-05-23 23:25:53 +02:00
if ( ctrl & NAND_CTRL_CHANGE ) {
unsigned char bits = ctrl & 0x07 ;
bits | = ( ctrl & 0x01 ) < < 4 ;
2006-07-15 13:05:24 +01:00
bits ^ = 0x11 ;
2008-10-16 17:58:18 +04:00
writeb ( ( readb ( sharpsl - > io + FLASHCTL ) & ~ 0x17 ) | bits , sharpsl - > io + FLASHCTL ) ;
2005-04-16 15:20:36 -07:00
}
2006-05-23 23:25:53 +02:00
if ( cmd ! = NAND_CMD_NONE )
writeb ( cmd , chip - > IO_ADDR_W ) ;
2005-04-16 15:20:36 -07:00
}
2006-05-13 18:07:53 +01:00
static int sharpsl_nand_dev_ready ( struct mtd_info * mtd )
2005-04-16 15:20:36 -07:00
{
2008-10-16 17:58:18 +04:00
struct sharpsl_nand * sharpsl = mtd_to_sharpsl ( mtd ) ;
return ! ( ( readb ( sharpsl - > io + FLASHCTL ) & FLRYBY ) = = 0 ) ;
2005-04-16 15:20:36 -07:00
}
2006-05-13 18:07:53 +01:00
static void sharpsl_nand_enable_hwecc ( struct mtd_info * mtd , int mode )
2005-04-16 15:20:36 -07:00
{
2008-10-16 17:58:18 +04:00
struct sharpsl_nand * sharpsl = mtd_to_sharpsl ( mtd ) ;
writeb ( 0 , sharpsl - > io + ECCCLRR ) ;
2005-04-16 15:20:36 -07:00
}
2006-05-13 18:07:53 +01:00
static int sharpsl_nand_calculate_ecc ( struct mtd_info * mtd , const u_char * dat , u_char * ecc_code )
2005-04-16 15:20:36 -07:00
{
2008-10-16 17:58:18 +04:00
struct sharpsl_nand * sharpsl = mtd_to_sharpsl ( mtd ) ;
ecc_code [ 0 ] = ~ readb ( sharpsl - > io + ECCLPUB ) ;
ecc_code [ 1 ] = ~ readb ( sharpsl - > io + ECCLPLB ) ;
ecc_code [ 2 ] = ( ~ readb ( sharpsl - > io + ECCCP ) < < 2 ) | 0x03 ;
return readb ( sharpsl - > io + ECCCNTR ) ! = 0 ;
2005-04-16 15:20:36 -07:00
}
/*
* Main initialization routine
*/
2012-11-19 13:23:07 -05:00
static int sharpsl_nand_probe ( struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
struct nand_chip * this ;
2015-12-10 09:00:24 +01:00
struct mtd_info * mtd ;
2008-10-16 12:08:14 +04:00
struct resource * r ;
2005-04-16 15:20:36 -07:00
int err = 0 ;
2008-10-16 17:49:06 +04:00
struct sharpsl_nand * sharpsl ;
2013-07-30 17:18:33 +09:00
struct sharpsl_nand_platform_data * data = dev_get_platdata ( & pdev - > dev ) ;
2008-10-16 18:43:48 +04:00
if ( ! data ) {
dev_err ( & pdev - > dev , " no platform data! \n " ) ;
return - EINVAL ;
}
2005-04-16 15:20:36 -07:00
/* Allocate memory for MTD device structure and private data */
2008-10-16 17:49:06 +04:00
sharpsl = kzalloc ( sizeof ( struct sharpsl_nand ) , GFP_KERNEL ) ;
2013-12-26 12:01:55 +09:00
if ( ! sharpsl )
2005-04-16 15:20:36 -07:00
return - ENOMEM ;
2005-11-07 11:15:49 +00:00
2008-10-16 12:08:14 +04:00
r = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
if ( ! r ) {
dev_err ( & pdev - > dev , " no io memory resource defined! \n " ) ;
err = - ENODEV ;
goto err_get_res ;
}
2008-02-03 17:22:34 +02:00
/* map physical address */
2008-10-16 17:58:18 +04:00
sharpsl - > io = ioremap ( r - > start , resource_size ( r ) ) ;
if ( ! sharpsl - > io ) {
2013-12-26 12:32:29 +09:00
dev_err ( & pdev - > dev , " ioremap to access Sharp SL NAND chip failed \n " ) ;
2008-10-16 17:49:06 +04:00
err = - EIO ;
goto err_ioremap ;
2005-04-16 15:20:36 -07:00
}
2005-11-07 11:15:49 +00:00
2005-04-16 15:20:36 -07:00
/* Get pointer to private data */
2008-10-16 17:49:06 +04:00
this = ( struct nand_chip * ) ( & sharpsl - > chip ) ;
2005-04-16 15:20:36 -07:00
/* Link the private data with the MTD structure */
2015-12-10 09:00:24 +01:00
mtd = nand_to_mtd ( this ) ;
mtd - > dev . parent = & pdev - > dev ;
2016-02-03 19:58:11 +01:00
mtd_set_ooblayout ( mtd , data - > ecc_layout ) ;
2008-10-16 17:49:06 +04:00
platform_set_drvdata ( pdev , sharpsl ) ;
2005-04-16 15:20:36 -07:00
/*
* PXA initialize
*/
2008-10-16 17:58:18 +04:00
writeb ( readb ( sharpsl - > io + FLASHCTL ) | FLWP , sharpsl - > io + FLASHCTL ) ;
2005-04-16 15:20:36 -07:00
/* Set address of NAND IO lines */
2008-10-16 17:58:18 +04:00
this - > IO_ADDR_R = sharpsl - > io + FLASHIO ;
this - > IO_ADDR_W = sharpsl - > io + FLASHIO ;
2005-04-16 15:20:36 -07:00
/* Set address of hardware control function */
2006-05-23 23:25:53 +02:00
this - > cmd_ctrl = sharpsl_nand_hwcontrol ;
2005-04-16 15:20:36 -07:00
this - > dev_ready = sharpsl_nand_dev_ready ;
/* 15 us command delay time */
this - > chip_delay = 15 ;
/* set eccmode using hardware ECC */
2006-05-23 12:00:46 +02:00
this - > ecc . mode = NAND_ECC_HW ;
this - > ecc . size = 256 ;
this - > ecc . bytes = 3 ;
2012-03-11 14:21:11 -07:00
this - > ecc . strength = 1 ;
2008-10-16 18:43:48 +04:00
this - > badblock_pattern = data - > badblock_pattern ;
2006-05-23 12:00:46 +02:00
this - > ecc . hwctl = sharpsl_nand_enable_hwecc ;
this - > ecc . calculate = sharpsl_nand_calculate_ecc ;
this - > ecc . correct = nand_correct_data ;
2005-04-16 15:20:36 -07:00
/* Scan to find existence of the device */
2015-12-10 09:00:24 +01:00
err = nand_scan ( mtd , 1 ) ;
2008-10-16 17:58:18 +04:00
if ( err )
goto err_scan ;
2005-04-16 15:20:36 -07:00
/* Register the partitions */
2015-12-10 09:00:24 +01:00
mtd - > name = " sharpsl-nand " ;
2005-04-16 15:20:36 -07:00
2015-12-10 09:00:24 +01:00
err = mtd_device_parse_register ( mtd , NULL , NULL ,
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
data - > partitions , data - > nr_partitions ) ;
2008-10-16 18:22:28 +04:00
if ( err )
goto err_add ;
2005-04-16 15:20:36 -07:00
/* Return happy */
return 0 ;
2006-05-13 18:07:53 +01:00
2008-10-16 18:22:28 +04:00
err_add :
2015-12-10 09:00:24 +01:00
nand_release ( mtd ) ;
2008-10-16 18:22:28 +04:00
2008-10-16 17:58:18 +04:00
err_scan :
iounmap ( sharpsl - > io ) ;
2008-10-16 17:49:06 +04:00
err_ioremap :
2008-10-16 12:08:14 +04:00
err_get_res :
2008-10-16 17:49:06 +04:00
kfree ( sharpsl ) ;
2008-10-16 12:08:14 +04:00
return err ;
}
2005-04-16 15:20:36 -07:00
/*
* Clean up routine
*/
2012-11-19 13:26:04 -05:00
static int sharpsl_nand_remove ( struct platform_device * pdev )
2005-04-16 15:20:36 -07:00
{
2008-10-16 17:49:06 +04:00
struct sharpsl_nand * sharpsl = platform_get_drvdata ( pdev ) ;
2005-04-16 15:20:36 -07:00
/* Release resources, unregister device */
2015-12-10 09:00:24 +01:00
nand_release ( nand_to_mtd ( & sharpsl - > chip ) ) ;
2008-10-16 17:49:06 +04:00
2008-10-16 17:58:18 +04:00
iounmap ( sharpsl - > io ) ;
2005-04-16 15:20:36 -07:00
/* Free the MTD device structure */
2008-10-16 17:49:06 +04:00
kfree ( sharpsl ) ;
2008-10-16 12:08:14 +04:00
return 0 ;
}
static struct platform_driver sharpsl_nand_driver = {
. driver = {
. name = " sharpsl-nand " ,
} ,
. probe = sharpsl_nand_probe ,
2012-11-19 13:21:24 -05:00
. remove = sharpsl_nand_remove ,
2008-10-16 12:08:14 +04:00
} ;
2011-11-27 20:45:03 +08:00
module_platform_driver ( sharpsl_nand_driver ) ;
2005-04-16 15:20:36 -07:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Richard Purdie <rpurdie@rpsys.net> " ) ;
MODULE_DESCRIPTION ( " Device specific logic for NAND flash on Sharp SL-C7xx Series " ) ;