linux/arch/arm/common/scoop.c
<<
>>
Prefs
   1/*
   2 * Support code for the SCOOP interface found on various Sharp PDAs
   3 *
   4 * Copyright (c) 2004 Richard Purdie
   5 *
   6 *      Based on code written by Sharp/Lineo for 2.4 kernels
   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 version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 */
  13
  14#include <linux/device.h>
  15#include <linux/string.h>
  16#include <linux/slab.h>
  17#include <linux/platform_device.h>
  18#include <linux/io.h>
  19#include <asm/gpio.h>
  20#include <asm/hardware/scoop.h>
  21
  22/* PCMCIA to Scoop linkage
  23
  24   There is no easy way to link multiple scoop devices into one
  25   single entity for the pxa2xx_pcmcia device so this structure
  26   is used which is setup by the platform code.
  27
  28   This file is never modular so this symbol is always
  29   accessile to the board support files.
  30*/
  31struct scoop_pcmcia_config *platform_scoop_config;
  32EXPORT_SYMBOL(platform_scoop_config);
  33
  34struct  scoop_dev {
  35        void __iomem *base;
  36        struct gpio_chip gpio;
  37        spinlock_t scoop_lock;
  38        unsigned short suspend_clr;
  39        unsigned short suspend_set;
  40        u32 scoop_gpwr;
  41};
  42
  43void reset_scoop(struct device *dev)
  44{
  45        struct scoop_dev *sdev = dev_get_drvdata(dev);
  46
  47        iowrite16(0x0100, sdev->base + SCOOP_MCR);  /* 00 */
  48        iowrite16(0x0000, sdev->base + SCOOP_CDR);  /* 04 */
  49        iowrite16(0x0000, sdev->base + SCOOP_CCR);  /* 10 */
  50        iowrite16(0x0000, sdev->base + SCOOP_IMR);  /* 18 */
  51        iowrite16(0x00FF, sdev->base + SCOOP_IRM);  /* 14 */
  52        iowrite16(0x0000, sdev->base + SCOOP_ISR);  /* 1C */
  53        iowrite16(0x0000, sdev->base + SCOOP_IRM);
  54}
  55
  56static void __scoop_gpio_set(struct scoop_dev *sdev,
  57                        unsigned offset, int value)
  58{
  59        unsigned short gpwr;
  60
  61        gpwr = ioread16(sdev->base + SCOOP_GPWR);
  62        if (value)
  63                gpwr |= 1 << (offset + 1);
  64        else
  65                gpwr &= ~(1 << (offset + 1));
  66        iowrite16(gpwr, sdev->base + SCOOP_GPWR);
  67}
  68
  69static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  70{
  71        struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
  72        unsigned long flags;
  73
  74        spin_lock_irqsave(&sdev->scoop_lock, flags);
  75
  76        __scoop_gpio_set(sdev, offset, value);
  77
  78        spin_unlock_irqrestore(&sdev->scoop_lock, flags);
  79}
  80
  81static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
  82{
  83        struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
  84
  85        /* XXX: I'm unsure, but it seems so */
  86        return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1));
  87}
  88
  89static int scoop_gpio_direction_input(struct gpio_chip *chip,
  90                        unsigned offset)
  91{
  92        struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
  93        unsigned long flags;
  94        unsigned short gpcr;
  95
  96        spin_lock_irqsave(&sdev->scoop_lock, flags);
  97
  98        gpcr = ioread16(sdev->base + SCOOP_GPCR);
  99        gpcr &= ~(1 << (offset + 1));
 100        iowrite16(gpcr, sdev->base + SCOOP_GPCR);
 101
 102        spin_unlock_irqrestore(&sdev->scoop_lock, flags);
 103
 104        return 0;
 105}
 106
 107static int scoop_gpio_direction_output(struct gpio_chip *chip,
 108                        unsigned offset, int value)
 109{
 110        struct scoop_dev *sdev = container_of(chip, struct scoop_dev, gpio);
 111        unsigned long flags;
 112        unsigned short gpcr;
 113
 114        spin_lock_irqsave(&sdev->scoop_lock, flags);
 115
 116        __scoop_gpio_set(sdev, offset, value);
 117
 118        gpcr = ioread16(sdev->base + SCOOP_GPCR);
 119        gpcr |= 1 << (offset + 1);
 120        iowrite16(gpcr, sdev->base + SCOOP_GPCR);
 121
 122        spin_unlock_irqrestore(&sdev->scoop_lock, flags);
 123
 124        return 0;
 125}
 126
 127unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
 128{
 129        struct scoop_dev *sdev = dev_get_drvdata(dev);
 130        return ioread16(sdev->base + reg);
 131}
 132
 133void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
 134{
 135        struct scoop_dev *sdev = dev_get_drvdata(dev);
 136        iowrite16(data, sdev->base + reg);
 137}
 138
 139EXPORT_SYMBOL(reset_scoop);
 140EXPORT_SYMBOL(read_scoop_reg);
 141EXPORT_SYMBOL(write_scoop_reg);
 142
 143#ifdef CONFIG_PM
 144static void check_scoop_reg(struct scoop_dev *sdev)
 145{
 146        unsigned short mcr;
 147
 148        mcr = ioread16(sdev->base + SCOOP_MCR);
 149        if ((mcr & 0x100) == 0)
 150                iowrite16(0x0101, sdev->base + SCOOP_MCR);
 151}
 152
 153static int scoop_suspend(struct platform_device *dev, pm_message_t state)
 154{
 155        struct scoop_dev *sdev = platform_get_drvdata(dev);
 156
 157        check_scoop_reg(sdev);
 158        sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
 159        iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
 160
 161        return 0;
 162}
 163
 164static int scoop_resume(struct platform_device *dev)
 165{
 166        struct scoop_dev *sdev = platform_get_drvdata(dev);
 167
 168        check_scoop_reg(sdev);
 169        iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
 170
 171        return 0;
 172}
 173#else
 174#define scoop_suspend   NULL
 175#define scoop_resume    NULL
 176#endif
 177
 178static int __devinit scoop_probe(struct platform_device *pdev)
 179{
 180        struct scoop_dev *devptr;
 181        struct scoop_config *inf;
 182        struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 183        int ret;
 184        int temp;
 185
 186        if (!mem)
 187                return -EINVAL;
 188
 189        devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
 190        if (!devptr)
 191                return -ENOMEM;
 192
 193        spin_lock_init(&devptr->scoop_lock);
 194
 195        inf = pdev->dev.platform_data;
 196        devptr->base = ioremap(mem->start, mem->end - mem->start + 1);
 197
 198        if (!devptr->base) {
 199                ret = -ENOMEM;
 200                goto err_ioremap;
 201        }
 202
 203        platform_set_drvdata(pdev, devptr);
 204
 205        printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
 206
 207        iowrite16(0x0140, devptr->base + SCOOP_MCR);
 208        reset_scoop(&pdev->dev);
 209        iowrite16(0x0000, devptr->base + SCOOP_CPR);
 210        iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
 211        iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
 212
 213        devptr->suspend_clr = inf->suspend_clr;
 214        devptr->suspend_set = inf->suspend_set;
 215
 216        devptr->gpio.base = -1;
 217
 218        if (inf->gpio_base != 0) {
 219                devptr->gpio.label = dev_name(&pdev->dev);
 220                devptr->gpio.base = inf->gpio_base;
 221                devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
 222                devptr->gpio.set = scoop_gpio_set;
 223                devptr->gpio.get = scoop_gpio_get;
 224                devptr->gpio.direction_input = scoop_gpio_direction_input;
 225                devptr->gpio.direction_output = scoop_gpio_direction_output;
 226
 227                ret = gpiochip_add(&devptr->gpio);
 228                if (ret)
 229                        goto err_gpio;
 230        }
 231
 232        return 0;
 233
 234        if (devptr->gpio.base != -1)
 235                temp = gpiochip_remove(&devptr->gpio);
 236err_gpio:
 237        platform_set_drvdata(pdev, NULL);
 238err_ioremap:
 239        iounmap(devptr->base);
 240        kfree(devptr);
 241
 242        return ret;
 243}
 244
 245static int __devexit scoop_remove(struct platform_device *pdev)
 246{
 247        struct scoop_dev *sdev = platform_get_drvdata(pdev);
 248        int ret;
 249
 250        if (!sdev)
 251                return -EINVAL;
 252
 253        if (sdev->gpio.base != -1) {
 254                ret = gpiochip_remove(&sdev->gpio);
 255                if (ret) {
 256                        dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret);
 257                        return ret;
 258                }
 259        }
 260
 261        platform_set_drvdata(pdev, NULL);
 262        iounmap(sdev->base);
 263        kfree(sdev);
 264
 265        return 0;
 266}
 267
 268static struct platform_driver scoop_driver = {
 269        .probe          = scoop_probe,
 270        .remove         = __devexit_p(scoop_remove),
 271        .suspend        = scoop_suspend,
 272        .resume         = scoop_resume,
 273        .driver         = {
 274                .name   = "sharp-scoop",
 275        },
 276};
 277
 278static int __init scoop_init(void)
 279{
 280        return platform_driver_register(&scoop_driver);
 281}
 282
 283subsys_initcall(scoop_init);
 284