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 <asm/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 */ 31 struct scoop_pcmcia_config *platform_scoop_config; 32 EXPORT_SYMBOL(platform_scoop_config); 33 34 struct 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 43 void 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 56 static 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 69 static 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 81 static 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 usure, but it seems so */ 86 return ioread16(sdev->base + SCOOP_GPRR) & (1 << (offset + 1)); 87 } 88 89 static 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 107 static 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 127 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) 128 { 129 unsigned short gpio_bit; 130 unsigned long flag; 131 struct scoop_dev *sdev = dev_get_drvdata(dev); 132 133 spin_lock_irqsave(&sdev->scoop_lock, flag); 134 gpio_bit = ioread16(sdev->base + SCOOP_GPWR) | bit; 135 iowrite16(gpio_bit, sdev->base + SCOOP_GPWR); 136 spin_unlock_irqrestore(&sdev->scoop_lock, flag); 137 138 return gpio_bit; 139 } 140 141 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) 142 { 143 unsigned short gpio_bit; 144 unsigned long flag; 145 struct scoop_dev *sdev = dev_get_drvdata(dev); 146 147 spin_lock_irqsave(&sdev->scoop_lock, flag); 148 gpio_bit = ioread16(sdev->base + SCOOP_GPWR) & ~bit; 149 iowrite16(gpio_bit, sdev->base + SCOOP_GPWR); 150 spin_unlock_irqrestore(&sdev->scoop_lock, flag); 151 152 return gpio_bit; 153 } 154 155 EXPORT_SYMBOL(set_scoop_gpio); 156 EXPORT_SYMBOL(reset_scoop_gpio); 157 158 unsigned short read_scoop_reg(struct device *dev, unsigned short reg) 159 { 160 struct scoop_dev *sdev = dev_get_drvdata(dev); 161 return ioread16(sdev->base + reg); 162 } 163 164 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data) 165 { 166 struct scoop_dev *sdev = dev_get_drvdata(dev); 167 iowrite16(data, sdev->base + reg); 168 } 169 170 EXPORT_SYMBOL(reset_scoop); 171 EXPORT_SYMBOL(read_scoop_reg); 172 EXPORT_SYMBOL(write_scoop_reg); 173 174 static void check_scoop_reg(struct scoop_dev *sdev) 175 { 176 unsigned short mcr; 177 178 mcr = ioread16(sdev->base + SCOOP_MCR); 179 if ((mcr & 0x100) == 0) 180 iowrite16(0x0101, sdev->base + SCOOP_MCR); 181 } 182 183 #ifdef CONFIG_PM 184 static int scoop_suspend(struct platform_device *dev, pm_message_t state) 185 { 186 struct scoop_dev *sdev = platform_get_drvdata(dev); 187 188 check_scoop_reg(sdev); 189 sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR); 190 iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR); 191 192 return 0; 193 } 194 195 static int scoop_resume(struct platform_device *dev) 196 { 197 struct scoop_dev *sdev = platform_get_drvdata(dev); 198 199 check_scoop_reg(sdev); 200 iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR); 201 202 return 0; 203 } 204 #else 205 #define scoop_suspend NULL 206 #define scoop_resume NULL 207 #endif 208 209 static int __devinit scoop_probe(struct platform_device *pdev) 210 { 211 struct scoop_dev *devptr; 212 struct scoop_config *inf; 213 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 214 int ret; 215 int temp; 216 217 if (!mem) 218 return -EINVAL; 219 220 devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL); 221 if (!devptr) 222 return -ENOMEM; 223 224 spin_lock_init(&devptr->scoop_lock); 225 226 inf = pdev->dev.platform_data; 227 devptr->base = ioremap(mem->start, mem->end - mem->start + 1); 228 229 if (!devptr->base) { 230 ret = -ENOMEM; 231 goto err_ioremap; 232 } 233 234 platform_set_drvdata(pdev, devptr); 235 236 printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base); 237 238 iowrite16(0x0140, devptr->base + SCOOP_MCR); 239 reset_scoop(&pdev->dev); 240 iowrite16(0x0000, devptr->base + SCOOP_CPR); 241 iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR); 242 iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR); 243 244 devptr->suspend_clr = inf->suspend_clr; 245 devptr->suspend_set = inf->suspend_set; 246 247 devptr->gpio.base = -1; 248 249 if (inf->gpio_base != 0) { 250 devptr->gpio.label = dev_name(&pdev->dev); 251 devptr->gpio.base = inf->gpio_base; 252 devptr->gpio.ngpio = 12; /* PA11 = 0, PA12 = 1, etc. up to PA22 = 11 */ 253 devptr->gpio.set = scoop_gpio_set; 254 devptr->gpio.get = scoop_gpio_get; 255 devptr->gpio.direction_input = scoop_gpio_direction_input; 256 devptr->gpio.direction_output = scoop_gpio_direction_output; 257 258 ret = gpiochip_add(&devptr->gpio); 259 if (ret) 260 goto err_gpio; 261 } 262 263 return 0; 264 265 if (devptr->gpio.base != -1) 266 temp = gpiochip_remove(&devptr->gpio); 267 err_gpio: 268 platform_set_drvdata(pdev, NULL); 269 err_ioremap: 270 iounmap(devptr->base); 271 kfree(devptr); 272 273 return ret; 274 } 275 276 static int __devexit scoop_remove(struct platform_device *pdev) 277 { 278 struct scoop_dev *sdev = platform_get_drvdata(pdev); 279 int ret; 280 281 if (!sdev) 282 return -EINVAL; 283 284 if (sdev->gpio.base != -1) { 285 ret = gpiochip_remove(&sdev->gpio); 286 if (ret) { 287 dev_err(&pdev->dev, "Can't remove gpio chip: %d\n", ret); 288 return ret; 289 } 290 } 291 292 platform_set_drvdata(pdev, NULL); 293 iounmap(sdev->base); 294 kfree(sdev); 295 296 return 0; 297 } 298 299 static struct platform_driver scoop_driver = { 300 .probe = scoop_probe, 301 .remove = __devexit_p(scoop_remove), 302 .suspend = scoop_suspend, 303 .resume = scoop_resume, 304 .driver = { 305 .name = "sharp-scoop", 306 }, 307 }; 308 309 static int __init scoop_init(void) 310 { 311 return platform_driver_register(&scoop_driver); 312 } 313 314 subsys_initcall(scoop_init); 315