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