2005-04-17 02:20:36 +04:00
/*
* pcmciamtd . c - MTD driver for PCMCIA flash memory cards
*
* Author : Simon Evans < spse @ secret . org . uk >
*
* Copyright ( C ) 2002 Simon Evans
*
* Licence : GPL
*
*/
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/timer.h>
# include <linux/init.h>
# include <asm/io.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/ds.h>
# include <linux/mtd/map.h>
# include <linux/mtd/mtd.h>
# define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg)
# define DRIVER_DESC "PCMCIA Flash memory card driver"
/* Size of the PCMCIA address space: 26 bits = 64 MB */
# define MAX_PCMCIA_ADDR 0x4000000
struct pcmciamtd_dev {
2006-03-05 12:45:09 +03:00
struct pcmcia_device * p_dev ;
2015-12-29 22:55:33 +03:00
void __iomem * win_base ; /* ioremapped address of PCMCIA window */
2005-04-17 02:20:36 +04:00
unsigned int win_size ; /* size of window */
unsigned int offset ; /* offset into card the window currently points at */
struct map_info pcmcia_map ;
struct mtd_info * mtd_info ;
int vpp ;
char mtd_name [ sizeof ( struct cistpl_vers_1_t ) ] ;
} ;
/* Module parameters */
/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
static int bankwidth = 2 ;
/* Speed of memory accesses, in ns */
static int mem_speed ;
/* Force the size of an SRAM card */
static int force_size ;
/* Force Vpp */
static int vpp ;
/* Set Vpp */
static int setvpp ;
/* Force card to be treated as FLASH, ROM or RAM */
static int mem_type ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " Simon Evans <spse@secret.org.uk> " ) ;
MODULE_DESCRIPTION ( DRIVER_DESC ) ;
2006-03-25 14:07:05 +03:00
module_param ( bankwidth , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( bankwidth , " Set bankwidth (1=8 bit, 2=16 bit, default=2) " ) ;
2006-03-25 14:07:05 +03:00
module_param ( mem_speed , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( mem_speed , " Set memory access speed in ns " ) ;
2006-03-25 14:07:05 +03:00
module_param ( force_size , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( force_size , " Force size of card in MiB (1-64) " ) ;
2006-03-25 14:07:05 +03:00
module_param ( setvpp , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( setvpp , " Set Vpp (0=Never, 1=On writes, 2=Always on, default=0) " ) ;
2006-03-25 14:07:05 +03:00
module_param ( vpp , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( vpp , " Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous) " ) ;
2006-03-25 14:07:05 +03:00
module_param ( mem_type , int , 0 ) ;
2005-04-17 02:20:36 +04:00
MODULE_PARM_DESC ( mem_type , " Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0) " ) ;
2010-05-13 14:00:00 +04:00
/* read/write{8,16} copy_{from,to} routines with window remapping
* to access whole card
*/
2015-12-29 22:55:33 +03:00
static void __iomem * remap_window ( struct map_info * map , unsigned long to )
2005-04-17 02:20:36 +04:00
{
struct pcmciamtd_dev * dev = ( struct pcmciamtd_dev * ) map - > map_priv_1 ;
2010-07-28 12:59:06 +04:00
struct resource * win = ( struct resource * ) map - > map_priv_2 ;
2010-07-24 20:46:42 +04:00
unsigned int offset ;
2005-04-17 02:20:36 +04:00
int ret ;
2006-03-02 02:09:29 +03:00
if ( ! pcmcia_dev_present ( dev - > p_dev ) ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " device removed \n " ) ;
2014-07-31 18:31:16 +04:00
return NULL ;
2005-04-17 02:20:36 +04:00
}
2010-07-24 20:46:42 +04:00
offset = to & ~ ( dev - > win_size - 1 ) ;
if ( offset ! = dev - > offset ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " Remapping window from 0x%8.8x to 0x%8.8x \n " ,
2010-07-24 20:46:42 +04:00
dev - > offset , offset ) ;
ret = pcmcia_map_mem_page ( dev - > p_dev , win , offset ) ;
2009-10-24 17:55:39 +04:00
if ( ret ! = 0 )
2005-04-17 02:20:36 +04:00
return NULL ;
2010-07-24 20:46:42 +04:00
dev - > offset = offset ;
2005-04-17 02:20:36 +04:00
}
return dev - > win_base + ( to & ( dev - > win_size - 1 ) ) ;
}
static map_word pcmcia_read8_remap ( struct map_info * map , unsigned long ofs )
{
2015-12-29 22:55:33 +03:00
void __iomem * addr ;
2005-04-17 02:20:36 +04:00
map_word d = { { 0 } } ;
addr = remap_window ( map , ofs ) ;
if ( ! addr )
return d ;
d . x [ 0 ] = readb ( addr ) ;
2011-07-19 21:06:11 +04:00
pr_debug ( " ofs = 0x%08lx (%p) data = 0x%02lx \n " , ofs , addr , d . x [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
return d ;
}
static map_word pcmcia_read16_remap ( struct map_info * map , unsigned long ofs )
{
2015-12-29 22:55:33 +03:00
void __iomem * addr ;
2005-04-17 02:20:36 +04:00
map_word d = { { 0 } } ;
addr = remap_window ( map , ofs ) ;
if ( ! addr )
return d ;
d . x [ 0 ] = readw ( addr ) ;
2011-07-19 21:06:11 +04:00
pr_debug ( " ofs = 0x%08lx (%p) data = 0x%04lx \n " , ofs , addr , d . x [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
return d ;
}
static void pcmcia_copy_from_remap ( struct map_info * map , void * to , unsigned long from , ssize_t len )
{
struct pcmciamtd_dev * dev = ( struct pcmciamtd_dev * ) map - > map_priv_1 ;
unsigned long win_size = dev - > win_size ;
2011-07-19 21:06:11 +04:00
pr_debug ( " to = %p from = %lu len = %zd \n " , to , from , len ) ;
2005-04-17 02:20:36 +04:00
while ( len ) {
int toread = win_size - ( from & ( win_size - 1 ) ) ;
2015-12-29 22:55:33 +03:00
void __iomem * addr ;
2005-04-17 02:20:36 +04:00
if ( toread > len )
toread = len ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
addr = remap_window ( map , from ) ;
if ( ! addr )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " memcpy from %p to %p len = %d \n " , addr , to , toread ) ;
2005-04-17 02:20:36 +04:00
memcpy_fromio ( to , addr , toread ) ;
len - = toread ;
to + = toread ;
from + = toread ;
}
}
static void pcmcia_write8_remap ( struct map_info * map , map_word d , unsigned long adr )
{
2015-12-29 22:55:33 +03:00
void __iomem * addr = remap_window ( map , adr ) ;
2005-04-17 02:20:36 +04:00
if ( ! addr )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " adr = 0x%08lx (%p) data = 0x%02lx \n " , adr , addr , d . x [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
writeb ( d . x [ 0 ] , addr ) ;
}
static void pcmcia_write16_remap ( struct map_info * map , map_word d , unsigned long adr )
{
2015-12-29 22:55:33 +03:00
void __iomem * addr = remap_window ( map , adr ) ;
2005-04-17 02:20:36 +04:00
if ( ! addr )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " adr = 0x%08lx (%p) data = 0x%04lx \n " , adr , addr , d . x [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
writew ( d . x [ 0 ] , addr ) ;
}
static void pcmcia_copy_to_remap ( struct map_info * map , unsigned long to , const void * from , ssize_t len )
{
struct pcmciamtd_dev * dev = ( struct pcmciamtd_dev * ) map - > map_priv_1 ;
unsigned long win_size = dev - > win_size ;
2011-07-19 21:06:11 +04:00
pr_debug ( " to = %lu from = %p len = %zd \n " , to , from , len ) ;
2005-04-17 02:20:36 +04:00
while ( len ) {
int towrite = win_size - ( to & ( win_size - 1 ) ) ;
2015-12-29 22:55:33 +03:00
void __iomem * addr ;
2005-04-17 02:20:36 +04:00
if ( towrite > len )
towrite = len ;
addr = remap_window ( map , to ) ;
if ( ! addr )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " memcpy from %p to %p len = %d \n " , from , addr , towrite ) ;
2005-04-17 02:20:36 +04:00
memcpy_toio ( addr , from , towrite ) ;
len - = towrite ;
to + = towrite ;
from + = towrite ;
}
}
/* read/write{8,16} copy_{from,to} routines with direct access */
2006-03-02 02:09:29 +03:00
# define DEV_REMOVED(x) (!(pcmcia_dev_present(((struct pcmciamtd_dev *)map->map_priv_1)->p_dev)))
2005-04-17 02:20:36 +04:00
static map_word pcmcia_read8 ( struct map_info * map , unsigned long ofs )
{
2015-12-29 22:55:33 +03:00
void __iomem * win_base = ( void __iomem * ) map - > map_priv_2 ;
2005-04-17 02:20:36 +04:00
map_word d = { { 0 } } ;
if ( DEV_REMOVED ( map ) )
return d ;
d . x [ 0 ] = readb ( win_base + ofs ) ;
2011-07-19 21:06:11 +04:00
pr_debug ( " ofs = 0x%08lx (%p) data = 0x%02lx \n " ,
2010-05-13 14:00:00 +04:00
ofs , win_base + ofs , d . x [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
return d ;
}
static map_word pcmcia_read16 ( struct map_info * map , unsigned long ofs )
{
2015-12-29 22:55:33 +03:00
void __iomem * win_base = ( void __iomem * ) map - > map_priv_2 ;
2005-04-17 02:20:36 +04:00
map_word d = { { 0 } } ;
if ( DEV_REMOVED ( map ) )
return d ;
d . x [ 0 ] = readw ( win_base + ofs ) ;
2011-07-19 21:06:11 +04:00
pr_debug ( " ofs = 0x%08lx (%p) data = 0x%04lx \n " ,
2010-05-13 14:00:00 +04:00
ofs , win_base + ofs , d . x [ 0 ] ) ;
2005-04-17 02:20:36 +04:00
return d ;
}
static void pcmcia_copy_from ( struct map_info * map , void * to , unsigned long from , ssize_t len )
{
2015-12-29 22:55:33 +03:00
void __iomem * win_base = ( void __iomem * ) map - > map_priv_2 ;
2005-04-17 02:20:36 +04:00
if ( DEV_REMOVED ( map ) )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " to = %p from = %lu len = %zd \n " , to , from , len ) ;
2005-04-17 02:20:36 +04:00
memcpy_fromio ( to , win_base + from , len ) ;
}
2010-05-13 13:59:59 +04:00
static void pcmcia_write8 ( struct map_info * map , map_word d , unsigned long adr )
2005-04-17 02:20:36 +04:00
{
2015-12-29 22:55:33 +03:00
void __iomem * win_base = ( void __iomem * ) map - > map_priv_2 ;
2005-04-17 02:20:36 +04:00
if ( DEV_REMOVED ( map ) )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " adr = 0x%08lx (%p) data = 0x%02lx \n " ,
2010-05-13 14:00:00 +04:00
adr , win_base + adr , d . x [ 0 ] ) ;
2010-05-13 13:59:59 +04:00
writeb ( d . x [ 0 ] , win_base + adr ) ;
2005-04-17 02:20:36 +04:00
}
2010-05-13 13:59:59 +04:00
static void pcmcia_write16 ( struct map_info * map , map_word d , unsigned long adr )
2005-04-17 02:20:36 +04:00
{
2015-12-29 22:55:33 +03:00
void __iomem * win_base = ( void __iomem * ) map - > map_priv_2 ;
2005-04-17 02:20:36 +04:00
if ( DEV_REMOVED ( map ) )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " adr = 0x%08lx (%p) data = 0x%04lx \n " ,
2010-05-13 14:00:00 +04:00
adr , win_base + adr , d . x [ 0 ] ) ;
2010-05-13 13:59:59 +04:00
writew ( d . x [ 0 ] , win_base + adr ) ;
2005-04-17 02:20:36 +04:00
}
static void pcmcia_copy_to ( struct map_info * map , unsigned long to , const void * from , ssize_t len )
{
2015-12-29 22:55:33 +03:00
void __iomem * win_base = ( void __iomem * ) map - > map_priv_2 ;
2005-04-17 02:20:36 +04:00
if ( DEV_REMOVED ( map ) )
return ;
2011-07-19 21:06:11 +04:00
pr_debug ( " to = %lu from = %p len = %zd \n " , to , from , len ) ;
2005-04-17 02:20:36 +04:00
memcpy_toio ( win_base + to , from , len ) ;
}
2019-12-19 06:20:23 +03:00
static DEFINE_MUTEX ( pcmcia_vpp_lock ) ;
2012-03-07 18:13:41 +04:00
static int pcmcia_vpp_refcnt ;
2005-04-17 02:20:36 +04:00
static void pcmciamtd_set_vpp ( struct map_info * map , int on )
{
struct pcmciamtd_dev * dev = ( struct pcmciamtd_dev * ) map - > map_priv_1 ;
2006-03-31 19:21:06 +04:00
struct pcmcia_device * link = dev - > p_dev ;
2005-04-17 02:20:36 +04:00
2011-07-19 21:06:11 +04:00
pr_debug ( " dev = %p on = %d vpp = %d \n \n " , dev , on , dev - > vpp ) ;
2019-12-19 06:20:23 +03:00
mutex_lock ( & pcmcia_vpp_lock ) ;
2012-03-07 18:13:41 +04:00
if ( on ) {
if ( + + pcmcia_vpp_refcnt = = 1 ) /* first nested 'on' */
pcmcia_fixup_vpp ( link , dev - > vpp ) ;
} else {
if ( - - pcmcia_vpp_refcnt = = 0 ) /* last nested 'off' */
pcmcia_fixup_vpp ( link , 0 ) ;
}
2019-12-19 06:20:23 +03:00
mutex_unlock ( & pcmcia_vpp_lock ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 19:21:06 +04:00
static void pcmciamtd_release ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct pcmciamtd_dev * dev = link - > priv ;
2011-07-19 21:06:11 +04:00
pr_debug ( " link = 0x%p \n " , link ) ;
2005-04-17 02:20:36 +04:00
2010-07-28 12:59:06 +04:00
if ( link - > resource [ 2 ] - > end ) {
2005-04-17 02:20:36 +04:00
if ( dev - > win_base ) {
iounmap ( dev - > win_base ) ;
dev - > win_base = NULL ;
}
}
2006-03-31 19:21:06 +04:00
pcmcia_disable_device ( link ) ;
2005-04-17 02:20:36 +04:00
}
2009-10-19 01:57:58 +04:00
static int pcmciamtd_cistpl_format ( struct pcmcia_device * p_dev ,
tuple_t * tuple ,
void * priv_data )
2005-04-17 02:20:36 +04:00
{
cisparse_t parse ;
2005-11-07 14:15:40 +03:00
2009-10-19 01:57:58 +04:00
if ( ! pcmcia_parse_tuple ( tuple , & parse ) ) {
cistpl_format_t * t = & parse . format ;
( void ) t ; /* Shut up, gcc */
2011-07-19 21:06:11 +04:00
pr_debug ( " Format type: %u, Error Detection: %u, offset = %u, length =%u \n " ,
2009-10-19 01:57:58 +04:00
t - > type , t - > edc , t - > offset , t - > length ) ;
}
return - ENOSPC ;
}
2005-11-07 14:15:40 +03:00
2009-10-19 01:57:58 +04:00
static int pcmciamtd_cistpl_jedec ( struct pcmcia_device * p_dev ,
tuple_t * tuple ,
void * priv_data )
{
cisparse_t parse ;
int i ;
2005-11-07 14:15:40 +03:00
2009-10-19 01:57:58 +04:00
if ( ! pcmcia_parse_tuple ( tuple , & parse ) ) {
cistpl_jedec_t * t = & parse . jedec ;
for ( i = 0 ; i < t - > nid ; i + + )
2011-07-19 21:06:11 +04:00
pr_debug ( " JEDEC: 0x%02x 0x%02x \n " ,
2010-05-13 14:00:00 +04:00
t - > id [ i ] . mfr , t - > id [ i ] . info ) ;
2009-10-19 01:57:58 +04:00
}
return - ENOSPC ;
}
2005-11-07 14:15:40 +03:00
2009-10-19 01:57:58 +04:00
static int pcmciamtd_cistpl_device ( struct pcmcia_device * p_dev ,
tuple_t * tuple ,
void * priv_data )
{
struct pcmciamtd_dev * dev = priv_data ;
cisparse_t parse ;
cistpl_device_t * t = & parse . device ;
int i ;
if ( pcmcia_parse_tuple ( tuple , & parse ) )
return - EINVAL ;
2011-07-19 21:06:11 +04:00
pr_debug ( " Common memory: \n " ) ;
2009-10-19 01:57:58 +04:00
dev - > pcmcia_map . size = t - > dev [ 0 ] . size ;
/* from here on: DEBUG only */
for ( i = 0 ; i < t - > ndev ; i + + ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " Region %d, type = %u \n " , i , t - > dev [ i ] . type ) ;
pr_debug ( " Region %d, wp = %u \n " , i , t - > dev [ i ] . wp ) ;
pr_debug ( " Region %d, speed = %u ns \n " , i , t - > dev [ i ] . speed ) ;
pr_debug ( " Region %d, size = %u bytes \n " , i , t - > dev [ i ] . size ) ;
2009-10-19 01:57:58 +04:00
}
return 0 ;
}
2005-11-07 14:15:40 +03:00
2009-10-19 01:57:58 +04:00
static int pcmciamtd_cistpl_geo ( struct pcmcia_device * p_dev ,
tuple_t * tuple ,
void * priv_data )
{
struct pcmciamtd_dev * dev = priv_data ;
cisparse_t parse ;
cistpl_device_geo_t * t = & parse . device_geo ;
int i ;
if ( pcmcia_parse_tuple ( tuple , & parse ) )
return - EINVAL ;
dev - > pcmcia_map . bankwidth = t - > geo [ 0 ] . buswidth ;
/* from here on: DEBUG only */
for ( i = 0 ; i < t - > ngeo ; i + + ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " region: %d bankwidth = %u \n " , i , t - > geo [ i ] . buswidth ) ;
pr_debug ( " region: %d erase_block = %u \n " , i , t - > geo [ i ] . erase_block ) ;
pr_debug ( " region: %d read_block = %u \n " , i , t - > geo [ i ] . read_block ) ;
pr_debug ( " region: %d write_block = %u \n " , i , t - > geo [ i ] . write_block ) ;
pr_debug ( " region: %d partition = %u \n " , i , t - > geo [ i ] . partition ) ;
pr_debug ( " region: %d interleave = %u \n " , i , t - > geo [ i ] . interleave ) ;
2009-10-19 01:57:58 +04:00
}
return 0 ;
}
2005-11-07 14:15:40 +03:00
2010-05-13 13:59:59 +04:00
static void card_settings ( struct pcmciamtd_dev * dev , struct pcmcia_device * p_dev , int * new_name )
2009-10-19 01:57:58 +04:00
{
int i ;
if ( p_dev - > prod_id [ 0 ] ) {
dev - > mtd_name [ 0 ] = ' \0 ' ;
for ( i = 0 ; i < 4 ; i + + ) {
if ( i )
strcat ( dev - > mtd_name , " " ) ;
if ( p_dev - > prod_id [ i ] )
strcat ( dev - > mtd_name , p_dev - > prod_id [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
2011-07-19 21:06:11 +04:00
pr_debug ( " Found name: %s \n " , dev - > mtd_name ) ;
2005-04-17 02:20:36 +04:00
}
2009-10-19 01:57:58 +04:00
pcmcia_loop_tuple ( p_dev , CISTPL_FORMAT , pcmciamtd_cistpl_format , NULL ) ;
pcmcia_loop_tuple ( p_dev , CISTPL_JEDEC_C , pcmciamtd_cistpl_jedec , NULL ) ;
pcmcia_loop_tuple ( p_dev , CISTPL_DEVICE , pcmciamtd_cistpl_device , dev ) ;
pcmcia_loop_tuple ( p_dev , CISTPL_DEVICE_GEO , pcmciamtd_cistpl_geo , dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > pcmcia_map . size )
dev - > pcmcia_map . size = MAX_PCMCIA_ADDR ;
if ( ! dev - > pcmcia_map . bankwidth )
dev - > pcmcia_map . bankwidth = 2 ;
if ( force_size ) {
dev - > pcmcia_map . size = force_size < < 20 ;
2011-07-19 21:06:11 +04:00
pr_debug ( " size forced to %dM \n " , force_size ) ;
2005-04-17 02:20:36 +04:00
}
if ( bankwidth ) {
dev - > pcmcia_map . bankwidth = bankwidth ;
2011-07-19 21:06:11 +04:00
pr_debug ( " bankwidth forced to %d \n " , bankwidth ) ;
2005-11-07 14:15:40 +03:00
}
2005-04-17 02:20:36 +04:00
dev - > pcmcia_map . name = dev - > mtd_name ;
if ( ! dev - > mtd_name [ 0 ] ) {
strcpy ( dev - > mtd_name , " PCMCIA Memory card " ) ;
* new_name = 1 ;
}
2011-07-19 21:06:11 +04:00
pr_debug ( " Device: Size: %lu Width:%d Name: %s \n " ,
2010-05-13 14:00:00 +04:00
dev - > pcmcia_map . size ,
dev - > pcmcia_map . bankwidth < < 3 , dev - > mtd_name ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 19:26:06 +04:00
static int pcmciamtd_config ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct pcmciamtd_dev * dev = link - > priv ;
struct mtd_info * mtd = NULL ;
int ret ;
2010-07-28 12:59:06 +04:00
int i , j = 0 ;
2005-04-17 02:20:36 +04:00
static char * probes [ ] = { " jedec_probe " , " cfi_probe " } ;
int new_name = 0 ;
2011-07-19 21:06:11 +04:00
pr_debug ( " link=0x%p \n " , link ) ;
2005-04-17 02:20:36 +04:00
card_settings ( dev , link , & new_name ) ;
dev - > pcmcia_map . phys = NO_XIP ;
dev - > pcmcia_map . copy_from = pcmcia_copy_from_remap ;
dev - > pcmcia_map . copy_to = pcmcia_copy_to_remap ;
if ( dev - > pcmcia_map . bankwidth = = 1 ) {
dev - > pcmcia_map . read = pcmcia_read8_remap ;
dev - > pcmcia_map . write = pcmcia_write8_remap ;
} else {
dev - > pcmcia_map . read = pcmcia_read16_remap ;
dev - > pcmcia_map . write = pcmcia_write16_remap ;
}
if ( setvpp = = 1 )
dev - > pcmcia_map . set_vpp = pcmciamtd_set_vpp ;
2010-05-13 14:00:00 +04:00
/* Request a memory window for PCMCIA. Some architeures can map windows
2011-03-31 05:57:33 +04:00
* up to the maximum that PCMCIA can support ( 64 MiB ) - this is ideal and
2010-05-13 14:00:00 +04:00
* we aim for a window the size of the whole card - otherwise we try
* smaller windows until we succeed
*/
2005-04-17 02:20:36 +04:00
2010-07-28 12:59:06 +04:00
link - > resource [ 2 ] - > flags | = WIN_MEMORY_TYPE_CM | WIN_ENABLE ;
link - > resource [ 2 ] - > flags | = ( dev - > pcmcia_map . bankwidth = = 1 ) ?
WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16 ;
link - > resource [ 2 ] - > start = 0 ;
link - > resource [ 2 ] - > end = ( force_size ) ? force_size < < 20 :
MAX_PCMCIA_ADDR ;
2005-04-17 02:20:36 +04:00
dev - > win_size = 0 ;
do {
int ret ;
2011-07-19 21:06:11 +04:00
pr_debug ( " requesting window with size = %luKiB memspeed = %d \n " ,
2010-07-28 12:59:06 +04:00
( unsigned long ) resource_size ( link - > resource [ 2 ] ) > > 10 ,
mem_speed ) ;
ret = pcmcia_request_window ( link , link - > resource [ 2 ] , mem_speed ) ;
2011-07-19 21:06:11 +04:00
pr_debug ( " ret = %d dev->win_size = %d \n " , ret , dev - > win_size ) ;
2005-04-17 02:20:36 +04:00
if ( ret ) {
2010-07-28 12:59:06 +04:00
j + + ;
link - > resource [ 2 ] - > start = 0 ;
link - > resource [ 2 ] - > end = ( force_size ) ?
force_size < < 20 : MAX_PCMCIA_ADDR ;
link - > resource [ 2 ] - > end > > = j ;
2005-04-17 02:20:36 +04:00
} else {
2011-07-19 21:06:11 +04:00
pr_debug ( " Got window of size %luKiB \n " , ( unsigned long )
2010-07-28 12:59:06 +04:00
resource_size ( link - > resource [ 2 ] ) > > 10 ) ;
dev - > win_size = resource_size ( link - > resource [ 2 ] ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2010-07-28 12:59:06 +04:00
} while ( link - > resource [ 2 ] - > end > = 0x1000 ) ;
2005-04-17 02:20:36 +04:00
2011-07-19 21:06:11 +04:00
pr_debug ( " dev->win_size = %d \n " , dev - > win_size ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > win_size ) {
2010-05-13 14:00:00 +04:00
dev_err ( & dev - > p_dev - > dev , " Cannot allocate memory window \n " ) ;
2005-04-17 02:20:36 +04:00
pcmciamtd_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2011-07-19 21:06:11 +04:00
pr_debug ( " Allocated a window of %dKiB \n " , dev - > win_size > > 10 ) ;
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
/* Get write protect status */
2010-07-28 12:59:06 +04:00
dev - > win_base = ioremap ( link - > resource [ 2 ] - > start ,
resource_size ( link - > resource [ 2 ] ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! dev - > win_base ) {
2010-07-28 12:59:06 +04:00
dev_err ( & dev - > p_dev - > dev , " ioremap(%pR) failed \n " ,
link - > resource [ 2 ] ) ;
2005-04-17 02:20:36 +04:00
pcmciamtd_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2011-07-19 21:06:11 +04:00
pr_debug ( " mapped window dev = %p @ %pR, base = %p \n " ,
2010-07-28 12:59:06 +04:00
dev , link - > resource [ 2 ] , dev - > win_base ) ;
2005-04-17 02:20:36 +04:00
dev - > offset = 0 ;
dev - > pcmcia_map . map_priv_1 = ( unsigned long ) dev ;
2010-07-28 12:59:06 +04:00
dev - > pcmcia_map . map_priv_2 = ( unsigned long ) link - > resource [ 2 ] ;
2005-04-17 02:20:36 +04:00
2010-05-13 13:59:59 +04:00
dev - > vpp = ( vpp ) ? vpp : link - > socket - > socket . Vpp ;
2005-04-17 02:20:36 +04:00
if ( setvpp = = 2 ) {
2010-07-29 17:50:55 +04:00
link - > vpp = dev - > vpp ;
2005-04-17 02:20:36 +04:00
} else {
2010-07-29 17:50:55 +04:00
link - > vpp = 0 ;
2005-04-17 02:20:36 +04:00
}
2010-07-29 20:35:47 +04:00
link - > config_index = 0 ;
2011-07-19 21:06:11 +04:00
pr_debug ( " Setting Configuration \n " ) ;
2010-07-29 21:27:09 +04:00
ret = pcmcia_enable_device ( link ) ;
2008-08-03 12:07:45 +04:00
if ( ret ! = 0 ) {
2006-09-21 16:42:43 +04:00
if ( dev - > win_base ) {
iounmap ( dev - > win_base ) ;
dev - > win_base = NULL ;
}
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
if ( mem_type = = 1 ) {
mtd = do_map_probe ( " map_ram " , & dev - > pcmcia_map ) ;
} else if ( mem_type = = 2 ) {
mtd = do_map_probe ( " map_rom " , & dev - > pcmcia_map ) ;
} else {
2006-03-31 14:29:45 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( probes ) ; i + + ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " Trying %s \n " , probes [ i ] ) ;
2005-04-17 02:20:36 +04:00
mtd = do_map_probe ( probes [ i ] , & dev - > pcmcia_map ) ;
if ( mtd )
break ;
2005-11-07 14:15:40 +03:00
2011-07-19 21:06:11 +04:00
pr_debug ( " FAILED: %s \n " , probes [ i ] ) ;
2005-04-17 02:20:36 +04:00
}
}
2005-11-07 14:15:40 +03:00
2005-04-17 02:20:36 +04:00
if ( ! mtd ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " Can not find an MTD \n " ) ;
2005-04-17 02:20:36 +04:00
pcmciamtd_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
dev - > mtd_info = mtd ;
mtd - > owner = THIS_MODULE ;
if ( new_name ) {
int size = 0 ;
char unit = ' ' ;
2010-05-13 14:00:00 +04:00
/* Since we are using a default name, make it better by adding
* in the size
*/
2005-04-17 02:20:36 +04:00
if ( mtd - > size < 1048576 ) { /* <1MiB in size, show size in KiB */
size = mtd - > size > > 10 ;
unit = ' K ' ;
} else {
size = mtd - > size > > 20 ;
unit = ' M ' ;
}
snprintf ( dev - > mtd_name , sizeof ( dev - > mtd_name ) , " %d%ciB %s " , size , unit , " PCMCIA Memory card " ) ;
}
/* If the memory found is fits completely into the mapped PCMCIA window,
use the faster non - remapping read / write functions */
if ( mtd - > size < = dev - > win_size ) {
2011-07-19 21:06:11 +04:00
pr_debug ( " Using non remapping memory functions \n " ) ;
2005-04-17 02:20:36 +04:00
dev - > pcmcia_map . map_priv_2 = ( unsigned long ) dev - > win_base ;
if ( dev - > pcmcia_map . bankwidth = = 1 ) {
dev - > pcmcia_map . read = pcmcia_read8 ;
dev - > pcmcia_map . write = pcmcia_write8 ;
} else {
dev - > pcmcia_map . read = pcmcia_read16 ;
dev - > pcmcia_map . write = pcmcia_write16 ;
}
dev - > pcmcia_map . copy_from = pcmcia_copy_from ;
dev - > pcmcia_map . copy_to = pcmcia_copy_to ;
}
2011-05-23 13:23:40 +04:00
if ( mtd_device_register ( mtd , NULL , 0 ) ) {
2005-04-17 02:20:36 +04:00
map_destroy ( mtd ) ;
dev - > mtd_info = NULL ;
2010-05-13 14:00:00 +04:00
dev_err ( & dev - > p_dev - > dev ,
" Could not register the MTD device \n " ) ;
2005-04-17 02:20:36 +04:00
pcmciamtd_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
}
2010-05-13 14:00:00 +04:00
dev_info ( & dev - > p_dev - > dev , " mtd%d: %s \n " , mtd - > index , mtd - > name ) ;
2006-03-31 19:26:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-11-14 23:21:18 +03:00
static int pcmciamtd_suspend ( struct pcmcia_device * dev )
{
2011-07-19 21:06:11 +04:00
pr_debug ( " EVENT_PM_RESUME \n " ) ;
2005-11-14 23:21:18 +03:00
/* get_lock(link); */
return 0 ;
}
static int pcmciamtd_resume ( struct pcmcia_device * dev )
{
2011-07-19 21:06:11 +04:00
pr_debug ( " EVENT_PM_SUSPEND \n " ) ;
2005-11-14 23:21:18 +03:00
/* free_lock(link); */
return 0 ;
}
2005-04-17 02:20:36 +04:00
2006-03-31 19:21:06 +04:00
static void pcmciamtd_detach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2006-03-02 02:09:29 +03:00
struct pcmciamtd_dev * dev = link - > priv ;
2005-11-14 23:23:14 +03:00
2011-07-19 21:06:11 +04:00
pr_debug ( " link=0x%p \n " , link ) ;
2005-04-17 02:20:36 +04:00
2006-03-02 02:09:29 +03:00
if ( dev - > mtd_info ) {
2011-05-23 13:23:40 +04:00
mtd_device_unregister ( dev - > mtd_info ) ;
2010-05-13 14:00:00 +04:00
dev_info ( & dev - > p_dev - > dev , " mtd%d: Removing \n " ,
dev - > mtd_info - > index ) ;
2006-05-17 14:47:48 +04:00
map_destroy ( dev - > mtd_info ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-02 02:09:29 +03:00
pcmciamtd_release ( link ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 19:26:06 +04:00
static int pcmciamtd_probe ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct pcmciamtd_dev * dev ;
/* Create new memory card device */
2006-11-15 22:10:29 +03:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
2005-11-14 23:25:51 +03:00
if ( ! dev ) return - ENOMEM ;
2011-07-19 21:06:11 +04:00
pr_debug ( " dev=0x%p \n " , dev ) ;
2005-04-17 02:20:36 +04:00
2006-03-31 19:21:06 +04:00
dev - > p_dev = link ;
2005-04-17 02:20:36 +04:00
link - > priv = dev ;
2006-03-31 19:26:06 +04:00
return pcmciamtd_config ( link ) ;
2005-04-17 02:20:36 +04:00
}
2011-05-04 06:29:01 +04:00
static const struct pcmcia_device_id pcmciamtd_ids [ ] = {
2005-06-28 03:28:32 +04:00
PCMCIA_DEVICE_FUNC_ID ( 1 ) ,
PCMCIA_DEVICE_PROD_ID123 ( " IO DATA " , " PCS-2M " , " 2MB SRAM " , 0x547e66dc , 0x1fed36cd , 0x36eadd21 ) ,
PCMCIA_DEVICE_PROD_ID12 ( " IBM " , " 2MB SRAM " , 0xb569a6e5 , 0x36eadd21 ) ,
PCMCIA_DEVICE_PROD_ID12 ( " IBM " , " 4MB FLASH " , 0xb569a6e5 , 0x8bc54d2a ) ,
PCMCIA_DEVICE_PROD_ID12 ( " IBM " , " 8MB FLASH " , 0xb569a6e5 , 0x6df1be3e ) ,
PCMCIA_DEVICE_PROD_ID12 ( " Intel " , " S2E20SW " , 0x816cc815 , 0xd14c9dcf ) ,
PCMCIA_DEVICE_PROD_ID12 ( " Intel " , " S2E8 SW " , 0x816cc815 , 0xa2d7dedb ) ,
PCMCIA_DEVICE_PROD_ID12 ( " intel " , " SERIES2-02 " , 0x40ade711 , 0x145cea5c ) ,
PCMCIA_DEVICE_PROD_ID12 ( " intel " , " SERIES2-04 " , 0x40ade711 , 0x42064dda ) ,
PCMCIA_DEVICE_PROD_ID12 ( " intel " , " SERIES2-20 " , 0x40ade711 , 0x25ee5cb0 ) ,
PCMCIA_DEVICE_PROD_ID12 ( " intel " , " VALUE SERIES 100 " , 0x40ade711 , 0xdf8506d8 ) ,
PCMCIA_DEVICE_PROD_ID12 ( " KINGMAX TECHNOLOGY INC. " , " SRAM 256K Bytes " , 0x54d0c69c , 0xad12c29c ) ,
PCMCIA_DEVICE_PROD_ID12 ( " Maxtor " , " MAXFL MobileMax Flash Memory Card " , 0xb68968c8 , 0x2dfb47b0 ) ,
2010-05-13 13:59:59 +04:00
PCMCIA_DEVICE_PROD_ID123 ( " M-Systems " , " M-SYS Flash Memory Card " , " (c) M-Systems " , 0x7ed2ad87 , 0x675dc3fb , 0x7aef3965 ) ,
2010-05-13 14:00:01 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " PRETEC " , " 2MB SRAM CARD " , 0xebf91155 , 0x805360ca ) ,
2015-09-18 22:42:59 +03:00
PCMCIA_DEVICE_PROD_ID12 ( " PRETEC " , " 4MB SRAM CARD " , 0xebf91155 , 0x20b6bf17 ) ,
2005-06-28 03:28:32 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " SEIKO EPSON " , " WWB101EN20 " , 0xf9876baf , 0xad0b207b ) ,
PCMCIA_DEVICE_PROD_ID12 ( " SEIKO EPSON " , " WWB513EN20 " , 0xf9876baf , 0xe8d884ad ) ,
2010-05-13 13:59:59 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " SMART Modular Technologies " , " 4MB FLASH Card " , 0x96fd8277 , 0x737a5b05 ) ,
2005-06-28 03:28:32 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " Starfish, Inc. " , " REX-3000 " , 0x05ddca47 , 0xe7d67bca ) ,
PCMCIA_DEVICE_PROD_ID12 ( " Starfish, Inc. " , " REX-4100 " , 0x05ddca47 , 0x7bc32944 ) ,
/* the following was commented out in pcmcia-cs-3.2.7 */
/* PCMCIA_DEVICE_PROD_ID12("RATOC Systems,Inc.", "SmartMedia ADAPTER PC Card", 0xf4a2fefe, 0x5885b2ae), */
# ifdef CONFIG_MTD_PCMCIA_ANONYMOUS
{ . match_flags = PCMCIA_DEV_ID_MATCH_ANONYMOUS , } ,
# endif
PCMCIA_DEVICE_NULL
} ;
MODULE_DEVICE_TABLE ( pcmcia , pcmciamtd_ids ) ;
2005-04-17 02:20:36 +04:00
static struct pcmcia_driver pcmciamtd_driver = {
2010-08-08 13:36:26 +04:00
. name = " pcmciamtd " ,
2006-03-31 19:26:06 +04:00
. probe = pcmciamtd_probe ,
2005-11-14 23:23:14 +03:00
. remove = pcmciamtd_detach ,
2005-06-28 03:28:32 +04:00
. owner = THIS_MODULE ,
. id_table = pcmciamtd_ids ,
2005-11-14 23:21:18 +03:00
. suspend = pcmciamtd_suspend ,
. resume = pcmciamtd_resume ,
2005-04-17 02:20:36 +04:00
} ;
static int __init init_pcmciamtd ( void )
{
if ( bankwidth & & bankwidth ! = 1 & & bankwidth ! = 2 ) {
info ( " bad bankwidth (%d), using default " , bankwidth ) ;
bankwidth = 2 ;
}
if ( force_size & & ( force_size < 1 | | force_size > 64 ) ) {
info ( " bad force_size (%d), using default " , force_size ) ;
force_size = 0 ;
}
if ( mem_type & & mem_type ! = 1 & & mem_type ! = 2 ) {
info ( " bad mem_type (%d), using default " , mem_type ) ;
mem_type = 0 ;
}
return pcmcia_register_driver ( & pcmciamtd_driver ) ;
}
static void __exit exit_pcmciamtd ( void )
{
2011-07-19 21:06:11 +04:00
pr_debug ( DRIVER_DESC " unloading " ) ;
2005-04-17 02:20:36 +04:00
pcmcia_unregister_driver ( & pcmciamtd_driver ) ;
}
module_init ( init_pcmciamtd ) ;
module_exit ( exit_pcmciamtd ) ;