0004-ipts.patch 57 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089
  1. From 964a397cb3e5ed3c8887f4203c27c8a28c2f166d Mon Sep 17 00:00:00 2001
  2. From: Dorian Stoll <dorian.stoll@tmsp.io>
  3. Date: Mon, 27 Jan 2020 21:16:20 +0100
  4. Subject: [PATCH] mei: Add IPTS device IDs
  5. Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
  6. Patchset: ipts
  7. ---
  8. drivers/misc/mei/hw-me-regs.h | 2 ++
  9. drivers/misc/mei/pci-me.c | 2 ++
  10. 2 files changed, 4 insertions(+)
  11. diff --git a/drivers/misc/mei/hw-me-regs.h b/drivers/misc/mei/hw-me-regs.h
  12. index e56dc4754064..a55c61c89238 100644
  13. --- a/drivers/misc/mei/hw-me-regs.h
  14. +++ b/drivers/misc/mei/hw-me-regs.h
  15. @@ -59,6 +59,7 @@
  16. #define MEI_DEV_ID_SPT 0x9D3A /* Sunrise Point */
  17. #define MEI_DEV_ID_SPT_2 0x9D3B /* Sunrise Point 2 */
  18. +#define MEI_DEV_ID_SPT_4 0x9D3E /* Sunrise Point 4 (iTouch) */
  19. #define MEI_DEV_ID_SPT_H 0xA13A /* Sunrise Point H */
  20. #define MEI_DEV_ID_SPT_H_2 0xA13B /* Sunrise Point H 2 */
  21. @@ -90,6 +91,7 @@
  22. #define MEI_DEV_ID_CDF 0x18D3 /* Cedar Fork */
  23. #define MEI_DEV_ID_ICP_LP 0x34E0 /* Ice Lake Point LP */
  24. +#define MEI_DEV_ID_ICP_LP_4 0x34E4 /* Ice Lake Point LP 4 (iTouch) */
  25. #define MEI_DEV_ID_TGP_LP 0xA0E0 /* Tiger Lake Point LP */
  26. diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
  27. index 75ab2ffbf235..78790904d77c 100644
  28. --- a/drivers/misc/mei/pci-me.c
  29. +++ b/drivers/misc/mei/pci-me.c
  30. @@ -77,6 +77,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
  31. {MEI_PCI_DEVICE(MEI_DEV_ID_SPT, MEI_ME_PCH8_CFG)},
  32. {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_2, MEI_ME_PCH8_CFG)},
  33. + {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_4, MEI_ME_PCH8_CFG)},
  34. {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H, MEI_ME_PCH8_SPS_CFG)},
  35. {MEI_PCI_DEVICE(MEI_DEV_ID_SPT_H_2, MEI_ME_PCH8_SPS_CFG)},
  36. {MEI_PCI_DEVICE(MEI_DEV_ID_LBG, MEI_ME_PCH12_CFG)},
  37. @@ -103,6 +104,7 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
  38. {MEI_PCI_DEVICE(MEI_DEV_ID_CMP_H_3, MEI_ME_PCH8_CFG)},
  39. {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP, MEI_ME_PCH12_CFG)},
  40. + {MEI_PCI_DEVICE(MEI_DEV_ID_ICP_LP_4, MEI_ME_PCH12_CFG)},
  41. {MEI_PCI_DEVICE(MEI_DEV_ID_TGP_LP, MEI_ME_PCH12_CFG)},
  42. --
  43. 2.30.1
  44. From 749e05593270579c5ac9c692204f1e104be42b67 Mon Sep 17 00:00:00 2001
  45. From: Dorian Stoll <dorian.stoll@tmsp.io>
  46. Date: Fri, 20 Dec 2019 23:15:58 +0100
  47. Subject: [PATCH] uapi: Add MEI bus ID
  48. Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
  49. Patchset: ipts
  50. ---
  51. include/uapi/linux/input.h | 1 +
  52. 1 file changed, 1 insertion(+)
  53. diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
  54. index 9a61c28ed3ae..47fc20975245 100644
  55. --- a/include/uapi/linux/input.h
  56. +++ b/include/uapi/linux/input.h
  57. @@ -271,6 +271,7 @@ struct input_mask {
  58. #define BUS_RMI 0x1D
  59. #define BUS_CEC 0x1E
  60. #define BUS_INTEL_ISHTP 0x1F
  61. +#define BUS_MEI 0x44
  62. /*
  63. * MT_TOOL types
  64. --
  65. 2.30.1
  66. From 73dcca12dbedbe0ca69958d2997a7fec4a64f139 Mon Sep 17 00:00:00 2001
  67. From: Dorian Stoll <dorian.stoll@tmsp.io>
  68. Date: Mon, 27 Jan 2020 21:22:42 +0100
  69. Subject: [PATCH] input: Add support for Intel Precise Touch & Stylus
  70. Signed-off-by: Dorian Stoll <dorian.stoll@tmsp.io>
  71. Patchset: ipts
  72. ---
  73. drivers/input/touchscreen/Kconfig | 2 +
  74. drivers/input/touchscreen/Makefile | 1 +
  75. drivers/input/touchscreen/ipts/Kconfig | 16 ++
  76. drivers/input/touchscreen/ipts/Makefile | 17 ++
  77. drivers/input/touchscreen/ipts/context.h | 60 ++++
  78. drivers/input/touchscreen/ipts/control.c | 94 +++++++
  79. drivers/input/touchscreen/ipts/control.h | 18 ++
  80. drivers/input/touchscreen/ipts/data.c | 107 +++++++
  81. drivers/input/touchscreen/ipts/data.h | 12 +
  82. drivers/input/touchscreen/ipts/hid.c | 38 +++
  83. drivers/input/touchscreen/ipts/hid.h | 13 +
  84. drivers/input/touchscreen/ipts/init.c | 93 ++++++
  85. drivers/input/touchscreen/ipts/math.c | 103 +++++++
  86. drivers/input/touchscreen/ipts/math.h | 21 ++
  87. drivers/input/touchscreen/ipts/params.c | 27 ++
  88. drivers/input/touchscreen/ipts/params.h | 15 +
  89. drivers/input/touchscreen/ipts/payload.c | 52 ++++
  90. drivers/input/touchscreen/ipts/payload.h | 14 +
  91. .../touchscreen/ipts/protocol/commands.h | 61 ++++
  92. .../input/touchscreen/ipts/protocol/data.h | 30 ++
  93. .../input/touchscreen/ipts/protocol/events.h | 29 ++
  94. .../touchscreen/ipts/protocol/feedback.h | 30 ++
  95. .../input/touchscreen/ipts/protocol/payload.h | 47 ++++
  96. .../touchscreen/ipts/protocol/responses.h | 62 ++++
  97. .../touchscreen/ipts/protocol/singletouch.h | 17 ++
  98. .../input/touchscreen/ipts/protocol/stylus.h | 52 ++++
  99. drivers/input/touchscreen/ipts/receiver.c | 265 ++++++++++++++++++
  100. drivers/input/touchscreen/ipts/receiver.h | 8 +
  101. drivers/input/touchscreen/ipts/resources.c | 131 +++++++++
  102. drivers/input/touchscreen/ipts/resources.h | 11 +
  103. drivers/input/touchscreen/ipts/singletouch.c | 64 +++++
  104. drivers/input/touchscreen/ipts/singletouch.h | 14 +
  105. drivers/input/touchscreen/ipts/stylus.c | 179 ++++++++++++
  106. drivers/input/touchscreen/ipts/stylus.h | 14 +
  107. 34 files changed, 1717 insertions(+)
  108. create mode 100644 drivers/input/touchscreen/ipts/Kconfig
  109. create mode 100644 drivers/input/touchscreen/ipts/Makefile
  110. create mode 100644 drivers/input/touchscreen/ipts/context.h
  111. create mode 100644 drivers/input/touchscreen/ipts/control.c
  112. create mode 100644 drivers/input/touchscreen/ipts/control.h
  113. create mode 100644 drivers/input/touchscreen/ipts/data.c
  114. create mode 100644 drivers/input/touchscreen/ipts/data.h
  115. create mode 100644 drivers/input/touchscreen/ipts/hid.c
  116. create mode 100644 drivers/input/touchscreen/ipts/hid.h
  117. create mode 100644 drivers/input/touchscreen/ipts/init.c
  118. create mode 100644 drivers/input/touchscreen/ipts/math.c
  119. create mode 100644 drivers/input/touchscreen/ipts/math.h
  120. create mode 100644 drivers/input/touchscreen/ipts/params.c
  121. create mode 100644 drivers/input/touchscreen/ipts/params.h
  122. create mode 100644 drivers/input/touchscreen/ipts/payload.c
  123. create mode 100644 drivers/input/touchscreen/ipts/payload.h
  124. create mode 100644 drivers/input/touchscreen/ipts/protocol/commands.h
  125. create mode 100644 drivers/input/touchscreen/ipts/protocol/data.h
  126. create mode 100644 drivers/input/touchscreen/ipts/protocol/events.h
  127. create mode 100644 drivers/input/touchscreen/ipts/protocol/feedback.h
  128. create mode 100644 drivers/input/touchscreen/ipts/protocol/payload.h
  129. create mode 100644 drivers/input/touchscreen/ipts/protocol/responses.h
  130. create mode 100644 drivers/input/touchscreen/ipts/protocol/singletouch.h
  131. create mode 100644 drivers/input/touchscreen/ipts/protocol/stylus.h
  132. create mode 100644 drivers/input/touchscreen/ipts/receiver.c
  133. create mode 100644 drivers/input/touchscreen/ipts/receiver.h
  134. create mode 100644 drivers/input/touchscreen/ipts/resources.c
  135. create mode 100644 drivers/input/touchscreen/ipts/resources.h
  136. create mode 100644 drivers/input/touchscreen/ipts/singletouch.c
  137. create mode 100644 drivers/input/touchscreen/ipts/singletouch.h
  138. create mode 100644 drivers/input/touchscreen/ipts/stylus.c
  139. create mode 100644 drivers/input/touchscreen/ipts/stylus.h
  140. diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
  141. index 1e812a193ce7..9dcd6cea224f 100644
  142. --- a/drivers/input/touchscreen/Kconfig
  143. +++ b/drivers/input/touchscreen/Kconfig
  144. @@ -1315,4 +1315,6 @@ config TOUCHSCREEN_IQS5XX
  145. To compile this driver as a module, choose M here: the
  146. module will be called iqs5xx.
  147. +source "drivers/input/touchscreen/ipts/Kconfig"
  148. +
  149. endif
  150. diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
  151. index 94c6162409b3..864f0e092ab6 100644
  152. --- a/drivers/input/touchscreen/Makefile
  153. +++ b/drivers/input/touchscreen/Makefile
  154. @@ -45,6 +45,7 @@ obj-$(CONFIG_TOUCHSCREEN_EXC3000) += exc3000.o
  155. obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o
  156. obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o
  157. obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
  158. +obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts/
  159. obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
  160. obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o
  161. obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
  162. diff --git a/drivers/input/touchscreen/ipts/Kconfig b/drivers/input/touchscreen/ipts/Kconfig
  163. new file mode 100644
  164. index 000000000000..d3c530dafa94
  165. --- /dev/null
  166. +++ b/drivers/input/touchscreen/ipts/Kconfig
  167. @@ -0,0 +1,16 @@
  168. +# SPDX-License-Identifier: GPL-2.0-or-later
  169. +
  170. +config TOUCHSCREEN_IPTS
  171. + tristate "Intel Precise Touch & Stylus"
  172. + select INTEL_MEI
  173. + depends on X86
  174. + depends on PCI
  175. + depends on HID
  176. + help
  177. + Say Y here if your system has a touchscreen using Intels
  178. + Precise Touch & Stylus (IPTS).
  179. +
  180. + If unsure say N.
  181. +
  182. + To compile this driver as a module, choose M here: the
  183. + module will be called ipts.
  184. diff --git a/drivers/input/touchscreen/ipts/Makefile b/drivers/input/touchscreen/ipts/Makefile
  185. new file mode 100644
  186. index 000000000000..0f7c904e7317
  187. --- /dev/null
  188. +++ b/drivers/input/touchscreen/ipts/Makefile
  189. @@ -0,0 +1,17 @@
  190. +# SPDX-License-Identifier: GPL-2.0-or-later
  191. +#
  192. +# Makefile for the IPTS touchscreen driver
  193. +#
  194. +
  195. +obj-$(CONFIG_TOUCHSCREEN_IPTS) += ipts.o
  196. +ipts-objs := control.o
  197. +ipts-objs += data.o
  198. +ipts-objs += hid.o
  199. +ipts-objs += init.o
  200. +ipts-objs += math.o
  201. +ipts-objs += params.o
  202. +ipts-objs += payload.o
  203. +ipts-objs += receiver.o
  204. +ipts-objs += resources.o
  205. +ipts-objs += singletouch.o
  206. +ipts-objs += stylus.o
  207. diff --git a/drivers/input/touchscreen/ipts/context.h b/drivers/input/touchscreen/ipts/context.h
  208. new file mode 100644
  209. index 000000000000..ab26552579a5
  210. --- /dev/null
  211. +++ b/drivers/input/touchscreen/ipts/context.h
  212. @@ -0,0 +1,60 @@
  213. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  214. +
  215. +#ifndef _IPTS_CONTEXT_H_
  216. +#define _IPTS_CONTEXT_H_
  217. +
  218. +#include <linux/kthread.h>
  219. +#include <linux/input.h>
  220. +#include <linux/mei_cl_bus.h>
  221. +#include <linux/types.h>
  222. +
  223. +#include "protocol/commands.h"
  224. +#include "protocol/responses.h"
  225. +
  226. +/* HACK: Workaround for DKMS build without BUS_MEI patch */
  227. +#ifndef BUS_MEI
  228. +#define BUS_MEI 0x44
  229. +#endif
  230. +
  231. +/* IPTS driver states */
  232. +enum ipts_host_status {
  233. + IPTS_HOST_STATUS_NONE,
  234. + IPTS_HOST_STATUS_INIT,
  235. + IPTS_HOST_STATUS_RESOURCE_READY,
  236. + IPTS_HOST_STATUS_STARTED,
  237. + IPTS_HOST_STATUS_STOPPING,
  238. + IPTS_HOST_STATUS_RESTARTING
  239. +};
  240. +
  241. +struct ipts_buffer_info {
  242. + u8 *address;
  243. + dma_addr_t dma_address;
  244. +};
  245. +
  246. +struct ipts_context {
  247. + struct mei_cl_device *client_dev;
  248. + struct device *dev;
  249. + struct ipts_device_info device_info;
  250. +
  251. + enum ipts_host_status status;
  252. + enum ipts_sensor_mode mode;
  253. +
  254. + struct ipts_buffer_info data[16];
  255. + struct ipts_buffer_info feedback[16];
  256. + struct ipts_buffer_info doorbell;
  257. +
  258. + /*
  259. + * These buffers are not actually used by anything, but they need
  260. + * to be allocated and passed to the ME to get proper functionality.
  261. + */
  262. + struct ipts_buffer_info workqueue;
  263. + struct ipts_buffer_info host2me;
  264. +
  265. + struct task_struct *receiver_loop;
  266. + struct task_struct *data_loop;
  267. +
  268. + struct input_dev *stylus;
  269. + struct input_dev *singletouch;
  270. +};
  271. +
  272. +#endif /* _IPTS_CONTEXT_H_ */
  273. diff --git a/drivers/input/touchscreen/ipts/control.c b/drivers/input/touchscreen/ipts/control.c
  274. new file mode 100644
  275. index 000000000000..9179eca66558
  276. --- /dev/null
  277. +++ b/drivers/input/touchscreen/ipts/control.c
  278. @@ -0,0 +1,94 @@
  279. +// SPDX-License-Identifier: GPL-2.0-or-later
  280. +
  281. +#include <linux/mei_cl_bus.h>
  282. +#include <linux/types.h>
  283. +
  284. +#include "context.h"
  285. +#include "data.h"
  286. +#include "params.h"
  287. +#include "protocol/commands.h"
  288. +#include "protocol/events.h"
  289. +#include "protocol/feedback.h"
  290. +#include "resources.h"
  291. +
  292. +int ipts_control_send(struct ipts_context *ipts,
  293. + u32 cmd, void *data, u32 size)
  294. +{
  295. + int ret;
  296. + struct ipts_command msg;
  297. +
  298. + memset(&msg, 0, sizeof(struct ipts_command));
  299. + msg.code = cmd;
  300. +
  301. + // Copy message payload
  302. + if (data && size > 0)
  303. + memcpy(&msg.data, data, size);
  304. +
  305. + ret = mei_cldev_send(ipts->client_dev, (u8 *)&msg,
  306. + sizeof(msg.code) + size);
  307. + if (ret < 0) {
  308. + dev_err(ipts->dev, "%s: error 0x%X:%d\n", __func__, cmd, ret);
  309. + return ret;
  310. + }
  311. +
  312. + return 0;
  313. +}
  314. +
  315. +int ipts_control_send_feedback(struct ipts_context *ipts,
  316. + u32 buffer, u32 transaction)
  317. +{
  318. + struct ipts_buffer_info feedback_buffer;
  319. + struct ipts_feedback *feedback;
  320. + struct ipts_feedback_cmd cmd;
  321. +
  322. + feedback_buffer = ipts->feedback[buffer];
  323. + feedback = (struct ipts_feedback *)feedback_buffer.address;
  324. +
  325. + memset(feedback, 0, sizeof(struct ipts_feedback));
  326. + memset(&cmd, 0, sizeof(struct ipts_feedback_cmd));
  327. +
  328. + feedback->type = IPTS_FEEDBACK_TYPE_NONE;
  329. + feedback->transaction = transaction;
  330. +
  331. + cmd.buffer = buffer;
  332. + cmd.transaction = transaction;
  333. +
  334. + return ipts_control_send(ipts, IPTS_CMD(FEEDBACK),
  335. + &cmd, sizeof(struct ipts_feedback_cmd));
  336. +}
  337. +
  338. +int ipts_control_start(struct ipts_context *ipts)
  339. +{
  340. + ipts->status = IPTS_HOST_STATUS_INIT;
  341. +
  342. + if (ipts_params.singletouch)
  343. + ipts->mode = IPTS_SENSOR_MODE_SINGLETOUCH;
  344. + else
  345. + ipts->mode = IPTS_SENSOR_MODE_MULTITOUCH;
  346. +
  347. + return ipts_control_send(ipts, IPTS_CMD(NOTIFY_DEV_READY), NULL, 0);
  348. +}
  349. +
  350. +void ipts_control_stop(struct ipts_context *ipts)
  351. +{
  352. + enum ipts_host_status old_status = ipts->status;
  353. +
  354. + ipts->status = IPTS_HOST_STATUS_STOPPING;
  355. + ipts_control_send(ipts, IPTS_CMD(QUIESCE_IO), NULL, 0);
  356. + ipts_control_send(ipts, IPTS_CMD(CLEAR_MEM_WINDOW), NULL, 0);
  357. +
  358. + if (old_status < IPTS_HOST_STATUS_RESOURCE_READY)
  359. + return;
  360. +
  361. + ipts_data_free(ipts);
  362. + ipts_resources_free(ipts);
  363. +}
  364. +
  365. +int ipts_control_restart(struct ipts_context *ipts)
  366. +{
  367. + dev_info(ipts->dev, "Restarting IPTS\n");
  368. + ipts_control_stop(ipts);
  369. +
  370. + ipts->status = IPTS_HOST_STATUS_RESTARTING;
  371. + return ipts_control_send(ipts, IPTS_CMD(QUIESCE_IO), NULL, 0);
  372. +}
  373. diff --git a/drivers/input/touchscreen/ipts/control.h b/drivers/input/touchscreen/ipts/control.h
  374. new file mode 100644
  375. index 000000000000..e57609c85d62
  376. --- /dev/null
  377. +++ b/drivers/input/touchscreen/ipts/control.h
  378. @@ -0,0 +1,18 @@
  379. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  380. +
  381. +#ifndef _IPTS_CONTROL_H_
  382. +#define _IPTS_CONTROL_H_
  383. +
  384. +#include <linux/types.h>
  385. +
  386. +#include "context.h"
  387. +
  388. +int ipts_control_start(struct ipts_context *ipts);
  389. +void ipts_control_stop(struct ipts_context *ipts);
  390. +int ipts_control_restart(struct ipts_context *ipts);
  391. +int ipts_control_send(struct ipts_context *ipts,
  392. + u32 cmd, void *data, u32 size);
  393. +int ipts_control_send_feedback(struct ipts_context *ipts,
  394. + u32 buffer, u32 transaction);
  395. +
  396. +#endif /* _IPTS_CONTROL_H_ */
  397. diff --git a/drivers/input/touchscreen/ipts/data.c b/drivers/input/touchscreen/ipts/data.c
  398. new file mode 100644
  399. index 000000000000..568bf04f7ea6
  400. --- /dev/null
  401. +++ b/drivers/input/touchscreen/ipts/data.c
  402. @@ -0,0 +1,107 @@
  403. +// SPDX-License-Identifier: GPL-2.0-or-later
  404. +
  405. +#include <linux/delay.h>
  406. +#include <linux/kthread.h>
  407. +#include <linux/ktime.h>
  408. +
  409. +#include "context.h"
  410. +#include "control.h"
  411. +#include "hid.h"
  412. +#include "params.h"
  413. +#include "payload.h"
  414. +#include "protocol/data.h"
  415. +
  416. +static void ipts_data_handle_input(struct ipts_context *ipts, int buffer_id)
  417. +{
  418. + struct ipts_buffer_info buffer;
  419. + struct ipts_data *data;
  420. +
  421. + buffer = ipts->data[buffer_id];
  422. + data = (struct ipts_data *)buffer.address;
  423. +
  424. + if (ipts_params.debug) {
  425. + dev_info(ipts->dev, "Buffer %d\n", buffer_id);
  426. + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 32, 1,
  427. + data->data, data->size, false);
  428. + }
  429. +
  430. + switch (data->type) {
  431. + case IPTS_DATA_TYPE_PAYLOAD:
  432. + ipts_payload_handle_input(ipts, data);
  433. + break;
  434. + case IPTS_DATA_TYPE_HID_REPORT:
  435. + ipts_hid_handle_input(ipts, data);
  436. + break;
  437. + default:
  438. + // ignore
  439. + break;
  440. + }
  441. +
  442. + ipts_control_send_feedback(ipts, buffer_id, data->transaction);
  443. +}
  444. +
  445. +int ipts_data_loop(void *data)
  446. +{
  447. + time64_t timeout;
  448. + u32 doorbell;
  449. + u32 last_doorbell;
  450. + struct ipts_context *ipts;
  451. +
  452. + timeout = ktime_get_seconds() + 5;
  453. + ipts = (struct ipts_context *)data;
  454. + last_doorbell = 0;
  455. + doorbell = 0;
  456. +
  457. + dev_info(ipts->dev, "Starting data loop\n");
  458. +
  459. + while (!kthread_should_stop()) {
  460. + if (ipts->status != IPTS_HOST_STATUS_STARTED) {
  461. + msleep(1000);
  462. + continue;
  463. + }
  464. +
  465. + // IPTS will increment the doorbell after if filled up one of
  466. + // the data buffers. If the doorbell didn't change, there is
  467. + // no work for us to do. Otherwise, the value of the doorbell
  468. + // will stand for the *next* buffer thats going to be filled.
  469. + doorbell = *(u32 *)ipts->doorbell.address;
  470. + if (doorbell == last_doorbell)
  471. + goto sleep;
  472. +
  473. + timeout = ktime_get_seconds() + 5;
  474. +
  475. + while (last_doorbell != doorbell) {
  476. + ipts_data_handle_input(ipts, last_doorbell % 16);
  477. + last_doorbell++;
  478. + }
  479. +sleep:
  480. + if (timeout > ktime_get_seconds())
  481. + usleep_range(5000, 30000);
  482. + else
  483. + msleep(200);
  484. + }
  485. +
  486. + dev_info(ipts->dev, "Stopping data loop\n");
  487. + return 0;
  488. +}
  489. +
  490. +int ipts_data_init(struct ipts_context *ipts)
  491. +{
  492. + int ret;
  493. +
  494. + ret = ipts_payload_init(ipts);
  495. + if (ret)
  496. + return ret;
  497. +
  498. + ret = ipts_hid_init(ipts);
  499. + if (ret)
  500. + return ret;
  501. +
  502. + return 0;
  503. +}
  504. +
  505. +void ipts_data_free(struct ipts_context *ipts)
  506. +{
  507. + ipts_payload_free(ipts);
  508. + ipts_hid_free(ipts);
  509. +}
  510. diff --git a/drivers/input/touchscreen/ipts/data.h b/drivers/input/touchscreen/ipts/data.h
  511. new file mode 100644
  512. index 000000000000..fa72c1be0945
  513. --- /dev/null
  514. +++ b/drivers/input/touchscreen/ipts/data.h
  515. @@ -0,0 +1,12 @@
  516. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  517. +
  518. +#ifndef _IPTS_DATA_H_
  519. +#define _IPTS_DATA_H_
  520. +
  521. +#include "context.h"
  522. +
  523. +int ipts_data_loop(void *data);
  524. +int ipts_data_init(struct ipts_context *ipts);
  525. +void ipts_data_free(struct ipts_context *ipts);
  526. +
  527. +#endif /* _IPTS_DATA_H_ */
  528. diff --git a/drivers/input/touchscreen/ipts/hid.c b/drivers/input/touchscreen/ipts/hid.c
  529. new file mode 100644
  530. index 000000000000..2642990b8c42
  531. --- /dev/null
  532. +++ b/drivers/input/touchscreen/ipts/hid.c
  533. @@ -0,0 +1,38 @@
  534. +// SPDX-License-Identifier: GPL-2.0-or-later
  535. +
  536. +#include "context.h"
  537. +#include "protocol/data.h"
  538. +#include "singletouch.h"
  539. +
  540. +/*
  541. + * IPTS on surface gen7 appears to make heavy use of HID reports, unlike
  542. + * previous generations. This file can be used to implement handling for
  543. + * them in the future, seperated from the actual singletouch implementation.
  544. + */
  545. +
  546. +void ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data)
  547. +{
  548. + // Make sure that we only handle singletouch inputs
  549. + // 40 is the report id of the singletouch device in the generic
  550. + // IPTS HID descriptor.
  551. + if (data->data[0] != 0x40)
  552. + return;
  553. +
  554. + ipts_singletouch_handle_input(ipts, data);
  555. +}
  556. +
  557. +int ipts_hid_init(struct ipts_context *ipts)
  558. +{
  559. + int ret;
  560. +
  561. + ret = ipts_singletouch_init(ipts);
  562. + if (ret)
  563. + return ret;
  564. +
  565. + return 0;
  566. +}
  567. +
  568. +void ipts_hid_free(struct ipts_context *ipts)
  569. +{
  570. + ipts_singletouch_free(ipts);
  571. +}
  572. diff --git a/drivers/input/touchscreen/ipts/hid.h b/drivers/input/touchscreen/ipts/hid.h
  573. new file mode 100644
  574. index 000000000000..e6cf38fce454
  575. --- /dev/null
  576. +++ b/drivers/input/touchscreen/ipts/hid.h
  577. @@ -0,0 +1,13 @@
  578. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  579. +
  580. +#ifndef _IPTS_HID_H_
  581. +#define _IPTS_HID_H_
  582. +
  583. +#include "context.h"
  584. +#include "protocol/data.h"
  585. +
  586. +int ipts_hid_handle_input(struct ipts_context *ipts, struct ipts_data *data);
  587. +int ipts_hid_init(struct ipts_context *ipts);
  588. +void ipts_hid_free(struct ipts_context *ipts);
  589. +
  590. +#endif /* _IPTS_HID_H_ */
  591. diff --git a/drivers/input/touchscreen/ipts/init.c b/drivers/input/touchscreen/ipts/init.c
  592. new file mode 100644
  593. index 000000000000..fb70d55542af
  594. --- /dev/null
  595. +++ b/drivers/input/touchscreen/ipts/init.c
  596. @@ -0,0 +1,93 @@
  597. +// SPDX-License-Identifier: GPL-2.0-or-later
  598. +
  599. +#include <linux/dma-mapping.h>
  600. +#include <linux/mei_cl_bus.h>
  601. +#include <linux/module.h>
  602. +#include <linux/mod_devicetable.h>
  603. +
  604. +#include "context.h"
  605. +#include "control.h"
  606. +#include "data.h"
  607. +#include "receiver.h"
  608. +
  609. +#define IPTS_MEI_UUID UUID_LE(0x3e8d0870, 0x271a, 0x4208, \
  610. + 0x8e, 0xb5, 0x9a, 0xcb, 0x94, 0x02, 0xae, 0x04)
  611. +
  612. +static int ipts_init_probe(struct mei_cl_device *cldev,
  613. + const struct mei_cl_device_id *id)
  614. +{
  615. + int ret;
  616. + struct ipts_context *ipts = NULL;
  617. +
  618. + dev_info(&cldev->dev, "Probing IPTS\n");
  619. +
  620. + // Setup the DMA bit mask
  621. + if (!dma_coerce_mask_and_coherent(&cldev->dev, DMA_BIT_MASK(64))) {
  622. + dev_info(&cldev->dev, "IPTS using DMA_BIT_MASK(64)\n");
  623. + } else if (!dma_coerce_mask_and_coherent(&cldev->dev,
  624. + DMA_BIT_MASK(32))) {
  625. + dev_info(&cldev->dev, "IPTS using DMA_BIT_MASK(32)");
  626. + } else {
  627. + dev_err(&cldev->dev, "No suitable DMA for IPTS available\n");
  628. + return -EFAULT;
  629. + }
  630. +
  631. + ret = mei_cldev_enable(cldev);
  632. + if (ret) {
  633. + dev_err(&cldev->dev, "Cannot enable IPTS\n");
  634. + return ret;
  635. + }
  636. +
  637. + ipts = devm_kzalloc(&cldev->dev,
  638. + sizeof(struct ipts_context), GFP_KERNEL);
  639. + if (!ipts) {
  640. + mei_cldev_disable(cldev);
  641. + return -ENOMEM;
  642. + }
  643. +
  644. + ipts->client_dev = cldev;
  645. + ipts->dev = &cldev->dev;
  646. +
  647. + mei_cldev_set_drvdata(cldev, ipts);
  648. +
  649. + ipts->receiver_loop = kthread_run(ipts_receiver_loop, (void *)ipts,
  650. + "ipts_receiver_loop");
  651. + ipts->data_loop = kthread_run(ipts_data_loop, (void *)ipts,
  652. + "ipts_data_loop");
  653. +
  654. + ipts_control_start(ipts);
  655. +
  656. + return 0;
  657. +}
  658. +
  659. +static int ipts_init_remove(struct mei_cl_device *cldev)
  660. +{
  661. + struct ipts_context *ipts = mei_cldev_get_drvdata(cldev);
  662. +
  663. + dev_info(&cldev->dev, "Removing IPTS\n");
  664. +
  665. + ipts_control_stop(ipts);
  666. + mei_cldev_disable(cldev);
  667. + kthread_stop(ipts->receiver_loop);
  668. + kthread_stop(ipts->data_loop);
  669. +
  670. + return 0;
  671. +}
  672. +
  673. +static struct mei_cl_device_id ipts_device_id[] = {
  674. + { "", IPTS_MEI_UUID, MEI_CL_VERSION_ANY },
  675. + { },
  676. +};
  677. +MODULE_DEVICE_TABLE(mei, ipts_device_id);
  678. +
  679. +static struct mei_cl_driver ipts_driver = {
  680. + .id_table = ipts_device_id,
  681. + .name = "ipts",
  682. + .probe = ipts_init_probe,
  683. + .remove = ipts_init_remove,
  684. +};
  685. +module_mei_cl_driver(ipts_driver);
  686. +
  687. +MODULE_DESCRIPTION("IPTS touchscreen driver");
  688. +MODULE_AUTHOR("Dorian Stoll <dorian.stoll@tmsp.io>");
  689. +MODULE_LICENSE("GPL");
  690. diff --git a/drivers/input/touchscreen/ipts/math.c b/drivers/input/touchscreen/ipts/math.c
  691. new file mode 100644
  692. index 000000000000..df956e5447e0
  693. --- /dev/null
  694. +++ b/drivers/input/touchscreen/ipts/math.c
  695. @@ -0,0 +1,103 @@
  696. +// SPDX-License-Identifier: GPL-2.0-or-later
  697. +
  698. +#include <linux/bug.h>
  699. +#include <linux/fixp-arith.h>
  700. +#include <linux/kernel.h>
  701. +#include <linux/types.h>
  702. +
  703. +#include "math.h"
  704. +
  705. +/*
  706. + * Since we need to work with [-pi, pi] in the atan functions, we are using
  707. + * 1 << 29 for the fixed point numbers. This allows us to store numbers from
  708. + * [-4, 4] using the full 32-bit signed integer range.
  709. + *
  710. + * Some constants such as PI have been already converted to the fixed-point
  711. + * format and are defined in math.h.
  712. + */
  713. +
  714. +static inline s32 ipts_math_mul(s32 x, s32 y)
  715. +{
  716. + return (x * (s64)y) >> 29;
  717. +}
  718. +
  719. +static inline s32 ipts_math_div(s32 x, s32 y)
  720. +{
  721. + return ((s64)x << 29) / y;
  722. +}
  723. +
  724. +static s32 ipts_math_atan(s32 x)
  725. +{
  726. + s32 tmp = ipts_math_mul(
  727. + ipts_math_mul(x, (abs(x) - (1 << 29))),
  728. + CONST_2447 + ipts_math_mul(CONST_0663, abs(x)));
  729. +
  730. + return ipts_math_mul(M_PI_4, x) - tmp;
  731. +}
  732. +
  733. +static s32 ipts_math_atan2(s32 y, s32 x)
  734. +{
  735. + s32 z;
  736. +
  737. + if (x != 0) {
  738. + if (abs(x) > abs(y)) {
  739. + z = ipts_math_div(y, x);
  740. + if (x > 0)
  741. + return ipts_math_atan(z);
  742. + else if (y >= 0)
  743. + return ipts_math_atan(z) + M_PI;
  744. + else
  745. + return ipts_math_atan(z) - M_PI;
  746. + } else {
  747. + z = ipts_math_div(x, y);
  748. + if (y > 0)
  749. + return -ipts_math_atan(z) + M_PI_2;
  750. + else
  751. + return -ipts_math_atan(z) - M_PI_2;
  752. + }
  753. + } else {
  754. + if (y > 0)
  755. + return M_PI_2;
  756. + else if (y < 0)
  757. + return -M_PI_2;
  758. + }
  759. +
  760. + return 0;
  761. +}
  762. +
  763. +/*
  764. + * Convert altitude in range [0, 9000] and azimuth in range [0, 36000]
  765. + * to x-/y-tilt in range [-9000, 9000]. Azimuth is given
  766. + * counter-clockwise, starting with zero on the right. Altitude is
  767. + * given as angle between stylus and z-axis.
  768. + */
  769. +void ipts_math_altitude_azimuth_to_tilt(s32 alt, s32 azm, s32 *tx, s32 *ty)
  770. +{
  771. + s32 sin_alt, cos_alt;
  772. + s32 sin_azm, cos_azm;
  773. +
  774. + s32 x, y, z;
  775. + s64 atan_x, atan_y;
  776. +
  777. + sin_alt = fixp_sin32_rad(alt, 36000) / 4;
  778. + sin_azm = fixp_sin32_rad(azm, 36000) / 4;
  779. +
  780. + cos_alt = fixp_cos32_rad(alt, 36000) / 4;
  781. + cos_azm = fixp_cos32_rad(azm, 36000) / 4;
  782. +
  783. + x = ipts_math_mul(sin_alt, cos_azm);
  784. + y = ipts_math_mul(sin_alt, sin_azm);
  785. + z = cos_alt;
  786. +
  787. + atan_x = ipts_math_atan2(z, x);
  788. + atan_y = ipts_math_atan2(z, y);
  789. +
  790. + atan_x = atan_x * 4500;
  791. + atan_y = atan_y * 4500;
  792. +
  793. + atan_x = atan_x / M_PI_4;
  794. + atan_y = atan_y / M_PI_4;
  795. +
  796. + *tx = 9000 - atan_x;
  797. + *ty = atan_y - 9000;
  798. +}
  799. diff --git a/drivers/input/touchscreen/ipts/math.h b/drivers/input/touchscreen/ipts/math.h
  800. new file mode 100644
  801. index 000000000000..8e831074ab60
  802. --- /dev/null
  803. +++ b/drivers/input/touchscreen/ipts/math.h
  804. @@ -0,0 +1,21 @@
  805. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  806. +
  807. +#ifndef _IPTS_MATH_H_
  808. +#define _IPTS_MATH_H_
  809. +
  810. +#include <linux/types.h>
  811. +
  812. +/* (pi / 4) * (1 << 29) */
  813. +#define M_PI_4 421657428
  814. +#define M_PI_2 (M_PI_4 * 2)
  815. +#define M_PI (M_PI_2 * 2)
  816. +
  817. +/* 0.2447 * (1 << 29) */
  818. +#define CONST_2447 131372312
  819. +
  820. +/* 0.0663 * (1 << 29) */
  821. +#define CONST_0663 35594541
  822. +
  823. +void ipts_math_altitude_azimuth_to_tilt(s32 alt, s32 azm, s32 *tx, s32 *ty);
  824. +
  825. +#endif /* _IPTS_MATH_H_ */
  826. diff --git a/drivers/input/touchscreen/ipts/params.c b/drivers/input/touchscreen/ipts/params.c
  827. new file mode 100644
  828. index 000000000000..6aa3f5cf1d76
  829. --- /dev/null
  830. +++ b/drivers/input/touchscreen/ipts/params.c
  831. @@ -0,0 +1,27 @@
  832. +// SPDX-License-Identifier: GPL-2.0-or-later
  833. +
  834. +#include <linux/moduleparam.h>
  835. +#include <linux/types.h>
  836. +
  837. +#include "params.h"
  838. +
  839. +#define IPTS_PARM(NAME, TYPE, PERM) \
  840. + module_param_named(NAME, ipts_params.NAME, TYPE, PERM)
  841. +
  842. +#define IPTS_DESC(NAME, DESC) \
  843. + MODULE_PARM_DESC(NAME, DESC)
  844. +
  845. +struct ipts_modparams ipts_params = {
  846. + .debug = false,
  847. + .singletouch = false,
  848. +};
  849. +
  850. +IPTS_PARM(debug, bool, 0400);
  851. +IPTS_DESC(debug,
  852. + "Enable additional debugging in the IPTS driver (default: false)"
  853. +);
  854. +
  855. +IPTS_PARM(singletouch, bool, 0400);
  856. +IPTS_DESC(singletouch,
  857. + "Enables IPTS single touch mode (disables stylus) (default: false)"
  858. +);
  859. diff --git a/drivers/input/touchscreen/ipts/params.h b/drivers/input/touchscreen/ipts/params.h
  860. new file mode 100644
  861. index 000000000000..1f992a3bc21b
  862. --- /dev/null
  863. +++ b/drivers/input/touchscreen/ipts/params.h
  864. @@ -0,0 +1,15 @@
  865. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  866. +
  867. +#ifndef _IPTS_PARAMS_H_
  868. +#define _IPTS_PARAMS_H_
  869. +
  870. +#include <linux/types.h>
  871. +
  872. +struct ipts_modparams {
  873. + bool debug;
  874. + bool singletouch;
  875. +};
  876. +
  877. +extern struct ipts_modparams ipts_params;
  878. +
  879. +#endif /* _IPTS_PARAMS_H_ */
  880. diff --git a/drivers/input/touchscreen/ipts/payload.c b/drivers/input/touchscreen/ipts/payload.c
  881. new file mode 100644
  882. index 000000000000..3572ddc0f2fb
  883. --- /dev/null
  884. +++ b/drivers/input/touchscreen/ipts/payload.c
  885. @@ -0,0 +1,52 @@
  886. +// SPDX-License-Identifier: GPL-2.0-or-later
  887. +
  888. +#include <linux/types.h>
  889. +
  890. +#include "context.h"
  891. +#include "protocol/data.h"
  892. +#include "protocol/payload.h"
  893. +#include "stylus.h"
  894. +
  895. +void ipts_payload_handle_input(struct ipts_context *ipts,
  896. + struct ipts_data *data)
  897. +{
  898. + u32 i, offset;
  899. + struct ipts_payload *payload;
  900. + struct ipts_payload_frame *frame;
  901. +
  902. + payload = (struct ipts_payload *)data->data;
  903. + offset = 0;
  904. +
  905. + for (i = 0; i < payload->num_frames; i++) {
  906. + frame = (struct ipts_payload_frame *)&payload->data[offset];
  907. + offset += sizeof(struct ipts_payload_frame) + frame->size;
  908. +
  909. + switch (frame->type) {
  910. + case IPTS_PAYLOAD_FRAME_TYPE_STYLUS:
  911. + ipts_stylus_handle_input(ipts, frame);
  912. + break;
  913. + case IPTS_PAYLOAD_FRAME_TYPE_TOUCH:
  914. + // ignored (for the moment)
  915. + break;
  916. + default:
  917. + // ignored
  918. + break;
  919. + }
  920. + }
  921. +}
  922. +
  923. +int ipts_payload_init(struct ipts_context *ipts)
  924. +{
  925. + int ret;
  926. +
  927. + ret = ipts_stylus_init(ipts);
  928. + if (ret)
  929. + return ret;
  930. +
  931. + return 0;
  932. +}
  933. +
  934. +void ipts_payload_free(struct ipts_context *ipts)
  935. +{
  936. + ipts_stylus_free(ipts);
  937. +}
  938. diff --git a/drivers/input/touchscreen/ipts/payload.h b/drivers/input/touchscreen/ipts/payload.h
  939. new file mode 100644
  940. index 000000000000..6603714bb6fd
  941. --- /dev/null
  942. +++ b/drivers/input/touchscreen/ipts/payload.h
  943. @@ -0,0 +1,14 @@
  944. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  945. +
  946. +#ifndef _IPTS_PAYLOAD_H_
  947. +#define _IPTS_PAYLOAD_H_
  948. +
  949. +#include "context.h"
  950. +#include "protocol/data.h"
  951. +
  952. +void ipts_payload_handle_input(struct ipts_context *ipts,
  953. + struct ipts_data *data);
  954. +int ipts_payload_init(struct ipts_context *ipts);
  955. +void ipts_payload_free(struct ipts_context *ipts);
  956. +
  957. +#endif /* _IPTS_PAYLOAD_H_ */
  958. diff --git a/drivers/input/touchscreen/ipts/protocol/commands.h b/drivers/input/touchscreen/ipts/protocol/commands.h
  959. new file mode 100644
  960. index 000000000000..2533dfb13584
  961. --- /dev/null
  962. +++ b/drivers/input/touchscreen/ipts/protocol/commands.h
  963. @@ -0,0 +1,61 @@
  964. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  965. +
  966. +#ifndef _IPTS_PROTOCOL_COMMANDS_H_
  967. +#define _IPTS_PROTOCOL_COMMANDS_H_
  968. +
  969. +#include <linux/build_bug.h>
  970. +#include <linux/types.h>
  971. +
  972. +enum ipts_sensor_mode {
  973. + IPTS_SENSOR_MODE_SINGLETOUCH = 0,
  974. + IPTS_SENSOR_MODE_MULTITOUCH,
  975. + IPTS_SENSOR_MODE_MAX
  976. +};
  977. +
  978. +struct ipts_set_mode_cmd {
  979. + u32 sensor_mode;
  980. + u8 reserved[12];
  981. +} __packed;
  982. +
  983. +struct ipts_set_mem_window_cmd {
  984. + u32 data_buffer_addr_lower[16];
  985. + u32 data_buffer_addr_upper[16];
  986. + u32 workqueue_addr_lower;
  987. + u32 workqueue_addr_upper;
  988. + u32 doorbell_addr_lower;
  989. + u32 doorbell_addr_upper;
  990. + u32 feedback_buffer_addr_lower[16];
  991. + u32 feedback_buffer_addr_upper[16];
  992. + u32 host2me_addr_lower;
  993. + u32 host2me_addr_upper;
  994. + u32 host2me_size;
  995. + u8 reserved1;
  996. + u8 workqueue_item_size;
  997. + u16 workqueue_size;
  998. + u8 reserved[32];
  999. +} __packed;
  1000. +
  1001. +struct ipts_feedback_cmd {
  1002. + u32 buffer;
  1003. + u32 transaction;
  1004. + u8 reserved[8];
  1005. +} __packed;
  1006. +
  1007. +/*
  1008. + * Commands are sent from the host to the ME
  1009. + */
  1010. +struct ipts_command {
  1011. + u32 code;
  1012. + union {
  1013. + struct ipts_set_mode_cmd set_mode;
  1014. + struct ipts_set_mem_window_cmd set_mem_window;
  1015. + struct ipts_feedback_cmd feedback;
  1016. + } data;
  1017. +} __packed;
  1018. +
  1019. +static_assert(sizeof(struct ipts_set_mode_cmd) == 16);
  1020. +static_assert(sizeof(struct ipts_set_mem_window_cmd) == 320);
  1021. +static_assert(sizeof(struct ipts_feedback_cmd) == 16);
  1022. +static_assert(sizeof(struct ipts_command) == 324);
  1023. +
  1024. +#endif /* _IPTS_PROTOCOL_COMMANDS_H_ */
  1025. diff --git a/drivers/input/touchscreen/ipts/protocol/data.h b/drivers/input/touchscreen/ipts/protocol/data.h
  1026. new file mode 100644
  1027. index 000000000000..148e0545b2e4
  1028. --- /dev/null
  1029. +++ b/drivers/input/touchscreen/ipts/protocol/data.h
  1030. @@ -0,0 +1,30 @@
  1031. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1032. +
  1033. +#ifndef _IPTS_PROTOCOL_DATA_H_
  1034. +#define _IPTS_PROTOCOL_DATA_H_
  1035. +
  1036. +#include <linux/build_bug.h>
  1037. +#include <linux/types.h>
  1038. +
  1039. +enum ipts_data_type {
  1040. + IPTS_DATA_TYPE_PAYLOAD = 0,
  1041. + IPTS_DATA_TYPE_ERROR,
  1042. + IPTS_DATA_TYPE_VENDOR_DATA,
  1043. + IPTS_DATA_TYPE_HID_REPORT,
  1044. + IPTS_DATA_TYPE_GET_FEATURES,
  1045. + IPTS_DATA_TYPE_MAX
  1046. +};
  1047. +
  1048. +struct ipts_data {
  1049. + u32 type;
  1050. + u32 size;
  1051. + u32 buffer;
  1052. + u8 reserved1[20];
  1053. + u8 transaction;
  1054. + u8 reserved2[31];
  1055. + u8 data[];
  1056. +} __packed;
  1057. +
  1058. +static_assert(sizeof(struct ipts_data) == 64);
  1059. +
  1060. +#endif /* _IPTS_PROTOCOL_DATA_H_ */
  1061. diff --git a/drivers/input/touchscreen/ipts/protocol/events.h b/drivers/input/touchscreen/ipts/protocol/events.h
  1062. new file mode 100644
  1063. index 000000000000..f8b771f90bd2
  1064. --- /dev/null
  1065. +++ b/drivers/input/touchscreen/ipts/protocol/events.h
  1066. @@ -0,0 +1,29 @@
  1067. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1068. +
  1069. +#ifndef _IPTS_PROTOCOL_EVENTS_H_
  1070. +#define _IPTS_PROTOCOL_EVENTS_H_
  1071. +
  1072. +/*
  1073. + * Helpers to avoid writing boilerplate code.
  1074. + * The response to a command code is always 0x8000000x, where x
  1075. + * is the command code itself. Instead of writing two definitions,
  1076. + * we use macros to calculate the value on the fly instead.
  1077. + */
  1078. +#define IPTS_CMD(COMMAND) IPTS_EVT_##COMMAND
  1079. +#define IPTS_RSP(COMMAND) (IPTS_CMD(COMMAND) + 0x80000000)
  1080. +
  1081. +/*
  1082. + * Events that can be sent to / received from the ME
  1083. + */
  1084. +enum ipts_evt_code {
  1085. + IPTS_EVT_GET_DEVICE_INFO = 1,
  1086. + IPTS_EVT_SET_MODE,
  1087. + IPTS_EVT_SET_MEM_WINDOW,
  1088. + IPTS_EVT_QUIESCE_IO,
  1089. + IPTS_EVT_READY_FOR_DATA,
  1090. + IPTS_EVT_FEEDBACK,
  1091. + IPTS_EVT_CLEAR_MEM_WINDOW,
  1092. + IPTS_EVT_NOTIFY_DEV_READY,
  1093. +};
  1094. +
  1095. +#endif /* _IPTS_PROTOCOL_EVENTS_H_ */
  1096. diff --git a/drivers/input/touchscreen/ipts/protocol/feedback.h b/drivers/input/touchscreen/ipts/protocol/feedback.h
  1097. new file mode 100644
  1098. index 000000000000..8b3d8b689ee8
  1099. --- /dev/null
  1100. +++ b/drivers/input/touchscreen/ipts/protocol/feedback.h
  1101. @@ -0,0 +1,30 @@
  1102. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1103. +
  1104. +#ifndef _IPTS_PROTOCOL_FEEDBACK_H_
  1105. +#define _IPTS_PROTOCOL_FEEDBACK_H_
  1106. +
  1107. +#include <linux/build_bug.h>
  1108. +#include <linux/types.h>
  1109. +
  1110. +enum ipts_feedback_type {
  1111. + IPTS_FEEDBACK_TYPE_NONE = 0,
  1112. + IPTS_FEEDBACK_TYPE_SOFT_RESET,
  1113. + IPTS_FEEDBACK_TYPE_GOTO_ARMED,
  1114. + IPTS_FEEDBACK_TYPE_GOTO_SENSING,
  1115. + IPTS_FEEDBACK_TYPE_GOTO_SLEEP,
  1116. + IPTS_FEEDBACK_TYPE_GOTO_DOZE,
  1117. + IPTS_FEEDBACK_TYPE_HARD_RESET,
  1118. + IPTS_FEEDBACK_TYPE_MAX
  1119. +};
  1120. +
  1121. +struct ipts_feedback {
  1122. + u32 type;
  1123. + u32 size;
  1124. + u32 transaction;
  1125. + u8 reserved[52];
  1126. + u8 data[];
  1127. +} __packed;
  1128. +
  1129. +static_assert(sizeof(struct ipts_feedback) == 64);
  1130. +
  1131. +#endif /* _IPTS_PROTOCOL_FEEDBACK_H_ */
  1132. diff --git a/drivers/input/touchscreen/ipts/protocol/payload.h b/drivers/input/touchscreen/ipts/protocol/payload.h
  1133. new file mode 100644
  1134. index 000000000000..f46da4ea81f2
  1135. --- /dev/null
  1136. +++ b/drivers/input/touchscreen/ipts/protocol/payload.h
  1137. @@ -0,0 +1,47 @@
  1138. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1139. +
  1140. +#ifndef _IPTS_PROTOCOL_PAYLOAD_H_
  1141. +#define _IPTS_PROTOCOL_PAYLOAD_H_
  1142. +
  1143. +#include <linux/build_bug.h>
  1144. +#include <linux/types.h>
  1145. +
  1146. +enum ipts_payload_frame_type {
  1147. + IPTS_PAYLOAD_FRAME_TYPE_STYLUS = 6,
  1148. + IPTS_PAYLOAD_FRAME_TYPE_TOUCH = 8,
  1149. +};
  1150. +
  1151. +enum ipts_report_type {
  1152. + IPTS_REPORT_TYPE_TOUCH_HEATMAP_DIM = 0x0403,
  1153. + IPTS_REPORT_TYPE_TOUCH_HEATMAP = 0x0425,
  1154. + IPTS_REPORT_TYPE_STYLUS_NO_TILT = 0x0410,
  1155. + IPTS_REPORT_TYPE_STYLUS_TILT = 0x0461,
  1156. + IPTS_REPORT_TYPE_STYLUS_TILT_SERIAL = 0x0460,
  1157. +};
  1158. +
  1159. +struct ipts_payload {
  1160. + u32 counter;
  1161. + u32 num_frames;
  1162. + u8 reserved[4];
  1163. + u8 data[];
  1164. +} __packed;
  1165. +
  1166. +struct ipts_payload_frame {
  1167. + u16 index;
  1168. + u16 type;
  1169. + u32 size;
  1170. + u8 reserved[8];
  1171. + u8 data[];
  1172. +} __packed;
  1173. +
  1174. +struct ipts_report {
  1175. + u16 type;
  1176. + u16 size;
  1177. + u8 data[];
  1178. +} __packed;
  1179. +
  1180. +static_assert(sizeof(struct ipts_payload) == 12);
  1181. +static_assert(sizeof(struct ipts_payload_frame) == 16);
  1182. +static_assert(sizeof(struct ipts_report) == 4);
  1183. +
  1184. +#endif /* _IPTS_PROTOCOL_PAYLOAD_H_ */
  1185. diff --git a/drivers/input/touchscreen/ipts/protocol/responses.h b/drivers/input/touchscreen/ipts/protocol/responses.h
  1186. new file mode 100644
  1187. index 000000000000..27153d82a5d6
  1188. --- /dev/null
  1189. +++ b/drivers/input/touchscreen/ipts/protocol/responses.h
  1190. @@ -0,0 +1,62 @@
  1191. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1192. +
  1193. +#ifndef _IPTS_PROTOCOL_RESPONSES_H_
  1194. +#define _IPTS_PROTOCOL_RESPONSES_H_
  1195. +
  1196. +#include <linux/build_bug.h>
  1197. +#include <linux/types.h>
  1198. +
  1199. +enum ipts_me_status {
  1200. + IPTS_ME_STATUS_SUCCESS = 0,
  1201. + IPTS_ME_STATUS_INVALID_PARAMS,
  1202. + IPTS_ME_STATUS_ACCESS_DENIED,
  1203. + IPTS_ME_STATUS_CMD_SIZE_ERROR,
  1204. + IPTS_ME_STATUS_NOT_READY,
  1205. + IPTS_ME_STATUS_REQUEST_OUTSTANDING,
  1206. + IPTS_ME_STATUS_NO_SENSOR_FOUND,
  1207. + IPTS_ME_STATUS_OUT_OF_MEMORY,
  1208. + IPTS_ME_STATUS_INTERNAL_ERROR,
  1209. + IPTS_ME_STATUS_SENSOR_DISABLED,
  1210. + IPTS_ME_STATUS_COMPAT_CHECK_FAIL,
  1211. + IPTS_ME_STATUS_SENSOR_EXPECTED_RESET,
  1212. + IPTS_ME_STATUS_SENSOR_UNEXPECTED_RESET,
  1213. + IPTS_ME_STATUS_RESET_FAILED,
  1214. + IPTS_ME_STATUS_TIMEOUT,
  1215. + IPTS_ME_STATUS_TEST_MODE_FAIL,
  1216. + IPTS_ME_STATUS_SENSOR_FAIL_FATAL,
  1217. + IPTS_ME_STATUS_SENSOR_FAIL_NONFATAL,
  1218. + IPTS_ME_STATUS_INVALID_DEVICE_CAPS,
  1219. + IPTS_ME_STATUS_QUIESCE_IO_IN_PROGRESS,
  1220. + IPTS_ME_STATUS_MAX
  1221. +};
  1222. +
  1223. +struct ipts_device_info {
  1224. + u16 vendor_id;
  1225. + u16 device_id;
  1226. + u32 hw_rev;
  1227. + u32 fw_rev;
  1228. +
  1229. + /* Required size of one touch data buffer */
  1230. + u32 data_size;
  1231. +
  1232. + /* Required size of one feedback buffer */
  1233. + u32 feedback_size;
  1234. + u8 reserved[24];
  1235. +} __packed;
  1236. +
  1237. +/*
  1238. + * Responses are sent from the ME to the host, reacting to a command.
  1239. + */
  1240. +struct ipts_response {
  1241. + u32 code;
  1242. + u32 status;
  1243. + union {
  1244. + struct ipts_device_info device_info;
  1245. + u8 reserved[80];
  1246. + } data;
  1247. +} __packed;
  1248. +
  1249. +static_assert(sizeof(struct ipts_device_info) == 44);
  1250. +static_assert(sizeof(struct ipts_response) == 88);
  1251. +
  1252. +#endif /* _IPTS_PROTOCOL_RESPONSES_H_ */
  1253. diff --git a/drivers/input/touchscreen/ipts/protocol/singletouch.h b/drivers/input/touchscreen/ipts/protocol/singletouch.h
  1254. new file mode 100644
  1255. index 000000000000..bf9912ee2af4
  1256. --- /dev/null
  1257. +++ b/drivers/input/touchscreen/ipts/protocol/singletouch.h
  1258. @@ -0,0 +1,17 @@
  1259. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1260. +
  1261. +#ifndef _IPTS_PROTOCOL_SINGLETOUCH_H_
  1262. +#define _IPTS_PROTOCOL_SINGLETOUCH_H_
  1263. +
  1264. +#include <linux/build_bug.h>
  1265. +#include <linux/types.h>
  1266. +
  1267. +struct ipts_singletouch_report {
  1268. + u8 touch;
  1269. + u16 x;
  1270. + u16 y;
  1271. +} __packed;
  1272. +
  1273. +static_assert(sizeof(struct ipts_singletouch_report) == 5);
  1274. +
  1275. +#endif /* _IPTS_PROTOCOL_SINGLETOUCH_H_ */
  1276. diff --git a/drivers/input/touchscreen/ipts/protocol/stylus.h b/drivers/input/touchscreen/ipts/protocol/stylus.h
  1277. new file mode 100644
  1278. index 000000000000..950850b365df
  1279. --- /dev/null
  1280. +++ b/drivers/input/touchscreen/ipts/protocol/stylus.h
  1281. @@ -0,0 +1,52 @@
  1282. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1283. +
  1284. +#ifndef _IPTS_PROTOCOL_STYLUS_H_
  1285. +#define _IPTS_PROTOCOL_STYLUS_H_
  1286. +
  1287. +#include <linux/build_bug.h>
  1288. +#include <linux/types.h>
  1289. +
  1290. +struct ipts_stylus_report {
  1291. + u8 reports;
  1292. + u8 reserved[3];
  1293. + u8 data[];
  1294. +} __packed;
  1295. +
  1296. +struct ipts_stylus_report_serial {
  1297. + u8 reports;
  1298. + u8 reserved[3];
  1299. + u32 serial;
  1300. + u8 data[];
  1301. +} __packed;
  1302. +
  1303. +struct ipts_stylus_report_data {
  1304. + u16 timestamp;
  1305. + u16 mode;
  1306. + u16 x;
  1307. + u16 y;
  1308. + u16 pressure;
  1309. + u16 altitude;
  1310. + u16 azimuth;
  1311. + u16 reserved;
  1312. +} __packed;
  1313. +
  1314. +struct ipts_stylus_report_data_no_tilt {
  1315. + u8 reserved[4];
  1316. + u8 mode;
  1317. + u16 x;
  1318. + u16 y;
  1319. + u16 pressure;
  1320. + u8 reserved2;
  1321. +} __packed;
  1322. +
  1323. +#define IPTS_STYLUS_REPORT_MODE_PROX BIT(0)
  1324. +#define IPTS_STYLUS_REPORT_MODE_TOUCH BIT(1)
  1325. +#define IPTS_STYLUS_REPORT_MODE_BUTTON BIT(2)
  1326. +#define IPTS_STYLUS_REPORT_MODE_ERASER BIT(3)
  1327. +
  1328. +static_assert(sizeof(struct ipts_stylus_report) == 4);
  1329. +static_assert(sizeof(struct ipts_stylus_report_serial) == 8);
  1330. +static_assert(sizeof(struct ipts_stylus_report_data) == 16);
  1331. +static_assert(sizeof(struct ipts_stylus_report_data_no_tilt) == 12);
  1332. +
  1333. +#endif /* _IPTS_PAYLOAD_STYLUS_H_ */
  1334. diff --git a/drivers/input/touchscreen/ipts/receiver.c b/drivers/input/touchscreen/ipts/receiver.c
  1335. new file mode 100644
  1336. index 000000000000..ab283994c3e5
  1337. --- /dev/null
  1338. +++ b/drivers/input/touchscreen/ipts/receiver.c
  1339. @@ -0,0 +1,265 @@
  1340. +// SPDX-License-Identifier: GPL-2.0-or-later
  1341. +
  1342. +#include <linux/types.h>
  1343. +
  1344. +#include "context.h"
  1345. +#include "control.h"
  1346. +#include "data.h"
  1347. +#include "protocol/commands.h"
  1348. +#include "protocol/events.h"
  1349. +#include "protocol/responses.h"
  1350. +#include "resources.h"
  1351. +
  1352. +static void ipts_receiver_handle_notify_dev_ready(struct ipts_context *ipts,
  1353. + struct ipts_response *msg, int *cmd_status)
  1354. +{
  1355. + if (msg->status != IPTS_ME_STATUS_SENSOR_FAIL_NONFATAL &&
  1356. + msg->status != IPTS_ME_STATUS_SUCCESS) {
  1357. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1358. + msg->code, msg->status);
  1359. + return;
  1360. + }
  1361. +
  1362. + *cmd_status = ipts_control_send(ipts,
  1363. + IPTS_CMD(GET_DEVICE_INFO), NULL, 0);
  1364. +}
  1365. +
  1366. +static void ipts_receiver_handle_get_device_info(struct ipts_context *ipts,
  1367. + struct ipts_response *msg, int *cmd_status)
  1368. +{
  1369. + if (msg->status != IPTS_ME_STATUS_COMPAT_CHECK_FAIL &&
  1370. + msg->status != IPTS_ME_STATUS_SUCCESS) {
  1371. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1372. + msg->code, msg->status);
  1373. + return;
  1374. + }
  1375. +
  1376. + memcpy(&ipts->device_info, &msg->data.device_info,
  1377. + sizeof(struct ipts_device_info));
  1378. +
  1379. + dev_info(ipts->dev, "Device %04hX:%04hX found\n",
  1380. + ipts->device_info.vendor_id,
  1381. + ipts->device_info.device_id);
  1382. +
  1383. + if (ipts_data_init(ipts))
  1384. + return;
  1385. +
  1386. + *cmd_status = ipts_control_send(ipts,
  1387. + IPTS_CMD(CLEAR_MEM_WINDOW), NULL, 0);
  1388. +}
  1389. +
  1390. +static void ipts_receiver_handle_clear_mem_window(struct ipts_context *ipts,
  1391. + struct ipts_response *msg, int *cmd_status, int *ret)
  1392. +{
  1393. + struct ipts_set_mode_cmd sensor_mode_cmd;
  1394. +
  1395. + if (msg->status != IPTS_ME_STATUS_TIMEOUT &&
  1396. + msg->status != IPTS_ME_STATUS_SUCCESS) {
  1397. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1398. + msg->code, msg->status);
  1399. + return;
  1400. + }
  1401. +
  1402. + if (ipts->status == IPTS_HOST_STATUS_STOPPING)
  1403. + return;
  1404. +
  1405. + if (ipts_resources_init(ipts))
  1406. + return;
  1407. +
  1408. + ipts->status = IPTS_HOST_STATUS_RESOURCE_READY;
  1409. +
  1410. + memset(&sensor_mode_cmd, 0, sizeof(struct ipts_set_mode_cmd));
  1411. + sensor_mode_cmd.sensor_mode = ipts->mode;
  1412. +
  1413. + *cmd_status = ipts_control_send(ipts, IPTS_CMD(SET_MODE),
  1414. + &sensor_mode_cmd, sizeof(struct ipts_set_mode_cmd));
  1415. +}
  1416. +
  1417. +static void ipts_receiver_handle_set_mode(struct ipts_context *ipts,
  1418. + struct ipts_response *msg, int *cmd_status)
  1419. +{
  1420. + int i;
  1421. + struct ipts_set_mem_window_cmd cmd;
  1422. +
  1423. + if (msg->status != IPTS_ME_STATUS_SUCCESS) {
  1424. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1425. + msg->code, msg->status);
  1426. + return;
  1427. + }
  1428. +
  1429. + memset(&cmd, 0, sizeof(struct ipts_set_mem_window_cmd));
  1430. +
  1431. + for (i = 0; i < 16; i++) {
  1432. + cmd.data_buffer_addr_lower[i] =
  1433. + lower_32_bits(ipts->data[i].dma_address);
  1434. +
  1435. + cmd.data_buffer_addr_upper[i] =
  1436. + upper_32_bits(ipts->data[i].dma_address);
  1437. +
  1438. + cmd.feedback_buffer_addr_lower[i] =
  1439. + lower_32_bits(ipts->feedback[i].dma_address);
  1440. +
  1441. + cmd.feedback_buffer_addr_upper[i] =
  1442. + upper_32_bits(ipts->feedback[i].dma_address);
  1443. + }
  1444. +
  1445. + cmd.workqueue_addr_lower = lower_32_bits(ipts->workqueue.dma_address);
  1446. + cmd.workqueue_addr_upper = upper_32_bits(ipts->workqueue.dma_address);
  1447. +
  1448. + cmd.doorbell_addr_lower = lower_32_bits(ipts->doorbell.dma_address);
  1449. + cmd.doorbell_addr_upper = upper_32_bits(ipts->doorbell.dma_address);
  1450. +
  1451. + cmd.host2me_addr_lower = lower_32_bits(ipts->host2me.dma_address);
  1452. + cmd.host2me_addr_upper = upper_32_bits(ipts->host2me.dma_address);
  1453. + cmd.host2me_size = ipts->device_info.data_size;
  1454. +
  1455. + cmd.workqueue_size = 8192;
  1456. + cmd.workqueue_item_size = 16;
  1457. +
  1458. + *cmd_status = ipts_control_send(ipts, IPTS_CMD(SET_MEM_WINDOW),
  1459. + &cmd, sizeof(struct ipts_set_mem_window_cmd));
  1460. +}
  1461. +
  1462. +static void ipts_receiver_handle_set_mem_window(struct ipts_context *ipts,
  1463. + struct ipts_response *msg, int *cmd_status)
  1464. +{
  1465. + if (msg->status != IPTS_ME_STATUS_SUCCESS) {
  1466. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1467. + msg->code, msg->status);
  1468. + return;
  1469. + }
  1470. +
  1471. + *cmd_status = ipts_control_send(ipts,
  1472. + IPTS_CMD(READY_FOR_DATA), NULL, 0);
  1473. + if (*cmd_status)
  1474. + return;
  1475. +
  1476. + ipts->status = IPTS_HOST_STATUS_STARTED;
  1477. + dev_info(ipts->dev, "IPTS enabled\n");
  1478. +}
  1479. +
  1480. +static void ipts_receiver_handle_ready_for_data(struct ipts_context *ipts,
  1481. + struct ipts_response *msg)
  1482. +{
  1483. + if (msg->status != IPTS_ME_STATUS_SENSOR_DISABLED &&
  1484. + msg->status != IPTS_ME_STATUS_SUCCESS) {
  1485. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1486. + msg->code, msg->status);
  1487. + return;
  1488. + }
  1489. +
  1490. + if (ipts->mode != IPTS_SENSOR_MODE_SINGLETOUCH ||
  1491. + ipts->status != IPTS_HOST_STATUS_STARTED)
  1492. + return;
  1493. +
  1494. + // Increment the doorbell manually to indicate that a new buffer
  1495. + // filled with touch data is available
  1496. + *((u32 *)ipts->doorbell.address) += 1;
  1497. +}
  1498. +
  1499. +static void ipts_recever_handle_feedback(struct ipts_context *ipts,
  1500. + struct ipts_response *msg, int *cmd_status)
  1501. +{
  1502. + if (msg->status != IPTS_ME_STATUS_COMPAT_CHECK_FAIL &&
  1503. + msg->status != IPTS_ME_STATUS_SUCCESS &&
  1504. + msg->status != IPTS_ME_STATUS_INVALID_PARAMS) {
  1505. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1506. + msg->code, msg->status);
  1507. + return;
  1508. + }
  1509. +
  1510. + if (ipts->mode != IPTS_SENSOR_MODE_SINGLETOUCH)
  1511. + return;
  1512. +
  1513. + *cmd_status = ipts_control_send(ipts,
  1514. + IPTS_CMD(READY_FOR_DATA), NULL, 0);
  1515. +}
  1516. +
  1517. +static void ipts_receiver_handle_quiesce_io(struct ipts_context *ipts,
  1518. + struct ipts_response *msg)
  1519. +{
  1520. + if (msg->status != IPTS_ME_STATUS_SUCCESS) {
  1521. + dev_err(ipts->dev, "0x%08x failed - status = %d\n",
  1522. + msg->code, msg->status);
  1523. + return;
  1524. + }
  1525. +
  1526. + if (ipts->status == IPTS_HOST_STATUS_RESTARTING)
  1527. + ipts_control_start(ipts);
  1528. +}
  1529. +
  1530. +
  1531. +static int ipts_receiver_handle_response(struct ipts_context *ipts,
  1532. + struct ipts_response *msg, u32 msg_len)
  1533. +{
  1534. + int cmd_status = 0;
  1535. + int ret = 0;
  1536. +
  1537. + switch (msg->code) {
  1538. + case IPTS_RSP(NOTIFY_DEV_READY):
  1539. + ipts_receiver_handle_notify_dev_ready(ipts, msg, &cmd_status);
  1540. + break;
  1541. + case IPTS_RSP(GET_DEVICE_INFO):
  1542. + ipts_receiver_handle_get_device_info(ipts, msg, &cmd_status);
  1543. + break;
  1544. + case IPTS_RSP(CLEAR_MEM_WINDOW):
  1545. + ipts_receiver_handle_clear_mem_window(ipts, msg,
  1546. + &cmd_status, &ret);
  1547. + break;
  1548. + case IPTS_RSP(SET_MODE):
  1549. + ipts_receiver_handle_set_mode(ipts, msg, &cmd_status);
  1550. + break;
  1551. + case IPTS_RSP(SET_MEM_WINDOW):
  1552. + ipts_receiver_handle_set_mem_window(ipts, msg, &cmd_status);
  1553. + break;
  1554. + case IPTS_RSP(READY_FOR_DATA):
  1555. + ipts_receiver_handle_ready_for_data(ipts, msg);
  1556. + break;
  1557. + case IPTS_RSP(FEEDBACK):
  1558. + ipts_recever_handle_feedback(ipts, msg, &cmd_status);
  1559. + break;
  1560. + case IPTS_RSP(QUIESCE_IO):
  1561. + ipts_receiver_handle_quiesce_io(ipts, msg);
  1562. + break;
  1563. + }
  1564. +
  1565. + if (ipts->status == IPTS_HOST_STATUS_STOPPING)
  1566. + return 0;
  1567. +
  1568. + if (msg->status == IPTS_ME_STATUS_SENSOR_UNEXPECTED_RESET ||
  1569. + msg->status == IPTS_ME_STATUS_SENSOR_EXPECTED_RESET) {
  1570. + dev_info(ipts->dev, "Sensor has been reset: %d\n", msg->status);
  1571. + ipts_control_restart(ipts);
  1572. + }
  1573. +
  1574. + if (cmd_status)
  1575. + ipts_control_restart(ipts);
  1576. +
  1577. + return ret;
  1578. +}
  1579. +
  1580. +int ipts_receiver_loop(void *data)
  1581. +{
  1582. + u32 msg_len;
  1583. + struct ipts_context *ipts;
  1584. + struct ipts_response msg;
  1585. +
  1586. + ipts = (struct ipts_context *)data;
  1587. + dev_info(ipts->dev, "Starting receive loop\n");
  1588. +
  1589. + while (!kthread_should_stop()) {
  1590. + msg_len = mei_cldev_recv(ipts->client_dev,
  1591. + (u8 *)&msg, sizeof(msg));
  1592. +
  1593. + if (msg_len <= 0) {
  1594. + dev_err(ipts->dev, "Error in reading ME message\n");
  1595. + continue;
  1596. + }
  1597. +
  1598. + if (ipts_receiver_handle_response(ipts, &msg, msg_len))
  1599. + dev_err(ipts->dev, "Error in handling ME message\n");
  1600. + }
  1601. +
  1602. + dev_info(ipts->dev, "Stopping receive loop\n");
  1603. + return 0;
  1604. +}
  1605. diff --git a/drivers/input/touchscreen/ipts/receiver.h b/drivers/input/touchscreen/ipts/receiver.h
  1606. new file mode 100644
  1607. index 000000000000..4d413a0abd4c
  1608. --- /dev/null
  1609. +++ b/drivers/input/touchscreen/ipts/receiver.h
  1610. @@ -0,0 +1,8 @@
  1611. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1612. +
  1613. +#ifndef _IPTS_RECEIVER_H_
  1614. +#define _IPTS_RECEIVER_H_
  1615. +
  1616. +int ipts_receiver_loop(void *data);
  1617. +
  1618. +#endif /* _IPTS_RECEIVER_H_ */
  1619. diff --git a/drivers/input/touchscreen/ipts/resources.c b/drivers/input/touchscreen/ipts/resources.c
  1620. new file mode 100644
  1621. index 000000000000..704db9fdd3fd
  1622. --- /dev/null
  1623. +++ b/drivers/input/touchscreen/ipts/resources.c
  1624. @@ -0,0 +1,131 @@
  1625. +// SPDX-License-Identifier: GPL-2.0-or-later
  1626. +
  1627. +#include <linux/dma-mapping.h>
  1628. +
  1629. +#include "context.h"
  1630. +
  1631. +void ipts_resources_free(struct ipts_context *ipts)
  1632. +{
  1633. + int i;
  1634. + u32 touch_buffer_size;
  1635. + u32 feedback_buffer_size;
  1636. + struct ipts_buffer_info *buffers;
  1637. +
  1638. + touch_buffer_size = ipts->device_info.data_size;
  1639. + feedback_buffer_size = ipts->device_info.feedback_size;
  1640. +
  1641. + buffers = ipts->data;
  1642. + for (i = 0; i < 16; i++) {
  1643. + if (!buffers[i].address)
  1644. + continue;
  1645. +
  1646. + dmam_free_coherent(ipts->dev, touch_buffer_size,
  1647. + buffers[i].address, buffers[i].dma_address);
  1648. +
  1649. + buffers[i].address = 0;
  1650. + buffers[i].dma_address = 0;
  1651. + }
  1652. +
  1653. + buffers = ipts->feedback;
  1654. + for (i = 0; i < 16; i++) {
  1655. + if (!buffers[i].address)
  1656. + continue;
  1657. +
  1658. + dmam_free_coherent(ipts->dev, feedback_buffer_size,
  1659. + buffers[i].address, buffers[i].dma_address);
  1660. +
  1661. + buffers[i].address = 0;
  1662. + buffers[i].dma_address = 0;
  1663. + }
  1664. +
  1665. + if (ipts->doorbell.address) {
  1666. + dmam_free_coherent(ipts->dev, sizeof(u32),
  1667. + ipts->doorbell.address,
  1668. + ipts->doorbell.dma_address);
  1669. +
  1670. + ipts->doorbell.address = 0;
  1671. + ipts->doorbell.dma_address = 0;
  1672. + }
  1673. +
  1674. + if (ipts->workqueue.address) {
  1675. + dmam_free_coherent(ipts->dev, sizeof(u32),
  1676. + ipts->workqueue.address,
  1677. + ipts->workqueue.dma_address);
  1678. +
  1679. + ipts->workqueue.address = 0;
  1680. + ipts->workqueue.dma_address = 0;
  1681. + }
  1682. +
  1683. + if (ipts->host2me.address) {
  1684. + dmam_free_coherent(ipts->dev, touch_buffer_size,
  1685. + ipts->host2me.address,
  1686. + ipts->host2me.dma_address);
  1687. +
  1688. + ipts->host2me.address = 0;
  1689. + ipts->host2me.dma_address = 0;
  1690. + }
  1691. +}
  1692. +
  1693. +int ipts_resources_init(struct ipts_context *ipts)
  1694. +{
  1695. + int i;
  1696. + u32 touch_buffer_size;
  1697. + u32 feedback_buffer_size;
  1698. + struct ipts_buffer_info *buffers;
  1699. +
  1700. + touch_buffer_size = ipts->device_info.data_size;
  1701. + feedback_buffer_size = ipts->device_info.feedback_size;
  1702. +
  1703. + buffers = ipts->data;
  1704. + for (i = 0; i < 16; i++) {
  1705. + buffers[i].address = dmam_alloc_coherent(ipts->dev,
  1706. + touch_buffer_size,
  1707. + &buffers[i].dma_address,
  1708. + GFP_ATOMIC | __GFP_ZERO);
  1709. +
  1710. + if (!buffers[i].address)
  1711. + goto release_resources;
  1712. + }
  1713. +
  1714. + buffers = ipts->feedback;
  1715. + for (i = 0; i < 16; i++) {
  1716. + buffers[i].address = dmam_alloc_coherent(ipts->dev,
  1717. + feedback_buffer_size,
  1718. + &buffers[i].dma_address,
  1719. + GFP_ATOMIC | __GFP_ZERO);
  1720. +
  1721. + if (!buffers[i].address)
  1722. + goto release_resources;
  1723. + }
  1724. +
  1725. + ipts->doorbell.address = dmam_alloc_coherent(ipts->dev,
  1726. + sizeof(u32),
  1727. + &ipts->doorbell.dma_address,
  1728. + GFP_ATOMIC | __GFP_ZERO);
  1729. +
  1730. + if (!ipts->doorbell.address)
  1731. + goto release_resources;
  1732. +
  1733. + ipts->workqueue.address = dmam_alloc_coherent(ipts->dev,
  1734. + sizeof(u32),
  1735. + &ipts->workqueue.dma_address,
  1736. + GFP_ATOMIC | __GFP_ZERO);
  1737. +
  1738. + if (!ipts->workqueue.address)
  1739. + goto release_resources;
  1740. +
  1741. + ipts->host2me.address = dmam_alloc_coherent(ipts->dev,
  1742. + touch_buffer_size,
  1743. + &ipts->host2me.dma_address,
  1744. + GFP_ATOMIC | __GFP_ZERO);
  1745. +
  1746. + if (!ipts->workqueue.address)
  1747. + goto release_resources;
  1748. +
  1749. + return 0;
  1750. +
  1751. +release_resources:
  1752. +
  1753. + ipts_resources_free(ipts);
  1754. + return -ENOMEM;
  1755. +}
  1756. diff --git a/drivers/input/touchscreen/ipts/resources.h b/drivers/input/touchscreen/ipts/resources.h
  1757. new file mode 100644
  1758. index 000000000000..cf9807b0dbe6
  1759. --- /dev/null
  1760. +++ b/drivers/input/touchscreen/ipts/resources.h
  1761. @@ -0,0 +1,11 @@
  1762. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1763. +
  1764. +#ifndef _IPTS_RESOURCES_H_
  1765. +#define _IPTS_RESOURCES_H_
  1766. +
  1767. +#include "context.h"
  1768. +
  1769. +int ipts_resources_init(struct ipts_context *ipts);
  1770. +void ipts_resources_free(struct ipts_context *ipts);
  1771. +
  1772. +#endif /* _IPTS_RESOURCES_H_ */
  1773. diff --git a/drivers/input/touchscreen/ipts/singletouch.c b/drivers/input/touchscreen/ipts/singletouch.c
  1774. new file mode 100644
  1775. index 000000000000..ed70444f649c
  1776. --- /dev/null
  1777. +++ b/drivers/input/touchscreen/ipts/singletouch.c
  1778. @@ -0,0 +1,64 @@
  1779. +// SPDX-License-Identifier: GPL-2.0-or-later
  1780. +
  1781. +#include <linux/input.h>
  1782. +#include <linux/kernel.h>
  1783. +
  1784. +#include "context.h"
  1785. +#include "protocol/data.h"
  1786. +#include "protocol/singletouch.h"
  1787. +
  1788. +void ipts_singletouch_handle_input(struct ipts_context *ipts,
  1789. + struct ipts_data *data)
  1790. +{
  1791. + struct ipts_singletouch_report *report =
  1792. + (struct ipts_singletouch_report *)&data->data[1];
  1793. +
  1794. + input_report_key(ipts->singletouch, BTN_TOUCH, report->touch);
  1795. + input_report_abs(ipts->singletouch, ABS_X, report->x);
  1796. + input_report_abs(ipts->singletouch, ABS_Y, report->y);
  1797. +
  1798. + input_sync(ipts->singletouch);
  1799. +}
  1800. +
  1801. +int ipts_singletouch_init(struct ipts_context *ipts)
  1802. +{
  1803. + int ret;
  1804. +
  1805. + ipts->singletouch = input_allocate_device();
  1806. + if (!ipts->singletouch)
  1807. + return -ENOMEM;
  1808. +
  1809. + __set_bit(INPUT_PROP_DIRECT, ipts->singletouch->propbit);
  1810. +
  1811. + input_set_capability(ipts->singletouch, EV_KEY, BTN_TOUCH);
  1812. + input_set_abs_params(ipts->singletouch, ABS_X, 0, 32767, 0, 0);
  1813. + input_abs_set_res(ipts->singletouch, ABS_X, 112);
  1814. + input_set_abs_params(ipts->singletouch, ABS_Y, 0, 32767, 0, 0);
  1815. + input_abs_set_res(ipts->singletouch, ABS_Y, 199);
  1816. +
  1817. + ipts->singletouch->id.bustype = BUS_MEI;
  1818. + ipts->singletouch->id.vendor = ipts->device_info.vendor_id;
  1819. + ipts->singletouch->id.product = ipts->device_info.device_id;
  1820. + ipts->singletouch->id.version = ipts->device_info.fw_rev;
  1821. +
  1822. + ipts->singletouch->phys = "heci3";
  1823. + ipts->singletouch->name = "IPTS Singletouch";
  1824. +
  1825. + ret = input_register_device(ipts->singletouch);
  1826. + if (ret) {
  1827. + dev_err(ipts->dev, "Cannot register input device: %s (%d)\n",
  1828. + ipts->singletouch->name, ret);
  1829. + input_free_device(ipts->singletouch);
  1830. + return ret;
  1831. + }
  1832. +
  1833. + return 0;
  1834. +}
  1835. +
  1836. +void ipts_singletouch_free(struct ipts_context *ipts)
  1837. +{
  1838. + if (!ipts->singletouch)
  1839. + return;
  1840. +
  1841. + input_unregister_device(ipts->singletouch);
  1842. +}
  1843. diff --git a/drivers/input/touchscreen/ipts/singletouch.h b/drivers/input/touchscreen/ipts/singletouch.h
  1844. new file mode 100644
  1845. index 000000000000..53207497a462
  1846. --- /dev/null
  1847. +++ b/drivers/input/touchscreen/ipts/singletouch.h
  1848. @@ -0,0 +1,14 @@
  1849. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  1850. +
  1851. +#ifndef _IPTS_SINGLETOUCH_H_
  1852. +#define _IPTS_SINGLETOUCH_H_
  1853. +
  1854. +#include "context.h"
  1855. +#include "protocol/data.h"
  1856. +
  1857. +void ipts_singletouch_handle_input(struct ipts_context *ipts,
  1858. + struct ipts_data *data);
  1859. +int ipts_singletouch_init(struct ipts_context *ipts);
  1860. +void ipts_singletouch_free(struct ipts_context *ipts);
  1861. +
  1862. +#endif /* _IPTS_SINGLETOUCH_H_ */
  1863. diff --git a/drivers/input/touchscreen/ipts/stylus.c b/drivers/input/touchscreen/ipts/stylus.c
  1864. new file mode 100644
  1865. index 000000000000..987fa756fec3
  1866. --- /dev/null
  1867. +++ b/drivers/input/touchscreen/ipts/stylus.c
  1868. @@ -0,0 +1,179 @@
  1869. +// SPDX-License-Identifier: GPL-2.0-or-later
  1870. +
  1871. +#include <linux/input.h>
  1872. +#include <linux/kernel.h>
  1873. +
  1874. +#include "context.h"
  1875. +#include "math.h"
  1876. +#include "protocol/payload.h"
  1877. +#include "protocol/stylus.h"
  1878. +
  1879. +static void ipts_stylus_handle_stylus_data(struct ipts_context *ipts,
  1880. + struct ipts_stylus_report_data *data)
  1881. +{
  1882. + u8 prox = data->mode & IPTS_STYLUS_REPORT_MODE_PROX;
  1883. + u8 touch = data->mode & IPTS_STYLUS_REPORT_MODE_TOUCH;
  1884. + u8 button = data->mode & IPTS_STYLUS_REPORT_MODE_BUTTON;
  1885. + u8 rubber = data->mode & IPTS_STYLUS_REPORT_MODE_ERASER;
  1886. +
  1887. + s32 tx = 0;
  1888. + s32 ty = 0;
  1889. +
  1890. + // avoid unnecessary computations
  1891. + // altitude is zero if stylus does not touch the screen
  1892. + if (data->altitude) {
  1893. + ipts_math_altitude_azimuth_to_tilt(data->altitude,
  1894. + data->azimuth, &tx, &ty);
  1895. + }
  1896. +
  1897. + input_report_key(ipts->stylus, BTN_TOUCH, touch);
  1898. + input_report_key(ipts->stylus, BTN_TOOL_PEN, prox && !rubber);
  1899. + input_report_key(ipts->stylus, BTN_TOOL_RUBBER, prox && rubber);
  1900. + input_report_key(ipts->stylus, BTN_STYLUS, button);
  1901. +
  1902. + input_report_abs(ipts->stylus, ABS_X, data->x);
  1903. + input_report_abs(ipts->stylus, ABS_Y, data->y);
  1904. + input_report_abs(ipts->stylus, ABS_PRESSURE, data->pressure);
  1905. + input_report_abs(ipts->stylus, ABS_MISC, data->timestamp);
  1906. +
  1907. + input_report_abs(ipts->stylus, ABS_TILT_X, tx);
  1908. + input_report_abs(ipts->stylus, ABS_TILT_Y, ty);
  1909. +
  1910. + input_sync(ipts->stylus);
  1911. +}
  1912. +
  1913. +static void ipts_stylus_handle_report_tilt_serial(struct ipts_context *ipts,
  1914. + struct ipts_report *report)
  1915. +{
  1916. + int i;
  1917. + struct ipts_stylus_report_serial *stylus_report;
  1918. + struct ipts_stylus_report_data *data;
  1919. +
  1920. + stylus_report = (struct ipts_stylus_report_serial *)report->data;
  1921. + data = (struct ipts_stylus_report_data *)stylus_report->data;
  1922. +
  1923. + // TODO: Track serial number and support multiple styli
  1924. +
  1925. + for (i = 0; i < stylus_report->reports; i++)
  1926. + ipts_stylus_handle_stylus_data(ipts, &data[i]);
  1927. +}
  1928. +
  1929. +static void ipts_stylus_handle_report_tilt(struct ipts_context *ipts,
  1930. + struct ipts_report *report)
  1931. +{
  1932. + int i;
  1933. + struct ipts_stylus_report *stylus_report;
  1934. + struct ipts_stylus_report_data *data;
  1935. +
  1936. + stylus_report = (struct ipts_stylus_report *)report->data;
  1937. + data = (struct ipts_stylus_report_data *)stylus_report->data;
  1938. +
  1939. + for (i = 0; i < stylus_report->reports; i++)
  1940. + ipts_stylus_handle_stylus_data(ipts, &data[i]);
  1941. +}
  1942. +
  1943. +static void ipts_stylus_handle_report_no_tilt(struct ipts_context *ipts,
  1944. + struct ipts_report *report)
  1945. +{
  1946. + int i;
  1947. + struct ipts_stylus_report_serial *stylus_report;
  1948. + struct ipts_stylus_report_data_no_tilt *data;
  1949. + struct ipts_stylus_report_data new_data;
  1950. +
  1951. + stylus_report = (struct ipts_stylus_report_serial *)report->data;
  1952. + data = (struct ipts_stylus_report_data_no_tilt *)stylus_report->data;
  1953. +
  1954. + for (i = 0; i < stylus_report->reports; i++) {
  1955. + new_data.mode = data[i].mode;
  1956. + new_data.x = data[i].x;
  1957. + new_data.y = data[i].y;
  1958. + new_data.pressure = data[i].pressure * 4;
  1959. + new_data.altitude = 0;
  1960. + new_data.azimuth = 0;
  1961. + new_data.timestamp = 0;
  1962. +
  1963. + ipts_stylus_handle_stylus_data(ipts, &new_data);
  1964. + }
  1965. +}
  1966. +
  1967. +void ipts_stylus_handle_input(struct ipts_context *ipts,
  1968. + struct ipts_payload_frame *frame)
  1969. +{
  1970. + int size;
  1971. + struct ipts_report *report;
  1972. +
  1973. + size = 0;
  1974. +
  1975. + while (size < frame->size) {
  1976. + report = (struct ipts_report *)&frame->data[size];
  1977. + size += sizeof(struct ipts_report) + report->size;
  1978. +
  1979. + switch (report->type) {
  1980. + case IPTS_REPORT_TYPE_STYLUS_NO_TILT:
  1981. + ipts_stylus_handle_report_no_tilt(ipts, report);
  1982. + break;
  1983. + case IPTS_REPORT_TYPE_STYLUS_TILT:
  1984. + ipts_stylus_handle_report_tilt(ipts, report);
  1985. + break;
  1986. + case IPTS_REPORT_TYPE_STYLUS_TILT_SERIAL:
  1987. + ipts_stylus_handle_report_tilt_serial(ipts, report);
  1988. + break;
  1989. + default:
  1990. + // ignored
  1991. + break;
  1992. + }
  1993. + }
  1994. +}
  1995. +
  1996. +int ipts_stylus_init(struct ipts_context *ipts)
  1997. +{
  1998. + int ret;
  1999. +
  2000. + ipts->stylus = input_allocate_device();
  2001. + if (!ipts->stylus)
  2002. + return -ENOMEM;
  2003. +
  2004. + __set_bit(INPUT_PROP_DIRECT, ipts->stylus->propbit);
  2005. + __set_bit(INPUT_PROP_POINTER, ipts->stylus->propbit);
  2006. +
  2007. + input_set_abs_params(ipts->stylus, ABS_X, 0, 9600, 0, 0);
  2008. + input_abs_set_res(ipts->stylus, ABS_X, 34);
  2009. + input_set_abs_params(ipts->stylus, ABS_Y, 0, 7200, 0, 0);
  2010. + input_abs_set_res(ipts->stylus, ABS_Y, 38);
  2011. + input_set_abs_params(ipts->stylus, ABS_PRESSURE, 0, 4096, 0, 0);
  2012. + input_set_abs_params(ipts->stylus, ABS_TILT_X, -9000, 9000, 0, 0);
  2013. + input_abs_set_res(ipts->stylus, ABS_TILT_X, 5730);
  2014. + input_set_abs_params(ipts->stylus, ABS_TILT_Y, -9000, 9000, 0, 0);
  2015. + input_abs_set_res(ipts->stylus, ABS_TILT_Y, 5730);
  2016. + input_set_abs_params(ipts->stylus, ABS_MISC, 0, 65535, 0, 0);
  2017. + input_set_capability(ipts->stylus, EV_KEY, BTN_TOUCH);
  2018. + input_set_capability(ipts->stylus, EV_KEY, BTN_STYLUS);
  2019. + input_set_capability(ipts->stylus, EV_KEY, BTN_TOOL_PEN);
  2020. + input_set_capability(ipts->stylus, EV_KEY, BTN_TOOL_RUBBER);
  2021. +
  2022. + ipts->stylus->id.bustype = BUS_MEI;
  2023. + ipts->stylus->id.vendor = ipts->device_info.vendor_id;
  2024. + ipts->stylus->id.product = ipts->device_info.device_id;
  2025. + ipts->stylus->id.version = ipts->device_info.fw_rev;
  2026. +
  2027. + ipts->stylus->phys = "heci3";
  2028. + ipts->stylus->name = "IPTS Stylus";
  2029. +
  2030. + ret = input_register_device(ipts->stylus);
  2031. + if (ret) {
  2032. + dev_err(ipts->dev, "Cannot register input device: %s (%d)\n",
  2033. + ipts->stylus->name, ret);
  2034. + input_free_device(ipts->stylus);
  2035. + return ret;
  2036. + }
  2037. +
  2038. + return 0;
  2039. +}
  2040. +
  2041. +void ipts_stylus_free(struct ipts_context *ipts)
  2042. +{
  2043. + if (!ipts->stylus)
  2044. + return;
  2045. +
  2046. + input_unregister_device(ipts->stylus);
  2047. +}
  2048. diff --git a/drivers/input/touchscreen/ipts/stylus.h b/drivers/input/touchscreen/ipts/stylus.h
  2049. new file mode 100644
  2050. index 000000000000..5b93add1eac2
  2051. --- /dev/null
  2052. +++ b/drivers/input/touchscreen/ipts/stylus.h
  2053. @@ -0,0 +1,14 @@
  2054. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  2055. +
  2056. +#ifndef _IPTS_STYLUS_H_
  2057. +#define _IPTS_STYLUS_H_
  2058. +
  2059. +#include "context.h"
  2060. +#include "protocol/payload.h"
  2061. +
  2062. +void ipts_stylus_handle_input(struct ipts_context *ipts,
  2063. + struct ipts_payload_frame *frame);
  2064. +int ipts_stylus_init(struct ipts_context *ipts);
  2065. +void ipts_stylus_free(struct ipts_context *ipts);
  2066. +
  2067. +#endif /* _IPTS_STYLUS_H_ */
  2068. --
  2069. 2.30.1