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