electra_cf.c (7843B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) 2007 PA Semi, Inc 4 * 5 * Maintained by: Olof Johansson <olof@lixom.net> 6 * 7 * Based on drivers/pcmcia/omap_cf.c 8 */ 9 10#include <linux/module.h> 11#include <linux/kernel.h> 12#include <linux/sched.h> 13#include <linux/platform_device.h> 14#include <linux/errno.h> 15#include <linux/init.h> 16#include <linux/delay.h> 17#include <linux/interrupt.h> 18#include <linux/mm.h> 19#include <linux/vmalloc.h> 20#include <linux/of_address.h> 21#include <linux/of_irq.h> 22#include <linux/of_platform.h> 23#include <linux/slab.h> 24 25#include <pcmcia/ss.h> 26 27static const char driver_name[] = "electra-cf"; 28 29struct electra_cf_socket { 30 struct pcmcia_socket socket; 31 32 struct timer_list timer; 33 unsigned present:1; 34 unsigned active:1; 35 36 struct platform_device *ofdev; 37 unsigned long mem_phys; 38 void __iomem *mem_base; 39 unsigned long mem_size; 40 void __iomem *io_virt; 41 unsigned int io_base; 42 unsigned int io_size; 43 u_int irq; 44 struct resource iomem; 45 void __iomem *gpio_base; 46 int gpio_detect; 47 int gpio_vsense; 48 int gpio_3v; 49 int gpio_5v; 50}; 51 52#define POLL_INTERVAL (2 * HZ) 53 54 55static int electra_cf_present(struct electra_cf_socket *cf) 56{ 57 unsigned int gpio; 58 59 gpio = in_le32(cf->gpio_base+0x40); 60 return !(gpio & (1 << cf->gpio_detect)); 61} 62 63static int electra_cf_ss_init(struct pcmcia_socket *s) 64{ 65 return 0; 66} 67 68/* the timer is primarily to kick this socket's pccardd */ 69static void electra_cf_timer(struct timer_list *t) 70{ 71 struct electra_cf_socket *cf = from_timer(cf, t, timer); 72 int present = electra_cf_present(cf); 73 74 if (present != cf->present) { 75 cf->present = present; 76 pcmcia_parse_events(&cf->socket, SS_DETECT); 77 } 78 79 if (cf->active) 80 mod_timer(&cf->timer, jiffies + POLL_INTERVAL); 81} 82 83static irqreturn_t electra_cf_irq(int irq, void *_cf) 84{ 85 struct electra_cf_socket *cf = _cf; 86 87 electra_cf_timer(&cf->timer); 88 return IRQ_HANDLED; 89} 90 91static int electra_cf_get_status(struct pcmcia_socket *s, u_int *sp) 92{ 93 struct electra_cf_socket *cf; 94 95 if (!sp) 96 return -EINVAL; 97 98 cf = container_of(s, struct electra_cf_socket, socket); 99 100 /* NOTE CF is always 3VCARD */ 101 if (electra_cf_present(cf)) { 102 *sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD; 103 104 s->pci_irq = cf->irq; 105 } else 106 *sp = 0; 107 return 0; 108} 109 110static int electra_cf_set_socket(struct pcmcia_socket *sock, 111 struct socket_state_t *s) 112{ 113 unsigned int gpio; 114 unsigned int vcc; 115 struct electra_cf_socket *cf; 116 117 cf = container_of(sock, struct electra_cf_socket, socket); 118 119 /* "reset" means no power in our case */ 120 vcc = (s->flags & SS_RESET) ? 0 : s->Vcc; 121 122 switch (vcc) { 123 case 0: 124 gpio = 0; 125 break; 126 case 33: 127 gpio = (1 << cf->gpio_3v); 128 break; 129 case 5: 130 gpio = (1 << cf->gpio_5v); 131 break; 132 default: 133 return -EINVAL; 134 } 135 136 gpio |= 1 << (cf->gpio_3v + 16); /* enwr */ 137 gpio |= 1 << (cf->gpio_5v + 16); /* enwr */ 138 out_le32(cf->gpio_base+0x90, gpio); 139 140 pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n", 141 driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask); 142 143 return 0; 144} 145 146static int electra_cf_set_io_map(struct pcmcia_socket *s, 147 struct pccard_io_map *io) 148{ 149 return 0; 150} 151 152static int electra_cf_set_mem_map(struct pcmcia_socket *s, 153 struct pccard_mem_map *map) 154{ 155 struct electra_cf_socket *cf; 156 157 if (map->card_start) 158 return -EINVAL; 159 cf = container_of(s, struct electra_cf_socket, socket); 160 map->static_start = cf->mem_phys; 161 map->flags &= MAP_ACTIVE|MAP_ATTRIB; 162 if (!(map->flags & MAP_ATTRIB)) 163 map->static_start += 0x800; 164 return 0; 165} 166 167static struct pccard_operations electra_cf_ops = { 168 .init = electra_cf_ss_init, 169 .get_status = electra_cf_get_status, 170 .set_socket = electra_cf_set_socket, 171 .set_io_map = electra_cf_set_io_map, 172 .set_mem_map = electra_cf_set_mem_map, 173}; 174 175static int electra_cf_probe(struct platform_device *ofdev) 176{ 177 struct device *device = &ofdev->dev; 178 struct device_node *np = ofdev->dev.of_node; 179 struct electra_cf_socket *cf; 180 struct resource mem, io; 181 int status = -ENOMEM; 182 const unsigned int *prop; 183 int err; 184 185 err = of_address_to_resource(np, 0, &mem); 186 if (err) 187 return -EINVAL; 188 189 err = of_address_to_resource(np, 1, &io); 190 if (err) 191 return -EINVAL; 192 193 cf = kzalloc(sizeof(*cf), GFP_KERNEL); 194 if (!cf) 195 return -ENOMEM; 196 197 timer_setup(&cf->timer, electra_cf_timer, 0); 198 cf->irq = 0; 199 200 cf->ofdev = ofdev; 201 cf->mem_phys = mem.start; 202 cf->mem_size = PAGE_ALIGN(resource_size(&mem)); 203 cf->mem_base = ioremap(cf->mem_phys, cf->mem_size); 204 if (!cf->mem_base) 205 goto out_free_cf; 206 cf->io_size = PAGE_ALIGN(resource_size(&io)); 207 cf->io_virt = ioremap_phb(io.start, cf->io_size); 208 if (!cf->io_virt) 209 goto out_unmap_mem; 210 211 cf->gpio_base = ioremap(0xfc103000, 0x1000); 212 if (!cf->gpio_base) 213 goto out_unmap_virt; 214 dev_set_drvdata(device, cf); 215 216 cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END; 217 cf->iomem.start = (unsigned long)cf->mem_base; 218 cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - mem.start); 219 cf->iomem.flags = IORESOURCE_MEM; 220 221 cf->irq = irq_of_parse_and_map(np, 0); 222 223 status = request_irq(cf->irq, electra_cf_irq, IRQF_SHARED, 224 driver_name, cf); 225 if (status < 0) { 226 dev_err(device, "request_irq failed\n"); 227 goto fail1; 228 } 229 230 cf->socket.pci_irq = cf->irq; 231 232 status = -EINVAL; 233 234 prop = of_get_property(np, "card-detect-gpio", NULL); 235 if (!prop) 236 goto fail1; 237 cf->gpio_detect = *prop; 238 239 prop = of_get_property(np, "card-vsense-gpio", NULL); 240 if (!prop) 241 goto fail1; 242 cf->gpio_vsense = *prop; 243 244 prop = of_get_property(np, "card-3v-gpio", NULL); 245 if (!prop) 246 goto fail1; 247 cf->gpio_3v = *prop; 248 249 prop = of_get_property(np, "card-5v-gpio", NULL); 250 if (!prop) 251 goto fail1; 252 cf->gpio_5v = *prop; 253 254 cf->socket.io_offset = cf->io_base; 255 256 /* reserve chip-select regions */ 257 if (!request_mem_region(cf->mem_phys, cf->mem_size, driver_name)) { 258 status = -ENXIO; 259 dev_err(device, "Can't claim memory region\n"); 260 goto fail1; 261 } 262 263 if (!request_region(cf->io_base, cf->io_size, driver_name)) { 264 status = -ENXIO; 265 dev_err(device, "Can't claim I/O region\n"); 266 goto fail2; 267 } 268 269 cf->socket.owner = THIS_MODULE; 270 cf->socket.dev.parent = &ofdev->dev; 271 cf->socket.ops = &electra_cf_ops; 272 cf->socket.resource_ops = &pccard_static_ops; 273 cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP | 274 SS_CAP_MEM_ALIGN; 275 cf->socket.map_size = 0x800; 276 277 status = pcmcia_register_socket(&cf->socket); 278 if (status < 0) { 279 dev_err(device, "pcmcia_register_socket failed\n"); 280 goto fail3; 281 } 282 283 dev_info(device, "at mem 0x%lx io 0x%llx irq %d\n", 284 cf->mem_phys, io.start, cf->irq); 285 286 cf->active = 1; 287 electra_cf_timer(&cf->timer); 288 return 0; 289 290fail3: 291 release_region(cf->io_base, cf->io_size); 292fail2: 293 release_mem_region(cf->mem_phys, cf->mem_size); 294fail1: 295 if (cf->irq) 296 free_irq(cf->irq, cf); 297 298 iounmap(cf->gpio_base); 299out_unmap_virt: 300 device_init_wakeup(&ofdev->dev, 0); 301 iounmap(cf->io_virt); 302out_unmap_mem: 303 iounmap(cf->mem_base); 304out_free_cf: 305 kfree(cf); 306 return status; 307 308} 309 310static int electra_cf_remove(struct platform_device *ofdev) 311{ 312 struct device *device = &ofdev->dev; 313 struct electra_cf_socket *cf; 314 315 cf = dev_get_drvdata(device); 316 317 cf->active = 0; 318 pcmcia_unregister_socket(&cf->socket); 319 free_irq(cf->irq, cf); 320 del_timer_sync(&cf->timer); 321 322 iounmap(cf->io_virt); 323 iounmap(cf->mem_base); 324 iounmap(cf->gpio_base); 325 release_mem_region(cf->mem_phys, cf->mem_size); 326 release_region(cf->io_base, cf->io_size); 327 328 kfree(cf); 329 330 return 0; 331} 332 333static const struct of_device_id electra_cf_match[] = { 334 { 335 .compatible = "electra-cf", 336 }, 337 {}, 338}; 339MODULE_DEVICE_TABLE(of, electra_cf_match); 340 341static struct platform_driver electra_cf_driver = { 342 .driver = { 343 .name = driver_name, 344 .of_match_table = electra_cf_match, 345 }, 346 .probe = electra_cf_probe, 347 .remove = electra_cf_remove, 348}; 349 350module_platform_driver(electra_cf_driver); 351 352MODULE_LICENSE("GPL"); 353MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); 354MODULE_DESCRIPTION("PA Semi Electra CF driver");