diff options
author | Rob Purchase <shotofadds@rockbox.org> | 2009-10-10 17:35:02 +0000 |
---|---|---|
committer | Rob Purchase <shotofadds@rockbox.org> | 2009-10-10 17:35:02 +0000 |
commit | 16ada4cb81c70c1a151c69aa08da13e55aba0081 (patch) | |
tree | c92dda004a162cea1d2ded3188cffe1ca6f04077 /firmware/drivers | |
parent | 31464f7930cd8857ef8d00ed75534087057058e2 (diff) | |
download | rockbox-16ada4cb81c70c1a151c69aa08da13e55aba0081.tar.gz rockbox-16ada4cb81c70c1a151c69aa08da13e55aba0081.zip |
Initial support for runtime detection of the PMU used in newer D2+ models (PCF50635). The backlight and battery monitoring should work, but the RTC and touchscreen are not yet implemented.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23078 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/drivers')
-rw-r--r-- | firmware/drivers/pcf50606.c | 12 | ||||
-rw-r--r-- | firmware/drivers/pcf50635.c | 132 |
2 files changed, 143 insertions, 1 deletions
diff --git a/firmware/drivers/pcf50606.c b/firmware/drivers/pcf50606.c index 8592c005fe..4ef747fe80 100644 --- a/firmware/drivers/pcf50606.c +++ b/firmware/drivers/pcf50606.c | |||
@@ -53,7 +53,17 @@ int pcf50606_read_multiple(int address, unsigned char* buf, int count) | |||
53 | 53 | ||
54 | void pcf50606_init(void) | 54 | void pcf50606_init(void) |
55 | { | 55 | { |
56 | // TODO | 56 | #ifdef COWON_D2 |
57 | /* Set outputs as per OF - further investigation required. */ | ||
58 | pcf50606_write(PCF5060X_DCDEC1, 0xe4); | ||
59 | pcf50606_write(PCF5060X_IOREGC, 0xf5); | ||
60 | pcf50606_write(PCF5060X_D1REGC1, 0xf5); | ||
61 | pcf50606_write(PCF5060X_D2REGC1, 0xe9); | ||
62 | pcf50606_write(PCF5060X_D3REGC1, 0xf8); /* WM8985 3.3v */ | ||
63 | pcf50606_write(PCF5060X_DCUDC1, 0xe7); | ||
64 | pcf50606_write(PCF5060X_LPREGC1, 0x0); | ||
65 | pcf50606_write(PCF5060X_LPREGC2, 0x2); | ||
66 | #endif | ||
57 | } | 67 | } |
58 | 68 | ||
59 | void pcf50606_reset_timeout(void) | 69 | void pcf50606_reset_timeout(void) |
diff --git a/firmware/drivers/pcf50635.c b/firmware/drivers/pcf50635.c new file mode 100644 index 0000000000..c436498670 --- /dev/null +++ b/firmware/drivers/pcf50635.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2009 by Rob Purchase | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "pcf50635.h" | ||
22 | #include "i2c.h" | ||
23 | #include "system.h" | ||
24 | |||
25 | #define PCF50635_ADDR 0xe6 | ||
26 | |||
27 | int pcf50635_write(int address, unsigned char val) | ||
28 | { | ||
29 | unsigned char data[] = { address, val }; | ||
30 | return i2c_write(PCF50635_ADDR, data, 2); | ||
31 | } | ||
32 | |||
33 | int pcf50635_write_multiple(int address, const unsigned char* buf, int count) | ||
34 | { | ||
35 | int i; | ||
36 | |||
37 | for (i = 0; i < count; i++) | ||
38 | pcf50635_write(address + i, buf[i]); | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | int pcf50635_read(int address) | ||
44 | { | ||
45 | unsigned char val = -1; | ||
46 | i2c_readmem(PCF50635_ADDR, address, &val, 1); | ||
47 | return val; | ||
48 | } | ||
49 | |||
50 | int pcf50635_read_multiple(int address, unsigned char* buf, int count) | ||
51 | { | ||
52 | return i2c_readmem(PCF50635_ADDR, address, buf, count); | ||
53 | } | ||
54 | |||
55 | void pcf50635_init(void) | ||
56 | { | ||
57 | #ifdef COWON_D2 | ||
58 | /* Configure outputs as per OF */ | ||
59 | pcf50635_write(PCF5063X_REG_DOWN1OUT, 0x13); /* DOWN1 = 1.2V */ | ||
60 | pcf50635_write(PCF5063X_REG_DOWN1CTL, 0x1e); /* DOWN1 DVM step = max */ | ||
61 | pcf50635_write(PCF5063X_REG_DOWN1ENA, 0x1); /* DOWN1 enable */ | ||
62 | pcf50635_write(PCF5063X_REG_DOWN2OUT, 0x2f); /* DOWN2 = 1.8V */ | ||
63 | pcf50635_write(PCF5063X_REG_DOWN2CTL, 0x1e); /* DOWN2 DVM step = max */ | ||
64 | pcf50635_write(PCF5063X_REG_DOWN2ENA, 0x1); /* DOWN2 enable */ | ||
65 | pcf50635_write(PCF5063X_REG_AUTOOUT, 0x5f); /* AUTO = 3.0V */ | ||
66 | pcf50635_write(PCF5063X_REG_AUTOENA, 0x1); /* AUTO enable */ | ||
67 | pcf50635_write(PCF5063X_REG_LDO1OUT, 0x18); /* LDO1 = 3.3V */ | ||
68 | pcf50635_write(PCF5063X_REG_LDO1ENA, 0x1); /* LDO1 enable */ | ||
69 | pcf50635_write(PCF5063X_REG_LDO2OUT, 0x15); /* LDO2 = 3.0V */ | ||
70 | pcf50635_write(PCF5063X_REG_LDO2ENA, 0x1); /* LDO2 enable */ | ||
71 | pcf50635_write(PCF5063X_REG_LDO3ENA, 0x0); /* LDO3 disable */ | ||
72 | pcf50635_write(PCF5063X_REG_LDO4OUT, 0x15); /* LDO4 = 3.0V */ | ||
73 | pcf50635_write(PCF5063X_REG_LDO4ENA, 0x1); /* LDO4 enable */ | ||
74 | pcf50635_write(PCF5063X_REG_LDO5OUT, 0x9); /* LDO5 = 1.8V */ | ||
75 | pcf50635_write(PCF5063X_REG_LDO5ENA, 0x1); /* LDO4 enable */ | ||
76 | pcf50635_write(PCF5063X_REG_LDO6OUT, 0xc); /* LDO6 = 2.1V */ | ||
77 | pcf50635_write(PCF5063X_REG_LDO6ENA, 0x1); /* LDO4 enable */ | ||
78 | pcf50635_write(PCF5063X_REG_HCLDOENA, 0x0); /* HCLDO disable */ | ||
79 | |||
80 | /* Configure automatic battery charging as per OF */ | ||
81 | pcf50635_write(PCF5063X_REG_MBCC1, | ||
82 | pcf50635_read(PCF5063X_REG_MBCC1) | 7); /* auto charge termination & resume */ | ||
83 | pcf50635_write(PCF5063X_REG_MBCC2, 0xa8); /* Vmax = 4.2V, Vbatcond = 2.7V, long debounce */ | ||
84 | pcf50635_write(PCF5063X_REG_MBCC3, 0x2a); /* precharge level = 16% */ | ||
85 | pcf50635_write(PCF5063X_REG_MBCC4, 0x94); /* fastcharge level = 58% */ | ||
86 | pcf50635_write(PCF5063X_REG_MBCC5, 0xff); /* fastcharge level (usb) = 100% */ | ||
87 | pcf50635_write(PCF5063X_REG_MBCC6, 0x4); /* cutoff level = 12.5% */ | ||
88 | pcf50635_write(PCF5063X_REG_MBCC7, 0xc1); /* bat-sysimax = 2.2A, USB = 500mA */ | ||
89 | pcf50635_write(PCF5063X_REG_BVMCTL, 0xe); /* batok level = 3.4V */ | ||
90 | |||
91 | /* IRQ masks */ | ||
92 | pcf50635_write(PCF5063X_REG_INT1M, 0x8a); /* enable alarm, usbins, adpins */ | ||
93 | pcf50635_write(PCF5063X_REG_INT2M, 0xff); /* mask all */ | ||
94 | pcf50635_write(PCF5063X_REG_INT3M, 0x7f); /* enable onkey1s */ | ||
95 | pcf50635_write(PCF5063X_REG_INT4M, 0xfd); /* enable lowbat */ | ||
96 | pcf50635_write(PCF5063X_REG_INT5M, 0xff); /* mask all */ | ||
97 | |||
98 | pcf50635_write(PCF5063X_REG_OOCMODE, 0x0); | ||
99 | pcf50635_write(PCF5063X_REG_OOCCTL, 0x2); /* actphrst = phase 3 */ | ||
100 | pcf50635_write(PCF5063X_REG_OOCWAKE, /* adapter, usb, (rtc) wake */ | ||
101 | (pcf50635_read(PCF5063X_REG_OOCWAKE) & 0x10) | 0xc1); | ||
102 | |||
103 | /* We don't care about the GPIOs, disable them */ | ||
104 | pcf50635_write(PCF5063X_REG_GPIOCTL, 0x0); | ||
105 | pcf50635_write(PCF5063X_REG_GPIO1CFG, 0x0); | ||
106 | pcf50635_write(PCF5063X_REG_GPIO2CFG, 0x0); | ||
107 | pcf50635_write(PCF5063X_REG_GPIO3CFG, 0x0); | ||
108 | #endif | ||
109 | } | ||
110 | |||
111 | void pcf50635_read_adc(int adc, short* res1, short* res2) | ||
112 | { | ||
113 | int adcs1 = 0, adcs2 = 0, adcs3 = 0; | ||
114 | |||
115 | int level = disable_irq_save(); | ||
116 | |||
117 | pcf50635_write(PCF5063X_REG_ADCC1, PCF5063X_ADCC1_ADCSTART | adc); | ||
118 | |||
119 | do { | ||
120 | adcs3 = pcf50635_read(PCF5063X_REG_ADCS3); | ||
121 | } while (!(adcs3 & PCF5063X_ADCS3_ADCRDY)); | ||
122 | |||
123 | if (res1 != NULL) adcs1 = pcf50635_read(PCF5063X_REG_ADCS1); | ||
124 | if (res2 != NULL) adcs2 = pcf50635_read(PCF5063X_REG_ADCS2); | ||
125 | |||
126 | pcf50635_write(PCF5063X_REG_ADCC1, 0); | ||
127 | |||
128 | restore_interrupt(level); | ||
129 | |||
130 | if (res1 != NULL) *res1 = (adcs1 << 2) | (adcs3 & 3); | ||
131 | if (res2 != NULL) *res2 = (adcs2 << 2) | ((adcs3 & 0xC) >> 2); | ||
132 | } | ||