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