diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/Kconfig | 7 | ||||
-rw-r--r-- | drivers/pcmcia/Makefile | 1 | ||||
-rw-r--r-- | drivers/pcmcia/cs.c | 9 | ||||
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 4 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 34 | ||||
-rw-r--r-- | drivers/pcmcia/omap_cf.c | 373 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_ioctl.c | 12 | ||||
-rw-r--r-- | drivers/pcmcia/pcmcia_resource.c | 11 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_base.c | 2 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_mainstone.c | 2 | ||||
-rw-r--r-- | drivers/pcmcia/pxa2xx_sharpsl.c | 116 | ||||
-rw-r--r-- | drivers/pcmcia/sa1100_generic.c | 2 | ||||
-rw-r--r-- | drivers/pcmcia/sa1111_generic.c | 2 | ||||
-rw-r--r-- | drivers/pcmcia/sa11xx_base.c | 2 | ||||
-rw-r--r-- | drivers/pcmcia/topic.h | 17 | ||||
-rw-r--r-- | drivers/pcmcia/yenta_socket.c | 172 | ||||
-rw-r--r-- | drivers/pcmcia/yenta_socket.h | 8 |
17 files changed, 644 insertions, 130 deletions
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 6485f75d2fb..ddc741e6ecb 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig @@ -221,6 +221,13 @@ config PCMCIA_VRC4173 tristate "NEC VRC4173 CARDU support" depends on CPU_VR41XX && PCI && PCMCIA +config OMAP_CF + tristate "OMAP CompactFlash Controller" + depends on PCMCIA && ARCH_OMAP16XX + help + Say Y here to support the CompactFlash controller on OMAP. + Note that this doesn't support "True IDE" mode. + config PCCARD_NONSTATIC tristate diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index ef694c74dfb..a41fbb38fdc 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_M32R_CFC) += m32r_cfc.o obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o obj-$(CONFIG_PCMCIA_VRC4171) += vrc4171_card.o obj-$(CONFIG_PCMCIA_VRC4173) += vrc4173_cardu.o +obj-$(CONFIG_OMAP_CF) += omap_cf.o sa11xx_core-y += soc_common.o sa11xx_base.o pxa2xx_core-y += soc_common.o pxa2xx_base.o diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index e39178fc59d..fabd3529ceb 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -654,9 +654,10 @@ static int pccardd(void *__skt) skt->thread = NULL; complete_and_exit(&skt->thread_done, 0); } - complete(&skt->thread_done); add_wait_queue(&skt->thread_wait, &wait); + complete(&skt->thread_done); + for (;;) { unsigned long flags; unsigned int events; @@ -682,11 +683,11 @@ static int pccardd(void *__skt) continue; } - schedule(); - try_to_freeze(); - if (!skt->thread) break; + + schedule(); + try_to_freeze(); } remove_wait_queue(&skt->thread_wait, &wait); diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 6bbfbd0e02a..55867bc7f19 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h @@ -17,9 +17,6 @@ #include <linux/config.h> -#define CLIENT_MAGIC 0x51E6 -typedef struct client_t client_t; - /* Flags in client state */ #define CLIENT_CONFIG_LOCKED 0x0001 #define CLIENT_IRQ_REQ 0x0002 @@ -45,7 +42,6 @@ typedef struct region_t { typedef struct config_t { u_int state; u_int Attributes; - u_int Vcc, Vpp1, Vpp2; u_int IntType; u_int ConfigBase; u_char Status, Pin, Copy, Option, ExtStatus; diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 43da2e92d50..080608c7381 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c @@ -354,6 +354,7 @@ static void pcmcia_release_dev(struct device *dev) struct pcmcia_device *p_dev = to_pcmcia_dev(dev); ds_dbg(1, "releasing dev %p\n", p_dev); pcmcia_put_socket(p_dev->socket); + kfree(p_dev->devname); kfree(p_dev); } @@ -424,9 +425,13 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) { cistpl_manfid_t manf_id; cistpl_funcid_t func_id; - cistpl_vers_1_t vers1; + cistpl_vers_1_t *vers1; unsigned int i; + vers1 = kmalloc(sizeof(*vers1), GFP_KERNEL); + if (!vers1) + return -ENOMEM; + if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_MANFID, &manf_id)) { p_dev->manf_id = manf_id.manf; @@ -443,23 +448,30 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) /* rule of thumb: cards with no FUNCID, but with * common memory device geometry information, are * probably memory cards (from pcmcia-cs) */ - cistpl_device_geo_t devgeo; + cistpl_device_geo_t *devgeo; + + devgeo = kmalloc(sizeof(*devgeo), GFP_KERNEL); + if (!devgeo) { + kfree(vers1); + return -ENOMEM; + } if (!pccard_read_tuple(p_dev->socket, p_dev->func, - CISTPL_DEVICE_GEO, &devgeo)) { + CISTPL_DEVICE_GEO, devgeo)) { ds_dbg(0, "mem device geometry probably means " "FUNCID_MEMORY\n"); p_dev->func_id = CISTPL_FUNCID_MEMORY; p_dev->has_func_id = 1; } + kfree(devgeo); } if (!pccard_read_tuple(p_dev->socket, p_dev->func, CISTPL_VERS_1, - &vers1)) { - for (i=0; i < vers1.ns; i++) { + vers1)) { + for (i=0; i < vers1->ns; i++) { char *tmp; unsigned int length; - tmp = vers1.str + vers1.ofs[i]; + tmp = vers1->str + vers1->ofs[i]; length = strlen(tmp) + 1; if ((length < 3) || (length > 255)) @@ -475,6 +487,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) } } + kfree(vers1); return 0; } @@ -492,6 +505,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f { struct pcmcia_device *p_dev; unsigned long flags; + int bus_id_len; s = pcmcia_get_socket(s); if (!s) @@ -515,7 +529,12 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f p_dev->dev.bus = &pcmcia_bus_type; p_dev->dev.parent = s->dev.dev; p_dev->dev.release = pcmcia_release_dev; - sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); + bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no); + + p_dev->devname = kmalloc(6 + bus_id_len + 1, GFP_KERNEL); + if (!p_dev->devname) + goto err_free; + sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); /* compat */ p_dev->state = CLIENT_UNBOUND; @@ -540,6 +559,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f return p_dev; err_free: + kfree(p_dev->devname); kfree(p_dev); s->device_count--; err_put: diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c new file mode 100644 index 00000000000..08d1c928826 --- /dev/null +++ b/drivers/pcmcia/omap_cf.c @@ -0,0 +1,373 @@ +/* + * omap_cf.c -- OMAP 16xx CompactFlash controller driver + * + * Copyright (c) 2005 David Brownell + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> + +#include <pcmcia/ss.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/mach-types.h> +#include <asm/sizes.h> + +#include <asm/arch/mux.h> +#include <asm/arch/tc.h> + + +/* NOTE: don't expect this to support many I/O cards. The 16xx chips have + * hard-wired timings to support Compact Flash memory cards; they won't work + * with various other devices (like WLAN adapters) without some external + * logic to help out. + * + * NOTE: CF controller docs disagree with address space docs as to where + * CF_BASE really lives; this is a doc erratum. + */ +#define CF_BASE 0xfffe2800 + +/* status; read after IRQ */ +#define CF_STATUS_REG __REG16(CF_BASE + 0x00) +# define CF_STATUS_BAD_READ (1 << 2) +# define CF_STATUS_BAD_WRITE (1 << 1) +# define CF_STATUS_CARD_DETECT (1 << 0) + +/* which chipselect (CS0..CS3) is used for CF (active low) */ +#define CF_CFG_REG __REG16(CF_BASE + 0x02) + +/* card reset */ +#define CF_CONTROL_REG __REG16(CF_BASE + 0x04) +# define CF_CONTROL_RESET (1 << 0) + +#define omap_cf_present() (!(CF_STATUS_REG & CF_STATUS_CARD_DETECT)) + +/*--------------------------------------------------------------------------*/ + +static const char driver_name[] = "omap_cf"; + +struct omap_cf_socket { + struct pcmcia_socket socket; + + struct timer_list timer; + unsigned present:1; + unsigned active:1; + + struct platform_device *pdev; + unsigned long phys_cf; + u_int irq; +}; + +#define POLL_INTERVAL (2 * HZ) + +#define SZ_2K (2 * SZ_1K) + +/*--------------------------------------------------------------------------*/ + +static int omap_cf_ss_init(struct pcmcia_socket *s) +{ + return 0; +} + +/* the timer is primarily to kick this socket's pccardd */ +static void omap_cf_timer(unsigned long _cf) +{ + struct omap_cf_socket *cf = (void *) _cf; + unsigned present = omap_cf_present(); + + if (present != cf->present) { + cf->present = present; + pr_debug("%s: card %s\n", driver_name, + present ? "present" : "gone"); + pcmcia_parse_events(&cf->socket, SS_DETECT); + } + + if (cf->active) + mod_timer(&cf->timer, jiffies + POLL_INTERVAL); +} + +/* This irq handler prevents "irqNNN: nobody cared" messages as drivers + * claim the card's IRQ. It may also detect some card insertions, but + * not removals; it can't always eliminate timer irqs. + */ +static irqreturn_t omap_cf_irq(int irq, void *_cf, struct pt_regs *r) +{ + omap_cf_timer((unsigned long)_cf); + return IRQ_HANDLED; +} + +static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp) +{ + if (!sp) + return -EINVAL; + + /* FIXME power management should probably be board-specific: + * - 3VCARD vs XVCARD (OSK only handles 3VCARD) + * - POWERON (switched on/off by set_socket) + */ + if (omap_cf_present()) { + struct omap_cf_socket *cf; + + *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD; + cf = container_of(s, struct omap_cf_socket, socket); + s->irq.AssignedIRQ = cf->irq; + } else + *sp = 0; + return 0; +} + +static int +omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s) +{ + u16 control; + + /* FIXME some non-OSK boards will support power switching */ + switch (s->Vcc) { + case 0: + case 33: + break; + default: + return -EINVAL; + } + + control = CF_CONTROL_REG; + if (s->flags & SS_RESET) + CF_CONTROL_REG = CF_CONTROL_RESET; + else + CF_CONTROL_REG = 0; + + pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n", + driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask); + + return 0; +} + +static int omap_cf_ss_suspend(struct pcmcia_socket *s) +{ + pr_debug("%s: %s\n", driver_name, __FUNCTION__); + return omap_cf_set_socket(s, &dead_socket); +} + +/* regions are 2K each: mem, attrib, io (and reserved-for-ide) */ + +static int +omap_cf_set_io_map(struct pcmcia_socket *s, struct pccard_io_map *io) +{ + struct omap_cf_socket *cf; + + cf = container_of(s, struct omap_cf_socket, socket); + io->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + io->start = cf->phys_cf + SZ_4K; + io->stop = io->start + SZ_2K - 1; + return 0; +} + +static int +omap_cf_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *map) +{ + struct omap_cf_socket *cf; + + if (map->card_start) + return -EINVAL; + cf = container_of(s, struct omap_cf_socket, socket); + map->static_start = cf->phys_cf; + map->flags &= MAP_ACTIVE|MAP_ATTRIB|MAP_16BIT; + if (map->flags & MAP_ATTRIB) + map->static_start += SZ_2K; + return 0; +} + +static struct pccard_operations omap_cf_ops = { + .init = omap_cf_ss_init, + .suspend = omap_cf_ss_suspend, + .get_status = omap_cf_get_status, + .set_socket = omap_cf_set_socket, + .set_io_map = omap_cf_set_io_map, + .set_mem_map = omap_cf_set_mem_map, +}; + +/*--------------------------------------------------------------------------*/ + +/* + * NOTE: right now the only board-specific platform_data is + * "what chipselect is used". Boards could want more. + */ + +static int __init omap_cf_probe(struct device *dev) +{ + unsigned seg; + struct omap_cf_socket *cf; + struct platform_device *pdev = to_platform_device(dev); + int irq; + int status; + + seg = (int) dev->platform_data; + if (seg == 0 || seg > 3) + return -ENODEV; + + /* either CFLASH.IREQ (INT_1610_CF) or some GPIO */ + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + + cf = kcalloc(1, sizeof *cf, GFP_KERNEL); + if (!cf) + return -ENOMEM; + init_timer(&cf->timer); + cf->timer.function = omap_cf_timer; + cf->timer.data = (unsigned long) cf; + + cf->pdev = pdev; + dev_set_drvdata(dev, cf); + + /* this primarily just shuts up irq handling noise */ + status = request_irq(irq, omap_cf_irq, SA_SHIRQ, + driver_name, cf); + if (status < 0) + goto fail0; + cf->irq = irq; + cf->socket.pci_irq = irq; + + switch (seg) { + /* NOTE: CS0 could be configured too ... */ + case 1: + cf->phys_cf = OMAP_CS1_PHYS; + break; + case 2: + cf->phys_cf = OMAP_CS2_PHYS; + break; + case 3: + cf->phys_cf = omap_cs3_phys(); + break; + default: + goto fail1; + } + + /* pcmcia layer only remaps "real" memory */ + cf->socket.io_offset = (unsigned long) + ioremap(cf->phys_cf + SZ_4K, SZ_2K); + if (!cf->socket.io_offset) + goto fail1; + + if (!request_mem_region(cf->phys_cf, SZ_8K, driver_name)) + goto fail1; + + /* NOTE: CF conflicts with MMC1 */ + omap_cfg_reg(W11_1610_CF_CD1); + omap_cfg_reg(P11_1610_CF_CD2); + omap_cfg_reg(R11_1610_CF_IOIS16); + omap_cfg_reg(V10_1610_CF_IREQ); + omap_cfg_reg(W10_1610_CF_RESET); + + CF_CFG_REG = ~(1 << seg); + + pr_info("%s: cs%d on irq %d\n", driver_name, seg, irq); + + /* NOTE: better EMIFS setup might support more cards; but the + * TRM only shows how to affect regular flash signals, not their + * CF/PCMCIA variants... + */ + pr_debug("%s: cs%d, previous ccs %08x acs %08x\n", driver_name, + seg, EMIFS_CCS(seg), EMIFS_ACS(seg)); + EMIFS_CCS(seg) = 0x0004a1b3; /* synch mode 4 etc */ + EMIFS_ACS(seg) = 0x00000000; /* OE hold/setup */ + + /* CF uses armxor_ck, which is "always" available */ + + pr_debug("%s: sts %04x cfg %04x control %04x %s\n", driver_name, + CF_STATUS_REG, CF_CFG_REG, CF_CONTROL_REG, + omap_cf_present() ? "present" : "(not present)"); + + cf->socket.owner = THIS_MODULE; + cf->socket.dev.dev = dev; + cf->socket.ops = &omap_cf_ops; + cf->socket.resource_ops = &pccard_static_ops; + cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP + | SS_CAP_MEM_ALIGN; + cf->socket.map_size = SZ_2K; + + status = pcmcia_register_socket(&cf->socket); + if (status < 0) + goto fail2; + + cf->active = 1; + mod_timer(&cf->timer, jiffies + POLL_INTERVAL); + return 0; + +fail2: + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(cf->phys_cf, SZ_8K); +fail1: + free_irq(irq, cf); +fail0: + kfree(cf); + return status; +} + +static int __devexit omap_cf_remove(struct device *dev) +{ + struct omap_cf_socket *cf = dev_get_drvdata(dev); + + cf->active = 0; + pcmcia_unregister_socket(&cf->socket); + del_timer_sync(&cf->timer); + iounmap((void __iomem *) cf->socket.io_offset); + release_mem_region(cf->phys_cf, SZ_8K); + free_irq(cf->irq, cf); + kfree(cf); + return 0; +} + +static int omap_cf_suspend(struct device *dev, pm_message_t mesg, u32 level) +{ + if (level != SUSPEND_SAVE_STATE) + return 0; + return pcmcia_socket_dev_suspend(dev, mesg); +} + +static int omap_cf_resume(struct device *dev, u32 level) +{ + if (level != RESUME_RESTORE_STATE) + return 0; + return pcmcia_socket_dev_resume(dev); +} + +static struct device_driver omap_cf_driver = { + .name = (char *) driver_name, + .bus = &platform_bus_type, + .probe = omap_cf_probe, + .remove = __devexit_p(omap_cf_remove), + .suspend = omap_cf_suspend, + .resume = omap_cf_resume, +}; + +static int __init omap_cf_init(void) +{ + if (cpu_is_omap16xx()) + driver_register(&omap_cf_driver); + return 0; +} + +static void __exit omap_cf_exit(void) +{ + if (cpu_is_omap16xx()) + driver_unregister(&omap_cf_driver); +} + +module_init(omap_cf_init); +module_exit(omap_cf_exit); + +MODULE_DESCRIPTION("OMAP CF Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c index 39ba6406fd5..80969f7e7a0 100644 --- a/drivers/pcmcia/pcmcia_ioctl.c +++ b/drivers/pcmcia/pcmcia_ioctl.c @@ -376,6 +376,7 @@ static int ds_open(struct inode *inode, struct file *file) socket_t i = iminor(inode); struct pcmcia_socket *s; user_info_t *user; + static int warning_printed = 0; ds_dbg(0, "ds_open(socket %d)\n", i); @@ -407,6 +408,17 @@ static int ds_open(struct inode *inode, struct file *file) s->user = user; file->private_data = user; + if (!warning_printed) { + printk(KERN_INFO "pcmcia: Detected deprecated PCMCIA ioctl " + "usage.\n"); + printk(KERN_INFO "pcmcia: This interface will soon be removed from " + "the kernel; please expect breakage unless you upgrade " + "to new tools.\n"); + printk(KERN_INFO "pcmcia: see http://www.kernel.org/pub/linux/" + "utils/kernel/pcmcia/pcmcia.html for details.\n"); + warning_printed = 1; + } + if (s->pcmcia_state.present) queue_event(user, CS_EVENT_CARD_INSERTION); return 0; diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 599b116d974..89022ad5b52 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -447,7 +447,7 @@ int pcmcia_modify_configuration(struct pcmcia_device *p_dev, (mod->Attributes & CONF_VPP2_CHANGE_VALID)) { if (mod->Vpp1 != mod->Vpp2) return CS_BAD_VPP; - c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1; + s->socket.Vpp = mod->Vpp1; if (s->ops->set_socket(s, &s->socket)) return CS_BAD_VPP; } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) || @@ -623,8 +623,6 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev, if (s->ops->set_socket(s, &s->socket)) return CS_BAD_VPP; - c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1; - /* Pick memory or I/O card, DMA mode, interrupt */ c->IntType = req->IntType; c->Attributes = req->Attributes; @@ -822,7 +820,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || (s->functions > 1) || (irq == s->pci_irq)) ? SA_SHIRQ : 0, - p_dev->dev.bus_id, + p_dev->devname, (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); if (!ret) { if (!(req->Attributes & IRQ_HANDLE_PRESENT)) @@ -832,7 +830,8 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) } } #endif - if (ret) { + /* only assign PCI irq if no IRQ already assigned */ + if (ret && !s->irq.AssignedIRQ) { if (!s->pci_irq) return ret; irq = s->pci_irq; @@ -843,7 +842,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || (s->functions > 1) || (irq == s->pci_irq)) ? SA_SHIRQ : 0, - p_dev->dev.bus_id, req->Instance)) + p_dev->devname, req->Instance)) return CS_IN_USE; } diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 3e23cd461fb..325c992f7d8 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -246,7 +246,7 @@ static void __exit pxa2xx_pcmcia_exit(void) driver_unregister(&pxa2xx_pcmcia_driver); } -module_init(pxa2xx_pcmcia_init); +fs_initcall(pxa2xx_pcmcia_init); module_exit(pxa2xx_pcmcia_exit); MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>"); diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 5309734e168..bbe69b07ce5 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c @@ -196,7 +196,7 @@ static void __exit mst_pcmcia_exit(void) platform_device_unregister(mst_pcmcia_device); } -module_init(mst_pcmcia_init); +fs_initcall(mst_pcmcia_init); module_exit(mst_pcmcia_exit); MODULE_LICENSE("GPL"); diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 42efe218867..a1178a600e3 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c @@ -20,27 +20,18 @@ #include <asm/hardware.h> #include <asm/irq.h> - #include <asm/hardware/scoop.h> -#include <asm/arch/corgi.h> #include <asm/arch/pxa-regs.h> #include "soc_common.h" #define NO_KEEP_VS 0x0001 -static unsigned char keep_vs; -static unsigned char keep_rd; - -static struct pcmcia_irqs irqs[] = { - { 0, CORGI_IRQ_GPIO_CF_CD, "PCMCIA0 CD"}, -}; - -static void sharpsl_pcmcia_init_reset(void) +static void sharpsl_pcmcia_init_reset(struct scoop_pcmcia_dev *scoopdev) { - reset_scoop(&corgiscoop_device.dev); - keep_vs = NO_KEEP_VS; - keep_rd = 0; + reset_scoop(scoopdev->dev); + scoopdev->keep_vs = NO_KEEP_VS; + scoopdev->keep_rd = 0; } static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) @@ -71,29 +62,35 @@ static int sharpsl_pcmcia_hw_init(struct soc_pcmcia_socket *skt) pxa_gpio_mode(GPIO57_nIOIS16_MD); /* Register interrupts */ - ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); - - if (ret) { - printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); - return ret; + if (scoop_devs[skt->nr].cd_irq >= 0) { + struct pcmcia_irqs cd_irq; + + cd_irq.sock = skt->nr; + cd_irq.irq = scoop_devs[skt->nr].cd_irq; + cd_irq.str = scoop_devs[skt->nr].cd_irq_str; + ret = soc_pcmcia_request_irqs(skt, &cd_irq, 1); + + if (ret) { + printk(KERN_ERR "Request for Compact Flash IRQ failed\n"); + return ret; + } } - /* Enable interrupt */ - write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, 0x00C0); - write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, 0x0101); - keep_vs = NO_KEEP_VS; - - skt->irq = CORGI_IRQ_GPIO_CF_IRQ; + skt->irq = scoop_devs[skt->nr].irq; return 0; } static void sharpsl_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); + if (scoop_devs[skt->nr].cd_irq >= 0) { + struct pcmcia_irqs cd_irq; - /* CF_BUS_OFF */ - sharpsl_pcmcia_init_reset(); + cd_irq.sock = skt->nr; + cd_irq.irq = scoop_devs[skt->nr].cd_irq; + cd_irq.str = scoop_devs[skt->nr].cd_irq_str; + soc_pcmcia_free_irqs(skt, &cd_irq, 1); + } } @@ -101,31 +98,32 @@ static void sharpsl_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state) { unsigned short cpr, csr; + struct device *scoop = scoop_devs[skt->nr].dev; - cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR); + cpr = read_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_CPR); - write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x00FF); - write_scoop_reg(&corgiscoop_device.dev, SCOOP_ISR, 0x0000); - write_scoop_reg(&corgiscoop_device.dev, SCOOP_IRM, 0x0000); - csr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CSR); + write_scoop_reg(scoop, SCOOP_IRM, 0x00FF); + write_scoop_reg(scoop, SCOOP_ISR, 0x0000); + write_scoop_reg(scoop, SCOOP_IRM, 0x0000); + csr = read_scoop_reg(scoop, SCOOP_CSR); if (csr & 0x0004) { /* card eject */ - write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); - keep_vs = NO_KEEP_VS; + write_scoop_reg(scoop, SCOOP_CDR, 0x0000); + scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; } - else if (!(keep_vs & NO_KEEP_VS)) { + else if (!(scoop_devs[skt->nr].keep_vs & NO_KEEP_VS)) { /* keep vs1,vs2 */ - write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); - csr |= keep_vs; + write_scoop_reg(scoop, SCOOP_CDR, 0x0000); + csr |= scoop_devs[skt->nr].keep_vs; } else if (cpr & 0x0003) { /* power on */ - write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0000); - keep_vs = (csr & 0x00C0); + write_scoop_reg(scoop, SCOOP_CDR, 0x0000); + scoop_devs[skt->nr].keep_vs = (csr & 0x00C0); } else { /* card detect */ - write_scoop_reg(&corgiscoop_device.dev, SCOOP_CDR, 0x0002); + write_scoop_reg(scoop, SCOOP_CDR, 0x0002); } state->detect = (csr & 0x0004) ? 0 : 1; @@ -147,6 +145,7 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state) { unsigned long flags; + struct device *scoop = scoop_devs[skt->nr].dev; unsigned short cpr, ncpr, ccr, nccr, mcr, nmcr, imr, nimr; @@ -166,10 +165,10 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, local_irq_save(flags); - nmcr = (mcr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR)) & ~0x0010; - ncpr = (cpr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR)) & ~0x0083; - nccr = (ccr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR)) & ~0x0080; - nimr = (imr = read_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR)) & ~0x003E; + nmcr = (mcr = read_scoop_reg(scoop, SCOOP_MCR)) & ~0x0010; + ncpr = (cpr = read_scoop_reg(scoop, SCOOP_CPR)) & ~0x0083; + nccr = (ccr = read_scoop_reg(scoop, SCOOP_CCR)) & ~0x0080; + nimr = (imr = read_scoop_reg(scoop, SCOOP_IMR)) & ~0x003E; ncpr |= (state->Vcc == 33) ? 0x0001 : (state->Vcc == 50) ? 0x0002 : 0; @@ -184,22 +183,22 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, ((skt->status&SS_WRPROT) ? 0x0008 : 0); if (!(ncpr & 0x0003)) { - keep_rd = 0; - } else if (!keep_rd) { + scoop_devs[skt->nr].keep_rd = 0; + } else if (!scoop_devs[skt->nr].keep_rd) { if (nccr & 0x0080) - keep_rd = 1; + scoop_devs[skt->nr].keep_rd = 1; else nccr |= 0x0080; } if (mcr != nmcr) - write_scoop_reg(&corgiscoop_device.dev, SCOOP_MCR, nmcr); + write_scoop_reg(scoop, SCOOP_MCR, nmcr); if (cpr != ncpr) - write_scoop_reg(&corgiscoop_device.dev, SCOOP_CPR, ncpr); + write_scoop_reg(scoop, SCOOP_CPR, ncpr); if (ccr != nccr) - write_scoop_reg(&corgiscoop_device.dev, SCOOP_CCR, nccr); + write_scoop_reg(scoop, SCOOP_CCR, nccr); if (imr != nimr) - write_scoop_reg(&corgiscoop_device.dev, SCOOP_IMR, nimr); + write_scoop_reg(scoop, SCOOP_IMR, nimr); local_irq_restore(flags); @@ -208,10 +207,18 @@ static int sharpsl_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, static void sharpsl_pcmcia_socket_init(struct soc_pcmcia_socket *skt) { + sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); + + /* Enable interrupt */ + write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_IMR, 0x00C0); + write_scoop_reg(scoop_devs[skt->nr].dev, SCOOP_MCR, 0x0101); + scoop_devs[skt->nr].keep_vs = NO_KEEP_VS; } static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { + /* CF_BUS_OFF */ + sharpsl_pcmcia_init_reset(&scoop_devs[skt->nr]); } static struct pcmcia_low_level sharpsl_pcmcia_ops = { @@ -223,7 +230,7 @@ static struct pcmcia_low_level sharpsl_pcmcia_ops = { .socket_init = sharpsl_pcmcia_socket_init, .socket_suspend = sharpsl_pcmcia_socket_suspend, .first = 0, - .nr = 1, + .nr = 0, }; static struct platform_device *sharpsl_pcmcia_device; @@ -232,12 +239,15 @@ static int __init sharpsl_pcmcia_init(void) { int ret; + sharpsl_pcmcia_ops.nr=scoop_num; sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); if (!sharpsl_pcmcia_device) return -ENOMEM; + memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; + sharpsl_pcmcia_device->dev.parent=scoop_devs[0].dev; ret = platform_device_register(sharpsl_pcmcia_device); if (ret) @@ -257,7 +267,7 @@ static void __exit sharpsl_pcmcia_exit(void) platform_device_unregister(sharpsl_pcmcia_device); } -module_init(sharpsl_pcmcia_init); +fs_initcall(sharpsl_pcmcia_init); module_exit(sharpsl_pcmcia_exit); MODULE_DESCRIPTION("Sharp SL Series PCMCIA Support"); diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index e98bb3d80e7..d4ed508b38b 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -126,5 +126,5 @@ MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>"); MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11x0 Socket Controller"); MODULE_LICENSE("Dual MPL/GPL"); -module_init(sa11x0_pcmcia_init); +fs_initcall(sa11x0_pcmcia_init); module_exit(sa11x0_pcmcia_exit); diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index b441f43a6a5..bb90a1448a5 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -189,7 +189,7 @@ static void __exit sa1111_drv_pcmcia_exit(void) sa1111_driver_unregister(&pcmcia_driver); } -module_init(sa1111_drv_pcmcia_init); +fs_initcall(sa1111_drv_pcmcia_init); module_exit(sa1111_drv_pcmcia_exit); MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver"); diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index db04ffb6f68..59c5d968e9f 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -189,7 +189,7 @@ static int __init sa11xx_pcmcia_init(void) { return 0; } -module_init(sa11xx_pcmcia_init); +fs_initcall(sa11xx_pcmcia_init); static void __exit sa11xx_pcmcia_exit(void) {} diff --git a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h index be420bb2911..edccfa5bb40 100644 --- a/drivers/pcmcia/topic.h +++ b/drivers/pcmcia/topic.h @@ -101,6 +101,8 @@ #define TOPIC97_AVS_AUDIO_CONTROL 0x02 #define TOPIC97_AVS_VIDEO_CONTROL 0x01 +#define TOPIC_EXCA_IF_CONTROL 0x3e /* 8 bit */ +#define TOPIC_EXCA_IFC_33V_ENA 0x01 static void topic97_zoom_video(struct pcmcia_socket *sock, int onoff) { @@ -137,4 +139,19 @@ static int topic97_override(struct yenta_socket *socket) return 0; } + +static int topic95_override(struct yenta_socket *socket) +{ + u8 fctrl; + + /* enable 3.3V support for 16bit cards */ + fctrl = exca_readb(socket, TOPIC_EXCA_IF_CONTROL); + exca_writeb(socket, TOPIC_EXCA_IF_CONTROL, fctrl | TOPIC_EXCA_IFC_33V_ENA); + + /* tell yenta to use exca registers to power 16bit cards */ + socket->flags |= YENTA_16BIT_POWER_EXCA | YENTA_16BIT_POWER_DF; + + return 0; +} + #endif /* _LINUX_TOPIC_H */ diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 62fd705203f..f0997c36c9b 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -72,6 +72,7 @@ static inline void cb_writel(struct yenta_socket *socket, unsigned reg, u32 val) { debug("%p %04x %08x\n", socket, reg, val); writel(val, socket->base + reg); + readl(socket->base + reg); /* avoid problems with PCI write posting */ } static inline u8 config_readb(struct yenta_socket *socket, unsigned offset) @@ -136,6 +137,7 @@ static inline void exca_writeb(struct yenta_socket *socket, unsigned reg, u8 val { debug("%p %04x %02x\n", socket, reg, val); writeb(val, socket->base + 0x800 + reg); + readb(socket->base + 0x800 + reg); /* PCI write posting... */ } static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) @@ -143,6 +145,10 @@ static void exca_writew(struct yenta_socket *socket, unsigned reg, u16 val) debug("%p %04x %04x\n", socket, reg, val); writeb(val, socket->base + 0x800 + reg); writeb(val >> 8, socket->base + 0x800 + reg + 1); + + /* PCI write posting... */ + readb(socket->base + 0x800 + reg); + readb(socket->base + 0x800 + reg + 1); } /* @@ -184,22 +190,52 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value) return 0; } -static int yenta_Vcc_power(u32 control) +static void yenta_get_power(struct yenta_socket *socket, socket_state_t *state) { - switch (control & CB_SC_VCC_MASK) { - case CB_SC_VCC_5V: return 50; - case CB_SC_VCC_3V: return 33; - default: return 0; - } -} + if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) && + (socket->flags & YENTA_16BIT_POWER_EXCA)) { + u8 reg, vcc, vpp; + + reg = exca_readb(socket, I365_POWER); + vcc = reg & I365_VCC_MASK; + vpp = reg & I365_VPP1_MASK; + state->Vcc = state->Vpp = 0; + + if (socket->flags & YENTA_16BIT_POWER_DF) { + if (vcc == I365_VCC_3V) + state->Vcc = 33; + if (vcc == I365_VCC_5V) + state->Vcc = 50; + if (vpp == I365_VPP1_5V) + state->Vpp = state->Vcc; + if (vpp == I365_VPP1_12V) + state->Vpp = 120; + } else { + if (reg & I365_VCC_5V) { + state->Vcc = 50; + if (vpp == I365_VPP1_5V) + state->Vpp = 50; + if (vpp == I365_VPP1_12V) + state->Vpp = 120; + } + } + } else { + u32 control; -static int yenta_Vpp_power(u32 control) -{ - switch (control & CB_SC_VPP_MASK) { - case CB_SC_VPP_12V: return 120; - case CB_SC_VPP_5V: return 50; - case CB_SC_VPP_3V: return 33; - default: return 0; + control = cb_readl(socket, CB_SOCKET_CONTROL); + + switch (control & CB_SC_VCC_MASK) { + case CB_SC_VCC_5V: state->Vcc = 50; break; + case CB_SC_VCC_3V: state->Vcc = 33; break; + default: state->Vcc = 0; + } + + switch (control & CB_SC_VPP_MASK) { + case CB_SC_VPP_12V: state->Vpp = 120; break; + case CB_SC_VPP_5V: state->Vpp = 50; break; + case CB_SC_VPP_3V: state->Vpp = 33; break; + default: state->Vpp = 0; + } } } @@ -211,8 +247,7 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state) control = cb_readl(socket, CB_SOCKET_CONTROL); - state->Vcc = yenta_Vcc_power(control); - state->Vpp = yenta_Vpp_power(control); + yenta_get_power(socket, state); state->io_irq = socket->io_irq; if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { @@ -246,19 +281,54 @@ static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state) static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state) { - u32 reg = 0; /* CB_SC_STPCLK? */ - switch (state->Vcc) { - case 33: reg = CB_SC_VCC_3V; break; - case 50: reg = CB_SC_VCC_5V; break; - default: reg = 0; break; - } - switch (state->Vpp) { - case 33: reg |= CB_SC_VPP_3V; break; - case 50: reg |= CB_SC_VPP_5V; break; - case 120: reg |= CB_SC_VPP_12V; break; + /* some birdges require to use the ExCA registers to power 16bit cards */ + if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) && + (socket->flags & YENTA_16BIT_POWER_EXCA)) { + u8 reg, old; + reg = old = exca_readb(socket, I365_POWER); + reg &= ~(I365_VCC_MASK | I365_VPP1_MASK | I365_VPP2_MASK); + + /* i82365SL-DF style */ + if (socket->flags & YENTA_16BIT_POWER_DF) { + switch (state->Vcc) { + case 33: reg |= I365_VCC_3V; break; + case 50: reg |= I365_VCC_5V; break; + default: reg = 0; break; + } + switch (state->Vpp) { + case 33: + case 50: reg |= I365_VPP1_5V; break; + case 120: reg |= I365_VPP1_12V; break; + } + } else { + /* i82365SL-B style */ + switch (state->Vcc) { + case 50: reg |= I365_VCC_5V; break; + default: reg = 0; break; + } + switch (state->Vpp) { + case 50: reg |= I365_VPP1_5V | I365_VPP2_5V; break; + case 120: reg |= I365_VPP1_12V | I365_VPP2_12V; break; + } + } + + if (reg != old) + exca_writeb(socket, I365_POWER, reg); + } else { + u32 reg = 0; /* CB_SC_STPCLK? */ + switch (state->Vcc) { + case 33: reg = CB_SC_VCC_3V; break; + case 50: reg = CB_SC_VCC_5V; break; + default: reg = 0; break; + } + switch (state->Vpp) { + case 33: reg |= CB_SC_VPP_3V; break; + case 50: reg |= CB_SC_VPP_5V; break; + case 120: reg |= CB_SC_VPP_12V; break; + } + if (reg != cb_readl(socket, CB_SOCKET_CONTROL)) + cb_writel(socket, CB_SOCKET_CONTROL, reg); } - if (reg != cb_readl(socket, CB_SOCKET_CONTROL)) - cb_writel(socket, CB_SOCKET_CONTROL, reg); } static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) @@ -603,7 +673,7 @@ static int yenta_search_res(struct yenta_socket *socket, struct resource *res, return 0; } -static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) +static int yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end) { struct resource *root, *res; struct pci_bus_region region; @@ -612,7 +682,7 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr; /* Already allocated? */ if (res->parent) - return; + return 0; /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */ mask = ~0xfff; @@ -628,7 +698,7 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ pcibios_bus_to_resource(socket->dev, res, ®ion); root = pci_find_parent_resource(socket->dev, res); if (root && (request_resource(root, res) == 0)) - return; + return 0; printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n", pci_name(socket->dev), nr); } @@ -636,35 +706,27 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ if (type & IORESOURCE_IO) { if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) || (yenta_search_res(socket, res, BRIDGE_IO_ACC)) || - (yenta_search_res(socket, res, BRIDGE_IO_MIN))) { - config_writel(socket, addr_start, res->start); - config_writel(socket, addr_end, res->end); - return; - } + (yenta_search_res(socket, res, BRIDGE_IO_MIN))) + return 1; } else { if (type & IORESOURCE_PREFETCH) { if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || - (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { - config_writel(socket, addr_start, res->start); - config_writel(socket, addr_end, res->end); - return; - } + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) + return 1; /* Approximating prefetchable by non-prefetchable */ res->flags = IORESOURCE_MEM; } if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) || (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) || - (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) { - config_writel(socket, addr_start, res->start); - config_writel(socket, addr_end, res->end); - return; - } + (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) + return 1; } printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n", pci_name(socket->dev), type); res->start = res->end = res->flags = 0; + return 0; } /* @@ -672,14 +734,17 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ */ static void yenta_allocate_resources(struct yenta_socket *socket) { - yenta_allocate_res(socket, 0, IORESOURCE_IO, + int program = 0; + program += yenta_allocate_res(socket, 0, IORESOURCE_IO, PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0); - yenta_allocate_res(socket, 1, IORESOURCE_IO, + program += yenta_allocate_res(socket, 1, IORESOURCE_IO, PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1); - yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, + program += yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH, PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0); - yenta_allocate_res(socket, 3, IORESOURCE_MEM, + program += yenta_allocate_res(socket, 3, IORESOURCE_MEM, PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1); + if (program) + pci_setup_cardbus(socket->dev->subordinate); } @@ -694,7 +759,7 @@ static void yenta_free_resources(struct yenta_socket *socket) res = socket->dev->resource + PCI_BRIDGE_RESOURCES + i; if (res->start != 0 && res->end != 0) release_resource(res); - res->start = res->end = 0; + res->start = res->end = res->flags = 0; } } @@ -751,6 +816,7 @@ enum { CARDBUS_TYPE_TI12XX, CARDBUS_TYPE_TI1250, CARDBUS_TYPE_RICOH, + CARDBUS_TYPE_TOPIC95, CARDBUS_TYPE_TOPIC97, CARDBUS_TYPE_O2MICRO, }; @@ -789,6 +855,9 @@ static struct cardbus_type cardbus_type[] = { .save_state = ricoh_save_state, .restore_state = ricoh_restore_state, }, + [CARDBUS_TYPE_TOPIC95] = { + .override = topic95_override, + }, [CARDBUS_TYPE_TOPIC97] = { .override = topic97_override, }, @@ -1196,6 +1265,7 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH), CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH), + CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95), CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97), CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97), diff --git a/drivers/pcmcia/yenta_socket.h b/drivers/pcmcia/yenta_socket.h index 4e637eef207..4e75e9e258c 100644 --- a/drivers/pcmcia/yenta_socket.h +++ b/drivers/pcmcia/yenta_socket.h @@ -95,6 +95,12 @@ */ #define CB_MEM_PAGE(map) (0x40 + (map)) + +/* control how 16bit cards are powered */ +#define YENTA_16BIT_POWER_EXCA 0x00000001 +#define YENTA_16BIT_POWER_DF 0x00000002 + + struct yenta_socket; struct cardbus_type { @@ -113,6 +119,8 @@ struct yenta_socket { struct pcmcia_socket socket; struct cardbus_type *type; + u32 flags; + /* for PCI interrupt probing */ unsigned int probe_status; |