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_types.h> 24 #include <pcmcia/cs.h> 25 #include <pcmcia/cistpl.h> 26 #include <pcmcia/cisreg.h> 27 #include <pcmcia/ds.h> 28 29 #include <linux/usb/sl811.h> 30 31 MODULE_AUTHOR("Botond Botyanszki"); 32 MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); 33 MODULE_LICENSE("GPL"); 34 35 36 /*====================================================================*/ 37 /* MACROS */ 38 /*====================================================================*/ 39 40 #if defined(DEBUG) || defined(PCMCIA_DEBUG) 41 42 static int pc_debug = 0; 43 module_param(pc_debug, int, 0644); 44 45 #define DBG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG "sl811_cs: " args) 46 47 #else 48 #define DBG(n, args...) do{}while(0) 49 #endif /* no debugging */ 50 51 #define INFO(args...) printk(KERN_INFO "sl811_cs: " args) 52 53 #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) 54 55 #define CS_CHECK(fn, ret) \ 56 do { \ 57 last_fn = (fn); \ 58 if ((last_ret = (ret)) != 0) \ 59 goto cs_failed; \ 60 } while (0) 61 62 /*====================================================================*/ 63 /* VARIABLES */ 64 /*====================================================================*/ 65 66 static const char driver_name[DEV_NAME_LEN] = "sl811_cs"; 67 68 typedef struct local_info_t { 69 struct pcmcia_device *p_dev; 70 dev_node_t node; 71 } local_info_t; 72 73 static void sl811_cs_release(struct pcmcia_device * link); 74 75 /*====================================================================*/ 76 77 static void release_platform_dev(struct device * dev) 78 { 79 DBG(0, "sl811_cs platform_dev release\n"); 80 dev->parent = NULL; 81 } 82 83 static struct sl811_platform_data platform_data = { 84 .potpg = 100, 85 .power = 50, /* == 100mA */ 86 // .reset = ... FIXME: invoke CF reset on the card 87 }; 88 89 static struct resource resources[] = { 90 [0] = { 91 .flags = IORESOURCE_IRQ, 92 }, 93 [1] = { 94 // .name = "address", 95 .flags = IORESOURCE_IO, 96 }, 97 [2] = { 98 // .name = "data", 99 .flags = IORESOURCE_IO, 100 }, 101 }; 102 103 extern struct platform_driver sl811h_driver; 104 105 static struct platform_device platform_dev = { 106 .id = -1, 107 .dev = { 108 .platform_data = &platform_data, 109 .release = release_platform_dev, 110 }, 111 .resource = resources, 112 .num_resources = ARRAY_SIZE(resources), 113 }; 114 115 static int sl811_hc_init(struct device *parent, resource_size_t base_addr, 116 int irq) 117 { 118 if (platform_dev.dev.parent) 119 return -EBUSY; 120 platform_dev.dev.parent = parent; 121 122 /* finish seting up the platform device */ 123 resources[0].start = irq; 124 125 resources[1].start = base_addr; 126 resources[1].end = base_addr; 127 128 resources[2].start = base_addr + 1; 129 resources[2].end = base_addr + 1; 130 131 /* The driver core will probe for us. We know sl811-hcd has been 132 * initialized already because of the link order dependency created 133 * by referencing "sl811h_driver". 134 */ 135 platform_dev.name = sl811h_driver.driver.name; 136 return platform_device_register(&platform_dev); 137 } 138 139 /*====================================================================*/ 140 141 static void sl811_cs_detach(struct pcmcia_device *link) 142 { 143 DBG(0, "sl811_cs_detach(0x%p)\n", link); 144 145 sl811_cs_release(link); 146 147 /* This points to the parent local_info_t struct */ 148 kfree(link->priv); 149 } 150 151 static void sl811_cs_release(struct pcmcia_device * link) 152 { 153 DBG(0, "sl811_cs_release(0x%p)\n", link); 154 155 pcmcia_disable_device(link); 156 platform_device_unregister(&platform_dev); 157 } 158 159 static int sl811_cs_config_check(struct pcmcia_device *p_dev, 160 cistpl_cftable_entry_t *cfg, 161 cistpl_cftable_entry_t *dflt, 162 unsigned int vcc, 163 void *priv_data) 164 { 165 if (cfg->index == 0) 166 return -ENODEV; 167 168 /* Use power settings for Vcc and Vpp if present */ 169 /* Note that the CIS values need to be rescaled */ 170 if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) { 171 if (cfg->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc) 172 return -ENODEV; 173 } else if (dflt->vcc.present & (1<<CISTPL_POWER_VNOM)) { 174 if (dflt->vcc.param[CISTPL_POWER_VNOM]/10000 != vcc) 175 return -ENODEV; 176 } 177 178 if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) 179 p_dev->conf.Vpp = 180 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; 181 else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) 182 p_dev->conf.Vpp = 183 dflt->vpp1.param[CISTPL_POWER_VNOM]/10000; 184 185 /* we need an interrupt */ 186 if (cfg->irq.IRQInfo1 || dflt->irq.IRQInfo1) 187 p_dev->conf.Attributes |= CONF_ENABLE_IRQ; 188 189 /* IO window settings */ 190 p_dev->io.NumPorts1 = p_dev->io.NumPorts2 = 0; 191 if ((cfg->io.nwin > 0) || (dflt->io.nwin > 0)) { 192 cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt->io; 193 194 p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; 195 p_dev->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK; 196 p_dev->io.BasePort1 = io->win[0].base; 197 p_dev->io.NumPorts1 = io->win[0].len; 198 199 return pcmcia_request_io(p_dev, &p_dev->io); 200 } 201 pcmcia_disable_device(p_dev); 202 return -ENODEV; 203 } 204 205 206 static int sl811_cs_config(struct pcmcia_device *link) 207 { 208 struct device *parent = &handle_to_dev(link); 209 local_info_t *dev = link->priv; 210 int last_fn, last_ret; 211 212 DBG(0, "sl811_cs_config(0x%p)\n", link); 213 214 if (pcmcia_loop_config(link, sl811_cs_config_check, NULL)) 215 goto failed; 216 217 /* require an IRQ and two registers */ 218 if (!link->io.NumPorts1 || link->io.NumPorts1 < 2) 219 goto failed; 220 if (link->conf.Attributes & CONF_ENABLE_IRQ) 221 CS_CHECK(RequestIRQ, 222 pcmcia_request_irq(link, &link->irq)); 223 else 224 goto failed; 225 226 CS_CHECK(RequestConfiguration, 227 pcmcia_request_configuration(link, &link->conf)); 228 229 sprintf(dev->node.dev_name, driver_name); 230 dev->node.major = dev->node.minor = 0; 231 link->dev_node = &dev->node; 232 233 printk(KERN_INFO "%s: index 0x%02x: ", 234 dev->node.dev_name, link->conf.ConfigIndex); 235 if (link->conf.Vpp) 236 printk(", Vpp %d.%d", link->conf.Vpp/10, link->conf.Vpp%10); 237 printk(", irq %d", link->irq.AssignedIRQ); 238 printk(", io 0x%04x-0x%04x", link->io.BasePort1, 239 link->io.BasePort1+link->io.NumPorts1-1); 240 printk("\n"); 241 242 if (sl811_hc_init(parent, link->io.BasePort1, link->irq.AssignedIRQ) 243 < 0) { 244 cs_failed: 245 cs_error(link, last_fn, last_ret); 246 failed: 247 printk(KERN_WARNING "sl811_cs_config failed\n"); 248 sl811_cs_release(link); 249 return -ENODEV; 250 } 251 return 0; 252 } 253 254 static int sl811_cs_probe(struct pcmcia_device *link) 255 { 256 local_info_t *local; 257 258 local = kzalloc(sizeof(local_info_t), GFP_KERNEL); 259 if (!local) 260 return -ENOMEM; 261 local->p_dev = link; 262 link->priv = local; 263 264 /* Initialize */ 265 link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; 266 link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; 267 link->irq.Handler = NULL; 268 269 link->conf.Attributes = 0; 270 link->conf.IntType = INT_MEMORY_AND_IO; 271 272 return sl811_cs_config(link); 273 } 274 275 static struct pcmcia_device_id sl811_ids[] = { 276 PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */ 277 PCMCIA_DEVICE_NULL, 278 }; 279 MODULE_DEVICE_TABLE(pcmcia, sl811_ids); 280 281 static struct pcmcia_driver sl811_cs_driver = { 282 .owner = THIS_MODULE, 283 .drv = { 284 .name = (char *)driver_name, 285 }, 286 .probe = sl811_cs_probe, 287 .remove = sl811_cs_detach, 288 .id_table = sl811_ids, 289 }; 290 291 /*====================================================================*/ 292 293 static int __init init_sl811_cs(void) 294 { 295 return pcmcia_register_driver(&sl811_cs_driver); 296 } 297 module_init(init_sl811_cs); 298 299 static void __exit exit_sl811_cs(void) 300 { 301 pcmcia_unregister_driver(&sl811_cs_driver); 302 } 303 module_exit(exit_sl811_cs); 304