Commit 09182ed2 authored by Hans de Goede's avatar Hans de Goede Committed by Dmitry Torokhov

Input: goodix - add support for controllers without flash

Some Goodix touchscreen controllers, such as for example the GT912,
don't have flash-storage for their firmware.

These models require the OS to load the firmware at runtime, as well as
some other special handling. Add support for this to the goodix driver.

This patch was developed and tested on a Glavey TM800A550L tablet.

Note the "goodix,main-clk" and "firmware-name" device-properties used
by the new code are *not* documented in the
Documentation/devicetree/bindings/input/touchscreen/goodix.yaml
device-tree bindings for now.

Not documenting these is intentional. This is done because this code has
only been tested on x86/ACPI so far, where devicetree is not used.
Instead these properties are set through a software-fwnode attached to the
device by the drivers/platform/x86/touchscreen_dmi.c code. This means that
the use of this properties for now is purely a kernel-internal thing and
the name/working of the properties may still be changed for now.
Reviewed-by: default avatarBastien Nocera <hadess@hadess.net>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20210920150643.155872-7-hdegoede@redhat.comSigned-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 20e31722
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
wm97xx-ts-y := wm97xx-core.o wm97xx-ts-y := wm97xx-core.o
goodix_ts-y := goodix.o goodix_fwupload.o
obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o
obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o
...@@ -44,7 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o ...@@ -44,7 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o
obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL) += egalax_ts_serial.o
obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix_ts.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o
......
...@@ -326,6 +326,11 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) ...@@ -326,6 +326,11 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
return touch_num; return touch_num;
} }
if (data[0] == 0 && ts->firmware_name) {
if (goodix_handle_fw_request(ts))
return 0;
}
usleep_range(1000, 2000); /* Poll every 1 - 2 ms */ usleep_range(1000, 2000); /* Poll every 1 - 2 ms */
} while (time_before(jiffies, max_timeout)); } while (time_before(jiffies, max_timeout));
...@@ -940,12 +945,19 @@ static void goodix_read_config(struct goodix_ts_data *ts) ...@@ -940,12 +945,19 @@ static void goodix_read_config(struct goodix_ts_data *ts)
int x_max, y_max; int x_max, y_max;
int error; int error;
error = goodix_i2c_read(ts->client, ts->chip->config_addr, /*
ts->config, ts->chip->config_len); * On controllers where we need to upload the firmware
if (error) { * (controllers without flash) ts->config already has the config
ts->int_trigger_type = GOODIX_INT_TRIGGER; * at this point and the controller itself does not have it yet!
ts->max_touch_num = GOODIX_MAX_CONTACTS; */
return; if (!ts->firmware_name) {
error = goodix_i2c_read(ts->client, ts->chip->config_addr,
ts->config, ts->chip->config_len);
if (error) {
ts->int_trigger_type = GOODIX_INT_TRIGGER;
ts->max_touch_num = GOODIX_MAX_CONTACTS;
return;
}
} }
ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03; ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
...@@ -1139,7 +1151,16 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx) ...@@ -1139,7 +1151,16 @@ static void goodix_config_cb(const struct firmware *cfg, void *ctx)
struct goodix_ts_data *ts = ctx; struct goodix_ts_data *ts = ctx;
int error; int error;
if (cfg) { if (ts->firmware_name) {
if (!cfg)
goto err_release_cfg;
error = goodix_check_cfg(ts, cfg->data, cfg->size);
if (error)
goto err_release_cfg;
memcpy(ts->config, cfg->data, cfg->size);
} else if (cfg) {
/* send device configuration to the firmware */ /* send device configuration to the firmware */
error = goodix_send_cfg(ts, cfg->data, cfg->size); error = goodix_send_cfg(ts, cfg->data, cfg->size);
if (error) if (error)
...@@ -1231,6 +1252,10 @@ static int goodix_ts_probe(struct i2c_client *client, ...@@ -1231,6 +1252,10 @@ static int goodix_ts_probe(struct i2c_client *client,
return error; return error;
} }
error = goodix_firmware_check(ts);
if (error)
return error;
error = goodix_read_version(ts); error = goodix_read_version(ts);
if (error) if (error)
return error; return error;
...@@ -1297,6 +1322,9 @@ static int __maybe_unused goodix_suspend(struct device *dev) ...@@ -1297,6 +1322,9 @@ static int __maybe_unused goodix_suspend(struct device *dev)
/* Free IRQ as IRQ pin is used as output in the suspend sequence */ /* Free IRQ as IRQ pin is used as output in the suspend sequence */
goodix_free_irq(ts); goodix_free_irq(ts);
/* Save reference (calibration) info if necessary */
goodix_save_bak_ref(ts);
/* Output LOW on the INT pin for 5 ms */ /* Output LOW on the INT pin for 5 ms */
error = goodix_irq_direction_output(ts, 0); error = goodix_irq_direction_output(ts, 0);
if (error) { if (error) {
......
...@@ -10,13 +10,48 @@ ...@@ -10,13 +10,48 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
/* Register defines */ /* Register defines */
#define GOODIX_REG_MISCTL_DSP_CTL 0x4010
#define GOODIX_REG_MISCTL_SRAM_BANK 0x4048
#define GOODIX_REG_MISCTL_MEM_CD_EN 0x4049
#define GOODIX_REG_MISCTL_CACHE_EN 0x404B
#define GOODIX_REG_MISCTL_TMR0_EN 0x40B0
#define GOODIX_REG_MISCTL_SWRST 0x4180
#define GOODIX_REG_MISCTL_CPU_SWRST_PULSE 0x4184
#define GOODIX_REG_MISCTL_BOOTCTL 0x4190
#define GOODIX_REG_MISCTL_BOOT_OPT 0x4218
#define GOODIX_REG_MISCTL_BOOT_CTL 0x5094
#define GOODIX_REG_FW_SIG 0x8000
#define GOODIX_FW_SIG_LEN 10
#define GOODIX_REG_MAIN_CLK 0x8020
#define GOODIX_MAIN_CLK_LEN 6
#define GOODIX_REG_COMMAND 0x8040 #define GOODIX_REG_COMMAND 0x8040
#define GOODIX_CMD_SCREEN_OFF 0x05 #define GOODIX_CMD_SCREEN_OFF 0x05
#define GOODIX_REG_SW_WDT 0x8041
#define GOODIX_REG_REQUEST 0x8043
#define GOODIX_RQST_RESPONDED 0x00
#define GOODIX_RQST_CONFIG 0x01
#define GOODIX_RQST_BAK_REF 0x02
#define GOODIX_RQST_RESET 0x03
#define GOODIX_RQST_MAIN_CLOCK 0x04
/*
* Unknown request which gets send by the controller aprox.
* every 34 seconds once it is up and running.
*/
#define GOODIX_RQST_UNKNOWN 0x06
#define GOODIX_RQST_IDLE 0xFF
#define GOODIX_REG_STATUS 0x8044
#define GOODIX_GT1X_REG_CONFIG_DATA 0x8050 #define GOODIX_GT1X_REG_CONFIG_DATA 0x8050
#define GOODIX_GT9X_REG_CONFIG_DATA 0x8047 #define GOODIX_GT9X_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140 #define GOODIX_REG_ID 0x8140
#define GOODIX_READ_COOR_ADDR 0x814E #define GOODIX_READ_COOR_ADDR 0x814E
#define GOODIX_REG_BAK_REF 0x99D0
#define GOODIX_ID_MAX_LEN 4 #define GOODIX_ID_MAX_LEN 4
#define GOODIX_CONFIG_MAX_LENGTH 240 #define GOODIX_CONFIG_MAX_LENGTH 240
...@@ -42,6 +77,7 @@ struct goodix_ts_data { ...@@ -42,6 +77,7 @@ struct goodix_ts_data {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input_dev; struct input_dev *input_dev;
const struct goodix_chip_data *chip; const struct goodix_chip_data *chip;
const char *firmware_name;
struct touchscreen_properties prop; struct touchscreen_properties prop;
unsigned int max_touch_num; unsigned int max_touch_num;
unsigned int int_trigger_type; unsigned int int_trigger_type;
...@@ -62,6 +98,9 @@ struct goodix_ts_data { ...@@ -62,6 +98,9 @@ struct goodix_ts_data {
unsigned int contact_size; unsigned int contact_size;
u8 config[GOODIX_CONFIG_MAX_LENGTH]; u8 config[GOODIX_CONFIG_MAX_LENGTH];
unsigned short keymap[GOODIX_MAX_KEYS]; unsigned short keymap[GOODIX_MAX_KEYS];
u8 main_clk[GOODIX_MAIN_CLK_LEN];
int bak_ref_len;
u8 *bak_ref;
}; };
int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len); int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
...@@ -71,4 +110,8 @@ int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len); ...@@ -71,4 +110,8 @@ int goodix_send_cfg(struct goodix_ts_data *ts, const u8 *cfg, int len);
int goodix_int_sync(struct goodix_ts_data *ts); int goodix_int_sync(struct goodix_ts_data *ts);
int goodix_reset_no_int_sync(struct goodix_ts_data *ts); int goodix_reset_no_int_sync(struct goodix_ts_data *ts);
int goodix_firmware_check(struct goodix_ts_data *ts);
bool goodix_handle_fw_request(struct goodix_ts_data *ts);
void goodix_save_bak_ref(struct goodix_ts_data *ts);
#endif #endif
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment