Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Support code for the SCOOP interface found on various Sharp PDAs
0004  *
0005  * Copyright (c) 2004 Richard Purdie
0006  *
0007  *  Based on code written by Sharp/Lineo for 2.4 kernels
0008  */
0009 
0010 #include <linux/device.h>
0011 #include <linux/gpio/driver.h>
0012 #include <linux/string.h>
0013 #include <linux/slab.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/export.h>
0016 #include <linux/io.h>
0017 #include <asm/hardware/scoop.h>
0018 
0019 /* PCMCIA to Scoop linkage
0020 
0021    There is no easy way to link multiple scoop devices into one
0022    single entity for the pxa2xx_pcmcia device so this structure
0023    is used which is setup by the platform code.
0024 
0025    This file is never modular so this symbol is always
0026    accessile to the board support files.
0027 */
0028 struct scoop_pcmcia_config *platform_scoop_config;
0029 EXPORT_SYMBOL(platform_scoop_config);
0030 
0031 struct  scoop_dev {
0032     void __iomem *base;
0033     struct gpio_chip gpio;
0034     spinlock_t scoop_lock;
0035     unsigned short suspend_clr;
0036     unsigned short suspend_set;
0037     u32 scoop_gpwr;
0038 };
0039 
0040 void reset_scoop(struct device *dev)
0041 {
0042     struct scoop_dev *sdev = dev_get_drvdata(dev);
0043 
0044     iowrite16(0x0100, sdev->base + SCOOP_MCR);  /* 00 */
0045     iowrite16(0x0000, sdev->base + SCOOP_CDR);  /* 04 */
0046     iowrite16(0x0000, sdev->base + SCOOP_CCR);  /* 10 */
0047     iowrite16(0x0000, sdev->base + SCOOP_IMR);  /* 18 */
0048     iowrite16(0x00FF, sdev->base + SCOOP_IRM);  /* 14 */
0049     iowrite16(0x0000, sdev->base + SCOOP_ISR);  /* 1C */
0050     iowrite16(0x0000, sdev->base + SCOOP_IRM);
0051 }
0052 
0053 static void __scoop_gpio_set(struct scoop_dev *sdev,
0054             unsigned offset, int value)
0055 {
0056     unsigned short gpwr;
0057 
0058     gpwr = ioread16(sdev->base + SCOOP_GPWR);
0059     if (value)
0060         gpwr |= 1 << (offset + 1);
0061     else
0062         gpwr &= ~(1 << (offset + 1));
0063     iowrite16(gpwr, sdev->base + SCOOP_GPWR);
0064 }
0065 
0066 static void scoop_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
0067 {
0068     struct scoop_dev *sdev = gpiochip_get_data(chip);
0069     unsigned long flags;
0070 
0071     spin_lock_irqsave(&sdev->scoop_lock, flags);
0072 
0073     __scoop_gpio_set(sdev, offset, value);
0074 
0075     spin_unlock_irqrestore(&sdev->scoop_lock, flags);
0076 }
0077 
0078 static int scoop_gpio_get(struct gpio_chip *chip, unsigned offset)
0079 {
0080     struct scoop_dev *sdev = gpiochip_get_data(chip);
0081 
0082     /* XXX: I'm unsure, but it seems so */
0083     return !!(ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)));
0084 }
0085 
0086 static int scoop_gpio_direction_input(struct gpio_chip *chip,
0087             unsigned offset)
0088 {
0089     struct scoop_dev *sdev = gpiochip_get_data(chip);
0090     unsigned long flags;
0091     unsigned short gpcr;
0092 
0093     spin_lock_irqsave(&sdev->scoop_lock, flags);
0094 
0095     gpcr = ioread16(sdev->base + SCOOP_GPCR);
0096     gpcr &= ~(1 << (offset + 1));
0097     iowrite16(gpcr, sdev->base + SCOOP_GPCR);
0098 
0099     spin_unlock_irqrestore(&sdev->scoop_lock, flags);
0100 
0101     return 0;
0102 }
0103 
0104 static int scoop_gpio_direction_output(struct gpio_chip *chip,
0105             unsigned offset, int value)
0106 {
0107     struct scoop_dev *sdev = gpiochip_get_data(chip);
0108     unsigned long flags;
0109     unsigned short gpcr;
0110 
0111     spin_lock_irqsave(&sdev->scoop_lock, flags);
0112 
0113     __scoop_gpio_set(sdev, offset, value);
0114 
0115     gpcr = ioread16(sdev->base + SCOOP_GPCR);
0116     gpcr |= 1 << (offset + 1);
0117     iowrite16(gpcr, sdev->base + SCOOP_GPCR);
0118 
0119     spin_unlock_irqrestore(&sdev->scoop_lock, flags);
0120 
0121     return 0;
0122 }
0123 
0124 unsigned short read_scoop_reg(struct device *dev, unsigned short reg)
0125 {
0126     struct scoop_dev *sdev = dev_get_drvdata(dev);
0127     return ioread16(sdev->base + reg);
0128 }
0129 
0130 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data)
0131 {
0132     struct scoop_dev *sdev = dev_get_drvdata(dev);
0133     iowrite16(data, sdev->base + reg);
0134 }
0135 
0136 EXPORT_SYMBOL(reset_scoop);
0137 EXPORT_SYMBOL(read_scoop_reg);
0138 EXPORT_SYMBOL(write_scoop_reg);
0139 
0140 #ifdef CONFIG_PM
0141 static void check_scoop_reg(struct scoop_dev *sdev)
0142 {
0143     unsigned short mcr;
0144 
0145     mcr = ioread16(sdev->base + SCOOP_MCR);
0146     if ((mcr & 0x100) == 0)
0147         iowrite16(0x0101, sdev->base + SCOOP_MCR);
0148 }
0149 
0150 static int scoop_suspend(struct platform_device *dev, pm_message_t state)
0151 {
0152     struct scoop_dev *sdev = platform_get_drvdata(dev);
0153 
0154     check_scoop_reg(sdev);
0155     sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR);
0156     iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR);
0157 
0158     return 0;
0159 }
0160 
0161 static int scoop_resume(struct platform_device *dev)
0162 {
0163     struct scoop_dev *sdev = platform_get_drvdata(dev);
0164 
0165     check_scoop_reg(sdev);
0166     iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR);
0167 
0168     return 0;
0169 }
0170 #else
0171 #define scoop_suspend   NULL
0172 #define scoop_resume    NULL
0173 #endif
0174 
0175 static int scoop_probe(struct platform_device *pdev)
0176 {
0177     struct scoop_dev *devptr;
0178     struct scoop_config *inf;
0179     struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0180     int ret;
0181 
0182     if (!mem)
0183         return -EINVAL;
0184 
0185     devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL);
0186     if (!devptr)
0187         return -ENOMEM;
0188 
0189     spin_lock_init(&devptr->scoop_lock);
0190 
0191     inf = pdev->dev.platform_data;
0192     devptr->base = ioremap(mem->start, resource_size(mem));
0193 
0194     if (!devptr->base) {
0195         ret = -ENOMEM;
0196         goto err_ioremap;
0197     }
0198 
0199     platform_set_drvdata(pdev, devptr);
0200 
0201     printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base);
0202 
0203     iowrite16(0x0140, devptr->base + SCOOP_MCR);
0204     reset_scoop(&pdev->dev);
0205     iowrite16(0x0000, devptr->base + SCOOP_CPR);
0206     iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR);
0207     iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR);
0208 
0209     devptr->suspend_clr = inf->suspend_clr;
0210     devptr->suspend_set = inf->suspend_set;
0211 
0212     devptr->gpio.base = -1;
0213 
0214     if (inf->gpio_base != 0) {
0215         devptr->gpio.label = dev_name(&pdev->dev);
0216         devptr->gpio.base = inf->gpio_base;
0217         devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */
0218         devptr->gpio.set = scoop_gpio_set;
0219         devptr->gpio.get = scoop_gpio_get;
0220         devptr->gpio.direction_input = scoop_gpio_direction_input;
0221         devptr->gpio.direction_output = scoop_gpio_direction_output;
0222 
0223         ret = gpiochip_add_data(&devptr->gpio, devptr);
0224         if (ret)
0225             goto err_gpio;
0226     }
0227 
0228     return 0;
0229 
0230 err_gpio:
0231     platform_set_drvdata(pdev, NULL);
0232 err_ioremap:
0233     iounmap(devptr->base);
0234     kfree(devptr);
0235 
0236     return ret;
0237 }
0238 
0239 static int scoop_remove(struct platform_device *pdev)
0240 {
0241     struct scoop_dev *sdev = platform_get_drvdata(pdev);
0242 
0243     if (sdev->gpio.base != -1)
0244         gpiochip_remove(&sdev->gpio);
0245 
0246     platform_set_drvdata(pdev, NULL);
0247     iounmap(sdev->base);
0248     kfree(sdev);
0249 
0250     return 0;
0251 }
0252 
0253 static struct platform_driver scoop_driver = {
0254     .probe      = scoop_probe,
0255     .remove     = scoop_remove,
0256     .suspend    = scoop_suspend,
0257     .resume     = scoop_resume,
0258     .driver     = {
0259         .name   = "sharp-scoop",
0260     },
0261 };
0262 
0263 static int __init scoop_init(void)
0264 {
0265     return platform_driver_register(&scoop_driver);
0266 }
0267 
0268 subsys_initcall(scoop_init);