linux/drivers/pcmcia/bcm63xx_pcmcia.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
   7 */
   8
   9#include <linux/kernel.h>
  10#include <linux/module.h>
  11#include <linux/ioport.h>
  12#include <linux/timer.h>
  13#include <linux/platform_device.h>
  14#include <linux/slab.h>
  15#include <linux/delay.h>
  16#include <linux/pci.h>
  17#include <linux/gpio.h>
  18
  19#include <bcm63xx_regs.h>
  20#include <bcm63xx_io.h>
  21#include "bcm63xx_pcmcia.h"
  22
  23#define PFX     "bcm63xx_pcmcia: "
  24
  25#ifdef CONFIG_CARDBUS
  26/* if cardbus is used, platform device needs reference to actual pci
  27 * device */
  28static struct pci_dev *bcm63xx_cb_dev;
  29#endif
  30
  31/*
  32 * read/write helper for pcmcia regs
  33 */
  34static inline u32 pcmcia_readl(struct bcm63xx_pcmcia_socket *skt, u32 off)
  35{
  36        return bcm_readl(skt->base + off);
  37}
  38
  39static inline void pcmcia_writel(struct bcm63xx_pcmcia_socket *skt,
  40                                 u32 val, u32 off)
  41{
  42        bcm_writel(val, skt->base + off);
  43}
  44
  45/*
  46 * This callback should (re-)initialise the socket, turn on status
  47 * interrupts and PCMCIA bus, and wait for power to stabilise so that
  48 * the card status signals report correctly.
  49 *
  50 * Hardware cannot do that.
  51 */
  52static int bcm63xx_pcmcia_sock_init(struct pcmcia_socket *sock)
  53{
  54        return 0;
  55}
  56
  57/*
  58 * This callback should remove power on the socket, disable IRQs from
  59 * the card, turn off status interrupts, and disable the PCMCIA bus.
  60 *
  61 * Hardware cannot do that.
  62 */
  63static int bcm63xx_pcmcia_suspend(struct pcmcia_socket *sock)
  64{
  65        return 0;
  66}
  67
  68/*
  69 * Implements the set_socket() operation for the in-kernel PCMCIA
  70 * service (formerly SS_SetSocket in Card Services). We more or
  71 * less punt all of this work and let the kernel handle the details
  72 * of power configuration, reset, &c. We also record the value of
  73 * `state' in order to regurgitate it to the PCMCIA core later.
  74 */
  75static int bcm63xx_pcmcia_set_socket(struct pcmcia_socket *sock,
  76                                     socket_state_t *state)
  77{
  78        struct bcm63xx_pcmcia_socket *skt;
  79        unsigned long flags;
  80        u32 val;
  81
  82        skt = sock->driver_data;
  83
  84        spin_lock_irqsave(&skt->lock, flags);
  85
  86        /* note: hardware cannot control socket power, so we will
  87         * always report SS_POWERON */
  88
  89        /* apply socket reset */
  90        val = pcmcia_readl(skt, PCMCIA_C1_REG);
  91        if (state->flags & SS_RESET)
  92                val |= PCMCIA_C1_RESET_MASK;
  93        else
  94                val &= ~PCMCIA_C1_RESET_MASK;
  95
  96        /* reverse reset logic for cardbus card */
  97        if (skt->card_detected && (skt->card_type & CARD_CARDBUS))
  98                val ^= PCMCIA_C1_RESET_MASK;
  99
 100        pcmcia_writel(skt, val, PCMCIA_C1_REG);
 101
 102        /* keep requested state for event reporting */
 103        skt->requested_state = *state;
 104
 105        spin_unlock_irqrestore(&skt->lock, flags);
 106
 107        return 0;
 108}
 109
 110/*
 111 * identity cardtype from VS[12] input, CD[12] input while only VS2 is
 112 * floating, and CD[12] input while only VS1 is floating
 113 */
 114enum {
 115        IN_VS1 = (1 << 0),
 116        IN_VS2 = (1 << 1),
 117        IN_CD1_VS2H = (1 << 2),
 118        IN_CD2_VS2H = (1 << 3),
 119        IN_CD1_VS1H = (1 << 4),
 120        IN_CD2_VS1H = (1 << 5),
 121};
 122
 123static const u8 vscd_to_cardtype[] = {
 124
 125        /* VS1 float, VS2 float */
 126        [IN_VS1 | IN_VS2] = (CARD_PCCARD | CARD_5V),
 127
 128        /* VS1 grounded, VS2 float */
 129        [IN_VS2] = (CARD_PCCARD | CARD_5V | CARD_3V),
 130
 131        /* VS1 grounded, VS2 grounded */
 132        [0] = (CARD_PCCARD | CARD_5V | CARD_3V | CARD_XV),
 133
 134        /* VS1 tied to CD1, VS2 float */
 135        [IN_VS1 | IN_VS2 | IN_CD1_VS1H] = (CARD_CARDBUS | CARD_3V),
 136
 137        /* VS1 grounded, VS2 tied to CD2 */
 138        [IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V | CARD_XV),
 139
 140        /* VS1 tied to CD2, VS2 grounded */
 141        [IN_VS1 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_3V | CARD_XV | CARD_YV),
 142
 143        /* VS1 float, VS2 grounded */
 144        [IN_VS1] = (CARD_PCCARD | CARD_XV),
 145
 146        /* VS1 float, VS2 tied to CD2 */
 147        [IN_VS1 | IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V),
 148
 149        /* VS1 float, VS2 tied to CD1 */
 150        [IN_VS1 | IN_VS2 | IN_CD1_VS2H] = (CARD_CARDBUS | CARD_XV | CARD_YV),
 151
 152        /* VS1 tied to CD2, VS2 float */
 153        [IN_VS1 | IN_VS2 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_YV),
 154
 155        /* VS2 grounded, VS1 is tied to CD1, CD2 is grounded */
 156        [IN_VS1 | IN_CD1_VS1H] = 0, /* ignore cardbay */
 157};
 158
 159/*
 160 * poll hardware to check card insertion status
 161 */
 162static unsigned int __get_socket_status(struct bcm63xx_pcmcia_socket *skt)
 163{
 164        unsigned int stat;
 165        u32 val;
 166
 167        stat = 0;
 168
 169        /* check CD for card presence */
 170        val = pcmcia_readl(skt, PCMCIA_C1_REG);
 171
 172        if (!(val & PCMCIA_C1_CD1_MASK) && !(val & PCMCIA_C1_CD2_MASK))
 173                stat |= SS_DETECT;
 174
 175        /* if new insertion, detect cardtype */
 176        if ((stat & SS_DETECT) && !skt->card_detected) {
 177                unsigned int stat = 0;
 178
 179                /* float VS1, float VS2 */
 180                val |= PCMCIA_C1_VS1OE_MASK;
 181                val |= PCMCIA_C1_VS2OE_MASK;
 182                pcmcia_writel(skt, val, PCMCIA_C1_REG);
 183
 184                /* wait for output to stabilize and read VS[12] */
 185                udelay(10);
 186                val = pcmcia_readl(skt, PCMCIA_C1_REG);
 187                stat |= (val & PCMCIA_C1_VS1_MASK) ? IN_VS1 : 0;
 188                stat |= (val & PCMCIA_C1_VS2_MASK) ? IN_VS2 : 0;
 189
 190                /* drive VS1 low, float VS2 */
 191                val &= ~PCMCIA_C1_VS1OE_MASK;
 192                val |= PCMCIA_C1_VS2OE_MASK;
 193                pcmcia_writel(skt, val, PCMCIA_C1_REG);
 194
 195                /* wait for output to stabilize and read CD[12] */
 196                udelay(10);
 197                val = pcmcia_readl(skt, PCMCIA_C1_REG);
 198                stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS2H : 0;
 199                stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS2H : 0;
 200
 201                /* float VS1, drive VS2 low */
 202                val |= PCMCIA_C1_VS1OE_MASK;
 203                val &= ~PCMCIA_C1_VS2OE_MASK;
 204                pcmcia_writel(skt, val, PCMCIA_C1_REG);
 205
 206                /* wait for output to stabilize and read CD[12] */
 207                udelay(10);
 208                val = pcmcia_readl(skt, PCMCIA_C1_REG);
 209                stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS1H : 0;
 210                stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS1H : 0;
 211
 212                /* guess cardtype from all this */
 213                skt->card_type = vscd_to_cardtype[stat];
 214                if (!skt->card_type)
 215                        dev_err(&skt->socket.dev, "unsupported card type\n");
 216
 217                /* drive both VS pin to 0 again */
 218                val &= ~(PCMCIA_C1_VS1OE_MASK | PCMCIA_C1_VS2OE_MASK);
 219
 220                /* enable correct logic */
 221                val &= ~(PCMCIA_C1_EN_PCMCIA_MASK | PCMCIA_C1_EN_CARDBUS_MASK);
 222                if (skt->card_type & CARD_PCCARD)
 223                        val |= PCMCIA_C1_EN_PCMCIA_MASK;
 224                else
 225                        val |= PCMCIA_C1_EN_CARDBUS_MASK;
 226
 227                pcmcia_writel(skt, val, PCMCIA_C1_REG);
 228        }
 229        skt->card_detected = (stat & SS_DETECT) ? 1 : 0;
 230
 231        /* report card type/voltage */
 232        if (skt->card_type & CARD_CARDBUS)
 233                stat |= SS_CARDBUS;
 234        if (skt->card_type & CARD_3V)
 235                stat |= SS_3VCARD;
 236        if (skt->card_type & CARD_XV)
 237                stat |= SS_XVCARD;
 238        stat |= SS_POWERON;
 239
 240        if (gpio_get_value(skt->pd->ready_gpio))
 241                stat |= SS_READY;
 242
 243        return stat;
 244}
 245
 246/*
 247 * core request to get current socket status
 248 */
 249static int bcm63xx_pcmcia_get_status(struct pcmcia_socket *sock,
 250                                     unsigned int *status)
 251{
 252        struct bcm63xx_pcmcia_socket *skt;
 253
 254        skt = sock->driver_data;
 255
 256        spin_lock_bh(&skt->lock);
 257        *status = __get_socket_status(skt);
 258        spin_unlock_bh(&skt->lock);
 259
 260        return 0;
 261}
 262
 263/*
 264 * socket polling timer callback
 265 */
 266static void bcm63xx_pcmcia_poll(unsigned long data)
 267{
 268        struct bcm63xx_pcmcia_socket *skt;
 269        unsigned int stat, events;
 270
 271        skt = (struct bcm63xx_pcmcia_socket *)data;
 272
 273        spin_lock_bh(&skt->lock);
 274
 275        stat = __get_socket_status(skt);
 276
 277        /* keep only changed bits, and mask with required one from the
 278         * core */
 279        events = (stat ^ skt->old_status) & skt->requested_state.csc_mask;
 280        skt->old_status = stat;
 281        spin_unlock_bh(&skt->lock);
 282
 283        if (events)
 284                pcmcia_parse_events(&skt->socket, events);
 285
 286        mod_timer(&skt->timer,
 287                  jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE));
 288}
 289
 290static int bcm63xx_pcmcia_set_io_map(struct pcmcia_socket *sock,
 291                                     struct pccard_io_map *map)
 292{
 293        /* this doesn't seem to be called by pcmcia layer if static
 294         * mapping is used */
 295        return 0;
 296}
 297
 298static int bcm63xx_pcmcia_set_mem_map(struct pcmcia_socket *sock,
 299                                      struct pccard_mem_map *map)
 300{
 301        struct bcm63xx_pcmcia_socket *skt;
 302        struct resource *res;
 303
 304        skt = sock->driver_data;
 305        if (map->flags & MAP_ATTRIB)
 306                res = skt->attr_res;
 307        else
 308                res = skt->common_res;
 309
 310        map->static_start = res->start + map->card_start;
 311        return 0;
 312}
 313
 314static struct pccard_operations bcm63xx_pcmcia_operations = {
 315        .init                   = bcm63xx_pcmcia_sock_init,
 316        .suspend                = bcm63xx_pcmcia_suspend,
 317        .get_status             = bcm63xx_pcmcia_get_status,
 318        .set_socket             = bcm63xx_pcmcia_set_socket,
 319        .set_io_map             = bcm63xx_pcmcia_set_io_map,
 320        .set_mem_map            = bcm63xx_pcmcia_set_mem_map,
 321};
 322
 323/*
 324 * register pcmcia socket to core
 325 */
 326static int bcm63xx_drv_pcmcia_probe(struct platform_device *pdev)
 327{
 328        struct bcm63xx_pcmcia_socket *skt;
 329        struct pcmcia_socket *sock;
 330        struct resource *res, *irq_res;
 331        unsigned int regmem_size = 0, iomem_size = 0;
 332        u32 val;
 333        int ret;
 334
 335        skt = kzalloc(sizeof(*skt), GFP_KERNEL);
 336        if (!skt)
 337                return -ENOMEM;
 338        spin_lock_init(&skt->lock);
 339        sock = &skt->socket;
 340        sock->driver_data = skt;
 341
 342        /* make sure we have all resources we need */
 343        skt->common_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 344        skt->attr_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
 345        irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 346        skt->pd = pdev->dev.platform_data;
 347        if (!skt->common_res || !skt->attr_res || !irq_res || !skt->pd) {
 348                ret = -EINVAL;
 349                goto err;
 350        }
 351
 352        /* remap pcmcia registers */
 353        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 354        regmem_size = resource_size(res);
 355        if (!request_mem_region(res->start, regmem_size, "bcm63xx_pcmcia")) {
 356                ret = -EINVAL;
 357                goto err;
 358        }
 359        skt->reg_res = res;
 360
 361        skt->base = ioremap(res->start, regmem_size);
 362        if (!skt->base) {
 363                ret = -ENOMEM;
 364                goto err;
 365        }
 366
 367        /* remap io registers */
 368        res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
 369        iomem_size = resource_size(res);
 370        skt->io_base = ioremap(res->start, iomem_size);
 371        if (!skt->io_base) {
 372                ret = -ENOMEM;
 373                goto err;
 374        }
 375
 376        /* resources are static */
 377        sock->resource_ops = &pccard_static_ops;
 378        sock->ops = &bcm63xx_pcmcia_operations;
 379        sock->owner = THIS_MODULE;
 380        sock->dev.parent = &pdev->dev;
 381        sock->features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
 382        sock->io_offset = (unsigned long)skt->io_base;
 383        sock->pci_irq = irq_res->start;
 384
 385#ifdef CONFIG_CARDBUS
 386        sock->cb_dev = bcm63xx_cb_dev;
 387        if (bcm63xx_cb_dev)
 388                sock->features |= SS_CAP_CARDBUS;
 389#endif
 390
 391        /* assume common & attribute memory have the same size */
 392        sock->map_size = resource_size(skt->common_res);
 393
 394        /* initialize polling timer */
 395        setup_timer(&skt->timer, bcm63xx_pcmcia_poll, (unsigned long)skt);
 396
 397        /* initialize  pcmcia  control register,  drive  VS[12] to  0,
 398         * leave CB IDSEL to the old  value since it is set by the PCI
 399         * layer */
 400        val = pcmcia_readl(skt, PCMCIA_C1_REG);
 401        val &= PCMCIA_C1_CBIDSEL_MASK;
 402        val |= PCMCIA_C1_EN_PCMCIA_GPIO_MASK;
 403        pcmcia_writel(skt, val, PCMCIA_C1_REG);
 404
 405        /*
 406         * Hardware has only one set of timings registers, not one for
 407         * each memory access type, so we configure them for the
 408         * slowest one: attribute memory.
 409         */
 410        val = PCMCIA_C2_DATA16_MASK;
 411        val |= 10 << PCMCIA_C2_RWCOUNT_SHIFT;
 412        val |= 6 << PCMCIA_C2_INACTIVE_SHIFT;
 413        val |= 3 << PCMCIA_C2_SETUP_SHIFT;
 414        val |= 3 << PCMCIA_C2_HOLD_SHIFT;
 415        pcmcia_writel(skt, val, PCMCIA_C2_REG);
 416
 417        ret = pcmcia_register_socket(sock);
 418        if (ret)
 419                goto err;
 420
 421        /* start polling socket */
 422        mod_timer(&skt->timer,
 423                  jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE));
 424
 425        platform_set_drvdata(pdev, skt);
 426        return 0;
 427
 428err:
 429        if (skt->io_base)
 430                iounmap(skt->io_base);
 431        if (skt->base)
 432                iounmap(skt->base);
 433        if (skt->reg_res)
 434                release_mem_region(skt->reg_res->start, regmem_size);
 435        kfree(skt);
 436        return ret;
 437}
 438
 439static int bcm63xx_drv_pcmcia_remove(struct platform_device *pdev)
 440{
 441        struct bcm63xx_pcmcia_socket *skt;
 442        struct resource *res;
 443
 444        skt = platform_get_drvdata(pdev);
 445        del_timer_sync(&skt->timer);
 446        iounmap(skt->base);
 447        iounmap(skt->io_base);
 448        res = skt->reg_res;
 449        release_mem_region(res->start, resource_size(res));
 450        kfree(skt);
 451        return 0;
 452}
 453
 454struct platform_driver bcm63xx_pcmcia_driver = {
 455        .probe  = bcm63xx_drv_pcmcia_probe,
 456        .remove = bcm63xx_drv_pcmcia_remove,
 457        .driver = {
 458                .name   = "bcm63xx_pcmcia",
 459                .owner  = THIS_MODULE,
 460        },
 461};
 462
 463#ifdef CONFIG_CARDBUS
 464static int bcm63xx_cb_probe(struct pci_dev *dev,
 465                                      const struct pci_device_id *id)
 466{
 467        /* keep pci device */
 468        bcm63xx_cb_dev = dev;
 469        return platform_driver_register(&bcm63xx_pcmcia_driver);
 470}
 471
 472static void bcm63xx_cb_exit(struct pci_dev *dev)
 473{
 474        platform_driver_unregister(&bcm63xx_pcmcia_driver);
 475        bcm63xx_cb_dev = NULL;
 476}
 477
 478static DEFINE_PCI_DEVICE_TABLE(bcm63xx_cb_table) = {
 479        {
 480                .vendor         = PCI_VENDOR_ID_BROADCOM,
 481                .device         = BCM6348_CPU_ID,
 482                .subvendor      = PCI_VENDOR_ID_BROADCOM,
 483                .subdevice      = PCI_ANY_ID,
 484                .class          = PCI_CLASS_BRIDGE_CARDBUS << 8,
 485                .class_mask     = ~0,
 486        },
 487
 488        {
 489                .vendor         = PCI_VENDOR_ID_BROADCOM,
 490                .device         = BCM6358_CPU_ID,
 491                .subvendor      = PCI_VENDOR_ID_BROADCOM,
 492                .subdevice      = PCI_ANY_ID,
 493                .class          = PCI_CLASS_BRIDGE_CARDBUS << 8,
 494                .class_mask     = ~0,
 495        },
 496
 497        { },
 498};
 499
 500MODULE_DEVICE_TABLE(pci, bcm63xx_cb_table);
 501
 502static struct pci_driver bcm63xx_cardbus_driver = {
 503        .name           = "bcm63xx_cardbus",
 504        .id_table       = bcm63xx_cb_table,
 505        .probe          = bcm63xx_cb_probe,
 506        .remove         = bcm63xx_cb_exit,
 507};
 508#endif
 509
 510/*
 511 * if cardbus support is enabled, register our platform device after
 512 * our fake cardbus bridge has been registered
 513 */
 514static int __init bcm63xx_pcmcia_init(void)
 515{
 516#ifdef CONFIG_CARDBUS
 517        return pci_register_driver(&bcm63xx_cardbus_driver);
 518#else
 519        return platform_driver_register(&bcm63xx_pcmcia_driver);
 520#endif
 521}
 522
 523static void __exit bcm63xx_pcmcia_exit(void)
 524{
 525#ifdef CONFIG_CARDBUS
 526        return pci_unregister_driver(&bcm63xx_cardbus_driver);
 527#else
 528        platform_driver_unregister(&bcm63xx_pcmcia_driver);
 529#endif
 530}
 531
 532module_init(bcm63xx_pcmcia_init);
 533module_exit(bcm63xx_pcmcia_exit);
 534
 535MODULE_LICENSE("GPL");
 536MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
 537MODULE_DESCRIPTION("Linux PCMCIA Card Services: bcm63xx Socket Controller");
 538
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.