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                status = -ENOMEM;
 221                goto fail1;
 222        }
 223
 224        cf->io_virt = (void __iomem *)(area->addr);
 225
 226        cf->gpio_base = ioremap(0xfc103000, 0x1000);
 227        dev_set_drvdata(device, cf);
 228
 229        if (!cf->mem_base || !cf->io_virt || !cf->gpio_base ||
 230            (__ioremap_at(io.start, cf->io_virt, cf->io_size,
 231                _PAGE_NO_CACHE | _PAGE_GUARDED) == NULL)) {
 232                dev_err(device, "can't ioremap ranges\n");
 233                status = -ENOMEM;
 234                goto fail1;
 235        }
 236
 237
 238        cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
 239
 240        cf->iomem.start = (unsigned long)cf->mem_base;
 241        cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - mem.start);
 242        cf->iomem.flags = IORESOURCE_MEM;
 243
 244        cf->irq = irq_of_parse_and_map(np, 0);
 245
 246        status = request_irq(cf->irq, electra_cf_irq, IRQF_SHARED,
 247                             driver_name, cf);
 248        if (status < 0) {
 249                dev_err(device, "request_irq failed\n");
 250                goto fail1;
 251        }
 252
 253        cf->socket.pci_irq = cf->irq;
 254
 255        prop = of_get_property(np, "card-detect-gpio", NULL);
 256        if (!prop)
 257                goto fail1;
 258        cf->gpio_detect = *prop;
 259
 260        prop = of_get_property(np, "card-vsense-gpio", NULL);
 261        if (!prop)
 262                goto fail1;
 263        cf->gpio_vsense = *prop;
 264
 265        prop = of_get_property(np, "card-3v-gpio", NULL);
 266        if (!prop)
 267                goto fail1;
 268        cf->gpio_3v = *prop;
 269
 270        prop = of_get_property(np, "card-5v-gpio", NULL);
 271        if (!prop)
 272                goto fail1;
 273        cf->gpio_5v = *prop;
 274
 275        cf->socket.io_offset = cf->io_base;
 276
 277        /* reserve chip-select regions */
 278        if (!request_mem_region(cf->mem_phys, cf->mem_size, driver_name)) {
 279                status = -ENXIO;
 280                dev_err(device, "Can't claim memory region\n");
 281                goto fail1;
 282        }
 283
 284        if (!request_region(cf->io_base, cf->io_size, driver_name)) {
 285                status = -ENXIO;
 286                dev_err(device, "Can't claim I/O region\n");
 287                goto fail2;
 288        }
 289
 290        cf->socket.owner = THIS_MODULE;
 291        cf->socket.dev.parent = &ofdev->dev;
 292        cf->socket.ops = &electra_cf_ops;
 293        cf->socket.resource_ops = &pccard_static_ops;
 294        cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
 295                                SS_CAP_MEM_ALIGN;
 296        cf->socket.map_size = 0x800;
 297
 298        status = pcmcia_register_socket(&cf->socket);
 299        if (status < 0) {
 300                dev_err(device, "pcmcia_register_socket failed\n");
 301                goto fail3;
 302        }
 303
 304        dev_info(device, "at mem 0x%lx io 0x%llx irq %d\n",
 305                 cf->mem_phys, io.start, cf->irq);
 306
 307        cf->active = 1;
 308        electra_cf_timer((unsigned long)cf);
 309        return 0;
 310
 311fail3:
 312        release_region(cf->io_base, cf->io_size);
 313fail2:
 314        release_mem_region(cf->mem_phys, cf->mem_size);
 315fail1:
 316        if (cf->irq != NO_IRQ)
 317                free_irq(cf->irq, cf);
 318
 319        if (cf->io_virt)
 320                __iounmap_at(cf->io_virt, cf->io_size);
 321        if (cf->mem_base)
 322                iounmap(cf->mem_base);
 323        if (cf->gpio_base)
 324                iounmap(cf->gpio_base);
 325        if (area)
 326                device_init_wakeup(&ofdev->dev, 0);
 327        kfree(cf);
 328        return status;
 329
 330}
 331
 332static int electra_cf_remove(struct platform_device *ofdev)
 333{
 334        struct device *device = &ofdev->dev;
 335        struct electra_cf_socket *cf;
 336
 337        cf = dev_get_drvdata(device);
 338
 339        cf->active = 0;
 340        pcmcia_unregister_socket(&cf->socket);
 341        free_irq(cf->irq, cf);
 342        del_timer_sync(&cf->timer);
 343
 344        __iounmap_at(cf->io_virt, cf->io_size);
 345        iounmap(cf->mem_base);
 346        iounmap(cf->gpio_base);
 347        release_mem_region(cf->mem_phys, cf->mem_size);
 348        release_region(cf->io_base, cf->io_size);
 349
 350        kfree(cf);
 351
 352        return 0;
 353}
 354
 355static const struct of_device_id electra_cf_match[] = {
 356        {
 357                .compatible   = "electra-cf",
 358        },
 359        {},
 360};
 361MODULE_DEVICE_TABLE(of, electra_cf_match);
 362
 363static struct platform_driver electra_cf_driver = {
 364        .driver = {
 365                .name = driver_name,
 366                .of_match_table = electra_cf_match,
 367        },
 368        .probe    = electra_cf_probe,
 369        .remove   = electra_cf_remove,
 370};
 371
 372module_platform_driver(electra_cf_driver);
 373
 374MODULE_LICENSE("GPL");
 375MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
 376MODULE_DESCRIPTION("PA Semi Electra CF driver");
 377