input: atmel_mxt_ts: Support runtime selection of config data
Add support for dynamic configuration data update if the target can support more than one Atmel chip. Platform data contains an array of supported config data along with family ID, variant ID and firmware version. Driver searches for matching family ID, variant ID and firmware version, and uses the corresponding config data to program. Change-Id: I684da4bdef56a3445acab3bb8fe47dd5279bebe5 Signed-off-by: Jing Lin <jinglin@codeaurora.org>
This commit is contained in:
@@ -1554,9 +1554,20 @@ static void mxt_init_vkeys_8930(void)
|
||||
return;
|
||||
}
|
||||
|
||||
static struct mxt_config_info mxt_config_array[] = {
|
||||
{
|
||||
.config = mxt_config_data_8930,
|
||||
.config_length = ARRAY_SIZE(mxt_config_data_8930),
|
||||
.family_id = 0x81,
|
||||
.variant_id = 0x01,
|
||||
.version = 0x10,
|
||||
.build = 0xAA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mxt_platform_data mxt_platform_data_8930 = {
|
||||
.config = mxt_config_data_8930,
|
||||
.config_length = ARRAY_SIZE(mxt_config_data_8930),
|
||||
.config_array = mxt_config_array,
|
||||
.config_array_size = ARRAY_SIZE(mxt_config_array),
|
||||
.x_size = 1067,
|
||||
.y_size = 566,
|
||||
.irqflags = IRQF_TRIGGER_FALLING,
|
||||
|
||||
@@ -1397,8 +1397,8 @@ static struct i2c_board_info cyttsp_info[] __initdata = {
|
||||
},
|
||||
};
|
||||
|
||||
/* configuration data */
|
||||
static const u8 mxt_config_data[] = {
|
||||
/* configuration data for mxt1386 */
|
||||
static const u8 mxt1386_config_data[] = {
|
||||
/* T6 Object */
|
||||
0, 0, 0, 0, 0, 0,
|
||||
/* T38 Object */
|
||||
@@ -1472,9 +1472,20 @@ err_ldo_gpio_req:
|
||||
gpio_free(MXT_TS_LDO_EN_GPIO);
|
||||
}
|
||||
|
||||
static struct mxt_config_info mxt_config_array[] = {
|
||||
{
|
||||
.config = mxt1386_config_data,
|
||||
.config_length = ARRAY_SIZE(mxt1386_config_data),
|
||||
.family_id = 0xA0,
|
||||
.variant_id = 0x0,
|
||||
.version = 0x10,
|
||||
.build = 0xAA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct mxt_platform_data mxt_platform_data = {
|
||||
.config = mxt_config_data,
|
||||
.config_length = ARRAY_SIZE(mxt_config_data),
|
||||
.config_array = mxt_config_array,
|
||||
.config_array_size = ARRAY_SIZE(mxt_config_array),
|
||||
.x_size = 1365,
|
||||
.y_size = 767,
|
||||
.irqflags = IRQF_TRIGGER_FALLING,
|
||||
|
||||
@@ -292,6 +292,7 @@ struct mxt_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input_dev;
|
||||
const struct mxt_platform_data *pdata;
|
||||
const struct mxt_config_info *config_info;
|
||||
struct mxt_object *object_table;
|
||||
struct mxt_info info;
|
||||
struct mxt_finger finger[MXT_MAX_FINGER];
|
||||
@@ -312,6 +313,8 @@ struct mxt_data {
|
||||
u8 t9_min_reportid;
|
||||
u8 t15_max_reportid;
|
||||
u8 t15_min_reportid;
|
||||
u8 curr_cfg_version;
|
||||
int cfg_version_idx;
|
||||
};
|
||||
|
||||
static bool mxt_object_readable(unsigned int type)
|
||||
@@ -750,13 +753,13 @@ end:
|
||||
|
||||
static int mxt_check_reg_init(struct mxt_data *data)
|
||||
{
|
||||
const struct mxt_platform_data *pdata = data->pdata;
|
||||
const struct mxt_config_info *config_info = data->config_info;
|
||||
struct mxt_object *object;
|
||||
struct device *dev = &data->client->dev;
|
||||
int index = 0;
|
||||
int i, j, config_offset;
|
||||
|
||||
if (!pdata->config) {
|
||||
if (!config_info) {
|
||||
dev_dbg(dev, "No cfg data defined, skipping reg init\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -769,12 +772,12 @@ static int mxt_check_reg_init(struct mxt_data *data)
|
||||
|
||||
for (j = 0; j < object->size + 1; j++) {
|
||||
config_offset = index + j;
|
||||
if (config_offset > pdata->config_length) {
|
||||
if (config_offset > config_info->config_length) {
|
||||
dev_err(dev, "Not enough config data!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mxt_write_object(data, object->type, j,
|
||||
pdata->config[config_offset]);
|
||||
config_info->config[config_offset]);
|
||||
}
|
||||
index += object->size + 1;
|
||||
}
|
||||
@@ -846,6 +849,7 @@ static int mxt_get_object_table(struct mxt_data *data)
|
||||
u16 reg;
|
||||
u8 reportid = 0;
|
||||
u8 buf[MXT_OBJECT_SIZE];
|
||||
bool found_t38 = false;
|
||||
|
||||
for (i = 0; i < data->info.object_num; i++) {
|
||||
struct mxt_object *object = data->object_table + i;
|
||||
@@ -866,11 +870,94 @@ static int mxt_get_object_table(struct mxt_data *data)
|
||||
(object->instances + 1);
|
||||
object->max_reportid = reportid;
|
||||
}
|
||||
|
||||
/* Calculate index for config major version in config array.
|
||||
* Major version is the first byte in object T38.
|
||||
*/
|
||||
if (object->type == MXT_SPT_USERDATA_T38)
|
||||
found_t38 = true;
|
||||
if (!found_t38 && mxt_object_writable(object->type))
|
||||
data->cfg_version_idx += object->size + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mxt_search_config_array(struct mxt_data *data, bool version_match)
|
||||
{
|
||||
|
||||
const struct mxt_platform_data *pdata = data->pdata;
|
||||
const struct mxt_config_info *cfg_info;
|
||||
struct mxt_info *info = &data->info;
|
||||
int i;
|
||||
u8 cfg_version;
|
||||
|
||||
for (i = 0; i < pdata->config_array_size; i++) {
|
||||
|
||||
cfg_info = &pdata->config_array[i];
|
||||
|
||||
if (!cfg_info->config || !cfg_info->config_length)
|
||||
continue;
|
||||
|
||||
if (info->family_id == cfg_info->family_id &&
|
||||
info->variant_id == cfg_info->variant_id &&
|
||||
info->version == cfg_info->version &&
|
||||
info->build == cfg_info->build) {
|
||||
|
||||
cfg_version = cfg_info->config[data->cfg_version_idx];
|
||||
if (data->curr_cfg_version == cfg_version ||
|
||||
!version_match) {
|
||||
data->config_info = cfg_info;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&data->client->dev,
|
||||
"Config not found: F: %d, V: %d, FW: %d.%d.%d, CFG: %d\n",
|
||||
info->family_id, info->variant_id,
|
||||
info->version >> 4, info->version & 0xF, info->build,
|
||||
data->curr_cfg_version);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int mxt_get_config(struct mxt_data *data)
|
||||
{
|
||||
const struct mxt_platform_data *pdata = data->pdata;
|
||||
struct device *dev = &data->client->dev;
|
||||
struct mxt_object *object;
|
||||
int error;
|
||||
|
||||
if (!pdata->config_array || !pdata->config_array_size) {
|
||||
dev_dbg(dev, "No cfg data provided by platform data\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get current config version */
|
||||
object = mxt_get_object(data, MXT_SPT_USERDATA_T38);
|
||||
if (!object) {
|
||||
dev_err(dev, "Unable to obtain USERDATA object\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error = mxt_read_reg(data->client, object->start_address,
|
||||
&data->curr_cfg_version);
|
||||
if (error) {
|
||||
dev_err(dev, "Unable to read config version\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* It is possible that the config data on the controller is not
|
||||
* versioned and the version number returns 0. In this case,
|
||||
* find a match without the config version checking.
|
||||
*/
|
||||
error = mxt_search_config_array(data,
|
||||
data->curr_cfg_version != 0 ? true : false);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void mxt_reset_delay(struct mxt_data *data)
|
||||
{
|
||||
struct mxt_info *info = &data->info;
|
||||
@@ -919,6 +1006,11 @@ static int mxt_initialize(struct mxt_data *data)
|
||||
if (error)
|
||||
goto free_object_table;
|
||||
|
||||
/* Get config data from platform data */
|
||||
error = mxt_get_config(data);
|
||||
if (error)
|
||||
dev_dbg(&client->dev, "Config info not found.\n");
|
||||
|
||||
/* Check register init values */
|
||||
error = mxt_check_reg_init(data);
|
||||
if (error)
|
||||
|
||||
@@ -29,10 +29,20 @@
|
||||
/* MXT_TOUCH_KEYARRAY_T15 */
|
||||
#define MXT_KEYARRAY_MAX_KEYS 32
|
||||
|
||||
/* The platform data for the Atmel maXTouch touchscreen driver */
|
||||
struct mxt_platform_data {
|
||||
/* Config data for a given maXTouch controller with a specific firmware */
|
||||
struct mxt_config_info {
|
||||
const u8 *config;
|
||||
size_t config_length;
|
||||
u8 family_id;
|
||||
u8 variant_id;
|
||||
u8 version;
|
||||
u8 build;
|
||||
};
|
||||
|
||||
/* The platform data for the Atmel maXTouch touchscreen driver */
|
||||
struct mxt_platform_data {
|
||||
const struct mxt_config_info *config_array;
|
||||
size_t config_array_size;
|
||||
|
||||
unsigned int x_size;
|
||||
unsigned int y_size;
|
||||
|
||||
Reference in New Issue
Block a user