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/gpio.h>
  16#include <linux/string.h>
  17#include <linux/slab.h>
  18#include <linux/platform_device.h>
  19#include <linux/export.h>
  20#include <linux/io.h>
  21#include <asm/hardware/scoop.h>
  22
  23/* PCMCIA to Scoop linkage
  24
  25   There is no easy way to link multiple scoop devices into one
  26   single entity for the pxa2xx_pcmcia device so this structure
  27   is used which is setup by the platform code.
  28
  29   This file is never modular so this symbol is always
  30   accessile to the board support files.
  31*/
  32struct scoop_pcmcia_config *platform_scoop_config;
  33EXPORT_SYMBOL(platform_scoop_config);
  34
  35struct  scoop_dev {
  36        void __iomem *base;
  37        struct gpio_chip gpio;
  38        spinlock_t scoop_lock;
  39        unsigned short suspend_clr;
  40        unsigned short suspend_set;
  41        u32 scoop_gpwr;
  42};
  43
  44void reset_scoop(struct device *dev)
  45{
  46        struct scoop_dev *sdev = dev_get_drvdata(dev);
  47
  48        iowrite16(0x0100, sdev->base + SCOOP_MCR);  /* 00 */
  49        iowrite16(0x0000, sdev->base + SCOOP_CDR);  /* 04 */
  50        iowrite16(0x0000, sdev->base + SCOOP_CCR);  /* 10 */
  51        iowrite16(0x0000, sdev->base + SCOOP_IMR);  /* 18 */
  52        iowrite16(0x00FF, sdev->base + SCOOP_IRM);  /* 14 */
  53        iowrite16(0x0000, sdev->base + SCOOP_ISR);  /* 1C */
  54        iowrite16(0x0000, sdev->base + SCOOP_IRM);
  55}
  56
  57static void __scoop_gpio_set(struct scoop_dev *sdev,
  58                        unsigned offset, int value)
  59{
  60        unsigned short gpwr;
  61
  62        gpwr = ioread16(sdev->base + SCOOP_GPWR);
  63        if (value)
  64                gpwr |= 1 << (offset + 1);
  65        else
  66                gpwr &= ~(1 << (offset + 1));
  67        iowrite16(gpwr, sdev->base + SCOOP_GPWR);
  68}
  69
  70static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
  71{
  72        struct scoop_dev *sdev = gpiochip_get_data(chip);
  73        unsigned long flags;
  74
  75        spin_lock_irqsave(&sdev->scoop_lock, flags);
  76
  77        __scoop_gpio_set(sdev, offset, value);
  78
  79        spin_unlock_irqrestore(&sdev->scoop_lock, flags);
  80}
  81
  82static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
  83{
  84        struct scoop_dev *sdev = gpiochip_get_data(chip);
  85
  86        /* XXX: I'm unsure, but it seems so */
  87        return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
  88}
  89
  90static int scoop_gpio_direction_input(struct gpio_chip *chip,
  91                        unsigned offset)
  92{
  93        struct scoop_dev *sdev = gpiochip_get_data(chip);
  94        unsigned long flags;
  95        unsigned short gpcr;
  96
  97        spin_lock_irqsave(&sdev->scoop_lock, flags);
  98
  99        gpcr = ioread16(sdev->base + SCOOP_GPCR);
 100        gpcr &= ~(1 << (offset + 1));
 101        iowrite16(gpcr, sdev->base + SCOOP_GPCR);
 102
 103        spin_unlock_irqrestore(&sdev->scoop_lock, flags);
 104
 105        return 0;
 106}
 107
 108static int scoop_gpio_direction_output(struct gpio_chip *chip,
 109                        unsigned offset, int value)
 110{
 111        struct scoop_dev *sdev = gpiochip_get_data(chip);
 112        unsigned long flags;
 113        unsigned short gpcr;
 114
 115        spin_lock_irqsave(&sdev->scoop_lock, flags);
 116
 117        __scoop_gpio_set(sdev, offset, value);
 118
 119        gpcr = ioread16(sdev->base + SCOOP_GPCR);
 120        gpcr |= 1 << (offset + 1);
 121        iowrite16(gpcr, sdev->base + SCOOP_GPCR);
 122
 123        spin_unlock_irqrestore(&sdev->scoop_lock, flags);
 124
 125        return 0;
 126}
 127
 128unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
 129{
 130        struct scoop_dev *sdev = dev_get_drvdata(dev);
 131        return ioread16(sdev->base + reg);
 132}
 133
 134void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
 135{
 136        struct scoop_dev *sdev = dev_get_drvdata(dev);
 137        iowrite16(data, sdev->base + reg);
 138}
 139
 140EXPORT_SYMBOL(reset_scoop);
 141EXPORT_SYMBOL(read_scoop_reg);
 142EXPORT_SYMBOL(write_scoop_reg);
 143
 144#ifdef CONFIG_PM
 145static void check_scoop_reg(struct scoop_dev *sdev)
 146{
 147        unsigned short mcr;
 148
 149        mcr = ioread16(sdev->base + SCOOP_MCR);
 150        if ((mcr & 0x100) == 0)
 151                iowrite16(0x0101, sdev->base + SCOOP_MCR);
 152}
 153
 154static int scoop_suspend(struct platform_device *dev, pm_message_t state)
 155{
 156        struct scoop_dev *sdev = platform_get_drvdata(dev);
 157
 158        check_scoop_reg(sdev);
 159        sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
 160        iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
 161
 162        return 0;
 163}
 164
 165static int scoop_resume(struct platform_device *dev)
 166{
 167        struct scoop_dev *sdev = platform_get_drvdata(dev);
 168
 169        check_scoop_reg(sdev);
 170        iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
 171
 172        return 0;
 173}
 174#else
 175#define scoop_suspend   NULL
 176#define scoop_resume    NULL
 177#endif
 178
 179static int scoop_probe(struct platform_device *pdev)
 180{
 181        struct scoop_dev *devptr;
 182        struct scoop_config *inf;
 183        struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 184        int ret;
 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, resource_size(mem));
 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_data(&devptr->gpio, devptr);
 228                if (ret)
 229                        goto err_gpio;
 230        }
 231
 232        return 0;
 233
 234err_gpio:
 235        platform_set_drvdata(pdev, NULL);
 236err_ioremap:
 237        iounmap(devptr->base);
 238        kfree(devptr);
 239
 240        return ret;
 241}
 242
 243static int scoop_remove(struct platform_device *pdev)
 244{
 245        struct scoop_dev *sdev = platform_get_drvdata(pdev);
 246
 247        if (!sdev)
 248                return -EINVAL;
 249
 250        if (sdev->gpio.base != -1)
 251                gpiochip_remove(&sdev->gpio);
 252
 253        platform_set_drvdata(pdev, NULL);
 254        iounmap(sdev->base);
 255        kfree(sdev);
 256
 257        return 0;
 258}
 259
 260static struct platform_driver scoop_driver = {
 261        .probe          = scoop_probe,
 262        .remove         = scoop_remove,
 263        .suspend        = scoop_suspend,
 264        .resume         = scoop_resume,
 265        .driver         = {
 266                .name   = "sharp-scoop",
 267        },
 268};
 269
 270static int __init scoop_init(void)
 271{
 272        return platform_driver_register(&scoop_driver);
 273}
 274
 275subsys_initcall(scoop_init);
 276