102d26b9aSEnric Balletbo i Serra // SPDX-License-Identifier: GPL-2.0+
202d26b9aSEnric Balletbo i Serra // Expose an I2C passthrough to the ChromeOS EC.
302d26b9aSEnric Balletbo i Serra //
402d26b9aSEnric Balletbo i Serra // Copyright (C) 2013 Google, Inc.
59d230c9eSDoug Anderson
69af1563aSAkshu Agrawal #include <linux/acpi.h>
79d230c9eSDoug Anderson #include <linux/module.h>
89d230c9eSDoug Anderson #include <linux/i2c.h>
9840d9f13SEnric Balletbo i Serra #include <linux/platform_data/cros_ec_commands.h>
10840d9f13SEnric Balletbo i Serra #include <linux/platform_data/cros_ec_proto.h>
119d230c9eSDoug Anderson #include <linux/platform_device.h>
129d230c9eSDoug Anderson #include <linux/slab.h>
139d230c9eSDoug Anderson
1497720706SDerek Basehore #define I2C_MAX_RETRIES 3
1597720706SDerek Basehore
169d230c9eSDoug Anderson /**
179d230c9eSDoug Anderson * struct ec_i2c_device - Driver data for I2C tunnel
189d230c9eSDoug Anderson *
199d230c9eSDoug Anderson * @dev: Device node
209d230c9eSDoug Anderson * @adap: I2C adapter
219d230c9eSDoug Anderson * @ec: Pointer to EC device
229d230c9eSDoug Anderson * @remote_bus: The EC bus number we tunnel to on the other side.
239d230c9eSDoug Anderson * @request_buf: Buffer for transmitting data; we expect most transfers to fit.
249d230c9eSDoug Anderson * @response_buf: Buffer for receiving data; we expect most transfers to fit.
259d230c9eSDoug Anderson */
269d230c9eSDoug Anderson
279d230c9eSDoug Anderson struct ec_i2c_device {
289d230c9eSDoug Anderson struct device *dev;
299d230c9eSDoug Anderson struct i2c_adapter adap;
309d230c9eSDoug Anderson struct cros_ec_device *ec;
319d230c9eSDoug Anderson
329d230c9eSDoug Anderson u16 remote_bus;
339d230c9eSDoug Anderson
349d230c9eSDoug Anderson u8 request_buf[256];
359d230c9eSDoug Anderson u8 response_buf[256];
369d230c9eSDoug Anderson };
379d230c9eSDoug Anderson
389d230c9eSDoug Anderson /**
399d230c9eSDoug Anderson * ec_i2c_count_message - Count bytes needed for ec_i2c_construct_message
409d230c9eSDoug Anderson *
419d230c9eSDoug Anderson * @i2c_msgs: The i2c messages to read
429d230c9eSDoug Anderson * @num: The number of i2c messages.
439d230c9eSDoug Anderson *
449d230c9eSDoug Anderson * Returns the number of bytes the messages will take up.
459d230c9eSDoug Anderson */
ec_i2c_count_message(const struct i2c_msg i2c_msgs[],int num)469d230c9eSDoug Anderson static int ec_i2c_count_message(const struct i2c_msg i2c_msgs[], int num)
479d230c9eSDoug Anderson {
489d230c9eSDoug Anderson int i;
499d230c9eSDoug Anderson int size;
509d230c9eSDoug Anderson
519d230c9eSDoug Anderson size = sizeof(struct ec_params_i2c_passthru);
529d230c9eSDoug Anderson size += num * sizeof(struct ec_params_i2c_passthru_msg);
539d230c9eSDoug Anderson for (i = 0; i < num; i++)
549d230c9eSDoug Anderson if (!(i2c_msgs[i].flags & I2C_M_RD))
559d230c9eSDoug Anderson size += i2c_msgs[i].len;
569d230c9eSDoug Anderson
579d230c9eSDoug Anderson return size;
589d230c9eSDoug Anderson }
599d230c9eSDoug Anderson
609d230c9eSDoug Anderson /**
619d230c9eSDoug Anderson * ec_i2c_construct_message - construct a message to go to the EC
629d230c9eSDoug Anderson *
639d230c9eSDoug Anderson * This function effectively stuffs the standard i2c_msg format of Linux into
649d230c9eSDoug Anderson * a format that the EC understands.
659d230c9eSDoug Anderson *
669d230c9eSDoug Anderson * @buf: The buffer to fill. We assume that the buffer is big enough.
679d230c9eSDoug Anderson * @i2c_msgs: The i2c messages to read.
689d230c9eSDoug Anderson * @num: The number of i2c messages.
699d230c9eSDoug Anderson * @bus_num: The remote bus number we want to talk to.
709d230c9eSDoug Anderson *
719d230c9eSDoug Anderson * Returns 0 or a negative error number.
729d230c9eSDoug Anderson */
ec_i2c_construct_message(u8 * buf,const struct i2c_msg i2c_msgs[],int num,u16 bus_num)739d230c9eSDoug Anderson static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[],
749d230c9eSDoug Anderson int num, u16 bus_num)
759d230c9eSDoug Anderson {
769d230c9eSDoug Anderson struct ec_params_i2c_passthru *params;
779d230c9eSDoug Anderson u8 *out_data;
789d230c9eSDoug Anderson int i;
799d230c9eSDoug Anderson
809d230c9eSDoug Anderson out_data = buf + sizeof(struct ec_params_i2c_passthru) +
819d230c9eSDoug Anderson num * sizeof(struct ec_params_i2c_passthru_msg);
829d230c9eSDoug Anderson
839d230c9eSDoug Anderson params = (struct ec_params_i2c_passthru *)buf;
849d230c9eSDoug Anderson params->port = bus_num;
859d230c9eSDoug Anderson params->num_msgs = num;
869d230c9eSDoug Anderson for (i = 0; i < num; i++) {
879d230c9eSDoug Anderson const struct i2c_msg *i2c_msg = &i2c_msgs[i];
889d230c9eSDoug Anderson struct ec_params_i2c_passthru_msg *msg = ¶ms->msg[i];
899d230c9eSDoug Anderson
909d230c9eSDoug Anderson msg->len = i2c_msg->len;
919d230c9eSDoug Anderson msg->addr_flags = i2c_msg->addr;
929d230c9eSDoug Anderson
939d230c9eSDoug Anderson if (i2c_msg->flags & I2C_M_TEN)
94d8e0a86fSDoug Anderson return -EINVAL;
959d230c9eSDoug Anderson
969d230c9eSDoug Anderson if (i2c_msg->flags & I2C_M_RD) {
979d230c9eSDoug Anderson msg->addr_flags |= EC_I2C_FLAG_READ;
989d230c9eSDoug Anderson } else {
999d230c9eSDoug Anderson memcpy(out_data, i2c_msg->buf, msg->len);
1009d230c9eSDoug Anderson out_data += msg->len;
1019d230c9eSDoug Anderson }
1029d230c9eSDoug Anderson }
1039d230c9eSDoug Anderson
1049d230c9eSDoug Anderson return 0;
1059d230c9eSDoug Anderson }
1069d230c9eSDoug Anderson
1079d230c9eSDoug Anderson /**
1089d230c9eSDoug Anderson * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response
1099d230c9eSDoug Anderson *
1108b6d8d00SXiang wangx * @i2c_msgs: The i2c messages to fill up.
1119d230c9eSDoug Anderson * @num: The number of i2c messages expected.
1129d230c9eSDoug Anderson *
1139d230c9eSDoug Anderson * Returns the number of response bytes expeced.
1149d230c9eSDoug Anderson */
ec_i2c_count_response(struct i2c_msg i2c_msgs[],int num)1159d230c9eSDoug Anderson static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num)
1169d230c9eSDoug Anderson {
1179d230c9eSDoug Anderson int size;
1189d230c9eSDoug Anderson int i;
1199d230c9eSDoug Anderson
1209d230c9eSDoug Anderson size = sizeof(struct ec_response_i2c_passthru);
1219d230c9eSDoug Anderson for (i = 0; i < num; i++)
1229d230c9eSDoug Anderson if (i2c_msgs[i].flags & I2C_M_RD)
1239d230c9eSDoug Anderson size += i2c_msgs[i].len;
1249d230c9eSDoug Anderson
1259d230c9eSDoug Anderson return size;
1269d230c9eSDoug Anderson }
1279d230c9eSDoug Anderson
1289d230c9eSDoug Anderson /**
1299d230c9eSDoug Anderson * ec_i2c_parse_response - Parse a response from the EC
1309d230c9eSDoug Anderson *
1319d230c9eSDoug Anderson * We'll take the EC's response and copy it back into msgs.
1329d230c9eSDoug Anderson *
1339d230c9eSDoug Anderson * @buf: The buffer to parse.
1348b6d8d00SXiang wangx * @i2c_msgs: The i2c messages to fill up.
1359d230c9eSDoug Anderson * @num: The number of i2c messages; will be modified to include the actual
1369d230c9eSDoug Anderson * number received.
1379d230c9eSDoug Anderson *
1389d230c9eSDoug Anderson * Returns 0 or a negative error number.
1399d230c9eSDoug Anderson */
ec_i2c_parse_response(const u8 * buf,struct i2c_msg i2c_msgs[],int * num)1409d230c9eSDoug Anderson static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[],
1419d230c9eSDoug Anderson int *num)
1429d230c9eSDoug Anderson {
1439d230c9eSDoug Anderson const struct ec_response_i2c_passthru *resp;
1449d230c9eSDoug Anderson const u8 *in_data;
1459d230c9eSDoug Anderson int i;
1469d230c9eSDoug Anderson
1479d230c9eSDoug Anderson in_data = buf + sizeof(struct ec_response_i2c_passthru);
1489d230c9eSDoug Anderson
1499d230c9eSDoug Anderson resp = (const struct ec_response_i2c_passthru *)buf;
1509d230c9eSDoug Anderson if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT)
1519d230c9eSDoug Anderson return -ETIMEDOUT;
15222ae1124SGuenter Roeck else if (resp->i2c_status & EC_I2C_STATUS_NAK)
15322ae1124SGuenter Roeck return -ENXIO;
1549d230c9eSDoug Anderson else if (resp->i2c_status & EC_I2C_STATUS_ERROR)
15522ae1124SGuenter Roeck return -EIO;
1569d230c9eSDoug Anderson
1579d230c9eSDoug Anderson /* Other side could send us back fewer messages, but not more */
1589d230c9eSDoug Anderson if (resp->num_msgs > *num)
1599d230c9eSDoug Anderson return -EPROTO;
1609d230c9eSDoug Anderson *num = resp->num_msgs;
1619d230c9eSDoug Anderson
1629d230c9eSDoug Anderson for (i = 0; i < *num; i++) {
1639d230c9eSDoug Anderson struct i2c_msg *i2c_msg = &i2c_msgs[i];
1649d230c9eSDoug Anderson
1659d230c9eSDoug Anderson if (i2c_msgs[i].flags & I2C_M_RD) {
1669d230c9eSDoug Anderson memcpy(i2c_msg->buf, in_data, i2c_msg->len);
1679d230c9eSDoug Anderson in_data += i2c_msg->len;
1689d230c9eSDoug Anderson }
1699d230c9eSDoug Anderson }
1709d230c9eSDoug Anderson
1719d230c9eSDoug Anderson return 0;
1729d230c9eSDoug Anderson }
1739d230c9eSDoug Anderson
ec_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg i2c_msgs[],int num)1749d230c9eSDoug Anderson static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
1759d230c9eSDoug Anderson int num)
1769d230c9eSDoug Anderson {
1779d230c9eSDoug Anderson struct ec_i2c_device *bus = adap->algo_data;
1789d230c9eSDoug Anderson struct device *dev = bus->dev;
1799d230c9eSDoug Anderson const u16 bus_num = bus->remote_bus;
1809d230c9eSDoug Anderson int request_len;
1819d230c9eSDoug Anderson int response_len;
182a8411784SJavier Martinez Canillas int alloc_size;
1839d230c9eSDoug Anderson int result;
184a8411784SJavier Martinez Canillas struct cros_ec_command *msg;
1859d230c9eSDoug Anderson
1869d230c9eSDoug Anderson request_len = ec_i2c_count_message(i2c_msgs, num);
1879d230c9eSDoug Anderson if (request_len < 0) {
1889d230c9eSDoug Anderson dev_warn(dev, "Error constructing message %d\n", request_len);
1891b84f2a4SJavier Martinez Canillas return request_len;
1909d230c9eSDoug Anderson }
1911b84f2a4SJavier Martinez Canillas
1929d230c9eSDoug Anderson response_len = ec_i2c_count_response(i2c_msgs, num);
1939d230c9eSDoug Anderson if (response_len < 0) {
1949d230c9eSDoug Anderson /* Unexpected; no errors should come when NULL response */
1959d230c9eSDoug Anderson dev_warn(dev, "Error preparing response %d\n", response_len);
1961b84f2a4SJavier Martinez Canillas return response_len;
1979d230c9eSDoug Anderson }
1989d230c9eSDoug Anderson
199a8411784SJavier Martinez Canillas alloc_size = max(request_len, response_len);
200a8411784SJavier Martinez Canillas msg = kmalloc(sizeof(*msg) + alloc_size, GFP_KERNEL);
201a8411784SJavier Martinez Canillas if (!msg)
202a8411784SJavier Martinez Canillas return -ENOMEM;
2035799f95aSBill Richardson
204a8411784SJavier Martinez Canillas result = ec_i2c_construct_message(msg->data, i2c_msgs, num, bus_num);
205a8411784SJavier Martinez Canillas if (result) {
206a8411784SJavier Martinez Canillas dev_err(dev, "Error constructing EC i2c message %d\n", result);
207a8411784SJavier Martinez Canillas goto exit;
208a8411784SJavier Martinez Canillas }
2095799f95aSBill Richardson
210a8411784SJavier Martinez Canillas msg->version = 0;
211a8411784SJavier Martinez Canillas msg->command = EC_CMD_I2C_PASSTHRU;
212a8411784SJavier Martinez Canillas msg->outsize = request_len;
213a8411784SJavier Martinez Canillas msg->insize = response_len;
2149d230c9eSDoug Anderson
2154d01d880SBrian Norris result = cros_ec_cmd_xfer_status(bus->ec, msg);
216a8411784SJavier Martinez Canillas if (result < 0) {
217a8411784SJavier Martinez Canillas dev_err(dev, "Error transferring EC i2c message %d\n", result);
218a8411784SJavier Martinez Canillas goto exit;
219a8411784SJavier Martinez Canillas }
220a8411784SJavier Martinez Canillas
221a8411784SJavier Martinez Canillas result = ec_i2c_parse_response(msg->data, i2c_msgs, &num);
22222ae1124SGuenter Roeck if (result < 0)
223a8411784SJavier Martinez Canillas goto exit;
2249d230c9eSDoug Anderson
2259d230c9eSDoug Anderson /* Indicate success by saying how many messages were sent */
226a8411784SJavier Martinez Canillas result = num;
227a8411784SJavier Martinez Canillas exit:
228a8411784SJavier Martinez Canillas kfree(msg);
229a8411784SJavier Martinez Canillas return result;
2309d230c9eSDoug Anderson }
2319d230c9eSDoug Anderson
ec_i2c_functionality(struct i2c_adapter * adap)2329d230c9eSDoug Anderson static u32 ec_i2c_functionality(struct i2c_adapter *adap)
2339d230c9eSDoug Anderson {
2349d230c9eSDoug Anderson return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
2359d230c9eSDoug Anderson }
2369d230c9eSDoug Anderson
2379d230c9eSDoug Anderson static const struct i2c_algorithm ec_i2c_algorithm = {
2389d230c9eSDoug Anderson .master_xfer = ec_i2c_xfer,
2399d230c9eSDoug Anderson .functionality = ec_i2c_functionality,
2409d230c9eSDoug Anderson };
2419d230c9eSDoug Anderson
ec_i2c_probe(struct platform_device * pdev)2429d230c9eSDoug Anderson static int ec_i2c_probe(struct platform_device *pdev)
2439d230c9eSDoug Anderson {
2449d230c9eSDoug Anderson struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
2459d230c9eSDoug Anderson struct device *dev = &pdev->dev;
2469d230c9eSDoug Anderson struct ec_i2c_device *bus = NULL;
2479d230c9eSDoug Anderson u32 remote_bus;
2489d230c9eSDoug Anderson int err;
2499d230c9eSDoug Anderson
2505799f95aSBill Richardson if (!ec->cmd_xfer) {
2519d230c9eSDoug Anderson dev_err(dev, "Missing sendrecv\n");
2529d230c9eSDoug Anderson return -EINVAL;
2539d230c9eSDoug Anderson }
2549d230c9eSDoug Anderson
2559d230c9eSDoug Anderson bus = devm_kzalloc(dev, sizeof(*bus), GFP_KERNEL);
2569d230c9eSDoug Anderson if (bus == NULL)
2579d230c9eSDoug Anderson return -ENOMEM;
2589d230c9eSDoug Anderson
2599af1563aSAkshu Agrawal err = device_property_read_u32(dev, "google,remote-bus", &remote_bus);
2609d230c9eSDoug Anderson if (err) {
2619d230c9eSDoug Anderson dev_err(dev, "Couldn't read remote-bus property\n");
2629d230c9eSDoug Anderson return err;
2639d230c9eSDoug Anderson }
2649d230c9eSDoug Anderson bus->remote_bus = remote_bus;
2659d230c9eSDoug Anderson
2669d230c9eSDoug Anderson bus->ec = ec;
2679d230c9eSDoug Anderson bus->dev = dev;
2689d230c9eSDoug Anderson
2699d230c9eSDoug Anderson bus->adap.owner = THIS_MODULE;
270ea1558ceSWolfram Sang strscpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name));
2719d230c9eSDoug Anderson bus->adap.algo = &ec_i2c_algorithm;
2729d230c9eSDoug Anderson bus->adap.algo_data = bus;
2739d230c9eSDoug Anderson bus->adap.dev.parent = &pdev->dev;
2749af1563aSAkshu Agrawal bus->adap.dev.of_node = pdev->dev.of_node;
27597720706SDerek Basehore bus->adap.retries = I2C_MAX_RETRIES;
2768ff2d7caSAkshu Agrawal ACPI_COMPANION_SET(&bus->adap.dev, ACPI_COMPANION(&pdev->dev));
2779d230c9eSDoug Anderson
2789d230c9eSDoug Anderson err = i2c_add_adapter(&bus->adap);
279ea734404SWolfram Sang if (err)
2809d230c9eSDoug Anderson return err;
2819d230c9eSDoug Anderson platform_set_drvdata(pdev, bus);
2829d230c9eSDoug Anderson
2839d230c9eSDoug Anderson return err;
2849d230c9eSDoug Anderson }
2859d230c9eSDoug Anderson
ec_i2c_remove(struct platform_device * dev)286*e190a0c3SUwe Kleine-König static void ec_i2c_remove(struct platform_device *dev)
2879d230c9eSDoug Anderson {
2889d230c9eSDoug Anderson struct ec_i2c_device *bus = platform_get_drvdata(dev);
2899d230c9eSDoug Anderson
2909d230c9eSDoug Anderson i2c_del_adapter(&bus->adap);
2919d230c9eSDoug Anderson }
2929d230c9eSDoug Anderson
2937a287433SKrzysztof Kozlowski static const struct of_device_id cros_ec_i2c_of_match[] __maybe_unused = {
2946c97c9c1SSjoerd Simons { .compatible = "google,cros-ec-i2c-tunnel" },
2956c97c9c1SSjoerd Simons {},
2966c97c9c1SSjoerd Simons };
2976c97c9c1SSjoerd Simons MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match);
2989af1563aSAkshu Agrawal
2997a287433SKrzysztof Kozlowski static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] __maybe_unused = {
300b49f8e0eSRaul E Rangel { "GOOG0012", 0 },
3019af1563aSAkshu Agrawal { }
3029af1563aSAkshu Agrawal };
3039af1563aSAkshu Agrawal MODULE_DEVICE_TABLE(acpi, cros_ec_i2c_tunnel_acpi_id);
3046c97c9c1SSjoerd Simons
3059d230c9eSDoug Anderson static struct platform_driver ec_i2c_tunnel_driver = {
3069d230c9eSDoug Anderson .probe = ec_i2c_probe,
307*e190a0c3SUwe Kleine-König .remove_new = ec_i2c_remove,
3089d230c9eSDoug Anderson .driver = {
3099d230c9eSDoug Anderson .name = "cros-ec-i2c-tunnel",
3109af1563aSAkshu Agrawal .acpi_match_table = ACPI_PTR(cros_ec_i2c_tunnel_acpi_id),
3116c97c9c1SSjoerd Simons .of_match_table = of_match_ptr(cros_ec_i2c_of_match),
3129d230c9eSDoug Anderson },
3139d230c9eSDoug Anderson };
3149d230c9eSDoug Anderson
3159d230c9eSDoug Anderson module_platform_driver(ec_i2c_tunnel_driver);
3169d230c9eSDoug Anderson
3179d230c9eSDoug Anderson MODULE_LICENSE("GPL");
3189d230c9eSDoug Anderson MODULE_DESCRIPTION("EC I2C tunnel driver");
3199d230c9eSDoug Anderson MODULE_ALIAS("platform:cros-ec-i2c-tunnel");
320