123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061 |
- From 2a57236358e1eaf2bdb4f3f6a247d1a8e25afd8b Mon Sep 17 00:00:00 2001
- From: Dorian Stoll <dorian.stoll@tmsp.io>
- Date: Mon, 27 Jan 2020 21:16:20 +0100
- Subject: [PATCH 6/6] ipts
- ---
- drivers/input/touchscreen/Kconfig | 2 +
- drivers/input/touchscreen/Makefile | 1 +
- drivers/input/touchscreen/ipts/Kconfig | 16 ++
- drivers/input/touchscreen/ipts/Makefile | 17 ++
- drivers/input/touchscreen/ipts/context.h | 60 ++++
- drivers/input/touchscreen/ipts/control.c | 94 +++++++
- drivers/input/touchscreen/ipts/control.h | 18 ++
- drivers/input/touchscreen/ipts/data.c | 107 +++++++
- drivers/input/touchscreen/ipts/data.h | 12 +
- drivers/input/touchscreen/ipts/hid.c | 38 +++
- drivers/input/touchscreen/ipts/hid.h | 13 +
- drivers/input/touchscreen/ipts/init.c | 93 ++++++
- drivers/input/touchscreen/ipts/math.c | 103 +++++++
- drivers/input/touchscreen/ipts/math.h | 21 ++
- drivers/input/touchscreen/ipts/params.c | 27 ++
- drivers/input/touchscreen/ipts/params.h | 15 +
- drivers/input/touchscreen/ipts/payload.c | 52 ++++
- drivers/input/touchscreen/ipts/payload.h | 14 +
- .../touchscreen/ipts/protocol/commands.h | 61 ++++
- .../input/touchscreen/ipts/protocol/data.h | 30 ++
- .../input/touchscreen/ipts/protocol/events.h | 29 ++
- .../touchscreen/ipts/protocol/feedback.h | 30 ++
- .../input/touchscreen/ipts/protocol/payload.h | 47 ++++
- .../touchscreen/ipts/protocol/responses.h | 62 ++++
- .../touchscreen/ipts/protocol/singletouch.h | 17 ++
- .../input/touchscreen/ipts/protocol/stylus.h | 52 ++++
- drivers/input/touchscreen/ipts/receiver.c | 265 ++++++++++++++++++
- drivers/input/touchscreen/ipts/receiver.h | 8 +
- drivers/input/touchscreen/ipts/resources.c | 131 +++++++++
- drivers/input/touchscreen/ipts/resources.h | 11 +
- drivers/input/touchscreen/ipts/singletouch.c | 64 +++++
- drivers/input/touchscreen/ipts/singletouch.h | 14 +
- drivers/input/touchscreen/ipts/stylus.c | 179 ++++++++++++
- drivers/input/touchscreen/ipts/stylus.h | 14 +
- drivers/misc/mei/hw-me-regs.h | 2 +
- drivers/misc/mei/pci-me.c | 2 +
- include/uapi/linux/input.h | 1 +
- 37 files changed, 1722 insertions(+)
- create mode 100644 drivers/input/touchscreen/ipts/Kconfig
- create mode 100644 drivers/input/touchscreen/ipts/Makefile
- create mode 100644 drivers/input/touchscreen/ipts/context.h
- create mode 100644 drivers/input/touchscreen/ipts/control.c
- create mode 100644 drivers/input/touchscreen/ipts/control.h
- create mode 100644 drivers/input/touchscreen/ipts/data.c
- create mode 100644 drivers/input/touchscreen/ipts/data.h
- create mode 100644 drivers/input/touchscreen/ipts/hid.c
- create mode 100644 drivers/input/touchscreen/ipts/hid.h
- create mode 100644 drivers/input/touchscreen/ipts/init.c
- create mode 100644 drivers/input/touchscreen/ipts/math.c
- create mode 100644 drivers/input/touchscreen/ipts/math.h
- create mode 100644 drivers/input/touchscreen/ipts/params.c
- create mode 100644 drivers/input/touchscreen/ipts/params.h
- create mode 100644 drivers/input/touchscreen/ipts/payload.c
- create mode 100644 drivers/input/touchscreen/ipts/payload.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/commands.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/data.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/events.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/feedback.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/payload.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/responses.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/singletouch.h
- create mode 100644 drivers/input/touchscreen/ipts/protocol/stylus.h
- create mode 100644 drivers/input/touchscreen/ipts/receiver.c
- create mode 100644 drivers/input/touchscreen/ipts/receiver.h
- create mode 100644 drivers/input/touchscreen/ipts/resources.c
- create mode 100644 drivers/input/touchscreen/ipts/resources.h
- create mode 100644 drivers/input/touchscreen/ipts/singletouch.c
- create mode 100644 drivers/input/touchscreen/ipts/singletouch.h
- create mode 100644 drivers/input/touchscreen/ipts/stylus.c
- create mode 100644 drivers/input/touchscreen/ipts/stylus.h
- diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
- index 46ad9090493bb..c476a153b2f80 100644
- --- a/drivers/input/touchscreen/Kconfig
- +++ b/drivers/input/touchscreen/Kconfig
- @@ -1314,4 +1314,6 @@ config TOUCHSCREEN_IQS5XX
- To compile this driver as a module, choose M here: the
- module will be called iqs5xx.
-
- +source "drivers/input/touchscreen/ipts/Kconfig"
- +
- endif
- diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
- index 94c6162409b37..864f0e092ab67 100644
- --- a/drivers/input/touchscreen/Makefile
- +++ b/drivers/input/touchscreen/Makefile
- @@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
- obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
- obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
- obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
- +obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts/
- obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
- obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
- obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
- diff --git a/drivers/input/touchscreen/ipts/Kconfig b/drivers/input/touchscreen/ipts/Kconfig
- new file mode 100644
- index 0000000000000..d3c530dafa948
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/Kconfig
- @@ -0,0 +1,16 @@
- +# SPDX-License-Identifier: GPL-2.0-or-later
- +
- +config TOUCHSCREEN_IPTS
- + tristate "Intel Precise Touch & Stylus"
- + select INTEL_MEI
- + depends on X86
- + depends on PCI
- + depends on HID
- + help
- + Say Y here if your system has a touchscreen using Intels
- + Precise Touch & Stylus (IPTS).
- +
- + If unsure say N.
- +
- + To compile this driver as a module, choose M here: the
- + module will be called ipts.
- diff --git a/drivers/input/touchscreen/ipts/Makefile b/drivers/input/touchscreen/ipts/Makefile
- new file mode 100644
- index 0000000000000..0f7c904e73171
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/Makefile
- @@ -0,0 +1,17 @@
- +# SPDX-License-Identifier: GPL-2.0-or-later
- +#
- +# Makefile for the IPTS touchscreen driver
- +#
- +
- +obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts.o
- +ipts-objs := control.o
- +ipts-objs += data.o
- +ipts-objs += hid.o
- +ipts-objs += init.o
- +ipts-objs += math.o
- +ipts-objs += params.o
- +ipts-objs += payload.o
- +ipts-objs += receiver.o
- +ipts-objs += resources.o
- +ipts-objs += singletouch.o
- +ipts-objs += stylus.o
- diff --git a/drivers/input/touchscreen/ipts/context.h b/drivers/input/touchscreen/ipts/context.h
- new file mode 100644
- index 0000000000000..ab26552579a5c
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/context.h
- @@ -0,0 +1,60 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_CONTEXT_H_
- +#define _IPTS_CONTEXT_H_
- +
- +#include <linux/kthread.h>
- +#include <linux/input.h>
- +#include <linux/mei_cl_bus.h>
- +#include <linux/types.h>
- +
- +#include "protocol/commands.h"
- +#include "protocol/responses.h"
- +
- +/* HACK: Workaround for DKMS build without BUS_MEI patch */
- +#ifndef BUS_MEI
- +#define BUS_MEI 0x44
- +#endif
- +
- +/* IPTS driver states */
- +enum ipts_host_status {
- + IPTS_HOST_STATUS_NONE,
- + IPTS_HOST_STATUS_INIT,
- + IPTS_HOST_STATUS_RESOURCE_READY,
- + IPTS_HOST_STATUS_STARTED,
- + IPTS_HOST_STATUS_STOPPING,
- + IPTS_HOST_STATUS_RESTARTING
- +};
- +
- +struct ipts_buffer_info {
- + u8 *address;
- + dma_addr_t dma_address;
- +};
- +
- +struct ipts_context {
- + struct mei_cl_device *client_dev;
- + struct device *dev;
- + struct ipts_device_info device_info;
- +
- + enum ipts_host_status status;
- + enum ipts_sensor_mode mode;
- +
- + struct ipts_buffer_info data[16];
- + struct ipts_buffer_info feedback[16];
- + struct ipts_buffer_info doorbell;
- +
- + /*
- + * These buffers are not actually used by anything, but they need
- + * to be allocated and passed to the ME to get proper functionality.
- + */
- + struct ipts_buffer_info workqueue;
- + struct ipts_buffer_info host2me;
- +
- + struct task_struct *receiver_loop;
- + struct task_struct *data_loop;
- +
- + struct input_dev *stylus;
- + struct input_dev *singletouch;
- +};
- +
- +#endif /* _IPTS_CONTEXT_H_ */
- diff --git a/drivers/input/touchscreen/ipts/control.c b/drivers/input/touchscreen/ipts/control.c
- new file mode 100644
- index 0000000000000..9179eca665585
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/control.c
- @@ -0,0 +1,94 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/mei_cl_bus.h>
- +#include <linux/types.h>
- +
- +#include "context.h"
- +#include "data.h"
- +#include "params.h"
- +#include "protocol/commands.h"
- +#include "protocol/events.h"
- +#include "protocol/feedback.h"
- +#include "resources.h"
- +
- +int ipts_control_send(struct ipts_context *ipts,
- + u32 cmd, void *data, u32 size)
- +{
- + int ret;
- + struct ipts_command msg;
- +
- + memset(&msg, 0, sizeof(struct ipts_command));
- + msg.code = cmd;
- +
- + // Copy message payload
- + if (data && size > 0)
- + memcpy(&msg.data, data, size);
- +
- + ret = mei_cldev_send(ipts->client_dev, (u8 *)&msg,
- + sizeof(msg.code) + size);
- + if (ret < 0) {
- + dev_err(ipts->dev, "%s: error 0x%X:%d\n", __func__, cmd, ret);
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +int ipts_control_send_feedback(struct ipts_context *ipts,
- + u32 buffer, u32 transaction)
- +{
- + struct ipts_buffer_info feedback_buffer;
- + struct ipts_feedback *feedback;
- + struct ipts_feedback_cmd cmd;
- +
- + feedback_buffer = ipts->feedback[buffer];
- + feedback = (struct ipts_feedback *)feedback_buffer.address;
- +
- + memset(feedback, 0, sizeof(struct ipts_feedback));
- + memset(&cmd, 0, sizeof(struct ipts_feedback_cmd));
- +
- + feedback->type = IPTS_FEEDBACK_TYPE_NONE;
- + feedback->transaction = transaction;
- +
- + cmd.buffer = buffer;
- + cmd.transaction = transaction;
- +
- + return ipts_control_send(ipts, IPTS_CMD(FEEDBACK),
- + &cmd, sizeof(struct ipts_feedback_cmd));
- +}
- +
- +int ipts_control_start(struct ipts_context *ipts)
- +{
- + ipts->status = IPTS_HOST_STATUS_INIT;
- +
- + if (ipts_params.singletouch)
- + ipts->mode = IPTS_SENSOR_MODE_SINGLETOUCH;
- + else
- + ipts->mode = IPTS_SENSOR_MODE_MULTITOUCH;
- +
- + return ipts_control_send(ipts, IPTS_CMD(NOTIFY_DEV_READY), NULL, 0);
- +}
- +
- +void ipts_control_stop(struct ipts_context *ipts)
- +{
- + enum ipts_host_status old_status = ipts->status;
- +
- + ipts->status = IPTS_HOST_STATUS_STOPPING;
- + ipts_control_send(ipts, IPTS_CMD(QUIESCE_IO), NULL, 0);
- + ipts_control_send(ipts, IPTS_CMD(CLEAR_MEM_WINDOW), NULL, 0);
- +
- + if (old_status < IPTS_HOST_STATUS_RESOURCE_READY)
- + return;
- +
- + ipts_data_free(ipts);
- + ipts_resources_free(ipts);
- +}
- +
- +int ipts_control_restart(struct ipts_context *ipts)
- +{
- + dev_info(ipts->dev, "Restarting IPTS\n");
- + ipts_control_stop(ipts);
- +
- + ipts->status = IPTS_HOST_STATUS_RESTARTING;
- + return ipts_control_send(ipts, IPTS_CMD(QUIESCE_IO), NULL, 0);
- +}
- diff --git a/drivers/input/touchscreen/ipts/control.h b/drivers/input/touchscreen/ipts/control.h
- new file mode 100644
- index 0000000000000..e57609c85d62a
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/control.h
- @@ -0,0 +1,18 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_CONTROL_H_
- +#define _IPTS_CONTROL_H_
- +
- +#include <linux/types.h>
- +
- +#include "context.h"
- +
- +int ipts_control_start(struct ipts_context *ipts);
- +void ipts_control_stop(struct ipts_context *ipts);
- +int ipts_control_restart(struct ipts_context *ipts);
- +int ipts_control_send(struct ipts_context *ipts,
- + u32 cmd, void *data, u32 size);
- +int ipts_control_send_feedback(struct ipts_context *ipts,
- + u32 buffer, u32 transaction);
- +
- +#endif /* _IPTS_CONTROL_H_ */
- diff --git a/drivers/input/touchscreen/ipts/data.c b/drivers/input/touchscreen/ipts/data.c
- new file mode 100644
- index 0000000000000..568bf04f7ea6e
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/data.c
- @@ -0,0 +1,107 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/delay.h>
- +#include <linux/kthread.h>
- +#include <linux/ktime.h>
- +
- +#include "context.h"
- +#include "control.h"
- +#include "hid.h"
- +#include "params.h"
- +#include "payload.h"
- +#include "protocol/data.h"
- +
- +static void ipts_data_handle_input(struct ipts_context *ipts, int buffer_id)
- +{
- + struct ipts_buffer_info buffer;
- + struct ipts_data *data;
- +
- + buffer = ipts->data[buffer_id];
- + data = (struct ipts_data *)buffer.address;
- +
- + if (ipts_params.debug) {
- + dev_info(ipts->dev, "Buffer %d\n", buffer_id);
- + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 32, 1,
- + data->data, data->size, false);
- + }
- +
- + switch (data->type) {
- + case IPTS_DATA_TYPE_PAYLOAD:
- + ipts_payload_handle_input(ipts, data);
- + break;
- + case IPTS_DATA_TYPE_HID_REPORT:
- + ipts_hid_handle_input(ipts, data);
- + break;
- + default:
- + // ignore
- + break;
- + }
- +
- + ipts_control_send_feedback(ipts, buffer_id, data->transaction);
- +}
- +
- +int ipts_data_loop(void *data)
- +{
- + time64_t timeout;
- + u32 doorbell;
- + u32 last_doorbell;
- + struct ipts_context *ipts;
- +
- + timeout = ktime_get_seconds() + 5;
- + ipts = (struct ipts_context *)data;
- + last_doorbell = 0;
- + doorbell = 0;
- +
- + dev_info(ipts->dev, "Starting data loop\n");
- +
- + while (!kthread_should_stop()) {
- + if (ipts->status != IPTS_HOST_STATUS_STARTED) {
- + msleep(1000);
- + continue;
- + }
- +
- + // IPTS will increment the doorbell after if filled up one of
- + // the data buffers. If the doorbell didn't change, there is
- + // no work for us to do. Otherwise, the value of the doorbell
- + // will stand for the *next* buffer thats going to be filled.
- + doorbell = *(u32 *)ipts->doorbell.address;
- + if (doorbell == last_doorbell)
- + goto sleep;
- +
- + timeout = ktime_get_seconds() + 5;
- +
- + while (last_doorbell != doorbell) {
- + ipts_data_handle_input(ipts, last_doorbell % 16);
- + last_doorbell++;
- + }
- +sleep:
- + if (timeout > ktime_get_seconds())
- + usleep_range(5000, 30000);
- + else
- + msleep(200);
- + }
- +
- + dev_info(ipts->dev, "Stopping data loop\n");
- + return 0;
- +}
- +
- +int ipts_data_init(struct ipts_context *ipts)
- +{
- + int ret;
- +
- + ret = ipts_payload_init(ipts);
- + if (ret)
- + return ret;
- +
- + ret = ipts_hid_init(ipts);
- + if (ret)
- + return ret;
- +
- + return 0;
- +}
- +
- +void ipts_data_free(struct ipts_context *ipts)
- +{
- + ipts_payload_free(ipts);
- + ipts_hid_free(ipts);
- +}
- diff --git a/drivers/input/touchscreen/ipts/data.h b/drivers/input/touchscreen/ipts/data.h
- new file mode 100644
- index 0000000000000..fa72c1be09451
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/data.h
- @@ -0,0 +1,12 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_DATA_H_
- +#define _IPTS_DATA_H_
- +
- +#include "context.h"
- +
- +int ipts_data_loop(void *data);
- +int ipts_data_init(struct ipts_context *ipts);
- +void ipts_data_free(struct ipts_context *ipts);
- +
- +#endif /* _IPTS_DATA_H_ */
- diff --git a/drivers/input/touchscreen/ipts/hid.c b/drivers/input/touchscreen/ipts/hid.c
- new file mode 100644
- index 0000000000000..2642990b8c420
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/hid.c
- @@ -0,0 +1,38 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include "context.h"
- +#include "protocol/data.h"
- +#include "singletouch.h"
- +
- +/*
- + * IPTS on surface gen7 appears to make heavy use of HID reports, unlike
- + * previous generations. This file can be used to implement handling for
- + * them in the future, seperated from the actual singletouch implementation.
- + */
- +
- +void ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data)
- +{
- + // Make sure that we only handle singletouch inputs
- + // 40 is the report id of the singletouch device in the generic
- + // IPTS HID descriptor.
- + if (data->data[0] != 0x40)
- + return;
- +
- + ipts_singletouch_handle_input(ipts, data);
- +}
- +
- +int ipts_hid_init(struct ipts_context *ipts)
- +{
- + int ret;
- +
- + ret = ipts_singletouch_init(ipts);
- + if (ret)
- + return ret;
- +
- + return 0;
- +}
- +
- +void ipts_hid_free(struct ipts_context *ipts)
- +{
- + ipts_singletouch_free(ipts);
- +}
- diff --git a/drivers/input/touchscreen/ipts/hid.h b/drivers/input/touchscreen/ipts/hid.h
- new file mode 100644
- index 0000000000000..e6cf38fce4541
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/hid.h
- @@ -0,0 +1,13 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_HID_H_
- +#define _IPTS_HID_H_
- +
- +#include "context.h"
- +#include "protocol/data.h"
- +
- +int ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data);
- +int ipts_hid_init(struct ipts_context *ipts);
- +void ipts_hid_free(struct ipts_context *ipts);
- +
- +#endif /* _IPTS_HID_H_ */
- diff --git a/drivers/input/touchscreen/ipts/init.c b/drivers/input/touchscreen/ipts/init.c
- new file mode 100644
- index 0000000000000..fb70d55542af7
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/init.c
- @@ -0,0 +1,93 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/dma-mapping.h>
- +#include <linux/mei_cl_bus.h>
- +#include <linux/module.h>
- +#include <linux/mod_devicetable.h>
- +
- +#include "context.h"
- +#include "control.h"
- +#include "data.h"
- +#include "receiver.h"
- +
- +#define IPTS_MEI_UUID UUID_LE(0x3e8d0870, 0x271a, 0x4208, \
- + 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04)
- +
- +static int ipts_init_probe(struct mei_cl_device *cldev,
- + const struct mei_cl_device_id *id)
- +{
- + int ret;
- + struct ipts_context *ipts = NULL;
- +
- + dev_info(&cldev->dev, "Probing IPTS\n");
- +
- + // Setup the DMA bit mask
- + if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) {
- + dev_info(&cldev->dev, "IPTS using DMA_BIT_MASK(64)\n");
- + } else if (!dma_coerce_mask_and_coherent(&cldev->dev,
- + DMA_BIT_MASK(32))) {
- + dev_info(&cldev->dev, "IPTS using DMA_BIT_MASK(32)");
- + } else {
- + dev_err(&cldev->dev, "No suitable DMA for IPTS available\n");
- + return -EFAULT;
- + }
- +
- + ret = mei_cldev_enable(cldev);
- + if (ret) {
- + dev_err(&cldev->dev, "Cannot enable IPTS\n");
- + return ret;
- + }
- +
- + ipts = devm_kzalloc(&cldev->dev,
- + sizeof(struct ipts_context), GFP_KERNEL);
- + if (!ipts) {
- + mei_cldev_disable(cldev);
- + return -ENOMEM;
- + }
- +
- + ipts->client_dev = cldev;
- + ipts->dev = &cldev->dev;
- +
- + mei_cldev_set_drvdata(cldev, ipts);
- +
- + ipts->receiver_loop = kthread_run(ipts_receiver_loop, (void *)ipts,
- + "ipts_receiver_loop");
- + ipts->data_loop = kthread_run(ipts_data_loop, (void *)ipts,
- + "ipts_data_loop");
- +
- + ipts_control_start(ipts);
- +
- + return 0;
- +}
- +
- +static int ipts_init_remove(struct mei_cl_device *cldev)
- +{
- + struct ipts_context *ipts = mei_cldev_get_drvdata(cldev);
- +
- + dev_info(&cldev->dev, "Removing IPTS\n");
- +
- + ipts_control_stop(ipts);
- + mei_cldev_disable(cldev);
- + kthread_stop(ipts->receiver_loop);
- + kthread_stop(ipts->data_loop);
- +
- + return 0;
- +}
- +
- +static struct mei_cl_device_id ipts_device_id[] = {
- + { "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY },
- + { },
- +};
- +MODULE_DEVICE_TABLE(mei, ipts_device_id);
- +
- +static struct mei_cl_driver ipts_driver = {
- + .id_table = ipts_device_id,
- + .name = "ipts",
- + .probe = ipts_init_probe,
- + .remove = ipts_init_remove,
- +};
- +module_mei_cl_driver(ipts_driver);
- +
- +MODULE_DESCRIPTION("IPTS touchscreen driver");
- +MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
- +MODULE_LICENSE("GPL");
- diff --git a/drivers/input/touchscreen/ipts/math.c b/drivers/input/touchscreen/ipts/math.c
- new file mode 100644
- index 0000000000000..df956e5447e03
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/math.c
- @@ -0,0 +1,103 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/bug.h>
- +#include <linux/fixp-arith.h>
- +#include <linux/kernel.h>
- +#include <linux/types.h>
- +
- +#include "math.h"
- +
- +/*
- + * Since we need to work with [-pi, pi] in the atan functions, we are using
- + * 1 << 29 for the fixed point numbers. This allows us to store numbers from
- + * [-4, 4] using the full 32-bit signed integer range.
- + *
- + * Some constants such as PI have been already converted to the fixed-point
- + * format and are defined in math.h.
- + */
- +
- +static inline s32 ipts_math_mul(s32 x, s32 y)
- +{
- + return (x * (s64)y) >> 29;
- +}
- +
- +static inline s32 ipts_math_div(s32 x, s32 y)
- +{
- + return ((s64)x << 29) / y;
- +}
- +
- +static s32 ipts_math_atan(s32 x)
- +{
- + s32 tmp = ipts_math_mul(
- + ipts_math_mul(x, (abs(x) - (1 << 29))),
- + CONST_2447 + ipts_math_mul(CONST_0663, abs(x)));
- +
- + return ipts_math_mul(M_PI_4, x) - tmp;
- +}
- +
- +static s32 ipts_math_atan2(s32 y, s32 x)
- +{
- + s32 z;
- +
- + if (x != 0) {
- + if (abs(x) > abs(y)) {
- + z = ipts_math_div(y, x);
- + if (x > 0)
- + return ipts_math_atan(z);
- + else if (y >= 0)
- + return ipts_math_atan(z) + M_PI;
- + else
- + return ipts_math_atan(z) - M_PI;
- + } else {
- + z = ipts_math_div(x, y);
- + if (y > 0)
- + return -ipts_math_atan(z) + M_PI_2;
- + else
- + return -ipts_math_atan(z) - M_PI_2;
- + }
- + } else {
- + if (y > 0)
- + return M_PI_2;
- + else if (y < 0)
- + return -M_PI_2;
- + }
- +
- + return 0;
- +}
- +
- +/*
- + * Convert altitude in range [0, 9000] and azimuth in range [0, 36000]
- + * to x-/y-tilt in range [-9000, 9000]. Azimuth is given
- + * counter-clockwise, starting with zero on the right. Altitude is
- + * given as angle between stylus and z-axis.
- + */
- +void ipts_math_altitude_azimuth_to_tilt(s32 alt, s32 azm, s32 *tx, s32 *ty)
- +{
- + s32 sin_alt, cos_alt;
- + s32 sin_azm, cos_azm;
- +
- + s32 x, y, z;
- + s64 atan_x, atan_y;
- +
- + sin_alt = fixp_sin32_rad(alt, 36000) / 4;
- + sin_azm = fixp_sin32_rad(azm, 36000) / 4;
- +
- + cos_alt = fixp_cos32_rad(alt, 36000) / 4;
- + cos_azm = fixp_cos32_rad(azm, 36000) / 4;
- +
- + x = ipts_math_mul(sin_alt, cos_azm);
- + y = ipts_math_mul(sin_alt, sin_azm);
- + z = cos_alt;
- +
- + atan_x = ipts_math_atan2(z, x);
- + atan_y = ipts_math_atan2(z, y);
- +
- + atan_x = atan_x * 4500;
- + atan_y = atan_y * 4500;
- +
- + atan_x = atan_x / M_PI_4;
- + atan_y = atan_y / M_PI_4;
- +
- + *tx = 9000 - atan_x;
- + *ty = atan_y - 9000;
- +}
- diff --git a/drivers/input/touchscreen/ipts/math.h b/drivers/input/touchscreen/ipts/math.h
- new file mode 100644
- index 0000000000000..8e831074ab60b
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/math.h
- @@ -0,0 +1,21 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_MATH_H_
- +#define _IPTS_MATH_H_
- +
- +#include <linux/types.h>
- +
- +/* (pi / 4) * (1 << 29) */
- +#define M_PI_4 421657428
- +#define M_PI_2 (M_PI_4 * 2)
- +#define M_PI (M_PI_2 * 2)
- +
- +/* 0.2447 * (1 << 29) */
- +#define CONST_2447 131372312
- +
- +/* 0.0663 * (1 << 29) */
- +#define CONST_0663 35594541
- +
- +void ipts_math_altitude_azimuth_to_tilt(s32 alt, s32 azm, s32 *tx, s32 *ty);
- +
- +#endif /* _IPTS_MATH_H_ */
- diff --git a/drivers/input/touchscreen/ipts/params.c b/drivers/input/touchscreen/ipts/params.c
- new file mode 100644
- index 0000000000000..6aa3f5cf1d762
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/params.c
- @@ -0,0 +1,27 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/moduleparam.h>
- +#include <linux/types.h>
- +
- +#include "params.h"
- +
- +#define IPTS_PARM(NAME, TYPE, PERM) \
- + module_param_named(NAME, ipts_params.NAME, TYPE, PERM)
- +
- +#define IPTS_DESC(NAME, DESC) \
- + MODULE_PARM_DESC(NAME, DESC)
- +
- +struct ipts_modparams ipts_params = {
- + .debug = false,
- + .singletouch = false,
- +};
- +
- +IPTS_PARM(debug, bool, 0400);
- +IPTS_DESC(debug,
- + "Enable additional debugging in the IPTS driver (default: false)"
- +);
- +
- +IPTS_PARM(singletouch, bool, 0400);
- +IPTS_DESC(singletouch,
- + "Enables IPTS single touch mode (disables stylus) (default: false)"
- +);
- diff --git a/drivers/input/touchscreen/ipts/params.h b/drivers/input/touchscreen/ipts/params.h
- new file mode 100644
- index 0000000000000..1f992a3bc21b9
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/params.h
- @@ -0,0 +1,15 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PARAMS_H_
- +#define _IPTS_PARAMS_H_
- +
- +#include <linux/types.h>
- +
- +struct ipts_modparams {
- + bool debug;
- + bool singletouch;
- +};
- +
- +extern struct ipts_modparams ipts_params;
- +
- +#endif /* _IPTS_PARAMS_H_ */
- diff --git a/drivers/input/touchscreen/ipts/payload.c b/drivers/input/touchscreen/ipts/payload.c
- new file mode 100644
- index 0000000000000..3572ddc0f2fb0
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/payload.c
- @@ -0,0 +1,52 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/types.h>
- +
- +#include "context.h"
- +#include "protocol/data.h"
- +#include "protocol/payload.h"
- +#include "stylus.h"
- +
- +void ipts_payload_handle_input(struct ipts_context *ipts,
- + struct ipts_data *data)
- +{
- + u32 i, offset;
- + struct ipts_payload *payload;
- + struct ipts_payload_frame *frame;
- +
- + payload = (struct ipts_payload *)data->data;
- + offset = 0;
- +
- + for (i = 0; i < payload->num_frames; i++) {
- + frame = (struct ipts_payload_frame *)&payload->data[offset];
- + offset += sizeof(struct ipts_payload_frame) + frame->size;
- +
- + switch (frame->type) {
- + case IPTS_PAYLOAD_FRAME_TYPE_STYLUS:
- + ipts_stylus_handle_input(ipts, frame);
- + break;
- + case IPTS_PAYLOAD_FRAME_TYPE_TOUCH:
- + // ignored (for the moment)
- + break;
- + default:
- + // ignored
- + break;
- + }
- + }
- +}
- +
- +int ipts_payload_init(struct ipts_context *ipts)
- +{
- + int ret;
- +
- + ret = ipts_stylus_init(ipts);
- + if (ret)
- + return ret;
- +
- + return 0;
- +}
- +
- +void ipts_payload_free(struct ipts_context *ipts)
- +{
- + ipts_stylus_free(ipts);
- +}
- diff --git a/drivers/input/touchscreen/ipts/payload.h b/drivers/input/touchscreen/ipts/payload.h
- new file mode 100644
- index 0000000000000..6603714bb6fd0
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/payload.h
- @@ -0,0 +1,14 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PAYLOAD_H_
- +#define _IPTS_PAYLOAD_H_
- +
- +#include "context.h"
- +#include "protocol/data.h"
- +
- +void ipts_payload_handle_input(struct ipts_context *ipts,
- + struct ipts_data *data);
- +int ipts_payload_init(struct ipts_context *ipts);
- +void ipts_payload_free(struct ipts_context *ipts);
- +
- +#endif /* _IPTS_PAYLOAD_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/commands.h b/drivers/input/touchscreen/ipts/protocol/commands.h
- new file mode 100644
- index 0000000000000..2533dfb13584a
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/commands.h
- @@ -0,0 +1,61 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_COMMANDS_H_
- +#define _IPTS_PROTOCOL_COMMANDS_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +enum ipts_sensor_mode {
- + IPTS_SENSOR_MODE_SINGLETOUCH = 0,
- + IPTS_SENSOR_MODE_MULTITOUCH,
- + IPTS_SENSOR_MODE_MAX
- +};
- +
- +struct ipts_set_mode_cmd {
- + u32 sensor_mode;
- + u8 reserved[12];
- +} __packed;
- +
- +struct ipts_set_mem_window_cmd {
- + u32 data_buffer_addr_lower[16];
- + u32 data_buffer_addr_upper[16];
- + u32 workqueue_addr_lower;
- + u32 workqueue_addr_upper;
- + u32 doorbell_addr_lower;
- + u32 doorbell_addr_upper;
- + u32 feedback_buffer_addr_lower[16];
- + u32 feedback_buffer_addr_upper[16];
- + u32 host2me_addr_lower;
- + u32 host2me_addr_upper;
- + u32 host2me_size;
- + u8 reserved1;
- + u8 workqueue_item_size;
- + u16 workqueue_size;
- + u8 reserved[32];
- +} __packed;
- +
- +struct ipts_feedback_cmd {
- + u32 buffer;
- + u32 transaction;
- + u8 reserved[8];
- +} __packed;
- +
- +/*
- + * Commands are sent from the host to the ME
- + */
- +struct ipts_command {
- + u32 code;
- + union {
- + struct ipts_set_mode_cmd set_mode;
- + struct ipts_set_mem_window_cmd set_mem_window;
- + struct ipts_feedback_cmd feedback;
- + } data;
- +} __packed;
- +
- +static_assert(sizeof(struct ipts_set_mode_cmd) == 16);
- +static_assert(sizeof(struct ipts_set_mem_window_cmd) == 320);
- +static_assert(sizeof(struct ipts_feedback_cmd) == 16);
- +static_assert(sizeof(struct ipts_command) == 324);
- +
- +#endif /* _IPTS_PROTOCOL_COMMANDS_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/data.h b/drivers/input/touchscreen/ipts/protocol/data.h
- new file mode 100644
- index 0000000000000..148e0545b2e4e
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/data.h
- @@ -0,0 +1,30 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_DATA_H_
- +#define _IPTS_PROTOCOL_DATA_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +enum ipts_data_type {
- + IPTS_DATA_TYPE_PAYLOAD = 0,
- + IPTS_DATA_TYPE_ERROR,
- + IPTS_DATA_TYPE_VENDOR_DATA,
- + IPTS_DATA_TYPE_HID_REPORT,
- + IPTS_DATA_TYPE_GET_FEATURES,
- + IPTS_DATA_TYPE_MAX
- +};
- +
- +struct ipts_data {
- + u32 type;
- + u32 size;
- + u32 buffer;
- + u8 reserved1[20];
- + u8 transaction;
- + u8 reserved2[31];
- + u8 data[];
- +} __packed;
- +
- +static_assert(sizeof(struct ipts_data) == 64);
- +
- +#endif /* _IPTS_PROTOCOL_DATA_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/events.h b/drivers/input/touchscreen/ipts/protocol/events.h
- new file mode 100644
- index 0000000000000..f8b771f90bd2b
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/events.h
- @@ -0,0 +1,29 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_EVENTS_H_
- +#define _IPTS_PROTOCOL_EVENTS_H_
- +
- +/*
- + * Helpers to avoid writing boilerplate code.
- + * The response to a command code is always 0x8000000x, where x
- + * is the command code itself. Instead of writing two definitions,
- + * we use macros to calculate the value on the fly instead.
- + */
- +#define IPTS_CMD(COMMAND) IPTS_EVT_##COMMAND
- +#define IPTS_RSP(COMMAND) (IPTS_CMD(COMMAND) + 0x80000000)
- +
- +/*
- + * Events that can be sent to / received from the ME
- + */
- +enum ipts_evt_code {
- + IPTS_EVT_GET_DEVICE_INFO = 1,
- + IPTS_EVT_SET_MODE,
- + IPTS_EVT_SET_MEM_WINDOW,
- + IPTS_EVT_QUIESCE_IO,
- + IPTS_EVT_READY_FOR_DATA,
- + IPTS_EVT_FEEDBACK,
- + IPTS_EVT_CLEAR_MEM_WINDOW,
- + IPTS_EVT_NOTIFY_DEV_READY,
- +};
- +
- +#endif /* _IPTS_PROTOCOL_EVENTS_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/feedback.h b/drivers/input/touchscreen/ipts/protocol/feedback.h
- new file mode 100644
- index 0000000000000..8b3d8b689ee83
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/feedback.h
- @@ -0,0 +1,30 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_FEEDBACK_H_
- +#define _IPTS_PROTOCOL_FEEDBACK_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +enum ipts_feedback_type {
- + IPTS_FEEDBACK_TYPE_NONE = 0,
- + IPTS_FEEDBACK_TYPE_SOFT_RESET,
- + IPTS_FEEDBACK_TYPE_GOTO_ARMED,
- + IPTS_FEEDBACK_TYPE_GOTO_SENSING,
- + IPTS_FEEDBACK_TYPE_GOTO_SLEEP,
- + IPTS_FEEDBACK_TYPE_GOTO_DOZE,
- + IPTS_FEEDBACK_TYPE_HARD_RESET,
- + IPTS_FEEDBACK_TYPE_MAX
- +};
- +
- +struct ipts_feedback {
- + u32 type;
- + u32 size;
- + u32 transaction;
- + u8 reserved[52];
- + u8 data[];
- +} __packed;
- +
- +static_assert(sizeof(struct ipts_feedback) == 64);
- +
- +#endif /* _IPTS_PROTOCOL_FEEDBACK_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/payload.h b/drivers/input/touchscreen/ipts/protocol/payload.h
- new file mode 100644
- index 0000000000000..f46da4ea81f25
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/payload.h
- @@ -0,0 +1,47 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_PAYLOAD_H_
- +#define _IPTS_PROTOCOL_PAYLOAD_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +enum ipts_payload_frame_type {
- + IPTS_PAYLOAD_FRAME_TYPE_STYLUS = 6,
- + IPTS_PAYLOAD_FRAME_TYPE_TOUCH = 8,
- +};
- +
- +enum ipts_report_type {
- + IPTS_REPORT_TYPE_TOUCH_HEATMAP_DIM = 0x0403,
- + IPTS_REPORT_TYPE_TOUCH_HEATMAP = 0x0425,
- + IPTS_REPORT_TYPE_STYLUS_NO_TILT = 0x0410,
- + IPTS_REPORT_TYPE_STYLUS_TILT = 0x0461,
- + IPTS_REPORT_TYPE_STYLUS_TILT_SERIAL = 0x0460,
- +};
- +
- +struct ipts_payload {
- + u32 counter;
- + u32 num_frames;
- + u8 reserved[4];
- + u8 data[];
- +} __packed;
- +
- +struct ipts_payload_frame {
- + u16 index;
- + u16 type;
- + u32 size;
- + u8 reserved[8];
- + u8 data[];
- +} __packed;
- +
- +struct ipts_report {
- + u16 type;
- + u16 size;
- + u8 data[];
- +} __packed;
- +
- +static_assert(sizeof(struct ipts_payload) == 12);
- +static_assert(sizeof(struct ipts_payload_frame) == 16);
- +static_assert(sizeof(struct ipts_report) == 4);
- +
- +#endif /* _IPTS_PROTOCOL_PAYLOAD_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/responses.h b/drivers/input/touchscreen/ipts/protocol/responses.h
- new file mode 100644
- index 0000000000000..27153d82a5d67
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/responses.h
- @@ -0,0 +1,62 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_RESPONSES_H_
- +#define _IPTS_PROTOCOL_RESPONSES_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +enum ipts_me_status {
- + IPTS_ME_STATUS_SUCCESS = 0,
- + IPTS_ME_STATUS_INVALID_PARAMS,
- + IPTS_ME_STATUS_ACCESS_DENIED,
- + IPTS_ME_STATUS_CMD_SIZE_ERROR,
- + IPTS_ME_STATUS_NOT_READY,
- + IPTS_ME_STATUS_REQUEST_OUTSTANDING,
- + IPTS_ME_STATUS_NO_SENSOR_FOUND,
- + IPTS_ME_STATUS_OUT_OF_MEMORY,
- + IPTS_ME_STATUS_INTERNAL_ERROR,
- + IPTS_ME_STATUS_SENSOR_DISABLED,
- + IPTS_ME_STATUS_COMPAT_CHECK_FAIL,
- + IPTS_ME_STATUS_SENSOR_EXPECTED_RESET,
- + IPTS_ME_STATUS_SENSOR_UNEXPECTED_RESET,
- + IPTS_ME_STATUS_RESET_FAILED,
- + IPTS_ME_STATUS_TIMEOUT,
- + IPTS_ME_STATUS_TEST_MODE_FAIL,
- + IPTS_ME_STATUS_SENSOR_FAIL_FATAL,
- + IPTS_ME_STATUS_SENSOR_FAIL_NONFATAL,
- + IPTS_ME_STATUS_INVALID_DEVICE_CAPS,
- + IPTS_ME_STATUS_QUIESCE_IO_IN_PROGRESS,
- + IPTS_ME_STATUS_MAX
- +};
- +
- +struct ipts_device_info {
- + u16 vendor_id;
- + u16 device_id;
- + u32 hw_rev;
- + u32 fw_rev;
- +
- + /* Required size of one touch data buffer */
- + u32 data_size;
- +
- + /* Required size of one feedback buffer */
- + u32 feedback_size;
- + u8 reserved[24];
- +} __packed;
- +
- +/*
- + * Responses are sent from the ME to the host, reacting to a command.
- + */
- +struct ipts_response {
- + u32 code;
- + u32 status;
- + union {
- + struct ipts_device_info device_info;
- + u8 reserved[80];
- + } data;
- +} __packed;
- +
- +static_assert(sizeof(struct ipts_device_info) == 44);
- +static_assert(sizeof(struct ipts_response) == 88);
- +
- +#endif /* _IPTS_PROTOCOL_RESPONSES_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/singletouch.h b/drivers/input/touchscreen/ipts/protocol/singletouch.h
- new file mode 100644
- index 0000000000000..bf9912ee2af4c
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/singletouch.h
- @@ -0,0 +1,17 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_SINGLETOUCH_H_
- +#define _IPTS_PROTOCOL_SINGLETOUCH_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +struct ipts_singletouch_report {
- + u8 touch;
- + u16 x;
- + u16 y;
- +} __packed;
- +
- +static_assert(sizeof(struct ipts_singletouch_report) == 5);
- +
- +#endif /* _IPTS_PROTOCOL_SINGLETOUCH_H_ */
- diff --git a/drivers/input/touchscreen/ipts/protocol/stylus.h b/drivers/input/touchscreen/ipts/protocol/stylus.h
- new file mode 100644
- index 0000000000000..950850b365dfb
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/protocol/stylus.h
- @@ -0,0 +1,52 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_PROTOCOL_STYLUS_H_
- +#define _IPTS_PROTOCOL_STYLUS_H_
- +
- +#include <linux/build_bug.h>
- +#include <linux/types.h>
- +
- +struct ipts_stylus_report {
- + u8 reports;
- + u8 reserved[3];
- + u8 data[];
- +} __packed;
- +
- +struct ipts_stylus_report_serial {
- + u8 reports;
- + u8 reserved[3];
- + u32 serial;
- + u8 data[];
- +} __packed;
- +
- +struct ipts_stylus_report_data {
- + u16 timestamp;
- + u16 mode;
- + u16 x;
- + u16 y;
- + u16 pressure;
- + u16 altitude;
- + u16 azimuth;
- + u16 reserved;
- +} __packed;
- +
- +struct ipts_stylus_report_data_no_tilt {
- + u8 reserved[4];
- + u8 mode;
- + u16 x;
- + u16 y;
- + u16 pressure;
- + u8 reserved2;
- +} __packed;
- +
- +#define IPTS_STYLUS_REPORT_MODE_PROX BIT(0)
- +#define IPTS_STYLUS_REPORT_MODE_TOUCH BIT(1)
- +#define IPTS_STYLUS_REPORT_MODE_BUTTON BIT(2)
- +#define IPTS_STYLUS_REPORT_MODE_ERASER BIT(3)
- +
- +static_assert(sizeof(struct ipts_stylus_report) == 4);
- +static_assert(sizeof(struct ipts_stylus_report_serial) == 8);
- +static_assert(sizeof(struct ipts_stylus_report_data) == 16);
- +static_assert(sizeof(struct ipts_stylus_report_data_no_tilt) == 12);
- +
- +#endif /* _IPTS_PAYLOAD_STYLUS_H_ */
- diff --git a/drivers/input/touchscreen/ipts/receiver.c b/drivers/input/touchscreen/ipts/receiver.c
- new file mode 100644
- index 0000000000000..ab283994c3e5f
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/receiver.c
- @@ -0,0 +1,265 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/types.h>
- +
- +#include "context.h"
- +#include "control.h"
- +#include "data.h"
- +#include "protocol/commands.h"
- +#include "protocol/events.h"
- +#include "protocol/responses.h"
- +#include "resources.h"
- +
- +static void ipts_receiver_handle_notify_dev_ready(struct ipts_context *ipts,
- + struct ipts_response *msg, int *cmd_status)
- +{
- + if (msg->status != IPTS_ME_STATUS_SENSOR_FAIL_NONFATAL &&
- + msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + *cmd_status = ipts_control_send(ipts,
- + IPTS_CMD(GET_DEVICE_INFO), NULL, 0);
- +}
- +
- +static void ipts_receiver_handle_get_device_info(struct ipts_context *ipts,
- + struct ipts_response *msg, int *cmd_status)
- +{
- + if (msg->status != IPTS_ME_STATUS_COMPAT_CHECK_FAIL &&
- + msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + memcpy(&ipts->device_info, &msg->data.device_info,
- + sizeof(struct ipts_device_info));
- +
- + dev_info(ipts->dev, "Device %04hX:%04hX found\n",
- + ipts->device_info.vendor_id,
- + ipts->device_info.device_id);
- +
- + if (ipts_data_init(ipts))
- + return;
- +
- + *cmd_status = ipts_control_send(ipts,
- + IPTS_CMD(CLEAR_MEM_WINDOW), NULL, 0);
- +}
- +
- +static void ipts_receiver_handle_clear_mem_window(struct ipts_context *ipts,
- + struct ipts_response *msg, int *cmd_status, int *ret)
- +{
- + struct ipts_set_mode_cmd sensor_mode_cmd;
- +
- + if (msg->status != IPTS_ME_STATUS_TIMEOUT &&
- + msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + if (ipts->status == IPTS_HOST_STATUS_STOPPING)
- + return;
- +
- + if (ipts_resources_init(ipts))
- + return;
- +
- + ipts->status = IPTS_HOST_STATUS_RESOURCE_READY;
- +
- + memset(&sensor_mode_cmd, 0, sizeof(struct ipts_set_mode_cmd));
- + sensor_mode_cmd.sensor_mode = ipts->mode;
- +
- + *cmd_status = ipts_control_send(ipts, IPTS_CMD(SET_MODE),
- + &sensor_mode_cmd, sizeof(struct ipts_set_mode_cmd));
- +}
- +
- +static void ipts_receiver_handle_set_mode(struct ipts_context *ipts,
- + struct ipts_response *msg, int *cmd_status)
- +{
- + int i;
- + struct ipts_set_mem_window_cmd cmd;
- +
- + if (msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + memset(&cmd, 0, sizeof(struct ipts_set_mem_window_cmd));
- +
- + for (i = 0; i < 16; i++) {
- + cmd.data_buffer_addr_lower[i] =
- + lower_32_bits(ipts->data[i].dma_address);
- +
- + cmd.data_buffer_addr_upper[i] =
- + upper_32_bits(ipts->data[i].dma_address);
- +
- + cmd.feedback_buffer_addr_lower[i] =
- + lower_32_bits(ipts->feedback[i].dma_address);
- +
- + cmd.feedback_buffer_addr_upper[i] =
- + upper_32_bits(ipts->feedback[i].dma_address);
- + }
- +
- + cmd.workqueue_addr_lower = lower_32_bits(ipts->workqueue.dma_address);
- + cmd.workqueue_addr_upper = upper_32_bits(ipts->workqueue.dma_address);
- +
- + cmd.doorbell_addr_lower = lower_32_bits(ipts->doorbell.dma_address);
- + cmd.doorbell_addr_upper = upper_32_bits(ipts->doorbell.dma_address);
- +
- + cmd.host2me_addr_lower = lower_32_bits(ipts->host2me.dma_address);
- + cmd.host2me_addr_upper = upper_32_bits(ipts->host2me.dma_address);
- + cmd.host2me_size = ipts->device_info.data_size;
- +
- + cmd.workqueue_size = 8192;
- + cmd.workqueue_item_size = 16;
- +
- + *cmd_status = ipts_control_send(ipts, IPTS_CMD(SET_MEM_WINDOW),
- + &cmd, sizeof(struct ipts_set_mem_window_cmd));
- +}
- +
- +static void ipts_receiver_handle_set_mem_window(struct ipts_context *ipts,
- + struct ipts_response *msg, int *cmd_status)
- +{
- + if (msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + *cmd_status = ipts_control_send(ipts,
- + IPTS_CMD(READY_FOR_DATA), NULL, 0);
- + if (*cmd_status)
- + return;
- +
- + ipts->status = IPTS_HOST_STATUS_STARTED;
- + dev_info(ipts->dev, "IPTS enabled\n");
- +}
- +
- +static void ipts_receiver_handle_ready_for_data(struct ipts_context *ipts,
- + struct ipts_response *msg)
- +{
- + if (msg->status != IPTS_ME_STATUS_SENSOR_DISABLED &&
- + msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + if (ipts->mode != IPTS_SENSOR_MODE_SINGLETOUCH ||
- + ipts->status != IPTS_HOST_STATUS_STARTED)
- + return;
- +
- + // Increment the doorbell manually to indicate that a new buffer
- + // filled with touch data is available
- + *((u32 *)ipts->doorbell.address) += 1;
- +}
- +
- +static void ipts_recever_handle_feedback(struct ipts_context *ipts,
- + struct ipts_response *msg, int *cmd_status)
- +{
- + if (msg->status != IPTS_ME_STATUS_COMPAT_CHECK_FAIL &&
- + msg->status != IPTS_ME_STATUS_SUCCESS &&
- + msg->status != IPTS_ME_STATUS_INVALID_PARAMS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + if (ipts->mode != IPTS_SENSOR_MODE_SINGLETOUCH)
- + return;
- +
- + *cmd_status = ipts_control_send(ipts,
- + IPTS_CMD(READY_FOR_DATA), NULL, 0);
- +}
- +
- +static void ipts_receiver_handle_quiesce_io(struct ipts_context *ipts,
- + struct ipts_response *msg)
- +{
- + if (msg->status != IPTS_ME_STATUS_SUCCESS) {
- + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
- + msg->code, msg->status);
- + return;
- + }
- +
- + if (ipts->status == IPTS_HOST_STATUS_RESTARTING)
- + ipts_control_start(ipts);
- +}
- +
- +
- +static int ipts_receiver_handle_response(struct ipts_context *ipts,
- + struct ipts_response *msg, u32 msg_len)
- +{
- + int cmd_status = 0;
- + int ret = 0;
- +
- + switch (msg->code) {
- + case IPTS_RSP(NOTIFY_DEV_READY):
- + ipts_receiver_handle_notify_dev_ready(ipts, msg, &cmd_status);
- + break;
- + case IPTS_RSP(GET_DEVICE_INFO):
- + ipts_receiver_handle_get_device_info(ipts, msg, &cmd_status);
- + break;
- + case IPTS_RSP(CLEAR_MEM_WINDOW):
- + ipts_receiver_handle_clear_mem_window(ipts, msg,
- + &cmd_status, &ret);
- + break;
- + case IPTS_RSP(SET_MODE):
- + ipts_receiver_handle_set_mode(ipts, msg, &cmd_status);
- + break;
- + case IPTS_RSP(SET_MEM_WINDOW):
- + ipts_receiver_handle_set_mem_window(ipts, msg, &cmd_status);
- + break;
- + case IPTS_RSP(READY_FOR_DATA):
- + ipts_receiver_handle_ready_for_data(ipts, msg);
- + break;
- + case IPTS_RSP(FEEDBACK):
- + ipts_recever_handle_feedback(ipts, msg, &cmd_status);
- + break;
- + case IPTS_RSP(QUIESCE_IO):
- + ipts_receiver_handle_quiesce_io(ipts, msg);
- + break;
- + }
- +
- + if (ipts->status == IPTS_HOST_STATUS_STOPPING)
- + return 0;
- +
- + if (msg->status == IPTS_ME_STATUS_SENSOR_UNEXPECTED_RESET ||
- + msg->status == IPTS_ME_STATUS_SENSOR_EXPECTED_RESET) {
- + dev_info(ipts->dev, "Sensor has been reset: %d\n", msg->status);
- + ipts_control_restart(ipts);
- + }
- +
- + if (cmd_status)
- + ipts_control_restart(ipts);
- +
- + return ret;
- +}
- +
- +int ipts_receiver_loop(void *data)
- +{
- + u32 msg_len;
- + struct ipts_context *ipts;
- + struct ipts_response msg;
- +
- + ipts = (struct ipts_context *)data;
- + dev_info(ipts->dev, "Starting receive loop\n");
- +
- + while (!kthread_should_stop()) {
- + msg_len = mei_cldev_recv(ipts->client_dev,
- + (u8 *)&msg, sizeof(msg));
- +
- + if (msg_len <= 0) {
- + dev_err(ipts->dev, "Error in reading ME message\n");
- + continue;
- + }
- +
- + if (ipts_receiver_handle_response(ipts, &msg, msg_len))
- + dev_err(ipts->dev, "Error in handling ME message\n");
- + }
- +
- + dev_info(ipts->dev, "Stopping receive loop\n");
- + return 0;
- +}
- diff --git a/drivers/input/touchscreen/ipts/receiver.h b/drivers/input/touchscreen/ipts/receiver.h
- new file mode 100644
- index 0000000000000..4d413a0abd4c5
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/receiver.h
- @@ -0,0 +1,8 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_RECEIVER_H_
- +#define _IPTS_RECEIVER_H_
- +
- +int ipts_receiver_loop(void *data);
- +
- +#endif /* _IPTS_RECEIVER_H_ */
- diff --git a/drivers/input/touchscreen/ipts/resources.c b/drivers/input/touchscreen/ipts/resources.c
- new file mode 100644
- index 0000000000000..704db9fdd3fd4
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/resources.c
- @@ -0,0 +1,131 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/dma-mapping.h>
- +
- +#include "context.h"
- +
- +void ipts_resources_free(struct ipts_context *ipts)
- +{
- + int i;
- + u32 touch_buffer_size;
- + u32 feedback_buffer_size;
- + struct ipts_buffer_info *buffers;
- +
- + touch_buffer_size = ipts->device_info.data_size;
- + feedback_buffer_size = ipts->device_info.feedback_size;
- +
- + buffers = ipts->data;
- + for (i = 0; i < 16; i++) {
- + if (!buffers[i].address)
- + continue;
- +
- + dmam_free_coherent(ipts->dev, touch_buffer_size,
- + buffers[i].address, buffers[i].dma_address);
- +
- + buffers[i].address = 0;
- + buffers[i].dma_address = 0;
- + }
- +
- + buffers = ipts->feedback;
- + for (i = 0; i < 16; i++) {
- + if (!buffers[i].address)
- + continue;
- +
- + dmam_free_coherent(ipts->dev, feedback_buffer_size,
- + buffers[i].address, buffers[i].dma_address);
- +
- + buffers[i].address = 0;
- + buffers[i].dma_address = 0;
- + }
- +
- + if (ipts->doorbell.address) {
- + dmam_free_coherent(ipts->dev, sizeof(u32),
- + ipts->doorbell.address,
- + ipts->doorbell.dma_address);
- +
- + ipts->doorbell.address = 0;
- + ipts->doorbell.dma_address = 0;
- + }
- +
- + if (ipts->workqueue.address) {
- + dmam_free_coherent(ipts->dev, sizeof(u32),
- + ipts->workqueue.address,
- + ipts->workqueue.dma_address);
- +
- + ipts->workqueue.address = 0;
- + ipts->workqueue.dma_address = 0;
- + }
- +
- + if (ipts->host2me.address) {
- + dmam_free_coherent(ipts->dev, touch_buffer_size,
- + ipts->host2me.address,
- + ipts->host2me.dma_address);
- +
- + ipts->host2me.address = 0;
- + ipts->host2me.dma_address = 0;
- + }
- +}
- +
- +int ipts_resources_init(struct ipts_context *ipts)
- +{
- + int i;
- + u32 touch_buffer_size;
- + u32 feedback_buffer_size;
- + struct ipts_buffer_info *buffers;
- +
- + touch_buffer_size = ipts->device_info.data_size;
- + feedback_buffer_size = ipts->device_info.feedback_size;
- +
- + buffers = ipts->data;
- + for (i = 0; i < 16; i++) {
- + buffers[i].address = dmam_alloc_coherent(ipts->dev,
- + touch_buffer_size,
- + &buffers[i].dma_address,
- + GFP_ATOMIC | __GFP_ZERO);
- +
- + if (!buffers[i].address)
- + goto release_resources;
- + }
- +
- + buffers = ipts->feedback;
- + for (i = 0; i < 16; i++) {
- + buffers[i].address = dmam_alloc_coherent(ipts->dev,
- + feedback_buffer_size,
- + &buffers[i].dma_address,
- + GFP_ATOMIC | __GFP_ZERO);
- +
- + if (!buffers[i].address)
- + goto release_resources;
- + }
- +
- + ipts->doorbell.address = dmam_alloc_coherent(ipts->dev,
- + sizeof(u32),
- + &ipts->doorbell.dma_address,
- + GFP_ATOMIC | __GFP_ZERO);
- +
- + if (!ipts->doorbell.address)
- + goto release_resources;
- +
- + ipts->workqueue.address = dmam_alloc_coherent(ipts->dev,
- + sizeof(u32),
- + &ipts->workqueue.dma_address,
- + GFP_ATOMIC | __GFP_ZERO);
- +
- + if (!ipts->workqueue.address)
- + goto release_resources;
- +
- + ipts->host2me.address = dmam_alloc_coherent(ipts->dev,
- + touch_buffer_size,
- + &ipts->host2me.dma_address,
- + GFP_ATOMIC | __GFP_ZERO);
- +
- + if (!ipts->workqueue.address)
- + goto release_resources;
- +
- + return 0;
- +
- +release_resources:
- +
- + ipts_resources_free(ipts);
- + return -ENOMEM;
- +}
- diff --git a/drivers/input/touchscreen/ipts/resources.h b/drivers/input/touchscreen/ipts/resources.h
- new file mode 100644
- index 0000000000000..cf9807b0dbe62
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/resources.h
- @@ -0,0 +1,11 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_RESOURCES_H_
- +#define _IPTS_RESOURCES_H_
- +
- +#include "context.h"
- +
- +int ipts_resources_init(struct ipts_context *ipts);
- +void ipts_resources_free(struct ipts_context *ipts);
- +
- +#endif /* _IPTS_RESOURCES_H_ */
- diff --git a/drivers/input/touchscreen/ipts/singletouch.c b/drivers/input/touchscreen/ipts/singletouch.c
- new file mode 100644
- index 0000000000000..ed70444f649c4
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/singletouch.c
- @@ -0,0 +1,64 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/input.h>
- +#include <linux/kernel.h>
- +
- +#include "context.h"
- +#include "protocol/data.h"
- +#include "protocol/singletouch.h"
- +
- +void ipts_singletouch_handle_input(struct ipts_context *ipts,
- + struct ipts_data *data)
- +{
- + struct ipts_singletouch_report *report =
- + (struct ipts_singletouch_report *)&data->data[1];
- +
- + input_report_key(ipts->singletouch, BTN_TOUCH, report->touch);
- + input_report_abs(ipts->singletouch, ABS_X, report->x);
- + input_report_abs(ipts->singletouch, ABS_Y, report->y);
- +
- + input_sync(ipts->singletouch);
- +}
- +
- +int ipts_singletouch_init(struct ipts_context *ipts)
- +{
- + int ret;
- +
- + ipts->singletouch = input_allocate_device();
- + if (!ipts->singletouch)
- + return -ENOMEM;
- +
- + __set_bit(INPUT_PROP_DIRECT, ipts->singletouch->propbit);
- +
- + input_set_capability(ipts->singletouch, EV_KEY, BTN_TOUCH);
- + input_set_abs_params(ipts->singletouch, ABS_X, 0, 32767, 0, 0);
- + input_abs_set_res(ipts->singletouch, ABS_X, 112);
- + input_set_abs_params(ipts->singletouch, ABS_Y, 0, 32767, 0, 0);
- + input_abs_set_res(ipts->singletouch, ABS_Y, 199);
- +
- + ipts->singletouch->id.bustype = BUS_MEI;
- + ipts->singletouch->id.vendor = ipts->device_info.vendor_id;
- + ipts->singletouch->id.product = ipts->device_info.device_id;
- + ipts->singletouch->id.version = ipts->device_info.fw_rev;
- +
- + ipts->singletouch->phys = "heci3";
- + ipts->singletouch->name = "IPTS Singletouch";
- +
- + ret = input_register_device(ipts->singletouch);
- + if (ret) {
- + dev_err(ipts->dev, "Cannot register input device: %s (%d)\n",
- + ipts->singletouch->name, ret);
- + input_free_device(ipts->singletouch);
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +void ipts_singletouch_free(struct ipts_context *ipts)
- +{
- + if (!ipts->singletouch)
- + return;
- +
- + input_unregister_device(ipts->singletouch);
- +}
- diff --git a/drivers/input/touchscreen/ipts/singletouch.h b/drivers/input/touchscreen/ipts/singletouch.h
- new file mode 100644
- index 0000000000000..53207497a4628
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/singletouch.h
- @@ -0,0 +1,14 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_SINGLETOUCH_H_
- +#define _IPTS_SINGLETOUCH_H_
- +
- +#include "context.h"
- +#include "protocol/data.h"
- +
- +void ipts_singletouch_handle_input(struct ipts_context *ipts,
- + struct ipts_data *data);
- +int ipts_singletouch_init(struct ipts_context *ipts);
- +void ipts_singletouch_free(struct ipts_context *ipts);
- +
- +#endif /* _IPTS_SINGLETOUCH_H_ */
- diff --git a/drivers/input/touchscreen/ipts/stylus.c b/drivers/input/touchscreen/ipts/stylus.c
- new file mode 100644
- index 0000000000000..987fa756fec33
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/stylus.c
- @@ -0,0 +1,179 @@
- +// SPDX-License-Identifier: GPL-2.0-or-later
- +
- +#include <linux/input.h>
- +#include <linux/kernel.h>
- +
- +#include "context.h"
- +#include "math.h"
- +#include "protocol/payload.h"
- +#include "protocol/stylus.h"
- +
- +static void ipts_stylus_handle_stylus_data(struct ipts_context *ipts,
- + struct ipts_stylus_report_data *data)
- +{
- + u8 prox = data->mode & IPTS_STYLUS_REPORT_MODE_PROX;
- + u8 touch = data->mode & IPTS_STYLUS_REPORT_MODE_TOUCH;
- + u8 button = data->mode & IPTS_STYLUS_REPORT_MODE_BUTTON;
- + u8 rubber = data->mode & IPTS_STYLUS_REPORT_MODE_ERASER;
- +
- + s32 tx = 0;
- + s32 ty = 0;
- +
- + // avoid unnecessary computations
- + // altitude is zero if stylus does not touch the screen
- + if (data->altitude) {
- + ipts_math_altitude_azimuth_to_tilt(data->altitude,
- + data->azimuth, &tx, &ty);
- + }
- +
- + input_report_key(ipts->stylus, BTN_TOUCH, touch);
- + input_report_key(ipts->stylus, BTN_TOOL_PEN, prox && !rubber);
- + input_report_key(ipts->stylus, BTN_TOOL_RUBBER, prox && rubber);
- + input_report_key(ipts->stylus, BTN_STYLUS, button);
- +
- + input_report_abs(ipts->stylus, ABS_X, data->x);
- + input_report_abs(ipts->stylus, ABS_Y, data->y);
- + input_report_abs(ipts->stylus, ABS_PRESSURE, data->pressure);
- + input_report_abs(ipts->stylus, ABS_MISC, data->timestamp);
- +
- + input_report_abs(ipts->stylus, ABS_TILT_X, tx);
- + input_report_abs(ipts->stylus, ABS_TILT_Y, ty);
- +
- + input_sync(ipts->stylus);
- +}
- +
- +static void ipts_stylus_handle_report_tilt_serial(struct ipts_context *ipts,
- + struct ipts_report *report)
- +{
- + int i;
- + struct ipts_stylus_report_serial *stylus_report;
- + struct ipts_stylus_report_data *data;
- +
- + stylus_report = (struct ipts_stylus_report_serial *)report->data;
- + data = (struct ipts_stylus_report_data *)stylus_report->data;
- +
- + // TODO: Track serial number and support multiple styli
- +
- + for (i = 0; i < stylus_report->reports; i++)
- + ipts_stylus_handle_stylus_data(ipts, &data[i]);
- +}
- +
- +static void ipts_stylus_handle_report_tilt(struct ipts_context *ipts,
- + struct ipts_report *report)
- +{
- + int i;
- + struct ipts_stylus_report *stylus_report;
- + struct ipts_stylus_report_data *data;
- +
- + stylus_report = (struct ipts_stylus_report *)report->data;
- + data = (struct ipts_stylus_report_data *)stylus_report->data;
- +
- + for (i = 0; i < stylus_report->reports; i++)
- + ipts_stylus_handle_stylus_data(ipts, &data[i]);
- +}
- +
- +static void ipts_stylus_handle_report_no_tilt(struct ipts_context *ipts,
- + struct ipts_report *report)
- +{
- + int i;
- + struct ipts_stylus_report_serial *stylus_report;
- + struct ipts_stylus_report_data_no_tilt *data;
- + struct ipts_stylus_report_data new_data;
- +
- + stylus_report = (struct ipts_stylus_report_serial *)report->data;
- + data = (struct ipts_stylus_report_data_no_tilt *)stylus_report->data;
- +
- + for (i = 0; i < stylus_report->reports; i++) {
- + new_data.mode = data[i].mode;
- + new_data.x = data[i].x;
- + new_data.y = data[i].y;
- + new_data.pressure = data[i].pressure * 4;
- + new_data.altitude = 0;
- + new_data.azimuth = 0;
- + new_data.timestamp = 0;
- +
- + ipts_stylus_handle_stylus_data(ipts, &new_data);
- + }
- +}
- +
- +void ipts_stylus_handle_input(struct ipts_context *ipts,
- + struct ipts_payload_frame *frame)
- +{
- + int size;
- + struct ipts_report *report;
- +
- + size = 0;
- +
- + while (size < frame->size) {
- + report = (struct ipts_report *)&frame->data[size];
- + size += sizeof(struct ipts_report) + report->size;
- +
- + switch (report->type) {
- + case IPTS_REPORT_TYPE_STYLUS_NO_TILT:
- + ipts_stylus_handle_report_no_tilt(ipts, report);
- + break;
- + case IPTS_REPORT_TYPE_STYLUS_TILT:
- + ipts_stylus_handle_report_tilt(ipts, report);
- + break;
- + case IPTS_REPORT_TYPE_STYLUS_TILT_SERIAL:
- + ipts_stylus_handle_report_tilt_serial(ipts, report);
- + break;
- + default:
- + // ignored
- + break;
- + }
- + }
- +}
- +
- +int ipts_stylus_init(struct ipts_context *ipts)
- +{
- + int ret;
- +
- + ipts->stylus = input_allocate_device();
- + if (!ipts->stylus)
- + return -ENOMEM;
- +
- + __set_bit(INPUT_PROP_DIRECT, ipts->stylus->propbit);
- + __set_bit(INPUT_PROP_POINTER, ipts->stylus->propbit);
- +
- + input_set_abs_params(ipts->stylus, ABS_X, 0, 9600, 0, 0);
- + input_abs_set_res(ipts->stylus, ABS_X, 34);
- + input_set_abs_params(ipts->stylus, ABS_Y, 0, 7200, 0, 0);
- + input_abs_set_res(ipts->stylus, ABS_Y, 38);
- + input_set_abs_params(ipts->stylus, ABS_PRESSURE, 0, 4096, 0, 0);
- + input_set_abs_params(ipts->stylus, ABS_TILT_X, -9000, 9000, 0, 0);
- + input_abs_set_res(ipts->stylus, ABS_TILT_X, 5730);
- + input_set_abs_params(ipts->stylus, ABS_TILT_Y, -9000, 9000, 0, 0);
- + input_abs_set_res(ipts->stylus, ABS_TILT_Y, 5730);
- + input_set_abs_params(ipts->stylus, ABS_MISC, 0, 65535, 0, 0);
- + input_set_capability(ipts->stylus, EV_KEY, BTN_TOUCH);
- + input_set_capability(ipts->stylus, EV_KEY, BTN_STYLUS);
- + input_set_capability(ipts->stylus, EV_KEY, BTN_TOOL_PEN);
- + input_set_capability(ipts->stylus, EV_KEY, BTN_TOOL_RUBBER);
- +
- + ipts->stylus->id.bustype = BUS_MEI;
- + ipts->stylus->id.vendor = ipts->device_info.vendor_id;
- + ipts->stylus->id.product = ipts->device_info.device_id;
- + ipts->stylus->id.version = ipts->device_info.fw_rev;
- +
- + ipts->stylus->phys = "heci3";
- + ipts->stylus->name = "IPTS Stylus";
- +
- + ret = input_register_device(ipts->stylus);
- + if (ret) {
- + dev_err(ipts->dev, "Cannot register input device: %s (%d)\n",
- + ipts->stylus->name, ret);
- + input_free_device(ipts->stylus);
- + return ret;
- + }
- +
- + return 0;
- +}
- +
- +void ipts_stylus_free(struct ipts_context *ipts)
- +{
- + if (!ipts->stylus)
- + return;
- +
- + input_unregister_device(ipts->stylus);
- +}
- diff --git a/drivers/input/touchscreen/ipts/stylus.h b/drivers/input/touchscreen/ipts/stylus.h
- new file mode 100644
- index 0000000000000..5b93add1eac2d
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/stylus.h
- @@ -0,0 +1,14 @@
- +/* SPDX-License-Identifier: GPL-2.0-or-later */
- +
- +#ifndef _IPTS_STYLUS_H_
- +#define _IPTS_STYLUS_H_
- +
- +#include "context.h"
- +#include "protocol/payload.h"
- +
- +void ipts_stylus_handle_input(struct ipts_context *ipts,
- + struct ipts_payload_frame *frame);
- +int ipts_stylus_init(struct ipts_context *ipts);
- +void ipts_stylus_free(struct ipts_context *ipts);
- +
- +#endif /* _IPTS_STYLUS_H_ */
- diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
- index e56dc47540646..a55c61c89238a 100644
- --- a/drivers/misc/mei/hw-me-regs.h
- +++ b/drivers/misc/mei/hw-me-regs.h
- @@ -59,6 +59,7 @@
-
- #define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */
- #define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */
- +#define MEI_DEV_ID_SPT_4 0x9D3E /* Sunrise Point 4 (iTouch) */
- #define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */
- #define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */
-
- @@ -90,6 +91,7 @@
- #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */
-
- #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
- +#define MEI_DEV_ID_ICP_LP_4 0x34E4 /* Ice Lake Point LP 4 (iTouch) */
-
- #define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */
-
- diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
- index 75ab2ffbf235f..78790904d77cb 100644
- --- a/drivers/misc/mei/pci-me.c
- +++ b/drivers/misc/mei/pci-me.c
- @@ -77,6 +77,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
-
- {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)},
- + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
- {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)},
- @@ -103,6 +104,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
- {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)},
-
- {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
- + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_4, MEI_ME_PCH12_CFG)},
-
- {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)},
-
- diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
- index 9a61c28ed3ae4..47fc20975245d 100644
- --- a/include/uapi/linux/input.h
- +++ b/include/uapi/linux/input.h
- @@ -271,6 +271,7 @@ struct input_mask {
- #define BUS_RMI 0x1D
- #define BUS_CEC 0x1E
- #define BUS_INTEL_ISHTP 0x1F
- +#define BUS_MEI 0x44
-
- /*
- * MT_TOOL types
- --
- 2.28.0
|