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