1
0
Fork 0
remarkable-linux/drivers/input/touchscreen/pt_platform.c

1050 lines
27 KiB
C
Executable File

/*
* pt_platform.c
* Parade TrueTouch(TM) Standard Product Platform Module.
* For use with Parade touchscreen controllers.
* Supported parts include:
* TMA5XX
* TMA448
* TMA445A
* TT21XXX
* TT31XXX
* TT4XXXX
* TT7XXX
* TC3XXX
*
* Copyright (C) 2015-2020 Parade Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2, and only version 2, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that 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.
*
* Contact Parade Technologies at www.paradetech.com <ttdrivers@paradetech.com>
*/
#include "pt_regs.h"
#include <linux/pt_platform.h>
#ifdef CONFIG_TOUCHSCREEN_PARADE_PLATFORM_FW_UPGRADE
/* FW for Panel ID = 0x00 */
#include "pt_fw_pid00.h"
static struct pt_touch_firmware pt_firmware_pid00 = {
.img = pt_img_pid00,
.size = ARRAY_SIZE(pt_img_pid00),
.ver = pt_ver_pid00,
.vsize = ARRAY_SIZE(pt_ver_pid00),
.panel_id = 0x00,
};
/* FW for Panel ID = 0x01 */
#include "pt_fw_pid01.h"
static struct pt_touch_firmware pt_firmware_pid01 = {
.img = pt_img_pid01,
.size = ARRAY_SIZE(pt_img_pid01),
.ver = pt_ver_pid01,
.vsize = ARRAY_SIZE(pt_ver_pid01),
.panel_id = 0x01,
};
/* FW for Panel ID not enabled (legacy) */
#include "pt_fw.h"
static struct pt_touch_firmware pt_firmware = {
.img = pt_img,
.size = ARRAY_SIZE(pt_img),
.ver = pt_ver,
.vsize = ARRAY_SIZE(pt_ver),
};
#else
/* FW for Panel ID not enabled (legacy) */
static struct pt_touch_firmware pt_firmware = {
.img = NULL,
.size = 0,
.ver = NULL,
.vsize = 0,
};
#endif
#ifdef CONFIG_TOUCHSCREEN_PARADE_PLATFORM_TTCONFIG_UPGRADE
/* TT Config for Panel ID = 0x00 */
#include "pt_params_pid00.h"
static struct touch_settings pt_sett_param_regs_pid00 = {
.data = (uint8_t *)&pt_param_regs_pid00[0],
.size = ARRAY_SIZE(pt_param_regs_pid00),
.tag = 0,
};
static struct touch_settings pt_sett_param_size_pid00 = {
.data = (uint8_t *)&pt_param_size_pid00[0],
.size = ARRAY_SIZE(pt_param_size_pid00),
.tag = 0,
};
static struct pt_touch_config pt_ttconfig_pid00 = {
.param_regs = &pt_sett_param_regs_pid00,
.param_size = &pt_sett_param_size_pid00,
.fw_ver = ttconfig_fw_ver_pid00,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver_pid00),
.panel_id = 0x00,
};
/* TT Config for Panel ID = 0x01 */
#include "pt_params_pid01.h"
static struct touch_settings pt_sett_param_regs_pid01 = {
.data = (uint8_t *)&pt_param_regs_pid01[0],
.size = ARRAY_SIZE(pt_param_regs_pid01),
.tag = 0,
};
static struct touch_settings pt_sett_param_size_pid01 = {
.data = (uint8_t *)&pt_param_size_pid01[0],
.size = ARRAY_SIZE(pt_param_size_pid01),
.tag = 0,
};
static struct pt_touch_config pt_ttconfig_pid01 = {
.param_regs = &pt_sett_param_regs_pid01,
.param_size = &pt_sett_param_size_pid01,
.fw_ver = ttconfig_fw_ver_pid01,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver_pid01),
.panel_id = 0x01,
};
/* TT Config for Panel ID not enabled (legacy)*/
#include "pt_params.h"
static struct touch_settings pt_sett_param_regs = {
.data = (uint8_t *)&pt_param_regs[0],
.size = ARRAY_SIZE(pt_param_regs),
.tag = 0,
};
static struct touch_settings pt_sett_param_size = {
.data = (uint8_t *)&pt_param_size[0],
.size = ARRAY_SIZE(pt_param_size),
.tag = 0,
};
static struct pt_touch_config pt_ttconfig = {
.param_regs = &pt_sett_param_regs,
.param_size = &pt_sett_param_size,
.fw_ver = ttconfig_fw_ver,
.fw_vsize = ARRAY_SIZE(ttconfig_fw_ver),
};
#else
/* TT Config for Panel ID not enabled (legacy)*/
static struct pt_touch_config pt_ttconfig = {
.param_regs = NULL,
.param_size = NULL,
.fw_ver = NULL,
.fw_vsize = 0,
};
#endif
static struct pt_touch_firmware *pt_firmwares[] = {
#ifdef CONFIG_TOUCHSCREEN_PARADE_PLATFORM_FW_UPGRADE
&pt_firmware_pid00,
&pt_firmware_pid01,
#endif
NULL, /* Last item should always be NULL */
};
static struct pt_touch_config *pt_ttconfigs[] = {
#ifdef CONFIG_TOUCHSCREEN_PARADE_PLATFORM_TTCONFIG_UPGRADE
&pt_ttconfig_pid00,
&pt_ttconfig_pid01,
#endif
NULL, /* Last item should always be NULL */
};
struct pt_loader_platform_data _pt_loader_platform_data = {
.fw = &pt_firmware,
.ttconfig = &pt_ttconfig,
.fws = pt_firmwares,
.ttconfigs = pt_ttconfigs,
.flags = PT_LOADER_FLAG_NONE,
};
/*******************************************************************************
* FUNCTION: pt_xres
*
* SUMMARY: Toggles the reset gpio (TP_XRES) to perform a HW reset
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
******************************************************************************/
int pt_xres(struct pt_core_platform_data *pdata,
struct device *dev)
{
int rst_gpio = pdata->rst_gpio;
int rc = 0;
int ddi_rst_gpio = pdata->ddi_rst_gpio;
pt_debug(dev, DL_WARN, "%s: 20ms HARD RESET on gpio=%d\n",
__func__, pdata->rst_gpio);
/* Toggling only TP_XRES as DDI_XRES resets the entire part */
gpio_set_value(rst_gpio, 1);
if (ddi_rst_gpio)
gpio_set_value(ddi_rst_gpio, 1);
usleep_range(3000, 4000);
gpio_set_value(rst_gpio, 0);
usleep_range(6000, 7000);
gpio_set_value(rst_gpio, 1);
if (ddi_rst_gpio)
gpio_set_value(ddi_rst_gpio, 1);
/* Sleep to allow the DUT to boot */
usleep_range(3000, 4000);
return rc;
}
#ifdef PT_PINCTRL_EN
/*******************************************************************************
* FUNCTION: pt_pinctrl_init
*
* SUMMARY: Pinctrl method to obtain pin state handler for TP_RST, IRQ
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
******************************************************************************/
static int pt_pinctrl_init(struct pt_core_platform_data *pdata,
struct device *dev)
{
int ret = 0;
pdata->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR_OR_NULL(pdata->pinctrl)) {
pt_debug(dev, DL_ERROR,
"Failed to get pinctrl, please check dts");
ret = PTR_ERR(pdata->pinctrl);
goto err_pinctrl_get;
}
pdata->pins_active =
pinctrl_lookup_state(pdata->pinctrl, "pmx_ts_active");
if (IS_ERR_OR_NULL(pdata->pins_active)) {
pt_debug(dev, DL_ERROR, "pmx_ts_active not found");
ret = PTR_ERR(pdata->pins_active);
goto err_pinctrl_lookup;
}
pdata->pins_suspend =
pinctrl_lookup_state(pdata->pinctrl, "pmx_ts_suspend");
if (IS_ERR_OR_NULL(pdata->pins_suspend)) {
pt_debug(dev, DL_ERROR, "pmx_ts_suspend not found");
ret = PTR_ERR(pdata->pins_suspend);
goto err_pinctrl_lookup;
}
pdata->pins_release =
pinctrl_lookup_state(pdata->pinctrl, "pmx_ts_release");
if (IS_ERR_OR_NULL(pdata->pins_release)) {
pt_debug(dev, DL_ERROR, "pmx_ts_release not found");
ret = PTR_ERR(pdata->pins_release);
goto err_pinctrl_lookup;
}
return 0;
err_pinctrl_lookup:
devm_pinctrl_put(pdata->pinctrl);
err_pinctrl_get:
pdata->pinctrl = NULL;
pdata->pins_release = NULL;
pdata->pins_suspend = NULL;
pdata->pins_active = NULL;
return ret;
}
/*******************************************************************************
* FUNCTION: pt_pinctrl_select_normal
*
* SUMMARY: Pinctrl method to configure drive mode for TP_RST, IRQ - normal
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
******************************************************************************/
static int pt_pinctrl_select_normal(struct pt_core_platform_data *pdata,
struct device *dev)
{
int ret = 0;
if (pdata->pinctrl && pdata->pins_active) {
ret = pinctrl_select_state(pdata->pinctrl, pdata->pins_active);
if (ret < 0) {
pt_debug(dev, DL_ERROR, "Set normal pin state error=%d",
ret);
}
}
return ret;
}
/*******************************************************************************
* FUNCTION: pt_pinctrl_select_suspend
*
* SUMMARY: Pinctrl method to configure drive mode for TP_RST, IRQ - suspend
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
******************************************************************************/
static int pt_pinctrl_select_suspend(struct pt_core_platform_data *pdata,
struct device *dev)
{
int ret = 0;
if (pdata->pinctrl && pdata->pins_suspend) {
ret = pinctrl_select_state(pdata->pinctrl, pdata->pins_suspend);
if (ret < 0) {
pt_debug(dev, DL_ERROR,
"Set suspend pin state error=%d", ret);
}
}
return ret;
}
/*******************************************************************************
* FUNCTION: pt_pinctrl_select_release
*
* SUMMARY: Pinctrl method to configure drive mode for TP_RST, IRQ - release
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
******************************************************************************/
static int pt_pinctrl_select_release(struct pt_core_platform_data *pdata,
struct device *dev)
{
int ret = 0;
if (pdata->pinctrl) {
if (IS_ERR_OR_NULL(pdata->pins_release)) {
devm_pinctrl_put(pdata->pinctrl);
pdata->pinctrl = NULL;
} else {
ret = pinctrl_select_state(pdata->pinctrl,
pdata->pins_release);
if (ret < 0)
pt_debug(dev, DL_ERROR,
"Set gesture pin state error=%d", ret);
}
}
return ret;
}
#endif /* PT_PINCTRL_EN */
/*******************************************************************************
* FUNCTION: pt_init
*
* SUMMARY: Set up/free gpios for TP_RST, IRQ, DDI_RST.
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* on - flag to set up or free gpios(0:free; !0:set up)
* *dev - pointer to Device structure
******************************************************************************/
int pt_init(struct pt_core_platform_data *pdata,
int on, struct device *dev)
{
int rst_gpio = pdata->rst_gpio;
int irq_gpio = pdata->irq_gpio;
int ddi_rst_gpio = pdata->ddi_rst_gpio;
int rc = 0;
#ifdef PT_PINCTRL_EN
if (on) {
rc = pt_pinctrl_init(pdata, dev);
if (!rc) {
pt_pinctrl_select_normal(pdata, dev);
} else {
pt_debug(dev, DL_ERROR,
"%s: Failed to request pinctrl\n", __func__);
}
}
#endif
if (on && rst_gpio) {
/* Configure RST GPIO */
pt_debug(dev, DL_WARN, "%s: Request RST GPIO %d",
__func__, rst_gpio);
rc = gpio_request(rst_gpio, NULL);
if (rc < 0) {
gpio_free(rst_gpio);
rc = gpio_request(rst_gpio, NULL);
}
if (rc < 0) {
pt_debug(dev, DL_ERROR,
"%s: Failed requesting RST GPIO %d\n",
__func__, rst_gpio);
goto fail_rst_gpio;
} else {
/*
* Set the GPIO direction and the starting level
* The start level is high because the DUT needs
* to stay in reset during power up.
*/
rc = gpio_direction_output(rst_gpio, 1);
if (rc < 0) {
pt_debug(dev, DL_ERROR,
"%s: Output Setup ERROR: RST GPIO %d\n",
__func__, rst_gpio);
goto fail_rst_gpio;
}
}
}
if (on && irq_gpio) {
/* Configure IRQ GPIO */
pt_debug(dev, DL_WARN, "%s: Request IRQ GPIO %d",
__func__, irq_gpio);
rc = gpio_request(irq_gpio, NULL);
if (rc < 0) {
gpio_free(irq_gpio);
rc = gpio_request(irq_gpio, NULL);
}
if (rc < 0) {
pt_debug(dev, DL_ERROR,
"%s: Failed requesting IRQ GPIO %d\n",
__func__, irq_gpio);
goto fail_irq_gpio;
} else {
/* Set the GPIO direction */
rc = gpio_direction_input(irq_gpio);
if (rc < 0) {
pt_debug(dev, DL_ERROR,
"%s: Input Setup ERROR: IRQ GPIO %d\n",
__func__, irq_gpio);
goto fail_irq_gpio;
}
}
}
if (on && ddi_rst_gpio) {
/* Configure DDI RST GPIO */
pt_debug(dev, DL_WARN, "%s: Request DDI RST GPIO %d",
__func__, ddi_rst_gpio);
rc = gpio_request(ddi_rst_gpio, NULL);
if (rc < 0) {
gpio_free(ddi_rst_gpio);
rc = gpio_request(ddi_rst_gpio, NULL);
}
if (rc < 0) {
pt_debug(dev, DL_ERROR,
"%s: Failed requesting DDI RST GPIO %d\n",
__func__, ddi_rst_gpio);
goto fail_ddi_rst_gpio;
} else {
/* Set the GPIO direction and the starting level */
rc = gpio_direction_output(ddi_rst_gpio, 0);
if (rc < 0) {
pt_debug(dev, DL_ERROR,
"%s: Output Setup ERROR: RST GPIO %d\n",
__func__, ddi_rst_gpio);
goto fail_ddi_rst_gpio;
}
}
}
if (!on) {
/* "on" not set, therefore free all gpio's */
if (ddi_rst_gpio)
gpio_free(ddi_rst_gpio);
if (irq_gpio)
gpio_free(irq_gpio);
if (rst_gpio)
gpio_free(rst_gpio);
#ifdef PT_PINCTRL_EN
pt_pinctrl_select_release(pdata, dev);
#endif
}
/* All GPIO's created successfully */
goto success;
fail_ddi_rst_gpio:
pt_debug(dev, DL_ERROR,
"%s: ERROR - GPIO setup Failure, freeing DDI_XRES GPIO %d\n",
__func__, ddi_rst_gpio);
gpio_free(ddi_rst_gpio);
fail_irq_gpio:
pt_debug(dev, DL_ERROR,
"%s: ERROR - GPIO setup Failure, freeing IRQ GPIO %d\n",
__func__, irq_gpio);
gpio_free(irq_gpio);
fail_rst_gpio:
pt_debug(dev, DL_ERROR,
"%s: ERROR - GPIO setup Failure, freeing TP_XRES GPIO %d\n",
__func__, rst_gpio);
gpio_free(rst_gpio);
success:
pt_debug(dev, DL_INFO,
"%s: SUCCESS - Configured DDI_XRES GPIO %d, IRQ GPIO %d, TP_XRES GPIO %d\n",
__func__, ddi_rst_gpio, irq_gpio, rst_gpio);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_wakeup
*
* SUMMARY: Resume power for "power on/off" sleep strategy which against to
* "deepsleep" strategy.
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
* *ignore_irq - pointer to atomic structure to allow the host ignoring false
* IRQ during power up
******************************************************************************/
static int pt_wakeup(struct pt_core_platform_data *pdata,
struct device *dev, atomic_t *ignore_irq)
{
/* Example for TT7XXX */
int rc = 0;
#ifdef PT_PINCTRL_EN
pt_pinctrl_select_normal(pdata, dev);
#endif
#ifdef TT7XXX_EXAMPLE
pt_debug(dev, DL_INFO,
"%s: Enable defined pwr: VDDI, VCC\n", __func__);
/*
* Force part into RESET by holding XRES#(TP_XRES)
* while powering it up
*/
if (pdata->rst_gpio)
gpio_set_value(pdata->rst_gpio, 0);
/* Turn on VDDI [Digital Interface] (+1.8v) */
if (pdata->vddi_gpio) {
rc = gpio_request(pdata->vddi_gpio, NULL);
if (rc < 0) {
gpio_free(pdata->vddi_gpio);
rc = gpio_request(pdata->vddi_gpio, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VDDI GPIO %d\n",
__func__, pdata->vddi_gpio);
}
rc = gpio_direction_output(pdata->vddi_gpio, 1);
if (rc)
pr_err("%s: setcfg for VDDI GPIO %d failed\n",
__func__, pdata->vddi_gpio);
gpio_free(pdata->vddi_gpio);
usleep_range(3000, 4000);
}
/* Turn on VCC */
if (pdata->vcc_gpio) {
rc = gpio_request(pdata->vcc_gpio, NULL);
if (rc < 0) {
gpio_free(pdata->vcc_gpio);
rc = gpio_request(pdata->vcc_gpio, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VCC GPIO %d\n",
__func__, pdata->vcc_gpio);
}
rc = gpio_direction_output(pdata->vcc_gpio, 1);
if (rc)
pr_err("%s: setcfg for VCC GPIO %d failed\n",
__func__, pdata->vcc_gpio);
gpio_free(pdata->vcc_gpio);
usleep_range(3000, 4000);
}
usleep_range(12000, 15000);
/* Force part out of RESET by releasing XRES#(TP_XRES) */
if (pdata->rst_gpio)
gpio_set_value(pdata->rst_gpio, 1);
#else
pt_debug(dev, DL_INFO, "%s: Enable defined pwr\n", __func__);
#endif
return rc;
}
/*******************************************************************************
* FUNCTION: pt_sleep
*
* SUMMARY: Suspend power for "power on/off" sleep strategy which against to
* "deepsleep" strategy.
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
* *ignore_irq - pointer to atomic structure to allow the host ignoring false
* IRQ during power down
******************************************************************************/
static int pt_sleep(struct pt_core_platform_data *pdata,
struct device *dev, atomic_t *ignore_irq)
{
/* Example for TT7XXX */
int rc = 0;
#ifdef TT7XXX_EXAMPLE
pt_debug(dev, DL_INFO,
"%s: Turn off defined pwr: VCC, VDDI\n", __func__);
/*
* Force part into RESET by holding XRES#(TP_XRES)
* while powering it up
*/
if (pdata->rst_gpio)
gpio_set_value(pdata->rst_gpio, 0);
/* Turn off VCC */
if (pdata->vcc_gpio) {
rc = gpio_request(pdata->vcc_gpio, NULL);
if (rc < 0) {
gpio_free(pdata->vcc_gpio);
rc = gpio_request(pdata->vcc_gpio, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VCC GPIO %d\n",
__func__, pdata->vcc_gpio);
}
rc = gpio_direction_output(pdata->vcc_gpio, 0);
if (rc)
pr_err("%s: setcfg for VCC GPIO %d failed\n",
__func__, pdata->vcc_gpio);
gpio_free(pdata->vcc_gpio);
}
/* Turn off VDDI [Digital Interface] (+1.8v) */
if (pdata->vddi_gpio) {
rc = gpio_request(pdata->vddi_gpio, NULL);
if (rc < 0) {
gpio_free(pdata->vddi_gpio);
rc = gpio_request(pdata->vddi_gpio, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VDDI GPIO %d\n",
__func__, pdata->vddi_gpio);
}
rc = gpio_direction_output(pdata->vddi_gpio, 0);
if (rc)
pr_err("%s: setcfg for VDDI GPIO %d failed\n",
__func__, pdata->vddi_gpio);
gpio_free(pdata->vddi_gpio);
usleep_range(10000, 12000);
}
#else
pt_debug(dev, DL_INFO, "%s: Turn off defined pwr\n", __func__);
#endif
#ifdef PT_PINCTRL_EN
pt_pinctrl_select_suspend(pdata, dev);
#endif
return rc;
}
/*******************************************************************************
* FUNCTION: pt_power
*
* SUMMARY: Wrapper function to resume/suspend power with function
* pt_wakeup()/pt_sleep().
*
* RETURN:
* 0 = success
* !0 = fail
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* on - flag to remsume/suspend power(0:resume; 1:suspend)
* *dev - pointer to Device structure
* *ignore_irq - pointer to atomic structure to allow the host ignoring false
* IRQ during power up/down
******************************************************************************/
int pt_power(struct pt_core_platform_data *pdata,
int on, struct device *dev, atomic_t *ignore_irq)
{
if (on)
return pt_wakeup(pdata, dev, ignore_irq);
return pt_sleep(pdata, dev, ignore_irq);
}
/*******************************************************************************
* FUNCTION: pt_irq_stat
*
* SUMMARY: Obtain the level state of IRQ gpio.
*
* RETURN:
* level state of IRQ gpio
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
******************************************************************************/
int pt_irq_stat(struct pt_core_platform_data *pdata,
struct device *dev)
{
return gpio_get_value(pdata->irq_gpio);
}
#ifdef PT_DETECT_HW
/*******************************************************************************
* FUNCTION: pt_detect
*
* SUMMARY: Detect the I2C device by reading one byte(FW sentiel) after the
* reset operation.
*
* RETURN:
* 0 - detected
* !0 - undetected
*
* PARAMETERS:
* *pdata - pointer to the platform data structure
* *dev - pointer to Device structure
* read - pointer to the function to perform a read operation
******************************************************************************/
int pt_detect(struct pt_core_platform_data *pdata,
struct device *dev, pt_platform_read read)
{
int retry = 3;
int rc;
char buf[1];
while (retry--) {
/* Perform reset, wait for 100 ms and perform read */
pt_debug(dev, DL_WARN, "%s: Performing a reset\n",
__func__);
pdata->xres(pdata, dev);
msleep(100);
rc = read(dev, buf, 1);
if (!rc)
return 0;
pt_debug(dev, DL_ERROR, "%s: Read unsuccessful, try=%d\n",
__func__, 3 - retry);
}
return rc;
}
#endif
/*******************************************************************************
* FUNCTION: pt_setup_power
*
* SUMMARY: Turn on/turn off voltage regulator
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pdata - pointer to core platform data
* on - flag to decide power state,PT_MT_POWER_ON/PT_MT_POWER_OFF
* *dev - pointer to device
******************************************************************************/
int pt_setup_power(struct pt_core_platform_data *pdata, int on,
struct device *dev)
{
int en_vcc = pdata->vcc_gpio;
int en_vddi = pdata->vddi_gpio;
int en_avdd = pdata->avdd_gpio;
int en_avee = pdata->avee_gpio;
int rc = 0;
/*
* For TDDI parts, force part into RESET by holding DDI XRES
* while powering it up
*/
if (pdata->ddi_rst_gpio)
gpio_set_value(pdata->ddi_rst_gpio, 0);
/*
* Force part into RESET by holding XRES#(TP_XRES)
* while powering it up
*/
if (pdata->rst_gpio)
gpio_set_value(pdata->rst_gpio, 0);
if (on == PT_MT_POWER_ON) {
/*
* Enable GPIOs to turn on voltage regulators to pwr up DUT
* - TC device power up order: VDDI, VCC, AVDD, AVEE
* - TT device power up order: VDDI, VCC
* NOTE: VDDI must be stable for >10ms before XRES is released
*/
pt_debug(dev, DL_INFO,
"%s: Enable defined pwr: VDDI, VCC, AVDD, AVEE\n", __func__);
/* Turn on VDDI [Digital Interface] (+1.8v) */
if (pdata->vddi_gpio) {
rc = gpio_request(en_vddi, NULL);
if (rc < 0) {
gpio_free(en_vddi);
rc = gpio_request(en_vddi, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VDDI GPIO %d\n",
__func__, en_vddi);
}
rc = gpio_direction_output(en_vddi, 1);
if (rc)
pr_err("%s: setcfg for VDDI GPIO %d failed\n",
__func__, en_vddi);
gpio_free(en_vddi);
usleep_range(3000, 4000);
}
/* Turn on VCC */
if (pdata->vcc_gpio) {
rc = gpio_request(en_vcc, NULL);
if (rc < 0) {
gpio_free(en_vcc);
rc = gpio_request(en_vcc, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VCC GPIO %d\n",
__func__, en_vcc);
}
rc = gpio_direction_output(en_vcc, 1);
if (rc)
pr_err("%s: setcfg for VCC GPIO %d failed\n",
__func__, en_vcc);
gpio_free(en_vcc);
usleep_range(3000, 4000);
}
/* Turn on AVDD (+5.0v) */
if (pdata->avdd_gpio) {
rc = gpio_request(en_avdd, NULL);
if (rc < 0) {
gpio_free(en_avdd);
rc = gpio_request(en_avdd, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting AVDD GPIO %d\n",
__func__, en_avdd);
}
rc = gpio_direction_output(en_avdd, 1);
if (rc)
pr_err("%s: setcfg for AVDD GPIO %d failed\n",
__func__, en_avdd);
gpio_free(en_avdd);
usleep_range(3000, 4000);
}
/* Turn on AVEE (-5.0v) */
if (pdata->avee_gpio) {
rc = gpio_request(en_avee, NULL);
if (rc < 0) {
gpio_free(en_avee);
rc = gpio_request(en_avee, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting AVEE GPIO %d\n",
__func__, en_avee);
}
rc = gpio_direction_output(en_avee, 1);
if (rc)
pr_err("%s: setcfg for AVEE GPIO %d failed\n",
__func__, en_avee);
gpio_free(en_avee);
usleep_range(3000, 4000);
}
} else {
/*
* Disable GPIOs to turn off voltage regulators to pwr down
* TC device The power down order is: AVEE, AVDD, VDDI
* TT device The power down order is: VCC, VDDI
*
* Note:Turn off some of regulators may effect display
* parts for TDDI chip
*/
pt_debug(dev, DL_INFO,
"%s: Turn off defined pwr: VCC, AVEE, AVDD, VDDI\n", __func__);
/* Turn off VCC */
if (pdata->vcc_gpio) {
rc = gpio_request(en_vcc, NULL);
if (rc < 0) {
gpio_free(en_vcc);
rc = gpio_request(en_vcc, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VCC GPIO %d\n",
__func__, en_vcc);
}
rc = gpio_direction_output(en_vcc, 0);
if (rc)
pr_err("%s: setcfg for VCC GPIO %d failed\n",
__func__, en_vcc);
gpio_free(en_vcc);
}
/* Turn off AVEE (-5.0v) */
if (pdata->avee_gpio) {
rc = gpio_request(en_avee, NULL);
if (rc < 0) {
gpio_free(en_avee);
rc = gpio_request(en_avee, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting AVEE GPIO %d\n",
__func__, en_avee);
}
rc = gpio_direction_output(en_avee, 0);
if (rc)
pr_err("%s: setcfg for AVEE GPIO %d failed\n",
__func__, en_avee);
gpio_free(en_avee);
}
/* Turn off AVDD (+5.0v) */
if (pdata->avdd_gpio) {
rc = gpio_request(en_avdd, NULL);
if (rc < 0) {
gpio_free(en_avdd);
rc = gpio_request(en_avdd, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting AVDD GPIO %d\n",
__func__, en_avdd);
}
rc = gpio_direction_output(en_avdd, 0);
if (rc)
pr_err("%s: setcfg for AVDD GPIO %d failed\n",
__func__, en_avdd);
gpio_free(en_avdd);
}
/* Turn off VDDI [Digital Interface] (+1.8v) */
if (pdata->vddi_gpio) {
rc = gpio_request(en_vddi, NULL);
if (rc < 0) {
gpio_free(en_vddi);
rc = gpio_request(en_vddi, NULL);
}
if (rc < 0) {
pr_err("%s: Failed requesting VDDI GPIO %d\n",
__func__, en_vddi);
}
rc = gpio_direction_output(en_vddi, 0);
if (rc)
pr_err("%s: setcfg for VDDI GPIO %d failed\n",
__func__, en_vddi);
gpio_free(en_vddi);
usleep_range(10000, 12000);
}
}
/* Force part out of RESET by releasing XRES#(TP_XRES) */
if (pdata->rst_gpio)
gpio_set_value(pdata->rst_gpio, 1);
/* Force part out of RESET by releasing DDI XRES */
if (pdata->ddi_rst_gpio)
gpio_set_value(pdata->ddi_rst_gpio, 1);
return rc;
}
/*******************************************************************************
* FUNCTION: pt_setup_irq
*
* SUMMARY: Configure the IRQ GPIO used by the TT DUT
*
* RETURN:
* 0 = success
* !0 = failure
*
* PARAMETERS:
* *pdata - pointer to core platform data
* on - flag to setup interrupt process work(PT_MT_IRQ_FREE/)
* *dev - pointer to device
******************************************************************************/
int pt_setup_irq(struct pt_core_platform_data *pdata, int on,
struct device *dev)
{
struct pt_core_data *cd = dev_get_drvdata(dev);
unsigned long irq_flags;
int rc = 0;
if (on == PT_MT_IRQ_REG) {
/*
* When TTDL has direct access to the GPIO the irq_stat function
* will be defined and the gpio_to_irq conversion must be
* performed. e.g. For CHROMEOS this is not the case, the irq is
* passed in directly.
*/
if (pdata->irq_stat) {
/* Initialize IRQ */
dev_vdbg(dev, "%s: Value Passed to gpio_to_irq =%d\n",
__func__, pdata->irq_gpio);
cd->irq = gpio_to_irq(pdata->irq_gpio);
dev_vdbg(dev,
"%s: Value Returned from gpio_to_irq =%d\n",
__func__, cd->irq);
}
if (cd->irq < 0)
return -EINVAL;
cd->irq_enabled = true;
pt_debug(dev, DL_INFO, "%s: initialize threaded irq=%d\n",
__func__, cd->irq);
if (pdata->level_irq_udelay > 0)
/* use level triggered interrupts */
irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
else
/* use edge triggered interrupts */
irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
rc = request_threaded_irq(cd->irq, NULL, pt_irq,
irq_flags, dev_name(dev), cd);
if (rc < 0)
pt_debug(dev, DL_ERROR,
"%s: Error, could not request irq\n", __func__);
} else {
disable_irq_nosync(cd->irq);
free_irq(cd->irq, cd);
}
return rc;
}