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 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 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 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 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 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