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/hardware/scoop.h> 20 21 /* PCMCIA to Scoop linkage 22 23 There is no easy way to link multiple scoop devices into one 24 single entity for the pxa2xx_pcmcia device so this structure 25 is used which is setup by the platform code. 26 27 This file is never modular so this symbol is always 28 accessile to the board support files. 29 */ 30 struct scoop_pcmcia_config *platform_scoop_config; 31 EXPORT_SYMBOL(platform_scoop_config); 32 33 struct scoop_dev { 34 void __iomem *base; 35 spinlock_t scoop_lock; 36 unsigned short suspend_clr; 37 unsigned short suspend_set; 38 u32 scoop_gpwr; 39 }; 40 41 void reset_scoop(struct device *dev) 42 { 43 struct scoop_dev *sdev = dev_get_drvdata(dev); 44 45 iowrite16(0x0100, sdev->base + SCOOP_MCR); // 00 46 iowrite16(0x0000, sdev->base + SCOOP_CDR); // 04 47 iowrite16(0x0000, sdev->base + SCOOP_CCR); // 10 48 iowrite16(0x0000, sdev->base + SCOOP_IMR); // 18 49 iowrite16(0x00FF, sdev->base + SCOOP_IRM); // 14 50 iowrite16(0x0000, sdev->base + SCOOP_ISR); // 1C 51 iowrite16(0x0000, sdev->base + SCOOP_IRM); 52 } 53 54 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) 55 { 56 unsigned short gpio_bit; 57 unsigned long flag; 58 struct scoop_dev *sdev = dev_get_drvdata(dev); 59 60 spin_lock_irqsave(&sdev->scoop_lock, flag); 61 gpio_bit = ioread16(sdev->base + SCOOP_GPWR) | bit; 62 iowrite16(gpio_bit, sdev->base + SCOOP_GPWR); 63 spin_unlock_irqrestore(&sdev->scoop_lock, flag); 64 65 return gpio_bit; 66 } 67 68 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) 69 { 70 unsigned short gpio_bit; 71 unsigned long flag; 72 struct scoop_dev *sdev = dev_get_drvdata(dev); 73 74 spin_lock_irqsave(&sdev->scoop_lock, flag); 75 gpio_bit = ioread16(sdev->base + SCOOP_GPWR) & ~bit; 76 iowrite16(gpio_bit, sdev->base + SCOOP_GPWR); 77 spin_unlock_irqrestore(&sdev->scoop_lock, flag); 78 79 return gpio_bit; 80 } 81 82 EXPORT_SYMBOL(set_scoop_gpio); 83 EXPORT_SYMBOL(reset_scoop_gpio); 84 85 unsigned short read_scoop_reg(struct device *dev, unsigned short reg) 86 { 87 struct scoop_dev *sdev = dev_get_drvdata(dev); 88 return ioread16(sdev->base + reg); 89 } 90 91 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data) 92 { 93 struct scoop_dev *sdev = dev_get_drvdata(dev); 94 iowrite16(data, sdev->base + reg); 95 } 96 97 EXPORT_SYMBOL(reset_scoop); 98 EXPORT_SYMBOL(read_scoop_reg); 99 EXPORT_SYMBOL(write_scoop_reg); 100 101 static void check_scoop_reg(struct scoop_dev *sdev) 102 { 103 unsigned short mcr; 104 105 mcr = ioread16(sdev->base + SCOOP_MCR); 106 if ((mcr & 0x100) == 0) 107 iowrite16(0x0101, sdev->base + SCOOP_MCR); 108 } 109 110 #ifdef CONFIG_PM 111 static int scoop_suspend(struct platform_device *dev, pm_message_t state) 112 { 113 struct scoop_dev *sdev = platform_get_drvdata(dev); 114 115 check_scoop_reg(sdev); 116 sdev->scoop_gpwr = ioread16(sdev->base + SCOOP_GPWR); 117 iowrite16((sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set, sdev->base + SCOOP_GPWR); 118 119 return 0; 120 } 121 122 static int scoop_resume(struct platform_device *dev) 123 { 124 struct scoop_dev *sdev = platform_get_drvdata(dev); 125 126 check_scoop_reg(sdev); 127 iowrite16(sdev->scoop_gpwr, sdev->base + SCOOP_GPWR); 128 129 return 0; 130 } 131 #else 132 #define scoop_suspend NULL 133 #define scoop_resume NULL 134 #endif 135 136 static int __devinit scoop_probe(struct platform_device *pdev) 137 { 138 struct scoop_dev *devptr; 139 struct scoop_config *inf; 140 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 141 142 if (!mem) 143 return -EINVAL; 144 145 devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL); 146 if (!devptr) 147 return -ENOMEM; 148 149 spin_lock_init(&devptr->scoop_lock); 150 151 inf = pdev->dev.platform_data; 152 devptr->base = ioremap(mem->start, mem->end - mem->start + 1); 153 154 if (!devptr->base) { 155 kfree(devptr); 156 return -ENOMEM; 157 } 158 159 platform_set_drvdata(pdev, devptr); 160 161 printk("Sharp Scoop Device found at 0x%08x -> 0x%8p\n",(unsigned int)mem->start, devptr->base); 162 163 iowrite16(0x0140, devptr->base + SCOOP_MCR); 164 reset_scoop(&pdev->dev); 165 iowrite16(0x0000, devptr->base + SCOOP_CPR); 166 iowrite16(inf->io_dir & 0xffff, devptr->base + SCOOP_GPCR); 167 iowrite16(inf->io_out & 0xffff, devptr->base + SCOOP_GPWR); 168 169 devptr->suspend_clr = inf->suspend_clr; 170 devptr->suspend_set = inf->suspend_set; 171 172 return 0; 173 } 174 175 static int __devexit scoop_remove(struct platform_device *pdev) 176 { 177 struct scoop_dev *sdev = platform_get_drvdata(pdev); 178 if (sdev) { 179 iounmap(sdev->base); 180 kfree(sdev); 181 platform_set_drvdata(pdev, NULL); 182 } 183 return 0; 184 } 185 186 static struct platform_driver scoop_driver = { 187 .probe = scoop_probe, 188 .remove = __devexit_p(scoop_remove), 189 .suspend = scoop_suspend, 190 .resume = scoop_resume, 191 .driver = { 192 .name = "sharp-scoop", 193 }, 194 }; 195 196 static int __init scoop_init(void) 197 { 198 return platform_driver_register(&scoop_driver); 199 } 200 201 subsys_initcall(scoop_init); 202