1553d6d5fSMaxime Bizon /* 2553d6d5fSMaxime Bizon * This file is subject to the terms and conditions of the GNU General Public 3553d6d5fSMaxime Bizon * License. See the file "COPYING" in the main directory of this archive 4553d6d5fSMaxime Bizon * for more details. 5553d6d5fSMaxime Bizon * 6553d6d5fSMaxime Bizon * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr> 7553d6d5fSMaxime Bizon */ 8553d6d5fSMaxime Bizon 9553d6d5fSMaxime Bizon #include <linux/kernel.h> 10553d6d5fSMaxime Bizon #include <linux/module.h> 11553d6d5fSMaxime Bizon #include <linux/ioport.h> 12553d6d5fSMaxime Bizon #include <linux/timer.h> 13553d6d5fSMaxime Bizon #include <linux/platform_device.h> 14553d6d5fSMaxime Bizon #include <linux/delay.h> 15553d6d5fSMaxime Bizon #include <linux/pci.h> 16553d6d5fSMaxime Bizon #include <linux/gpio.h> 17553d6d5fSMaxime Bizon 18553d6d5fSMaxime Bizon #include <bcm63xx_regs.h> 19553d6d5fSMaxime Bizon #include <bcm63xx_io.h> 20553d6d5fSMaxime Bizon #include "bcm63xx_pcmcia.h" 21553d6d5fSMaxime Bizon 22553d6d5fSMaxime Bizon #define PFX "bcm63xx_pcmcia: " 23553d6d5fSMaxime Bizon 24553d6d5fSMaxime Bizon #ifdef CONFIG_CARDBUS 25553d6d5fSMaxime Bizon /* if cardbus is used, platform device needs reference to actual pci 26553d6d5fSMaxime Bizon * device */ 27553d6d5fSMaxime Bizon static struct pci_dev *bcm63xx_cb_dev; 28553d6d5fSMaxime Bizon #endif 29553d6d5fSMaxime Bizon 30553d6d5fSMaxime Bizon /* 31553d6d5fSMaxime Bizon * read/write helper for pcmcia regs 32553d6d5fSMaxime Bizon */ 33553d6d5fSMaxime Bizon static inline u32 pcmcia_readl(struct bcm63xx_pcmcia_socket *skt, u32 off) 34553d6d5fSMaxime Bizon { 35553d6d5fSMaxime Bizon return bcm_readl(skt->base + off); 36553d6d5fSMaxime Bizon } 37553d6d5fSMaxime Bizon 38553d6d5fSMaxime Bizon static inline void pcmcia_writel(struct bcm63xx_pcmcia_socket *skt, 39553d6d5fSMaxime Bizon u32 val, u32 off) 40553d6d5fSMaxime Bizon { 41553d6d5fSMaxime Bizon bcm_writel(val, skt->base + off); 42553d6d5fSMaxime Bizon } 43553d6d5fSMaxime Bizon 44553d6d5fSMaxime Bizon /* 45553d6d5fSMaxime Bizon * This callback should (re-)initialise the socket, turn on status 46553d6d5fSMaxime Bizon * interrupts and PCMCIA bus, and wait for power to stabilise so that 47553d6d5fSMaxime Bizon * the card status signals report correctly. 48553d6d5fSMaxime Bizon * 49553d6d5fSMaxime Bizon * Hardware cannot do that. 50553d6d5fSMaxime Bizon */ 51553d6d5fSMaxime Bizon static int bcm63xx_pcmcia_sock_init(struct pcmcia_socket *sock) 52553d6d5fSMaxime Bizon { 53553d6d5fSMaxime Bizon return 0; 54553d6d5fSMaxime Bizon } 55553d6d5fSMaxime Bizon 56553d6d5fSMaxime Bizon /* 57553d6d5fSMaxime Bizon * This callback should remove power on the socket, disable IRQs from 58553d6d5fSMaxime Bizon * the card, turn off status interrupts, and disable the PCMCIA bus. 59553d6d5fSMaxime Bizon * 60553d6d5fSMaxime Bizon * Hardware cannot do that. 61553d6d5fSMaxime Bizon */ 62553d6d5fSMaxime Bizon static int bcm63xx_pcmcia_suspend(struct pcmcia_socket *sock) 63553d6d5fSMaxime Bizon { 64553d6d5fSMaxime Bizon return 0; 65553d6d5fSMaxime Bizon } 66553d6d5fSMaxime Bizon 67553d6d5fSMaxime Bizon /* 68553d6d5fSMaxime Bizon * Implements the set_socket() operation for the in-kernel PCMCIA 69553d6d5fSMaxime Bizon * service (formerly SS_SetSocket in Card Services). We more or 70553d6d5fSMaxime Bizon * less punt all of this work and let the kernel handle the details 71553d6d5fSMaxime Bizon * of power configuration, reset, &c. We also record the value of 72553d6d5fSMaxime Bizon * `state' in order to regurgitate it to the PCMCIA core later. 73553d6d5fSMaxime Bizon */ 74553d6d5fSMaxime Bizon static int bcm63xx_pcmcia_set_socket(struct pcmcia_socket *sock, 75553d6d5fSMaxime Bizon socket_state_t *state) 76553d6d5fSMaxime Bizon { 77553d6d5fSMaxime Bizon struct bcm63xx_pcmcia_socket *skt; 78553d6d5fSMaxime Bizon unsigned long flags; 79553d6d5fSMaxime Bizon u32 val; 80553d6d5fSMaxime Bizon 81553d6d5fSMaxime Bizon skt = sock->driver_data; 82553d6d5fSMaxime Bizon 83553d6d5fSMaxime Bizon spin_lock_irqsave(&skt->lock, flags); 84553d6d5fSMaxime Bizon 85553d6d5fSMaxime Bizon /* note: hardware cannot control socket power, so we will 86553d6d5fSMaxime Bizon * always report SS_POWERON */ 87553d6d5fSMaxime Bizon 88553d6d5fSMaxime Bizon /* apply socket reset */ 89553d6d5fSMaxime Bizon val = pcmcia_readl(skt, PCMCIA_C1_REG); 90553d6d5fSMaxime Bizon if (state->flags & SS_RESET) 91553d6d5fSMaxime Bizon val |= PCMCIA_C1_RESET_MASK; 92553d6d5fSMaxime Bizon else 93553d6d5fSMaxime Bizon val &= ~PCMCIA_C1_RESET_MASK; 94553d6d5fSMaxime Bizon 95553d6d5fSMaxime Bizon /* reverse reset logic for cardbus card */ 96553d6d5fSMaxime Bizon if (skt->card_detected && (skt->card_type & CARD_CARDBUS)) 97553d6d5fSMaxime Bizon val ^= PCMCIA_C1_RESET_MASK; 98553d6d5fSMaxime Bizon 99553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C1_REG); 100553d6d5fSMaxime Bizon 101553d6d5fSMaxime Bizon /* keep requested state for event reporting */ 102553d6d5fSMaxime Bizon skt->requested_state = *state; 103553d6d5fSMaxime Bizon 104553d6d5fSMaxime Bizon spin_unlock_irqrestore(&skt->lock, flags); 105553d6d5fSMaxime Bizon 106553d6d5fSMaxime Bizon return 0; 107553d6d5fSMaxime Bizon } 108553d6d5fSMaxime Bizon 109553d6d5fSMaxime Bizon /* 110553d6d5fSMaxime Bizon * identity cardtype from VS[12] input, CD[12] input while only VS2 is 111553d6d5fSMaxime Bizon * floating, and CD[12] input while only VS1 is floating 112553d6d5fSMaxime Bizon */ 113553d6d5fSMaxime Bizon enum { 114553d6d5fSMaxime Bizon IN_VS1 = (1 << 0), 115553d6d5fSMaxime Bizon IN_VS2 = (1 << 1), 116553d6d5fSMaxime Bizon IN_CD1_VS2H = (1 << 2), 117553d6d5fSMaxime Bizon IN_CD2_VS2H = (1 << 3), 118553d6d5fSMaxime Bizon IN_CD1_VS1H = (1 << 4), 119553d6d5fSMaxime Bizon IN_CD2_VS1H = (1 << 5), 120553d6d5fSMaxime Bizon }; 121553d6d5fSMaxime Bizon 122553d6d5fSMaxime Bizon static const u8 vscd_to_cardtype[] = { 123553d6d5fSMaxime Bizon 124553d6d5fSMaxime Bizon /* VS1 float, VS2 float */ 125553d6d5fSMaxime Bizon [IN_VS1 | IN_VS2] = (CARD_PCCARD | CARD_5V), 126553d6d5fSMaxime Bizon 127553d6d5fSMaxime Bizon /* VS1 grounded, VS2 float */ 128553d6d5fSMaxime Bizon [IN_VS2] = (CARD_PCCARD | CARD_5V | CARD_3V), 129553d6d5fSMaxime Bizon 130553d6d5fSMaxime Bizon /* VS1 grounded, VS2 grounded */ 131553d6d5fSMaxime Bizon [0] = (CARD_PCCARD | CARD_5V | CARD_3V | CARD_XV), 132553d6d5fSMaxime Bizon 133553d6d5fSMaxime Bizon /* VS1 tied to CD1, VS2 float */ 134553d6d5fSMaxime Bizon [IN_VS1 | IN_VS2 | IN_CD1_VS1H] = (CARD_CARDBUS | CARD_3V), 135553d6d5fSMaxime Bizon 136553d6d5fSMaxime Bizon /* VS1 grounded, VS2 tied to CD2 */ 137553d6d5fSMaxime Bizon [IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V | CARD_XV), 138553d6d5fSMaxime Bizon 139553d6d5fSMaxime Bizon /* VS1 tied to CD2, VS2 grounded */ 140553d6d5fSMaxime Bizon [IN_VS1 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_3V | CARD_XV | CARD_YV), 141553d6d5fSMaxime Bizon 142553d6d5fSMaxime Bizon /* VS1 float, VS2 grounded */ 143553d6d5fSMaxime Bizon [IN_VS1] = (CARD_PCCARD | CARD_XV), 144553d6d5fSMaxime Bizon 145553d6d5fSMaxime Bizon /* VS1 float, VS2 tied to CD2 */ 146553d6d5fSMaxime Bizon [IN_VS1 | IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V), 147553d6d5fSMaxime Bizon 148553d6d5fSMaxime Bizon /* VS1 float, VS2 tied to CD1 */ 149553d6d5fSMaxime Bizon [IN_VS1 | IN_VS2 | IN_CD1_VS2H] = (CARD_CARDBUS | CARD_XV | CARD_YV), 150553d6d5fSMaxime Bizon 151553d6d5fSMaxime Bizon /* VS1 tied to CD2, VS2 float */ 152553d6d5fSMaxime Bizon [IN_VS1 | IN_VS2 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_YV), 153553d6d5fSMaxime Bizon 154553d6d5fSMaxime Bizon /* VS2 grounded, VS1 is tied to CD1, CD2 is grounded */ 155553d6d5fSMaxime Bizon [IN_VS1 | IN_CD1_VS1H] = 0, /* ignore cardbay */ 156553d6d5fSMaxime Bizon }; 157553d6d5fSMaxime Bizon 158553d6d5fSMaxime Bizon /* 159553d6d5fSMaxime Bizon * poll hardware to check card insertion status 160553d6d5fSMaxime Bizon */ 161553d6d5fSMaxime Bizon static unsigned int __get_socket_status(struct bcm63xx_pcmcia_socket *skt) 162553d6d5fSMaxime Bizon { 163553d6d5fSMaxime Bizon unsigned int stat; 164553d6d5fSMaxime Bizon u32 val; 165553d6d5fSMaxime Bizon 166553d6d5fSMaxime Bizon stat = 0; 167553d6d5fSMaxime Bizon 168553d6d5fSMaxime Bizon /* check CD for card presence */ 169553d6d5fSMaxime Bizon val = pcmcia_readl(skt, PCMCIA_C1_REG); 170553d6d5fSMaxime Bizon 171553d6d5fSMaxime Bizon if (!(val & PCMCIA_C1_CD1_MASK) && !(val & PCMCIA_C1_CD2_MASK)) 172553d6d5fSMaxime Bizon stat |= SS_DETECT; 173553d6d5fSMaxime Bizon 174553d6d5fSMaxime Bizon /* if new insertion, detect cardtype */ 175553d6d5fSMaxime Bizon if ((stat & SS_DETECT) && !skt->card_detected) { 176553d6d5fSMaxime Bizon unsigned int stat = 0; 177553d6d5fSMaxime Bizon 178553d6d5fSMaxime Bizon /* float VS1, float VS2 */ 179553d6d5fSMaxime Bizon val |= PCMCIA_C1_VS1OE_MASK; 180553d6d5fSMaxime Bizon val |= PCMCIA_C1_VS2OE_MASK; 181553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C1_REG); 182553d6d5fSMaxime Bizon 183553d6d5fSMaxime Bizon /* wait for output to stabilize and read VS[12] */ 184553d6d5fSMaxime Bizon udelay(10); 185553d6d5fSMaxime Bizon val = pcmcia_readl(skt, PCMCIA_C1_REG); 186553d6d5fSMaxime Bizon stat |= (val & PCMCIA_C1_VS1_MASK) ? IN_VS1 : 0; 187553d6d5fSMaxime Bizon stat |= (val & PCMCIA_C1_VS2_MASK) ? IN_VS2 : 0; 188553d6d5fSMaxime Bizon 189553d6d5fSMaxime Bizon /* drive VS1 low, float VS2 */ 190553d6d5fSMaxime Bizon val &= ~PCMCIA_C1_VS1OE_MASK; 191553d6d5fSMaxime Bizon val |= PCMCIA_C1_VS2OE_MASK; 192553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C1_REG); 193553d6d5fSMaxime Bizon 194553d6d5fSMaxime Bizon /* wait for output to stabilize and read CD[12] */ 195553d6d5fSMaxime Bizon udelay(10); 196553d6d5fSMaxime Bizon val = pcmcia_readl(skt, PCMCIA_C1_REG); 197553d6d5fSMaxime Bizon stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS2H : 0; 198553d6d5fSMaxime Bizon stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS2H : 0; 199553d6d5fSMaxime Bizon 200553d6d5fSMaxime Bizon /* float VS1, drive VS2 low */ 201553d6d5fSMaxime Bizon val |= PCMCIA_C1_VS1OE_MASK; 202553d6d5fSMaxime Bizon val &= ~PCMCIA_C1_VS2OE_MASK; 203553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C1_REG); 204553d6d5fSMaxime Bizon 205553d6d5fSMaxime Bizon /* wait for output to stabilize and read CD[12] */ 206553d6d5fSMaxime Bizon udelay(10); 207553d6d5fSMaxime Bizon val = pcmcia_readl(skt, PCMCIA_C1_REG); 208553d6d5fSMaxime Bizon stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS1H : 0; 209553d6d5fSMaxime Bizon stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS1H : 0; 210553d6d5fSMaxime Bizon 211553d6d5fSMaxime Bizon /* guess cardtype from all this */ 212553d6d5fSMaxime Bizon skt->card_type = vscd_to_cardtype[stat]; 213553d6d5fSMaxime Bizon if (!skt->card_type) 214553d6d5fSMaxime Bizon dev_err(&skt->socket.dev, "unsupported card type\n"); 215553d6d5fSMaxime Bizon 216553d6d5fSMaxime Bizon /* drive both VS pin to 0 again */ 217553d6d5fSMaxime Bizon val &= ~(PCMCIA_C1_VS1OE_MASK | PCMCIA_C1_VS2OE_MASK); 218553d6d5fSMaxime Bizon 219553d6d5fSMaxime Bizon /* enable correct logic */ 220553d6d5fSMaxime Bizon val &= ~(PCMCIA_C1_EN_PCMCIA_MASK | PCMCIA_C1_EN_CARDBUS_MASK); 221553d6d5fSMaxime Bizon if (skt->card_type & CARD_PCCARD) 222553d6d5fSMaxime Bizon val |= PCMCIA_C1_EN_PCMCIA_MASK; 223553d6d5fSMaxime Bizon else 224553d6d5fSMaxime Bizon val |= PCMCIA_C1_EN_CARDBUS_MASK; 225553d6d5fSMaxime Bizon 226553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C1_REG); 227553d6d5fSMaxime Bizon } 228553d6d5fSMaxime Bizon skt->card_detected = (stat & SS_DETECT) ? 1 : 0; 229553d6d5fSMaxime Bizon 230553d6d5fSMaxime Bizon /* report card type/voltage */ 231553d6d5fSMaxime Bizon if (skt->card_type & CARD_CARDBUS) 232553d6d5fSMaxime Bizon stat |= SS_CARDBUS; 233553d6d5fSMaxime Bizon if (skt->card_type & CARD_3V) 234553d6d5fSMaxime Bizon stat |= SS_3VCARD; 235553d6d5fSMaxime Bizon if (skt->card_type & CARD_XV) 236553d6d5fSMaxime Bizon stat |= SS_XVCARD; 237553d6d5fSMaxime Bizon stat |= SS_POWERON; 238553d6d5fSMaxime Bizon 239553d6d5fSMaxime Bizon if (gpio_get_value(skt->pd->ready_gpio)) 240553d6d5fSMaxime Bizon stat |= SS_READY; 241553d6d5fSMaxime Bizon 242553d6d5fSMaxime Bizon return stat; 243553d6d5fSMaxime Bizon } 244553d6d5fSMaxime Bizon 245553d6d5fSMaxime Bizon /* 246553d6d5fSMaxime Bizon * core request to get current socket status 247553d6d5fSMaxime Bizon */ 248553d6d5fSMaxime Bizon static int bcm63xx_pcmcia_get_status(struct pcmcia_socket *sock, 249553d6d5fSMaxime Bizon unsigned int *status) 250553d6d5fSMaxime Bizon { 251553d6d5fSMaxime Bizon struct bcm63xx_pcmcia_socket *skt; 252553d6d5fSMaxime Bizon 253553d6d5fSMaxime Bizon skt = sock->driver_data; 254553d6d5fSMaxime Bizon 255553d6d5fSMaxime Bizon spin_lock_bh(&skt->lock); 256553d6d5fSMaxime Bizon *status = __get_socket_status(skt); 257553d6d5fSMaxime Bizon spin_unlock_bh(&skt->lock); 258553d6d5fSMaxime Bizon 259553d6d5fSMaxime Bizon return 0; 260553d6d5fSMaxime Bizon } 261553d6d5fSMaxime Bizon 262553d6d5fSMaxime Bizon /* 263553d6d5fSMaxime Bizon * socket polling timer callback 264553d6d5fSMaxime Bizon */ 265553d6d5fSMaxime Bizon static void bcm63xx_pcmcia_poll(unsigned long data) 266553d6d5fSMaxime Bizon { 267553d6d5fSMaxime Bizon struct bcm63xx_pcmcia_socket *skt; 268553d6d5fSMaxime Bizon unsigned int stat, events; 269553d6d5fSMaxime Bizon 270553d6d5fSMaxime Bizon skt = (struct bcm63xx_pcmcia_socket *)data; 271553d6d5fSMaxime Bizon 272553d6d5fSMaxime Bizon spin_lock_bh(&skt->lock); 273553d6d5fSMaxime Bizon 274553d6d5fSMaxime Bizon stat = __get_socket_status(skt); 275553d6d5fSMaxime Bizon 276553d6d5fSMaxime Bizon /* keep only changed bits, and mask with required one from the 277553d6d5fSMaxime Bizon * core */ 278553d6d5fSMaxime Bizon events = (stat ^ skt->old_status) & skt->requested_state.csc_mask; 279553d6d5fSMaxime Bizon skt->old_status = stat; 280553d6d5fSMaxime Bizon spin_unlock_bh(&skt->lock); 281553d6d5fSMaxime Bizon 282553d6d5fSMaxime Bizon if (events) 283553d6d5fSMaxime Bizon pcmcia_parse_events(&skt->socket, events); 284553d6d5fSMaxime Bizon 285553d6d5fSMaxime Bizon mod_timer(&skt->timer, 286553d6d5fSMaxime Bizon jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE)); 287553d6d5fSMaxime Bizon } 288553d6d5fSMaxime Bizon 289553d6d5fSMaxime Bizon static int bcm63xx_pcmcia_set_io_map(struct pcmcia_socket *sock, 290553d6d5fSMaxime Bizon struct pccard_io_map *map) 291553d6d5fSMaxime Bizon { 292553d6d5fSMaxime Bizon /* this doesn't seem to be called by pcmcia layer if static 293553d6d5fSMaxime Bizon * mapping is used */ 294553d6d5fSMaxime Bizon return 0; 295553d6d5fSMaxime Bizon } 296553d6d5fSMaxime Bizon 297553d6d5fSMaxime Bizon static int bcm63xx_pcmcia_set_mem_map(struct pcmcia_socket *sock, 298553d6d5fSMaxime Bizon struct pccard_mem_map *map) 299553d6d5fSMaxime Bizon { 300553d6d5fSMaxime Bizon struct bcm63xx_pcmcia_socket *skt; 301553d6d5fSMaxime Bizon struct resource *res; 302553d6d5fSMaxime Bizon 303553d6d5fSMaxime Bizon skt = sock->driver_data; 304553d6d5fSMaxime Bizon if (map->flags & MAP_ATTRIB) 305553d6d5fSMaxime Bizon res = skt->attr_res; 306553d6d5fSMaxime Bizon else 307553d6d5fSMaxime Bizon res = skt->common_res; 308553d6d5fSMaxime Bizon 309553d6d5fSMaxime Bizon map->static_start = res->start + map->card_start; 310553d6d5fSMaxime Bizon return 0; 311553d6d5fSMaxime Bizon } 312553d6d5fSMaxime Bizon 313553d6d5fSMaxime Bizon static struct pccard_operations bcm63xx_pcmcia_operations = { 314553d6d5fSMaxime Bizon .init = bcm63xx_pcmcia_sock_init, 315553d6d5fSMaxime Bizon .suspend = bcm63xx_pcmcia_suspend, 316553d6d5fSMaxime Bizon .get_status = bcm63xx_pcmcia_get_status, 317553d6d5fSMaxime Bizon .set_socket = bcm63xx_pcmcia_set_socket, 318553d6d5fSMaxime Bizon .set_io_map = bcm63xx_pcmcia_set_io_map, 319553d6d5fSMaxime Bizon .set_mem_map = bcm63xx_pcmcia_set_mem_map, 320553d6d5fSMaxime Bizon }; 321553d6d5fSMaxime Bizon 322553d6d5fSMaxime Bizon /* 323553d6d5fSMaxime Bizon * register pcmcia socket to core 324553d6d5fSMaxime Bizon */ 325553d6d5fSMaxime Bizon static int __devinit bcm63xx_drv_pcmcia_probe(struct platform_device *pdev) 326553d6d5fSMaxime Bizon { 327553d6d5fSMaxime Bizon struct bcm63xx_pcmcia_socket *skt; 328553d6d5fSMaxime Bizon struct pcmcia_socket *sock; 329553d6d5fSMaxime Bizon struct resource *res, *irq_res; 330553d6d5fSMaxime Bizon unsigned int regmem_size = 0, iomem_size = 0; 331553d6d5fSMaxime Bizon u32 val; 332553d6d5fSMaxime Bizon int ret; 333553d6d5fSMaxime Bizon 334553d6d5fSMaxime Bizon skt = kzalloc(sizeof(*skt), GFP_KERNEL); 335553d6d5fSMaxime Bizon if (!skt) 336553d6d5fSMaxime Bizon return -ENOMEM; 337553d6d5fSMaxime Bizon spin_lock_init(&skt->lock); 338553d6d5fSMaxime Bizon sock = &skt->socket; 339553d6d5fSMaxime Bizon sock->driver_data = skt; 340553d6d5fSMaxime Bizon 341553d6d5fSMaxime Bizon /* make sure we have all resources we need */ 342553d6d5fSMaxime Bizon skt->common_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 343553d6d5fSMaxime Bizon skt->attr_res = platform_get_resource(pdev, IORESOURCE_MEM, 2); 344553d6d5fSMaxime Bizon irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 345553d6d5fSMaxime Bizon skt->pd = pdev->dev.platform_data; 346553d6d5fSMaxime Bizon if (!skt->common_res || !skt->attr_res || !irq_res || !skt->pd) { 347553d6d5fSMaxime Bizon ret = -EINVAL; 348553d6d5fSMaxime Bizon goto err; 349553d6d5fSMaxime Bizon } 350553d6d5fSMaxime Bizon 351553d6d5fSMaxime Bizon /* remap pcmcia registers */ 352553d6d5fSMaxime Bizon res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 353553d6d5fSMaxime Bizon regmem_size = resource_size(res); 354553d6d5fSMaxime Bizon if (!request_mem_region(res->start, regmem_size, "bcm63xx_pcmcia")) { 355553d6d5fSMaxime Bizon ret = -EINVAL; 356553d6d5fSMaxime Bizon goto err; 357553d6d5fSMaxime Bizon } 358553d6d5fSMaxime Bizon skt->reg_res = res; 359553d6d5fSMaxime Bizon 360553d6d5fSMaxime Bizon skt->base = ioremap(res->start, regmem_size); 361553d6d5fSMaxime Bizon if (!skt->base) { 362553d6d5fSMaxime Bizon ret = -ENOMEM; 363553d6d5fSMaxime Bizon goto err; 364553d6d5fSMaxime Bizon } 365553d6d5fSMaxime Bizon 366553d6d5fSMaxime Bizon /* remap io registers */ 367553d6d5fSMaxime Bizon res = platform_get_resource(pdev, IORESOURCE_MEM, 3); 368553d6d5fSMaxime Bizon iomem_size = resource_size(res); 369553d6d5fSMaxime Bizon skt->io_base = ioremap(res->start, iomem_size); 370553d6d5fSMaxime Bizon if (!skt->io_base) { 371553d6d5fSMaxime Bizon ret = -ENOMEM; 372553d6d5fSMaxime Bizon goto err; 373553d6d5fSMaxime Bizon } 374553d6d5fSMaxime Bizon 375553d6d5fSMaxime Bizon /* resources are static */ 376553d6d5fSMaxime Bizon sock->resource_ops = &pccard_static_ops; 377553d6d5fSMaxime Bizon sock->ops = &bcm63xx_pcmcia_operations; 378553d6d5fSMaxime Bizon sock->owner = THIS_MODULE; 379553d6d5fSMaxime Bizon sock->dev.parent = &pdev->dev; 380553d6d5fSMaxime Bizon sock->features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD; 381553d6d5fSMaxime Bizon sock->io_offset = (unsigned long)skt->io_base; 382553d6d5fSMaxime Bizon sock->pci_irq = irq_res->start; 383553d6d5fSMaxime Bizon 384553d6d5fSMaxime Bizon #ifdef CONFIG_CARDBUS 385553d6d5fSMaxime Bizon sock->cb_dev = bcm63xx_cb_dev; 386553d6d5fSMaxime Bizon if (bcm63xx_cb_dev) 387553d6d5fSMaxime Bizon sock->features |= SS_CAP_CARDBUS; 388553d6d5fSMaxime Bizon #endif 389553d6d5fSMaxime Bizon 390553d6d5fSMaxime Bizon /* assume common & attribute memory have the same size */ 391553d6d5fSMaxime Bizon sock->map_size = resource_size(skt->common_res); 392553d6d5fSMaxime Bizon 393553d6d5fSMaxime Bizon /* initialize polling timer */ 394553d6d5fSMaxime Bizon setup_timer(&skt->timer, bcm63xx_pcmcia_poll, (unsigned long)skt); 395553d6d5fSMaxime Bizon 396553d6d5fSMaxime Bizon /* initialize pcmcia control register, drive VS[12] to 0, 397553d6d5fSMaxime Bizon * leave CB IDSEL to the old value since it is set by the PCI 398553d6d5fSMaxime Bizon * layer */ 399553d6d5fSMaxime Bizon val = pcmcia_readl(skt, PCMCIA_C1_REG); 400553d6d5fSMaxime Bizon val &= PCMCIA_C1_CBIDSEL_MASK; 401553d6d5fSMaxime Bizon val |= PCMCIA_C1_EN_PCMCIA_GPIO_MASK; 402553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C1_REG); 403553d6d5fSMaxime Bizon 404553d6d5fSMaxime Bizon /* 405553d6d5fSMaxime Bizon * Hardware has only one set of timings registers, not one for 406553d6d5fSMaxime Bizon * each memory access type, so we configure them for the 407553d6d5fSMaxime Bizon * slowest one: attribute memory. 408553d6d5fSMaxime Bizon */ 409553d6d5fSMaxime Bizon val = PCMCIA_C2_DATA16_MASK; 410553d6d5fSMaxime Bizon val |= 10 << PCMCIA_C2_RWCOUNT_SHIFT; 411553d6d5fSMaxime Bizon val |= 6 << PCMCIA_C2_INACTIVE_SHIFT; 412553d6d5fSMaxime Bizon val |= 3 << PCMCIA_C2_SETUP_SHIFT; 413553d6d5fSMaxime Bizon val |= 3 << PCMCIA_C2_HOLD_SHIFT; 414553d6d5fSMaxime Bizon pcmcia_writel(skt, val, PCMCIA_C2_REG); 415553d6d5fSMaxime Bizon 416553d6d5fSMaxime Bizon ret = pcmcia_register_socket(sock); 417553d6d5fSMaxime Bizon if (ret) 418553d6d5fSMaxime Bizon goto err; 419553d6d5fSMaxime Bizon 420553d6d5fSMaxime Bizon /* start polling socket */ 421553d6d5fSMaxime Bizon mod_timer(&skt->timer, 422553d6d5fSMaxime Bizon jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE)); 423553d6d5fSMaxime Bizon 424553d6d5fSMaxime Bizon platform_set_drvdata(pdev, skt); 425553d6d5fSMaxime Bizon return 0; 426553d6d5fSMaxime Bizon 427553d6d5fSMaxime Bizon err: 428553d6d5fSMaxime Bizon if (skt->io_base) 429553d6d5fSMaxime Bizon iounmap(skt->io_base); 430553d6d5fSMaxime Bizon if (skt->base) 431553d6d5fSMaxime Bizon iounmap(skt->base); 432553d6d5fSMaxime Bizon if (skt->reg_res) 433553d6d5fSMaxime Bizon release_mem_region(skt->reg_res->start, regmem_size); 434553d6d5fSMaxime Bizon kfree(skt); 435553d6d5fSMaxime Bizon return ret; 436553d6d5fSMaxime Bizon } 437553d6d5fSMaxime Bizon 438553d6d5fSMaxime Bizon static int __devexit bcm63xx_drv_pcmcia_remove(struct platform_device *pdev) 439553d6d5fSMaxime Bizon { 440553d6d5fSMaxime Bizon struct bcm63xx_pcmcia_socket *skt; 441553d6d5fSMaxime Bizon struct resource *res; 442553d6d5fSMaxime Bizon 443553d6d5fSMaxime Bizon skt = platform_get_drvdata(pdev); 444553d6d5fSMaxime Bizon del_timer_sync(&skt->timer); 445553d6d5fSMaxime Bizon iounmap(skt->base); 446553d6d5fSMaxime Bizon iounmap(skt->io_base); 447553d6d5fSMaxime Bizon res = skt->reg_res; 448553d6d5fSMaxime Bizon release_mem_region(res->start, resource_size(res)); 449553d6d5fSMaxime Bizon kfree(skt); 450553d6d5fSMaxime Bizon return 0; 451553d6d5fSMaxime Bizon } 452553d6d5fSMaxime Bizon 453553d6d5fSMaxime Bizon struct platform_driver bcm63xx_pcmcia_driver = { 454553d6d5fSMaxime Bizon .probe = bcm63xx_drv_pcmcia_probe, 455553d6d5fSMaxime Bizon .remove = __devexit_p(bcm63xx_drv_pcmcia_remove), 456553d6d5fSMaxime Bizon .driver = { 457553d6d5fSMaxime Bizon .name = "bcm63xx_pcmcia", 458553d6d5fSMaxime Bizon .owner = THIS_MODULE, 459553d6d5fSMaxime Bizon }, 460553d6d5fSMaxime Bizon }; 461553d6d5fSMaxime Bizon 462553d6d5fSMaxime Bizon #ifdef CONFIG_CARDBUS 463553d6d5fSMaxime Bizon static int __devinit bcm63xx_cb_probe(struct pci_dev *dev, 464553d6d5fSMaxime Bizon const struct pci_device_id *id) 465553d6d5fSMaxime Bizon { 466553d6d5fSMaxime Bizon /* keep pci device */ 467553d6d5fSMaxime Bizon bcm63xx_cb_dev = dev; 468553d6d5fSMaxime Bizon return platform_driver_register(&bcm63xx_pcmcia_driver); 469553d6d5fSMaxime Bizon } 470553d6d5fSMaxime Bizon 471553d6d5fSMaxime Bizon static void __devexit bcm63xx_cb_exit(struct pci_dev *dev) 472553d6d5fSMaxime Bizon { 473553d6d5fSMaxime Bizon platform_driver_unregister(&bcm63xx_pcmcia_driver); 474553d6d5fSMaxime Bizon bcm63xx_cb_dev = NULL; 475553d6d5fSMaxime Bizon } 476553d6d5fSMaxime Bizon 477553d6d5fSMaxime Bizon static struct pci_device_id bcm63xx_cb_table[] = { 478553d6d5fSMaxime Bizon { 479553d6d5fSMaxime Bizon .vendor = PCI_VENDOR_ID_BROADCOM, 480553d6d5fSMaxime Bizon .device = BCM6348_CPU_ID, 481553d6d5fSMaxime Bizon .subvendor = PCI_VENDOR_ID_BROADCOM, 482553d6d5fSMaxime Bizon .subdevice = PCI_ANY_ID, 483553d6d5fSMaxime Bizon .class = PCI_CLASS_BRIDGE_CARDBUS << 8, 484553d6d5fSMaxime Bizon .class_mask = ~0, 485553d6d5fSMaxime Bizon }, 486553d6d5fSMaxime Bizon 487553d6d5fSMaxime Bizon { 488553d6d5fSMaxime Bizon .vendor = PCI_VENDOR_ID_BROADCOM, 489553d6d5fSMaxime Bizon .device = BCM6358_CPU_ID, 490553d6d5fSMaxime Bizon .subvendor = PCI_VENDOR_ID_BROADCOM, 491553d6d5fSMaxime Bizon .subdevice = PCI_ANY_ID, 492553d6d5fSMaxime Bizon .class = PCI_CLASS_BRIDGE_CARDBUS << 8, 493553d6d5fSMaxime Bizon .class_mask = ~0, 494553d6d5fSMaxime Bizon }, 495553d6d5fSMaxime Bizon 496553d6d5fSMaxime Bizon { }, 497553d6d5fSMaxime Bizon }; 498553d6d5fSMaxime Bizon 499553d6d5fSMaxime Bizon MODULE_DEVICE_TABLE(pci, bcm63xx_cb_table); 500553d6d5fSMaxime Bizon 501553d6d5fSMaxime Bizon static struct pci_driver bcm63xx_cardbus_driver = { 502553d6d5fSMaxime Bizon .name = "bcm63xx_cardbus", 503553d6d5fSMaxime Bizon .id_table = bcm63xx_cb_table, 504553d6d5fSMaxime Bizon .probe = bcm63xx_cb_probe, 505553d6d5fSMaxime Bizon .remove = __devexit_p(bcm63xx_cb_exit), 506553d6d5fSMaxime Bizon }; 507553d6d5fSMaxime Bizon #endif 508553d6d5fSMaxime Bizon 509553d6d5fSMaxime Bizon /* 510553d6d5fSMaxime Bizon * if cardbus support is enabled, register our platform device after 511553d6d5fSMaxime Bizon * our fake cardbus bridge has been registered 512553d6d5fSMaxime Bizon */ 513553d6d5fSMaxime Bizon static int __init bcm63xx_pcmcia_init(void) 514553d6d5fSMaxime Bizon { 515553d6d5fSMaxime Bizon #ifdef CONFIG_CARDBUS 516553d6d5fSMaxime Bizon return pci_register_driver(&bcm63xx_cardbus_driver); 517553d6d5fSMaxime Bizon #else 518553d6d5fSMaxime Bizon return platform_driver_register(&bcm63xx_pcmcia_driver); 519553d6d5fSMaxime Bizon #endif 520553d6d5fSMaxime Bizon } 521553d6d5fSMaxime Bizon 522553d6d5fSMaxime Bizon static void __exit bcm63xx_pcmcia_exit(void) 523553d6d5fSMaxime Bizon { 524553d6d5fSMaxime Bizon #ifdef CONFIG_CARDBUS 525553d6d5fSMaxime Bizon return pci_unregister_driver(&bcm63xx_cardbus_driver); 526553d6d5fSMaxime Bizon #else 527553d6d5fSMaxime Bizon platform_driver_unregister(&bcm63xx_pcmcia_driver); 528553d6d5fSMaxime Bizon #endif 529553d6d5fSMaxime Bizon } 530553d6d5fSMaxime Bizon 531553d6d5fSMaxime Bizon module_init(bcm63xx_pcmcia_init); 532553d6d5fSMaxime Bizon module_exit(bcm63xx_pcmcia_exit); 533553d6d5fSMaxime Bizon 534553d6d5fSMaxime Bizon MODULE_LICENSE("GPL"); 535553d6d5fSMaxime Bizon MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>"); 536553d6d5fSMaxime Bizon MODULE_DESCRIPTION("Linux PCMCIA Card Services: bcm63xx Socket Controller"); 537