summaryrefslogtreecommitdiff
path: root/firmware/target/arm/s5l8702/ipod6g/pmu-6g.c
diff options
context:
space:
mode:
authorCástor Muñoz <cmvidal@gmail.com>2017-03-03 22:46:57 +0100
committerCástor Muñoz <cmvidal@gmail.com>2017-03-03 22:50:38 +0100
commit1ba5ef716d37a9fe7f0863caed2fab8570b2c7c4 (patch)
tree2e209052bc802183b73a705f77ebc552250c9353 /firmware/target/arm/s5l8702/ipod6g/pmu-6g.c
parent8ff1b6b6033aad55fadf076f066da5d8b7d2e631 (diff)
downloadrockbox-1ba5ef716d37a9fe7f0863caed2fab8570b2c7c4.tar.gz
rockbox-1ba5ef716d37a9fe7f0863caed2fab8570b2c7c4.zip
ipod6g: rename some target files
As preparation to add new targets to the s5l8702 directory, rename files as: s5l8702/ipod6g/*-ipod6g.c -> s5l8702/ipod6g/*-6g.c Change-Id: I0cd03d6bcf39b2aa198235f9014cb6948bbafcd5
Diffstat (limited to 'firmware/target/arm/s5l8702/ipod6g/pmu-6g.c')
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/pmu-6g.c469
1 files changed, 469 insertions, 0 deletions
diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-6g.c b/firmware/target/arm/s5l8702/ipod6g/pmu-6g.c
new file mode 100644
index 0000000000..d282a48d5b
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/pmu-6g.c
@@ -0,0 +1,469 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: pmu-nano2g.c 27752 2010-08-08 10:49:32Z bertrik $
9 *
10 * Copyright © 2008 Rafaël Carré
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
22#include "config.h"
23#include "kernel.h"
24#include "thread.h"
25
26#include "pmu-target.h"
27#include "adc-target.h"
28#include "i2c-s5l8702.h"
29#include "gpio-s5l8702.h"
30
31
32int pmu_read_multiple(int address, int count, unsigned char* buffer)
33{
34 return i2c_read(0, 0xe6, address, count, buffer);
35}
36
37int pmu_write_multiple(int address, int count, unsigned char* buffer)
38{
39 return i2c_write(0, 0xe6, address, count, buffer);
40}
41
42unsigned char pmu_read(int address)
43{
44 unsigned char tmp;
45
46 pmu_read_multiple(address, 1, &tmp);
47
48 return tmp;
49}
50
51int pmu_write(int address, unsigned char val)
52{
53 return pmu_write_multiple(address, 1, &val);
54}
55
56void pmu_ldo_on_in_standby(unsigned int ldo, int onoff)
57{
58 if (ldo < 4)
59 {
60 unsigned char newval = pmu_read(0x3B) & ~(1 << (2 * ldo));
61 if (onoff) newval |= 1 << (2 * ldo);
62 pmu_write(0x3B, newval);
63 }
64 else if (ldo < 8)
65 {
66 unsigned char newval = pmu_read(0x3C) & ~(1 << (2 * (ldo - 4)));
67 if (onoff) newval |= 1 << (2 * (ldo - 4));
68 pmu_write(0x3C, newval);
69 }
70}
71
72void pmu_ldo_set_voltage(unsigned int ldo, unsigned char voltage)
73{
74 if (ldo > 6) return;
75 pmu_write(0x2d + (ldo << 1), voltage);
76}
77
78void pmu_hdd_power(bool on)
79{
80 pmu_write(0x1b, on ? 1 : 0);
81}
82
83void pmu_ldo_power_on(unsigned int ldo)
84{
85 if (ldo > 6) return;
86 pmu_write(0x2e + (ldo << 1), 1);
87}
88
89void pmu_ldo_power_off(unsigned int ldo)
90{
91 if (ldo > 6) return;
92 pmu_write(0x2e + (ldo << 1), 0);
93}
94
95void pmu_set_wake_condition(unsigned char condition)
96{
97 pmu_write(0xd, condition);
98}
99
100void pmu_enter_standby(void)
101{
102 pmu_write(0xc, 1);
103}
104
105void pmu_read_rtc(unsigned char* buffer)
106{
107 pmu_read_multiple(0x59, 7, buffer);
108}
109
110void pmu_write_rtc(unsigned char* buffer)
111{
112 pmu_write_multiple(0x59, 7, buffer);
113}
114
115/*
116 * ADC
117 */
118#define ADC_FULL_SCALE 2000
119#define ADC_FULL_SCALE_VISA 2400
120#define ADC_SUBTR_OFFSET 2250
121
122static struct mutex pmu_adc_mutex;
123
124/* converts raw 8/10-bit value to millivolts */
125unsigned short pmu_adc_raw2mv(
126 const struct pmu_adc_channel *ch, unsigned short raw)
127{
128 int full_scale = ADC_FULL_SCALE;
129 int offset = 0;
130
131 switch (ch->adcc1 & PCF5063X_ADCC1_ADCMUX_MASK)
132 {
133 case PCF5063X_ADCC1_MUX_BATSNS_RES:
134 case PCF5063X_ADCC1_MUX_ADCIN2_RES:
135 full_scale *= ((ch->adcc1 & PCF5063X_ADCC3_RES_DIV_MASK) ==
136 PCF5063X_ADCC3_RES_DIV_TWO) ? 2 : 3;
137 break;
138 case PCF5063X_ADCC1_MUX_BATSNS_SUBTR:
139 case PCF5063X_ADCC1_MUX_ADCIN2_SUBTR:
140 offset = ADC_SUBTR_OFFSET;
141 break;
142 case PCF5063X_ADCC1_MUX_BATTEMP:
143 if (ch->adcc2 & PCF5063X_ADCC2_RATIO_BATTEMP)
144 full_scale = ADC_FULL_SCALE_VISA;
145 break;
146 case PCF5063X_ADCC1_MUX_ADCIN1:
147 if (ch->adcc2 & PCF5063X_ADCC2_RATIO_ADCIN1)
148 full_scale = ADC_FULL_SCALE_VISA;
149 break;
150 }
151
152 int nrb = ((ch->adcc1 & PCF5063X_ADCC1_RES_MASK) ==
153 PCF5063X_ADCC1_RES_8BIT) ? 8 : 10;
154 return (raw * full_scale / ((1<<nrb)-1)) + offset;
155}
156
157/* returns raw value, 8 or 10-bit resolution */
158unsigned short pmu_read_adc(const struct pmu_adc_channel *ch)
159{
160 mutex_lock(&pmu_adc_mutex);
161
162 pmu_write(PCF5063X_REG_ADCC3, ch->adcc3);
163 if (ch->bias_dly)
164 sleep(ch->bias_dly);
165 uint8_t buf[2] = { ch->adcc2, ch->adcc1 | PCF5063X_ADCC1_ADCSTART };
166 pmu_write_multiple(PCF5063X_REG_ADCC2, 2, buf);
167
168 int adcs3 = 0;
169 while (!(adcs3 & PCF5063X_ADCS3_ADCRDY))
170 {
171 yield();
172 adcs3 = pmu_read(PCF5063X_REG_ADCS3);
173 }
174
175 int raw = pmu_read(PCF5063X_REG_ADCS1);
176 if ((ch->adcc1 & PCF5063X_ADCC1_RES_MASK) == PCF5063X_ADCC1_RES_10BIT)
177 raw = (raw << 2) | (adcs3 & PCF5063X_ADCS3_ADCDAT1L_MASK);
178
179 mutex_unlock(&pmu_adc_mutex);
180 return raw;
181}
182
183/*
184 * eINT
185 */
186#define Q_EINT 0
187
188static char pmu_thread_stack[DEFAULT_STACK_SIZE/2];
189static struct event_queue pmu_queue;
190static unsigned char ints_msk[6];
191
192static void pmu_eint_isr(struct eint_handler*);
193
194static struct eint_handler pmu_eint =
195{
196 .gpio_n = GPIO_EINT_PMU,
197 .type = EIC_INTTYPE_LEVEL,
198 .level = EIC_INTLEVEL_LOW,
199 .isr = pmu_eint_isr,
200};
201
202static int pmu_input_holdswitch;
203
204int pmu_holdswitch_locked(void)
205{
206 return pmu_input_holdswitch;
207}
208
209#ifdef IPOD_ACCESSORY_PROTOCOL
210static int pmu_input_accessory;
211
212int pmu_accessory_present(void)
213{
214 return pmu_input_accessory;
215}
216#endif
217
218#if CONFIG_CHARGING
219static int pmu_input_firewire;
220
221int pmu_firewire_present(void)
222{
223 return pmu_input_firewire;
224}
225
226static void pmu_read_inputs_mbcs(void)
227{
228 pmu_input_firewire = !!(pmu_read(PCF5063X_REG_MBCS1)
229 & PCF5063X_MBCS1_ADAPTPRES);
230}
231#endif
232
233static void pmu_read_inputs_gpio(void)
234{
235 pmu_input_holdswitch = !(pmu_read(PCF50635_REG_GPIOSTAT)
236 & PCF50635_GPIOSTAT_GPIO2);
237}
238
239static void pmu_read_inputs_ooc(void)
240{
241 unsigned char oocstat = pmu_read(PCF5063X_REG_OOCSTAT);
242 if (oocstat & PCF5063X_OOCSTAT_EXTON2)
243 usb_insert_int();
244 else
245 usb_remove_int();
246#ifdef IPOD_ACCESSORY_PROTOCOL
247 pmu_input_accessory = !(oocstat & PCF5063X_OOCSTAT_EXTON3);
248#endif
249}
250
251static void pmu_eint_isr(struct eint_handler *h)
252{
253 eint_unregister(h);
254 queue_post(&pmu_queue, Q_EINT, 0);
255}
256
257static void NORETURN_ATTR pmu_thread(void)
258{
259 struct queue_event ev;
260 unsigned char ints[6];
261
262 while (true)
263 {
264 queue_wait_w_tmo(&pmu_queue, &ev, TIMEOUT_BLOCK);
265 switch (ev.id)
266 {
267 case Q_EINT:
268 /* read (clear) PMU interrupts, this will also
269 raise the PMU IRQ pin */
270 pmu_read_multiple(PCF5063X_REG_INT1, 2, ints);
271 ints[5] = pmu_read(PCF50635_REG_INT6);
272
273#if CONFIG_CHARGING
274 if (ints[0] & ~ints_msk[0]) pmu_read_inputs_mbcs();
275#endif
276 if (ints[1] & ~ints_msk[1]) pmu_read_inputs_ooc();
277 if (ints[5] & ~ints_msk[5]) pmu_read_inputs_gpio();
278
279 eint_register(&pmu_eint);
280 break;
281
282 case SYS_TIMEOUT:
283 break;
284 }
285 }
286}
287
288/* main init */
289void pmu_init(void)
290{
291 mutex_init(&pmu_adc_mutex);
292 queue_init(&pmu_queue, false);
293
294 create_thread(pmu_thread,
295 pmu_thread_stack, sizeof(pmu_thread_stack), 0,
296 "PMU" IF_PRIO(, PRIORITY_SYSTEM) IF_COP(, CPU));
297
298 /* configure PMU interrutps */
299 for (int i = 0; i < 6; i++)
300 ints_msk[i] = 0xff;
301
302#if CONFIG_CHARGING
303 ints_msk[0] &= ~PCF5063X_INT1_ADPINS & /* FireWire */
304 ~PCF5063X_INT1_ADPREM;
305#endif
306 ints_msk[1] &= ~PCF5063X_INT2_EXTON2R & /* USB */
307 ~PCF5063X_INT2_EXTON2F;
308#ifdef IPOD_ACCESSORY_PROTOCOL
309 ints_msk[1] &= ~PCF5063X_INT2_EXTON3R & /* Accessory */
310 ~PCF5063X_INT2_EXTON3F;
311#endif
312 ints_msk[5] &= ~PCF50635_INT6_GPIO2; /* Holdswitch */
313
314 pmu_write_multiple(PCF5063X_REG_INT1M, 5, ints_msk);
315 pmu_write(PCF50635_REG_INT6M, ints_msk[5]);
316
317 /* clear all */
318 unsigned char ints[5];
319 pmu_read_multiple(PCF5063X_REG_INT1, 5, ints);
320 pmu_read(PCF50635_REG_INT6);
321
322 /* get initial values */
323#if CONFIG_CHARGING
324 pmu_read_inputs_mbcs();
325#endif
326 pmu_read_inputs_ooc();
327 pmu_read_inputs_gpio();
328
329 eint_register(&pmu_eint);
330}
331
332/*
333 * preinit
334 */
335int pmu_rd_multiple(int address, int count, unsigned char* buffer)
336{
337 return i2c_rd(0, 0xe6, address, count, buffer);
338}
339
340int pmu_wr_multiple(int address, int count, unsigned char* buffer)
341{
342 return i2c_wr(0, 0xe6, address, count, buffer);
343}
344
345unsigned char pmu_rd(int address)
346{
347 unsigned char val;
348 pmu_rd_multiple(address, 1, &val);
349 return val;
350}
351
352int pmu_wr(int address, unsigned char val)
353{
354 return pmu_wr_multiple(address, 1, &val);
355}
356
357void pmu_preinit(void)
358{
359 static const char init_data[] =
360 {
361 /* reset OOC shutdown register */
362 PCF5063X_REG_OOCSHDWN, 0x0,
363
364 /* LDO_UNK1: 3000 mV, enabled */
365 PCF5063X_REG_LDO1OUT, 0x15,
366 PCF5063X_REG_LDO1ENA, 0x1,
367
368 /* LDO_UNK2: 3000 mV, enabled */
369 PCF5063X_REG_LDO2OUT, 0x15,
370 PCF5063X_REG_LDO2ENA, 0x1,
371
372 /* LDO_LCD: 3000 mV, enabled */
373 PCF5063X_REG_LDO3OUT, 0x15,
374 PCF5063X_REG_LDO3ENA, 0x1,
375
376 /* LDO_CODEC: 1800 mV, enabled */
377 PCF5063X_REG_LDO4OUT, 0x9,
378 PCF5063X_REG_LDO4ENA, 0x1,
379
380 /* LDO_UNK5: 3000 mV, disabled */
381 PCF5063X_REG_LDO5OUT, 0x15,
382 PCF5063X_REG_LDO5ENA, 0x0,
383
384 /* LDO_CWHEEL: 3000 mV, ON when GPIO2 High */
385 PCF5063X_REG_LDO6OUT, 0x15,
386 PCF5063X_REG_LDO6ENA, 0x4,
387
388 /* LDO_ACCY: 3300 mV, disabled */
389 PCF5063X_REG_HCLDOOUT, 0x18,
390 PCF5063X_REG_HCLDOENA, 0x0,
391
392 /* LDO_CWHEEL is ON in STANDBY state,
393 LDO_CWHEEL and MEMLDO are ON in UNKNOWN state (TBC) */
394 PCF5063X_REG_STBYCTL1, 0x0,
395 PCF5063X_REG_STBYCTL2, 0x8c,
396
397 /* GPIO1,2 = input, GPIO3 = output High (NoPower default) */
398 PCF5063X_REG_GPIOCTL, 0x3,
399 PCF5063X_REG_GPIO1CFG, 0x0,
400 PCF5063X_REG_GPIO2CFG, 0x0,
401 PCF5063X_REG_GPIO3CFG, 0x7,
402
403 /* DOWN2 converter (SDRAM): 1800 mV, enabled,
404 startup current limit = 15mA*0x10 (TBC) */
405 PCF5063X_REG_DOWN2OUT, 0x2f,
406 PCF5063X_REG_DOWN2ENA, 0x1,
407 PCF5063X_REG_DOWN2CTL, 0x0,
408 PCF5063X_REG_DOWN2MXC, 0x10,
409
410 /* MEMLDO: 1800 mV, enabled */
411 PCF5063X_REG_MEMLDOOUT, 0x9,
412 PCF5063X_REG_MEMLDOENA, 0x1,
413
414 /* AUTOLDO (HDD): 3400 mV, disabled,
415 limit = 1000 mA (40mA*0x19), limit always active */
416 PCF5063X_REG_AUTOOUT, 0x6f,
417#ifdef BOOTLOADER
418 PCF5063X_REG_AUTOENA, 0x0,
419#endif
420 PCF5063X_REG_AUTOCTL, 0x0,
421 PCF5063X_REG_AUTOMXC, 0x59,
422
423 /* Vsysok = 3100 mV */
424 PCF5063X_REG_SVMCTL, 0x8,
425
426 /* Reserved */
427 0x58, 0x0,
428
429 /* Mask all PMU interrupts */
430 PCF5063X_REG_INT1M, 0xff,
431 PCF5063X_REG_INT2M, 0xff,
432 PCF5063X_REG_INT3M, 0xff,
433 PCF5063X_REG_INT4M, 0xff,
434 PCF5063X_REG_INT5M, 0xff,
435 PCF50635_REG_INT6M, 0xff,
436
437 /* Wakeup on rising edge for EXTON1 and EXTON2,
438 wakeup on falling edge for EXTON3 and !ONKEY,
439 wakeup on RTC alarm, wakeup on adapter insert,
440 Vbat status has no effect in state machine */
441 PCF5063X_REG_OOCWAKE, 0xdf,
442 PCF5063X_REG_OOCTIM1, 0xaa,
443 PCF5063X_REG_OOCTIM2, 0x4a,
444 PCF5063X_REG_OOCMODE, 0x5,
445 PCF5063X_REG_OOCCTL, 0x27,
446
447 /* GPO selection = LED external NFET drive signal */
448 PCF5063X_REG_GPOCFG, 0x1,
449 /* LED converter OFF, overvoltage protection enabled,
450 OCP limit is 500 mA, led_dimstep = 16*0x6/32768 */
451#ifdef BOOTLOADER
452 PCF5063X_REG_LEDENA, 0x0,
453#endif
454 PCF5063X_REG_LEDCTL, 0x5,
455 PCF5063X_REG_LEDDIM, 0x6,
456
457 /* end marker */
458 0
459 };
460
461 const char* ptr;
462 for (ptr = init_data; *ptr != 0; ptr += 2)
463 pmu_wr(ptr[0], ptr[1]);
464
465 /* clear PMU interrupts */
466 unsigned char rd_buf[5];
467 pmu_rd_multiple(PCF5063X_REG_INT1, 5, rd_buf);
468 pmu_rd(PCF50635_REG_INT6);
469}