Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * PCMCIA driver for SL811HS (as found in REX-CFU1U)
0004  * Filename: sl811_cs.c
0005  * Author:   Yukio Yamamoto
0006  *
0007  *  Port to sl811-hcd and 2.6.x by
0008  *    Botond Botyanszki <boti@rocketmail.com>
0009  *    Simon Pickering
0010  *
0011  *  Last update: 2005-05-12
0012  */
0013 
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/ptrace.h>
0017 #include <linux/slab.h>
0018 #include <linux/string.h>
0019 #include <linux/timer.h>
0020 #include <linux/ioport.h>
0021 #include <linux/platform_device.h>
0022 
0023 #include <pcmcia/cistpl.h>
0024 #include <pcmcia/cisreg.h>
0025 #include <pcmcia/ds.h>
0026 
0027 #include <linux/usb/sl811.h>
0028 
0029 MODULE_AUTHOR("Botond Botyanszki");
0030 MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6");
0031 MODULE_LICENSE("GPL");
0032 
0033 
0034 /*====================================================================*/
0035 /* MACROS                                                             */
0036 /*====================================================================*/
0037 
0038 #define INFO(args...) printk(KERN_INFO "sl811_cs: " args)
0039 
0040 /*====================================================================*/
0041 /* VARIABLES                                                          */
0042 /*====================================================================*/
0043 
0044 typedef struct local_info_t {
0045     struct pcmcia_device    *p_dev;
0046 } local_info_t;
0047 
0048 static void sl811_cs_release(struct pcmcia_device * link);
0049 
0050 /*====================================================================*/
0051 
0052 static void release_platform_dev(struct device * dev)
0053 {
0054     dev_dbg(dev, "sl811_cs platform_dev release\n");
0055     dev->parent = NULL;
0056 }
0057 
0058 static struct sl811_platform_data platform_data = {
0059     .potpg      = 100,
0060     .power      = 50,       /* == 100mA */
0061     // .reset   = ... FIXME:  invoke CF reset on the card
0062 };
0063 
0064 static struct resource resources[] = {
0065     [0] = {
0066         .flags  = IORESOURCE_IRQ,
0067     },
0068     [1] = {
0069         // .name   = "address",
0070         .flags  = IORESOURCE_IO,
0071     },
0072     [2] = {
0073         // .name   = "data",
0074         .flags  = IORESOURCE_IO,
0075     },
0076 };
0077 
0078 extern struct platform_driver sl811h_driver;
0079 
0080 static struct platform_device platform_dev = {
0081     .id         = -1,
0082     .dev = {
0083         .platform_data = &platform_data,
0084         .release       = release_platform_dev,
0085     },
0086     .resource       = resources,
0087     .num_resources      = ARRAY_SIZE(resources),
0088 };
0089 
0090 static int sl811_hc_init(struct device *parent, resource_size_t base_addr,
0091              int irq)
0092 {
0093     if (platform_dev.dev.parent)
0094         return -EBUSY;
0095     platform_dev.dev.parent = parent;
0096 
0097     /* finish setting up the platform device */
0098     resources[0].start = irq;
0099 
0100     resources[1].start = base_addr;
0101     resources[1].end = base_addr;
0102 
0103     resources[2].start = base_addr + 1;
0104     resources[2].end   = base_addr + 1;
0105 
0106     /* The driver core will probe for us.  We know sl811-hcd has been
0107      * initialized already because of the link order dependency created
0108      * by referencing "sl811h_driver".
0109      */
0110     platform_dev.name = sl811h_driver.driver.name;
0111     return platform_device_register(&platform_dev);
0112 }
0113 
0114 /*====================================================================*/
0115 
0116 static void sl811_cs_detach(struct pcmcia_device *link)
0117 {
0118     dev_dbg(&link->dev, "sl811_cs_detach\n");
0119 
0120     sl811_cs_release(link);
0121 
0122     /* This points to the parent local_info_t struct */
0123     kfree(link->priv);
0124 }
0125 
0126 static void sl811_cs_release(struct pcmcia_device * link)
0127 {
0128     dev_dbg(&link->dev, "sl811_cs_release\n");
0129 
0130     pcmcia_disable_device(link);
0131     platform_device_unregister(&platform_dev);
0132 }
0133 
0134 static int sl811_cs_config_check(struct pcmcia_device *p_dev, void *priv_data)
0135 {
0136     if (p_dev->config_index == 0)
0137         return -EINVAL;
0138 
0139     return pcmcia_request_io(p_dev);
0140 }
0141 
0142 
0143 static int sl811_cs_config(struct pcmcia_device *link)
0144 {
0145     struct device       *parent = &link->dev;
0146     int         ret;
0147 
0148     dev_dbg(&link->dev, "sl811_cs_config\n");
0149 
0150     link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
0151         CONF_AUTO_CHECK_VCC | CONF_AUTO_SET_IO;
0152 
0153     if (pcmcia_loop_config(link, sl811_cs_config_check, NULL))
0154         goto failed;
0155 
0156     /* require an IRQ and two registers */
0157     if (resource_size(link->resource[0]) < 2)
0158         goto failed;
0159 
0160     if (!link->irq)
0161         goto failed;
0162 
0163     ret = pcmcia_enable_device(link);
0164     if (ret)
0165         goto failed;
0166 
0167     if (sl811_hc_init(parent, link->resource[0]->start, link->irq)
0168             < 0) {
0169 failed:
0170         printk(KERN_WARNING "sl811_cs_config failed\n");
0171         sl811_cs_release(link);
0172         return  -ENODEV;
0173     }
0174     return 0;
0175 }
0176 
0177 static int sl811_cs_probe(struct pcmcia_device *link)
0178 {
0179     local_info_t *local;
0180 
0181     local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
0182     if (!local)
0183         return -ENOMEM;
0184     local->p_dev = link;
0185     link->priv = local;
0186 
0187     return sl811_cs_config(link);
0188 }
0189 
0190 static const struct pcmcia_device_id sl811_ids[] = {
0191     PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */
0192     PCMCIA_DEVICE_NULL,
0193 };
0194 MODULE_DEVICE_TABLE(pcmcia, sl811_ids);
0195 
0196 static struct pcmcia_driver sl811_cs_driver = {
0197     .owner      = THIS_MODULE,
0198     .name       = "sl811_cs",
0199     .probe      = sl811_cs_probe,
0200     .remove     = sl811_cs_detach,
0201     .id_table   = sl811_ids,
0202 };
0203 module_pcmcia_driver(sl811_cs_driver);