summaryrefslogtreecommitdiff
path: root/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
diff options
context:
space:
mode:
authorAidan MacDonald <amachronic@protonmail.com>2021-05-23 17:30:58 +0100
committerAidan MacDonald <amachronic@protonmail.com>2021-07-13 22:01:33 +0100
commit4c60bc9e681865fcfc149775a1ed7ccd2613d5bf (patch)
tree99f8d91af2c171cf3843f0c14d41a20d9dc29c4f /firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
parent3abb7c5dd5be2ec6744bfc0a80967b20f1b59e30 (diff)
downloadrockbox-4c60bc9e681865fcfc149775a1ed7ccd2613d5bf.tar.gz
rockbox-4c60bc9e681865fcfc149775a1ed7ccd2613d5bf.zip
New port: Shanling Q1 native
- Audio playback works - Touchscreen and buttons work - Bootloader works and is capable of dual boot - Plugins are working - Cabbiev2 theme has been ported - Stable for general usage Thanks to Marc Aarts for porting Cabbiev2 and plugin bitmaps. There's a few minor known issues: - Bootloader must be installed manually using 'usbboot' as there is no support in jztool yet. - Keymaps may be lacking, need further testing and feedback. - Some plugins may not be fully adapted to the screen size and could benefit from further tweaking. - LCD shows abnormal effects under some circumstances: for example, after viewing a mostly black screen an afterimage appears briefly when going back to a brightly-lit screen. Sudden power-off without proper shutdown of the backlight causes a "dissolving" effect. - CW2015 battery reporting driver is buggy, and disabled for now. Battery reporting is currently voltage-based using the AXP192. Change-Id: I635e83f02a880192c5a82cb0861ad3a61c137c3a
Diffstat (limited to 'firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c')
-rw-r--r--firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
new file mode 100644
index 0000000000..27c49a7bd7
--- /dev/null
+++ b/firmware/target/mips/ingenic_x1000/shanlingq1/button-shanlingq1.c
@@ -0,0 +1,195 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2021 Aidan MacDonald
11 * Copyright (C) 2021 Dana Conrad
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#include "button.h"
24#include "touchscreen.h"
25#include "ft6x06.h"
26#include "axp-pmu.h"
27#include "kernel.h"
28#include "backlight.h"
29#include "powermgmt.h"
30#include "gpio-x1000.h"
31#include "irq-x1000.h"
32#include "i2c-x1000.h"
33#include <stdbool.h>
34
35/* Volume wheel rotation */
36static volatile int wheel_pos = 0;
37
38/* Value of headphone detect register */
39static uint8_t hp_detect_reg = 0x00;
40
41/* Interval to poll the register */
42#define HPD_POLL_TIME (HZ/2)
43
44static int hp_detect_tmo_cb(struct timeout* tmo)
45{
46 i2c_descriptor* d = (i2c_descriptor*)tmo->data;
47 i2c_async_queue(AXP_PMU_BUS, TIMEOUT_NOBLOCK, I2C_Q_ADD, 0, d);
48 return HPD_POLL_TIME;
49}
50
51static void hp_detect_init(void)
52{
53 /* TODO: replace this copy paste cruft with an API in axp-pmu */
54 static struct timeout tmo;
55 static const uint8_t gpio_reg = AXP192_REG_GPIOSTATE1;
56 static i2c_descriptor desc = {
57 .slave_addr = AXP_PMU_ADDR,
58 .bus_cond = I2C_START | I2C_STOP,
59 .tran_mode = I2C_READ,
60 .buffer[0] = (void*)&gpio_reg,
61 .count[0] = 1,
62 .buffer[1] = &hp_detect_reg,
63 .count[1] = 1,
64 .callback = NULL,
65 .arg = 0,
66 .next = NULL,
67 };
68
69 /* Headphone detect is wired to AXP192 GPIO: set it to input state */
70 i2c_reg_write1(AXP_PMU_BUS, AXP_PMU_ADDR, AXP192_REG_GPIO1FUNCTION, 0x01);
71
72 /* Get an initial reading before startup */
73 int r = i2c_reg_read1(AXP_PMU_BUS, AXP_PMU_ADDR, gpio_reg);
74 if(r >= 0)
75 hp_detect_reg = r;
76
77 /* Poll the register every second */
78 timeout_register(&tmo, &hp_detect_tmo_cb, HPD_POLL_TIME, (intptr_t)&desc);
79}
80
81void button_init_device(void)
82{
83 /* Setup interrupts for the volume wheel */
84 gpio_set_function(GPIO_WHEEL1, GPIOF_IRQ_EDGE(0));
85 gpio_set_function(GPIO_WHEEL2, GPIOF_IRQ_EDGE(0));
86 gpio_flip_edge_irq(GPIO_WHEEL1);
87 gpio_flip_edge_irq(GPIO_WHEEL2);
88 gpio_enable_irq(GPIO_WHEEL1);
89 gpio_enable_irq(GPIO_WHEEL2);
90
91 /* Init touchscreen driver */
92 i2c_x1000_set_freq(FT6x06_BUS, I2C_FREQ_400K);
93 ft6x06_init();
94
95 /* Reset touch controller */
96 gpio_set_level(GPIO_FT6x06_POWER, 1);
97 gpio_set_level(GPIO_FT6x06_RESET, 0);
98 mdelay(5);
99 gpio_set_level(GPIO_FT6x06_RESET, 1);
100
101 /* Enable ft6x06 interrupt */
102 system_set_irq_handler(GPIO_TO_IRQ(GPIO_FT6x06_INTERRUPT), ft6x06_irq_handler);
103 gpio_set_function(GPIO_FT6x06_INTERRUPT, GPIOF_IRQ_EDGE(0));
104 gpio_enable_irq(GPIO_FT6x06_INTERRUPT);
105
106 /* Headphone detection */
107 hp_detect_init();
108}
109
110int button_read_device(int* data)
111{
112 int r = 0;
113
114 /* Read GPIO buttons, these are all active low */
115 uint32_t b = REG_GPIO_PIN(GPIO_B);
116 if((b & (1 << 21)) == 0) r |= BUTTON_PREV;
117 if((b & (1 << 22)) == 0) r |= BUTTON_NEXT;
118 if((b & (1 << 28)) == 0) r |= BUTTON_PLAY;
119 if((b & (1 << 31)) == 0) r |= BUTTON_POWER;
120
121 /* Check the wheel */
122 int wheel_btn = 0;
123 int whpos = wheel_pos;
124 if(whpos > 3)
125 wheel_btn = BUTTON_VOL_DOWN;
126 else if(whpos < -3)
127 wheel_btn = BUTTON_VOL_UP;
128
129 if(wheel_btn) {
130 wheel_pos = 0;
131
132 /* Post the event (rapid motion is more reliable this way) */
133 queue_post(&button_queue, wheel_btn, 0);
134 queue_post(&button_queue, wheel_btn|BUTTON_REL, 0);
135
136 /* Poke the backlight */
137 backlight_on();
138 reset_poweroff_timer();
139 }
140
141 /* Handle touchscreen
142 *
143 * TODO: Support 2-point multitouch (useful for 3x3 grid mode)
144 * TODO: Support simple gestures by converting them to fake buttons
145 */
146 int t = touchscreen_to_pixels(ft6x06_state.pos_x, ft6x06_state.pos_y, data);
147 if(ft6x06_state.event == FT6x06_EVT_PRESS ||
148 ft6x06_state.event == FT6x06_EVT_CONTACT) {
149 /* Only set the button bit if the screen is being touched. */
150 r |= t;
151 }
152
153 return r;
154}
155
156void touchscreen_enable_device(bool en)
157{
158 ft6x06_enable(en);
159 /* TODO: check if it's worth shutting off the power pin */
160}
161
162bool headphones_inserted(void)
163{
164 /* TODO: Also check if the headset button is detectable via an ADC.
165 * The AXP driver should probably get proper interrupt handling,
166 * that would be useful for more things than just GPIO polling. */
167 return hp_detect_reg & 0x20 ? true : false;
168}
169
170static void handle_wheel_irq(void)
171{
172 /* Wheel stuff adapted from button-erosqnative.c */
173 static const int delta[16] = { 0, -1, 1, 0,
174 1, 0, 0, -1,
175 -1, 0, 0, 1,
176 0, 1, -1, 0 };
177 static uint32_t state = 0;
178 state <<= 2;
179 state |= (REG_GPIO_PIN(GPIO_D) >> 2) & 3;
180 state &= 0xf;
181
182 wheel_pos += delta[state];
183}
184
185void GPIOD02(void)
186{
187 handle_wheel_irq();
188 gpio_flip_edge_irq(GPIO_WHEEL1);
189}
190
191void GPIOD03(void)
192{
193 handle_wheel_irq();
194 gpio_flip_edge_irq(GPIO_WHEEL2);
195}