18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// I2C interface for ChromeOS Embedded Controller 38c2ecf20Sopenharmony_ci// 48c2ecf20Sopenharmony_ci// Copyright (C) 2012 Google, Inc 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/acpi.h> 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/i2c.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_data/cros_ec_commands.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_data/cros_ec_proto.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "cros_ec.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * Request format for protocol v3 218c2ecf20Sopenharmony_ci * byte 0 0xda (EC_COMMAND_PROTOCOL_3) 228c2ecf20Sopenharmony_ci * byte 1-8 struct ec_host_request 238c2ecf20Sopenharmony_ci * byte 10- response data 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cistruct ec_host_request_i2c { 268c2ecf20Sopenharmony_ci /* Always 0xda to backward compatible with v2 struct */ 278c2ecf20Sopenharmony_ci uint8_t command_protocol; 288c2ecf20Sopenharmony_ci struct ec_host_request ec_request; 298c2ecf20Sopenharmony_ci} __packed; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * Response format for protocol v3 348c2ecf20Sopenharmony_ci * byte 0 result code 358c2ecf20Sopenharmony_ci * byte 1 packet_length 368c2ecf20Sopenharmony_ci * byte 2-9 struct ec_host_response 378c2ecf20Sopenharmony_ci * byte 10- response data 388c2ecf20Sopenharmony_ci */ 398c2ecf20Sopenharmony_cistruct ec_host_response_i2c { 408c2ecf20Sopenharmony_ci uint8_t result; 418c2ecf20Sopenharmony_ci uint8_t packet_length; 428c2ecf20Sopenharmony_ci struct ec_host_response ec_response; 438c2ecf20Sopenharmony_ci} __packed; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic inline struct cros_ec_device *to_ec_dev(struct device *dev) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci return i2c_get_clientdata(client); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int cros_ec_pkt_xfer_i2c(struct cros_ec_device *ec_dev, 538c2ecf20Sopenharmony_ci struct cros_ec_command *msg) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct i2c_client *client = ec_dev->priv; 568c2ecf20Sopenharmony_ci int ret = -ENOMEM; 578c2ecf20Sopenharmony_ci int i; 588c2ecf20Sopenharmony_ci int packet_len; 598c2ecf20Sopenharmony_ci u8 *out_buf = NULL; 608c2ecf20Sopenharmony_ci u8 *in_buf = NULL; 618c2ecf20Sopenharmony_ci u8 sum; 628c2ecf20Sopenharmony_ci struct i2c_msg i2c_msg[2]; 638c2ecf20Sopenharmony_ci struct ec_host_response *ec_response; 648c2ecf20Sopenharmony_ci struct ec_host_request_i2c *ec_request_i2c; 658c2ecf20Sopenharmony_ci struct ec_host_response_i2c *ec_response_i2c; 668c2ecf20Sopenharmony_ci int request_header_size = sizeof(struct ec_host_request_i2c); 678c2ecf20Sopenharmony_ci int response_header_size = sizeof(struct ec_host_response_i2c); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci i2c_msg[0].addr = client->addr; 708c2ecf20Sopenharmony_ci i2c_msg[0].flags = 0; 718c2ecf20Sopenharmony_ci i2c_msg[1].addr = client->addr; 728c2ecf20Sopenharmony_ci i2c_msg[1].flags = I2C_M_RD; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci packet_len = msg->insize + response_header_size; 758c2ecf20Sopenharmony_ci BUG_ON(packet_len > ec_dev->din_size); 768c2ecf20Sopenharmony_ci in_buf = ec_dev->din; 778c2ecf20Sopenharmony_ci i2c_msg[1].len = packet_len; 788c2ecf20Sopenharmony_ci i2c_msg[1].buf = (char *) in_buf; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci packet_len = msg->outsize + request_header_size; 818c2ecf20Sopenharmony_ci BUG_ON(packet_len > ec_dev->dout_size); 828c2ecf20Sopenharmony_ci out_buf = ec_dev->dout; 838c2ecf20Sopenharmony_ci i2c_msg[0].len = packet_len; 848c2ecf20Sopenharmony_ci i2c_msg[0].buf = (char *) out_buf; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci /* create request data */ 878c2ecf20Sopenharmony_ci ec_request_i2c = (struct ec_host_request_i2c *) out_buf; 888c2ecf20Sopenharmony_ci ec_request_i2c->command_protocol = EC_COMMAND_PROTOCOL_3; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci ec_dev->dout++; 918c2ecf20Sopenharmony_ci ret = cros_ec_prepare_tx(ec_dev, msg); 928c2ecf20Sopenharmony_ci ec_dev->dout--; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci /* send command to EC and read answer */ 958c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, i2c_msg, 2); 968c2ecf20Sopenharmony_ci if (ret < 0) { 978c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "i2c transfer failed: %d\n", ret); 988c2ecf20Sopenharmony_ci goto done; 998c2ecf20Sopenharmony_ci } else if (ret != 2) { 1008c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "failed to get response: %d\n", ret); 1018c2ecf20Sopenharmony_ci ret = -EIO; 1028c2ecf20Sopenharmony_ci goto done; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci ec_response_i2c = (struct ec_host_response_i2c *) in_buf; 1068c2ecf20Sopenharmony_ci msg->result = ec_response_i2c->result; 1078c2ecf20Sopenharmony_ci ec_response = &ec_response_i2c->ec_response; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci switch (msg->result) { 1108c2ecf20Sopenharmony_ci case EC_RES_SUCCESS: 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case EC_RES_IN_PROGRESS: 1138c2ecf20Sopenharmony_ci ret = -EAGAIN; 1148c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "command 0x%02x in progress\n", 1158c2ecf20Sopenharmony_ci msg->command); 1168c2ecf20Sopenharmony_ci goto done; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci default: 1198c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "command 0x%02x returned %d\n", 1208c2ecf20Sopenharmony_ci msg->command, msg->result); 1218c2ecf20Sopenharmony_ci /* 1228c2ecf20Sopenharmony_ci * When we send v3 request to v2 ec, ec won't recognize the 1238c2ecf20Sopenharmony_ci * 0xda (EC_COMMAND_PROTOCOL_3) and will return with status 1248c2ecf20Sopenharmony_ci * EC_RES_INVALID_COMMAND with zero data length. 1258c2ecf20Sopenharmony_ci * 1268c2ecf20Sopenharmony_ci * In case of invalid command for v3 protocol the data length 1278c2ecf20Sopenharmony_ci * will be at least sizeof(struct ec_host_response) 1288c2ecf20Sopenharmony_ci */ 1298c2ecf20Sopenharmony_ci if (ec_response_i2c->result == EC_RES_INVALID_COMMAND && 1308c2ecf20Sopenharmony_ci ec_response_i2c->packet_length == 0) { 1318c2ecf20Sopenharmony_ci ret = -EPROTONOSUPPORT; 1328c2ecf20Sopenharmony_ci goto done; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (ec_response_i2c->packet_length < sizeof(struct ec_host_response)) { 1378c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, 1388c2ecf20Sopenharmony_ci "response of %u bytes too short; not a full header\n", 1398c2ecf20Sopenharmony_ci ec_response_i2c->packet_length); 1408c2ecf20Sopenharmony_ci ret = -EBADMSG; 1418c2ecf20Sopenharmony_ci goto done; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci if (msg->insize < ec_response->data_len) { 1458c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, 1468c2ecf20Sopenharmony_ci "response data size is too large: expected %u, got %u\n", 1478c2ecf20Sopenharmony_ci msg->insize, 1488c2ecf20Sopenharmony_ci ec_response->data_len); 1498c2ecf20Sopenharmony_ci ret = -EMSGSIZE; 1508c2ecf20Sopenharmony_ci goto done; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* copy response packet payload and compute checksum */ 1548c2ecf20Sopenharmony_ci sum = 0; 1558c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(struct ec_host_response); i++) 1568c2ecf20Sopenharmony_ci sum += ((u8 *)ec_response)[i]; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci memcpy(msg->data, 1598c2ecf20Sopenharmony_ci in_buf + response_header_size, 1608c2ecf20Sopenharmony_ci ec_response->data_len); 1618c2ecf20Sopenharmony_ci for (i = 0; i < ec_response->data_len; i++) 1628c2ecf20Sopenharmony_ci sum += msg->data[i]; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* All bytes should sum to zero */ 1658c2ecf20Sopenharmony_ci if (sum) { 1668c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "bad packet checksum\n"); 1678c2ecf20Sopenharmony_ci ret = -EBADMSG; 1688c2ecf20Sopenharmony_ci goto done; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci ret = ec_response->data_len; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cidone: 1748c2ecf20Sopenharmony_ci if (msg->command == EC_CMD_REBOOT_EC) 1758c2ecf20Sopenharmony_ci msleep(EC_REBOOT_DELAY_MS); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return ret; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int cros_ec_cmd_xfer_i2c(struct cros_ec_device *ec_dev, 1818c2ecf20Sopenharmony_ci struct cros_ec_command *msg) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct i2c_client *client = ec_dev->priv; 1848c2ecf20Sopenharmony_ci int ret = -ENOMEM; 1858c2ecf20Sopenharmony_ci int i; 1868c2ecf20Sopenharmony_ci int len; 1878c2ecf20Sopenharmony_ci int packet_len; 1888c2ecf20Sopenharmony_ci u8 *out_buf = NULL; 1898c2ecf20Sopenharmony_ci u8 *in_buf = NULL; 1908c2ecf20Sopenharmony_ci u8 sum; 1918c2ecf20Sopenharmony_ci struct i2c_msg i2c_msg[2]; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci i2c_msg[0].addr = client->addr; 1948c2ecf20Sopenharmony_ci i2c_msg[0].flags = 0; 1958c2ecf20Sopenharmony_ci i2c_msg[1].addr = client->addr; 1968c2ecf20Sopenharmony_ci i2c_msg[1].flags = I2C_M_RD; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci /* 1998c2ecf20Sopenharmony_ci * allocate larger packet (one byte for checksum, one byte for 2008c2ecf20Sopenharmony_ci * length, and one for result code) 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci packet_len = msg->insize + 3; 2038c2ecf20Sopenharmony_ci in_buf = kzalloc(packet_len, GFP_KERNEL); 2048c2ecf20Sopenharmony_ci if (!in_buf) 2058c2ecf20Sopenharmony_ci goto done; 2068c2ecf20Sopenharmony_ci i2c_msg[1].len = packet_len; 2078c2ecf20Sopenharmony_ci i2c_msg[1].buf = (char *)in_buf; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* 2108c2ecf20Sopenharmony_ci * allocate larger packet (one byte for checksum, one for 2118c2ecf20Sopenharmony_ci * command code, one for length, and one for command version) 2128c2ecf20Sopenharmony_ci */ 2138c2ecf20Sopenharmony_ci packet_len = msg->outsize + 4; 2148c2ecf20Sopenharmony_ci out_buf = kzalloc(packet_len, GFP_KERNEL); 2158c2ecf20Sopenharmony_ci if (!out_buf) 2168c2ecf20Sopenharmony_ci goto done; 2178c2ecf20Sopenharmony_ci i2c_msg[0].len = packet_len; 2188c2ecf20Sopenharmony_ci i2c_msg[0].buf = (char *)out_buf; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci out_buf[0] = EC_CMD_VERSION0 + msg->version; 2218c2ecf20Sopenharmony_ci out_buf[1] = msg->command; 2228c2ecf20Sopenharmony_ci out_buf[2] = msg->outsize; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci /* copy message payload and compute checksum */ 2258c2ecf20Sopenharmony_ci sum = out_buf[0] + out_buf[1] + out_buf[2]; 2268c2ecf20Sopenharmony_ci for (i = 0; i < msg->outsize; i++) { 2278c2ecf20Sopenharmony_ci out_buf[3 + i] = msg->data[i]; 2288c2ecf20Sopenharmony_ci sum += out_buf[3 + i]; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci out_buf[3 + msg->outsize] = sum; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci /* send command to EC and read answer */ 2338c2ecf20Sopenharmony_ci ret = i2c_transfer(client->adapter, i2c_msg, 2); 2348c2ecf20Sopenharmony_ci if (ret < 0) { 2358c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "i2c transfer failed: %d\n", ret); 2368c2ecf20Sopenharmony_ci goto done; 2378c2ecf20Sopenharmony_ci } else if (ret != 2) { 2388c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "failed to get response: %d\n", ret); 2398c2ecf20Sopenharmony_ci ret = -EIO; 2408c2ecf20Sopenharmony_ci goto done; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* check response error code */ 2448c2ecf20Sopenharmony_ci msg->result = i2c_msg[1].buf[0]; 2458c2ecf20Sopenharmony_ci ret = cros_ec_check_result(ec_dev, msg); 2468c2ecf20Sopenharmony_ci if (ret) 2478c2ecf20Sopenharmony_ci goto done; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci len = in_buf[1]; 2508c2ecf20Sopenharmony_ci if (len > msg->insize) { 2518c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "packet too long (%d bytes, expected %d)", 2528c2ecf20Sopenharmony_ci len, msg->insize); 2538c2ecf20Sopenharmony_ci ret = -ENOSPC; 2548c2ecf20Sopenharmony_ci goto done; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* copy response packet payload and compute checksum */ 2588c2ecf20Sopenharmony_ci sum = in_buf[0] + in_buf[1]; 2598c2ecf20Sopenharmony_ci for (i = 0; i < len; i++) { 2608c2ecf20Sopenharmony_ci msg->data[i] = in_buf[2 + i]; 2618c2ecf20Sopenharmony_ci sum += in_buf[2 + i]; 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci dev_dbg(ec_dev->dev, "packet: %*ph, sum = %02x\n", 2648c2ecf20Sopenharmony_ci i2c_msg[1].len, in_buf, sum); 2658c2ecf20Sopenharmony_ci if (sum != in_buf[2 + len]) { 2668c2ecf20Sopenharmony_ci dev_err(ec_dev->dev, "bad packet checksum\n"); 2678c2ecf20Sopenharmony_ci ret = -EBADMSG; 2688c2ecf20Sopenharmony_ci goto done; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ret = len; 2728c2ecf20Sopenharmony_cidone: 2738c2ecf20Sopenharmony_ci kfree(in_buf); 2748c2ecf20Sopenharmony_ci kfree(out_buf); 2758c2ecf20Sopenharmony_ci if (msg->command == EC_CMD_REBOOT_EC) 2768c2ecf20Sopenharmony_ci msleep(EC_REBOOT_DELAY_MS); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistatic int cros_ec_i2c_probe(struct i2c_client *client, 2828c2ecf20Sopenharmony_ci const struct i2c_device_id *dev_id) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 2858c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = NULL; 2868c2ecf20Sopenharmony_ci int err; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL); 2898c2ecf20Sopenharmony_ci if (!ec_dev) 2908c2ecf20Sopenharmony_ci return -ENOMEM; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci i2c_set_clientdata(client, ec_dev); 2938c2ecf20Sopenharmony_ci ec_dev->dev = dev; 2948c2ecf20Sopenharmony_ci ec_dev->priv = client; 2958c2ecf20Sopenharmony_ci ec_dev->irq = client->irq; 2968c2ecf20Sopenharmony_ci ec_dev->cmd_xfer = cros_ec_cmd_xfer_i2c; 2978c2ecf20Sopenharmony_ci ec_dev->pkt_xfer = cros_ec_pkt_xfer_i2c; 2988c2ecf20Sopenharmony_ci ec_dev->phys_name = client->adapter->name; 2998c2ecf20Sopenharmony_ci ec_dev->din_size = sizeof(struct ec_host_response_i2c) + 3008c2ecf20Sopenharmony_ci sizeof(struct ec_response_get_protocol_info); 3018c2ecf20Sopenharmony_ci ec_dev->dout_size = sizeof(struct ec_host_request_i2c); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci err = cros_ec_register(ec_dev); 3048c2ecf20Sopenharmony_ci if (err) { 3058c2ecf20Sopenharmony_ci dev_err(dev, "cannot register EC\n"); 3068c2ecf20Sopenharmony_ci return err; 3078c2ecf20Sopenharmony_ci } 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return 0; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic int cros_ec_i2c_remove(struct i2c_client *client) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = i2c_get_clientdata(client); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return cros_ec_unregister(ec_dev); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3208c2ecf20Sopenharmony_cistatic int cros_ec_i2c_suspend(struct device *dev) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = to_ec_dev(dev); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return cros_ec_suspend(ec_dev); 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int cros_ec_i2c_resume(struct device *dev) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct cros_ec_device *ec_dev = to_ec_dev(dev); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return cros_ec_resume(ec_dev); 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci#endif 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cros_ec_i2c_pm_ops = { 3368c2ecf20Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(cros_ec_i2c_suspend, cros_ec_i2c_resume) 3378c2ecf20Sopenharmony_ci}; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 3408c2ecf20Sopenharmony_cistatic const struct of_device_id cros_ec_i2c_of_match[] = { 3418c2ecf20Sopenharmony_ci { .compatible = "google,cros-ec-i2c", }, 3428c2ecf20Sopenharmony_ci { /* sentinel */ }, 3438c2ecf20Sopenharmony_ci}; 3448c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match); 3458c2ecf20Sopenharmony_ci#endif 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const struct i2c_device_id cros_ec_i2c_id[] = { 3488c2ecf20Sopenharmony_ci { "cros-ec-i2c", 0 }, 3498c2ecf20Sopenharmony_ci { } 3508c2ecf20Sopenharmony_ci}; 3518c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, cros_ec_i2c_id); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI 3548c2ecf20Sopenharmony_cistatic const struct acpi_device_id cros_ec_i2c_acpi_id[] = { 3558c2ecf20Sopenharmony_ci { "GOOG0008", 0 }, 3568c2ecf20Sopenharmony_ci { /* sentinel */ } 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, cros_ec_i2c_acpi_id); 3598c2ecf20Sopenharmony_ci#endif 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic struct i2c_driver cros_ec_driver = { 3628c2ecf20Sopenharmony_ci .driver = { 3638c2ecf20Sopenharmony_ci .name = "cros-ec-i2c", 3648c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(cros_ec_i2c_acpi_id), 3658c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(cros_ec_i2c_of_match), 3668c2ecf20Sopenharmony_ci .pm = &cros_ec_i2c_pm_ops, 3678c2ecf20Sopenharmony_ci }, 3688c2ecf20Sopenharmony_ci .probe = cros_ec_i2c_probe, 3698c2ecf20Sopenharmony_ci .remove = cros_ec_i2c_remove, 3708c2ecf20Sopenharmony_ci .id_table = cros_ec_i2c_id, 3718c2ecf20Sopenharmony_ci}; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cimodule_i2c_driver(cros_ec_driver); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3768c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("I2C interface for ChromeOS Embedded Controller"); 377