17b6bf51dSK Naduvalath, Sumesh // SPDX-License-Identifier: GPL-2.0-only
27b6bf51dSK Naduvalath, Sumesh /*
37b6bf51dSK Naduvalath, Sumesh * Intel ECLite opregion driver for talking to ECLite firmware running on
47b6bf51dSK Naduvalath, Sumesh * Intel Integrated Sensor Hub (ISH) using ISH Transport Protocol (ISHTP)
57b6bf51dSK Naduvalath, Sumesh *
67b6bf51dSK Naduvalath, Sumesh * Copyright (c) 2021, Intel Corporation.
77b6bf51dSK Naduvalath, Sumesh */
87b6bf51dSK Naduvalath, Sumesh
97b6bf51dSK Naduvalath, Sumesh #include <linux/acpi.h>
107b6bf51dSK Naduvalath, Sumesh #include <linux/bitops.h>
117b6bf51dSK Naduvalath, Sumesh #include <linux/device.h>
127b6bf51dSK Naduvalath, Sumesh #include <linux/errno.h>
137b6bf51dSK Naduvalath, Sumesh #include <linux/intel-ish-client-if.h>
147b6bf51dSK Naduvalath, Sumesh #include <linux/kernel.h>
157b6bf51dSK Naduvalath, Sumesh #include <linux/module.h>
167b6bf51dSK Naduvalath, Sumesh #include <linux/mutex.h>
177b6bf51dSK Naduvalath, Sumesh #include <linux/slab.h>
187b6bf51dSK Naduvalath, Sumesh #include <linux/suspend.h>
197b6bf51dSK Naduvalath, Sumesh #include <linux/types.h>
207b6bf51dSK Naduvalath, Sumesh #include <linux/uuid.h>
217b6bf51dSK Naduvalath, Sumesh #include <linux/uaccess.h>
227b6bf51dSK Naduvalath, Sumesh
237b6bf51dSK Naduvalath, Sumesh #define ECLITE_DATA_OPREGION_ID 0x9E
247b6bf51dSK Naduvalath, Sumesh #define ECLITE_CMD_OPREGION_ID 0x9F
257b6bf51dSK Naduvalath, Sumesh
267b6bf51dSK Naduvalath, Sumesh #define ECL_MSG_DATA 0x1
277b6bf51dSK Naduvalath, Sumesh #define ECL_MSG_EVENT 0x2
287b6bf51dSK Naduvalath, Sumesh
297b6bf51dSK Naduvalath, Sumesh #define ECL_ISH_READ 0x1
307b6bf51dSK Naduvalath, Sumesh #define ECL_ISH_WRITE 0x2
317b6bf51dSK Naduvalath, Sumesh #define ECL_ISH_HEADER_VERSION 0
327b6bf51dSK Naduvalath, Sumesh
337b6bf51dSK Naduvalath, Sumesh #define ECL_CL_RX_RING_SIZE 16
347b6bf51dSK Naduvalath, Sumesh #define ECL_CL_TX_RING_SIZE 8
357b6bf51dSK Naduvalath, Sumesh
367b6bf51dSK Naduvalath, Sumesh #define ECL_DATA_OPR_BUFLEN 384
377b6bf51dSK Naduvalath, Sumesh #define ECL_EVENTS_NOTIFY 333
387b6bf51dSK Naduvalath, Sumesh
397b6bf51dSK Naduvalath, Sumesh #define cmd_opr_offsetof(element) offsetof(struct opregion_cmd, element)
407b6bf51dSK Naduvalath, Sumesh #define cl_data_to_dev(opr_dev) ishtp_device((opr_dev)->cl_device)
417b6bf51dSK Naduvalath, Sumesh
427b6bf51dSK Naduvalath, Sumesh #ifndef BITS_TO_BYTES
437b6bf51dSK Naduvalath, Sumesh #define BITS_TO_BYTES(x) ((x) / 8)
447b6bf51dSK Naduvalath, Sumesh #endif
457b6bf51dSK Naduvalath, Sumesh
467b6bf51dSK Naduvalath, Sumesh struct opregion_cmd {
477b6bf51dSK Naduvalath, Sumesh unsigned int command;
487b6bf51dSK Naduvalath, Sumesh unsigned int offset;
497b6bf51dSK Naduvalath, Sumesh unsigned int length;
507b6bf51dSK Naduvalath, Sumesh unsigned int event_id;
517b6bf51dSK Naduvalath, Sumesh };
527b6bf51dSK Naduvalath, Sumesh
537b6bf51dSK Naduvalath, Sumesh struct opregion_data {
547b6bf51dSK Naduvalath, Sumesh char data[ECL_DATA_OPR_BUFLEN];
557b6bf51dSK Naduvalath, Sumesh };
567b6bf51dSK Naduvalath, Sumesh
577b6bf51dSK Naduvalath, Sumesh struct opregion_context {
587b6bf51dSK Naduvalath, Sumesh struct opregion_cmd cmd_area;
597b6bf51dSK Naduvalath, Sumesh struct opregion_data data_area;
607b6bf51dSK Naduvalath, Sumesh };
617b6bf51dSK Naduvalath, Sumesh
627b6bf51dSK Naduvalath, Sumesh struct ecl_message_header {
637b6bf51dSK Naduvalath, Sumesh unsigned int version:2;
647b6bf51dSK Naduvalath, Sumesh unsigned int data_type:2;
657b6bf51dSK Naduvalath, Sumesh unsigned int request_type:2;
667b6bf51dSK Naduvalath, Sumesh unsigned int offset:9;
677b6bf51dSK Naduvalath, Sumesh unsigned int data_len:9;
687b6bf51dSK Naduvalath, Sumesh unsigned int event:8;
697b6bf51dSK Naduvalath, Sumesh };
707b6bf51dSK Naduvalath, Sumesh
717b6bf51dSK Naduvalath, Sumesh struct ecl_message {
727b6bf51dSK Naduvalath, Sumesh struct ecl_message_header header;
737b6bf51dSK Naduvalath, Sumesh char payload[ECL_DATA_OPR_BUFLEN];
747b6bf51dSK Naduvalath, Sumesh };
757b6bf51dSK Naduvalath, Sumesh
767b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev {
777b6bf51dSK Naduvalath, Sumesh struct opregion_context opr_context;
787b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl;
797b6bf51dSK Naduvalath, Sumesh struct ishtp_cl_device *cl_device;
807b6bf51dSK Naduvalath, Sumesh struct ishtp_fw_client *fw_client;
817b6bf51dSK Naduvalath, Sumesh struct ishtp_cl_rb *rb;
827b6bf51dSK Naduvalath, Sumesh struct acpi_device *adev;
837b6bf51dSK Naduvalath, Sumesh unsigned int dsm_event_id;
847b6bf51dSK Naduvalath, Sumesh unsigned int ish_link_ready;
857b6bf51dSK Naduvalath, Sumesh unsigned int ish_read_done;
867b6bf51dSK Naduvalath, Sumesh unsigned int acpi_init_done;
877b6bf51dSK Naduvalath, Sumesh wait_queue_head_t read_wait;
887b6bf51dSK Naduvalath, Sumesh struct work_struct event_work;
897b6bf51dSK Naduvalath, Sumesh struct work_struct reset_work;
907b6bf51dSK Naduvalath, Sumesh /* lock for opregion context */
917b6bf51dSK Naduvalath, Sumesh struct mutex lock;
927b6bf51dSK Naduvalath, Sumesh
937b6bf51dSK Naduvalath, Sumesh };
947b6bf51dSK Naduvalath, Sumesh
957b6bf51dSK Naduvalath, Sumesh /* eclite ishtp client UUID: 6a19cc4b-d760-4de3-b14d-f25ebd0fbcd9 */
96*bf9167a8SArnd Bergmann static const struct ishtp_device_id ecl_ishtp_id_table[] = {
97*bf9167a8SArnd Bergmann { .guid = GUID_INIT(0x6a19cc4b, 0xd760, 0x4de3,
98*bf9167a8SArnd Bergmann 0xb1, 0x4d, 0xf2, 0x5e, 0xbd, 0xf, 0xbc, 0xd9), },
99*bf9167a8SArnd Bergmann { }
100*bf9167a8SArnd Bergmann };
101*bf9167a8SArnd Bergmann MODULE_DEVICE_TABLE(ishtp, ecl_ishtp_id_table);
1027b6bf51dSK Naduvalath, Sumesh
1037b6bf51dSK Naduvalath, Sumesh /* ACPI DSM UUID: 91d936a7-1f01-49c6-a6b4-72f00ad8d8a5 */
1047b6bf51dSK Naduvalath, Sumesh static const guid_t ecl_acpi_guid =
1057b6bf51dSK Naduvalath, Sumesh GUID_INIT(0x91d936a7, 0x1f01, 0x49c6, 0xa6,
1067b6bf51dSK Naduvalath, Sumesh 0xb4, 0x72, 0xf0, 0x0a, 0xd8, 0xd8, 0xa5);
1077b6bf51dSK Naduvalath, Sumesh
1087b6bf51dSK Naduvalath, Sumesh /**
1097b6bf51dSK Naduvalath, Sumesh * ecl_ish_cl_read() - Read data from eclite FW
1107b6bf51dSK Naduvalath, Sumesh *
1117b6bf51dSK Naduvalath, Sumesh * @opr_dev: pointer to opregion device
1127b6bf51dSK Naduvalath, Sumesh *
1137b6bf51dSK Naduvalath, Sumesh * This function issues a read request to eclite FW and waits until it
1147b6bf51dSK Naduvalath, Sumesh * receives a response. When response is received the read data is copied to
1157b6bf51dSK Naduvalath, Sumesh * opregion buffer.
1167b6bf51dSK Naduvalath, Sumesh */
ecl_ish_cl_read(struct ishtp_opregion_dev * opr_dev)1177b6bf51dSK Naduvalath, Sumesh static int ecl_ish_cl_read(struct ishtp_opregion_dev *opr_dev)
1187b6bf51dSK Naduvalath, Sumesh {
1197b6bf51dSK Naduvalath, Sumesh struct ecl_message_header header;
1207b6bf51dSK Naduvalath, Sumesh int len, rv;
1217b6bf51dSK Naduvalath, Sumesh
1227b6bf51dSK Naduvalath, Sumesh if (!opr_dev->ish_link_ready)
1237b6bf51dSK Naduvalath, Sumesh return -EIO;
1247b6bf51dSK Naduvalath, Sumesh
1257b6bf51dSK Naduvalath, Sumesh if ((opr_dev->opr_context.cmd_area.offset +
1267b6bf51dSK Naduvalath, Sumesh opr_dev->opr_context.cmd_area.length) > ECL_DATA_OPR_BUFLEN) {
1277b6bf51dSK Naduvalath, Sumesh return -EINVAL;
1287b6bf51dSK Naduvalath, Sumesh }
1297b6bf51dSK Naduvalath, Sumesh
1307b6bf51dSK Naduvalath, Sumesh header.version = ECL_ISH_HEADER_VERSION;
1317b6bf51dSK Naduvalath, Sumesh header.data_type = ECL_MSG_DATA;
1327b6bf51dSK Naduvalath, Sumesh header.request_type = ECL_ISH_READ;
1337b6bf51dSK Naduvalath, Sumesh header.offset = opr_dev->opr_context.cmd_area.offset;
1347b6bf51dSK Naduvalath, Sumesh header.data_len = opr_dev->opr_context.cmd_area.length;
1357b6bf51dSK Naduvalath, Sumesh header.event = opr_dev->opr_context.cmd_area.event_id;
1367b6bf51dSK Naduvalath, Sumesh len = sizeof(header);
1377b6bf51dSK Naduvalath, Sumesh
1387b6bf51dSK Naduvalath, Sumesh opr_dev->ish_read_done = false;
1397b6bf51dSK Naduvalath, Sumesh rv = ishtp_cl_send(opr_dev->ecl_ishtp_cl, (uint8_t *)&header, len);
1407b6bf51dSK Naduvalath, Sumesh if (rv) {
1417b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "ish-read : send failed\n");
1427b6bf51dSK Naduvalath, Sumesh return -EIO;
1437b6bf51dSK Naduvalath, Sumesh }
1447b6bf51dSK Naduvalath, Sumesh
1457b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev),
1467b6bf51dSK Naduvalath, Sumesh "[ish_rd] Req: off : %x, len : %x\n",
1477b6bf51dSK Naduvalath, Sumesh header.offset,
1487b6bf51dSK Naduvalath, Sumesh header.data_len);
1497b6bf51dSK Naduvalath, Sumesh
1507b6bf51dSK Naduvalath, Sumesh rv = wait_event_interruptible_timeout(opr_dev->read_wait,
1517b6bf51dSK Naduvalath, Sumesh opr_dev->ish_read_done,
1527b6bf51dSK Naduvalath, Sumesh 2 * HZ);
1537b6bf51dSK Naduvalath, Sumesh if (!rv) {
1547b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev),
1557b6bf51dSK Naduvalath, Sumesh "[ish_rd] No response from firmware\n");
1567b6bf51dSK Naduvalath, Sumesh return -EIO;
1577b6bf51dSK Naduvalath, Sumesh }
1587b6bf51dSK Naduvalath, Sumesh
1597b6bf51dSK Naduvalath, Sumesh return 0;
1607b6bf51dSK Naduvalath, Sumesh }
1617b6bf51dSK Naduvalath, Sumesh
1627b6bf51dSK Naduvalath, Sumesh /**
1637b6bf51dSK Naduvalath, Sumesh * ecl_ish_cl_write() - This function writes data to eclite FW.
1647b6bf51dSK Naduvalath, Sumesh *
1657b6bf51dSK Naduvalath, Sumesh * @opr_dev: pointer to opregion device
1667b6bf51dSK Naduvalath, Sumesh *
1677b6bf51dSK Naduvalath, Sumesh * This function writes data to eclite FW.
1687b6bf51dSK Naduvalath, Sumesh */
ecl_ish_cl_write(struct ishtp_opregion_dev * opr_dev)1697b6bf51dSK Naduvalath, Sumesh static int ecl_ish_cl_write(struct ishtp_opregion_dev *opr_dev)
1707b6bf51dSK Naduvalath, Sumesh {
1717b6bf51dSK Naduvalath, Sumesh struct ecl_message message;
1727b6bf51dSK Naduvalath, Sumesh int len;
1737b6bf51dSK Naduvalath, Sumesh
1747b6bf51dSK Naduvalath, Sumesh if (!opr_dev->ish_link_ready)
1757b6bf51dSK Naduvalath, Sumesh return -EIO;
1767b6bf51dSK Naduvalath, Sumesh
1777b6bf51dSK Naduvalath, Sumesh if ((opr_dev->opr_context.cmd_area.offset +
1787b6bf51dSK Naduvalath, Sumesh opr_dev->opr_context.cmd_area.length) > ECL_DATA_OPR_BUFLEN) {
1797b6bf51dSK Naduvalath, Sumesh return -EINVAL;
1807b6bf51dSK Naduvalath, Sumesh }
1817b6bf51dSK Naduvalath, Sumesh
1827b6bf51dSK Naduvalath, Sumesh message.header.version = ECL_ISH_HEADER_VERSION;
1837b6bf51dSK Naduvalath, Sumesh message.header.data_type = ECL_MSG_DATA;
1847b6bf51dSK Naduvalath, Sumesh message.header.request_type = ECL_ISH_WRITE;
1857b6bf51dSK Naduvalath, Sumesh message.header.offset = opr_dev->opr_context.cmd_area.offset;
1867b6bf51dSK Naduvalath, Sumesh message.header.data_len = opr_dev->opr_context.cmd_area.length;
1877b6bf51dSK Naduvalath, Sumesh message.header.event = opr_dev->opr_context.cmd_area.event_id;
1887b6bf51dSK Naduvalath, Sumesh len = sizeof(struct ecl_message_header) + message.header.data_len;
1897b6bf51dSK Naduvalath, Sumesh
1907b6bf51dSK Naduvalath, Sumesh memcpy(message.payload,
1917b6bf51dSK Naduvalath, Sumesh opr_dev->opr_context.data_area.data + message.header.offset,
1927b6bf51dSK Naduvalath, Sumesh message.header.data_len);
1937b6bf51dSK Naduvalath, Sumesh
1947b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev),
1957b6bf51dSK Naduvalath, Sumesh "[ish_wr] off : %x, len : %x\n",
1967b6bf51dSK Naduvalath, Sumesh message.header.offset,
1977b6bf51dSK Naduvalath, Sumesh message.header.data_len);
1987b6bf51dSK Naduvalath, Sumesh
1997b6bf51dSK Naduvalath, Sumesh return ishtp_cl_send(opr_dev->ecl_ishtp_cl, (uint8_t *)&message, len);
2007b6bf51dSK Naduvalath, Sumesh }
2017b6bf51dSK Naduvalath, Sumesh
2027b6bf51dSK Naduvalath, Sumesh static acpi_status
ecl_opregion_cmd_handler(u32 function,acpi_physical_address address,u32 bits,u64 * value64,void * handler_context,void * region_context)2037b6bf51dSK Naduvalath, Sumesh ecl_opregion_cmd_handler(u32 function, acpi_physical_address address,
2047b6bf51dSK Naduvalath, Sumesh u32 bits, u64 *value64,
2057b6bf51dSK Naduvalath, Sumesh void *handler_context, void *region_context)
2067b6bf51dSK Naduvalath, Sumesh {
2077b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev;
2087b6bf51dSK Naduvalath, Sumesh struct opregion_cmd *cmd;
2097b6bf51dSK Naduvalath, Sumesh acpi_status status = AE_OK;
2107b6bf51dSK Naduvalath, Sumesh
2117b6bf51dSK Naduvalath, Sumesh if (!region_context || !value64)
2127b6bf51dSK Naduvalath, Sumesh return AE_BAD_PARAMETER;
2137b6bf51dSK Naduvalath, Sumesh
2147b6bf51dSK Naduvalath, Sumesh if (function == ACPI_READ)
2157b6bf51dSK Naduvalath, Sumesh return AE_ERROR;
2167b6bf51dSK Naduvalath, Sumesh
2177b6bf51dSK Naduvalath, Sumesh opr_dev = (struct ishtp_opregion_dev *)region_context;
2187b6bf51dSK Naduvalath, Sumesh
2197b6bf51dSK Naduvalath, Sumesh mutex_lock(&opr_dev->lock);
2207b6bf51dSK Naduvalath, Sumesh
2217b6bf51dSK Naduvalath, Sumesh cmd = &opr_dev->opr_context.cmd_area;
2227b6bf51dSK Naduvalath, Sumesh
2237b6bf51dSK Naduvalath, Sumesh switch (address) {
2247b6bf51dSK Naduvalath, Sumesh case cmd_opr_offsetof(command):
2257b6bf51dSK Naduvalath, Sumesh cmd->command = (u32)*value64;
2267b6bf51dSK Naduvalath, Sumesh
2277b6bf51dSK Naduvalath, Sumesh if (cmd->command == ECL_ISH_READ)
2287b6bf51dSK Naduvalath, Sumesh status = ecl_ish_cl_read(opr_dev);
2297b6bf51dSK Naduvalath, Sumesh else if (cmd->command == ECL_ISH_WRITE)
2307b6bf51dSK Naduvalath, Sumesh status = ecl_ish_cl_write(opr_dev);
2317b6bf51dSK Naduvalath, Sumesh else
2327b6bf51dSK Naduvalath, Sumesh status = AE_ERROR;
2337b6bf51dSK Naduvalath, Sumesh break;
2347b6bf51dSK Naduvalath, Sumesh case cmd_opr_offsetof(offset):
2357b6bf51dSK Naduvalath, Sumesh cmd->offset = (u32)*value64;
2367b6bf51dSK Naduvalath, Sumesh break;
2377b6bf51dSK Naduvalath, Sumesh case cmd_opr_offsetof(length):
2387b6bf51dSK Naduvalath, Sumesh cmd->length = (u32)*value64;
2397b6bf51dSK Naduvalath, Sumesh break;
2407b6bf51dSK Naduvalath, Sumesh case cmd_opr_offsetof(event_id):
2417b6bf51dSK Naduvalath, Sumesh cmd->event_id = (u32)*value64;
2427b6bf51dSK Naduvalath, Sumesh break;
2437b6bf51dSK Naduvalath, Sumesh default:
2447b6bf51dSK Naduvalath, Sumesh status = AE_ERROR;
2457b6bf51dSK Naduvalath, Sumesh }
2467b6bf51dSK Naduvalath, Sumesh
2477b6bf51dSK Naduvalath, Sumesh mutex_unlock(&opr_dev->lock);
2487b6bf51dSK Naduvalath, Sumesh
2497b6bf51dSK Naduvalath, Sumesh return status;
2507b6bf51dSK Naduvalath, Sumesh }
2517b6bf51dSK Naduvalath, Sumesh
2527b6bf51dSK Naduvalath, Sumesh static acpi_status
ecl_opregion_data_handler(u32 function,acpi_physical_address address,u32 bits,u64 * value64,void * handler_context,void * region_context)2537b6bf51dSK Naduvalath, Sumesh ecl_opregion_data_handler(u32 function, acpi_physical_address address,
2547b6bf51dSK Naduvalath, Sumesh u32 bits, u64 *value64,
2557b6bf51dSK Naduvalath, Sumesh void *handler_context, void *region_context)
2567b6bf51dSK Naduvalath, Sumesh {
2577b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev;
2587b6bf51dSK Naduvalath, Sumesh unsigned int bytes = BITS_TO_BYTES(bits);
2597b6bf51dSK Naduvalath, Sumesh void *data_addr;
2607b6bf51dSK Naduvalath, Sumesh
2617b6bf51dSK Naduvalath, Sumesh if (!region_context || !value64)
2627b6bf51dSK Naduvalath, Sumesh return AE_BAD_PARAMETER;
2637b6bf51dSK Naduvalath, Sumesh
2647b6bf51dSK Naduvalath, Sumesh if (address + bytes > ECL_DATA_OPR_BUFLEN)
2657b6bf51dSK Naduvalath, Sumesh return AE_BAD_PARAMETER;
2667b6bf51dSK Naduvalath, Sumesh
2677b6bf51dSK Naduvalath, Sumesh opr_dev = (struct ishtp_opregion_dev *)region_context;
2687b6bf51dSK Naduvalath, Sumesh
2697b6bf51dSK Naduvalath, Sumesh mutex_lock(&opr_dev->lock);
2707b6bf51dSK Naduvalath, Sumesh
2717b6bf51dSK Naduvalath, Sumesh data_addr = &opr_dev->opr_context.data_area.data[address];
2727b6bf51dSK Naduvalath, Sumesh
2737b6bf51dSK Naduvalath, Sumesh if (function == ACPI_READ) {
2747b6bf51dSK Naduvalath, Sumesh memcpy(value64, data_addr, bytes);
2757b6bf51dSK Naduvalath, Sumesh } else if (function == ACPI_WRITE) {
2767b6bf51dSK Naduvalath, Sumesh memcpy(data_addr, value64, bytes);
2777b6bf51dSK Naduvalath, Sumesh } else {
2787b6bf51dSK Naduvalath, Sumesh mutex_unlock(&opr_dev->lock);
2797b6bf51dSK Naduvalath, Sumesh return AE_BAD_PARAMETER;
2807b6bf51dSK Naduvalath, Sumesh }
2817b6bf51dSK Naduvalath, Sumesh
2827b6bf51dSK Naduvalath, Sumesh mutex_unlock(&opr_dev->lock);
2837b6bf51dSK Naduvalath, Sumesh
2847b6bf51dSK Naduvalath, Sumesh return AE_OK;
2857b6bf51dSK Naduvalath, Sumesh }
2867b6bf51dSK Naduvalath, Sumesh
acpi_find_eclite_device(struct ishtp_opregion_dev * opr_dev)2877b6bf51dSK Naduvalath, Sumesh static int acpi_find_eclite_device(struct ishtp_opregion_dev *opr_dev)
2887b6bf51dSK Naduvalath, Sumesh {
2897b6bf51dSK Naduvalath, Sumesh struct acpi_device *adev;
2907b6bf51dSK Naduvalath, Sumesh
2917b6bf51dSK Naduvalath, Sumesh /* Find ECLite device and save reference */
2927b6bf51dSK Naduvalath, Sumesh adev = acpi_dev_get_first_match_dev("INTC1035", NULL, -1);
2937b6bf51dSK Naduvalath, Sumesh if (!adev) {
2947b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "eclite ACPI device not found\n");
2957b6bf51dSK Naduvalath, Sumesh return -ENODEV;
2967b6bf51dSK Naduvalath, Sumesh }
2977b6bf51dSK Naduvalath, Sumesh
2987b6bf51dSK Naduvalath, Sumesh opr_dev->adev = adev;
2997b6bf51dSK Naduvalath, Sumesh
3007b6bf51dSK Naduvalath, Sumesh return 0;
3017b6bf51dSK Naduvalath, Sumesh }
3027b6bf51dSK Naduvalath, Sumesh
acpi_opregion_init(struct ishtp_opregion_dev * opr_dev)3037b6bf51dSK Naduvalath, Sumesh static int acpi_opregion_init(struct ishtp_opregion_dev *opr_dev)
3047b6bf51dSK Naduvalath, Sumesh {
3057b6bf51dSK Naduvalath, Sumesh acpi_status status;
3067b6bf51dSK Naduvalath, Sumesh
3077b6bf51dSK Naduvalath, Sumesh status = acpi_install_address_space_handler(opr_dev->adev->handle,
3087b6bf51dSK Naduvalath, Sumesh ECLITE_CMD_OPREGION_ID,
3097b6bf51dSK Naduvalath, Sumesh ecl_opregion_cmd_handler,
3107b6bf51dSK Naduvalath, Sumesh NULL, opr_dev);
3117b6bf51dSK Naduvalath, Sumesh if (ACPI_FAILURE(status)) {
3127b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev),
3137b6bf51dSK Naduvalath, Sumesh "cmd space handler install failed\n");
3147b6bf51dSK Naduvalath, Sumesh return -ENODEV;
3157b6bf51dSK Naduvalath, Sumesh }
3167b6bf51dSK Naduvalath, Sumesh
3177b6bf51dSK Naduvalath, Sumesh status = acpi_install_address_space_handler(opr_dev->adev->handle,
3187b6bf51dSK Naduvalath, Sumesh ECLITE_DATA_OPREGION_ID,
3197b6bf51dSK Naduvalath, Sumesh ecl_opregion_data_handler,
3207b6bf51dSK Naduvalath, Sumesh NULL, opr_dev);
3217b6bf51dSK Naduvalath, Sumesh if (ACPI_FAILURE(status)) {
3227b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev),
3237b6bf51dSK Naduvalath, Sumesh "data space handler install failed\n");
3247b6bf51dSK Naduvalath, Sumesh
3257b6bf51dSK Naduvalath, Sumesh acpi_remove_address_space_handler(opr_dev->adev->handle,
3267b6bf51dSK Naduvalath, Sumesh ECLITE_CMD_OPREGION_ID,
3277b6bf51dSK Naduvalath, Sumesh ecl_opregion_cmd_handler);
3287b6bf51dSK Naduvalath, Sumesh return -ENODEV;
3297b6bf51dSK Naduvalath, Sumesh }
3307b6bf51dSK Naduvalath, Sumesh opr_dev->acpi_init_done = true;
3317b6bf51dSK Naduvalath, Sumesh
3327b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev), "Opregion handlers are installed\n");
3337b6bf51dSK Naduvalath, Sumesh
3347b6bf51dSK Naduvalath, Sumesh return 0;
3357b6bf51dSK Naduvalath, Sumesh }
3367b6bf51dSK Naduvalath, Sumesh
acpi_opregion_deinit(struct ishtp_opregion_dev * opr_dev)3377b6bf51dSK Naduvalath, Sumesh static void acpi_opregion_deinit(struct ishtp_opregion_dev *opr_dev)
3387b6bf51dSK Naduvalath, Sumesh {
3397b6bf51dSK Naduvalath, Sumesh acpi_remove_address_space_handler(opr_dev->adev->handle,
3407b6bf51dSK Naduvalath, Sumesh ECLITE_CMD_OPREGION_ID,
3417b6bf51dSK Naduvalath, Sumesh ecl_opregion_cmd_handler);
3427b6bf51dSK Naduvalath, Sumesh
3437b6bf51dSK Naduvalath, Sumesh acpi_remove_address_space_handler(opr_dev->adev->handle,
3447b6bf51dSK Naduvalath, Sumesh ECLITE_DATA_OPREGION_ID,
3457b6bf51dSK Naduvalath, Sumesh ecl_opregion_data_handler);
3467b6bf51dSK Naduvalath, Sumesh opr_dev->acpi_init_done = false;
3477b6bf51dSK Naduvalath, Sumesh }
3487b6bf51dSK Naduvalath, Sumesh
ecl_acpi_invoke_dsm(struct work_struct * work)3497b6bf51dSK Naduvalath, Sumesh static void ecl_acpi_invoke_dsm(struct work_struct *work)
3507b6bf51dSK Naduvalath, Sumesh {
3517b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev;
3527b6bf51dSK Naduvalath, Sumesh union acpi_object *obj;
3537b6bf51dSK Naduvalath, Sumesh
3547b6bf51dSK Naduvalath, Sumesh opr_dev = container_of(work, struct ishtp_opregion_dev, event_work);
3557b6bf51dSK Naduvalath, Sumesh if (!opr_dev->acpi_init_done)
3567b6bf51dSK Naduvalath, Sumesh return;
3577b6bf51dSK Naduvalath, Sumesh
3587b6bf51dSK Naduvalath, Sumesh obj = acpi_evaluate_dsm(opr_dev->adev->handle, &ecl_acpi_guid, 0,
3597b6bf51dSK Naduvalath, Sumesh opr_dev->dsm_event_id, NULL);
3607b6bf51dSK Naduvalath, Sumesh if (!obj) {
3617b6bf51dSK Naduvalath, Sumesh dev_warn(cl_data_to_dev(opr_dev), "_DSM fn call failed\n");
3627b6bf51dSK Naduvalath, Sumesh return;
3637b6bf51dSK Naduvalath, Sumesh }
3647b6bf51dSK Naduvalath, Sumesh
3657b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev), "Exec DSM function code: %d success\n",
3667b6bf51dSK Naduvalath, Sumesh opr_dev->dsm_event_id);
3677b6bf51dSK Naduvalath, Sumesh
3687b6bf51dSK Naduvalath, Sumesh ACPI_FREE(obj);
3697b6bf51dSK Naduvalath, Sumesh }
3707b6bf51dSK Naduvalath, Sumesh
ecl_ish_process_rx_data(struct ishtp_opregion_dev * opr_dev)3717b6bf51dSK Naduvalath, Sumesh static void ecl_ish_process_rx_data(struct ishtp_opregion_dev *opr_dev)
3727b6bf51dSK Naduvalath, Sumesh {
3737b6bf51dSK Naduvalath, Sumesh struct ecl_message *message =
3747b6bf51dSK Naduvalath, Sumesh (struct ecl_message *)opr_dev->rb->buffer.data;
3757b6bf51dSK Naduvalath, Sumesh
3767b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev),
3777b6bf51dSK Naduvalath, Sumesh "[ish_rd] Resp: off : %x, len : %x\n",
3787b6bf51dSK Naduvalath, Sumesh message->header.offset,
3797b6bf51dSK Naduvalath, Sumesh message->header.data_len);
3807b6bf51dSK Naduvalath, Sumesh
3817b6bf51dSK Naduvalath, Sumesh if ((message->header.offset + message->header.data_len) >
3827b6bf51dSK Naduvalath, Sumesh ECL_DATA_OPR_BUFLEN) {
3837b6bf51dSK Naduvalath, Sumesh return;
3847b6bf51dSK Naduvalath, Sumesh }
3857b6bf51dSK Naduvalath, Sumesh
3867b6bf51dSK Naduvalath, Sumesh memcpy(opr_dev->opr_context.data_area.data + message->header.offset,
3877b6bf51dSK Naduvalath, Sumesh message->payload, message->header.data_len);
3887b6bf51dSK Naduvalath, Sumesh
3897b6bf51dSK Naduvalath, Sumesh opr_dev->ish_read_done = true;
3907b6bf51dSK Naduvalath, Sumesh wake_up_interruptible(&opr_dev->read_wait);
3917b6bf51dSK Naduvalath, Sumesh }
3927b6bf51dSK Naduvalath, Sumesh
ecl_ish_process_rx_event(struct ishtp_opregion_dev * opr_dev)3937b6bf51dSK Naduvalath, Sumesh static void ecl_ish_process_rx_event(struct ishtp_opregion_dev *opr_dev)
3947b6bf51dSK Naduvalath, Sumesh {
3957b6bf51dSK Naduvalath, Sumesh struct ecl_message_header *header =
3967b6bf51dSK Naduvalath, Sumesh (struct ecl_message_header *)opr_dev->rb->buffer.data;
3977b6bf51dSK Naduvalath, Sumesh
3987b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev),
3997b6bf51dSK Naduvalath, Sumesh "[ish_ev] Evt received: %8x\n", header->event);
4007b6bf51dSK Naduvalath, Sumesh
4017b6bf51dSK Naduvalath, Sumesh opr_dev->dsm_event_id = header->event;
4027b6bf51dSK Naduvalath, Sumesh schedule_work(&opr_dev->event_work);
4037b6bf51dSK Naduvalath, Sumesh }
4047b6bf51dSK Naduvalath, Sumesh
ecl_ish_cl_enable_events(struct ishtp_opregion_dev * opr_dev,bool config_enable)4057b6bf51dSK Naduvalath, Sumesh static int ecl_ish_cl_enable_events(struct ishtp_opregion_dev *opr_dev,
4067b6bf51dSK Naduvalath, Sumesh bool config_enable)
4077b6bf51dSK Naduvalath, Sumesh {
4087b6bf51dSK Naduvalath, Sumesh struct ecl_message message;
4097b6bf51dSK Naduvalath, Sumesh int len;
4107b6bf51dSK Naduvalath, Sumesh
4117b6bf51dSK Naduvalath, Sumesh message.header.version = ECL_ISH_HEADER_VERSION;
4127b6bf51dSK Naduvalath, Sumesh message.header.data_type = ECL_MSG_DATA;
4137b6bf51dSK Naduvalath, Sumesh message.header.request_type = ECL_ISH_WRITE;
4147b6bf51dSK Naduvalath, Sumesh message.header.offset = ECL_EVENTS_NOTIFY;
4157b6bf51dSK Naduvalath, Sumesh message.header.data_len = 1;
4167b6bf51dSK Naduvalath, Sumesh message.payload[0] = config_enable;
4177b6bf51dSK Naduvalath, Sumesh
4187b6bf51dSK Naduvalath, Sumesh len = sizeof(struct ecl_message_header) + message.header.data_len;
4197b6bf51dSK Naduvalath, Sumesh
4207b6bf51dSK Naduvalath, Sumesh return ishtp_cl_send(opr_dev->ecl_ishtp_cl, (uint8_t *)&message, len);
4217b6bf51dSK Naduvalath, Sumesh }
4227b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_event_cb(struct ishtp_cl_device * cl_device)4237b6bf51dSK Naduvalath, Sumesh static void ecl_ishtp_cl_event_cb(struct ishtp_cl_device *cl_device)
4247b6bf51dSK Naduvalath, Sumesh {
4257b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device);
4267b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev;
4277b6bf51dSK Naduvalath, Sumesh struct ecl_message_header *header;
4287b6bf51dSK Naduvalath, Sumesh struct ishtp_cl_rb *rb;
4297b6bf51dSK Naduvalath, Sumesh
4307b6bf51dSK Naduvalath, Sumesh opr_dev = ishtp_get_client_data(ecl_ishtp_cl);
4317b6bf51dSK Naduvalath, Sumesh while ((rb = ishtp_cl_rx_get_rb(opr_dev->ecl_ishtp_cl)) != NULL) {
4327b6bf51dSK Naduvalath, Sumesh opr_dev->rb = rb;
4337b6bf51dSK Naduvalath, Sumesh header = (struct ecl_message_header *)rb->buffer.data;
4347b6bf51dSK Naduvalath, Sumesh
4357b6bf51dSK Naduvalath, Sumesh if (header->data_type == ECL_MSG_DATA)
4367b6bf51dSK Naduvalath, Sumesh ecl_ish_process_rx_data(opr_dev);
4377b6bf51dSK Naduvalath, Sumesh else if (header->data_type == ECL_MSG_EVENT)
4387b6bf51dSK Naduvalath, Sumesh ecl_ish_process_rx_event(opr_dev);
4397b6bf51dSK Naduvalath, Sumesh else
4407b6bf51dSK Naduvalath, Sumesh /* Got an event with wrong data_type, ignore it */
4417b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev),
4427b6bf51dSK Naduvalath, Sumesh "[ish_cb] Received wrong data_type\n");
4437b6bf51dSK Naduvalath, Sumesh
4447b6bf51dSK Naduvalath, Sumesh ishtp_cl_io_rb_recycle(rb);
4457b6bf51dSK Naduvalath, Sumesh }
4467b6bf51dSK Naduvalath, Sumesh }
4477b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_init(struct ishtp_cl * ecl_ishtp_cl)4487b6bf51dSK Naduvalath, Sumesh static int ecl_ishtp_cl_init(struct ishtp_cl *ecl_ishtp_cl)
4497b6bf51dSK Naduvalath, Sumesh {
4507b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev =
4517b6bf51dSK Naduvalath, Sumesh ishtp_get_client_data(ecl_ishtp_cl);
4527b6bf51dSK Naduvalath, Sumesh struct ishtp_fw_client *fw_client;
4537b6bf51dSK Naduvalath, Sumesh struct ishtp_device *dev;
4547b6bf51dSK Naduvalath, Sumesh int rv;
4557b6bf51dSK Naduvalath, Sumesh
4567b6bf51dSK Naduvalath, Sumesh rv = ishtp_cl_link(ecl_ishtp_cl);
4577b6bf51dSK Naduvalath, Sumesh if (rv) {
4587b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "ishtp_cl_link failed\n");
4597b6bf51dSK Naduvalath, Sumesh return rv;
4607b6bf51dSK Naduvalath, Sumesh }
4617b6bf51dSK Naduvalath, Sumesh
4627b6bf51dSK Naduvalath, Sumesh dev = ishtp_get_ishtp_device(ecl_ishtp_cl);
4637b6bf51dSK Naduvalath, Sumesh
4647b6bf51dSK Naduvalath, Sumesh /* Connect to FW client */
4657b6bf51dSK Naduvalath, Sumesh ishtp_set_tx_ring_size(ecl_ishtp_cl, ECL_CL_TX_RING_SIZE);
4667b6bf51dSK Naduvalath, Sumesh ishtp_set_rx_ring_size(ecl_ishtp_cl, ECL_CL_RX_RING_SIZE);
4677b6bf51dSK Naduvalath, Sumesh
468*bf9167a8SArnd Bergmann fw_client = ishtp_fw_cl_get_client(dev, &ecl_ishtp_id_table[0].guid);
4697b6bf51dSK Naduvalath, Sumesh if (!fw_client) {
4707b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "fw client not found\n");
4717b6bf51dSK Naduvalath, Sumesh return -ENOENT;
4727b6bf51dSK Naduvalath, Sumesh }
4737b6bf51dSK Naduvalath, Sumesh
4747b6bf51dSK Naduvalath, Sumesh ishtp_cl_set_fw_client_id(ecl_ishtp_cl,
4757b6bf51dSK Naduvalath, Sumesh ishtp_get_fw_client_id(fw_client));
4767b6bf51dSK Naduvalath, Sumesh
4777b6bf51dSK Naduvalath, Sumesh ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_CONNECTING);
4787b6bf51dSK Naduvalath, Sumesh
4797b6bf51dSK Naduvalath, Sumesh rv = ishtp_cl_connect(ecl_ishtp_cl);
4807b6bf51dSK Naduvalath, Sumesh if (rv) {
4817b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "client connect failed\n");
4827b6bf51dSK Naduvalath, Sumesh
4837b6bf51dSK Naduvalath, Sumesh ishtp_cl_unlink(ecl_ishtp_cl);
4847b6bf51dSK Naduvalath, Sumesh return rv;
4857b6bf51dSK Naduvalath, Sumesh }
4867b6bf51dSK Naduvalath, Sumesh
4877b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev), "Host connected to fw client\n");
4887b6bf51dSK Naduvalath, Sumesh
4897b6bf51dSK Naduvalath, Sumesh return 0;
4907b6bf51dSK Naduvalath, Sumesh }
4917b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_deinit(struct ishtp_cl * ecl_ishtp_cl)4927b6bf51dSK Naduvalath, Sumesh static void ecl_ishtp_cl_deinit(struct ishtp_cl *ecl_ishtp_cl)
4937b6bf51dSK Naduvalath, Sumesh {
4947b6bf51dSK Naduvalath, Sumesh ishtp_cl_unlink(ecl_ishtp_cl);
4957b6bf51dSK Naduvalath, Sumesh ishtp_cl_flush_queues(ecl_ishtp_cl);
4967b6bf51dSK Naduvalath, Sumesh ishtp_cl_free(ecl_ishtp_cl);
4977b6bf51dSK Naduvalath, Sumesh }
4987b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_reset_handler(struct work_struct * work)4997b6bf51dSK Naduvalath, Sumesh static void ecl_ishtp_cl_reset_handler(struct work_struct *work)
5007b6bf51dSK Naduvalath, Sumesh {
5017b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev;
5027b6bf51dSK Naduvalath, Sumesh struct ishtp_cl_device *cl_device;
5037b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl;
5047b6bf51dSK Naduvalath, Sumesh int rv;
5057b6bf51dSK Naduvalath, Sumesh int retry;
5067b6bf51dSK Naduvalath, Sumesh
5077b6bf51dSK Naduvalath, Sumesh opr_dev = container_of(work, struct ishtp_opregion_dev, reset_work);
5087b6bf51dSK Naduvalath, Sumesh
5097b6bf51dSK Naduvalath, Sumesh opr_dev->ish_link_ready = false;
5107b6bf51dSK Naduvalath, Sumesh
5117b6bf51dSK Naduvalath, Sumesh cl_device = opr_dev->cl_device;
5127b6bf51dSK Naduvalath, Sumesh ecl_ishtp_cl = opr_dev->ecl_ishtp_cl;
5137b6bf51dSK Naduvalath, Sumesh
5147b6bf51dSK Naduvalath, Sumesh ecl_ishtp_cl_deinit(ecl_ishtp_cl);
5157b6bf51dSK Naduvalath, Sumesh
5167b6bf51dSK Naduvalath, Sumesh ecl_ishtp_cl = ishtp_cl_allocate(cl_device);
5177b6bf51dSK Naduvalath, Sumesh if (!ecl_ishtp_cl)
5187b6bf51dSK Naduvalath, Sumesh return;
5197b6bf51dSK Naduvalath, Sumesh
5207b6bf51dSK Naduvalath, Sumesh ishtp_set_drvdata(cl_device, ecl_ishtp_cl);
5217b6bf51dSK Naduvalath, Sumesh ishtp_set_client_data(ecl_ishtp_cl, opr_dev);
5227b6bf51dSK Naduvalath, Sumesh
5237b6bf51dSK Naduvalath, Sumesh opr_dev->ecl_ishtp_cl = ecl_ishtp_cl;
5247b6bf51dSK Naduvalath, Sumesh
5257b6bf51dSK Naduvalath, Sumesh for (retry = 0; retry < 3; ++retry) {
5267b6bf51dSK Naduvalath, Sumesh rv = ecl_ishtp_cl_init(ecl_ishtp_cl);
5277b6bf51dSK Naduvalath, Sumesh if (!rv)
5287b6bf51dSK Naduvalath, Sumesh break;
5297b6bf51dSK Naduvalath, Sumesh }
5307b6bf51dSK Naduvalath, Sumesh if (rv) {
5317b6bf51dSK Naduvalath, Sumesh ishtp_cl_free(ecl_ishtp_cl);
5327b6bf51dSK Naduvalath, Sumesh opr_dev->ecl_ishtp_cl = NULL;
5337b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev),
5347b6bf51dSK Naduvalath, Sumesh "[ish_rst] Reset failed. Link not ready.\n");
5357b6bf51dSK Naduvalath, Sumesh return;
5367b6bf51dSK Naduvalath, Sumesh }
5377b6bf51dSK Naduvalath, Sumesh
5387b6bf51dSK Naduvalath, Sumesh ishtp_register_event_cb(cl_device, ecl_ishtp_cl_event_cb);
5397b6bf51dSK Naduvalath, Sumesh dev_info(cl_data_to_dev(opr_dev),
5407b6bf51dSK Naduvalath, Sumesh "[ish_rst] Reset Success. Link ready.\n");
5417b6bf51dSK Naduvalath, Sumesh
5427b6bf51dSK Naduvalath, Sumesh opr_dev->ish_link_ready = true;
5437b6bf51dSK Naduvalath, Sumesh
5447b6bf51dSK Naduvalath, Sumesh if (opr_dev->acpi_init_done)
5457b6bf51dSK Naduvalath, Sumesh return;
5467b6bf51dSK Naduvalath, Sumesh
5477b6bf51dSK Naduvalath, Sumesh rv = acpi_opregion_init(opr_dev);
5487b6bf51dSK Naduvalath, Sumesh if (rv) {
5497b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev),
5507b6bf51dSK Naduvalath, Sumesh "ACPI opregion init failed\n");
5517b6bf51dSK Naduvalath, Sumesh }
5527b6bf51dSK Naduvalath, Sumesh }
5537b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_probe(struct ishtp_cl_device * cl_device)5547b6bf51dSK Naduvalath, Sumesh static int ecl_ishtp_cl_probe(struct ishtp_cl_device *cl_device)
5557b6bf51dSK Naduvalath, Sumesh {
5567b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl;
5577b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev;
5587b6bf51dSK Naduvalath, Sumesh int rv;
5597b6bf51dSK Naduvalath, Sumesh
5607b6bf51dSK Naduvalath, Sumesh opr_dev = devm_kzalloc(ishtp_device(cl_device), sizeof(*opr_dev),
5617b6bf51dSK Naduvalath, Sumesh GFP_KERNEL);
5627b6bf51dSK Naduvalath, Sumesh if (!opr_dev)
5637b6bf51dSK Naduvalath, Sumesh return -ENOMEM;
5647b6bf51dSK Naduvalath, Sumesh
5657b6bf51dSK Naduvalath, Sumesh ecl_ishtp_cl = ishtp_cl_allocate(cl_device);
5667b6bf51dSK Naduvalath, Sumesh if (!ecl_ishtp_cl)
5677b6bf51dSK Naduvalath, Sumesh return -ENOMEM;
5687b6bf51dSK Naduvalath, Sumesh
5697b6bf51dSK Naduvalath, Sumesh ishtp_set_drvdata(cl_device, ecl_ishtp_cl);
5707b6bf51dSK Naduvalath, Sumesh ishtp_set_client_data(ecl_ishtp_cl, opr_dev);
5717b6bf51dSK Naduvalath, Sumesh opr_dev->ecl_ishtp_cl = ecl_ishtp_cl;
5727b6bf51dSK Naduvalath, Sumesh opr_dev->cl_device = cl_device;
5737b6bf51dSK Naduvalath, Sumesh
5747b6bf51dSK Naduvalath, Sumesh init_waitqueue_head(&opr_dev->read_wait);
5757b6bf51dSK Naduvalath, Sumesh INIT_WORK(&opr_dev->event_work, ecl_acpi_invoke_dsm);
5767b6bf51dSK Naduvalath, Sumesh INIT_WORK(&opr_dev->reset_work, ecl_ishtp_cl_reset_handler);
5777b6bf51dSK Naduvalath, Sumesh
5787b6bf51dSK Naduvalath, Sumesh /* Initialize ish client device */
5797b6bf51dSK Naduvalath, Sumesh rv = ecl_ishtp_cl_init(ecl_ishtp_cl);
5807b6bf51dSK Naduvalath, Sumesh if (rv) {
5817b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "Client init failed\n");
5827b6bf51dSK Naduvalath, Sumesh goto err_exit;
5837b6bf51dSK Naduvalath, Sumesh }
5847b6bf51dSK Naduvalath, Sumesh
5857b6bf51dSK Naduvalath, Sumesh dev_dbg(cl_data_to_dev(opr_dev), "eclite-ishtp client initialised\n");
5867b6bf51dSK Naduvalath, Sumesh
5877b6bf51dSK Naduvalath, Sumesh opr_dev->ish_link_ready = true;
5887b6bf51dSK Naduvalath, Sumesh mutex_init(&opr_dev->lock);
5897b6bf51dSK Naduvalath, Sumesh
5907b6bf51dSK Naduvalath, Sumesh rv = acpi_find_eclite_device(opr_dev);
5917b6bf51dSK Naduvalath, Sumesh if (rv) {
5927b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "ECLite ACPI ID not found\n");
5937b6bf51dSK Naduvalath, Sumesh goto err_exit;
5947b6bf51dSK Naduvalath, Sumesh }
5957b6bf51dSK Naduvalath, Sumesh
5967b6bf51dSK Naduvalath, Sumesh /* Register a handler for eclite fw events */
5977b6bf51dSK Naduvalath, Sumesh ishtp_register_event_cb(cl_device, ecl_ishtp_cl_event_cb);
5987b6bf51dSK Naduvalath, Sumesh
5997b6bf51dSK Naduvalath, Sumesh /* Now init opregion handlers */
6007b6bf51dSK Naduvalath, Sumesh rv = acpi_opregion_init(opr_dev);
6017b6bf51dSK Naduvalath, Sumesh if (rv) {
6027b6bf51dSK Naduvalath, Sumesh dev_err(cl_data_to_dev(opr_dev), "ACPI opregion init failed\n");
6037b6bf51dSK Naduvalath, Sumesh goto err_exit;
6047b6bf51dSK Naduvalath, Sumesh }
6057b6bf51dSK Naduvalath, Sumesh
6067b6bf51dSK Naduvalath, Sumesh /* Reprobe devices depending on ECLite - battery, fan, etc. */
6077b6bf51dSK Naduvalath, Sumesh acpi_dev_clear_dependencies(opr_dev->adev);
6087b6bf51dSK Naduvalath, Sumesh
6097b6bf51dSK Naduvalath, Sumesh return 0;
6107b6bf51dSK Naduvalath, Sumesh err_exit:
6117b6bf51dSK Naduvalath, Sumesh ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_DISCONNECTING);
6127b6bf51dSK Naduvalath, Sumesh ishtp_cl_disconnect(ecl_ishtp_cl);
6137b6bf51dSK Naduvalath, Sumesh ecl_ishtp_cl_deinit(ecl_ishtp_cl);
6147b6bf51dSK Naduvalath, Sumesh
6157b6bf51dSK Naduvalath, Sumesh return rv;
6167b6bf51dSK Naduvalath, Sumesh }
6177b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_remove(struct ishtp_cl_device * cl_device)6187b6bf51dSK Naduvalath, Sumesh static void ecl_ishtp_cl_remove(struct ishtp_cl_device *cl_device)
6197b6bf51dSK Naduvalath, Sumesh {
6207b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device);
6217b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev =
6227b6bf51dSK Naduvalath, Sumesh ishtp_get_client_data(ecl_ishtp_cl);
6237b6bf51dSK Naduvalath, Sumesh
6247b6bf51dSK Naduvalath, Sumesh if (opr_dev->acpi_init_done)
6257b6bf51dSK Naduvalath, Sumesh acpi_opregion_deinit(opr_dev);
6267b6bf51dSK Naduvalath, Sumesh
6277b6bf51dSK Naduvalath, Sumesh acpi_dev_put(opr_dev->adev);
6287b6bf51dSK Naduvalath, Sumesh
6297b6bf51dSK Naduvalath, Sumesh ishtp_set_connection_state(ecl_ishtp_cl, ISHTP_CL_DISCONNECTING);
6307b6bf51dSK Naduvalath, Sumesh ishtp_cl_disconnect(ecl_ishtp_cl);
6317b6bf51dSK Naduvalath, Sumesh ecl_ishtp_cl_deinit(ecl_ishtp_cl);
6327b6bf51dSK Naduvalath, Sumesh
6337b6bf51dSK Naduvalath, Sumesh cancel_work_sync(&opr_dev->reset_work);
6347b6bf51dSK Naduvalath, Sumesh cancel_work_sync(&opr_dev->event_work);
6357b6bf51dSK Naduvalath, Sumesh }
6367b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_reset(struct ishtp_cl_device * cl_device)6377b6bf51dSK Naduvalath, Sumesh static int ecl_ishtp_cl_reset(struct ishtp_cl_device *cl_device)
6387b6bf51dSK Naduvalath, Sumesh {
6397b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device);
6407b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev =
6417b6bf51dSK Naduvalath, Sumesh ishtp_get_client_data(ecl_ishtp_cl);
6427b6bf51dSK Naduvalath, Sumesh
6437b6bf51dSK Naduvalath, Sumesh schedule_work(&opr_dev->reset_work);
6447b6bf51dSK Naduvalath, Sumesh
6457b6bf51dSK Naduvalath, Sumesh return 0;
6467b6bf51dSK Naduvalath, Sumesh }
6477b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_suspend(struct device * device)6487b6bf51dSK Naduvalath, Sumesh static int ecl_ishtp_cl_suspend(struct device *device)
6497b6bf51dSK Naduvalath, Sumesh {
6507b6bf51dSK Naduvalath, Sumesh struct ishtp_cl_device *cl_device = ishtp_dev_to_cl_device(device);
6517b6bf51dSK Naduvalath, Sumesh struct ishtp_cl *ecl_ishtp_cl = ishtp_get_drvdata(cl_device);
6527b6bf51dSK Naduvalath, Sumesh struct ishtp_opregion_dev *opr_dev =
6537b6bf51dSK Naduvalath, Sumesh ishtp_get_client_data(ecl_ishtp_cl);
6547b6bf51dSK Naduvalath, Sumesh
6557b6bf51dSK Naduvalath, Sumesh if (acpi_target_system_state() == ACPI_STATE_S0)
6567b6bf51dSK Naduvalath, Sumesh return 0;
6577b6bf51dSK Naduvalath, Sumesh
6587b6bf51dSK Naduvalath, Sumesh acpi_opregion_deinit(opr_dev);
6597b6bf51dSK Naduvalath, Sumesh ecl_ish_cl_enable_events(opr_dev, false);
6607b6bf51dSK Naduvalath, Sumesh
6617b6bf51dSK Naduvalath, Sumesh return 0;
6627b6bf51dSK Naduvalath, Sumesh }
6637b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_cl_resume(struct device * device)6647b6bf51dSK Naduvalath, Sumesh static int ecl_ishtp_cl_resume(struct device *device)
6657b6bf51dSK Naduvalath, Sumesh {
6667b6bf51dSK Naduvalath, Sumesh /* A reset is expected to call after an Sx. At this point
6677b6bf51dSK Naduvalath, Sumesh * we are not sure if the link is up or not to restore anything,
6687b6bf51dSK Naduvalath, Sumesh * so do nothing in resume path
6697b6bf51dSK Naduvalath, Sumesh */
6707b6bf51dSK Naduvalath, Sumesh return 0;
6717b6bf51dSK Naduvalath, Sumesh }
6727b6bf51dSK Naduvalath, Sumesh
6737b6bf51dSK Naduvalath, Sumesh static const struct dev_pm_ops ecl_ishtp_pm_ops = {
6747b6bf51dSK Naduvalath, Sumesh .suspend = ecl_ishtp_cl_suspend,
6757b6bf51dSK Naduvalath, Sumesh .resume = ecl_ishtp_cl_resume,
6767b6bf51dSK Naduvalath, Sumesh };
6777b6bf51dSK Naduvalath, Sumesh
6787b6bf51dSK Naduvalath, Sumesh static struct ishtp_cl_driver ecl_ishtp_cl_driver = {
6797b6bf51dSK Naduvalath, Sumesh .name = "ishtp-eclite",
680*bf9167a8SArnd Bergmann .id = ecl_ishtp_id_table,
6817b6bf51dSK Naduvalath, Sumesh .probe = ecl_ishtp_cl_probe,
6827b6bf51dSK Naduvalath, Sumesh .remove = ecl_ishtp_cl_remove,
6837b6bf51dSK Naduvalath, Sumesh .reset = ecl_ishtp_cl_reset,
6847b6bf51dSK Naduvalath, Sumesh .driver.pm = &ecl_ishtp_pm_ops,
6857b6bf51dSK Naduvalath, Sumesh };
6867b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_init(void)6877b6bf51dSK Naduvalath, Sumesh static int __init ecl_ishtp_init(void)
6887b6bf51dSK Naduvalath, Sumesh {
6897b6bf51dSK Naduvalath, Sumesh return ishtp_cl_driver_register(&ecl_ishtp_cl_driver, THIS_MODULE);
6907b6bf51dSK Naduvalath, Sumesh }
6917b6bf51dSK Naduvalath, Sumesh
ecl_ishtp_exit(void)6927b6bf51dSK Naduvalath, Sumesh static void __exit ecl_ishtp_exit(void)
6937b6bf51dSK Naduvalath, Sumesh {
6947b6bf51dSK Naduvalath, Sumesh return ishtp_cl_driver_unregister(&ecl_ishtp_cl_driver);
6957b6bf51dSK Naduvalath, Sumesh }
6967b6bf51dSK Naduvalath, Sumesh
6977b6bf51dSK Naduvalath, Sumesh late_initcall(ecl_ishtp_init);
6987b6bf51dSK Naduvalath, Sumesh module_exit(ecl_ishtp_exit);
6997b6bf51dSK Naduvalath, Sumesh
7007b6bf51dSK Naduvalath, Sumesh MODULE_DESCRIPTION("ISH ISHTP eclite client opregion driver");
7017b6bf51dSK Naduvalath, Sumesh MODULE_AUTHOR("K Naduvalath, Sumesh <sumesh.k.naduvalath@intel.com>");
7027b6bf51dSK Naduvalath, Sumesh
7037b6bf51dSK Naduvalath, Sumesh MODULE_LICENSE("GPL v2");
704