sl811_cs.c revision e8405f0f617856de0ceb7d04e65b663051451544
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 30MODULE_AUTHOR("Botond Botyanszki"); 31MODULE_DESCRIPTION("REX-CFU1U PCMCIA driver for 2.6"); 32MODULE_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 45typedef struct local_info_t { 46 struct pcmcia_device *p_dev; 47} local_info_t; 48 49static void sl811_cs_release(struct pcmcia_device * link); 50 51/*====================================================================*/ 52 53static void release_platform_dev(struct device * dev) 54{ 55 dev_dbg(dev, "sl811_cs platform_dev release\n"); 56 dev->parent = NULL; 57} 58 59static struct sl811_platform_data platform_data = { 60 .potpg = 100, 61 .power = 50, /* == 100mA */ 62 // .reset = ... FIXME: invoke CF reset on the card 63}; 64 65static 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 79extern struct platform_driver sl811h_driver; 80 81static 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 91static 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 117static 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 127static 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 135static 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->vpp = 156 cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; 157 else if (dflt->vpp1.present & (1<<CISTPL_POWER_VNOM)) 158 p_dev->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 181static 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->vpp) 205 printk(", Vpp %d.%d", link->vpp/10, link->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) { 212failed: 213 printk(KERN_WARNING "sl811_cs_config failed\n"); 214 sl811_cs_release(link); 215 return -ENODEV; 216 } 217 return 0; 218} 219 220static 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 236static struct pcmcia_device_id sl811_ids[] = { 237 PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */ 238 PCMCIA_DEVICE_NULL, 239}; 240MODULE_DEVICE_TABLE(pcmcia, sl811_ids); 241 242static 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 254static int __init init_sl811_cs(void) 255{ 256 return pcmcia_register_driver(&sl811_cs_driver); 257} 258module_init(init_sl811_cs); 259 260static void __exit exit_sl811_cs(void) 261{ 262 pcmcia_unregister_driver(&sl811_cs_driver); 263} 264module_exit(exit_sl811_cs); 265