0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/ioport.h>
0012 #include <linux/timer.h>
0013 #include <linux/platform_device.h>
0014 #include <linux/slab.h>
0015 #include <linux/delay.h>
0016 #include <linux/pci.h>
0017 #include <linux/gpio.h>
0018
0019 #include <bcm63xx_regs.h>
0020 #include <bcm63xx_io.h>
0021 #include "bcm63xx_pcmcia.h"
0022
0023 #define PFX "bcm63xx_pcmcia: "
0024
0025 #ifdef CONFIG_CARDBUS
0026
0027
0028 static struct pci_dev *bcm63xx_cb_dev;
0029 #endif
0030
0031
0032
0033
0034 static inline u32 pcmcia_readl(struct bcm63xx_pcmcia_socket *skt, u32 off)
0035 {
0036 return bcm_readl(skt->base + off);
0037 }
0038
0039 static inline void pcmcia_writel(struct bcm63xx_pcmcia_socket *skt,
0040 u32 val, u32 off)
0041 {
0042 bcm_writel(val, skt->base + off);
0043 }
0044
0045
0046
0047
0048
0049
0050
0051
0052 static int bcm63xx_pcmcia_sock_init(struct pcmcia_socket *sock)
0053 {
0054 return 0;
0055 }
0056
0057
0058
0059
0060
0061
0062
0063 static int bcm63xx_pcmcia_suspend(struct pcmcia_socket *sock)
0064 {
0065 return 0;
0066 }
0067
0068
0069
0070
0071
0072
0073
0074
0075 static int bcm63xx_pcmcia_set_socket(struct pcmcia_socket *sock,
0076 socket_state_t *state)
0077 {
0078 struct bcm63xx_pcmcia_socket *skt;
0079 unsigned long flags;
0080 u32 val;
0081
0082 skt = sock->driver_data;
0083
0084 spin_lock_irqsave(&skt->lock, flags);
0085
0086
0087
0088
0089
0090 val = pcmcia_readl(skt, PCMCIA_C1_REG);
0091 if (state->flags & SS_RESET)
0092 val |= PCMCIA_C1_RESET_MASK;
0093 else
0094 val &= ~PCMCIA_C1_RESET_MASK;
0095
0096
0097 if (skt->card_detected && (skt->card_type & CARD_CARDBUS))
0098 val ^= PCMCIA_C1_RESET_MASK;
0099
0100 pcmcia_writel(skt, val, PCMCIA_C1_REG);
0101
0102
0103 skt->requested_state = *state;
0104
0105 spin_unlock_irqrestore(&skt->lock, flags);
0106
0107 return 0;
0108 }
0109
0110
0111
0112
0113
0114 enum {
0115 IN_VS1 = (1 << 0),
0116 IN_VS2 = (1 << 1),
0117 IN_CD1_VS2H = (1 << 2),
0118 IN_CD2_VS2H = (1 << 3),
0119 IN_CD1_VS1H = (1 << 4),
0120 IN_CD2_VS1H = (1 << 5),
0121 };
0122
0123 static const u8 vscd_to_cardtype[] = {
0124
0125
0126 [IN_VS1 | IN_VS2] = (CARD_PCCARD | CARD_5V),
0127
0128
0129 [IN_VS2] = (CARD_PCCARD | CARD_5V | CARD_3V),
0130
0131
0132 [0] = (CARD_PCCARD | CARD_5V | CARD_3V | CARD_XV),
0133
0134
0135 [IN_VS1 | IN_VS2 | IN_CD1_VS1H] = (CARD_CARDBUS | CARD_3V),
0136
0137
0138 [IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V | CARD_XV),
0139
0140
0141 [IN_VS1 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_3V | CARD_XV | CARD_YV),
0142
0143
0144 [IN_VS1] = (CARD_PCCARD | CARD_XV),
0145
0146
0147 [IN_VS1 | IN_VS2 | IN_CD2_VS2H] = (CARD_CARDBUS | CARD_3V),
0148
0149
0150 [IN_VS1 | IN_VS2 | IN_CD1_VS2H] = (CARD_CARDBUS | CARD_XV | CARD_YV),
0151
0152
0153 [IN_VS1 | IN_VS2 | IN_CD2_VS1H] = (CARD_CARDBUS | CARD_YV),
0154
0155
0156 [IN_VS1 | IN_CD1_VS1H] = 0,
0157 };
0158
0159
0160
0161
0162 static unsigned int __get_socket_status(struct bcm63xx_pcmcia_socket *skt)
0163 {
0164 unsigned int stat;
0165 u32 val;
0166
0167 stat = 0;
0168
0169
0170 val = pcmcia_readl(skt, PCMCIA_C1_REG);
0171
0172 if (!(val & PCMCIA_C1_CD1_MASK) && !(val & PCMCIA_C1_CD2_MASK))
0173 stat |= SS_DETECT;
0174
0175
0176 if ((stat & SS_DETECT) && !skt->card_detected) {
0177 unsigned int stat = 0;
0178
0179
0180 val |= PCMCIA_C1_VS1OE_MASK;
0181 val |= PCMCIA_C1_VS2OE_MASK;
0182 pcmcia_writel(skt, val, PCMCIA_C1_REG);
0183
0184
0185 udelay(10);
0186 val = pcmcia_readl(skt, PCMCIA_C1_REG);
0187 stat |= (val & PCMCIA_C1_VS1_MASK) ? IN_VS1 : 0;
0188 stat |= (val & PCMCIA_C1_VS2_MASK) ? IN_VS2 : 0;
0189
0190
0191 val &= ~PCMCIA_C1_VS1OE_MASK;
0192 val |= PCMCIA_C1_VS2OE_MASK;
0193 pcmcia_writel(skt, val, PCMCIA_C1_REG);
0194
0195
0196 udelay(10);
0197 val = pcmcia_readl(skt, PCMCIA_C1_REG);
0198 stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS2H : 0;
0199 stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS2H : 0;
0200
0201
0202 val |= PCMCIA_C1_VS1OE_MASK;
0203 val &= ~PCMCIA_C1_VS2OE_MASK;
0204 pcmcia_writel(skt, val, PCMCIA_C1_REG);
0205
0206
0207 udelay(10);
0208 val = pcmcia_readl(skt, PCMCIA_C1_REG);
0209 stat |= (val & PCMCIA_C1_CD1_MASK) ? IN_CD1_VS1H : 0;
0210 stat |= (val & PCMCIA_C1_CD2_MASK) ? IN_CD2_VS1H : 0;
0211
0212
0213 skt->card_type = vscd_to_cardtype[stat];
0214 if (!skt->card_type)
0215 dev_err(&skt->socket.dev, "unsupported card type\n");
0216
0217
0218 val &= ~(PCMCIA_C1_VS1OE_MASK | PCMCIA_C1_VS2OE_MASK);
0219
0220
0221 val &= ~(PCMCIA_C1_EN_PCMCIA_MASK | PCMCIA_C1_EN_CARDBUS_MASK);
0222 if (skt->card_type & CARD_PCCARD)
0223 val |= PCMCIA_C1_EN_PCMCIA_MASK;
0224 else
0225 val |= PCMCIA_C1_EN_CARDBUS_MASK;
0226
0227 pcmcia_writel(skt, val, PCMCIA_C1_REG);
0228 }
0229 skt->card_detected = (stat & SS_DETECT) ? 1 : 0;
0230
0231
0232 if (skt->card_type & CARD_CARDBUS)
0233 stat |= SS_CARDBUS;
0234 if (skt->card_type & CARD_3V)
0235 stat |= SS_3VCARD;
0236 if (skt->card_type & CARD_XV)
0237 stat |= SS_XVCARD;
0238 stat |= SS_POWERON;
0239
0240 if (gpio_get_value(skt->pd->ready_gpio))
0241 stat |= SS_READY;
0242
0243 return stat;
0244 }
0245
0246
0247
0248
0249 static int bcm63xx_pcmcia_get_status(struct pcmcia_socket *sock,
0250 unsigned int *status)
0251 {
0252 struct bcm63xx_pcmcia_socket *skt;
0253
0254 skt = sock->driver_data;
0255
0256 spin_lock_bh(&skt->lock);
0257 *status = __get_socket_status(skt);
0258 spin_unlock_bh(&skt->lock);
0259
0260 return 0;
0261 }
0262
0263
0264
0265
0266 static void bcm63xx_pcmcia_poll(struct timer_list *t)
0267 {
0268 struct bcm63xx_pcmcia_socket *skt;
0269 unsigned int stat, events;
0270
0271 skt = from_timer(skt, t, timer);
0272
0273 spin_lock_bh(&skt->lock);
0274
0275 stat = __get_socket_status(skt);
0276
0277
0278
0279 events = (stat ^ skt->old_status) & skt->requested_state.csc_mask;
0280 skt->old_status = stat;
0281 spin_unlock_bh(&skt->lock);
0282
0283 if (events)
0284 pcmcia_parse_events(&skt->socket, events);
0285
0286 mod_timer(&skt->timer,
0287 jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE));
0288 }
0289
0290 static int bcm63xx_pcmcia_set_io_map(struct pcmcia_socket *sock,
0291 struct pccard_io_map *map)
0292 {
0293
0294
0295 return 0;
0296 }
0297
0298 static int bcm63xx_pcmcia_set_mem_map(struct pcmcia_socket *sock,
0299 struct pccard_mem_map *map)
0300 {
0301 struct bcm63xx_pcmcia_socket *skt;
0302 struct resource *res;
0303
0304 skt = sock->driver_data;
0305 if (map->flags & MAP_ATTRIB)
0306 res = skt->attr_res;
0307 else
0308 res = skt->common_res;
0309
0310 map->static_start = res->start + map->card_start;
0311 return 0;
0312 }
0313
0314 static struct pccard_operations bcm63xx_pcmcia_operations = {
0315 .init = bcm63xx_pcmcia_sock_init,
0316 .suspend = bcm63xx_pcmcia_suspend,
0317 .get_status = bcm63xx_pcmcia_get_status,
0318 .set_socket = bcm63xx_pcmcia_set_socket,
0319 .set_io_map = bcm63xx_pcmcia_set_io_map,
0320 .set_mem_map = bcm63xx_pcmcia_set_mem_map,
0321 };
0322
0323
0324
0325
0326 static int bcm63xx_drv_pcmcia_probe(struct platform_device *pdev)
0327 {
0328 struct bcm63xx_pcmcia_socket *skt;
0329 struct pcmcia_socket *sock;
0330 struct resource *res;
0331 unsigned int regmem_size = 0, iomem_size = 0;
0332 u32 val;
0333 int ret;
0334 int irq;
0335
0336 skt = kzalloc(sizeof(*skt), GFP_KERNEL);
0337 if (!skt)
0338 return -ENOMEM;
0339 spin_lock_init(&skt->lock);
0340 sock = &skt->socket;
0341 sock->driver_data = skt;
0342
0343
0344 skt->common_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
0345 skt->attr_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
0346 irq = platform_get_irq(pdev, 0);
0347 skt->pd = pdev->dev.platform_data;
0348 if (!skt->common_res || !skt->attr_res || (irq < 0) || !skt->pd) {
0349 ret = -EINVAL;
0350 goto err;
0351 }
0352
0353
0354 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0355 regmem_size = resource_size(res);
0356 if (!request_mem_region(res->start, regmem_size, "bcm63xx_pcmcia")) {
0357 ret = -EINVAL;
0358 goto err;
0359 }
0360 skt->reg_res = res;
0361
0362 skt->base = ioremap(res->start, regmem_size);
0363 if (!skt->base) {
0364 ret = -ENOMEM;
0365 goto err;
0366 }
0367
0368
0369 res = platform_get_resource(pdev, IORESOURCE_MEM, 3);
0370 iomem_size = resource_size(res);
0371 skt->io_base = ioremap(res->start, iomem_size);
0372 if (!skt->io_base) {
0373 ret = -ENOMEM;
0374 goto err;
0375 }
0376
0377
0378 sock->resource_ops = &pccard_static_ops;
0379 sock->ops = &bcm63xx_pcmcia_operations;
0380 sock->owner = THIS_MODULE;
0381 sock->dev.parent = &pdev->dev;
0382 sock->features = SS_CAP_STATIC_MAP | SS_CAP_PCCARD;
0383 sock->io_offset = (unsigned long)skt->io_base;
0384 sock->pci_irq = irq;
0385
0386 #ifdef CONFIG_CARDBUS
0387 sock->cb_dev = bcm63xx_cb_dev;
0388 if (bcm63xx_cb_dev)
0389 sock->features |= SS_CAP_CARDBUS;
0390 #endif
0391
0392
0393 sock->map_size = resource_size(skt->common_res);
0394
0395
0396 timer_setup(&skt->timer, bcm63xx_pcmcia_poll, 0);
0397
0398
0399
0400
0401 val = pcmcia_readl(skt, PCMCIA_C1_REG);
0402 val &= PCMCIA_C1_CBIDSEL_MASK;
0403 val |= PCMCIA_C1_EN_PCMCIA_GPIO_MASK;
0404 pcmcia_writel(skt, val, PCMCIA_C1_REG);
0405
0406
0407
0408
0409
0410
0411 val = PCMCIA_C2_DATA16_MASK;
0412 val |= 10 << PCMCIA_C2_RWCOUNT_SHIFT;
0413 val |= 6 << PCMCIA_C2_INACTIVE_SHIFT;
0414 val |= 3 << PCMCIA_C2_SETUP_SHIFT;
0415 val |= 3 << PCMCIA_C2_HOLD_SHIFT;
0416 pcmcia_writel(skt, val, PCMCIA_C2_REG);
0417
0418 ret = pcmcia_register_socket(sock);
0419 if (ret)
0420 goto err;
0421
0422
0423 mod_timer(&skt->timer,
0424 jiffies + msecs_to_jiffies(BCM63XX_PCMCIA_POLL_RATE));
0425
0426 platform_set_drvdata(pdev, skt);
0427 return 0;
0428
0429 err:
0430 if (skt->io_base)
0431 iounmap(skt->io_base);
0432 if (skt->base)
0433 iounmap(skt->base);
0434 if (skt->reg_res)
0435 release_mem_region(skt->reg_res->start, regmem_size);
0436 kfree(skt);
0437 return ret;
0438 }
0439
0440 static int bcm63xx_drv_pcmcia_remove(struct platform_device *pdev)
0441 {
0442 struct bcm63xx_pcmcia_socket *skt;
0443 struct resource *res;
0444
0445 skt = platform_get_drvdata(pdev);
0446 del_timer_sync(&skt->timer);
0447 iounmap(skt->base);
0448 iounmap(skt->io_base);
0449 res = skt->reg_res;
0450 release_mem_region(res->start, resource_size(res));
0451 kfree(skt);
0452 return 0;
0453 }
0454
0455 struct platform_driver bcm63xx_pcmcia_driver = {
0456 .probe = bcm63xx_drv_pcmcia_probe,
0457 .remove = bcm63xx_drv_pcmcia_remove,
0458 .driver = {
0459 .name = "bcm63xx_pcmcia",
0460 .owner = THIS_MODULE,
0461 },
0462 };
0463
0464 #ifdef CONFIG_CARDBUS
0465 static int bcm63xx_cb_probe(struct pci_dev *dev,
0466 const struct pci_device_id *id)
0467 {
0468
0469 bcm63xx_cb_dev = dev;
0470 return platform_driver_register(&bcm63xx_pcmcia_driver);
0471 }
0472
0473 static void bcm63xx_cb_exit(struct pci_dev *dev)
0474 {
0475 platform_driver_unregister(&bcm63xx_pcmcia_driver);
0476 bcm63xx_cb_dev = NULL;
0477 }
0478
0479 static const struct pci_device_id bcm63xx_cb_table[] = {
0480 {
0481 .vendor = PCI_VENDOR_ID_BROADCOM,
0482 .device = BCM6348_CPU_ID,
0483 .subvendor = PCI_VENDOR_ID_BROADCOM,
0484 .subdevice = PCI_ANY_ID,
0485 .class = PCI_CLASS_BRIDGE_CARDBUS << 8,
0486 .class_mask = ~0,
0487 },
0488
0489 {
0490 .vendor = PCI_VENDOR_ID_BROADCOM,
0491 .device = BCM6358_CPU_ID,
0492 .subvendor = PCI_VENDOR_ID_BROADCOM,
0493 .subdevice = PCI_ANY_ID,
0494 .class = PCI_CLASS_BRIDGE_CARDBUS << 8,
0495 .class_mask = ~0,
0496 },
0497
0498 { },
0499 };
0500
0501 MODULE_DEVICE_TABLE(pci, bcm63xx_cb_table);
0502
0503 static struct pci_driver bcm63xx_cardbus_driver = {
0504 .name = "bcm63xx_cardbus",
0505 .id_table = bcm63xx_cb_table,
0506 .probe = bcm63xx_cb_probe,
0507 .remove = bcm63xx_cb_exit,
0508 };
0509 #endif
0510
0511
0512
0513
0514
0515 static int __init bcm63xx_pcmcia_init(void)
0516 {
0517 #ifdef CONFIG_CARDBUS
0518 return pci_register_driver(&bcm63xx_cardbus_driver);
0519 #else
0520 return platform_driver_register(&bcm63xx_pcmcia_driver);
0521 #endif
0522 }
0523
0524 static void __exit bcm63xx_pcmcia_exit(void)
0525 {
0526 #ifdef CONFIG_CARDBUS
0527 return pci_unregister_driver(&bcm63xx_cardbus_driver);
0528 #else
0529 platform_driver_unregister(&bcm63xx_pcmcia_driver);
0530 #endif
0531 }
0532
0533 module_init(bcm63xx_pcmcia_init);
0534 module_exit(bcm63xx_pcmcia_exit);
0535
0536 MODULE_LICENSE("GPL");
0537 MODULE_AUTHOR("Maxime Bizon <mbizon@freebox.fr>");
0538 MODULE_DESCRIPTION("Linux PCMCIA Card Services: bcm63xx Socket Controller");