blob: fd5af219878141d20bf0fbad9f4eacb68c8e8cef [file] [log] [blame]
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Linus Nielsen Feltzing
11 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000012 * 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.
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +000016 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "config.h"
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +000022#include "system.h"
Michael Sevakis784dd782006-10-25 23:24:07 +000023#include "kernel.h"
24#include "pcf50606.h"
Michael Sevakisc4a0d452006-10-28 23:10:45 +000025#include "button-target.h"
Michael Sevakis3bee89e2006-09-12 14:20:29 +000026#include "powermgmt.h"
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +000027
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +000028/* These voltages were determined by measuring the output of the PCF50606
29 on a running X5, and verified by disassembling the original firmware */
30static void set_voltages(void)
31{
Michael Sevakisb26e3962006-10-25 06:10:22 +000032 static const unsigned char buf[4] =
33 {
34 0xf4, /* IOREGC = 2.9V, ON in all states */
35 0xf0, /* D1REGC = 2.5V, ON in all states */
Jens Arnold39e1b592007-03-15 19:08:24 +000036#ifdef IAUDIO_M5
37 0xf8, /* D2REGC = 3.3V, ON in all states */
38#else
Michael Sevakisb26e3962006-10-25 06:10:22 +000039 0xf6, /* D2REGC = 3.1V, ON in all states */
Jens Arnold39e1b592007-03-15 19:08:24 +000040#endif
Michael Sevakisb26e3962006-10-25 06:10:22 +000041 0xf4, /* D3REGC = 2.9V, ON in all states */
42 };
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +000043
44 pcf50606_write_multiple(0x23, buf, 4);
45}
46
Michael Sevakisb26e3962006-10-25 06:10:22 +000047static void init_pmu_interrupts(void)
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +000048{
Michael Sevakis3bee89e2006-09-12 14:20:29 +000049 /* inital data is interrupt masks */
50 unsigned char data[3] =
51 {
52 ~0x04, /* unmask ONKEY1S */
53 ~0x00,
Michael Sevakis1d4a9c62006-10-27 05:31:28 +000054 ~0x06, /* unmask ACDREM, ACDINS */
Michael Sevakis3bee89e2006-09-12 14:20:29 +000055 };
Michael Sevakis32ba11f2006-09-09 07:49:25 +000056
Michael Sevakisc3b14752006-09-10 04:32:35 +000057 /* make sure GPI0 interrupt is off before unmasking anything */
Michael Sevakisb26e3962006-10-25 06:10:22 +000058 and_l(~0xf, &INTPRI5); /* INT32 - Priority 0 (Off) */
Michael Sevakisc3b14752006-09-10 04:32:35 +000059
Michael Sevakis3bee89e2006-09-12 14:20:29 +000060 /* unmask the PMU interrupts we want to service */
61 pcf50606_write_multiple(0x05, data, 3);
Michael Sevakis32ba11f2006-09-09 07:49:25 +000062 /* clear INT1-3 as these are left set after standby */
Michael Sevakis3bee89e2006-09-12 14:20:29 +000063 pcf50606_read_multiple(0x02, data, 3);
Michael Sevakis32ba11f2006-09-09 07:49:25 +000064
Michael Sevakisc3b14752006-09-10 04:32:35 +000065 /* Set to read pcf50606 INT but keep GPI0 off until init completes */
Michael Sevakis32ba11f2006-09-09 07:49:25 +000066 and_l(~0x00000001, &GPIO_ENABLE);
67 or_l(0x00000001, &GPIO_FUNCTION);
68 or_l(0x00000100, &GPIO_INT_EN); /* GPI0 H-L */
Michael Sevakisb26e3962006-10-25 06:10:22 +000069}
Michael Sevakisc3b14752006-09-10 04:32:35 +000070
Michael Sevakisb26e3962006-10-25 06:10:22 +000071static inline void enable_pmu_interrupts(void)
72{
Michael Sevakis1d4a9c62006-10-27 05:31:28 +000073 /* clear pending GPI0 interrupts first or it may miss the first
74 H-L transition */
75 or_l(0x00000100, &GPIO_INT_CLEAR);
Michael Sevakisb26e3962006-10-25 06:10:22 +000076 or_l(0x3, &INTPRI5); /* INT32 - Priority 3 */
77}
78
79void pcf50606_init(void)
80{
Michael Sevakis784dd782006-10-25 23:24:07 +000081 pcf50606_i2c_init();
Michael Sevakisb26e3962006-10-25 06:10:22 +000082
83 /* initialize pmu interrupts but don't service them yet */
84 init_pmu_interrupts();
Michael Sevakisc3b14752006-09-10 04:32:35 +000085 set_voltages();
Michael Sevakis32ba11f2006-09-09 07:49:25 +000086
Rani Hod3c810c42006-07-23 21:41:58 +000087 pcf50606_write(0x39, 0x00); /* GPOOD0 = green led OFF */
88 pcf50606_write(0x3a, 0x00); /* GPOOD1 = red led OFF */
89
Michael Sevakis1d4a9c62006-10-27 05:31:28 +000090 /* Accessory detect */
Jens Arnold6adbbc02006-11-26 18:24:23 +000091 pcf50606_write(0x33, 0x8c); /* ACDAPE=1, THRSHLD=2.20V */
Michael Sevakis1d4a9c62006-10-27 05:31:28 +000092
Michael Sevakisc3b14752006-09-10 04:32:35 +000093 /* allow GPI0 interrupts from PMU now */
Michael Sevakisb26e3962006-10-25 06:10:22 +000094 enable_pmu_interrupts();
Michael Sevakis3bee89e2006-09-12 14:20:29 +000095}
96
97void pcf50606_reset_timeout(void)
98{
Michael Sevakisaf395f42008-03-26 01:50:41 +000099 int level = disable_irq_save();
Michael Sevakis3bee89e2006-09-12 14:20:29 +0000100 pcf50606_write(0x08, pcf50606_read(0x08) | 0x02); /* OOCC1 - TOTRST=1 */
Michael Sevakisaf395f42008-03-26 01:50:41 +0000101 restore_irq(level);
Linus Nielsen Feltzing4feb0fc2006-02-23 15:24:45 +0000102}
Michael Sevakis32ba11f2006-09-09 07:49:25 +0000103
104/* Handles interrupts generated by the pcf50606 */
105void GPI0(void) __attribute__ ((interrupt_handler, section(".text")));
106void GPI0(void)
107{
Michael Sevakis1d4a9c62006-10-27 05:31:28 +0000108 unsigned char data[3]; /* 0 = INT1, 1 = INT2, 2 = INT3 */
109
110 /* Clear pending GPI0 interrupts */
111 or_l(0x00000100, &GPIO_INT_CLEAR);
Michael Sevakis32ba11f2006-09-09 07:49:25 +0000112
Michael Sevakis3bee89e2006-09-12 14:20:29 +0000113 /* clear pending interrupts from pcf50606 */
Michael Sevakis1d4a9c62006-10-27 05:31:28 +0000114 pcf50606_read_multiple(0x02, data, 3);
Michael Sevakis32ba11f2006-09-09 07:49:25 +0000115
Michael Sevakis1d4a9c62006-10-27 05:31:28 +0000116 if (data[0] & 0x04)
Michael Sevakis32ba11f2006-09-09 07:49:25 +0000117 {
Michael Sevakis3bee89e2006-09-12 14:20:29 +0000118 /* ONKEY1S */
119 if (GPIO_READ & 0x02000000)
120 sys_poweroff(); /* main ONKEY */
121 else
122 pcf50606_reset_timeout(); /* remote ONKEY */
Michael Sevakis32ba11f2006-09-09 07:49:25 +0000123 }
124
Michael Sevakis1d4a9c62006-10-27 05:31:28 +0000125 if (data[2] & 0x06)
126 {
127 /* ACDINS/ACDREM */
Michael Sevakis9e8fe0e2006-10-30 11:33:38 +0000128 /* Check if main buttons should be actually be scanned or not
129 - bias towards "yes" out of paranoia. */
Michael Sevakisc4a0d452006-10-28 23:10:45 +0000130 button_enable_scan((data[2] & 0x02) != 0 ||
131 (pcf50606_read(0x33) & 0x01) != 0);
Michael Sevakis1d4a9c62006-10-27 05:31:28 +0000132 }
Michael Sevakis32ba11f2006-09-09 07:49:25 +0000133}