git subrepo pull --force emummc
subrepo: subdir: "emummc" merged: "2fc47cbb8" upstream: origin: "https://github.com/lulle2007200/emuMMC.git" branch: "develop" commit: "2fc47cbb8" git-subrepo: version: "0.4.9" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "30db3b8"
This commit is contained in:
156
emummc/source/fatal/bdk/input/als.c
vendored
Normal file
156
emummc/source/fatal/bdk/input/als.c
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "als.h"
|
||||
#include <power/max7762x.h>
|
||||
#include <soc/clock.h>
|
||||
#include <soc/i2c.h>
|
||||
#include <soc/pinmux.h>
|
||||
#include <utils/util.h>
|
||||
|
||||
#define BH1730_DEFAULT_GAIN BH1730_GAIN_64X
|
||||
#define BH1730_DEFAULT_ICYCLE 38
|
||||
|
||||
#define BH1730_INTERNAL_CLOCK_NS 2800
|
||||
#define BH1730_ADC_CALC_DELAY_US 2000 /* BH1730_INTERNAL_CLOCK_MS * 714 */
|
||||
#define BH1730_ITIME_CYCLE_TO_US 2700 /* BH1730_INTERNAL_CLOCK_MS * 964 */
|
||||
|
||||
#define BH1730_DEFAULT_ITIME_MS 100
|
||||
|
||||
#define BH1730_LUX_MULTIPLIER 3600
|
||||
#define BH1730_LUX_MULTIPLIER_AULA 1410
|
||||
|
||||
#define BH1730_LUX_MAX 100000
|
||||
|
||||
typedef struct _opt_win_cal_t
|
||||
{
|
||||
u32 rc;
|
||||
u32 cv;
|
||||
u32 ci;
|
||||
} opt_win_cal_t;
|
||||
|
||||
// Nintendo Switch Icosa/Iowa Optical Window calibration.
|
||||
static const opt_win_cal_t opt_win_cal_default[] = {
|
||||
{ 500, 5002, 7502 },
|
||||
{ 754, 2250, 2000 },
|
||||
{ 1029, 1999, 1667 },
|
||||
{ 1373, 884, 583 },
|
||||
{ 1879, 309, 165 }
|
||||
};
|
||||
|
||||
// Nintendo Switch Aula Optical Window calibration.
|
||||
static const opt_win_cal_t opt_win_cal_aula[] = {
|
||||
{ 231, 9697, 30300 },
|
||||
{ 993, 3333, 2778 },
|
||||
{ 1478, 1621, 1053 },
|
||||
{ 7500, 81, 10 }
|
||||
};
|
||||
|
||||
static const u32 als_gain_idx_tbl[4] = { 1, 2, 64, 128 };
|
||||
|
||||
void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle)
|
||||
{
|
||||
if (gain > BH1730_GAIN_128X)
|
||||
gain = BH1730_GAIN_128X;
|
||||
|
||||
if (!cycle)
|
||||
cycle = 1;
|
||||
else if (cycle > 255)
|
||||
cycle = 255;
|
||||
|
||||
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_GAIN_REG), gain);
|
||||
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_TIMING_REG), (256 - cycle));
|
||||
|
||||
als_ctxt->gain = gain;
|
||||
als_ctxt->cycle = cycle;
|
||||
}
|
||||
|
||||
void get_als_lux(als_ctxt_t *als_ctxt)
|
||||
{
|
||||
u32 data[2];
|
||||
u32 vi_light;
|
||||
u32 ir_light;
|
||||
u64 lux = 0;
|
||||
u32 itime_us = BH1730_ITIME_CYCLE_TO_US * als_ctxt->cycle;
|
||||
|
||||
// Get visible and ir light raw data. Mode is continuous so waiting for new values doesn't matter.
|
||||
data[0] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0LOW_REG)) +
|
||||
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA0HIGH_REG)) << 8);
|
||||
data[1] = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1LOW_REG)) +
|
||||
(i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_DATA1HIGH_REG)) << 8);
|
||||
|
||||
vi_light = data[0];
|
||||
ir_light = data[1];
|
||||
|
||||
als_ctxt->vi_light = vi_light;
|
||||
als_ctxt->ir_light = ir_light;
|
||||
als_ctxt->over_limit = vi_light > 65534 || ir_light > 65534;
|
||||
|
||||
if (!vi_light)
|
||||
{
|
||||
als_ctxt->lux = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Set calibration parameters.
|
||||
u32 lux_multiplier = BH1730_LUX_MULTIPLIER;
|
||||
u32 opt_win_cal_count = ARRAY_SIZE(opt_win_cal_default);
|
||||
const opt_win_cal_t *opt_win_cal = opt_win_cal_default;
|
||||
|
||||
// Apply optical window calibration coefficients.
|
||||
for (u32 i = 0; i < opt_win_cal_count; i++)
|
||||
{
|
||||
if (1000 * ir_light / vi_light < opt_win_cal[i].rc)
|
||||
{
|
||||
lux = ((u64)opt_win_cal[i].cv * data[0]) - (opt_win_cal[i].ci * data[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lux *= BH1730_DEFAULT_ITIME_MS * lux_multiplier;
|
||||
lux /= als_gain_idx_tbl[als_ctxt->gain] * itime_us;
|
||||
lux /= 1000;
|
||||
|
||||
if (lux > BH1730_LUX_MAX)
|
||||
lux = BH1730_LUX_MAX;
|
||||
|
||||
als_ctxt->lux = lux;
|
||||
}
|
||||
|
||||
u8 als_power_on(als_ctxt_t *als_ctxt)
|
||||
{
|
||||
// Enable power to ALS IC.
|
||||
max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);
|
||||
max7762x_regulator_enable(REGULATOR_LDO6, true);
|
||||
|
||||
// Init I2C2.
|
||||
pinmux_config_i2c(I2C_2);
|
||||
clock_enable_i2c(I2C_2);
|
||||
i2c_init(I2C_2);
|
||||
|
||||
// Initialize ALS.
|
||||
u8 id = i2c_recv_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(0x12));
|
||||
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_SPEC(BH1730_SPECCMD_RESET), 0);
|
||||
|
||||
set_als_cfg(als_ctxt, BH1730_DEFAULT_GAIN, BH1730_DEFAULT_ICYCLE);
|
||||
|
||||
i2c_send_byte(I2C_2, BH1730_I2C_ADDR, BH1730_ADDR(BH1730_CONTROL_REG), BH1730_CTL_POWER_ON | BH1730_CTL_ADC_EN);
|
||||
|
||||
return id;
|
||||
}
|
||||
65
emummc/source/fatal/bdk/input/als.h
vendored
Normal file
65
emummc/source/fatal/bdk/input/als.h
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ALS_H_
|
||||
#define __ALS_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
#define BH1730_I2C_ADDR 0x29
|
||||
|
||||
#define BH1730_CMD_MAGIC 0x80
|
||||
#define BH1730_CMD_SETADDR 0x00
|
||||
#define BH1730_CMD_SPECCMD 0x60
|
||||
#define BH1730_SPECCMD_RESET 0x4
|
||||
|
||||
#define BH1730_CONTROL_REG 0x00
|
||||
#define BH1730_CTL_ADC_VALID 0x10
|
||||
#define BH1730_CTL_ONE_TIME 0x08
|
||||
#define BH1730_CTL_DAT0_ONLY 0x04
|
||||
#define BH1730_CTL_ADC_EN 0x02
|
||||
#define BH1730_CTL_POWER_ON 0x01
|
||||
#define BH1730_TIMING_REG 0x01
|
||||
#define BH1730_GAIN_REG 0x07
|
||||
#define BH1730_GAIN_1X 0x00
|
||||
#define BH1730_GAIN_2X 0x01
|
||||
#define BH1730_GAIN_64X 0x02
|
||||
#define BH1730_GAIN_128X 0x03
|
||||
#define BH1730_DATA0LOW_REG 0x14
|
||||
#define BH1730_DATA0HIGH_REG 0x15
|
||||
#define BH1730_DATA1LOW_REG 0x16
|
||||
#define BH1730_DATA1HIGH_REG 0x17
|
||||
|
||||
#define BH1730_ADDR(reg) (BH1730_CMD_MAGIC | BH1730_CMD_SETADDR | (reg))
|
||||
#define BH1730_SPEC(cmd) (BH1730_CMD_MAGIC | BH1730_CMD_SPECCMD | (cmd))
|
||||
|
||||
typedef struct _als_ctxt_t
|
||||
{
|
||||
u32 lux;
|
||||
bool over_limit;
|
||||
u32 vi_light;
|
||||
u32 ir_light;
|
||||
u8 gain;
|
||||
u8 cycle;
|
||||
} als_ctxt_t;
|
||||
|
||||
void set_als_cfg(als_ctxt_t *als_ctxt, u8 gain, u8 cycle);
|
||||
void get_als_lux(als_ctxt_t *als_ctxt);
|
||||
u8 als_power_on(als_ctxt_t *als_ctxt);
|
||||
|
||||
#endif /* __ALS_H_ */
|
||||
1274
emummc/source/fatal/bdk/input/joycon.c
vendored
Normal file
1274
emummc/source/fatal/bdk/input/joycon.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
108
emummc/source/fatal/bdk/input/joycon.h
vendored
Normal file
108
emummc/source/fatal/bdk/input/joycon.h
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Ambient light sensor driver for Nintendo Switch's Rohm BH1730
|
||||
*
|
||||
* Copyright (c) 2018 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __JOYCON_H_
|
||||
#define __JOYCON_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
#define JC_BTNS_DIRECTION_PAD 0xF0000
|
||||
#define JC_BTNS_PREV_NEXT 0x800080
|
||||
#define JC_BTNS_ENTER 0x400008
|
||||
#define JC_BTNS_ESC 0x4
|
||||
|
||||
#define JC_BTNS_ALL (JC_BTNS_PREV_NEXT | JC_BTNS_ENTER | JC_BTNS_DIRECTION_PAD | JC_BTNS_ESC)
|
||||
|
||||
typedef struct _jc_bt_conn_t
|
||||
{
|
||||
u8 type;
|
||||
u8 mac[6];
|
||||
u8 host_mac[6];
|
||||
u8 ltk[16];
|
||||
} jc_bt_conn_t;
|
||||
|
||||
typedef struct _jc_gamepad_rpt_t
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
// Joy-Con (R).
|
||||
/*00*/ u32 y:1;
|
||||
/*01*/ u32 x:1;
|
||||
/*02*/ u32 b:1;
|
||||
/*03*/ u32 a:1;
|
||||
/*04*/ u32 sr_r:1;
|
||||
/*05*/ u32 sl_r:1;
|
||||
/*06*/ u32 r:1;
|
||||
/*07*/ u32 zr:1;
|
||||
|
||||
// Shared
|
||||
/*08*/ u32 minus:1;
|
||||
/*09*/ u32 plus:1;
|
||||
/*10*/ u32 r3:1;
|
||||
/*11*/ u32 l3:1;
|
||||
/*12*/ u32 home:1;
|
||||
/*13*/ u32 cap:1;
|
||||
/*14*/ u32 pad:1;
|
||||
/*15*/ u32 wired:1;
|
||||
|
||||
// Joy-Con (L).
|
||||
/*16*/ u32 down:1;
|
||||
/*17*/ u32 up:1;
|
||||
/*18*/ u32 right:1;
|
||||
/*19*/ u32 left:1;
|
||||
/*20*/ u32 sr_l:1;
|
||||
/*21*/ u32 sl_l:1;
|
||||
/*22*/ u32 l:1;
|
||||
/*23*/ u32 zl:1;
|
||||
};
|
||||
u32 buttons;
|
||||
};
|
||||
|
||||
u16 lstick_x;
|
||||
u16 lstick_y;
|
||||
u16 rstick_x;
|
||||
u16 rstick_y;
|
||||
bool center_stick_l;
|
||||
bool center_stick_r;
|
||||
bool conn_l;
|
||||
bool conn_r;
|
||||
bool sio_mode;
|
||||
u8 batt_info_l; // Also Sio Connected status.
|
||||
u8 batt_info_r; // Also Sio IRQ.
|
||||
jc_bt_conn_t bt_conn_l;
|
||||
jc_bt_conn_t bt_conn_r;
|
||||
} jc_gamepad_rpt_t;
|
||||
|
||||
typedef struct _jc_calib_t
|
||||
{
|
||||
u16 x_max:12;
|
||||
u16 y_max:12;
|
||||
u16 x_center:12;
|
||||
u16 y_center:12;
|
||||
u16 x_min:12;
|
||||
u16 y_min:12;
|
||||
} __attribute__((packed)) jc_calib_t;
|
||||
|
||||
void jc_init_hw();
|
||||
void jc_deinit();
|
||||
jc_gamepad_rpt_t *joycon_poll();
|
||||
jc_gamepad_rpt_t *jc_get_bt_pairing_info(bool *is_l_hos, bool *is_r_hos);
|
||||
|
||||
#endif
|
||||
461
emummc/source/fatal/bdk/input/touch.c
vendored
Normal file
461
emummc/source/fatal/bdk/input/touch.c
vendored
Normal file
@@ -0,0 +1,461 @@
|
||||
/*
|
||||
* Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller
|
||||
*
|
||||
* Copyright (c) 2018 langerhans
|
||||
* Copyright (c) 2018-2023 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <soc/clock.h>
|
||||
#include <soc/i2c.h>
|
||||
#include <soc/pinmux.h>
|
||||
#include <power/max7762x.h>
|
||||
#include <soc/gpio.h>
|
||||
#include <soc/timer.h>
|
||||
#include <soc/t210.h>
|
||||
#include <utils/btn.h>
|
||||
#include "touch.h"
|
||||
|
||||
|
||||
#include <gfx_utils.h>
|
||||
#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||
|
||||
static touch_panel_info_t _panels[] =
|
||||
{
|
||||
{ 0, 1, 1, 1, "NISSHA NFT-K12D" },// 0.
|
||||
{ 1, 0, 1, 1, "GiS GGM6 B2X" },// 1.
|
||||
{ 2, 0, 0, 0, "NISSHA NBF-K9A" },// 3.
|
||||
{ 3, 1, 0, 0, "GiS 5.5\"" },// 4.
|
||||
{ 4, 0, 0, 1, "Samsung TSP" },// 5?
|
||||
{ -1, 1, 0, 1, "GiS VA 6.2\"" } // 2.
|
||||
};
|
||||
|
||||
static int touch_command(u8 cmd, u8 *buf, u8 size)
|
||||
{
|
||||
int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd, buf, size);
|
||||
if (!res)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int touch_read_reg(u8 *cmd, u32 csize, u8 *buf, u32 size)
|
||||
{
|
||||
int res = i2c_send_buf_small(I2C_3, STMFTS_I2C_ADDR, cmd[0], &cmd[1], csize - 1);
|
||||
if (res)
|
||||
res = i2c_recv_buf(buf, size, I2C_3, STMFTS_I2C_ADDR);
|
||||
if (!res)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int touch_wait_event(u8 event, u8 status, u32 timeout, u8 *buf)
|
||||
{
|
||||
u32 timer = get_tmr_ms() + timeout;
|
||||
while (true)
|
||||
{
|
||||
u8 tmp[8] = {0};
|
||||
i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT);
|
||||
if (tmp[1] == event && tmp[2] == status)
|
||||
{
|
||||
if (buf)
|
||||
memcpy(buf, &tmp[3], 5);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (get_tmr_ms() > timer)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#define X_REAL_MAX 1264
|
||||
#define Y_REAL_MAX 704
|
||||
#define EDGE_OFFSET 15
|
||||
|
||||
static void _touch_compensate_limits(touch_event *event, bool touching)
|
||||
{
|
||||
event->x = MAX(event->x, EDGE_OFFSET);
|
||||
event->x = MIN(event->x, X_REAL_MAX);
|
||||
event->x -= EDGE_OFFSET;
|
||||
u32 x_adj = (1280 * 1000) / (X_REAL_MAX - EDGE_OFFSET);
|
||||
event->x = ((u32)event->x * x_adj) / 1000;
|
||||
|
||||
if (touching)
|
||||
{
|
||||
event->y = MAX(event->y, EDGE_OFFSET);
|
||||
event->y = MIN(event->y, Y_REAL_MAX);
|
||||
event->y -= EDGE_OFFSET;
|
||||
u32 y_adj = (720 * 1000) / (Y_REAL_MAX - EDGE_OFFSET);
|
||||
event->y = ((u32)event->y * y_adj) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
static void _touch_process_contact_event(touch_event *event, bool touching)
|
||||
{
|
||||
event->x = (event->raw[2] << 4) | ((event->raw[4] & STMFTS_MASK_Y_LSB) >> 4);
|
||||
|
||||
// Normally, GUI elements have bigger horizontal estate.
|
||||
// Avoid parsing y axis when finger is removed to minimize touch noise.
|
||||
if (touching)
|
||||
{
|
||||
event->y = (event->raw[3] << 4) | (event->raw[4] & STMFTS_MASK_X_MSB);
|
||||
|
||||
event->z = event->raw[5] | (event->raw[6] << 8);
|
||||
event->z = event->z << 6;
|
||||
|
||||
u16 tmp = 0x40;
|
||||
if ((event->raw[7] & 0x3F) != 1 && (event->raw[7] & 0x3F) != 0x3F)
|
||||
tmp = event->raw[7] & 0x3F;
|
||||
event->z /= tmp + 0x40;
|
||||
|
||||
event->fingers = ((event->raw[1] & STMFTS_MASK_TOUCH_ID) >> 4) + 1;
|
||||
}
|
||||
else
|
||||
event->fingers = 0;
|
||||
|
||||
_touch_compensate_limits(event, touching);
|
||||
}
|
||||
|
||||
static void _touch_parse_event(touch_event *event)
|
||||
{
|
||||
event->type = event->raw[1] & STMFTS_MASK_EVENT_ID;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case STMFTS_EV_MULTI_TOUCH_ENTER:
|
||||
case STMFTS_EV_MULTI_TOUCH_MOTION:
|
||||
_touch_process_contact_event(event, true);
|
||||
if (event->z < 255) // Reject palm rest.
|
||||
event->touch = true;
|
||||
else
|
||||
{
|
||||
event->touch = false;
|
||||
event->type = STMFTS_EV_MULTI_TOUCH_LEAVE;
|
||||
}
|
||||
break;
|
||||
case STMFTS_EV_MULTI_TOUCH_LEAVE:
|
||||
event->touch = false;
|
||||
_touch_process_contact_event(event, false);
|
||||
break;
|
||||
case STMFTS_EV_NO_EVENT:
|
||||
if (event->touch)
|
||||
event->type = STMFTS_EV_MULTI_TOUCH_MOTION;
|
||||
break;
|
||||
default:
|
||||
if (event->touch && event->raw[0] == STMFTS_EV_MULTI_TOUCH_MOTION)
|
||||
event->type = STMFTS_EV_MULTI_TOUCH_MOTION;
|
||||
else
|
||||
event->type = STMFTS_EV_MULTI_TOUCH_LEAVE;
|
||||
}
|
||||
|
||||
// gfx_con_setpos(0, 300);
|
||||
// DPRINTF("x = %d \ny = %d \nz = %d \n", event->x, event->y, event->z);
|
||||
// DPRINTF("0 = %02X\n1 = %02X\n2 = %02X\n3 = %02X\n", event->raw[0], event->raw[1], event->raw[2], event->raw[3]);
|
||||
// DPRINTF("4 = %02X\n5 = %02X\n6 = %02X\n7 = %02X\n", event->raw[4], event->raw[5], event->raw[6], event->raw[7]);
|
||||
}
|
||||
|
||||
void touch_poll(touch_event *event)
|
||||
{
|
||||
i2c_recv_buf_small(event->raw, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_LATEST_EVENT);
|
||||
|
||||
_touch_parse_event(event);
|
||||
}
|
||||
|
||||
touch_event touch_poll_wait()
|
||||
{
|
||||
touch_event event;
|
||||
do
|
||||
{
|
||||
touch_poll(&event);
|
||||
} while (event.type != STMFTS_EV_MULTI_TOUCH_LEAVE);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
touch_info touch_get_info()
|
||||
{
|
||||
touch_info info;
|
||||
u8 buf[8];
|
||||
memset(&buf, 0, 8);
|
||||
i2c_recv_buf_small(buf, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_INFO);
|
||||
|
||||
info.chip_id = buf[0] << 8 | buf[1];
|
||||
info.fw_ver = buf[2] << 8 | buf[3];
|
||||
info.config_id = buf[4];
|
||||
info.config_ver = buf[5];
|
||||
|
||||
//DPRINTF("ID: %04X, FW Ver: %d.%02d\nCfg ID: %02X, Cfg Ver: %d\n",
|
||||
// info.chip_id, info.fw_ver >> 8, info.fw_ver & 0xFF, info.config_id, info.config_ver);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
touch_panel_info_t *touch_get_panel_vendor()
|
||||
{
|
||||
u8 buf[5] = {0};
|
||||
u8 cmd = STMFTS_VENDOR_GPIO_STATE;
|
||||
static touch_panel_info_t panel_info = { -2, 0, 0, 0, ""};
|
||||
|
||||
if (touch_command(STMFTS_VENDOR, &cmd, 1))
|
||||
return NULL;
|
||||
|
||||
if (touch_wait_event(STMFTS_EV_VENDOR, STMFTS_VENDOR_GPIO_STATE, 2000, buf))
|
||||
return NULL;
|
||||
|
||||
for (u32 i = 0; i < ARRAY_SIZE(_panels); i++)
|
||||
{
|
||||
touch_panel_info_t *panel = &_panels[i];
|
||||
if (buf[0] == panel->gpio0 && buf[1] == panel->gpio1 && buf[2] == panel->gpio2)
|
||||
return panel;
|
||||
}
|
||||
|
||||
// Touch panel not found, return current gpios.
|
||||
panel_info.gpio0 = buf[0];
|
||||
panel_info.gpio1 = buf[1];
|
||||
panel_info.gpio2 = buf[2];
|
||||
|
||||
return &panel_info;
|
||||
}
|
||||
|
||||
int touch_get_fw_info(touch_fw_info_t *fw)
|
||||
{
|
||||
u8 buf[8] = {0};
|
||||
|
||||
memset(fw, 0, sizeof(touch_fw_info_t));
|
||||
|
||||
// Get fw address info.
|
||||
u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0x60 };
|
||||
int res = touch_read_reg(cmd, 3, buf, 3);
|
||||
if (!res)
|
||||
{
|
||||
// Get fw info.
|
||||
cmd[1] = buf[2]; cmd[2] = buf[1];
|
||||
res = touch_read_reg(cmd, 3, buf, 8);
|
||||
if (!res)
|
||||
{
|
||||
fw->fw_id = (buf[1] << 24) | (buf[2] << 16) | (buf[3] << 8) | buf[4];
|
||||
fw->ftb_ver = (buf[6] << 8) | buf[5];
|
||||
}
|
||||
|
||||
cmd[2]++;
|
||||
res = touch_read_reg(cmd, 3, buf, 8);
|
||||
if (!res)
|
||||
fw->fw_rev = (buf[7] << 8) | buf[6];
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int touch_sys_reset()
|
||||
{
|
||||
u8 cmd[3] = { 0, 0x28, 0x80 }; // System reset cmd.
|
||||
for (u8 retries = 0; retries < 3; retries++)
|
||||
{
|
||||
if (touch_command(STMFTS_WRITE_REG, cmd, 3))
|
||||
{
|
||||
msleep(10);
|
||||
continue;
|
||||
}
|
||||
msleep(10);
|
||||
if (touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL))
|
||||
continue;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int touch_panel_ito_test(u8 *err)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
// Reset touchscreen module.
|
||||
if (touch_sys_reset())
|
||||
return res;
|
||||
|
||||
// Do ITO Production test.
|
||||
u8 cmd[2] = { 1, 0 };
|
||||
if (touch_command(STMFTS_ITO_CHECK, cmd, 2))
|
||||
return res;
|
||||
|
||||
u32 timer = get_tmr_ms() + 2000;
|
||||
while (true)
|
||||
{
|
||||
u8 tmp[8] = {0};
|
||||
i2c_recv_buf_small(tmp, 8, I2C_3, STMFTS_I2C_ADDR, STMFTS_READ_ONE_EVENT);
|
||||
if (tmp[1] == 0xF && tmp[2] == 0x5)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
err[0] = tmp[3];
|
||||
err[1] = tmp[4];
|
||||
}
|
||||
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (get_tmr_ms() > timer)
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset touchscreen module.
|
||||
touch_sys_reset();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int touch_get_fb_info(u8 *buf)
|
||||
{
|
||||
u8 tmp[5];
|
||||
|
||||
u8 cmd[3] = { STMFTS_RW_FRAMEBUFFER_REG, 0, 0 };
|
||||
int res = 0;
|
||||
|
||||
|
||||
for (u32 i = 0; i < 0x10000; i += 4)
|
||||
{
|
||||
if (!res)
|
||||
{
|
||||
cmd[1] = (i >> 8) & 0xFF;
|
||||
cmd[2] = i & 0xFF;
|
||||
memset(tmp, 0xCC, 5);
|
||||
res = touch_read_reg(cmd, 3, tmp, 5);
|
||||
memcpy(&buf[i], tmp + 1, 4);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int touch_sense_enable()
|
||||
{
|
||||
// Switch sense mode and enable multi-touch sensing.
|
||||
u8 cmd = STMFTS_FINGER_MODE;
|
||||
if (touch_command(STMFTS_SWITCH_SENSE_MODE, &cmd, 1))
|
||||
return 0;
|
||||
|
||||
if (touch_command(STMFTS_MS_MT_SENSE_ON, NULL, 0))
|
||||
return 0;
|
||||
|
||||
if (touch_command(STMFTS_CLEAR_EVENT_STACK, NULL, 0))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int touch_execute_autotune()
|
||||
{
|
||||
// Reset touchscreen module.
|
||||
if (touch_sys_reset())
|
||||
return 0;
|
||||
|
||||
// Trim low power oscillator.
|
||||
if (touch_command(STMFTS_LP_TIMER_CALIB, NULL, 0))
|
||||
return 0;
|
||||
msleep(200);
|
||||
|
||||
// Apply Mutual Sense Compensation tuning.
|
||||
if (touch_command(STMFTS_MS_CX_TUNING, NULL, 0))
|
||||
return 0;
|
||||
if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_MS_CX_TUNING_DONE, 2000, NULL))
|
||||
return 0;
|
||||
|
||||
// Apply Self Sense Compensation tuning.
|
||||
if (touch_command(STMFTS_SS_CX_TUNING, NULL, 0))
|
||||
return 0;
|
||||
if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_SS_CX_TUNING_DONE, 2000, NULL))
|
||||
return 0;
|
||||
|
||||
// Save Compensation data to EEPROM.
|
||||
if (touch_command(STMFTS_SAVE_CX_TUNING, NULL, 0))
|
||||
return 0;
|
||||
if (touch_wait_event(STMFTS_EV_STATUS, STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE, 2000, NULL))
|
||||
return 0;
|
||||
|
||||
return touch_sense_enable();
|
||||
}
|
||||
|
||||
static int touch_init()
|
||||
{
|
||||
// Initialize touchscreen module.
|
||||
if (touch_sys_reset())
|
||||
return 0;
|
||||
|
||||
return touch_sense_enable();
|
||||
}
|
||||
|
||||
int touch_power_on()
|
||||
{
|
||||
// Configure Touscreen and GCAsic shared GPIO.
|
||||
PINMUX_AUX(PINMUX_AUX_CAM_I2C_SDA) = PINMUX_LPDR | PINMUX_INPUT_ENABLE | PINMUX_TRISTATE | PINMUX_PULL_UP | 2;
|
||||
PINMUX_AUX(PINMUX_AUX_CAM_I2C_SCL) = PINMUX_IO_HV | PINMUX_LPDR | PINMUX_TRISTATE | PINMUX_PULL_DOWN | 2; // Unused.
|
||||
gpio_config(GPIO_PORT_S, GPIO_PIN_3, GPIO_MODE_GPIO); // GC detect.
|
||||
|
||||
// Configure touchscreen Touch Reset pin.
|
||||
PINMUX_AUX(PINMUX_AUX_DAP4_SCLK) = PINMUX_PULL_DOWN | 1;
|
||||
gpio_direction_output(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW);
|
||||
usleep(20);
|
||||
|
||||
// Enable LDO6 for touchscreen AVDD and DVDD supply.
|
||||
max7762x_regulator_set_voltage(REGULATOR_LDO6, 2900000);
|
||||
max7762x_regulator_enable(REGULATOR_LDO6, true);
|
||||
|
||||
// Initialize I2C3.
|
||||
pinmux_config_i2c(I2C_3);
|
||||
clock_enable_i2c(I2C_3);
|
||||
i2c_init(I2C_3);
|
||||
usleep(1000);
|
||||
|
||||
// Set Touch Reset pin.
|
||||
gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_HIGH);
|
||||
usleep(10000);
|
||||
|
||||
// Wait for the touchscreen module to get ready.
|
||||
touch_wait_event(STMFTS_EV_CONTROLLER_READY, 0, 20, NULL);
|
||||
|
||||
// Check for forced boot time calibration.
|
||||
if (btn_read_vol() == (BTN_VOL_UP | BTN_VOL_DOWN))
|
||||
{
|
||||
u8 err[2];
|
||||
if (touch_panel_ito_test(err))
|
||||
if (!err[0] && !err[1])
|
||||
return touch_execute_autotune();
|
||||
}
|
||||
|
||||
// Initialize touchscreen.
|
||||
u32 retries = 3;
|
||||
while (retries)
|
||||
{
|
||||
if (touch_init())
|
||||
return 1;
|
||||
retries--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void touch_power_off()
|
||||
{
|
||||
// Disable touchscreen power.
|
||||
gpio_write(GPIO_PORT_J, GPIO_PIN_7, GPIO_LOW);
|
||||
|
||||
// Disables LDO6 for touchscreen VDD, AVDD supply
|
||||
max7762x_regulator_enable(REGULATOR_LDO6, false);
|
||||
|
||||
clock_disable_i2c(I2C_3);
|
||||
}
|
||||
176
emummc/source/fatal/bdk/input/touch.h
vendored
Normal file
176
emummc/source/fatal/bdk/input/touch.h
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Touch driver for Nintendo Switch's STM FingerTip S (4CD60D) touch controller
|
||||
*
|
||||
* Copyright (c) 2018 langerhans
|
||||
* Copyright (c) 2018-2020 CTCaer
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __TOUCH_H_
|
||||
#define __TOUCH_H_
|
||||
|
||||
#include <utils/types.h>
|
||||
|
||||
#define STMFTS_I2C_ADDR 0x49
|
||||
|
||||
/* I2C commands */
|
||||
#define STMFTS_READ_INFO 0x80
|
||||
#define STMFTS_READ_STATUS 0x84
|
||||
#define STMFTS_READ_ONE_EVENT 0x85
|
||||
#define STMFTS_READ_ALL_EVENT 0x86
|
||||
#define STMFTS_LATEST_EVENT 0x87
|
||||
#define STMFTS_SLEEP_IN 0x90
|
||||
#define STMFTS_SLEEP_OUT 0x91
|
||||
#define STMFTS_MS_MT_SENSE_OFF 0x92
|
||||
#define STMFTS_MS_MT_SENSE_ON 0x93
|
||||
#define STMFTS_SS_HOVER_SENSE_OFF 0x94
|
||||
#define STMFTS_SS_HOVER_SENSE_ON 0x95
|
||||
#define STMFTS_LP_TIMER_CALIB 0x97
|
||||
#define STMFTS_MS_KEY_SENSE_OFF 0x9A
|
||||
#define STMFTS_MS_KEY_SENSE_ON 0x9B
|
||||
#define STMFTS_SYSTEM_RESET 0xA0
|
||||
#define STMFTS_CLEAR_EVENT_STACK 0xA1
|
||||
#define STMFTS_FULL_FORCE_CALIBRATION 0xA2
|
||||
#define STMFTS_MS_CX_TUNING 0xA3
|
||||
#define STMFTS_SS_CX_TUNING 0xA4
|
||||
#define STMFTS_ITO_CHECK 0xA7
|
||||
#define STMFTS_RELEASEINFO 0xAA
|
||||
#define STMFTS_WRITE_REG 0xB6
|
||||
#define STMFTS_SWITCH_SENSE_MODE 0xC3
|
||||
#define STMFTS_NOISE_WRITE 0xC7
|
||||
#define STMFTS_NOISE_READ 0xC8
|
||||
#define STMFTS_RW_FRAMEBUFFER_REG 0xD0
|
||||
#define STMFTS_SAVE_CX_TUNING 0xFC
|
||||
|
||||
#define STMFTS_DETECTION_CONFIG 0xB0
|
||||
#define STMFTS_REQU_COMP_DATA 0xB8
|
||||
#define STMFTS_VENDOR 0xCF
|
||||
#define STMFTS_FLASH_UNLOCK 0xF7
|
||||
#define STMFTS_FLASH_WRITE_64K 0xF8
|
||||
#define STMFTS_FLASH_STATUS 0xF9
|
||||
#define STMFTS_FLASH_OP 0xFA
|
||||
#define STMFTS_UNK5 0x62
|
||||
|
||||
/* cmd parameters */
|
||||
#define STMFTS_VENDOR_GPIO_STATE 0x01
|
||||
#define STMFTS_VENDOR_SENSE_MODE 0x02
|
||||
#define STMFTS_STYLUS_MODE 0x00
|
||||
#define STMFTS_FINGER_MODE 0x01
|
||||
#define STMFTS_HOVER_MODE 0x02
|
||||
|
||||
/* events */
|
||||
#define STMFTS_EV_NO_EVENT 0x00
|
||||
#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02
|
||||
#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03
|
||||
#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04
|
||||
#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05
|
||||
#define STMFTS_EV_HOVER_ENTER 0x07
|
||||
#define STMFTS_EV_HOVER_LEAVE 0x08
|
||||
#define STMFTS_EV_HOVER_MOTION 0x09
|
||||
#define STMFTS_EV_KEY_STATUS 0x0e
|
||||
#define STMFTS_EV_ERROR 0x0f
|
||||
#define STMFTS_EV_NOISE_READ 0x17
|
||||
#define STMFTS_EV_NOISE_WRITE 0x18
|
||||
#define STMFTS_EV_VENDOR 0x20
|
||||
|
||||
#define STMFTS_EV_CONTROLLER_READY 0x10
|
||||
#define STMFTS_EV_STATUS 0x16
|
||||
#define STMFTS_EV_DEBUG 0xDB
|
||||
|
||||
#define STMFTS_EV_STATUS_MS_CX_TUNING_DONE 1
|
||||
#define STMFTS_EV_STATUS_SS_CX_TUNING_DONE 2
|
||||
#define STMFTS_EV_STATUS_WRITE_CX_TUNE_DONE 4
|
||||
|
||||
/* multi touch related event masks */
|
||||
#define STMFTS_MASK_EVENT_ID 0x0F
|
||||
#define STMFTS_MASK_TOUCH_ID 0xF0
|
||||
#define STMFTS_MASK_LEFT_EVENT 0x0F
|
||||
#define STMFTS_MASK_X_MSB 0x0F
|
||||
#define STMFTS_MASK_Y_LSB 0xF0
|
||||
|
||||
/* key related event masks */
|
||||
#define STMFTS_MASK_KEY_NO_TOUCH 0x00
|
||||
#define STMFTS_MASK_KEY_MENU 0x01
|
||||
#define STMFTS_MASK_KEY_BACK 0x02
|
||||
|
||||
#define STMFTS_EVENT_SIZE 8
|
||||
#define STMFTS_STACK_DEPTH 32
|
||||
#define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH)
|
||||
#define STMFTS_MAX_FINGERS 10
|
||||
|
||||
typedef enum _touch_ito_error {
|
||||
ITO_NO_ERROR = 0,
|
||||
ITO_FORCE_OPEN,
|
||||
ITO_SENSE_OPEN,
|
||||
ITO_FORCE_SHRT_GND,
|
||||
ITO_SENSE_SHRT_GND,
|
||||
ITO_FORCE_SHRT_VCM,
|
||||
ITO_SENSE_SHRT_VCM,
|
||||
ITO_FORCE_SHRT_FORCE,
|
||||
ITO_SENSE_SHRT_SENSE,
|
||||
ITO_F2E_SENSE,
|
||||
ITO_FPC_FORCE_OPEN,
|
||||
ITO_FPC_SENSE_OPEN,
|
||||
ITO_KEY_FORCE_OPEN,
|
||||
ITO_KEY_SENSE_OPEN,
|
||||
ITO_RESERVED0,
|
||||
ITO_RESERVED1,
|
||||
ITO_RESERVED2,
|
||||
ITO_MAX_ERR_REACHED = 0xFF
|
||||
} touch_ito_error;
|
||||
|
||||
typedef struct _touch_event {
|
||||
u8 raw[8];
|
||||
u16 type; // Event type.
|
||||
u16 x; // Horizontal coordinates.
|
||||
u16 y; // Vertical coordinates.
|
||||
u32 z;
|
||||
u8 fingers;
|
||||
bool touch;
|
||||
} touch_event;
|
||||
|
||||
typedef struct _touch_panel_info_t
|
||||
{
|
||||
u8 idx;
|
||||
u8 gpio0;
|
||||
u8 gpio1;
|
||||
u8 gpio2;
|
||||
char *vendor;
|
||||
} touch_panel_info_t;
|
||||
|
||||
typedef struct _touch_info {
|
||||
u16 chip_id;
|
||||
u16 fw_ver;
|
||||
u16 config_id;
|
||||
u16 config_ver;
|
||||
} touch_info;
|
||||
|
||||
typedef struct _touch_fw_info_t {
|
||||
u32 fw_id;
|
||||
u16 ftb_ver;
|
||||
u16 fw_rev;
|
||||
} touch_fw_info_t;
|
||||
|
||||
void touch_poll(touch_event *event);
|
||||
touch_event touch_poll_wait();
|
||||
touch_panel_info_t *touch_get_panel_vendor();
|
||||
int touch_get_fw_info(touch_fw_info_t *fw);
|
||||
touch_info touch_get_info();
|
||||
int touch_panel_ito_test(u8 *err);
|
||||
int touch_execute_autotune();
|
||||
int touch_sense_enable();
|
||||
int touch_power_on();
|
||||
void touch_power_off();
|
||||
|
||||
#endif /* __TOUCH_H_ */
|
||||
Reference in New Issue
Block a user