⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hx4700_core.c

📁 pocket pc hx4700 linux driver
💻 C
字号:
/* Core Hardware driver for Hx4700 (Serial, ASIC3, EGPIOs) * * Copyright (c) 2005 SDG Systems, LLC * * 2005-03-29   Todd Blumer             Converted  basic structure to support hx4700 * 2005-04-30	Todd Blumer		Add IRDA code from H2200 */#include <linux/module.h>#include <linux/version.h>#include <linux/config.h>#include <linux/interrupt.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/pm.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/mach/irq.h>#include <asm/arch/pxa-regs.h>#include <asm/arch/pxa-pm_ll.h>#include <asm/arch/hx4700-gpio.h>#include <asm/arch/hx4700-asic.h>#include <asm/arch/hx4700-core.h>#include <linux/soc/asic3_base.h>#include <asm/hardware/ipaq-asic3.h>#define EGPIO_OFFSET	0#define EGPIO_BASE	(PXA_CS5_PHYS+EGPIO_OFFSET)volatile u_int16_t *egpios;u_int16_t egpio_reg;static int htc_bootloader = 0;	/* Is the stock HTC bootloader installed? */static u32 save[4];static u32 save2[13];/* * may make sense to put egpios elsewhere, but they're here now * since they share some of the same address space with the TI WLAN * * EGPIO register is write-only */voidhx4700_egpio_enable( u_int16_t bits ){	unsigned long flags;	local_irq_save(flags);	egpio_reg |= bits;	*egpios = egpio_reg;	local_irq_restore(flags);}EXPORT_SYMBOL(hx4700_egpio_enable);voidhx4700_egpio_disable( u_int16_t bits ){	unsigned long flags;	local_irq_save(flags);	egpio_reg &= ~bits;	*egpios = egpio_reg;	local_irq_restore(flags);}EXPORT_SYMBOL(hx4700_egpio_disable);inthx4700_udc_detect( void ){	return (ipaq_asic3_read_gpio_status_d(&hx4700_asic3.dev)			& (1 << GPIOD_USBC_DETECT_N)) ? 0 : 1;}static unsigned int serial_irq = 0xffffffff;static voidserial_change_task_handler( void *x ){	unsigned int statusd;	int connected;	statusd = ipaq_asic3_read_gpio_status_d( &hx4700_asic3.dev );	connected = (statusd & (1<<GPIOD_COM_DCD)) != 0;	if (connected)	    set_irq_type( serial_irq, IRQT_FALLING ); 	else	    set_irq_type( serial_irq, IRQT_RISING ); 	SET_HX4700_GPIO( RS232_ON, connected );	printk( KERN_INFO "serial_isr: com_dcd=%d\n", connected );}DECLARE_WORK(serial_change_task, serial_change_task_handler, NULL);static intserial_isr(int irq, void *dev_id, struct pt_regs *regs){	schedule_delayed_work( &serial_change_task, 100 ); /* debounce */	return IRQ_HANDLED;}#ifdef CONFIG_PMstatic int hx4700_suspend(struct device *dev, pm_message_t state){	/* Turn off external clocks here, because hx4700_power and asic3_mmc	 * scared to do so to not hurt each other. (-5 mA) */#if 0	asic3_set_clock_cdex(&hx4700_asic3.dev,		CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1, 0 | 0);#endif	/* 0x20c2 is HTC clock value	 * CLOCK_CDEX_SOURCE		2	 * CLOCK_CDEX_SPI		0	 * CLOCK_CDEX_OWM		0	 *	 * CLOCK_CDEX_PWM0		0	 * CLOCK_CDEX_PWM1		0	 * CLOCK_CDEX_LED0		1	 * CLOCK_CDEX_LED1		1	 *	 * CLOCK_CDEX_LED2		0	 * CLOCK_CDEX_SD_HOST		0	 * CLOCK_CDEX_SD_BUS		0	 * CLOCK_CDEX_SMBUS		0	 *	 * CLOCK_CDEX_CONTROL_CX	0	 * CLOCK_CDEX_EX0		1	 * CLOCK_CDEX_EX1		0	 * */	asic3_set_clock_cdex(&hx4700_asic3.dev, 0xffff, 0x21c2);	*egpios = 0;	/* turn off all egpio power */	/*	 * Note that WEP1 wake up event is used by bootldr to set the	 * LEDS when power is applied/removed for charging.	 */	PWER = PWER_RTC | PWER_GPIO0 | PWER_GPIO1 | PWER_GPIO12 | PWER_WEP1;	// rtc + power + reset + asic3 + wep1	PFER = PWER_GPIO1;				// Falling Edge Detect	PRER = PWER_GPIO0 | PWER_GPIO12;		// Rising Edge Detect	PGSR0 = 0x080DC01C;	PGSR1 = 0x34CF0002;	PGSR2 = 0x0123C18C;	/* PGSR3 = 0x00104202; */	PGSR3 = 0x00100202;	/* These next checks are specifically for charging.  We want to enable	* it if it is already enabled */	/* Check for charge enable, GPIO 72 */	if(GPLR2 & (1 << 8)) {		/* Set it */		PGSR2 |= (1U << 8);	} else {		/* Clear it */		PGSR2 &= ~(1U << 8);	}	/* Check for USB_CHARGE_RATE, GPIO 96 */	if(GPLR3 & (1 << 0)) {		/* Set it */		PGSR3 |= (1U << 0);	} else {		/* Clear it */		PGSR3 &= ~(1U << 0);	}	PCFR = PCFR_GPROD|PCFR_DC_EN|PCFR_GPR_EN|PCFR_OPDE		|PCFR_FP|PCFR_PI2CEN; /* was 0x1091; */	/* The 2<<2 below turns on the Power Island state preservation	 * and counters.  This allows us to wake up bootldr after a	 * period of time, and it can set the LEDs correctly based on	 * the power state.  The bootldr turns it off when it's	 * charged.	 */	PSLR=0xc8000000 | (2 << 2);	/*	 * If we're using bootldr and not the stock HTC bootloader,	 * we want to wake up periodically to see if the charge is full while	 * it is suspended.  We do this with the OS timer 4 in the pxa270.	 */	if (!htc_bootloader) {		OMCR4 = 0x4b;   /* Periodic, self-resetting, 1-second timer */		OSMR4 = 5;      /* Wake up bootldr after x seconds so it can				   figure out what to do with the LEDs. */		OIER |= 0x10;   /* Enable interrupt source for Timer 4 */		OSCR4 = 0;      /* This starts the timer */	}	asic3_set_extcf_select(&hx4700_asic3.dev, ASIC3_EXTCF_OWM_EN, 0);	return 0;}static int hx4700_resume(struct device *dev){	hx4700_egpio_enable(0);	/* check for changes to serial that may have occurred */	schedule_work( &serial_change_task );	return 0;}#else#   define hx4700_suspend NULL#   define hx4700_resume NULL#endifstatic voidhx4700_pxa_ll_pm_suspend(unsigned long resume_addr){	int i;	u32 csum, tmp, *p;	/* Save the 13 words at 0xa0038000. */	for (p = phys_to_virt(0xa0038000), i = 0; i < 13; i++)		save2[i] = p[i];	/* Save the first four words at 0xa0000000. */	for (p = phys_to_virt(0xa0000000), i = 0; i < 4; i++)		save[i] = p[i];	/* Set the first four words at 0xa0000000 to:	 * resume address; MMU control; TLB base addr; domain id */	p[0] = resume_addr;	asm( "mrc\tp15, 0, %0, c1, c0, 0" : "=r" (tmp) );	p[1] = tmp & ~(0x3987);	    /* mmu off */	asm( "mrc\tp15, 0, %0, c2, c0, 0" : "=r" (tmp) );	p[2] = tmp;	/* Shouldn't matter, since MMU will be off. */	asm( "mrc\tp15, 0, %0, c3, c0, 0" : "=r" (tmp) );	p[3] = tmp;	/* Shouldn't matter, since MMU will be off. */	/* Set PSPR to the checksum the HTC bootloader wants to see. */	for (csum = 0, i = 0; i < 52; i++) {		tmp = p[i] & 0x1;		tmp = tmp << 31;		tmp |= tmp >> 1;		csum += tmp;	}	PSPR = csum;}static voidhx4700_pxa_ll_pm_resume(void){	int i;	u32 *p;	/* Restore the first four words at 0xa0000000. */	for (p = phys_to_virt(0xa0000000), i = 0; i < 4; i++)		p[i] = save[i];	/* Restore the 13 words at 0xa0038000. */	for (p = phys_to_virt(0xa0038000), i = 0; i < 13; i++)		p[i] = save2[i];	/* XXX Do we need to flush the cache? */}struct pxa_ll_pm_ops hx4700_ll_pm_ops = {	.suspend = hx4700_pxa_ll_pm_suspend,	.resume  = hx4700_pxa_ll_pm_resume,};static inthx4700_core_probe( struct device *dev ){	unsigned int statusd;	int connected;	struct hx4700_core_funcs *funcs = (struct hx4700_core_funcs *) dev->platform_data;	u32 *bootldr;	int i;	printk( KERN_NOTICE "hx4700 Core Hardware Driver\n" );	funcs->udc_detect = hx4700_udc_detect;	egpios = (volatile u_int16_t *)ioremap_nocache( EGPIO_BASE, sizeof *egpios );	if (!egpios)		return -ENODEV;	/* UART IRQ */        serial_irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE                + GPIOD_COM_DCD;	statusd = ipaq_asic3_read_gpio_status_d( &hx4700_asic3.dev );	connected = (statusd & (1<<GPIOD_COM_DCD)) != 0;	// printk( KERN_INFO "Serial: connected=%d\n", connected );	if (connected)		set_irq_type( serial_irq, IRQT_FALLING ); 	else		set_irq_type( serial_irq, IRQT_RISING );         if (request_irq( serial_irq, serial_isr, SA_INTERRUPT,			    "Hx4700 Serial", NULL ) != 0) {		printk( KERN_ERR "Unable to configure serial port interrupt.\n" );		return -ENODEV;	}	/* Is the stock HTC bootloader installed? */	bootldr = (u32 *) ioremap(PXA_CS0_PHYS, 1024 * 1024);	i = 0x000414dc / 4;	if (bootldr[i]   == 0xe59f1360 && /* ldr r1, [pc, #864] ; power base */	    bootldr[i+1] == 0xe5914008 && /* ldr r4, [r1, #8]   ; PSPR */	    bootldr[i+2] == 0xe1320004) { /* teq r2, r4 */		printk("Stock HTC bootloader detected\n");		htc_bootloader = 1;		pxa_pm_set_ll_ops(&hx4700_ll_pm_ops);	}	iounmap(bootldr);	return 0;}static inthx4700_core_remove( struct device *dev ){	struct hx4700_core_funcs *funcs = (struct hx4700_core_funcs *) dev->platform_data;	if (egpios != NULL)		iounmap( (void *)egpios );	if (serial_irq != 0xffffffff)		free_irq( serial_irq, NULL );	funcs->udc_detect = NULL;	return 0;}struct device_driver hx4700_core_driver = {	.name     = "hx4700-core",	.bus	  = &platform_bus_type,	.probe    = hx4700_core_probe,	.remove   = hx4700_core_remove,	.suspend  = hx4700_suspend,	.resume   = hx4700_resume,};static int __inithx4700_core_init( void ){	return driver_register( &hx4700_core_driver );}static void __exithx4700_core_exit( void ){	driver_unregister( &hx4700_core_driver );}module_init( hx4700_core_init );module_exit( hx4700_core_exit );MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC");MODULE_DESCRIPTION("hx4700 Core Hardware Driver");MODULE_LICENSE("GPL");/* vim600: set noexpandtab sw=8 ts=8 :*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -