mirror of
https://gitee.com/Vancouver2017/luban-lite-t3e-pro.git
synced 2025-12-14 18:38:55 +00:00
686 lines
18 KiB
C
686 lines
18 KiB
C
/*
|
|
* Copyright (c) 2022-2023, ArtInChip Technology Co., Ltd
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Authors: matteo <duanmt@artinchip.com>
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "aic_core.h"
|
|
#include "aic_hal_clk.h"
|
|
|
|
#include "hal_rtp.h"
|
|
|
|
/* Register definition for RTP */
|
|
#define RTP_MCR (RTP_BASE + 0x000)
|
|
#define RTP_INTR (RTP_BASE + 0x004)
|
|
#define RTP_PDEB (RTP_BASE + 0x008)
|
|
#define RTP_PCTL (RTP_BASE + 0x00C)
|
|
#define RTP_CHCFG (RTP_BASE + 0x010)
|
|
#define RTP_MMSC (RTP_BASE + 0x014)
|
|
#define RTP_FIL (RTP_BASE + 0x018)
|
|
#define RTP_AMSC (RTP_BASE + 0x01C)
|
|
#define RTP_FCR (RTP_BASE + 0x020)
|
|
#define RTP_DATA (RTP_BASE + 0x024)
|
|
#define RTP_DLY (RTP_BASE + 0x028)
|
|
#define RTP_VERSION (RTP_BASE + 0xFFC)
|
|
|
|
#define RTP_MCR_PRES_DET_BYPASS BIT(16)
|
|
#define RTP_MCR_RISE_STS BIT(12)
|
|
#define RTP_MCR_PRES_DET_EN BIT(8)
|
|
#define RTR_MCR_MODE_SHIFT 4
|
|
#define RTR_MCR_MODE_MASK GENMASK(7, 4)
|
|
#define RTP_MCR_EN BIT(0)
|
|
|
|
#define RTP_INTR_SCI_FLG BIT(21)
|
|
#define RTP_INTR_DOUR_FLG BIT(20)
|
|
#define RTP_INTR_FIFO_FLG BIT(19)
|
|
#define RTP_INTR_DRDY_FLG BIT(18)
|
|
#define RTP_INTR_RISE_DET_FLG BIT(17)
|
|
#define RTP_INTR_PRES_DET_FLG BIT(16)
|
|
#define RTP_INTR_SCI_IE BIT(5)
|
|
#define RTP_INTR_DOUR_INTEN BIT(4)
|
|
#define RTP_INTR_FIFO_ERR_IE BIT(3)
|
|
#define RTP_INTR_DAT_RDY_IE BIT(2)
|
|
#define RTP_INTR_RISE_DET_IE BIT(1)
|
|
#define RTP_INTR_PRES_DET_IE BIT(0)
|
|
|
|
#define RTP_PCTL_PRES_DET_BYPASS BIT(16)
|
|
|
|
#define RTP_MMSC_VREF_MINUS_SEL_SHIFT 22
|
|
#define RTP_MMSC_VREF_PLUS_SEL_SHIFT 20
|
|
#define RTP_MMSC_XY_DRV_X_PLUS BIT(19)
|
|
#define RTP_MMSC_XY_DRV_Y_PLUS BIT(18)
|
|
#define RTP_MMSC_XY_DRV_X_MINUS BIT(17)
|
|
#define RTP_MMSC_XY_DRV_Y_MINUS BIT(16)
|
|
#define RTP_MMSC_XY_DRV_SHIFT 16
|
|
#define RTP_MMSC_SMP_CNT_PER_TRIG_SHIFT 8
|
|
#define RTP_MMSC_SMP_CH_SEL_SHIFT 4
|
|
#define RTP_MMSC_SMP_TRIG BIT(0)
|
|
|
|
#define RTP_FIL_Z_REL_RANGE_SHIFT 28
|
|
#define RTP_FIL_X_ABS_RANGE_SHIFT 24
|
|
#define RTP_FIL_XY_REL_RANGE_SHIFT 20
|
|
#define RTP_FIL_XY_ABS_RANGE_SHIFT 16
|
|
|
|
#define RTP_AMSC_PERIOD_SAMPLE_INT_SHIFT 12
|
|
#define RTP_AMSC_PERIOD_SAMPLE_EN BIT(1)
|
|
#define RTP_AMSC_SINGLE_SAMPLE_EN BIT(0)
|
|
|
|
#define RTP_FCR_DAT_CNT_SHIFT 24
|
|
#define RTP_FCR_DAT_CNT_MASK GENMASK(28, 24)
|
|
#define RTP_FCR_UF_FLAG BIT(18)
|
|
#define RTP_FCR_OF_FLAG BIT(17)
|
|
#define RTP_FCR_DAT_RDY_THD_SHIFT 8
|
|
#define RTP_FCR_DAT_RDY_THD_MASK GENMASK(12, 8)
|
|
#define RTP_FCR_UF_IE BIT(2)
|
|
#define RTP_FCR_OF_IE BIT(1)
|
|
#define RTP_FCR_FLUSH BIT(0)
|
|
|
|
#define RTP_DATA_CH_NUM_SHIFT 12
|
|
#define RTP_DATA_CH_NUM_MASK GENMASK(13, 12)
|
|
#define RTP_DATA_DATA_MASK GENMASK(11, 0)
|
|
|
|
enum aic_rtp_vref_minus_sel {
|
|
RTP_VREF_MINUS_2_GND = 0,
|
|
RTP_VREF_MINUS_2_X_MINUS,
|
|
RTP_VREF_MINUS_2_Y_MINUS
|
|
};
|
|
|
|
enum aic_rtp_vref_plus_sel {
|
|
RTP_VREF_PLUS_2_VCC = 0,
|
|
RTP_VREF_PLUS_2_X_PLUS,
|
|
RTP_VREF_PLUS_2_Y_PLUS
|
|
};
|
|
|
|
enum aic_rtp_relative_range {
|
|
RTP_REL_RANGE_DISABLE = 0,
|
|
RTP_REL_RANGE_MAX_1_8,
|
|
RTP_REL_RANGE_MAX_1_16,
|
|
RTP_REL_RANGE_MAX_1_32,
|
|
RTP_REL_RANGE_MAX_1_64,
|
|
RTP_REL_RANGE_MAX_1_128,
|
|
RTP_REL_RANGE_MAX_1_256,
|
|
RTP_REL_RANGE_MAX_1_512
|
|
};
|
|
|
|
enum aic_rtp_absolute_range {
|
|
RTP_ABS_RANGE_DISABLE = 0,
|
|
RTP_ABS_RANGE_MAX_2_9,
|
|
RTP_ABS_RANGE_MAX_2_8,
|
|
RTP_ABS_RANGE_MAX_2_7,
|
|
RTP_ABS_RANGE_MAX_2_6,
|
|
RTP_ABS_RANGE_MAX_2_5,
|
|
RTP_ABS_RANGE_MAX_2_4,
|
|
RTP_ABS_RANGE_MAX_2_3
|
|
};
|
|
|
|
/* n_m - Pick out n samples from m continuous samples,
|
|
* and drop (m-n)/2 max and (m-n)/2 min samples.
|
|
*/
|
|
enum aic_rtp_filter_type {
|
|
RTP_FILTER_NONE = 0,
|
|
RTP_FILTER_2_4,
|
|
RTP_FILTER_4_6,
|
|
RTP_FILTER_4_8
|
|
};
|
|
|
|
enum aic_rtp_ch {
|
|
RTP_CH_Y_MINUS = 0,
|
|
RTP_CH_X_MINUS,
|
|
RTP_CH_Y_PLUS,
|
|
RTP_CH_X_PLUS,
|
|
RTP_CH_Z_A,
|
|
RTP_CH_Z_B,
|
|
RTP_CH_Z_C,
|
|
RTP_CH_Z_D,
|
|
|
|
RTP_CH_MAX
|
|
};
|
|
|
|
enum aic_rtp_manual_mode_status {
|
|
RTP_MMS_X_MINUS = 0,
|
|
RTP_MMS_Y_MINUS,
|
|
RTP_MMS_Z_A,
|
|
RTP_MMS_Z_B,
|
|
RTP_MMS_DOWN,
|
|
RTP_MMS_IDLE,
|
|
RTP_MMS_FINISH
|
|
};
|
|
|
|
void hal_rtp_status_show(struct aic_rtp_dev *rtp)
|
|
{
|
|
int mcr, version;
|
|
|
|
mcr = readl(RTP_MCR);
|
|
version = readl(RTP_VERSION);
|
|
|
|
printf("In RTP controller V%d.%02d:\n"
|
|
"Mode hw %d/ sw %d, RTP enale %d, Press detect enable %d\n"
|
|
"Pressure enable %d, max %d, x-plate %d, y-plate %d\n"
|
|
"Sample period: %d ms, Fuzz: %d\n",
|
|
version >> 8, version & 0xff,
|
|
(u32)((mcr & RTR_MCR_MODE_MASK) >> RTR_MCR_MODE_SHIFT),
|
|
rtp->mode, (u32)(mcr & RTP_MCR_EN),
|
|
(mcr & RTP_MCR_PRES_DET_EN) ? 1 : 0,
|
|
rtp->pressure_det, rtp->max_press,
|
|
rtp->x_plate, rtp->y_plate,
|
|
rtp->smp_period, rtp->fuzz);
|
|
}
|
|
|
|
static struct aic_rtp_dev *g_rtp_dev_of_user = NULL;
|
|
|
|
static u32 rtp_ms2itv(u32 pclk_rate, u32 ms)
|
|
{
|
|
u32 tmp = pclk_rate / 1000;
|
|
|
|
tmp = (tmp * ms) >> 12;
|
|
return tmp;
|
|
}
|
|
|
|
static s32 rtp_is_rise(void)
|
|
{
|
|
return readl(RTP_MCR) & RTP_MCR_RISE_STS ? 1 : 0;
|
|
}
|
|
|
|
static void rtp_reg_enable(int offset, int bit, int enable)
|
|
{
|
|
int tmp;
|
|
|
|
tmp = readl((long)offset);
|
|
tmp &= ~bit;
|
|
if (enable)
|
|
tmp |= bit;
|
|
|
|
writel(tmp, (long)offset);
|
|
}
|
|
|
|
static void rtp_fifo_flush(void)
|
|
{
|
|
u32 sta = readl(RTP_FCR);
|
|
|
|
if (sta & RTP_FCR_UF_FLAG)
|
|
pr_err("FIFO is Underflow!%#x\n", sta);
|
|
if (sta & RTP_FCR_OF_FLAG)
|
|
pr_err("FIFO is Overflow!%#x\n", sta);
|
|
|
|
writel(sta | RTP_FCR_FLUSH, RTP_FCR);
|
|
}
|
|
|
|
void hal_rtp_enable(struct aic_rtp_dev *rtp, int en)
|
|
{
|
|
if (!en) {
|
|
rtp_fifo_flush();
|
|
pr_info("clean fifo\n");
|
|
}
|
|
|
|
rtp_reg_enable(RTP_MCR,
|
|
rtp->mode << RTR_MCR_MODE_SHIFT | RTP_MCR_PRES_DET_EN | RTP_MCR_EN,
|
|
en);
|
|
|
|
#if defined(CONFIG_ARTINCHIP_ADCIM_DM)
|
|
writel(0, RTP_PDEB);
|
|
#else
|
|
writel(0x230f230f, RTP_PDEB);
|
|
#endif
|
|
|
|
if (rtp->mode != RTP_MODE_MANUAL) {
|
|
writel(0x1f000021, RTP_DLY);
|
|
rtp_reg_enable(RTP_MCR, RTP_MCR_PRES_DET_BYPASS, en);
|
|
}
|
|
|
|
rtp->pclk_rate = hal_clk_get_freq(hal_clk_get_parent(CLK_RTP));
|
|
g_rtp_dev_of_user = rtp;
|
|
}
|
|
|
|
void hal_rtp_int_enable(struct aic_rtp_dev *rtp, int en)
|
|
{
|
|
u32 val = RTP_INTR_FIFO_ERR_IE | RTP_INTR_DAT_RDY_IE
|
|
| RTP_INTR_RISE_DET_IE | RTP_INTR_SCI_IE;
|
|
|
|
if (rtp->mode == RTP_MODE_MANUAL)
|
|
val |= RTP_INTR_PRES_DET_IE;
|
|
|
|
rtp_reg_enable(RTP_INTR, val, en);
|
|
}
|
|
|
|
static void rtp_fifo_init(enum aic_rtp_mode mode, u32 smp_period)
|
|
{
|
|
u32 thd = 0;
|
|
|
|
switch (mode) {
|
|
case RTP_MODE_AUTO1:
|
|
if (smp_period)
|
|
thd = 8;
|
|
else
|
|
thd = 2;
|
|
break;
|
|
case RTP_MODE_AUTO2:
|
|
if (smp_period)
|
|
thd = 12;
|
|
else
|
|
thd = 4;
|
|
break;
|
|
case RTP_MODE_AUTO3:
|
|
if (smp_period)
|
|
thd = 12;
|
|
else
|
|
thd = 6;
|
|
break;
|
|
case RTP_MODE_AUTO4:
|
|
default:
|
|
thd = 8;
|
|
break;
|
|
}
|
|
thd <<= RTP_FCR_DAT_RDY_THD_SHIFT;
|
|
|
|
writel(thd | RTP_FCR_UF_IE | RTP_FCR_OF_IE, RTP_FCR);
|
|
}
|
|
|
|
static u32 rtp_press_calc(struct aic_rtp_dev *rtp)
|
|
{
|
|
struct aic_rtp_dat *dat = &rtp->latest;
|
|
u32 pressure = rtp->x_plate * dat->x_minus / AIC_RTP_VAL_RANGE;
|
|
|
|
if (rtp->y_plate) {
|
|
pressure = pressure * (AIC_RTP_VAL_RANGE - dat->z_a) / dat->z_a;
|
|
pressure -= rtp->y_plate * (AIC_RTP_VAL_RANGE - dat->y_minus)
|
|
/ AIC_RTP_VAL_RANGE;
|
|
} else {
|
|
pressure = pressure * (dat->z_b - dat->z_a) / dat->z_a;
|
|
}
|
|
pr_debug("Current pressure: %d\n", pressure);
|
|
|
|
if (pressure > rtp->max_press) {
|
|
pr_debug("Invalid pressure %d\n", pressure);
|
|
pressure = AIC_RTP_INVALID_VAL;
|
|
}
|
|
#if defined(CONFIG_ARTINCHIP_ADCIM_DM)
|
|
return (dat->z_a + dat->z_b) / 2;
|
|
#else
|
|
return pressure;
|
|
#endif
|
|
}
|
|
|
|
static void rtp_report_abs(struct aic_rtp_dev *rtp, u16 down)
|
|
{
|
|
struct aic_rtp_dat *dat = &rtp->latest;
|
|
struct aic_rtp_event e = {0};
|
|
|
|
if (dat->x_minus == AIC_RTP_INVALID_VAL
|
|
|| dat->y_minus == AIC_RTP_INVALID_VAL)
|
|
return;
|
|
|
|
if (rtp->pressure_det) {
|
|
int pressure = rtp_press_calc(rtp);
|
|
|
|
if (pressure == AIC_RTP_INVALID_VAL)
|
|
return;
|
|
e.pressure = pressure;
|
|
}
|
|
|
|
e.x = dat->x_minus;
|
|
e.y = dat->y_minus;
|
|
e.down = down;
|
|
e.timestamp = dat->timestamp;
|
|
|
|
if (rtp->callback)
|
|
rtp->callback();
|
|
hal_rtp_ebuf_write(&rtp->ebuf, &e);
|
|
}
|
|
|
|
static void rtp_smp_period(u32 period)
|
|
{
|
|
u32 val = 0;
|
|
|
|
if (period) {
|
|
val = period << RTP_AMSC_PERIOD_SAMPLE_INT_SHIFT
|
|
| RTP_AMSC_PERIOD_SAMPLE_EN;
|
|
} else {
|
|
val = RTP_AMSC_SINGLE_SAMPLE_EN;
|
|
writel(0, RTP_AMSC);
|
|
}
|
|
writel(val, RTP_AMSC);
|
|
}
|
|
|
|
void hal_rtp_auto_mode(struct aic_rtp_dev *rtp)
|
|
{
|
|
writel(RTP_FILTER_4_8, RTP_FIL);
|
|
rtp_smp_period(rtp_ms2itv(rtp->pclk_rate, rtp->smp_period));
|
|
rtp_fifo_init(rtp->mode, rtp->smp_period);
|
|
}
|
|
|
|
/* Data format: XN, YN */
|
|
static void rtp_report_abs_auto1(struct aic_rtp_dev *rtp, u16 *ori, u32 cnt)
|
|
{
|
|
u32 i = 0;
|
|
struct aic_rtp_dat *latest = &rtp->latest;
|
|
|
|
for (i = 0; i < cnt; ) {
|
|
latest->x_minus = ori[i];
|
|
latest->y_minus = ori[i + 1];
|
|
rtp_report_abs(rtp, 1);
|
|
|
|
i += 2;
|
|
pr_debug("X %d, Y %d\n", latest->x_minus, latest->y_minus);
|
|
}
|
|
}
|
|
|
|
/* Data format: XN, YN, ZA, ZB */
|
|
static void rtp_report_abs_auto2(struct aic_rtp_dev *rtp, u16 *ori, u32 cnt)
|
|
{
|
|
u32 i = 0;
|
|
struct aic_rtp_dat *latest = &rtp->latest;
|
|
|
|
for (i = 0; i < cnt; ) {
|
|
latest->x_minus = ori[i];
|
|
latest->y_minus = ori[i + 1];
|
|
latest->z_a = ori[i + 2];
|
|
latest->z_b = ori[i + 3];
|
|
rtp_report_abs(rtp, 1);
|
|
|
|
i += 4;
|
|
pr_debug("X %d, Y %d, ZA %d ZB %d\n", latest->x_minus, latest->y_minus,
|
|
latest->z_a, latest->z_b);
|
|
}
|
|
}
|
|
|
|
static s32 rtp_distance_is_far(struct aic_rtp_dat *latest)
|
|
{
|
|
s32 ret = 0;
|
|
|
|
if (latest->x_minus != latest->x_plus) {
|
|
if (latest->x_plus > latest->x_minus)
|
|
ret = latest->x_plus > latest->x_minus +
|
|
AIC_RTP_SCATTER_THD;
|
|
else
|
|
ret = latest->x_minus > latest->x_plus +
|
|
AIC_RTP_SCATTER_THD;
|
|
}
|
|
if (ret)
|
|
return 1;
|
|
|
|
if (latest->y_minus != latest->y_plus) {
|
|
if (latest->y_plus > latest->y_minus)
|
|
ret = latest->y_plus > latest->y_minus +
|
|
AIC_RTP_SCATTER_THD;
|
|
else
|
|
ret = latest->y_minus > latest->y_plus +
|
|
AIC_RTP_SCATTER_THD;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/* Data format: XN, XP, YN, YP, ZA, ZB */
|
|
static void rtp_report_abs_auto3(struct aic_rtp_dev *rtp, u16 *ori, u32 cnt)
|
|
{
|
|
u32 i = 0;
|
|
struct aic_rtp_dat *latest = &rtp->latest;
|
|
|
|
for (i = 0; i < cnt; ) {
|
|
latest->x_minus = ori[i];
|
|
latest->x_plus = ori[i + 1];
|
|
latest->y_minus = ori[i + 2];
|
|
latest->y_plus = ori[i + 3];
|
|
latest->z_a = ori[i + 4];
|
|
latest->z_b = ori[i + 5];
|
|
pr_debug("X %u-%u, Y %u-%u, ZA %u, ZB %u\n",
|
|
latest->x_minus, latest->x_plus,
|
|
latest->y_minus, latest->y_plus,
|
|
latest->z_a, latest->z_b);
|
|
|
|
if (!rtp_distance_is_far(latest)) {
|
|
latest->x_minus += latest->x_plus;
|
|
latest->x_minus >>= 1;
|
|
latest->y_minus += latest->y_plus;
|
|
latest->y_minus >>= 1;
|
|
rtp_report_abs(rtp, 1);
|
|
} else {
|
|
pr_debug("Distance is so far\n");
|
|
}
|
|
|
|
i += 6;
|
|
if (i + 6 > cnt)
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Data format: XN, XP, YN, YP, ZA, ZB, ZC, ZD */
|
|
static void rtp_report_abs_auto4(struct aic_rtp_dev *rtp, u16 *ori, u32 cnt)
|
|
{
|
|
u32 i = 0;
|
|
struct aic_rtp_dat *latest = &rtp->latest;
|
|
|
|
for (i = 0; i < cnt; ) {
|
|
latest->x_minus = ori[i];
|
|
latest->x_plus = ori[i + 1];
|
|
latest->y_minus = ori[i + 2];
|
|
latest->y_plus = ori[i + 3];
|
|
latest->z_a = ori[i + 4];
|
|
latest->z_b = ori[i + 5];
|
|
latest->z_c = ori[i + 6];
|
|
latest->z_d = ori[i + 7];
|
|
|
|
pr_debug("X %u-%u, Y %u-%u, ZA %u-%u, ZB %u-%u\n",
|
|
latest->x_minus, latest->x_plus,
|
|
latest->y_minus, latest->y_plus,
|
|
latest->z_a, latest->z_c,
|
|
latest->z_b, latest->z_d);
|
|
|
|
#if defined(CONFIG_ARTINCHIP_ADCIM_DM)
|
|
rtp_report_abs(rtp, 1);
|
|
latest->x_minus = latest->x_plus;
|
|
latest->y_minus = latest->y_plus;
|
|
latest->z_a = latest->z_c;
|
|
latest->z_b = latest->z_d;
|
|
rtp_report_abs(rtp, 1);
|
|
#else
|
|
if (!rtp_distance_is_far(latest)) {
|
|
latest->x_minus += latest->x_plus;
|
|
latest->x_minus >>= 1;
|
|
latest->y_minus += latest->y_plus;
|
|
latest->y_minus >>= 1;
|
|
rtp_report_abs(rtp, 1);
|
|
} else {
|
|
pr_debug("Distance is so far\n");
|
|
}
|
|
#endif
|
|
|
|
i += 8;
|
|
if (i + 8 > cnt)
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void aic_rtp_read_fifo(struct aic_rtp_dev *rtp, u32 cnt)
|
|
{
|
|
int i;
|
|
u32 tmp;
|
|
u16 data[AIC_RTP_FIFO_DEPTH] = {0};
|
|
|
|
tmp = (readl(RTP_FCR) & RTP_FCR_DAT_CNT_MASK) >> RTP_FCR_DAT_CNT_SHIFT;
|
|
if (tmp != cnt) {
|
|
if (rtp->mode == RTP_MODE_MANUAL)
|
|
pr_err("FIFO did changed %d/%d\n", tmp, cnt);
|
|
else
|
|
cnt = tmp;
|
|
}
|
|
|
|
for (i = 0; i < cnt; i++) {
|
|
if (!(readl(RTP_FCR) & RTP_FCR_DAT_CNT_MASK)) {
|
|
pr_err("FIFO is empty %d/%d\n", i, cnt);
|
|
return;
|
|
}
|
|
tmp = readl(RTP_DATA);
|
|
data[i] = tmp & RTP_DATA_DATA_MASK;
|
|
// pr_debug("%d/%d - Read chan %d, data %d \n", i, 12 + (tmp >> 12), tmp >> 12, data[i]);
|
|
}
|
|
|
|
rtp->latest.timestamp = aic_get_time_ms();
|
|
|
|
tmp = readl(RTP_FCR) & RTP_FCR_DAT_CNT_MASK;
|
|
if (tmp) {
|
|
pr_err("FIFO is not empty! %d\n", tmp >> RTP_FCR_DAT_CNT_SHIFT);
|
|
rtp_fifo_flush();
|
|
}
|
|
tmp = readl(RTP_INTR);
|
|
if (tmp & (RTP_INTR_DOUR_FLG | RTP_INTR_SCI_FLG))
|
|
pr_debug("After read FIFO, INTR %#x, FCR %#x\n", tmp, readl(RTP_FCR));
|
|
|
|
switch (rtp->mode) {
|
|
case RTP_MODE_AUTO1:
|
|
rtp_report_abs_auto1(rtp, data, cnt);
|
|
break;
|
|
case RTP_MODE_AUTO2:
|
|
rtp_report_abs_auto2(rtp, data, cnt);
|
|
break;
|
|
case RTP_MODE_AUTO3:
|
|
rtp_report_abs_auto3(rtp, data, cnt);
|
|
break;
|
|
case RTP_MODE_AUTO4:
|
|
rtp_report_abs_auto4(rtp, data, cnt);
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
s32 hal_rtp_register_callback(rtp_callback_t callback)
|
|
{
|
|
struct aic_rtp_dev *rtp = g_rtp_dev_of_user;
|
|
if (callback == NULL) {
|
|
hal_log_err("Invalid callback function!\n");
|
|
return -1;
|
|
}
|
|
rtp->callback = callback;
|
|
return 0;
|
|
}
|
|
|
|
irqreturn_t hal_rtp_isr(int irq, void *arg)
|
|
{
|
|
// TODO: struct aic_rtp_dev *rtp = (struct aic_rtp_dev *)arg;
|
|
struct aic_rtp_dev *rtp = g_rtp_dev_of_user;
|
|
u32 intr, fcr;
|
|
|
|
intr = readl(RTP_INTR);
|
|
fcr = readl(RTP_FCR);
|
|
writel(fcr, RTP_FCR);
|
|
writel(intr, RTP_INTR);
|
|
|
|
pr_debug("INTS %#x, FCR %#x, Pressed %d\n", intr, fcr, !rtp_is_rise());
|
|
if ((intr & RTP_INTR_PRES_DET_FLG) && (intr & RTP_INTR_RISE_DET_FLG)) {
|
|
pr_debug("Press&rise happened at the same time!\n");
|
|
if (rtp_is_rise())
|
|
intr &= ~RTP_INTR_PRES_DET_FLG;
|
|
else
|
|
intr &= ~RTP_INTR_RISE_DET_FLG;
|
|
}
|
|
|
|
if (intr & RTP_INTR_SCI_FLG) {
|
|
pr_err("SCI error, flush the FIFO ...\n");
|
|
goto irq_clean_fifo;
|
|
}
|
|
|
|
if (intr & RTP_INTR_DOUR_FLG) {
|
|
pr_err("DOUR error, flush the FIFO ...\n");
|
|
goto irq_clean_fifo;
|
|
}
|
|
|
|
if (intr & RTP_INTR_FIFO_FLG) {
|
|
/* When FIFO is overflow, the FIFO data is valid, so read it */
|
|
if (!(fcr & RTP_FCR_OF_FLAG) || !(intr & RTP_INTR_RISE_DET_FLG)) {
|
|
pr_err("FIFO error, flush the FIFO ...\n");
|
|
goto irq_clean_fifo;
|
|
}
|
|
}
|
|
|
|
if (intr & RTP_INTR_RISE_DET_FLG)
|
|
rtp_report_abs(rtp, 0);
|
|
|
|
if (intr & RTP_INTR_DRDY_FLG)
|
|
aic_rtp_read_fifo(rtp, (fcr & RTP_FCR_DAT_CNT_MASK)
|
|
>> RTP_FCR_DAT_CNT_SHIFT);
|
|
|
|
goto irq_done;
|
|
|
|
irq_clean_fifo:
|
|
rtp_fifo_flush();
|
|
|
|
irq_done:
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
u32 hal_rtp_ebuf_read_space(struct aic_rtp_ebuf *ebuf)
|
|
{
|
|
u16 rd = ebuf->rd_pos;
|
|
u16 wr = ebuf->wr_pos;
|
|
|
|
if (rd == wr) {
|
|
return 0;
|
|
} else if (rd < wr) {
|
|
return wr - rd;
|
|
} else {
|
|
return AIC_RTP_EVT_BUF_SIZE - (rd - wr - 1);
|
|
}
|
|
}
|
|
|
|
s32 hal_rtp_ebuf_write(struct aic_rtp_ebuf *ebuf, struct aic_rtp_event *e)
|
|
{
|
|
if (hal_rtp_ebuf_full(ebuf)) {
|
|
pr_debug("ebuf is full! Will drop a event\n");
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&ebuf->event[ebuf->wr_pos], e, sizeof(struct aic_rtp_event));
|
|
ebuf->wr_pos++;
|
|
|
|
if (ebuf->wr_pos >= AIC_RTP_EVT_BUF_SIZE)
|
|
ebuf->wr_pos = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 hal_rtp_ebuf_read(struct aic_rtp_ebuf *ebuf, struct aic_rtp_event *e)
|
|
{
|
|
if (hal_rtp_ebuf_empty(ebuf)) {
|
|
pr_debug("There is no RTP event in ebuf\n");
|
|
return -1;
|
|
}
|
|
|
|
memcpy(e, &ebuf->event[ebuf->rd_pos], sizeof(struct aic_rtp_event));
|
|
ebuf->rd_pos++;
|
|
if (ebuf->rd_pos >= AIC_RTP_EVT_BUF_SIZE)
|
|
ebuf->rd_pos = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
s32 hal_rtp_ebuf_sync(struct aic_rtp_ebuf *ebuf)
|
|
{
|
|
if (ebuf->wr_pos != 0)
|
|
ebuf->rd_pos = ebuf->wr_pos - 1;
|
|
else
|
|
ebuf->rd_pos = AIC_RTP_EVT_BUF_SIZE - 1;
|
|
return 0;
|
|
}
|
|
|
|
s32 hal_rtp_clk_init(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = hal_clk_enable(CLK_RTP);
|
|
if (ret < 0) {
|
|
pr_err("RTP clk enable failed!");
|
|
return -1;
|
|
}
|
|
|
|
ret = hal_clk_enable_deassertrst(CLK_RTP);
|
|
if (ret < 0) {
|
|
pr_err("RTP reset deassert failed!");
|
|
return -1;
|
|
}
|
|
return ret;
|
|
}
|