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