Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5699fc5e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "input: synaptics_i2c_rmi4: Add GPIO configuration support"

parents 51cb0927 36205baa
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -135,6 +135,9 @@ static ssize_t fwu_sysfs_bl_config_block_count_show(struct device *dev,
static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
		struct device_attribute *attr, char *buf);

static ssize_t fwu_sysfs_config_id_show(struct device *dev,
		struct device_attribute *attr, char *buf);

static int fwu_wait_for_idle(int timeout_ms);

struct image_header {
@@ -289,6 +292,9 @@ static struct device_attribute attrs[] = {
	__ATTR(dispconfigblockcount, S_IRUGO,
			fwu_sysfs_disp_config_block_count_show,
			synaptics_rmi4_store_error),
	__ATTR(config_id, S_IRUGO,
			fwu_sysfs_config_id_show,
			synaptics_rmi4_store_error),
};

static struct synaptics_rmi4_fwu_handle *fwu;
@@ -1519,6 +1525,20 @@ static ssize_t fwu_sysfs_disp_config_block_count_show(struct device *dev,
	return snprintf(buf, PAGE_SIZE, "%u\n", fwu->disp_config_block_count);
}

static ssize_t fwu_sysfs_config_id_show(struct device *dev,
		struct device_attribute *attr, char *buf)
{
	unsigned char config_id[4];
	/* device config id */
	fwu->fn_ptr->read(fwu->rmi4_data,
				fwu->f34_fd.ctrl_base_addr,
				config_id,
				sizeof(config_id));

	return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n",
		config_id[0], config_id[1], config_id[2], config_id[3]);
}

static void synaptics_rmi4_fwu_attn(struct synaptics_rmi4_data *rmi4_data,
		unsigned char intr_mask)
{
@@ -1681,4 +1701,4 @@ module_exit(rmi4_fw_update_module_exit);

MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("RMI4 FW Update Module");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
+264 −65
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 *
 * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
 * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -71,6 +72,19 @@
#define NO_SLEEP_OFF (0 << 3)
#define NO_SLEEP_ON (1 << 3)

#define RMI4_VTG_MIN_UV		2700000
#define RMI4_VTG_MAX_UV		3300000
#define RMI4_ACTIVE_LOAD_UA	15000
#define RMI4_LPM_LOAD_UA	10

#define RMI4_I2C_VTG_MIN_UV	1800000
#define RMI4_I2C_VTG_MAX_UV	1800000
#define RMI4_I2C_LOAD_UA	10000
#define RMI4_I2C_LPM_LOAD_UA	10

#define RMI4_GPIO_SLEEP_LOW_US 10000
#define RMI4_GPIO_WAIT_HIGH_MS 25

static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
		unsigned short addr, unsigned char *data,
		unsigned short length);
@@ -1492,10 +1506,6 @@ static void synaptics_rmi4_detection_work(struct work_struct *work)
			container_of(work, struct synaptics_rmi4_data,
			det_work.work);

	queue_delayed_work(rmi4_data->det_workqueue,
			&rmi4_data->det_work,
			msecs_to_jiffies(EXP_FN_DET_INTERVAL));

	mutex_lock(&exp_fn_list_mutex);
	if (!list_empty(&exp_fn_list)) {
		list_for_each_entry_safe(exp_fhandler,
@@ -1575,6 +1585,164 @@ exit:
}
EXPORT_SYMBOL(synaptics_rmi4_new_function);


static int reg_set_optimum_mode_check(struct regulator *reg, int load_uA)
{
	return (regulator_count_voltages(reg) > 0) ?
		regulator_set_optimum_mode(reg, load_uA) : 0;
}

static int synaptics_rmi4_regulator_configure(struct synaptics_rmi4_data
						*rmi4_data, bool on)
{
	int retval;

	if (on == false)
		goto hw_shutdown;

	if (rmi4_data->board->regulator_en) {
		rmi4_data->vdd = regulator_get(&rmi4_data->i2c_client->dev,
						"vdd");
		if (IS_ERR(rmi4_data->vdd)) {
			dev_err(&rmi4_data->i2c_client->dev,
					"%s: Failed to get vdd regulator\n",
					__func__);
			return PTR_ERR(rmi4_data->vdd);
		}

		if (regulator_count_voltages(rmi4_data->vdd) > 0) {
			retval = regulator_set_voltage(rmi4_data->vdd,
				RMI4_VTG_MIN_UV, RMI4_VTG_MAX_UV);
			if (retval) {
				dev_err(&rmi4_data->i2c_client->dev,
					"regulator set_vtg failed retval=%d\n",
					retval);
				goto err_set_vtg_vdd;
			}
		}
	}

	if (rmi4_data->board->i2c_pull_up) {
		rmi4_data->vcc_i2c = regulator_get(&rmi4_data->i2c_client->dev,
						"vcc_i2c");
		if (IS_ERR(rmi4_data->vcc_i2c)) {
			dev_err(&rmi4_data->i2c_client->dev,
					"%s: Failed to get i2c regulator\n",
					__func__);
			retval = PTR_ERR(rmi4_data->vcc_i2c);
			goto err_get_vtg_i2c;
		}

		if (regulator_count_voltages(rmi4_data->vcc_i2c) > 0) {
			retval = regulator_set_voltage(rmi4_data->vcc_i2c,
				RMI4_I2C_VTG_MIN_UV, RMI4_I2C_VTG_MAX_UV);
			if (retval) {
				dev_err(&rmi4_data->i2c_client->dev,
					"reg set i2c vtg failed retval=%d\n",
					retval);
			goto err_set_vtg_i2c;
			}
		}
	}

err_set_vtg_i2c:
	if (rmi4_data->board->i2c_pull_up)
		regulator_put(rmi4_data->vcc_i2c);
err_get_vtg_i2c:
	if (rmi4_data->board->regulator_en)
		if (regulator_count_voltages(rmi4_data->vdd) > 0)
			regulator_set_voltage(rmi4_data->vdd, 0,
				RMI4_VTG_MAX_UV);
err_set_vtg_vdd:
	if (rmi4_data->board->regulator_en)
		regulator_put(rmi4_data->vdd);
	return retval;

hw_shutdown:
	if (rmi4_data->board->regulator_en) {
		if (regulator_count_voltages(rmi4_data->vdd) > 0)
			regulator_set_voltage(rmi4_data->vdd, 0,
				RMI4_VTG_MAX_UV);
		regulator_put(rmi4_data->vdd);
	}
	if (rmi4_data->board->i2c_pull_up) {
		if (regulator_count_voltages(rmi4_data->vcc_i2c) > 0)
			regulator_set_voltage(rmi4_data->vcc_i2c, 0,
					RMI4_I2C_VTG_MAX_UV);
		regulator_put(rmi4_data->vcc_i2c);
	}
	return 0;
};

static int synaptics_rmi4_power_on(struct synaptics_rmi4_data *rmi4_data,
					bool on) {
	int retval;

	if (on == false)
		goto power_off;

	if (rmi4_data->board->regulator_en) {
		retval = reg_set_optimum_mode_check(rmi4_data->vdd,
			RMI4_ACTIVE_LOAD_UA);
		if (retval < 0) {
			dev_err(&rmi4_data->i2c_client->dev,
				"Regulator vdd set_opt failed rc=%d\n",
				retval);
			return retval;
		}

		retval = regulator_enable(rmi4_data->vdd);
		if (retval) {
			dev_err(&rmi4_data->i2c_client->dev,
				"Regulator vdd enable failed rc=%d\n",
				retval);
			goto error_reg_en_vdd;
		}
	}

	if (rmi4_data->board->i2c_pull_up) {
		retval = reg_set_optimum_mode_check(rmi4_data->vcc_i2c,
			RMI4_I2C_LOAD_UA);
		if (retval < 0) {
			dev_err(&rmi4_data->i2c_client->dev,
				"Regulator vcc_i2c set_opt failed rc=%d\n",
				retval);
			goto error_reg_opt_i2c;
		}

		retval = regulator_enable(rmi4_data->vcc_i2c);
		if (retval) {
			dev_err(&rmi4_data->i2c_client->dev,
				"Regulator vcc_i2c enable failed rc=%d\n",
				retval);
			goto error_reg_en_vcc_i2c;
		}
	}
	return 0;

error_reg_en_vcc_i2c:
	if (rmi4_data->board->i2c_pull_up)
		reg_set_optimum_mode_check(rmi4_data->vdd, 0);
error_reg_opt_i2c:
	if (rmi4_data->board->regulator_en)
		regulator_disable(rmi4_data->vdd);
error_reg_en_vdd:
	if (rmi4_data->board->regulator_en)
		reg_set_optimum_mode_check(rmi4_data->vdd, 0);
	return retval;

power_off:
	if (rmi4_data->board->regulator_en) {
		reg_set_optimum_mode_check(rmi4_data->vdd, 0);
		regulator_disable(rmi4_data->vdd);
	}
	if (rmi4_data->board->i2c_pull_up) {
		reg_set_optimum_mode_check(rmi4_data->vcc_i2c, 0);
		regulator_disable(rmi4_data->vcc_i2c);
	}
	return 0;
}

 /**
 * synaptics_rmi4_probe()
 *
@@ -1592,7 +1760,7 @@ EXPORT_SYMBOL(synaptics_rmi4_new_function);
static int synaptics_rmi4_probe(struct i2c_client *client,
		const struct i2c_device_id *dev_id)
{
	int retval;
	int retval = 0;
	unsigned char ii;
	unsigned char attr_count;
	struct synaptics_rmi4_f1a_handle *f1a;
@@ -1629,20 +1797,6 @@ static int synaptics_rmi4_probe(struct i2c_client *client,
		goto err_input_device;
	}

	if (platform_data->regulator_en) {
		rmi4_data->regulator = devm_regulator_get(&client->dev, "vdd");
		if (IS_ERR(rmi4_data->regulator)) {
			dev_err(&client->dev,
					"%s: Failed to get regulator\n",
					__func__);
			retval = PTR_ERR(rmi4_data->regulator);
			goto err_regulator;
		}
		retval = regulator_enable(rmi4_data->regulator);
		if (retval)
			return retval;
	}

	rmi4_data->i2c_client = client;
	rmi4_data->current_page = MASK_8BIT;
	rmi4_data->board = platform_data;
@@ -1655,24 +1809,11 @@ static int synaptics_rmi4_probe(struct i2c_client *client,
	rmi4_data->irq_enable = synaptics_rmi4_irq_enable;
	rmi4_data->reset_device = synaptics_rmi4_reset_device;

	init_waitqueue_head(&rmi4_data->wait);
	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));

	retval = synaptics_rmi4_query_device(rmi4_data);
	if (retval < 0) {
		dev_err(&client->dev,
				"%s: Failed to query device\n",
				__func__);
		goto err_query_device;
	}

	i2c_set_clientdata(client, rmi4_data);

	rmi4_data->input_dev->name = DRIVER_NAME;
	rmi4_data->input_dev->phys = INPUT_PHYS_NAME;
	rmi4_data->input_dev->id.bustype = BUS_I2C;
	rmi4_data->input_dev->id.product = SYNAPTICS_RMI4_DRIVER_PRODUCT;
	rmi4_data->input_dev->id.version = SYNAPTICS_RMI4_DRIVER_VERSION;
	rmi4_data->input_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
	rmi4_data->input_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
	rmi4_data->input_dev->dev.parent = &client->dev;
	input_set_drvdata(rmi4_data->input_dev, rmi4_data);

@@ -1703,6 +1844,76 @@ static int synaptics_rmi4_probe(struct i2c_client *client,
			rmi4_data->num_of_fingers);
#endif

	retval = synaptics_rmi4_regulator_configure(rmi4_data, true);
	if (retval < 0) {
		dev_err(&client->dev, "Failed to configure regulators\n");
		goto err_reg_configure;
	}

	retval = synaptics_rmi4_power_on(rmi4_data, true);
	if (retval < 0) {
		dev_err(&client->dev, "Failed to power on\n");
		goto err_power_device;
	}

	if (gpio_is_valid(platform_data->irq_gpio)) {
		/* configure touchscreen irq gpio */
		retval = gpio_request(platform_data->irq_gpio, "rmi4_irq_gpio");
		if (retval) {
			dev_err(&client->dev, "unable to request gpio [%d]\n",
						platform_data->irq_gpio);
			goto err_query_device;
		}
		retval = gpio_direction_input(platform_data->irq_gpio);
		if (retval) {
			dev_err(&client->dev,
				"unable to set direction for gpio [%d]\n",
				platform_data->irq_gpio);
			goto err_irq_gpio_req;
		}
	} else {
		dev_err(&client->dev, "irq gpio not provided\n");
		goto err_query_device;
	}

	if (gpio_is_valid(platform_data->reset_gpio)) {
		/* configure touchscreen reset out gpio */
		retval = gpio_request(platform_data->reset_gpio,
				"rmi4_reset_gpio");
		if (retval) {
			dev_err(&client->dev, "unable to request gpio [%d]\n",
						platform_data->reset_gpio);
			goto err_irq_gpio_req;
		}

		retval = gpio_direction_output(platform_data->reset_gpio, 1);
		if (retval) {
			dev_err(&client->dev,
				"unable to set direction for gpio [%d]\n",
				platform_data->reset_gpio);
			goto err_reset_gpio_req;
		}

		gpio_set_value(platform_data->reset_gpio, 0);
		usleep(RMI4_GPIO_SLEEP_LOW_US);
		gpio_set_value(platform_data->reset_gpio, 1);
		msleep(RMI4_GPIO_WAIT_HIGH_MS);
	}


	init_waitqueue_head(&rmi4_data->wait);
	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));

	retval = synaptics_rmi4_query_device(rmi4_data);
	if (retval < 0) {
		dev_err(&client->dev,
				"%s: Failed to query device\n",
				__func__);
		goto err_reset_gpio_req;
	}

	i2c_set_clientdata(client, rmi4_data);

	f1a = NULL;
	if (!list_empty(&rmi->support_fn_list)) {
		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
@@ -1782,12 +1993,6 @@ err_enable_irq:
	input_unregister_device(rmi4_data->input_dev);

err_register_input:
err_query_device:
	if (platform_data->regulator_en) {
		regulator_disable(rmi4_data->regulator);
		regulator_put(rmi4_data->regulator);
	}

	if (!list_empty(&rmi->support_fn_list)) {
		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
@@ -1797,11 +2002,19 @@ err_query_device:
			kfree(fhandler);
		}
	}

err_regulator:
err_reset_gpio_req:
	if (gpio_is_valid(platform_data->reset_gpio))
		gpio_free(platform_data->reset_gpio);
err_irq_gpio_req:
	if (gpio_is_valid(platform_data->irq_gpio))
		gpio_free(platform_data->irq_gpio);
err_query_device:
	synaptics_rmi4_power_on(rmi4_data, false);
err_power_device:
	synaptics_rmi4_regulator_configure(rmi4_data, false);
err_reg_configure:
	input_free_device(rmi4_data->input_dev);
	rmi4_data->input_dev = NULL;

err_input_device:
	kfree(rmi4_data);

@@ -1824,8 +2037,6 @@ static int synaptics_rmi4_remove(struct i2c_client *client)
	struct synaptics_rmi4_fn *fhandler;
	struct synaptics_rmi4_data *rmi4_data = i2c_get_clientdata(client);
	struct synaptics_rmi4_device_info *rmi;
	const struct synaptics_rmi4_platform_data *platform_data =
			rmi4_data->board;

	rmi = &(rmi4_data->rmi4_mod_info);

@@ -1845,11 +2056,6 @@ static int synaptics_rmi4_remove(struct i2c_client *client)

	input_unregister_device(rmi4_data->input_dev);

	if (platform_data->regulator_en) {
		regulator_disable(rmi4_data->regulator);
		regulator_put(rmi4_data->regulator);
	}

	if (!list_empty(&rmi->support_fn_list)) {
		list_for_each_entry(fhandler, &rmi->support_fn_list, link) {
			if (fhandler->fn_number == SYNAPTICS_RMI4_F1A)
@@ -1859,7 +2065,14 @@ static int synaptics_rmi4_remove(struct i2c_client *client)
			kfree(fhandler);
		}
	}
	input_free_device(rmi4_data->input_dev);

	if (gpio_is_valid(rmi4_data->board->reset_gpio))
		gpio_free(rmi4_data->board->reset_gpio);
	if (gpio_is_valid(rmi4_data->board->irq_gpio))
		gpio_free(rmi4_data->board->irq_gpio);

	synaptics_rmi4_power_on(rmi4_data, false);
	synaptics_rmi4_regulator_configure(rmi4_data, false);

	kfree(rmi4_data);

@@ -2013,8 +2226,6 @@ static void synaptics_rmi4_late_resume(struct early_suspend *h)
static int synaptics_rmi4_suspend(struct device *dev)
{
	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
	const struct synaptics_rmi4_platform_data *platform_data =
			rmi4_data->board;

	if (!rmi4_data->sensor_sleep) {
		rmi4_data->touch_stopped = true;
@@ -2023,9 +2234,6 @@ static int synaptics_rmi4_suspend(struct device *dev)
		synaptics_rmi4_sensor_sleep(rmi4_data);
	}

	if (platform_data->regulator_en)
		regulator_disable(rmi4_data->regulator);

	return 0;
}

@@ -2041,16 +2249,7 @@ static int synaptics_rmi4_suspend(struct device *dev)
 */
static int synaptics_rmi4_resume(struct device *dev)
{
	int ret;
	struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
	const struct synaptics_rmi4_platform_data *platform_data =
			rmi4_data->board;

	if (platform_data->regulator_en) {
		ret = regulator_enable(rmi4_data->regulator);
		if (ret)
			return ret;
	}

	synaptics_rmi4_sensor_wake(rmi4_data);
	rmi4_data->touch_stopped = false;
+7 −5
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 *
 * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
 * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -20,10 +21,10 @@
#ifndef _SYNAPTICS_DSX_RMI4_H_
#define _SYNAPTICS_DSX_RMI4_H_

#define SYNAPTICS_RMI4_DS4 0x0001
#define SYNAPTICS_RMI4_DS5 0x0002
#define SYNAPTICS_RMI4_DRIVER_PRODUCT SYNAPTICS_RMI4_DS4
#define SYNAPTICS_RMI4_DRIVER_VERSION 0x1001
#define SYNAPTICS_DS4 (1 << 0)
#define SYNAPTICS_DS5 (1 << 1)
#define SYNAPTICS_DSX_DRIVER_PRODUCT SYNAPTICS_DS4
#define SYNAPTICS_DSX_DRIVER_VERSION 0x1002

#include <linux/version.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
@@ -187,7 +188,8 @@ struct synaptics_rmi4_data {
	struct input_dev *input_dev;
	const struct synaptics_rmi4_platform_data *board;
	struct synaptics_rmi4_device_info rmi4_mod_info;
	struct regulator *regulator;
	struct regulator *vdd;
	struct regulator *vcc_i2c;
	struct mutex rmi4_io_ctrl_mutex;
	struct delayed_work det_work;
	struct workqueue_struct *det_workqueue;
+1 −1
Original line number Diff line number Diff line
@@ -700,4 +700,4 @@ module_exit(rmidev_module_exit);

MODULE_AUTHOR("Synaptics, Inc.");
MODULE_DESCRIPTION("RMI4 RMI_Dev Module");
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL v2");
+2 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 *
 * Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
 * Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -47,6 +48,7 @@ struct synaptics_rmi4_platform_data {
	bool x_flip;
	bool y_flip;
	bool regulator_en;
	bool i2c_pull_up;
	unsigned irq_gpio;
	unsigned long irq_flags;
	unsigned reset_gpio;