2008-08-29 17:41:36 -07:00
/* sun_uflash.c - Driver for user-programmable flash on
* Sun Microsystems SME boardsets .
2005-04-16 15:20:36 -07:00
*
* This driver does NOT provide access to the OBP - flash for
* safety reasons - - use < linux > / drivers / sbus / char / flash . c instead .
*
* Copyright ( c ) 2001 Eric Brower ( ebrower @ usa . net )
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/ioport.h>
2008-08-29 17:41:36 -07:00
# include <linux/of.h>
# include <linux/of_device.h>
2006-06-24 23:27:00 -07:00
# include <asm/prom.h>
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
# include <asm/io.h>
# include <linux/mtd/mtd.h>
# include <linux/mtd/map.h>
# define UFLASH_OBPNAME "flashprom"
2008-08-29 17:41:36 -07:00
# define DRIVER_NAME "sun_uflash"
# define PFX DRIVER_NAME ": "
2005-04-16 15:20:36 -07:00
# define UFLASH_WINDOW_SIZE 0x200000
# define UFLASH_BUSWIDTH 1 /* EBus is 8-bit */
2006-06-24 23:27:00 -07:00
MODULE_AUTHOR ( " Eric Brower <ebrower@usa.net> " ) ;
MODULE_DESCRIPTION ( " User-programmable flash device on Sun Microsystems boardsets " ) ;
2008-08-29 17:41:36 -07:00
MODULE_SUPPORTED_DEVICE ( DRIVER_NAME ) ;
2006-06-24 23:27:00 -07:00
MODULE_LICENSE ( " GPL " ) ;
2008-08-29 17:41:36 -07:00
MODULE_VERSION ( " 2.1 " ) ;
2005-04-16 15:20:36 -07:00
struct uflash_dev {
2007-03-29 00:49:54 -07:00
const char * name ; /* device name */
2005-04-16 15:20:36 -07:00
struct map_info map ; /* mtd map info */
2006-06-24 23:27:00 -07:00
struct mtd_info * mtd ; /* mtd info */
2005-04-16 15:20:36 -07:00
} ;
struct map_info uflash_map_templ = {
2006-06-24 23:27:00 -07:00
. name = " SUNW,???-???? " ,
. size = UFLASH_WINDOW_SIZE ,
. bankwidth = UFLASH_BUSWIDTH ,
2005-04-16 15:20:36 -07:00
} ;
2008-08-29 17:41:36 -07:00
int uflash_devinit ( struct of_device * op , struct device_node * dp )
2005-04-16 15:20:36 -07:00
{
2006-06-24 23:27:00 -07:00
struct uflash_dev * up ;
2005-04-16 15:20:36 -07:00
2008-08-29 17:41:36 -07:00
if ( op - > resource [ 1 ] . flags ) {
2005-04-16 15:20:36 -07:00
/* Non-CFI userflash device-- once I find one we
* can work on supporting it .
*/
2008-08-29 17:41:36 -07:00
printk ( KERN_ERR PFX " Unsupported device at %s, 0x%llx \n " ,
dp - > full_name , ( unsigned long long ) op - > resource [ 0 ] . start ) ;
2006-06-24 23:27:00 -07:00
2005-04-16 15:20:36 -07:00
return - ENODEV ;
}
2006-06-24 23:27:00 -07:00
up = kzalloc ( sizeof ( struct uflash_dev ) , GFP_KERNEL ) ;
2008-08-29 17:41:36 -07:00
if ( ! up ) {
printk ( KERN_ERR PFX " Cannot allocate struct uflash_dev \n " ) ;
2006-06-24 23:27:00 -07:00
return - ENOMEM ;
2008-08-29 17:41:36 -07:00
}
2005-11-07 11:15:40 +00:00
2005-04-16 15:20:36 -07:00
/* copy defaults and tweak parameters */
2006-06-24 23:27:00 -07:00
memcpy ( & up - > map , & uflash_map_templ , sizeof ( uflash_map_templ ) ) ;
2008-08-29 17:41:36 -07:00
up - > map . size = resource_size ( & op - > resource [ 0 ] ) ;
2006-06-24 23:27:00 -07:00
up - > name = of_get_property ( dp , " model " , NULL ) ;
if ( up - > name & & 0 < strlen ( up - > name ) )
2007-03-29 00:49:54 -07:00
up - > map . name = ( char * ) up - > name ;
2006-06-24 23:27:00 -07:00
2008-08-29 17:41:36 -07:00
up - > map . phys = op - > resource [ 0 ] . start ;
2006-06-24 23:27:00 -07:00
2008-08-29 17:41:36 -07:00
up - > map . virt = of_ioremap ( & op - > resource [ 0 ] , 0 , up - > map . size ,
DRIVER_NAME ) ;
2006-06-24 23:27:00 -07:00
if ( ! up - > map . virt ) {
2008-08-29 17:41:36 -07:00
printk ( KERN_ERR PFX " Failed to map device. \n " ) ;
2006-06-24 23:27:00 -07:00
kfree ( up ) ;
return - EINVAL ;
2005-04-16 15:20:36 -07:00
}
2006-06-24 23:27:00 -07:00
simple_map_init ( & up - > map ) ;
2005-04-16 15:20:36 -07:00
/* MTD registration */
2006-06-24 23:27:00 -07:00
up - > mtd = do_map_probe ( " cfi_probe " , & up - > map ) ;
if ( ! up - > mtd ) {
2008-08-29 17:41:36 -07:00
of_iounmap ( & op - > resource [ 0 ] , up - > map . virt , up - > map . size ) ;
2006-06-24 23:27:00 -07:00
kfree ( up ) ;
return - ENXIO ;
2005-04-16 15:20:36 -07:00
}
2006-06-24 23:27:00 -07:00
up - > mtd - > owner = THIS_MODULE ;
2005-04-16 15:20:36 -07:00
2006-06-24 23:27:00 -07:00
add_mtd_device ( up - > mtd ) ;
2005-04-16 15:20:36 -07:00
2008-08-29 17:41:36 -07:00
dev_set_drvdata ( & op - > dev , up ) ;
2006-06-24 23:27:00 -07:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2008-08-29 17:41:36 -07:00
static int __devinit uflash_probe ( struct of_device * op , const struct of_device_id * match )
2005-04-16 15:20:36 -07:00
{
2008-08-29 17:41:36 -07:00
struct device_node * dp = op - > node ;
2005-04-16 15:20:36 -07:00
2008-08-29 17:41:36 -07:00
/* Flashprom must have the "user" property in order to
* be used by this driver .
*/
if ( ! of_find_property ( dp , " user " , NULL ) )
2005-04-16 15:20:36 -07:00
return - ENODEV ;
2006-06-24 23:27:00 -07:00
2008-08-29 17:41:36 -07:00
return uflash_devinit ( op , dp ) ;
2005-04-16 15:20:36 -07:00
}
2008-08-29 17:41:36 -07:00
static int __devexit uflash_remove ( struct of_device * op )
2005-04-16 15:20:36 -07:00
{
2008-08-29 17:41:36 -07:00
struct uflash_dev * up = dev_get_drvdata ( & op - > dev ) ;
2006-06-24 23:27:00 -07:00
if ( up - > mtd ) {
del_mtd_device ( up - > mtd ) ;
map_destroy ( up - > mtd ) ;
2005-11-07 11:15:40 +00:00
}
2006-06-24 23:27:00 -07:00
if ( up - > map . virt ) {
2008-08-29 17:41:36 -07:00
of_iounmap ( & op - > resource [ 0 ] , up - > map . virt , up - > map . size ) ;
2006-06-24 23:27:00 -07:00
up - > map . virt = NULL ;
}
kfree ( up ) ;
return 0 ;
}
2008-08-31 01:23:17 -07:00
static const struct of_device_id uflash_match [ ] = {
2006-06-24 23:27:00 -07:00
{
. name = UFLASH_OBPNAME ,
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , uflash_match ) ;
static struct of_platform_driver uflash_driver = {
2008-08-29 17:41:36 -07:00
. name = DRIVER_NAME ,
2006-06-24 23:27:00 -07:00
. match_table = uflash_match ,
. probe = uflash_probe ,
. remove = __devexit_p ( uflash_remove ) ,
} ;
static int __init uflash_init ( void )
{
2008-08-29 17:41:36 -07:00
return of_register_driver ( & uflash_driver , & of_bus_type ) ;
2006-06-24 23:27:00 -07:00
}
static void __exit uflash_exit ( void )
{
of_unregister_driver ( & uflash_driver ) ;
2005-04-16 15:20:36 -07:00
}
module_init ( uflash_init ) ;
2006-06-24 23:27:00 -07:00
module_exit ( uflash_exit ) ;