hh.org updates
[hh.org.git] / arch / arm / mach-pxa / hx4700 / hx4700_power.c
blob111db6e6dd833ad915452dc0da56e11316454c47
1 /*
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
6 * more details.
8 * Sat 11 Jun 2005 Aric D. Blumer
9 */
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/interrupt.h>
14 #include <linux/irq.h>
15 #include <linux/soc/asic3_base.h>
16 #include <linux/delay.h>
17 #include <linux/battery.h>
18 #include <linux/leds.h>
20 #include <asm/io.h>
21 #include <asm/apm.h>
23 #include <asm/hardware/ipaq-asic3.h>
24 #include <asm/hardware/asic3_leds.h>
26 #include <asm/arch/hx4700-gpio.h>
27 #include <asm/arch/hx4700-asic.h>
28 #include <asm/arch/hx4700-core.h>
30 #define DRIVER_NAME "hx4700_power"
31 static char driver_name[] = DRIVER_NAME;
33 static void w1_init(void);
34 static void w1_deinit(void);
36 static enum {
37 POWER_NONE,
38 POWER_AC,
39 POWER_USB,
40 } power_status;
42 static int cdiv = 0x2;
43 static int net = 0x0;
45 module_param(cdiv, int, 0444);
46 MODULE_PARM_DESC(cdiv, "Clock Divisor");
47 module_param(net, int, 0444);
48 MODULE_PARM_DESC(net, "Use net address");
50 struct w1_data {
51 volatile unsigned short __iomem *base;
52 int w1_irq;
53 wait_queue_head_t irqwait;
54 unsigned short data_register;
55 unsigned short irqstatus;
56 int battery_class;
57 struct timer_list irqtimer;
59 unsigned int temp;
60 unsigned int voltage;
61 int Current;
62 int current_accum;
63 int acr_reset;
64 int minutes;
65 int battery_life;
67 int ac_irq;
68 int usb_irq;
70 int initialized;
72 char net_address[8];
74 u64 jiffies_64;
76 } module_data;
78 #define DS1WM_COMMAND 0
79 #define DS1WM_TXRX 1
80 #define DS1WM_IRQ 2
81 #define DS1WM_IRQ_EN 3
82 #define DS1WM_CLOCK_DIV 4
84 #define WRITE_REGISTER(r, value) do { \
85 /* printk("Write %p = 0x%04x\n", (module_data.base + (r)), value); */ \
86 ((*(module_data.base + (r))) = (value)); \
87 } while(0)
89 #define READ_REGISTER(R, r) do { \
90 (R = *(module_data.base + (r))); \
91 /* printk("Read %p = 0x%04x\n", (module_data.base + (r)), R); */ \
92 } while(0)
94 static int w1_detect(void);
95 static int w1_write_byte(unsigned short data);
96 static int w1_read_byte(unsigned int *data);
97 static void w1_send_net_address(void);
99 DECLARE_MUTEX(update_mutex);
101 static void
102 update_data(int force)
104 int flag = 0;
105 int retries = 30;
107 /* Only allow an update every second. */
108 if(!force && (module_data.jiffies_64 + 5 * HZ > jiffies_64)) {
109 return;
112 if(down_trylock(&update_mutex)) {
113 return;
116 try_again:
117 if(w1_detect()) {
118 unsigned int readval;
120 w1_send_net_address();
121 w1_write_byte(0x69); /* Read */
122 w1_write_byte(0x00); /* Starting at offset 0x0 */
123 w1_read_byte(&readval); /* 0x0 */
124 if(readval == 0xff) {
126 * We have an unknown read problem. Try again.
128 msleep(1 * retries);
129 if(0 == retries--) {
130 // printk("hx4700_power: Whoops\n");
131 goto exit_please;
133 goto try_again;
136 /* Get rid of stuff we don't want */
137 w1_read_byte(&readval); /* 0x1 */
138 w1_read_byte(&readval); /* 0x2 */
139 w1_read_byte(&readval); /* 0x3 */
140 w1_read_byte(&readval); /* 0x4 */
141 w1_read_byte(&readval); /* 0x5 */
142 w1_read_byte(&readval); /* 0x6 */
143 w1_read_byte(&readval); /* 0x7 */
144 w1_read_byte(&readval); /* 0x8 */
145 w1_read_byte(&readval); /* 0x9 */
146 w1_read_byte(&readval); /* 0xa */
147 w1_read_byte(&readval); /* 0xb */
149 /* VOLTAGE */
150 w1_read_byte(&readval); /* 0xc */
151 if(readval == 0xff) {
153 * We have an unknown read problem. Try again.
155 msleep(1 * retries);
156 if(0 == retries--) {
157 // printk("hx4700_power: Whoops2\n");
158 goto exit_please;
160 goto try_again;
162 module_data.voltage = readval << 8;
163 w1_read_byte(&readval); /* 0xd */
164 if(readval == 0xff) {
166 * We have an unknown read problem. Try again.
168 msleep(1 * retries);
169 if(0 == retries--) {
170 // printk("hx4700_power: Whoops2\n");
171 goto exit_please;
173 goto try_again;
175 module_data.voltage |= readval;
176 module_data.voltage >>= 5;
177 /* 4997 / 1024 is almost equal to 4880 / 1000 */
178 module_data.voltage *= 4997;
179 module_data.voltage /= 1024;
180 /****************/
182 /* Current */
183 w1_read_byte(&readval); /* 0xe */
184 if(readval == 0xff) {
186 * We have an unknown read problem. Try again.
188 msleep(1 * retries);
189 if(0 == retries--) {
190 // printk("hx4700_power: Whoops2\n");
191 goto exit_please;
193 goto try_again;
195 if(readval & (1 << 7)) {
196 /* The sign bit is set */
197 module_data.Current = -1 ^ 0x7fff;
198 } else {
199 module_data.Current = 0;
201 module_data.Current |= readval << 8;
202 w1_read_byte(&readval); /* 0xf */
203 if(readval == 0xff) {
205 * We have an unknown read problem. Try again.
207 msleep(1 * retries);
208 if(0 == retries--) {
209 // printk("hx4700_power: Whoops2\n");
210 goto exit_please;
212 goto try_again;
214 module_data.Current |= readval;
215 module_data.Current >>= 3;
216 /* 655360 / 1024*1024 is equal to 6250000 / 1000000 */
217 module_data.Current *= 655360;
218 module_data.Current /= 1024 * 1024;
219 /****************/
221 /* Current Accumulator */
222 w1_read_byte(&readval); /* 0x10 */
223 if(readval == 0xff) {
225 * We have an unknown read problem. Try again.
227 msleep(1 * retries);
228 if(0 == retries--) {
229 // printk("hx4700_power: Whoops2\n");
230 goto exit_please;
232 goto try_again;
234 if(readval & (1 << 7)) {
235 /* The sign bit is set */
236 module_data.current_accum = -1 ^ 0xffff;
237 } else {
238 module_data.current_accum = 0;
240 module_data.current_accum |= readval << 8;
241 w1_read_byte(&readval); /* 0x11 */
242 if(readval == 0xff) {
244 * We have an unknown read problem. Try again.
246 msleep(1 * retries);
247 if(0 == retries--) {
248 // printk("hx4700_power: Whoops2\n");
249 goto exit_please;
251 goto try_again;
253 module_data.current_accum |= readval;
254 /* Units are 250 uAh. We wan't mAh. So each unit is 1/4 mAh. But
255 * we want fractions of hours, so let's keep the 1/4 mAh units. */
256 /* Now convert to quarter hours by dividing by mA. */
257 if(module_data.Current == 0) {
258 module_data.minutes = module_data.current_accum * 15;
259 } else {
260 module_data.minutes = -((module_data.current_accum * 15) / module_data.Current);
262 /****************/
264 /* Get rid of stuff we don't want */
265 w1_read_byte(&readval); /* 0x12 */
266 w1_read_byte(&readval); /* 0x13 */
267 w1_read_byte(&readval); /* 0x14 */
268 w1_read_byte(&readval); /* 0x15 */
269 w1_read_byte(&readval); /* 0x16 */
270 w1_read_byte(&readval); /* 0x17 */
272 /* Temperature */
273 w1_read_byte(&readval); /* 0x18 */
274 if(readval == 0xff) {
276 * We have an unknown read problem. Try again.
278 msleep(1 * retries);
279 if(0 == retries--) {
280 // printk("hx4700_power: Whoops2\n");
281 goto exit_please;
283 goto try_again;
285 module_data.temp = readval << 8;
286 w1_read_byte(&readval); /* 0x19 */
287 if(readval == 0xff) {
289 * We have an unknown read problem. Try again.
291 msleep(1 * retries);
292 if(0 == retries--) {
293 // printk("hx4700_power: Whoops2\n");
294 goto exit_please;
296 goto try_again;
298 module_data.temp |= readval;
299 module_data.temp >>= 5;
300 module_data.temp += module_data.temp / 4;
301 /****************/
303 if(module_data.voltage > 8000) {
304 /* There is an unknown problem where things get into a strange
305 * state. We know it because the voltage is reported as too
306 * high. This is an attempt at robustness to correct the problem.
307 * I'd like to fix it permanently, though.
309 if(!flag) {
310 printk("%s: Bad state detected. Retrying.\n", driver_name);
311 flag = 1;
312 mdelay(1);
313 goto try_again;
314 } else {
315 printk("w1 fix didn't work. We give up.\n");
319 /* Reset ACR when battery gets full. */
320 if (module_data.Current >= 0 && module_data.Current < 32 &&
321 !module_data.acr_reset) {
322 printk(KERN_INFO "ACR reset\n");
323 module_data.current_accum = 1800 * 4;
324 if (w1_detect()) {
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;
334 module_data.battery_life = (module_data.current_accum * 25) / 1800;
335 if(module_data.battery_life > 100) module_data.battery_life = 100;
336 if(module_data.battery_life < 0) module_data.battery_life = 0;
337 } else {
338 printk("%s: Device not detected\n", driver_name);
339 module_data.temp = 0;
340 module_data.voltage = 0;
341 module_data.current_accum = 0;
342 module_data.Current = 0;
345 exit_please:
346 module_data.jiffies_64 = jiffies_64;
347 up(&update_mutex);
351 static irqreturn_t
352 w1_isr(int irq, void *opaque)
355 * Note that the w1 control logic is quite slow, running at 1 MHz. It is
356 * possible to read the IRQ status, and return and the interrupt still be
357 * active. In this case, we're OK because we only update the irqstatus
358 * when an actual interrupt causing bit is set.
361 unsigned short tmp;
362 /* Just reading the register clears the source */
363 READ_REGISTER(tmp, DS1WM_IRQ);
364 if( tmp & (1 << 0) /* Presence Detect */
365 || tmp & (1 << 4) /* Receive Buffer Full */
367 int junk, count;
368 module_data.irqstatus = tmp;
369 for(count = 0; count < 10; count++) {
370 READ_REGISTER(module_data.data_register, DS1WM_TXRX);
371 READ_REGISTER(junk, DS1WM_CLOCK_DIV); /* Delay */
372 READ_REGISTER(tmp, DS1WM_IRQ);
373 if(!(tmp & (1 << 4))) break;
375 wake_up_interruptible(&module_data.irqwait);
377 return IRQ_HANDLED;
381 static void
382 w1_init(void)
384 /* Turn on external clocks and the OWM clock */
385 asic3_set_clock_cdex(&hx4700_asic3.dev,
386 CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM,
387 CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | CLOCK_CDEX_OWM);
389 mdelay(1);
391 asic3_set_extcf_reset(&hx4700_asic3.dev, ASIC3_EXTCF_OWM_RESET, ASIC3_EXTCF_OWM_RESET);
392 mdelay(1);
393 asic3_set_extcf_reset(&hx4700_asic3.dev, ASIC3_EXTCF_OWM_RESET, 0);
394 mdelay(1);
396 /* Clear OWM_SMB, set OWM_EN */
397 asic3_set_extcf_select(&hx4700_asic3.dev,
398 ASIC3_EXTCF_OWM_SMB | ASIC3_EXTCF_OWM_EN,
399 0 | ASIC3_EXTCF_OWM_EN);
401 mdelay(1);
403 WRITE_REGISTER(DS1WM_CLOCK_DIV, cdiv);
404 /* Enable interrupts: RBF, PD */
405 /* Set Interrupt Active High (IAS = 1) */
406 WRITE_REGISTER(DS1WM_IRQ_EN,
407 (0 << 6) /* ENBSY */
408 | (0 << 5) /* ESINT */
409 | (1 << 4) /* ERBF */
410 | (0 << 3) /* ETMT */
411 | (0 << 2) /* ETBE */
412 | (1 << 1) /* IAS 0 = active low interrupt, 1 = active high */
413 | (1 << 0) /* EPD */
416 mdelay(1);
418 /* Set asic3 interrupt status to zero. Hmmmmm. not accesible in
419 * asic3_base.c */
422 static int
423 w1_detect(void)
425 int retry_count = 5;
427 try_again:
428 module_data.irqstatus = 0;
430 /* Set 1WR (one wire reset) bit */
431 WRITE_REGISTER(DS1WM_COMMAND, 1);
432 if(wait_event_interruptible_timeout(module_data.irqwait,
433 module_data.irqstatus & (1 << 0) /* PD set? */, HZ)) {
435 if(0 == (module_data.irqstatus & (1 << 1)) /* PDR set? */) {
436 mdelay(1);
437 return 1;
439 } else {
440 printk("%s: detect timeout\n", driver_name);
442 if(retry_count--) {
443 mdelay(1);
444 goto try_again;
446 return 0;
449 static int
450 w1_read_byte(unsigned int *data)
452 module_data.irqstatus = 0;
453 WRITE_REGISTER(DS1WM_TXRX, 0xff);
454 if(wait_event_interruptible_timeout(module_data.irqwait,
455 module_data.irqstatus & (1 << 4) /* RBF set? */, HZ)) {
456 *data = module_data.data_register;
457 return 1;
458 } else {
459 printk("%s: RBF not set\n", driver_name);
461 return 0;
464 static int
465 w1_write_byte(unsigned short data)
467 module_data.irqstatus = 0;
468 WRITE_REGISTER(DS1WM_TXRX, data);
469 if(wait_event_interruptible_timeout(module_data.irqwait,
470 module_data.irqstatus & (1 << 2) /* TBE set? */, HZ)) {
471 return 1;
472 } else {
473 printk("%s: TBE not set\n", driver_name);
475 return 0;
478 int get_min_voltage(struct battery *b)
480 return 0;
482 int get_min_current(struct battery *b)
484 return -1900; /* negative 1900 mA */
486 int get_min_charge(struct battery *b)
488 return 0;
490 int get_max_voltage(struct battery *b)
492 return 4750; /* mV */
494 int get_max_current(struct battery *b)
496 return 1900; /* positive 1900 mA */
498 int get_max_charge(struct battery *b)
500 return 1;
502 int get_temp(struct battery *b)
504 update_data(0);
505 return module_data.temp;
507 int get_voltage(struct battery *b)
509 update_data(0);
510 return module_data.voltage;
512 int get_Current(struct battery *b)
514 update_data(0);
515 return module_data.Current;
517 int get_charge(struct battery *b)
519 return module_data.current_accum / 4;
521 int get_status(struct battery *b)
523 return power_status == POWER_NONE? 0: 1;
526 static struct battery hx4700_power = {
527 .name = "hx4700_primary",
528 .id = "main",
529 .get_min_voltage = get_min_voltage,
530 .get_min_current = get_min_current,
531 .get_min_charge = get_min_charge,
532 .get_max_voltage = get_max_voltage,
533 .get_max_current = get_max_current,
534 .get_max_charge = get_max_charge,
535 .get_temp = get_temp,
536 .get_voltage = get_voltage,
537 .get_current = get_Current,
538 .get_charge = get_charge,
539 .get_status = get_status,
542 DEFINE_LED_TRIGGER(charging_trig);
543 DEFINE_LED_TRIGGER(chargefull_trig);
545 static void
546 set_leds(int status, int Current, int battery_life)
548 if (status == APM_AC_ONLINE) {
549 /* check life to update LEDs. LEDs are off when on battery */
551 * It has been observed that the Current is greater when the device is
552 * suspended compared to when it is awake. So we have to use
553 * different parameters here compared to bootldr
555 if((Current < 32) && (battery_life == 100)) {
556 /* Green LED on solid, amber off */
557 led_trigger_event(chargefull_trig, LED_FULL);
558 led_trigger_event(charging_trig, LED_OFF);
559 } else {
560 /* Amber LED blinking, green off */
561 led_trigger_event(chargefull_trig, LED_OFF);
562 led_trigger_event(charging_trig, LED_FULL);
564 } else {
565 /* No charging power is applied; both LEDs off */
566 led_trigger_event(chargefull_trig, LED_OFF);
567 led_trigger_event(charging_trig, LED_OFF);
572 static void
573 hx4700_apm_get_power_status( struct apm_power_info *info )
575 update_data(0);
577 info->ac_line_status = (power_status == POWER_NONE)
578 ? APM_AC_OFFLINE : APM_AC_ONLINE;
580 /* It is possible to be hooked up to USB and getting some power from
581 * it, but still having a current drain on the battery with a busy CPU
583 info->battery_life = module_data.battery_life;
585 if (info->ac_line_status == APM_AC_ONLINE) {
586 info->battery_status = APM_BATTERY_STATUS_CHARGING;
587 } else {
588 info->time = module_data.minutes;
589 info->units = APM_UNITS_MINS;
590 module_data.acr_reset = 0;
592 info->battery_status = APM_BATTERY_STATUS_CRITICAL;
593 if(info->battery_life > 5) {
594 info->battery_status = APM_BATTERY_STATUS_LOW;
596 if(info->battery_life > 20) {
597 info->battery_status = APM_BATTERY_STATUS_HIGH;
601 set_leds(info->ac_line_status, module_data.Current, module_data.battery_life);
604 static void
605 power_change_task_handler(unsigned long enableirq)
607 unsigned int retval;
608 int ac_in, usb_in;
610 if(!module_data.initialized) return;
612 retval = asic3_get_gpio_status_d( &hx4700_asic3.dev );
613 ac_in = (retval & (1<<GPIOD_AC_IN_N)) == 0;
614 usb_in = (retval & (1<<GPIOD_USBC_DETECT_N)) == 0;
615 printk( KERN_INFO "hx4700 power_change: ac_in=%d\n", ac_in );
616 printk( KERN_INFO "hx4700 power_change: usb_in=%d\n", usb_in );
618 if (usb_in) {
619 set_irq_type( module_data.usb_irq, IRQT_RISING );
620 } else {
621 set_irq_type( module_data.usb_irq, IRQT_FALLING );
624 if (ac_in) {
625 set_irq_type( module_data.ac_irq, IRQT_RISING );
626 } else {
627 set_irq_type( module_data.ac_irq, IRQT_FALLING );
630 if (ac_in) {
631 /* If we're on AC, it doesn't matter if we're on USB or not, use AC
632 * only */
633 SET_HX4700_GPIO_N( CHARGE_EN, 1 );
634 SET_HX4700_GPIO( USB_CHARGE_RATE, 0 );
635 power_status = POWER_AC;
636 set_leds(APM_AC_ONLINE, module_data.Current, module_data.battery_life);
637 } else if (usb_in) {
638 /* We're not on AC, but we are on USB, so charge with that */
639 SET_HX4700_GPIO( USB_CHARGE_RATE, 1 );
640 SET_HX4700_GPIO_N( CHARGE_EN, 1 );
641 power_status = POWER_USB;
642 set_leds(APM_AC_ONLINE, module_data.Current, module_data.battery_life);
643 } else {
644 /* We're not on AC or USB, don't charge */
645 SET_HX4700_GPIO_N( CHARGE_EN, 0 );
646 SET_HX4700_GPIO( USB_CHARGE_RATE, 0 );
647 power_status = POWER_NONE;
648 set_leds(APM_AC_OFFLINE, module_data.Current, module_data.battery_life);
649 module_data.acr_reset = 0;
653 /* update_data(1); */
654 module_data.jiffies_64 = 0; /* Force a re-read on next try */
656 if(enableirq) {
657 enable_irq(module_data.usb_irq);
658 enable_irq(module_data.ac_irq);
662 static int
663 attach_isr(int irq, void *dev_id)
665 if(irq != module_data.usb_irq
666 && irq != module_data.ac_irq) {
667 printk("Bad irq: %d, not %d or %d\n", irq, module_data.usb_irq, module_data.ac_irq);
669 if(module_data.initialized) {
670 SET_HX4700_GPIO_N( CHARGE_EN, 0 );
671 mod_timer(&module_data.irqtimer, jiffies + HZ/10);
672 disable_irq(module_data.usb_irq);
673 disable_irq(module_data.ac_irq);
675 return IRQ_HANDLED;
678 static int
679 battery_class_uevent(struct class_device *dev, char **envp, int num_envp,
680 char *buffer, int buffer_size)
682 return 0;
685 static void
686 battery_class_release(struct class_device *dev)
690 static void
691 battery_class_class_release(struct class *class)
695 static void
696 w1_send_net_address(void)
698 if(net) {
699 int i;
700 w1_write_byte(0x55); /* Match Net Address */
701 for(i = 0; i < sizeof(module_data.net_address)/sizeof(module_data.net_address[0]); i++) {
702 w1_write_byte(module_data.net_address[i]);
704 } else {
705 w1_write_byte(0xcc); /* Skip Net Address */
709 static int
710 w1_probe(struct platform_device *pdev)
712 int retval;
714 led_trigger_register_simple("hx4700-chargefull", &chargefull_trig);
715 led_trigger_register_asic3_timer("hx4700-charging", &charging_trig);
716 led_trigger_event(chargefull_trig, LED_OFF);
717 led_trigger_event(charging_trig, LED_OFF);
719 module_data.initialized = 0;
720 module_data.w1_irq = -1;
721 module_data.usb_irq = -1;
722 module_data.ac_irq = -1;
723 module_data.base = 0;
724 module_data.jiffies_64 = 0;
725 module_data.acr_reset = 0;
727 init_timer(&module_data.irqtimer);
728 module_data.irqtimer.function = power_change_task_handler;
729 module_data.irqtimer.data = 1;
731 init_waitqueue_head(&module_data.irqwait);
733 platform_set_drvdata(pdev, &module_data);
735 module_data.base = ioremap_nocache(0x0c000600, 64);
736 module_data.battery_class = 0;
738 if(!module_data.base) {
739 printk(KERN_NOTICE "%s: Unable to map device\n", driver_name);
740 return -ENODEV;
744 module_data.w1_irq = asic3_irq_base(&hx4700_asic3.dev) + ASIC3_OWM_IRQ;
745 retval = request_irq(module_data.w1_irq, w1_isr, SA_INTERRUPT, driver_name, &module_data);
746 if(retval) {
747 printk(KERN_NOTICE "%s: Unable to get interrupt %d: %d\n",
748 driver_name, module_data.w1_irq, retval);
749 iounmap((void __iomem *)module_data.base);
750 module_data.base = 0;
751 module_data.w1_irq = -1;
752 return -ENODEV;
755 w1_init();
756 if(w1_detect()) {
757 unsigned int readval;
758 int i;
759 w1_write_byte(0x33);
760 for(i = 0; i < sizeof(module_data.net_address)/sizeof(module_data.net_address[0]); i++) {
761 w1_read_byte(&readval);
762 module_data.net_address[i] = readval & 0xff;
764 if(module_data.net_address[0] != 0x30) {
765 printk("Looks like wrong net address is "
766 "%02x %02x %02x %02x %02x %02x %02x %02x\n",
767 module_data.net_address[0], module_data.net_address[1],
768 module_data.net_address[2], module_data.net_address[3],
769 module_data.net_address[4], module_data.net_address[5],
770 module_data.net_address[6], module_data.net_address[7]
773 } else {
774 printk("Could not detect device for net address\n");
775 iounmap((void __iomem *)module_data.base);
776 free_irq(module_data.w1_irq, &module_data);
777 module_data.base = 0;
778 module_data.w1_irq = -1;
779 return -ENODEV;
781 if(w1_detect()) {
782 unsigned int readval;
783 if(battery_class_register(&hx4700_power)) {
784 printk(KERN_ERR "%s: Could not register battery class\n",
785 driver_name);
786 } else {
787 module_data.battery_class = 1;
788 hx4700_power.class_dev.class->uevent = battery_class_uevent;
789 hx4700_power.class_dev.class->release = battery_class_release;
790 hx4700_power.class_dev.class->class_release = battery_class_class_release;
792 w1_send_net_address();
793 w1_write_byte(0x69); /* Read */
794 w1_write_byte(0x08); /* Special Feature Address */
795 w1_read_byte(&readval);
796 if(!(readval & (1 << 7))) {
797 printk("PS is low. Writing 1.\n");
798 /* The PS signal is low. The docs say to write a 1 to it to ensure
799 * proper operation. */
800 if(w1_detect()) {
801 w1_send_net_address();
802 w1_write_byte(0x6c); /* Write */
803 w1_write_byte(0x08); /* Special Feature Address */
804 w1_write_byte(readval | (1 << 7)); /* Data */
805 } else {
806 printk("No detect when writing PS\n");
809 } else {
810 printk("%s: Device not detected on init\n", driver_name);
811 return -ENODEV;
814 module_data.usb_irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE
815 + GPIOD_USBC_DETECT_N;
816 module_data.ac_irq = asic3_irq_base( &hx4700_asic3.dev ) + ASIC3_GPIOD_IRQ_BASE
817 + GPIOD_AC_IN_N;
818 module_data.initialized = 1;
820 /* Get first power state */
821 power_change_task_handler(0);
823 /* USB IRQ */
824 if (request_irq( module_data.usb_irq, attach_isr, SA_INTERRUPT,
825 "Hx4700 USB Detect", NULL ) != 0) {
826 printk( KERN_ERR "Unable to configure USB detect interrupt.\n" );
827 module_data.usb_irq = -1;
830 /* AC IRQ */
831 if (request_irq( module_data.ac_irq, attach_isr, SA_INTERRUPT,
832 "Hx4700 AC Detect", NULL ) != 0) {
833 printk( KERN_ERR "Unable to configure AC detect interrupt.\n" );
834 module_data.ac_irq = -1;
837 #ifdef CONFIG_PM
838 apm_get_power_status = hx4700_apm_get_power_status;
839 #endif
841 return 0;
844 static void
845 w1_deinit(void)
847 /* Turn off OWM clock. I hate to touch the others because they might be
848 * used by other devices like MMC. */
849 asic3_set_clock_cdex(&hx4700_asic3.dev,
850 /* CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | */ CLOCK_CDEX_OWM,
851 /* CLOCK_CDEX_EX0 | CLOCK_CDEX_EX1 | */ 0);
853 /* Clear OWM_EN */
854 asic3_set_extcf_select(&hx4700_asic3.dev,
855 ASIC3_EXTCF_OWM_EN, 0);
857 mdelay(1);
860 static int
861 w1_remove(struct platform_device *pdev)
863 printk("w1_remove\n");
865 led_trigger_unregister_simple(chargefull_trig);
866 led_trigger_unregister_asic3_timer(charging_trig);
868 #ifdef CONFIG_PM
869 apm_get_power_status = NULL;
870 #endif
872 if(module_data.base) {
873 w1_deinit();
875 if(module_data.battery_class) {
876 battery_class_unregister(&hx4700_power);
877 printk("battery class unregistered\n");
879 if(module_data.base) {
880 iounmap((void __iomem *)module_data.base);
881 printk("Base unmapped\n");
883 if(module_data.w1_irq != -1) {
884 disable_irq(module_data.w1_irq);
885 free_irq(module_data.w1_irq, &module_data);
886 printk("w1 irq freed\n");
888 if (module_data.ac_irq != -1) {
889 disable_irq(module_data.ac_irq);
890 free_irq( module_data.ac_irq, NULL );
891 printk("ac irq freed\n");
893 if (module_data.usb_irq != -1) {
894 disable_irq(module_data.usb_irq);
895 free_irq( module_data.usb_irq, NULL );
896 printk("usb irq freed\n");
899 while(timer_pending(&module_data.irqtimer)) {
900 msleep(100);
902 del_timer(&module_data.irqtimer);
904 return 0;
907 static int
908 w1_suspend(struct platform_device *pdev, pm_message_t state)
910 // printk("w1_suspend\n");
911 w1_deinit();
912 return 0;
915 static int
916 w1_resume(struct platform_device *pdev)
918 // printk("w1_resume\n");
919 w1_init();
920 /* check for changes to power that may have occurred */
921 power_change_task_handler(0);
922 /* I think this will work to ensure the interrupt is unmasked. */
923 disable_irq(module_data.w1_irq);
924 enable_irq(module_data.w1_irq);
925 /* Clear OWM_SMB, set OWM_EN */
926 asic3_set_extcf_select(&hx4700_asic3.dev, ASIC3_EXTCF_OWM_EN, ASIC3_EXTCF_OWM_EN);
927 return 0;
930 static struct platform_driver w1_driver = {
931 .driver = {
932 .name = "hx4700-power",
934 .probe = w1_probe,
935 .remove = w1_remove,
936 .suspend = w1_suspend,
937 .resume = w1_resume
940 static int __init
941 w1init(void)
943 printk(KERN_NOTICE "hx4700 Power Management Driver\n");
944 return platform_driver_register(&w1_driver);
947 static void __exit
948 w1exit(void)
950 platform_driver_unregister(&w1_driver);
953 module_init(w1init);
954 module_exit(w1exit);
956 MODULE_AUTHOR("Aric D. Blumer, SDG Systems, LLC");
957 MODULE_DESCRIPTION("hx4700 Power Management Driver");
958 MODULE_LICENSE("GPL");
960 /* vim600: set expandtab: */