All pastes #435244 Raw Edit

Miscellany

public c v1 · immutable
·published 2007-04-11 21:06 UTC
rendered paste body
/* * Battery driver for iPAQ blueangel * * Copyright 2007 Anton Vorontsov <cbou@mail.ru> * Copyright 2005 SDG Systems, LLC * Copyright 2005 Aric D. Blumer * Copyright 2005 Phil Blundell * * 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. * * History: * 2007/02/14  Anton Vorontsov         Use ds2760_battery driver, cleanup */#include <linux/module.h>#include <linux/platform_device.h>#include <linux/timer.h>#include <linux/pm.h>#include <linux/irq.h>#include <linux/interrupt.h>#include <linux/leds.h>#include <linux/ds2760_battery.h>#include <linux/adc_battery.h>#include <asm/mach-types.h>#include <asm/hardware.h>#include <linux/soc/asic3_base.h>#include <asm/hardware/asic3_leds.h>#include <asm/arch/htcblueangel-gpio.h>#include <asm/arch/htcblueangel-asic.h>#define DRIVER_NAME "blueangel_power"#define POWER_NONE	0#define POWER_AC	1#define POWER_USB	2extern struct platform_device blueangel_asic3;static struct ds2760_device_info ds2760_di;static int supply_status;static unsigned int ac_irq, usb_irq;struct timer_list isr_timer;DEFINE_LED_TRIGGER(charging_trig);DEFINE_LED_TRIGGER(chargefull_trig);static void blueangel_update_leds(const struct ds2760_device_info *di){	if (supply_status) {		if (di->charge_status == BATTERY_STATUS_FULL) {			led_trigger_event(chargefull_trig, LED_FULL);			led_trigger_event(charging_trig, LED_OFF);			return;		}		else if (di->charge_status == BATTERY_STATUS_CHARGING) {			led_trigger_event(chargefull_trig, LED_OFF);			led_trigger_event(charging_trig, LED_FULL);			return;		}	}	led_trigger_event(chargefull_trig, LED_OFF);	led_trigger_event(charging_trig, LED_OFF);	return;}static void blueangel_supply_changed(void){/*	if (supply_status & POWER_AC) {		// If we're on AC, it doesn't matter if we're on USB or not,		//  use AC only 		SET_blueangel_GPIO_N(CHARGE_EN, 1);		SET_blueangel_GPIO(USB_CHARGE_RATE, 0);	}	else if (supply_status & POWER_USB) {		// We're not on AC, but we are on USB, so charge with that 		SET_blueangel_GPIO(USB_CHARGE_RATE, 1);		SET_blueangel_GPIO_N(CHARGE_EN, 1);	}	else {		// We're not on AC or USB, don't charge 		SET_blueangel_GPIO_N(CHARGE_EN, 0);		SET_blueangel_GPIO(USB_CHARGE_RATE, 0);	}*/	return;}static int blueangel_update_supply_status(void){	unsigned int val;	int ac_in, usb_in;	val = asic3_get_gpio_status_d( &blueangel_asic3.dev );	ac_in  = (val & (1<<GPIOD_AC_CHARGER_N)) == 0;	usb_in = (val & (1<<GPIOC_USB_PUEN)) == 0;	supply_status = POWER_NONE;	if (ac_in) supply_status |= POWER_AC;	if (usb_in) supply_status |= POWER_USB;	return supply_status;}static void blueangel_isr_timer_func(unsigned long enableirq){	supply_status = blueangel_update_supply_status();	printk(KERN_INFO "blueangel power_change: ac_in=%d, usb_in=%d\n",	       supply_status & POWER_AC, supply_status & POWER_USB );	blueangel_supply_changed();	blueangel_update_leds(&ds2760_di);	if (ds2760_di.charge_power_changed)		ds2760_di.charge_power_changed(&ds2760_di);	if (supply_status & POWER_USB)		set_irq_type(usb_irq, IRQF_TRIGGER_RISING);	else		set_irq_type(usb_irq, IRQF_TRIGGER_FALLING);	if (supply_status & POWER_AC)		set_irq_type(ac_irq, IRQF_TRIGGER_RISING);	else		set_irq_type(ac_irq, IRQF_TRIGGER_FALLING);	if (enableirq) {		enable_irq(usb_irq);		enable_irq(ac_irq);	}	return;}static irqreturn_t blueangel_attach_isr(int irq, void *dev_id){	if(irq != usb_irq && irq != ac_irq) {		printk(DRIVER_NAME " bad irq: %d, not %d or %d\n",		       irq, usb_irq, ac_irq);	}	disable_irq(usb_irq);	disable_irq(ac_irq);	mod_timer(&isr_timer, jiffies + HZ/10);	return IRQ_HANDLED;}static void blueangel_charge_callback(const struct ds2760_device_info *di){	if (di->charge_status == BATTERY_STATUS_UNKNOWN) {		/* ds2760_battery is about to suspend or resume. On suspend		 * we should turn off leds, and on resume we should update		 * supply status. */		int old_status = supply_status;		blueangel_update_supply_status();		if (old_status != supply_status)			blueangel_isr_timer_func(0);	}	blueangel_update_leds(di);	return;}void blueangel_null_release(struct device *dev){	return; /* current platform_device api is weird */}static struct ds2760_device_info ds2760_di = {	.battery_info = {		.name = "blueangel_primary",		.id   = "main",		.main_battery = 1,		.max_voltage = 3700,		.min_voltage = 0,		.max_current =  1490,		.min_current = -1490,		.min_charge  = 0,	},	.is_charge_power_supplied = blueangel_update_supply_status,	.charge_callback = blueangel_charge_callback,};static struct platform_device ds2760_pdev = {	.name = "ds2760-battery",	.dev = {		.platform_data = &ds2760_di,		.release = blueangel_null_release,	},};static struct battery_adc_platform_data blueangel_backup_batt_params = {	.battery_info = {		.name = "blueangel_backup",		.id = "backup",		.max_voltage = 1400,		.min_voltage = 1000,		.max_current = 500,		.min_current = 0,		.min_charge = 0,		.max_charge = 100,	},	.voltage_pin = "ads7846-ssp:vaux",};static struct platform_device blueangel_backup_batt = { 	.name = "adc-battery",	.id = -1,	.dev = {		.platform_data = &blueangel_backup_batt_params,	}};static int blueangel_battery_init (void){	int ret;		setup_timer(&isr_timer, blueangel_isr_timer_func, 1);	ac_irq = asic3_irq_base(&blueangel_asic3.dev) + ASIC3_GPIOD_IRQ_BASE		+ GPIOD_AC_CHARGER_N;	ret = request_irq (ac_irq, blueangel_attach_isr, IRQF_DISABLED,	                   "blueangel AC Detect", NULL);	if (ret) goto ac_irq_failed;		usb_irq = asic3_irq_base(&blueangel_asic3.dev) + ASIC3_GPIOC_IRQ_BASE		+ GPIOC_USB_PUEN;	ret = request_irq (usb_irq, blueangel_attach_isr, IRQF_DISABLED,	                   "blueangel USB Detect", NULL);	if (ret) goto usb_irq_failed;	ret = platform_device_register(&ds2760_pdev);	if (ret) goto platform_device_failed;	ret = platform_device_register(&blueangel_backup_batt);	/* Not being able to register backup battery is not fatal */	if (ret)		printk(KERN_ERR DRIVER_NAME ": Could not register backup battery: err=%d\n", ret);		led_trigger_register_simple("blueangel-chargefull", &chargefull_trig);	led_trigger_register_hwtimer("blueangel-charging", &charging_trig);	blueangel_isr_timer_func(0);	goto success;platform_device_failed:	printk (KERN_ERR "%s: failed to register device\n", __FUNCTION__);	free_irq(usb_irq, NULL);usb_irq_failed:	printk (KERN_ERR "%s: unable to grab USB in IRQ\n", __FUNCTION__);	free_irq(ac_irq, NULL);ac_irq_failed:	printk (KERN_ERR "%s: unable to grab AC in IRQ\n", __FUNCTION__);success:	return ret;}static void blueangel_battery_exit(void){	led_trigger_unregister_simple(chargefull_trig);	led_trigger_unregister_hwtimer(charging_trig);	free_irq(ac_irq, NULL);	free_irq(usb_irq, NULL);	del_timer_sync(&isr_timer);	platform_device_unregister(&ds2760_pdev);	platform_device_unregister(&blueangel_backup_batt);	return;}module_init(blueangel_battery_init);module_exit(blueangel_battery_exit);MODULE_LICENSE("GPL");