Index: Kconfig =================================================================== RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/htcblueangel/Kconfig,v retrieving revision 1.8 diff -u -r1.8 Kconfig --- Kconfig 17 Dec 2006 12:23:37 -0000 1.8 +++ Kconfig 30 Dec 2006 19:53:03 -0000 @@ -46,10 +46,6 @@ Support for function keys Pull-out keyboard not yet working -menuconfig MACH_BLUEANGEL_AUDIO - tristate "HTC Blueangel audio support" - depends on MACH_BLUEANGEL - menuconfig MACH_BLUEANGEL_BATTERY tristate "HTC Blueangel battery support" depends on MACH_BLUEANGEL @@ -68,7 +64,12 @@ ---help--- Required for using data transfer via GPRS, CSD and FAX +menuconfig MACH_BLUEANGEL_TSC2200 + tristate "HTC Blueangel tsc2200 support" + depends on MACH_BLUEANGEL + ---help--- + Required for using tsc2200 + config MACH_BLUEANGEL_UDC bool "HTC Blueangel UDC support" depends on MACH_BLUEANGEL - Index: Makefile =================================================================== RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/htcblueangel/Makefile,v retrieving revision 1.7 diff -u -r1.7 Makefile --- Makefile 17 Dec 2006 12:23:37 -0000 1.7 +++ Makefile 30 Dec 2006 19:53:03 -0000 @@ -3,7 +3,7 @@ # obj-$(CONFIG_MACH_BLUEANGEL) += blueangel.o -obj-$(CONFIG_MACH_BLUEANGEL) += blueangel_tsc2200.o +obj-$(CONFIG_MACH_BLUEANGEL_TSC2200) += blueangel_tsc2200.o obj-$(CONFIG_MACH_BLUEANGEL_LCD) += blueangel_lcd.o obj-$(CONFIG_MACH_BLUEANGEL_DS1WM) += blueangel_ds1wm.o obj-$(CONFIG_MACH_BLUEANGEL_BACKLIGHT) += blueangel_bl.o @@ -16,3 +16,4 @@ obj-$(CONFIG_MACH_BLUEANGEL_ROM) += blueangel_rom.o obj-$(CONFIG_MACH_BLUEANGEL_DPRAM) += blueangel_dpram.o obj-$(CONFIG_MACH_BLUEANGEL_UDC) += blueangel_udc.o +obj-$(CONFIG_MACH_BLUEANGEL_DS1WM) += blueangel_ds1wm.o Index: blueangel_battery.c =================================================================== RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/htcblueangel/blueangel_battery.c,v retrieving revision 1.5 diff -u -r1.5 blueangel_battery.c --- blueangel_battery.c 22 Dec 2006 03:57:06 -0000 1.5 +++ blueangel_battery.c 30 Dec 2006 19:53:04 -0000 @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -23,15 +25,54 @@ #include +#include "../../../../drivers/w1/w1.h" +#include "../../../../drivers/w1/slaves/w1_ds2760.h" + #ifdef DEBUG #define dprintk(x...) printk(x) #else #define dprintk(x...) #endif +#define BATTERY_CHECK_INTERVAL (HZ * 60) /* every 60 seconds */ + +#define BLUEANGEL_BATTERY_MAX_VOLTAGE 4400 /* My measurements */ +#define BLUEANGEL_BATTERY_MIN_VOLTAGE 0 /* Maybe incorrect */ +#define BLUEANGEL_BATTERY_MAX_CURRENT 950 /* MUST BE MEASURED */ +#define BLUEANGEL_BATTERY_MIN_CURRENT -950 /* Maybe incorrect */ +#define BLUEANGEL_BATTERY_MIN_CHARGE 0 /* Maybe incorrect */ + +/* DS2760 device */ +struct device *ds2760_dev = NULL; + +/* Cache the battery status for this many seconds. */ +#define STATUS_CACHE_TIME (HZ * 1) +static struct ds2760_status battery_status; + + extern struct platform_device blueangel_tsc2200; +extern struct platform_device blueangel_asic3; + DEFINE_LED_TRIGGER(ledtrig_cradle); +DEFINE_LED_TRIGGER(ledtrig_phone); + +/* w1_samcop device */ +static struct workqueue_struct *probe_q; +static struct work_struct probe_work; + +/* battery monitor */ +static struct timer_list monitor_timer; +static struct workqueue_struct *monitor_q; +static struct work_struct monitor_work; + +static int battery_charge_state; +#define BATTERY_STATE_UNKNOWN 0 +#define BATTERY_DISCHARGING 1 +#define BATTERY_CHARGING 2 +#define BATTERY_FULL 3 +/* AC present? */ +static int power_status; static void bat_tsc2200_start_conv_scan(void) @@ -47,18 +88,6 @@ TSC2200_CTRLREG_ADC_PV (TSC2200_CTRLREG_ADC_PV_500uS) ); } -static void bat_tsc2200_start_conv_temp(void) -{ - tsc2200_write(&blueangel_tsc2200.dev, TSC2200_CTRLREG_REF, 31); - tsc2200_write(&blueangel_tsc2200.dev, TSC2200_CTRLREG_ADC, - TSC2200_CTRLREG_ADC_AD3 | - TSC2200_CTRLREG_ADC_AD1 | - TSC2200_CTRLREG_ADC_RES (TSC2200_CTRLREG_ADC_RES_12BITP) | - TSC2200_CTRLREG_ADC_AVG (TSC2200_CTRLREG_ADC_8AVG) | - TSC2200_CTRLREG_ADC_CL (TSC2200_CTRLREG_ADC_CL_2MHZ_12BIT) | - TSC2200_CTRLREG_ADC_PV (TSC2200_CTRLREG_ADC_PV_500uS) ); -} - static void bat_tsc2200_stop_conv(void) { tsc2200_write(&blueangel_tsc2200.dev, TSC2200_CTRLREG_ADC, @@ -70,6 +99,60 @@ TSC2200_CTRLREG_ADC_PV (TSC2200_CTRLREG_ADC_PV_500uS) ); } +int blueangel_battery_read_status(void) +{ + if (jiffies < (battery_status.update_time + STATUS_CACHE_TIME)) + return 0; + + if (!ds2760_dev) + return 0; + + if (!w1_ds2760_status(ds2760_dev, &battery_status)) { + printk("call to w1_ds2760_status failed (0x%08x)\n", + (unsigned int)ds2760_dev); + return 1; + } + + return 0; +} + +static int +blueangel_battery_match_callback(struct device *dev, void *data) +{ + struct w1_slave *sl; + + if (!(dev->driver && dev->driver->name && + (strcmp(dev->driver->name, "w1_slave_driver") == 0))) + return 0; + + sl = container_of(dev, struct w1_slave, dev); + + /* DS2760 w1 slave device names begin with the family number 0x30. */ + if (strncmp(sl->name, "30-", 3) != 0) + return 0; + + return 1; +} + +void +blueangel_battery_probe_work(void *data) +{ + struct bus_type *bus; + + /* Get the battery w1 slave device. */ + bus = find_bus("w1"); + if (bus) + ds2760_dev = bus_find_device(bus, NULL, NULL, + blueangel_battery_match_callback); + + if (!ds2760_dev) { + /* No DS2760 device found; try again later. */ + //queue_delayed_work(probe_q, &probe_work, HZ * 5); + return; + } +} + + static int blueangel_battery_get_status(struct battery *bat) { dprintk("%s: in.\n", __FUNCTION__); @@ -108,116 +191,176 @@ static int blueangel_battery_get_voltage(struct battery *bat) { int retval; - - dprintk("%s: in.\n", __FUNCTION__); - - //down_interruptible(&tsc2200_sem); - //tsc2200_lock(&blueangel_tsc2200.dev); - bat_tsc2200_start_conv_scan(); - - while ( !(tsc2200_read(&blueangel_tsc2200.dev, TSC2200_CTRLREG_ADC) & 0x4000) && - !tsc2200_dav(&blueangel_tsc2200.dev )) { - dprintk("B2: %X\n", tsc2200_read(&blueangel_tsc2200.dev, TSC2200_CTRLREG_ADC)); - mdelay(1); - } - - retval = tsc2200_read(&blueangel_tsc2200.dev, TSC2200_DATAREG_AUX2); - - bat_tsc2200_stop_conv(); - //tsc2200_unlock(&blueangel_tsc2200.dev); - //up(&tsc2200_sem); + blueangel_battery_read_status(); + retval = battery_status.voltage_mV; return retval; } static int blueangel_battery_get_temp(struct battery *bat) { int retval; + blueangel_battery_read_status(); + retval = battery_status.temp_C; - dprintk("%s: in.\n", __FUNCTION__); + return retval; +} +blueangel_battery_get_max_voltage(struct battery *bat) +{ + return BLUEANGEL_BATTERY_MAX_VOLTAGE; +} - //down_interruptible(&tsc2200_sem); - //tsc2200_lock(&blueangel_tsc2200.dev); - bat_tsc2200_start_conv_temp(); +int +blueangel_battery_get_min_voltage(struct battery *bat) +{ + return BLUEANGEL_BATTERY_MIN_VOLTAGE; +} - while ( !(tsc2200_read(&blueangel_tsc2200.dev, TSC2200_CTRLREG_ADC) & 0x4000) && - !tsc2200_dav(&blueangel_tsc2200.dev)) { - dprintk("1: %X\n", tsc2200_read(&blueangel_tsc2200.dev, TSC2200_CTRLREG_ADC)); - mdelay(1); - } - - retval = tsc2200_read(&blueangel_tsc2200.dev, TSC2200_DATAREG_TEMP1); - dprintk("retval=0x%x\n", retval); - - bat_tsc2200_stop_conv(); - //tsc2200_unlock(&blueangel_tsc2200.dev); - //up(&tsc2200_sem); - dprintk("%s: out\n", __FUNCTION__); - return retval; +int +blueangel_battery_get_max_current(struct battery *bat) +{ + return BLUEANGEL_BATTERY_MAX_CURRENT; +} + +int +blueangel_battery_get_min_current(struct battery *bat) +{ + return BLUEANGEL_BATTERY_MIN_CURRENT; +} + +int +blueangel_battery_get_current(struct battery *bat) +{ + blueangel_battery_read_status(); + return battery_status.current_mA; +} +int +blueangel_battery_get_max_charge(struct battery *bat) +{ + blueangel_battery_read_status(); + return battery_status.rated_capacity; } +int +blueangel_battery_get_min_charge(struct battery *bat) +{ + return BLUEANGEL_BATTERY_MIN_CHARGE; +} + +int +blueangel_battery_get_charge(struct battery *bat) +{ + blueangel_battery_read_status(); + return battery_status.accum_current_mAh; +} + + struct battery battery_dev = { - .name = "Main battery", + .name = "main", .id = "battery0", .get_voltage = blueangel_battery_get_voltage, - .get_status = blueangel_battery_get_status, - //.get_temp = blueangel_battery_get_temp, + .get_min_voltage = blueangel_battery_get_min_voltage, + .get_max_voltage = blueangel_battery_get_max_voltage, + .get_current = blueangel_battery_get_current, + .get_min_current = blueangel_battery_get_min_current, + .get_max_current = blueangel_battery_get_max_current, + .get_charge = blueangel_battery_get_charge, + .get_min_charge = blueangel_battery_get_min_charge, + .get_max_charge = blueangel_battery_get_max_charge, + .get_temp = blueangel_battery_get_temp, + .get_status = blueangel_battery_get_status, + }; struct battery battery_dev1 = { - .name = "Backup battery", + .name = "backup", .id = "battery1", .get_voltage = blueangel_battery_get_voltage1, .get_status = blueangel_battery_get_status, - //.get_temp = blueangel_battery_get_tempi1, }; +static irqreturn_t +blueangel_ac_plug_isr (int isr, void *data) +{ + + /* Update the LED status right away, for timely feedback. */ + /* Set the proper charging rate. */ + if (!(asic3_get_gpio_status_d(&blueangel_asic3.dev) & GPIOD_AC_CHARGER_N)) { + power_status = APM_AC_ONLINE; + } + if (!(GPLR(GPIO_NR_BLUEANGEL_USB_DETECT_N) & GPIO_bit(GPIO_NR_BLUEANGEL_USB_DETECT_N))) { + power_status = APM_AC_ONLINE; + } + if (power_status) { + /* Start off with a solid LED; if we're charging, + the LED state will be updated when the queued work runs. */ + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_event(ledtrig_cradle, LED_FULL); + #endif + } else { + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_event(ledtrig_cradle, LED_OFF); + #endif + } + + /* Force the data to be re-read. */ + battery_status.update_time = 0; + + /* Wait a few seconds to let the DS2760 update its current reading. */ + queue_delayed_work(monitor_q, &monitor_work, HZ * 7); + + return IRQ_HANDLED; +} + + static void blueangel_battery_get_power_status (struct apm_power_info *info) { - int val; - int val1; - int full=0x8ea; - int empty=0x8a3; - - int full1=0xb0f; - int empty1=0x8a3; - val=blueangel_battery_get_voltage(NULL); - val1=blueangel_battery_get_voltage1(NULL); - - info->battery_life = (val1-empty)*100/(full-empty); - if (info->battery_life < 0 || info->battery_life > 100) - printk("battery voltage (0x%x) not within [0x%x,0x%x]. Please report.\n", val, full, empty); - if (info->battery_life < 0) - info->battery_life = 0; - if (info->battery_life > 100) - info->battery_life = 100; + blueangel_battery_read_status(); + info->ac_line_status = APM_AC_OFFLINE; - if (!(asic3_get_gpio_status_d(&blueangel_tsc2200.dev) & GPIOD_AC_CHARGER_N)) { + if (!(asic3_get_gpio_status_d(&blueangel_asic3.dev) & GPIOD_AC_CHARGER_N)) { info->ac_line_status = APM_AC_ONLINE; } if (!(GPLR(GPIO_NR_BLUEANGEL_USB_DETECT_N) & GPIO_bit(GPIO_NR_BLUEANGEL_USB_DETECT_N))) { info->ac_line_status = APM_AC_ONLINE; } - info->units=APM_UNITS_MINS; - info->time = 360 * info->battery_life/100; /* time remaining */ - info->battery_flag = 0; - if (info->ac_line_status == APM_AC_OFFLINE) { + power_status = info->ac_line_status; + + if (info->ac_line_status == APM_AC_ONLINE && current > 0) { #ifdef CONFIG_LEDS_TRIGGERS - led_trigger_event(ledtrig_cradle, LED_OFF); + led_trigger_event(ledtrig_cradle, LED_FULL); #endif - info->battery_status = APM_BATTERY_STATUS_CRITICAL; - if(info->battery_life > 5) { - info->battery_status = APM_BATTERY_STATUS_LOW; - } - if(info->battery_life > 20) { - info->battery_status = APM_BATTERY_STATUS_HIGH; - } - } else { - info->battery_status = APM_BATTERY_STATUS_CHARGING; + info->battery_status = APM_BATTERY_STATUS_CHARGING; + } else { #ifdef CONFIG_LEDS_TRIGGERS - led_trigger_event(ledtrig_cradle, LED_FULL); + led_trigger_event(ledtrig_cradle, LED_OFF); #endif - } + + info->battery_status = battery_status.accum_current_mAh > + ((battery_status.rated_capacity * 75) / 100) ? + APM_BATTERY_STATUS_HIGH : + battery_status.accum_current_mAh > + ((battery_status.rated_capacity* 25) / 100) ? + APM_BATTERY_STATUS_LOW : APM_BATTERY_STATUS_CRITICAL; + } + + info->battery_flag = info->battery_status; + + if (battery_status.rated_capacity) + info->battery_life = (battery_status.accum_current_mAh * 100) / + battery_status.rated_capacity; + + if (info->battery_life > 100) + info->battery_life = 100; + if (info->battery_life < 0) + info->battery_life = 0; + + if (battery_status.current_mA) { + info->time = - ((battery_status.accum_current_mAh * 6000) / + battery_status.current_mA) / 100; + info->units = APM_UNITS_MINS; + } else + info->units = APM_UNITS_UNKNOWN; } static int bat_setup(void) @@ -227,17 +370,131 @@ return 0; } -static int __init bat_init(void) +static void +blueangel_battery_timer(unsigned long data) { - bat_setup(); - blueangel_battery_get_voltage(NULL); - blueangel_battery_get_voltage1(NULL); - blueangel_battery_get_temp(NULL); - apm_get_power_status = blueangel_battery_get_power_status; + queue_work(monitor_q, &monitor_work); + mod_timer(&monitor_timer, jiffies + BATTERY_CHECK_INTERVAL); +} + +void +blueangel_battery_update_status(void *data) +{ + static int full_counter; + + blueangel_battery_read_status(); + + if (battery_charge_state == BATTERY_STATE_UNKNOWN) + full_counter = 0; + + /* Set the proper charging rate. */ + if (!(asic3_get_gpio_status_d(&blueangel_asic3.dev) & GPIOD_AC_CHARGER_N)) { + power_status = APM_AC_ONLINE; + } + if (!(GPLR(GPIO_NR_BLUEANGEL_USB_DETECT_N) & GPIO_bit(GPIO_NR_BLUEANGEL_USB_DETECT_N))) { + power_status = APM_AC_ONLINE; + } + if (power_status) { + + asic3_set_gpio_out_c(&blueangel_asic3.dev,1 << GPIOC_CHARGER_MODE, 1 << GPIOC_CHARGER_MODE); + + if (battery_status.current_mA > 10) { + + battery_charge_state = BATTERY_CHARGING; + full_counter = 0; + + } else if (battery_status.current_mA < 10 && + battery_charge_state != BATTERY_FULL) { + + /* Don't consider the battery to be full unless + * we've seen the current < 10 mA at least two + * consecutive times. */ + + full_counter++; + + if (full_counter < 2) + battery_charge_state = BATTERY_CHARGING; + else { + + unsigned char acr[2]; + + acr[0] = (battery_status.rated_capacity * 4) >> 8; + acr[1] = (battery_status.rated_capacity * 4) & 0xff; + + if (w1_ds2760_write(ds2760_dev, acr, + DS2760_CURRENT_ACCUM_MSB, 2) < 2) + printk(KERN_ERR "ACR reset failed\n"); + battery_charge_state = BATTERY_FULL; + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_event(ledtrig_phone, LED_FULL); + #endif + } + } + + if (battery_charge_state == BATTERY_CHARGING) { + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_event(ledtrig_cradle, LED_FULL); + #endif + } else { + + /* Set the LED solid while on AC and not charging. */ + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_event(ledtrig_phone, LED_FULL); + led_trigger_event(ledtrig_cradle, LED_OFF); + #endif + } + + } else { + + battery_charge_state = BATTERY_DISCHARGING; + full_counter = 0; + asic3_set_gpio_out_c(&blueangel_asic3.dev,1 << GPIOC_CHARGER_MODE, 0); + + /* Turn off the LED while unplugged from AC. */ #ifdef CONFIG_LEDS_TRIGGERS - led_trigger_register_simple("charge", &ledtrig_cradle); + led_trigger_event(ledtrig_cradle, LED_OFF); #endif + } + +} + + + +static int __init bat_init(void) +{ + bat_setup(); + + battery_charge_state = BATTERY_STATE_UNKNOWN; + + /* Install an interrupt handler for AC plug/unplug. */ + set_irq_type(IRQ_GPIO(GPIO_NR_BLUEANGEL_USB_DETECT_N), IRQT_BOTHEDGE); + request_irq(IRQ_GPIO(GPIO_NR_BLUEANGEL_USB_DETECT_N), blueangel_ac_plug_isr, SA_SAMPLE_RANDOM, + "AC plug", NULL); + + /* Create a workqueue in which the battery monitor will run. */ + monitor_q = create_singlethread_workqueue("battmon"); + INIT_WORK(&monitor_work, blueangel_battery_update_status, NULL); + + /* Create a timer to run the battery monitor every + BATTERY_CHECK_INTERVAL seconds. */ + init_timer(&monitor_timer); + monitor_timer.function = blueangel_battery_timer; + monitor_timer.data = 0; + /* Start the first monitor task a few seconds from now. */ + mod_timer(&monitor_timer, jiffies + HZ * 10); + + apm_get_power_status = blueangel_battery_get_power_status; + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_register_simple("charge", &ledtrig_cradle); + led_trigger_register_simple("phone", &ledtrig_phone); + #endif + + /* Get the DS2760 W1 device. */ + probe_q = create_singlethread_workqueue("battmonprb"); + INIT_WORK(&probe_work, blueangel_battery_probe_work, NULL); + blueangel_battery_probe_work(NULL); + //enable_irq(IRQ_GPIO(GPIO_NR_BLUEANGEL_USB_DETECT_N)); return 0; } @@ -246,14 +503,32 @@ apm_get_power_status = NULL; battery_class_unregister(&battery_dev); battery_class_unregister(&battery_dev1); - #ifdef CONFIG_LEDS_TRIGGERS - led_trigger_unregister_simple(ledtrig_cradle); - #endif + + disable_irq(IRQ_GPIO(GPIO_NR_BLUEANGEL_USB_DETECT_N)); + free_irq(IRQ_GPIO(GPIO_NR_BLUEANGEL_USB_DETECT_N), NULL); + + + cancel_delayed_work(&monitor_work); + flush_workqueue(monitor_q); + destroy_workqueue(monitor_q); + + cancel_delayed_work(&probe_work); + flush_workqueue(probe_q); + destroy_workqueue(probe_q); + + if (ds2760_dev) + put_device(ds2760_dev); + #ifdef CONFIG_LEDS_TRIGGERS + led_trigger_event(ledtrig_phone, LED_OFF); + led_trigger_unregister_simple(ledtrig_phone); + led_trigger_event(ledtrig_cradle, LED_OFF); + led_trigger_unregister_simple(ledtrig_cradle); + #endif } module_init(bat_init) module_exit(bat_exit) MODULE_AUTHOR("Matthias Burghardt"); -MODULE_DESCRIPTION("Battery (TI TSC2200) support for the HTC Blueangel"); +MODULE_DESCRIPTION("Battery (TI TSC2200) and DS2760 upport for the HTC Blueangel"); MODULE_LICENSE("GPL"); Index: blueangel_ds1wm.c =================================================================== RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/htcblueangel/blueangel_ds1wm.c,v retrieving revision 1.5 diff -u -r1.5 blueangel_ds1wm.c --- blueangel_ds1wm.c 17 Dec 2006 12:23:37 -0000 1.5 +++ blueangel_ds1wm.c 30 Dec 2006 19:53:04 -0000 @@ -36,7 +36,7 @@ .flags = IORESOURCE_MEM, }, [1] = { - .start = 0, +// .start = 0, .flags = IORESOURCE_IRQ, } @@ -75,9 +75,8 @@ int irq; printk("HTC Blueangel DS1WM driver\n"); irq = asic3_irq_base(&blueangel_asic3.dev) + BLUEANGEL_OWM_IRQ; - - enable_irq(irq); blueangel_ds1wm_resources[1].start = irq; + blueangel_ds1wm_resources[1].end = irq; if (clk_register(&ds1wm_clk) < 0) printk(KERN_ERR "failed to register DS1WM clock\n"); @@ -97,13 +96,14 @@ platform_device_put(blueangel_ds1wm); printk("blueangel_ds1wm: failed to add platform device\n"); } + printk("HTC Blueangel DS1WM registered\n"); return ret; } static void blueangel_ds1wm_exit(void) { - disable_irq(asic3_irq_base(&blueangel_asic3.dev) + BLUEANGEL_OWM_IRQ); + //disable_irq(asic3_irq_base(&blueangel_asic3.dev) + BLUEANGEL_OWM_IRQ); platform_device_del(blueangel_ds1wm); } Index: blueangel_lcd.c =================================================================== RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/htcblueangel/blueangel_lcd.c,v retrieving revision 1.8 diff -u -r1.8 blueangel_lcd.c --- blueangel_lcd.c 21 Dec 2006 00:18:17 -0000 1.8 +++ blueangel_lcd.c 30 Dec 2006 19:53:04 -0000 @@ -221,7 +221,7 @@ .lcd_format = 0x00000003, .lcdd_cntl1 = 0x00000000, .lcdd_cntl2 = 0x0003ffff, - .genlcd_cntl1 = 0x00fff003, // 0x00fff003 + .genlcd_cntl1 = 0x00abf003, // 0x00fff003 .genlcd_cntl2 = 0x00000003, .genlcd_cntl3 = 0x000102aa, }; Index: blueangel_pcmcia.c =================================================================== RCS file: /cvs/linux/kernel26/arch/arm/mach-pxa/htcblueangel/blueangel_pcmcia.c,v retrieving revision 1.5 diff -u -r1.5 blueangel_pcmcia.c --- blueangel_pcmcia.c 4 Dec 2006 02:23:51 -0000 1.5 +++ blueangel_pcmcia.c 30 Dec 2006 19:53:04 -0000 @@ -1,278 +1,170 @@ -/* - * HTC Blueangel PCMCIA support - * - * Copyright (c) 2005 SDG Systems, LLC - * - * Based on code from iPAQ h2200 - * Copyright 2004 Koen Kooi - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - */ + /* + * h4000_pcmcia.c + * + * Created Apr 2, 2005, by Shawn Anderson + * + * 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 "../../../../drivers/pcmcia/soc_common.h" +#include "../../../../drivers/pcmcia/pxa2xx_base.h" +#include +#include extern struct platform_device blueangel_asic3; -/* - * CF resources used on blueangel : - * - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_POE_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PWE_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PIOR_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PIOW_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PCE1_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PCE2_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PREG_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PWAIT_N_MD); - * pxa_gpio_mode(GPIO_NR_BLUEANGEL_PIOIS16_N_MD); - */ - -#if 0 -#define _debug(s, args...) printk (KERN_INFO s, ##args) -#define _debug_func(s, args...) _debug ("%s: " s, __FUNCTION__, ##args) -#else -#define _debug(s, args...) -#define _debug_func(s, args...) _debug ("%s: " s, __FUNCTION__, ##args) -#endif - -#if 0 -static struct pcmcia_irqs blueangel_cd_irq[] = { - { 0, 0, "PCMCIA CD" } /* fill in IRQ below */ -}; -#endif +#define GET_BLUEANGEL_GPIO(gpio) \ + (GPLR(GPIO_NR_BLUEANGEL_ ## gpio) & GPIO_bit(GPIO_NR_BLUEANGEL_ ## gpio)) + +#define SET_BLUEANGEL_GPIO(gpio, setp) \ +do { \ +if (setp) \ + GPSR( gpio) = GPIO_bit( gpio); \ +else \ + GPCR( gpio) = GPIO_bit( gpio); \ +} while (0) -static int power_en=0; +static struct pcmcia_irqs irqs[] = { + {0, IRQ_GPIO(75), "PCMCIA0"}, +}; -static void -blueangel_cf_reset( int state ) +static irqreturn_t acx_event(int irq, void* data, struct pt_regs *regs) { - printk("reset\n"); -#if 0 - _debug_func ("%d\n", state); - SET_HX4700_GPIO( CF_RESET, state?1:0 ); -#endif -} + struct acx_data *devdata = data; -static int -blueangel_pcmcia_hw_init( struct soc_pcmcia_socket *skt ) + printk("acx receive irq pcmcia shared\n"); + + return IRQ_HANDLED; +}; +static int htcblueangel_pcmcia_hw_init(struct soc_pcmcia_socket *skt) { - int statusd; - int irq; + GPSR(GPIO48_nPOE) = GPIO_bit(GPIO48_nPOE) | GPIO_bit(GPIO49_nPWE) | + GPIO_bit(GPIO52_nPCE_1_MD) | GPIO_bit(GPIO53_nPCE_2_MD) | + GPIO_bit(GPIO55_nPREG_MD) | GPIO_bit(GPIO56_nPWAIT_MD); - _debug_func ("\n"); + pxa_gpio_mode(GPIO48_nPOE_MD); + pxa_gpio_mode(GPIO49_nPWE_MD); + pxa_gpio_mode(GPIO52_nPCE_1_MD); + pxa_gpio_mode(GPIO55_nPREG_MD); + pxa_gpio_mode(GPIO56_nPWAIT_MD); + pxa_gpio_mode(75 | GPIO_IN); - printk("hw_init\n"); -#if 0 - /* Turn on sleep mode, I think */ - asic3_set_extcf_select(&blueangel_asic3.dev, - ASIC3_EXTCF_CF_SLEEP | (ASIC3_EXTCF_CF0_SLEEP_MODE * 3) | ASIC3_EXTCF_CF0_BUF_EN | ASIC3_EXTCF_CF0_PWAIT_EN, - ASIC3_EXTCF_CF_SLEEP | 0 | 0 | 0 - ); - mdelay(50); - - statusd = asic3_get_gpio_status_d( &blueangel_asic3.dev ); - power_en = (statusd & (1<irq = HX4700_IRQ( CF_RNB ); - - if (power_en) { - hx4700_egpio_enable( EGPIO4_CF_3V3_ON ); - set_irq_type( irq, IRQT_RISING ); - } - else { - hx4700_egpio_disable( EGPIO4_CF_3V3_ON ); - set_irq_type( irq, IRQT_FALLING ); - } + asic3_set_clock_cdex(&blueangel_asic3.dev, CLOCK_CDEX_EX1, CLOCK_CDEX_EX1); + asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << GPIOA_WLAN_RESET, + 1 << GPIOA_WLAN_RESET); + asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << GPIOA_WLAN_RESET, 0); - pxa_gpio_mode(GPIO_NR_HX4700_POE_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PWE_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PIOR_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PIOW_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PCE1_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PCE2_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PREG_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PWAIT_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PIOIS16_N_MD | GPIO_DFLT_HIGH); - pxa_gpio_mode(GPIO_NR_HX4700_PSKTSEL_MD); + skt->irq = irqs[0].irq; - return soc_pcmcia_request_irqs(skt, blueangel_cd_irq, ARRAY_SIZE(blueangel_cd_irq)); -#endif - return 0; + return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -/* - * Release all resources. - */ -static void -blueangel_pcmcia_hw_shutdown( struct soc_pcmcia_socket *skt ) +static void htcblueangel_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) { - printk("shutdown\n"); -#if 0 - _debug_func ("\n"); - soc_pcmcia_free_irqs( skt, blueangel_cd_irq, ARRAY_SIZE(blueangel_cd_irq) ); -#endif + soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static void -blueangel_pcmcia_socket_state( struct soc_pcmcia_socket *skt, - struct pcmcia_state *state ) +static void htcblueangel_pcmcia_socket_state(struct soc_pcmcia_socket *skt, + struct pcmcia_state *state) { - int statusd; - - printk("socket_state\n"); - state->detect = 1; - state->ready = 1; - state->bvd1 = 1; - state->bvd2 = 1; + state->detect = GET_BLUEANGEL_GPIO(WLAN_IRQ2_N) ? 1 : 0; // 1; // always attached + state->ready = 1; //GET_BLUEANGEL_GPIO(WLAN_IRQ2_N) ? 1 : 0; + state->bvd1 = 1; + state->bvd2 = 1; state->wrprot = 0; - state->vs_3v = 1; - state->vs_Xv = 0; - -#if 0 - if (state->detect) - asic3_set_gpio_status_c( &hx4700_asic3.dev, 1<detect, state->ready, state->vs_3v ); -} + state->vs_3v = asic3_get_gpio_status_a(&blueangel_asic3.dev) + & (1 << GPIOA_WLAN_PWR2); + state->vs_Xv = 0; +}; -static int -blueangel_pcmcia_config_socket( struct soc_pcmcia_socket *skt, - const socket_state_t *state ) +static int htcblueangel_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, + const socket_state_t * state) { - int statusc; - -#if 0 - statusc = asic3_get_gpio_status_c( &hx4700_asic3.dev ); -#endif - printk("config_socket\n"); - /* Silently ignore Vpp, output enable, speaker enable. */ - _debug_func( "Reset:%d Vcc:%d Astatusc=0x%x\n", - (state->flags & SS_RESET) ? 1 : 0, state->Vcc, - statusc ); - -#if 0 - blueangel_cf_reset( state->flags & SS_RESET ); - if (state->Vcc == 0) { - /* Turn on sleep mode, I think. No docs for these bits. */ - asic3_set_extcf_select(&blueangel_asic3.dev, - ASIC3_EXTCF_CF_SLEEP | (ASIC3_EXTCF_CF0_SLEEP_MODE * 3) | ASIC3_EXTCF_CF0_BUF_EN | ASIC3_EXTCF_CF0_PWAIT_EN, - ASIC3_EXTCF_CF_SLEEP | 0 | 0 | 0 - ); - blueangel_egpio_disable( EGPIO4_CF_3V3_ON ); - power_en = 0; - } - else if (state->Vcc == 33 || state->Vcc == 50) { - blueangel_egpio_enable( EGPIO4_CF_3V3_ON ); - mdelay(1); - /* Turn on CF stuff without messing with SD bit 14. */ - asic3_set_extcf_select(&blueangel_asic3.dev, - ASIC3_EXTCF_CF_SLEEP | (ASIC3_EXTCF_CF0_SLEEP_MODE * 3) | ASIC3_EXTCF_CF0_BUF_EN | ASIC3_EXTCF_CF0_PWAIT_EN, - 0 | (ASIC3_EXTCF_CF0_SLEEP_MODE * 2) | ASIC3_EXTCF_CF0_BUF_EN | ASIC3_EXTCF_CF0_PWAIT_EN - ); - power_en = 1; + switch (state->Vcc) { + case 0: + asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << GPIOA_WLAN_PWR1, + 1 << GPIOA_WLAN_PWR1); + asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << GPIOA_WLAN_PWR2, + 1 << GPIOA_WLAN_PWR2); + break; + case 50: + case 33: + asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << GPIOA_WLAN_PWR1, + 1 << GPIOA_WLAN_PWR1); + asic3_set_gpio_out_a(&blueangel_asic3.dev, 1 << GPIOA_WLAN_PWR2, + 1 << GPIOA_WLAN_PWR2); + break; + default: + printk(KERN_ERR "%s: Unsupported Vcc:%d\n", __FUNCTION__, + state->Vcc); } - else { - printk (KERN_ERR "%s: Unsupported Vcc:%d\n", - __FUNCTION__, state->Vcc); - } -#endif return 0; + } -/* - * Enable card status IRQs on (re-)initialisation. This can - * be called at initialisation, power management event, or - * pcmcia event. - */ -static void -blueangel_pcmcia_socket_init(struct soc_pcmcia_socket *skt) +static void htcblueangel_pcmcia_socket_init(struct soc_pcmcia_socket *skt) { - printk("socket_init\n"); -#if 0 - _debug_func ("\n"); - blueangel_cf_reset(0); -#endif + soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -/* - * Disable card status IRQs on suspend. - */ -static void -blueangel_pcmcia_socket_suspend( struct soc_pcmcia_socket *skt ) +static void htcblueangel_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) { - printk("socket_suspend\n"); -#if 0 - _debug_func ("\n"); - blueangel_cf_reset(1); -#endif + soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs)); } -static struct pcmcia_low_level blueangel_pcmcia_ops = { - .owner = THIS_MODULE, - .nr = 1, - .hw_init = blueangel_pcmcia_hw_init, - .hw_shutdown = blueangel_pcmcia_hw_shutdown, - .socket_state = blueangel_pcmcia_socket_state, - .configure_socket = blueangel_pcmcia_config_socket, - .socket_init = blueangel_pcmcia_socket_init, - .socket_suspend = blueangel_pcmcia_socket_suspend, +static struct pcmcia_low_level htcblueangel_pcmcia_ops = { + .owner = THIS_MODULE, + .first = 0, + .nr = 1, + .hw_init = htcblueangel_pcmcia_hw_init, + .hw_shutdown = htcblueangel_pcmcia_hw_shutdown, + .socket_state = htcblueangel_pcmcia_socket_state, + .configure_socket = htcblueangel_pcmcia_configure_socket, + .socket_init = htcblueangel_pcmcia_socket_init, + .socket_suspend = htcblueangel_pcmcia_socket_suspend, + .set_timing = pxa2xx_pcmcia_set_timing, }; -static struct platform_device blueangel_pcmcia_device = { - .name = "pxa2xx-pcmcia", - .dev = { - .platform_data = &blueangel_pcmcia_ops, - } +static struct platform_device htcblueangel_pcmcia = { + .name = "pxa2xx-pcmcia", + .dev = {.platform_data = &htcblueangel_pcmcia_ops}, }; -static int __init -blueangel_pcmcia_init(void) +static int __init htcblueangel_pcmcia_probe(struct platform_device *pdev) { - _debug_func ("\n"); + return platform_device_register(&htcblueangel_pcmcia); +} - return platform_device_register( &blueangel_pcmcia_device ); +static struct platform_driver htcblueangel_pcmcia_driver = { + .driver = { + .name = "htcblueangel_pcmcia", + }, + .probe = htcblueangel_pcmcia_probe, +}; + +static int __init htcblueangel_pcmcia_init(void) +{ + return platform_driver_register(&htcblueangel_pcmcia_driver); } -static void __exit -blueangel_pcmcia_exit(void) +static void __exit htcblueangel_pcmcia_exit(void) { - platform_device_unregister( &blueangel_pcmcia_device ); + platform_device_unregister(&htcblueangel_pcmcia); + platform_driver_unregister(&htcblueangel_pcmcia_driver); } -module_init(blueangel_pcmcia_init); -module_exit(blueangel_pcmcia_exit); +module_init(htcblueangel_pcmcia_init); +module_exit(htcblueangel_pcmcia_exit); -MODULE_AUTHOR("Todd Blumer, SDG Systems, LLC"); -MODULE_DESCRIPTION("HTC Blueangel PCMCIA/CF platform-specific driver"); MODULE_LICENSE("GPL"); - -/* vim600: set noexpandtab sw=8 ts=8 :*/ -