1 /* 2 * PCMCIA driver for SL811HS (as found in REX-CFU1U) 3 * Filename: sl811_cs.c 4 * Author: Yukio Yamamoto 5 * 6 * Port to sl811-hcd and 2.6.x by 7 * Botond Botyanszki <boti@rocketmail.com> 8 * Simon Pickering 9 * 10 * Last update: 2005-05-12 11 */ 12 13 #include <linux/kernel.h> 14 #include <linux/module.h> 15 #include <linux/init.h> 16 #include <linux/ptrace.h> 17 #include <linux/slab.h> 18 #include <linux/string.h> 19 #include <linux/timer.h> 20 #include <linux/ioport.h> 21 #include <linux/platform_device.h> 22 23 #include <pcmcia/cs.h> 24 #include <pcmcia/cistpl.h> 25 #include <pcmcia/cisreg.h> 26 #include <pcmcia/ds.h> 27 28 #include <linux/usb/sl811.h> 29 30 MODULE_AUTHOR("Botond Botyanszki"); 31 MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); 32 MODULE_LICENSE("GPL"); 33 34 35 /*====================================================================*/ 36 /* MACROS */ 37 /*====================================================================*/ 38 39 #define INFO(args...) printk(KERN_INFO "sl811_cs: " args) 40 41 /*====================================================================*/ 42 /* VARIABLES */ 43 /*====================================================================*/ 44 45 typedef struct local_info_t { 46 struct pcmcia_device *p_dev; 47 } local_info_t; 48 49 static void sl811_cs_release(struct pcmcia_device * link); 50 51 /*====================================================================*/ 52 53 static void release_platform_dev(struct device * dev) 54 { 55 dev_dbg(dev, "sl811_cs platform_dev release\n"); 56 dev->parent = NULL; 57 } 58 59 static struct sl811_platform_data platform_data = { 60 .potpg = 100, 61 .power = 50, /* == 100mA */ 62 // .reset = ... FIXME: invoke CF reset on the card 63 }; 64 65 static struct resource resources[] = { 66 [0] = { 67 .flags = IORESOURCE_IRQ, 68 }, 69 [1] = { 70 // .name = "address", 71 .flags = IORESOURCE_IO, 72 }, 73 [2] = { 74 // .name = "data", 75 .flags = IORESOURCE_IO, 76 }, 77 }; 78 79 extern struct platform_driver sl811h_driver; 80 81 static struct platform_device platform_dev = { 82 .id = -1, 83 .dev = { 84 .platform_data = &platform_data, 85 .release = release_platform_dev, 86 }, 87 .resource = resources, 88 .num_resources = ARRAY_SIZE(resources), 89 }; 90 91 static int sl811_hc_init(struct device *parent, resource_size_t base_addr, 92 int irq) 93 { 94 if (platform_dev.dev.parent) 95 return -EBUSY; 96 platform_dev.dev.parent = parent; 97 98 /* finish seting up the platform device */ 99 resources[0].start = irq; 100 101 resources[1].start = base_addr; 102 resources[1].end = base_addr; 103 104 resources[2].start = base_addr + 1; 105 resources[2].end = base_addr + 1; 106 107 /* The driver core will probe for us. We know sl811-hcd has been 108 * initialized already because of the link order dependency created 109 * by referencing "sl811h_driver". 110 */ 111 platform_dev.name = sl811h_driver.driver.name; 112 return platform_device_register(&platform_dev); 113 } 114 115 /*====================================================================*/ 116 117 static void sl811_cs_detach(struct pcmcia_device *link) 118 { 119 dev_dbg(&link->dev, "sl811_cs_detach\n"); 120 121 sl811_cs_release(link); 122 123 /* This points to the parent local_info_t struct */ 124 kfree(link->priv); 125 } 126 127 static void sl811_cs_release(struct pcmcia_device * link) 128 { 129 dev_dbg(&link->dev, "sl811_cs_release\n"); 130 131 pcmcia_disable_device(link); 132 platform_device_unregister(&platform_dev); 133 } 134 135 static int sl811_cs_config_check(struct pcmcia_device *p_dev, 136 cistpl_cftable_entry_t *cfg, 137 cistpl_cftable_entry_t *dflt, 138 unsigned int vcc, 139 void *priv_data) 140 { 141 if (cfg->index == 0) 142 return -ENODEV; 143 144 /* Use power settings for Vcc and Vpp if present */ 145 /* Note that the CIS values need to be rescaled */ 146 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { 147 if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc) 148 return -ENODEV; 149 } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) { 150 if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc) 151 return -ENODEV; 152 } 153 154 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) 155 p_dev->conf.Vpp = 156 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; 157 else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) 158 p_dev->conf.Vpp = 159 dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; 160 161 /* we need an interrupt */ 162 p_dev->conf.Attributes |= CONF_ENABLE_IRQ; 163 164 /* IO window settings */ 165 p_dev->resource[0]->end = p_dev->resource[1]->end = 0; 166 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { 167 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; 168 p_dev->io_lines = io->flags & CISTPL_IO_LINES_MASK; 169 170 p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; 171 p_dev->resource[0]->start = io->win[0].base; 172 p_dev->resource[0]->end = io->win[0].len; 173 174 return pcmcia_request_io(p_dev); 175 } 176 pcmcia_disable_device(p_dev); 177 return -ENODEV; 178 } 179 180 181 static int sl811_cs_config(struct pcmcia_device *link) 182 { 183 struct device *parent = &link->dev; 184 int ret; 185 186 dev_dbg(&link->dev, "sl811_cs_config\n"); 187 188 if (pcmcia_loop_config(link, sl811_cs_config_check, NULL)) 189 goto failed; 190 191 /* require an IRQ and two registers */ 192 if (resource_size(link->resource[0]) < 2) 193 goto failed; 194 195 if (!link->irq) 196 goto failed; 197 198 ret = pcmcia_request_configuration(link, &link->conf); 199 if (ret) 200 goto failed; 201 202 dev_info(&link->dev, "index 0x%02x: ", 203 link->conf.ConfigIndex); 204 if (link->conf.Vpp) 205 printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); 206 printk(", irq %d", link->irq); 207 printk(", io %pR", link->resource[0]); 208 printk("\n"); 209 210 if (sl811_hc_init(parent, link->resource[0]->start, link->irq) 211 < 0) { 212 failed: 213 printk(KERN_WARNING "sl811_cs_config failed\n"); 214 sl811_cs_release(link); 215 return -ENODEV; 216 } 217 return 0; 218 } 219 220 static int sl811_cs_probe(struct pcmcia_device *link) 221 { 222 local_info_t *local; 223 224 local = kzalloc(sizeof(local_info_t), GFP_KERNEL); 225 if (!local) 226 return -ENOMEM; 227 local->p_dev = link; 228 link->priv = local; 229 230 link->conf.Attributes = 0; 231 link->conf.IntType = INT_MEMORY_AND_IO; 232 233 return sl811_cs_config(link); 234 } 235 236 static struct pcmcia_device_id sl811_ids[] = { 237 PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */ 238 PCMCIA_DEVICE_NULL, 239 }; 240 MODULE_DEVICE_TABLE(pcmcia, sl811_ids); 241 242 static struct pcmcia_driver sl811_cs_driver = { 243 .owner = THIS_MODULE, 244 .drv = { 245 .name = "sl811_cs", 246 }, 247 .probe = sl811_cs_probe, 248 .remove = sl811_cs_detach, 249 .id_table = sl811_ids, 250 }; 251 252 /*====================================================================*/ 253 254 static int __init init_sl811_cs(void) 255 { 256 return pcmcia_register_driver(&sl811_cs_driver); 257 } 258 module_init(init_sl811_cs); 259 260 static void __exit exit_sl811_cs(void) 261 { 262 pcmcia_unregister_driver(&sl811_cs_driver); 263 } 264 module_exit(exit_sl811_cs); 265