in touchscreen/edt-ft5x06.c [1075:1267]
static int edt_ft5x06_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
const struct edt_i2c_chip_data *chip_data;
struct edt_ft5x06_ts_data *tsdata;
u8 buf[2] = { 0xfc, 0x00 };
struct input_dev *input;
unsigned long irq_flags;
int error;
char fw_version[EDT_NAME_LEN];
dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
if (!tsdata) {
dev_err(&client->dev, "failed to allocate driver data.\n");
return -ENOMEM;
}
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");
return -EINVAL;
}
tsdata->max_support_points = chip_data->max_support_points;
tsdata->vcc = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(tsdata->vcc)) {
error = PTR_ERR(tsdata->vcc);
if (error != -EPROBE_DEFER)
dev_err(&client->dev,
"failed to request regulator: %d\n", error);
return error;
}
tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc");
if (IS_ERR(tsdata->iovcc)) {
error = PTR_ERR(tsdata->iovcc);
if (error != -EPROBE_DEFER)
dev_err(&client->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);
return error;
}
/* Delay enabling VCC for > 10us (T_ivd) after IOVCC */
usleep_range(10, 100);
error = regulator_enable(tsdata->vcc);
if (error < 0) {
dev_err(&client->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,
tsdata);
if (error)
return error;
tsdata->reset_gpio = devm_gpiod_get_optional(&client->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);
return error;
}
tsdata->wake_gpio = devm_gpiod_get_optional(&client->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);
return error;
}
/*
* Check which sleep modes we can support. Power-off requieres the
* reset-pin to ensure correct power-down/power-up behaviour. Start with
* the EDT_PMODE_POWEROFF test since this is the deepest possible sleep
* mode.
*/
if (tsdata->reset_gpio)
tsdata->suspend_mode = EDT_PMODE_POWEROFF;
else if (tsdata->wake_gpio)
tsdata->suspend_mode = EDT_PMODE_HIBERNATE;
else
tsdata->suspend_mode = EDT_PMODE_NOT_SUPPORTED;
if (tsdata->wake_gpio) {
usleep_range(5000, 6000);
gpiod_set_value_cansleep(tsdata->wake_gpio, 1);
}
if (tsdata->reset_gpio) {
usleep_range(5000, 6000);
gpiod_set_value_cansleep(tsdata->reset_gpio, 0);
msleep(300);
}
input = devm_input_allocate_device(&client->dev);
if (!input) {
dev_err(&client->dev, "failed to allocate input device.\n");
return -ENOMEM;
}
mutex_init(&tsdata->mutex);
tsdata->client = client;
tsdata->input = input;
tsdata->factory_mode = false;
error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
if (error) {
dev_err(&client->dev, "touchscreen probe failed\n");
return error;
}
/*
* Dummy read access. EP0700MLP1 returns bogus data on the first
* register read access and ignores writes.
*/
edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf);
edt_ft5x06_ts_set_regs(tsdata);
edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
edt_ft5x06_ts_get_parameters(tsdata);
dev_dbg(&client->dev,
"Model \"%s\", Rev. \"%s\", %dx%d sensors\n",
tsdata->name, fw_version, tsdata->num_x, tsdata->num_y);
input->name = tsdata->name;
input->id.bustype = BUS_I2C;
input->dev.parent = &client->dev;
input_set_abs_params(input, ABS_MT_POSITION_X,
0, tsdata->num_x * 64 - 1, 0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y,
0, tsdata->num_y * 64 - 1, 0, 0);
touchscreen_parse_properties(input, true, &tsdata->prop);
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");
return error;
}
i2c_set_clientdata(client, tsdata);
irq_flags = irq_get_trigger_type(client->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);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
return error;
}
error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
if (error)
return error;
error = input_register_device(input);
if (error)
return error;
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
dev_dbg(&client->dev,
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
client->irq,
tsdata->wake_gpio ? desc_to_gpio(tsdata->wake_gpio) : -1,
tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
return 0;
}