/* * Copyright (c) 2020-2021 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ #include "hdf_touch.h" #include "gpio_if.h" #include "hdf_device_desc.h" #include "hdf_log.h" #include "hdf_pm.h" #include "osal_mem.h" #include "osal_io.h" #include "event_hub.h" #include "input_i2c_ops.h" #if defined(CONFIG_ARCH_ROCKCHIP) #include #include #include #include #include #include #endif #define I2C_TYPE 0 #define SPI_TYPE 1 #define MAX_TOUCH_DEVICE 5 #define REGISTER_BYTE_SIZE 4 #define TOUCH_CHIP_NAME_LEN 10 #if defined(CONFIG_ARCH_ROCKCHIP) #define GTP_ESD_PROTECT 1 #define GTP_REG_CMD 0x8040 #define GTP_REG_CMD_1 0x8041 #endif static TouchDriver *g_touchDriverList[MAX_TOUCH_DEVICE]; static void InputFrameReport(TouchDriver *driver); static int32_t ChipCheckResetRetry(ChipDevice *chipDev); static int32_t SetGpioDirAndLevel(int gpio, int dir, int level) { int32_t ret; if ((dir == GPIO_DIR_IN) || (dir == GPIO_DIR_OUT)) { ret = GpioSetDir(gpio, dir); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set gpio%d to %d dir failed, ret %d", __func__, gpio, dir, ret); return HDF_FAILURE; } } if ((level == GPIO_VAL_LOW) || (level == GPIO_VAL_HIGH)) { ret = GpioWrite(gpio, level); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: pull gpio%d to %d level failed, ret %d", __func__, gpio, level, ret); return HDF_FAILURE; } } return HDF_SUCCESS; } static int32_t SetVccPower(uint32_t status) { (void)status; return HDF_SUCCESS; } static int32_t SetVciPower(uint32_t status) { (void)status; return HDF_SUCCESS; } static int32_t SetGpio(uint16_t gpio, uint32_t dir, uint32_t status) { int32_t ret = SetGpioDirAndLevel(gpio, dir, status); CHECK_RETURN_VALUE(ret); return HDF_SUCCESS; } static int32_t HandleResetEvent(ChipDevice *chipDev, uint32_t *timing, uint32_t length) { int32_t ret = 0; uint16_t gpio; if (length <= PWR_DELAY_INDEX) { HDF_LOGE("%s: invalid param", __func__); return HDF_FAILURE; } uint32_t type = timing[PWR_TYPE_INDEX]; uint32_t status = timing[PWR_STATUS_INDEX]; uint32_t dir = timing[PWR_DIR_INDEX]; uint32_t delay = timing[PWR_DELAY_INDEX]; HDF_LOGD("%s: type = %u, status = %u, dir = %u, delay = %u", __func__, type, status, dir, delay); switch (type) { case TYPE_VCC: case TYPE_VCI: break; case TYPE_INT: gpio = chipDev->boardCfg->pins.intGpio; ret = SetGpio(gpio, dir, status); break; case TYPE_RESET: gpio = chipDev->boardCfg->pins.rstGpio; ret = SetGpio(gpio, dir, status); break; default: HDF_LOGE("%s: unknown power type", __func__); break; } if (delay > 0) { OsalMSleep(delay); } return ret; } static int32_t HandlePowerEvent(ChipDevice *chipDev, uint32_t *timing, uint32_t length) { int32_t ret = 0; uint16_t gpio; if (length <= PWR_DELAY_INDEX) { HDF_LOGE("%s: invalid param", __func__); return HDF_FAILURE; } uint32_t type = timing[PWR_TYPE_INDEX]; uint32_t status = timing[PWR_STATUS_INDEX]; uint32_t dir = timing[PWR_DIR_INDEX]; uint32_t delay = timing[PWR_DELAY_INDEX]; HDF_LOGD("%s: type = %u, status = %u, dir = %u, delay = %u", __func__, type, status, dir, delay); switch (type) { case TYPE_VCC: ret = SetVccPower(status); break; case TYPE_VCI: ret = SetVciPower(status); break; case TYPE_RESET: gpio = chipDev->boardCfg->pins.rstGpio; ret = SetGpio(gpio, dir, status); break; case TYPE_INT: gpio = chipDev->boardCfg->pins.intGpio; ret = SetGpio(gpio, dir, status); break; default: HDF_LOGE("%s: unknown power type", __func__); break; } if (delay > 0) { OsalMSleep(delay); } return ret; } static int32_t InputPinMuxCfg(uint32_t regAddr, int32_t regSize, uint32_t regValue) { #if defined(CONFIG_ARCH_SPRD) || defined(CONFIG_ARCH_ROCKCHIP) return HDF_SUCCESS; #endif uint8_t *base = NULL; if (regAddr == 0) { HDF_LOGE("%s: regAddr invalid", __func__); return HDF_FAILURE; } base = OsalIoRemap(regAddr, regSize); if (base == NULL) { HDF_LOGE("%s: ioremap failed", __func__); return HDF_FAILURE; } OSAL_WRITEL(regValue, base); OsalIoUnmap((void *)base); return HDF_SUCCESS; } #if defined(CONFIG_ARCH_ROCKCHIP) static int32_t SetResetStatus(TouchDriver *driver) { int32_t ret; uint8_t writeBuf[5]; // 5: buffer size writeBuf[0] = (GTP_REG_CMD_1 >> 8) & 0xFF; // 8:high byte 0xff:mask writeBuf[1] = GTP_REG_CMD_1 & 0xFF; writeBuf[2] = 0x00; // 2:index 0x00: reg value writeBuf[3] = 0x56; // 3:index 0x56: reg value writeBuf[4] = 0xAA; // 4:index 0xAA: reg value ret = InputI2cWrite(&driver->i2cClient, writeBuf, 5); // 5: buffer size if (ret != HDF_SUCCESS) { HDF_LOGE("%s: InputI2cWrite failed, ret = %d", __func__, ret); return ret; } writeBuf[0] = (GTP_REG_CMD >> 8) & 0xFF; // 8:high byte 0xff:mask writeBuf[1] = GTP_REG_CMD & 0xFF; writeBuf[2] = 0xAA; // 2:index 0xAA: reg value ret = InputI2cWrite(&driver->i2cClient, writeBuf, 3); // 3: buffer size if (ret != HDF_SUCCESS) { HDF_LOGE("%s: InputI2cWrite failed, ret = %d", __func__, ret); return ret; } return HDF_SUCCESS; } #endif static int32_t SetPowerOnTiming(ChipDevice *chipDev, bool enableRst) { int32_t i; int32_t ret; uint32_t rstPinAddr; uint32_t rstPinValue; uint32_t intPinAddr; uint32_t intPinValue; SeqArray pwrOnTiming = {0}; TouchDriver *driver = chipDev->driver; rstPinAddr = driver->boardCfg->pins.rstPinReg[0]; rstPinValue = driver->boardCfg->pins.rstPinReg[1]; intPinAddr = driver->boardCfg->pins.intPinReg[0]; intPinValue = driver->boardCfg->pins.intPinReg[1]; if (InputPinMuxCfg(rstPinAddr, REGISTER_BYTE_SIZE, rstPinValue) != HDF_SUCCESS) { return HDF_FAILURE; } if (InputPinMuxCfg(intPinAddr, REGISTER_BYTE_SIZE, intPinValue) != HDF_SUCCESS) { return HDF_FAILURE; } HDF_LOGD("%s: rstPinAddr = 0x%x, rstPinValue = 0x%x, intPinAddr = 0x%x, intPinValue = 0x%x", __func__, rstPinAddr, rstPinValue, intPinAddr, intPinValue); ret = memcpy_s(&pwrOnTiming, sizeof(SeqArray), &chipDev->chipCfg->pwrSeq.pwrOn, sizeof(SeqArray)); if (ret != EOK) { HDF_LOGE("%s: memcpy_s failed", __func__); return HDF_FAILURE; } if ((pwrOnTiming.buf == NULL) || (pwrOnTiming.count == 0)) { HDF_LOGE("%s: pwrOnTiming config is invalid", __func__); return HDF_FAILURE; } for (i = 0; i < pwrOnTiming.count / PWR_CELL_LEN; i++) { if (enableRst) { ret = HandleResetEvent(chipDev, pwrOnTiming.buf, PWR_CELL_LEN); } else { ret = HandlePowerEvent(chipDev, pwrOnTiming.buf, PWR_CELL_LEN); } CHECK_RETURN_VALUE(ret); pwrOnTiming.buf = pwrOnTiming.buf + PWR_CELL_LEN; } #if defined(CONFIG_ARCH_ROCKCHIP) ret = SetResetStatus(driver); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: SetResetStatus failed", __func__); } #endif return HDF_SUCCESS; } static void EventHandle(TouchDriver *driver, ChipDevice *chipDev) { int32_t ret; if ((chipDev->ops == NULL) || (chipDev->ops->DataHandle == NULL)) { return; } ret = chipDev->ops->DataHandle(chipDev); if (ret == HDF_SUCCESS) { InputFrameReport(driver); } else { HDF_LOGE("%s: DataHandle failed", __func__); } } static int32_t IrqHandle(uint16_t intGpioNum, void *data) { TouchDriver *driver = (TouchDriver *)data; int ret = GpioDisableIrq(intGpioNum); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: disable irq failed, ret %d", __func__, ret); return HDF_FAILURE; } EventHandle(driver, driver->device); ret = GpioEnableIrq(intGpioNum); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: enable irq failed, ret %d", __func__, ret); return HDF_FAILURE; } return HDF_SUCCESS; } static void InputFrameReport(TouchDriver *driver) { InputDevice *dev = driver->inputDev; FrameData *frame = &driver->frameData; int32_t i; OsalMutexLock(&driver->mutex); for (i = 0; i < MAX_FINGERS_NUM; i++) { if (frame->fingers[i].valid) { input_report_abs(dev, ABS_MT_POSITION_X, frame->fingers[i].x); input_report_abs(dev, ABS_MT_POSITION_Y, frame->fingers[i].y); input_report_abs(dev, ABS_MT_TRACKING_ID, frame->fingers[i].trackId); input_mt_sync(dev); } } if ((frame->definedEvent == TOUCH_DOWN) || (frame->definedEvent == TOUCH_CONTACT)) { input_report_key(dev, BTN_TOUCH, 1); // BTN_TOUCH DOWN } else { input_report_key(dev, BTN_TOUCH, 0); // BTN_TOUCH UP } OsalMutexUnlock(&driver->mutex); input_sync(dev); } static int32_t SetupChipIrq(ChipDevice *chipDev) { int32_t ret; uint16_t intGpioNum = chipDev->boardCfg->pins.intGpio; uint16_t irqFlag = chipDev->chipCfg->bus.chipI2c.irqFlag; if (chipDev->driver == NULL) { HDF_LOGE("%s: invalid param", __func__); return HDF_FAILURE; } irqFlag |= GPIO_IRQ_USING_THREAD; HDF_LOGD("%s: gpioNum = %u, irqFlag = %u", __func__, intGpioNum, irqFlag); ret = GpioSetIrq(intGpioNum, irqFlag, IrqHandle, chipDev->driver); if (ret != 0) { HDF_LOGE("%s: register irq failed, ret %d", __func__, ret); return ret; } ret = GpioEnableIrq(intGpioNum); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: enable irq failed, ret %d", __func__, ret); return HDF_FAILURE; } return HDF_SUCCESS; } static void ChipReset(ChipDevice *chipDev) { if (chipDev == NULL) { HDF_LOGE("%s: invalid param", __func__); return; } (void)SetPowerOnTiming(chipDev, true); } #if GTP_ESD_PROTECT static TouchDriver *g_touchDriver; static struct workqueue_struct *gt1x_workqueue = NULL; static int esd_work_cycle = 200; static struct delayed_work esd_check_work; static int esd_running; static void Gt1xEsdCheckFunc(struct work_struct *); int32_t Gt1xSedFeedWatchdog(TouchDriver *driver, uint8_t cmd, uint8_t data) { (void)driver; int32_t ret; uint8_t writeBuf[4]; // 4: buffer len writeBuf[0] = 0x80; // 0x80: reg address high bit writeBuf[1] = 0x41; // 0x41: reg address low bit writeBuf[2] = 0; // 2: bit nu 0: reg value writeBuf[3] = (uint8_t) ((0 - cmd - data) & 0xFF); // 3: bit nu 0xFF: mask ret = InputI2cWrite(&g_touchDriver->i2cClient, writeBuf, 4); // 4: len CHIP_CHECK_RETURN(ret); writeBuf[0] = 0x80; // 0x80: reg address high bit writeBuf[1] = 0x40; // 0x40: reg address low bit writeBuf[2] = 0xAA; // 2:bit nu 0xAA: reg value ret = InputI2cWrite(&g_touchDriver->i2cClient, writeBuf, 3); // 3: len CHIP_CHECK_RETURN(ret); OsalMSleep(50); // 50: ms return ret; } static int32_t Gt1xSedReadStatus(TouchDriver *driver) { int32_t ret = -1; uint8_t buf[4] = {0}; uint8_t reg[2] = {0}; reg[0] = 0x80; // 0x80: reg address high bit reg[1] = 0x40; // 0x40: reg address low bit ret = InputI2cRead(&g_touchDriver->i2cClient, reg, 2, buf, 4); // 2: len 4: len return (!ret && buf[0] != 0xAA && buf[3] == 0xAA); // 0xAA: reg value 3: bit nu } static int32_t Gt1xSedResetStatus(TouchDriver *driver) { int32_t ret = -1; uint8_t writeBuf[6]; // 6: buffer size writeBuf[0] = 0x42; // 0x42: reg address high bit writeBuf[1] = 0x26; // 0x26: reg address low bit writeBuf[2] = 0x01; // 0x01: reg value writeBuf[3] = 0x01; // 3: bit nu 0x01: reg value writeBuf[4] = 0x01; // 4: bit nu 0x01: reg value writeBuf[5] = 0x01; // 5: bit nu 0x01: reg value ret = InputI2cWrite(&g_touchDriver->i2cClient, writeBuf, 6); // 6: len return ret; } void Gt1xInitEsdProtect(void) { esd_work_cycle = 2 * HZ; // 2:nu HZ: clock ticks in 1 second generated by system HDF_LOGI("Clock ticks for an esd cycle: %d", esd_work_cycle); INIT_DELAYED_WORK(&esd_check_work, Gt1xEsdCheckFunc); } void Gt1xEsdSwitch(int32_t on) { if (on) { // switch on esd check HDF_LOGI("Esd protector started!"); queue_delayed_work(gt1x_workqueue, &esd_check_work, 1); } else { // switch off esd check HDF_LOGI("Esd protector stoped!"); cancel_delayed_work(&esd_check_work); } } static void Gt1xDeinitEsdProtect(void) { Gt1xEsdSwitch(0); } static int32_t ChipEsdResetRetry(TouchDriver *driver) { int32_t ret; ChipDevice *chipDev = driver->device; uint16_t intGpioNum = driver->device->boardCfg->pins.intGpio; ret = GpioDisableIrq(intGpioNum); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: disable irq failed, ret %d", __func__, ret); return HDF_FAILURE; } HDF_LOGI("start ChipEsdResetRetry"); ret = ChipCheckResetRetry(chipDev); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: enable irq failed, ret %d", __func__, ret); ret = GpioEnableIrq(intGpioNum); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: enable irq failed, ret %d", __func__, ret); } return HDF_FAILURE; } HDF_LOGI("end ChipEsdResetRetry"); ret = GpioEnableIrq(intGpioNum); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: enable irq failed, ret %d", __func__, ret); return HDF_FAILURE; } return HDF_SUCCESS; } static void Gt1xEsdCheckFunc(struct work_struct *work) { int32_t i = 0; int32_t ret = -1; for (i = 0; i < 3; i++) { // 3:nu ret = Gt1xSedReadStatus(g_touchDriver); if (ret) { break; } OsalMSleep(50); // 50: sleep time } if (likely(i < 3)) { // 3:nu Gt1xSedFeedWatchdog(g_touchDriver, 0xaa, 0); // 0xaa: reg value queue_delayed_work(gt1x_workqueue, &esd_check_work, esd_work_cycle); } else { HDF_LOGI("IC works abnormally! Process reset guitar"); Gt1xSedResetStatus(g_touchDriver); OsalMSleep(50); // 50: sleep time ret = ChipEsdResetRetry(g_touchDriver); if (ret == HDF_SUCCESS) { queue_delayed_work(gt1x_workqueue, &esd_check_work, esd_work_cycle); } else { HDF_LOGE("ESD failed, exit esd check work thread"); } } } #endif #if defined(CONFIG_ARCH_ROCKCHIP) static int32_t Gt1xRequestIo(ChipDevice *chipDev) { int32_t ret; ret = SetGpio(chipDev->boardCfg->pins.rstGpio, 1, 0); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set rstGpio to output failed, ret %d", __func__, ret); return HDF_FAILURE; } ret = SetGpio(chipDev->boardCfg->pins.intGpio, 1, 0); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set intGpio to output failed, ret %d", __func__, ret); return HDF_FAILURE; } OsalMSleep(100); // 100 : delay time ret = SetGpio(chipDev->boardCfg->pins.rstGpio, 1, 1); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: set intGpio to output failed, ret %d", __func__, ret); return HDF_FAILURE; } OsalMSleep(20); // 20 : delay time return HDF_SUCCESS; } #endif static int32_t ChipCheckResetRetry(ChipDevice *chipDev) { int32_t count = 20; // 20 : reset time int32_t ret; if ((chipDev->ops == NULL) || (chipDev->ops->Detect == NULL)) { return HDF_FAILURE; } while (count --) { ChipReset(chipDev); OsalMSleep(100); // 100 : wait 100msthen try one time ret = chipDev->ops->Detect(chipDev); if (ret == HDF_SUCCESS) { return HDF_SUCCESS; } HDF_LOGI("%s: reset chip %d time", __func__, count); } return HDF_FAILURE; } static int32_t ChipDriverInit(ChipDevice *chipDev) { int32_t ret; #if defined(CONFIG_ARCH_ROCKCHIP) g_touchDriver = chipDev->driver; ret = Gt1xRequestIo(chipDev); CHECK_RETURN_VALUE(ret); #else ret = SetPowerOnTiming(chipDev, false); CHECK_RETURN_VALUE(ret); #endif OsalMSleep(100); // 100 : delay time ret = ChipCheckResetRetry(chipDev); CHECK_RETURN_VALUE(ret); #if GTP_ESD_PROTECT gt1x_workqueue = create_singlethread_workqueue("gt1x_workthread"); if (gt1x_workqueue == NULL) { HDF_LOGE("Create workqueue failed!"); } Gt1xInitEsdProtect(); Gt1xEsdSwitch(1); #endif HDF_LOGI("%s: chipDetect succ, ret = %d ", __func__, ret); #if defined(CONFIG_ARCH_SPRD) || defined(CONFIG_ARCH_ROCKCHIP) HDF_LOGI("%s: DAYU do not update firmware", __func__); #else ret = chipDev->ops->UpdateFirmware(chipDev); CHECK_RETURN_VALUE(ret); HDF_LOGI("%s: update firmware success", __func__); #endif ret = SetupChipIrq(chipDev); CHECK_RETURN_VALUE(ret); return HDF_SUCCESS; } static InputDevice *InputDeviceInstance(ChipDevice *chipDev) { InputDevice *inputDev = (InputDevice *)OsalMemAlloc(sizeof(InputDevice)); if (inputDev == NULL) { HDF_LOGE("%s: instance input device failed", __func__); return NULL; } (void)memset_s(inputDev, sizeof(InputDevice), 0, sizeof(InputDevice)); inputDev->hdfDevObj = chipDev->driver->hdfTouchDev; inputDev->pvtData = (void *)chipDev; inputDev->devType = chipDev->driver->boardCfg->attr.devType; inputDev->devName = chipDev->driver->devName; return inputDev; } static int32_t ChipMatchCheck(const ChipDevice *chipDev, const TouchDriver *driver) { const struct DeviceResourceNode *boardNode = driver->boardCfg->boardNode; const struct DeviceResourceNode *chipNode = chipDev->chipCfg->chipNode; if ((boardNode == NULL) || (boardNode->parent == NULL)) { HDF_LOGE("%s: board node or upper node is null", __func__); return HDF_FAILURE; } if ((chipNode == NULL) || (chipNode->parent == NULL) || (chipNode->parent->parent == NULL)) { HDF_LOGE("%s: chip node or upper node is null ", __func__); return HDF_FAILURE; } if (boardNode->parent == chipNode->parent->parent) { HDF_LOGI("%s: boardNode's father name = %s, chipNode's grandpa name = %s", __func__, boardNode->parent->name, chipNode->parent->parent->name); return HDF_SUCCESS; } return HDF_FAILURE; } static int32_t DeviceBindDriver(ChipDevice *chipDev) { TouchDriver *driver = NULL; int32_t ret = HDF_FAILURE; int32_t i; for (i = 0; i < MAX_TOUCH_DEVICE; i++) { if ((g_touchDriverList[i] != NULL) && g_touchDriverList[i]->initedFlag) { ret = ChipMatchCheck(chipDev, g_touchDriverList[i]); if (ret == HDF_SUCCESS) { driver = g_touchDriverList[i]; break; } } } if ((ret == HDF_FAILURE) || (driver == NULL)) { return HDF_FAILURE; } driver->i2cClient.i2cCfg.addr = chipDev->chipCfg->bus.chipI2c.commAddr; driver->device = chipDev; chipDev->driver = driver; chipDev->boardCfg = driver->boardCfg; return HDF_SUCCESS; } int32_t RegisterTouchChipDevice(ChipDevice *chipDev) { int32_t ret; InputDevice *inputDev = NULL; if ((chipDev == NULL) || (chipDev->chipCfg == NULL)) { return HDF_ERR_INVALID_PARAM; } ret = DeviceBindDriver(chipDev); if (ret != HDF_SUCCESS) { HDF_LOGE("%s: chip device match driver failed", __func__); return HDF_FAILURE; } ret = ChipDriverInit(chipDev); if (ret != HDF_SUCCESS) { goto EXIT; } inputDev = InputDeviceInstance(chipDev); if (inputDev == NULL) { return HDF_ERR_MALLOC_FAIL; } ret = RegisterInputDevice(inputDev); if (ret != HDF_SUCCESS) { goto EXIT1; } chipDev->driver->inputDev = inputDev; chipDev->ops->SetAbility(chipDev); return HDF_SUCCESS; EXIT1: OsalMemFree(inputDev); EXIT: chipDev->driver->device = NULL; return HDF_FAILURE; } static int32_t TouchGetDevType(TouchDriver *driver, struct HdfSBuf *reply) { uint32_t devType = driver->devType; HDF_LOGI("%s: enter, devType is %u", __func__, devType); bool ret = HdfSbufWriteUint32(reply, devType); if (!ret) { HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__); return HDF_FAILURE; } return HDF_SUCCESS; } static int32_t TouchSetPowerStatus(TouchDriver *driver, struct HdfSBuf *data) { uint32_t pwrStatus = 0; bool ret = HdfSbufReadUint32(data, &pwrStatus); if (!ret) { HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__); return HDF_FAILURE; } driver->pwrStatus = pwrStatus; HDF_LOGI("%s: set power status is %u", __func__, pwrStatus); return HDF_SUCCESS; } static int32_t TouchGetPowerStatus(TouchDriver *driver, struct HdfSBuf *reply) { uint32_t pwrStatus = driver->pwrStatus; bool ret = HdfSbufWriteUint32(reply, pwrStatus); if (!ret) { HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__); return HDF_FAILURE; } HDF_LOGI("%s: get power status is %u", __func__, pwrStatus); return HDF_SUCCESS; } static int32_t TouchGetDeviceStrInfo(TouchDriver *driver, int32_t cmd, struct HdfSBuf *reply) { const char *info = NULL; if ((driver->device == NULL) || (driver->device->chipCfg == NULL)) { HDF_LOGE("%s: parameter invalid", __func__); return HDF_ERR_INVALID_PARAM; } switch (cmd) { case GET_CHIP_NAME: info = driver->device->chipName; break; case GET_VENDOR_NAME: info = driver->device->vendorName; break; case GET_CHIP_INFO: info = driver->device->chipCfg->chipInfo; break; default: info = NULL; break; } bool ret = HdfSbufWriteString(reply, info); if (!ret) { HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__); return HDF_FAILURE; } HDF_LOGI("%s: cmd is %d, the info is %s", __func__, cmd, info); return HDF_SUCCESS; } static int32_t TouchGetDeviceAttr(TouchDriver *driver, struct HdfSBuf *reply) { char *tempStr = "main_touch"; int32_t ret; if (driver->inputDev == NULL) { return HDF_FAILURE; } HDF_LOGE("%s: enter", __func__); ret = strncpy_s(driver->inputDev->attrSet.devName, DEV_NAME_LEN, tempStr, strlen(tempStr)); if (ret != 0) { HDF_LOGE("%s: strncpy dev attr failed", __func__); return HDF_FAILURE; } if (!HdfSbufWriteBuffer(reply, &driver->inputDev->attrSet, sizeof(DevAttr))) { HDF_LOGE("%s: sbuf write dev attr failed", __func__); } HDF_LOGI("%s: get dev attr succ", __func__); return HDF_SUCCESS; } static int32_t TouchGetDeviceAbility(TouchDriver *driver, struct HdfSBuf *reply) { if (driver->inputDev == NULL) { return HDF_FAILURE; } HDF_LOGE("%s: enter", __func__); if (!HdfSbufWriteBuffer(reply, &driver->inputDev->abilitySet, sizeof(DevAbility))) { HDF_LOGE("%s: sbuf write dev ability failed", __func__); } HDF_LOGI("%s: get dev ability succ", __func__); return HDF_SUCCESS; } static int32_t TouchSetGestureMode(TouchDriver *driver, struct HdfSBuf *data) { uint32_t gestureMode = 0; bool ret = HdfSbufReadUint32(data, &gestureMode); if (!ret) { HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__); return HDF_FAILURE; } driver->gestureMode = gestureMode; HDF_LOGD("%s: set gesture mode is %u", __func__, gestureMode); return HDF_SUCCESS; } static int32_t TouchSelfCapacitance(TouchDriver *driver, struct HdfSBuf *data, struct HdfSBuf *reply) { CapacitanceTestInfo capacTest = {0}; bool ret = HdfSbufReadUint32(data, &capacTest.testType); if (!ret) { HDF_LOGE("%s: HdfSbufWriteUint32 failed", __func__); return HDF_FAILURE; } if (strncpy_s(capacTest.testResult, SELF_TEST_RESULT_LEN, "SUCCESS", sizeof("SUCCESS")) != EOK) { HDF_LOGE("%s: strncpy_s fail", __func__); return HDF_FAILURE; } ret = HdfSbufWriteString(reply, (const char *)capacTest.testResult); if (!ret) { HDF_LOGE("%s: HdfSbufWriteString failed", __func__); return HDF_FAILURE; } HDF_LOGD("%s: capac test type is %u, test result is %s", __func__, capacTest.testType, capacTest.testResult); return HDF_SUCCESS; } static int32_t TouchRunExtraCmd(TouchDriver *driver, struct HdfSBuf *data) { InputExtraCmd cmd = {0}; cmd.cmdCode = HdfSbufReadString(data); if (cmd.cmdCode == NULL) { HDF_LOGE("%s: HdfSbufReadString failed", __func__); return HDF_FAILURE; } cmd.cmdValue = HdfSbufReadString(data); if (cmd.cmdValue == NULL) { HDF_LOGE("%s: HdfSbufReadString failed", __func__); return HDF_FAILURE; } HDF_LOGD("%s: extra cmd code is %s, cmd value is %s", __func__, cmd.cmdCode, cmd.cmdValue); return HDF_SUCCESS; } static int32_t HdfTouchDispatch(struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply) { int32_t ret; TouchDriver *touchDriver = NULL; if ((client == NULL) || (client->device == NULL) || (data == NULL) || (reply == NULL)) { HDF_LOGE("%s: param is null", __func__); return HDF_FAILURE; } touchDriver = (TouchDriver *)client->device->priv; if (touchDriver == NULL) { HDF_LOGE("%s: touchDriver is null", __func__); return HDF_FAILURE; } HDF_LOGI("%s: cmd = %d", __func__, cmd); switch (cmd) { case GET_DEV_TYPE: ret = TouchGetDevType(touchDriver, reply); break; case SET_PWR_STATUS: ret = TouchSetPowerStatus(touchDriver, data); break; case GET_PWR_STATUS: ret = TouchGetPowerStatus(touchDriver, reply); break; case GET_CHIP_NAME: case GET_VENDOR_NAME: case GET_CHIP_INFO: ret = TouchGetDeviceStrInfo(touchDriver, cmd, reply); break; case GET_DEV_ATTR: ret = TouchGetDeviceAttr(touchDriver, reply); break; case GET_DEV_ABILITY: ret = TouchGetDeviceAbility(touchDriver, reply); break; case SET_GESTURE_MODE: ret = TouchSetGestureMode(touchDriver, data); break; case RUN_CAPAC_TEST: ret = TouchSelfCapacitance(touchDriver, data, reply); break; case RUN_EXTRA_CMD: ret = TouchRunExtraCmd(touchDriver, data); break; default: ret = HDF_SUCCESS; HDF_LOGE("%s: cmd unknown, cmd = 0x%x", __func__, cmd); break; } return ret; } static int32_t TouchSetupBus(TouchDriver *driver, TouchBoardCfg *config) { uint8_t busType = config->bus.busType; uint8_t busNum = config->bus.i2c.busNum; if (busType == I2C_TYPE) { uint32_t i2cClkAddr = config->bus.i2c.i2cClkReg[0]; uint32_t i2cClkValue = config->bus.i2c.i2cClkReg[1]; uint32_t i2cDataAddr = config->bus.i2c.i2cDataReg[0]; uint32_t i2cDataValue = config->bus.i2c.i2cDataReg[1]; if (InputPinMuxCfg(i2cClkAddr, REGISTER_BYTE_SIZE, i2cClkValue) != HDF_SUCCESS) { return HDF_FAILURE; } if (InputPinMuxCfg(i2cDataAddr, REGISTER_BYTE_SIZE, i2cDataValue) != HDF_SUCCESS) { return HDF_FAILURE; } /* get i2c handle */ driver->i2cClient.i2cHandle = I2cOpen(busNum); if (driver->i2cClient.i2cHandle == NULL) { HDF_LOGE("%s: open i2c%u failed", __func__, busNum); return HDF_FAILURE; } return HDF_SUCCESS; } if (busType == SPI_TYPE) { HDF_LOGI("%s: setup spi bus succ", __func__); return HDF_SUCCESS; } return HDF_FAILURE; } static int32_t TouchInitData(TouchDriver *driver, TouchBoardCfg *config) { driver->devType = config->attr.devType; driver->devName = config->attr.devName; driver->i2cClient.i2cCfg.busNum = config->bus.i2c.busNum; driver->irqStopFlag = false; return HDF_SUCCESS; } static int32_t TouchDriverInit(TouchDriver *driver, TouchBoardCfg *config) { int32_t ret = TouchInitData(driver, config); CHECK_RETURN_VALUE(ret); ret = TouchSetupBus(driver, config); CHECK_RETURN_VALUE(ret); ret = OsalMutexInit(&driver->mutex); CHECK_RETURN_VALUE(ret); driver->initedFlag = true; return HDF_SUCCESS; } static TouchBoardCfg *BoardConfigInstance(struct HdfDeviceObject *device) { TouchBoardCfg *boardCfg = (TouchBoardCfg *)OsalMemAlloc(sizeof(TouchBoardCfg)); if (boardCfg == NULL) { HDF_LOGE("%s: instance board config failed", __func__); return NULL; } (void)memset_s(boardCfg, sizeof(TouchBoardCfg), 0, sizeof(TouchBoardCfg)); if (ParseTouchBoardConfig(device->property, boardCfg) != HDF_SUCCESS) { HDF_LOGE("%s: parse board config failed", __func__); OsalMemFree(boardCfg); boardCfg = NULL; } return boardCfg; } static TouchDriver *TouchDriverInstance(void) { TouchDriver *touchDrv = (TouchDriver *)OsalMemAlloc(sizeof(TouchDriver)); if (touchDrv == NULL) { HDF_LOGE("%s: instance touch driver failed", __func__); return NULL; } (void)memset_s(touchDrv, sizeof(TouchDriver), 0, sizeof(TouchDriver)); return touchDrv; } static void AddTouchDriver(TouchDriver *driver) { int32_t i; for (i = 0; i < MAX_TOUCH_DEVICE; i++) { if (g_touchDriverList[i] == NULL) { g_touchDriverList[i] = driver; return; } } } static int32_t HdfTouchDriverBind(struct HdfDeviceObject *device) { if (device == NULL) { HDF_LOGE("%s: param is null", __func__); return HDF_ERR_INVALID_PARAM; } static struct IDeviceIoService touchService = { .Dispatch = HdfTouchDispatch, }; device->service = &touchService; return HDF_SUCCESS; } #if defined(CONFIG_ARCH_ROCKCHIP) static int HdfTouchDriverDozeResume(struct HdfDeviceObject *device) { if (device == NULL) { HDF_LOGE("%s: param is null", __func__); return HDF_ERR_INVALID_PARAM; } HDF_LOGI("%s:called", __func__); static int32_t isFirstResume = 1; if (isFirstResume == 1) { isFirstResume = 0; return HDF_SUCCESS; } TouchDriver *touchDriver = (TouchDriver *)device->priv; ChipReset(touchDriver->device); return HDF_SUCCESS; } static int HdfTouchDriverDozeSuspend(struct HdfDeviceObject *device) { if (device == NULL) { HDF_LOGE("%s: param is null", __func__); return HDF_ERR_INVALID_PARAM; } HDF_LOGI("%s:called", __func__); int32_t ret = -1; uint8_t writeBuf[3]; // 3: buffer size TouchDriver *touchDriver = (TouchDriver *)device->priv; uint16_t intGpioNum = touchDriver->device->boardCfg->pins.intGpio; GpioSetDir(intGpioNum, 1); GpioWrite(intGpioNum, 0); writeBuf[0] = 0x80; // 0x42: reg address high bit writeBuf[1] = 0x40; // 0x26: reg address low bit writeBuf[2] = 0x05; // 0x01: reg value ret = InputI2cWrite(&touchDriver->i2cClient, writeBuf, 3); // 3: len HDF_LOGI("%s:ret = %d", __func__, ret); return HDF_SUCCESS; } static void HdfTouchDriverRegisterPowerListener(struct HdfDeviceObject *device) { int ret; static struct IPowerEventListener powerListener = {0}; HDF_LOGI("%s::enter!", __func__); powerListener.DozeResume = HdfTouchDriverDozeResume; powerListener.DozeSuspend = HdfTouchDriverDozeSuspend; powerListener.Resume = NULL; powerListener.Suspend = NULL; ret = HdfPmRegisterPowerListener(device, &powerListener); HDF_LOGI("%s:register power listener, ret = %d", __func__, ret); } static void HdfTouchDriverUnregisterPowerListener(struct HdfDeviceObject *device) { static struct IPowerEventListener powerListener = {0}; HDF_LOGI("%s::enter!", __func__); powerListener.DozeResume = NULL; powerListener.DozeSuspend = NULL; powerListener.Resume = NULL; powerListener.Suspend = NULL; HdfPmUnregisterPowerListener(device, &powerListener); } #endif static int32_t HdfTouchDriverProbe(struct HdfDeviceObject *device) { int32_t ret; TouchBoardCfg *boardCfg = NULL; TouchDriver *touchDriver = NULL; HDF_LOGI("%s: enter", __func__); if (device == NULL) { HDF_LOGE("%s: param is null", __func__); return HDF_ERR_INVALID_PARAM; } boardCfg = BoardConfigInstance(device); if (boardCfg == NULL) { return HDF_ERR_MALLOC_FAIL; } touchDriver = TouchDriverInstance(); if (touchDriver == NULL) { goto EXIT; } ret = TouchDriverInit(touchDriver, boardCfg); if (ret == HDF_SUCCESS) { touchDriver->hdfTouchDev = device; touchDriver->boardCfg = boardCfg; AddTouchDriver(touchDriver); device->priv = (void *)touchDriver; #if defined(CONFIG_ARCH_ROCKCHIP) HdfTouchDriverRegisterPowerListener(device); #endif HDF_LOGI("%s: %s exit succ", __func__, boardCfg->attr.devName); return HDF_SUCCESS; } EXIT: OsalMemFree(boardCfg); if (touchDriver != NULL) { touchDriver->boardCfg = NULL; OsalMemFree(touchDriver); } return HDF_FAILURE; } static void HdfTouchDriverRelease(struct HdfDeviceObject *device) { TouchDriver *driver = NULL; InputDevice *inputDev = NULL; int32_t i; if (device == NULL || device->priv == NULL) { HDF_LOGE("%s: param is null", __func__); return; } driver = device->priv; for (i = 0; i < MAX_TOUCH_DEVICE; i++) { if (g_touchDriverList[i] == driver) { inputDev = driver->inputDev; break; } } if (inputDev != NULL) { UnregisterInputDevice(inputDev); driver->inputDev = NULL; } #if defined(CONFIG_ARCH_ROCKCHIP) HdfTouchDriverUnregisterPowerListener(device); #endif OsalMutexDestroy(&driver->mutex); OsalMemFree(driver); if (i < MAX_TOUCH_DEVICE) { g_touchDriverList[i] = NULL; } } struct HdfDriverEntry g_hdfTouchEntry = { .moduleVersion = 1, .moduleName = "HDF_TOUCH", .Bind = HdfTouchDriverBind, .Init = HdfTouchDriverProbe, .Release = HdfTouchDriverRelease, }; HDF_INIT(g_hdfTouchEntry);