18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * MacBook (Pro) SPI keyboard and touchpad driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2015-2018 Federico Lorenzi 68c2ecf20Sopenharmony_ci * Copyright (c) 2017-2018 Ronald Tschalär 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * The keyboard and touchpad controller on the MacBookAir6, MacBookPro12, 118c2ecf20Sopenharmony_ci * MacBook8 and newer can be driven either by USB or SPI. However the USB 128c2ecf20Sopenharmony_ci * pins are only connected on the MacBookAir6 and 7 and the MacBookPro12. 138c2ecf20Sopenharmony_ci * All others need this driver. The interface is selected using ACPI methods: 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * * UIEN ("USB Interface Enable"): If invoked with argument 1, disables SPI 168c2ecf20Sopenharmony_ci * and enables USB. If invoked with argument 0, disables USB. 178c2ecf20Sopenharmony_ci * * UIST ("USB Interface Status"): Returns 1 if USB is enabled, 0 otherwise. 188c2ecf20Sopenharmony_ci * * SIEN ("SPI Interface Enable"): If invoked with argument 1, disables USB 198c2ecf20Sopenharmony_ci * and enables SPI. If invoked with argument 0, disables SPI. 208c2ecf20Sopenharmony_ci * * SIST ("SPI Interface Status"): Returns 1 if SPI is enabled, 0 otherwise. 218c2ecf20Sopenharmony_ci * * ISOL: Resets the four GPIO pins used for SPI. Intended to be invoked with 228c2ecf20Sopenharmony_ci * argument 1, then once more with argument 0. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * UIEN and UIST are only provided on models where the USB pins are connected. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * SPI-based Protocol 278c2ecf20Sopenharmony_ci * ------------------ 288c2ecf20Sopenharmony_ci * 298c2ecf20Sopenharmony_ci * The device and driver exchange messages (struct message); each message is 308c2ecf20Sopenharmony_ci * encapsulated in one or more packets (struct spi_packet). There are two types 318c2ecf20Sopenharmony_ci * of exchanges: reads, and writes. A read is signaled by a GPE, upon which one 328c2ecf20Sopenharmony_ci * message can be read from the device. A write exchange consists of writing a 338c2ecf20Sopenharmony_ci * command message, immediately reading a short status packet, and then, upon 348c2ecf20Sopenharmony_ci * receiving a GPE, reading the response message. Write exchanges cannot be 358c2ecf20Sopenharmony_ci * interleaved, i.e. a new write exchange must not be started till the previous 368c2ecf20Sopenharmony_ci * write exchange is complete. Whether a received message is part of a read or 378c2ecf20Sopenharmony_ci * write exchange is indicated in the encapsulating packet's flags field. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * A single message may be too large to fit in a single packet (which has a 408c2ecf20Sopenharmony_ci * fixed, 256-byte size). In that case it will be split over multiple, 418c2ecf20Sopenharmony_ci * consecutive packets. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <linux/acpi.h> 458c2ecf20Sopenharmony_ci#include <linux/crc16.h> 468c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 478c2ecf20Sopenharmony_ci#include <linux/delay.h> 488c2ecf20Sopenharmony_ci#include <linux/efi.h> 498c2ecf20Sopenharmony_ci#include <linux/input.h> 508c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 518c2ecf20Sopenharmony_ci#include <linux/ktime.h> 528c2ecf20Sopenharmony_ci#include <linux/leds.h> 538c2ecf20Sopenharmony_ci#include <linux/module.h> 548c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 558c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 568c2ecf20Sopenharmony_ci#include <linux/wait.h> 578c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#include <asm/barrier.h> 608c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define CREATE_TRACE_POINTS 638c2ecf20Sopenharmony_ci#include "applespi.h" 648c2ecf20Sopenharmony_ci#include "applespi_trace.h" 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci#define APPLESPI_PACKET_SIZE 256 678c2ecf20Sopenharmony_ci#define APPLESPI_STATUS_SIZE 4 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci#define PACKET_TYPE_READ 0x20 708c2ecf20Sopenharmony_ci#define PACKET_TYPE_WRITE 0x40 718c2ecf20Sopenharmony_ci#define PACKET_DEV_KEYB 0x01 728c2ecf20Sopenharmony_ci#define PACKET_DEV_TPAD 0x02 738c2ecf20Sopenharmony_ci#define PACKET_DEV_INFO 0xd0 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci#define MAX_ROLLOVER 6 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define MAX_FINGERS 11 788c2ecf20Sopenharmony_ci#define MAX_FINGER_ORIENTATION 16384 798c2ecf20Sopenharmony_ci#define MAX_PKTS_PER_MSG 2 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci#define KBD_BL_LEVEL_MIN 32U 828c2ecf20Sopenharmony_ci#define KBD_BL_LEVEL_MAX 255U 838c2ecf20Sopenharmony_ci#define KBD_BL_LEVEL_SCALE 1000000U 848c2ecf20Sopenharmony_ci#define KBD_BL_LEVEL_ADJ \ 858c2ecf20Sopenharmony_ci ((KBD_BL_LEVEL_MAX - KBD_BL_LEVEL_MIN) * KBD_BL_LEVEL_SCALE / 255U) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci#define EFI_BL_LEVEL_NAME L"KeyboardBacklightLevel" 888c2ecf20Sopenharmony_ci#define EFI_BL_LEVEL_GUID EFI_GUID(0xa076d2af, 0x9678, 0x4386, 0x8b, 0x58, 0x1f, 0xc8, 0xef, 0x04, 0x16, 0x19) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci#define APPLE_FLAG_FKEY 0x01 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define SPI_RW_CHG_DELAY_US 100 /* from experimentation, in µs */ 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci#define SYNAPTICS_VENDOR_ID 0x06cb 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic unsigned int fnmode = 1; 978c2ecf20Sopenharmony_cimodule_param(fnmode, uint, 0644); 988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fnmode, "Mode of Fn key on Apple keyboards (0 = disabled, [1] = fkeyslast, 2 = fkeysfirst)"); 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic unsigned int fnremap; 1018c2ecf20Sopenharmony_cimodule_param(fnremap, uint, 0644); 1028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fnremap, "Remap Fn key ([0] = no-remap; 1 = left-ctrl, 2 = left-shift, 3 = left-alt, 4 = left-meta, 6 = right-shift, 7 = right-alt, 8 = right-meta)"); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic bool iso_layout; 1058c2ecf20Sopenharmony_cimodule_param(iso_layout, bool, 0644); 1068c2ecf20Sopenharmony_ciMODULE_PARM_DESC(iso_layout, "Enable/Disable hardcoded ISO-layout of the keyboard. ([0] = disabled, 1 = enabled)"); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic char touchpad_dimensions[40]; 1098c2ecf20Sopenharmony_cimodule_param_string(touchpad_dimensions, touchpad_dimensions, 1108c2ecf20Sopenharmony_ci sizeof(touchpad_dimensions), 0444); 1118c2ecf20Sopenharmony_ciMODULE_PARM_DESC(touchpad_dimensions, "The pixel dimensions of the touchpad, as XxY+W+H ."); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci/** 1148c2ecf20Sopenharmony_ci * struct keyboard_protocol - keyboard message. 1158c2ecf20Sopenharmony_ci * message.type = 0x0110, message.length = 0x000a 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * @unknown1: unknown 1188c2ecf20Sopenharmony_ci * @modifiers: bit-set of modifier/control keys pressed 1198c2ecf20Sopenharmony_ci * @unknown2: unknown 1208c2ecf20Sopenharmony_ci * @keys_pressed: the (non-modifier) keys currently pressed 1218c2ecf20Sopenharmony_ci * @fn_pressed: whether the fn key is currently pressed 1228c2ecf20Sopenharmony_ci * @crc16: crc over the whole message struct (message header + 1238c2ecf20Sopenharmony_ci * this struct) minus this @crc16 field 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_cistruct keyboard_protocol { 1268c2ecf20Sopenharmony_ci u8 unknown1; 1278c2ecf20Sopenharmony_ci u8 modifiers; 1288c2ecf20Sopenharmony_ci u8 unknown2; 1298c2ecf20Sopenharmony_ci u8 keys_pressed[MAX_ROLLOVER]; 1308c2ecf20Sopenharmony_ci u8 fn_pressed; 1318c2ecf20Sopenharmony_ci __le16 crc16; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/** 1358c2ecf20Sopenharmony_ci * struct tp_finger - single trackpad finger structure, le16-aligned 1368c2ecf20Sopenharmony_ci * 1378c2ecf20Sopenharmony_ci * @origin: zero when switching track finger 1388c2ecf20Sopenharmony_ci * @abs_x: absolute x coordinate 1398c2ecf20Sopenharmony_ci * @abs_y: absolute y coordinate 1408c2ecf20Sopenharmony_ci * @rel_x: relative x coordinate 1418c2ecf20Sopenharmony_ci * @rel_y: relative y coordinate 1428c2ecf20Sopenharmony_ci * @tool_major: tool area, major axis 1438c2ecf20Sopenharmony_ci * @tool_minor: tool area, minor axis 1448c2ecf20Sopenharmony_ci * @orientation: 16384 when point, else 15 bit angle 1458c2ecf20Sopenharmony_ci * @touch_major: touch area, major axis 1468c2ecf20Sopenharmony_ci * @touch_minor: touch area, minor axis 1478c2ecf20Sopenharmony_ci * @unused: zeros 1488c2ecf20Sopenharmony_ci * @pressure: pressure on forcetouch touchpad 1498c2ecf20Sopenharmony_ci * @multi: one finger: varies, more fingers: constant 1508c2ecf20Sopenharmony_ci * @crc16: on last finger: crc over the whole message struct 1518c2ecf20Sopenharmony_ci * (i.e. message header + this struct) minus the last 1528c2ecf20Sopenharmony_ci * @crc16 field; unknown on all other fingers. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_cistruct tp_finger { 1558c2ecf20Sopenharmony_ci __le16 origin; 1568c2ecf20Sopenharmony_ci __le16 abs_x; 1578c2ecf20Sopenharmony_ci __le16 abs_y; 1588c2ecf20Sopenharmony_ci __le16 rel_x; 1598c2ecf20Sopenharmony_ci __le16 rel_y; 1608c2ecf20Sopenharmony_ci __le16 tool_major; 1618c2ecf20Sopenharmony_ci __le16 tool_minor; 1628c2ecf20Sopenharmony_ci __le16 orientation; 1638c2ecf20Sopenharmony_ci __le16 touch_major; 1648c2ecf20Sopenharmony_ci __le16 touch_minor; 1658c2ecf20Sopenharmony_ci __le16 unused[2]; 1668c2ecf20Sopenharmony_ci __le16 pressure; 1678c2ecf20Sopenharmony_ci __le16 multi; 1688c2ecf20Sopenharmony_ci __le16 crc16; 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/** 1728c2ecf20Sopenharmony_ci * struct touchpad_protocol - touchpad message. 1738c2ecf20Sopenharmony_ci * message.type = 0x0210 1748c2ecf20Sopenharmony_ci * 1758c2ecf20Sopenharmony_ci * @unknown1: unknown 1768c2ecf20Sopenharmony_ci * @clicked: 1 if a button-click was detected, 0 otherwise 1778c2ecf20Sopenharmony_ci * @unknown2: unknown 1788c2ecf20Sopenharmony_ci * @number_of_fingers: the number of fingers being reported in @fingers 1798c2ecf20Sopenharmony_ci * @clicked2: same as @clicked 1808c2ecf20Sopenharmony_ci * @unknown3: unknown 1818c2ecf20Sopenharmony_ci * @fingers: the data for each finger 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cistruct touchpad_protocol { 1848c2ecf20Sopenharmony_ci u8 unknown1[1]; 1858c2ecf20Sopenharmony_ci u8 clicked; 1868c2ecf20Sopenharmony_ci u8 unknown2[28]; 1878c2ecf20Sopenharmony_ci u8 number_of_fingers; 1888c2ecf20Sopenharmony_ci u8 clicked2; 1898c2ecf20Sopenharmony_ci u8 unknown3[16]; 1908c2ecf20Sopenharmony_ci struct tp_finger fingers[]; 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/** 1948c2ecf20Sopenharmony_ci * struct command_protocol_tp_info - get touchpad info. 1958c2ecf20Sopenharmony_ci * message.type = 0x1020, message.length = 0x0000 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * @crc16: crc over the whole message struct (message header + 1988c2ecf20Sopenharmony_ci * this struct) minus this @crc16 field 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_cistruct command_protocol_tp_info { 2018c2ecf20Sopenharmony_ci __le16 crc16; 2028c2ecf20Sopenharmony_ci}; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/** 2058c2ecf20Sopenharmony_ci * struct touchpad_info - touchpad info response. 2068c2ecf20Sopenharmony_ci * message.type = 0x1020, message.length = 0x006e 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * @unknown1: unknown 2098c2ecf20Sopenharmony_ci * @model_flags: flags (vary by model number, but significance otherwise 2108c2ecf20Sopenharmony_ci * unknown) 2118c2ecf20Sopenharmony_ci * @model_no: the touchpad model number 2128c2ecf20Sopenharmony_ci * @unknown2: unknown 2138c2ecf20Sopenharmony_ci * @crc16: crc over the whole message struct (message header + 2148c2ecf20Sopenharmony_ci * this struct) minus this @crc16 field 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_cistruct touchpad_info_protocol { 2178c2ecf20Sopenharmony_ci u8 unknown1[105]; 2188c2ecf20Sopenharmony_ci u8 model_flags; 2198c2ecf20Sopenharmony_ci u8 model_no; 2208c2ecf20Sopenharmony_ci u8 unknown2[3]; 2218c2ecf20Sopenharmony_ci __le16 crc16; 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/** 2258c2ecf20Sopenharmony_ci * struct command_protocol_mt_init - initialize multitouch. 2268c2ecf20Sopenharmony_ci * message.type = 0x0252, message.length = 0x0002 2278c2ecf20Sopenharmony_ci * 2288c2ecf20Sopenharmony_ci * @cmd: value: 0x0102 2298c2ecf20Sopenharmony_ci * @crc16: crc over the whole message struct (message header + 2308c2ecf20Sopenharmony_ci * this struct) minus this @crc16 field 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistruct command_protocol_mt_init { 2338c2ecf20Sopenharmony_ci __le16 cmd; 2348c2ecf20Sopenharmony_ci __le16 crc16; 2358c2ecf20Sopenharmony_ci}; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci/** 2388c2ecf20Sopenharmony_ci * struct command_protocol_capsl - toggle caps-lock led 2398c2ecf20Sopenharmony_ci * message.type = 0x0151, message.length = 0x0002 2408c2ecf20Sopenharmony_ci * 2418c2ecf20Sopenharmony_ci * @unknown: value: 0x01 (length?) 2428c2ecf20Sopenharmony_ci * @led: 0 off, 2 on 2438c2ecf20Sopenharmony_ci * @crc16: crc over the whole message struct (message header + 2448c2ecf20Sopenharmony_ci * this struct) minus this @crc16 field 2458c2ecf20Sopenharmony_ci */ 2468c2ecf20Sopenharmony_cistruct command_protocol_capsl { 2478c2ecf20Sopenharmony_ci u8 unknown; 2488c2ecf20Sopenharmony_ci u8 led; 2498c2ecf20Sopenharmony_ci __le16 crc16; 2508c2ecf20Sopenharmony_ci}; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci/** 2538c2ecf20Sopenharmony_ci * struct command_protocol_bl - set keyboard backlight brightness 2548c2ecf20Sopenharmony_ci * message.type = 0xB051, message.length = 0x0006 2558c2ecf20Sopenharmony_ci * 2568c2ecf20Sopenharmony_ci * @const1: value: 0x01B0 2578c2ecf20Sopenharmony_ci * @level: the brightness level to set 2588c2ecf20Sopenharmony_ci * @const2: value: 0x0001 (backlight off), 0x01F4 (backlight on) 2598c2ecf20Sopenharmony_ci * @crc16: crc over the whole message struct (message header + 2608c2ecf20Sopenharmony_ci * this struct) minus this @crc16 field 2618c2ecf20Sopenharmony_ci */ 2628c2ecf20Sopenharmony_cistruct command_protocol_bl { 2638c2ecf20Sopenharmony_ci __le16 const1; 2648c2ecf20Sopenharmony_ci __le16 level; 2658c2ecf20Sopenharmony_ci __le16 const2; 2668c2ecf20Sopenharmony_ci __le16 crc16; 2678c2ecf20Sopenharmony_ci}; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci/** 2708c2ecf20Sopenharmony_ci * struct message - a complete spi message. 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * Each message begins with fixed header, followed by a message-type specific 2738c2ecf20Sopenharmony_ci * payload, and ends with a 16-bit crc. Because of the varying lengths of the 2748c2ecf20Sopenharmony_ci * payload, the crc is defined at the end of each payload struct, rather than 2758c2ecf20Sopenharmony_ci * in this struct. 2768c2ecf20Sopenharmony_ci * 2778c2ecf20Sopenharmony_ci * @type: the message type 2788c2ecf20Sopenharmony_ci * @zero: always 0 2798c2ecf20Sopenharmony_ci * @counter: incremented on each message, rolls over after 255; there is a 2808c2ecf20Sopenharmony_ci * separate counter for each message type. 2818c2ecf20Sopenharmony_ci * @rsp_buf_len:response buffer length (the exact nature of this field is quite 2828c2ecf20Sopenharmony_ci * speculative). On a request/write this is often the same as 2838c2ecf20Sopenharmony_ci * @length, though in some cases it has been seen to be much larger 2848c2ecf20Sopenharmony_ci * (e.g. 0x400); on a response/read this the same as on the 2858c2ecf20Sopenharmony_ci * request; for reads that are not responses it is 0. 2868c2ecf20Sopenharmony_ci * @length: length of the remainder of the data in the whole message 2878c2ecf20Sopenharmony_ci * structure (after re-assembly in case of being split over 2888c2ecf20Sopenharmony_ci * multiple spi-packets), minus the trailing crc. The total size 2898c2ecf20Sopenharmony_ci * of the message struct is therefore @length + 10. 2908c2ecf20Sopenharmony_ci */ 2918c2ecf20Sopenharmony_cistruct message { 2928c2ecf20Sopenharmony_ci __le16 type; 2938c2ecf20Sopenharmony_ci u8 zero; 2948c2ecf20Sopenharmony_ci u8 counter; 2958c2ecf20Sopenharmony_ci __le16 rsp_buf_len; 2968c2ecf20Sopenharmony_ci __le16 length; 2978c2ecf20Sopenharmony_ci union { 2988c2ecf20Sopenharmony_ci struct keyboard_protocol keyboard; 2998c2ecf20Sopenharmony_ci struct touchpad_protocol touchpad; 3008c2ecf20Sopenharmony_ci struct touchpad_info_protocol tp_info; 3018c2ecf20Sopenharmony_ci struct command_protocol_tp_info tp_info_command; 3028c2ecf20Sopenharmony_ci struct command_protocol_mt_init init_mt_command; 3038c2ecf20Sopenharmony_ci struct command_protocol_capsl capsl_command; 3048c2ecf20Sopenharmony_ci struct command_protocol_bl bl_command; 3058c2ecf20Sopenharmony_ci u8 data[0]; 3068c2ecf20Sopenharmony_ci }; 3078c2ecf20Sopenharmony_ci}; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci/* type + zero + counter + rsp_buf_len + length */ 3108c2ecf20Sopenharmony_ci#define MSG_HEADER_SIZE 8 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci/** 3138c2ecf20Sopenharmony_ci * struct spi_packet - a complete spi packet; always 256 bytes. This carries 3148c2ecf20Sopenharmony_ci * the (parts of the) message in the data. But note that this does not 3158c2ecf20Sopenharmony_ci * necessarily contain a complete message, as in some cases (e.g. many 3168c2ecf20Sopenharmony_ci * fingers pressed) the message is split over multiple packets (see the 3178c2ecf20Sopenharmony_ci * @offset, @remaining, and @length fields). In general the data parts in 3188c2ecf20Sopenharmony_ci * spi_packet's are concatenated until @remaining is 0, and the result is an 3198c2ecf20Sopenharmony_ci * message. 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * @flags: 0x40 = write (to device), 0x20 = read (from device); note that 3228c2ecf20Sopenharmony_ci * the response to a write still has 0x40. 3238c2ecf20Sopenharmony_ci * @device: 1 = keyboard, 2 = touchpad 3248c2ecf20Sopenharmony_ci * @offset: specifies the offset of this packet's data in the complete 3258c2ecf20Sopenharmony_ci * message; i.e. > 0 indicates this is a continuation packet (in 3268c2ecf20Sopenharmony_ci * the second packet for a message split over multiple packets 3278c2ecf20Sopenharmony_ci * this would then be the same as the @length in the first packet) 3288c2ecf20Sopenharmony_ci * @remaining: number of message bytes remaining in subsequents packets (in 3298c2ecf20Sopenharmony_ci * the first packet of a message split over two packets this would 3308c2ecf20Sopenharmony_ci * then be the same as the @length in the second packet) 3318c2ecf20Sopenharmony_ci * @length: length of the valid data in the @data in this packet 3328c2ecf20Sopenharmony_ci * @data: all or part of a message 3338c2ecf20Sopenharmony_ci * @crc16: crc over this whole structure minus this @crc16 field. This 3348c2ecf20Sopenharmony_ci * covers just this packet, even on multi-packet messages (in 3358c2ecf20Sopenharmony_ci * contrast to the crc in the message). 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_cistruct spi_packet { 3388c2ecf20Sopenharmony_ci u8 flags; 3398c2ecf20Sopenharmony_ci u8 device; 3408c2ecf20Sopenharmony_ci __le16 offset; 3418c2ecf20Sopenharmony_ci __le16 remaining; 3428c2ecf20Sopenharmony_ci __le16 length; 3438c2ecf20Sopenharmony_ci u8 data[246]; 3448c2ecf20Sopenharmony_ci __le16 crc16; 3458c2ecf20Sopenharmony_ci}; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistruct spi_settings { 3488c2ecf20Sopenharmony_ci u64 spi_cs_delay; /* cs-to-clk delay in us */ 3498c2ecf20Sopenharmony_ci u64 reset_a2r_usec; /* active-to-receive delay? */ 3508c2ecf20Sopenharmony_ci u64 reset_rec_usec; /* ? (cur val: 10) */ 3518c2ecf20Sopenharmony_ci}; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/* this mimics struct drm_rect */ 3548c2ecf20Sopenharmony_cistruct applespi_tp_info { 3558c2ecf20Sopenharmony_ci int x_min; 3568c2ecf20Sopenharmony_ci int y_min; 3578c2ecf20Sopenharmony_ci int x_max; 3588c2ecf20Sopenharmony_ci int y_max; 3598c2ecf20Sopenharmony_ci}; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistruct applespi_data { 3628c2ecf20Sopenharmony_ci struct spi_device *spi; 3638c2ecf20Sopenharmony_ci struct spi_settings spi_settings; 3648c2ecf20Sopenharmony_ci struct input_dev *keyboard_input_dev; 3658c2ecf20Sopenharmony_ci struct input_dev *touchpad_input_dev; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci u8 *tx_buffer; 3688c2ecf20Sopenharmony_ci u8 *tx_status; 3698c2ecf20Sopenharmony_ci u8 *rx_buffer; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci u8 *msg_buf; 3728c2ecf20Sopenharmony_ci unsigned int saved_msg_len; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci struct applespi_tp_info tp_info; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci u8 last_keys_pressed[MAX_ROLLOVER]; 3778c2ecf20Sopenharmony_ci u8 last_keys_fn_pressed[MAX_ROLLOVER]; 3788c2ecf20Sopenharmony_ci u8 last_fn_pressed; 3798c2ecf20Sopenharmony_ci struct input_mt_pos pos[MAX_FINGERS]; 3808c2ecf20Sopenharmony_ci int slots[MAX_FINGERS]; 3818c2ecf20Sopenharmony_ci int gpe; 3828c2ecf20Sopenharmony_ci acpi_handle sien; 3838c2ecf20Sopenharmony_ci acpi_handle sist; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci struct spi_transfer dl_t; 3868c2ecf20Sopenharmony_ci struct spi_transfer rd_t; 3878c2ecf20Sopenharmony_ci struct spi_message rd_m; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci struct spi_transfer ww_t; 3908c2ecf20Sopenharmony_ci struct spi_transfer wd_t; 3918c2ecf20Sopenharmony_ci struct spi_transfer wr_t; 3928c2ecf20Sopenharmony_ci struct spi_transfer st_t; 3938c2ecf20Sopenharmony_ci struct spi_message wr_m; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci bool want_tp_info_cmd; 3968c2ecf20Sopenharmony_ci bool want_mt_init_cmd; 3978c2ecf20Sopenharmony_ci bool want_cl_led_on; 3988c2ecf20Sopenharmony_ci bool have_cl_led_on; 3998c2ecf20Sopenharmony_ci unsigned int want_bl_level; 4008c2ecf20Sopenharmony_ci unsigned int have_bl_level; 4018c2ecf20Sopenharmony_ci unsigned int cmd_msg_cntr; 4028c2ecf20Sopenharmony_ci /* lock to protect the above parameters and flags below */ 4038c2ecf20Sopenharmony_ci spinlock_t cmd_msg_lock; 4048c2ecf20Sopenharmony_ci ktime_t cmd_msg_queued; 4058c2ecf20Sopenharmony_ci enum applespi_evt_type cmd_evt_type; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci struct led_classdev backlight_info; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci bool suspended; 4108c2ecf20Sopenharmony_ci bool drain; 4118c2ecf20Sopenharmony_ci wait_queue_head_t drain_complete; 4128c2ecf20Sopenharmony_ci bool read_active; 4138c2ecf20Sopenharmony_ci bool write_active; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci struct work_struct work; 4168c2ecf20Sopenharmony_ci struct touchpad_info_protocol rcvd_tp_info; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci struct dentry *debugfs_root; 4198c2ecf20Sopenharmony_ci bool debug_tp_dim; 4208c2ecf20Sopenharmony_ci char tp_dim_val[40]; 4218c2ecf20Sopenharmony_ci int tp_dim_min_x; 4228c2ecf20Sopenharmony_ci int tp_dim_max_x; 4238c2ecf20Sopenharmony_ci int tp_dim_min_y; 4248c2ecf20Sopenharmony_ci int tp_dim_max_y; 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic const unsigned char applespi_scancodes[] = { 4288c2ecf20Sopenharmony_ci 0, 0, 0, 0, 4298c2ecf20Sopenharmony_ci KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, 4308c2ecf20Sopenharmony_ci KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, 4318c2ecf20Sopenharmony_ci KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, 4328c2ecf20Sopenharmony_ci KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0, 4338c2ecf20Sopenharmony_ci KEY_ENTER, KEY_ESC, KEY_BACKSPACE, KEY_TAB, KEY_SPACE, KEY_MINUS, 4348c2ecf20Sopenharmony_ci KEY_EQUAL, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, 0, 4358c2ecf20Sopenharmony_ci KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_COMMA, KEY_DOT, KEY_SLASH, 4368c2ecf20Sopenharmony_ci KEY_CAPSLOCK, 4378c2ecf20Sopenharmony_ci KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, 4388c2ecf20Sopenharmony_ci KEY_F10, KEY_F11, KEY_F12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4398c2ecf20Sopenharmony_ci KEY_RIGHT, KEY_LEFT, KEY_DOWN, KEY_UP, 4408c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_102ND, 4418c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4428c2ecf20Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RO, 0, KEY_YEN, 0, 0, 0, 0, 0, 4438c2ecf20Sopenharmony_ci 0, KEY_KATAKANAHIRAGANA, KEY_MUHENKAN 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci/* 4478c2ecf20Sopenharmony_ci * This must have exactly as many entries as there are bits in 4488c2ecf20Sopenharmony_ci * struct keyboard_protocol.modifiers . 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_cistatic const unsigned char applespi_controlcodes[] = { 4518c2ecf20Sopenharmony_ci KEY_LEFTCTRL, 4528c2ecf20Sopenharmony_ci KEY_LEFTSHIFT, 4538c2ecf20Sopenharmony_ci KEY_LEFTALT, 4548c2ecf20Sopenharmony_ci KEY_LEFTMETA, 4558c2ecf20Sopenharmony_ci 0, 4568c2ecf20Sopenharmony_ci KEY_RIGHTSHIFT, 4578c2ecf20Sopenharmony_ci KEY_RIGHTALT, 4588c2ecf20Sopenharmony_ci KEY_RIGHTMETA 4598c2ecf20Sopenharmony_ci}; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistruct applespi_key_translation { 4628c2ecf20Sopenharmony_ci u16 from; 4638c2ecf20Sopenharmony_ci u16 to; 4648c2ecf20Sopenharmony_ci u8 flags; 4658c2ecf20Sopenharmony_ci}; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic const struct applespi_key_translation applespi_fn_codes[] = { 4688c2ecf20Sopenharmony_ci { KEY_BACKSPACE, KEY_DELETE }, 4698c2ecf20Sopenharmony_ci { KEY_ENTER, KEY_INSERT }, 4708c2ecf20Sopenharmony_ci { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY }, 4718c2ecf20Sopenharmony_ci { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY }, 4728c2ecf20Sopenharmony_ci { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY }, 4738c2ecf20Sopenharmony_ci { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY }, 4748c2ecf20Sopenharmony_ci { KEY_F5, KEY_KBDILLUMDOWN, APPLE_FLAG_FKEY }, 4758c2ecf20Sopenharmony_ci { KEY_F6, KEY_KBDILLUMUP, APPLE_FLAG_FKEY }, 4768c2ecf20Sopenharmony_ci { KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY }, 4778c2ecf20Sopenharmony_ci { KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY }, 4788c2ecf20Sopenharmony_ci { KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY }, 4798c2ecf20Sopenharmony_ci { KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY }, 4808c2ecf20Sopenharmony_ci { KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY }, 4818c2ecf20Sopenharmony_ci { KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY }, 4828c2ecf20Sopenharmony_ci { KEY_RIGHT, KEY_END }, 4838c2ecf20Sopenharmony_ci { KEY_LEFT, KEY_HOME }, 4848c2ecf20Sopenharmony_ci { KEY_DOWN, KEY_PAGEDOWN }, 4858c2ecf20Sopenharmony_ci { KEY_UP, KEY_PAGEUP }, 4868c2ecf20Sopenharmony_ci { } 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic const struct applespi_key_translation apple_iso_keyboard[] = { 4908c2ecf20Sopenharmony_ci { KEY_GRAVE, KEY_102ND }, 4918c2ecf20Sopenharmony_ci { KEY_102ND, KEY_GRAVE }, 4928c2ecf20Sopenharmony_ci { } 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistruct applespi_tp_model_info { 4968c2ecf20Sopenharmony_ci u16 model; 4978c2ecf20Sopenharmony_ci struct applespi_tp_info tp_info; 4988c2ecf20Sopenharmony_ci}; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic const struct applespi_tp_model_info applespi_tp_models[] = { 5018c2ecf20Sopenharmony_ci { 5028c2ecf20Sopenharmony_ci .model = 0x04, /* MB8 MB9 MB10 */ 5038c2ecf20Sopenharmony_ci .tp_info = { -5087, -182, 5579, 6089 }, 5048c2ecf20Sopenharmony_ci }, 5058c2ecf20Sopenharmony_ci { 5068c2ecf20Sopenharmony_ci .model = 0x05, /* MBP13,1 MBP13,2 MBP14,1 MBP14,2 */ 5078c2ecf20Sopenharmony_ci .tp_info = { -6243, -170, 6749, 7685 }, 5088c2ecf20Sopenharmony_ci }, 5098c2ecf20Sopenharmony_ci { 5108c2ecf20Sopenharmony_ci .model = 0x06, /* MBP13,3 MBP14,3 */ 5118c2ecf20Sopenharmony_ci .tp_info = { -7456, -163, 7976, 9283 }, 5128c2ecf20Sopenharmony_ci }, 5138c2ecf20Sopenharmony_ci {} 5148c2ecf20Sopenharmony_ci}; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_citypedef void (*applespi_trace_fun)(enum applespi_evt_type, 5178c2ecf20Sopenharmony_ci enum applespi_pkt_type, u8 *, size_t); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic applespi_trace_fun applespi_get_trace_fun(enum applespi_evt_type type) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci switch (type) { 5228c2ecf20Sopenharmony_ci case ET_CMD_TP_INI: 5238c2ecf20Sopenharmony_ci return trace_applespi_tp_ini_cmd; 5248c2ecf20Sopenharmony_ci case ET_CMD_BL: 5258c2ecf20Sopenharmony_ci return trace_applespi_backlight_cmd; 5268c2ecf20Sopenharmony_ci case ET_CMD_CL: 5278c2ecf20Sopenharmony_ci return trace_applespi_caps_lock_cmd; 5288c2ecf20Sopenharmony_ci case ET_RD_KEYB: 5298c2ecf20Sopenharmony_ci return trace_applespi_keyboard_data; 5308c2ecf20Sopenharmony_ci case ET_RD_TPAD: 5318c2ecf20Sopenharmony_ci return trace_applespi_touchpad_data; 5328c2ecf20Sopenharmony_ci case ET_RD_UNKN: 5338c2ecf20Sopenharmony_ci return trace_applespi_unknown_data; 5348c2ecf20Sopenharmony_ci default: 5358c2ecf20Sopenharmony_ci WARN_ONCE(1, "Unknown msg type %d", type); 5368c2ecf20Sopenharmony_ci return trace_applespi_unknown_data; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic void applespi_setup_read_txfrs(struct applespi_data *applespi) 5418c2ecf20Sopenharmony_ci{ 5428c2ecf20Sopenharmony_ci struct spi_message *msg = &applespi->rd_m; 5438c2ecf20Sopenharmony_ci struct spi_transfer *dl_t = &applespi->dl_t; 5448c2ecf20Sopenharmony_ci struct spi_transfer *rd_t = &applespi->rd_t; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci memset(dl_t, 0, sizeof(*dl_t)); 5478c2ecf20Sopenharmony_ci memset(rd_t, 0, sizeof(*rd_t)); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay; 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci rd_t->rx_buf = applespi->rx_buffer; 5528c2ecf20Sopenharmony_ci rd_t->len = APPLESPI_PACKET_SIZE; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci spi_message_init(msg); 5558c2ecf20Sopenharmony_ci spi_message_add_tail(dl_t, msg); 5568c2ecf20Sopenharmony_ci spi_message_add_tail(rd_t, msg); 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_cistatic void applespi_setup_write_txfrs(struct applespi_data *applespi) 5608c2ecf20Sopenharmony_ci{ 5618c2ecf20Sopenharmony_ci struct spi_message *msg = &applespi->wr_m; 5628c2ecf20Sopenharmony_ci struct spi_transfer *wt_t = &applespi->ww_t; 5638c2ecf20Sopenharmony_ci struct spi_transfer *dl_t = &applespi->wd_t; 5648c2ecf20Sopenharmony_ci struct spi_transfer *wr_t = &applespi->wr_t; 5658c2ecf20Sopenharmony_ci struct spi_transfer *st_t = &applespi->st_t; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci memset(wt_t, 0, sizeof(*wt_t)); 5688c2ecf20Sopenharmony_ci memset(dl_t, 0, sizeof(*dl_t)); 5698c2ecf20Sopenharmony_ci memset(wr_t, 0, sizeof(*wr_t)); 5708c2ecf20Sopenharmony_ci memset(st_t, 0, sizeof(*st_t)); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* 5738c2ecf20Sopenharmony_ci * All we need here is a delay at the beginning of the message before 5748c2ecf20Sopenharmony_ci * asserting cs. But the current spi API doesn't support this, so we 5758c2ecf20Sopenharmony_ci * end up with an extra unnecessary (but harmless) cs assertion and 5768c2ecf20Sopenharmony_ci * deassertion. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci wt_t->delay_usecs = SPI_RW_CHG_DELAY_US; 5798c2ecf20Sopenharmony_ci wt_t->cs_change = 1; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dl_t->delay_usecs = applespi->spi_settings.spi_cs_delay; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci wr_t->tx_buf = applespi->tx_buffer; 5848c2ecf20Sopenharmony_ci wr_t->len = APPLESPI_PACKET_SIZE; 5858c2ecf20Sopenharmony_ci wr_t->delay_usecs = SPI_RW_CHG_DELAY_US; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci st_t->rx_buf = applespi->tx_status; 5888c2ecf20Sopenharmony_ci st_t->len = APPLESPI_STATUS_SIZE; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci spi_message_init(msg); 5918c2ecf20Sopenharmony_ci spi_message_add_tail(wt_t, msg); 5928c2ecf20Sopenharmony_ci spi_message_add_tail(dl_t, msg); 5938c2ecf20Sopenharmony_ci spi_message_add_tail(wr_t, msg); 5948c2ecf20Sopenharmony_ci spi_message_add_tail(st_t, msg); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int applespi_async(struct applespi_data *applespi, 5988c2ecf20Sopenharmony_ci struct spi_message *message, void (*complete)(void *)) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci message->complete = complete; 6018c2ecf20Sopenharmony_ci message->context = applespi; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci return spi_async(applespi->spi, message); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic inline bool applespi_check_write_status(struct applespi_data *applespi, 6078c2ecf20Sopenharmony_ci int sts) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci static u8 status_ok[] = { 0xac, 0x27, 0x68, 0xd5 }; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci if (sts < 0) { 6128c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, "Error writing to device: %d\n", 6138c2ecf20Sopenharmony_ci sts); 6148c2ecf20Sopenharmony_ci return false; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (memcmp(applespi->tx_status, status_ok, APPLESPI_STATUS_SIZE)) { 6188c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, "Error writing to device: %*ph\n", 6198c2ecf20Sopenharmony_ci APPLESPI_STATUS_SIZE, applespi->tx_status); 6208c2ecf20Sopenharmony_ci return false; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci return true; 6248c2ecf20Sopenharmony_ci} 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_cistatic int applespi_get_spi_settings(struct applespi_data *applespi) 6278c2ecf20Sopenharmony_ci{ 6288c2ecf20Sopenharmony_ci struct acpi_device *adev = ACPI_COMPANION(&applespi->spi->dev); 6298c2ecf20Sopenharmony_ci const union acpi_object *o; 6308c2ecf20Sopenharmony_ci struct spi_settings *settings = &applespi->spi_settings; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (!acpi_dev_get_property(adev, "spiCSDelay", ACPI_TYPE_BUFFER, &o)) 6338c2ecf20Sopenharmony_ci settings->spi_cs_delay = *(u64 *)o->buffer.pointer; 6348c2ecf20Sopenharmony_ci else 6358c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 6368c2ecf20Sopenharmony_ci "Property spiCSDelay not found\n"); 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (!acpi_dev_get_property(adev, "resetA2RUsec", ACPI_TYPE_BUFFER, &o)) 6398c2ecf20Sopenharmony_ci settings->reset_a2r_usec = *(u64 *)o->buffer.pointer; 6408c2ecf20Sopenharmony_ci else 6418c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 6428c2ecf20Sopenharmony_ci "Property resetA2RUsec not found\n"); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (!acpi_dev_get_property(adev, "resetRecUsec", ACPI_TYPE_BUFFER, &o)) 6458c2ecf20Sopenharmony_ci settings->reset_rec_usec = *(u64 *)o->buffer.pointer; 6468c2ecf20Sopenharmony_ci else 6478c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 6488c2ecf20Sopenharmony_ci "Property resetRecUsec not found\n"); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci dev_dbg(&applespi->spi->dev, 6518c2ecf20Sopenharmony_ci "SPI settings: spi_cs_delay=%llu reset_a2r_usec=%llu reset_rec_usec=%llu\n", 6528c2ecf20Sopenharmony_ci settings->spi_cs_delay, settings->reset_a2r_usec, 6538c2ecf20Sopenharmony_ci settings->reset_rec_usec); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_cistatic int applespi_setup_spi(struct applespi_data *applespi) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci int sts; 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci sts = applespi_get_spi_settings(applespi); 6638c2ecf20Sopenharmony_ci if (sts) 6648c2ecf20Sopenharmony_ci return sts; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci spin_lock_init(&applespi->cmd_msg_lock); 6678c2ecf20Sopenharmony_ci init_waitqueue_head(&applespi->drain_complete); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return 0; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int applespi_enable_spi(struct applespi_data *applespi) 6738c2ecf20Sopenharmony_ci{ 6748c2ecf20Sopenharmony_ci acpi_status acpi_sts; 6758c2ecf20Sopenharmony_ci unsigned long long spi_status; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* check if SPI is already enabled, so we can skip the delay below */ 6788c2ecf20Sopenharmony_ci acpi_sts = acpi_evaluate_integer(applespi->sist, NULL, NULL, 6798c2ecf20Sopenharmony_ci &spi_status); 6808c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_sts) && spi_status) 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* SIEN(1) will enable SPI communication */ 6848c2ecf20Sopenharmony_ci acpi_sts = acpi_execute_simple_method(applespi->sien, NULL, 1); 6858c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) { 6868c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, "SIEN failed: %s\n", 6878c2ecf20Sopenharmony_ci acpi_format_exception(acpi_sts)); 6888c2ecf20Sopenharmony_ci return -ENODEV; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci /* 6928c2ecf20Sopenharmony_ci * Allow the SPI interface to come up before returning. Without this 6938c2ecf20Sopenharmony_ci * delay, the SPI commands to enable multitouch mode may not reach 6948c2ecf20Sopenharmony_ci * the trackpad controller, causing pointer movement to break upon 6958c2ecf20Sopenharmony_ci * resume from sleep. 6968c2ecf20Sopenharmony_ci */ 6978c2ecf20Sopenharmony_ci msleep(50); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci return 0; 7008c2ecf20Sopenharmony_ci} 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_cistatic int applespi_send_cmd_msg(struct applespi_data *applespi); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_cistatic void applespi_msg_complete(struct applespi_data *applespi, 7058c2ecf20Sopenharmony_ci bool is_write_msg, bool is_read_compl) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci unsigned long flags; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_ci if (is_read_compl) 7128c2ecf20Sopenharmony_ci applespi->read_active = false; 7138c2ecf20Sopenharmony_ci if (is_write_msg) 7148c2ecf20Sopenharmony_ci applespi->write_active = false; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (applespi->drain && !applespi->write_active) 7178c2ecf20Sopenharmony_ci wake_up_all(&applespi->drain_complete); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci if (is_write_msg) { 7208c2ecf20Sopenharmony_ci applespi->cmd_msg_queued = 0; 7218c2ecf20Sopenharmony_ci applespi_send_cmd_msg(applespi); 7228c2ecf20Sopenharmony_ci } 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 7258c2ecf20Sopenharmony_ci} 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_cistatic void applespi_async_write_complete(void *context) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct applespi_data *applespi = context; 7308c2ecf20Sopenharmony_ci enum applespi_evt_type evt_type = applespi->cmd_evt_type; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci applespi_get_trace_fun(evt_type)(evt_type, PT_WRITE, 7338c2ecf20Sopenharmony_ci applespi->tx_buffer, 7348c2ecf20Sopenharmony_ci APPLESPI_PACKET_SIZE); 7358c2ecf20Sopenharmony_ci applespi_get_trace_fun(evt_type)(evt_type, PT_STATUS, 7368c2ecf20Sopenharmony_ci applespi->tx_status, 7378c2ecf20Sopenharmony_ci APPLESPI_STATUS_SIZE); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci if (!applespi_check_write_status(applespi, applespi->wr_m.status)) { 7408c2ecf20Sopenharmony_ci /* 7418c2ecf20Sopenharmony_ci * If we got an error, we presumably won't get the expected 7428c2ecf20Sopenharmony_ci * response message either. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci applespi_msg_complete(applespi, true, false); 7458c2ecf20Sopenharmony_ci } 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_cistatic int applespi_send_cmd_msg(struct applespi_data *applespi) 7498c2ecf20Sopenharmony_ci{ 7508c2ecf20Sopenharmony_ci u16 crc; 7518c2ecf20Sopenharmony_ci int sts; 7528c2ecf20Sopenharmony_ci struct spi_packet *packet = (struct spi_packet *)applespi->tx_buffer; 7538c2ecf20Sopenharmony_ci struct message *message = (struct message *)packet->data; 7548c2ecf20Sopenharmony_ci u16 msg_len; 7558c2ecf20Sopenharmony_ci u8 device; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci /* check if draining */ 7588c2ecf20Sopenharmony_ci if (applespi->drain) 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci /* check whether send is in progress */ 7628c2ecf20Sopenharmony_ci if (applespi->cmd_msg_queued) { 7638c2ecf20Sopenharmony_ci if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000) 7648c2ecf20Sopenharmony_ci return 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, "Command %d timed out\n", 7678c2ecf20Sopenharmony_ci applespi->cmd_evt_type); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci applespi->cmd_msg_queued = 0; 7708c2ecf20Sopenharmony_ci applespi->write_active = false; 7718c2ecf20Sopenharmony_ci } 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci /* set up packet */ 7748c2ecf20Sopenharmony_ci memset(packet, 0, APPLESPI_PACKET_SIZE); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* are we processing init commands? */ 7778c2ecf20Sopenharmony_ci if (applespi->want_tp_info_cmd) { 7788c2ecf20Sopenharmony_ci applespi->want_tp_info_cmd = false; 7798c2ecf20Sopenharmony_ci applespi->want_mt_init_cmd = true; 7808c2ecf20Sopenharmony_ci applespi->cmd_evt_type = ET_CMD_TP_INI; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* build init command */ 7838c2ecf20Sopenharmony_ci device = PACKET_DEV_INFO; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci message->type = cpu_to_le16(0x1020); 7868c2ecf20Sopenharmony_ci msg_len = sizeof(message->tp_info_command); 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci message->zero = 0x02; 7898c2ecf20Sopenharmony_ci message->rsp_buf_len = cpu_to_le16(0x0200); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci } else if (applespi->want_mt_init_cmd) { 7928c2ecf20Sopenharmony_ci applespi->want_mt_init_cmd = false; 7938c2ecf20Sopenharmony_ci applespi->cmd_evt_type = ET_CMD_TP_INI; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci /* build init command */ 7968c2ecf20Sopenharmony_ci device = PACKET_DEV_TPAD; 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci message->type = cpu_to_le16(0x0252); 7998c2ecf20Sopenharmony_ci msg_len = sizeof(message->init_mt_command); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci message->init_mt_command.cmd = cpu_to_le16(0x0102); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* do we need caps-lock command? */ 8048c2ecf20Sopenharmony_ci } else if (applespi->want_cl_led_on != applespi->have_cl_led_on) { 8058c2ecf20Sopenharmony_ci applespi->have_cl_led_on = applespi->want_cl_led_on; 8068c2ecf20Sopenharmony_ci applespi->cmd_evt_type = ET_CMD_CL; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci /* build led command */ 8098c2ecf20Sopenharmony_ci device = PACKET_DEV_KEYB; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci message->type = cpu_to_le16(0x0151); 8128c2ecf20Sopenharmony_ci msg_len = sizeof(message->capsl_command); 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci message->capsl_command.unknown = 0x01; 8158c2ecf20Sopenharmony_ci message->capsl_command.led = applespi->have_cl_led_on ? 2 : 0; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci /* do we need backlight command? */ 8188c2ecf20Sopenharmony_ci } else if (applespi->want_bl_level != applespi->have_bl_level) { 8198c2ecf20Sopenharmony_ci applespi->have_bl_level = applespi->want_bl_level; 8208c2ecf20Sopenharmony_ci applespi->cmd_evt_type = ET_CMD_BL; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci /* build command buffer */ 8238c2ecf20Sopenharmony_ci device = PACKET_DEV_KEYB; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci message->type = cpu_to_le16(0xB051); 8268c2ecf20Sopenharmony_ci msg_len = sizeof(message->bl_command); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci message->bl_command.const1 = cpu_to_le16(0x01B0); 8298c2ecf20Sopenharmony_ci message->bl_command.level = 8308c2ecf20Sopenharmony_ci cpu_to_le16(applespi->have_bl_level); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (applespi->have_bl_level > 0) 8338c2ecf20Sopenharmony_ci message->bl_command.const2 = cpu_to_le16(0x01F4); 8348c2ecf20Sopenharmony_ci else 8358c2ecf20Sopenharmony_ci message->bl_command.const2 = cpu_to_le16(0x0001); 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* everything's up-to-date */ 8388c2ecf20Sopenharmony_ci } else { 8398c2ecf20Sopenharmony_ci return 0; 8408c2ecf20Sopenharmony_ci } 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci /* finalize packet */ 8438c2ecf20Sopenharmony_ci packet->flags = PACKET_TYPE_WRITE; 8448c2ecf20Sopenharmony_ci packet->device = device; 8458c2ecf20Sopenharmony_ci packet->length = cpu_to_le16(MSG_HEADER_SIZE + msg_len); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci message->counter = applespi->cmd_msg_cntr++ % (U8_MAX + 1); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci message->length = cpu_to_le16(msg_len - 2); 8508c2ecf20Sopenharmony_ci if (!message->rsp_buf_len) 8518c2ecf20Sopenharmony_ci message->rsp_buf_len = message->length; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci crc = crc16(0, (u8 *)message, le16_to_cpu(packet->length) - 2); 8548c2ecf20Sopenharmony_ci put_unaligned_le16(crc, &message->data[msg_len - 2]); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci crc = crc16(0, (u8 *)packet, sizeof(*packet) - 2); 8578c2ecf20Sopenharmony_ci packet->crc16 = cpu_to_le16(crc); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* send command */ 8608c2ecf20Sopenharmony_ci sts = applespi_async(applespi, &applespi->wr_m, 8618c2ecf20Sopenharmony_ci applespi_async_write_complete); 8628c2ecf20Sopenharmony_ci if (sts) { 8638c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 8648c2ecf20Sopenharmony_ci "Error queueing async write to device: %d\n", sts); 8658c2ecf20Sopenharmony_ci return sts; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci applespi->cmd_msg_queued = ktime_get_coarse(); 8698c2ecf20Sopenharmony_ci applespi->write_active = true; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_cistatic void applespi_init(struct applespi_data *applespi, bool is_resume) 8758c2ecf20Sopenharmony_ci{ 8768c2ecf20Sopenharmony_ci unsigned long flags; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci if (is_resume) 8818c2ecf20Sopenharmony_ci applespi->want_mt_init_cmd = true; 8828c2ecf20Sopenharmony_ci else 8838c2ecf20Sopenharmony_ci applespi->want_tp_info_cmd = true; 8848c2ecf20Sopenharmony_ci applespi_send_cmd_msg(applespi); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic int applespi_set_capsl_led(struct applespi_data *applespi, 8908c2ecf20Sopenharmony_ci bool capslock_on) 8918c2ecf20Sopenharmony_ci{ 8928c2ecf20Sopenharmony_ci unsigned long flags; 8938c2ecf20Sopenharmony_ci int sts; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci applespi->want_cl_led_on = capslock_on; 8988c2ecf20Sopenharmony_ci sts = applespi_send_cmd_msg(applespi); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci return sts; 9038c2ecf20Sopenharmony_ci} 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_cistatic void applespi_set_bl_level(struct led_classdev *led_cdev, 9068c2ecf20Sopenharmony_ci enum led_brightness value) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct applespi_data *applespi = 9098c2ecf20Sopenharmony_ci container_of(led_cdev, struct applespi_data, backlight_info); 9108c2ecf20Sopenharmony_ci unsigned long flags; 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (value == 0) { 9158c2ecf20Sopenharmony_ci applespi->want_bl_level = value; 9168c2ecf20Sopenharmony_ci } else { 9178c2ecf20Sopenharmony_ci /* 9188c2ecf20Sopenharmony_ci * The backlight does not turn on till level 32, so we scale 9198c2ecf20Sopenharmony_ci * the range here so that from a user's perspective it turns 9208c2ecf20Sopenharmony_ci * on at 1. 9218c2ecf20Sopenharmony_ci */ 9228c2ecf20Sopenharmony_ci applespi->want_bl_level = 9238c2ecf20Sopenharmony_ci ((value * KBD_BL_LEVEL_ADJ) / KBD_BL_LEVEL_SCALE + 9248c2ecf20Sopenharmony_ci KBD_BL_LEVEL_MIN); 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci applespi_send_cmd_msg(applespi); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic int applespi_event(struct input_dev *dev, unsigned int type, 9338c2ecf20Sopenharmony_ci unsigned int code, int value) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci struct applespi_data *applespi = input_get_drvdata(dev); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci switch (type) { 9388c2ecf20Sopenharmony_ci case EV_LED: 9398c2ecf20Sopenharmony_ci applespi_set_capsl_led(applespi, !!test_bit(LED_CAPSL, dev->led)); 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci return -EINVAL; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci/* lifted from the BCM5974 driver and renamed from raw2int */ 9478c2ecf20Sopenharmony_ci/* convert 16-bit little endian to signed integer */ 9488c2ecf20Sopenharmony_cistatic inline int le16_to_int(__le16 x) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci return (signed short)le16_to_cpu(x); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic void applespi_debug_update_dimensions(struct applespi_data *applespi, 9548c2ecf20Sopenharmony_ci const struct tp_finger *f) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci applespi->tp_dim_min_x = min(applespi->tp_dim_min_x, 9578c2ecf20Sopenharmony_ci le16_to_int(f->abs_x)); 9588c2ecf20Sopenharmony_ci applespi->tp_dim_max_x = max(applespi->tp_dim_max_x, 9598c2ecf20Sopenharmony_ci le16_to_int(f->abs_x)); 9608c2ecf20Sopenharmony_ci applespi->tp_dim_min_y = min(applespi->tp_dim_min_y, 9618c2ecf20Sopenharmony_ci le16_to_int(f->abs_y)); 9628c2ecf20Sopenharmony_ci applespi->tp_dim_max_y = max(applespi->tp_dim_max_y, 9638c2ecf20Sopenharmony_ci le16_to_int(f->abs_y)); 9648c2ecf20Sopenharmony_ci} 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_cistatic int applespi_tp_dim_open(struct inode *inode, struct file *file) 9678c2ecf20Sopenharmony_ci{ 9688c2ecf20Sopenharmony_ci struct applespi_data *applespi = inode->i_private; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci file->private_data = applespi; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci snprintf(applespi->tp_dim_val, sizeof(applespi->tp_dim_val), 9738c2ecf20Sopenharmony_ci "0x%.4x %dx%d+%u+%u\n", 9748c2ecf20Sopenharmony_ci applespi->touchpad_input_dev->id.product, 9758c2ecf20Sopenharmony_ci applespi->tp_dim_min_x, applespi->tp_dim_min_y, 9768c2ecf20Sopenharmony_ci applespi->tp_dim_max_x - applespi->tp_dim_min_x, 9778c2ecf20Sopenharmony_ci applespi->tp_dim_max_y - applespi->tp_dim_min_y); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci return nonseekable_open(inode, file); 9808c2ecf20Sopenharmony_ci} 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_cistatic ssize_t applespi_tp_dim_read(struct file *file, char __user *buf, 9838c2ecf20Sopenharmony_ci size_t len, loff_t *off) 9848c2ecf20Sopenharmony_ci{ 9858c2ecf20Sopenharmony_ci struct applespi_data *applespi = file->private_data; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci return simple_read_from_buffer(buf, len, off, applespi->tp_dim_val, 9888c2ecf20Sopenharmony_ci strlen(applespi->tp_dim_val)); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic const struct file_operations applespi_tp_dim_fops = { 9928c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9938c2ecf20Sopenharmony_ci .open = applespi_tp_dim_open, 9948c2ecf20Sopenharmony_ci .read = applespi_tp_dim_read, 9958c2ecf20Sopenharmony_ci .llseek = no_llseek, 9968c2ecf20Sopenharmony_ci}; 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic void report_finger_data(struct input_dev *input, int slot, 9998c2ecf20Sopenharmony_ci const struct input_mt_pos *pos, 10008c2ecf20Sopenharmony_ci const struct tp_finger *f) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci input_mt_slot(input, slot); 10038c2ecf20Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_TOUCH_MAJOR, 10068c2ecf20Sopenharmony_ci le16_to_int(f->touch_major) << 1); 10078c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_TOUCH_MINOR, 10088c2ecf20Sopenharmony_ci le16_to_int(f->touch_minor) << 1); 10098c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_WIDTH_MAJOR, 10108c2ecf20Sopenharmony_ci le16_to_int(f->tool_major) << 1); 10118c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_WIDTH_MINOR, 10128c2ecf20Sopenharmony_ci le16_to_int(f->tool_minor) << 1); 10138c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_ORIENTATION, 10148c2ecf20Sopenharmony_ci MAX_FINGER_ORIENTATION - le16_to_int(f->orientation)); 10158c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_X, pos->x); 10168c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_Y, pos->y); 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic void report_tp_state(struct applespi_data *applespi, 10208c2ecf20Sopenharmony_ci struct touchpad_protocol *t) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci const struct tp_finger *f; 10238c2ecf20Sopenharmony_ci struct input_dev *input; 10248c2ecf20Sopenharmony_ci const struct applespi_tp_info *tp_info = &applespi->tp_info; 10258c2ecf20Sopenharmony_ci int i, n; 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci /* touchpad_input_dev is set async in worker */ 10288c2ecf20Sopenharmony_ci input = smp_load_acquire(&applespi->touchpad_input_dev); 10298c2ecf20Sopenharmony_ci if (!input) 10308c2ecf20Sopenharmony_ci return; /* touchpad isn't initialized yet */ 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci n = 0; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci for (i = 0; i < t->number_of_fingers; i++) { 10358c2ecf20Sopenharmony_ci f = &t->fingers[i]; 10368c2ecf20Sopenharmony_ci if (le16_to_int(f->touch_major) == 0) 10378c2ecf20Sopenharmony_ci continue; 10388c2ecf20Sopenharmony_ci applespi->pos[n].x = le16_to_int(f->abs_x); 10398c2ecf20Sopenharmony_ci applespi->pos[n].y = tp_info->y_min + tp_info->y_max - 10408c2ecf20Sopenharmony_ci le16_to_int(f->abs_y); 10418c2ecf20Sopenharmony_ci n++; 10428c2ecf20Sopenharmony_ci 10438c2ecf20Sopenharmony_ci if (applespi->debug_tp_dim) 10448c2ecf20Sopenharmony_ci applespi_debug_update_dimensions(applespi, f); 10458c2ecf20Sopenharmony_ci } 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci input_mt_assign_slots(input, applespi->slots, applespi->pos, n, 0); 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 10508c2ecf20Sopenharmony_ci report_finger_data(input, applespi->slots[i], 10518c2ecf20Sopenharmony_ci &applespi->pos[i], &t->fingers[i]); 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci input_mt_sync_frame(input); 10548c2ecf20Sopenharmony_ci input_report_key(input, BTN_LEFT, t->clicked); 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci input_sync(input); 10578c2ecf20Sopenharmony_ci} 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_cistatic const struct applespi_key_translation * 10608c2ecf20Sopenharmony_ciapplespi_find_translation(const struct applespi_key_translation *table, u16 key) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci const struct applespi_key_translation *trans; 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci for (trans = table; trans->from; trans++) 10658c2ecf20Sopenharmony_ci if (trans->from == key) 10668c2ecf20Sopenharmony_ci return trans; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci return NULL; 10698c2ecf20Sopenharmony_ci} 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_cistatic unsigned int applespi_translate_fn_key(unsigned int key, int fn_pressed) 10728c2ecf20Sopenharmony_ci{ 10738c2ecf20Sopenharmony_ci const struct applespi_key_translation *trans; 10748c2ecf20Sopenharmony_ci int do_translate; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci trans = applespi_find_translation(applespi_fn_codes, key); 10778c2ecf20Sopenharmony_ci if (trans) { 10788c2ecf20Sopenharmony_ci if (trans->flags & APPLE_FLAG_FKEY) 10798c2ecf20Sopenharmony_ci do_translate = (fnmode == 2 && fn_pressed) || 10808c2ecf20Sopenharmony_ci (fnmode == 1 && !fn_pressed); 10818c2ecf20Sopenharmony_ci else 10828c2ecf20Sopenharmony_ci do_translate = fn_pressed; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci if (do_translate) 10858c2ecf20Sopenharmony_ci key = trans->to; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci return key; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_cistatic unsigned int applespi_translate_iso_layout(unsigned int key) 10928c2ecf20Sopenharmony_ci{ 10938c2ecf20Sopenharmony_ci const struct applespi_key_translation *trans; 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci trans = applespi_find_translation(apple_iso_keyboard, key); 10968c2ecf20Sopenharmony_ci if (trans) 10978c2ecf20Sopenharmony_ci key = trans->to; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci return key; 11008c2ecf20Sopenharmony_ci} 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_cistatic unsigned int applespi_code_to_key(u8 code, int fn_pressed) 11038c2ecf20Sopenharmony_ci{ 11048c2ecf20Sopenharmony_ci unsigned int key = applespi_scancodes[code]; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci if (fnmode) 11078c2ecf20Sopenharmony_ci key = applespi_translate_fn_key(key, fn_pressed); 11088c2ecf20Sopenharmony_ci if (iso_layout) 11098c2ecf20Sopenharmony_ci key = applespi_translate_iso_layout(key); 11108c2ecf20Sopenharmony_ci return key; 11118c2ecf20Sopenharmony_ci} 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_cistatic void 11148c2ecf20Sopenharmony_ciapplespi_remap_fn_key(struct keyboard_protocol *keyboard_protocol) 11158c2ecf20Sopenharmony_ci{ 11168c2ecf20Sopenharmony_ci unsigned char tmp; 11178c2ecf20Sopenharmony_ci u8 bit = BIT((fnremap - 1) & 0x07); 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (!fnremap || fnremap > ARRAY_SIZE(applespi_controlcodes) || 11208c2ecf20Sopenharmony_ci !applespi_controlcodes[fnremap - 1]) 11218c2ecf20Sopenharmony_ci return; 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_ci tmp = keyboard_protocol->fn_pressed; 11248c2ecf20Sopenharmony_ci keyboard_protocol->fn_pressed = !!(keyboard_protocol->modifiers & bit); 11258c2ecf20Sopenharmony_ci if (tmp) 11268c2ecf20Sopenharmony_ci keyboard_protocol->modifiers |= bit; 11278c2ecf20Sopenharmony_ci else 11288c2ecf20Sopenharmony_ci keyboard_protocol->modifiers &= ~bit; 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic void 11328c2ecf20Sopenharmony_ciapplespi_handle_keyboard_event(struct applespi_data *applespi, 11338c2ecf20Sopenharmony_ci struct keyboard_protocol *keyboard_protocol) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci unsigned int key; 11368c2ecf20Sopenharmony_ci int i; 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci compiletime_assert(ARRAY_SIZE(applespi_controlcodes) == 11398c2ecf20Sopenharmony_ci sizeof_field(struct keyboard_protocol, modifiers) * 8, 11408c2ecf20Sopenharmony_ci "applespi_controlcodes has wrong number of entries"); 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* check for rollover overflow, which is signalled by all keys == 1 */ 11438c2ecf20Sopenharmony_ci if (!memchr_inv(keyboard_protocol->keys_pressed, 1, MAX_ROLLOVER)) 11448c2ecf20Sopenharmony_ci return; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci /* remap fn key if desired */ 11478c2ecf20Sopenharmony_ci applespi_remap_fn_key(keyboard_protocol); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* check released keys */ 11508c2ecf20Sopenharmony_ci for (i = 0; i < MAX_ROLLOVER; i++) { 11518c2ecf20Sopenharmony_ci if (memchr(keyboard_protocol->keys_pressed, 11528c2ecf20Sopenharmony_ci applespi->last_keys_pressed[i], MAX_ROLLOVER)) 11538c2ecf20Sopenharmony_ci continue; /* key is still pressed */ 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci key = applespi_code_to_key(applespi->last_keys_pressed[i], 11568c2ecf20Sopenharmony_ci applespi->last_keys_fn_pressed[i]); 11578c2ecf20Sopenharmony_ci input_report_key(applespi->keyboard_input_dev, key, 0); 11588c2ecf20Sopenharmony_ci applespi->last_keys_fn_pressed[i] = 0; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci /* check pressed keys */ 11628c2ecf20Sopenharmony_ci for (i = 0; i < MAX_ROLLOVER; i++) { 11638c2ecf20Sopenharmony_ci if (keyboard_protocol->keys_pressed[i] < 11648c2ecf20Sopenharmony_ci ARRAY_SIZE(applespi_scancodes) && 11658c2ecf20Sopenharmony_ci keyboard_protocol->keys_pressed[i] > 0) { 11668c2ecf20Sopenharmony_ci key = applespi_code_to_key( 11678c2ecf20Sopenharmony_ci keyboard_protocol->keys_pressed[i], 11688c2ecf20Sopenharmony_ci keyboard_protocol->fn_pressed); 11698c2ecf20Sopenharmony_ci input_report_key(applespi->keyboard_input_dev, key, 1); 11708c2ecf20Sopenharmony_ci applespi->last_keys_fn_pressed[i] = 11718c2ecf20Sopenharmony_ci keyboard_protocol->fn_pressed; 11728c2ecf20Sopenharmony_ci } 11738c2ecf20Sopenharmony_ci } 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci /* check control keys */ 11768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++) { 11778c2ecf20Sopenharmony_ci if (keyboard_protocol->modifiers & BIT(i)) 11788c2ecf20Sopenharmony_ci input_report_key(applespi->keyboard_input_dev, 11798c2ecf20Sopenharmony_ci applespi_controlcodes[i], 1); 11808c2ecf20Sopenharmony_ci else 11818c2ecf20Sopenharmony_ci input_report_key(applespi->keyboard_input_dev, 11828c2ecf20Sopenharmony_ci applespi_controlcodes[i], 0); 11838c2ecf20Sopenharmony_ci } 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci /* check function key */ 11868c2ecf20Sopenharmony_ci if (keyboard_protocol->fn_pressed && !applespi->last_fn_pressed) 11878c2ecf20Sopenharmony_ci input_report_key(applespi->keyboard_input_dev, KEY_FN, 1); 11888c2ecf20Sopenharmony_ci else if (!keyboard_protocol->fn_pressed && applespi->last_fn_pressed) 11898c2ecf20Sopenharmony_ci input_report_key(applespi->keyboard_input_dev, KEY_FN, 0); 11908c2ecf20Sopenharmony_ci applespi->last_fn_pressed = keyboard_protocol->fn_pressed; 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_ci /* done */ 11938c2ecf20Sopenharmony_ci input_sync(applespi->keyboard_input_dev); 11948c2ecf20Sopenharmony_ci memcpy(&applespi->last_keys_pressed, keyboard_protocol->keys_pressed, 11958c2ecf20Sopenharmony_ci sizeof(applespi->last_keys_pressed)); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic const struct applespi_tp_info *applespi_find_touchpad_info(u8 model) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci const struct applespi_tp_model_info *info; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci for (info = applespi_tp_models; info->model; info++) { 12038c2ecf20Sopenharmony_ci if (info->model == model) 12048c2ecf20Sopenharmony_ci return &info->tp_info; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci return NULL; 12088c2ecf20Sopenharmony_ci} 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_cistatic int 12118c2ecf20Sopenharmony_ciapplespi_register_touchpad_device(struct applespi_data *applespi, 12128c2ecf20Sopenharmony_ci struct touchpad_info_protocol *rcvd_tp_info) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci const struct applespi_tp_info *tp_info; 12158c2ecf20Sopenharmony_ci struct input_dev *touchpad_input_dev; 12168c2ecf20Sopenharmony_ci int sts; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci /* set up touchpad dimensions */ 12198c2ecf20Sopenharmony_ci tp_info = applespi_find_touchpad_info(rcvd_tp_info->model_no); 12208c2ecf20Sopenharmony_ci if (!tp_info) { 12218c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 12228c2ecf20Sopenharmony_ci "Unknown touchpad model %x - falling back to MB8 touchpad\n", 12238c2ecf20Sopenharmony_ci rcvd_tp_info->model_no); 12248c2ecf20Sopenharmony_ci tp_info = &applespi_tp_models[0].tp_info; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci applespi->tp_info = *tp_info; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci if (touchpad_dimensions[0]) { 12308c2ecf20Sopenharmony_ci int x, y, w, h; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci sts = sscanf(touchpad_dimensions, "%dx%d+%u+%u", &x, &y, &w, &h); 12338c2ecf20Sopenharmony_ci if (sts == 4) { 12348c2ecf20Sopenharmony_ci dev_info(&applespi->spi->dev, 12358c2ecf20Sopenharmony_ci "Overriding touchpad dimensions from module param\n"); 12368c2ecf20Sopenharmony_ci applespi->tp_info.x_min = x; 12378c2ecf20Sopenharmony_ci applespi->tp_info.y_min = y; 12388c2ecf20Sopenharmony_ci applespi->tp_info.x_max = x + w; 12398c2ecf20Sopenharmony_ci applespi->tp_info.y_max = y + h; 12408c2ecf20Sopenharmony_ci } else { 12418c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 12428c2ecf20Sopenharmony_ci "Invalid touchpad dimensions '%s': must be in the form XxY+W+H\n", 12438c2ecf20Sopenharmony_ci touchpad_dimensions); 12448c2ecf20Sopenharmony_ci touchpad_dimensions[0] = '\0'; 12458c2ecf20Sopenharmony_ci } 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci if (!touchpad_dimensions[0]) { 12488c2ecf20Sopenharmony_ci snprintf(touchpad_dimensions, sizeof(touchpad_dimensions), 12498c2ecf20Sopenharmony_ci "%dx%d+%u+%u", 12508c2ecf20Sopenharmony_ci applespi->tp_info.x_min, 12518c2ecf20Sopenharmony_ci applespi->tp_info.y_min, 12528c2ecf20Sopenharmony_ci applespi->tp_info.x_max - applespi->tp_info.x_min, 12538c2ecf20Sopenharmony_ci applespi->tp_info.y_max - applespi->tp_info.y_min); 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci /* create touchpad input device */ 12578c2ecf20Sopenharmony_ci touchpad_input_dev = devm_input_allocate_device(&applespi->spi->dev); 12588c2ecf20Sopenharmony_ci if (!touchpad_input_dev) { 12598c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 12608c2ecf20Sopenharmony_ci "Failed to allocate touchpad input device\n"); 12618c2ecf20Sopenharmony_ci return -ENOMEM; 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci touchpad_input_dev->name = "Apple SPI Touchpad"; 12658c2ecf20Sopenharmony_ci touchpad_input_dev->phys = "applespi/input1"; 12668c2ecf20Sopenharmony_ci touchpad_input_dev->dev.parent = &applespi->spi->dev; 12678c2ecf20Sopenharmony_ci touchpad_input_dev->id.bustype = BUS_SPI; 12688c2ecf20Sopenharmony_ci touchpad_input_dev->id.vendor = SYNAPTICS_VENDOR_ID; 12698c2ecf20Sopenharmony_ci touchpad_input_dev->id.product = 12708c2ecf20Sopenharmony_ci rcvd_tp_info->model_no << 8 | rcvd_tp_info->model_flags; 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci /* basic properties */ 12738c2ecf20Sopenharmony_ci input_set_capability(touchpad_input_dev, EV_REL, REL_X); 12748c2ecf20Sopenharmony_ci input_set_capability(touchpad_input_dev, EV_REL, REL_Y); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci __set_bit(INPUT_PROP_POINTER, touchpad_input_dev->propbit); 12778c2ecf20Sopenharmony_ci __set_bit(INPUT_PROP_BUTTONPAD, touchpad_input_dev->propbit); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci /* finger touch area */ 12808c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MAJOR, 12818c2ecf20Sopenharmony_ci 0, 5000, 0, 0); 12828c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_TOUCH_MINOR, 12838c2ecf20Sopenharmony_ci 0, 5000, 0, 0); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci /* finger approach area */ 12868c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MAJOR, 12878c2ecf20Sopenharmony_ci 0, 5000, 0, 0); 12888c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_WIDTH_MINOR, 12898c2ecf20Sopenharmony_ci 0, 5000, 0, 0); 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci /* finger orientation */ 12928c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_ORIENTATION, 12938c2ecf20Sopenharmony_ci -MAX_FINGER_ORIENTATION, MAX_FINGER_ORIENTATION, 12948c2ecf20Sopenharmony_ci 0, 0); 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci /* finger position */ 12978c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_X, 12988c2ecf20Sopenharmony_ci applespi->tp_info.x_min, applespi->tp_info.x_max, 12998c2ecf20Sopenharmony_ci 0, 0); 13008c2ecf20Sopenharmony_ci input_set_abs_params(touchpad_input_dev, ABS_MT_POSITION_Y, 13018c2ecf20Sopenharmony_ci applespi->tp_info.y_min, applespi->tp_info.y_max, 13028c2ecf20Sopenharmony_ci 0, 0); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci /* touchpad button */ 13058c2ecf20Sopenharmony_ci input_set_capability(touchpad_input_dev, EV_KEY, BTN_LEFT); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* multitouch */ 13088c2ecf20Sopenharmony_ci sts = input_mt_init_slots(touchpad_input_dev, MAX_FINGERS, 13098c2ecf20Sopenharmony_ci INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | 13108c2ecf20Sopenharmony_ci INPUT_MT_TRACK); 13118c2ecf20Sopenharmony_ci if (sts) { 13128c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 13138c2ecf20Sopenharmony_ci "failed to initialize slots: %d", sts); 13148c2ecf20Sopenharmony_ci return sts; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* register input device */ 13188c2ecf20Sopenharmony_ci sts = input_register_device(touchpad_input_dev); 13198c2ecf20Sopenharmony_ci if (sts) { 13208c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 13218c2ecf20Sopenharmony_ci "Unable to register touchpad input device (%d)\n", sts); 13228c2ecf20Sopenharmony_ci return sts; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci /* touchpad_input_dev is read async in spi callback */ 13268c2ecf20Sopenharmony_ci smp_store_release(&applespi->touchpad_input_dev, touchpad_input_dev); 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci return 0; 13298c2ecf20Sopenharmony_ci} 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_cistatic void applespi_worker(struct work_struct *work) 13328c2ecf20Sopenharmony_ci{ 13338c2ecf20Sopenharmony_ci struct applespi_data *applespi = 13348c2ecf20Sopenharmony_ci container_of(work, struct applespi_data, work); 13358c2ecf20Sopenharmony_ci 13368c2ecf20Sopenharmony_ci applespi_register_touchpad_device(applespi, &applespi->rcvd_tp_info); 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic void applespi_handle_cmd_response(struct applespi_data *applespi, 13408c2ecf20Sopenharmony_ci struct spi_packet *packet, 13418c2ecf20Sopenharmony_ci struct message *message) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci if (packet->device == PACKET_DEV_INFO && 13448c2ecf20Sopenharmony_ci le16_to_cpu(message->type) == 0x1020) { 13458c2ecf20Sopenharmony_ci /* 13468c2ecf20Sopenharmony_ci * We're not allowed to sleep here, but registering an input 13478c2ecf20Sopenharmony_ci * device can sleep. 13488c2ecf20Sopenharmony_ci */ 13498c2ecf20Sopenharmony_ci applespi->rcvd_tp_info = message->tp_info; 13508c2ecf20Sopenharmony_ci schedule_work(&applespi->work); 13518c2ecf20Sopenharmony_ci return; 13528c2ecf20Sopenharmony_ci } 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci if (le16_to_cpu(message->length) != 0x0000) { 13558c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 13568c2ecf20Sopenharmony_ci "Received unexpected write response: length=%x\n", 13578c2ecf20Sopenharmony_ci le16_to_cpu(message->length)); 13588c2ecf20Sopenharmony_ci return; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (packet->device == PACKET_DEV_TPAD && 13628c2ecf20Sopenharmony_ci le16_to_cpu(message->type) == 0x0252 && 13638c2ecf20Sopenharmony_ci le16_to_cpu(message->rsp_buf_len) == 0x0002) 13648c2ecf20Sopenharmony_ci dev_info(&applespi->spi->dev, "modeswitch done.\n"); 13658c2ecf20Sopenharmony_ci} 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_cistatic bool applespi_verify_crc(struct applespi_data *applespi, u8 *buffer, 13688c2ecf20Sopenharmony_ci size_t buflen) 13698c2ecf20Sopenharmony_ci{ 13708c2ecf20Sopenharmony_ci u16 crc; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci crc = crc16(0, buffer, buflen); 13738c2ecf20Sopenharmony_ci if (crc) { 13748c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 13758c2ecf20Sopenharmony_ci "Received corrupted packet (crc mismatch)\n"); 13768c2ecf20Sopenharmony_ci trace_applespi_bad_crc(ET_RD_CRC, READ, buffer, buflen); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci return false; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci return true; 13828c2ecf20Sopenharmony_ci} 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_cistatic void applespi_debug_print_read_packet(struct applespi_data *applespi, 13858c2ecf20Sopenharmony_ci struct spi_packet *packet) 13868c2ecf20Sopenharmony_ci{ 13878c2ecf20Sopenharmony_ci unsigned int evt_type; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci if (packet->flags == PACKET_TYPE_READ && 13908c2ecf20Sopenharmony_ci packet->device == PACKET_DEV_KEYB) 13918c2ecf20Sopenharmony_ci evt_type = ET_RD_KEYB; 13928c2ecf20Sopenharmony_ci else if (packet->flags == PACKET_TYPE_READ && 13938c2ecf20Sopenharmony_ci packet->device == PACKET_DEV_TPAD) 13948c2ecf20Sopenharmony_ci evt_type = ET_RD_TPAD; 13958c2ecf20Sopenharmony_ci else if (packet->flags == PACKET_TYPE_WRITE) 13968c2ecf20Sopenharmony_ci evt_type = applespi->cmd_evt_type; 13978c2ecf20Sopenharmony_ci else 13988c2ecf20Sopenharmony_ci evt_type = ET_RD_UNKN; 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci applespi_get_trace_fun(evt_type)(evt_type, PT_READ, applespi->rx_buffer, 14018c2ecf20Sopenharmony_ci APPLESPI_PACKET_SIZE); 14028c2ecf20Sopenharmony_ci} 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_cistatic void applespi_got_data(struct applespi_data *applespi) 14058c2ecf20Sopenharmony_ci{ 14068c2ecf20Sopenharmony_ci struct spi_packet *packet; 14078c2ecf20Sopenharmony_ci struct message *message; 14088c2ecf20Sopenharmony_ci unsigned int msg_len; 14098c2ecf20Sopenharmony_ci unsigned int off; 14108c2ecf20Sopenharmony_ci unsigned int rem; 14118c2ecf20Sopenharmony_ci unsigned int len; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci /* process packet header */ 14148c2ecf20Sopenharmony_ci if (!applespi_verify_crc(applespi, applespi->rx_buffer, 14158c2ecf20Sopenharmony_ci APPLESPI_PACKET_SIZE)) { 14168c2ecf20Sopenharmony_ci unsigned long flags; 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci if (applespi->drain) { 14218c2ecf20Sopenharmony_ci applespi->read_active = false; 14228c2ecf20Sopenharmony_ci applespi->write_active = false; 14238c2ecf20Sopenharmony_ci 14248c2ecf20Sopenharmony_ci wake_up_all(&applespi->drain_complete); 14258c2ecf20Sopenharmony_ci } 14268c2ecf20Sopenharmony_ci 14278c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci return; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci packet = (struct spi_packet *)applespi->rx_buffer; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci applespi_debug_print_read_packet(applespi, packet); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci off = le16_to_cpu(packet->offset); 14378c2ecf20Sopenharmony_ci rem = le16_to_cpu(packet->remaining); 14388c2ecf20Sopenharmony_ci len = le16_to_cpu(packet->length); 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (len > sizeof(packet->data)) { 14418c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 14428c2ecf20Sopenharmony_ci "Received corrupted packet (invalid packet length %u)\n", 14438c2ecf20Sopenharmony_ci len); 14448c2ecf20Sopenharmony_ci goto msg_complete; 14458c2ecf20Sopenharmony_ci } 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci /* handle multi-packet messages */ 14488c2ecf20Sopenharmony_ci if (rem > 0 || off > 0) { 14498c2ecf20Sopenharmony_ci if (off != applespi->saved_msg_len) { 14508c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 14518c2ecf20Sopenharmony_ci "Received unexpected offset (got %u, expected %u)\n", 14528c2ecf20Sopenharmony_ci off, applespi->saved_msg_len); 14538c2ecf20Sopenharmony_ci goto msg_complete; 14548c2ecf20Sopenharmony_ci } 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (off + rem > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) { 14578c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 14588c2ecf20Sopenharmony_ci "Received message too large (size %u)\n", 14598c2ecf20Sopenharmony_ci off + rem); 14608c2ecf20Sopenharmony_ci goto msg_complete; 14618c2ecf20Sopenharmony_ci } 14628c2ecf20Sopenharmony_ci 14638c2ecf20Sopenharmony_ci if (off + len > MAX_PKTS_PER_MSG * APPLESPI_PACKET_SIZE) { 14648c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 14658c2ecf20Sopenharmony_ci "Received message too large (size %u)\n", 14668c2ecf20Sopenharmony_ci off + len); 14678c2ecf20Sopenharmony_ci goto msg_complete; 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci memcpy(applespi->msg_buf + off, &packet->data, len); 14718c2ecf20Sopenharmony_ci applespi->saved_msg_len += len; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci if (rem > 0) 14748c2ecf20Sopenharmony_ci return; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci message = (struct message *)applespi->msg_buf; 14778c2ecf20Sopenharmony_ci msg_len = applespi->saved_msg_len; 14788c2ecf20Sopenharmony_ci } else { 14798c2ecf20Sopenharmony_ci message = (struct message *)&packet->data; 14808c2ecf20Sopenharmony_ci msg_len = len; 14818c2ecf20Sopenharmony_ci } 14828c2ecf20Sopenharmony_ci 14838c2ecf20Sopenharmony_ci /* got complete message - verify */ 14848c2ecf20Sopenharmony_ci if (!applespi_verify_crc(applespi, (u8 *)message, msg_len)) 14858c2ecf20Sopenharmony_ci goto msg_complete; 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci if (le16_to_cpu(message->length) != msg_len - MSG_HEADER_SIZE - 2) { 14888c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 14898c2ecf20Sopenharmony_ci "Received corrupted packet (invalid message length %u - expected %u)\n", 14908c2ecf20Sopenharmony_ci le16_to_cpu(message->length), 14918c2ecf20Sopenharmony_ci msg_len - MSG_HEADER_SIZE - 2); 14928c2ecf20Sopenharmony_ci goto msg_complete; 14938c2ecf20Sopenharmony_ci } 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_ci /* handle message */ 14968c2ecf20Sopenharmony_ci if (packet->flags == PACKET_TYPE_READ && 14978c2ecf20Sopenharmony_ci packet->device == PACKET_DEV_KEYB) { 14988c2ecf20Sopenharmony_ci applespi_handle_keyboard_event(applespi, &message->keyboard); 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci } else if (packet->flags == PACKET_TYPE_READ && 15018c2ecf20Sopenharmony_ci packet->device == PACKET_DEV_TPAD) { 15028c2ecf20Sopenharmony_ci struct touchpad_protocol *tp; 15038c2ecf20Sopenharmony_ci size_t tp_len; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci tp = &message->touchpad; 15068c2ecf20Sopenharmony_ci tp_len = struct_size(tp, fingers, tp->number_of_fingers); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if (le16_to_cpu(message->length) + 2 != tp_len) { 15098c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 15108c2ecf20Sopenharmony_ci "Received corrupted packet (invalid message length %u - num-fingers %u, tp-len %zu)\n", 15118c2ecf20Sopenharmony_ci le16_to_cpu(message->length), 15128c2ecf20Sopenharmony_ci tp->number_of_fingers, tp_len); 15138c2ecf20Sopenharmony_ci goto msg_complete; 15148c2ecf20Sopenharmony_ci } 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (tp->number_of_fingers > MAX_FINGERS) { 15178c2ecf20Sopenharmony_ci dev_warn_ratelimited(&applespi->spi->dev, 15188c2ecf20Sopenharmony_ci "Number of reported fingers (%u) exceeds max (%u))\n", 15198c2ecf20Sopenharmony_ci tp->number_of_fingers, 15208c2ecf20Sopenharmony_ci MAX_FINGERS); 15218c2ecf20Sopenharmony_ci tp->number_of_fingers = MAX_FINGERS; 15228c2ecf20Sopenharmony_ci } 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_ci report_tp_state(applespi, tp); 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci } else if (packet->flags == PACKET_TYPE_WRITE) { 15278c2ecf20Sopenharmony_ci applespi_handle_cmd_response(applespi, packet, message); 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_cimsg_complete: 15318c2ecf20Sopenharmony_ci applespi->saved_msg_len = 0; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci applespi_msg_complete(applespi, packet->flags == PACKET_TYPE_WRITE, 15348c2ecf20Sopenharmony_ci true); 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_cistatic void applespi_async_read_complete(void *context) 15388c2ecf20Sopenharmony_ci{ 15398c2ecf20Sopenharmony_ci struct applespi_data *applespi = context; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (applespi->rd_m.status < 0) { 15428c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, "Error reading from device: %d\n", 15438c2ecf20Sopenharmony_ci applespi->rd_m.status); 15448c2ecf20Sopenharmony_ci /* 15458c2ecf20Sopenharmony_ci * We don't actually know if this was a pure read, or a response 15468c2ecf20Sopenharmony_ci * to a write. But this is a rare error condition that should 15478c2ecf20Sopenharmony_ci * never occur, so clearing both flags to avoid deadlock. 15488c2ecf20Sopenharmony_ci */ 15498c2ecf20Sopenharmony_ci applespi_msg_complete(applespi, true, true); 15508c2ecf20Sopenharmony_ci } else { 15518c2ecf20Sopenharmony_ci applespi_got_data(applespi); 15528c2ecf20Sopenharmony_ci } 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci acpi_finish_gpe(NULL, applespi->gpe); 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_cistatic u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context) 15588c2ecf20Sopenharmony_ci{ 15598c2ecf20Sopenharmony_ci struct applespi_data *applespi = context; 15608c2ecf20Sopenharmony_ci int sts; 15618c2ecf20Sopenharmony_ci unsigned long flags; 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci trace_applespi_irq_received(ET_RD_IRQ, PT_READ); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci if (!applespi->suspended) { 15688c2ecf20Sopenharmony_ci sts = applespi_async(applespi, &applespi->rd_m, 15698c2ecf20Sopenharmony_ci applespi_async_read_complete); 15708c2ecf20Sopenharmony_ci if (sts) 15718c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 15728c2ecf20Sopenharmony_ci "Error queueing async read to device: %d\n", 15738c2ecf20Sopenharmony_ci sts); 15748c2ecf20Sopenharmony_ci else 15758c2ecf20Sopenharmony_ci applespi->read_active = true; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci return ACPI_INTERRUPT_HANDLED; 15818c2ecf20Sopenharmony_ci} 15828c2ecf20Sopenharmony_ci 15838c2ecf20Sopenharmony_cistatic int applespi_get_saved_bl_level(struct applespi_data *applespi) 15848c2ecf20Sopenharmony_ci{ 15858c2ecf20Sopenharmony_ci struct efivar_entry *efivar_entry; 15868c2ecf20Sopenharmony_ci u16 efi_data = 0; 15878c2ecf20Sopenharmony_ci unsigned long efi_data_len; 15888c2ecf20Sopenharmony_ci int sts; 15898c2ecf20Sopenharmony_ci 15908c2ecf20Sopenharmony_ci efivar_entry = kmalloc(sizeof(*efivar_entry), GFP_KERNEL); 15918c2ecf20Sopenharmony_ci if (!efivar_entry) 15928c2ecf20Sopenharmony_ci return -ENOMEM; 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci memcpy(efivar_entry->var.VariableName, EFI_BL_LEVEL_NAME, 15958c2ecf20Sopenharmony_ci sizeof(EFI_BL_LEVEL_NAME)); 15968c2ecf20Sopenharmony_ci efivar_entry->var.VendorGuid = EFI_BL_LEVEL_GUID; 15978c2ecf20Sopenharmony_ci efi_data_len = sizeof(efi_data); 15988c2ecf20Sopenharmony_ci 15998c2ecf20Sopenharmony_ci sts = efivar_entry_get(efivar_entry, NULL, &efi_data_len, &efi_data); 16008c2ecf20Sopenharmony_ci if (sts && sts != -ENOENT) 16018c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 16028c2ecf20Sopenharmony_ci "Error getting backlight level from EFI vars: %d\n", 16038c2ecf20Sopenharmony_ci sts); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci kfree(efivar_entry); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci return sts ? sts : efi_data; 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic void applespi_save_bl_level(struct applespi_data *applespi, 16118c2ecf20Sopenharmony_ci unsigned int level) 16128c2ecf20Sopenharmony_ci{ 16138c2ecf20Sopenharmony_ci efi_guid_t efi_guid; 16148c2ecf20Sopenharmony_ci u32 efi_attr; 16158c2ecf20Sopenharmony_ci unsigned long efi_data_len; 16168c2ecf20Sopenharmony_ci u16 efi_data; 16178c2ecf20Sopenharmony_ci int sts; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci /* Save keyboard backlight level */ 16208c2ecf20Sopenharmony_ci efi_guid = EFI_BL_LEVEL_GUID; 16218c2ecf20Sopenharmony_ci efi_data = (u16)level; 16228c2ecf20Sopenharmony_ci efi_data_len = sizeof(efi_data); 16238c2ecf20Sopenharmony_ci efi_attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | 16248c2ecf20Sopenharmony_ci EFI_VARIABLE_RUNTIME_ACCESS; 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci sts = efivar_entry_set_safe((efi_char16_t *)EFI_BL_LEVEL_NAME, efi_guid, 16278c2ecf20Sopenharmony_ci efi_attr, true, efi_data_len, &efi_data); 16288c2ecf20Sopenharmony_ci if (sts) 16298c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 16308c2ecf20Sopenharmony_ci "Error saving backlight level to EFI vars: %d\n", sts); 16318c2ecf20Sopenharmony_ci} 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_cistatic int applespi_probe(struct spi_device *spi) 16348c2ecf20Sopenharmony_ci{ 16358c2ecf20Sopenharmony_ci struct applespi_data *applespi; 16368c2ecf20Sopenharmony_ci acpi_handle spi_handle = ACPI_HANDLE(&spi->dev); 16378c2ecf20Sopenharmony_ci acpi_status acpi_sts; 16388c2ecf20Sopenharmony_ci int sts, i; 16398c2ecf20Sopenharmony_ci unsigned long long gpe, usb_status; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci /* check if the USB interface is present and enabled already */ 16428c2ecf20Sopenharmony_ci acpi_sts = acpi_evaluate_integer(spi_handle, "UIST", NULL, &usb_status); 16438c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(acpi_sts) && usb_status) { 16448c2ecf20Sopenharmony_ci /* let the USB driver take over instead */ 16458c2ecf20Sopenharmony_ci dev_info(&spi->dev, "USB interface already enabled\n"); 16468c2ecf20Sopenharmony_ci return -ENODEV; 16478c2ecf20Sopenharmony_ci } 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci /* allocate driver data */ 16508c2ecf20Sopenharmony_ci applespi = devm_kzalloc(&spi->dev, sizeof(*applespi), GFP_KERNEL); 16518c2ecf20Sopenharmony_ci if (!applespi) 16528c2ecf20Sopenharmony_ci return -ENOMEM; 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ci applespi->spi = spi; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci INIT_WORK(&applespi->work, applespi_worker); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci /* store the driver data */ 16598c2ecf20Sopenharmony_ci spi_set_drvdata(spi, applespi); 16608c2ecf20Sopenharmony_ci 16618c2ecf20Sopenharmony_ci /* create our buffers */ 16628c2ecf20Sopenharmony_ci applespi->tx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE, 16638c2ecf20Sopenharmony_ci GFP_KERNEL); 16648c2ecf20Sopenharmony_ci applespi->tx_status = devm_kmalloc(&spi->dev, APPLESPI_STATUS_SIZE, 16658c2ecf20Sopenharmony_ci GFP_KERNEL); 16668c2ecf20Sopenharmony_ci applespi->rx_buffer = devm_kmalloc(&spi->dev, APPLESPI_PACKET_SIZE, 16678c2ecf20Sopenharmony_ci GFP_KERNEL); 16688c2ecf20Sopenharmony_ci applespi->msg_buf = devm_kmalloc_array(&spi->dev, MAX_PKTS_PER_MSG, 16698c2ecf20Sopenharmony_ci APPLESPI_PACKET_SIZE, 16708c2ecf20Sopenharmony_ci GFP_KERNEL); 16718c2ecf20Sopenharmony_ci 16728c2ecf20Sopenharmony_ci if (!applespi->tx_buffer || !applespi->tx_status || 16738c2ecf20Sopenharmony_ci !applespi->rx_buffer || !applespi->msg_buf) 16748c2ecf20Sopenharmony_ci return -ENOMEM; 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci /* set up our spi messages */ 16778c2ecf20Sopenharmony_ci applespi_setup_read_txfrs(applespi); 16788c2ecf20Sopenharmony_ci applespi_setup_write_txfrs(applespi); 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci /* cache ACPI method handles */ 16818c2ecf20Sopenharmony_ci acpi_sts = acpi_get_handle(spi_handle, "SIEN", &applespi->sien); 16828c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) { 16838c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 16848c2ecf20Sopenharmony_ci "Failed to get SIEN ACPI method handle: %s\n", 16858c2ecf20Sopenharmony_ci acpi_format_exception(acpi_sts)); 16868c2ecf20Sopenharmony_ci return -ENODEV; 16878c2ecf20Sopenharmony_ci } 16888c2ecf20Sopenharmony_ci 16898c2ecf20Sopenharmony_ci acpi_sts = acpi_get_handle(spi_handle, "SIST", &applespi->sist); 16908c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) { 16918c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 16928c2ecf20Sopenharmony_ci "Failed to get SIST ACPI method handle: %s\n", 16938c2ecf20Sopenharmony_ci acpi_format_exception(acpi_sts)); 16948c2ecf20Sopenharmony_ci return -ENODEV; 16958c2ecf20Sopenharmony_ci } 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci /* switch on the SPI interface */ 16988c2ecf20Sopenharmony_ci sts = applespi_setup_spi(applespi); 16998c2ecf20Sopenharmony_ci if (sts) 17008c2ecf20Sopenharmony_ci return sts; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci sts = applespi_enable_spi(applespi); 17038c2ecf20Sopenharmony_ci if (sts) 17048c2ecf20Sopenharmony_ci return sts; 17058c2ecf20Sopenharmony_ci 17068c2ecf20Sopenharmony_ci /* setup the keyboard input dev */ 17078c2ecf20Sopenharmony_ci applespi->keyboard_input_dev = devm_input_allocate_device(&spi->dev); 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci if (!applespi->keyboard_input_dev) 17108c2ecf20Sopenharmony_ci return -ENOMEM; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->name = "Apple SPI Keyboard"; 17138c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->phys = "applespi/input0"; 17148c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->dev.parent = &spi->dev; 17158c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->id.bustype = BUS_SPI; 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->evbit[0] = 17188c2ecf20Sopenharmony_ci BIT_MASK(EV_KEY) | BIT_MASK(EV_LED) | BIT_MASK(EV_REP); 17198c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->ledbit[0] = BIT_MASK(LED_CAPSL); 17208c2ecf20Sopenharmony_ci 17218c2ecf20Sopenharmony_ci input_set_drvdata(applespi->keyboard_input_dev, applespi); 17228c2ecf20Sopenharmony_ci applespi->keyboard_input_dev->event = applespi_event; 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(applespi_scancodes); i++) 17258c2ecf20Sopenharmony_ci if (applespi_scancodes[i]) 17268c2ecf20Sopenharmony_ci input_set_capability(applespi->keyboard_input_dev, 17278c2ecf20Sopenharmony_ci EV_KEY, applespi_scancodes[i]); 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(applespi_controlcodes); i++) 17308c2ecf20Sopenharmony_ci if (applespi_controlcodes[i]) 17318c2ecf20Sopenharmony_ci input_set_capability(applespi->keyboard_input_dev, 17328c2ecf20Sopenharmony_ci EV_KEY, applespi_controlcodes[i]); 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(applespi_fn_codes); i++) 17358c2ecf20Sopenharmony_ci if (applespi_fn_codes[i].to) 17368c2ecf20Sopenharmony_ci input_set_capability(applespi->keyboard_input_dev, 17378c2ecf20Sopenharmony_ci EV_KEY, applespi_fn_codes[i].to); 17388c2ecf20Sopenharmony_ci 17398c2ecf20Sopenharmony_ci input_set_capability(applespi->keyboard_input_dev, EV_KEY, KEY_FN); 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci sts = input_register_device(applespi->keyboard_input_dev); 17428c2ecf20Sopenharmony_ci if (sts) { 17438c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 17448c2ecf20Sopenharmony_ci "Unable to register keyboard input device (%d)\n", sts); 17458c2ecf20Sopenharmony_ci return -ENODEV; 17468c2ecf20Sopenharmony_ci } 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci /* 17498c2ecf20Sopenharmony_ci * The applespi device doesn't send interrupts normally (as is described 17508c2ecf20Sopenharmony_ci * in its DSDT), but rather seems to use ACPI GPEs. 17518c2ecf20Sopenharmony_ci */ 17528c2ecf20Sopenharmony_ci acpi_sts = acpi_evaluate_integer(spi_handle, "_GPE", NULL, &gpe); 17538c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) { 17548c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 17558c2ecf20Sopenharmony_ci "Failed to obtain GPE for SPI slave device: %s\n", 17568c2ecf20Sopenharmony_ci acpi_format_exception(acpi_sts)); 17578c2ecf20Sopenharmony_ci return -ENODEV; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci applespi->gpe = (int)gpe; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci acpi_sts = acpi_install_gpe_handler(NULL, applespi->gpe, 17628c2ecf20Sopenharmony_ci ACPI_GPE_LEVEL_TRIGGERED, 17638c2ecf20Sopenharmony_ci applespi_notify, applespi); 17648c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) { 17658c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 17668c2ecf20Sopenharmony_ci "Failed to install GPE handler for GPE %d: %s\n", 17678c2ecf20Sopenharmony_ci applespi->gpe, acpi_format_exception(acpi_sts)); 17688c2ecf20Sopenharmony_ci return -ENODEV; 17698c2ecf20Sopenharmony_ci } 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci applespi->suspended = false; 17728c2ecf20Sopenharmony_ci 17738c2ecf20Sopenharmony_ci acpi_sts = acpi_enable_gpe(NULL, applespi->gpe); 17748c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) { 17758c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 17768c2ecf20Sopenharmony_ci "Failed to enable GPE handler for GPE %d: %s\n", 17778c2ecf20Sopenharmony_ci applespi->gpe, acpi_format_exception(acpi_sts)); 17788c2ecf20Sopenharmony_ci acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify); 17798c2ecf20Sopenharmony_ci return -ENODEV; 17808c2ecf20Sopenharmony_ci } 17818c2ecf20Sopenharmony_ci 17828c2ecf20Sopenharmony_ci /* trigger touchpad setup */ 17838c2ecf20Sopenharmony_ci applespi_init(applespi, false); 17848c2ecf20Sopenharmony_ci 17858c2ecf20Sopenharmony_ci /* 17868c2ecf20Sopenharmony_ci * By default this device is not enabled for wakeup; but USB keyboards 17878c2ecf20Sopenharmony_ci * generally are, so the expectation is that by default the keyboard 17888c2ecf20Sopenharmony_ci * will wake the system. 17898c2ecf20Sopenharmony_ci */ 17908c2ecf20Sopenharmony_ci device_wakeup_enable(&spi->dev); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci /* set up keyboard-backlight */ 17938c2ecf20Sopenharmony_ci sts = applespi_get_saved_bl_level(applespi); 17948c2ecf20Sopenharmony_ci if (sts >= 0) 17958c2ecf20Sopenharmony_ci applespi_set_bl_level(&applespi->backlight_info, sts); 17968c2ecf20Sopenharmony_ci 17978c2ecf20Sopenharmony_ci applespi->backlight_info.name = "spi::kbd_backlight"; 17988c2ecf20Sopenharmony_ci applespi->backlight_info.default_trigger = "kbd-backlight"; 17998c2ecf20Sopenharmony_ci applespi->backlight_info.brightness_set = applespi_set_bl_level; 18008c2ecf20Sopenharmony_ci 18018c2ecf20Sopenharmony_ci sts = devm_led_classdev_register(&spi->dev, &applespi->backlight_info); 18028c2ecf20Sopenharmony_ci if (sts) 18038c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 18048c2ecf20Sopenharmony_ci "Unable to register keyboard backlight class dev (%d)\n", 18058c2ecf20Sopenharmony_ci sts); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci /* set up debugfs entries for touchpad dimensions logging */ 18088c2ecf20Sopenharmony_ci applespi->debugfs_root = debugfs_create_dir("applespi", NULL); 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci debugfs_create_bool("enable_tp_dim", 0600, applespi->debugfs_root, 18118c2ecf20Sopenharmony_ci &applespi->debug_tp_dim); 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_ci debugfs_create_file("tp_dim", 0400, applespi->debugfs_root, applespi, 18148c2ecf20Sopenharmony_ci &applespi_tp_dim_fops); 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci return 0; 18178c2ecf20Sopenharmony_ci} 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_cistatic void applespi_drain_writes(struct applespi_data *applespi) 18208c2ecf20Sopenharmony_ci{ 18218c2ecf20Sopenharmony_ci unsigned long flags; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 18248c2ecf20Sopenharmony_ci 18258c2ecf20Sopenharmony_ci applespi->drain = true; 18268c2ecf20Sopenharmony_ci wait_event_lock_irq(applespi->drain_complete, !applespi->write_active, 18278c2ecf20Sopenharmony_ci applespi->cmd_msg_lock); 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 18308c2ecf20Sopenharmony_ci} 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_cistatic void applespi_drain_reads(struct applespi_data *applespi) 18338c2ecf20Sopenharmony_ci{ 18348c2ecf20Sopenharmony_ci unsigned long flags; 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci wait_event_lock_irq(applespi->drain_complete, !applespi->read_active, 18398c2ecf20Sopenharmony_ci applespi->cmd_msg_lock); 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci applespi->suspended = true; 18428c2ecf20Sopenharmony_ci 18438c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 18448c2ecf20Sopenharmony_ci} 18458c2ecf20Sopenharmony_ci 18468c2ecf20Sopenharmony_cistatic int applespi_remove(struct spi_device *spi) 18478c2ecf20Sopenharmony_ci{ 18488c2ecf20Sopenharmony_ci struct applespi_data *applespi = spi_get_drvdata(spi); 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_ci applespi_drain_writes(applespi); 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci acpi_disable_gpe(NULL, applespi->gpe); 18538c2ecf20Sopenharmony_ci acpi_remove_gpe_handler(NULL, applespi->gpe, applespi_notify); 18548c2ecf20Sopenharmony_ci device_wakeup_disable(&spi->dev); 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ci applespi_drain_reads(applespi); 18578c2ecf20Sopenharmony_ci 18588c2ecf20Sopenharmony_ci debugfs_remove_recursive(applespi->debugfs_root); 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_ci return 0; 18618c2ecf20Sopenharmony_ci} 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_cistatic void applespi_shutdown(struct spi_device *spi) 18648c2ecf20Sopenharmony_ci{ 18658c2ecf20Sopenharmony_ci struct applespi_data *applespi = spi_get_drvdata(spi); 18668c2ecf20Sopenharmony_ci 18678c2ecf20Sopenharmony_ci applespi_save_bl_level(applespi, applespi->have_bl_level); 18688c2ecf20Sopenharmony_ci} 18698c2ecf20Sopenharmony_ci 18708c2ecf20Sopenharmony_cistatic int applespi_poweroff_late(struct device *dev) 18718c2ecf20Sopenharmony_ci{ 18728c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 18738c2ecf20Sopenharmony_ci struct applespi_data *applespi = spi_get_drvdata(spi); 18748c2ecf20Sopenharmony_ci 18758c2ecf20Sopenharmony_ci applespi_save_bl_level(applespi, applespi->have_bl_level); 18768c2ecf20Sopenharmony_ci 18778c2ecf20Sopenharmony_ci return 0; 18788c2ecf20Sopenharmony_ci} 18798c2ecf20Sopenharmony_ci 18808c2ecf20Sopenharmony_cistatic int __maybe_unused applespi_suspend(struct device *dev) 18818c2ecf20Sopenharmony_ci{ 18828c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 18838c2ecf20Sopenharmony_ci struct applespi_data *applespi = spi_get_drvdata(spi); 18848c2ecf20Sopenharmony_ci acpi_status acpi_sts; 18858c2ecf20Sopenharmony_ci int sts; 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_ci /* turn off caps-lock - it'll stay on otherwise */ 18888c2ecf20Sopenharmony_ci sts = applespi_set_capsl_led(applespi, false); 18898c2ecf20Sopenharmony_ci if (sts) 18908c2ecf20Sopenharmony_ci dev_warn(&applespi->spi->dev, 18918c2ecf20Sopenharmony_ci "Failed to turn off caps-lock led (%d)\n", sts); 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci applespi_drain_writes(applespi); 18948c2ecf20Sopenharmony_ci 18958c2ecf20Sopenharmony_ci /* disable the interrupt */ 18968c2ecf20Sopenharmony_ci acpi_sts = acpi_disable_gpe(NULL, applespi->gpe); 18978c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) 18988c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 18998c2ecf20Sopenharmony_ci "Failed to disable GPE handler for GPE %d: %s\n", 19008c2ecf20Sopenharmony_ci applespi->gpe, acpi_format_exception(acpi_sts)); 19018c2ecf20Sopenharmony_ci 19028c2ecf20Sopenharmony_ci applespi_drain_reads(applespi); 19038c2ecf20Sopenharmony_ci 19048c2ecf20Sopenharmony_ci return 0; 19058c2ecf20Sopenharmony_ci} 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_cistatic int __maybe_unused applespi_resume(struct device *dev) 19088c2ecf20Sopenharmony_ci{ 19098c2ecf20Sopenharmony_ci struct spi_device *spi = to_spi_device(dev); 19108c2ecf20Sopenharmony_ci struct applespi_data *applespi = spi_get_drvdata(spi); 19118c2ecf20Sopenharmony_ci acpi_status acpi_sts; 19128c2ecf20Sopenharmony_ci unsigned long flags; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci /* ensure our flags and state reflect a newly resumed device */ 19158c2ecf20Sopenharmony_ci spin_lock_irqsave(&applespi->cmd_msg_lock, flags); 19168c2ecf20Sopenharmony_ci 19178c2ecf20Sopenharmony_ci applespi->drain = false; 19188c2ecf20Sopenharmony_ci applespi->have_cl_led_on = false; 19198c2ecf20Sopenharmony_ci applespi->have_bl_level = 0; 19208c2ecf20Sopenharmony_ci applespi->cmd_msg_queued = 0; 19218c2ecf20Sopenharmony_ci applespi->read_active = false; 19228c2ecf20Sopenharmony_ci applespi->write_active = false; 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci applespi->suspended = false; 19258c2ecf20Sopenharmony_ci 19268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags); 19278c2ecf20Sopenharmony_ci 19288c2ecf20Sopenharmony_ci /* switch on the SPI interface */ 19298c2ecf20Sopenharmony_ci applespi_enable_spi(applespi); 19308c2ecf20Sopenharmony_ci 19318c2ecf20Sopenharmony_ci /* re-enable the interrupt */ 19328c2ecf20Sopenharmony_ci acpi_sts = acpi_enable_gpe(NULL, applespi->gpe); 19338c2ecf20Sopenharmony_ci if (ACPI_FAILURE(acpi_sts)) 19348c2ecf20Sopenharmony_ci dev_err(&applespi->spi->dev, 19358c2ecf20Sopenharmony_ci "Failed to re-enable GPE handler for GPE %d: %s\n", 19368c2ecf20Sopenharmony_ci applespi->gpe, acpi_format_exception(acpi_sts)); 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_ci /* switch the touchpad into multitouch mode */ 19398c2ecf20Sopenharmony_ci applespi_init(applespi, true); 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci return 0; 19428c2ecf20Sopenharmony_ci} 19438c2ecf20Sopenharmony_ci 19448c2ecf20Sopenharmony_cistatic const struct acpi_device_id applespi_acpi_match[] = { 19458c2ecf20Sopenharmony_ci { "APP000D", 0 }, 19468c2ecf20Sopenharmony_ci { } 19478c2ecf20Sopenharmony_ci}; 19488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, applespi_acpi_match); 19498c2ecf20Sopenharmony_ci 19508c2ecf20Sopenharmony_cistatic const struct dev_pm_ops applespi_pm_ops = { 19518c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(applespi_suspend, applespi_resume) 19528c2ecf20Sopenharmony_ci .poweroff_late = applespi_poweroff_late, 19538c2ecf20Sopenharmony_ci}; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic struct spi_driver applespi_driver = { 19568c2ecf20Sopenharmony_ci .driver = { 19578c2ecf20Sopenharmony_ci .name = "applespi", 19588c2ecf20Sopenharmony_ci .acpi_match_table = applespi_acpi_match, 19598c2ecf20Sopenharmony_ci .pm = &applespi_pm_ops, 19608c2ecf20Sopenharmony_ci }, 19618c2ecf20Sopenharmony_ci .probe = applespi_probe, 19628c2ecf20Sopenharmony_ci .remove = applespi_remove, 19638c2ecf20Sopenharmony_ci .shutdown = applespi_shutdown, 19648c2ecf20Sopenharmony_ci}; 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_cimodule_spi_driver(applespi_driver) 19678c2ecf20Sopenharmony_ci 19688c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 19698c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("MacBook(Pro) SPI Keyboard/Touchpad driver"); 19708c2ecf20Sopenharmony_ciMODULE_AUTHOR("Federico Lorenzi"); 19718c2ecf20Sopenharmony_ciMODULE_AUTHOR("Ronald Tschalär"); 1972