summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorRafaël Carré <rafael.carre@gmail.com>2010-05-17 20:53:25 +0000
committerRafaël Carré <rafael.carre@gmail.com>2010-05-17 20:53:25 +0000
commit88c55d7290b7c360075557c40fdf65ceeeaf0c4b (patch)
tree29cf685626bf8c01bb64ed9456850f62e4a57d7d /firmware/target/arm
parent2ed7745ddefc084ca7030d48b251882e94fa2f9c (diff)
downloadrockbox-88c55d7290b7c360075557c40fdf65ceeeaf0c4b.tar.gz
rockbox-88c55d7290b7c360075557c40fdf65ceeeaf0c4b.zip
as3514/as3543 fixes
- Enable end of charge monitoring once, it doesn't need to be disabled - Acknowledge the first (wrong) end of charge interrupt on charger enable (this had been broken in r25299) - Centralize reads to ENRD* registers and cache the results when needed - on PP it is not needed because reads are atomic, we only check for end of charge when the charging, and for charger presence when discharging as3525v2 (using as3543) specifics - I got the datasheet today from AMS, thanks to them for being so fast and not require me to sign tons of papers! - USB detection now works on as3525v2 using the as3543. Clip+ won't reboot to OF yet, it needs mkamsboot support first (usbstack disabled) - Charging should work, the CHARGER register is at a different place, it is an extended PMU register -> use ascodec_read/write_charger() to access it - real interrupts are not used yet for ENRD, we get thousands of interrupts per second, apparently only limited by the i2c clock. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@26116 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/as3525/ascodec-as3525.c98
-rw-r--r--firmware/target/arm/as3525/ascodec-target.h66
-rw-r--r--firmware/target/arm/as3525/power-as3525.c2
-rw-r--r--firmware/target/arm/as3525/usb-as3525.c21
-rw-r--r--firmware/target/arm/as3525/usb-target.h2
-rw-r--r--firmware/target/arm/ascodec-target.h23
-rw-r--r--firmware/target/arm/powermgmt-ascodec.c22
7 files changed, 142 insertions, 92 deletions
diff --git a/firmware/target/arm/as3525/ascodec-as3525.c b/firmware/target/arm/as3525/ascodec-as3525.c
index 87a1447c63..52d50ef077 100644
--- a/firmware/target/arm/as3525/ascodec-as3525.c
+++ b/firmware/target/arm/as3525/ascodec-as3525.c
@@ -185,10 +185,18 @@ void ascodec_init(void)
185 185
186 I2C2_IMR = 0x00; /* disable interrupts */ 186 I2C2_IMR = 0x00; /* disable interrupts */
187 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */ 187 I2C2_INT_CLR |= I2C2_RIS; /* clear interrupt status */
188 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO | INTERRUPT_AUDIO; 188 VIC_INT_ENABLE = INTERRUPT_I2C_AUDIO;
189#if CONFIG_CPU == AS3525 /* interrupts do not work correctly on as3525v2 */
190 VIC_INT_ENABLE = INTERRUPT_AUDIO;
191#endif
189 192
190 /* Generate irq for usb+charge status change */ 193 /* Generate irq for usb+charge status change */
191 ascodec_write(AS3514_IRQ_ENRD0, /*IRQ_CHGSTAT |*/ IRQ_USBSTAT); 194 ascodec_write(AS3514_IRQ_ENRD0,
195#ifdef CONFIG_CHARGING /* m200v4 can't charge */
196 IRQ_CHGSTAT | IRQ_ENDOFCH |
197#endif
198 IRQ_USBSTAT);
199
192 /* Generate irq for push-pull, active high, irq on rtc+adc change */ 200 /* Generate irq for push-pull, active high, irq on rtc+adc change */
193 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE | 201 ascodec_write(AS3514_IRQ_ENRD2, IRQ_PUSHPULL | IRQ_HIGHACTIVE |
194 /*IRQ_RTC |*/ IRQ_ADC); 202 /*IRQ_RTC |*/ IRQ_ADC);
@@ -342,19 +350,8 @@ static void ascodec_wait(struct ascodec_request *req)
342void ascodec_async_write(unsigned int index, unsigned int value, 350void ascodec_async_write(unsigned int index, unsigned int value,
343 struct ascodec_request *req) 351 struct ascodec_request *req)
344{ 352{
345 switch(index) { 353 if (index == AS3514_CVDD_DCDC3) /* prevent setting of the LREG_CP_not bit */
346 case AS3514_CVDD_DCDC3:
347 /* prevent setting of the LREG_CP_not bit */
348 value &= ~(1 << 5); 354 value &= ~(1 << 5);
349 break;
350 case AS3514_IRQ_ENRD0:
351 /* save value in register shadow
352 * for ascodec_(en|dis)able_endofch_irq() */
353 ascodec_enrd0_shadow = value;
354 break;
355 default:
356 break;
357 }
358 355
359 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1); 356 ascodec_req_init(req, ASCODEC_REQ_WRITE, index, 1);
360 req->data[0] = value; 357 req->data[0] = value;
@@ -429,24 +426,37 @@ int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data)
429 return i; 426 return i;
430} 427}
431 428
432#if CONFIG_CPU == AS3525 429/*
433static void ascodec_read_cb(unsigned const char *data, unsigned int len) 430 * Reading AS3514_IRQ_ENRD0 clears all interrupt bits, so we cache the results
431 * and clear individual bits when a specific interrupt is checked:
432 * - we clear the ENDOFCH (end of charge) interrupt when it's read
433 * - we set the usb and charger presence when the status change is detected
434 *
435 * on AS3525(v1) ENRD0 is only read in an interrupt handler
436 * on AS3525v2 the interrupt handler doesn't work (yet), so we read the register
437 * synchronously.
438 * - To avoid race conditions all the reads to this register must be atomic.
439 * We don't need to disable interrupts when reading it because all the reads
440 * (in powermgmt-ascodec.c and power-as3525.c) are performed by the same
441 * thread (the power thread).
442 */
443static void cache_enrd0(int enrd0)
434{ 444{
435 if (len != 3) /* some error happened? */ 445 if (enrd0 & CHG_ENDOFCH) { /* chg finished */
436 return; 446 ascodec_enrd0_shadow |= CHG_ENDOFCH;
437
438 if (data[0] & CHG_ENDOFCH) { /* chg finished */
439 IFDEBUG(int_chg_finished++); 447 IFDEBUG(int_chg_finished++);
440 } 448 }
441 if (data[0] & CHG_CHANGED) { /* chg status changed */ 449 if (enrd0 & CHG_CHANGED) { /* chg status changed */
442 if (data[0] & CHG_STATUS) { 450 if (enrd0 & CHG_STATUS) {
451 ascodec_enrd0_shadow |= CHG_STATUS;
443 IFDEBUG(int_chg_insert++); 452 IFDEBUG(int_chg_insert++);
444 } else { 453 } else {
454 ascodec_enrd0_shadow &= ~CHG_STATUS;
445 IFDEBUG(int_chg_remove++); 455 IFDEBUG(int_chg_remove++);
446 } 456 }
447 } 457 }
448 if (data[0] & USB_CHANGED) { /* usb status changed */ 458 if (enrd0 & USB_CHANGED) { /* usb status changed */
449 if (data[0] & USB_STATUS) { 459 if (enrd0 & USB_STATUS) {
450 IFDEBUG(int_usb_insert++); 460 IFDEBUG(int_usb_insert++);
451 usb_insert_int(); 461 usb_insert_int();
452 } else { 462 } else {
@@ -454,6 +464,16 @@ static void ascodec_read_cb(unsigned const char *data, unsigned int len)
454 usb_remove_int(); 464 usb_remove_int();
455 } 465 }
456 } 466 }
467}
468
469#if CONFIG_CPU == AS3525
470static void ascodec_read_cb(unsigned const char *data, unsigned int len)
471{
472 if (len != 3) /* some error happened? */
473 return;
474
475 cache_enrd0(data[0]);
476
457 if (data[2] & IRQ_RTC) { /* rtc irq */ 477 if (data[2] & IRQ_RTC) { /* rtc irq */
458 /* 478 /*
459 * Can be configured for once per second or once per minute, 479 * Can be configured for once per second or once per minute,
@@ -468,22 +488,40 @@ static void ascodec_read_cb(unsigned const char *data, unsigned int len)
468 VIC_INT_ENABLE = INTERRUPT_AUDIO; 488 VIC_INT_ENABLE = INTERRUPT_AUDIO;
469} 489}
470 490
491#endif /* CONFIG_CPU == AS3525 */
492
471void ascodec_wait_adc_finished(void) 493void ascodec_wait_adc_finished(void)
472{ 494{
495#if CONFIG_CPU == AS3525
473 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK); 496 wakeup_wait(&adc_wkup, TIMEOUT_BLOCK);
497#else
498 /* no interrupts, busy wait
499 * XXX: make sure this is the only reader of IRQ_ENRD2
500 */
501 while(!(ascodec_read(AS3514_IRQ_ENRD2) & IRQ_ADC))
502 yield();
503#endif
474} 504}
475#endif /* CONFIG_CPU == AS3525 */
476
477 505
478void ascodec_enable_endofch_irq(void) 506#ifdef CONFIG_CHARGING
507bool ascodec_endofch(void)
479{ 508{
480 ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow | CHG_ENDOFCH); 509#if CONFIG_CPU != AS3525
510 cache_enrd0(ascodec_read(AS3514_IRQ_ENRD0));
511#endif
512 bool ret = ascodec_enrd0_shadow & CHG_ENDOFCH;
513 ascodec_enrd0_shadow &= ~CHG_ENDOFCH; // clear interrupt
514 return ret;
481} 515}
482 516
483void ascodec_disable_endofch_irq(void) 517bool ascodec_chg_status(void)
484{ 518{
485 ascodec_write(AS3514_IRQ_ENRD0, ascodec_enrd0_shadow & ~CHG_ENDOFCH); 519#if CONFIG_CPU != AS3525
520 cache_enrd0(ascodec_read(AS3514_IRQ_ENRD0));
521#endif
522 return ascodec_enrd0_shadow & CHG_STATUS;
486} 523}
524#endif /* CONFIG_CHARGING */
487 525
488/* 526/*
489 * NOTE: 527 * NOTE:
diff --git a/firmware/target/arm/as3525/ascodec-target.h b/firmware/target/arm/as3525/ascodec-target.h
index 37947541c2..8ce9a428d3 100644
--- a/firmware/target/arm/as3525/ascodec-target.h
+++ b/firmware/target/arm/as3525/ascodec-target.h
@@ -52,7 +52,7 @@
52/* 52/*
53 * How many bytes we using in struct ascodec_request for the data buffer. 53 * How many bytes we using in struct ascodec_request for the data buffer.
54 * 4 fits the alignment best right now. 54 * 4 fits the alignment best right now.
55 * We don't actually use more than 2 at the moment (in adc_read). 55 * We don't actually use more than 3 at the moment (when reading interrupts)
56 * Upper limit would be 255 since DACNT is 8 bits! 56 * Upper limit would be 255 since DACNT is 8 bits!
57 */ 57 */
58#define ASCODEC_REQ_MAXLEN 4 58#define ASCODEC_REQ_MAXLEN 4
@@ -74,19 +74,6 @@ void ascodec_init(void);
74 74
75int ascodec_write(unsigned int index, unsigned int value); 75int ascodec_write(unsigned int index, unsigned int value);
76 76
77#if CONFIG_CPU == AS3525v2
78static inline void ascodec_write_pmu(unsigned int index, unsigned int subreg,
79 unsigned int value)
80{
81 /* we disable interrupts to make sure no operation happen on the i2c bus
82 * between selecting the sub register and writing to it */
83 int oldstatus = disable_irq_save();
84 ascodec_write(AS3543_PMU_ENABLE, 8|subreg);
85 ascodec_write(index, value);
86 restore_irq(oldstatus);
87}
88#endif
89
90int ascodec_read(unsigned int index); 77int ascodec_read(unsigned int index);
91 78
92int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data); 79int ascodec_readbytes(unsigned int index, unsigned int len, unsigned char *data);
@@ -119,18 +106,55 @@ void ascodec_lock(void);
119 106
120void ascodec_unlock(void); 107void ascodec_unlock(void);
121 108
122#if CONFIG_CPU == AS3525
123void ascodec_wait_adc_finished(void); 109void ascodec_wait_adc_finished(void);
124#else 110
125static inline void ascodec_wait_adc_finished(void) 111static inline void ascodec_monitor_endofch(void) {} /* already enabled */
112
113bool ascodec_endofch(void);
114
115bool ascodec_chg_status(void);
116
117#if CONFIG_CPU == AS3525v2
118static inline void ascodec_write_pmu(unsigned int index, unsigned int subreg,
119 unsigned int value)
120{
121 /* we disable interrupts to make sure no operation happen on the i2c bus
122 * between selecting the sub register and writing to it */
123 int oldstatus = disable_irq_save();
124 ascodec_write(AS3543_PMU_ENABLE, 8|subreg);
125 ascodec_write(index, value);
126 restore_irq(oldstatus);
127}
128
129static inline int ascodec_read_pmu(unsigned int index, unsigned int subreg)
126{ 130{
127 /* FIXME: Doesn't work yet on AS3525v2 */ 131 /* we disable interrupts to make sure no operation happen on the i2c bus
132 * between selecting the sub register and reading it */
133 int oldstatus = disable_irq_save();
134 ascodec_write(AS3543_PMU_ENABLE, 8|subreg);
135 int ret = ascodec_read(index);
136 restore_irq(oldstatus);
137 return ret;
128} 138}
129#endif 139#endif /* CONFIG_CPU == AS3525v2 */
130 140
131void ascodec_enable_endofch_irq(void); 141static inline void ascodec_write_charger(int value)
142{
143#if CONFIG_CPU == AS3525
144 ascodec_write(AS3514_CHARGER, value);
145#else
146 ascodec_write_pmu(AS3543_CHARGER, 1, value);
147#endif
148}
132 149
133void ascodec_disable_endofch_irq(void); 150static inline int ascodec_read_charger(void)
151{
152#if CONFIG_CPU == AS3525
153 return ascodec_read(AS3514_CHARGER);
154#else
155 return ascodec_read_pmu(AS3543_CHARGER, 1);
156#endif
157}
134 158
135#endif /* !SIMULATOR */ 159#endif /* !SIMULATOR */
136 160
diff --git a/firmware/target/arm/as3525/power-as3525.c b/firmware/target/arm/as3525/power-as3525.c
index 3570d7c75a..7b93dd1cd1 100644
--- a/firmware/target/arm/as3525/power-as3525.c
+++ b/firmware/target/arm/as3525/power-as3525.c
@@ -41,7 +41,7 @@ void power_init(void)
41#if CONFIG_CHARGING 41#if CONFIG_CHARGING
42unsigned int power_input_status(void) 42unsigned int power_input_status(void)
43{ 43{
44 return (ascodec_read(AS3514_IRQ_ENRD0) & (1<<5)) ? 44 return ascodec_chg_status() ?
45 POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE; 45 POWER_INPUT_MAIN_CHARGER : POWER_INPUT_NONE;
46 46
47 /* TODO: Handle USB and other sources properly */ 47 /* TODO: Handle USB and other sources properly */
diff --git a/firmware/target/arm/as3525/usb-as3525.c b/firmware/target/arm/as3525/usb-as3525.c
index 74bfc17364..be62752033 100644
--- a/firmware/target/arm/as3525/usb-as3525.c
+++ b/firmware/target/arm/as3525/usb-as3525.c
@@ -29,13 +29,7 @@
29#include "power.h" 29#include "power.h"
30#include "as3525.h" 30#include "as3525.h"
31 31
32#if CONFIG_CPU == AS3525
33static int usb_status = USB_EXTRACTED; 32static int usb_status = USB_EXTRACTED;
34#else
35#if defined(SANSA_CLIPV2)
36#define USB_DETECT_PIN 6
37#endif
38#endif
39 33
40void usb_enable(bool on) 34void usb_enable(bool on)
41{ 35{
@@ -51,12 +45,8 @@ void usb_enable(bool on)
51 45
52void usb_init_device(void) 46void usb_init_device(void)
53{ 47{
54#ifdef USB_DETECT_PIN
55 GPIOA_DIR &= ~(1 << USB_DETECT_PIN); /* set as input */
56#endif
57} 48}
58 49
59#if CONFIG_CPU == AS3525
60void usb_insert_int(void) 50void usb_insert_int(void)
61{ 51{
62 usb_status = USB_INSERTED; 52 usb_status = USB_INSERTED;
@@ -71,14 +61,3 @@ int usb_detect(void)
71{ 61{
72 return usb_status; 62 return usb_status;
73} 63}
74#else
75int usb_detect(void)
76{
77#ifdef USB_DETECT_PIN
78 if (GPIOA_PIN( USB_DETECT_PIN ))
79 return USB_INSERTED;
80 else
81#endif
82 return USB_EXTRACTED;
83}
84#endif
diff --git a/firmware/target/arm/as3525/usb-target.h b/firmware/target/arm/as3525/usb-target.h
index 4c54dc182d..6df6d7c1d5 100644
--- a/firmware/target/arm/as3525/usb-target.h
+++ b/firmware/target/arm/as3525/usb-target.h
@@ -23,9 +23,7 @@
23 23
24void usb_init_device(void); 24void usb_init_device(void);
25int usb_detect(void); 25int usb_detect(void);
26#if CONFIG_CPU == AS3525
27void usb_insert_int(void); 26void usb_insert_int(void);
28void usb_remove_int(void); 27void usb_remove_int(void);
29#endif /* CONFIG_CPU == AS3525 */
30 28
31#endif /* USB_TARGET_H */ 29#endif /* USB_TARGET_H */
diff --git a/firmware/target/arm/ascodec-target.h b/firmware/target/arm/ascodec-target.h
index c87d869ebb..68d9905a6b 100644
--- a/firmware/target/arm/ascodec-target.h
+++ b/firmware/target/arm/ascodec-target.h
@@ -59,14 +59,19 @@ static inline void ascodec_unlock(void)
59 i2c_unlock(); 59 i2c_unlock();
60} 60}
61 61
62static inline void ascodec_enable_endofch_irq(void) 62static inline bool ascodec_chg_status(void)
63{ 63{
64 ascodec_write(AS3514_IRQ_ENRD0, IRQ_ENDOFCH); 64 return ascodec_read(AS3514_IRQ_ENRD0) & CHG_STATUS;
65}
66
67static inline bool ascodec_endofch(void)
68{
69 return ascodec_read(AS3514_IRQ_ENRD0) & CHG_ENDOFCH;
65} 70}
66 71
67static inline void ascodec_disable_endofch_irq(void) 72static inline void ascodec_monitor_endofch(void)
68{ 73{
69 ascodec_write(AS3514_IRQ_ENRD0, 0); 74 ascodec_write(AS3514_IRQ_ENRD0, IRQ_ENDOFCH);
70} 75}
71 76
72static inline void ascodec_wait_adc_finished(void) 77static inline void ascodec_wait_adc_finished(void)
@@ -81,6 +86,16 @@ static inline void ascodec_wait_adc_finished(void)
81 */ 86 */
82} 87}
83 88
89static inline void ascodec_write_charger(int value)
90{
91 ascodec_write(AS3514_CHARGER, value);
92}
93
94static inline int ascodec_read_charger(void)
95{
96 return ascodec_read(AS3514_CHARGER);
97}
98
84extern void ascodec_suppressor_on(bool on); 99extern void ascodec_suppressor_on(bool on);
85 100
86#endif /* CPU_PP */ 101#endif /* CPU_PP */
diff --git a/firmware/target/arm/powermgmt-ascodec.c b/firmware/target/arm/powermgmt-ascodec.c
index b463486346..e50367fe93 100644
--- a/firmware/target/arm/powermgmt-ascodec.c
+++ b/firmware/target/arm/powermgmt-ascodec.c
@@ -94,9 +94,7 @@ static void battery_voltage_sync(void)
94/* Disable charger and minimize all settings. Reset timers, etc. */ 94/* Disable charger and minimize all settings. Reset timers, etc. */
95static void disable_charger(void) 95static void disable_charger(void)
96{ 96{
97 ascodec_disable_endofch_irq(); 97 ascodec_write_charger(TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
98 ascodec_write(AS3514_CHARGER,
99 TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
100 98
101 if (charge_state > DISCHARGING) 99 if (charge_state > DISCHARGING)
102 charge_state = DISCHARGING; /* Not an error state already */ 100 charge_state = DISCHARGING; /* Not an error state already */
@@ -108,14 +106,13 @@ static void disable_charger(void)
108/* Enable charger with specified settings. Start timers, etc. */ 106/* Enable charger with specified settings. Start timers, etc. */
109static void enable_charger(void) 107static void enable_charger(void)
110{ 108{
111 ascodec_write(AS3514_CHARGER, BATT_CHG_I | BATT_CHG_V); 109 ascodec_write_charger(BATT_CHG_I | BATT_CHG_V);
112 /* Watch for end of charge. Temperature supervision is handled in
113 * hardware. Charger status can be read and has no interrupt enable. */
114 ascodec_enable_endofch_irq();
115 110
116 sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */ 111 sleep(HZ/10); /* Allow charger turn-on time (it could be gradual). */
117 112
118 ascodec_disable_endofch_irq(); 113 /* acknowledge first end of charging interrupt, it seems to happen both
114 * at charger plug and charger unplug */
115 ascodec_endofch();
119 116
120 charge_state = CHARGING; 117 charge_state = CHARGING;
121 charger_total_timer = CHARGER_TOTAL_TIMER; 118 charger_total_timer = CHARGER_TOTAL_TIMER;
@@ -125,9 +122,8 @@ static void enable_charger(void)
125void powermgmt_init_target(void) 122void powermgmt_init_target(void)
126{ 123{
127 /* Everything CHARGER, OFF! */ 124 /* Everything CHARGER, OFF! */
128 ascodec_disable_endofch_irq(); 125 ascodec_monitor_endofch();
129 ascodec_write(AS3514_CHARGER, 126 ascodec_write_charger(TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
130 TMPSUP_OFF | CHG_I_50MA | CHG_V_3_90V | CHG_OFF);
131} 127}
132 128
133static inline void charger_plugged(void) 129static inline void charger_plugged(void)
@@ -148,7 +144,7 @@ static inline void charger_control(void)
148 if (BATT_FULL_VOLTAGE == thresh) 144 if (BATT_FULL_VOLTAGE == thresh)
149 { 145 {
150 /* Wait for CHG_status to be indicated. */ 146 /* Wait for CHG_status to be indicated. */
151 if ((ascodec_read(AS3514_IRQ_ENRD0) & CHG_STATUS) == 0) 147 if (!ascodec_chg_status())
152 break; 148 break;
153 149
154 batt_threshold = BATT_VAUTO_RECHARGE; 150 batt_threshold = BATT_VAUTO_RECHARGE;
@@ -163,7 +159,7 @@ static inline void charger_control(void)
163 159
164 case CHARGING: 160 case CHARGING:
165 { 161 {
166 if ((ascodec_read(AS3514_IRQ_ENRD0) & CHG_ENDOFCH) == 0) 162 if (!ascodec_endofch())
167 { 163 {
168 if (--charger_total_timer > 0) 164 if (--charger_total_timer > 0)
169 break; 165 break;