--- arch/arm/mach-pxa/Kconfig | 10 arch/arm/mach-pxa/Makefile | 1 arch/arm/mach-pxa/hx2750.c | 450 ++++++++++++++++++++++++++++++++++++++ arch/arm/mach-pxa/hx2750_test.c | 433 ++++++++++++++++++++++++++++++++++++ arch/arm/mach-pxa/pm.c | 5 arch/arm/mach-pxa/pxa25x.c | 4 arch/arm/mach-pxa/pxa27x.c | 4 include/asm-arm/arch-pxa/hx2750.h | 90 +++++++ 8 files changed, 995 insertions(+), 2 deletions(-) --- /dev/null +++ linux-2.6.24-rc1/include/asm-arm/arch-pxa/hx2750.h @@ -0,0 +1,90 @@ +/* + * Hardware specific definitions for iPAQ hx2750 + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#ifndef __ASM_ARCH_HX2750_H +#define __ASM_ARCH_HX2750_H 1 + +/* + * HX2750 (Non Standard) GPIO Definitions + */ + +#define HX2750_GPIO_KEYPWR (0) /* Power button */ +#define HX2750_GPIO_BATTCOVER1 (9) /* Battery Cover Switch */ +#define HX2750_GPIO_CF_IRQ (11) /* CF IRQ? */ +#define HX2750_GPIO_USBCONNECT (12) /* USB Connected? */ +#define HX2750_GPIO_CF_DETECT (13) /* CF Card Detect? */ +#define HX2750_GPIO_EXTPWR (14) /* External Power Detect */ +#define HX2750_GPIO_BATLVL (15) /* Battery Level Detect */ +#define HX2750_GPIO_CF_PWR (17) /* CF Power? */ +#define HX2750_GPIO_SR_STROBE (18) /* Shift Register Strobe */ +#define HX2750_GPIO_CHARGE (22) /* Charging Enable (active low) */ +#define HX2750_GPIO_TSC2101_SS (24) /* TSC2101 SS# */ +#define HX2750_GPIO_BTPWR (27) /* Bluetooth Power? */ +#define HX2750_GPIO_BATTCOVER2 (33) /* Battery Cover Switch */ +#define HX2750_GPIO_SD_DETECT (38) /* MMC Card Detect */ +#define HX2750_GPIO_SR_CLK1 (52) /* Shift Register Clock */ +#define HX2750_GPIO_SR_CLK2 (53) +#define HX2750_GPIO_CF_WIFIIRQ (54) /* CF Wifi IRQ? */ +#define HX2750_GPIO_GPIO_DIN (88) /* Shift Register Data */ +#define HX2750_GPIO_KEYLEFT (90) /* Left button */ +#define HX2750_GPIO_KEYRIGHT (91) /* Right button */ +#define HX2750_GPIO_KEYCAL (93) /* Calander button */ +#define HX2750_GPIO_KEYTASK (94) /* Task button */ +#define HX2750_GPIO_KEYSIDE (95) /* Side button */ +#define HX2750_GPIO_KEYENTER (96) /* Enter Button*/ +#define HX2750_GPIO_KEYCON (97) /* Contacts button */ +#define HX2750_GPIO_KEYMAIL (98) /* Mail button */ +#define HX2750_GPIO_BIOPWR (99) /* BIO Reader Power? */ +#define HX2750_GPIO_KEYUP (100) /* Up button */ +#define HX2750_GPIO_KEYDOWN (101) /* Down button*/ +#define HX2750_GPIO_SD_READONLY (103) /* MMC/SD Write Protection */ +#define HX2750_GPIO_LEDMAIL (106) /* Green Mail LED */ +#define HX2750_GPIO_HP_JACK (108) /* Head Phone Jack Present */ +#define HX2750_GPIO_PENDOWN (117) /* Touch Screen Pendown */ + + +//#define HX2750_GPIO_ () /* */ + +/* + * HX2750 Interrupts + */ +#define HX2750_IRQ_GPIO_EXTPWR IRQ_GPIO(HX2750_GPIO_EXTPWR) +#define HX2750_IRQ_GPIO_SD_DETECT IRQ_GPIO(HX2750_GPIO_SD_DETECT) +#define HX2750_IRQ_GPIO_PENDOWN IRQ_GPIO(HX2750_GPIO_PENDOWN) +#define HX2750_IRQ_GPIO_CF_DETECT IRQ_GPIO(HX2750_GPIO_CF_DETECT) +#define HX2750_IRQ_GPIO_CF_IRQ IRQ_GPIO(HX2750_GPIO_CF_IRQ) +#define HX2750_IRQ_GPIO_CF_WIFIIRQ IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ) + +/* + * HX2750 Extra GPIO Definitions + */ + +#define HX2750_EGPIO_WIFI_PWR (1 << 11) /* Wifi power */ +#define HX2750_EGPIO_LCD_PWR (1 << 10) /* LCD Power */ +#define HX2750_EGPIO_BL_PWR (1 << 9) /* Backlight LED Power */ +#define HX2750_EGPIO_8 (1 << 8) /* */ +#define HX2750_EGPIO_7 (1 << 7) /* */ +#define HX2750_EGPIO_SD_PWR (1 << 6) /* SD Power */ +#define HX2750_EGPIO_TSC_PWR (1 << 5) /* TS Power */ +#define HX2750_EGPIO_CF0_RESET (1 << 4) /* CF0 Reset */ +#define HX2750_EGPIO_CF1_RESET (1 << 3) /* CF1 Reset */ +#define HX2750_EGPIO_2 (1 << 2) /* Power/Red LED Related?*/ +#define HX2750_EGPIO_1 (1 << 1) /* Power/Red LED Related?*/ +#define HX2750_EGPIO_PWRLED (1 << 0) /* Power/Red LED Related?*/ + + +void hx2750_set_egpio(unsigned int gpio); +void hx2750_clear_egpio(unsigned int gpio); + + +#endif /* __ASM_ARCH_HX2750_H */ + --- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/Makefile +++ linux-2.6.24-rc1/arch/arm/mach-pxa/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_MACH_POODLE) += poodle.o corgi_ssp.o obj-$(CONFIG_MACH_TOSA) += tosa.o obj-$(CONFIG_MACH_EM_X270) += em-x270.o +obj-$(CONFIG_MACH_HX2750) += hx2750.o hx2750_test.o ifeq ($(CONFIG_MACH_ZYLONITE),y) obj-y += zylonite.o --- /dev/null +++ linux-2.6.24-rc1/arch/arm/mach-pxa/hx2750_test.c @@ -0,0 +1,433 @@ +/* + * HP iPAQ hx2750 Test Development Code + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +static int prodval; + +/* + * Sysfs functions + */ +static ssize_t test1_show(struct device *dev, char *buf) +{ + unsigned long rp; + + asm ("mrc p15, 0, %0, cr1, cr0;\n" :"=r"(rp) ); + printk("%lx\n",rp); + + asm ("mrc p15, 0, %0, cr1, cr1;\n" :"=r"(rp) ); + printk("%lx\n",rp); + + asm ("mrc p15, 0, %0, cr2, cr0;\n" :"=r"(rp) ); + printk("%lx\n",rp); + + asm ("mrc p15, 0, %0, cr3, cr0;\n" :"=r"(rp) ); + printk("%lx\n",rp); + + asm ("mrc p15, 0, %0, cr13, cr0;\n" :"=r"(rp) ); + printk("%lx\n",rp); + + return sprintf(buf, "%d\n",prodval); +} +extern void tsc2101_print_miscdata(struct device *dev); +extern struct platform_device tsc2101_device; + +static ssize_t test1_store(struct device *dev, const char *buf, size_t count) +{ + prodval = simple_strtoul(buf, NULL, 10); + + tsc2101_print_miscdata(&tsc2101_device.dev); + + return count; +} + +static DEVICE_ATTR(test1, 0644, test1_show, test1_store); + +static ssize_t test2_show(struct device *dev, char *buf) +{ + printk(KERN_ERR "SSCR0_P2: %08x\n", SSCR0_P2); + printk(KERN_ERR "SSCR1_P2: %08x\n", SSCR1_P2); + printk(KERN_ERR "SSSR_P2: %08x\n", SSSR_P2); + printk(KERN_ERR "SSITR_P2: %08x\n", SSITR_P2); + printk(KERN_ERR "SSDR_P2: %08x\n", SSDR_P2); + printk(KERN_ERR "SSTO_P2: %08x\n", SSTO_P2); + printk(KERN_ERR "SSPSP_P2: %08x\n", SSPSP_P2); + + hx2750_ssp_init2(); + + printk(KERN_ERR "SSCR0_P2: %08x\n", SSCR0_P2); + printk(KERN_ERR "SSCR1_P2: %08x\n", SSCR1_P2); + printk(KERN_ERR "SSSR_P2: %08x\n", SSSR_P2); + printk(KERN_ERR "SSITR_P2: %08x\n", SSITR_P2); + printk(KERN_ERR "SSDR_P2: %08x\n", SSDR_P2); + printk(KERN_ERR "SSTO_P2: %08x\n", SSTO_P2); + printk(KERN_ERR "SSPSP_P2: %08x\n", SSPSP_P2); + + return sprintf(buf, "%d\n",0); +} + +static DEVICE_ATTR(test2, 0444, test2_show, NULL); + +extern unsigned int hx2750_egpio_current; + +static ssize_t setegpio_show(struct device *dev, char *buf) +{ + return sprintf(buf, "%x\n",hx2750_egpio_current); +} + +static ssize_t setegpio_store(struct device *dev, const char *buf, size_t count) +{ + unsigned int val = simple_strtoul(buf, NULL, 10); + + hx2750_set_egpio(1 << val); + + return count; +} + +static DEVICE_ATTR(setegpio, 0644, setegpio_show, setegpio_store); + +static ssize_t clregpio_show(struct device *dev, char *buf) +{ + return sprintf(buf, "%x\n",hx2750_egpio_current); +} + +static ssize_t gpio_show(struct device *dev, char *buf) +{ + int i; + + printk(KERN_ERR "GPIO# D S A INTER\n"); + + for (i=0;i<119;i++) { + printk(KERN_ERR " %3d: ",i); + if (GPDR(i) & GPIO_bit(i)) + printk("O "); + else + printk("I "); + printk("%d ",(GPLR(i) & GPIO_bit(i)) != 0); + printk("%d ",((GAFR(i) & (0x3 << (((i) & 0xf)*2)))) >> (((i) & 0xf)*2) ); + if (GEDR(i) & GPIO_bit(i)) + printk("ED "); + if (GRER(i) & GPIO_bit(i)) + printk("RE "); + if (GFER(i) & GPIO_bit(i)) + printk("FE "); + + printk("\n"); + } + return sprintf(buf, "EGPIO: %x\n",hx2750_egpio_current); +} + +static ssize_t clregpio_store(struct device *dev, const char *buf, size_t count) +{ + unsigned int val = simple_strtoul(buf, NULL, 10); + + hx2750_clear_egpio(1 << val); + + return count; +} + +static DEVICE_ATTR(clregpio, 0644, clregpio_show, clregpio_store); + + +static ssize_t gpioclr_store(struct device *dev, const char *buf, size_t count) +{ + int prod; + prod = simple_strtoul(buf, NULL, 10); + + GPCR(prod) = GPIO_bit(prod); + + return count; +} + +static DEVICE_ATTR(gpioclr, 0644, gpio_show, gpioclr_store); + +static ssize_t gpioset_store(struct device *dev, const char *buf, size_t count) +{ + int prod; + prod = simple_strtoul(buf, NULL, 10); + + GPSR(prod) = GPIO_bit(prod); + + return count; +} + +static DEVICE_ATTR(gpioset, 0644, gpio_show, gpioset_store); + + +static ssize_t ssp2read_store(struct device *dev, const char *buf, size_t count) +{ + unsigned int val = simple_strtoul(buf, NULL, 16); + + printk("Read: %08x\n",hx2750_ssp2_read(val)); + + return count; +} + +static DEVICE_ATTR(ssp2read, 0200, NULL, ssp2read_store); + +static ssize_t ssp2write_store(struct device *dev, const char *buf, size_t count) +{ + unsigned int val = simple_strtoul(buf, NULL, 16); + + printk("Write: %08x\n",hx2750_ssp2_write(val)); + + return count; +} + +static DEVICE_ATTR(ssp2write, 0200, NULL, ssp2write_store); + + +static ssize_t sspr_store(struct device *dev, const char *buf, size_t count) +{ + unsigned long val,ret; + val = simple_strtoul(buf, NULL, 0); + + hx2750_tsc2101_send(1<<15,val,&ret,1); + + printk("Response: %x\n",ret); + + return count; +} + +static DEVICE_ATTR(sspr, 0200, NULL, sspr_store); + +static ssize_t sspw_store(struct device *dev, const char *buf, size_t count) +{ + int val,ret; + sscanf(buf, "%lx %lx", &val, &ret); + + hx2750_tsc2101_send(0,val,&ret,1); + + return count; +} + +static DEVICE_ATTR(sspw, 0200, NULL, sspw_store); + + +extern struct pm_ops pxa_pm_ops; +extern void pxa_cpu_resume(void); +extern unsigned long pxa_pm_pspr_value; + +static int (*pxa_pm_enter_orig)(suspend_state_t state); + +//static struct { +// u32 ffier, fflcr, ffmcr, ffspr, ffisr, ffdll, ffdlh; +//} sys_ctx; + +u32 resstruct[20]; + +static int hx2750_pxa_pm_enter(suspend_state_t state) +{ + int i; + u32 save[10]; + + PWER = 0xC0000003;// | PWER_RTC; + PFER = 0x00000003; + PRER = 0x00000003; + + PGSR0=0x00000018; + PGSR1=0x00000380; + PGSR2=0x00800000; + PGSR3=0x00500400; + + //PVCR=0x494; or 0x14; + //PVCR=0x14; + //PCMD0=0x41f; + //i=PISR; + //PICR=0x00000062; + + //PCFR=0x457; + //PCFR=0x70; // Does not resume from sleep + PCFR=0x077; // was 0x477 + PSLR=0xff100004; + + resstruct[0]=0x0000b4e6; + resstruct[1]=0x00000001; + resstruct[2]=virt_to_phys(pxa_cpu_resume); + resstruct[3]=0xffffffff; //value for r0 + + resstruct[14]=0x00000078; //mcr 15, 0, r0, cr1, cr0, {0} + resstruct[15]=0x00000000; //mcr 15, 0, r0, cr1, cr1, {0} 0xffffffff + resstruct[16]=0xa0000000; //mcr 15, 0, r0, cr2, cr0, {0} 0xa0748000 + resstruct[17]=0x00000001; //mcr 15, 0, r0, cr3, cr0, {0} 0x00000015 + resstruct[18]=0x00000000; //mcr 15, 0, r0, cr13, cr0, {0} 0x00000000 + + pxa_pm_pspr_value=virt_to_phys(&resstruct[0]); + + hx2750_send_egpio(3); + + pxa_gpio_mode(87 | GPIO_OUT | GPIO_DFLT_HIGH); + + //sys_ctx.ffier = FFIER; + //sys_ctx.fflcr = FFLCR; + //sys_ctx.ffmcr = FFMCR; + //sys_ctx.ffspr = FFSPR; + //sys_ctx.ffisr = FFISR; + //FFLCR |= 0x80; + //sys_ctx.ffdll = FFDLL; + //sys_ctx.ffdlh = FFDLH; + //FFLCR &= 0xef; + + pxa_pm_enter_orig(state); + + //FFMCR = sys_ctx.ffmcr; + //FFSPR = sys_ctx.ffspr; + //FFLCR = sys_ctx.fflcr; + //FFLCR |= 0x80; + //FFDLH = sys_ctx.ffdlh; + //FFDLL = sys_ctx.ffdll; + //FFLCR = sys_ctx.fflcr; + //FFISR = sys_ctx.ffisr; + //FFLCR = 0x07; + //FFIER = sys_ctx.ffier; + + return 0; +} + +static irqreturn_t hx2750_charge_int(int irq, void *dev_id, struct pt_regs *regs) +{ + if ((GPLR(HX2750_GPIO_EXTPWR) & GPIO_bit(HX2750_GPIO_EXTPWR)) == 0) { + printk("Charging On\n"); + GPCR(HX2750_GPIO_CHARGE); + } else { + printk("Charging Off\n"); + GPSR(HX2750_GPIO_CHARGE); + } + + return IRQ_HANDLED; +} + + + + +static irqreturn_t hx2750_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + printk("Input %d changed.\n", irq-32); + + return IRQ_HANDLED; +} + + +static int __init hx2750_test_probe(struct device *dev) +{ + pxa_gpio_mode(21 | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(HX2750_GPIO_CHARGE | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(83 | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(HX2750_GPIO_BIOPWR | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(116 | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(118 | GPIO_OUT | GPIO_DFLT_HIGH); + + + //pxa_gpio_mode(HX2750_GPIO_CF_PWR | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(HX2750_GPIO_CF_PWR | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(HX2750_GPIO_BTPWR | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(79 | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(85 | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(HX2750_GPIO_LEDMAIL | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(107 | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(114 | GPIO_OUT | GPIO_DFLT_LOW); + + pxa_gpio_mode(HX2750_GPIO_BATTCOVER1 | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_BATTCOVER2 | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_CF_IRQ | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_USBCONNECT | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_CF_DETECT | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_EXTPWR | GPIO_IN); + + pxa_gpio_mode(HX2750_GPIO_BATLVL | GPIO_IN); + //pxa_gpio_mode(HX2750_GPIO_CF_WIFIIRQ | GPIO_IN); + pxa_gpio_mode(80 | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_HP_JACK | GPIO_IN); + pxa_gpio_mode(115 | GPIO_IN); + pxa_gpio_mode(119 | GPIO_IN); + + request_irq(IRQ_GPIO(HX2750_GPIO_BATLVL), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + //request_irq(IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + request_irq(IRQ_GPIO(80), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + request_irq(IRQ_GPIO(115), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + request_irq(IRQ_GPIO(119), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + request_irq(IRQ_GPIO(HX2750_GPIO_SR_CLK2), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + + //request_irq(IRQ_GPIO(10), hx2750_interrupt, SA_INTERRUPT, "hx2750test", NULL); + + set_irq_type(IRQ_GPIO(HX2750_GPIO_BATLVL),IRQT_BOTHEDGE); + //set_irq_type(IRQ_GPIO(HX2750_GPIO_CF_WIFIIRQ),IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO(80),IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO(115),IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO(119),IRQT_BOTHEDGE); + set_irq_type(IRQ_GPIO(HX2750_GPIO_SR_CLK2),IRQT_BOTHEDGE); + + //set_irq_type(IRQ_GPIO(10),IRQT_BOTHEDGE); + + printk("hx2750 Test Code Initialized.\n"); + device_create_file(dev, &dev_attr_test1); + device_create_file(dev, &dev_attr_test2); + device_create_file(dev, &dev_attr_setegpio); + device_create_file(dev, &dev_attr_clregpio); + device_create_file(dev, &dev_attr_gpioset); + device_create_file(dev, &dev_attr_gpioclr); + device_create_file(dev, &dev_attr_sspr); + device_create_file(dev, &dev_attr_sspw); + device_create_file(dev, &dev_attr_ssp2read); + device_create_file(dev, &dev_attr_ssp2write); + + request_irq(HX2750_IRQ_GPIO_EXTPWR, hx2750_charge_int, SA_INTERRUPT, "hx2750_extpwr", NULL); + set_irq_type(HX2750_IRQ_GPIO_EXTPWR, IRQT_BOTHEDGE); + + pxa_pm_enter_orig=pxa_pm_ops.enter; + pxa_pm_ops.enter=hx2750_pxa_pm_enter; + + return 0; +} + +static struct device_driver hx2750_test_driver = { + .name = "hx2750-test", + .bus = &platform_bus_type, + .probe = hx2750_test_probe, +// .remove = hx2750_bl_remove, +// .suspend = hx2750_bl_suspend, +// .resume = hx2750_bl_resume, +}; + + +static int __init hx2750_test_init(void) +{ + return driver_register(&hx2750_test_driver); +} + + +static void __exit hx2750_test_exit(void) +{ + driver_unregister(&hx2750_test_driver); +} + +module_init(hx2750_test_init); +module_exit(hx2750_test_exit); + +MODULE_AUTHOR("Richard Purdie "); +MODULE_DESCRIPTION("iPAQ hx2750 Backlight Driver"); +MODULE_LICENSE("GPLv2"); --- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/Kconfig +++ linux-2.6.24-rc1/arch/arm/mach-pxa/Kconfig @@ -83,6 +83,15 @@ bool "Sharp PXA270 models (SL-Cxx00)" select PXA27x +config MACH_HX2750 + bool "HP iPAQ hx2750" + select PXA27x + select PXA_KEYS + select MFD_TSC2101 + select PXA_SSP + help + This enables support for the HP iPAQ HX2750 handheld. + endchoice endif @@ -181,3 +190,4 @@ help Enable support for PXA2xx SSP ports endif + --- /dev/null +++ linux-2.6.24-rc1/arch/arm/mach-pxa/hx2750.c @@ -0,0 +1,450 @@ +/* + * Machine definitions for HP iPAQ hx2750 + * + * Copyright 2005 Openedhand Ltd. + * + * Author: Richard Purdie + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "generic.h" + + +/* + * Keys Support + */ +static struct pxa_keys_button hx2750_button_table[] = { + { KEY_POWER, HX2750_GPIO_KEYPWR, PXAKEY_PWR_KEY }, + { KEY_LEFT, HX2750_GPIO_KEYLEFT, 0 }, + { KEY_RIGHT, HX2750_GPIO_KEYRIGHT, 0 }, + { KEY_KP0, HX2750_GPIO_KEYCAL, 0 }, + { KEY_KP1, HX2750_GPIO_KEYTASK, 0 }, + { KEY_KP2, HX2750_GPIO_KEYSIDE, 0 }, + { KEY_ENTER, HX2750_GPIO_KEYENTER, 0 }, + { KEY_KP3, HX2750_GPIO_KEYCON, 0 }, //KEY_CONTACTS + { KEY_MAIL, HX2750_GPIO_KEYMAIL, 0 }, + { KEY_UP, HX2750_GPIO_KEYUP, 0 }, + { KEY_DOWN, HX2750_GPIO_KEYDOWN, 0 }, +}; + +static struct pxa_keys_platform_data hx2750_pxa_keys_data = { + .buttons = hx2750_button_table, + .nbuttons = ARRAY_SIZE(hx2750_button_table), +}; + +static struct platform_device hx2750_pxa_keys = { + .name = "pxa2xx-keys", + .dev = { + .platform_data = &hx2750_pxa_keys_data, + }, +}; + + +/* + * Backlight Device + */ +extern struct platform_device pxafb_device; + +static struct platform_device hx2750_bl_device = { + .name = "hx2750-bl", + .id = -1, +// .dev = { +// .parent = &pxafb_device.dev, +// } +}; + + +/* + * UDC/USB + */ +static int hx2750_udc_is_connected (void) +{ + return GPLR0 & GPIO_bit(HX2750_GPIO_USBCONNECT); +} + +//static void hx2750_udc_command (int cmd) +//{ +//} + +static struct pxa2xx_udc_mach_info hx2750_udc_mach_info = { + .udc_is_connected = hx2750_udc_is_connected, +// .udc_command = hx2750_udc_command, +}; + + +/* + * SSP Devices Setup + */ +static struct ssp_dev hx2750_ssp_dev1; +static struct ssp_dev hx2750_ssp_dev2; +static struct ssp_dev hx2750_ssp_dev3; + +void hx2750_ssp_init(void) +{ + pxa_gpio_mode(HX2750_GPIO_TSC2101_SS | GPIO_OUT | GPIO_DFLT_HIGH); + + if (ssp_init(&hx2750_ssp_dev1, 1, 0)) + printk(KERN_ERR "Unable to register SSP1 handler!\n"); + else { + ssp_disable(&hx2750_ssp_dev1); + ssp_config(&hx2750_ssp_dev1, (SSCR0_Motorola | (SSCR0_DSS & 0x0f )), SSCR1_SPH, 0, SSCR0_SerClkDiv(6)); + ssp_enable(&hx2750_ssp_dev1); + hx2750_set_egpio(HX2750_EGPIO_TSC_PWR); + } + +// if (ssp_init(&hx2750_ssp_dev2, 2, 0)) +// printk(KERN_ERR "Unable to register SSP2 handler!\n"); +// else { +// ssp_disable(&hx2750_ssp_dev2); +// ssp_config(&hx2750_ssp_dev2, (SSCR0_TI | (SSCR0_DSS & 0x09 )), 0, 0, SSCR0_SerClkDiv(140)); +// ssp_enable(&hx2750_ssp_dev2); +// } +// + if (ssp_init(&hx2750_ssp_dev3, 3, 0)) + printk(KERN_ERR "Unable to register SSP3 handler!\n"); + else { + ssp_disable(&hx2750_ssp_dev3); + ssp_config(&hx2750_ssp_dev3, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), SSCR1_SPO | SSCR1_SPH, 0, SSCR0_SerClkDiv(166)); + ssp_enable(&hx2750_ssp_dev3); + } + + printk("SSP Devices Initialised\n"); + + return; +} + +struct ssp_state ssp1; + +void hx2750_ssp_suspend(void) +{ + ssp_disable(&hx2750_ssp_dev1); + ssp_save_state(&hx2750_ssp_dev1,&ssp1); + hx2750_clear_egpio(HX2750_EGPIO_TSC_PWR); +} + +void hx2750_ssp_resume(void) +{ + hx2750_set_egpio(HX2750_EGPIO_TSC_PWR); + ssp_restore_state(&hx2750_ssp_dev1,&ssp1); + ssp_enable(&hx2750_ssp_dev1); +} + +void hx2750_ssp_init2(void) +{ + printk("Stage 1: %x\n",CKEN); + if (ssp_init(&hx2750_ssp_dev2, 2, 0)) + printk(KERN_ERR "Unable to register SSP2 handler!\n"); + else { + printk("Stage 2: %x\n",CKEN); + ssp_disable(&hx2750_ssp_dev2); + printk("Stage 3: %x\n",CKEN); + ssp_config(&hx2750_ssp_dev2, (SSCR0_TI | (SSCR0_DSS & 0x09 )) | SSCR0_SSE, 0, 0, SSCR0_SerClkDiv(212)); + printk("Stage 4: %x\n",CKEN); + ssp_enable(&hx2750_ssp_dev2); + printk("Stage 5: %x\n",CKEN); + } + printk("SSP Device2 Initialised\n"); + + printk("Sent: 0x3ff\n"); + ssp_write_word(&hx2750_ssp_dev2,0x3ff); + + return; +} + +void hx2750_ssp2_reset(void) +{ + ssp_write_word(&hx2750_ssp_dev2,0x000); + ssp_write_word(&hx2750_ssp_dev2,0x000); + +} + +unsigned long hx2750_ssp2_read(void) +{ + u32 ret = 0; + ssp_read_word(&hx2750_ssp_dev2, &ret); + return ret; +} + +void hx2750_ssp2_write(unsigned long data) +{ + ssp_write_word(&hx2750_ssp_dev2, data); +} + + +/* + * Extra hx2750 Specific GPIOs + */ +void hx2750_send_egpio(unsigned int val) +{ + int i; + + GPCR0 = GPIO_bit(HX2750_GPIO_SR_STROBE); + GPCR1 = GPIO_bit(HX2750_GPIO_SR_CLK1); + + for (i=0;i<12;i++) { + if (val & 0x01) + GPSR2 = GPIO_bit(HX2750_GPIO_GPIO_DIN); + else + GPCR2 = GPIO_bit(HX2750_GPIO_GPIO_DIN); + val >>= 1; + GPSR1 = GPIO_bit(HX2750_GPIO_SR_CLK1); + GPCR1 = GPIO_bit(HX2750_GPIO_SR_CLK1); + } + + GPSR0 = GPIO_bit(HX2750_GPIO_SR_STROBE); + GPCR0 = GPIO_bit(HX2750_GPIO_SR_STROBE); +} + +EXPORT_SYMBOL(hx2750_send_egpio); + +unsigned int hx2750_egpio_current; + +void hx2750_set_egpio(unsigned int gpio) +{ + hx2750_egpio_current|=gpio; + + hx2750_send_egpio(hx2750_egpio_current); +} +EXPORT_SYMBOL(hx2750_set_egpio); + +void hx2750_clear_egpio(unsigned int gpio) +{ + hx2750_egpio_current&=~gpio; + + hx2750_send_egpio(hx2750_egpio_current); +} +EXPORT_SYMBOL(hx2750_clear_egpio); + + +/* + * Touchscreen/Sound/Battery Status + */ +void hx2750_tsc2101_send(int read, int command, int *values, int numval) +{ + u32 ret = 0; + int i; + + GPCR0 = GPIO_bit(HX2750_GPIO_TSC2101_SS); + + ssp_write_word(&hx2750_ssp_dev1, command | read); + /* dummy read */ + ssp_read_word(&hx2750_ssp_dev1, &ret); + + for (i=0; i < numval; i++) { + if (read) { + ssp_write_word(&hx2750_ssp_dev1, 0); + ssp_read_word(&hx2750_ssp_dev1, &values[i]); + } else { + ssp_write_word(&hx2750_ssp_dev1, values[i]); + ssp_read_word(&hx2750_ssp_dev1, &ret); + } + } + + GPSR0 = GPIO_bit(HX2750_GPIO_TSC2101_SS); +} + +static int hx2750_tsc2101_pendown(void) +{ + if ((GPLR(HX2750_GPIO_PENDOWN) & GPIO_bit(HX2750_GPIO_PENDOWN)) == 0) + return 1; + return 0; +} + +static struct tsc2101_platform_info hx2750_tsc2101_info = { + .send = hx2750_tsc2101_send, + .suspend = hx2750_ssp_suspend, + .resume = hx2750_ssp_resume, + .irq = HX2750_IRQ_GPIO_PENDOWN, + .pendown = hx2750_tsc2101_pendown, +}; + +struct platform_device tsc2101_device = { + .name = "tsc2101", + .dev = { + .platform_data = &hx2750_tsc2101_info, + //.parent = &corgissp_device.dev, + }, + .id = -1, +}; + + +/* + * MMC/SD Device + * + * The card detect interrupt isn't debounced so we delay it by 250ms + * to give the card a chance to fully insert/eject. + */ +static struct pxamci_platform_data hx2750_mci_platform_data; + +static int hx2750_mci_init(struct device *dev, irq_handler_t hx2750_detect_int, void *data) +{ + int err; + + /* + * setup GPIO for PXA27x MMC controller + */ + pxa_gpio_mode(GPIO32_MMCCLK_MD); + pxa_gpio_mode(GPIO112_MMCCMD_MD); + pxa_gpio_mode(GPIO92_MMCDAT0_MD); + pxa_gpio_mode(GPIO109_MMCDAT1_MD); + pxa_gpio_mode(GPIO110_MMCDAT2_MD); + pxa_gpio_mode(GPIO111_MMCDAT3_MD); + pxa_gpio_mode(HX2750_GPIO_SD_DETECT | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_SD_READONLY | GPIO_IN); + + hx2750_mci_platform_data.detect_delay = msecs_to_jiffies(250); + + err = request_irq(HX2750_IRQ_GPIO_SD_DETECT, hx2750_detect_int, + IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "MMC card detect", data); + if (err) { + printk(KERN_ERR "hx2750_mci_init: MMC/SD: can't request MMC card detect IRQ\n"); + return -1; + } + + return 0; +} + +static void hx2750_mci_setpower(struct device *dev, unsigned int vdd) +{ + struct pxamci_platform_data* p_d = dev->platform_data; + + if (( 1 << vdd) & p_d->ocr_mask) + hx2750_set_egpio(HX2750_EGPIO_SD_PWR); + else + hx2750_clear_egpio(HX2750_EGPIO_SD_PWR); +} + +static void hx2750_mci_exit(struct device *dev, void *data) +{ + free_irq(HX2750_IRQ_GPIO_SD_DETECT, data); +} + +static struct pxamci_platform_data hx2750_mci_platform_data = { + .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34, + .init = hx2750_mci_init, + .setpower = hx2750_mci_setpower, + .exit = hx2750_mci_exit, +}; + + +/* + * FrameBuffer + */ +static struct pxafb_mode_info hx2750_pxafb_modes = { + .pixclock = 288462, + .xres = 240, + .yres = 320, + .bpp = 16, + .hsync_len = 20, + .left_margin = 42, + .right_margin = 18, + .vsync_len = 4, + .upper_margin = 3, + .lower_margin = 4, + .sync = 0, +}; + +static struct pxafb_mach_info hx2750_pxafb_info = { + .modes = &hx2750_pxafb_modes, + .num_modes = 1, + .fixed_modes = 1, + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_PixFlEdg | LCCR3_OutEnH, + .pxafb_backlight_power = NULL, +}; + + +/* + * Test Device + */ +static struct platform_device hx2750_test_device = { + .name = "hx2750-test", + .id = -1, +}; + + +/* Initialization code */ +static struct platform_device *devices[] __initdata = { + &hx2750_bl_device, + &hx2750_test_device, + &hx2750_pxa_keys, + &tsc2101_device, +}; + +static void __init hx2750_init( void ) +{ + PWER = 0xC0000003;// | PWER_RTC; + PFER = 0x00000003; + PRER = 0x00000003; + + PGSR0=0x00000018; + PGSR1=0x00000380; + PGSR2=0x00800000; + PGSR3=0x00500400; + + //PCFR |= PCFR_OPDE; + PCFR=0x77; + PSLR=0xff100000; + //PCFR=0x10; - does not return from suspend + + //PCFR= 0x00004040; + //PSLR= 0xff400f04; + + /* Setup Extra GPIO Bank access */ + pxa_gpio_mode(HX2750_GPIO_GPIO_DIN | GPIO_OUT | GPIO_DFLT_HIGH); + pxa_gpio_mode(HX2750_GPIO_SR_CLK1 | GPIO_OUT | GPIO_DFLT_LOW); + pxa_gpio_mode(HX2750_GPIO_SR_CLK2 | GPIO_IN); + pxa_gpio_mode(HX2750_GPIO_SR_STROBE | GPIO_OUT | GPIO_DFLT_LOW); + + /* Init Extra GPIOs - Bootloader reset default is 0x484 */ + /* This is 0xe84 */ + hx2750_set_egpio(HX2750_EGPIO_2 | HX2750_EGPIO_7 | HX2750_EGPIO_LCD_PWR | HX2750_EGPIO_BL_PWR | HX2750_EGPIO_WIFI_PWR); + + pxa_set_udc_info(&hx2750_udc_mach_info); + pxa_set_mci_info(&hx2750_mci_platform_data); + set_pxa_fb_info(&hx2750_pxafb_info); + hx2750_ssp_init(); + platform_add_devices (devices, ARRAY_SIZE (devices)); +} + + +MACHINE_START(HX2750, "HP iPAQ HX2750") + .phys_io = 0x40000000, + .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc, + .boot_params = 0xa0000100, + .map_io = pxa_map_io, + .init_irq = pxa_init_irq, + .timer = &pxa_timer, + .init_machine = hx2750_init, +MACHINE_END + --- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pm.c +++ linux-2.6.24-rc1/arch/arm/mach-pxa/pm.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -91,6 +92,9 @@ .enter = pxa_pm_enter, }; +unsigned long pxa_pm_pspr_value; +extern void pxa_cpu_resume(void); + static int __init pxa_pm_init(void) { if (!pxa_cpu_pm_fns) { @@ -104,6 +108,7 @@ return -ENOMEM; } + pxa_pm_pspr_value=virt_to_phys(pxa_cpu_resume); suspend_set_ops(&pxa_pm_ops); return 0; } --- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pxa27x.c +++ linux-2.6.24-rc1/arch/arm/mach-pxa/pxa27x.c @@ -259,6 +259,8 @@ RESTORE(PSTR); } +extern unsigned long pxa_pm_pspr_value; + void pxa27x_cpu_pm_enter(suspend_state_t state) { extern void pxa_cpu_standby(void); @@ -281,7 +283,7 @@ break; case PM_SUSPEND_MEM: /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); + PSPR = pxa_pm_pspr_value; pxa27x_cpu_suspend(PWRMODE_SLEEP); break; } --- linux-2.6.24-rc1.orig/arch/arm/mach-pxa/pxa25x.c +++ linux-2.6.24-rc1/arch/arm/mach-pxa/pxa25x.c @@ -200,6 +200,8 @@ RESTORE(PSTR); } +extern unsigned long pxa_pm_pspr_value; + static void pxa25x_cpu_pm_enter(suspend_state_t state) { CKEN = 0; @@ -207,7 +209,7 @@ switch (state) { case PM_SUSPEND_MEM: /* set resume return address */ - PSPR = virt_to_phys(pxa_cpu_resume); + PSPR = pxa_pm_pspr_value; pxa25x_cpu_suspend(PWRMODE_SLEEP); break; }