-
-
Save luk1337/00ce7067ff26ed736ce2f018fcdac3ce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Kconfig b/Kconfig | |
index 1cb30a9..cfa0dde 100644 | |
--- a/Kconfig | |
+++ b/Kconfig | |
@@ -1,7 +1,7 @@ | |
# | |
# Synaptics DSX touchscreen driver configuration | |
# | |
-menuconfig TOUCHSCREEN_SYNAPTICS_DSX | |
+menuconfig TOUCHSCREEN_SYNAPTICS_DSX_FORCE | |
bool "Synaptics DSX touchscreen" | |
default y | |
help | |
@@ -10,23 +10,23 @@ menuconfig TOUCHSCREEN_SYNAPTICS_DSX | |
If unsure, say N. | |
-if TOUCHSCREEN_SYNAPTICS_DSX | |
+if TOUCHSCREEN_SYNAPTICS_DSX_FORCE | |
choice | |
- default TOUCHSCREEN_SYNAPTICS_DSX_I2C | |
+ default TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE | |
prompt "Synaptics DSX bus interface" | |
-config TOUCHSCREEN_SYNAPTICS_DSX_I2C | |
+config TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE | |
bool "RMI over I2C" | |
depends on I2C | |
-config TOUCHSCREEN_SYNAPTICS_DSX_SPI | |
+config TOUCHSCREEN_SYNAPTICS_DSX_SPI_FORCE | |
bool "RMI over SPI" | |
depends on SPI_MASTER | |
-config TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C | |
+config TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_FORCE | |
bool "HID over I2C" | |
depends on I2C | |
endchoice | |
-config TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+config TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
tristate "Synaptics DSX core driver module" | |
depends on I2C || SPI_MASTER | |
help | |
@@ -37,9 +37,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_core. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV | |
+config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_FORCE | |
tristate "Synaptics DSX RMI device module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for direct RMI register access. | |
@@ -48,9 +48,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_rmi_dev. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE | |
+config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_FORCE | |
tristate "Synaptics DSX firmware update module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for doing firmware update. | |
@@ -59,9 +59,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_fw_update. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING | |
+config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_FORCE | |
tristate "Synaptics DSX test reporting module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for retrieving production test reports. | |
@@ -70,9 +70,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_test_reporting. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY | |
+config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_FORCE | |
tristate "Synaptics DSX proximity module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for proximity functionality. | |
@@ -81,9 +81,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_proximity. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN | |
+config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_FORCE | |
tristate "Synaptics DSX active pen module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for active pen functionality. | |
@@ -92,9 +92,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_active_pen. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE | |
+config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_FORCE | |
tristate "Synaptics DSX user defined gesture module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for user defined gesture functionality. | |
@@ -103,9 +103,9 @@ config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_gesture. | |
-config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO | |
+config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_FORCE | |
tristate "Synaptics DSX video module" | |
- depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
help | |
Say Y here to enable support for video communication functionality. | |
@@ -114,4 +114,18 @@ config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO | |
To compile this driver as a module, choose M here: the | |
module will be called synaptics_dsx_video. | |
+config TOUCHSCREEN_SYNAPTICS_DSX_2D_PRESSURE_FORCE | |
+ bool "Synaptics DSX 2D pressure support" | |
+ default n | |
+ depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE | |
+ help | |
+ Say Y here to enable support for 2D pressure. | |
+ | |
+config TOUCH_DEBUG_FS | |
+ bool "touch debugfs suport" | |
+ default n | |
+ depends on DEBUG_FS | |
+ help | |
+ Say Y here to enable support for touch debugfs. | |
+ | |
endif | |
diff --git a/Makefile b/Makefile | |
index 515bc17..f613ea9 100644 | |
--- a/Makefile | |
+++ b/Makefile | |
@@ -4,14 +4,14 @@ | |
# Each configuration option enables a list of files. | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C) += synaptics_dsx_i2c.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI) += synaptics_dsx_spi.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C) += synaptics_dsx_rmi_hid_i2c.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE) += synaptics_dsx_core.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV) += synaptics_dsx_rmi_dev.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE) += synaptics_dsx_fw_update.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING) += synaptics_dsx_test_reporting.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY) += synaptics_dsx_proximity.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN) += synaptics_dsx_active_pen.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_GESTURE) += synaptics_dsx_gesture.o | |
-obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_VIDEO) += synaptics_dsx_video.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_FORCE) += synaptics_dsx_i2c.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_FORCE) += synaptics_dsx_spi.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_FORCE) += synaptics_dsx_rmi_hid_i2c.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_FORCE) += synaptics_dsx_core.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_FORCE) += synaptics_dsx_rmi_dev.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_FORCE) += synaptics_dsx_fw_update.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_FORCE) += synaptics_dsx_test_reporting.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_FORCE) += synaptics_dsx_proximity.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_FORCE) += synaptics_dsx_active_pen.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_FORCE) += synaptics_dsx_gesture.o | |
+obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_FORCE) += synaptics_dsx_video.o | |
diff --git a/synaptics_dsx_active_pen.c b/synaptics_dsx_active_pen.c | |
index 910ab16..1ff7a6d 100644 | |
--- a/synaptics_dsx_active_pen.c | |
+++ b/synaptics_dsx_active_pen.c | |
@@ -609,14 +609,14 @@ static struct synaptics_rmi4_exp_fn active_pen_module = { | |
static int __init rmi4_active_pen_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&active_pen_module, true); | |
+ synaptics_rmi4_new_function_force(&active_pen_module, true); | |
return 0; | |
} | |
static void __exit rmi4_active_pen_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&active_pen_module, false); | |
+ synaptics_rmi4_new_function_force(&active_pen_module, false); | |
wait_for_completion(&apen_remove_complete); | |
diff --git a/synaptics_dsx_core.c b/synaptics_dsx_core.c | |
index b72ed74..c76a1b1 100644 | |
--- a/synaptics_dsx_core.c | |
+++ b/synaptics_dsx_core.c | |
@@ -16,6 +16,20 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
#include <linux/kernel.h> | |
@@ -32,6 +46,7 @@ | |
#ifdef KERNEL_ABOVE_2_6_38 | |
#include <linux/input/mt.h> | |
#endif | |
+ | |
#if defined(CONFIG_SECURE_TOUCH) | |
#include <linux/pm_runtime.h> | |
#include <linux/errno.h> | |
@@ -39,6 +54,14 @@ | |
#include <linux/power_supply.h> | |
+#ifdef CONFIG_TOUCH_DEBUG_FS | |
+#include <linux/fs.h> | |
+#include <linux/debugfs.h> | |
+#include <linux/uaccess.h> | |
+#endif | |
+ | |
+#include <linux/mdss_io_util.h> | |
+ | |
#define INPUT_PHYS_NAME "synaptics_dsx/touch_input" | |
#define STYLUS_PHYS_NAME "synaptics_dsx/stylus" | |
@@ -54,6 +77,10 @@ | |
#define REPORT_2D_Z | |
#define REPORT_2D_W | |
+#ifdef TOUCHSCREEN_SYNAPTICS_DSX_2D_PRESSURE_FORCE | |
+#define REPORT_2D_PRESSURE | |
+#endif | |
+ | |
#define F12_DATA_15_WORKAROUND | |
#define IGNORE_FN_INIT_FAILURE | |
@@ -99,6 +126,10 @@ | |
#define F12_CONTINUOUS_MODE 0x00 | |
#define F12_WAKEUP_GESTURE_MODE 0x02 | |
#define F12_UDG_DETECT 0x0f | |
+#define F12_HOMEKEY_DETECT 0x0c | |
+ | |
+#define DOUBLE_TAP 0x01 | |
+#define HOMEKEY_WAKEUP 0x80 | |
#define INPUT_EVENT_START 0 | |
#define INPUT_EVENT_SENSITIVE_MODE_OFF 0 | |
@@ -109,16 +140,16 @@ | |
#define INPUT_EVENT_WAKUP_MODE_ON 5 | |
#define INPUT_EVENT_COVER_MODE_OFF 6 | |
#define INPUT_EVENT_COVER_MODE_ON 7 | |
-#define INPUT_EVENT_END 7 | |
+#define INPUT_EVENT_CAPTOUCH_MODE_OFF 8 | |
+#define INPUT_EVENT_CAPTOUCH_MODE_ON 9 | |
+#define INPUT_EVENT_END 9 | |
+ | |
+#define BUTTON_WG_EN 1 | |
-#define COMMAND_TIMEOUT_100MS 20 | |
+void (*captouch_key_report_ptr)(int key_status) = NULL; | |
+bool (*captouch_get_status_ptr)(void) = NULL; | |
-#define BTN_DOZE_WAKEUP_TH 0x0013 | |
-#define BTN_FAST_RELAX_RATE 0x011f | |
-#define BTN_SLOW_RELAX_RATE 0x011e | |
-#define BTN_RELEASE_TH 0x0317 | |
-#define BTN_TOUCH_TH1 0x0313 | |
-#define BTN_TOUCH_TH2 0x0314 | |
+static bool check_captouch_support(struct synaptics_rmi4_data *rmi4_data); | |
static int synaptics_rmi4_check_status(struct synaptics_rmi4_data *rmi4_data, | |
bool *was_in_bl_mode); | |
@@ -153,9 +184,12 @@ static int synaptics_rmi4_fb_notifier_cb_lgd(struct notifier_block *self, | |
unsigned long event, void *data); | |
#endif | |
-static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enable); | |
+#define DISP_REG_VDD (1<<0) | |
+#define DISP_REG_LAB (1<<1) | |
+#define DISP_REG_IBB (1<<2) | |
+#define DISP_REG_ALL (DISP_REG_VDD | DISP_REG_LAB | DISP_REG_IBB) | |
-static void synaptics_rmi4_protection_film(struct synaptics_rmi4_data *rmi4_data); | |
+static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, unsigned int flag, bool enable); | |
#ifdef CONFIG_HAS_EARLYSUSPEND | |
#ifndef CONFIG_FB | |
@@ -200,9 +234,21 @@ static ssize_t synaptics_rmi4_wake_gesture_show(struct device *dev, | |
static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, | |
struct device_attribute *attr, const char *buf, size_t count); | |
+static ssize_t synaptics_rmi4_irq_enable_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf); | |
+ | |
+static ssize_t synaptics_rmi4_irq_enable_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count); | |
+ | |
+static ssize_t synaptics_rmi4_captouch_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count); | |
+ | |
static ssize_t synaptics_rmi4_panel_color_show(struct device *dev, | |
struct device_attribute *attr, char *buf); | |
+static ssize_t synaptics_rmi4_panel_vendor_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf); | |
+ | |
static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj, | |
struct kobj_attribute *attr, char *buf); | |
@@ -408,8 +454,48 @@ struct synaptics_rmi4_f12_query_5 { | |
unsigned char ctrl30_is_present:1; | |
unsigned char ctrl31_is_present:1; | |
} __packed; | |
+ struct { | |
+ unsigned char ctrl32_is_present:1; | |
+ unsigned char ctrl33_is_present:1; | |
+ unsigned char ctrl34_is_present:1; | |
+ unsigned char ctrl35_is_present:1; | |
+ unsigned char ctrl36_is_present:1; | |
+ unsigned char ctrl37_is_present:1; | |
+ unsigned char ctrl38_is_present:1; | |
+ unsigned char ctrl39_is_present:1; | |
+ } __packed; | |
+ struct { | |
+ unsigned char ctrl40_is_present:1; | |
+ unsigned char ctrl41_is_present:1; | |
+ unsigned char ctrl42_is_present:1; | |
+ unsigned char ctrl43_is_present:1; | |
+ unsigned char ctrl44_is_present:1; | |
+ unsigned char ctrl45_is_present:1; | |
+ unsigned char ctrl46_is_present:1; | |
+ unsigned char ctrl47_is_present:1; | |
+ } __packed; | |
+ struct { | |
+ unsigned char ctrl48_is_present:1; | |
+ unsigned char ctrl49_is_present:1; | |
+ unsigned char ctrl50_is_present:1; | |
+ unsigned char ctrl51_is_present:1; | |
+ unsigned char ctrl52_is_present:1; | |
+ unsigned char ctrl53_is_present:1; | |
+ unsigned char ctrl54_is_present:1; | |
+ unsigned char ctrl55_is_present:1; | |
+ } __packed; | |
+ struct { | |
+ unsigned char ctrl56_is_present:1; | |
+ unsigned char ctrl57_is_present:1; | |
+ unsigned char ctrl58_is_present:1; | |
+ unsigned char ctrl59_is_present:1; | |
+ unsigned char ctrl60_is_present:1; | |
+ unsigned char ctrl61_is_present:1; | |
+ unsigned char ctrl62_is_present:1; | |
+ unsigned char ctrl63_is_present:1; | |
+ } __packed; | |
}; | |
- unsigned char data[5]; | |
+ unsigned char data[9]; | |
}; | |
}; | |
@@ -447,8 +533,18 @@ struct synaptics_rmi4_f12_query_8 { | |
unsigned char data22_is_present:1; | |
unsigned char data23_is_present:1; | |
} __packed; | |
+ struct { | |
+ unsigned char data24_is_present:1; | |
+ unsigned char data25_is_present:1; | |
+ unsigned char data26_is_present:1; | |
+ unsigned char data27_is_present:1; | |
+ unsigned char data28_is_present:1; | |
+ unsigned char data29_is_present:1; | |
+ unsigned char data30_is_present:1; | |
+ unsigned char data31_is_present:1; | |
+ } __packed; | |
}; | |
- unsigned char data[4]; | |
+ unsigned char data[5]; | |
}; | |
}; | |
@@ -528,6 +624,28 @@ struct synaptics_rmi4_f12_ctrl_31 { | |
}; | |
}; | |
+struct synaptics_rmi4_f12_ctrl_58 { | |
+ union { | |
+ struct { | |
+ unsigned char reporting_format; | |
+ unsigned char f12_ctr58_00_reserved; | |
+ unsigned char min_force_lsb; | |
+ unsigned char min_force_msb; | |
+ unsigned char max_force_lsb; | |
+ unsigned char max_force_msb; | |
+ unsigned char light_press_threshold_lsb; | |
+ unsigned char light_press_threshold_msb; | |
+ unsigned char light_press_hysteresis_lsb; | |
+ unsigned char light_press_hysteresis_msb; | |
+ unsigned char hard_press_threshold_lsb; | |
+ unsigned char hard_press_threshold_msb; | |
+ unsigned char hard_press_hysteresis_lsb; | |
+ unsigned char hard_press_hysteresis_msb; | |
+ }; | |
+ unsigned char data[14]; | |
+ }; | |
+}; | |
+ | |
struct synaptics_rmi4_f12_finger_data { | |
unsigned char object_type_and_status; | |
unsigned char x_lsb; | |
@@ -547,7 +665,10 @@ struct synaptics_rmi4_f1a_query { | |
union { | |
struct { | |
unsigned char max_button_count:3; | |
- unsigned char reserved:5; | |
+ unsigned char f1a_query0_b3__4:2; | |
+ unsigned char has_query4:1; | |
+ unsigned char has_query3:1; | |
+ unsigned char has_query2:1; | |
unsigned char has_general_control:1; | |
unsigned char has_interrupt_enable:1; | |
unsigned char has_multibutton_select:1; | |
@@ -561,6 +682,18 @@ struct synaptics_rmi4_f1a_query { | |
}; | |
}; | |
+struct synaptics_rmi4_f1a_query_4 { | |
+ union { | |
+ struct { | |
+ unsigned char has_ctrl19:1; | |
+ unsigned char f1a_query4_b1__4:4; | |
+ unsigned char has_ctrl24:1; | |
+ unsigned char f1a_query4_b6__7:2; | |
+ } __packed; | |
+ unsigned char data[1]; | |
+ }; | |
+}; | |
+ | |
struct synaptics_rmi4_f1a_control_0 { | |
union { | |
struct { | |
@@ -636,6 +769,9 @@ static struct device_attribute attrs[] = { | |
__ATTR(wake_gesture, (S_IRUGO | S_IWUSR), | |
synaptics_rmi4_wake_gesture_show, | |
synaptics_rmi4_wake_gesture_store), | |
+ __ATTR(irq_enable, (S_IRUGO | S_IWUSR), | |
+ synaptics_rmi4_irq_enable_show, | |
+ synaptics_rmi4_irq_enable_store), | |
}; | |
#if defined(CONFIG_SECURE_TOUCH) | |
@@ -866,6 +1002,8 @@ static ssize_t synaptics_secure_touch_show(struct device *dev, | |
#endif | |
static DEVICE_ATTR(panel_color, S_IRUSR, synaptics_rmi4_panel_color_show, NULL); | |
+static DEVICE_ATTR(captouch, S_IWUSR, NULL, synaptics_rmi4_captouch_store); | |
+static DEVICE_ATTR(panel_vendor, S_IRUSR, synaptics_rmi4_panel_vendor_show, NULL); | |
static struct kobj_attribute virtual_key_map_attr = { | |
.attr = { | |
@@ -1058,6 +1196,55 @@ static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev, | |
return count; | |
} | |
+static ssize_t synaptics_rmi4_irq_enable_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf) | |
+{ | |
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); | |
+ | |
+ return snprintf(buf, PAGE_SIZE, "%u\n", | |
+ rmi4_data->irq_enabled); | |
+} | |
+ | |
+static ssize_t synaptics_rmi4_irq_enable_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count) | |
+{ | |
+ unsigned int input; | |
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); | |
+ | |
+ if (sscanf(buf, "%u", &input) != 1) | |
+ return -EINVAL; | |
+ if (input) | |
+ enable_irq(rmi4_data->irq); | |
+ else | |
+ disable_irq(rmi4_data->irq); | |
+ | |
+ return count; | |
+} | |
+static ssize_t synaptics_rmi4_captouch_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count) | |
+{ | |
+ unsigned int input; | |
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); | |
+ const struct synaptics_dsx_board_data *bdata = | |
+ rmi4_data->hw_if->board_data; | |
+ | |
+ if (sscanf(buf, "%u", &input) != 1) | |
+ return -EINVAL; | |
+ | |
+ if (bdata->cut_off_power) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Unable to switch wakeup gesture mode\n", __func__); | |
+ return count; | |
+ } | |
+ | |
+ input = input > 0 ? 1 : 0; | |
+ | |
+ if (bdata->captouch_use) | |
+ rmi4_data->homekey_wakeup = input; | |
+ | |
+ return count; | |
+} | |
+ | |
static ssize_t synaptics_rmi4_panel_color_show(struct device *dev, | |
struct device_attribute *attr, char *buf) | |
{ | |
@@ -1067,6 +1254,15 @@ static ssize_t synaptics_rmi4_panel_color_show(struct device *dev, | |
rmi4_data->lockdown_info[2]); | |
} | |
+static ssize_t synaptics_rmi4_panel_vendor_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf) | |
+{ | |
+ struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev); | |
+ | |
+ return snprintf(buf, PAGE_SIZE, "%c\n", | |
+ rmi4_data->lockdown_info[0]); | |
+} | |
+ | |
static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj, | |
struct kobj_attribute *attr, char *buf) | |
{ | |
@@ -1269,9 +1465,18 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
int wx; | |
int wy; | |
int temp; | |
-#ifdef REPORT_2D_PRESSURE | |
+#if defined(REPORT_2D_PRESSURE) || defined(F51_DISCRETE_FORCE) | |
int pressure; | |
#endif | |
+#ifdef REPORT_2D_PRESSURE | |
+ unsigned char f_fingers; | |
+ unsigned char f_lsb; | |
+ unsigned char f_msb; | |
+ unsigned char *f_data; | |
+#endif | |
+#ifdef F51_DISCRETE_FORCE | |
+ unsigned char force_level; | |
+#endif | |
struct synaptics_rmi4_f12_extra_data *extra_data; | |
struct synaptics_rmi4_f12_finger_data *data; | |
struct synaptics_rmi4_f12_finger_data *finger_data; | |
@@ -1292,7 +1497,7 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; | |
size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data); | |
- if (rmi4_data->suspend && rmi4_data->enable_wakeup_gesture) { | |
+ if (rmi4_data->suspend && (rmi4_data->enable_wakeup_gesture || rmi4_data->homekey_wakeup)) { | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
data_addr + extra_data->data4_offset, | |
rmi4_data->gesture_detection, | |
@@ -1301,7 +1506,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
return 0; | |
gesture_type = rmi4_data->gesture_detection[0]; | |
- | |
if (gesture_type && gesture_type != F12_UDG_DETECT) { | |
input_report_key(rmi4_data->input_dev, KEY_WAKEUP, 1); | |
input_sync(rmi4_data->input_dev); | |
@@ -1309,6 +1513,14 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
input_sync(rmi4_data->input_dev); | |
} | |
+ if (gesture_type == F12_HOMEKEY_DETECT) { | |
+ if (captouch_key_report_ptr != NULL) { | |
+ dev_info(rmi4_data->pdev->dev.parent, | |
+ "(captouch) fake report captouch keydown~!!\n"); | |
+ captouch_key_report_ptr(1); | |
+ } | |
+ } | |
+ | |
return 0; | |
} | |
@@ -1366,9 +1578,9 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
#ifdef REPORT_2D_PRESSURE | |
if (rmi4_data->report_pressure) { | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- data_addr + extra_data->data23_offset, | |
- extra_data->data23_data, | |
- fingers_to_process); | |
+ data_addr + extra_data->data29_offset, | |
+ extra_data->data29_data, | |
+ extra_data->data29_size); | |
if (retval < 0) | |
return 0; | |
} | |
@@ -1384,26 +1596,26 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
objects_already_present = finger + 1; | |
#endif | |
- x = (finger_data->x_msb << 8) | (finger_data->x_lsb); | |
- y = (finger_data->y_msb << 8) | (finger_data->y_lsb); | |
+ x = (finger_data->x_msb << 8) | (finger_data->x_lsb); | |
+ y = (finger_data->y_msb << 8) | (finger_data->y_lsb); | |
#ifdef REPORT_2D_W | |
- wx = finger_data->wx; | |
- wy = finger_data->wy; | |
+ wx = finger_data->wx; | |
+ wy = finger_data->wy; | |
#endif | |
- if (rmi4_data->hw_if->board_data->swap_axes) { | |
- temp = x; | |
- x = y; | |
- y = temp; | |
- temp = wx; | |
- wx = wy; | |
- wy = temp; | |
- } | |
+ if (rmi4_data->hw_if->board_data->swap_axes) { | |
+ temp = x; | |
+ x = y; | |
+ y = temp; | |
+ temp = wx; | |
+ wx = wy; | |
+ wy = temp; | |
+ } | |
- if (rmi4_data->hw_if->board_data->x_flip) | |
- x = rmi4_data->sensor_max_x - x; | |
- if (rmi4_data->hw_if->board_data->y_flip) | |
- y = rmi4_data->sensor_max_y - y; | |
+ if (rmi4_data->hw_if->board_data->x_flip) | |
+ x = rmi4_data->sensor_max_x - x; | |
+ if (rmi4_data->hw_if->board_data->y_flip) | |
+ y = rmi4_data->sensor_max_y - y; | |
switch (finger_status) { | |
case F12_FINGER_STATUS: | |
@@ -1441,14 +1653,41 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
#endif | |
#ifdef REPORT_2D_PRESSURE | |
if (rmi4_data->report_pressure) { | |
- pressure = extra_data->data23_data[finger]; | |
+ f_fingers = extra_data->data29_size / 2; | |
+ f_data = extra_data->data29_data; | |
+ if (finger + 1 > f_fingers) { | |
+ pressure = 1; | |
+ } else { | |
+ f_lsb = finger * 2; | |
+ f_msb = finger * 2 + 1; | |
+ pressure = (int)f_data[f_lsb] << 0 | | |
+ (int)f_data[f_msb] << 8; | |
+ } | |
+ pressure = pressure > 0 ? pressure : 1; | |
+ if (pressure > rmi4_data->force_max) | |
+ pressure = rmi4_data->force_max; | |
input_report_abs(rmi4_data->input_dev, | |
ABS_MT_PRESSURE, pressure); | |
} | |
+#elif defined(F51_DISCRETE_FORCE) | |
+ if (finger == 0) { | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ FORCE_LEVEL_ADDR, | |
+ &force_level, | |
+ sizeof(force_level)); | |
+ if (retval < 0) | |
+ return 0; | |
+ pressure = force_level > 0 ? force_level : 1; | |
+ } else { | |
+ pressure = 1; | |
+ } | |
+ input_report_abs(rmi4_data->input_dev, | |
+ ABS_MT_PRESSURE, pressure); | |
#endif | |
#ifndef TYPE_B_PROTOCOL | |
input_mt_sync(rmi4_data->input_dev); | |
#endif | |
+ input_sync(rmi4_data->input_dev); | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
"%s: Finger %d: " | |
@@ -1476,36 +1715,33 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
break; | |
case F12_STYLUS_STATUS: | |
case F12_ERASER_STATUS: | |
- if (rmi4_data->stylus_enable && rmi4_data->stylus_dev != NULL) { | |
- if (finger_presence) { /* Stylus has priority over fingers */ | |
- mutex_unlock(&(rmi4_data->rmi4_report_mutex)); | |
- synaptics_rmi4_free_fingers(rmi4_data); | |
- mutex_lock(&(rmi4_data->rmi4_report_mutex)); | |
- finger_presence = 0; | |
- } | |
- if (stylus_presence) {/* Allow one stylus at a timee */ | |
- if (finger + 1 != stylus_presence) | |
- break; | |
- } | |
+ if (finger_presence) { /* Stylus has priority over fingers */ | |
+ mutex_unlock(&(rmi4_data->rmi4_report_mutex)); | |
+ synaptics_rmi4_free_fingers(rmi4_data); | |
+ mutex_lock(&(rmi4_data->rmi4_report_mutex)); | |
+ finger_presence = 0; | |
+ } | |
+ if (stylus_presence) {/* Allow one stylus at a timee */ | |
+ if (finger + 1 != stylus_presence) | |
+ break; | |
+ } | |
+ input_report_key(rmi4_data->stylus_dev, | |
+ BTN_TOUCH, 1); | |
+ if (finger_status == F12_STYLUS_STATUS) { | |
input_report_key(rmi4_data->stylus_dev, | |
- BTN_TOUCH, 1); | |
- if (finger_status == F12_STYLUS_STATUS) { | |
- input_report_key(rmi4_data->stylus_dev, | |
- BTN_TOOL_PEN, 1); | |
- } else { | |
- input_report_key(rmi4_data->stylus_dev, | |
- BTN_TOOL_RUBBER, 1); | |
- } | |
- input_report_abs(rmi4_data->stylus_dev, | |
- ABS_X, x); | |
- input_report_abs(rmi4_data->stylus_dev, | |
- ABS_Y, y); | |
- input_sync(rmi4_data->stylus_dev); | |
- | |
- stylus_presence = finger + 1; | |
- touch_count++; | |
+ BTN_TOOL_PEN, 1); | |
+ } else { | |
+ input_report_key(rmi4_data->stylus_dev, | |
+ BTN_TOOL_RUBBER, 1); | |
} | |
+ input_report_abs(rmi4_data->stylus_dev, | |
+ ABS_X, x); | |
+ input_report_abs(rmi4_data->stylus_dev, | |
+ ABS_Y, y); | |
+ input_sync(rmi4_data->stylus_dev); | |
+ stylus_presence = finger + 1; | |
+ touch_count++; | |
break; | |
default: | |
#ifdef TYPE_B_PROTOCOL | |
@@ -1531,7 +1767,7 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
#endif | |
input_sync(rmi4_data->input_dev); | |
- if (rmi4_data->stylus_enable && rmi4_data->stylus_dev != NULL) { | |
+ if (rmi4_data->stylus_enable) { | |
stylus_presence = 0; | |
input_report_key(rmi4_data->stylus_dev, | |
BTN_TOUCH, 0); | |
@@ -1545,8 +1781,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data, | |
} | |
} | |
- input_sync(rmi4_data->input_dev); | |
- | |
mutex_unlock(&(rmi4_data->rmi4_report_mutex)); | |
return touch_count; | |
@@ -1600,9 +1834,10 @@ static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data, | |
shift = button % 8; | |
status = ((data[index] >> shift) & MASK_1BIT); | |
- if (current_status[button] == status) | |
- continue; | |
- else | |
+ if (current_status[button] == status) { | |
+ if (!rmi4_data->suspend) | |
+ continue; | |
+ } else | |
current_status[button] = status; | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
@@ -1622,6 +1857,17 @@ static void synaptics_rmi4_f1a_report(struct synaptics_rmi4_data *rmi4_data, | |
before_2d_status[button] = 0; | |
} | |
} | |
+ | |
+ if (f1a->button_map[button] == KEY_HOME) { | |
+ if (captouch_key_report_ptr != NULL) { | |
+ captouch_key_report_ptr(status); | |
+ } else { | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: captouch is enabled but captouch_key_report_ptr is NULL\n", __func__); | |
+ } | |
+ if (check_captouch_support(rmi4_data)) | |
+ continue; | |
+ } | |
touch_count++; | |
input_report_key(rmi4_data->input_dev, | |
f1a->button_map[button], | |
@@ -1694,8 +1940,6 @@ static void synaptics_rmi4_report_touch(struct synaptics_rmi4_data *rmi4_data, | |
return; | |
} | |
-extern void mdss_fb_prim_panel_recover(void); | |
- | |
static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data, | |
bool report) | |
{ | |
@@ -1725,9 +1969,6 @@ static void synaptics_rmi4_sensor_report(struct synaptics_rmi4_data *rmi4_data, | |
return; | |
} | |
- if (rmi4_data->chip_id == CHIP_ID_4322 && (status.status_code == 0x09 && status.unconfigured)) | |
- mdss_fb_prim_panel_recover(); | |
- | |
status.data[0] = data[0]; | |
if (status.status_code == STATUS_CRC_IN_PROGRESS) { | |
retval = synaptics_rmi4_check_status(rmi4_data, | |
@@ -1948,26 +2189,39 @@ static int synaptics_rmi4_query_product_id(struct synaptics_rmi4_data *rmi4_data | |
static int synaptics_rmi4_query_chip_id(struct synaptics_rmi4_data *rmi4_data) | |
{ | |
int retval; | |
- unsigned short lockdown_addr; | |
+ unsigned short chipdata_addr; | |
unsigned char query_data[8] = {0}; | |
- lockdown_addr = rmi4_data->f01_query_base_addr + F01_PROD_ID_OFFSET; | |
+ chipdata_addr = rmi4_data->f01_query_base_addr + F01_PROD_ID_OFFSET; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- lockdown_addr, | |
+ chipdata_addr, | |
query_data, | |
8); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"Failed reading reg %d\n", | |
- lockdown_addr); | |
+ chipdata_addr); | |
return retval; | |
} | |
- if (query_data[0] == 0x53) | |
- rmi4_data->chip_id = CHIP_ID_3330; | |
- else { | |
- rmi4_data->chip_id = CHIP_ID_4322; | |
+ dev_info(rmi4_data->pdev->dev.parent, | |
+ "chip info: 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", | |
+ query_data[0], query_data[1], | |
+ query_data[2], query_data[3], | |
+ query_data[4], query_data[5], | |
+ query_data[6], query_data[7]); | |
+ | |
+ | |
+ if (query_data[0] == 0x53 && query_data[4] == 0x30) | |
+ rmi4_data->chip_id = rmi4_data->hw_if->board_data->chip_3330; | |
+ else if (query_data[0] == 0x53 && query_data[4] == 0x31) | |
+ rmi4_data->chip_id = rmi4_data->hw_if->board_data->chip_3331; | |
+ else if (query_data[0] == 0x54 && query_data[3] == 0x33) { | |
+ rmi4_data->chip_id = rmi4_data->hw_if->board_data->chip_4322; | |
+ rmi4_data->hw_if->board_data->reset_gpio = -1; | |
+ } else if (query_data[0] == 0x54 && query_data[3] == 0x37) { | |
+ rmi4_data->chip_id = rmi4_data->hw_if->board_data->chip_4722; | |
rmi4_data->hw_if->board_data->reset_gpio = -1; | |
} | |
@@ -2255,93 +2509,94 @@ static int synaptics_rmi4_f12_set_enables(struct synaptics_rmi4_data *rmi4_data, | |
return retval; | |
} | |
-static int synaptics_rmi4_f12_ctrl_sub(struct synaptics_rmi4_data *rmi4_data, | |
+static int synaptics_rmi4_f12_find_sub(struct synaptics_rmi4_data *rmi4_data, | |
struct synaptics_rmi4_fn *fhandler, | |
- struct synaptics_rmi4_f12_query_5 *query_5, | |
- unsigned char ctrlreg, unsigned char subpacket) | |
+ unsigned char *presence, unsigned char presence_size, | |
+ unsigned char structure_offset, unsigned char reg, | |
+ unsigned char sub) | |
{ | |
int retval; | |
unsigned char cnt; | |
unsigned char regnum; | |
unsigned char bitnum; | |
- unsigned char q5_index; | |
- unsigned char q6_index; | |
+ unsigned char p_index; | |
+ unsigned char s_index; | |
unsigned char offset; | |
- unsigned char max_ctrlreg; | |
- unsigned char *query_6; | |
+ unsigned char max_reg; | |
+ unsigned char *structure; | |
- max_ctrlreg = (sizeof(query_5->data) - 1) * 8 - 1; | |
+ max_reg = (presence_size - 1) * 8 - 1; | |
- if (ctrlreg > max_ctrlreg) { | |
+ if (reg > max_reg) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Control register number (%d) over limit\n", | |
- __func__, ctrlreg); | |
+ "%s: Register number (%d) over limit\n", | |
+ __func__, reg); | |
return -EINVAL; | |
} | |
- q5_index = ctrlreg / 8 + 1; | |
- bitnum = ctrlreg % 8; | |
- if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) { | |
+ p_index = reg / 8 + 1; | |
+ bitnum = reg % 8; | |
+ if ((presence[p_index] & (1 << bitnum)) == 0x00) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Control %d is not present\n", | |
- __func__, ctrlreg); | |
+ "%s: Register %d is not present\n", | |
+ __func__, reg); | |
return -EINVAL; | |
} | |
- query_6 = kmalloc(query_5->size_of_query6, GFP_KERNEL); | |
- if (!query_6) { | |
+ structure = kmalloc(presence[0], GFP_KERNEL); | |
+ if (!structure) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to alloc mem for query 6\n", | |
+ "%s: Failed to alloc mem for structure register\n", | |
__func__); | |
return -ENOMEM; | |
} | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- fhandler->full_addr.query_base + 6, | |
- query_6, | |
- query_5->size_of_query6); | |
+ fhandler->full_addr.query_base + structure_offset, | |
+ structure, | |
+ presence[0]); | |
if (retval < 0) | |
goto exit; | |
- q6_index = 0; | |
+ s_index = 0; | |
- for (regnum = 0; regnum < ctrlreg; regnum++) { | |
- q5_index = regnum / 8 + 1; | |
+ for (regnum = 0; regnum < reg; regnum++) { | |
+ p_index = regnum / 8 + 1; | |
bitnum = regnum % 8; | |
- if ((query_5->data[q5_index] & (1 << bitnum)) == 0x00) | |
+ if ((presence[p_index] & (1 << bitnum)) == 0x00) | |
continue; | |
- if (query_6[q6_index] == 0x00) | |
- q6_index += 3; | |
+ if (structure[s_index] == 0x00) | |
+ s_index += 3; | |
else | |
- q6_index++; | |
+ s_index++; | |
- while (query_6[q6_index] & ~MASK_7BIT) | |
- q6_index++; | |
+ while (structure[s_index] & ~MASK_7BIT) | |
+ s_index++; | |
- q6_index++; | |
+ s_index++; | |
} | |
cnt = 0; | |
- q6_index++; | |
- offset = subpacket / 7; | |
- bitnum = subpacket % 7; | |
+ s_index++; | |
+ offset = sub / 7; | |
+ bitnum = sub % 7; | |
do { | |
if (cnt == offset) { | |
- if (query_6[q6_index + cnt] & (1 << bitnum)) | |
+ if (structure[s_index + cnt] & (1 << bitnum)) | |
retval = 1; | |
else | |
retval = 0; | |
goto exit; | |
} | |
cnt++; | |
- } while (query_6[q6_index + cnt - 1] & ~MASK_7BIT); | |
+ } while (structure[s_index + cnt - 1] & ~MASK_7BIT); | |
retval = 0; | |
exit: | |
- kfree(query_6); | |
+ kfree(structure); | |
return retval; | |
} | |
@@ -2356,13 +2611,17 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
unsigned char subpacket; | |
unsigned char ctrl_23_size; | |
unsigned char size_of_2d_data; | |
+ unsigned char size_of_query5; | |
unsigned char size_of_query8; | |
unsigned char ctrl_8_offset; | |
unsigned char ctrl_20_offset; | |
unsigned char ctrl_23_offset; | |
unsigned char ctrl_26_offset; | |
+ unsigned char ctrl_27_offset; | |
unsigned char ctrl_28_offset; | |
unsigned char ctrl_31_offset; | |
+ unsigned char ctrl_47_offset; | |
+ unsigned char ctrl_58_offset; | |
unsigned char num_of_fingers; | |
struct synaptics_rmi4_f12_extra_data *extra_data; | |
struct synaptics_rmi4_f12_query_5 *query_5 = NULL; | |
@@ -2370,6 +2629,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
struct synaptics_rmi4_f12_ctrl_8 *ctrl_8 = NULL; | |
struct synaptics_rmi4_f12_ctrl_23 *ctrl_23 = NULL; | |
struct synaptics_rmi4_f12_ctrl_31 *ctrl_31 = NULL; | |
+ struct synaptics_rmi4_f12_ctrl_58 *ctrl_58 = NULL; | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
@@ -2385,7 +2645,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; | |
size_of_2d_data = sizeof(struct synaptics_rmi4_f12_finger_data); | |
- query_5 = kmalloc(sizeof(*query_5), GFP_KERNEL); | |
+ query_5 = kzalloc(sizeof(*query_5), GFP_KERNEL); | |
if (!query_5) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to alloc mem for query_5\n", | |
@@ -2394,7 +2654,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
- query_8 = kmalloc(sizeof(*query_8), GFP_KERNEL); | |
+ query_8 = kzalloc(sizeof(*query_8), GFP_KERNEL); | |
if (!query_8) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to alloc mem for query_8\n", | |
@@ -2403,7 +2663,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
- ctrl_8 = kmalloc(sizeof(*ctrl_8), GFP_KERNEL); | |
+ ctrl_8 = kzalloc(sizeof(*ctrl_8), GFP_KERNEL); | |
if (!ctrl_8) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to alloc mem for ctrl_8\n", | |
@@ -2412,7 +2672,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
- ctrl_23 = kmalloc(sizeof(*ctrl_23), GFP_KERNEL); | |
+ ctrl_23 = kzalloc(sizeof(*ctrl_23), GFP_KERNEL); | |
if (!ctrl_23) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to alloc mem for ctrl_23\n", | |
@@ -2421,7 +2681,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
- ctrl_31 = kmalloc(sizeof(*ctrl_31), GFP_KERNEL); | |
+ ctrl_31 = kzalloc(sizeof(*ctrl_31), GFP_KERNEL); | |
if (!ctrl_31) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to alloc mem for ctrl_31\n", | |
@@ -2430,10 +2690,36 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
+ ctrl_58 = kzalloc(sizeof(*ctrl_58), GFP_KERNEL); | |
+ if (!ctrl_58) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for ctrl_58\n", | |
+ __func__); | |
+ retval = -ENOMEM; | |
+ goto exit; | |
+ } | |
+ | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ fhandler->full_addr.query_base + 4, | |
+ &size_of_query5, | |
+ sizeof(size_of_query5)); | |
+ if (retval < 0) | |
+ goto exit; | |
+ | |
+ pr_err("%s %d: fhandler->full_addr.query_base = 0x%04x\n", __func__, __LINE__, fhandler->full_addr.query_base); | |
+ pr_err("%s %d: fhandler->full_addr.ctrl_base = 0x%04x\n", __func__, __LINE__, fhandler->full_addr.ctrl_base); | |
+ pr_err("%s %d: size_of_query5 = %d\n", __func__, __LINE__, size_of_query5); | |
+ | |
+ if (size_of_query5 > sizeof(query_5->data)) | |
+ size_of_query5 = sizeof(query_5->data); | |
+ memset(query_5->data, 0x00, sizeof(query_5->data)); | |
+ | |
+ pr_err("%s %d: size_of_query5 = %d\n", __func__, __LINE__, size_of_query5); | |
+ | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
fhandler->full_addr.query_base + 5, | |
query_5->data, | |
- sizeof(query_5->data)); | |
+ size_of_query5); | |
if (retval < 0) | |
goto exit; | |
@@ -2471,8 +2757,10 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
query_5->ctrl24_is_present + | |
query_5->ctrl25_is_present; | |
- ctrl_28_offset = ctrl_26_offset + | |
- query_5->ctrl26_is_present + | |
+ ctrl_27_offset = ctrl_26_offset + | |
+ query_5->ctrl26_is_present; | |
+ | |
+ ctrl_28_offset = ctrl_27_offset + | |
query_5->ctrl27_is_present; | |
ctrl_31_offset = ctrl_28_offset + | |
@@ -2480,10 +2768,41 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
query_5->ctrl29_is_present + | |
query_5->ctrl30_is_present; | |
+ ctrl_47_offset = ctrl_31_offset + | |
+ query_5->ctrl31_is_present + | |
+ query_5->ctrl32_is_present + | |
+ query_5->ctrl33_is_present + | |
+ query_5->ctrl34_is_present + | |
+ query_5->ctrl35_is_present + | |
+ query_5->ctrl36_is_present + | |
+ query_5->ctrl37_is_present + | |
+ query_5->ctrl38_is_present + | |
+ query_5->ctrl39_is_present + | |
+ query_5->ctrl40_is_present + | |
+ query_5->ctrl41_is_present + | |
+ query_5->ctrl42_is_present + | |
+ query_5->ctrl43_is_present + | |
+ query_5->ctrl44_is_present + | |
+ query_5->ctrl45_is_present + | |
+ query_5->ctrl46_is_present; | |
+ ctrl_58_offset = ctrl_47_offset + | |
+ query_5->ctrl47_is_present + | |
+ query_5->ctrl48_is_present + | |
+ query_5->ctrl49_is_present + | |
+ query_5->ctrl50_is_present + | |
+ query_5->ctrl51_is_present + | |
+ query_5->ctrl52_is_present + | |
+ query_5->ctrl53_is_present + | |
+ query_5->ctrl54_is_present + | |
+ query_5->ctrl55_is_present + | |
+ query_5->ctrl56_is_present + | |
+ query_5->ctrl57_is_present; | |
+ | |
ctrl_23_size = 2; | |
for (subpacket = 2; subpacket <= 4; subpacket++) { | |
- retval = synaptics_rmi4_f12_ctrl_sub(rmi4_data, | |
- fhandler, query_5, 23, subpacket); | |
+ retval = synaptics_rmi4_f12_find_sub(rmi4_data, | |
+ fhandler, query_5->data, sizeof(query_5->data), | |
+ 6, 23, subpacket); | |
if (retval == 1) | |
ctrl_23_size++; | |
else if (retval < 0) | |
@@ -2498,7 +2817,8 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
/* Maximum number of fingers supported */ | |
- fhandler->num_of_data_points = min(ctrl_23->max_reported_objects, | |
+ fhandler->num_of_data_points = min_t(unsigned char, | |
+ ctrl_23->max_reported_objects, | |
(unsigned char)F12_FINGERS_TO_SUPPORT); | |
num_of_fingers = fhandler->num_of_data_points; | |
@@ -2514,6 +2834,10 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
if (retval < 0) | |
goto exit; | |
+ if (size_of_query8 > sizeof(query_8->data)) | |
+ size_of_query8 = sizeof(query_8->data); | |
+ memset(query_8->data, 0x00, sizeof(query_8->data)); | |
+ | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
fhandler->full_addr.query_base + 8, | |
query_8->data, | |
@@ -2546,8 +2870,8 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
} | |
#ifdef REPORT_2D_PRESSURE | |
- if ((size_of_query8 >= 4) && (query_8->data23_is_present)) { | |
- extra_data->data23_offset = query_8->data0_is_present + | |
+ if ((size_of_query8 >= 5) && (query_8->data29_is_present)) { | |
+ extra_data->data29_offset = query_8->data0_is_present + | |
query_8->data1_is_present + | |
query_8->data2_is_present + | |
query_8->data3_is_present + | |
@@ -2569,11 +2893,48 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
query_8->data19_is_present + | |
query_8->data20_is_present + | |
query_8->data21_is_present + | |
- query_8->data22_is_present; | |
- extra_data->data23_size = num_of_fingers; | |
+ query_8->data22_is_present + | |
+ query_8->data23_is_present + | |
+ query_8->data24_is_present + | |
+ query_8->data25_is_present + | |
+ query_8->data26_is_present + | |
+ query_8->data27_is_present + | |
+ query_8->data28_is_present; | |
+ extra_data->data29_size = 0; | |
+ for (subpacket = 0; subpacket <= num_of_fingers; subpacket++) { | |
+ retval = synaptics_rmi4_f12_find_sub(rmi4_data, | |
+ fhandler, query_8->data, | |
+ sizeof(query_8->data), | |
+ 9, 29, subpacket); | |
+ if (retval == 1) | |
+ extra_data->data29_size += 2; | |
+ else if (retval < 0) | |
+ goto exit; | |
+ } | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ fhandler->full_addr.ctrl_base + ctrl_58_offset, | |
+ ctrl_58->data, | |
+ sizeof(ctrl_58->data)); | |
+ if (retval < 0) | |
+ goto exit; | |
+ | |
+ pr_err("%s %d: extra_data->data29_offset = %d\n", __func__, __LINE__, extra_data->data29_offset); | |
+ pr_err("%s %d: extra_data->data29_size = %d\n", __func__, __LINE__, extra_data->data29_size); | |
+ pr_err("%s %d: ctrl_58_offset = %d\n", __func__, __LINE__, ctrl_58_offset); | |
+ | |
+ rmi4_data->force_min = | |
+ (int)(ctrl_58->min_force_lsb << 0) | | |
+ (int)(ctrl_58->min_force_msb << 8); | |
+ rmi4_data->force_max = | |
+ (int)(ctrl_58->max_force_lsb << 0) | | |
+ (int)(ctrl_58->max_force_msb << 8); | |
+ | |
+ pr_err("%s %d: rmi4_data->force_min = %d\n", __func__, __LINE__, rmi4_data->force_min); | |
+ pr_err("%s %d: rmi4_data->force_max = %d\n", __func__, __LINE__, rmi4_data->force_max); | |
+ | |
rmi4_data->report_pressure = true; | |
} else { | |
- extra_data->data23_size = 0; | |
+ extra_data->data29_size = 0; | |
rmi4_data->report_pressure = false; | |
} | |
#endif | |
@@ -2655,6 +3016,7 @@ static int synaptics_rmi4_f12_init(struct synaptics_rmi4_data *rmi4_data, | |
synaptics_rmi4_set_intr_mask(fhandler, fd, intr_count); | |
extra_data->ctrl26_offset = ctrl_26_offset; | |
+ extra_data->ctrl27_offset = ctrl_27_offset; | |
/* Allocate memory for finger data storage space */ | |
fhandler->data_size = num_of_fingers * size_of_2d_data; | |
@@ -2673,6 +3035,7 @@ exit: | |
kfree(ctrl_8); | |
kfree(ctrl_23); | |
kfree(ctrl_31); | |
+ kfree(ctrl_58); | |
return retval; | |
} | |
@@ -2743,18 +3106,19 @@ static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data, | |
{ | |
int retval; | |
unsigned char ii; | |
- unsigned char mapping_offset = 0; | |
+ unsigned char offset = 0; | |
+ struct synaptics_rmi4_f1a_query_4 query_4; | |
struct synaptics_rmi4_f1a_handle *f1a = fhandler->data; | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
- mapping_offset = f1a->button_query.has_general_control + | |
+ offset = f1a->button_query.has_general_control + | |
f1a->button_query.has_interrupt_enable + | |
f1a->button_query.has_multibutton_select; | |
if (f1a->button_query.has_tx_rx_map) { | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- fhandler->full_addr.ctrl_base + mapping_offset, | |
+ fhandler->full_addr.ctrl_base + offset, | |
f1a->button_control.txrx_map, | |
f1a->max_count * 2); | |
if (retval < 0) { | |
@@ -2767,6 +3131,27 @@ static int synaptics_rmi4_f1a_button_map(struct synaptics_rmi4_data *rmi4_data, | |
rmi4_data->button_txrx_mapping = f1a->button_control.txrx_map; | |
} | |
+ if (f1a->button_query.has_query4) { | |
+ offset = 2 + f1a->button_query.has_query2 + | |
+ f1a->button_query.has_query3; | |
+ | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ fhandler->full_addr.query_base + offset, | |
+ query_4.data, | |
+ sizeof(query_4.data)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read button features 4\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ if (query_4.has_ctrl24) | |
+ rmi4_data->external_afe_buttons = true; | |
+ else | |
+ rmi4_data->external_afe_buttons = false; | |
+ } | |
+ | |
if (!bdata->cap_button_map) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: cap_button_map is NULL in board file\n", | |
@@ -2945,7 +3330,7 @@ static void synaptics_rmi4_set_configured(struct synaptics_rmi4_data *rmi4_data) | |
static int synaptics_rmi4_alloc_fh(struct synaptics_rmi4_fn **fhandler, | |
struct synaptics_rmi4_fn_desc *rmi_fd, int page_number) | |
{ | |
- *fhandler = kmalloc(sizeof(**fhandler), GFP_KERNEL); | |
+ *fhandler = kzalloc(sizeof(**fhandler), GFP_KERNEL); | |
if (!(*fhandler)) | |
return -ENOMEM; | |
@@ -3124,11 +3509,29 @@ rescan_pdt: | |
case SYNAPTICS_RMI4_F35: | |
f35found = true; | |
break; | |
- case SYNAPTICS_RMI4_F54: | |
- rmi4_data->f54_cmd_base_addr = | |
- rmi_fd.cmd_base_addr | | |
+ | |
+ case SYNAPTICS_RMI4_F51: | |
+ if (rmi4_data->hw_if->board_data->captouch_use) { | |
+ retval = synaptics_rmi4_alloc_fh(&fhandler, | |
+ &rmi_fd, page_number); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc for F%d\n", | |
+ __func__, | |
+ rmi_fd.fn_number); | |
+ return retval; | |
+ } | |
+ | |
+ fhandler->fn_number = SYNAPTICS_RMI4_F51; | |
+ fhandler->data = NULL; | |
+ fhandler->extra = NULL; | |
+ } | |
+#ifdef F51_DISCRETE_FORCE | |
+ rmi4_data->f51_query_base_addr = | |
+ rmi_fd.query_base_addr | | |
(page_number << 8); | |
break; | |
+#endif | |
} | |
/* Accumulate the interrupt count */ | |
@@ -3328,9 +3731,13 @@ static void synaptics_rmi4_set_params(struct synaptics_rmi4_data *rmi4_data) | |
#ifdef REPORT_2D_PRESSURE | |
if (rmi4_data->report_pressure) { | |
input_set_abs_params(rmi4_data->input_dev, | |
- ABS_MT_PRESSURE, 0, | |
- MAX_F12_TOUCH_PRESSURE, 0, 0); | |
+ ABS_MT_PRESSURE, rmi4_data->force_min, | |
+ rmi4_data->force_max, 0, 0); | |
} | |
+#elif defined(F51_DISCRETE_FORCE) | |
+ input_set_abs_params(rmi4_data->input_dev, | |
+ ABS_MT_PRESSURE, 0, | |
+ FORCE_LEVEL_MAX, 0, 0); | |
#endif | |
#ifdef TYPE_B_PROTOCOL | |
@@ -3385,13 +3792,19 @@ static void synaptics_rmi4_wakeup_reconfigure(struct synaptics_rmi4_data *rmi4_d | |
synaptics_rmi4_sleep_enable(rmi4_data, !enable); | |
- if (enable) | |
- mdss_regulator_ctrl(rmi4_data, true); | |
+ if (enable) { | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, true); | |
+ if (rmi4_data->hw_if->board_data->mdss_reset != 0) | |
+ gpio_set_value(rmi4_data->hw_if->board_data->mdss_reset, rmi4_data->hw_if->board_data->mdss_reset_state); | |
+ } | |
synaptics_rmi4_wakeup_gesture(rmi4_data, enable); | |
- if (!enable) | |
- mdss_regulator_ctrl(rmi4_data, false); | |
+ if (!enable) { | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, false); | |
+ if (rmi4_data->hw_if->board_data->mdss_reset != 0) | |
+ gpio_set_value(rmi4_data->hw_if->board_data->mdss_reset, !rmi4_data->hw_if->board_data->mdss_reset_state); | |
+ } | |
synaptics_rmi4_irq_enable(rmi4_data, enable, false); | |
@@ -3451,52 +3864,6 @@ static void synaptics_key_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enabl | |
return ; | |
} | |
-static void do_force_update(struct synaptics_rmi4_data *rmi4_data) | |
-{ | |
- int retval; | |
- unsigned char command = 0x04; | |
- unsigned char timeout_count; | |
- | |
- retval = synaptics_rmi4_reg_write(rmi4_data, | |
- rmi4_data->f54_cmd_base_addr, | |
- &command, | |
- sizeof(command)); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to write command\n", | |
- __func__); | |
- return; | |
- } | |
- | |
- timeout_count = 0; | |
- do { | |
- retval = synaptics_rmi4_reg_read(rmi4_data, | |
- rmi4_data->f54_cmd_base_addr, | |
- &command, | |
- sizeof(command)); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to read command register\n", | |
- __func__); | |
- return; | |
- } | |
- | |
- if ((command & 0x04) == 0x00) | |
- break; | |
- | |
- msleep(100); | |
- timeout_count++; | |
- } while (timeout_count < COMMAND_TIMEOUT_100MS); | |
- | |
- if (timeout_count == COMMAND_TIMEOUT_100MS) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Timed out waiting for command completion\n", | |
- __func__); | |
- } | |
- | |
- return; | |
-} | |
- | |
static void cover_mode_set(struct synaptics_rmi4_data *rmi4_data, int enable) | |
{ | |
struct synaptics_rmi4_f12_extra_data *extra_data; | |
@@ -3548,9 +3915,6 @@ static void cover_mode_set(struct synaptics_rmi4_data *rmi4_data, int enable) | |
} | |
synaptics_key_ctrl(rmi4_data, true); | |
- | |
- if (rmi4_data->chip_id == CHIP_ID_4322) | |
- do_force_update(rmi4_data); | |
} else { | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
fhandler->full_addr.ctrl_base + extra_data->ctrl26_offset, | |
@@ -3582,9 +3946,6 @@ static void cover_mode_set(struct synaptics_rmi4_data *rmi4_data, int enable) | |
} | |
synaptics_key_ctrl(rmi4_data, false); | |
- | |
- if (rmi4_data->chip_id == CHIP_ID_4322) | |
- do_force_update(rmi4_data); | |
} | |
mutex_unlock(&rmi4_data->rmi4_cover_mutex); | |
@@ -3606,12 +3967,15 @@ static void synaptics_rmi4_switch_mode_work(struct work_struct *work) | |
rmi4_data->enable_wakeup_gesture = value - INPUT_EVENT_WAKUP_MODE_OFF; | |
- if (rmi4_data->suspend && rmi4_data->chip_id != CHIP_ID_4322) | |
+ if (rmi4_data->suspend && rmi4_data->chip_id != bdata->chip_4322 && rmi4_data->chip_id != bdata->chip_4722) | |
synaptics_rmi4_wakeup_reconfigure(rmi4_data, | |
(bool)rmi4_data->enable_wakeup_gesture); | |
} else if (value >= INPUT_EVENT_COVER_MODE_OFF && value <= INPUT_EVENT_COVER_MODE_ON) { | |
rmi4_data->enable_cover_mode = value - INPUT_EVENT_COVER_MODE_OFF; | |
cover_mode_set(rmi4_data, rmi4_data->enable_cover_mode); | |
+ } else if (value >= INPUT_EVENT_CAPTOUCH_MODE_OFF && value <= INPUT_EVENT_CAPTOUCH_MODE_ON) { | |
+ if (bdata->captouch_use) | |
+ rmi4_data->homekey_wakeup = value - INPUT_EVENT_CAPTOUCH_MODE_OFF; | |
} else { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"Does not support touch mode %d\n", value); | |
@@ -3986,12 +4350,6 @@ static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data) | |
{ | |
unsigned char ii; | |
- if (rmi4_data->input_dev == NULL) { | |
- dev_err(rmi4_data->pdev->dev.parent, "input_dev is NULL, do not report data\n"); | |
- | |
- return 0; | |
- } | |
- | |
mutex_lock(&(rmi4_data->rmi4_report_mutex)); | |
#ifdef TYPE_B_PROTOCOL | |
@@ -4010,7 +4368,7 @@ static int synaptics_rmi4_free_fingers(struct synaptics_rmi4_data *rmi4_data) | |
#endif | |
input_sync(rmi4_data->input_dev); | |
- if (rmi4_data->stylus_enable && rmi4_data->stylus_dev != NULL) { | |
+ if (rmi4_data->stylus_enable) { | |
input_report_key(rmi4_data->stylus_dev, | |
BTN_TOUCH, 0); | |
input_report_key(rmi4_data->stylus_dev, | |
@@ -4049,9 +4407,6 @@ static int synaptics_rmi4_sw_reset(struct synaptics_rmi4_data *rmi4_data) | |
return retval; | |
} | |
- if (rmi4_data->chip_id != CHIP_ID_3330) | |
- synaptics_rmi4_protection_film(rmi4_data); | |
- | |
return 0; | |
} | |
@@ -4345,7 +4700,7 @@ static void synaptics_rmi4_exp_fn_work(struct work_struct *work) | |
return; | |
} | |
-void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn, | |
+void synaptics_rmi4_new_function_force(struct synaptics_rmi4_exp_fn *exp_fn, | |
bool insert) | |
{ | |
struct synaptics_rmi4_exp_fhandler *exp_fhandler; | |
@@ -4389,7 +4744,6 @@ exit: | |
return; | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_new_function); | |
static void charger_reg_set(struct synaptics_rmi4_data *rmi4_data, bool enable) | |
{ | |
@@ -4403,6 +4757,8 @@ static void charger_reg_set(struct synaptics_rmi4_data *rmi4_data, bool enable) | |
&val, | |
1); | |
if (retval < 0) { | |
+ pr_err("%s: Failed to read reg of charger noise\n", __func__); | |
+ | |
mutex_unlock(&rmi4_data->rmi4_charger_mutex); | |
return ; | |
@@ -4418,6 +4774,9 @@ static void charger_reg_set(struct synaptics_rmi4_data *rmi4_data, bool enable) | |
&val, | |
1); | |
+ if (retval < 0) | |
+ pr_err("%s: Failed to write reg of charger noise\n", __func__); | |
+ | |
mutex_unlock(&rmi4_data->rmi4_charger_mutex); | |
} | |
@@ -4452,31 +4811,167 @@ static int synaptics_power_supply_event(struct notifier_block *nb, unsigned long | |
return 0; | |
} | |
-static void synaptics_rmi4_protection_film(struct synaptics_rmi4_data *rmi4_data) | |
+#ifdef CONFIG_TOUCH_DEBUG_FS | |
+static int synaptics_tpdbg_suspend(struct synaptics_rmi4_data *rmi4_data) | |
{ | |
- unsigned char value; | |
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler; | |
+ | |
+ synaptics_rmi4_irq_enable(rmi4_data, false, false); | |
+ if (!rmi4_data->enable_wakeup_gesture && !rmi4_data->homekey_wakeup) | |
+ synaptics_rmi4_sleep_enable(rmi4_data, true); | |
- value = 0x1e; | |
- synaptics_rmi4_reg_write(rmi4_data, BTN_DOZE_WAKEUP_TH, &value, sizeof(value)); | |
+ if (rmi4_data->enable_wakeup_gesture || rmi4_data->homekey_wakeup) { | |
+ msleep(300); | |
+ synaptics_rmi4_wakeup_gesture(rmi4_data, true); | |
+ synaptics_rmi4_irq_enable(rmi4_data, true, false); | |
+ goto exit; | |
+ } | |
- value = 0x80; | |
- synaptics_rmi4_reg_write(rmi4_data, BTN_FAST_RELAX_RATE, &value, sizeof(value)); | |
+ mutex_lock(&exp_data.mutex); | |
+ if (!list_empty(&exp_data.list)) { | |
+ list_for_each_entry(exp_fhandler, &exp_data.list, link) | |
+ if (exp_fhandler->exp_fn->suspend != NULL) | |
+ exp_fhandler->exp_fn->suspend(rmi4_data); | |
+ } | |
+ mutex_unlock(&exp_data.mutex); | |
- value = 0x0a; | |
- synaptics_rmi4_reg_write(rmi4_data, BTN_SLOW_RELAX_RATE, &value, sizeof(value)); | |
+exit: | |
+ return 0; | |
+} | |
- value = 0x80; | |
- synaptics_rmi4_reg_write(rmi4_data, BTN_RELEASE_TH, &value, sizeof(value)); | |
+static int synaptics_tpdbg_resume(struct synaptics_rmi4_data *rmi4_data) | |
+{ | |
+ struct synaptics_rmi4_exp_fhandler *exp_fhandler; | |
+ const struct synaptics_dsx_board_data *bdata = | |
+ rmi4_data->hw_if->board_data; | |
- value = 0x54; | |
- synaptics_rmi4_reg_write(rmi4_data, BTN_TOUCH_TH1, &value, sizeof(value)); | |
+ if (rmi4_data->enable_wakeup_gesture || rmi4_data->homekey_wakeup) { | |
+ synaptics_rmi4_wakeup_gesture(rmi4_data, false); | |
+ if (bdata->reset_gpio >= 0) { | |
+ gpio_set_value(bdata->reset_gpio, bdata->reset_on_state); | |
+ msleep(bdata->reset_active_ms); | |
+ gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state); | |
+ msleep(bdata->reset_delay_ms); | |
+ } | |
+ } else { | |
+ rmi4_data->current_page = MASK_8BIT; | |
+ if (bdata->reset_gpio >= 0) { | |
+ gpio_set_value(bdata->reset_gpio, bdata->reset_on_state); | |
+ msleep(bdata->reset_active_ms); | |
+ gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state); | |
+ msleep(bdata->reset_delay_ms); | |
+ } | |
- value = 0x54; | |
- synaptics_rmi4_reg_write(rmi4_data, BTN_TOUCH_TH2, &value, sizeof(value)); | |
+ synaptics_rmi4_sleep_enable(rmi4_data, false); | |
+ synaptics_rmi4_irq_enable(rmi4_data, true, false); | |
- do_force_update(rmi4_data); | |
+ mutex_lock(&exp_data.mutex); | |
+ if (!list_empty(&exp_data.list)) { | |
+ list_for_each_entry(exp_fhandler, &exp_data.list, link) | |
+ if (exp_fhandler->exp_fn->resume != NULL) | |
+ exp_fhandler->exp_fn->resume(rmi4_data); | |
+ } | |
+ mutex_unlock(&exp_data.mutex); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+static void tpdbg_shutdown(struct synaptics_rmi4_data *rmi4_data, bool sleep) | |
+{ | |
+ synaptics_rmi4_sleep_enable(rmi4_data, sleep); | |
+} | |
+ | |
+static void tpdbg_suspend(struct synaptics_rmi4_data *rmi4_data, bool enable) | |
+{ | |
+ if (enable) | |
+ synaptics_tpdbg_suspend(rmi4_data); | |
+ else | |
+ synaptics_tpdbg_resume(rmi4_data); | |
+} | |
+ | |
+static int tpdbg_open(struct inode *inode, struct file *file) | |
+{ | |
+ file->private_data = inode->i_private; | |
+ | |
+ return 0; | |
+} | |
+ | |
+ssize_t tpdbg_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) | |
+{ | |
+ const char *str = "cmd support as below:\n \ | |
+ \necho \"irq-disable\" or \"irq-enable\" to ctrl irq\n \ | |
+ \necho \"shutdown-en\" of \"shutdown-off\" to ctrl panel in or off sleep mode\n \ | |
+ \necho \"suspend-en\" or \"suspend-off\" to ctrl panel in or off suspend status\n"; | |
+ | |
+ loff_t pos = *ppos; | |
+ int len = strlen(str); | |
+ | |
+ if (pos < 0) | |
+ return -EINVAL; | |
+ if (pos >= len) | |
+ return 0; | |
+ | |
+ if (copy_to_user(buf, str, len)) | |
+ return -EFAULT; | |
+ | |
+ *ppos = pos + len; | |
+ | |
+ return len; | |
} | |
+ssize_t tpdbg_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos) | |
+{ | |
+ struct synaptics_rmi4_data *rmi4_data = file->private_data; | |
+ char *cmd = kzalloc(size + 1, GFP_KERNEL); | |
+ int ret = size; | |
+ | |
+ if (!cmd) | |
+ return -ENOMEM; | |
+ | |
+ if (copy_from_user(cmd, buf, size)) { | |
+ ret = -EFAULT; | |
+ goto out; | |
+ } | |
+ | |
+ cmd[size] = '\0'; | |
+ | |
+ if (!strncmp(cmd, "irq-disable", 11)) | |
+ disable_irq(rmi4_data->irq); | |
+ else if (!strncmp(cmd, "irq-enable", 10)) | |
+ enable_irq(rmi4_data->irq); | |
+ else if (!strncmp(cmd, "shutdown-en", 11)) | |
+ tpdbg_shutdown(rmi4_data, true); | |
+ else if (!strncmp(cmd, "shutdown-off", 12)) | |
+ tpdbg_shutdown(rmi4_data, false); | |
+ else if (!strncmp(cmd, "suspend-en", 10)) | |
+ tpdbg_suspend(rmi4_data, true); | |
+ else if (!strncmp(cmd, "suspend-off", 11)) | |
+ tpdbg_suspend(rmi4_data, false); | |
+out: | |
+ kfree(cmd); | |
+ | |
+ return ret; | |
+} | |
+ | |
+int tpdbg_release (struct inode *inode, struct file *file) | |
+{ | |
+ file->private_data = NULL; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static const struct file_operations tpdbg_operations = { | |
+ .owner = THIS_MODULE, | |
+ .open = tpdbg_open, | |
+ .read = tpdbg_read, | |
+ .write = tpdbg_write, | |
+ .release = tpdbg_release, | |
+}; | |
+#endif | |
+ | |
+extern unsigned int get_hw_version_major(void); | |
+ | |
static int synaptics_rmi4_probe(struct platform_device *pdev) | |
{ | |
int retval; | |
@@ -4486,15 +4981,20 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
const struct synaptics_dsx_board_data *bdata; | |
hw_if = pdev->dev.platform_data; | |
+ if (!hw_if) { | |
+ dev_err(&pdev->dev, | |
+ "%s: No hardware interface found\n", | |
+ __func__); | |
+ return -EINVAL; | |
+ } | |
bdata = hw_if->board_data; | |
if (!bdata) { | |
dev_err(&pdev->dev, | |
- "%s: No board data found\n", | |
- __func__); | |
+ "%s: No board data found\n", | |
+ __func__); | |
return -EINVAL; | |
} | |
- | |
rmi4_data = kzalloc(sizeof(*rmi4_data), GFP_KERNEL); | |
if (!rmi4_data) { | |
dev_err(&pdev->dev, | |
@@ -4510,15 +5010,18 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
rmi4_data->irq_enabled = false; | |
rmi4_data->fingers_on_2d = false; | |
rmi4_data->wakeup_en = false; | |
+ rmi4_data->homekey_wakeup = false; | |
rmi4_data->reset_device = synaptics_rmi4_reset_device; | |
rmi4_data->irq_enable = synaptics_rmi4_irq_enable; | |
rmi4_data->sleep_enable = synaptics_rmi4_sleep_enable; | |
+ rmi4_data->hw_version = get_hw_version_major(); | |
mutex_init(&(rmi4_data->rmi4_reset_mutex)); | |
mutex_init(&(rmi4_data->rmi4_report_mutex)); | |
mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex)); | |
mutex_init(&(rmi4_data->rmi4_exp_init_mutex)); | |
+ mutex_init(&(rmi4_data->rmi4_irq_enable_mutex)); | |
mutex_init(&(rmi4_data->rmi4_cover_mutex)); | |
mutex_init(&(rmi4_data->rmi4_charger_mutex)); | |
@@ -4567,6 +5070,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
goto err_pinctrl_init; | |
} | |
+ | |
retval = synaptics_rmi4_set_input_dev(rmi4_data); | |
if (retval < 0) { | |
dev_err(&pdev->dev, | |
@@ -4578,7 +5082,7 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
synaptics_rmi4_query_chip_id(rmi4_data); | |
#ifdef CONFIG_FB | |
- if (rmi4_data->chip_id == CHIP_ID_3330) | |
+ if (rmi4_data->chip_id != bdata->chip_4322 && rmi4_data->chip_id != bdata->chip_4722) | |
rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb_jdi; | |
else | |
rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb_lgd; | |
@@ -4645,13 +5149,24 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
} | |
+ if (bdata->captouch_use) { | |
+ retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_captouch.attr); | |
+ | |
+ if (retval < 0) { | |
+ dev_err(&pdev->dev, | |
+ "%s: Failed to create sysfs attributes\n", | |
+ __func__); | |
+ goto err_sysfs; | |
+ } | |
+ } | |
+ | |
retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_color.attr); | |
if (retval < 0) { | |
dev_err(&pdev->dev, | |
"%s: Failed to create sysfs attributes\n", | |
__func__); | |
- goto err_sysfs; | |
+ goto err_sysfs_captouch; | |
} | |
#if defined(CONFIG_SECURE_TOUCH) | |
@@ -4674,6 +5189,22 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
} | |
#endif | |
+ retval = sysfs_create_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_vendor.attr); | |
+ | |
+ if (retval < 0) { | |
+ dev_err(&pdev->dev, | |
+ "%s: Failed to create sysfs attributes\n", | |
+ __func__); | |
+ goto err_sysfs_panel_vendor; | |
+ } | |
+ | |
+#ifdef CONFIG_TOUCH_DEBUG_FS | |
+ rmi4_data->debugfs = debugfs_create_dir("tp_debug", NULL); | |
+ if (rmi4_data->debugfs) { | |
+ debugfs_create_file("switch_state", 0660, rmi4_data->debugfs, rmi4_data, &tpdbg_operations); | |
+ } | |
+#endif | |
+ | |
dev_set_drvdata(rmi4_data->pdev->dev.parent, rmi4_data); | |
rmi4_data->rb_workqueue = | |
@@ -4700,7 +5231,8 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
synaptics_secure_touch_init(rmi4_data); | |
synaptics_secure_touch_stop(rmi4_data, 1); | |
- if (rmi4_data->chip_id != CHIP_ID_3330) { | |
+ | |
+ if (rmi4_data->chip_id == bdata->chip_4322 || rmi4_data->chip_id == bdata->chip_4722) { | |
rmi4_data->power_supply_notif.notifier_call = synaptics_power_supply_event; | |
INIT_WORK(&rmi4_data->noise_work, synaptics_noise_work); | |
power_supply_reg_notifier(&rmi4_data->power_supply_notif); | |
@@ -4709,12 +5241,17 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) | |
return retval; | |
+err_sysfs_panel_vendor: | |
#if defined(CONFIG_SECURE_TOUCH) | |
+ sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch_enable.attr); | |
err_sysfs_secure_enable: | |
sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch.attr); | |
err_sysfs_secure: | |
sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_color.attr); | |
#endif | |
+err_sysfs_captouch: | |
+ if (bdata->captouch_use) | |
+ sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_captouch.attr); | |
err_sysfs: | |
for (attr_count--; attr_count >= 0; attr_count--) { | |
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj, | |
@@ -4780,9 +5317,6 @@ static int synaptics_rmi4_remove(struct platform_device *pdev) | |
struct synaptics_rmi4_data *rmi4_data = platform_get_drvdata(pdev); | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
- | |
- if (rmi4_data->chip_id != CHIP_ID_3330) | |
- power_supply_unreg_notifier(&rmi4_data->power_supply_notif); | |
#ifdef FB_READY_RESET | |
cancel_work_sync(&rmi4_data->reset_work); | |
flush_workqueue(rmi4_data->reset_workqueue); | |
@@ -4797,10 +5331,19 @@ static int synaptics_rmi4_remove(struct platform_device *pdev) | |
flush_workqueue(rmi4_data->rb_workqueue); | |
destroy_workqueue(rmi4_data->rb_workqueue); | |
+#ifdef CONFIG_TOUCH_DEBUG_FS | |
+ debugfs_remove_recursive(rmi4_data->debugfs); | |
+#endif | |
+ | |
+ sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_vendor.attr); | |
#if defined(CONFIG_SECURE_TOUCH) | |
sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch_enable.attr); | |
sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_secure_touch.attr); | |
#endif | |
+ | |
+ if (bdata->captouch_use) | |
+ sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_captouch.attr); | |
+ | |
sysfs_remove_file(&rmi4_data->pdev->dev.parent->kobj, &dev_attr_panel_color.attr); | |
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { | |
@@ -4894,15 +5437,16 @@ static void synaptics_rmi4_f11_wg(struct synaptics_rmi4_data *rmi4_data, | |
return; | |
} | |
-static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enable) | |
+static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, unsigned int flag, bool enable) | |
{ | |
int retval = 0; | |
+ static unsigned int status; | |
if (rmi4_data == NULL) | |
return; | |
if (enable) { | |
- if (rmi4_data->disp_reg) { | |
+ if (rmi4_data->disp_reg && (flag & DISP_REG_VDD) && !(status & DISP_REG_VDD)) { | |
retval = regulator_enable(rmi4_data->disp_reg); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4910,9 +5454,11 @@ static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enab | |
__func__); | |
return; | |
} | |
+ | |
+ status |= DISP_REG_VDD; | |
} | |
- if (rmi4_data->lab_reg) { | |
+ if (rmi4_data->lab_reg && (flag & DISP_REG_LAB) && !(status & DISP_REG_LAB)) { | |
retval = regulator_enable(rmi4_data->lab_reg); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4920,9 +5466,11 @@ static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enab | |
__func__); | |
return; | |
} | |
+ | |
+ status |= DISP_REG_LAB; | |
} | |
- if (rmi4_data->ibb_reg) { | |
+ if (rmi4_data->ibb_reg && (flag & DISP_REG_IBB) && !(status & DISP_REG_IBB)) { | |
retval = regulator_enable(rmi4_data->ibb_reg); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4930,9 +5478,11 @@ static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enab | |
__func__); | |
return; | |
} | |
+ | |
+ status |= DISP_REG_IBB; | |
} | |
} else { | |
- if (rmi4_data->ibb_reg) { | |
+ if (rmi4_data->ibb_reg && (flag & DISP_REG_IBB) && (status & DISP_REG_IBB)) { | |
retval = regulator_disable(rmi4_data->ibb_reg); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4940,9 +5490,11 @@ static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enab | |
__func__); | |
return; | |
} | |
+ | |
+ status &= ~DISP_REG_IBB; | |
} | |
- if (rmi4_data->lab_reg) { | |
+ if (rmi4_data->lab_reg && (flag & DISP_REG_LAB) && (status & DISP_REG_LAB)) { | |
retval = regulator_disable(rmi4_data->lab_reg); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4950,9 +5502,11 @@ static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enab | |
__func__); | |
return; | |
} | |
+ | |
+ status &= ~DISP_REG_LAB; | |
} | |
- if (rmi4_data->disp_reg) { | |
+ if (rmi4_data->disp_reg && (flag & DISP_REG_VDD) && (status & DISP_REG_VDD)) { | |
retval = regulator_disable(rmi4_data->disp_reg); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4960,6 +5514,8 @@ static void mdss_regulator_ctrl(struct synaptics_rmi4_data *rmi4_data, bool enab | |
__func__); | |
return; | |
} | |
+ | |
+ status &= ~DISP_REG_VDD; | |
} | |
} | |
} | |
@@ -5004,6 +5560,7 @@ static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data, | |
fhandler->full_addr.ctrl_base + offset, | |
reporting_control, | |
sizeof(reporting_control)); | |
+ | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to change reporting mode\n", | |
@@ -5014,6 +5571,51 @@ static void synaptics_rmi4_f12_wg(struct synaptics_rmi4_data *rmi4_data, | |
return; | |
} | |
+static void synaptics_rmi4_gesture_ctrl(struct synaptics_rmi4_data *rmi4_data, unsigned char value) | |
+{ | |
+ struct synaptics_rmi4_f12_extra_data *extra_data; | |
+ struct synaptics_rmi4_fn *fhandler; | |
+ struct synaptics_rmi4_device_info *rmi; | |
+ int retval; | |
+ | |
+ rmi = &(rmi4_data->rmi4_mod_info); | |
+ | |
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) { | |
+ if (fhandler->fn_number == SYNAPTICS_RMI4_F12) | |
+ break; | |
+ } | |
+ | |
+ extra_data = (struct synaptics_rmi4_f12_extra_data *)fhandler->extra; | |
+ | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ fhandler->full_addr.ctrl_base + extra_data->ctrl27_offset, | |
+ &value, | |
+ 1); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to switch double click mode\n", | |
+ __func__); | |
+ } | |
+} | |
+ | |
+static bool check_captouch_support(struct synaptics_rmi4_data *rmi4_data) | |
+{ | |
+ struct synaptics_dsx_board_data *bdata = NULL; | |
+ | |
+ if (rmi4_data == NULL) | |
+ return false; | |
+ | |
+ bdata = rmi4_data->hw_if->board_data; | |
+ | |
+ if (bdata == NULL) | |
+ return false; | |
+ | |
+ if (bdata->captouch_use && (captouch_get_status_ptr != NULL) && !captouch_get_status_ptr()) | |
+ return true; | |
+ else | |
+ return false; | |
+} | |
+ | |
static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data, | |
bool enable) | |
{ | |
@@ -5022,7 +5624,14 @@ static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data, | |
else if (rmi4_data->f12_wakeup_gesture) | |
synaptics_rmi4_f12_wg(rmi4_data, enable); | |
- return; | |
+ if (rmi4_data->hw_if->board_data->captouch_use) { | |
+ if (rmi4_data->enable_wakeup_gesture && rmi4_data->homekey_wakeup) | |
+ synaptics_rmi4_gesture_ctrl(rmi4_data, DOUBLE_TAP | HOMEKEY_WAKEUP); | |
+ else if (rmi4_data->enable_wakeup_gesture && !rmi4_data->homekey_wakeup) | |
+ synaptics_rmi4_gesture_ctrl(rmi4_data, DOUBLE_TAP); | |
+ else if (!rmi4_data->enable_wakeup_gesture && rmi4_data->homekey_wakeup) | |
+ synaptics_rmi4_gesture_ctrl(rmi4_data, HOMEKEY_WAKEUP); | |
+ } | |
} | |
#ifdef CONFIG_FB | |
@@ -5036,6 +5645,7 @@ static int synaptics_rmi4_fb_notifier_cb_jdi(struct notifier_block *self, | |
struct synaptics_rmi4_data *rmi4_data = | |
container_of(self, struct synaptics_rmi4_data, | |
fb_notifier); | |
+ | |
const struct synaptics_dsx_board_data *bdata = NULL; | |
if (rmi4_data->hw_if->board_data) | |
@@ -5053,17 +5663,26 @@ static int synaptics_rmi4_fb_notifier_cb_jdi(struct notifier_block *self, | |
} else if ((*transition == FB_BLANK_UNBLANK) || (*transition == FB_BLANK_NORMAL)) { | |
synaptics_rmi4_resume(&rmi4_data->pdev->dev); | |
rmi4_data->fb_ready = true; | |
- if (rmi4_data->enable_wakeup_gesture) { | |
+ if (rmi4_data->wakeup_en) { | |
mdss_panel_reset_skip_enable(false); | |
- mdss_regulator_ctrl(rmi4_data, false); | |
+ if (rmi4_data->enable_wakeup_gesture) { | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, false); | |
+ } else if (rmi4_data->homekey_wakeup) { | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_VDD, false); | |
+ } | |
+ rmi4_data->wakeup_en = false; | |
} | |
} | |
} else if (event == FB_EARLY_EVENT_BLANK) { | |
transition = evdata->data; | |
if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) { | |
if (rmi4_data->enable_wakeup_gesture) { | |
- mdss_regulator_ctrl(rmi4_data, true); | |
+ rmi4_data->wakeup_en = true; | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, true); | |
mdss_panel_reset_skip_enable(true); | |
+ } else if (rmi4_data->homekey_wakeup) { | |
+ rmi4_data->wakeup_en = true; | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_VDD, true); | |
} | |
} else if ((*transition == FB_BLANK_UNBLANK) || (*transition == FB_BLANK_NORMAL)) { | |
if (bdata->reset_gpio >= 0 && rmi4_data->suspend) { | |
@@ -5071,7 +5690,7 @@ static int synaptics_rmi4_fb_notifier_cb_jdi(struct notifier_block *self, | |
msleep(bdata->reset_active_ms); | |
gpio_set_value(bdata->reset_gpio, !bdata->reset_on_state); | |
} | |
- if (rmi4_data->enable_wakeup_gesture) { | |
+ if (rmi4_data->wakeup_en && rmi4_data->enable_wakeup_gesture) { | |
if (bdata->mdss_reset != 0) { | |
gpio_set_value(bdata->mdss_reset, !bdata->mdss_reset_state); | |
msleep(10); | |
@@ -5095,38 +5714,48 @@ static int synaptics_rmi4_fb_notifier_cb_lgd(struct notifier_block *self, | |
container_of(self, struct synaptics_rmi4_data, | |
fb_notifier); | |
+ if (mdss_prim_panel_is_dead()) | |
+ return 0; | |
+ | |
/* Receive notifications from primary panel only */ | |
if (evdata && evdata->data && rmi4_data && mdss_panel_is_prim(evdata->info)) { | |
if (event == FB_EVENT_BLANK) { | |
transition = evdata->data; | |
if ((*transition == FB_BLANK_UNBLANK) || (*transition == FB_BLANK_NORMAL)) { | |
- synaptics_rmi4_resume(&rmi4_data->pdev->dev); | |
- rmi4_data->fb_ready = true; | |
- if (rmi4_data->wakeup_en && rmi4_data->enable_wakeup_gesture) { | |
- mdss_panel_reset_skip_enable(false); | |
- mdss_regulator_ctrl(rmi4_data, false); | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, false); | |
+ mdss_panel_reset_skip_enable(false); | |
+ if (rmi4_data->wakeup_en) | |
rmi4_data->wakeup_en = false; | |
+ } else if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) { | |
+ msleep(160); | |
+ synaptics_rmi4_suspend(&rmi4_data->pdev->dev); | |
+ rmi4_data->fb_ready = false; | |
+ | |
+ if (!rmi4_data->wakeup_en) { | |
+ msleep(10); | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_IBB, false); | |
+ msleep(10); | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_LAB, false); | |
} | |
} | |
} else if (event == FB_EARLY_EVENT_BLANK) { | |
transition = evdata->data; | |
if (*transition == FB_BLANK_UNBLANK) { | |
- if (rmi4_data->wakeup_en && rmi4_data->enable_wakeup_gesture) { | |
- if (rmi4_data->hw_if->board_data->mdss_reset != 0) { | |
- gpio_set_value(rmi4_data->hw_if->board_data->mdss_reset, !rmi4_data->hw_if->board_data->mdss_reset_state); | |
- msleep(10); | |
- gpio_set_value(rmi4_data->hw_if->board_data->mdss_reset, rmi4_data->hw_if->board_data->mdss_reset_state); | |
- msleep(100); | |
- } | |
+ if (!rmi4_data->wakeup_en) { | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_LAB, true); | |
+ msleep(10); | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_IBB, true); | |
+ msleep(10); | |
} | |
+ | |
+ synaptics_rmi4_resume(&rmi4_data->pdev->dev); | |
+ rmi4_data->fb_ready = true; | |
+ msleep(10); | |
} else if ((*transition == FB_BLANK_POWERDOWN) || (*transition == FB_BLANK_NORMAL)) { | |
- if (rmi4_data->enable_wakeup_gesture) { | |
+ mdss_panel_reset_skip_enable(true); | |
+ mdss_regulator_ctrl(rmi4_data, DISP_REG_ALL, true); | |
+ if (rmi4_data->enable_wakeup_gesture || rmi4_data->homekey_wakeup) | |
rmi4_data->wakeup_en = true; | |
- mdss_panel_reset_skip_enable(true); | |
- mdss_regulator_ctrl(rmi4_data, true); | |
- } | |
- synaptics_rmi4_suspend(&rmi4_data->pdev->dev); | |
- rmi4_data->fb_ready = false; | |
} | |
} | |
} | |
@@ -5231,12 +5860,11 @@ static int synaptics_rmi4_suspend(struct device *dev) | |
if (rmi4_data->stay_awake || rmi4_data->suspend) | |
return 0; | |
- if (bdata->cut_off_power || (rmi4_data->chip_id == CHIP_ID_4322 && !rmi4_data->wakeup_en)) { | |
+ if (bdata->cut_off_power) { | |
if (rmi4_data->fw_updating) | |
return 0; | |
synaptics_rmi4_irq_enable(rmi4_data, false, false); | |
- synaptics_rmi4_free_fingers(rmi4_data); | |
if (bdata->power_gpio >= 0) | |
gpio_set_value(bdata->power_gpio, | |
@@ -5248,20 +5876,25 @@ static int synaptics_rmi4_suspend(struct device *dev) | |
mdelay(bdata->reset_active_ms); | |
} | |
- synaptics_rmi4_enable_reg(rmi4_data, false); | |
+ if (!bdata->power_ctrl || (bdata->power_ctrl && rmi4_data->hw_version > 2)) | |
+ synaptics_rmi4_enable_reg(rmi4_data, false); | |
} else { | |
synaptics_secure_touch_stop(rmi4_data, 1); | |
- synaptics_rmi4_free_fingers(rmi4_data); | |
- | |
if (!rmi4_data->suspend) { | |
synaptics_rmi4_irq_enable(rmi4_data, false, false); | |
- if (!rmi4_data->enable_wakeup_gesture) | |
+ if (!rmi4_data->wakeup_en) { | |
+ if (rmi4_data->chip_id == bdata->chip_4322 || rmi4_data->chip_id == bdata->chip_4722) { | |
+ synaptics_rmi4_wakeup_gesture(rmi4_data, true); | |
+ msleep(10); | |
+ } | |
synaptics_rmi4_sleep_enable(rmi4_data, true); | |
+ } | |
} | |
- if (rmi4_data->enable_wakeup_gesture) { | |
- msleep(300); | |
+ if (rmi4_data->wakeup_en) { | |
+ if (rmi4_data->chip_id != bdata->chip_4322 && rmi4_data->chip_id != bdata->chip_4722) | |
+ msleep(300); | |
synaptics_rmi4_wakeup_gesture(rmi4_data, true); | |
synaptics_rmi4_irq_enable(rmi4_data, true, false); | |
goto exit; | |
@@ -5277,6 +5910,8 @@ static int synaptics_rmi4_suspend(struct device *dev) | |
} | |
exit: | |
+ synaptics_rmi4_free_fingers(rmi4_data); | |
+ | |
rmi4_data->suspend = true; | |
return 0; | |
@@ -5304,8 +5939,9 @@ static int synaptics_rmi4_resume(struct device *dev) | |
if (rmi4_data->stay_awake || !rmi4_data->suspend) | |
return 0; | |
- if (bdata->cut_off_power || (rmi4_data->chip_id == CHIP_ID_4322 && !rmi4_data->wakeup_en)) { | |
- synaptics_rmi4_enable_reg(rmi4_data, true); | |
+ if (bdata->cut_off_power) { | |
+ if (!bdata->power_ctrl || (bdata->power_ctrl && rmi4_data->hw_version > 2)) | |
+ synaptics_rmi4_enable_reg(rmi4_data, true); | |
if (bdata->power_gpio >= 0) { | |
gpio_set_value(bdata->power_gpio, | |
@@ -5320,17 +5956,19 @@ static int synaptics_rmi4_resume(struct device *dev) | |
} | |
synaptics_rmi4_irq_enable(rmi4_data, true, false); | |
- | |
- if (rmi4_data->enable_cover_mode) | |
- cover_mode_set(rmi4_data, rmi4_data->enable_cover_mode); | |
} else { | |
synaptics_secure_touch_stop(rmi4_data, 0); | |
- if (rmi4_data->enable_wakeup_gesture) { | |
+ if (rmi4_data->wakeup_en) { | |
synaptics_rmi4_wakeup_gesture(rmi4_data, false); | |
} else { | |
rmi4_data->current_page = MASK_8BIT; | |
- synaptics_rmi4_sleep_enable(rmi4_data, false); | |
+ | |
+ if (rmi4_data->chip_id == bdata->chip_4322 || rmi4_data->chip_id == bdata->chip_4722) { | |
+ synaptics_rmi4_wakeup_gesture(rmi4_data, false); | |
+ rmi4_data->sensor_sleep = false; | |
+ } else | |
+ synaptics_rmi4_sleep_enable(rmi4_data, false); | |
synaptics_rmi4_irq_enable(rmi4_data, true, false); | |
#ifdef FB_READY_RESET | |
@@ -5354,11 +5992,6 @@ static int synaptics_rmi4_resume(struct device *dev) | |
cover_mode_set(rmi4_data, rmi4_data->enable_cover_mode); | |
} | |
- if (rmi4_data->chip_id != CHIP_ID_3330 && rmi4_data->is_usb_plug_in) | |
- charger_reg_set(rmi4_data, true); | |
- | |
- if (rmi4_data->chip_id != CHIP_ID_3330) | |
- synaptics_rmi4_protection_film(rmi4_data); | |
rmi4_data->suspend = false; | |
return 0; | |
@@ -5372,7 +6005,7 @@ static int synaptics_rmi4_pm_suspend(struct device *dev) | |
rmi4_data->hw_if->board_data; | |
if (device_may_wakeup(dev) && | |
- rmi4_data->enable_wakeup_gesture && | |
+ rmi4_data->wakeup_en && | |
!bdata->cut_off_power) { | |
dev_info(rmi4_data->pdev->dev.parent, | |
"Enable touch irq wake\n"); | |
@@ -5391,7 +6024,7 @@ static int synaptics_rmi4_pm_resume(struct device *dev) | |
rmi4_data->hw_if->board_data; | |
if (device_may_wakeup(dev) && | |
- rmi4_data->enable_wakeup_gesture && | |
+ rmi4_data->wakeup_en && | |
!bdata->cut_off_power) { | |
dev_info(rmi4_data->pdev->dev.parent, | |
"Disable touch irq wake\n"); | |
@@ -5410,7 +6043,7 @@ static const struct dev_pm_ops synaptics_rmi4_dev_pm_ops = { | |
static struct platform_driver synaptics_rmi4_driver = { | |
.driver = { | |
- .name = PLATFORM_DRIVER_NAME, | |
+ .name = PLATFORM_DRIVER_FORCE, | |
.owner = THIS_MODULE, | |
#ifdef CONFIG_PM | |
.pm = &synaptics_rmi4_dev_pm_ops, | |
@@ -5424,7 +6057,7 @@ static int __init synaptics_rmi4_init(void) | |
{ | |
int retval; | |
- retval = synaptics_rmi4_bus_init(); | |
+ retval = synaptics_rmi4_bus_init_force(); | |
if (retval) | |
return retval; | |
@@ -5435,7 +6068,7 @@ static void __exit synaptics_rmi4_exit(void) | |
{ | |
platform_driver_unregister(&synaptics_rmi4_driver); | |
- synaptics_rmi4_bus_exit(); | |
+ synaptics_rmi4_bus_exit_force(); | |
return; | |
} | |
diff --git a/synaptics_dsx_core.h b/synaptics_dsx_core.h | |
index 588915c..5a96473 100644 | |
--- a/synaptics_dsx_core.h | |
+++ b/synaptics_dsx_core.h | |
@@ -16,6 +16,20 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
#ifndef _SYNAPTICS_DSX_RMI4_H_ | |
@@ -24,10 +38,7 @@ | |
#define SYNAPTICS_DS4 (1 << 0) | |
#define SYNAPTICS_DS5 (1 << 1) | |
#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5) | |
-#define SYNAPTICS_DSX_DRIVER_VERSION 0x2050 | |
- | |
-#define CHIP_ID_3330 1 | |
-#define CHIP_ID_4322 2 | |
+#define SYNAPTICS_DSX_DRIVER_VERSION 0x2065 | |
#include <linux/version.h> | |
#ifdef CONFIG_FB | |
@@ -37,6 +48,7 @@ | |
#ifdef CONFIG_HAS_EARLYSUSPEND | |
#include <linux/earlysuspend.h> | |
#endif | |
+ | |
#if defined(CONFIG_SECURE_TOUCH) | |
#include <linux/completion.h> | |
#include <linux/atomic.h> | |
@@ -63,7 +75,7 @@ | |
#define PDT_ENTRY_SIZE (0x0006) | |
#define PAGES_TO_SERVICE (10) | |
#define PAGE_SELECT_LEN (2) | |
-#define ADDRESS_WORD_LEN (2) | |
+#define ADDRESS_LEN (2) | |
#define SYNAPTICS_RMI4_F01 (0x01) | |
#define SYNAPTICS_RMI4_F11 (0x11) | |
@@ -182,9 +194,9 @@ struct synaptics_rmi4_f11_extra_data { | |
* @data15_offset: offset to F12_2D_DATA15 register | |
* @data15_size: size of F12_2D_DATA15 register | |
* @data15_data: buffer for reading F12_2D_DATA15 register | |
- * @data23_offset: offset to F12_2D_DATA23 register | |
- * @data23_size: size of F12_2D_DATA23 register | |
- * @data23_data: buffer for reading F12_2D_DATA23 register | |
+ * @data29_offset: offset to F12_2D_DATA29 register | |
+ * @data29_size: size of F12_2D_DATA29 register | |
+ * @data29_data: buffer for reading F12_2D_DATA29 register | |
* @ctrl20_offset: offset to F12_2D_CTRL20 register | |
*/ | |
struct synaptics_rmi4_f12_extra_data { | |
@@ -193,11 +205,12 @@ struct synaptics_rmi4_f12_extra_data { | |
unsigned char data15_offset; | |
unsigned char data15_size; | |
unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8]; | |
- unsigned char data23_offset; | |
- unsigned char data23_size; | |
- unsigned char data23_data[F12_FINGERS_TO_SUPPORT]; | |
+ unsigned char data29_offset; | |
+ unsigned char data29_size; | |
+ unsigned char data29_data[F12_FINGERS_TO_SUPPORT * 2]; | |
unsigned char ctrl20_offset; | |
unsigned char ctrl26_offset; | |
+ unsigned char ctrl27_offset; | |
}; | |
/* | |
@@ -265,6 +278,7 @@ struct synaptics_rmi4_device_info { | |
* @rmi4_report_mutex: mutex for input event reporting | |
* @rmi4_io_ctrl_mutex: mutex for communication interface I/O | |
* @rmi4_exp_init_mutex: mutex for expansion function module initialization | |
+ * @rmi4_irq_enable_mutex: mutex for enabling/disabling interrupt | |
* @rb_work: work for rebuilding input device | |
* @rb_workqueue: workqueue for rebuilding input device | |
* @fb_notifier: framebuffer notifier client | |
@@ -305,9 +319,11 @@ struct synaptics_rmi4_device_info { | |
* @report_pressure: flag to indicate reporting of pressure data | |
* @stylus_enable: flag to indicate reporting of stylus data | |
* @eraser_enable: flag to indicate reporting of eraser data | |
+ * @external_afe_buttons: flag to indicate presence of external AFE buttons | |
* @reset_device: pointer to device reset function | |
* @irq_enable: pointer to interrupt enable function | |
* @sleep_enable: pointer to sleep enable function | |
+ * @report_touch: pointer to touch reporting function | |
*/ | |
struct synaptics_rmi4_data { | |
struct platform_device *pdev; | |
@@ -327,6 +343,7 @@ struct synaptics_rmi4_data { | |
struct mutex rmi4_exp_init_mutex; | |
struct mutex rmi4_cover_mutex; | |
struct mutex rmi4_charger_mutex; | |
+ struct mutex rmi4_irq_enable_mutex; | |
struct delayed_work rb_work; | |
struct workqueue_struct *rb_workqueue; | |
#ifdef CONFIG_FB | |
@@ -353,12 +370,18 @@ struct synaptics_rmi4_data { | |
unsigned short f01_cmd_base_addr; | |
unsigned short f01_ctrl_base_addr; | |
unsigned short f01_data_base_addr; | |
- unsigned short f54_cmd_base_addr; | |
+#ifdef F51_DISCRETE_FORCE | |
+ unsigned short f51_query_base_addr; | |
+#endif | |
+ unsigned int hw_version; | |
unsigned int firmware_id; | |
unsigned char lockdown_info[LOCKDOWN_INFO_SIZE]; | |
+ unsigned char valid_button_count; | |
int irq; | |
int sensor_max_x; | |
int sensor_max_y; | |
+ int force_min; | |
+ int force_max; | |
int chip_id; | |
bool flash_prog_mode; | |
bool irq_enabled; | |
@@ -375,18 +398,26 @@ struct synaptics_rmi4_data { | |
bool report_pressure; | |
bool stylus_enable; | |
bool eraser_enable; | |
+ bool external_afe_buttons; | |
bool fw_updating; | |
bool wakeup_en; | |
+ bool homekey_wakeup; | |
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data, | |
bool rebuild); | |
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable, | |
bool attn_only); | |
void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data, | |
bool enable); | |
+ void (*report_touch)(struct synaptics_rmi4_data *rmi4_data, | |
+ struct synaptics_rmi4_fn *fhandler); | |
struct pinctrl *ts_pinctrl; | |
struct pinctrl_state *pinctrl_state_active; | |
struct pinctrl_state *pinctrl_state_suspend; | |
+#ifdef CONFIG_TOUCH_DEBUG_FS | |
+ struct dentry *debugfs; | |
+#endif | |
+ | |
#if defined(CONFIG_SECURE_TOUCH) | |
atomic_t st_enabled; | |
atomic_t st_pending_irqs; | |
@@ -437,11 +468,11 @@ struct synaptics_rmi4_mode_switch { | |
struct work_struct switch_mode_work; | |
}; | |
-int synaptics_rmi4_bus_init(void); | |
+int synaptics_rmi4_bus_init_force(void); | |
-void synaptics_rmi4_bus_exit(void); | |
+void synaptics_rmi4_bus_exit_force(void); | |
-void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module, | |
+void synaptics_rmi4_new_function_force(struct synaptics_rmi4_exp_fn *exp_fn_module, | |
bool insert); | |
int synaptics_fw_updater(const unsigned char *fw_data); | |
@@ -505,4 +536,5 @@ static inline void hstoba(unsigned char *dest, unsigned short src) | |
dest[0] = src % 0x100; | |
dest[1] = src / 0x100; | |
} | |
+ | |
#endif | |
diff --git a/synaptics_dsx_fw_update.c b/synaptics_dsx_fw_update.c | |
index ab725ee..e177bd7 100644 | |
--- a/synaptics_dsx_fw_update.c | |
+++ b/synaptics_dsx_fw_update.c | |
@@ -16,7 +16,22 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
+ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/slab.h> | |
@@ -27,18 +42,13 @@ | |
#include <linux/platform_device.h> | |
#include <linux/input/synaptics_dsx.h> | |
#include "synaptics_dsx_core.h" | |
+ | |
+#define FW_IHEX_NAME "synaptics/startup_fw_update.bin" | |
#define FW_IMAGE_NAME "synaptics/startup_fw_update.img" | |
#define DO_STARTUP_FW_UPDATE | |
-/* | |
-#ifdef DO_STARTUP_FW_UPDATE | |
-#ifdef CONFIG_FB | |
-#define WAIT_FOR_FB_READY | |
-#define FB_READY_WAIT_MS 100 | |
-#define FB_READY_TIMEOUT_S 30 | |
-#endif | |
-#endif | |
-*/ | |
+#define MAX_WRITE_SIZE 4096 | |
+ | |
#define FORCE_UPDATE false | |
#define DO_LOCKDOWN false | |
@@ -52,6 +62,8 @@ | |
#define IMAGE_AREA_OFFSET 0x100 | |
#define LOCKDOWN_SIZE 0x50 | |
+#define MAX_UTILITY_PARAMS 20 | |
+ | |
#define V5V6_BOOTLOADER_ID_OFFSET 0 | |
#define V5V6_CONFIG_ID_SIZE 4 | |
@@ -82,6 +94,7 @@ | |
#define V7_PARTITION_SUPPORT_BYTES 4 | |
#define F35_ERROR_CODE_OFFSET 0 | |
+#define F35_FLASH_STATUS_OFFSET 5 | |
#define F35_CHUNK_NUM_LSB_OFFSET 0 | |
#define F35_CHUNK_NUM_MSB_OFFSET 1 | |
#define F35_CHUNK_DATA_OFFSET 2 | |
@@ -106,12 +119,12 @@ | |
#define INT_DISABLE_WAIT_MS 20 | |
#define ENTER_FLASH_PROG_WAIT_MS 20 | |
-static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd); | |
- | |
static int fwu_do_reflash(void); | |
static int fwu_recovery_check_status(void); | |
+static int fwu_read_f34_blocks(unsigned short block_cnt, unsigned char cmd); | |
+ | |
static ssize_t fwu_sysfs_show_image(struct file *data_file, | |
struct kobject *kobj, struct bin_attribute *attributes, | |
char *buf, loff_t pos, size_t count); | |
@@ -198,6 +211,7 @@ enum config_area { | |
BL_CONFIG_AREA, | |
DP_CONFIG_AREA, | |
FLASH_CONFIG_AREA, | |
+ INVALID_CONFIG_AREA = 0xff, | |
}; | |
enum v7_status { | |
@@ -225,6 +239,8 @@ enum v7_partition_id { | |
CORE_CONFIG_PARTITION, | |
GUEST_CODE_PARTITION, | |
DISPLAY_CONFIG_PARTITION, | |
+ EXTERNAL_TOUCH_AFE_CONFIG_PARTITION, | |
+ UTILITY_PARAMETER_PARTITION, | |
}; | |
enum v7_flash_command { | |
@@ -259,6 +275,8 @@ enum flash_command { | |
CMD_WRITE_CONFIG, | |
CMD_WRITE_LOCKDOWN, | |
CMD_WRITE_GUEST_CODE, | |
+ CMD_WRITE_BOOTLOADER, | |
+ CMD_WRITE_UTILITY_PARAM, | |
CMD_READ_CONFIG, | |
CMD_ERASE_ALL, | |
CMD_ERASE_UI_FIRMWARE, | |
@@ -267,6 +285,8 @@ enum flash_command { | |
CMD_ERASE_DISP_CONFIG, | |
CMD_ERASE_FLASH_CONFIG, | |
CMD_ERASE_GUEST_CODE, | |
+ CMD_ERASE_BOOTLOADER, | |
+ CMD_ERASE_UTILITY_PARAMETER, | |
CMD_ENABLE_FLASH_PROG, | |
CMD_READ_LOCKDOWN_DATA, | |
}; | |
@@ -301,6 +321,15 @@ enum container_id { | |
CORE_CODE_CONTAINER, | |
CORE_CONFIG_CONTAINER, | |
DISPLAY_CONFIG_CONTAINER, | |
+ EXTERNAL_TOUCH_AFE_CONFIG_CONTAINER, | |
+ UTILITY_CONTAINER, | |
+ UTILITY_PARAMETER_CONTAINER, | |
+}; | |
+ | |
+enum utility_parameter_id { | |
+ UNUSED = 0, | |
+ FORCE_PARAMETER, | |
+ ANTI_BENDING_PARAMETER, | |
}; | |
struct pdt_properties { | |
@@ -486,6 +515,7 @@ struct block_count { | |
unsigned short fl_config; | |
unsigned short bl_image; | |
unsigned short bl_config; | |
+ unsigned short utility_param; | |
unsigned short lockdown; | |
unsigned short guest_code; | |
unsigned short lockdown_data; | |
@@ -496,7 +526,12 @@ struct physical_address { | |
unsigned short ui_firmware; | |
unsigned short ui_config; | |
unsigned short dp_config; | |
+ unsigned short pm_config; | |
unsigned short fl_config; | |
+ unsigned short bl_image; | |
+ unsigned short bl_config; | |
+ unsigned short utility_param; | |
+ unsigned short lockdown; | |
unsigned short guest_code; | |
}; | |
@@ -582,6 +617,7 @@ struct image_metadata { | |
bool contains_disp_config; | |
bool contains_perm_config; | |
bool contains_flash_config; | |
+ bool contains_utility_param; | |
unsigned int firmware_id; | |
unsigned int checksum; | |
unsigned int bootloader_size; | |
@@ -589,7 +625,9 @@ struct image_metadata { | |
unsigned char bl_version; | |
unsigned char product_id[PRODUCT_ID_SIZE + 1]; | |
unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; | |
+ unsigned char utility_param_id[MAX_UTILITY_PARAMS]; | |
struct block_data bootloader; | |
+ struct block_data utility; | |
struct block_data ui_firmware; | |
struct block_data ui_config; | |
struct block_data dp_config; | |
@@ -597,6 +635,7 @@ struct image_metadata { | |
struct block_data fl_config; | |
struct block_data bl_image; | |
struct block_data bl_config; | |
+ struct block_data utility_param[MAX_UTILITY_PARAMS]; | |
struct block_data lockdown; | |
struct block_data guest_code; | |
struct block_count blkcount; | |
@@ -608,11 +647,15 @@ struct synaptics_rmi4_fwu_handle { | |
bool initialized; | |
bool in_bl_mode; | |
bool in_ub_mode; | |
+ bool bl_mode_device; | |
bool force_update; | |
bool do_lockdown; | |
bool has_guest_code; | |
bool has_lockdown_data; | |
+ bool has_utility_param; | |
bool new_partition_table; | |
+ bool incompatible_partition_tables; | |
+ bool write_bootloader; | |
unsigned int data_pos; | |
unsigned char *ext_data_source; | |
unsigned char *read_config_buf; | |
@@ -622,6 +665,13 @@ struct synaptics_rmi4_fwu_handle { | |
unsigned char config_id[32]; | |
unsigned char flash_status; | |
unsigned char partitions; | |
+#ifdef F51_DISCRETE_FORCE | |
+ unsigned char *cal_data; | |
+ unsigned short cal_data_off; | |
+ unsigned short cal_data_size; | |
+ unsigned short cal_data_buf_size; | |
+ unsigned short cal_packet_data_size; | |
+#endif | |
unsigned short block_size; | |
unsigned short config_size; | |
unsigned short config_area; | |
@@ -706,10 +756,42 @@ static struct device_attribute attrs[] = { | |
static struct synaptics_rmi4_fwu_handle *fwu; | |
-DECLARE_COMPLETION(fwu_remove_complete); | |
- | |
+DECLARE_COMPLETION(fwu_remove_complete_force); | |
static int fwu_read_f34_guest_serialization_partition(void); | |
+static void calculate_checksum(unsigned short *data, unsigned long len, | |
+ unsigned long *result) | |
+{ | |
+ unsigned long temp; | |
+ unsigned long sum1 = 0xffff; | |
+ unsigned long sum2 = 0xffff; | |
+ | |
+ *result = 0xffffffff; | |
+ | |
+ while (len--) { | |
+ temp = *data; | |
+ sum1 += temp; | |
+ sum2 += sum1; | |
+ sum1 = (sum1 & 0xffff) + (sum1 >> 16); | |
+ sum2 = (sum2 & 0xffff) + (sum2 >> 16); | |
+ data++; | |
+ } | |
+ | |
+ *result = sum2 << 16 | sum1; | |
+ | |
+ return; | |
+} | |
+ | |
+static void convert_to_little_endian(unsigned char *dest, unsigned long src) | |
+{ | |
+ dest[0] = (unsigned char)(src & 0xff); | |
+ dest[1] = (unsigned char)((src >> 8) & 0xff); | |
+ dest[2] = (unsigned char)((src >> 16) & 0xff); | |
+ dest[3] = (unsigned char)((src >> 24) & 0xff); | |
+ | |
+ return; | |
+} | |
+ | |
static unsigned int le_to_uint(const unsigned char *ptr) | |
{ | |
return (unsigned int)ptr[0] + | |
@@ -718,6 +800,79 @@ static unsigned int le_to_uint(const unsigned char *ptr) | |
(unsigned int)ptr[3] * 0x1000000; | |
} | |
+#ifdef F51_DISCRETE_FORCE | |
+static int fwu_f51_force_data_init(void) | |
+{ | |
+ int retval; | |
+ unsigned char query_count; | |
+ unsigned char packet_info; | |
+ unsigned char offset[2]; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ rmi4_data->f51_query_base_addr + 7, | |
+ offset, | |
+ sizeof(offset)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read force data offset\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ fwu->cal_data_off = offset[0] | offset[1] << 8; | |
+ | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ rmi4_data->f51_query_base_addr, | |
+ &query_count, | |
+ sizeof(query_count)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read number of F51 query registers\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ if (query_count >= 10) { | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ rmi4_data->f51_query_base_addr + 9, | |
+ &packet_info, | |
+ sizeof(packet_info)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read F51 packet register info\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ if (packet_info & MASK_1BIT) { | |
+ fwu->cal_packet_data_size = packet_info >> 1; | |
+ fwu->cal_packet_data_size *= 2; | |
+ } else { | |
+ fwu->cal_packet_data_size = 0; | |
+ } | |
+ } else { | |
+ fwu->cal_packet_data_size = 0; | |
+ } | |
+ | |
+ fwu->cal_data_size = CAL_DATA_SIZE + fwu->cal_packet_data_size; | |
+ if (fwu->cal_data_size > fwu->cal_data_buf_size) { | |
+ kfree(fwu->cal_data); | |
+ fwu->cal_data_buf_size = fwu->cal_data_size; | |
+ fwu->cal_data = kmalloc(fwu->cal_data_buf_size, GFP_KERNEL); | |
+ if (!fwu->cal_data) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for fwu->cal_data\n", | |
+ __func__); | |
+ fwu->cal_data_buf_size = 0; | |
+ return -ENOMEM; | |
+ } | |
+ } | |
+ | |
+ return 0; | |
+} | |
+#endif | |
+ | |
static int fwu_allocate_read_config_buf(unsigned int count) | |
{ | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
@@ -740,32 +895,39 @@ static int fwu_allocate_read_config_buf(unsigned int count) | |
static void fwu_compare_partition_tables(void) | |
{ | |
- if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware) { | |
- fwu->new_partition_table = true; | |
- return; | |
+ fwu->incompatible_partition_tables = false; | |
+ | |
+ if (fwu->phyaddr.bl_image != fwu->img.phyaddr.bl_image) | |
+ fwu->incompatible_partition_tables = true; | |
+ else if (fwu->phyaddr.lockdown != fwu->img.phyaddr.lockdown) | |
+ fwu->incompatible_partition_tables = true; | |
+ else if (fwu->phyaddr.bl_config != fwu->img.phyaddr.bl_config) | |
+ fwu->incompatible_partition_tables = true; | |
+ else if (fwu->phyaddr.utility_param != fwu->img.phyaddr.utility_param) | |
+ fwu->incompatible_partition_tables = true; | |
+ | |
+ if (fwu->bl_version == BL_V7) { | |
+ if (fwu->phyaddr.fl_config != fwu->img.phyaddr.fl_config) | |
+ fwu->incompatible_partition_tables = true; | |
} | |
- if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config) { | |
+ fwu->new_partition_table = false; | |
+ | |
+ if (fwu->phyaddr.ui_firmware != fwu->img.phyaddr.ui_firmware) | |
+ fwu->new_partition_table = true; | |
+ else if (fwu->phyaddr.ui_config != fwu->img.phyaddr.ui_config) | |
fwu->new_partition_table = true; | |
- return; | |
- } | |
if (fwu->flash_properties.has_disp_config) { | |
- if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) { | |
+ if (fwu->phyaddr.dp_config != fwu->img.phyaddr.dp_config) | |
fwu->new_partition_table = true; | |
- return; | |
- } | |
} | |
if (fwu->has_guest_code) { | |
- if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code) { | |
+ if (fwu->phyaddr.guest_code != fwu->img.phyaddr.guest_code) | |
fwu->new_partition_table = true; | |
- return; | |
- } | |
} | |
- fwu->new_partition_table = false; | |
- | |
return; | |
} | |
@@ -815,9 +977,18 @@ static void fwu_parse_partition_table(const unsigned char *partition_table, | |
break; | |
case BOOTLOADER_PARTITION: | |
blkcount->bl_image = partition_length; | |
+ phyaddr->bl_image = physical_address; | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
- "%s: Core config block count: %d\n", | |
- __func__, blkcount->ui_config); | |
+ "%s: Bootloader block count: %d\n", | |
+ __func__, blkcount->bl_image); | |
+ blkcount->total_count += partition_length; | |
+ break; | |
+ case UTILITY_PARAMETER_PARTITION: | |
+ blkcount->utility_param = partition_length; | |
+ phyaddr->utility_param = physical_address; | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Utility parameter block count: %d\n", | |
+ __func__, blkcount->utility_param); | |
blkcount->total_count += partition_length; | |
break; | |
case DISPLAY_CONFIG_PARTITION: | |
@@ -846,6 +1017,7 @@ static void fwu_parse_partition_table(const unsigned char *partition_table, | |
break; | |
case GUEST_SERIALIZATION_PARTITION: | |
blkcount->pm_config = partition_length; | |
+ phyaddr->pm_config = physical_address; | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
"%s: Guest serialization block count: %d\n", | |
__func__, blkcount->pm_config); | |
@@ -853,6 +1025,7 @@ static void fwu_parse_partition_table(const unsigned char *partition_table, | |
break; | |
case GLOBAL_PARAMETERS_PARTITION: | |
blkcount->bl_config = partition_length; | |
+ phyaddr->bl_config = physical_address; | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
"%s: Global parameters block count: %d\n", | |
__func__, blkcount->bl_config); | |
@@ -860,6 +1033,7 @@ static void fwu_parse_partition_table(const unsigned char *partition_table, | |
break; | |
case DEVICE_CONFIG_PARTITION: | |
blkcount->lockdown = partition_length; | |
+ phyaddr->lockdown = physical_address; | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
"%s: Device config block count: %d\n", | |
__func__, blkcount->lockdown); | |
@@ -871,7 +1045,42 @@ static void fwu_parse_partition_table(const unsigned char *partition_table, | |
return; | |
} | |
-static void fwu_parse_image_header_10_bl_container(const unsigned char *image) | |
+static void fwu_parse_image_header_10_utility(const unsigned char *image) | |
+{ | |
+ unsigned char ii; | |
+ unsigned char num_of_containers; | |
+ unsigned int addr; | |
+ unsigned int container_id; | |
+ unsigned int length; | |
+ const unsigned char *content; | |
+ struct container_descriptor *descriptor; | |
+ | |
+ num_of_containers = fwu->img.utility.size / 4; | |
+ | |
+ for (ii = 0; ii < num_of_containers; ii++) { | |
+ if (ii >= MAX_UTILITY_PARAMS) | |
+ continue; | |
+ addr = le_to_uint(fwu->img.utility.data + (ii * 4)); | |
+ descriptor = (struct container_descriptor *)(image + addr); | |
+ container_id = descriptor->container_id[0] | | |
+ descriptor->container_id[1] << 8; | |
+ content = image + le_to_uint(descriptor->content_address); | |
+ length = le_to_uint(descriptor->content_length); | |
+ switch (container_id) { | |
+ case UTILITY_PARAMETER_CONTAINER: | |
+ fwu->img.utility_param[ii].data = content; | |
+ fwu->img.utility_param[ii].size = length; | |
+ fwu->img.utility_param_id[ii] = content[0]; | |
+ break; | |
+ default: | |
+ break; | |
+ }; | |
+ } | |
+ | |
+ return; | |
+} | |
+ | |
+static void fwu_parse_image_header_10_bootloader(const unsigned char *image) | |
{ | |
unsigned char ii; | |
unsigned char num_of_containers; | |
@@ -962,7 +1171,12 @@ static void fwu_parse_image_header_10(void) | |
fwu->img.bl_version = *content; | |
fwu->img.bootloader.data = content; | |
fwu->img.bootloader.size = length; | |
- fwu_parse_image_header_10_bl_container(image); | |
+ fwu_parse_image_header_10_bootloader(image); | |
+ break; | |
+ case UTILITY_CONTAINER: | |
+ fwu->img.utility.data = content; | |
+ fwu->img.utility.size = length; | |
+ fwu_parse_image_header_10_utility(image); | |
break; | |
case GUEST_CODE_CONTAINER: | |
fwu->img.contains_guest_code = true; | |
@@ -1031,8 +1245,7 @@ static void fwu_parse_image_header_05_06(void) | |
fwu->img.ui_firmware.size; | |
} | |
- if ((fwu->img.bl_version == BL_V5 && fwu->img.contains_bootloader) || | |
- (fwu->img.bl_version == BL_V6 && header->options_tddi)) | |
+ if (fwu->img.contains_bootloader || header->options_tddi) | |
fwu->img.contains_disp_config = true; | |
else | |
fwu->img.contains_disp_config = false; | |
@@ -1112,9 +1325,13 @@ static int fwu_parse_image_info(void) | |
fwu_parse_partition_table(fwu->img.fl_config.data, | |
&fwu->img.blkcount, &fwu->img.phyaddr); | |
+ if (fwu->img.blkcount.utility_param) | |
+ fwu->img.contains_utility_param = true; | |
+ | |
fwu_compare_partition_tables(); | |
} else { | |
fwu->new_partition_table = false; | |
+ fwu->incompatible_partition_tables = false; | |
} | |
return 0; | |
@@ -1147,12 +1364,18 @@ static int fwu_read_flash_status(void) | |
else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) | |
fwu->flash_status = status & MASK_5BIT; | |
+ if (fwu->write_bootloader) | |
+ fwu->flash_status = 0x00; | |
+ | |
if (fwu->flash_status != 0x00) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Flash status = %d, command = 0x%02x\n", | |
- __func__, fwu->flash_status, fwu->command); | |
+ "%s: Flash status = %d, command = 0x%02x, config area = 0x%02x\n", | |
+ __func__, fwu->flash_status, fwu->command, fwu->config_area); | |
} | |
+ if (fwu->flash_status == 0x08) | |
+ fwu->flash_status = 0; | |
+ | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
fwu->f34_fd.data_base_addr + fwu->off.flash_cmd, | |
&command, | |
@@ -1171,6 +1394,9 @@ static int fwu_read_flash_status(void) | |
else if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) | |
fwu->command = command; | |
+ if (fwu->write_bootloader) | |
+ fwu->command = 0x00; | |
+ | |
return 0; | |
} | |
@@ -1201,11 +1427,11 @@ static int fwu_wait_for_idle(int timeout_ms, bool poll) | |
static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
struct f34_v7_data_1_5 data_1_5; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
memset(data_1_5.data, 0x00, sizeof(data_1_5.data)); | |
@@ -1238,6 +1464,14 @@ static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) | |
data_1_5.partition_id = GUEST_CODE_PARTITION; | |
data_1_5.command = CMD_V7_ERASE; | |
break; | |
+ case CMD_ERASE_BOOTLOADER: | |
+ data_1_5.partition_id = BOOTLOADER_PARTITION; | |
+ data_1_5.command = CMD_V7_ERASE; | |
+ break; | |
+ case CMD_ERASE_UTILITY_PARAMETER: | |
+ data_1_5.partition_id = UTILITY_PARAMETER_PARTITION; | |
+ data_1_5.command = CMD_V7_ERASE; | |
+ break; | |
case CMD_ENABLE_FLASH_PROG: | |
data_1_5.partition_id = BOOTLOADER_PARTITION; | |
data_1_5.command = CMD_V7_ENTER_BL; | |
@@ -1248,7 +1482,7 @@ static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) | |
data_1_5.payload_1 = fwu->bootloader_id[1]; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.partition_id, | |
+ data_base + fwu->off.partition_id, | |
data_1_5.data, | |
sizeof(data_1_5.data)); | |
if (retval < 0) { | |
@@ -1264,17 +1498,19 @@ static int fwu_write_f34_v7_command_single_transaction(unsigned char cmd) | |
static int fwu_write_f34_v7_command(unsigned char cmd) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char command; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
switch (cmd) { | |
case CMD_WRITE_FW: | |
case CMD_WRITE_CONFIG: | |
case CMD_WRITE_LOCKDOWN: | |
case CMD_WRITE_GUEST_CODE: | |
+ case CMD_WRITE_BOOTLOADER: | |
+ case CMD_WRITE_UTILITY_PARAM: | |
command = CMD_V7_WRITE; | |
break; | |
case CMD_READ_CONFIG: | |
@@ -1289,6 +1525,8 @@ static int fwu_write_f34_v7_command(unsigned char cmd) | |
case CMD_ERASE_DISP_CONFIG: | |
case CMD_ERASE_FLASH_CONFIG: | |
case CMD_ERASE_GUEST_CODE: | |
+ case CMD_ERASE_BOOTLOADER: | |
+ case CMD_ERASE_UTILITY_PARAMETER: | |
command = CMD_V7_ERASE; | |
break; | |
case CMD_ENABLE_FLASH_PROG: | |
@@ -1311,6 +1549,8 @@ static int fwu_write_f34_v7_command(unsigned char cmd) | |
case CMD_ERASE_DISP_CONFIG: | |
case CMD_ERASE_FLASH_CONFIG: | |
case CMD_ERASE_GUEST_CODE: | |
+ case CMD_ERASE_BOOTLOADER: | |
+ case CMD_ERASE_UTILITY_PARAMETER: | |
case CMD_ENABLE_FLASH_PROG: | |
retval = fwu_write_f34_v7_command_single_transaction(cmd); | |
if (retval < 0) | |
@@ -1322,7 +1562,7 @@ static int fwu_write_f34_v7_command(unsigned char cmd) | |
}; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.flash_cmd, | |
+ data_base + fwu->off.flash_cmd, | |
&command, | |
sizeof(command)); | |
if (retval < 0) { | |
@@ -1338,11 +1578,11 @@ static int fwu_write_f34_v7_command(unsigned char cmd) | |
static int fwu_write_f34_v5v6_command(unsigned char cmd) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char command; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
switch (cmd) { | |
case CMD_IDLE: | |
@@ -1395,7 +1635,7 @@ static int fwu_write_f34_v5v6_command(unsigned char cmd) | |
case CMD_ERASE_GUEST_CODE: | |
case CMD_ENABLE_FLASH_PROG: | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.payload, | |
+ data_base + fwu->off.payload, | |
fwu->bootloader_id, | |
sizeof(fwu->bootloader_id)); | |
if (retval < 0) { | |
@@ -1412,7 +1652,7 @@ static int fwu_write_f34_v5v6_command(unsigned char cmd) | |
fwu->command = command; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.flash_cmd, | |
+ data_base + fwu->off.flash_cmd, | |
&command, | |
sizeof(command)); | |
if (retval < 0) { | |
@@ -1440,11 +1680,11 @@ static int fwu_write_f34_command(unsigned char cmd) | |
static int fwu_write_f34_v7_partition_id(unsigned char cmd) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char partition; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
switch (cmd) { | |
case CMD_WRITE_FW: | |
@@ -1469,6 +1709,12 @@ static int fwu_write_f34_v7_partition_id(unsigned char cmd) | |
case CMD_WRITE_GUEST_CODE: | |
partition = GUEST_CODE_PARTITION; | |
break; | |
+ case CMD_WRITE_BOOTLOADER: | |
+ partition = BOOTLOADER_PARTITION; | |
+ break; | |
+ case CMD_WRITE_UTILITY_PARAM: | |
+ partition = UTILITY_PARAMETER_PARTITION; | |
+ break; | |
case CMD_ERASE_ALL: | |
partition = CORE_CODE_PARTITION; | |
break; | |
@@ -1487,6 +1733,9 @@ static int fwu_write_f34_v7_partition_id(unsigned char cmd) | |
case CMD_ERASE_GUEST_CODE: | |
partition = GUEST_CODE_PARTITION; | |
break; | |
+ case CMD_ERASE_BOOTLOADER: | |
+ partition = BOOTLOADER_PARTITION; | |
+ break; | |
case CMD_ENABLE_FLASH_PROG: | |
partition = BOOTLOADER_PARTITION; | |
break; | |
@@ -1498,7 +1747,7 @@ static int fwu_write_f34_v7_partition_id(unsigned char cmd) | |
}; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.partition_id, | |
+ data_base + fwu->off.partition_id, | |
&partition, | |
sizeof(partition)); | |
if (retval < 0) { | |
@@ -1526,12 +1775,12 @@ static int fwu_write_f34_partition_id(unsigned char cmd) | |
static int fwu_read_f34_v7_partition_table(unsigned char *partition_table) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char length[2]; | |
unsigned short block_number = 0; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
fwu->config_area = FLASH_CONFIG_AREA; | |
@@ -1540,7 +1789,7 @@ static int fwu_read_f34_v7_partition_table(unsigned char *partition_table) | |
return retval; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.block_number, | |
+ data_base + fwu->off.block_number, | |
(unsigned char *)&block_number, | |
sizeof(block_number)); | |
if (retval < 0) { | |
@@ -1554,7 +1803,7 @@ static int fwu_read_f34_v7_partition_table(unsigned char *partition_table) | |
length[1] = (unsigned char)(fwu->flash_config_length >> 8); | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.transfer_length, | |
+ data_base + fwu->off.transfer_length, | |
length, | |
sizeof(length)); | |
if (retval < 0) { | |
@@ -1581,7 +1830,7 @@ static int fwu_read_f34_v7_partition_table(unsigned char *partition_table) | |
} | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.payload, | |
+ data_base + fwu->off.payload, | |
partition_table, | |
fwu->partition_table_bytes); | |
if (retval < 0) { | |
@@ -1598,7 +1847,7 @@ static int fwu_read_f34_v7_queries(void) | |
{ | |
int retval; | |
unsigned char ii; | |
- unsigned char base; | |
+ unsigned char query_base; | |
unsigned char index; | |
unsigned char offset; | |
unsigned char *ptable; | |
@@ -1606,10 +1855,10 @@ static int fwu_read_f34_v7_queries(void) | |
struct f34_v7_query_1_7 query_1_7; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.query_base_addr; | |
+ query_base = fwu->f34_fd.query_base_addr; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base, | |
+ query_base, | |
query_0.data, | |
sizeof(query_0.data)); | |
if (retval < 0) { | |
@@ -1622,7 +1871,7 @@ static int fwu_read_f34_v7_queries(void) | |
offset = query_0.subpacket_1_size + 1; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + offset, | |
+ query_base + offset, | |
query_1_7.data, | |
sizeof(query_1_7.data)); | |
if (retval < 0) { | |
@@ -1709,6 +1958,11 @@ static int fwu_read_f34_v7_queries(void) | |
else | |
fwu->has_guest_code = 0; | |
+ if (fwu->blkcount.utility_param) | |
+ fwu->has_utility_param = 1; | |
+ else | |
+ fwu->has_utility_param = 0; | |
+ | |
kfree(ptable); | |
if (rmi4_data->hw_if->board_data->lockdown_area == LOCKDOWN_AREA_GUEST_SERIALIZATION) | |
@@ -1755,15 +2009,15 @@ static int fwu_read_f34_v5v6_queries(void) | |
{ | |
int retval; | |
unsigned char count; | |
- unsigned char base; | |
+ unsigned char query_base; | |
unsigned char buf[10]; | |
struct f34_v5v6_flash_properties_2 properties_2; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.query_base_addr; | |
+ query_base = fwu->f34_fd.query_base_addr; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + V5V6_BOOTLOADER_ID_OFFSET, | |
+ query_base + V5V6_BOOTLOADER_ID_OFFSET, | |
fwu->bootloader_id, | |
sizeof(fwu->bootloader_id)); | |
if (retval < 0) { | |
@@ -1789,7 +2043,7 @@ static int fwu_read_f34_v5v6_queries(void) | |
} | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.block_size, | |
+ query_base + fwu->off.block_size, | |
buf, | |
2); | |
if (retval < 0) { | |
@@ -1810,7 +2064,7 @@ static int fwu_read_f34_v5v6_queries(void) | |
} | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.properties, | |
+ query_base + fwu->off.properties, | |
fwu->flash_properties.data, | |
sizeof(fwu->flash_properties.data)); | |
if (retval < 0) { | |
@@ -1832,7 +2086,7 @@ static int fwu_read_f34_v5v6_queries(void) | |
count += 2; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.block_count, | |
+ query_base + fwu->off.block_count, | |
buf, | |
count); | |
if (retval < 0) { | |
@@ -1866,7 +2120,7 @@ static int fwu_read_f34_v5v6_queries(void) | |
if (fwu->flash_properties.has_query4) { | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.properties_2, | |
+ query_base + fwu->off.properties_2, | |
properties_2.data, | |
sizeof(properties_2.data)); | |
if (retval < 0) { | |
@@ -1881,7 +2135,7 @@ static int fwu_read_f34_v5v6_queries(void) | |
if (properties_2.has_guest_code) { | |
count++; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.properties_2 + count, | |
+ query_base + fwu->off.properties_2 + count, | |
buf, | |
2); | |
if (retval < 0) { | |
@@ -1904,7 +2158,7 @@ static int fwu_read_f34_v5v6_queries(void) | |
if (properties_2.has_lockdown_data_block) { | |
count++; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.properties_2 + count, | |
+ query_base + fwu->off.properties_2 + count, | |
buf, | |
2); | |
if (retval < 0) { | |
@@ -1921,6 +2175,8 @@ static int fwu_read_f34_v5v6_queries(void) | |
} | |
} | |
+ fwu->has_utility_param = false; | |
+ | |
return 0; | |
} | |
@@ -1943,22 +2199,24 @@ static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, | |
unsigned short block_cnt, unsigned char command) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char length[2]; | |
unsigned short transfer; | |
- unsigned short max_transfer; | |
unsigned short remaining = block_cnt; | |
unsigned short block_number = 0; | |
+ unsigned short left_bytes; | |
+ unsigned short write_size; | |
+ unsigned short max_write_size; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
retval = fwu_write_f34_partition_id(command); | |
if (retval < 0) | |
return retval; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.block_number, | |
+ data_base + fwu->off.block_number, | |
(unsigned char *)&block_number, | |
sizeof(block_number)); | |
if (retval < 0) { | |
@@ -1968,14 +2226,9 @@ static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, | |
return retval; | |
} | |
- if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) | |
- max_transfer = PAGE_SIZE / fwu->block_size; | |
- else | |
- max_transfer = fwu->payload_length; | |
- | |
do { | |
- if (remaining / max_transfer) | |
- transfer = max_transfer; | |
+ if (remaining / fwu->payload_length) | |
+ transfer = fwu->payload_length; | |
else | |
transfer = remaining; | |
@@ -1983,12 +2236,12 @@ static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, | |
length[1] = (unsigned char)(transfer >> 8); | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.transfer_length, | |
+ data_base + fwu->off.transfer_length, | |
length, | |
sizeof(length)); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to write transfer length (%d blocks remaining)\n", | |
+ "%s: Failed to write transfer length (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
@@ -1996,31 +2249,53 @@ static int fwu_write_f34_v7_blocks(unsigned char *block_ptr, | |
retval = fwu_write_f34_command(command); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to write command (%d blocks remaining)\n", | |
+ "%s: Failed to write command (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
- retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.payload, | |
- block_ptr, | |
- transfer * fwu->block_size); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to write block data (%d blocks remaining)\n", | |
- __func__, remaining); | |
- return retval; | |
- } | |
+#ifdef MAX_WRITE_SIZE | |
+ max_write_size = MAX_WRITE_SIZE; | |
+ if (max_write_size >= transfer * fwu->block_size) | |
+ max_write_size = transfer * fwu->block_size; | |
+ else if (max_write_size > fwu->block_size) | |
+ max_write_size -= max_write_size % fwu->block_size; | |
+ else | |
+ max_write_size = fwu->block_size; | |
+#else | |
+ max_write_size = transfer * fwu->block_size; | |
+#endif | |
+ left_bytes = transfer * fwu->block_size; | |
+ | |
+ do { | |
+ if (left_bytes / max_write_size) | |
+ write_size = max_write_size; | |
+ else | |
+ write_size = left_bytes; | |
+ | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ data_base + fwu->off.payload, | |
+ block_ptr, | |
+ write_size); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to write block data (remaining = %d)\n", | |
+ __func__, remaining); | |
+ return retval; | |
+ } | |
+ | |
+ block_ptr += write_size; | |
+ left_bytes -= write_size; | |
+ } while (left_bytes); | |
retval = fwu_wait_for_idle(WRITE_WAIT_MS, false); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to wait for idle status (%d blocks remaining)\n", | |
+ "%s: Failed to wait for idle status (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
- block_ptr += (transfer * fwu->block_size); | |
remaining -= transfer; | |
} while (remaining); | |
@@ -2031,17 +2306,17 @@ static int fwu_write_f34_v5v6_blocks(unsigned char *block_ptr, | |
unsigned short block_cnt, unsigned char command) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char block_number[] = {0, 0}; | |
unsigned short blk; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
block_number[1] |= (fwu->config_area << 5); | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.block_number, | |
+ data_base + fwu->off.block_number, | |
block_number, | |
sizeof(block_number)); | |
if (retval < 0) { | |
@@ -2053,7 +2328,7 @@ static int fwu_write_f34_v5v6_blocks(unsigned char *block_ptr, | |
for (blk = 0; blk < block_cnt; blk++) { | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.payload, | |
+ data_base + fwu->off.payload, | |
block_ptr, | |
fwu->block_size); | |
if (retval < 0) { | |
@@ -2102,23 +2377,22 @@ static int fwu_read_f34_v7_blocks(unsigned short block_cnt, | |
unsigned char command) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char length[2]; | |
unsigned short transfer; | |
- unsigned short max_transfer; | |
unsigned short remaining = block_cnt; | |
unsigned short block_number = 0; | |
unsigned short index = 0; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
retval = fwu_write_f34_partition_id(command); | |
if (retval < 0) | |
return retval; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.block_number, | |
+ data_base + fwu->off.block_number, | |
(unsigned char *)&block_number, | |
sizeof(block_number)); | |
if (retval < 0) { | |
@@ -2128,14 +2402,9 @@ static int fwu_read_f34_v7_blocks(unsigned short block_cnt, | |
return retval; | |
} | |
- if (fwu->payload_length > (PAGE_SIZE / fwu->block_size)) | |
- max_transfer = PAGE_SIZE / fwu->block_size; | |
- else | |
- max_transfer = fwu->payload_length; | |
- | |
do { | |
- if (remaining / max_transfer) | |
- transfer = max_transfer; | |
+ if (remaining / fwu->payload_length) | |
+ transfer = fwu->payload_length; | |
else | |
transfer = remaining; | |
@@ -2143,12 +2412,12 @@ static int fwu_read_f34_v7_blocks(unsigned short block_cnt, | |
length[1] = (unsigned char)(transfer >> 8); | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.transfer_length, | |
+ data_base + fwu->off.transfer_length, | |
length, | |
sizeof(length)); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to write transfer length (%d blocks remaining)\n", | |
+ "%s: Failed to write transfer length (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
@@ -2156,7 +2425,7 @@ static int fwu_read_f34_v7_blocks(unsigned short block_cnt, | |
retval = fwu_write_f34_command(command); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to write command (%d blocks remaining)\n", | |
+ "%s: Failed to write command (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
@@ -2164,18 +2433,18 @@ static int fwu_read_f34_v7_blocks(unsigned short block_cnt, | |
retval = fwu_wait_for_idle(WRITE_WAIT_MS, true); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to wait for idle status (%d blocks remaining)\n", | |
+ "%s: Failed to wait for idle status (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.payload, | |
+ data_base + fwu->off.payload, | |
&fwu->read_config_buf[index], | |
transfer * fwu->block_size); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to read block data (%d blocks remaining)\n", | |
+ "%s: Failed to read block data (remaining = %d)\n", | |
__func__, remaining); | |
return retval; | |
} | |
@@ -2191,18 +2460,18 @@ static int fwu_read_f34_v5v6_blocks(unsigned short block_cnt, | |
unsigned char command) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char block_number[] = {0, 0}; | |
unsigned short blk; | |
unsigned short index = 0; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f34_fd.data_base_addr; | |
+ data_base = fwu->f34_fd.data_base_addr; | |
block_number[1] |= (fwu->config_area << 5); | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + fwu->off.block_number, | |
+ data_base + fwu->off.block_number, | |
block_number, | |
sizeof(block_number)); | |
if (retval < 0) { | |
@@ -2230,7 +2499,7 @@ static int fwu_read_f34_v5v6_blocks(unsigned short block_cnt, | |
} | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + fwu->off.payload, | |
+ data_base + fwu->off.payload, | |
&fwu->read_config_buf[index], | |
fwu->block_size); | |
if (retval < 0) { | |
@@ -2390,7 +2659,7 @@ static enum flash_area fwu_go_nogo(void) | |
} | |
/* Update both UI and config if device is in bootloader mode */ | |
- if (fwu->in_bl_mode) { | |
+ if (fwu->bl_mode_device) { | |
flash_area = UI_FIRMWARE; | |
goto exit; | |
} | |
@@ -2541,6 +2810,8 @@ static int fwu_scan_pdt(void) | |
rmi_fd.ctrl_base_addr; | |
fwu->f35_fd.data_base_addr = | |
rmi_fd.data_base_addr; | |
+ fwu->f35_fd.cmd_base_addr = | |
+ rmi_fd.cmd_base_addr; | |
break; | |
} | |
} else { | |
@@ -2631,6 +2902,8 @@ static int fwu_enter_flash_prog(void) | |
if (retval < 0) | |
return retval; | |
+ pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode); | |
+ | |
retval = fwu_read_f34_queries(); | |
if (retval < 0) | |
return retval; | |
@@ -2766,16 +3039,6 @@ static int fwu_check_guest_code_size(void) | |
return 0; | |
} | |
-static int fwu_write_firmware(void) | |
-{ | |
- unsigned short firmware_block_count; | |
- | |
- firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size; | |
- | |
- return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data, | |
- firmware_block_count, CMD_WRITE_FW); | |
-} | |
- | |
static int fwu_erase_configuration(void) | |
{ | |
int retval; | |
@@ -2797,6 +3060,16 @@ static int fwu_erase_configuration(void) | |
if (retval < 0) | |
return retval; | |
break; | |
+ case FLASH_CONFIG_AREA: | |
+ retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG); | |
+ if (retval < 0) | |
+ return retval; | |
+ break; | |
+ default: | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Invalid config area\n", | |
+ __func__); | |
+ return -EINVAL; | |
} | |
dev_dbg(rmi4_data->pdev->dev.parent, | |
@@ -2814,6 +3087,54 @@ static int fwu_erase_configuration(void) | |
return retval; | |
} | |
+static int fwu_erase_bootloader(void) | |
+{ | |
+ int retval; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ retval = fwu_write_f34_command(CMD_ERASE_BOOTLOADER); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Erase command written\n", | |
+ __func__); | |
+ | |
+ retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Idle status detected\n", | |
+ __func__); | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int fwu_erase_utility_parameter(void) | |
+{ | |
+ int retval; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ retval = fwu_write_f34_command(CMD_ERASE_UTILITY_PARAMETER); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Erase command written\n", | |
+ __func__); | |
+ | |
+ retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Idle status detected\n", | |
+ __func__); | |
+ | |
+ return 0; | |
+} | |
+ | |
static int fwu_erase_guest_code(void) | |
{ | |
int retval; | |
@@ -2844,6 +3165,7 @@ static int fwu_erase_all(void) | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
if (fwu->bl_version == BL_V7) { | |
+ fwu->config_area = INVALID_CONFIG_AREA; | |
retval = fwu_write_f34_command(CMD_ERASE_UI_FIRMWARE); | |
if (retval < 0) | |
return retval; | |
@@ -2860,10 +3182,14 @@ static int fwu_erase_all(void) | |
"%s: Idle status detected\n", | |
__func__); | |
+ pr_err("erased core code\n"); | |
+ | |
fwu->config_area = UI_CONFIG_AREA; | |
retval = fwu_erase_configuration(); | |
if (retval < 0) | |
return retval; | |
+ | |
+ pr_err("erased core config\n"); | |
} else { | |
retval = fwu_write_f34_command(CMD_ERASE_ALL); | |
if (retval < 0) | |
@@ -2905,33 +3231,153 @@ static int fwu_erase_all(void) | |
return 0; | |
} | |
-static int fwu_write_configuration(void) | |
+static int fwu_write_firmware(void) | |
{ | |
- return fwu_write_f34_blocks((unsigned char *)fwu->config_data, | |
- fwu->config_block_count, CMD_WRITE_CONFIG); | |
-} | |
+ unsigned short firmware_block_count; | |
-static int fwu_write_ui_configuration(void) | |
-{ | |
- fwu->config_area = UI_CONFIG_AREA; | |
- fwu->config_data = fwu->img.ui_config.data; | |
- fwu->config_size = fwu->img.ui_config.size; | |
- fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ firmware_block_count = fwu->img.ui_firmware.size / fwu->block_size; | |
- return fwu_write_configuration(); | |
+ pr_err("core code block count = %d\n", firmware_block_count); | |
+ | |
+ return fwu_write_f34_blocks((unsigned char *)fwu->img.ui_firmware.data, | |
+ firmware_block_count, CMD_WRITE_FW); | |
} | |
-static int fwu_write_dp_configuration(void) | |
+static int fwu_write_bootloader(void) | |
{ | |
- fwu->config_area = DP_CONFIG_AREA; | |
- fwu->config_data = fwu->img.dp_config.data; | |
- fwu->config_size = fwu->img.dp_config.size; | |
- fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ int retval; | |
+ unsigned short bootloader_block_count; | |
- return fwu_write_configuration(); | |
+ bootloader_block_count = fwu->img.bl_image.size / fwu->block_size; | |
+ | |
+ pr_err("bootloader block count = %d\n", bootloader_block_count); | |
+ | |
+ fwu->write_bootloader = true; | |
+ retval = fwu_write_f34_blocks((unsigned char *)fwu->img.bl_image.data, | |
+ bootloader_block_count, CMD_WRITE_BOOTLOADER); | |
+ fwu->write_bootloader = false; | |
+ | |
+ return retval; | |
} | |
-static int fwu_write_pm_configuration(void) | |
+static int fwu_write_utility_parameter(void) | |
+{ | |
+ int retval; | |
+ unsigned char ii; | |
+ unsigned char checksum_array[4]; | |
+ unsigned char *pbuf; | |
+ unsigned short remaining_size; | |
+ unsigned short utility_param_size; | |
+ unsigned long checksum; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ utility_param_size = fwu->blkcount.utility_param * fwu->block_size; | |
+ retval = fwu_allocate_read_config_buf(utility_param_size); | |
+ if (retval < 0) | |
+ return retval; | |
+ memset(fwu->read_config_buf, 0x00, utility_param_size); | |
+ | |
+ pbuf = fwu->read_config_buf; | |
+ remaining_size = utility_param_size - 4; | |
+ | |
+ for (ii = 0; ii < MAX_UTILITY_PARAMS; ii++) { | |
+ if (fwu->img.utility_param_id[ii] == UNUSED) | |
+ continue; | |
+ | |
+#ifdef F51_DISCRETE_FORCE | |
+ if (fwu->img.utility_param_id[ii] == FORCE_PARAMETER) { | |
+ if (fwu->bl_mode_device) { | |
+ dev_info(rmi4_data->pdev->dev.parent, | |
+ "%s: Device in bootloader mode, skipping calibration data restoration\n", | |
+ __func__); | |
+ goto image_param; | |
+ } | |
+ retval = secure_memcpy(&(pbuf[4]), | |
+ remaining_size - 4, | |
+ fwu->cal_data, | |
+ fwu->cal_data_buf_size, | |
+ fwu->cal_data_size); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to copy force calibration data\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ pbuf[0] = FORCE_PARAMETER; | |
+ pbuf[1] = 0x00; | |
+ pbuf[2] = (4 + fwu->cal_data_size) / 2; | |
+ pbuf += (fwu->cal_data_size + 4); | |
+ remaining_size -= (fwu->cal_data_size + 4); | |
+ continue; | |
+ } | |
+image_param: | |
+#endif | |
+ | |
+ retval = secure_memcpy(pbuf, | |
+ remaining_size, | |
+ fwu->img.utility_param[ii].data, | |
+ fwu->img.utility_param[ii].size, | |
+ fwu->img.utility_param[ii].size); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to copy utility parameter data\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ pbuf += fwu->img.utility_param[ii].size; | |
+ remaining_size -= fwu->img.utility_param[ii].size; | |
+ } | |
+ | |
+ calculate_checksum((unsigned short *)fwu->read_config_buf, | |
+ ((utility_param_size - 4) / 2), | |
+ &checksum); | |
+ | |
+ convert_to_little_endian(checksum_array, checksum); | |
+ | |
+ fwu->read_config_buf[utility_param_size - 4] = checksum_array[0]; | |
+ fwu->read_config_buf[utility_param_size - 3] = checksum_array[1]; | |
+ fwu->read_config_buf[utility_param_size - 2] = checksum_array[2]; | |
+ fwu->read_config_buf[utility_param_size - 1] = checksum_array[3]; | |
+ | |
+ pr_err("utility parameter block count = %d\n", fwu->blkcount.utility_param); | |
+ | |
+ retval = fwu_write_f34_blocks((unsigned char *)fwu->read_config_buf, | |
+ fwu->blkcount.utility_param, CMD_WRITE_UTILITY_PARAM); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ return 0; | |
+} | |
+ | |
+static int fwu_write_configuration(void) | |
+{ | |
+ return fwu_write_f34_blocks((unsigned char *)fwu->config_data, | |
+ fwu->config_block_count, CMD_WRITE_CONFIG); | |
+} | |
+ | |
+static int fwu_write_ui_configuration(void) | |
+{ | |
+ fwu->config_area = UI_CONFIG_AREA; | |
+ fwu->config_data = fwu->img.ui_config.data; | |
+ fwu->config_size = fwu->img.ui_config.size; | |
+ fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ | |
+ pr_err("core config block count = %d\n", fwu->config_block_count); | |
+ | |
+ return fwu_write_configuration(); | |
+} | |
+ | |
+static int fwu_write_dp_configuration(void) | |
+{ | |
+ fwu->config_area = DP_CONFIG_AREA; | |
+ fwu->config_data = fwu->img.dp_config.data; | |
+ fwu->config_size = fwu->img.dp_config.size; | |
+ fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ | |
+ return fwu_write_configuration(); | |
+} | |
+ | |
+static int fwu_write_pm_configuration(void) | |
{ | |
fwu->config_area = PM_CONFIG_AREA; | |
fwu->config_data = fwu->img.pm_config.data; | |
@@ -2958,22 +3404,10 @@ static int fwu_write_flash_configuration(void) | |
return -EINVAL; | |
} | |
- retval = fwu_write_f34_command(CMD_ERASE_FLASH_CONFIG); | |
- if (retval < 0) | |
- return retval; | |
- | |
- dev_dbg(rmi4_data->pdev->dev.parent, | |
- "%s: Erase flash configuration command written\n", | |
- __func__); | |
- | |
- retval = fwu_wait_for_idle(ERASE_WAIT_MS, false); | |
+ retval = fwu_erase_configuration(); | |
if (retval < 0) | |
return retval; | |
- dev_dbg(rmi4_data->pdev->dev.parent, | |
- "%s: Idle status detected\n", | |
- __func__); | |
- | |
retval = fwu_write_configuration(); | |
if (retval < 0) | |
return retval; | |
@@ -3071,9 +3505,95 @@ static int fwu_write_partition_table_v7(void) | |
return 0; | |
} | |
+static int fwu_write_bl_area_v7(void) | |
+{ | |
+ int retval; | |
+ bool has_utility_param; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ has_utility_param = fwu->has_utility_param; | |
+ | |
+ if (fwu->has_utility_param) { | |
+ retval = fwu_erase_utility_parameter(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("erased utility parameter\n"); | |
+ } | |
+ | |
+ fwu->config_area = BL_CONFIG_AREA; | |
+ retval = fwu_erase_configuration(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("erased bootloader config\n"); | |
+ | |
+ fwu->config_area = FLASH_CONFIG_AREA; | |
+ retval = fwu_erase_configuration(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("erased flash config\n"); | |
+ | |
+ retval = fwu_erase_bootloader(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("erased bootloader\n"); | |
+ | |
+ retval = fwu_write_bootloader(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("bootloader written\n"); | |
+ | |
+ msleep(rmi4_data->hw_if->board_data->reset_delay_ms); | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ | |
+ pr_err("reset after writing bootloader\n"); | |
+ | |
+ fwu->config_area = FLASH_CONFIG_AREA; | |
+ fwu->config_data = fwu->img.fl_config.data; | |
+ fwu->config_size = fwu->img.fl_config.size; | |
+ fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ pr_err("flash config block count = %d\n", fwu->config_block_count); | |
+ retval = fwu_write_configuration(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("flash config written\n"); | |
+ | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ | |
+ pr_err("reset after writing flash config\n"); | |
+ | |
+ fwu->config_area = BL_CONFIG_AREA; | |
+ fwu->config_data = fwu->img.bl_config.data; | |
+ fwu->config_size = fwu->img.bl_config.size; | |
+ fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ pr_err("bootloader config block count = %d\n", fwu->config_block_count); | |
+ retval = fwu_write_configuration(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("bootloader config written\n"); | |
+ | |
+ if (fwu->img.contains_utility_param) { | |
+ retval = fwu_write_utility_parameter(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ pr_err("utility parameter written\n"); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
static int fwu_do_reflash(void) | |
{ | |
int retval; | |
+ bool do_bl_update = false; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
if (!fwu->new_partition_table) { | |
retval = fwu_check_ui_firmware_size(); | |
@@ -3102,11 +3622,44 @@ static int fwu_do_reflash(void) | |
return retval; | |
} | |
+ if (!fwu->has_utility_param && fwu->img.contains_utility_param) { | |
+ if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) | |
+ do_bl_update = true; | |
+ } | |
+ | |
+ if (fwu->has_utility_param && !fwu->img.contains_utility_param) { | |
+ if (fwu->bl_version == BL_V7 || fwu->bl_version == BL_V8) | |
+ do_bl_update = true; | |
+ } | |
+ | |
+ pr_err("fwu->has_utility_param = %d\n", fwu->has_utility_param); | |
+ pr_err("fwu->img.contains_utility_param = %d\n", fwu->img.contains_utility_param); | |
+ pr_err("do_bl_update = %d\n", do_bl_update); | |
+ | |
+ if (!do_bl_update && fwu->incompatible_partition_tables) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Incompatible partition tables\n", | |
+ __func__); | |
+ return -EINVAL; | |
+ } else if (!do_bl_update && fwu->new_partition_table) { | |
+ if (!fwu->force_update) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Partition table mismatch\n", | |
+ __func__); | |
+ return -EINVAL; | |
+ } | |
+ } | |
+ | |
retval = fwu_erase_all(); | |
if (retval < 0) | |
return retval; | |
- if (fwu->bl_version == BL_V7 && fwu->new_partition_table) { | |
+ if (do_bl_update) { | |
+ retval = fwu_write_bl_area_v7(); | |
+ if (retval < 0) | |
+ return retval; | |
+ pr_notice("%s: Bootloader area programmed\n", __func__); | |
+ } else if (fwu->bl_version == BL_V7 && fwu->new_partition_table) { | |
retval = fwu_write_partition_table_v7(); | |
if (retval < 0) | |
return retval; | |
@@ -3201,13 +3754,13 @@ static int fwu_do_read_config(void) | |
mutex_lock(&rmi4_data->rmi4_exp_init_mutex); | |
- config_area = fwu->config_area; | |
- | |
- retval = fwu_enter_flash_prog(); | |
- if (retval < 0) | |
- goto exit; | |
- | |
- fwu->config_area = config_area; | |
+ if (fwu->bl_version == BL_V5 || fwu->bl_version == BL_V6) { | |
+ config_area = fwu->config_area; | |
+ retval = fwu_enter_flash_prog(); | |
+ fwu->config_area = config_area; | |
+ if (retval < 0) | |
+ goto exit; | |
+ } | |
fwu->config_size = fwu->block_size * block_count; | |
@@ -3218,7 +3771,8 @@ static int fwu_do_read_config(void) | |
retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); | |
exit: | |
- rmi4_data->reset_device(rmi4_data, false); | |
+ if (fwu->bl_version == BL_V5 || fwu->bl_version == BL_V6) | |
+ rmi4_data->reset_device(rmi4_data, false); | |
mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); | |
@@ -3298,6 +3852,68 @@ static int fwu_do_lockdown_v5v6(void) | |
return retval; | |
} | |
+#ifdef F51_DISCRETE_FORCE | |
+static int fwu_do_restore_f51_cal_data(void) | |
+{ | |
+ int retval; | |
+ unsigned char checksum_array[4]; | |
+ unsigned short block_count; | |
+ unsigned long checksum; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ block_count = fwu->blkcount.ui_config; | |
+ fwu->config_size = fwu->block_size * block_count; | |
+ fwu->config_area = UI_CONFIG_AREA; | |
+ | |
+ retval = fwu_allocate_read_config_buf(fwu->config_size); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ retval = fwu_read_f34_blocks(block_count, CMD_READ_CONFIG); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ retval = secure_memcpy(&fwu->read_config_buf[fwu->cal_data_off], | |
+ fwu->cal_data_size, fwu->cal_data, | |
+ fwu->cal_data_buf_size, fwu->cal_data_size); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to restore calibration data\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ calculate_checksum((unsigned short *)fwu->read_config_buf, | |
+ ((fwu->config_size - 4) / 2), | |
+ &checksum); | |
+ | |
+ convert_to_little_endian(checksum_array, checksum); | |
+ | |
+ fwu->read_config_buf[fwu->config_size - 4] = checksum_array[0]; | |
+ fwu->read_config_buf[fwu->config_size - 3] = checksum_array[1]; | |
+ fwu->read_config_buf[fwu->config_size - 2] = checksum_array[2]; | |
+ fwu->read_config_buf[fwu->config_size - 1] = checksum_array[3]; | |
+ | |
+ retval = fwu_enter_flash_prog(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ fwu->config_area = UI_CONFIG_AREA; | |
+ fwu->config_data = fwu->read_config_buf; | |
+ fwu->config_block_count = fwu->config_size / fwu->block_size; | |
+ | |
+ retval = fwu_erase_configuration(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ retval = fwu_write_configuration(); | |
+ if (retval < 0) | |
+ return retval; | |
+ | |
+ return 0; | |
+} | |
+#endif | |
+ | |
static int fwu_start_write_guest_code(void) | |
{ | |
int retval; | |
@@ -3509,12 +4125,17 @@ static const char *fwu_get_firmware_name(struct synaptics_rmi4_data *rmi4_data) | |
const char *fw_name = NULL; | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
- int i, j; | |
+ int i, j, def = -1; | |
bool found = false; | |
if (bdata->tp_id_num != 0) { | |
for (i = 0; i < bdata->config_array_size; i++) { | |
found = true; | |
+ if (rmi4_data->chip_id != bdata->config_array[i].chip_id) | |
+ continue; | |
+ else | |
+ def = i; | |
+ | |
for (j = 0; j < bdata->tp_id_num; j++) { | |
if (bdata->config_array[i].tp_ids[j] != | |
rmi4_data->lockdown_info[bdata->tp_id_bytes[j]]) { | |
@@ -3530,12 +4151,11 @@ static const char *fwu_get_firmware_name(struct synaptics_rmi4_data *rmi4_data) | |
} | |
} | |
- if (!fw_name && rmi4_data->chip_id > 0) | |
- fw_name = bdata->config_array[rmi4_data->chip_id - 1].fw_name; | |
+ if (!fw_name && (def >= 0)) | |
+ fw_name = bdata->config_array[def].fw_name; | |
- if (fw_name) | |
- dev_info(rmi4_data->pdev->dev.parent, | |
- "%s: Choose firmware %s\n", __func__, fw_name); | |
+ dev_info(rmi4_data->pdev->dev.parent, | |
+ "%s: Choose firmware %s\n", __func__, fw_name); | |
return fw_name; | |
} | |
@@ -3544,6 +4164,7 @@ static int fwu_start_reflash(void) | |
{ | |
int retval = 0; | |
enum flash_area flash_area; | |
+ bool do_rebuild = false; | |
const struct firmware *fw_entry = NULL; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
const char *fw_name; | |
@@ -3558,10 +4179,12 @@ static int fwu_start_reflash(void) | |
fw_name = fwu_get_firmware_name(rmi4_data); | |
if (fw_name == NULL) { | |
- dev_err(rmi4_data->pdev->dev.parent, "%s: do not found fw need by ic\n", __func__); | |
- return 0; | |
+ dev_err(rmi4_data->pdev->dev.parent, "%s: do not found fw to update\n", __func__); | |
+ | |
+ return -EINVAL; | |
} | |
+ | |
rmi4_data->stay_awake = true; | |
mutex_lock(&rmi4_data->rmi4_exp_init_mutex); | |
@@ -3620,22 +4243,17 @@ static int fwu_start_reflash(void) | |
goto exit; | |
} | |
- if (!fwu->force_update && fwu->new_partition_table) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Partition table mismatch\n", | |
- __func__); | |
- retval = -EINVAL; | |
- goto exit; | |
- } | |
- | |
retval = fwu_read_flash_status(); | |
if (retval < 0) | |
goto exit; | |
if (fwu->in_bl_mode) { | |
+ fwu->bl_mode_device = true; | |
dev_info(rmi4_data->pdev->dev.parent, | |
"%s: Device in bootloader mode\n", | |
__func__); | |
+ } else { | |
+ fwu->bl_mode_device = false; | |
} | |
flash_area = fwu_go_nogo(); | |
@@ -3648,12 +4266,62 @@ static int fwu_start_reflash(void) | |
} | |
} | |
+#ifdef F51_DISCRETE_FORCE | |
+ if (flash_area != NONE && !fwu->bl_mode_device) { | |
+ fwu->config_size = fwu->block_size * fwu->blkcount.ui_config; | |
+ fwu->config_area = UI_CONFIG_AREA; | |
+ | |
+ retval = fwu_allocate_read_config_buf(fwu->config_size); | |
+ if (retval < 0) { | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ goto exit; | |
+ } | |
+ | |
+ retval = fwu_read_f34_blocks(fwu->blkcount.ui_config, | |
+ CMD_READ_CONFIG); | |
+ if (retval < 0) { | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ goto exit; | |
+ } | |
+ | |
+ retval = secure_memcpy(fwu->cal_data, fwu->cal_data_buf_size, | |
+ &fwu->read_config_buf[fwu->cal_data_off], | |
+ fwu->cal_data_size, fwu->cal_data_size); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to save calibration data\n", | |
+ __func__); | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ goto exit; | |
+ } | |
+ } | |
+#endif | |
+ | |
switch (flash_area) { | |
case UI_FIRMWARE: | |
+ do_rebuild = true; | |
retval = fwu_do_reflash(); | |
- rmi4_data->reset_device(rmi4_data, true); | |
+#ifdef F51_DISCRETE_FORCE | |
+ if (retval < 0) | |
+ break; | |
+ | |
+ if (fwu->has_utility_param || fwu->img.contains_utility_param) | |
+ break; | |
+ | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ | |
+ if (fwu->bl_mode_device || fwu->in_bl_mode) { | |
+ dev_info(rmi4_data->pdev->dev.parent, | |
+ "%s: Device in bootloader mode, skipping calibration data restoration\n", | |
+ __func__); | |
+ break; | |
+ } | |
+ | |
+ retval = fwu_do_restore_f51_cal_data(); | |
+#endif | |
break; | |
case UI_CONFIG: | |
+ do_rebuild = true; | |
retval = fwu_check_ui_configuration_size(); | |
if (retval < 0) | |
break; | |
@@ -3662,15 +4330,25 @@ static int fwu_start_reflash(void) | |
if (retval < 0) | |
break; | |
retval = fwu_write_ui_configuration(); | |
- rmi4_data->reset_device(rmi4_data, true); | |
+#ifdef F51_DISCRETE_FORCE | |
+ if (retval < 0) | |
+ break; | |
+ | |
+ if (fwu->has_utility_param) | |
+ break; | |
+ | |
+ retval = fwu_do_restore_f51_cal_data(); | |
+#endif | |
break; | |
case NONE: | |
default: | |
- rmi4_data->reset_device(rmi4_data, false); | |
break; | |
} | |
if (retval < 0) { | |
+ do_rebuild = false; | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode); | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to do reflash\n", | |
__func__); | |
@@ -3708,6 +4386,9 @@ exit: | |
if (fw_entry) | |
release_firmware(fw_entry); | |
+ if (do_rebuild) | |
+ rmi4_data->reset_device(rmi4_data, true); | |
+ | |
pr_notice("%s: End of reflash process\n", __func__); | |
mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); | |
@@ -3720,14 +4401,14 @@ exit: | |
static int fwu_recovery_check_status(void) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char data_base; | |
unsigned char status; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f35_fd.data_base_addr; | |
+ data_base = fwu->f35_fd.data_base_addr; | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
- base + F35_ERROR_CODE_OFFSET, | |
+ data_base + F35_ERROR_CODE_OFFSET, | |
&status, | |
1); | |
if (retval < 0) { | |
@@ -3749,17 +4430,92 @@ static int fwu_recovery_check_status(void) | |
return 0; | |
} | |
+static int fwu_recovery_erase_completion(void) | |
+{ | |
+ int retval; | |
+ unsigned char data_base; | |
+ unsigned char command; | |
+ unsigned char status; | |
+ unsigned int timeout = F35_ERASE_ALL_WAIT_MS / 20; | |
+ struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
+ data_base = fwu->f35_fd.data_base_addr; | |
+ | |
+ do { | |
+ command = 0x01; | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ fwu->f35_fd.cmd_base_addr, | |
+ &command, | |
+ sizeof(command)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to issue command\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ do { | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ fwu->f35_fd.cmd_base_addr, | |
+ &command, | |
+ sizeof(command)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read command status\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ if ((command & 0x01) == 0x00) | |
+ break; | |
+ | |
+ msleep(20); | |
+ timeout--; | |
+ } while (timeout > 0); | |
+ | |
+ if (timeout == 0) | |
+ goto exit; | |
+ | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ data_base + F35_FLASH_STATUS_OFFSET, | |
+ &status, | |
+ sizeof(status)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read flash status\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ | |
+ if ((status & 0x01) == 0x00) | |
+ break; | |
+ | |
+ msleep(20); | |
+ timeout--; | |
+ } while (timeout > 0); | |
+ | |
+exit: | |
+ if (timeout == 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Timed out waiting for flash erase completion\n", | |
+ __func__); | |
+ return -ETIMEDOUT; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
static int fwu_recovery_erase_all(void) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char ctrl_base; | |
unsigned char command = CMD_F35_ERASE_ALL; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f35_fd.ctrl_base_addr; | |
+ ctrl_base = fwu->f35_fd.ctrl_base_addr; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + F35_CHUNK_COMMAND_OFFSET, | |
+ ctrl_base + F35_CHUNK_COMMAND_OFFSET, | |
&command, | |
sizeof(command)); | |
if (retval < 0) { | |
@@ -3769,7 +4525,13 @@ static int fwu_recovery_erase_all(void) | |
return retval; | |
} | |
- msleep(F35_ERASE_ALL_WAIT_MS); | |
+ if (fwu->f35_fd.cmd_base_addr) { | |
+ retval = fwu_recovery_erase_completion(); | |
+ if (retval < 0) | |
+ return retval; | |
+ } else { | |
+ msleep(F35_ERASE_ALL_WAIT_MS); | |
+ } | |
retval = fwu_recovery_check_status(); | |
if (retval < 0) | |
@@ -3781,7 +4543,7 @@ static int fwu_recovery_erase_all(void) | |
static int fwu_recovery_write_chunk(void) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char ctrl_base; | |
unsigned char chunk_number[] = {0, 0}; | |
unsigned char chunk_spare; | |
unsigned char chunk_size; | |
@@ -3792,10 +4554,10 @@ static int fwu_recovery_write_chunk(void) | |
unsigned char *chunk_ptr = (unsigned char *)fwu->image; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f35_fd.ctrl_base_addr; | |
+ ctrl_base = fwu->f35_fd.ctrl_base_addr; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + F35_CHUNK_NUM_LSB_OFFSET, | |
+ ctrl_base + F35_CHUNK_NUM_LSB_OFFSET, | |
chunk_number, | |
sizeof(chunk_number)); | |
if (retval < 0) { | |
@@ -3824,7 +4586,7 @@ static int fwu_recovery_write_chunk(void) | |
chunk_size); | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + F35_CHUNK_DATA_OFFSET, | |
+ ctrl_base + F35_CHUNK_DATA_OFFSET, | |
buf, | |
sizeof(buf)); | |
if (retval < 0) { | |
@@ -3851,14 +4613,14 @@ static int fwu_recovery_write_chunk(void) | |
static int fwu_recovery_reset(void) | |
{ | |
int retval; | |
- unsigned char base; | |
+ unsigned char ctrl_base; | |
unsigned char command = CMD_F35_RESET; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
- base = fwu->f35_fd.ctrl_base_addr; | |
+ ctrl_base = fwu->f35_fd.ctrl_base_addr; | |
retval = synaptics_rmi4_reg_write(rmi4_data, | |
- base + F35_CHUNK_COMMAND_OFFSET, | |
+ ctrl_base + F35_CHUNK_COMMAND_OFFSET, | |
&command, | |
sizeof(command)); | |
if (retval < 0) { | |
@@ -3876,6 +4638,7 @@ static int fwu_recovery_reset(void) | |
static int fwu_start_recovery(void) | |
{ | |
int retval; | |
+ const struct firmware *fw_entry = NULL; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
if (rmi4_data->sensor_sleep) { | |
@@ -3891,6 +4654,38 @@ static int fwu_start_recovery(void) | |
pr_notice("%s: Start of recovery process\n", __func__); | |
+ if (fwu->image == NULL) { | |
+ retval = secure_memcpy(fwu->image_name, MAX_IMAGE_NAME_LEN, | |
+ FW_IHEX_NAME, sizeof(FW_IHEX_NAME), | |
+ sizeof(FW_IHEX_NAME)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to copy ihex file name\n", | |
+ __func__); | |
+ goto exit; | |
+ } | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Requesting firmware ihex %s\n", | |
+ __func__, fwu->image_name); | |
+ | |
+ retval = request_firmware(&fw_entry, fwu->image_name, | |
+ rmi4_data->pdev->dev.parent); | |
+ if (retval != 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Firmware ihex %s not available\n", | |
+ __func__, fwu->image_name); | |
+ retval = -EINVAL; | |
+ goto exit; | |
+ } | |
+ | |
+ dev_dbg(rmi4_data->pdev->dev.parent, | |
+ "%s: Firmware image size = %d\n", | |
+ __func__, (unsigned int)fw_entry->size); | |
+ | |
+ fwu->image = fw_entry->data; | |
+ fwu->image_size = fw_entry->size; | |
+ } | |
+ | |
retval = rmi4_data->irq_enable(rmi4_data, false, false); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -3934,6 +4729,9 @@ static int fwu_start_recovery(void) | |
retval = 0; | |
exit: | |
+ if (fw_entry) | |
+ release_firmware(fw_entry); | |
+ | |
pr_notice("%s: End of recovery process\n", __func__); | |
mutex_unlock(&rmi4_data->rmi4_exp_init_mutex); | |
@@ -3943,7 +4741,7 @@ exit: | |
return retval; | |
} | |
-int synaptics_fw_updater(const unsigned char *fw_data) | |
+int synaptics_fw_updater_force(const unsigned char *fw_data) | |
{ | |
int retval; | |
@@ -3966,21 +4764,20 @@ int synaptics_fw_updater(const unsigned char *fw_data) | |
return retval; | |
} | |
-EXPORT_SYMBOL(synaptics_fw_updater); | |
+EXPORT_SYMBOL(synaptics_fw_updater_force); | |
#ifdef DO_STARTUP_FW_UPDATE | |
static void fwu_startup_fw_update_work(struct work_struct *work) | |
{ | |
static unsigned char do_once = 1; | |
struct synaptics_rmi4_data *rmi4_data = fwu->rmi4_data; | |
+ | |
#ifdef WAIT_FOR_FB_READY | |
unsigned int timeout; | |
#endif | |
- | |
if (!do_once) | |
return; | |
do_once = 0; | |
- | |
#ifdef WAIT_FOR_FB_READY | |
timeout = FB_READY_TIMEOUT_S * 1000 / FB_READY_WAIT_MS + 1; | |
@@ -3996,9 +4793,10 @@ static void fwu_startup_fw_update_work(struct work_struct *work) | |
} | |
#endif | |
- synaptics_fw_updater(NULL); | |
+ synaptics_fw_updater_force(NULL); | |
- if (rmi4_data->chip_id == CHIP_ID_4322) | |
+ if (rmi4_data->chip_id == rmi4_data->hw_if->board_data->chip_4322 || | |
+ rmi4_data->chip_id == rmi4_data->hw_if->board_data->chip_4722) | |
firmware_force_update(rmi4_data); | |
return; | |
@@ -4064,6 +4862,12 @@ static ssize_t fwu_sysfs_do_recovery_store(struct device *dev, | |
goto exit; | |
} | |
+ retval = fwu_scan_pdt(); | |
+ if (retval < 0) | |
+ goto exit; | |
+ | |
+ pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode); | |
+ | |
if (!fwu->in_ub_mode) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Not in microbootloader mode\n", | |
@@ -4132,7 +4936,7 @@ static ssize_t fwu_sysfs_do_reflash_store(struct device *dev, | |
if (input == FORCE) | |
fwu->force_update = true; | |
- retval = synaptics_fw_updater(fwu->image); | |
+ retval = synaptics_fw_updater_force(fwu->image); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to do reflash\n", | |
@@ -4393,11 +5197,11 @@ static void firmware_force_update(struct synaptics_rmi4_data *rmi4_data) | |
{ | |
int retval; | |
const struct firmware *fw_entry = NULL; | |
- | |
+ const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data; | |
if (!fwu->in_ub_mode) | |
return; | |
- retval = request_firmware(&fw_entry, "synaptics_lgd_incell_backup.fw", | |
+ retval = request_firmware(&fw_entry, bdata->backup_fw_name, | |
rmi4_data->pdev->dev.parent); | |
if (retval != 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -4476,6 +5280,8 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) | |
if (retval < 0) | |
goto exit_free_mem; | |
+ pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode); | |
+ | |
if (!fwu->in_ub_mode) { | |
retval = fwu_read_f34_queries(); | |
if (retval < 0) | |
@@ -4522,6 +5328,15 @@ static int synaptics_rmi4_fwu_init(struct synaptics_rmi4_data *rmi4_data) | |
&fwu->fwu_work); | |
#endif | |
+#ifdef F51_DISCRETE_FORCE | |
+ fwu_read_flash_status(); | |
+ if (!fwu->in_bl_mode) { | |
+ retval = fwu_f51_force_data_init(); | |
+ if (retval < 0) | |
+ goto exit_remove_attrs; | |
+ } | |
+#endif | |
+ | |
return 0; | |
exit_remove_attrs: | |
@@ -4563,13 +5378,16 @@ static void synaptics_rmi4_fwu_remove(struct synaptics_rmi4_data *rmi4_data) | |
sysfs_remove_bin_file(&rmi4_data->input_dev->dev.kobj, &dev_attr_data); | |
+#ifdef F51_DISCRETE_FORCE | |
+ kfree(fwu->cal_data); | |
+#endif | |
kfree(fwu->read_config_buf); | |
kfree(fwu->image_name); | |
kfree(fwu); | |
fwu = NULL; | |
exit: | |
- complete(&fwu_remove_complete); | |
+ complete(&fwu_remove_complete_force); | |
return; | |
} | |
@@ -4587,9 +5405,17 @@ static void synaptics_rmi4_fwu_reset(struct synaptics_rmi4_data *rmi4_data) | |
if (retval < 0) | |
return; | |
+ pr_err("%s: fwu->in_ub_mode = %d\n", __func__, fwu->in_ub_mode); | |
+ | |
if (!fwu->in_ub_mode) | |
fwu_read_f34_queries(); | |
+#ifdef F51_DISCRETE_FORCE | |
+ fwu_read_flash_status(); | |
+ if (!fwu->in_bl_mode) | |
+ fwu_f51_force_data_init(); | |
+#endif | |
+ | |
return; | |
} | |
@@ -4608,16 +5434,16 @@ static struct synaptics_rmi4_exp_fn fwu_module = { | |
static int __init rmi4_fw_update_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&fwu_module, true); | |
+ synaptics_rmi4_new_function_force(&fwu_module, true); | |
return 0; | |
} | |
static void __exit rmi4_fw_update_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&fwu_module, false); | |
+ synaptics_rmi4_new_function_force(&fwu_module, false); | |
- wait_for_completion(&fwu_remove_complete); | |
+ wait_for_completion(&fwu_remove_complete_force); | |
return; | |
} | |
diff --git a/synaptics_dsx_gesture.c b/synaptics_dsx_gesture.c | |
index 8a8f371..f58d843 100644 | |
--- a/synaptics_dsx_gesture.c | |
+++ b/synaptics_dsx_gesture.c | |
@@ -2290,14 +2290,14 @@ static struct synaptics_rmi4_exp_fn gesture_module = { | |
static int __init rmi4_gesture_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&gesture_module, true); | |
+ synaptics_rmi4_new_function_force(&gesture_module, true); | |
return 0; | |
} | |
static void __exit rmi4_gesture_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&gesture_module, false); | |
+ synaptics_rmi4_new_function_force(&gesture_module, false); | |
wait_for_completion(&udg_remove_complete); | |
diff --git a/synaptics_dsx_i2c.c b/synaptics_dsx_i2c.c | |
index 9994dae..dfb738f 100644 | |
--- a/synaptics_dsx_i2c.c | |
+++ b/synaptics_dsx_i2c.c | |
@@ -16,7 +16,22 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
+ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/slab.h> | |
@@ -31,12 +46,9 @@ | |
#define SYN_I2C_RETRY_TIMES 4 | |
-/* | |
-#define I2C_BURST_LIMIT 255 | |
-*/ | |
-/* | |
-#define XFER_MSGS_LIMIT 8 | |
-*/ | |
+#define I2C_BURST_LIMIT 2048 | |
+ | |
+#define MAX_WRITE_SIZE 4096 | |
static unsigned char *wr_buf; | |
@@ -174,6 +186,10 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
bdata->cut_off_power = of_property_read_bool(np, "synaptics,cut-off-power"); | |
+ bdata->captouch_use = of_property_read_bool(np, "synaptics,captouch-use"); | |
+ | |
+ bdata->power_ctrl = of_property_read_bool(np, "synaptics,power-ctrl"); | |
+ | |
bdata->power_gpio = of_get_named_gpio_flags(np, | |
"synaptics,power-gpio", 0, NULL); | |
if (bdata->power_gpio >= 0) { | |
@@ -227,7 +243,7 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
retval = of_property_read_u32(np, "synaptics,reset-delay-ms", | |
&value); | |
if (retval < 0) | |
- bdata->reset_delay_ms = 200; /* No reset delay by default */ | |
+ bdata->reset_delay_ms = 0; /* No reset delay by default */ | |
else | |
bdata->reset_delay_ms = value; | |
@@ -251,6 +267,42 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
else | |
bdata->ub_i2c_addr = (unsigned short)value; | |
+ retval = of_property_read_string(np, "synaptics,backup-fw", &name); | |
+ if (retval == -EINVAL) | |
+ bdata->backup_fw_name = NULL; | |
+ else if (retval < 0) | |
+ return retval; | |
+ else | |
+ bdata->backup_fw_name = name; | |
+ | |
+ retval = of_property_read_u32(np, "synaptics,chip-3330", | |
+ &value); | |
+ if (retval < 0) | |
+ bdata->chip_3330 = 0; | |
+ else | |
+ bdata->chip_3330 = value; | |
+ | |
+ retval = of_property_read_u32(np, "synaptics,chip-3331", | |
+ &value); | |
+ if (retval < 0) | |
+ bdata->chip_3331 = 1; | |
+ else | |
+ bdata->chip_3331 = value; | |
+ | |
+ retval = of_property_read_u32(np, "synaptics,chip-4322", | |
+ &value); | |
+ if (retval < 0) | |
+ bdata->chip_4322 = 2; | |
+ else | |
+ bdata->chip_4322 = value; | |
+ | |
+ retval = of_property_read_u32(np, "synaptics,chip-4722", | |
+ &value); | |
+ if (retval < 0) | |
+ bdata->chip_4722 = 3; | |
+ else | |
+ bdata->chip_4722 = value; | |
+ | |
prop = of_find_property(np, "synaptics,cap-button-codes", NULL); | |
if (prop && prop->length) { | |
bdata->cap_button_map->map = devm_kzalloc(dev, | |
@@ -351,6 +403,13 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
config_info = bdata->config_array; | |
for_each_child_of_node(np, temp) { | |
+ retval = of_property_read_u32(temp, "synaptics,chip-id", | |
+ &value); | |
+ if (retval < 0) | |
+ config_info->chip_id = -1; | |
+ else | |
+ config_info->chip_id = value; | |
+ | |
prop = of_find_property(temp, "synaptics,tp-id", NULL); | |
if (prop && prop->length) { | |
if (bdata->tp_id_num != prop->length / sizeof(u8)) { | |
@@ -479,21 +538,15 @@ static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, | |
int retval; | |
unsigned char retry; | |
unsigned char buf; | |
-#ifdef I2C_BURST_LIMIT | |
- unsigned char ii; | |
- unsigned char rd_msgs = ((length - 1) / I2C_BURST_LIMIT) + 1; | |
-#else | |
- unsigned char rd_msgs = 1; | |
-#endif | |
- unsigned char index = 0; | |
- unsigned char xfer_msgs; | |
- unsigned char remaining_msgs; | |
unsigned short i2c_addr; | |
unsigned short data_offset = 0; | |
- unsigned short remaining_length = length; | |
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); | |
struct i2c_adapter *adap = i2c->adapter; | |
- struct i2c_msg msg[rd_msgs + 1]; | |
+ struct i2c_msg msg[2]; | |
+ unsigned short index = 0; | |
+ unsigned short read_size; | |
+ unsigned short max_read_size; | |
+ unsigned short left_bytes = length; | |
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); | |
@@ -508,39 +561,36 @@ static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, | |
msg[0].len = 1; | |
msg[0].buf = &buf; | |
+ msg[1].addr = hw_if.board_data->i2c_addr; | |
+ msg[1].flags = I2C_M_RD; | |
+ | |
#ifdef I2C_BURST_LIMIT | |
- for (ii = 0; ii < (rd_msgs - 1); ii++) { | |
- msg[ii + 1].addr = hw_if.board_data->i2c_addr; | |
- msg[ii + 1].flags = I2C_M_RD; | |
- msg[ii + 1].len = I2C_BURST_LIMIT; | |
- msg[ii + 1].buf = &data[data_offset]; | |
- data_offset += I2C_BURST_LIMIT; | |
- remaining_length -= I2C_BURST_LIMIT; | |
- } | |
+ max_read_size = I2C_BURST_LIMIT; | |
+#else | |
+ max_read_size = length; | |
#endif | |
- msg[rd_msgs].addr = hw_if.board_data->i2c_addr; | |
- msg[rd_msgs].flags = I2C_M_RD; | |
- msg[rd_msgs].len = remaining_length; | |
- msg[rd_msgs].buf = &data[data_offset]; | |
+ do { | |
+ if (left_bytes / max_read_size) | |
+ read_size = max_read_size; | |
+ else | |
+ read_size = left_bytes; | |
- buf = addr & MASK_8BIT; | |
+ msg[1].len = read_size; | |
+ msg[1].buf = &data[data_offset + index]; | |
- remaining_msgs = rd_msgs + 1; | |
+ buf = addr & MASK_8BIT; | |
- while (remaining_msgs) { | |
-#ifdef XFER_MSGS_LIMIT | |
- if (remaining_msgs > XFER_MSGS_LIMIT) | |
- xfer_msgs = XFER_MSGS_LIMIT; | |
- else | |
- xfer_msgs = remaining_msgs; | |
-#else | |
- xfer_msgs = remaining_msgs; | |
-#endif | |
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { | |
- retval = i2c_transfer(adap, &msg[index], xfer_msgs); | |
- if (retval == xfer_msgs) | |
- break; | |
+ if (left_bytes == length) { | |
+ retval = i2c_transfer(adap, &msg[0], 2); | |
+ if (retval == 2) | |
+ break; | |
+ } else { | |
+ retval = i2c_transfer(adap, &msg[1], 1); | |
+ if (retval == 1) | |
+ break; | |
+ } | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: I2C retry %d\n", | |
@@ -551,11 +601,7 @@ static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, | |
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c); | |
i2c_addr = hw_if.board_data->i2c_addr; | |
msg[0].addr = i2c_addr; | |
-#ifdef I2C_BURST_LIMIT | |
- for (ii = 0; ii < (rd_msgs - 1); ii++) | |
- msg[ii + 1].addr = i2c_addr; | |
-#endif | |
- msg[rd_msgs].addr = i2c_addr; | |
+ msg[1].addr = i2c_addr; | |
} | |
} | |
@@ -567,9 +613,9 @@ static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
- remaining_msgs -= xfer_msgs; | |
- index += xfer_msgs; | |
- } | |
+ index += read_size; | |
+ left_bytes -= read_size; | |
+ } while (left_bytes); | |
retval = length; | |
@@ -586,8 +632,18 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, | |
unsigned char retry; | |
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent); | |
struct i2c_msg msg[1]; | |
+ unsigned short index = 0; | |
+ unsigned short write_size; | |
+ unsigned short max_write_size; | |
+ unsigned short left_bytes = length; | |
- retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1); | |
+#ifdef MAX_WRITE_SIZE | |
+ max_write_size = MAX_WRITE_SIZE; | |
+#else | |
+ max_write_size = length; | |
+#endif | |
+ | |
+ retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, max_write_size + 1); | |
if (retval < 0) | |
return retval; | |
@@ -599,42 +655,52 @@ static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data, | |
goto exit; | |
} | |
- msg[0].addr = hw_if.board_data->i2c_addr; | |
- msg[0].flags = 0; | |
- msg[0].len = length + 1; | |
- msg[0].buf = wr_buf; | |
+ do { | |
+ if (left_bytes / max_write_size) | |
+ write_size = max_write_size; | |
+ else | |
+ write_size = left_bytes; | |
- wr_buf[0] = addr & MASK_8BIT; | |
- retval = secure_memcpy(&wr_buf[1], length, &data[0], length, length); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to copy data\n", | |
- __func__); | |
- goto exit; | |
- } | |
+ msg[0].addr = hw_if.board_data->i2c_addr; | |
+ msg[0].flags = 0; | |
+ msg[0].len = write_size + 1; | |
+ msg[0].buf = wr_buf; | |
+ | |
+ wr_buf[0] = addr & MASK_8BIT; | |
+ retval = secure_memcpy(&wr_buf[1], write_size, &data[index], write_size, write_size); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to copy data\n", | |
+ __func__); | |
+ goto exit; | |
+ } | |
+ | |
+ for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { | |
+ if (i2c_transfer(i2c->adapter, msg, 1) == 1) { | |
+ retval = length; | |
+ break; | |
+ } | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: I2C retry %d\n", | |
+ __func__, retry + 1); | |
+ msleep(20); | |
- for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { | |
- if (i2c_transfer(i2c->adapter, msg, 1) == 1) { | |
- retval = length; | |
- break; | |
+ if (retry == SYN_I2C_RETRY_TIMES / 2) { | |
+ synaptics_rmi4_i2c_check_addr(rmi4_data, i2c); | |
+ msg[0].addr = hw_if.board_data->i2c_addr; | |
+ } | |
} | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: I2C retry %d\n", | |
- __func__, retry + 1); | |
- msleep(20); | |
- | |
- if (retry == SYN_I2C_RETRY_TIMES / 2) { | |
- synaptics_rmi4_i2c_check_addr(rmi4_data, i2c); | |
- msg[0].addr = hw_if.board_data->i2c_addr; | |
+ | |
+ if (retry == SYN_I2C_RETRY_TIMES) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: I2C write over retry limit\n", | |
+ __func__); | |
+ retval = -EIO; | |
} | |
- } | |
- if (retry == SYN_I2C_RETRY_TIMES) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: I2C write over retry limit\n", | |
- __func__); | |
- retval = -EIO; | |
- } | |
+ index += write_size; | |
+ left_bytes -= write_size; | |
+ } while (left_bytes); | |
exit: | |
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
@@ -716,7 +782,7 @@ static int synaptics_rmi4_i2c_probe(struct i2c_client *client, | |
hw_if.bus_access = &bus_access; | |
hw_if.board_data->i2c_addr = client->addr; | |
- synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME; | |
+ synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_FORCE; | |
synaptics_dsx_i2c_device->id = 0; | |
synaptics_dsx_i2c_device->num_resources = 0; | |
synaptics_dsx_i2c_device->dev.parent = &client->dev; | |
@@ -742,41 +808,40 @@ static int synaptics_rmi4_i2c_remove(struct i2c_client *client) | |
} | |
static const struct i2c_device_id synaptics_rmi4_id_table[] = { | |
- {I2C_DRIVER_NAME, 0}, | |
+ {I2C_DRIVER_FORCE, 0}, | |
{}, | |
}; | |
MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table); | |
#ifdef CONFIG_OF | |
-static struct of_device_id synaptics_rmi4_of_match_table[] = { | |
+static struct of_device_id synaptics_rmi4_of_match_table_force[] = { | |
{ | |
- .compatible = "synaptics,dsx-i2c", | |
+ .compatible = "synaptics,dsx-i2c-force", | |
}, | |
{}, | |
}; | |
-MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table); | |
+MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table_force); | |
#else | |
#define synaptics_rmi4_of_match_table NULL | |
#endif | |
static struct i2c_driver synaptics_rmi4_i2c_driver = { | |
.driver = { | |
- .name = I2C_DRIVER_NAME, | |
+ .name = "synaptics_dsi_force", | |
.owner = THIS_MODULE, | |
- .of_match_table = synaptics_rmi4_of_match_table, | |
+ .of_match_table = synaptics_rmi4_of_match_table_force, | |
}, | |
.probe = synaptics_rmi4_i2c_probe, | |
.remove = synaptics_rmi4_i2c_remove, | |
.id_table = synaptics_rmi4_id_table, | |
}; | |
-int synaptics_rmi4_bus_init(void) | |
+int synaptics_rmi4_bus_init_force(void) | |
{ | |
return i2c_add_driver(&synaptics_rmi4_i2c_driver); | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_bus_init); | |
-void synaptics_rmi4_bus_exit(void) | |
+void synaptics_rmi4_bus_exit_force(void) | |
{ | |
kfree(wr_buf); | |
@@ -784,7 +849,6 @@ void synaptics_rmi4_bus_exit(void) | |
return; | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_bus_exit); | |
MODULE_AUTHOR("Synaptics, Inc."); | |
MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module"); | |
diff --git a/synaptics_dsx_proximity.c b/synaptics_dsx_proximity.c | |
index 6dcc4d2..a4c92ce 100644 | |
--- a/synaptics_dsx_proximity.c | |
+++ b/synaptics_dsx_proximity.c | |
@@ -16,7 +16,22 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
+ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/slab.h> | |
@@ -656,14 +671,14 @@ static struct synaptics_rmi4_exp_fn proximity_module = { | |
static int __init rmi4_proximity_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&proximity_module, true); | |
+ synaptics_rmi4_new_function_force(&proximity_module, true); | |
return 0; | |
} | |
static void __exit rmi4_proximity_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&proximity_module, false); | |
+ synaptics_rmi4_new_function_force(&proximity_module, false); | |
wait_for_completion(&prox_remove_complete); | |
diff --git a/synaptics_dsx_rmi_dev.c b/synaptics_dsx_rmi_dev.c | |
index 3ba6d46..2d888b8 100644 | |
--- a/synaptics_dsx_rmi_dev.c | |
+++ b/synaptics_dsx_rmi_dev.c | |
@@ -16,7 +16,22 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
+ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/slab.h> | |
@@ -70,6 +85,12 @@ static ssize_t rmidev_sysfs_intr_mask_show(struct device *dev, | |
static ssize_t rmidev_sysfs_intr_mask_store(struct device *dev, | |
struct device_attribute *attr, const char *buf, size_t count); | |
+static ssize_t rmidev_sysfs_concurrent_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf); | |
+ | |
+static ssize_t rmidev_sysfs_concurrent_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count); | |
+ | |
struct rmidev_handle { | |
dev_t dev_no; | |
pid_t pid; | |
@@ -83,7 +104,7 @@ struct rmidev_handle { | |
struct siginfo terminate_signal; | |
struct task_struct *task; | |
void *data; | |
- bool irq_enabled; | |
+ bool concurrent; | |
}; | |
struct rmidev_data { | |
@@ -123,6 +144,9 @@ static struct device_attribute attrs[] = { | |
__ATTR(intr_mask, S_IRUGO | S_IWUSR, | |
rmidev_sysfs_intr_mask_show, | |
rmidev_sysfs_intr_mask_store), | |
+ __ATTR(concurrent, S_IRUGO | S_IWUSR, | |
+ rmidev_sysfs_concurrent_show, | |
+ rmidev_sysfs_concurrent_store), | |
}; | |
static int rmidev_major_num; | |
@@ -131,7 +155,7 @@ static struct class *rmidev_device_class; | |
static struct rmidev_handle *rmidev; | |
-DECLARE_COMPLETION(rmidev_remove_complete); | |
+DECLARE_COMPLETION(rmidev_remove_complete_force); | |
static irqreturn_t rmidev_sysfs_irq(int irq, void *data) | |
{ | |
@@ -151,9 +175,15 @@ static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data, | |
unsigned long irq_flags = IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | | |
IRQF_ONESHOT; | |
+ mutex_lock(&(rmi4_data->rmi4_irq_enable_mutex)); | |
+ | |
if (enable) { | |
- if (rmidev->irq_enabled) | |
- return retval; | |
+ if (rmi4_data->irq_enabled) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Interrupt already enabled\n", | |
+ __func__); | |
+ goto exit; | |
+ } | |
/* Clear interrupts first */ | |
retval = synaptics_rmi4_reg_read(rmi4_data, | |
@@ -161,7 +191,7 @@ static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data, | |
intr_status, | |
rmi4_data->num_of_intr_regs); | |
if (retval < 0) | |
- return retval; | |
+ goto exit; | |
retval = request_threaded_irq(rmi4_data->irq, NULL, | |
rmidev_sysfs_irq, irq_flags, | |
@@ -170,18 +200,21 @@ static int rmidev_sysfs_irq_enable(struct synaptics_rmi4_data *rmi4_data, | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to create irq thread\n", | |
__func__); | |
- return retval; | |
+ goto exit; | |
} | |
- rmidev->irq_enabled = true; | |
+ rmi4_data->irq_enabled = true; | |
} else { | |
- if (rmidev->irq_enabled) { | |
+ if (rmi4_data->irq_enabled) { | |
disable_irq(rmi4_data->irq); | |
free_irq(rmi4_data->irq, rmi4_data); | |
- rmidev->irq_enabled = false; | |
+ rmi4_data->irq_enabled = false; | |
} | |
} | |
+exit: | |
+ mutex_unlock(&(rmi4_data->rmi4_irq_enable_mutex)); | |
+ | |
return retval; | |
} | |
@@ -190,10 +223,15 @@ static ssize_t rmidev_sysfs_data_show(struct file *data_file, | |
char *buf, loff_t pos, size_t count) | |
{ | |
int retval; | |
+ unsigned char intr_status = 0; | |
unsigned int length = (unsigned int)count; | |
unsigned short address = (unsigned short)pos; | |
+ struct synaptics_rmi4_fn *fhandler; | |
+ struct synaptics_rmi4_device_info *rmi; | |
struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; | |
+ rmi = &(rmi4_data->rmi4_mod_info); | |
+ | |
if (length > (REG_ADDR_LIMIT - address)) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Out of register map limit\n", | |
@@ -216,6 +254,29 @@ static ssize_t rmidev_sysfs_data_show(struct file *data_file, | |
return -EINVAL; | |
} | |
+ if (!rmidev->concurrent) | |
+ goto exit; | |
+ | |
+ if (address != rmi4_data->f01_data_base_addr) | |
+ goto exit; | |
+ | |
+ if (length <= 1) | |
+ goto exit; | |
+ | |
+ intr_status = buf[1]; | |
+ | |
+ if (!list_empty(&rmi->support_fn_list)) { | |
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) { | |
+ if (fhandler->num_of_data_sources) { | |
+ if (fhandler->intr_mask & intr_status) { | |
+ rmi4_data->report_touch(rmi4_data, | |
+ fhandler); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
+exit: | |
return length; | |
} | |
@@ -297,11 +358,6 @@ static ssize_t rmidev_sysfs_release_store(struct device *dev, | |
return -EINVAL; | |
rmidev_sysfs_irq_enable(rmi4_data, false); | |
- rmi4_data->irq_enable(rmi4_data, true, false); | |
- | |
- dev_dbg(rmi4_data->pdev->dev.parent, | |
- "%s: Attention interrupt enabled\n", | |
- __func__); | |
rmi4_data->reset_device(rmi4_data, false); | |
@@ -389,6 +445,25 @@ static ssize_t rmidev_sysfs_intr_mask_store(struct device *dev, | |
return count; | |
} | |
+static ssize_t rmidev_sysfs_concurrent_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf) | |
+{ | |
+ return snprintf(buf, PAGE_SIZE, "%d\n", rmidev->concurrent); | |
+} | |
+ | |
+static ssize_t rmidev_sysfs_concurrent_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count) | |
+{ | |
+ unsigned int input; | |
+ | |
+ if (sscanf(buf, "%u", &input) != 1) | |
+ return -EINVAL; | |
+ | |
+ rmidev->concurrent = input > 0 ? true : false; | |
+ | |
+ return count; | |
+} | |
+ | |
static int rmidev_allocate_buffer(int count) | |
{ | |
if (count + 1 > rmidev->tmpbuf_size) { | |
@@ -477,7 +552,14 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, | |
size_t count, loff_t *f_pos) | |
{ | |
ssize_t retval; | |
+ unsigned char intr_status = 0; | |
+ unsigned short address; | |
struct rmidev_data *dev_data = filp->private_data; | |
+ struct synaptics_rmi4_fn *fhandler; | |
+ struct synaptics_rmi4_device_info *rmi; | |
+ struct synaptics_rmi4_data *rmi4_data = rmidev->rmi4_data; | |
+ | |
+ rmi = &(rmi4_data->rmi4_mod_info); | |
if (IS_ERR(dev_data)) { | |
pr_err("%s: Pointer of char device data is invalid", __func__); | |
@@ -490,10 +572,12 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, | |
if (count > (REG_ADDR_LIMIT - *f_pos)) | |
count = REG_ADDR_LIMIT - *f_pos; | |
- rmidev_allocate_buffer(count); | |
+ address = (unsigned short)(*f_pos); | |
mutex_lock(&(dev_data->file_mutex)); | |
+ rmidev_allocate_buffer(count); | |
+ | |
retval = synaptics_rmi4_reg_read(rmidev->rmi4_data, | |
*f_pos, | |
rmidev->tmpbuf, | |
@@ -506,6 +590,28 @@ static ssize_t rmidev_read(struct file *filp, char __user *buf, | |
else | |
*f_pos += retval; | |
+ if (!rmidev->concurrent) | |
+ goto clean_up; | |
+ | |
+ if (address != rmi4_data->f01_data_base_addr) | |
+ goto clean_up; | |
+ | |
+ if (count <= 1) | |
+ goto clean_up; | |
+ | |
+ intr_status = rmidev->tmpbuf[1]; | |
+ | |
+ if (!list_empty(&rmi->support_fn_list)) { | |
+ list_for_each_entry(fhandler, &rmi->support_fn_list, link) { | |
+ if (fhandler->num_of_data_sources) { | |
+ if (fhandler->intr_mask & intr_status) { | |
+ rmi4_data->report_touch(rmi4_data, | |
+ fhandler); | |
+ } | |
+ } | |
+ } | |
+ } | |
+ | |
clean_up: | |
mutex_unlock(&(dev_data->file_mutex)); | |
@@ -537,12 +643,14 @@ static ssize_t rmidev_write(struct file *filp, const char __user *buf, | |
if (count > (REG_ADDR_LIMIT - *f_pos)) | |
count = REG_ADDR_LIMIT - *f_pos; | |
+ mutex_lock(&(dev_data->file_mutex)); | |
+ | |
rmidev_allocate_buffer(count); | |
- if (copy_from_user(rmidev->tmpbuf, buf, count)) | |
+ if (copy_from_user(rmidev->tmpbuf, buf, count)) { | |
+ mutex_unlock(&(dev_data->file_mutex)); | |
return -EFAULT; | |
- | |
- mutex_lock(&(dev_data->file_mutex)); | |
+ } | |
retval = synaptics_rmi4_reg_write(rmidev->rmi4_data, | |
*f_pos, | |
@@ -609,17 +717,13 @@ static int rmidev_release(struct inode *inp, struct file *filp) | |
if (dev_data->ref_count < 0) | |
dev_data->ref_count = 0; | |
- rmi4_data->irq_enable(rmi4_data, true, false); | |
- dev_dbg(rmi4_data->pdev->dev.parent, | |
- "%s: Attention interrupt enabled\n", | |
- __func__); | |
- | |
- mutex_unlock(&(dev_data->file_mutex)); | |
- rmi4_data->reset_device(rmi4_data, false); | |
+ rmi4_data->irq_enable(rmi4_data, true, false); | |
rmi4_data->stay_awake = false; | |
+ mutex_unlock(&(dev_data->file_mutex)); | |
+ | |
return 0; | |
} | |
@@ -914,7 +1018,7 @@ static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data) | |
rmidev = NULL; | |
exit: | |
- complete(&rmidev_remove_complete); | |
+ complete(&rmidev_remove_complete_force); | |
return; | |
} | |
@@ -934,16 +1038,16 @@ static struct synaptics_rmi4_exp_fn rmidev_module = { | |
static int __init rmidev_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&rmidev_module, true); | |
+ synaptics_rmi4_new_function_force(&rmidev_module, true); | |
return 0; | |
} | |
static void __exit rmidev_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&rmidev_module, false); | |
+ synaptics_rmi4_new_function_force(&rmidev_module, false); | |
- wait_for_completion(&rmidev_remove_complete); | |
+ wait_for_completion(&rmidev_remove_complete_force); | |
return; | |
} | |
diff --git a/synaptics_dsx_rmi_hid_i2c.c b/synaptics_dsx_rmi_hid_i2c.c | |
index 568fe35..cb17318 100644 | |
--- a/synaptics_dsx_rmi_hid_i2c.c | |
+++ b/synaptics_dsx_rmi_hid_i2c.c | |
@@ -130,7 +130,8 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
struct device_node *np = dev->of_node; | |
bdata->irq_gpio = of_get_named_gpio_flags(np, | |
- "synaptics,irq-gpio", 0, NULL); | |
+ "synaptics,irq-gpio", 0, | |
+ (enum of_gpio_flags *)&bdata->irq_flags); | |
retval = of_property_read_u32(np, "synaptics,irq-on-state", | |
&value); | |
@@ -139,117 +140,141 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
else | |
bdata->irq_on_state = value; | |
- retval = of_property_read_u32(np, "synaptics,irq-flags", &value); | |
- if (retval < 0) | |
- return retval; | |
- else | |
- bdata->irq_flags = value; | |
- | |
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); | |
- if (retval == -EINVAL) | |
+ if (retval < 0) | |
bdata->pwr_reg_name = NULL; | |
- else if (retval < 0) | |
- return retval; | |
else | |
bdata->pwr_reg_name = name; | |
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name); | |
- if (retval == -EINVAL) | |
+ if (retval < 0) | |
bdata->bus_reg_name = NULL; | |
- else if (retval < 0) | |
- return retval; | |
else | |
bdata->bus_reg_name = name; | |
- if (of_property_read_bool(np, "synaptics,power-gpio")) { | |
+ prop = of_find_property(np, "synaptics,power-gpio", NULL); | |
+ if (prop && prop->length) { | |
bdata->power_gpio = of_get_named_gpio_flags(np, | |
"synaptics,power-gpio", 0, NULL); | |
retval = of_property_read_u32(np, "synaptics,power-on-state", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->power_on_state = value; | |
+ } | |
} else { | |
bdata->power_gpio = -1; | |
} | |
- if (of_property_read_bool(np, "synaptics,power-delay-ms")) { | |
+ prop = of_find_property(np, "synaptics,power-delay-ms", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,power-delay-ms", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->power_delay_ms = value; | |
+ } | |
} else { | |
bdata->power_delay_ms = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,reset-gpio")) { | |
+ prop = of_find_property(np, "synaptics,reset-gpio", NULL); | |
+ if (prop && prop->length) { | |
bdata->reset_gpio = of_get_named_gpio_flags(np, | |
"synaptics,reset-gpio", 0, NULL); | |
retval = of_property_read_u32(np, "synaptics,reset-on-state", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->reset_on_state = value; | |
+ } | |
retval = of_property_read_u32(np, "synaptics,reset-active-ms", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->reset_active_ms = value; | |
+ } | |
} else { | |
bdata->reset_gpio = -1; | |
} | |
- if (of_property_read_bool(np, "synaptics,reset-delay-ms")) { | |
+ prop = of_find_property(np, "synaptics,reset-delay-ms", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,reset-delay-ms", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->reset_delay_ms = value; | |
+ } | |
} else { | |
bdata->reset_delay_ms = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,dev-dscrptr-addr")) { | |
+ prop = of_find_property(np, "synaptics,dev-dscrptr-addr", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,dev-dscrptr-addr", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,dev-dscrptr-addr property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->device_descriptor_addr = (unsigned short)value; | |
+ } | |
} else { | |
bdata->device_descriptor_addr = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,max-y-for-2d")) { | |
+ prop = of_find_property(np, "synaptics,max-y-for-2d", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,max-y-for-2d", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->max_y_for_2d = value; | |
+ } | |
} else { | |
bdata->max_y_for_2d = -1; | |
} | |
- bdata->swap_axes = of_property_read_bool(np, "synaptics,swap-axes"); | |
+ prop = of_find_property(np, "synaptics,swap-axes", NULL); | |
+ bdata->swap_axes = prop > 0 ? true : false; | |
- bdata->x_flip = of_property_read_bool(np, "synaptics,x-flip"); | |
+ prop = of_find_property(np, "synaptics,x-flip", NULL); | |
+ bdata->x_flip = prop > 0 ? true : false; | |
- bdata->y_flip = of_property_read_bool(np, "synaptics,y-flip"); | |
+ prop = of_find_property(np, "synaptics,y-flip", NULL); | |
+ bdata->y_flip = prop > 0 ? true : false; | |
- if (of_property_read_bool(np, "synaptics,ub-i2c-addr")) { | |
+ prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,ub-i2c-addr", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->ub_i2c_addr = (unsigned short)value; | |
+ } | |
} else { | |
bdata->ub_i2c_addr = -1; | |
} | |
@@ -963,19 +988,17 @@ static struct i2c_driver synaptics_rmi4_i2c_driver = { | |
.id_table = synaptics_rmi4_id_table, | |
}; | |
-int synaptics_rmi4_bus_init(void) | |
+int synaptics_rmi4_bus_init_force(void) | |
{ | |
return i2c_add_driver(&synaptics_rmi4_i2c_driver); | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_bus_init); | |
-void synaptics_rmi4_bus_exit(void) | |
+void synaptics_rmi4_bus_exit_force(void) | |
{ | |
i2c_del_driver(&synaptics_rmi4_i2c_driver); | |
return; | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_bus_exit); | |
MODULE_AUTHOR("Synaptics, Inc."); | |
MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module"); | |
diff --git a/synaptics_dsx_spi.c b/synaptics_dsx_spi.c | |
index 7e86cf8..2acd05d 100644 | |
--- a/synaptics_dsx_spi.c | |
+++ b/synaptics_dsx_spi.c | |
@@ -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) 2016 XiaoMi, Inc. | |
* | |
* 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 | |
@@ -15,7 +16,22 @@ | |
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
* GNU General Public License for more details. | |
+ * | |
+ * INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS | |
+ * EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, | |
+ * AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS. | |
+ * IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
+ * SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION | |
+ * WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED | |
+ * AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF | |
+ * THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES | |
+ * NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' | |
+ * TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. | |
+ * DOLLARS. | |
*/ | |
+ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/slab.h> | |
@@ -31,6 +47,10 @@ | |
#define SPI_READ 0x80 | |
#define SPI_WRITE 0x00 | |
+static unsigned char *buf; | |
+ | |
+static struct spi_transfer *xfer; | |
+ | |
#ifdef CONFIG_OF | |
static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
{ | |
@@ -41,7 +61,8 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
struct device_node *np = dev->of_node; | |
bdata->irq_gpio = of_get_named_gpio_flags(np, | |
- "synaptics,irq-gpio", 0, NULL); | |
+ "synaptics,irq-gpio", 0, | |
+ (enum of_gpio_flags *)&bdata->irq_flags); | |
retval = of_property_read_u32(np, "synaptics,irq-on-state", | |
&value); | |
@@ -50,120 +71,174 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
else | |
bdata->irq_on_state = value; | |
- retval = of_property_read_u32(np, "synaptics,irq-flags", &value); | |
- if (retval < 0) | |
- return retval; | |
- else | |
- bdata->irq_flags = value; | |
- | |
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name); | |
- if (retval == -EINVAL) | |
+ if (retval < 0) | |
bdata->pwr_reg_name = NULL; | |
- else if (retval < 0) | |
- return retval; | |
else | |
bdata->pwr_reg_name = name; | |
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name); | |
- if (retval == -EINVAL) | |
+ if (retval < 0) | |
bdata->bus_reg_name = NULL; | |
- else if (retval < 0) | |
- return retval; | |
else | |
bdata->bus_reg_name = name; | |
- if (of_property_read_bool(np, "synaptics,power-gpio")) { | |
+ prop = of_find_property(np, "synaptics,power-gpio", NULL); | |
+ if (prop && prop->length) { | |
bdata->power_gpio = of_get_named_gpio_flags(np, | |
"synaptics,power-gpio", 0, NULL); | |
retval = of_property_read_u32(np, "synaptics,power-on-state", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->power_on_state = value; | |
+ } | |
} else { | |
bdata->power_gpio = -1; | |
} | |
- if (of_property_read_bool(np, "synaptics,power-delay-ms")) { | |
+ prop = of_find_property(np, "synaptics,power-delay-ms", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,power-delay-ms", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->power_delay_ms = value; | |
+ } | |
} else { | |
bdata->power_delay_ms = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,reset-gpio")) { | |
+ prop = of_find_property(np, "synaptics,reset-gpio", NULL); | |
+ if (prop && prop->length) { | |
bdata->reset_gpio = of_get_named_gpio_flags(np, | |
"synaptics,reset-gpio", 0, NULL); | |
retval = of_property_read_u32(np, "synaptics,reset-on-state", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->reset_on_state = value; | |
+ } | |
retval = of_property_read_u32(np, "synaptics,reset-active-ms", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->reset_active_ms = value; | |
+ } | |
} else { | |
bdata->reset_gpio = -1; | |
} | |
- if (of_property_read_bool(np, "synaptics,reset-delay-ms")) { | |
+ prop = of_find_property(np, "synaptics,reset-delay-ms", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,reset-delay-ms", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->reset_delay_ms = value; | |
+ } | |
} else { | |
bdata->reset_delay_ms = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,byte-delay-us")) { | |
+ prop = of_find_property(np, "synaptics,byte-delay-us", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,byte-delay-us", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,byte-delay-us property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->byte_delay_us = value; | |
+ } | |
} else { | |
bdata->byte_delay_us = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,block-delay-us")) { | |
+ prop = of_find_property(np, "synaptics,block-delay-us", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,block-delay-us", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,block-delay-us property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->block_delay_us = value; | |
+ } | |
} else { | |
bdata->block_delay_us = 0; | |
} | |
- if (of_property_read_bool(np, "synaptics,max-y-for-2d")) { | |
+ prop = of_find_property(np, "synaptics,address-delay-us", NULL); | |
+ if (prop && prop->length) { | |
+ retval = of_property_read_u32(np, "synaptics,address-delay-us", | |
+ &value); | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,address-delay-us property\n", | |
+ __func__); | |
+ return retval; | |
+ } else { | |
+ bdata->addr_delay_us = value; | |
+ } | |
+ } else { | |
+ bdata->addr_delay_us = 0; | |
+ } | |
+ | |
+ prop = of_find_property(np, "synaptics,max-y-for-2d", NULL); | |
+ if (prop && prop->length) { | |
retval = of_property_read_u32(np, "synaptics,max-y-for-2d", | |
&value); | |
- if (retval < 0) | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n", | |
+ __func__); | |
return retval; | |
- else | |
+ } else { | |
bdata->max_y_for_2d = value; | |
+ } | |
} else { | |
bdata->max_y_for_2d = -1; | |
} | |
- bdata->swap_axes = of_property_read_bool(np, "synaptics,swap-axes"); | |
+ prop = of_find_property(np, "synaptics,swap-axes", NULL); | |
+ bdata->swap_axes = prop > 0 ? true : false; | |
- bdata->x_flip = of_property_read_bool(np, "synaptics,x-flip"); | |
+ prop = of_find_property(np, "synaptics,x-flip", NULL); | |
+ bdata->x_flip = prop > 0 ? true : false; | |
- bdata->y_flip = of_property_read_bool(np, "synaptics,y-flip"); | |
+ prop = of_find_property(np, "synaptics,y-flip", NULL); | |
+ bdata->y_flip = prop > 0 ? true : false; | |
+ | |
+ prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL); | |
+ if (prop && prop->length) { | |
+ retval = of_property_read_u32(np, "synaptics,ub-i2c-addr", | |
+ &value); | |
+ if (retval < 0) { | |
+ dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n", | |
+ __func__); | |
+ return retval; | |
+ } else { | |
+ bdata->ub_i2c_addr = (unsigned short)value; | |
+ } | |
+ } else { | |
+ bdata->ub_i2c_addr = -1; | |
+ } | |
prop = of_find_property(np, "synaptics,cap-button-codes", NULL); | |
if (prop && prop->length) { | |
@@ -212,50 +287,100 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata) | |
} | |
#endif | |
+static int synaptics_rmi4_spi_alloc_buf(struct synaptics_rmi4_data *rmi4_data, | |
+ unsigned int size, unsigned int count) | |
+{ | |
+ static unsigned int buf_size; | |
+ static unsigned int xfer_count; | |
+ | |
+ if (size > buf_size) { | |
+ if (buf_size) | |
+ kfree(buf); | |
+ buf = kmalloc(size, GFP_KERNEL); | |
+ if (!buf) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for buf\n", | |
+ __func__); | |
+ buf_size = 0; | |
+ return -ENOMEM; | |
+ } | |
+ buf_size = size; | |
+ } | |
+ | |
+ if (count > xfer_count) { | |
+ if (xfer_count) | |
+ kfree(xfer); | |
+ xfer = kcalloc(count, sizeof(struct spi_transfer), GFP_KERNEL); | |
+ if (!xfer) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for xfer\n", | |
+ __func__); | |
+ xfer_count = 0; | |
+ return -ENOMEM; | |
+ } | |
+ xfer_count = count; | |
+ } else { | |
+ memset(xfer, 0, count * sizeof(struct spi_transfer)); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
static int synaptics_rmi4_spi_set_page(struct synaptics_rmi4_data *rmi4_data, | |
unsigned short addr) | |
{ | |
int retval; | |
unsigned int index; | |
- unsigned int xfer_count = PAGE_SELECT_LEN + 1; | |
- unsigned char txbuf[xfer_count]; | |
+ unsigned int byte_count = PAGE_SELECT_LEN + 1; | |
unsigned char page; | |
struct spi_message msg; | |
- struct spi_transfer xfers[xfer_count]; | |
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent); | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
- page = ((addr >> 8) & ~MASK_7BIT); | |
- if (page != rmi4_data->current_page) { | |
- spi_message_init(&msg); | |
+ page = ((addr >> 8) & MASK_8BIT); | |
+ if ((page >> 7) == (rmi4_data->current_page >> 7)) | |
+ return PAGE_SELECT_LEN; | |
- txbuf[0] = SPI_WRITE; | |
- txbuf[1] = MASK_8BIT; | |
- txbuf[2] = page; | |
+ spi_message_init(&msg); | |
- for (index = 0; index < xfer_count; index++) { | |
- memset(&xfers[index], 0, sizeof(struct spi_transfer)); | |
- xfers[index].len = 1; | |
- xfers[index].delay_usecs = bdata->byte_delay_us; | |
- xfers[index].tx_buf = &txbuf[index]; | |
- spi_message_add_tail(&xfers[index], &msg); | |
- } | |
+ retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, byte_count, | |
+ byte_count); | |
+ if (retval < 0) | |
+ return retval; | |
- if (bdata->block_delay_us) | |
- xfers[index - 1].delay_usecs = bdata->block_delay_us; | |
+ buf[0] = SPI_WRITE; | |
+ buf[1] = MASK_8BIT; | |
+ buf[2] = page; | |
- retval = spi_sync(spi, &msg); | |
- if (retval == 0) { | |
- rmi4_data->current_page = page; | |
- retval = PAGE_SELECT_LEN; | |
- } else { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to complete SPI transfer, error = %d\n", | |
- __func__, retval); | |
- } | |
+ if (bdata->byte_delay_us == 0) { | |
+ xfer[0].len = byte_count; | |
+ xfer[0].tx_buf = &buf[0]; | |
+ if (bdata->block_delay_us) | |
+ xfer[0].delay_usecs = bdata->block_delay_us; | |
+ spi_message_add_tail(&xfer[0], &msg); | |
} else { | |
+ for (index = 0; index < byte_count; index++) { | |
+ xfer[index].len = 1; | |
+ xfer[index].tx_buf = &buf[index]; | |
+ if (index == 1) | |
+ xfer[index].delay_usecs = bdata->addr_delay_us; | |
+ else | |
+ xfer[index].delay_usecs = bdata->byte_delay_us; | |
+ spi_message_add_tail(&xfer[index], &msg); | |
+ } | |
+ if (bdata->block_delay_us) | |
+ xfer[index - 1].delay_usecs = bdata->block_delay_us; | |
+ } | |
+ | |
+ retval = spi_sync(spi, &msg); | |
+ if (retval == 0) { | |
+ rmi4_data->current_page = page; | |
retval = PAGE_SELECT_LEN; | |
+ } else { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to complete SPI transfer, error = %d\n", | |
+ __func__, retval); | |
} | |
return retval; | |
@@ -266,63 +391,67 @@ static int synaptics_rmi4_spi_read(struct synaptics_rmi4_data *rmi4_data, | |
{ | |
int retval; | |
unsigned int index; | |
- unsigned int xfer_count = length + ADDRESS_WORD_LEN; | |
- unsigned char txbuf[ADDRESS_WORD_LEN]; | |
- unsigned char *rxbuf = NULL; | |
+ unsigned int byte_count = length + ADDRESS_LEN; | |
+ unsigned char txbuf[ADDRESS_LEN]; | |
struct spi_message msg; | |
- struct spi_transfer *xfers = NULL; | |
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent); | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
spi_message_init(&msg); | |
- xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL); | |
- if (!xfers) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to allocate memory for xfers\n", | |
- __func__); | |
- retval = -ENOMEM; | |
- goto exit; | |
- } | |
- | |
txbuf[0] = (addr >> 8) | SPI_READ; | |
txbuf[1] = addr & MASK_8BIT; | |
- rxbuf = kmalloc(length, GFP_KERNEL); | |
- if (!rxbuf) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to allocate memory for rxbuf\n", | |
- __func__); | |
- retval = -ENOMEM; | |
- goto exit; | |
- } | |
- | |
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); | |
retval = synaptics_rmi4_spi_set_page(rmi4_data, addr); | |
if (retval != PAGE_SELECT_LEN) { | |
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
- retval = -EIO; | |
- goto exit; | |
+ return -EIO; | |
} | |
- for (index = 0; index < xfer_count; index++) { | |
- xfers[index].len = 1; | |
- xfers[index].delay_usecs = bdata->byte_delay_us; | |
- if (index < ADDRESS_WORD_LEN) | |
- xfers[index].tx_buf = &txbuf[index]; | |
- else | |
- xfers[index].rx_buf = &rxbuf[index - ADDRESS_WORD_LEN]; | |
- spi_message_add_tail(&xfers[index], &msg); | |
+ if (bdata->byte_delay_us == 0) { | |
+ retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, length, | |
+ 2); | |
+ } else { | |
+ retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, length, | |
+ byte_count); | |
+ } | |
+ if (retval < 0) { | |
+ mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
+ return retval; | |
} | |
- if (bdata->block_delay_us) | |
- xfers[index - 1].delay_usecs = bdata->block_delay_us; | |
+ if (bdata->byte_delay_us == 0) { | |
+ xfer[0].len = ADDRESS_LEN; | |
+ xfer[0].tx_buf = &txbuf[0]; | |
+ spi_message_add_tail(&xfer[0], &msg); | |
+ xfer[1].len = length; | |
+ xfer[1].rx_buf = &buf[0]; | |
+ if (bdata->block_delay_us) | |
+ xfer[1].delay_usecs = bdata->block_delay_us; | |
+ spi_message_add_tail(&xfer[1], &msg); | |
+ } else { | |
+ for (index = 0; index < byte_count; index++) { | |
+ xfer[index].len = 1; | |
+ if (index < ADDRESS_LEN) | |
+ xfer[index].tx_buf = &txbuf[index]; | |
+ else | |
+ xfer[index].rx_buf = &buf[index - ADDRESS_LEN]; | |
+ if (index == 1) | |
+ xfer[index].delay_usecs = bdata->addr_delay_us; | |
+ else | |
+ xfer[index].delay_usecs = bdata->byte_delay_us; | |
+ spi_message_add_tail(&xfer[index], &msg); | |
+ } | |
+ if (bdata->block_delay_us) | |
+ xfer[index - 1].delay_usecs = bdata->block_delay_us; | |
+ } | |
retval = spi_sync(spi, &msg); | |
if (retval == 0) { | |
- retval = secure_memcpy(data, length, rxbuf, length, length); | |
+ retval = secure_memcpy(data, length, buf, length, length); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to copy data\n", | |
@@ -338,10 +467,6 @@ static int synaptics_rmi4_spi_read(struct synaptics_rmi4_data *rmi4_data, | |
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
-exit: | |
- kfree(rxbuf); | |
- kfree(xfers); | |
- | |
return retval; | |
} | |
@@ -350,64 +475,66 @@ static int synaptics_rmi4_spi_write(struct synaptics_rmi4_data *rmi4_data, | |
{ | |
int retval; | |
unsigned int index; | |
- unsigned int xfer_count = length + ADDRESS_WORD_LEN; | |
- unsigned char *txbuf = NULL; | |
+ unsigned int byte_count = length + ADDRESS_LEN; | |
struct spi_message msg; | |
- struct spi_transfer *xfers = NULL; | |
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent); | |
const struct synaptics_dsx_board_data *bdata = | |
rmi4_data->hw_if->board_data; | |
spi_message_init(&msg); | |
- xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL); | |
- if (!xfers) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to allocate memory for xfers\n", | |
- __func__); | |
- retval = -ENOMEM; | |
- goto exit; | |
+ mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); | |
+ | |
+ retval = synaptics_rmi4_spi_set_page(rmi4_data, addr); | |
+ if (retval != PAGE_SELECT_LEN) { | |
+ mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
+ return -EIO; | |
} | |
- txbuf = kmalloc(xfer_count, GFP_KERNEL); | |
- if (!txbuf) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to allocate memory for txbuf\n", | |
- __func__); | |
- retval = -ENOMEM; | |
- goto exit; | |
+ if (bdata->byte_delay_us == 0) { | |
+ retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, byte_count, | |
+ 1); | |
+ } else { | |
+ retval = synaptics_rmi4_spi_alloc_buf(rmi4_data, byte_count, | |
+ byte_count); | |
+ } | |
+ if (retval < 0) { | |
+ mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
+ return retval; | |
} | |
- txbuf[0] = (addr >> 8) & ~SPI_READ; | |
- txbuf[1] = addr & MASK_8BIT; | |
- retval = secure_memcpy(&txbuf[ADDRESS_WORD_LEN], | |
- xfer_count - ADDRESS_WORD_LEN, data, length, length); | |
+ buf[0] = (addr >> 8) & ~SPI_READ; | |
+ buf[1] = addr & MASK_8BIT; | |
+ retval = secure_memcpy(&buf[ADDRESS_LEN], | |
+ byte_count - ADDRESS_LEN, data, length, length); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
"%s: Failed to copy data\n", | |
__func__); | |
- goto exit; | |
- } | |
- | |
- mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex); | |
- | |
- retval = synaptics_rmi4_spi_set_page(rmi4_data, addr); | |
- if (retval != PAGE_SELECT_LEN) { | |
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
- retval = -EIO; | |
- goto exit; | |
+ return retval; | |
} | |
- for (index = 0; index < xfer_count; index++) { | |
- xfers[index].len = 1; | |
- xfers[index].delay_usecs = bdata->byte_delay_us; | |
- xfers[index].tx_buf = &txbuf[index]; | |
- spi_message_add_tail(&xfers[index], &msg); | |
+ if (bdata->byte_delay_us == 0) { | |
+ xfer[0].len = byte_count; | |
+ xfer[0].tx_buf = &buf[0]; | |
+ if (bdata->block_delay_us) | |
+ xfer[0].delay_usecs = bdata->block_delay_us; | |
+ spi_message_add_tail(xfer, &msg); | |
+ } else { | |
+ for (index = 0; index < byte_count; index++) { | |
+ xfer[index].len = 1; | |
+ xfer[index].tx_buf = &buf[index]; | |
+ if (index == 1) | |
+ xfer[index].delay_usecs = bdata->addr_delay_us; | |
+ else | |
+ xfer[index].delay_usecs = bdata->byte_delay_us; | |
+ spi_message_add_tail(&xfer[index], &msg); | |
+ } | |
+ if (bdata->block_delay_us) | |
+ xfer[index - 1].delay_usecs = bdata->block_delay_us; | |
} | |
- if (bdata->block_delay_us) | |
- xfers[index - 1].delay_usecs = bdata->block_delay_us; | |
- | |
retval = spi_sync(spi, &msg); | |
if (retval == 0) { | |
retval = length; | |
@@ -419,10 +546,6 @@ static int synaptics_rmi4_spi_write(struct synaptics_rmi4_data *rmi4_data, | |
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex); | |
-exit: | |
- kfree(txbuf); | |
- kfree(xfers); | |
- | |
return retval; | |
} | |
@@ -537,6 +660,12 @@ static int synaptics_rmi4_spi_remove(struct spi_device *spi) | |
return 0; | |
} | |
+static const struct spi_device_id synaptics_rmi4_id_table[] = { | |
+ {SPI_DRIVER_NAME, 0}, | |
+ {}, | |
+}; | |
+MODULE_DEVICE_TABLE(spi, synaptics_rmi4_id_table); | |
+ | |
#ifdef CONFIG_OF | |
static struct of_device_id synaptics_rmi4_of_match_table[] = { | |
{ | |
@@ -557,22 +686,25 @@ static struct spi_driver synaptics_rmi4_spi_driver = { | |
}, | |
.probe = synaptics_rmi4_spi_probe, | |
.remove = synaptics_rmi4_spi_remove, | |
+ .id_table = synaptics_rmi4_id_table, | |
}; | |
-int synaptics_rmi4_bus_init(void) | |
+int synaptics_rmi4_bus_init_force(void) | |
{ | |
return spi_register_driver(&synaptics_rmi4_spi_driver); | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_bus_init); | |
-void synaptics_rmi4_bus_exit(void) | |
+void synaptics_rmi4_bus_exit_force(void) | |
{ | |
+ kfree(buf); | |
+ | |
+ kfree(xfer); | |
+ | |
spi_unregister_driver(&synaptics_rmi4_spi_driver); | |
return; | |
} | |
-EXPORT_SYMBOL(synaptics_rmi4_bus_exit); | |
MODULE_AUTHOR("Synaptics, Inc."); | |
MODULE_DESCRIPTION("Synaptics DSX SPI Bus Support Module"); | |
diff --git a/synaptics_dsx_test_reporting.c b/synaptics_dsx_test_reporting.c | |
index e063a60..b52ac26 100644 | |
--- a/synaptics_dsx_test_reporting.c | |
+++ b/synaptics_dsx_test_reporting.c | |
@@ -48,7 +48,9 @@ | |
#define SYSFS_FOLDER_NAME "f54" | |
-#define USE_RT8 | |
+ | |
+ | |
+#define BUTTON_COUNT 3 | |
#define GET_REPORT_TIMEOUT_S 3 | |
#define CALIBRATION_TIMEOUT_S 10 | |
@@ -66,9 +68,6 @@ | |
#define SENSOR_RX_MAPPING_OFFSET 1 | |
#define SENSOR_TX_MAPPING_OFFSET 2 | |
-/* td43xx start */ | |
-#define AMP_SENSOR_CHAR_OFFSET 5 | |
-/* td43xx end */ | |
#define COMMAND_GET_REPORT 1 | |
#define COMMAND_FORCE_CAL 2 | |
@@ -188,13 +187,37 @@ | |
#define CONTROL_147_SIZE 1 | |
#define CONTROL_148_SIZE 1 | |
#define CONTROL_149_SIZE 1 | |
+#define CONTROL_150_SIZE 1 | |
+#define CONTROL_151_SIZE 1 | |
+#define CONTROL_152_SIZE 1 | |
+#define CONTROL_153_SIZE 1 | |
+#define CONTROL_154_SIZE 1 | |
+#define CONTROL_155_SIZE 1 | |
+#define CONTROL_156_SIZE 1 | |
+#define CONTROL_157_158_SIZE 2 | |
#define CONTROL_163_SIZE 1 | |
#define CONTROL_165_SIZE 1 | |
#define CONTROL_166_SIZE 1 | |
#define CONTROL_167_SIZE 1 | |
+#define CONTROL_168_SIZE 1 | |
+#define CONTROL_169_SIZE 1 | |
+#define CONTROL_171_SIZE 1 | |
+#define CONTROL_172_SIZE 1 | |
+#define CONTROL_173_SIZE 1 | |
+#define CONTROL_174_SIZE 1 | |
+#define CONTROL_175_SIZE 1 | |
#define CONTROL_176_SIZE 1 | |
+#define CONTROL_177_178_SIZE 2 | |
#define CONTROL_179_SIZE 1 | |
+#define CONTROL_182_SIZE 1 | |
+#define CONTROL_183_SIZE 1 | |
+#define CONTROL_185_SIZE 1 | |
+#define CONTROL_186_SIZE 1 | |
+#define CONTROL_187_SIZE 1 | |
#define CONTROL_188_SIZE 1 | |
+#define CONTROL_196_SIZE 1 | |
+#define CONTROL_218_SIZE 1 | |
+#define CONTROL_223_SIZE 1 | |
#define HIGH_RESISTANCE_DATA_SIZE 6 | |
#define FULL_RAW_CAP_MIN_MAX_DATA_SIZE 4 | |
@@ -207,6 +230,9 @@ | |
#define TDDI_OPEN_TEST_INT_DUR_TWO 15 | |
#define TDDI_OPEN_TEST_LIMIT_PHASE2_LOWER 50 | |
+#define ABS_0D_OPEN_FACTOR 8 | |
+#define ABS_0D_OPEN_TEST_LIMIT 30 | |
+ | |
#define TEST_INVALID 0 | |
#define TEST_FAILED 1 | |
#define TEST_OK 2 | |
@@ -214,7 +240,8 @@ | |
#define TEST_TYPE_20_333X "20" | |
#define TEST_TYPE_25_333X "25" | |
#define TEST_TYPE_26_333X "26" | |
- | |
+#define TEST_TYPE_02 "2" | |
+#define TEST_TYPE_03 "3" | |
#define CHIP_ID_OFFSET 11 | |
@@ -300,11 +327,8 @@ enum f54_report_types { | |
F54_RX_TO_RX_SHORTS_2 = 17, | |
F54_RX_OPENS_2 = 18, | |
F54_FULL_RAW_CAP = 19, | |
-#ifdef USE_RT8 | |
- F54_FULL_RAW_CAP_NO_RX_COUPLING = 8, | |
-#else | |
+ F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING = 8, | |
F54_FULL_RAW_CAP_NO_RX_COUPLING = 20, | |
-#endif | |
F54_SENSOR_SPEED = 22, | |
F54_ADC_RANGE = 23, | |
F54_TRX_OPENS = 24, | |
@@ -571,7 +595,7 @@ struct f54_query_30 { | |
unsigned char has_ctrl121:1; | |
unsigned char has_ctrl122_query31:1; | |
unsigned char has_ctrl123:1; | |
- unsigned char f54_query30_b6:1; | |
+ unsigned char has_ctrl124:1; | |
unsigned char has_query32:1; | |
} __packed; | |
unsigned char data[1]; | |
@@ -597,10 +621,10 @@ struct f54_query_32 { | |
struct f54_query_33 { | |
union { | |
struct { | |
- unsigned char f54_query33_b0:1; | |
- unsigned char f54_query33_b1:1; | |
- unsigned char f54_query33_b2:1; | |
- unsigned char f54_query33_b3:1; | |
+ unsigned char has_ctrl128:1; | |
+ unsigned char has_ctrl129:1; | |
+ unsigned char has_ctrl130:1; | |
+ unsigned char has_ctrl131:1; | |
unsigned char has_ctrl132:1; | |
unsigned char has_ctrl133:1; | |
unsigned char has_ctrl134:1; | |
@@ -614,8 +638,8 @@ struct f54_query_35 { | |
union { | |
struct { | |
unsigned char has_data25:1; | |
- unsigned char f54_query35_b1:1; | |
- unsigned char f54_query35_b2:1; | |
+ unsigned char has_ctrl135:1; | |
+ unsigned char has_ctrl136:1; | |
unsigned char has_ctrl137:1; | |
unsigned char has_ctrl138:1; | |
unsigned char has_ctrl139:1; | |
@@ -629,7 +653,7 @@ struct f54_query_35 { | |
struct f54_query_36 { | |
union { | |
struct { | |
- unsigned char f54_query36_b0:1; | |
+ unsigned char has_ctrl141:1; | |
unsigned char has_ctrl142:1; | |
unsigned char has_query37:1; | |
unsigned char has_ctrl143:1; | |
@@ -648,7 +672,10 @@ struct f54_query_38 { | |
unsigned char has_ctrl147:1; | |
unsigned char has_ctrl148:1; | |
unsigned char has_ctrl149:1; | |
- unsigned char f54_query38_b3__6:4; | |
+ unsigned char has_ctrl150:1; | |
+ unsigned char has_ctrl151:1; | |
+ unsigned char has_ctrl152:1; | |
+ unsigned char has_ctrl153:1; | |
unsigned char has_query39:1; | |
} __packed; | |
unsigned char data[1]; | |
@@ -658,7 +685,12 @@ struct f54_query_38 { | |
struct f54_query_39 { | |
union { | |
struct { | |
- unsigned char f54_query39_b0__6:7; | |
+ unsigned char has_ctrl154:1; | |
+ unsigned char has_ctrl155:1; | |
+ unsigned char has_ctrl156:1; | |
+ unsigned char has_ctrl160:1; | |
+ unsigned char has_ctrl157_ctrl158:1; | |
+ unsigned char f54_query39_b5__6:2; | |
unsigned char has_query40:1; | |
} __packed; | |
unsigned char data[1]; | |
@@ -668,13 +700,13 @@ struct f54_query_39 { | |
struct f54_query_40 { | |
union { | |
struct { | |
- unsigned char f54_query40_b0:1; | |
+ unsigned char has_ctrl169:1; | |
unsigned char has_ctrl163_query41:1; | |
unsigned char f54_query40_b2:1; | |
unsigned char has_ctrl165_query42:1; | |
unsigned char has_ctrl166:1; | |
unsigned char has_ctrl167:1; | |
- unsigned char f54_query40_b6:1; | |
+ unsigned char has_ctrl168:1; | |
unsigned char has_query43:1; | |
} __packed; | |
unsigned char data[1]; | |
@@ -684,7 +716,12 @@ struct f54_query_40 { | |
struct f54_query_43 { | |
union { | |
struct { | |
- unsigned char f54_query43_b0__6:7; | |
+ unsigned char f54_query43_b0__1:2; | |
+ unsigned char has_ctrl171:1; | |
+ unsigned char has_ctrl172_query44_query45:1; | |
+ unsigned char has_ctrl173:1; | |
+ unsigned char has_ctrl174:1; | |
+ unsigned char has_ctrl175:1; | |
unsigned char has_query46:1; | |
} __packed; | |
unsigned char data[1]; | |
@@ -695,7 +732,7 @@ struct f54_query_46 { | |
union { | |
struct { | |
unsigned char has_ctrl176:1; | |
- unsigned char f54_query46_b1:1; | |
+ unsigned char has_ctrl177_ctrl178:1; | |
unsigned char has_ctrl179:1; | |
unsigned char f54_query46_b3:1; | |
unsigned char has_data27:1; | |
@@ -710,7 +747,13 @@ struct f54_query_46 { | |
struct f54_query_47 { | |
union { | |
struct { | |
- unsigned char f54_query47_b0__6:7; | |
+ unsigned char f54_query47_b0:1; | |
+ unsigned char has_ctrl182:1; | |
+ unsigned char has_ctrl183:1; | |
+ unsigned char f54_query47_b3:1; | |
+ unsigned char has_ctrl185:1; | |
+ unsigned char has_ctrl186:1; | |
+ unsigned char has_ctrl187:1; | |
unsigned char has_query49:1; | |
} __packed; | |
unsigned char data[1]; | |
@@ -743,7 +786,11 @@ struct f54_query_50 { | |
struct f54_query_51 { | |
union { | |
struct { | |
- unsigned char f54_query51_b0__4:5; | |
+ unsigned char f54_query51_b0:1; | |
+ unsigned char has_ctrl196:1; | |
+ unsigned char f54_query51_b2:1; | |
+ unsigned char f54_query51_b3:1; | |
+ unsigned char f54_query51_b4:1; | |
unsigned char has_query53_query54_ctrl198:1; | |
unsigned char has_ctrl199:1; | |
unsigned char has_query55:1; | |
@@ -806,7 +853,7 @@ struct f54_query_61 { | |
unsigned char has_ctrl214:1; | |
unsigned char has_ctrl215_query62_query63:1; | |
unsigned char f54_query61_b2__4:3; | |
- unsigned char has_misc_host_ctrl:1; | |
+ unsigned char has_ctrl218:1; | |
unsigned char has_hybrid_abs_buttons:1; | |
unsigned char has_query64:1; | |
} __packed; | |
@@ -821,7 +868,7 @@ struct f54_query_64 { | |
unsigned char has_ctrl220:1; | |
unsigned char f54_query64_b2__3:2; | |
unsigned char has_ctrl219_sub1:1; | |
- unsigned char f54_query64_b5:1; | |
+ unsigned char has_ctrl103_sub3:1; | |
unsigned char has_ctrl224_ctrl226_ctrl227:1; | |
unsigned char has_query65:1; | |
} __packed; | |
@@ -1068,6 +1115,18 @@ struct f54_control_188 { | |
}; | |
}; | |
+struct f54_control_223 { | |
+ union { | |
+ struct { | |
+ unsigned char voltages_for_0d:8; | |
+ } __packed; | |
+ struct { | |
+ unsigned char data[1]; | |
+ unsigned short address; | |
+ } __packed; | |
+ }; | |
+}; | |
+ | |
struct f54_control { | |
struct f54_control_7 *reg_7; | |
struct f54_control_41 *reg_41; | |
@@ -1082,6 +1141,7 @@ struct f54_control { | |
struct f54_control_110 *reg_110; | |
struct f54_control_149 *reg_149; | |
struct f54_control_188 *reg_188; | |
+ struct f54_control_223 *reg_223; | |
}; | |
struct synaptics_rmi4_f54_handle { | |
@@ -1325,6 +1385,7 @@ struct f55_control_43 { | |
struct synaptics_rmi4_f55_handle { | |
bool amp_sensor; | |
bool extended_amp; | |
+ bool extended_amp_btn; | |
bool has_force; | |
unsigned char size_of_column2mux; | |
unsigned char afe_mux_offset; | |
@@ -1372,6 +1433,7 @@ show_store_prototype(td43xx_full_raw) | |
show_store_prototype(td43xx_noise) | |
show_store_prototype(td43xx_ee_short) | |
show_store_prototype(td43xx_amp_open) | |
+show_store_prototype(abs_0d_open_w_autoservo) | |
/* td43xx end */ | |
static struct attribute *attrs[] = { | |
@@ -1397,6 +1459,7 @@ static struct attribute *attrs[] = { | |
attrify(td43xx_noise), | |
attrify(td43xx_ee_short), | |
attrify(td43xx_amp_open), | |
+ attrify(abs_0d_open_w_autoservo), | |
/* td43xx end */ | |
NULL, | |
}; | |
@@ -1404,6 +1467,20 @@ static struct attribute *attrs[] = { | |
static struct attribute_group attr_group = { | |
.attrs = attrs, | |
}; | |
+/* | |
+static ssize_t test_sysfs_data_read(struct file *data_file, | |
+ struct kobject *kobj, struct bin_attribute *attributes, | |
+ char *buf, loff_t pos, size_t count); | |
+ | |
+static struct bin_attribute test_report_data = { | |
+ .attr = { | |
+ .name = "report_data", | |
+ .mode = S_IRUGO, | |
+ }, | |
+ .size = 0, | |
+ .read = test_sysfs_data_read, | |
+}; | |
+*/ | |
static struct synaptics_rmi4_f54_handle *f54; | |
static struct synaptics_rmi4_f55_handle *f55; | |
@@ -1413,8 +1490,10 @@ static signed short *td43xx_noise_delta; | |
static unsigned char *td43xx_ee_short_data; | |
static unsigned char *td43xx_amp_open_data; | |
/* td43xx end */ | |
+static int *g_abs_0d_open_data_output; | |
+static char g_flag_read_report_fail; | |
-DECLARE_COMPLETION(test_remove_complete); | |
+DECLARE_COMPLETION(test_remove_complete_force); | |
static bool test_report_type_valid(enum f54_report_types report_type) | |
{ | |
@@ -1433,6 +1512,7 @@ static bool test_report_type_valid(enum f54_report_types report_type) | |
case F54_RX_TO_RX_SHORTS_2: | |
case F54_RX_OPENS_2: | |
case F54_FULL_RAW_CAP: | |
+ case F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING: | |
case F54_FULL_RAW_CAP_NO_RX_COUPLING: | |
case F54_SENSOR_SPEED: | |
case F54_ADC_RANGE: | |
@@ -1474,6 +1554,7 @@ static void test_set_report_size(void) | |
case F54_RAW_16BIT_IMAGE: | |
case F54_TRUE_BASELINE: | |
case F54_FULL_RAW_CAP: | |
+ case F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING: | |
case F54_FULL_RAW_CAP_NO_RX_COUPLING: | |
case F54_SENSOR_SPEED: | |
case F54_AMP_FULL_RAW_CAP: | |
@@ -1697,35 +1778,37 @@ static int test_do_preparation(void) | |
int retval; | |
unsigned char value; | |
unsigned char zero = 0x00; | |
-#ifndef USE_RT8 | |
- unsigned char device_ctrl; | |
-#endif | |
struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; | |
+ const struct synaptics_dsx_board_data *bdata = | |
+ rmi4_data->hw_if->board_data; | |
#ifndef USE_RT8 | |
- retval = synaptics_rmi4_reg_read(rmi4_data, | |
- rmi4_data->f01_ctrl_base_addr, | |
- &device_ctrl, | |
- sizeof(device_ctrl)); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to set no sleep\n", | |
- __func__); | |
- return retval; | |
- } | |
+ unsigned char device_ctrl; | |
- device_ctrl |= NO_SLEEP_ON; | |
+ if (!bdata->captouch_use) { | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ rmi4_data->f01_ctrl_base_addr, | |
+ &device_ctrl, | |
+ sizeof(device_ctrl)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to set no sleep\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
- retval = synaptics_rmi4_reg_write(rmi4_data, | |
- rmi4_data->f01_ctrl_base_addr, | |
- &device_ctrl, | |
- sizeof(device_ctrl)); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to set no sleep\n", | |
- __func__); | |
- return retval; | |
- } | |
+ device_ctrl |= NO_SLEEP_ON; | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ rmi4_data->f01_ctrl_base_addr, | |
+ &device_ctrl, | |
+ sizeof(device_ctrl)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to set no sleep\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
+ } | |
#endif | |
if (f54->skip_preparation) | |
return 0; | |
@@ -1739,6 +1822,7 @@ static int test_do_preparation(void) | |
case F54_ABS_DELTA_CAP: | |
case F54_ABS_HYBRID_DELTA_CAP: | |
case F54_ABS_HYBRID_RAW_CAP: | |
+ case F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING: | |
#ifdef USE_RT8 | |
case F54_FULL_RAW_CAP_NO_RX_COUPLING: | |
#endif | |
@@ -2014,30 +2098,36 @@ static int test_do_resume_touch(void) | |
{ | |
int retval = 0; | |
struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; | |
+ const struct synaptics_dsx_board_data *bdata = | |
+ rmi4_data->hw_if->board_data; | |
#ifndef USE_RT8 | |
- retval = synaptics_rmi4_reg_read(rmi4_data, | |
- rmi4_data->f01_ctrl_base_addr, | |
- &device_ctrl, | |
- sizeof(device_ctrl)); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to restore no sleep setting\n", | |
- __func__); | |
- return retval; | |
- } | |
+ unsigned char device_ctrl; | |
- device_ctrl = device_ctrl & ~NO_SLEEP_ON; | |
- device_ctrl |= rmi4_data->no_sleep_setting; | |
+ if (!bdata->captouch_use) { | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ rmi4_data->f01_ctrl_base_addr, | |
+ &device_ctrl, | |
+ sizeof(device_ctrl)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to restore no sleep setting\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
- retval = synaptics_rmi4_reg_write(rmi4_data, | |
- rmi4_data->f01_ctrl_base_addr, | |
- &device_ctrl, | |
- sizeof(device_ctrl)); | |
- if (retval < 0) { | |
- dev_err(rmi4_data->pdev->dev.parent, | |
- "%s: Failed to restore no sleep setting\n", | |
- __func__); | |
- return retval; | |
+ device_ctrl = device_ctrl & ~NO_SLEEP_ON; | |
+ device_ctrl |= rmi4_data->no_sleep_setting; | |
+ | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ rmi4_data->f01_ctrl_base_addr, | |
+ &device_ctrl, | |
+ sizeof(device_ctrl)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to restore no sleep setting\n", | |
+ __func__); | |
+ return retval; | |
+ } | |
} | |
#endif | |
test_set_interrupt(false); | |
@@ -2054,6 +2144,7 @@ static int test_do_resume_touch(void) | |
case F54_ABS_DELTA_CAP: | |
case F54_ABS_HYBRID_DELTA_CAP: | |
case F54_ABS_HYBRID_RAW_CAP: | |
+ case F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING: | |
#ifdef USE_RT8 | |
case F54_FULL_RAW_CAP_NO_RX_COUPLING: | |
#endif | |
@@ -2376,6 +2467,11 @@ static ssize_t test_sysfs_get_report_store(struct device *dev, | |
f54->status = STATUS_BUSY; | |
f54->report_size = 0; | |
f54->data_pos = 0; | |
+/* | |
+ hrtimer_start(&f54->watchdog, | |
+ ktime_set(GET_REPORT_TIMEOUT_S, 0), | |
+ HRTIMER_MODE_REL); | |
+*/ | |
retval = count; | |
exit: | |
@@ -2450,7 +2546,11 @@ static ssize_t test_sysfs_report_type_store(struct device *dev, | |
unsigned char data; | |
unsigned long setting; | |
struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; | |
+ const struct synaptics_dsx_board_data *bdata = | |
+ rmi4_data->hw_if->board_data; | |
+#ifdef USE_RT8 | |
static bool do_once; | |
+#endif | |
retval = sstrtoul(buf, 10, &setting); | |
if (retval) | |
@@ -2462,9 +2562,11 @@ static ssize_t test_sysfs_report_type_store(struct device *dev, | |
if (retval < 0) | |
goto exit; | |
+ if (bdata->captouch_use && setting == F54_FULL_RAW_CAP_NO_RX_COUPLING) | |
+ setting = F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING; | |
#ifdef USE_RT8 | |
- if (setting == 20) | |
- setting = 8; | |
+ if (setting == F54_FULL_RAW_CAP_NO_RX_COUPLING) | |
+ setting = F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING; | |
#endif | |
if (!test_report_type_valid((enum f54_report_types)setting)) { | |
@@ -2475,6 +2577,8 @@ static ssize_t test_sysfs_report_type_store(struct device *dev, | |
goto exit; | |
} | |
+ if (bdata->captouch_use && setting == 20) | |
+ setting = 8; | |
#ifdef USE_RT8 | |
if ((f54->report_type == F54_FULL_RAW_CAP_NO_RX_COUPLING) && do_once) { | |
rmi4_data->reset_device(rmi4_data, false); | |
@@ -2675,6 +2779,7 @@ static ssize_t test_sysfs_read_report_show(struct device *dev, | |
case F54_RAW_16BIT_IMAGE: | |
case F54_TRUE_BASELINE: | |
case F54_FULL_RAW_CAP: | |
+ case F54_FULL_RAW_CAP_NO_RX_SELF_COUPLING: | |
case F54_FULL_RAW_CAP_NO_RX_COUPLING: | |
case F54_SENSOR_SPEED: | |
case F54_AMP_FULL_RAW_CAP: | |
@@ -2939,7 +3044,8 @@ static ssize_t test_sysfs_read_report_store(struct device *dev, | |
pr_err("%s: done test_wait_for_command_completion\n", __func__); | |
- if (rmi4_data->chip_id == CHIP_ID_4322) | |
+ if (rmi4_data->chip_id == rmi4_data->hw_if->board_data->chip_4322 || | |
+ rmi4_data->chip_id == rmi4_data->hw_if->board_data->chip_4722) | |
queue_work(f54->test_report_workqueue, &f54->test_report_work); | |
timeout_count = 0; | |
@@ -3813,6 +3919,268 @@ static ssize_t test_sysfs_td43xx_amp_open_show(struct device *dev, | |
return snprintf(buf, PAGE_SIZE, "%s\n", (result == 1) ? "PASS" : "FAIL"); | |
} | |
+ | |
+ | |
+static ssize_t test_sysfs_abs_0d_open_w_autoservo_store(struct device *dev, | |
+ struct device_attribute *attr, const char *buf, size_t count) | |
+{ | |
+ int retval = 0; | |
+ int i, j, k; | |
+ int tx_num = f54->tx_assigned; | |
+ int rx_num = f54->rx_assigned; | |
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; | |
+ struct f54_control control = f54->control; | |
+ unsigned long setting; | |
+ | |
+ unsigned char original_data_f54_ctr223 = 0x00; | |
+ unsigned char data = 0x00; | |
+ | |
+ signed char *p_report_data_8 = NULL; | |
+ signed short *p_rt92_image_1 = NULL; | |
+ signed short *p_rt92_image_2 = NULL; | |
+ | |
+ unsigned char button_count = rmi4_data->valid_button_count; | |
+ | |
+ button_count = BUTTON_COUNT; | |
+ | |
+ retval = sstrtoul(buf, 10, &setting); | |
+ if (retval) | |
+ return retval; | |
+ | |
+ if (setting != 1) | |
+ return -EINVAL; | |
+ | |
+ if (button_count == 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to get rmi button (count = %d)\n", | |
+ __func__, rmi4_data->valid_button_count); | |
+ retval = -EINVAL; | |
+ goto exit; | |
+ } | |
+ | |
+ /* allocate the g_tddi_amp_open_data_output */ | |
+ if (g_abs_0d_open_data_output) | |
+ kfree(g_abs_0d_open_data_output); | |
+ g_abs_0d_open_data_output = kzalloc(button_count * sizeof(int), GFP_KERNEL); | |
+ if (!g_abs_0d_open_data_output) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for g_abs_0d_open_data_output\n", | |
+ __func__); | |
+ return -ENOMEM; | |
+ } | |
+ | |
+ g_flag_read_report_fail = 0; | |
+ | |
+ /* allocate the buffer */ | |
+ p_report_data_8 = kzalloc(tx_num * rx_num * 2, GFP_KERNEL); | |
+ if (!p_report_data_8) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for p_report_data_8\n", | |
+ __func__); | |
+ retval = -ENOMEM; | |
+ goto exit; | |
+ } | |
+ | |
+ p_rt92_image_1 = kzalloc(tx_num * rx_num * sizeof(signed short), GFP_KERNEL); | |
+ if (!p_rt92_image_1) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for p_rt92_image_1\n", | |
+ __func__); | |
+ retval = -ENOMEM; | |
+ goto exit; | |
+ } | |
+ | |
+ p_rt92_image_2 = kzalloc(tx_num * rx_num * sizeof(signed short), GFP_KERNEL); | |
+ if (!p_rt92_image_2) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to alloc mem for p_rt92_image_2\n", | |
+ __func__); | |
+ retval = -ENOMEM; | |
+ goto exit; | |
+ } | |
+ | |
+ /* step 1 */ | |
+ /* get first rt92 image */ | |
+ retval = test_sysfs_read_report_td43xx(dev, attr, "92", count, | |
+ false, false); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read report 92 in step 1\n", | |
+ __func__); | |
+ g_flag_read_report_fail = 1; /* special code to indicate the failure of report reading */ | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ | |
+ secure_memcpy(p_report_data_8, tx_num * rx_num * 2, | |
+ f54->report_data, f54->report_size, f54->report_size); | |
+ | |
+ /* normalize the rt92 image with 16-bit */ | |
+ k = 0; | |
+ for (i = 0; i < tx_num; i++) { | |
+ for (j = 0; j < rx_num; j++) { | |
+ p_rt92_image_1[i * rx_num + j] = | |
+ (signed short)(p_report_data_8[k] & 0xff) | (signed short)(p_report_data_8[k + 1] << 8); | |
+ | |
+ k += 2; | |
+ } | |
+ } | |
+ | |
+ memset(p_report_data_8, 0x00, tx_num * rx_num * 2); | |
+ | |
+ /* step 2 */ | |
+ /* read original 0d voltages */ | |
+ retval = synaptics_rmi4_reg_read(rmi4_data, | |
+ control.reg_223->address, | |
+ &original_data_f54_ctr223, | |
+ sizeof(original_data_f54_ctr223)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read original 0d_voltaes in step 2\n", | |
+ __func__); | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ | |
+ /* step 3 */ | |
+ /* modify 0d voltages and force update */ | |
+ data = original_data_f54_ctr223 - ABS_0D_OPEN_FACTOR; | |
+ if (data < 0) | |
+ data = 0; | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ control.reg_223->address, | |
+ &data, | |
+ sizeof(data)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to modify 0d voltages to f54_ctrl_223 in step 3\n", | |
+ __func__); | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ retval = test_do_command(COMMAND_FORCE_UPDATE); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to do force update in step 3\n", | |
+ __func__); | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ msleep(100); | |
+ | |
+ /* step 4 */ | |
+ /* get second rt92 image */ | |
+ retval = test_sysfs_read_report_td43xx(dev, attr, "92", count, | |
+ false, false); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to read report 92 in step 4\n", | |
+ __func__); | |
+ g_flag_read_report_fail = 1; /* special code to indicate the failure of report reading */ | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ | |
+ secure_memcpy(p_report_data_8, tx_num * rx_num * 2, | |
+ f54->report_data, f54->report_size, f54->report_size); | |
+ | |
+ /* normalize the rt92 image with 16-bit */ | |
+ k = 0; | |
+ for (i = 0; i < tx_num; i++) { | |
+ for (j = 0; j < rx_num; j++) { | |
+ p_rt92_image_2[i * rx_num + j] = | |
+ (signed short)(p_report_data_8[k] & 0xff) | (signed short)(p_report_data_8[k + 1] << 8); | |
+ | |
+ k += 2; | |
+ } | |
+ } | |
+ | |
+ /* step 5 */ | |
+ /* restore original 0d voltages and force update */ | |
+ retval = synaptics_rmi4_reg_write(rmi4_data, | |
+ control.reg_223->address, | |
+ &original_data_f54_ctr223, | |
+ sizeof(original_data_f54_ctr223)); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to restore 0d voltages to f54_ctrl_223 in step 5\n", | |
+ __func__); | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ retval = test_do_command(COMMAND_FORCE_UPDATE); | |
+ if (retval < 0) { | |
+ dev_err(rmi4_data->pdev->dev.parent, | |
+ "%s: Failed to do force update in step 5\n", | |
+ __func__); | |
+ retval = -EIO; | |
+ goto exit; | |
+ } | |
+ | |
+ /* step 6 */ | |
+ /* calculation */ | |
+ for (i = 0; i < button_count; i++) { | |
+ g_abs_0d_open_data_output[i] = abs(p_rt92_image_1[(tx_num-1)*rx_num + i] - p_rt92_image_2[(tx_num-1)*rx_num + i]); | |
+ g_abs_0d_open_data_output[i] = (g_abs_0d_open_data_output[i] * 100)/p_rt92_image_1[(tx_num-1)*rx_num + i]; | |
+ printk(KERN_ERR "ref value is %d value1 is %d value2 is %d\n", g_abs_0d_open_data_output[i], p_rt92_image_1[(tx_num-1)*rx_num + i], p_rt92_image_2[(tx_num-1)*rx_num + i]); | |
+ if (g_abs_0d_open_data_output[i] < ABS_0D_OPEN_TEST_LIMIT) | |
+ g_abs_0d_open_data_output[i] = 1; /* fail */ | |
+ else | |
+ g_abs_0d_open_data_output[i] = 0; /* pass */ | |
+ } | |
+ | |
+exit: | |
+ /* release resource */ | |
+ kfree(p_rt92_image_1); | |
+ kfree(p_rt92_image_2); | |
+ kfree(p_report_data_8); | |
+ | |
+ pr_err("%s: resetting device\n", __func__); | |
+ rmi4_data->reset_device(rmi4_data, false); | |
+ pr_err("%s: done resetting device\n", __func__); | |
+ | |
+ return count; | |
+} | |
+ | |
+ | |
+static ssize_t test_sysfs_abs_0d_open_w_autoservo_show(struct device *dev, | |
+ struct device_attribute *attr, char *buf) | |
+{ | |
+ bool result = 0; | |
+ struct synaptics_rmi4_data *rmi4_data = f54->rmi4_data; | |
+ unsigned char button_count = rmi4_data->valid_button_count; | |
+ int i; | |
+ | |
+ if (!g_abs_0d_open_data_output) | |
+ return -EINVAL; | |
+ | |
+ /* check the special code if the failure of report image reading */ | |
+ if (1 == g_flag_read_report_fail) { | |
+ kfree(g_abs_0d_open_data_output); | |
+ g_abs_0d_open_data_output = NULL; | |
+ return snprintf(buf, PAGE_SIZE, "ERROR: Fail to read RT92 image\n"); | |
+ } | |
+ | |
+ button_count = BUTTON_COUNT; | |
+ | |
+ for (i = 0; i < button_count; i++) { | |
+ if (g_abs_0d_open_data_output[i] != 0) { | |
+ | |
+ result = 0; /* 0: fail */ | |
+ break; | |
+ /*dev_err(f54->rmi4_data->pdev->dev.parent, | |
+ "%s: Failed at 0D_button_%d\n", __func__, i); */ | |
+ } | |
+ } | |
+ | |
+ if (i == button_count) | |
+ result = 1; | |
+ | |
+ kfree(g_abs_0d_open_data_output); | |
+ g_abs_0d_open_data_output = NULL; | |
+ return snprintf(buf, PAGE_SIZE, "%s\n", (result == 1) ? "PASS" : "FAIL"); | |
+} | |
+ | |
static void test_report_work(struct work_struct *work) | |
{ | |
int retval; | |
@@ -4509,7 +4877,9 @@ static int test_set_controls(void) | |
if (f54->query_30.has_ctrl123) | |
reg_addr += CONTROL_123_SIZE; | |
- /* control 124 reserved */ | |
+ /* control 124 */ | |
+ if (f54->query_30.has_ctrl124) | |
+ reg_addr += CONTROL_124_SIZE; | |
/* control 125 */ | |
if (f54->query_32.has_ctrl125) | |
@@ -4523,7 +4893,21 @@ static int test_set_controls(void) | |
if (f54->query_32.has_ctrl127) | |
reg_addr += CONTROL_127_SIZE; | |
- /* controls 128 129 130 131 reserved */ | |
+ /* control 128 */ | |
+ if (f54->query_33.has_ctrl128) | |
+ reg_addr += CONTROL_128_SIZE; | |
+ | |
+ /* control 129 */ | |
+ if (f54->query_33.has_ctrl129) | |
+ reg_addr += CONTROL_129_SIZE; | |
+ | |
+ /* control 130 */ | |
+ if (f54->query_33.has_ctrl130) | |
+ reg_addr += CONTROL_130_SIZE; | |
+ | |
+ /* control 131 */ | |
+ if (f54->query_33.has_ctrl131) | |
+ reg_addr += CONTROL_131_SIZE; | |
/* control 132 */ | |
if (f54->query_33.has_ctrl132) | |
@@ -4537,7 +4921,13 @@ static int test_set_controls(void) | |
if (f54->query_33.has_ctrl134) | |
reg_addr += CONTROL_134_SIZE; | |
- /* controls 135 136 reserved */ | |
+ /* control 135 */ | |
+ if (f54->query_35.has_ctrl135) | |
+ reg_addr += CONTROL_135_SIZE; | |
+ | |
+ /* control 136 */ | |
+ if (f54->query_35.has_ctrl136) | |
+ reg_addr += CONTROL_136_SIZE; | |
/* control 137 */ | |
if (f54->query_35.has_ctrl137) | |
@@ -4555,7 +4945,9 @@ static int test_set_controls(void) | |
if (f54->query_35.has_ctrl140) | |
reg_addr += CONTROL_140_SIZE; | |
- /* control 141 reserved */ | |
+ /* control 141 */ | |
+ if (f54->query_36.has_ctrl141) | |
+ reg_addr += CONTROL_141_SIZE; | |
/* control 142 */ | |
if (f54->query_36.has_ctrl142) | |
@@ -4595,7 +4987,39 @@ static int test_set_controls(void) | |
reg_addr += CONTROL_149_SIZE; | |
} | |
- /* controls 150 to 162 reserved */ | |
+ /* control 150 */ | |
+ if (f54->query_38.has_ctrl150) | |
+ reg_addr += CONTROL_150_SIZE; | |
+ | |
+ /* control 151 */ | |
+ if (f54->query_38.has_ctrl151) | |
+ reg_addr += CONTROL_151_SIZE; | |
+ | |
+ /* control 152 */ | |
+ if (f54->query_38.has_ctrl152) | |
+ reg_addr += CONTROL_152_SIZE; | |
+ | |
+ /* control 153 */ | |
+ if (f54->query_38.has_ctrl153) | |
+ reg_addr += CONTROL_153_SIZE; | |
+ | |
+ /* control 154 */ | |
+ if (f54->query_39.has_ctrl154) | |
+ reg_addr += CONTROL_154_SIZE; | |
+ | |
+ /* control 155 */ | |
+ if (f54->query_39.has_ctrl155) | |
+ reg_addr += CONTROL_155_SIZE; | |
+ | |
+ /* control 156 */ | |
+ if (f54->query_39.has_ctrl156) | |
+ reg_addr += CONTROL_156_SIZE; | |
+ | |
+ /* controls 157 158 */ | |
+ if (f54->query_39.has_ctrl157_ctrl158) | |
+ reg_addr += CONTROL_157_158_SIZE; | |
+ | |
+ /* controls 159 to 162 reserved */ | |
/* control 163 */ | |
if (f54->query_40.has_ctrl163_query41) | |
@@ -4615,19 +5039,71 @@ static int test_set_controls(void) | |
if (f54->query_40.has_ctrl167) | |
reg_addr += CONTROL_167_SIZE; | |
- /* controls 168 to 175 reserved */ | |
+ /* control 168 */ | |
+ if (f54->query_40.has_ctrl168) | |
+ reg_addr += CONTROL_168_SIZE; | |
+ | |
+ /* control 169 */ | |
+ if (f54->query_40.has_ctrl169) | |
+ reg_addr += CONTROL_169_SIZE; | |
+ | |
+ /* control 170 reserved */ | |
+ | |
+ /* control 171 */ | |
+ if (f54->query_43.has_ctrl171) | |
+ reg_addr += CONTROL_171_SIZE; | |
+ | |
+ /* control 172 */ | |
+ if (f54->query_43.has_ctrl172_query44_query45) | |
+ reg_addr += CONTROL_172_SIZE; | |
+ | |
+ /* control 173 */ | |
+ if (f54->query_43.has_ctrl173) | |
+ reg_addr += CONTROL_173_SIZE; | |
+ | |
+ /* control 174 */ | |
+ if (f54->query_43.has_ctrl174) | |
+ reg_addr += CONTROL_174_SIZE; | |
+ | |
+ /* control 175 */ | |
+ if (f54->query_43.has_ctrl175) | |
+ reg_addr += CONTROL_175_SIZE; | |
/* control 176 */ | |
if (f54->query_46.has_ctrl176) | |
reg_addr += CONTROL_176_SIZE; | |
- /* controls 177 178 reserved */ | |
+ /* controls 177 178 */ | |
+ if (f54->query_46.has_ctrl177_ctrl178) | |
+ reg_addr += CONTROL_177_178_SIZE; | |
/* control 179 */ | |
if (f54->query_46.has_ctrl179) | |
reg_addr += CONTROL_179_SIZE; | |
- /* controls 180 to 187 reserved */ | |
+ /* controls 180 to 181 reserved */ | |
+ | |
+ /* control 182 */ | |
+ if (f54->query_47.has_ctrl182) | |
+ reg_addr += CONTROL_182_SIZE; | |
+ | |
+ /* control 183 */ | |
+ if (f54->query_47.has_ctrl183) | |
+ reg_addr += CONTROL_183_SIZE; | |
+ | |
+ /* control 184 reserved */ | |
+ | |
+ /* control 185 */ | |
+ if (f54->query_47.has_ctrl185) | |
+ reg_addr += CONTROL_185_SIZE; | |
+ | |
+ /* control 186 */ | |
+ if (f54->query_47.has_ctrl186) | |
+ reg_addr += CONTROL_186_SIZE; | |
+ | |
+ /* control 187 */ | |
+ if (f54->query_47.has_ctrl187) | |
+ reg_addr += CONTROL_187_SIZE; | |
/* control 188 */ | |
if (f54->query_49.has_ctrl188) { | |
@@ -4639,6 +5115,30 @@ static int test_set_controls(void) | |
reg_addr += CONTROL_188_SIZE; | |
} | |
+ /* control 189 - 195 reserved */ | |
+ | |
+ /* control 196 */ | |
+ if (f54->query_51.has_ctrl196) | |
+ reg_addr += CONTROL_196_SIZE; | |
+ | |
+ /* control 197 - 217 reserved */ | |
+ | |
+ /* control 218 reserved */ | |
+ if (f54->query_61.has_ctrl218) | |
+ reg_addr += CONTROL_218_SIZE; | |
+ | |
+ /* control 219 - 222 reserved */ | |
+ | |
+ /* control 223 reserved */ | |
+ if (f54->query_64.has_ctrl103_sub3) { | |
+ control->reg_223 = kzalloc(sizeof(*(control->reg_223)), | |
+ GFP_KERNEL); | |
+ if (!control->reg_223) | |
+ goto exit_no_mem; | |
+ control->reg_223->address = reg_addr; | |
+ reg_addr += CONTROL_223_SIZE; | |
+ } | |
+ | |
return 0; | |
exit_no_mem: | |
@@ -4917,7 +5417,8 @@ static int test_set_queries(void) | |
offset += 1; | |
} | |
- /* queries 44 45 reserved */ | |
+ if (f54->query_43.has_ctrl172_query44_query45) | |
+ offset += 2; | |
/* query 46 */ | |
if (f54->query_43.has_query46) { | |
@@ -5459,6 +5960,7 @@ static int test_f55_set_queries(void) | |
offset += 1; | |
f55->extended_amp = f55->query_33.has_extended_amp_pad; | |
+ f55->extended_amp_btn = f55->query_33.has_extended_amp_btn; | |
} | |
return 0; | |
@@ -5900,12 +6402,12 @@ static ssize_t syna_selftest_write(struct file *file, const char __user *buf, si | |
} | |
if (!strncmp(buf, "short", 5)) { | |
- if (f54->rmi4_data->chip_id == CHIP_ID_3330) | |
+ if (f54->rmi4_data->chip_id == f54->rmi4_data->hw_if->board_data->chip_3330 || f54->rmi4_data->chip_id == f54->rmi4_data->hw_if->board_data->chip_3331) | |
retval = short_test_333x(); | |
else | |
retval = short_test_4x22(); | |
} else if (!strncmp(buf, "open", 4)) { | |
- if (f54->rmi4_data->chip_id == CHIP_ID_3330) | |
+ if (f54->rmi4_data->chip_id == f54->rmi4_data->hw_if->board_data->chip_3330 || f54->rmi4_data->chip_id == f54->rmi4_data->hw_if->board_data->chip_3331) | |
retval = open_test_333x(); | |
else | |
retval = open_test_4x22(); | |
@@ -5931,6 +6433,71 @@ static const struct file_operations syna_selftest_ops = { | |
.release = syna_selftest_release, | |
}; | |
+static int syna_datadump_open(struct inode *inode, struct file *file) | |
+{ | |
+ f54->data = vmalloc(PAGE_SIZE); | |
+ | |
+ return 0; | |
+} | |
+ | |
+static ssize_t syna_datadump_read(struct file *file, char __user *buf, size_t count, loff_t *pos) | |
+{ | |
+ int retval; | |
+ int cnt; | |
+ | |
+ if (*pos != 0) | |
+ return 0; | |
+ | |
+ retval = test_sysfs_read_report_store(NULL, NULL, TEST_TYPE_02, strlen(TEST_TYPE_02)); | |
+ if (retval < 0) { | |
+ snprintf(buf, PAGE_SIZE, "data test error: start\n"); | |
+ goto out; | |
+ } | |
+ | |
+ retval = test_sysfs_read_report_show(NULL, NULL, f54->data); | |
+ if (retval < 0) { | |
+ snprintf(buf, PAGE_SIZE, "data test error: read\n"); | |
+ goto out; | |
+ } | |
+ | |
+ cnt = snprintf(buf, PAGE_SIZE, "data:\n%s\n", f54->data); | |
+ | |
+ memset(f54->data, 0, PAGE_SIZE); | |
+ | |
+ retval = test_sysfs_read_report_store(NULL, NULL, TEST_TYPE_03, strlen(TEST_TYPE_03)); | |
+ if (retval < 0) { | |
+ snprintf(buf, PAGE_SIZE, "data test error: start\n"); | |
+ goto out; | |
+ } | |
+ | |
+ retval = test_sysfs_read_report_show(NULL, NULL, f54->data); | |
+ if (retval < 0) { | |
+ snprintf(buf, PAGE_SIZE, "data test error: read\n"); | |
+ goto out; | |
+ } | |
+ | |
+ snprintf(buf + cnt, PAGE_SIZE, "raw data:\n%s\n", f54->data); | |
+ | |
+out: | |
+ | |
+ *pos += strlen(buf); | |
+ | |
+ return strlen(buf); | |
+} | |
+ | |
+static int syna_datadump_release(struct inode *inode, struct file *file) | |
+{ | |
+ vfree(f54->data); | |
+ | |
+ return 0; | |
+} | |
+ | |
+static const struct file_operations syna_datadump_ops = { | |
+ .open = syna_datadump_open, | |
+ .read = syna_datadump_read, | |
+ .release = syna_datadump_release, | |
+}; | |
+ | |
static int synaptics_rmi4_test_init(struct synaptics_rmi4_data *rmi4_data) | |
{ | |
int retval; | |
@@ -5986,6 +6553,9 @@ static int synaptics_rmi4_test_init(struct synaptics_rmi4_data *rmi4_data) | |
if (f55) | |
test_f55_init(rmi4_data); | |
+ if (rmi4_data->external_afe_buttons) | |
+ f54->tx_assigned++; | |
+ | |
retval = test_set_sysfs(); | |
if (retval < 0) { | |
dev_err(rmi4_data->pdev->dev.parent, | |
@@ -6010,6 +6580,7 @@ static int synaptics_rmi4_test_init(struct synaptics_rmi4_data *rmi4_data) | |
if (!proc_already) { | |
proc_already = true; | |
proc_create("tp_selftest", 0, NULL, &syna_selftest_ops); | |
+ proc_create("tp_data_dump", 0, NULL, &syna_datadump_ops); | |
} | |
return 0; | |
@@ -6069,7 +6640,7 @@ static void synaptics_rmi4_test_remove(struct synaptics_rmi4_data *rmi4_data) | |
f54 = NULL; | |
exit: | |
- complete(&test_remove_complete); | |
+ complete(&test_remove_complete_force); | |
return; | |
} | |
@@ -6123,6 +6694,9 @@ static void synaptics_rmi4_test_reset(struct synaptics_rmi4_data *rmi4_data) | |
if (f55) | |
test_f55_init(rmi4_data); | |
+ if (rmi4_data->external_afe_buttons) | |
+ f54->tx_assigned++; | |
+ | |
f54->status = STATUS_IDLE; | |
return; | |
@@ -6166,16 +6740,16 @@ static struct synaptics_rmi4_exp_fn test_module = { | |
static int __init rmi4_test_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&test_module, true); | |
+ synaptics_rmi4_new_function_force(&test_module, true); | |
return 0; | |
} | |
static void __exit rmi4_test_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&test_module, false); | |
+ synaptics_rmi4_new_function_force(&test_module, false); | |
- wait_for_completion(&test_remove_complete); | |
+ wait_for_completion(&test_remove_complete_force); | |
return; | |
} | |
diff --git a/synaptics_dsx_video.c b/synaptics_dsx_video.c | |
index 1539e61..b52b4be 100644 | |
--- a/synaptics_dsx_video.c | |
+++ b/synaptics_dsx_video.c | |
@@ -43,6 +43,10 @@ | |
#define SYSFS_FOLDER_NAME "video" | |
+/* | |
+#define RMI_DCS_SUSPEND_RESUME | |
+*/ | |
+ | |
static ssize_t video_sysfs_dcs_write_store(struct device *dev, | |
struct device_attribute *attr, const char *buf, size_t count); | |
@@ -391,14 +395,14 @@ static struct synaptics_rmi4_exp_fn video_module = { | |
static int __init rmi4_video_module_init(void) | |
{ | |
- synaptics_rmi4_new_function(&video_module, true); | |
+ synaptics_rmi4_new_function_force(&video_module, true); | |
return 0; | |
} | |
static void __exit rmi4_video_module_exit(void) | |
{ | |
- synaptics_rmi4_new_function(&video_module, false); | |
+ synaptics_rmi4_new_function_force(&video_module, false); | |
wait_for_completion(&video_remove_complete); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment