summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/s5l8700/yps3/button-yps3.c
blob: 23b71a4675ca3daa7f26a296ee1b6104a47fd228 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/***************************************************************************
 *             __________               __   ___.
 *   Open      \______   \ ____   ____ |  | _\_ |__   _______  ___
 *   Source     |       _//  _ \_/ ___\|  |/ /| __ \ /  _ \  \/  /
 *   Jukebox    |    |   (  <_> )  \___|    < | \_\ (  <_> > <  <
 *   Firmware   |____|_  /\____/ \___  >__|_ \|___  /\____/__/\_ \
 *                     \/            \/     \/    \/            \/
 * $Id$
 *
 * Copyright (C) 2009 Bertrik Sikken
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
 * KIND, either express or implied.
 *
 ****************************************************************************/

#include <stdbool.h>
#include "config.h"

#include "inttypes.h"
#include "s5l87xx.h"
#include "button.h"
#include "button-target.h"

/*  Button driver for the touch keys on the Samsung YP-S3

    The exact controller is not known, but it is likely from Melfas.
    
    The protocol is as follows:
    * the communication is done using three signals: DRDY, DCLK and DOUT
    * in the idle state these signals are all high.
    * when a key is touched or released, the key controller pulls down DRDY
      and outputs the first bit of a 20-bit word on its DOUT signal.
    * the CPU stores the bit, then acknowledges it by toggling the DCLK signal.
    * the key controller prepares the next bit, then toggles its DRDY output,
      unless all 20 bits have been transferred (in that case it stays high).
    * the 20-bit word contains separate bits for each button, some fixed bits
      and a bit indicating the number of keys pressed (modulo 2).
 */


void button_init_device(void)
{
    /* P0.5/P1.0 power switch input */
    PCON0 &= ~(3 << 10);    
    PCON1 &= ~0x0000000F;
    
    /* P1.3 headphones detect input */
    PCON1 &= ~0x0000F000;

    /* P1.5 DATA, P1.6 DRDY inputs (touch key controller) */
    PCON1 &= ~0x0FF00000; 
    
    /* P3.4 DCLK output (touch key controller) */
    PCON3 = (PCON3 & ~0x000F0000) | 0x00010000;
    PDAT3 |= (1 << 4);
    
    /* P4.3 hold switch input */
    PCON4 &= ~0x0000F000;
}

/* returns the raw 20-bit word from the touch key controller */
static int tkey_read(void)
{
    static int value = 0;
    int i;

    /* check activity */
    if (PDAT1 & (1 << 6)) {
        return value;
    }

    /* get key bits */
    value = 0;
    for (i = 0; i < 10; i++) {
        /* sample bit from falling edge of DRDY */
        while ((PDAT1 & (1 << 6)) != 0);
        value <<= 1;
        if (PDAT1 & (1 << 5)) {
            value |= 1;
        }

        /* acknowledge on DCLK */
        PDAT3 &= ~(1 << 4);

        /* sample bit from rising edge of DRDY */
        while ((PDAT1 & (1 << 6)) == 0);
        value <<= 1;
        if (PDAT1 & (1 << 5)) {
            value |= 1;
        }

        /* acknowledge on DCLK */
        PDAT3 |= (1 << 4);
    }
    return value;
}


int button_read_device(void)
{
    int buttons = 0;
    int tkey_data;

    /* hold switch */
    if (button_hold()) {
        return 0;
    }

    /* power button */
    if (PDAT1 & (1 << 0)) {
        buttons |= BUTTON_POWER;
    }
    
    /* touch keys */
    tkey_data = tkey_read();
    if (tkey_data & (1 << 9)) {
        buttons |= BUTTON_BACK;
    }
    if (tkey_data & (1 << 8)) {
        buttons |= BUTTON_UP;
    }
    if (tkey_data & (1 << 7)) {
        buttons |= BUTTON_MENU;
    }
    if (tkey_data & (1 << 6)) {
        buttons |= BUTTON_LEFT;
    }
    if (tkey_data & (1 << 5)) {
        buttons |= BUTTON_SELECT;
    }
    if (tkey_data & (1 << 4)) {
        buttons |= BUTTON_RIGHT;
    }
    if (tkey_data & (1 << 3)) {
        buttons |= BUTTON_DOWN;
    }
    
    return buttons;
}

bool button_hold(void)
{
    return (PDAT4 & (1 << 3));
}

bool headphones_inserted(void)
{
    return ((PDAT1 & (1 << 3)) == 0);
}