18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Author: Simon Evans <spse@secret.org.uk>
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2002 Simon Evans
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Licence: GPL
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/slab.h>
148c2ecf20Sopenharmony_ci#include <linux/timer.h>
158c2ecf20Sopenharmony_ci#include <linux/init.h>
168c2ecf20Sopenharmony_ci#include <asm/io.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <pcmcia/cistpl.h>
198c2ecf20Sopenharmony_ci#include <pcmcia/ds.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <linux/mtd/map.h>
228c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define info(format, arg...) printk(KERN_INFO "pcmciamtd: " format "\n" , ## arg)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define DRIVER_DESC	"PCMCIA Flash memory card driver"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Size of the PCMCIA address space: 26 bits = 64 MB */
298c2ecf20Sopenharmony_ci#define MAX_PCMCIA_ADDR	0x4000000
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct pcmciamtd_dev {
328c2ecf20Sopenharmony_ci	struct pcmcia_device	*p_dev;
338c2ecf20Sopenharmony_ci	void __iomem	*win_base;	/* ioremapped address of PCMCIA window */
348c2ecf20Sopenharmony_ci	unsigned int	win_size;	/* size of window */
358c2ecf20Sopenharmony_ci	unsigned int	offset;		/* offset into card the window currently points at */
368c2ecf20Sopenharmony_ci	struct map_info	pcmcia_map;
378c2ecf20Sopenharmony_ci	struct mtd_info	*mtd_info;
388c2ecf20Sopenharmony_ci	int		vpp;
398c2ecf20Sopenharmony_ci	char		mtd_name[sizeof(struct cistpl_vers_1_t)];
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/* Module parameters */
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
468c2ecf20Sopenharmony_cistatic int bankwidth = 2;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci/* Speed of memory accesses, in ns */
498c2ecf20Sopenharmony_cistatic int mem_speed;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci/* Force the size of an SRAM card */
528c2ecf20Sopenharmony_cistatic int force_size;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Force Vpp */
558c2ecf20Sopenharmony_cistatic int vpp;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci/* Set Vpp */
588c2ecf20Sopenharmony_cistatic int setvpp;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci/* Force card to be treated as FLASH, ROM or RAM */
618c2ecf20Sopenharmony_cistatic int mem_type;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
668c2ecf20Sopenharmony_cimodule_param(bankwidth, int, 0);
678c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bankwidth, "Set bankwidth (1=8 bit, 2=16 bit, default=2)");
688c2ecf20Sopenharmony_cimodule_param(mem_speed, int, 0);
698c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
708c2ecf20Sopenharmony_cimodule_param(force_size, int, 0);
718c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_size, "Force size of card in MiB (1-64)");
728c2ecf20Sopenharmony_cimodule_param(setvpp, int, 0);
738c2ecf20Sopenharmony_ciMODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
748c2ecf20Sopenharmony_cimodule_param(vpp, int, 0);
758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
768c2ecf20Sopenharmony_cimodule_param(mem_type, int, 0);
778c2ecf20Sopenharmony_ciMODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/* read/write{8,16} copy_{from,to} routines with window remapping
818c2ecf20Sopenharmony_ci * to access whole card
828c2ecf20Sopenharmony_ci */
838c2ecf20Sopenharmony_cistatic void __iomem *remap_window(struct map_info *map, unsigned long to)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
868c2ecf20Sopenharmony_ci	struct resource *win = (struct resource *) map->map_priv_2;
878c2ecf20Sopenharmony_ci	unsigned int offset;
888c2ecf20Sopenharmony_ci	int ret;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	if (!pcmcia_dev_present(dev->p_dev)) {
918c2ecf20Sopenharmony_ci		pr_debug("device removed\n");
928c2ecf20Sopenharmony_ci		return NULL;
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	offset = to & ~(dev->win_size-1);
968c2ecf20Sopenharmony_ci	if (offset != dev->offset) {
978c2ecf20Sopenharmony_ci		pr_debug("Remapping window from 0x%8.8x to 0x%8.8x\n",
988c2ecf20Sopenharmony_ci		      dev->offset, offset);
998c2ecf20Sopenharmony_ci		ret = pcmcia_map_mem_page(dev->p_dev, win, offset);
1008c2ecf20Sopenharmony_ci		if (ret != 0)
1018c2ecf20Sopenharmony_ci			return NULL;
1028c2ecf20Sopenharmony_ci		dev->offset = offset;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	return dev->win_base + (to & (dev->win_size-1));
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic map_word pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	void __iomem *addr;
1118c2ecf20Sopenharmony_ci	map_word d = {{0}};
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	addr = remap_window(map, ofs);
1148c2ecf20Sopenharmony_ci	if(!addr)
1158c2ecf20Sopenharmony_ci		return d;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	d.x[0] = readb(addr);
1188c2ecf20Sopenharmony_ci	pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n", ofs, addr, d.x[0]);
1198c2ecf20Sopenharmony_ci	return d;
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic map_word pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	void __iomem *addr;
1268c2ecf20Sopenharmony_ci	map_word d = {{0}};
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	addr = remap_window(map, ofs);
1298c2ecf20Sopenharmony_ci	if(!addr)
1308c2ecf20Sopenharmony_ci		return d;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	d.x[0] = readw(addr);
1338c2ecf20Sopenharmony_ci	pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n", ofs, addr, d.x[0]);
1348c2ecf20Sopenharmony_ci	return d;
1358c2ecf20Sopenharmony_ci}
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
1418c2ecf20Sopenharmony_ci	unsigned long win_size = dev->win_size;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	pr_debug("to = %p from = %lu len = %zd\n", to, from, len);
1448c2ecf20Sopenharmony_ci	while(len) {
1458c2ecf20Sopenharmony_ci		int toread = win_size - (from & (win_size-1));
1468c2ecf20Sopenharmony_ci		void __iomem *addr;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci		if(toread > len)
1498c2ecf20Sopenharmony_ci			toread = len;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci		addr = remap_window(map, from);
1528c2ecf20Sopenharmony_ci		if(!addr)
1538c2ecf20Sopenharmony_ci			return;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci		pr_debug("memcpy from %p to %p len = %d\n", addr, to, toread);
1568c2ecf20Sopenharmony_ci		memcpy_fromio(to, addr, toread);
1578c2ecf20Sopenharmony_ci		len -= toread;
1588c2ecf20Sopenharmony_ci		to += toread;
1598c2ecf20Sopenharmony_ci		from += toread;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic void pcmcia_write8_remap(struct map_info *map, map_word d, unsigned long adr)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	void __iomem *addr = remap_window(map, adr);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if(!addr)
1698c2ecf20Sopenharmony_ci		return;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	pr_debug("adr = 0x%08lx (%p)  data = 0x%02lx\n", adr, addr, d.x[0]);
1728c2ecf20Sopenharmony_ci	writeb(d.x[0], addr);
1738c2ecf20Sopenharmony_ci}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic void pcmcia_write16_remap(struct map_info *map, map_word d, unsigned long adr)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	void __iomem *addr = remap_window(map, adr);
1798c2ecf20Sopenharmony_ci	if(!addr)
1808c2ecf20Sopenharmony_ci		return;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	pr_debug("adr = 0x%08lx (%p)  data = 0x%04lx\n", adr, addr, d.x[0]);
1838c2ecf20Sopenharmony_ci	writew(d.x[0], addr);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
1908c2ecf20Sopenharmony_ci	unsigned long win_size = dev->win_size;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	pr_debug("to = %lu from = %p len = %zd\n", to, from, len);
1938c2ecf20Sopenharmony_ci	while(len) {
1948c2ecf20Sopenharmony_ci		int towrite = win_size - (to & (win_size-1));
1958c2ecf20Sopenharmony_ci		void __iomem *addr;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci		if(towrite > len)
1988c2ecf20Sopenharmony_ci			towrite = len;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci		addr = remap_window(map, to);
2018c2ecf20Sopenharmony_ci		if(!addr)
2028c2ecf20Sopenharmony_ci			return;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci		pr_debug("memcpy from %p to %p len = %d\n", from, addr, towrite);
2058c2ecf20Sopenharmony_ci		memcpy_toio(addr, from, towrite);
2068c2ecf20Sopenharmony_ci		len -= towrite;
2078c2ecf20Sopenharmony_ci		to += towrite;
2088c2ecf20Sopenharmony_ci		from += towrite;
2098c2ecf20Sopenharmony_ci	}
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci/* read/write{8,16} copy_{from,to} routines with direct access */
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci#define DEV_REMOVED(x)  (!(pcmcia_dev_present(((struct pcmciamtd_dev *)map->map_priv_1)->p_dev)))
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_cistatic map_word pcmcia_read8(struct map_info *map, unsigned long ofs)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	void __iomem *win_base = (void __iomem *)map->map_priv_2;
2208c2ecf20Sopenharmony_ci	map_word d = {{0}};
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	if(DEV_REMOVED(map))
2238c2ecf20Sopenharmony_ci		return d;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	d.x[0] = readb(win_base + ofs);
2268c2ecf20Sopenharmony_ci	pr_debug("ofs = 0x%08lx (%p) data = 0x%02lx\n",
2278c2ecf20Sopenharmony_ci	      ofs, win_base + ofs, d.x[0]);
2288c2ecf20Sopenharmony_ci	return d;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic map_word pcmcia_read16(struct map_info *map, unsigned long ofs)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	void __iomem *win_base = (void __iomem *)map->map_priv_2;
2358c2ecf20Sopenharmony_ci	map_word d = {{0}};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if(DEV_REMOVED(map))
2388c2ecf20Sopenharmony_ci		return d;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	d.x[0] = readw(win_base + ofs);
2418c2ecf20Sopenharmony_ci	pr_debug("ofs = 0x%08lx (%p) data = 0x%04lx\n",
2428c2ecf20Sopenharmony_ci	      ofs, win_base + ofs, d.x[0]);
2438c2ecf20Sopenharmony_ci	return d;
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_cistatic void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	void __iomem *win_base = (void __iomem *)map->map_priv_2;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if(DEV_REMOVED(map))
2528c2ecf20Sopenharmony_ci		return;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	pr_debug("to = %p from = %lu len = %zd\n", to, from, len);
2558c2ecf20Sopenharmony_ci	memcpy_fromio(to, win_base + from, len);
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic void pcmcia_write8(struct map_info *map, map_word d, unsigned long adr)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	void __iomem *win_base = (void __iomem *)map->map_priv_2;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	if(DEV_REMOVED(map))
2648c2ecf20Sopenharmony_ci		return;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	pr_debug("adr = 0x%08lx (%p)  data = 0x%02lx\n",
2678c2ecf20Sopenharmony_ci	      adr, win_base + adr, d.x[0]);
2688c2ecf20Sopenharmony_ci	writeb(d.x[0], win_base + adr);
2698c2ecf20Sopenharmony_ci}
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic void pcmcia_write16(struct map_info *map, map_word d, unsigned long adr)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	void __iomem *win_base = (void __iomem *)map->map_priv_2;
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	if(DEV_REMOVED(map))
2778c2ecf20Sopenharmony_ci		return;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	pr_debug("adr = 0x%08lx (%p)  data = 0x%04lx\n",
2808c2ecf20Sopenharmony_ci	      adr, win_base + adr, d.x[0]);
2818c2ecf20Sopenharmony_ci	writew(d.x[0], win_base + adr);
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
2868c2ecf20Sopenharmony_ci{
2878c2ecf20Sopenharmony_ci	void __iomem *win_base = (void __iomem *)map->map_priv_2;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	if(DEV_REMOVED(map))
2908c2ecf20Sopenharmony_ci		return;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	pr_debug("to = %lu from = %p len = %zd\n", to, from, len);
2938c2ecf20Sopenharmony_ci	memcpy_toio(win_base + to, from, len);
2948c2ecf20Sopenharmony_ci}
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pcmcia_vpp_lock);
2988c2ecf20Sopenharmony_cistatic int pcmcia_vpp_refcnt;
2998c2ecf20Sopenharmony_cistatic void pcmciamtd_set_vpp(struct map_info *map, int on)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
3028c2ecf20Sopenharmony_ci	struct pcmcia_device *link = dev->p_dev;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	pr_debug("dev = %p on = %d vpp = %d\n\n", dev, on, dev->vpp);
3058c2ecf20Sopenharmony_ci	mutex_lock(&pcmcia_vpp_lock);
3068c2ecf20Sopenharmony_ci	if (on) {
3078c2ecf20Sopenharmony_ci		if (++pcmcia_vpp_refcnt == 1)   /* first nested 'on' */
3088c2ecf20Sopenharmony_ci			pcmcia_fixup_vpp(link, dev->vpp);
3098c2ecf20Sopenharmony_ci	} else {
3108c2ecf20Sopenharmony_ci		if (--pcmcia_vpp_refcnt == 0)   /* last nested 'off' */
3118c2ecf20Sopenharmony_ci			pcmcia_fixup_vpp(link, 0);
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci	mutex_unlock(&pcmcia_vpp_lock);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cistatic void pcmciamtd_release(struct pcmcia_device *link)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = link->priv;
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	pr_debug("link = 0x%p\n", link);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	if (link->resource[2]->end) {
3248c2ecf20Sopenharmony_ci		if(dev->win_base) {
3258c2ecf20Sopenharmony_ci			iounmap(dev->win_base);
3268c2ecf20Sopenharmony_ci			dev->win_base = NULL;
3278c2ecf20Sopenharmony_ci		}
3288c2ecf20Sopenharmony_ci	}
3298c2ecf20Sopenharmony_ci	pcmcia_disable_device(link);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_cistatic int pcmciamtd_cistpl_format(struct pcmcia_device *p_dev,
3348c2ecf20Sopenharmony_ci				tuple_t *tuple,
3358c2ecf20Sopenharmony_ci				void *priv_data)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	cisparse_t parse;
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (!pcmcia_parse_tuple(tuple, &parse)) {
3408c2ecf20Sopenharmony_ci		cistpl_format_t *t = &parse.format;
3418c2ecf20Sopenharmony_ci		(void)t; /* Shut up, gcc */
3428c2ecf20Sopenharmony_ci		pr_debug("Format type: %u, Error Detection: %u, offset = %u, length =%u\n",
3438c2ecf20Sopenharmony_ci			t->type, t->edc, t->offset, t->length);
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci	return -ENOSPC;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic int pcmciamtd_cistpl_jedec(struct pcmcia_device *p_dev,
3498c2ecf20Sopenharmony_ci				tuple_t *tuple,
3508c2ecf20Sopenharmony_ci				void *priv_data)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	cisparse_t parse;
3538c2ecf20Sopenharmony_ci	int i;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (!pcmcia_parse_tuple(tuple, &parse)) {
3568c2ecf20Sopenharmony_ci		cistpl_jedec_t *t = &parse.jedec;
3578c2ecf20Sopenharmony_ci		for (i = 0; i < t->nid; i++)
3588c2ecf20Sopenharmony_ci			pr_debug("JEDEC: 0x%02x 0x%02x\n",
3598c2ecf20Sopenharmony_ci			      t->id[i].mfr, t->id[i].info);
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci	return -ENOSPC;
3628c2ecf20Sopenharmony_ci}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_cistatic int pcmciamtd_cistpl_device(struct pcmcia_device *p_dev,
3658c2ecf20Sopenharmony_ci				tuple_t *tuple,
3668c2ecf20Sopenharmony_ci				void *priv_data)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = priv_data;
3698c2ecf20Sopenharmony_ci	cisparse_t parse;
3708c2ecf20Sopenharmony_ci	cistpl_device_t *t = &parse.device;
3718c2ecf20Sopenharmony_ci	int i;
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	if (pcmcia_parse_tuple(tuple, &parse))
3748c2ecf20Sopenharmony_ci		return -EINVAL;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	pr_debug("Common memory:\n");
3778c2ecf20Sopenharmony_ci	dev->pcmcia_map.size = t->dev[0].size;
3788c2ecf20Sopenharmony_ci	/* from here on: DEBUG only */
3798c2ecf20Sopenharmony_ci	for (i = 0; i < t->ndev; i++) {
3808c2ecf20Sopenharmony_ci		pr_debug("Region %d, type = %u\n", i, t->dev[i].type);
3818c2ecf20Sopenharmony_ci		pr_debug("Region %d, wp = %u\n", i, t->dev[i].wp);
3828c2ecf20Sopenharmony_ci		pr_debug("Region %d, speed = %u ns\n", i, t->dev[i].speed);
3838c2ecf20Sopenharmony_ci		pr_debug("Region %d, size = %u bytes\n", i, t->dev[i].size);
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci	return 0;
3868c2ecf20Sopenharmony_ci}
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_cistatic int pcmciamtd_cistpl_geo(struct pcmcia_device *p_dev,
3898c2ecf20Sopenharmony_ci				tuple_t *tuple,
3908c2ecf20Sopenharmony_ci				void *priv_data)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = priv_data;
3938c2ecf20Sopenharmony_ci	cisparse_t parse;
3948c2ecf20Sopenharmony_ci	cistpl_device_geo_t *t = &parse.device_geo;
3958c2ecf20Sopenharmony_ci	int i;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (pcmcia_parse_tuple(tuple, &parse))
3988c2ecf20Sopenharmony_ci		return -EINVAL;
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	dev->pcmcia_map.bankwidth = t->geo[0].buswidth;
4018c2ecf20Sopenharmony_ci	/* from here on: DEBUG only */
4028c2ecf20Sopenharmony_ci	for (i = 0; i < t->ngeo; i++) {
4038c2ecf20Sopenharmony_ci		pr_debug("region: %d bankwidth = %u\n", i, t->geo[i].buswidth);
4048c2ecf20Sopenharmony_ci		pr_debug("region: %d erase_block = %u\n", i, t->geo[i].erase_block);
4058c2ecf20Sopenharmony_ci		pr_debug("region: %d read_block = %u\n", i, t->geo[i].read_block);
4068c2ecf20Sopenharmony_ci		pr_debug("region: %d write_block = %u\n", i, t->geo[i].write_block);
4078c2ecf20Sopenharmony_ci		pr_debug("region: %d partition = %u\n", i, t->geo[i].partition);
4088c2ecf20Sopenharmony_ci		pr_debug("region: %d interleave = %u\n", i, t->geo[i].interleave);
4098c2ecf20Sopenharmony_ci	}
4108c2ecf20Sopenharmony_ci	return 0;
4118c2ecf20Sopenharmony_ci}
4128c2ecf20Sopenharmony_ci
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic void card_settings(struct pcmciamtd_dev *dev, struct pcmcia_device *p_dev, int *new_name)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	int i;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	if (p_dev->prod_id[0]) {
4198c2ecf20Sopenharmony_ci		dev->mtd_name[0] = '\0';
4208c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++) {
4218c2ecf20Sopenharmony_ci			if (i)
4228c2ecf20Sopenharmony_ci				strcat(dev->mtd_name, " ");
4238c2ecf20Sopenharmony_ci			if (p_dev->prod_id[i])
4248c2ecf20Sopenharmony_ci				strcat(dev->mtd_name, p_dev->prod_id[i]);
4258c2ecf20Sopenharmony_ci		}
4268c2ecf20Sopenharmony_ci		pr_debug("Found name: %s\n", dev->mtd_name);
4278c2ecf20Sopenharmony_ci	}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	pcmcia_loop_tuple(p_dev, CISTPL_FORMAT, pcmciamtd_cistpl_format, NULL);
4308c2ecf20Sopenharmony_ci	pcmcia_loop_tuple(p_dev, CISTPL_JEDEC_C, pcmciamtd_cistpl_jedec, NULL);
4318c2ecf20Sopenharmony_ci	pcmcia_loop_tuple(p_dev, CISTPL_DEVICE, pcmciamtd_cistpl_device, dev);
4328c2ecf20Sopenharmony_ci	pcmcia_loop_tuple(p_dev, CISTPL_DEVICE_GEO, pcmciamtd_cistpl_geo, dev);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if(!dev->pcmcia_map.size)
4358c2ecf20Sopenharmony_ci		dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	if(!dev->pcmcia_map.bankwidth)
4388c2ecf20Sopenharmony_ci		dev->pcmcia_map.bankwidth = 2;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	if(force_size) {
4418c2ecf20Sopenharmony_ci		dev->pcmcia_map.size = force_size << 20;
4428c2ecf20Sopenharmony_ci		pr_debug("size forced to %dM\n", force_size);
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if(bankwidth) {
4468c2ecf20Sopenharmony_ci		dev->pcmcia_map.bankwidth = bankwidth;
4478c2ecf20Sopenharmony_ci		pr_debug("bankwidth forced to %d\n", bankwidth);
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	dev->pcmcia_map.name = dev->mtd_name;
4518c2ecf20Sopenharmony_ci	if(!dev->mtd_name[0]) {
4528c2ecf20Sopenharmony_ci		strcpy(dev->mtd_name, "PCMCIA Memory card");
4538c2ecf20Sopenharmony_ci		*new_name = 1;
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	pr_debug("Device: Size: %lu Width:%d Name: %s\n",
4578c2ecf20Sopenharmony_ci	      dev->pcmcia_map.size,
4588c2ecf20Sopenharmony_ci	      dev->pcmcia_map.bankwidth << 3, dev->mtd_name);
4598c2ecf20Sopenharmony_ci}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_cistatic int pcmciamtd_config(struct pcmcia_device *link)
4638c2ecf20Sopenharmony_ci{
4648c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = link->priv;
4658c2ecf20Sopenharmony_ci	struct mtd_info *mtd = NULL;
4668c2ecf20Sopenharmony_ci	int ret;
4678c2ecf20Sopenharmony_ci	int i, j = 0;
4688c2ecf20Sopenharmony_ci	static char *probes[] = { "jedec_probe", "cfi_probe" };
4698c2ecf20Sopenharmony_ci	int new_name = 0;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	pr_debug("link=0x%p\n", link);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	card_settings(dev, link, &new_name);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	dev->pcmcia_map.phys = NO_XIP;
4768c2ecf20Sopenharmony_ci	dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
4778c2ecf20Sopenharmony_ci	dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
4788c2ecf20Sopenharmony_ci	if (dev->pcmcia_map.bankwidth == 1) {
4798c2ecf20Sopenharmony_ci		dev->pcmcia_map.read = pcmcia_read8_remap;
4808c2ecf20Sopenharmony_ci		dev->pcmcia_map.write = pcmcia_write8_remap;
4818c2ecf20Sopenharmony_ci	} else {
4828c2ecf20Sopenharmony_ci		dev->pcmcia_map.read = pcmcia_read16_remap;
4838c2ecf20Sopenharmony_ci		dev->pcmcia_map.write = pcmcia_write16_remap;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci	if(setvpp == 1)
4868c2ecf20Sopenharmony_ci		dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/* Request a memory window for PCMCIA. Some architeures can map windows
4898c2ecf20Sopenharmony_ci	 * up to the maximum that PCMCIA can support (64MiB) - this is ideal and
4908c2ecf20Sopenharmony_ci	 * we aim for a window the size of the whole card - otherwise we try
4918c2ecf20Sopenharmony_ci	 * smaller windows until we succeed
4928c2ecf20Sopenharmony_ci	 */
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	link->resource[2]->flags |=  WIN_MEMORY_TYPE_CM | WIN_ENABLE;
4958c2ecf20Sopenharmony_ci	link->resource[2]->flags |= (dev->pcmcia_map.bankwidth == 1) ?
4968c2ecf20Sopenharmony_ci					WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
4978c2ecf20Sopenharmony_ci	link->resource[2]->start = 0;
4988c2ecf20Sopenharmony_ci	link->resource[2]->end = (force_size) ? force_size << 20 :
4998c2ecf20Sopenharmony_ci					MAX_PCMCIA_ADDR;
5008c2ecf20Sopenharmony_ci	dev->win_size = 0;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	do {
5038c2ecf20Sopenharmony_ci		int ret;
5048c2ecf20Sopenharmony_ci		pr_debug("requesting window with size = %luKiB memspeed = %d\n",
5058c2ecf20Sopenharmony_ci			(unsigned long) resource_size(link->resource[2]) >> 10,
5068c2ecf20Sopenharmony_ci			mem_speed);
5078c2ecf20Sopenharmony_ci		ret = pcmcia_request_window(link, link->resource[2], mem_speed);
5088c2ecf20Sopenharmony_ci		pr_debug("ret = %d dev->win_size = %d\n", ret, dev->win_size);
5098c2ecf20Sopenharmony_ci		if(ret) {
5108c2ecf20Sopenharmony_ci			j++;
5118c2ecf20Sopenharmony_ci			link->resource[2]->start = 0;
5128c2ecf20Sopenharmony_ci			link->resource[2]->end = (force_size) ?
5138c2ecf20Sopenharmony_ci					force_size << 20 : MAX_PCMCIA_ADDR;
5148c2ecf20Sopenharmony_ci			link->resource[2]->end >>= j;
5158c2ecf20Sopenharmony_ci		} else {
5168c2ecf20Sopenharmony_ci			pr_debug("Got window of size %luKiB\n", (unsigned long)
5178c2ecf20Sopenharmony_ci				resource_size(link->resource[2]) >> 10);
5188c2ecf20Sopenharmony_ci			dev->win_size = resource_size(link->resource[2]);
5198c2ecf20Sopenharmony_ci			break;
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci	} while (link->resource[2]->end >= 0x1000);
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	pr_debug("dev->win_size = %d\n", dev->win_size);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	if(!dev->win_size) {
5268c2ecf20Sopenharmony_ci		dev_err(&dev->p_dev->dev, "Cannot allocate memory window\n");
5278c2ecf20Sopenharmony_ci		pcmciamtd_release(link);
5288c2ecf20Sopenharmony_ci		return -ENODEV;
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci	pr_debug("Allocated a window of %dKiB\n", dev->win_size >> 10);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	/* Get write protect status */
5338c2ecf20Sopenharmony_ci	dev->win_base = ioremap(link->resource[2]->start,
5348c2ecf20Sopenharmony_ci				resource_size(link->resource[2]));
5358c2ecf20Sopenharmony_ci	if(!dev->win_base) {
5368c2ecf20Sopenharmony_ci		dev_err(&dev->p_dev->dev, "ioremap(%pR) failed\n",
5378c2ecf20Sopenharmony_ci			link->resource[2]);
5388c2ecf20Sopenharmony_ci		pcmciamtd_release(link);
5398c2ecf20Sopenharmony_ci		return -ENODEV;
5408c2ecf20Sopenharmony_ci	}
5418c2ecf20Sopenharmony_ci	pr_debug("mapped window dev = %p @ %pR, base = %p\n",
5428c2ecf20Sopenharmony_ci	      dev, link->resource[2], dev->win_base);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	dev->offset = 0;
5458c2ecf20Sopenharmony_ci	dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
5468c2ecf20Sopenharmony_ci	dev->pcmcia_map.map_priv_2 = (unsigned long)link->resource[2];
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	dev->vpp = (vpp) ? vpp : link->socket->socket.Vpp;
5498c2ecf20Sopenharmony_ci	if(setvpp == 2) {
5508c2ecf20Sopenharmony_ci		link->vpp = dev->vpp;
5518c2ecf20Sopenharmony_ci	} else {
5528c2ecf20Sopenharmony_ci		link->vpp = 0;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	link->config_index = 0;
5568c2ecf20Sopenharmony_ci	pr_debug("Setting Configuration\n");
5578c2ecf20Sopenharmony_ci	ret = pcmcia_enable_device(link);
5588c2ecf20Sopenharmony_ci	if (ret != 0) {
5598c2ecf20Sopenharmony_ci		if (dev->win_base) {
5608c2ecf20Sopenharmony_ci			iounmap(dev->win_base);
5618c2ecf20Sopenharmony_ci			dev->win_base = NULL;
5628c2ecf20Sopenharmony_ci		}
5638c2ecf20Sopenharmony_ci		return -ENODEV;
5648c2ecf20Sopenharmony_ci	}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	if(mem_type == 1) {
5678c2ecf20Sopenharmony_ci		mtd = do_map_probe("map_ram", &dev->pcmcia_map);
5688c2ecf20Sopenharmony_ci	} else if(mem_type == 2) {
5698c2ecf20Sopenharmony_ci		mtd = do_map_probe("map_rom", &dev->pcmcia_map);
5708c2ecf20Sopenharmony_ci	} else {
5718c2ecf20Sopenharmony_ci		for(i = 0; i < ARRAY_SIZE(probes); i++) {
5728c2ecf20Sopenharmony_ci			pr_debug("Trying %s\n", probes[i]);
5738c2ecf20Sopenharmony_ci			mtd = do_map_probe(probes[i], &dev->pcmcia_map);
5748c2ecf20Sopenharmony_ci			if(mtd)
5758c2ecf20Sopenharmony_ci				break;
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci			pr_debug("FAILED: %s\n", probes[i]);
5788c2ecf20Sopenharmony_ci		}
5798c2ecf20Sopenharmony_ci	}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	if(!mtd) {
5828c2ecf20Sopenharmony_ci		pr_debug("Can not find an MTD\n");
5838c2ecf20Sopenharmony_ci		pcmciamtd_release(link);
5848c2ecf20Sopenharmony_ci		return -ENODEV;
5858c2ecf20Sopenharmony_ci	}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	dev->mtd_info = mtd;
5888c2ecf20Sopenharmony_ci	mtd->owner = THIS_MODULE;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if(new_name) {
5918c2ecf20Sopenharmony_ci		int size = 0;
5928c2ecf20Sopenharmony_ci		char unit = ' ';
5938c2ecf20Sopenharmony_ci		/* Since we are using a default name, make it better by adding
5948c2ecf20Sopenharmony_ci		 * in the size
5958c2ecf20Sopenharmony_ci		 */
5968c2ecf20Sopenharmony_ci		if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */
5978c2ecf20Sopenharmony_ci			size = mtd->size >> 10;
5988c2ecf20Sopenharmony_ci			unit = 'K';
5998c2ecf20Sopenharmony_ci		} else {
6008c2ecf20Sopenharmony_ci			size = mtd->size >> 20;
6018c2ecf20Sopenharmony_ci			unit = 'M';
6028c2ecf20Sopenharmony_ci		}
6038c2ecf20Sopenharmony_ci		snprintf(dev->mtd_name, sizeof(dev->mtd_name), "%d%ciB %s", size, unit, "PCMCIA Memory card");
6048c2ecf20Sopenharmony_ci	}
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	/* If the memory found is fits completely into the mapped PCMCIA window,
6078c2ecf20Sopenharmony_ci	   use the faster non-remapping read/write functions */
6088c2ecf20Sopenharmony_ci	if(mtd->size <= dev->win_size) {
6098c2ecf20Sopenharmony_ci		pr_debug("Using non remapping memory functions\n");
6108c2ecf20Sopenharmony_ci		dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
6118c2ecf20Sopenharmony_ci		if (dev->pcmcia_map.bankwidth == 1) {
6128c2ecf20Sopenharmony_ci			dev->pcmcia_map.read = pcmcia_read8;
6138c2ecf20Sopenharmony_ci			dev->pcmcia_map.write = pcmcia_write8;
6148c2ecf20Sopenharmony_ci		} else {
6158c2ecf20Sopenharmony_ci			dev->pcmcia_map.read = pcmcia_read16;
6168c2ecf20Sopenharmony_ci			dev->pcmcia_map.write = pcmcia_write16;
6178c2ecf20Sopenharmony_ci		}
6188c2ecf20Sopenharmony_ci		dev->pcmcia_map.copy_from = pcmcia_copy_from;
6198c2ecf20Sopenharmony_ci		dev->pcmcia_map.copy_to = pcmcia_copy_to;
6208c2ecf20Sopenharmony_ci	}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci	if (mtd_device_register(mtd, NULL, 0)) {
6238c2ecf20Sopenharmony_ci		map_destroy(mtd);
6248c2ecf20Sopenharmony_ci		dev->mtd_info = NULL;
6258c2ecf20Sopenharmony_ci		dev_err(&dev->p_dev->dev,
6268c2ecf20Sopenharmony_ci			"Could not register the MTD device\n");
6278c2ecf20Sopenharmony_ci		pcmciamtd_release(link);
6288c2ecf20Sopenharmony_ci		return -ENODEV;
6298c2ecf20Sopenharmony_ci	}
6308c2ecf20Sopenharmony_ci	dev_info(&dev->p_dev->dev, "mtd%d: %s\n", mtd->index, mtd->name);
6318c2ecf20Sopenharmony_ci	return 0;
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_cistatic int pcmciamtd_suspend(struct pcmcia_device *dev)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	pr_debug("EVENT_PM_RESUME\n");
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	/* get_lock(link); */
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	return 0;
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic int pcmciamtd_resume(struct pcmcia_device *dev)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	pr_debug("EVENT_PM_SUSPEND\n");
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	/* free_lock(link); */
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	return 0;
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_cistatic void pcmciamtd_detach(struct pcmcia_device *link)
6558c2ecf20Sopenharmony_ci{
6568c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev = link->priv;
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ci	pr_debug("link=0x%p\n", link);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	if(dev->mtd_info) {
6618c2ecf20Sopenharmony_ci		mtd_device_unregister(dev->mtd_info);
6628c2ecf20Sopenharmony_ci		dev_info(&dev->p_dev->dev, "mtd%d: Removing\n",
6638c2ecf20Sopenharmony_ci			 dev->mtd_info->index);
6648c2ecf20Sopenharmony_ci		map_destroy(dev->mtd_info);
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	pcmciamtd_release(link);
6688c2ecf20Sopenharmony_ci}
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic int pcmciamtd_probe(struct pcmcia_device *link)
6728c2ecf20Sopenharmony_ci{
6738c2ecf20Sopenharmony_ci	struct pcmciamtd_dev *dev;
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	/* Create new memory card device */
6768c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
6778c2ecf20Sopenharmony_ci	if (!dev) return -ENOMEM;
6788c2ecf20Sopenharmony_ci	pr_debug("dev=0x%p\n", dev);
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	dev->p_dev = link;
6818c2ecf20Sopenharmony_ci	link->priv = dev;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	return pcmciamtd_config(link);
6848c2ecf20Sopenharmony_ci}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_cistatic const struct pcmcia_device_id pcmciamtd_ids[] = {
6878c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_FUNC_ID(1),
6888c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
6898c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
6908c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IBM", "4MB FLASH", 0xb569a6e5, 0x8bc54d2a),
6918c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("IBM", "8MB FLASH", 0xb569a6e5, 0x6df1be3e),
6928c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Intel", "S2E20SW", 0x816cc815, 0xd14c9dcf),
6938c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Intel", "S2E8 SW", 0x816cc815, 0xa2d7dedb),
6948c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-02 ", 0x40ade711, 0x145cea5c),
6958c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-04 ", 0x40ade711, 0x42064dda),
6968c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-20 ", 0x40ade711, 0x25ee5cb0),
6978c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("intel", "VALUE SERIES 100 ", 0x40ade711, 0xdf8506d8),
6988c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("KINGMAX TECHNOLOGY INC.", "SRAM 256K Bytes", 0x54d0c69c, 0xad12c29c),
6998c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Maxtor", "MAXFL MobileMax Flash Memory Card", 0xb68968c8, 0x2dfb47b0),
7008c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID123("M-Systems", "M-SYS Flash Memory Card", "(c) M-Systems", 0x7ed2ad87, 0x675dc3fb, 0x7aef3965),
7018c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PRETEC", "  2MB SRAM CARD", 0xebf91155, 0x805360ca),
7028c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("PRETEC", "  4MB SRAM CARD", 0xebf91155, 0x20b6bf17),
7038c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB101EN20", 0xf9876baf, 0xad0b207b),
7048c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB513EN20", 0xf9876baf, 0xe8d884ad),
7058c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("SMART Modular Technologies", " 4MB FLASH Card", 0x96fd8277, 0x737a5b05),
7068c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-3000", 0x05ddca47, 0xe7d67bca),
7078c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-4100", 0x05ddca47, 0x7bc32944),
7088c2ecf20Sopenharmony_ci	/* the following was commented out in pcmcia-cs-3.2.7 */
7098c2ecf20Sopenharmony_ci	/* PCMCIA_DEVICE_PROD_ID12("RATOC Systems,Inc.", "SmartMedia ADAPTER PC Card", 0xf4a2fefe, 0x5885b2ae), */
7108c2ecf20Sopenharmony_ci#ifdef CONFIG_MTD_PCMCIA_ANONYMOUS
7118c2ecf20Sopenharmony_ci	{ .match_flags = PCMCIA_DEV_ID_MATCH_ANONYMOUS, },
7128c2ecf20Sopenharmony_ci#endif
7138c2ecf20Sopenharmony_ci	PCMCIA_DEVICE_NULL
7148c2ecf20Sopenharmony_ci};
7158c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, pcmciamtd_ids);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_cistatic struct pcmcia_driver pcmciamtd_driver = {
7188c2ecf20Sopenharmony_ci	.name		= "pcmciamtd",
7198c2ecf20Sopenharmony_ci	.probe		= pcmciamtd_probe,
7208c2ecf20Sopenharmony_ci	.remove		= pcmciamtd_detach,
7218c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
7228c2ecf20Sopenharmony_ci	.id_table	= pcmciamtd_ids,
7238c2ecf20Sopenharmony_ci	.suspend	= pcmciamtd_suspend,
7248c2ecf20Sopenharmony_ci	.resume		= pcmciamtd_resume,
7258c2ecf20Sopenharmony_ci};
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_cistatic int __init init_pcmciamtd(void)
7298c2ecf20Sopenharmony_ci{
7308c2ecf20Sopenharmony_ci	if(bankwidth && bankwidth != 1 && bankwidth != 2) {
7318c2ecf20Sopenharmony_ci		info("bad bankwidth (%d), using default", bankwidth);
7328c2ecf20Sopenharmony_ci		bankwidth = 2;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci	if(force_size && (force_size < 1 || force_size > 64)) {
7358c2ecf20Sopenharmony_ci		info("bad force_size (%d), using default", force_size);
7368c2ecf20Sopenharmony_ci		force_size = 0;
7378c2ecf20Sopenharmony_ci	}
7388c2ecf20Sopenharmony_ci	if(mem_type && mem_type != 1 && mem_type != 2) {
7398c2ecf20Sopenharmony_ci		info("bad mem_type (%d), using default", mem_type);
7408c2ecf20Sopenharmony_ci		mem_type = 0;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci	return pcmcia_register_driver(&pcmciamtd_driver);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_cistatic void __exit exit_pcmciamtd(void)
7478c2ecf20Sopenharmony_ci{
7488c2ecf20Sopenharmony_ci	pr_debug(DRIVER_DESC " unloading");
7498c2ecf20Sopenharmony_ci	pcmcia_unregister_driver(&pcmciamtd_driver);
7508c2ecf20Sopenharmony_ci}
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_cimodule_init(init_pcmciamtd);
7538c2ecf20Sopenharmony_cimodule_exit(exit_pcmciamtd);
754