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 #define SCOOP_REG(d,adr) (*(volatile unsigned short*)(d +(adr))) 34 35 struct scoop_dev { 36 void *base; 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 SCOOP_REG(sdev->base,SCOOP_MCR) = 0x0100; // 00 48 SCOOP_REG(sdev->base,SCOOP_CDR) = 0x0000; // 04 49 SCOOP_REG(sdev->base,SCOOP_CCR) = 0x0000; // 10 50 SCOOP_REG(sdev->base,SCOOP_IMR) = 0x0000; // 18 51 SCOOP_REG(sdev->base,SCOOP_IRM) = 0x00FF; // 14 52 SCOOP_REG(sdev->base,SCOOP_ISR) = 0x0000; // 1C 53 SCOOP_REG(sdev->base,SCOOP_IRM) = 0x0000; 54 } 55 56 unsigned short set_scoop_gpio(struct device *dev, unsigned short bit) 57 { 58 unsigned short gpio_bit; 59 unsigned long flag; 60 struct scoop_dev *sdev = dev_get_drvdata(dev); 61 62 spin_lock_irqsave(&sdev->scoop_lock, flag); 63 gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) | bit; 64 SCOOP_REG(sdev->base, SCOOP_GPWR) = gpio_bit; 65 spin_unlock_irqrestore(&sdev->scoop_lock, flag); 66 67 return gpio_bit; 68 } 69 70 unsigned short reset_scoop_gpio(struct device *dev, unsigned short bit) 71 { 72 unsigned short gpio_bit; 73 unsigned long flag; 74 struct scoop_dev *sdev = dev_get_drvdata(dev); 75 76 spin_lock_irqsave(&sdev->scoop_lock, flag); 77 gpio_bit = SCOOP_REG(sdev->base, SCOOP_GPWR) & ~bit; 78 SCOOP_REG(sdev->base,SCOOP_GPWR) = gpio_bit; 79 spin_unlock_irqrestore(&sdev->scoop_lock, flag); 80 81 return gpio_bit; 82 } 83 84 EXPORT_SYMBOL(set_scoop_gpio); 85 EXPORT_SYMBOL(reset_scoop_gpio); 86 87 unsigned short read_scoop_reg(struct device *dev, unsigned short reg) 88 { 89 struct scoop_dev *sdev = dev_get_drvdata(dev); 90 return SCOOP_REG(sdev->base,reg); 91 } 92 93 void write_scoop_reg(struct device *dev, unsigned short reg, unsigned short data) 94 { 95 struct scoop_dev *sdev = dev_get_drvdata(dev); 96 SCOOP_REG(sdev->base,reg)=data; 97 } 98 99 EXPORT_SYMBOL(reset_scoop); 100 EXPORT_SYMBOL(read_scoop_reg); 101 EXPORT_SYMBOL(write_scoop_reg); 102 103 static void check_scoop_reg(struct scoop_dev *sdev) 104 { 105 unsigned short mcr; 106 107 mcr = SCOOP_REG(sdev->base, SCOOP_MCR); 108 if ((mcr & 0x100) == 0) 109 SCOOP_REG(sdev->base, SCOOP_MCR) = 0x0101; 110 } 111 112 #ifdef CONFIG_PM 113 static int scoop_suspend(struct platform_device *dev, pm_message_t state) 114 { 115 struct scoop_dev *sdev = platform_get_drvdata(dev); 116 117 check_scoop_reg(sdev); 118 sdev->scoop_gpwr = SCOOP_REG(sdev->base, SCOOP_GPWR); 119 SCOOP_REG(sdev->base, SCOOP_GPWR) = (sdev->scoop_gpwr & ~sdev->suspend_clr) | sdev->suspend_set; 120 121 return 0; 122 } 123 124 static int scoop_resume(struct platform_device *dev) 125 { 126 struct scoop_dev *sdev = platform_get_drvdata(dev); 127 128 check_scoop_reg(sdev); 129 SCOOP_REG(sdev->base,SCOOP_GPWR) = sdev->scoop_gpwr; 130 131 return 0; 132 } 133 #else 134 #define scoop_suspend NULL 135 #define scoop_resume NULL 136 #endif 137 138 int __init scoop_probe(struct platform_device *pdev) 139 { 140 struct scoop_dev *devptr; 141 struct scoop_config *inf; 142 struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 143 144 if (!mem) 145 return -EINVAL; 146 147 devptr = kzalloc(sizeof(struct scoop_dev), GFP_KERNEL); 148 if (!devptr) 149 return -ENOMEM; 150 151 spin_lock_init(&devptr->scoop_lock); 152 153 inf = pdev->dev.platform_data; 154 devptr->base = ioremap(mem->start, mem->end - mem->start + 1); 155 156 if (!devptr->base) { 157 kfree(devptr); 158 return -ENOMEM; 159 } 160 161 platform_set_drvdata(pdev, devptr); 162 163 printk("Sharp Scoop Device found at 0x%08x -> 0x%08x\n",(unsigned int)mem->start,(unsigned int)devptr->base); 164 165 SCOOP_REG(devptr->base, SCOOP_MCR) = 0x0140; 166 reset_scoop(&pdev->dev); 167 SCOOP_REG(devptr->base, SCOOP_CPR) = 0x0000; 168 SCOOP_REG(devptr->base, SCOOP_GPCR) = inf->io_dir & 0xffff; 169 SCOOP_REG(devptr->base, SCOOP_GPWR) = inf->io_out & 0xffff; 170 171 devptr->suspend_clr = inf->suspend_clr; 172 devptr->suspend_set = inf->suspend_set; 173 174 return 0; 175 } 176 177 static int scoop_remove(struct platform_device *pdev) 178 { 179 struct scoop_dev *sdev = platform_get_drvdata(pdev); 180 if (sdev) { 181 iounmap(sdev->base); 182 kfree(sdev); 183 platform_set_drvdata(pdev, NULL); 184 } 185 return 0; 186 } 187 188 static struct platform_driver scoop_driver = { 189 .probe = scoop_probe, 190 .remove = scoop_remove, 191 .suspend = scoop_suspend, 192 .resume = scoop_resume, 193 .driver = { 194 .name = "sharp-scoop", 195 }, 196 }; 197 198 int __init scoop_init(void) 199 { 200 return platform_driver_register(&scoop_driver); 201 } 202 203 subsys_initcall(scoop_init); 204