1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074 |
- From 06ad5c909ea982d45ec4e53f9723cec4ea3b407e 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 7/7] 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 | 61 ++++
- 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 | 191 +++++++++++++
- 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, 1735 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 c071f7c407b6..028ff55d779d 100644
- --- a/drivers/input/touchscreen/Kconfig
- +++ b/drivers/input/touchscreen/Kconfig
- @@ -1310,4 +1310,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 94c6162409b3..864f0e092ab6 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 000000000000..d3c530dafa94
- --- /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 000000000000..0f7c904e7317
- --- /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 000000000000..13ea03b6482e
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/context.h
- @@ -0,0 +1,61 @@
- +/* 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;
- + u16 stylus_tool;
- +};
- +
- +#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 000000000000..9179eca66558
- --- /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 000000000000..e57609c85d62
- --- /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 000000000000..568bf04f7ea6
- --- /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 000000000000..fa72c1be0945
- --- /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 000000000000..2642990b8c42
- --- /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 000000000000..e6cf38fce454
- --- /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 000000000000..fb70d55542af
- --- /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 000000000000..df956e5447e0
- --- /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 000000000000..8e831074ab60
- --- /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 000000000000..6aa3f5cf1d76
- --- /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 000000000000..1f992a3bc21b
- --- /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 000000000000..3572ddc0f2fb
- --- /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 000000000000..6603714bb6fd
- --- /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 000000000000..2533dfb13584
- --- /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 000000000000..148e0545b2e4
- --- /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 000000000000..f8b771f90bd2
- --- /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 000000000000..8b3d8b689ee8
- --- /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 000000000000..f46da4ea81f2
- --- /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 000000000000..27153d82a5d6
- --- /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 000000000000..bf9912ee2af4
- --- /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 000000000000..950850b365df
- --- /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 000000000000..ab283994c3e5
- --- /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 000000000000..4d413a0abd4c
- --- /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 000000000000..704db9fdd3fd
- --- /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 000000000000..cf9807b0dbe6
- --- /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 000000000000..ed70444f649c
- --- /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 000000000000..53207497a462
- --- /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 000000000000..dbb4fe0bf559
- --- /dev/null
- +++ b/drivers/input/touchscreen/ipts/stylus.c
- @@ -0,0 +1,191 @@
- +// 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)
- +{
- + u16 tool;
- + 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);
- + }
- +
- + if (prox && rubber)
- + tool = BTN_TOOL_RUBBER;
- + else
- + tool = BTN_TOOL_PEN;
- +
- + // Fake proximity out to switch tools
- + if (ipts->stylus_tool != tool) {
- + input_report_key(ipts->stylus, ipts->stylus_tool, 0);
- + input_sync(ipts->stylus);
- + ipts->stylus_tool = tool;
- + }
- +
- + input_report_key(ipts->stylus, BTN_TOUCH, touch);
- + input_report_key(ipts->stylus, ipts->stylus_tool, prox);
- + 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 000000000000..5b93add1eac2
- --- /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 5213eacc8b86..ad78fa7d72fd 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_JSP_N 0x4DE0 /* Jasper Lake Point N */
-
- diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
- index 90ee4484a80a..01fee37dd4a4 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_PCH15_CFG)},
-
- diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
- index 9a61c28ed3ae..47fc20975245 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.26.0
|