summaryrefslogtreecommitdiff
path: root/drivers/pcmcia
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/Kconfig3
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/at91_cf.c3
-rw-r--r--drivers/pcmcia/au1000_generic.c14
-rw-r--r--drivers/pcmcia/bcm63xx_pcmcia.c1
-rw-r--r--drivers/pcmcia/bfin_cf_pcmcia.c13
-rw-r--r--drivers/pcmcia/cistpl.c9
-rw-r--r--drivers/pcmcia/cs.c140
-rw-r--r--drivers/pcmcia/db1xxx_ss.c40
-rw-r--r--drivers/pcmcia/ds.c86
-rw-r--r--drivers/pcmcia/electra_cf.c1
-rw-r--r--drivers/pcmcia/i82092.c16
-rw-r--r--drivers/pcmcia/i82365.c12
-rw-r--r--drivers/pcmcia/m32r_cfc.c12
-rw-r--r--drivers/pcmcia/m32r_pcc.c13
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c18
-rw-r--r--drivers/pcmcia/omap_cf.c13
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c8
-rw-r--r--drivers/pcmcia/pcmcia_resource.c11
-rw-r--r--drivers/pcmcia/pd6729.c81
-rw-r--r--drivers/pcmcia/pxa2xx_base.c9
-rw-r--r--drivers/pcmcia/pxa2xx_vpac270.c229
-rw-r--r--drivers/pcmcia/rsrc_mgr.c1
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c66
-rw-r--r--drivers/pcmcia/sa1100_generic.c14
-rw-r--r--drivers/pcmcia/sa1111_generic.c13
-rw-r--r--drivers/pcmcia/sa11xx_base.c1
-rw-r--r--drivers/pcmcia/socket_sysfs.c1
-rw-r--r--drivers/pcmcia/tcic.c13
-rw-r--r--drivers/pcmcia/vrc4171_card.c13
-rw-r--r--drivers/pcmcia/xxs1500_ss.c1
-rw-r--r--drivers/pcmcia/yenta_socket.c18
32 files changed, 456 insertions, 418 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index d189e4743e69..a44733d44ca1 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -234,7 +234,8 @@ config PCMCIA_PXA2XX
depends on ARM && ARCH_PXA && PCMCIA
depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \
|| MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \
- || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2)
+ || ARCOM_PCMCIA || ARCH_PXA_ESERIES || MACH_STARGATE2 \
+ || MACH_VPAC270)
select PCMCIA_SOC_COMMON
help
Say Y here to include support for the PXA2xx PCMCIA controller
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 381b031d9d75..4dae3613c458 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -66,6 +66,7 @@ pxa2xx-obj-$(CONFIG_MACH_PALMTC) += pxa2xx_palmtc.o
pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o
pxa2xx-obj-$(CONFIG_MACH_E740) += pxa2xx_e740.o
pxa2xx-obj-$(CONFIG_MACH_STARGATE2) += pxa2xx_stargate2.o
+pxa2xx-obj-$(CONFIG_MACH_VPAC270) += pxa2xx_vpac270.o
obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_base.o $(pxa2xx-obj-y)
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 5d228071ec69..fb33fa42d249 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -15,6 +15,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include <pcmcia/ss.h>
@@ -361,7 +362,6 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
struct at91_cf_data *board = cf->board;
- pcmcia_socket_dev_suspend(&pdev->dev);
if (device_may_wakeup(&pdev->dev)) {
enable_irq_wake(board->det_pin);
if (board->irq_pin)
@@ -381,7 +381,6 @@ static int at91_cf_resume(struct platform_device *pdev)
disable_irq_wake(board->irq_pin);
}
- pcmcia_socket_dev_resume(&pdev->dev);
return 0;
}
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index 171c8a654887..88c4c4098789 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -43,6 +43,7 @@
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -510,17 +511,6 @@ static int au1x00_drv_pcmcia_probe(struct platform_device *dev)
return ret;
}
-static int au1x00_drv_pcmcia_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int au1x00_drv_pcmcia_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
-
static struct platform_driver au1x00_pcmcia_driver = {
.driver = {
.name = "au1x00-pcmcia",
@@ -528,8 +518,6 @@ static struct platform_driver au1x00_pcmcia_driver = {
},
.probe = au1x00_drv_pcmcia_probe,
.remove = au1x00_drv_pcmcia_remove,
- .suspend = au1x00_drv_pcmcia_suspend,
- .resume = au1x00_drv_pcmcia_resume,
};
diff --git a/drivers/pcmcia/bcm63xx_pcmcia.c b/drivers/pcmcia/bcm63xx_pcmcia.c
index bc88a3b19bb3..693577e0fefc 100644
--- a/drivers/pcmcia/bcm63xx_pcmcia.c
+++ b/drivers/pcmcia/bcm63xx_pcmcia.c
@@ -11,6 +11,7 @@
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/gpio.h>
diff --git a/drivers/pcmcia/bfin_cf_pcmcia.c b/drivers/pcmcia/bfin_cf_pcmcia.c
index 2482ce7ac6dc..9e84d039de41 100644
--- a/drivers/pcmcia/bfin_cf_pcmcia.c
+++ b/drivers/pcmcia/bfin_cf_pcmcia.c
@@ -31,6 +31,7 @@
#include <linux/platform_device.h>
#include <linux/errno.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -300,16 +301,6 @@ static int __devexit bfin_cf_remove(struct platform_device *pdev)
return 0;
}
-static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
- return pcmcia_socket_dev_suspend(&pdev->dev);
-}
-
-static int bfin_cf_resume(struct platform_device *pdev)
-{
- return pcmcia_socket_dev_resume(&pdev->dev);
-}
-
static struct platform_driver bfin_cf_driver = {
.driver = {
.name = (char *)driver_name,
@@ -317,8 +308,6 @@ static struct platform_driver bfin_cf_driver = {
},
.probe = bfin_cf_probe,
.remove = __devexit_p(bfin_cf_remove),
- .suspend = bfin_cf_suspend,
- .resume = bfin_cf_resume,
};
static int __init bfin_cf_init(void)
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index f230f6543bff..854959cada3a 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -1484,6 +1484,11 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
if (!s)
return -EINVAL;
+ if (s->functions) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+
/* We do not want to validate the CIS cache... */
mutex_lock(&s->ops_mutex);
destroy_cis_cache(s);
@@ -1639,7 +1644,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
count = 0;
else {
struct pcmcia_socket *s;
- unsigned int chains;
+ unsigned int chains = 1;
if (off + count > size)
count = size - off;
@@ -1648,7 +1653,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj,
if (!(s->state & SOCKET_PRESENT))
return -ENODEV;
- if (pccard_validate_cis(s, &chains))
+ if (!s->functions && pccard_validate_cis(s, &chains))
return -EIO;
if (!chains)
return -ENODATA;
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index e679e708db63..c3383750e333 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -76,65 +76,6 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem);
EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
-/*
- * Low-level PCMCIA socket drivers need to register with the PCCard
- * core using pcmcia_register_socket.
- *
- * socket drivers are expected to use the following callbacks in their
- * .drv struct:
- * - pcmcia_socket_dev_suspend
- * - pcmcia_socket_dev_resume
- * These functions check for the appropriate struct pcmcia_soket arrays,
- * and pass them to the low-level functions pcmcia_{suspend,resume}_socket
- */
-static int socket_early_resume(struct pcmcia_socket *skt);
-static int socket_late_resume(struct pcmcia_socket *skt);
-static int socket_resume(struct pcmcia_socket *skt);
-static int socket_suspend(struct pcmcia_socket *skt);
-
-static void pcmcia_socket_dev_run(struct device *dev,
- int (*cb)(struct pcmcia_socket *))
-{
- struct pcmcia_socket *socket;
-
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
- if (socket->dev.parent != dev)
- continue;
- mutex_lock(&socket->skt_mutex);
- cb(socket);
- mutex_unlock(&socket->skt_mutex);
- }
- up_read(&pcmcia_socket_list_rwsem);
-}
-
-int pcmcia_socket_dev_suspend(struct device *dev)
-{
- pcmcia_socket_dev_run(dev, socket_suspend);
- return 0;
-}
-EXPORT_SYMBOL(pcmcia_socket_dev_suspend);
-
-void pcmcia_socket_dev_early_resume(struct device *dev)
-{
- pcmcia_socket_dev_run(dev, socket_early_resume);
-}
-EXPORT_SYMBOL(pcmcia_socket_dev_early_resume);
-
-void pcmcia_socket_dev_late_resume(struct device *dev)
-{
- pcmcia_socket_dev_run(dev, socket_late_resume);
-}
-EXPORT_SYMBOL(pcmcia_socket_dev_late_resume);
-
-int pcmcia_socket_dev_resume(struct device *dev)
-{
- pcmcia_socket_dev_run(dev, socket_resume);
- return 0;
-}
-EXPORT_SYMBOL(pcmcia_socket_dev_resume);
-
-
struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt)
{
struct device *dev = get_device(&skt->dev);
@@ -578,12 +519,18 @@ static int socket_early_resume(struct pcmcia_socket *skt)
static int socket_late_resume(struct pcmcia_socket *skt)
{
+ int ret;
+
mutex_lock(&skt->ops_mutex);
skt->state &= ~SOCKET_SUSPEND;
mutex_unlock(&skt->ops_mutex);
- if (!(skt->state & SOCKET_PRESENT))
- return socket_insert(skt);
+ if (!(skt->state & SOCKET_PRESENT)) {
+ ret = socket_insert(skt);
+ if (ret == -ENODEV)
+ ret = 0;
+ return ret;
+ }
if (skt->resume_status) {
socket_shutdown(skt);
@@ -724,20 +671,22 @@ static int pccardd(void *__skt)
socket_remove(skt);
if (sysfs_events & PCMCIA_UEVENT_INSERT)
socket_insert(skt);
- if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
- !(skt->state & SOCKET_CARDBUS)) {
- ret = socket_resume(skt);
- if (!ret && skt->callback)
- skt->callback->resume(skt);
- }
if ((sysfs_events & PCMCIA_UEVENT_SUSPEND) &&
!(skt->state & SOCKET_CARDBUS)) {
if (skt->callback)
ret = skt->callback->suspend(skt);
else
ret = 0;
- if (!ret)
+ if (!ret) {
socket_suspend(skt);
+ msleep(100);
+ }
+ }
+ if ((sysfs_events & PCMCIA_UEVENT_RESUME) &&
+ !(skt->state & SOCKET_CARDBUS)) {
+ ret = socket_resume(skt);
+ if (!ret && skt->callback)
+ skt->callback->resume(skt);
}
if ((sysfs_events & PCMCIA_UEVENT_REQUERY) &&
!(skt->state & SOCKET_CARDBUS)) {
@@ -919,11 +868,66 @@ static void pcmcia_release_socket_class(struct class *data)
}
+#ifdef CONFIG_PM
+
+static int __pcmcia_pm_op(struct device *dev,
+ int (*callback) (struct pcmcia_socket *skt))
+{
+ struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
+ int ret;
+
+ mutex_lock(&s->skt_mutex);
+ ret = callback(s);
+ mutex_unlock(&s->skt_mutex);
+
+ return ret;
+}
+
+static int pcmcia_socket_dev_suspend_noirq(struct device *dev)
+{
+ return __pcmcia_pm_op(dev, socket_suspend);
+}
+
+static int pcmcia_socket_dev_resume_noirq(struct device *dev)
+{
+ return __pcmcia_pm_op(dev, socket_early_resume);
+}
+
+static int pcmcia_socket_dev_resume(struct device *dev)
+{
+ return __pcmcia_pm_op(dev, socket_late_resume);
+}
+
+static const struct dev_pm_ops pcmcia_socket_pm_ops = {
+ /* dev_resume may be called with IRQs enabled */
+ SET_SYSTEM_SLEEP_PM_OPS(NULL,
+ pcmcia_socket_dev_resume)
+
+ /* late suspend must be called with IRQs disabled */
+ .suspend_noirq = pcmcia_socket_dev_suspend_noirq,
+ .freeze_noirq = pcmcia_socket_dev_suspend_noirq,
+ .poweroff_noirq = pcmcia_socket_dev_suspend_noirq,
+
+ /* early resume must be called with IRQs disabled */
+ .resume_noirq = pcmcia_socket_dev_resume_noirq,
+ .thaw_noirq = pcmcia_socket_dev_resume_noirq,
+ .restore_noirq = pcmcia_socket_dev_resume_noirq,
+};
+
+#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)
+
+#else /* CONFIG_PM */
+
+#define PCMCIA_SOCKET_CLASS_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
.dev_uevent = pcmcia_socket_uevent,
.dev_release = pcmcia_release_socket,
.class_release = pcmcia_release_socket_class,
+ .pm = PCMCIA_SOCKET_CLASS_PM_OPS,
};
EXPORT_SYMBOL(pcmcia_socket_class);
diff --git a/drivers/pcmcia/db1xxx_ss.c b/drivers/pcmcia/db1xxx_ss.c
index 9254ab0b29b1..0f4cc3f00028 100644
--- a/drivers/pcmcia/db1xxx_ss.c
+++ b/drivers/pcmcia/db1xxx_ss.c
@@ -26,6 +26,7 @@
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/resource.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <pcmcia/cs_types.h>
@@ -145,7 +146,6 @@ static irqreturn_t db1200_pcmcia_cdirq(int irq, void *data)
static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
{
int ret;
- unsigned long flags;
if (sock->stschg_irq != -1) {
ret = request_irq(sock->stschg_irq, db1000_pcmcia_stschgirq,
@@ -161,8 +161,6 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
* active one disabled.
*/
if (sock->board_type == BOARD_TYPE_DB1200) {
- local_irq_save(flags);
-
ret = request_irq(sock->insert_irq, db1200_pcmcia_cdirq,
IRQF_DISABLED, "pcmcia_insert", sock);
if (ret)
@@ -172,17 +170,14 @@ static int db1x_pcmcia_setup_irqs(struct db1x_pcmcia_sock *sock)
IRQF_DISABLED, "pcmcia_eject", sock);
if (ret) {
free_irq(sock->insert_irq, sock);
- local_irq_restore(flags);
goto out1;
}
- /* disable the currently active one */
+ /* enable the currently silent one */
if (db1200_card_inserted(sock))
- disable_irq_nosync(sock->insert_irq);
+ enable_irq(sock->eject_irq);
else
- disable_irq_nosync(sock->eject_irq);
-
- local_irq_restore(flags);
+ enable_irq(sock->insert_irq);
} else {
/* all other (older) Db1x00 boards use a GPIO to show
* card detection status: use both-edge triggers.
@@ -558,37 +553,10 @@ static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int db1x_pcmcia_suspend(struct device *dev)
-{
- return pcmcia_socket_dev_suspend(dev);
-}
-
-static int db1x_pcmcia_resume(struct device *dev)
-{
- return pcmcia_socket_dev_resume(dev);
-}
-
-static struct dev_pm_ops db1x_pcmcia_pmops = {
- .resume = db1x_pcmcia_resume,
- .suspend = db1x_pcmcia_suspend,
- .thaw = db1x_pcmcia_resume,
- .freeze = db1x_pcmcia_suspend,
-};
-
-#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops
-
-#else
-
-#define DB1XXX_SS_PMOPS NULL
-
-#endif
-
static struct platform_driver db1x_pcmcia_socket_driver = {
.driver = {
.name = "db1xxx_pcmcia",
.owner = THIS_MODULE,
- .pm = DB1XXX_SS_PMOPS
},
.probe = db1x_pcmcia_socket_probe,
.remove = __devexit_p(db1x_pcmcia_socket_remove),
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index ad93ebd7b2a2..041eee43fd8d 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -24,6 +24,7 @@
#include <linux/firmware.h>
#include <linux/kref.h>
#include <linux/dma-mapping.h>
+#include <linux/slab.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
@@ -334,7 +335,6 @@ static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *le
mutex_lock(&s->ops_mutex);
list_del(&p_dev->socket_device_list);
- p_dev->_removed = 1;
mutex_unlock(&s->ops_mutex);
dev_dbg(&p_dev->dev, "unregistering device\n");
@@ -509,8 +509,12 @@ struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s, unsigned int fu
p_dev->device_no = (s->device_count++);
mutex_unlock(&s->ops_mutex);
- /* max of 2 devices per card */
- if (p_dev->device_no >= 2)
+ /* max of 2 PFC devices */
+ if ((p_dev->device_no >= 2) && (function == 0))
+ goto err_free;
+
+ /* max of 4 devices overall */
+ if (p_dev->device_no >= 4)
goto err_free;
p_dev->socket = s;
@@ -649,14 +653,7 @@ static int pcmcia_requery_callback(struct device *dev, void * _data)
static void pcmcia_requery(struct pcmcia_socket *s)
{
- int present, has_pfc;
-
- mutex_lock(&s->ops_mutex);
- present = s->pcmcia_state.present;
- mutex_unlock(&s->ops_mutex);
-
- if (!present)
- return;
+ int has_pfc;
if (s->functions == 0) {
pcmcia_card_add(s);
@@ -682,12 +679,10 @@ static void pcmcia_requery(struct pcmcia_socket *s)
new_funcs = mfc.nfn;
else
new_funcs = 1;
- if (old_funcs > new_funcs) {
+ if (old_funcs != new_funcs) {
+ /* we need to re-start */
pcmcia_card_remove(s, NULL);
pcmcia_card_add(s);
- } else if (new_funcs > old_funcs) {
- s->functions = new_funcs;
- pcmcia_device_add(s, 1);
}
}
@@ -723,6 +718,8 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
struct pcmcia_socket *s = dev->socket;
const struct firmware *fw;
int ret = -ENOMEM;
+ cistpl_longlink_mfc_t mfc;
+ int old_funcs, new_funcs = 1;
if (!filename)
return -EINVAL;
@@ -745,6 +742,14 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
goto release;
}
+ /* we need to re-start if the number of functions changed */
+ old_funcs = s->functions;
+ if (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_LONGLINK_MFC,
+ &mfc))
+ new_funcs = mfc.nfn;
+
+ if (old_funcs != new_funcs)
+ ret = -EBUSY;
/* update information */
pcmcia_device_query(dev);
@@ -815,11 +820,12 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
- if (dev->device_no != did->device_no)
- return 0;
+ dev_dbg(&dev->dev, "this is a pseudo-multi-function device\n");
mutex_lock(&dev->socket->ops_mutex);
dev->socket->pcmcia_state.has_pfc = 1;
mutex_unlock(&dev->socket->ops_mutex);
+ if (dev->device_no != did->device_no)
+ return 0;
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
@@ -830,7 +836,7 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
/* if this is a pseudo-multi-function device,
* we need explicit matches */
- if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
+ if (dev->socket->pcmcia_state.has_pfc)
return 0;
if (dev->device_no)
return 0;
@@ -853,10 +859,8 @@ static inline int pcmcia_devmatch(struct pcmcia_device *dev,
if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
dev_dbg(&dev->dev, "device needs a fake CIS\n");
if (!dev->socket->fake_cis)
- pcmcia_load_firmware(dev, did->cisfile);
-
- if (!dev->socket->fake_cis)
- return 0;
+ if (pcmcia_load_firmware(dev, did->cisfile))
+ return 0;
}
if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
@@ -1249,9 +1253,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
switch (event) {
case CS_EVENT_CARD_REMOVAL:
- mutex_lock(&s->ops_mutex);
- s->pcmcia_state.present = 0;
- mutex_unlock(&s->ops_mutex);
+ atomic_set(&skt->present, 0);
pcmcia_card_remove(skt, NULL);
handle_event(skt, event);
mutex_lock(&s->ops_mutex);
@@ -1260,9 +1262,9 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
break;
case CS_EVENT_CARD_INSERTION:
+ atomic_set(&skt->present, 1);
mutex_lock(&s->ops_mutex);
s->pcmcia_state.has_pfc = 0;
- s->pcmcia_state.present = 1;
destroy_cis_cache(s); /* to be on the safe side... */
mutex_unlock(&s->ops_mutex);
pcmcia_card_add(skt);
@@ -1281,6 +1283,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
destroy_cis_cache(skt);
kfree(skt->fake_cis);
skt->fake_cis = NULL;
+ s->functions = 0;
mutex_unlock(&s->ops_mutex);
/* now, add the new card */
ds_event(skt, CS_EVENT_CARD_INSERTION,
@@ -1302,7 +1305,13 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
return 0;
} /* ds_event */
-
+/*
+ * NOTE: This is racy. There's no guarantee the card will still be
+ * physically present, even if the call to this function returns
+ * non-NULL. Furthermore, the device driver most likely is unbound
+ * almost immediately, so the timeframe where pcmcia_dev_present
+ * returns NULL is probably really really small.
+ */
struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
{
struct pcmcia_device *p_dev;
@@ -1312,22 +1321,9 @@ struct pcmcia_device *pcmcia_dev_present(struct pcmcia_device *_p_dev)
if (!p_dev)
return NULL;
- mutex_lock(&p_dev->socket->ops_mutex);
- if (!p_dev->socket->pcmcia_state.present)
- goto out;
-
- if (p_dev->socket->pcmcia_state.dead)
- goto out;
+ if (atomic_read(&p_dev->socket->present) != 0)
+ ret = p_dev;
- if (p_dev->_removed)
- goto out;
-
- if (p_dev->suspended)
- goto out;
-
- ret = p_dev;
- out:
- mutex_unlock(&p_dev->socket->ops_mutex);
pcmcia_put_dev(p_dev);
return ret;
}
@@ -1377,6 +1373,8 @@ static int __devinit pcmcia_bus_add_socket(struct device *dev,
return ret;
}
+ atomic_set(&socket->present, 0);
+
return 0;
}
@@ -1388,10 +1386,6 @@ static void pcmcia_bus_remove_socket(struct device *dev,
if (!socket)
return;
- mutex_lock(&socket->ops_mutex);
- socket->pcmcia_state.dead = 1;
- mutex_unlock(&socket->ops_mutex);
-
pccard_register_pcmcia(socket, NULL);
/* unregister any unbound devices */
diff --git a/drivers/pcmcia/electra_cf.c b/drivers/pcmcia/electra_cf.c
index 89cfddca089a..2e59fe947d28 100644
--- a/drivers/pcmcia/electra_cf.c
+++ b/drivers/pcmcia/electra_cf.c
@@ -31,6 +31,7 @@
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/of_platform.h>
+#include <linux/slab.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index f5da62653313..3003bb3dfcc0 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -39,27 +39,11 @@ static struct pci_device_id i82092aa_pci_ids[] = {
};
MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
-#ifdef CONFIG_PM
-static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int i82092aa_socket_resume (struct pci_dev *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
-#endif
-
static struct pci_driver i82092aa_pci_driver = {
.name = "i82092aa",
.id_table = i82092aa_pci_ids,
.probe = i82092aa_pci_probe,
.remove = __devexit_p(i82092aa_pci_remove),
-#ifdef CONFIG_PM
- .suspend = i82092aa_socket_suspend,
- .resume = i82092aa_socket_resume,
-#endif
};
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index c13fd9360511..9e2a15628de5 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -40,7 +40,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/timer.h>
-#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
@@ -1223,16 +1222,7 @@ static int pcic_init(struct pcmcia_socket *s)
return 0;
}
-static int i82365_drv_pcmcia_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-static int i82365_drv_pcmcia_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
static struct pccard_operations pcic_operations = {
.init = pcic_init,
.get_status = pcic_get_status,
@@ -1248,8 +1238,6 @@ static struct platform_driver i82365_driver = {
.name = "i82365",
.owner = THIS_MODULE,
},
- .suspend = i82365_drv_pcmcia_suspend,
- .resume = i82365_drv_pcmcia_resume,
};
static struct platform_device *i82365_device;
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 0ece2cd4a85e..7e16ed8eb0a4 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/timer.h>
-#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
@@ -685,16 +684,7 @@ static struct pccard_operations pcc_operations = {
.set_mem_map = pcc_set_mem_map,
};
-static int cfc_drv_pcmcia_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-static int cfc_drv_pcmcia_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
/*====================================================================*/
static struct platform_driver pcc_driver = {
@@ -702,8 +692,6 @@ static struct platform_driver pcc_driver = {
.name = "cfc",
.owner = THIS_MODULE,
},
- .suspend = cfc_drv_pcmcia_suspend,
- .resume = cfc_drv_pcmcia_resume,
};
static struct platform_device pcc_device = {
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 72844c5a6d05..6c5c3f910d71 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -16,7 +16,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/timer.h>
-#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
@@ -663,16 +662,6 @@ static struct pccard_operations pcc_operations = {
.set_mem_map = pcc_set_mem_map,
};
-static int pcc_drv_pcmcia_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int pcc_drv_pcmcia_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
/*====================================================================*/
static struct platform_driver pcc_driver = {
@@ -680,8 +669,6 @@ static struct platform_driver pcc_driver = {
.name = "pcc",
.owner = THIS_MODULE,
},
- .suspend = pcc_drv_pcmcia_suspend,
- .resume = pcc_drv_pcmcia_resume,
};
static struct platform_device pcc_device = {
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index 61c215918128..41cc954a5ffe 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -42,7 +42,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -1288,21 +1287,6 @@ static int m8xx_remove(struct of_device *ofdev)
return 0;
}
-#ifdef CONFIG_PM
-static int m8xx_suspend(struct platform_device *pdev, pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&pdev->dev);
-}
-
-static int m8xx_resume(struct platform_device *pdev)
-{
- return pcmcia_socket_dev_resume(&pdev->dev);
-}
-#else
-#define m8xx_suspend NULL
-#define m8xx_resume NULL
-#endif
-
static const struct of_device_id m8xx_pcmcia_match[] = {
{
.type = "pcmcia",
@@ -1318,8 +1302,6 @@ static struct of_platform_driver m8xx_pcmcia_driver = {
.match_table = m8xx_pcmcia_match,
.probe = m8xx_probe,
.remove = m8xx_remove,
- .suspend = m8xx_suspend,
- .resume = m8xx_resume,
};
static int __init m8xx_init(void)
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 3ef991552398..a7cfc7964c7c 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -16,6 +16,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include <pcmcia/ss.h>
@@ -330,24 +331,12 @@ static int __exit omap_cf_remove(struct platform_device *pdev)
return 0;
}
-static int omap_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
-{
- return pcmcia_socket_dev_suspend(&pdev->dev);
-}
-
-static int omap_cf_resume(struct platform_device *pdev)
-{
- return pcmcia_socket_dev_resume(&pdev->dev);
-}
-
static struct platform_driver omap_cf_driver = {
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
},
.remove = __exit_p(omap_cf_remove),
- .suspend = omap_cf_suspend,
- .resume = omap_cf_resume,
};
static int __init omap_cf_init(void)
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 13a7132cf688..7631faa0cadd 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -27,6 +27,7 @@
#include <linux/proc_fs.h>
#include <linux/poll.h>
#include <linux/pci.h>
+#include <linux/slab.h>
#include <linux/seq_file.h>
#include <linux/smp_lock.h>
#include <linux/workqueue.h>
@@ -710,7 +711,7 @@ static int ds_open(struct inode *inode, struct file *file)
warning_printed = 1;
}
- if (s->pcmcia_state.present)
+ if (atomic_read(&s->present))
queue_event(user, CS_EVENT_CARD_INSERTION);
out:
unlock_kernel();
@@ -769,9 +770,6 @@ static ssize_t ds_read(struct file *file, char __user *buf,
return -EIO;
s = user->socket;
- if (s->pcmcia_state.dead)
- return -EIO;
-
ret = wait_event_interruptible(s->queue, !queue_empty(user));
if (ret == 0)
ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
@@ -837,8 +835,6 @@ static int ds_ioctl(struct inode *inode, struct file *file,
return -EIO;
s = user->socket;
- if (s->pcmcia_state.dead)
- return -EIO;
size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
if (size > sizeof(ds_ioctl_arg_t))
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index c4612c52e4cb..7c3d03bb4f30 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -21,6 +21,7 @@
#include <linux/pci.h>
#include <linux/device.h>
#include <linux/netdevice.h>
+#include <linux/slab.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
@@ -754,12 +755,12 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
else
printk(KERN_WARNING "pcmcia: Driver needs updating to support IRQ sharing.\n");
-#ifdef CONFIG_PCMCIA_PROBE
-
- if (s->irq.AssignedIRQ != 0) {
- /* If the interrupt is already assigned, it must be the same */
+ /* If the interrupt is already assigned, it must be the same */
+ if (s->irq.AssignedIRQ != 0)
irq = s->irq.AssignedIRQ;
- } else {
+
+#ifdef CONFIG_PCMCIA_PROBE
+ if (!irq) {
int try;
u32 mask = s->irq_mask;
void *data = p_dev; /* something unique to this device */
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 7ba57a565cd7..b61a13663a0a 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -9,18 +9,19 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/device.h>
+#include <linux/io.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
#include <asm/system.h>
-#include <asm/io.h>
#include "pd6729.h"
#include "i82365.h"
@@ -222,9 +223,9 @@ static irqreturn_t pd6729_interrupt(int irq, void *dev)
? SS_READY : 0;
}
- if (events) {
+ if (events)
pcmcia_parse_events(&socket[i].socket, events);
- }
+
active |= events;
}
@@ -256,9 +257,8 @@ static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value)
status = indirect_read(socket, I365_STATUS);
*value = 0;
- if ((status & I365_CS_DETECT) == I365_CS_DETECT) {
+ if ((status & I365_CS_DETECT) == I365_CS_DETECT)
*value |= SS_DETECT;
- }
/*
* IO cards have a different meaning of bits 0,1
@@ -308,7 +308,7 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
socket->card_irq = state->io_irq;
reg = 0;
- /* The reset bit has "inverse" logic */
+ /* The reset bit has "inverse" logic */
if (!(state->flags & SS_RESET))
reg |= I365_PC_RESET;
if (state->flags & SS_IOCARD)
@@ -380,7 +380,7 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
indirect_write(socket, I365_POWER, reg);
if (irq_mode == 1) {
- /* all interrupts are to be done as PCI interrupts */
+ /* all interrupts are to be done as PCI interrupts */
data = PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ;
} else
data = 0;
@@ -391,9 +391,9 @@ static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
/* Enable specific interrupt events */
reg = 0x00;
- if (state->csc_mask & SS_DETECT) {
+ if (state->csc_mask & SS_DETECT)
reg |= I365_CSC_DETECT;
- }
+
if (state->flags & SS_IOCARD) {
if (state->csc_mask & SS_STSCHG)
reg |= I365_CSC_STSCHG;
@@ -450,9 +450,12 @@ static int pd6729_set_io_map(struct pcmcia_socket *sock,
ioctl = indirect_read(socket, I365_IOCTL) & ~I365_IOCTL_MASK(map);
- if (io->flags & MAP_0WS) ioctl |= I365_IOCTL_0WS(map);
- if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
- if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(map);
+ if (io->flags & MAP_0WS)
+ ioctl |= I365_IOCTL_0WS(map);
+ if (io->flags & MAP_16BIT)
+ ioctl |= I365_IOCTL_16BIT(map);
+ if (io->flags & MAP_AUTOSZ)
+ ioctl |= I365_IOCTL_IOCS16(map);
indirect_write(socket, I365_IOCTL, ioctl);
@@ -497,7 +500,7 @@ static int pd6729_set_mem_map(struct pcmcia_socket *sock,
/* write the stop address */
- i= (mem->res->end >> 12) & 0x0fff;
+ i = (mem->res->end >> 12) & 0x0fff;
switch (to_cycles(mem->speed)) {
case 0:
break;
@@ -563,7 +566,7 @@ static int pd6729_init(struct pcmcia_socket *sock)
/* the pccard structure and its functions */
static struct pccard_operations pd6729_operations = {
- .init = pd6729_init,
+ .init = pd6729_init,
.get_status = pd6729_get_status,
.set_socket = pd6729_set_socket,
.set_io_map = pd6729_set_io_map,
@@ -578,8 +581,13 @@ static irqreturn_t pd6729_test(int irq, void *dev)
static int pd6729_check_irq(int irq)
{
- if (request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x", pd6729_test)
- != 0) return -1;
+ int ret;
+
+ ret = request_irq(irq, pd6729_test, IRQF_PROBE_SHARED, "x",
+ pd6729_test);
+ if (ret)
+ return -1;
+
free_irq(irq, pd6729_test);
return 0;
}
@@ -591,7 +599,7 @@ static u_int __devinit pd6729_isa_scan(void)
if (irq_mode == 1) {
printk(KERN_INFO "pd6729: PCI card interrupts, "
- "PCI status changes\n");
+ "PCI status changes\n");
return 0;
}
@@ -607,9 +615,10 @@ static u_int __devinit pd6729_isa_scan(void)
if (mask & (1<<i))
printk("%s%d", ((mask & ((1<<i)-1)) ? "," : ""), i);
- if (mask == 0) printk("none!");
-
- printk(" polling status changes.\n");
+ if (mask == 0)
+ printk("none!");
+ else
+ printk(" polling status changes.\n");
return mask;
}
@@ -624,11 +633,16 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS,
GFP_KERNEL);
- if (!socket)
+ if (!socket) {
+ dev_warn(&dev->dev, "failed to kzalloc socket.\n");
return -ENOMEM;
+ }
- if ((ret = pci_enable_device(dev)))
+ ret = pci_enable_device(dev);
+ if (ret) {
+ dev_warn(&dev->dev, "failed to enable pci_device.\n");
goto err_out_free_mem;
+ }
if (!pci_resource_start(dev, 0)) {
dev_warn(&dev->dev, "refusing to load the driver as the "
@@ -639,7 +653,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
dev_info(&dev->dev, "Cirrus PD6729 PCI to PCMCIA Bridge at 0x%llx "
"on irq %d\n",
(unsigned long long)pci_resource_start(dev, 0), dev->irq);
- /*
+ /*
* Since we have no memory BARs some firmware may not
* have had PCI_COMMAND_MEMORY enabled, yet the device needs it.
*/
@@ -685,8 +699,9 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
pci_set_drvdata(dev, socket);
if (irq_mode == 1) {
/* Register the interrupt handler */
- if ((ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,
- "pd6729", socket))) {
+ ret = request_irq(dev->irq, pd6729_interrupt, IRQF_SHARED,
+ "pd6729", socket);
+ if (ret) {
dev_err(&dev->dev, "Failed to register irq %d\n",
dev->irq);
goto err_out_free_res;
@@ -750,18 +765,6 @@ static void __devexit pd6729_pci_remove(struct pci_dev *dev)
kfree(socket);
}
-#ifdef CONFIG_PM
-static int pd6729_socket_suspend(struct pci_dev *dev, pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int pd6729_socket_resume(struct pci_dev *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
-#endif
-
static struct pci_device_id pd6729_pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_CIRRUS,
@@ -778,10 +781,6 @@ static struct pci_driver pd6729_pci_driver = {
.id_table = pd6729_pci_ids,
.probe = pd6729_pci_probe,
.remove = __devexit_p(pd6729_pci_remove),
-#ifdef CONFIG_PM
- .suspend = pd6729_socket_suspend,
- .resume = pd6729_socket_resume,
-#endif
};
static int pd6729_module_init(void)
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c
index 76e640bccde8..df4532e91b1a 100644
--- a/drivers/pcmcia/pxa2xx_base.c
+++ b/drivers/pcmcia/pxa2xx_base.c
@@ -17,6 +17,7 @@
======================================================================*/
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/cpufreq.h>
#include <linux/ioport.h>
@@ -325,19 +326,13 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
return 0;
}
-static int pxa2xx_drv_pcmcia_suspend(struct device *dev)
-{
- return pcmcia_socket_dev_suspend(dev);
-}
-
static int pxa2xx_drv_pcmcia_resume(struct device *dev)
{
pxa2xx_configure_sockets(dev);
- return pcmcia_socket_dev_resume(dev);
+ return 0;
}
static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = {
- .suspend = pxa2xx_drv_pcmcia_suspend,
.resume = pxa2xx_drv_pcmcia_resume,
};
diff --git a/drivers/pcmcia/pxa2xx_vpac270.c b/drivers/pcmcia/pxa2xx_vpac270.c
new file mode 100644
index 000000000000..55627eccee8e
--- /dev/null
+++ b/drivers/pcmcia/pxa2xx_vpac270.c
@@ -0,0 +1,229 @@
+/*
+ * linux/drivers/pcmcia/pxa2xx_vpac270.c
+ *
+ * Driver for Voipac PXA270 PCMCIA and CF sockets
+ *
+ * Copyright (C) 2010
+ * Marek Vasut <marek.vasut@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/module.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+
+#include <mach/gpio.h>
+#include <mach/vpac270.h>
+
+#include "soc_common.h"
+
+static struct pcmcia_irqs cd_irqs[] = {
+ {
+ .sock = 0,
+ .irq = IRQ_GPIO(GPIO84_VPAC270_PCMCIA_CD),
+ .str = "PCMCIA CD"
+ },
+ {
+ .sock = 1,
+ .irq = IRQ_GPIO(GPIO17_VPAC270_CF_CD),
+ .str = "CF CD"
+ },
+};
+
+static int vpac270_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
+{
+ int ret;
+
+ if (skt->nr == 0) {
+ ret = gpio_request(GPIO84_VPAC270_PCMCIA_CD, "PCMCIA CD");
+ if (ret)
+ goto err1;
+ ret = gpio_direction_input(GPIO84_VPAC270_PCMCIA_CD);
+ if (ret)
+ goto err2;
+
+ ret = gpio_request(GPIO35_VPAC270_PCMCIA_RDY, "PCMCIA RDY");
+ if (ret)
+ goto err2;
+ ret = gpio_direction_input(GPIO35_VPAC270_PCMCIA_RDY);
+ if (ret)
+ goto err3;
+
+ ret = gpio_request(GPIO107_VPAC270_PCMCIA_PPEN, "PCMCIA PPEN");
+ if (ret)
+ goto err3;
+ ret = gpio_direction_output(GPIO107_VPAC270_PCMCIA_PPEN, 0);
+ if (ret)
+ goto err4;
+
+ ret = gpio_request(GPIO11_VPAC270_PCMCIA_RESET, "PCMCIA RESET");
+ if (ret)
+ goto err4;
+ ret = gpio_direction_output(GPIO11_VPAC270_PCMCIA_RESET, 0);
+ if (ret)
+ goto err5;
+
+ skt->socket.pci_irq = gpio_to_irq(GPIO35_VPAC270_PCMCIA_RDY);
+
+ return soc_pcmcia_request_irqs(skt, &cd_irqs[0], 1);
+
+err5:
+ gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
+err4:
+ gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
+err3:
+ gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
+err2:
+ gpio_free(GPIO84_VPAC270_PCMCIA_CD);
+err1:
+ return ret;
+
+ } else {
+ ret = gpio_request(GPIO17_VPAC270_CF_CD, "CF CD");
+ if (ret)
+ goto err6;
+ ret = gpio_direction_input(GPIO17_VPAC270_CF_CD);
+ if (ret)
+ goto err7;
+
+ ret = gpio_request(GPIO12_VPAC270_CF_RDY, "CF RDY");
+ if (ret)
+ goto err7;
+ ret = gpio_direction_input(GPIO12_VPAC270_CF_RDY);
+ if (ret)
+ goto err8;
+
+ ret = gpio_request(GPIO16_VPAC270_CF_RESET, "CF RESET");
+ if (ret)
+ goto err8;
+ ret = gpio_direction_output(GPIO16_VPAC270_CF_RESET, 0);
+ if (ret)
+ goto err9;
+
+ skt->socket.pci_irq = gpio_to_irq(GPIO12_VPAC270_CF_RDY);
+
+ return soc_pcmcia_request_irqs(skt, &cd_irqs[1], 1);
+
+err9:
+ gpio_free(GPIO16_VPAC270_CF_RESET);
+err8:
+ gpio_free(GPIO12_VPAC270_CF_RDY);
+err7:
+ gpio_free(GPIO17_VPAC270_CF_CD);
+err6:
+ return ret;
+
+ }
+}
+
+static void vpac270_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
+{
+ gpio_free(GPIO11_VPAC270_PCMCIA_RESET);
+ gpio_free(GPIO107_VPAC270_PCMCIA_PPEN);
+ gpio_free(GPIO35_VPAC270_PCMCIA_RDY);
+ gpio_free(GPIO84_VPAC270_PCMCIA_CD);
+ gpio_free(GPIO16_VPAC270_CF_RESET);
+ gpio_free(GPIO12_VPAC270_CF_RDY);
+ gpio_free(GPIO17_VPAC270_CF_CD);
+}
+
+static void vpac270_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
+ struct pcmcia_state *state)
+{
+ if (skt->nr == 0) {
+ state->detect = !gpio_get_value(GPIO84_VPAC270_PCMCIA_CD);
+ state->ready = !!gpio_get_value(GPIO35_VPAC270_PCMCIA_RDY);
+ } else {
+ state->detect = !gpio_get_value(GPIO17_VPAC270_CF_CD);
+ state->ready = !!gpio_get_value(GPIO12_VPAC270_CF_RDY);
+ }
+ state->bvd1 = 1;
+ state->bvd2 = 1;
+ state->wrprot = 0;
+ state->vs_3v = 1;
+ state->vs_Xv = 0;
+}
+
+static int
+vpac270_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
+ const socket_state_t *state)
+{
+ if (skt->nr == 0) {
+ gpio_set_value(GPIO11_VPAC270_PCMCIA_RESET,
+ (state->flags & SS_RESET));
+ gpio_set_value(GPIO107_VPAC270_PCMCIA_PPEN,
+ !(state->Vcc == 33 || state->Vcc == 50));
+ } else {
+ gpio_set_value(GPIO16_VPAC270_CF_RESET,
+ (state->flags & SS_RESET));
+ }
+
+ return 0;
+}
+
+static void vpac270_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
+{
+}
+
+static void vpac270_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+{
+}
+
+static struct pcmcia_low_level vpac270_pcmcia_ops = {
+ .owner = THIS_MODULE,
+
+ .first = 0,
+ .nr = 2,
+
+ .hw_init = vpac270_pcmcia_hw_init,
+ .hw_shutdown = vpac270_pcmcia_hw_shutdown,
+
+ .socket_state = vpac270_pcmcia_socket_state,
+ .configure_socket = vpac270_pcmcia_configure_socket,
+
+ .socket_init = vpac270_pcmcia_socket_init,
+ .socket_suspend = vpac270_pcmcia_socket_suspend,
+};
+
+static struct platform_device *vpac270_pcmcia_device;
+
+static int __init vpac270_pcmcia_init(void)
+{
+ int ret;
+
+ if (!machine_is_vpac270())
+ return -ENODEV;
+
+ vpac270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
+ if (!vpac270_pcmcia_device)
+ return -ENOMEM;
+
+ ret = platform_device_add_data(vpac270_pcmcia_device,
+ &vpac270_pcmcia_ops, sizeof(vpac270_pcmcia_ops));
+
+ if (!ret)
+ ret = platform_device_add(vpac270_pcmcia_device);
+
+ if (ret)
+ platform_device_put(vpac270_pcmcia_device);
+
+ return ret;
+}
+
+static void __exit vpac270_pcmcia_exit(void)
+{
+ platform_device_unregister(vpac270_pcmcia_device);
+}
+
+module_init(vpac270_pcmcia_init);
+module_exit(vpac270_pcmcia_exit);
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("PCMCIA support for Voipac PXA270");
+MODULE_ALIAS("platform:pxa2xx-pcmcia");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 452c83b512c4..ffa5f3cae57b 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -12,6 +12,7 @@
* (C) 1999 David A. Hinds
*/
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 4663b3fa9f96..a6eb7b59ba9f 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -214,7 +214,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
return;
}
for (i = base, most = 0; i < base+num; i += 8) {
- res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+ res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
if (!res)
continue;
hole = inb(i);
@@ -231,9 +231,14 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
bad = any = 0;
for (i = base; i < base+num; i += 8) {
- res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
- if (!res)
+ res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
+ if (!res) {
+ if (!any)
+ printk(" excluding");
+ if (!bad)
+ bad = any = i;
continue;
+ }
for (j = 0; j < 8; j++)
if (inb(i+j) != most)
break;
@@ -253,6 +258,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
}
if (bad) {
if ((num > 16) && (bad == base) && (i == base+num)) {
+ sub_interval(&s_data->io_db, bad, i-bad);
printk(" nothing: probe failed.\n");
return;
} else {
@@ -596,19 +602,17 @@ struct pcmcia_align_data {
struct resource_map *map;
};
-static resource_size_t
-pcmcia_common_align(void *align_data, const struct resource *res,
- resource_size_t size, resource_size_t align)
+static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
+ resource_size_t start)
{
- struct pcmcia_align_data *data = align_data;
- resource_size_t start;
+ resource_size_t ret;
/*
* Ensure that we have the correct start address
*/
- start = (res->start & ~data->mask) + data->offset;
- if (start < res->start)
- start += data->mask + 1;
- return start;
+ ret = (start & ~align_data->mask) + align_data->offset;
+ if (ret < start)
+ ret += align_data->mask + 1;
+ return ret;
}
static resource_size_t
@@ -619,29 +623,28 @@ pcmcia_align(void *align_data, const struct resource *res,
struct resource_map *m;
resource_size_t start;
- start = pcmcia_common_align(data, res, size, align);
+ start = pcmcia_common_align(data, res->start);
for (m = data->map->next; m != data->map; m = m->next) {
- unsigned long start = m->base;
- unsigned long end = m->base + m->num - 1;
+ unsigned long map_start = m->base;
+ unsigned long map_end = m->base + m->num - 1;
/*
* If the lower resources are not available, try aligning
* to this entry of the resource database to see if it'll
* fit here.
*/
- if (res->start < start) {
- start = pcmcia_common_align(data, res, size, align);
- }
+ if (start < map_start)
+ start = pcmcia_common_align(data, map_start);
/*
* If we're above the area which was passed in, there's
* no point proceeding.
*/
- if (res->start >= res->end)
+ if (start >= res->end)
break;
- if ((res->start + size - 1) <= end)
+ if ((start + size - 1) <= map_end)
break;
}
@@ -807,9 +810,18 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{
struct socket_data *data = s->resource_data;
- unsigned long size = end - start + 1;
+ unsigned long size;
int ret = 0;
+#if defined(CONFIG_X86)
+ /* on x86, avoid anything < 0x100 for it is often used for
+ * legacy platform devices */
+ if (start < 0x100)
+ start = 0x100;
+#endif
+
+ size = end - start + 1;
+
if (end < start)
return -EINVAL;
@@ -867,10 +879,8 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
if (res == &ioport_resource)
continue;
dev_printk(KERN_INFO, &s->cb_dev->dev,
- "pcmcia: parent PCI bridge I/O "
- "window: 0x%llx - 0x%llx\n",
- (unsigned long long)res->start,
- (unsigned long long)res->end);
+ "pcmcia: parent PCI bridge window: %pR\n",
+ res);
if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
done |= IORESOURCE_IO;
@@ -880,10 +890,8 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
if (res == &iomem_resource)
continue;
dev_printk(KERN_INFO, &s->cb_dev->dev,
- "pcmcia: parent PCI bridge Memory "
- "window: 0x%llx - 0x%llx\n",
- (unsigned long long)res->start,
- (unsigned long long)res->end);
+ "pcmcia: parent PCI bridge window: %pR\n",
+ res);
if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
done |= IORESOURCE_MEM;
}
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index 8db86b90c200..edbd8c472628 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -32,6 +32,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/slab.h>
#include <linux/platform_device.h>
#include <pcmcia/cs_types.h>
@@ -95,17 +96,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev)
return 0;
}
-static int sa11x0_drv_pcmcia_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int sa11x0_drv_pcmcia_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
-
static struct platform_driver sa11x0_pcmcia_driver = {
.driver = {
.name = "sa11x0-pcmcia",
@@ -113,8 +103,6 @@ static struct platform_driver sa11x0_pcmcia_driver = {
},
.probe = sa11x0_drv_pcmcia_probe,
.remove = sa11x0_drv_pcmcia_remove,
- .suspend = sa11x0_drv_pcmcia_suspend,
- .resume = sa11x0_drv_pcmcia_resume,
};
/* sa11x0_pcmcia_init()
diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c
index db79ca61cf96..59866905ea37 100644
--- a/drivers/pcmcia/sa1111_generic.c
+++ b/drivers/pcmcia/sa1111_generic.c
@@ -12,6 +12,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <pcmcia/ss.h>
@@ -213,16 +214,6 @@ static int __devexit pcmcia_remove(struct sa1111_dev *dev)
return 0;
}
-static int pcmcia_suspend(struct sa1111_dev *dev, pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int pcmcia_resume(struct sa1111_dev *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
-
static struct sa1111_driver pcmcia_driver = {
.drv = {
.name = "sa1111-pcmcia",
@@ -230,8 +221,6 @@ static struct sa1111_driver pcmcia_driver = {
.devid = SA1111_DEVID_PCMCIA,
.probe = pcmcia_probe,
.remove = __devexit_p(pcmcia_remove),
- .suspend = pcmcia_suspend,
- .resume = pcmcia_resume,
};
static int __init sa1111_drv_pcmcia_init(void)
diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c
index fc9a6527019b..fa28d8911b00 100644
--- a/drivers/pcmcia/sa11xx_base.c
+++ b/drivers/pcmcia/sa11xx_base.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <mach/hardware.h>
#include <asm/irq.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 08278016e58d..80e36bc407da 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -15,7 +15,6 @@
#include <linux/string.h>
#include <linux/major.h>
#include <linux/errno.h>
-#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 12c49ee135e1..56004a1b5bba 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -39,7 +39,6 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/delay.h>
@@ -348,16 +347,6 @@ static int __init get_tcic_id(void)
return id;
}
-static int tcic_drv_pcmcia_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int tcic_drv_pcmcia_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
/*====================================================================*/
static struct platform_driver tcic_driver = {
@@ -365,8 +354,6 @@ static struct platform_driver tcic_driver = {
.name = "tcic-pcmcia",
.owner = THIS_MODULE,
},
- .suspend = tcic_drv_pcmcia_suspend,
- .resume = tcic_drv_pcmcia_resume,
};
static struct platform_device tcic_device = {
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index aaccdb9f4ba1..86e4a1a3c642 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -705,24 +705,11 @@ static int __devinit vrc4171_card_setup(char *options)
__setup("vrc4171_card=", vrc4171_card_setup);
-static int vrc4171_card_suspend(struct platform_device *dev,
- pm_message_t state)
-{
- return pcmcia_socket_dev_suspend(&dev->dev);
-}
-
-static int vrc4171_card_resume(struct platform_device *dev)
-{
- return pcmcia_socket_dev_resume(&dev->dev);
-}
-
static struct platform_driver vrc4171_card_driver = {
.driver = {
.name = vrc4171_card_name,
.owner = THIS_MODULE,
},
- .suspend = vrc4171_card_suspend,
- .resume = vrc4171_card_resume,
};
static int __devinit vrc4171_card_init(void)
diff --git a/drivers/pcmcia/xxs1500_ss.c b/drivers/pcmcia/xxs1500_ss.c
index f9009d34254b..201ccfa1e97b 100644
--- a/drivers/pcmcia/xxs1500_ss.c
+++ b/drivers/pcmcia/xxs1500_ss.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/resource.h>
+#include <linux/slab.h>
#include <linux/spinlock.h>
#include <pcmcia/cs_types.h>
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 418988ab6edf..83ace277426c 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -17,6 +17,7 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
@@ -1290,12 +1291,9 @@ static int yenta_dev_suspend_noirq(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct yenta_socket *socket = pci_get_drvdata(pdev);
- int ret;
-
- ret = pcmcia_socket_dev_suspend(dev);
if (!socket)
- return ret;
+ return 0;
if (socket->type && socket->type->save_state)
socket->type->save_state(socket);
@@ -1312,7 +1310,7 @@ static int yenta_dev_suspend_noirq(struct device *dev)
*/
/* pci_set_power_state(dev, 3); */
- return ret;
+ return 0;
}
static int yenta_dev_resume_noirq(struct device *dev)
@@ -1336,26 +1334,16 @@ static int yenta_dev_resume_noirq(struct device *dev)
if (socket->type && socket->type->restore_state)
socket->type->restore_state(socket);
- pcmcia_socket_dev_early_resume(dev);
- return 0;
-}
-
-static int yenta_dev_resume(struct device *dev)
-{
- pcmcia_socket_dev_late_resume(dev);
return 0;
}
static const struct dev_pm_ops yenta_pm_ops = {
.suspend_noirq = yenta_dev_suspend_noirq,
.resume_noirq = yenta_dev_resume_noirq,
- .resume = yenta_dev_resume,
.freeze_noirq = yenta_dev_suspend_noirq,
.thaw_noirq = yenta_dev_resume_noirq,
- .thaw = yenta_dev_resume,
.poweroff_noirq = yenta_dev_suspend_noirq,
.restore_noirq = yenta_dev_resume_noirq,
- .restore = yenta_dev_resume,
};
#define YENTA_PM_OPS (&yenta_pm_ops)