/*
|
* cyttsp5_test_device_access_api.c
|
* Parade TrueTouch(TM) Standard Product V5 Device Access API test module.
|
* For use with Parade touchscreen controllers.
|
* Supported parts include:
|
* CYTMA5XX
|
* CYTMA448
|
* CYTMA445A
|
* CYTT21XXX
|
* CYTT31XXX
|
*
|
* Copyright (C) 2015 Parade Technologies
|
* Copyright (C) 2012-2015 Cypress Semiconductor
|
*
|
* 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 <linux/module.h>
|
#include <linux/cyttsp5_device_access-api.h>
|
#include <asm/unaligned.h>
|
|
#define BUFFER_SIZE 256
|
|
#define COMMAND_GET_SYSTEM_INFO 2
|
#define COMMAND_SUSPEND_SCANNING 3
|
#define COMMAND_RESUME_SCANNING 4
|
#define COMMAND_GET_PARAMETER 5
|
#define COMMAND_SET_PARAMETER 6
|
|
#define PARAMETER_ACTIVE_DISTANCE_2 0x0B
|
|
struct tt_output_report {
|
__le16 reg_address;
|
__le16 length;
|
u8 report_id;
|
u8 reserved;
|
u8 command;
|
u8 parameters[0];
|
} __packed;
|
|
struct tt_input_report {
|
__le16 length;
|
u8 report_id;
|
u8 reserved;
|
u8 command;
|
u8 return_data[0];
|
} __packed;
|
|
static int prepare_tt_output_report(struct tt_output_report *out,
|
u16 length, u8 command)
|
{
|
put_unaligned_le16(0x04, &out->reg_address);
|
put_unaligned_le16(5 + length, &out->length);
|
|
out->report_id = 0x2f;
|
out->reserved = 0x00;
|
out->command = command;
|
|
return 7 + length;
|
}
|
|
static int check_and_parse_tt_input_report(struct tt_input_report *in,
|
u16 *length, u8 *command)
|
{
|
if (in->report_id != 0x1f)
|
return -EINVAL;
|
|
*length = get_unaligned_le16(&in->length);
|
*command = in->command & 0x7f;
|
|
return 0;
|
}
|
|
static int prepare_get_system_info_report(u8 *buf)
|
{
|
struct tt_output_report *out = (struct tt_output_report *)buf;
|
|
return prepare_tt_output_report(out, 0, COMMAND_GET_SYSTEM_INFO);
|
}
|
|
static int check_get_system_info_response(u8 *buf, u16 read_length)
|
{
|
struct tt_input_report *in = (struct tt_input_report *)buf;
|
u16 length = 0;
|
u8 command = 0;
|
|
if (read_length != 51)
|
return -EINVAL;
|
|
if (check_and_parse_tt_input_report(in, &length, &command)
|
|| command != COMMAND_GET_SYSTEM_INFO
|
|| length != 51)
|
return -EINVAL;
|
|
pr_info("PIP Major Version: %d\n", in->return_data[0]);
|
pr_info("PIP Minor Version: %d\n", in->return_data[1]);
|
pr_info("Touch Firmware Product Id: %d\n",
|
get_unaligned_le16(&in->return_data[2]));
|
pr_info("Touch Firmware Major Version: %d\n", in->return_data[4]);
|
pr_info("Touch Firmware Minor Version: %d\n", in->return_data[5]);
|
pr_info("Touch Firmware Internal Revision Control Number: %d\n",
|
get_unaligned_le32(&in->return_data[6]));
|
pr_info("Customer Specified Firmware/Configuration Version: %d\n",
|
get_unaligned_le16(&in->return_data[10]));
|
pr_info("Bootloader Major Version: %d\n", in->return_data[12]);
|
pr_info("Bootloader Minor Version: %d\n", in->return_data[13]);
|
pr_info("Family ID: 0x%02x\n", in->return_data[14]);
|
pr_info("Revision ID: 0x%02x\n", in->return_data[15]);
|
pr_info("Silicon ID: 0x%02x\n",
|
get_unaligned_le16(&in->return_data[16]));
|
pr_info("Parade Manufacturing ID[0]: 0x%02x\n", in->return_data[18]);
|
pr_info("Parade Manufacturing ID[1]: 0x%02x\n", in->return_data[19]);
|
pr_info("Parade Manufacturing ID[2]: 0x%02x\n", in->return_data[20]);
|
pr_info("Parade Manufacturing ID[3]: 0x%02x\n", in->return_data[21]);
|
pr_info("Parade Manufacturing ID[4]: 0x%02x\n", in->return_data[22]);
|
pr_info("Parade Manufacturing ID[5]: 0x%02x\n", in->return_data[23]);
|
pr_info("Parade Manufacturing ID[6]: 0x%02x\n", in->return_data[24]);
|
pr_info("Parade Manufacturing ID[7]: 0x%02x\n", in->return_data[25]);
|
pr_info("POST Result Code: 0x%02x\n",
|
get_unaligned_le16(&in->return_data[26]));
|
|
pr_info("Number of X Electrodes: %d\n", in->return_data[28]);
|
pr_info("Number of Y Electrodes: %d\n", in->return_data[29]);
|
pr_info("Panel X Axis Length: %d\n",
|
get_unaligned_le16(&in->return_data[30]));
|
pr_info("Panel Y Axis Length: %d\n",
|
get_unaligned_le16(&in->return_data[32]));
|
pr_info("Panel X Axis Resolution: %d\n",
|
get_unaligned_le16(&in->return_data[34]));
|
pr_info("Panel Y Axis Resolution: %d\n",
|
get_unaligned_le16(&in->return_data[36]));
|
pr_info("Panel Pressure Resolution: %d\n",
|
get_unaligned_le16(&in->return_data[38]));
|
pr_info("X_ORG: %d\n", in->return_data[40]);
|
pr_info("Y_ORG: %d\n", in->return_data[41]);
|
pr_info("Panel ID: %d\n", in->return_data[42]);
|
pr_info("Buttons: 0x%02x\n", in->return_data[43]);
|
pr_info("BAL SELF MC: 0x%02x\n", in->return_data[44]);
|
pr_info("Max Number of Touch Records per Refresh Cycle: %d\n",
|
in->return_data[45]);
|
|
return 0;
|
}
|
|
static int prepare_get_parameter_report(u8 *buf, u8 parameter_id)
|
{
|
struct tt_output_report *out = (struct tt_output_report *)buf;
|
|
out->parameters[0] = parameter_id;
|
|
return prepare_tt_output_report(out, 1, COMMAND_GET_PARAMETER);
|
}
|
|
static int check_get_parameter_response(u8 *buf, u16 read_length,
|
u32 *parameter_value)
|
{
|
struct tt_input_report *in = (struct tt_input_report *)buf;
|
u16 length = 0;
|
u8 command = 0;
|
u32 param_value = 0;
|
u8 param_id;
|
u8 param_size = 0;
|
|
if (read_length != 8 && read_length != 9 && read_length != 11)
|
return -EINVAL;
|
|
if (check_and_parse_tt_input_report(in, &length, &command)
|
|| command != COMMAND_GET_PARAMETER
|
|| (length != 8 && length != 9 && length != 11))
|
return -EINVAL;
|
|
param_id = in->return_data[0];
|
|
param_size = in->return_data[1];
|
|
if (param_size == 1)
|
param_value = in->return_data[2];
|
else if (param_size == 2)
|
param_value = get_unaligned_le16(&in->return_data[2]);
|
else if (param_size == 4)
|
param_value = get_unaligned_le32(&in->return_data[2]);
|
else
|
return -EINVAL;
|
|
pr_info("%s: Parameter ID: 0x%02x Value: 0x%02x\n",
|
__func__, param_id, param_value);
|
|
if (parameter_value)
|
*parameter_value = param_value;
|
|
return 0;
|
}
|
|
static int prepare_set_parameter_report(u8 *buf, u8 parameter_id,
|
u8 parameter_size, u32 parameter_value)
|
{
|
struct tt_output_report *out = (struct tt_output_report *)buf;
|
|
out->parameters[0] = parameter_id;
|
out->parameters[1] = parameter_size;
|
|
if (parameter_size == 1)
|
out->parameters[2] = (u8)parameter_value;
|
else if (parameter_size == 2)
|
put_unaligned_le16(parameter_value, &out->parameters[2]);
|
else if (parameter_size == 4)
|
put_unaligned_le32(parameter_value, &out->parameters[2]);
|
else
|
return -EINVAL;
|
|
return prepare_tt_output_report(out, 2 + parameter_size,
|
COMMAND_SET_PARAMETER);
|
}
|
|
static int check_set_parameter_response(u8 *buf, u16 read_length)
|
{
|
struct tt_input_report *in = (struct tt_input_report *)buf;
|
u16 length = 0;
|
u8 command = 0;
|
u8 param_id;
|
u8 param_size = 0;
|
|
if (read_length != 7)
|
return -EINVAL;
|
|
if (check_and_parse_tt_input_report(in, &length, &command)
|
|| command != COMMAND_SET_PARAMETER
|
|| length != 7)
|
return -EINVAL;
|
|
param_id = in->return_data[0];
|
param_size = in->return_data[1];
|
|
pr_info("%s: Parameter ID: 0x%02x Size: 0x%02x\n",
|
__func__, param_id, param_size);
|
|
return 0;
|
}
|
|
static int prepare_suspend_scanning_report(u8 *buf)
|
{
|
struct tt_output_report *out = (struct tt_output_report *)buf;
|
|
return prepare_tt_output_report(out, 0, COMMAND_SUSPEND_SCANNING);
|
}
|
|
static int check_suspend_scanning_response(u8 *buf, u16 read_length)
|
{
|
struct tt_input_report *in = (struct tt_input_report *)buf;
|
u16 length = 0;
|
u8 command = 0;
|
|
if (read_length != 5)
|
return -EINVAL;
|
|
if (check_and_parse_tt_input_report(in, &length, &command)
|
|| command != COMMAND_SUSPEND_SCANNING
|
|| length != 5)
|
return -EINVAL;
|
|
return 0;
|
}
|
|
static int prepare_resume_scanning_report(u8 *buf)
|
{
|
struct tt_output_report *out = (struct tt_output_report *)buf;
|
|
return prepare_tt_output_report(out, 0, COMMAND_RESUME_SCANNING);
|
}
|
|
static int check_resume_scanning_response(u8 *buf, u16 read_length)
|
{
|
struct tt_input_report *in = (struct tt_input_report *)buf;
|
u16 length = 0;
|
u8 command = 0;
|
|
if (read_length != 5)
|
return -EINVAL;
|
|
if (check_and_parse_tt_input_report(in, &length, &command)
|
|| command != COMMAND_RESUME_SCANNING
|
|| length != 5)
|
return -EINVAL;
|
|
return 0;
|
}
|
|
void cyttsp5_user_command_async_cont(const char *core_name,
|
u16 read_len, u8 *read_buf, u16 write_len, u8 *write_buf,
|
u16 actual_read_length, int rc)
|
{
|
if (rc) {
|
pr_err("%s: suspend scan fails\n", __func__);
|
goto exit;
|
}
|
|
rc = check_suspend_scanning_response(read_buf, actual_read_length);
|
if (rc) {
|
pr_err("%s: check suspend scanning response fails\n", __func__);
|
goto exit;
|
}
|
|
pr_info("%s: suspend scanning succeeds\n", __func__);
|
exit:
|
return;
|
}
|
|
/* Read and write buffers */
|
static u8 write_buf[BUFFER_SIZE];
|
static u8 read_buf[BUFFER_SIZE];
|
|
static uint active_distance;
|
module_param(active_distance, uint, 0);
|
|
static int __init cyttsp5_test_device_access_api_init(void)
|
{
|
u32 initial_active_distance;
|
u16 actual_read_len;
|
int write_len;
|
int rc;
|
|
pr_info("%s: Enter\n", __func__);
|
|
/* CASE 1: Run get system information */
|
write_len = prepare_get_system_info_report(write_buf);
|
|
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
|
read_buf, write_len, write_buf,
|
&actual_read_len);
|
if (rc)
|
goto exit;
|
|
rc = check_get_system_info_response(read_buf, actual_read_len);
|
if (rc)
|
goto exit;
|
|
/* CASE 2: Run get parameter (Active distance) */
|
write_len = prepare_get_parameter_report(write_buf,
|
PARAMETER_ACTIVE_DISTANCE_2);
|
|
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
|
read_buf, write_len, write_buf,
|
&actual_read_len);
|
if (rc)
|
goto exit;
|
|
rc = check_get_parameter_response(read_buf, actual_read_len,
|
&initial_active_distance);
|
if (rc)
|
goto exit;
|
|
pr_info("%s: Initial Active Distance: %d\n",
|
__func__, initial_active_distance);
|
|
/* CASE 3: Run set parameter (Active distance) */
|
write_len = prepare_set_parameter_report(write_buf,
|
PARAMETER_ACTIVE_DISTANCE_2, 1,
|
active_distance);
|
|
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
|
read_buf, write_len, write_buf,
|
&actual_read_len);
|
if (rc)
|
goto exit;
|
|
rc = check_set_parameter_response(read_buf, actual_read_len);
|
if (rc)
|
goto exit;
|
|
pr_info("%s: Active Distance set to %d\n", __func__, active_distance);
|
|
/* CASE 4: Run get parameter (Active distance) */
|
write_len = prepare_get_parameter_report(write_buf,
|
PARAMETER_ACTIVE_DISTANCE_2);
|
|
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
|
read_buf, write_len, write_buf,
|
&actual_read_len);
|
if (rc)
|
goto exit;
|
|
rc = check_get_parameter_response(read_buf, actual_read_len,
|
&active_distance);
|
if (rc)
|
goto exit;
|
|
pr_info("%s: New Active Distance: %d\n", __func__, active_distance);
|
|
/* CASE 5: Run suspend scanning asynchronously */
|
write_len = prepare_suspend_scanning_report(write_buf);
|
|
preempt_disable();
|
rc = cyttsp5_device_access_user_command_async(NULL,
|
sizeof(read_buf), read_buf, write_len, write_buf,
|
cyttsp5_user_command_async_cont);
|
preempt_enable();
|
if (rc)
|
goto exit;
|
exit:
|
return rc;
|
}
|
module_init(cyttsp5_test_device_access_api_init);
|
|
static void __exit cyttsp5_test_device_access_api_exit(void)
|
{
|
u16 actual_read_len;
|
int write_len;
|
int rc;
|
|
/* CASE 6: Run resume scanning */
|
write_len = prepare_resume_scanning_report(write_buf);
|
|
rc = cyttsp5_device_access_user_command(NULL, sizeof(read_buf),
|
read_buf, write_len, write_buf,
|
&actual_read_len);
|
if (rc)
|
goto exit;
|
|
rc = check_resume_scanning_response(read_buf, actual_read_len);
|
if (rc)
|
goto exit;
|
|
pr_info("%s: resume scanning succeeds\n", __func__);
|
exit:
|
return;
|
}
|
module_exit(cyttsp5_test_device_access_api_exit);
|
|
MODULE_LICENSE("GPL");
|
MODULE_DESCRIPTION("Parade TrueTouch(R) Standard Product Device Access Driver API Tester");
|
MODULE_AUTHOR("Parade Technologies <ttdrivers@paradetech.com>");
|