rt-thread/bsp/imxrt/Libraries/imxrt1021/drivers/touch/drv_touch_ft5x06.c

236 lines
5.7 KiB
C

/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2017-08-08 Yang the first version
* 2018-10-29 XY
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "drv_touch.h"
#include "fsl_iomuxc.h"
#include "fsl_gpio.h"
#define TP_INT_PIN 54 /* GPIO_AD_B0_11 */
#define TP_RST_PIN 45 /* GPIO_AD_B0_02 */
#define FT5x06_TS_ADDR (0x38)
#if 0
#define TPDEBUG rt_kprintf
#else
#define TPDEBUG(...)
#endif
static struct touch_driver ft5x06_driver;
typedef enum _touch_event
{
kTouch_Down = 0, /*!< The state changed to touched. */
kTouch_Up = 1, /*!< The state changed to not touched. */
kTouch_Contact = 2, /*!< There is a continuous touch being detected. */
kTouch_Reserved = 3 /*!< No touch information available. */
} touch_event_t;
typedef struct _touch_point
{
touch_event_t TOUCH_EVENT; /*!< Indicates the state or event of the touch point. */
uint8_t TOUCH_ID; /*!< Id of the touch point. This numeric value stays constant between down and up event. */
uint16_t TOUCH_X; /*!< X coordinate of the touch point */
uint16_t TOUCH_Y; /*!< Y coordinate of the touch point */
} touch_point_t;
typedef struct _ft5406_touch_point
{
uint8_t XH;
uint8_t XL;
uint8_t YH;
uint8_t YL;
uint8_t RESERVED[2];
} ft5406_touch_point_t;
typedef struct _ft5406_touch_data
{
uint8_t DEVIDE_MODE;
uint8_t GEST_ID;
uint8_t TD_STATUS;
ft5406_touch_point_t TOUCH;
} ft5406_touch_data_t;
#define TOUCH_POINT_GET_EVENT(T) ((touch_event_t)((T).XH >> 6))
#define TOUCH_POINT_GET_ID(T) ((T).YH >> 4)
#define TOUCH_POINT_GET_X(T) ((((T).XH & 0x0f) << 8) | (T).XL)
#define TOUCH_POINT_GET_Y(T) ((((T).YH & 0x0f) << 8) | (T).YL)
static int ft5406_read_touch(touch_point_t *dp)
{
rt_uint8_t cmd = 0;
ft5406_touch_data_t touch_data;
if (rt_touch_read(FT5x06_TS_ADDR, &cmd, 1, &touch_data, sizeof(ft5406_touch_data_t)) != 0)
return -1;
dp->TOUCH_X = TOUCH_POINT_GET_Y(touch_data.TOUCH);
dp->TOUCH_Y = TOUCH_POINT_GET_X(touch_data.TOUCH);
dp->TOUCH_EVENT = TOUCH_POINT_GET_EVENT(touch_data.TOUCH);
dp->TOUCH_ID = TOUCH_POINT_GET_ID(touch_data.TOUCH);
if (dp->TOUCH_EVENT == 3) return -1;
if (touch_data.TD_STATUS != 0)
return 0;
else
return -1;
}
static void ft5x06_isr_enable(rt_bool_t enable)
{
if(enable == RT_TRUE)
{
rt_pin_irq_enable(TP_INT_PIN, PIN_IRQ_ENABLE);
}
else
{
rt_pin_irq_enable(TP_INT_PIN, PIN_IRQ_DISABLE);
}
}
static void ft5x06_touch_isr(void *parameter)
{
TPDEBUG("[TP] ft5x06_touch_isr\n");
ft5x06_isr_enable(RT_FALSE);
rt_sem_release(ft5x06_driver.isr_sem);
}
static rt_err_t ft5x06_read_point(touch_message_t msg)
{
touch_point_t dp;
if (ft5406_read_touch(&dp) != 0)
{
msg->event = TOUCH_EVENT_UP;
}
else
{
if (dp.TOUCH_EVENT == kTouch_Up)
{
msg->event = TOUCH_EVENT_UP;
}
else if (dp.TOUCH_EVENT == kTouch_Down)
{
msg->event = TOUCH_EVENT_DOWN;
}
else if (dp.TOUCH_EVENT == kTouch_Contact)
{
msg->event = TOUCH_EVENT_MOVE;
}
else
{
msg->event = TOUCH_EVENT_UP;
}
}
msg->x = dp.TOUCH_X;
msg->y = dp.TOUCH_Y;
TPDEBUG("[TP] [%d, %d] %s\n", msg->x, msg->y,
msg->event == TOUCH_EVENT_DOWN ? "DOWN" : (msg->event == TOUCH_EVENT_MOVE ? "MOVE" : (msg->event == TOUCH_EVENT_UP ? "UP" : "NONE")));
if (msg->event != TOUCH_EVENT_UP)
{
rt_sem_release(ft5x06_driver.isr_sem);
}
else
{
ft5x06_isr_enable(RT_TRUE);
}
return RT_EOK;
}
static void ft5x06_init(struct rt_i2c_bus_device *i2c_bus)
{
ft5x06_driver.isr_sem = rt_sem_create("ft5x06", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(ft5x06_driver.isr_sem);
rt_pin_attach_irq(TP_INT_PIN, PIN_IRQ_MODE_LOW_LEVEL, ft5x06_touch_isr, &ft5x06_driver);
rt_pin_irq_enable(TP_INT_PIN, PIN_IRQ_ENABLE);
rt_thread_delay(RT_TICK_PER_SECOND / 5);
}
static void ft5x06_deinit(void)
{
if (ft5x06_driver.isr_sem)
{
rt_sem_delete(ft5x06_driver.isr_sem);
ft5x06_driver.isr_sem = RT_NULL;
}
}
struct touch_ops ft5x06_ops =
{
ft5x06_init,
ft5x06_deinit,
ft5x06_read_point,
};
static void ft5406_hw_reset(void)
{
gpio_pin_config_t pin_config =
{
kGPIO_DigitalOutput, 0,
};
CLOCK_EnableClock(kCLOCK_Gpio1);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B0_02_GPIO1_IO02, 0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B0_02_GPIO1_IO02, 0x10B0u);
/* Enable touch panel controller */
GPIO_PinInit(GPIO1, 2, &pin_config);
GPIO_WritePinOutput(GPIO1, 2, 1);
rt_thread_delay(RT_TICK_PER_SECOND / 20);
GPIO_WritePinOutput(GPIO1, 2, 0);
rt_thread_delay(RT_TICK_PER_SECOND / 20);
GPIO_WritePinOutput(GPIO1, 2, 1);
}
static rt_bool_t ft5x06_probe(struct rt_i2c_bus_device *i2c_bus)
{
rt_uint16_t cmd = 0x000c;
rt_uint16_t tmp[2];
rt_uint16_t CurVersion;
ft5406_hw_reset();
if (rt_touch_read(FT5x06_TS_ADDR, &cmd, 2, tmp, 2) != 0)
{
TPDEBUG("[TP] %s failed!\n", __func__);
return RT_FALSE;
}
CurVersion = (tmp[0]<<8) | tmp[1];
rt_kprintf("[TP] FT5X06 Touch Version : %d\n", CurVersion);
return RT_TRUE;
}
int ft5x06_driver_register(void)
{
ft5x06_driver.probe = ft5x06_probe;
ft5x06_driver.ops = &ft5x06_ops;
ft5x06_driver.user_data = RT_NULL;
rt_touch_drivers_register(&ft5x06_driver);
return 0;
}
INIT_ENV_EXPORT(ft5x06_driver_register);