Some FocalTech controllers handled by this driver, such as the FT8722 TDDI, are connected over SPI. Prepare for an SPI transport by moving everything that depends on the i2c_client into a small I2C probe.
The only visible change for the I2C devices is that the interrupt is now requested with the device name (e.g. "1-0038") instead of the I2C client name, as the core no longer has access to the latter. Signed-off-by: Luka Panio <[email protected]> --- drivers/input/touchscreen/edt-ft5x06.c | 276 +++++++++++++------------ drivers/input/touchscreen/edt-ft5x06.h | 30 +++ 2 files changed, 179 insertions(+), 127 deletions(-) create mode 100644 drivers/input/touchscreen/edt-ft5x06.h diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index e69d64c3db2d..543cc62088c7 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -34,6 +34,8 @@ #include <linux/unaligned.h> +#include "edt-ft5x06.h" + #define WORK_REGISTER_THRESHOLD 0x00 #define WORK_REGISTER_REPORT_RATE 0x08 #define WORK_REGISTER_GAIN 0x30 @@ -106,7 +108,9 @@ struct edt_reg_addr { }; struct edt_ft5x06_ts_data { - struct i2c_client *client; + struct device *dev; + int irq; + struct dentry *debugfs; struct input_dev *input; struct touchscreen_properties prop; u16 num_x; @@ -148,15 +152,6 @@ struct edt_ft5x06_ts_data { unsigned int header_errors; }; -struct edt_i2c_chip_data { - int max_support_points; -}; - -static const struct regmap_config edt_ft5x06_i2c_regmap_config = { - .reg_bits = 8, - .val_bits = 8, -}; - static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, u8 *buf, int buflen) { @@ -168,7 +163,7 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, if (crc != buf[buflen - 1]) { tsdata->crc_errors++; - dev_err_ratelimited(&tsdata->client->dev, + dev_err_ratelimited(tsdata->dev, "crc error: 0x%02x expected, got 0x%02x\n", crc, buf[buflen - 1]); return false; @@ -182,7 +177,7 @@ static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size, { struct device *dev = context; struct i2c_client *i2c = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); struct i2c_msg xfer[2]; bool reg_read = false; u8 addr; @@ -258,7 +253,7 @@ static int edt_M06_i2c_write(void *context, const void *data, size_t count) { struct device *dev = context; struct i2c_client *i2c = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); u8 addr, val; u8 wbuf[4]; struct i2c_msg xfer; @@ -298,7 +293,7 @@ static const struct regmap_config edt_M06_i2c_regmap_config = { static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) { struct edt_ft5x06_ts_data *tsdata = dev_id; - struct device *dev = &tsdata->client->dev; + struct device *dev = tsdata->dev; u8 rdbuf[63]; int i, type, x, y, id; int error; @@ -376,8 +371,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, struct device_attribute *dattr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); struct edt_ft5x06_attribute *attr = container_of(dattr, struct edt_ft5x06_attribute, dattr); u8 *field = (u8 *)tsdata + attr->field_offset; @@ -412,7 +406,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, if (addr != NO_REGISTER) { error = regmap_read(tsdata->regmap, addr, &val); if (error) { - dev_err(&tsdata->client->dev, + dev_err(tsdata->dev, "Failed to fetch attribute %s, error %d\n", dattr->attr.name, error); return error; @@ -422,7 +416,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, } if (val != *field) { - dev_warn(&tsdata->client->dev, + dev_warn(tsdata->dev, "%s: read (%d) and stored value (%d) differ\n", dattr->attr.name, val, *field); *field = val; @@ -435,8 +429,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, struct device_attribute *dattr, const char *buf, size_t count) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); struct edt_ft5x06_attribute *attr = container_of(dattr, struct edt_ft5x06_attribute, dattr); u8 *field = (u8 *)tsdata + attr->field_offset; @@ -478,7 +471,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, if (addr != NO_REGISTER) { error = regmap_write(tsdata->regmap, addr, val); if (error) { - dev_err(&tsdata->client->dev, + dev_err(tsdata->dev, "Failed to update attribute %s, error: %d\n", dattr->attr.name, error); return error; @@ -511,8 +504,7 @@ static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE, static ssize_t model_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); return sysfs_emit(buf, "%s\n", tsdata->name); } @@ -522,8 +514,7 @@ static DEVICE_ATTR_RO(model); static ssize_t fw_version_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); return sysfs_emit(buf, "%s\n", tsdata->fw_version); } @@ -534,8 +525,7 @@ static DEVICE_ATTR_RO(fw_version); static ssize_t header_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); return sysfs_emit(buf, "%d\n", tsdata->header_errors); } @@ -546,8 +536,7 @@ static DEVICE_ATTR_RO(header_errors); static ssize_t crc_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); return sysfs_emit(buf, "%d\n", tsdata->crc_errors); } @@ -567,7 +556,16 @@ static struct attribute *edt_ft5x06_attrs[] = { &dev_attr_crc_errors.attr, NULL }; -ATTRIBUTE_GROUPS(edt_ft5x06); + +static const struct attribute_group edt_ft5x06_group = { + .attrs = edt_ft5x06_attrs, +}; + +const struct attribute_group *edt_ft5x06_groups[] = { + &edt_ft5x06_group, + NULL +}; +EXPORT_SYMBOL_NS_GPL(edt_ft5x06_groups, "EDT_FT5X06"); static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) { @@ -590,18 +588,17 @@ static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) #ifdef CONFIG_DEBUG_FS static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) { - struct i2c_client *client = tsdata->client; int retries = EDT_SWITCH_MODE_RETRIES; unsigned int val; int error; if (tsdata->version != EDT_M06) { - dev_err(&client->dev, + dev_err(tsdata->dev, "No factory mode support for non-M06 devices\n"); return -EINVAL; } - disable_irq(client->irq); + disable_irq(tsdata->irq); if (!tsdata->raw_buffer) { tsdata->raw_bufsize = tsdata->num_x * tsdata->num_y * @@ -616,7 +613,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) /* mode register is 0x3c when in the work mode */ error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03); if (error) { - dev_err(&client->dev, + dev_err(tsdata->dev, "failed to switch to factory mode, error %d\n", error); goto err_out; } @@ -632,7 +629,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) } while (--retries > 0); if (retries == 0) { - dev_err(&client->dev, "not in factory mode after %dms.\n", + dev_err(tsdata->dev, "not in factory mode after %dms.\n", EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); error = -EIO; goto err_out; @@ -644,14 +641,13 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) kfree(tsdata->raw_buffer); tsdata->raw_buffer = NULL; tsdata->factory_mode = false; - enable_irq(client->irq); + enable_irq(tsdata->irq); return error; } static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) { - struct i2c_client *client = tsdata->client; int retries = EDT_SWITCH_MODE_RETRIES; unsigned int val; int error; @@ -659,7 +655,7 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) /* mode register is 0x01 when in the factory mode */ error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1); if (error) { - dev_err(&client->dev, + dev_err(tsdata->dev, "failed to switch to work mode, error: %d\n", error); return error; } @@ -675,7 +671,7 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) } while (--retries > 0); if (retries == 0) { - dev_err(&client->dev, "not in work mode after %dms.\n", + dev_err(tsdata->dev, "not in work mode after %dms.\n", EDT_SWITCH_MODE_RETRIES * EDT_SWITCH_MODE_DELAY); tsdata->factory_mode = true; return -EIO; @@ -685,7 +681,7 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) tsdata->raw_buffer = NULL; edt_ft5x06_restore_reg_parameters(tsdata); - enable_irq(client->irq); + enable_irq(tsdata->irq); return 0; } @@ -723,7 +719,6 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, loff_t *off) { struct edt_ft5x06_ts_data *tsdata = file->private_data; - struct i2c_client *client = tsdata->client; int retries = EDT_RAW_DATA_RETRIES; unsigned int val; int i, error; @@ -741,7 +736,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, error = regmap_write(tsdata->regmap, 0x08, 0x01); if (error) { - dev_err(&client->dev, + dev_err(tsdata->dev, "failed to write 0x08 register, error %d\n", error); return error; } @@ -750,7 +745,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100); error = regmap_read(tsdata->regmap, 0x08, &val); if (error) { - dev_err(&client->dev, + dev_err(tsdata->dev, "failed to read 0x08 register, error %d\n", error); return error; @@ -761,7 +756,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, } while (--retries > 0); if (retries == 0) { - dev_err(&client->dev, + dev_err(tsdata->dev, "timed out waiting for register to settle\n"); return -ETIMEDOUT; } @@ -793,7 +788,10 @@ static const struct file_operations debugfs_raw_data_fops = { static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata) { - struct dentry *debug_dir = tsdata->client->debugfs; + struct dentry *debug_dir = tsdata->debugfs; + + if (!debug_dir) + return; debugfs_create_u16("num_x", S_IRUSR, debug_dir, &tsdata->num_x); debugfs_create_u16("num_y", S_IRUSR, debug_dir, &tsdata->num_y); @@ -829,9 +827,9 @@ static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata) #endif /* CONFIG_DEBUGFS */ -static int edt_ft5x06_ts_identify(struct i2c_client *client, - struct edt_ft5x06_ts_data *tsdata) +static int edt_ft5x06_ts_identify(struct edt_ft5x06_ts_data *tsdata) { + struct i2c_client *client; u8 rdbuf[EDT_NAME_LEN]; char *p; int error; @@ -854,6 +852,11 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, if (!strncasecmp(rdbuf + 1, "EP0", 3)) { tsdata->version = EDT_M06; + /* M06 uses its own register protocol, only over I2C */ + client = i2c_verify_client(tsdata->dev); + if (!client) + return -ENODEV; + /* remove last '$' end marker */ rdbuf[EDT_NAME_LEN - 1] = '\0'; if (rdbuf[EDT_NAME_LEN - 2] == '$') @@ -870,7 +873,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, tsdata->regmap = regmap_init_i2c(client, &edt_M06_i2c_regmap_config); if (IS_ERR(tsdata->regmap)) { - dev_err(&client->dev, "regmap allocation failed\n"); + dev_err(tsdata->dev, "regmap allocation failed\n"); return PTR_ERR(tsdata->regmap); } } else if (!strncasecmp(rdbuf, "EP0", 3)) { @@ -1113,10 +1116,10 @@ static void edt_ft5x06_disable_regulators(void *arg) regulator_disable(data->iovcc); } -static int edt_ft5x06_ts_probe(struct i2c_client *client) +int edt_ft5x06_probe(struct device *dev, struct regmap *regmap, int irq, + const struct edt_ft5x06_chip_data *chip_data, u16 bustype, + struct dentry *debugfs) { - const struct i2c_device_id *id = i2c_client_get_device_id(client); - const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; unsigned int val; struct input_dev *input; @@ -1124,57 +1127,50 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) int error; u32 report_rate; - dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); - - tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL); + tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); if (!tsdata) { - dev_err(&client->dev, "failed to allocate driver data.\n"); + regmap_exit(regmap); return -ENOMEM; } - tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config); - if (IS_ERR(tsdata->regmap)) { - dev_err(&client->dev, "regmap allocation failed\n"); - return PTR_ERR(tsdata->regmap); - } + tsdata->dev = dev; + tsdata->irq = irq; + tsdata->debugfs = debugfs; + tsdata->regmap = regmap; /* - * We are not using devm_regmap_init_i2c() and instead install a - * custom action because we may replace regmap with M06-specific one - * and we need to make sure that it will not be released too early. + * The bus driver hands over a regmap that is not device managed + * because we may replace it with the M06-specific one and we need to + * make sure that it will not be released too early. */ - error = devm_add_action_or_reset(&client->dev, edt_ft5x06_exit_regmap, - tsdata); + error = devm_add_action_or_reset(dev, edt_ft5x06_exit_regmap, tsdata); if (error) return error; - chip_data = device_get_match_data(&client->dev); - if (!chip_data) - chip_data = (const struct edt_i2c_chip_data *)id->driver_data; if (!chip_data || !chip_data->max_support_points) { - dev_err(&client->dev, "invalid or missing chip data\n"); + dev_err(dev, "invalid or missing chip data\n"); return -EINVAL; } tsdata->max_support_points = chip_data->max_support_points; - tsdata->vcc = devm_regulator_get(&client->dev, "vcc"); + tsdata->vcc = devm_regulator_get(dev, "vcc"); if (IS_ERR(tsdata->vcc)) - return dev_err_probe(&client->dev, PTR_ERR(tsdata->vcc), + return dev_err_probe(dev, PTR_ERR(tsdata->vcc), "failed to request regulator\n"); - tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc"); + tsdata->iovcc = devm_regulator_get(dev, "iovcc"); if (IS_ERR(tsdata->iovcc)) { error = PTR_ERR(tsdata->iovcc); if (error != -EPROBE_DEFER) - dev_err(&client->dev, + dev_err(dev, "failed to request iovcc regulator: %d\n", error); return error; } error = regulator_enable(tsdata->iovcc); if (error < 0) { - dev_err(&client->dev, "failed to enable iovcc: %d\n", error); + dev_err(dev, "failed to enable iovcc: %d\n", error); return error; } @@ -1183,32 +1179,30 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) error = regulator_enable(tsdata->vcc); if (error < 0) { - dev_err(&client->dev, "failed to enable vcc: %d\n", error); + dev_err(dev, "failed to enable vcc: %d\n", error); regulator_disable(tsdata->iovcc); return error; } - error = devm_add_action_or_reset(&client->dev, - edt_ft5x06_disable_regulators, + error = devm_add_action_or_reset(dev, edt_ft5x06_disable_regulators, tsdata); if (error) return error; - tsdata->reset_gpio = devm_gpiod_get_optional(&client->dev, - "reset", GPIOD_OUT_HIGH); + tsdata->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); if (IS_ERR(tsdata->reset_gpio)) { error = PTR_ERR(tsdata->reset_gpio); - dev_err(&client->dev, - "Failed to request GPIO reset pin, error %d\n", error); + dev_err(dev, "Failed to request GPIO reset pin, error %d\n", + error); return error; } - tsdata->wake_gpio = devm_gpiod_get_optional(&client->dev, - "wake", GPIOD_OUT_LOW); + tsdata->wake_gpio = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_LOW); if (IS_ERR(tsdata->wake_gpio)) { error = PTR_ERR(tsdata->wake_gpio); - dev_err(&client->dev, - "Failed to request GPIO wake pin, error %d\n", error); + dev_err(dev, "Failed to request GPIO wake pin, error %d\n", + error); return error; } @@ -1237,21 +1231,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) msleep(300); } - input = devm_input_allocate_device(&client->dev); + input = devm_input_allocate_device(dev); if (!input) { - dev_err(&client->dev, "failed to allocate input device.\n"); + dev_err(dev, "failed to allocate input device.\n"); return -ENOMEM; } mutex_init(&tsdata->mutex); - tsdata->client = client; tsdata->input = input; tsdata->factory_mode = false; - i2c_set_clientdata(client, tsdata); + dev_set_drvdata(dev, tsdata); - error = edt_ft5x06_ts_identify(client, tsdata); + error = edt_ft5x06_ts_identify(tsdata); if (error) { - dev_err(&client->dev, "touchscreen probe failed\n"); + dev_err(dev, "touchscreen probe failed\n"); return error; } @@ -1263,19 +1256,18 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) edt_ft5x06_ts_set_tdata_parameters(tsdata); edt_ft5x06_ts_set_regs(tsdata); - edt_ft5x06_ts_get_defaults(&client->dev, tsdata); + edt_ft5x06_ts_get_defaults(dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); if (tsdata->reg_addr.reg_report_rate != NO_REGISTER && - !device_property_read_u32(&client->dev, - "report-rate-hz", &report_rate)) { + !device_property_read_u32(dev, "report-rate-hz", &report_rate)) { if (tsdata->version == EDT_M06) tsdata->report_rate = clamp_val(report_rate, 30, 140); else tsdata->report_rate = clamp_val(report_rate, 1, 255); if (report_rate != tsdata->report_rate) - dev_warn(&client->dev, + dev_warn(dev, "report-rate %dHz is unsupported, use %dHz\n", report_rate, tsdata->report_rate); @@ -1286,12 +1278,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) tsdata->report_rate); } - dev_dbg(&client->dev, - "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", + dev_dbg(dev, "Model \"%s\", Rev. \"%s\", %dx%d sensors\n", tsdata->name, tsdata->fw_version, tsdata->num_x, tsdata->num_y); input->name = tsdata->name; - input->id.bustype = BUS_I2C; + input->id.bustype = bustype; input_set_abs_params(input, ABS_MT_POSITION_X, 0, tsdata->num_x * 64 - 1, 0, 0); @@ -1303,20 +1294,19 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) error = input_mt_init_slots(input, tsdata->max_support_points, INPUT_MT_DIRECT); if (error) { - dev_err(&client->dev, "Unable to init MT slots.\n"); + dev_err(dev, "Unable to init MT slots.\n"); return error; } - irq_flags = irq_get_trigger_type(client->irq); + irq_flags = irq_get_trigger_type(irq); if (irq_flags == IRQF_TRIGGER_NONE) irq_flags = IRQF_TRIGGER_FALLING; irq_flags |= IRQF_ONESHOT; - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, edt_ft5x06_ts_isr, irq_flags, - client->name, tsdata); + error = devm_request_threaded_irq(dev, irq, NULL, edt_ft5x06_ts_isr, + irq_flags, dev_name(dev), tsdata); if (error) { - dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + dev_err(dev, "Unable to request touchscreen IRQ.\n"); return error; } @@ -1326,26 +1316,27 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) edt_ft5x06_ts_prepare_debugfs(tsdata); - dev_dbg(&client->dev, + dev_dbg(dev, "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n", - client->irq, + irq, tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1, tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1); return 0; } +EXPORT_SYMBOL_NS_GPL(edt_ft5x06_probe, "EDT_FT5X06"); -static void edt_ft5x06_ts_remove(struct i2c_client *client) +void edt_ft5x06_remove(struct device *dev) { - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); edt_ft5x06_ts_teardown_debugfs(tsdata); } +EXPORT_SYMBOL_NS_GPL(edt_ft5x06_remove, "EDT_FT5X06"); static int edt_ft5x06_ts_suspend(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); struct gpio_desc *reset_gpio = tsdata->reset_gpio; int ret; @@ -1370,7 +1361,7 @@ static int edt_ft5x06_ts_suspend(struct device *dev) * settings. Disable the irq to avoid adjusting each host till the * device is back in a full functional state. */ - disable_irq(tsdata->client->irq); + disable_irq(tsdata->irq); gpiod_set_value_cansleep(reset_gpio, 1); usleep_range(1000, 2000); @@ -1387,8 +1378,7 @@ static int edt_ft5x06_ts_suspend(struct device *dev) static int edt_ft5x06_ts_resume(struct device *dev) { - struct i2c_client *client = to_i2c_client(dev); - struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); + struct edt_ft5x06_ts_data *tsdata = dev_get_drvdata(dev); int ret = 0; if (device_may_wakeup(dev)) @@ -1432,7 +1422,7 @@ static int edt_ft5x06_ts_resume(struct device *dev) msleep(300); edt_ft5x06_restore_reg_parameters(tsdata); - enable_irq(tsdata->client->irq); + enable_irq(tsdata->irq); if (tsdata->factory_mode) ret = edt_ft5x06_factory_mode(tsdata); @@ -1447,38 +1437,38 @@ static int edt_ft5x06_ts_resume(struct device *dev) return ret; } -static DEFINE_SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops, - edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume); +EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS(edt_ft5x06_pm_ops, edt_ft5x06_ts_suspend, + edt_ft5x06_ts_resume, EDT_FT5X06); -static const struct edt_i2c_chip_data edt_ft5x06_data = { +static const struct edt_ft5x06_chip_data edt_ft5x06_data = { .max_support_points = 5, }; -static const struct edt_i2c_chip_data edt_ft3518_data = { +static const struct edt_ft5x06_chip_data edt_ft3518_data = { .max_support_points = 10, }; -static const struct edt_i2c_chip_data edt_ft5452_data = { +static const struct edt_ft5x06_chip_data edt_ft5452_data = { .max_support_points = 5, }; -static const struct edt_i2c_chip_data edt_ft5506_data = { +static const struct edt_ft5x06_chip_data edt_ft5506_data = { .max_support_points = 10, }; -static const struct edt_i2c_chip_data edt_ft6236_data = { +static const struct edt_ft5x06_chip_data edt_ft6236_data = { .max_support_points = 2, }; -static const struct edt_i2c_chip_data edt_ft8201_data = { +static const struct edt_ft5x06_chip_data edt_ft8201_data = { .max_support_points = 10, }; -static const struct edt_i2c_chip_data edt_ft8716_data = { +static const struct edt_ft5x06_chip_data edt_ft8716_data = { .max_support_points = 10, }; -static const struct edt_i2c_chip_data edt_ft8719_data = { +static const struct edt_ft5x06_chip_data edt_ft8719_data = { .max_support_points = 10, }; @@ -1515,17 +1505,49 @@ static const struct of_device_id edt_ft5x06_of_match[] = { }; MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); +static const struct regmap_config edt_ft5x06_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int edt_ft5x06_i2c_probe(struct i2c_client *client) +{ + const struct i2c_device_id *id = i2c_client_get_device_id(client); + const struct edt_ft5x06_chip_data *chip_data; + struct regmap *regmap; + + dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n"); + + chip_data = device_get_match_data(&client->dev); + if (!chip_data && id) + chip_data = (const struct edt_ft5x06_chip_data *)id->driver_data; + + regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config); + if (IS_ERR(regmap)) { + dev_err(&client->dev, "regmap allocation failed\n"); + return PTR_ERR(regmap); + } + + return edt_ft5x06_probe(&client->dev, regmap, client->irq, chip_data, + BUS_I2C, client->debugfs); +} + +static void edt_ft5x06_i2c_remove(struct i2c_client *client) +{ + edt_ft5x06_remove(&client->dev); +} + static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { .name = "edt_ft5x06", .dev_groups = edt_ft5x06_groups, .of_match_table = edt_ft5x06_of_match, - .pm = pm_sleep_ptr(&edt_ft5x06_ts_pm_ops), + .pm = pm_sleep_ptr(&edt_ft5x06_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = edt_ft5x06_ts_id, - .probe = edt_ft5x06_ts_probe, - .remove = edt_ft5x06_ts_remove, + .probe = edt_ft5x06_i2c_probe, + .remove = edt_ft5x06_i2c_remove, }; module_i2c_driver(edt_ft5x06_ts_driver); diff --git a/drivers/input/touchscreen/edt-ft5x06.h b/drivers/input/touchscreen/edt-ft5x06.h new file mode 100644 index 000000000000..deadc756cd74 --- /dev/null +++ b/drivers/input/touchscreen/edt-ft5x06.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Bus independent core of the EDT FT5x06 touchscreen driver + * + * Copyright (C) 2026 Luka Panio, <[email protected]> + */ +#ifndef _EDT_FT5X06_H +#define _EDT_FT5X06_H + +#include <linux/types.h> + +struct attribute_group; +struct dentry; +struct dev_pm_ops; +struct device; +struct regmap; + +struct edt_ft5x06_chip_data { + int max_support_points; +}; + +int edt_ft5x06_probe(struct device *dev, struct regmap *regmap, int irq, + const struct edt_ft5x06_chip_data *chip_data, u16 bustype, + struct dentry *debugfs); +void edt_ft5x06_remove(struct device *dev); + +extern const struct dev_pm_ops edt_ft5x06_pm_ops; +extern const struct attribute_group *edt_ft5x06_groups[]; + +#endif -- 2.55.0
