xref: /linux/drivers/net/pse-pd/realtek-pse-mcu-i2c.c (revision 91ec2035134982b98fab0609a9fd8480e8217dc1)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #include <linux/delay.h>
4 #include <linux/i2c.h>
5 #include <linux/module.h>
6 #include <linux/of.h>
7 #include <linux/pse-pd/pse.h>
8 
9 #include "realtek-pse-mcu.h"
10 
11 /*
12  * The core has already waited RTPSE_MCU_RESPONSE_MS before calling us, so
13  * the response is normally ready on the very first read. For commands the
14  * MCU produces more slowly, keep polling at the typical response cadence
15  * up to the worst-case ceiling.
16  */
17 #define RTPSE_MCU_I2C_RETRY_MS	RTPSE_MCU_RESPONSE_MS
18 #define RTPSE_MCU_I2C_MAX_TRIES	(RTPSE_MCU_RESPONSE_MAX_MS / RTPSE_MCU_I2C_RETRY_MS)
19 
rtpse_mcu_i2c_smbus_send(struct rtpse_mcu_ctrl * pse,const struct rtpse_mcu_msg * req)20 static int rtpse_mcu_i2c_smbus_send(struct rtpse_mcu_ctrl *pse, const struct rtpse_mcu_msg *req)
21 {
22 	struct i2c_client *client = to_i2c_client(pse->dev);
23 
24 	/* Send opcode as SMBus command byte; remaining 11 bytes as block data */
25 	return i2c_smbus_write_i2c_block_data(client, req->opcode, RTPSE_MCU_MSG_SIZE - 1,
26 					      (const u8 *)req + 1);
27 }
28 
rtpse_mcu_i2c_smbus_recv(struct rtpse_mcu_ctrl * pse,const struct rtpse_mcu_msg * req,struct rtpse_mcu_msg * resp)29 static int rtpse_mcu_i2c_smbus_recv(struct rtpse_mcu_ctrl *pse, const struct rtpse_mcu_msg *req,
30 				    struct rtpse_mcu_msg *resp)
31 {
32 	struct i2c_client *client = to_i2c_client(pse->dev);
33 	int tries, ret;
34 
35 	for (tries = 0; tries < RTPSE_MCU_I2C_MAX_TRIES; tries++) {
36 		if (tries > 0)
37 			msleep(RTPSE_MCU_I2C_RETRY_MS);
38 
39 		/* MCU needs 0x00 as command byte for read */
40 		ret = i2c_smbus_read_i2c_block_data(client, 0x00,
41 						    RTPSE_MCU_MSG_SIZE,
42 						    (u8 *)resp);
43 		if (ret < 0)
44 			return ret;
45 		if (ret == RTPSE_MCU_MSG_SIZE && rtpse_mcu_resp_is_final(req, resp))
46 			return 0;
47 	}
48 
49 	return -ETIMEDOUT;
50 }
51 
52 static const struct rtpse_mcu_transport_ops rtpse_mcu_i2c_smbus_ops = {
53 	.send = rtpse_mcu_i2c_smbus_send,
54 	.recv = rtpse_mcu_i2c_smbus_recv,
55 };
56 
rtpse_mcu_i2c_native_send(struct rtpse_mcu_ctrl * pse,const struct rtpse_mcu_msg * req)57 static int rtpse_mcu_i2c_native_send(struct rtpse_mcu_ctrl *pse, const struct rtpse_mcu_msg *req)
58 {
59 	struct i2c_client *client = to_i2c_client(pse->dev);
60 	int ret;
61 
62 	ret = i2c_master_send(client, (const u8 *)req, RTPSE_MCU_MSG_SIZE);
63 	if (ret < 0)
64 		return ret;
65 	return ret == RTPSE_MCU_MSG_SIZE ? 0 : -EIO;
66 }
67 
rtpse_mcu_i2c_native_recv(struct rtpse_mcu_ctrl * pse,const struct rtpse_mcu_msg * req,struct rtpse_mcu_msg * resp)68 static int rtpse_mcu_i2c_native_recv(struct rtpse_mcu_ctrl *pse, const struct rtpse_mcu_msg *req,
69 				     struct rtpse_mcu_msg *resp)
70 {
71 	struct i2c_client *client = to_i2c_client(pse->dev);
72 	int tries, ret;
73 
74 	for (tries = 0; tries < RTPSE_MCU_I2C_MAX_TRIES; tries++) {
75 		if (tries > 0)
76 			msleep(RTPSE_MCU_I2C_RETRY_MS);
77 
78 		ret = i2c_master_recv(client, (u8 *)resp, RTPSE_MCU_MSG_SIZE);
79 		if (ret < 0)
80 			return ret;
81 		if (ret == RTPSE_MCU_MSG_SIZE && rtpse_mcu_resp_is_final(req, resp))
82 			return 0;
83 	}
84 
85 	return -ETIMEDOUT;
86 }
87 
88 static const struct rtpse_mcu_transport_ops rtpse_mcu_i2c_native_ops = {
89 	.send = rtpse_mcu_i2c_native_send,
90 	.recv = rtpse_mcu_i2c_native_recv,
91 };
92 
rtpse_mcu_i2c_probe(struct i2c_client * client)93 static int rtpse_mcu_i2c_probe(struct i2c_client *client)
94 {
95 	struct device *dev = &client->dev;
96 	const struct rtpse_mcu_match_data *match;
97 	struct rtpse_mcu_ctrl *pse;
98 	bool use_native;
99 
100 	match = device_get_match_data(dev);
101 	if (!match)
102 		return dev_err_probe(dev, -ENODEV, "missing match data\n");
103 
104 	/* The framing (raw I2C vs SMBus) is carried by the match data. */
105 	use_native = match->native_i2c;
106 	if (use_native) {
107 		if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
108 			return dev_err_probe(dev, -EOPNOTSUPP,
109 				"plain-I2C MCU protocol requires I2C-capable adapter\n");
110 	} else {
111 		if (!i2c_check_functionality(client->adapter,
112 					     I2C_FUNC_SMBUS_WRITE_I2C_BLOCK |
113 					     I2C_FUNC_SMBUS_READ_I2C_BLOCK))
114 			return dev_err_probe(dev, -EOPNOTSUPP,
115 				"SMBus MCU protocol requires SMBus I2C-block support\n");
116 	}
117 
118 	pse = devm_kzalloc(dev, sizeof(*pse), GFP_KERNEL);
119 	if (!pse)
120 		return -ENOMEM;
121 
122 	pse->dev = dev;
123 	pse->pcdev.owner = THIS_MODULE;
124 	pse->transport = use_native ? &rtpse_mcu_i2c_native_ops : &rtpse_mcu_i2c_smbus_ops;
125 
126 	return rtpse_mcu_register(pse);
127 }
128 
129 static const struct of_device_id rtpse_mcu_i2c_of_match[] = {
130 	{ .compatible = "realtek,pse-mcu-gen1-smbus", .data = &rtpse_mcu_gen1_data },
131 	{ .compatible = "realtek,pse-mcu-gen2-smbus", .data = &rtpse_mcu_gen2_data },
132 	{ .compatible = "realtek,pse-mcu-gen2-i2c", .data = &rtpse_mcu_gen2_i2c_data },
133 	{ /* sentinel */ }
134 };
135 MODULE_DEVICE_TABLE(of, rtpse_mcu_i2c_of_match);
136 
137 static struct i2c_driver rtpse_mcu_i2c_driver = {
138 	.driver = {
139 		.name		= "realtek-pse-mcu-i2c",
140 		.of_match_table	= rtpse_mcu_i2c_of_match,
141 	},
142 	.probe		= rtpse_mcu_i2c_probe,
143 };
144 module_i2c_driver(rtpse_mcu_i2c_driver);
145 
146 MODULE_AUTHOR("Jonas Jelonek <jelonek.jonas@gmail.com>");
147 MODULE_DESCRIPTION("Realtek PSE MCU driver (I2C transport)");
148 MODULE_LICENSE("GPL");
149