Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Broadcom 43xx PCMCIA-SSB bridge module
0003  *
0004  * Copyright (c) 2007 Michael Buesch <m@bues.ch>
0005  *
0006  * Licensed under the GNU/GPL. See COPYING for details.
0007  */
0008 
0009 #include "ssb_private.h"
0010 
0011 #include <linux/ssb/ssb.h>
0012 #include <linux/slab.h>
0013 #include <linux/module.h>
0014 
0015 #include <pcmcia/cistpl.h>
0016 #include <pcmcia/ciscode.h>
0017 #include <pcmcia/ds.h>
0018 #include <pcmcia/cisreg.h>
0019 
0020 static const struct pcmcia_device_id ssb_host_pcmcia_tbl[] = {
0021     PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x448),
0022     PCMCIA_DEVICE_MANF_CARD(0x2D0, 0x476),
0023     PCMCIA_DEVICE_NULL,
0024 };
0025 
0026 MODULE_DEVICE_TABLE(pcmcia, ssb_host_pcmcia_tbl);
0027 
0028 static int ssb_host_pcmcia_probe(struct pcmcia_device *dev)
0029 {
0030     struct ssb_bus *ssb;
0031     int err = -ENOMEM;
0032     int res = 0;
0033 
0034     ssb = kzalloc(sizeof(*ssb), GFP_KERNEL);
0035     if (!ssb)
0036         goto out_error;
0037 
0038     err = -ENODEV;
0039 
0040     dev->config_flags |= CONF_ENABLE_IRQ;
0041 
0042     dev->resource[2]->flags |=  WIN_ENABLE | WIN_DATA_WIDTH_16 |
0043              WIN_USE_WAIT;
0044     dev->resource[2]->start = 0;
0045     dev->resource[2]->end = SSB_CORE_SIZE;
0046     res = pcmcia_request_window(dev, dev->resource[2], 250);
0047     if (res != 0)
0048         goto err_kfree_ssb;
0049 
0050     res = pcmcia_map_mem_page(dev, dev->resource[2], 0);
0051     if (res != 0)
0052         goto err_disable;
0053 
0054     if (!dev->irq)
0055         goto err_disable;
0056 
0057     res = pcmcia_enable_device(dev);
0058     if (res != 0)
0059         goto err_disable;
0060 
0061     err = ssb_bus_pcmciabus_register(ssb, dev, dev->resource[2]->start);
0062     if (err)
0063         goto err_disable;
0064     dev->priv = ssb;
0065 
0066     return 0;
0067 
0068 err_disable:
0069     pcmcia_disable_device(dev);
0070 err_kfree_ssb:
0071     kfree(ssb);
0072 out_error:
0073     dev_err(&dev->dev, "Initialization failed (%d, %d)\n", res, err);
0074     return err;
0075 }
0076 
0077 static void ssb_host_pcmcia_remove(struct pcmcia_device *dev)
0078 {
0079     struct ssb_bus *ssb = dev->priv;
0080 
0081     ssb_bus_unregister(ssb);
0082     pcmcia_disable_device(dev);
0083     kfree(ssb);
0084     dev->priv = NULL;
0085 }
0086 
0087 #ifdef CONFIG_PM
0088 static int ssb_host_pcmcia_suspend(struct pcmcia_device *dev)
0089 {
0090     struct ssb_bus *ssb = dev->priv;
0091 
0092     return ssb_bus_suspend(ssb);
0093 }
0094 
0095 static int ssb_host_pcmcia_resume(struct pcmcia_device *dev)
0096 {
0097     struct ssb_bus *ssb = dev->priv;
0098 
0099     return ssb_bus_resume(ssb);
0100 }
0101 #else /* CONFIG_PM */
0102 # define ssb_host_pcmcia_suspend        NULL
0103 # define ssb_host_pcmcia_resume     NULL
0104 #endif /* CONFIG_PM */
0105 
0106 static struct pcmcia_driver ssb_host_pcmcia_driver = {
0107     .owner      = THIS_MODULE,
0108     .name       = "ssb-pcmcia",
0109     .id_table   = ssb_host_pcmcia_tbl,
0110     .probe      = ssb_host_pcmcia_probe,
0111     .remove     = ssb_host_pcmcia_remove,
0112     .suspend    = ssb_host_pcmcia_suspend,
0113     .resume     = ssb_host_pcmcia_resume,
0114 };
0115 
0116 static int pcmcia_init_failed;
0117 
0118 /*
0119  * These are not module init/exit functions!
0120  * The module_pcmcia_driver() helper cannot be used here.
0121  */
0122 int ssb_host_pcmcia_init(void)
0123 {
0124     pcmcia_init_failed = pcmcia_register_driver(&ssb_host_pcmcia_driver);
0125 
0126     return pcmcia_init_failed;
0127 }
0128 
0129 void ssb_host_pcmcia_exit(void)
0130 {
0131     if (!pcmcia_init_failed)
0132         pcmcia_unregister_driver(&ssb_host_pcmcia_driver);
0133 }