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 = &params->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