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