@@ -335,6 +335,8 @@ struct mxt_data {
struct regulator *reg_vdd;
struct regulator *reg_avdd;
char *fw_name;
+ char *cfg_name;
+ const char *pcfg_name;
/* Cached parameters from object table */
u16 T5_address;
@@ -377,6 +379,9 @@ struct mxt_data {
/* Indicates whether device is in suspend */
bool suspended;
+
+ /* Indicates whether device is updating configuration */
+ bool updating_config;
};
struct mxt_vb2_buffer {
@@ -2578,8 +2583,11 @@ static int mxt_initialize(struct mxt_data *data)
if (error)
return error;
- error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
- &client->dev, GFP_KERNEL, data,
+ error = request_firmware_nowait(THIS_MODULE, true,
+ data->cfg_name ?
+ data->cfg_name : MXT_CFG_NAME,
+ &client->dev,
+ GFP_KERNEL, data,
mxt_config_cb);
if (error) {
dev_err(&client->dev, "Failed to invoke firmware loader: %d\n",
@@ -3081,19 +3089,21 @@ static int mxt_configure_objects(struct mxt_data *data,
error = mxt_init_t7_power_cfg(data);
if (error) {
dev_err(dev, "Failed to initialize power cfg\n");
- return error;
+ goto err_free_object_table;
}
if (cfg) {
error = mxt_update_cfg(data, cfg);
- if (error)
+ if (error) {
dev_warn(dev, "Error %d updating config\n", error);
+ goto err_free_object_table;
+ }
}
if (data->multitouch) {
error = mxt_initialize_input_device(data);
if (error)
- return error;
+ goto err_free_object_table;
} else {
dev_warn(dev, "No touch object detected\n");
}
@@ -3101,6 +3111,10 @@ static int mxt_configure_objects(struct mxt_data *data,
mxt_debug_init(data);
return 0;
+
+err_free_object_table:
+ mxt_free_object_table(data);
+ return error;
}
/* Firmware Version is returned as Major.Minor.Build */
@@ -3392,6 +3406,55 @@ static ssize_t update_fw_store(struct device *dev,
return count;
}
+static ssize_t update_cfg_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mxt_data *data = dev_get_drvdata(dev);
+ const struct firmware *cfg;
+ int ret;
+
+ ret = mxt_update_file_name(dev, &data->cfg_name, buf, count);
+ if (ret)
+ return ret;
+
+ ret = request_firmware(&cfg, data->cfg_name, dev);
+ if (ret < 0) {
+ dev_err(dev, "Failure to request config file %s\n",
+ data->cfg_name);
+ ret = -ENOENT;
+ goto out;
+ }
+
+ data->updating_config = true;
+
+ mxt_free_input_device(data);
+
+ if (data->suspended) {
+ if (data->suspend_mode == MXT_SUSPEND_REGULATOR) {
+ enable_irq(data->irq);
+ mxt_regulator_enable(data);
+ } else if (data->suspend_mode == MXT_SUSPEND_DEEP_SLEEP) {
+ mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
+ mxt_acquire_irq(data);
+ }
+
+ data->suspended = false;
+ }
+
+ ret = mxt_configure_objects(data, cfg);
+ if (ret)
+ goto release;
+
+ ret = count;
+
+release:
+ release_firmware(cfg);
+out:
+ data->updating_config = false;
+ return ret;
+}
+
static DEVICE_ATTR_WO(update_fw);
static struct attribute *mxt_fw_attrs[] = {
@@ -3406,11 +3469,13 @@ static const struct attribute_group mxt_fw_attr_group = {
static DEVICE_ATTR_RO(fw_version);
static DEVICE_ATTR_RO(hw_version);
static DEVICE_ATTR(object, S_IRUGO, mxt_object_show, NULL);
+static DEVICE_ATTR_WO(update_cfg);
static struct attribute *mxt_attrs[] = {
&dev_attr_fw_version.attr,
&dev_attr_hw_version.attr,
&dev_attr_object.attr,
+ &dev_attr_update_cfg.attr,
NULL
};
@@ -3511,7 +3576,7 @@ static int mxt_stop(struct mxt_data *data)
{
int ret;
- if (data->suspended || data->in_bootloader)
+ if (data->suspended || data->in_bootloader || data->updating_config)
return 0;
switch (data->suspend_mode) {
@@ -3580,6 +3645,8 @@ static int mxt_parse_device_properties(struct mxt_data *data)
int n_keys;
int error;
+ device_property_read_string(dev, "atmel,cfg_name", &data->pcfg_name);
+
if (device_property_present(dev, keymap_property)) {
n_keys = device_property_count_u32(dev, keymap_property);
if (n_keys <= 0) {
@@ -3705,6 +3772,12 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
if (error)
return error;
+ if (data->pcfg_name)
+ mxt_update_file_name(&data->client->dev,
+ &data->cfg_name,
+ data->pcfg_name,
+ strlen(data->pcfg_name));
+
data->reset_gpio = devm_gpiod_get_optional(&client->dev,
"reset", GPIOD_OUT_LOW);
if (IS_ERR(data->reset_gpio)) {