static int __maybe_unused gsl_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct gsl_ts_data *ts = i2c_get_clientdata(client); dev_warn(&client->dev, "%s: suspending device\n", __func__); disable_irq(client->irq); gsl_ts_reset_chip(client); usleep_range(10000, 20000); gsl_ts_power(client, true); if (device_may_wakeup(dev)) { ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); } ts->state = GSL_TS_SHUTDOWN; return 0; }
static int __maybe_unused gsl_ts_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct gsl_ts_data *ts = i2c_get_clientdata(client); dev_warn(&client->dev, "%s: resuming device\n", __func__); if (device_may_wakeup(dev) && ts->wake_irq_enabled) { disable_irq_wake(client->irq); } gsl_ts_power(client, false); gsl_ts_reset_chip(client); gsl_ts_startup_chip(client); enable_irq(client->irq); ts->state = GSL_TS_GREEN; return 0; }
static int __maybe_unused gsl_ts_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct gsl_ts_data *ts = i2c_get_clientdata(client); dev_warn(&client->dev, "%s: suspending device\n", __func__); disable_irq(client->irq); gsl_ts_reset_chip(client); usleep_range(10000, 20000); /* Do we need to do this ourselves? */ acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D3); if (device_may_wakeup(dev)) { ts->wake_irq_enabled = (enable_irq_wake(client->irq) == 0); } ts->state = GSL_TS_SHUTDOWN; return 0; }
static int __maybe_unused gsl_ts_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct gsl_ts_data *ts = i2c_get_clientdata(client); dev_warn(&client->dev, "%s: resuming device\n", __func__); if (device_may_wakeup(dev) && ts->wake_irq_enabled) { disable_irq_wake(client->irq); } /* Do we need to do this ourselves? */ acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D0); usleep_range(20000, 50000); gsl_ts_reset_chip(client); gsl_ts_startup_chip(client); enable_irq(client->irq); ts->state = GSL_TS_GREEN; return 0; }
static int gsl_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct gsl_ts_data *ts; const struct firmware *fw = NULL; unsigned long irqflags; int error; bool acpipower; dev_warn(&client->dev, "%s: got a device named %s at address 0x%x, IRQ %d, flags 0x%x\n", __func__, client->name, client->addr, client->irq, client->flags); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c check functionality error\n", __func__); error = -ENXIO; goto release; } if (client->irq <= 0) { dev_err(&client->dev, "%s: missing IRQ configuration\n", __func__); error = -ENODEV; goto release; } ts = devm_kzalloc(&client->dev, sizeof(struct gsl_ts_data), GFP_KERNEL); if (!ts) { error = -ENOMEM; goto release; } ts->client = client; i2c_set_clientdata(client, ts); if (gsl_fw_name != NULL) { strncpy(ts->fw_name, gsl_fw_name, sizeof(ts->fw_name)); } else { strncpy(ts->fw_name, GSL_FW_NAME_DEFAULT, sizeof(ts->fw_name)); } error = request_firmware(&fw, ts->fw_name, &ts->client->dev); if (error < 0) { dev_err(&client->dev, "%s: failed to load firmware: %d\n", __func__, error); goto release; } error = gsl_ts_init(ts, fw); if (error < 0) { dev_err(&client->dev, "%s: failed to initialize: %d\n", __func__, error); goto release; } ts->input = devm_input_allocate_device(&client->dev); if (!ts->input) { dev_err(&client->dev, "%s: failed to allocate input device\n", __func__); error = -ENOMEM; goto release; } ts->input->name = "Silead GSLx680 Touchscreen"; ts->input->id.bustype = BUS_I2C; ts->input->phys = "input/ts"; input_set_capability(ts->input, EV_ABS, ABS_X); input_set_capability(ts->input, EV_ABS, ABS_Y); input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, ts->jitter, ts->deadzone); input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, ts->jitter, ts->deadzone); input_mt_init_slots(ts->input, ts->multi_touches, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK); input_set_drvdata(ts->input, ts); error = input_register_device(ts->input); if (error) { dev_err(&client->dev, "%s: unable to register input device: %d\n", __func__, error); goto release; } /* Try to use ACPI power methods first */ acpipower = false; #ifdef CONFIG_ACPI if (ACPI_COMPANION(&client->dev)) { /* Wake the device up with a power on reset */ if (acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D3)) { dev_warn(&client->dev, "%s: failed to wake up device through ACPI: %d, using GPIO controls instead\n", __func__, error); } else { acpipower = true; } } #endif /* Not available, use GPIO settings from DSDT/DT instead */ if (!acpipower) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ts->gpio = devm_gpiod_get_index(&client->dev, GSL_PWR_GPIO, 0); #else ts->gpio = devm_gpiod_get_index(&client->dev, GSL_PWR_GPIO, 0, GPIOD_OUT_LOW); #endif if (IS_ERR(ts->gpio)) { dev_err(&client->dev, "%s: error obtaining power pin GPIO resource\n", __func__); error = PTR_ERR(ts->gpio); goto release; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) error = gpiod_direction_output(ts->gpio, 0); if (error < 0) { dev_err(&client->dev, "%s: error setting GPIO pin direction\n", __func__); goto release; } #endif } else { ts->gpio = NULL; } /* Enable power */ gsl_ts_power(client, false); /* Execute the controller startup sequence */ error = gsl_ts_reset_chip(client); if (error < 0) { dev_err(&client->dev, "%s: chip reset failed\n", __func__); goto release; } error = gsl_ts_write_fw(ts, fw); if (error < 0) { dev_err(&client->dev, "%s: firmware transfer failed\n", __func__); goto release; } error = gsl_ts_startup_chip(client); if (error < 0) { dev_err(&client->dev, "%s: chip startup failed\n", __func__); goto release; } /* * Systems using device tree should set up interrupt via DTS, * the rest will use the default falling edge interrupts. */ irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; /* Set up interrupt handler - do we still need to account for shared interrupts? */ error = devm_request_threaded_irq( &client->dev, client->irq, NULL, gsl_ts_irq, irqflags | IRQF_ONESHOT, client->name, ts ); if (error) { dev_err(&client->dev, "%s: failed to register interrupt\n", __func__); goto release; } /* * Systems using device tree should set up wakeup via DTS, * the rest will configure device as wakeup source by default. */ if (!client->dev.of_node) { device_init_wakeup(&client->dev, true); } ts->state = GSL_TS_GREEN; release: if (fw) { release_firmware(fw); } if (error < 0) { return error; } return 0; }
static irqreturn_t gsl_ts_irq(int irq, void *arg) { int rc; struct gsl_ts_data *ts = (struct gsl_ts_data *) arg; struct i2c_client *client = ts->client; struct device *dev = &client->dev; u8 status[4] = { 0, 0, 0, 0 }; u8 event[GSL_PACKET_SIZE]; dev_dbg(&client->dev, "%s: IRQ received\n", __func__); if (ts->state == GSL_TS_SHUTDOWN) { dev_warn(&client->dev, "%s: device supended, not handling interrupt\n", __func__); return IRQ_HANDLED; } rc = gsl_ts_read(client, GSL_STATUS_REG, status, sizeof(status)); if (rc < 0) { dev_err(dev, "%s: error reading chip status\n", __func__); return IRQ_HANDLED; } if (status[0] == GSL_STATUS_FW) { /* TODO: Send firmware here instead of during init */ dev_info(dev, "%s: device waiting for firmware\n", __func__); } else if (status[0] == GSL_STATUS_TOUCH) { dev_vdbg(dev, "%s: touch event\n", __func__); rc = gsl_ts_read(client, GSL_DATA_REG, event, sizeof(event)); if (rc < 0) { dev_err(dev, "%s: touch data read failed\n", __func__); return IRQ_HANDLED; } if (event[0] == 0xff) { dev_warn(dev, "%s: ignoring invalid touch record (0xff)\n", __func__); return IRQ_HANDLED; } rc = gsl_ts_read(client, GSL_TOUCH_STATUS_REG, status, sizeof(status)); if (rc < 0) { dev_err(dev, "%s: reading touch status register failed\n", __func__); return IRQ_HANDLED; } if ((status[0] | status[1] | status[2] | status[3]) == 0) { gsl_ts_mt_event(ts, event); } else { dev_warn(dev, "%s: device seems to be stuck, resetting\n", __func__); rc = gsl_ts_reset_chip(ts->client); if (rc < 0) { dev_err(dev, "%s: reset_chip failed\n", __func__); return IRQ_HANDLED; } rc = gsl_ts_startup_chip(ts->client); if (rc < 0) { dev_err(dev, "%s: startup_chip failed\n", __func__); return IRQ_HANDLED; } } } else { dev_warn(&client->dev, "%s: IRQ received, unknown status 0x%02x\n", __func__, status[0]); } return IRQ_HANDLED; }
static int gsl_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct gsl_ts_data *ts; const struct firmware *fw; unsigned long irqflags; int error; dev_warn(&client->dev, "%s: got a device named %s at address 0x%x, IRQ %d, flags 0x%x\n", __func__, client->name, client->addr, client->irq, client->flags); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c check functionality error\n", __func__); return -ENXIO; } if (client->irq <= 0) { dev_err(&client->dev, "%s: missing IRQ configuration\n", __func__); return -ENODEV; } ts = devm_kzalloc(&client->dev, sizeof(struct gsl_ts_data), GFP_KERNEL); if (!ts) { return -ENOMEM; } ts->client = client; i2c_set_clientdata(client, ts); #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) /* Set up ACPI device descriptor GPIO name mappings. * This is a fallback, it will only be used if the system does not * provide a corresponding _DSD entry. */ error = acpi_dev_add_driver_gpios(ACPI_COMPANION(&client->dev), gsl_ts_acpi_gpios); if (error < 0) { dev_warn(&client->dev, "%s: failed to register GPIO names, continuing anyway\n", __func__); } #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) ts->gpio = devm_gpiod_get(&client->dev, GSL_PWR_GPIO); #else ts->gpio = devm_gpiod_get(&client->dev, GSL_PWR_GPIO, GPIOD_OUT_LOW); #endif if (IS_ERR(ts->gpio)) { dev_err(&client->dev, "%s: error obtaining power pin GPIO resource\n", __func__); error = PTR_ERR(ts->gpio); goto release_gpios; } #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0) error = gpiod_direction_output(ts->gpio, 0); if (error < 0) { dev_err(&client->dev, "%s: error setting GPIO pin direction\n", __func__); goto release_gpios; } #endif if (ACPI_COMPANION(&client->dev)) { /* Wake the device up with a power on reset */ error = acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D3); if (error == 0) { error = acpi_bus_set_power(ACPI_HANDLE(&client->dev), ACPI_STATE_D0); } if (error) { dev_err(&client->dev, "%s: failed to wake up device through ACPI: %d, continuting anyway\n", __func__, error); } } error = request_firmware(&fw, GSL_FW_NAME, &ts->client->dev); if (error < 0) { dev_err(&client->dev, "%s: failed to load firmware: %d\n", __func__, error); goto release_gpios; } error = gsl_ts_init(ts, fw); if (error < 0) { dev_err(&client->dev, "%s: failed to initialize: %d\n", __func__, error); goto release_fw; } ts->input = devm_input_allocate_device(&client->dev); if (!ts->input) { dev_err(&client->dev, "%s: failed to allocate input device\n", __func__); error = -ENOMEM; goto release_fw; } ts->input->name = "Silead GSLx680 Touchscreen"; ts->input->id.bustype = BUS_I2C; ts->input->phys = "input/ts"; input_set_capability(ts->input, EV_ABS, ABS_X); input_set_capability(ts->input, EV_ABS, ABS_Y); input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, ts->x_max, ts->jitter, ts->deadzone); input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, ts->y_max, ts->jitter, ts->deadzone); input_mt_init_slots(ts->input, ts->multi_touches, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK); input_set_drvdata(ts->input, ts); error = input_register_device(ts->input); if (error) { dev_err(&client->dev, "%s: unable to register input device: %d\n", __func__, error); goto release_fw; } /* * Systems using device tree should set up interrupt via DTS, * the rest will use the default falling edge interrupts. */ irqflags = client->dev.of_node ? 0 : IRQF_TRIGGER_FALLING; /* Set up interrupt handler - do we still need to account for shared interrupts? */ error = devm_request_threaded_irq( &client->dev, client->irq, NULL, gsl_ts_irq, irqflags | IRQF_ONESHOT, client->name, ts ); if (error) { dev_err(&client->dev, "%s: failed to register interrupt\n", __func__); goto release_fw; } /* Execute the controller startup sequence */ error = gsl_ts_reset_chip(client); if (error < 0) { dev_err(&client->dev, "%s: chip reset failed\n", __func__); goto release_fw; } error = gsl_ts_write_fw(ts, fw); if (error < 0) { dev_err(&client->dev, "%s: firmware transfer failed\n", __func__); goto release_fw; } error = gsl_ts_startup_chip(client); if (error < 0) { dev_err(&client->dev, "%s: chip startup failed\n", __func__); goto release_fw; } /* * Systems using device tree should set up wakeup via DTS, * the rest will configure device as wakeup source by default. */ if (!client->dev.of_node) { device_init_wakeup(&client->dev, true); } ts->state = GSL_TS_GREEN; release_fw: if (fw) { release_firmware(fw); } release_gpios: if (error < 0) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0) acpi_dev_remove_driver_gpios(ACPI_COMPANION(&client->dev)); #endif return error; } return 0; }