2 * Copyright 2005, SDG Systems, LLC
4 * This file is subject to the terms and conditions of the GNU General Public
5 * License. See the file COPYING in the main directory of this archive for
8 * Sat 11 Jun 2005 Aric D. Blumer
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/interrupt.h>
14 #include <linux/soc/asic3_base.h>
15 #include <linux/delay.h>
16 #include <linux/battery.h>
17 #include <linux/irq.h>
22 #include <asm/hardware/ipaq-asic3.h>
24 #include <asm/arch/htcuniversal-gpio.h>
25 #include <asm/arch/htcuniversal-asic.h>
27 #define DRIVER_NAME "htcuniversal_power"
28 static char driver_name
[] = DRIVER_NAME
;
30 #define BATTERY_ACR 1620 /* TODO: remove */
32 static void w1_init(void);
33 static void w1_deinit(void);
41 static int cdiv
= 0x2;
44 module_param(cdiv
, int, 0444);
45 MODULE_PARM_DESC(cdiv
, "Clock Divisor");
46 module_param(net
, int, 0444);
47 MODULE_PARM_DESC(net
, "Use net address");
50 volatile unsigned short __iomem
*base
;
52 wait_queue_head_t irqwait
;
53 unsigned short data_register
;
54 unsigned short irqstatus
;
56 struct timer_list irqtimer
;
77 #define DS1WM_COMMAND 0
80 #define DS1WM_IRQ_EN 3
81 #define DS1WM_CLOCK_DIV 4
83 #define WRITE_REGISTER(r, value) do { \
84 /* printk("Write %p = 0x%04x\n", (module_data.base + (r)), value); */ \
85 ((*(module_data.base + (r))) = (value)); \
88 #define READ_REGISTER(R, r) do { \
89 (R = *(module_data.base + (r))); \
90 /* printk("Read %p = 0x%04x\n", (module_data.base + (r)), R); */ \
93 static int w1_detect(void);
94 static int w1_write_byte(unsigned short data
);
95 static int w1_read_byte(unsigned int *data
);
96 static void w1_send_net_address(void);
98 DECLARE_MUTEX(update_mutex
);
101 update_data(int force
)
106 /* Only allow an update every second. */
107 if(!force
&& (module_data
.jiffies_64
+ 5 * HZ
> jiffies_64
)) {
111 if(down_trylock(&update_mutex
)) {
117 unsigned int readval
;
119 w1_send_net_address();
120 w1_write_byte(0x69); /* Read */
121 w1_write_byte(0x00); /* Starting at offset 0x0 */
122 w1_read_byte(&readval
); /* 0x0 */
123 if(readval
== 0xff) {
125 * We have an unknown read problem. Try again.
129 // printk("htcuniversal_power: Whoops\n");
135 /* Get rid of stuff we don't want */
136 w1_read_byte(&readval
); /* 0x1 */
137 w1_read_byte(&readval
); /* 0x2 */
138 w1_read_byte(&readval
); /* 0x3 */
139 w1_read_byte(&readval
); /* 0x4 */
140 w1_read_byte(&readval
); /* 0x5 */
141 w1_read_byte(&readval
); /* 0x6 */
142 w1_read_byte(&readval
); /* 0x7 */
143 w1_read_byte(&readval
); /* 0x8 */
144 w1_read_byte(&readval
); /* 0x9 */
145 w1_read_byte(&readval
); /* 0xa */
146 w1_read_byte(&readval
); /* 0xb */
149 w1_read_byte(&readval
); /* 0xc */
150 if(readval
== 0xff) {
152 * We have an unknown read problem. Try again.
156 // printk("htcuniversal_power: Whoops2\n");
161 module_data
.voltage
= readval
<< 8;
162 w1_read_byte(&readval
); /* 0xd */
163 if(readval
== 0xff) {
165 * We have an unknown read problem. Try again.
169 // printk("htcuniversal_power: Whoops2\n");
174 module_data
.voltage
|= readval
;
175 module_data
.voltage
>>= 5;
176 /* 4997 / 1024 is almost equal to 4880 / 1000 */
177 module_data
.voltage
*= 4997;
178 module_data
.voltage
/= 1024;
182 w1_read_byte(&readval
); /* 0xe */
183 if(readval
== 0xff) {
185 * We have an unknown read problem. Try again.
189 // printk("htcuniversal_power: Whoops2\n");
194 if(readval
& (1 << 7)) {
195 /* The sign bit is set */
196 module_data
.Current
= -1 ^ 0x7fff;
198 module_data
.Current
= 0;
200 module_data
.Current
|= readval
<< 8;
201 w1_read_byte(&readval
); /* 0xf */
202 if(readval
== 0xff) {
204 * We have an unknown read problem. Try again.
208 // printk("htcuniversal_power: Whoops2\n");
213 module_data
.Current
|= readval
;
214 module_data
.Current
>>= 3;
215 /* 655360 / 1024*1024 is equal to 6250000 / 1000000 */
216 module_data
.Current
*= 655360;
217 module_data
.Current
/= 1024 * 1024;
220 /* Current Accumulator */
221 w1_read_byte(&readval
); /* 0x10 */
222 if(readval
== 0xff) {
224 * We have an unknown read problem. Try again.
228 // printk("htcuniversal_power: Whoops2\n");
233 if(readval
& (1 << 7)) {
234 /* The sign bit is set */
235 module_data
.current_accum
= -1 ^ 0xffff;
237 module_data
.current_accum
= 0;
239 module_data
.current_accum
|= readval
<< 8;
240 w1_read_byte(&readval
); /* 0x11 */
241 if(readval
== 0xff) {
243 * We have an unknown read problem. Try again.
247 // printk("htcuniversal_power: Whoops2\n");
252 module_data
.current_accum
|= readval
;
253 /* Units are 250 uAh. We wan't mAh. So each unit is 1/4 mAh. But
254 * we want fractions of hours, so let's keep the 1/4 mAh units. */
255 /* Now convert to quarter hours by dividing by mA. */
256 if(module_data
.Current
== 0) {
257 module_data
.minutes
= module_data
.current_accum
* 15;
259 module_data
.minutes
= -((module_data
.current_accum
* 15) / module_data
.Current
);
263 /* Get rid of stuff we don't want */
264 w1_read_byte(&readval
); /* 0x12 */
265 w1_read_byte(&readval
); /* 0x13 */
266 w1_read_byte(&readval
); /* 0x14 */
267 w1_read_byte(&readval
); /* 0x15 */
268 w1_read_byte(&readval
); /* 0x16 */
269 w1_read_byte(&readval
); /* 0x17 */
272 w1_read_byte(&readval
); /* 0x18 */
273 if(readval
== 0xff) {
275 * We have an unknown read problem. Try again.
279 // printk("htcuniversal_power: Whoops2\n");
284 module_data
.temp
= readval
<< 8;
285 w1_read_byte(&readval
); /* 0x19 */
286 if(readval
== 0xff) {
288 * We have an unknown read problem. Try again.
292 // printk("htcuniversal_power: Whoops2\n");
297 module_data
.temp
|= readval
;
298 module_data
.temp
>>= 5;
299 module_data
.temp
+= module_data
.temp
/ 4;
302 if(module_data
.voltage
> 8000) {
303 /* There is an unknown problem where things get into a strange
304 * state. We know it because the voltage is reported as too
305 * high. This is an attempt at robustness to correct the problem.
306 * I'd like to fix it permanently, though.
309 printk("%s: Bad state detected. Retrying.\n", driver_name
);
314 printk("w1 fix didn't work. We give up.\n");
318 /* Reset ACR when battery gets full. */
319 if (module_data
.Current
>= 0 && module_data
.Current
< 32 &&
320 !module_data
.acr_reset
) {
321 printk(KERN_INFO
"ACR reset.\n");
322 module_data
.current_accum
= BATTERY_ACR
* 4;
325 w1_send_net_address();
326 w1_write_byte(0x6c); /* write */
327 w1_write_byte(0x10); /* current accum msb */
328 w1_write_byte((module_data
.current_accum
>> 8) & 0xff);
329 w1_write_byte(module_data
.current_accum
& 0xff);
330 module_data
.acr_reset
= 1;
335 module_data
.battery_life
= (module_data
.current_accum
* 25) / BATTERY_ACR
;
336 if(module_data
.battery_life
> 100) module_data
.battery_life
= 100;
337 if(module_data
.battery_life
< 0) module_data
.battery_life
= 0;
339 printk("%s: Device not detected\n", driver_name
);
340 module_data
.temp
= 0;
341 module_data
.voltage
= 0;
342 module_data
.current_accum
= 0;
343 module_data
.Current
= 0;
347 module_data
.jiffies_64
= jiffies_64
;
353 w1_isr(int irq
, void *opaque
)
356 * Note that the w1 control logic is quite slow, running at 1 MHz. It is
357 * possible to read the IRQ status, and return and the interrupt still be
358 * active. In this case, we're OK because we only update the irqstatus
359 * when an actual interrupt causing bit is set.
363 /* Just reading the register clears the source */
364 READ_REGISTER(tmp
, DS1WM_IRQ
);
365 if( tmp
& (1 << 0) /* Presence Detect */
366 || tmp
& (1 << 4) /* Receive Buffer Full */
369 module_data
.irqstatus
= tmp
;
370 for(count
= 0; count
< 10; count
++) {
371 READ_REGISTER(module_data
.data_register
, DS1WM_TXRX
);
372 READ_REGISTER(junk
, DS1WM_CLOCK_DIV
); /* Delay */
373 READ_REGISTER(tmp
, DS1WM_IRQ
);
374 if(!(tmp
& (1 << 4))) break;
376 wake_up_interruptible(&module_data
.irqwait
);
385 /* Turn on external clocks and the OWM clock */
386 asic3_set_clock_cdex(&htcuniversal_asic3
.dev
,
387 CLOCK_CDEX_EX0
| CLOCK_CDEX_EX1
| CLOCK_CDEX_OWM
,
388 CLOCK_CDEX_EX0
| CLOCK_CDEX_EX1
| CLOCK_CDEX_OWM
);
392 asic3_set_extcf_reset(&htcuniversal_asic3
.dev
, ASIC3_EXTCF_OWM_RESET
, ASIC3_EXTCF_OWM_RESET
);
394 asic3_set_extcf_reset(&htcuniversal_asic3
.dev
, ASIC3_EXTCF_OWM_RESET
, 0);
397 /* Clear OWM_SMB, set OWM_EN */
398 asic3_set_extcf_select(&htcuniversal_asic3
.dev
,
399 ASIC3_EXTCF_OWM_SMB
| ASIC3_EXTCF_OWM_EN
,
400 0 | ASIC3_EXTCF_OWM_EN
);
404 WRITE_REGISTER(DS1WM_CLOCK_DIV
, cdiv
);
405 /* Enable interrupts: RBF, PD */
406 /* Set Interrupt Active High (IAS = 1) */
407 WRITE_REGISTER(DS1WM_IRQ_EN
,
409 | (0 << 5) /* ESINT */
410 | (1 << 4) /* ERBF */
411 | (0 << 3) /* ETMT */
412 | (0 << 2) /* ETBE */
413 | (1 << 1) /* IAS 0 = active low interrupt, 1 = active high */
419 /* Set asic3 interrupt status to zero. Hmmmmm. not accesible in
429 module_data
.irqstatus
= 0;
431 /* Set 1WR (one wire reset) bit */
432 WRITE_REGISTER(DS1WM_COMMAND
, 1);
433 if(wait_event_interruptible_timeout(module_data
.irqwait
,
434 module_data
.irqstatus
& (1 << 0) /* PD set? */, HZ
)) {
436 if(0 == (module_data
.irqstatus
& (1 << 1)) /* PDR set? */) {
441 printk("%s: detect timeout\n", driver_name
);
451 w1_read_byte(unsigned int *data
)
453 module_data
.irqstatus
= 0;
454 WRITE_REGISTER(DS1WM_TXRX
, 0xff);
455 if(wait_event_interruptible_timeout(module_data
.irqwait
,
456 module_data
.irqstatus
& (1 << 4) /* RBF set? */, HZ
)) {
457 *data
= module_data
.data_register
;
460 printk("%s: RBF not set\n", driver_name
);
466 w1_write_byte(unsigned short data
)
468 module_data
.irqstatus
= 0;
469 WRITE_REGISTER(DS1WM_TXRX
, data
);
470 if(wait_event_interruptible_timeout(module_data
.irqwait
,
471 module_data
.irqstatus
& (1 << 2) /* TBE set? */, HZ
)) {
474 printk("%s: TBE not set\n", driver_name
);
479 int get_min_voltage(struct battery
*b
)
483 int get_min_current(struct battery
*b
)
485 return -1000; /* negative 1000 mA */
487 int get_min_charge(struct battery
*b
)
491 int get_max_voltage(struct battery
*b
)
493 return 4200; /* mV */
495 int get_max_current(struct battery
*b
)
497 return 1000; /* positive 1000 mA */
499 int get_max_charge(struct battery
*b
)
503 int get_temp(struct battery
*b
)
506 return module_data
.temp
;
508 int get_voltage(struct battery
*b
)
511 return module_data
.voltage
;
513 int get_Current(struct battery
*b
)
516 return module_data
.Current
;
518 int get_charge(struct battery
*b
)
520 return module_data
.current_accum
/ 4;
522 int get_status(struct battery
*b
)
524 return power_status
== POWER_NONE
? 0: 1;
527 static struct battery htcuniversal_power
= {
528 .name
= "htcuniversal_primary",
530 .get_min_voltage
= get_min_voltage
,
531 .get_min_current
= get_min_current
,
532 .get_min_charge
= get_min_charge
,
533 .get_max_voltage
= get_max_voltage
,
534 .get_max_current
= get_max_current
,
535 .get_max_charge
= get_max_charge
,
536 .get_temp
= get_temp
,
537 .get_voltage
= get_voltage
,
538 .get_current
= get_Current
,
539 .get_charge
= get_charge
,
540 .get_status
= get_status
,
544 set_leds(int status
, int Current
, int battery_life
)
546 if (status
== APM_AC_ONLINE
) {
547 /* check life to update LEDs. LEDs are off when on battery */
549 * It has been observed that the Current is greater when the device is
550 * suspended compared to when it is awake. So we have to use
551 * different parameters here compared to bootldr
553 if((Current
< 32) && (battery_life
== 100)) {
554 /* Green LED on solid, amber off */
555 // htcuniversal_set_led(0, 0, 16);
556 // htcuniversal_set_led(1, 16, 16);
558 /* Amber LED blinking, green off */
559 // htcuniversal_set_led(0, 128, 256);
560 // htcuniversal_set_led(1, 0, 16);
563 /* No charging power is applied; both LEDs off */
564 // htcuniversal_set_led(0, 0, 16);
565 // htcuniversal_set_led(1, 0, 16);
571 htcuniversal_apm_get_power_status( struct apm_power_info
*info
)
575 info
->ac_line_status
= (power_status
== POWER_NONE
)
576 ? APM_AC_OFFLINE
: APM_AC_ONLINE
;
578 /* It is possible to be hooked up to USB and getting some power from
579 * it, but still having a current drain on the battery with a busy CPU
581 info
->battery_life
= module_data
.battery_life
;
583 if (info
->ac_line_status
== APM_AC_ONLINE
) {
584 info
->battery_status
= APM_BATTERY_STATUS_CHARGING
;
586 info
->time
= module_data
.minutes
;
587 info
->units
= APM_UNITS_MINS
;
588 module_data
.acr_reset
= 0;
590 info
->battery_status
= APM_BATTERY_STATUS_CRITICAL
;
591 if(info
->battery_life
> 5) {
592 info
->battery_status
= APM_BATTERY_STATUS_LOW
;
594 if(info
->battery_life
> 20) {
595 info
->battery_status
= APM_BATTERY_STATUS_HIGH
;
599 // set_leds(info->ac_line_status, module_data.Current, module_data.battery_life);
603 power_change_task_handler(unsigned long enableirq
)
605 // unsigned int retval;
608 if(!module_data
.initialized
) return;
610 ac_in
= (GET_HTCUNIVERSAL_GPIO(POWER_DET
) == 0);
611 usb_in
= (GET_HTCUNIVERSAL_GPIO(USB_DET
) == 0);
612 printk( KERN_INFO
"htcuniversal power_change: ac_in=%d\n", ac_in
);
613 printk( KERN_INFO
"htcuniversal power_change: usb_in=%d\n", usb_in
);
616 /* If we're on AC, it doesn't matter if we're on USB or not, use AC
618 // SET_HX4700_GPIO_N( CHARGE_EN, 1 );
619 // SET_HX4700_GPIO( USB_CHARGE_RATE, 0 );
621 asic3_set_gpio_out_b(&htcuniversal_asic3
.dev
, 1<<GPIOB_CHARGE_EN
, 0);
622 power_status
= POWER_AC
;
623 set_leds(APM_AC_ONLINE
, module_data
.Current
, module_data
.battery_life
);
625 /* We're not on AC, but we are on USB, so charge with that */
626 // SET_HX4700_GPIO( USB_CHARGE_RATE, 1 );
627 // SET_HX4700_GPIO_N( CHARGE_EN, 1 );
629 asic3_set_gpio_out_b(&htcuniversal_asic3
.dev
, 1<<GPIOB_CHARGE_EN
, 0);
631 power_status
= POWER_USB
;
632 set_leds(APM_AC_ONLINE
, module_data
.Current
, module_data
.battery_life
);
634 /* We're not on AC or USB, don't charge */
635 // SET_HX4700_GPIO_N( CHARGE_EN, 0 );
636 // SET_HX4700_GPIO( USB_CHARGE_RATE, 0 );
638 asic3_set_gpio_out_b(&htcuniversal_asic3
.dev
, 1<<GPIOB_CHARGE_EN
, 1<<GPIOB_CHARGE_EN
);
640 power_status
= POWER_NONE
;
641 // htcuniversal_clear_led(0);
642 // htcuniversal_clear_led(1);
643 // set_leds(APM_AC_OFFLINE, module_data.Current, module_data.battery_life);
644 module_data
.acr_reset
= 0;
648 /* update_data(1); */
649 module_data
.jiffies_64
= 0; /* Force a re-read on next try */
652 enable_irq(module_data
.usb_irq
);
653 enable_irq(module_data
.ac_irq
);
658 attach_isr(int irq
, void *dev_id
)
660 if(irq
!= module_data
.usb_irq
661 && irq
!= module_data
.ac_irq
) {
662 printk("Bad irq: %d, not %d or %d\n", irq
, module_data
.usb_irq
, module_data
.ac_irq
);
664 if(module_data
.initialized
) {
665 // SET_HX4700_GPIO_N( CHARGE_EN, 0 );
667 asic3_set_gpio_out_b(&htcuniversal_asic3
.dev
, 1<<GPIOB_CHARGE_EN
, 1<<GPIOB_CHARGE_EN
);
669 mod_timer(&module_data
.irqtimer
, jiffies
+ HZ
/10);
670 disable_irq(module_data
.usb_irq
);
671 disable_irq(module_data
.ac_irq
);
677 battery_class_uevent(struct class_device
*dev
, char **envp
, int num_envp
,
678 char *buffer
, int buffer_size
)
684 battery_class_release(struct class_device
*dev
)
689 battery_class_class_release(struct class *class)
694 w1_send_net_address(void)
698 w1_write_byte(0x55); /* Match Net Address */
699 for(i
= 0; i
< sizeof(module_data
.net_address
)/sizeof(module_data
.net_address
[0]); i
++) {
700 w1_write_byte(module_data
.net_address
[i
]);
703 w1_write_byte(0xcc); /* Skip Net Address */
708 w1_probe(struct platform_device
*dev
)
713 module_data
.initialized
= 0;
714 module_data
.w1_irq
= -1;
715 module_data
.usb_irq
= -1;
716 module_data
.ac_irq
= -1;
717 module_data
.base
= 0;
718 module_data
.jiffies_64
= 0;
719 module_data
.acr_reset
= 0;
721 init_timer(&module_data
.irqtimer
);
722 module_data
.irqtimer
.function
= power_change_task_handler
;
723 module_data
.irqtimer
.data
= 1;
725 init_waitqueue_head(&module_data
.irqwait
);
727 platform_set_drvdata(dev
, &module_data
);
729 module_data
.base
= ioremap_nocache(0x10000600, 64);
730 module_data
.battery_class
= 0;
732 if(!module_data
.base
) {
733 printk(KERN_NOTICE
"%s: Unable to map device\n", driver_name
);
738 module_data
.w1_irq
= asic3_irq_base(&htcuniversal_asic3
.dev
) + ASIC3_OWM_IRQ
;
739 retval
= request_irq(module_data
.w1_irq
, w1_isr
, SA_INTERRUPT
, driver_name
, &module_data
);
741 printk(KERN_NOTICE
"%s: Unable to get interrupt %d: %d\n",
742 driver_name
, module_data
.w1_irq
, retval
);
743 iounmap((void __iomem
*)module_data
.base
);
744 module_data
.base
= 0;
745 module_data
.w1_irq
= -1;
751 unsigned int readval
;
754 for(i
= 0; i
< sizeof(module_data
.net_address
)/sizeof(module_data
.net_address
[0]); i
++) {
755 w1_read_byte(&readval
);
756 module_data
.net_address
[i
] = readval
& 0xff;
758 if(module_data
.net_address
[0] != 0x30) {
759 printk("Looks like wrong net address is "
760 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
761 module_data
.net_address
[0], module_data
.net_address
[1],
762 module_data
.net_address
[2], module_data
.net_address
[3],
763 module_data
.net_address
[4], module_data
.net_address
[5],
764 module_data
.net_address
[6], module_data
.net_address
[7]
769 printk("htcuniversal: your DS267x unique id is "
770 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
771 module_data
.net_address
[0], module_data
.net_address
[1],
772 module_data
.net_address
[2], module_data
.net_address
[3],
773 module_data
.net_address
[4], module_data
.net_address
[5],
774 module_data
.net_address
[6], module_data
.net_address
[7]
778 printk("Could not detect device for net address\n");
779 iounmap((void __iomem
*)module_data
.base
);
780 free_irq(module_data
.w1_irq
, &module_data
);
781 module_data
.base
= 0;
782 module_data
.w1_irq
= -1;
786 unsigned int readval
;
787 if(battery_class_register(&htcuniversal_power
)) {
788 printk(KERN_ERR
"%s: Could not register battery class\n",
791 module_data
.battery_class
= 1;
792 htcuniversal_power
.class_dev
.class->uevent
= battery_class_uevent
;
793 htcuniversal_power
.class_dev
.class->release
= battery_class_release
;
794 htcuniversal_power
.class_dev
.class->class_release
= battery_class_class_release
;
796 w1_send_net_address();
797 w1_write_byte(0x69); /* Read */
798 w1_write_byte(0x08); /* Special Feature Address */
799 w1_read_byte(&readval
);
800 if(!(readval
& (1 << 7))) {
801 printk("PS is low. Writing 1.\n");
802 /* The PS signal is low. The docs say to write a 1 to it to ensure
803 * proper operation. */
805 w1_send_net_address();
806 w1_write_byte(0x6c); /* Write */
807 w1_write_byte(0x08); /* Special Feature Address */
808 w1_write_byte(readval
| (1 << 7)); /* Data */
810 printk("No detect when writing PS\n");
814 printk("%s: Device not detected on init\n", driver_name
);
818 module_data
.usb_irq
= HTCUNIVERSAL_IRQ(USB_DET
);
819 module_data
.ac_irq
= HTCUNIVERSAL_IRQ(POWER_DET
);
821 module_data
.initialized
= 1;
823 /* Get first power state */
824 power_change_task_handler(0);
827 if (request_irq( module_data
.usb_irq
, attach_isr
, SA_INTERRUPT
,
828 "HTC Universal USB Detect", NULL
) != 0) {
829 printk( KERN_ERR
"Unable to configure USB detect interrupt.\n" );
830 module_data
.usb_irq
= -1;
833 set_irq_type( module_data
.usb_irq
, IRQ_TYPE_EDGE_BOTH
);
836 if (request_irq( module_data
.ac_irq
, attach_isr
, SA_INTERRUPT
,
837 "HTC Universal AC Detect", NULL
) != 0) {
838 printk( KERN_ERR
"Unable to configure AC detect interrupt.\n" );
839 module_data
.ac_irq
= -1;
842 set_irq_type( module_data
.ac_irq
, IRQ_TYPE_EDGE_BOTH
);
845 apm_get_power_status
= htcuniversal_apm_get_power_status
;
854 /* Turn off OWM clock. I hate to touch the others because they might be
855 * used by other devices like MMC. */
856 asic3_set_clock_cdex(&htcuniversal_asic3
.dev
,
857 /* CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | */ CLOCK_CDEX_OWM
,
858 /* CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | */ 0);
861 asic3_set_extcf_select(&htcuniversal_asic3
.dev
,
862 ASIC3_EXTCF_OWM_EN
, 0);
868 w1_remove(struct platform_device
*dev
)
870 printk("w1_remove\n");
873 apm_get_power_status
= NULL
;
876 if(module_data
.base
) {
879 if(module_data
.battery_class
) {
880 battery_class_unregister(&htcuniversal_power
);
881 printk("battery class unregistered\n");
883 if(module_data
.base
) {
884 iounmap((void __iomem
*)module_data
.base
);
885 printk("Base unmapped\n");
887 if(module_data
.w1_irq
!= -1) {
888 disable_irq(module_data
.w1_irq
);
889 free_irq(module_data
.w1_irq
, &module_data
);
890 printk("w1 irq freed\n");
892 if (module_data
.ac_irq
!= -1) {
893 disable_irq(module_data
.ac_irq
);
894 free_irq( module_data
.ac_irq
, NULL
);
895 printk("ac irq freed\n");
897 if (module_data
.usb_irq
!= -1) {
898 disable_irq(module_data
.usb_irq
);
899 free_irq( module_data
.usb_irq
, NULL
);
900 printk("usb irq freed\n");
903 while(timer_pending(&module_data
.irqtimer
)) {
906 del_timer(&module_data
.irqtimer
);
912 w1_suspend(struct platform_device
*dev
, pm_message_t state
)
914 printk("htcuniversal: w1_suspend\n");
920 w1_resume(struct platform_device
*dev
)
922 printk("htcuniversal: w1_resume\n");
924 /* check for changes to power that may have occurred */
925 power_change_task_handler(0);
926 /* I think this will work to ensure the interrupt is unmasked. */
927 disable_irq(module_data
.w1_irq
);
928 enable_irq(module_data
.w1_irq
);
929 /* Clear OWM_SMB, set OWM_EN */
930 asic3_set_extcf_select(&htcuniversal_asic3
.dev
, ASIC3_EXTCF_OWM_EN
, ASIC3_EXTCF_OWM_EN
);
934 static struct platform_driver w1_driver
= {
936 .name
= "htcuniversal_power",
940 .suspend
= w1_suspend
,
947 printk(KERN_NOTICE
"htcuniversal Power Management Driver\n");
948 return platform_driver_register(&w1_driver
);
954 platform_driver_unregister(&w1_driver
);
960 MODULE_AUTHOR("Aric D. Blumer, SDG Systems, LLC");
961 MODULE_DESCRIPTION("HTC Universal Power Management Driver");
962 MODULE_LICENSE("GPL");
964 /* vim600: set expandtab: */