1*c5cf27dbSMing Yu // SPDX-License-Identifier: GPL-2.0 2*c5cf27dbSMing Yu /* 3*c5cf27dbSMing Yu * Nuvoton NCT6694 I2C adapter driver based on USB interface. 4*c5cf27dbSMing Yu * 5*c5cf27dbSMing Yu * Copyright (C) 2025 Nuvoton Technology Corp. 6*c5cf27dbSMing Yu */ 7*c5cf27dbSMing Yu 8*c5cf27dbSMing Yu #include <linux/i2c.h> 9*c5cf27dbSMing Yu #include <linux/idr.h> 10*c5cf27dbSMing Yu #include <linux/kernel.h> 11*c5cf27dbSMing Yu #include <linux/mfd/nct6694.h> 12*c5cf27dbSMing Yu #include <linux/module.h> 13*c5cf27dbSMing Yu #include <linux/platform_device.h> 14*c5cf27dbSMing Yu 15*c5cf27dbSMing Yu /* 16*c5cf27dbSMing Yu * USB command module type for NCT6694 I2C controller. 17*c5cf27dbSMing Yu * This defines the module type used for communication with the NCT6694 18*c5cf27dbSMing Yu * I2C controller over the USB interface. 19*c5cf27dbSMing Yu */ 20*c5cf27dbSMing Yu #define NCT6694_I2C_MOD 0x03 21*c5cf27dbSMing Yu 22*c5cf27dbSMing Yu /* Command 00h - I2C Deliver */ 23*c5cf27dbSMing Yu #define NCT6694_I2C_DELIVER 0x00 24*c5cf27dbSMing Yu #define NCT6694_I2C_DELIVER_SEL 0x00 25*c5cf27dbSMing Yu 26*c5cf27dbSMing Yu #define NCT6694_I2C_MAX_XFER_SIZE 64 27*c5cf27dbSMing Yu #define NCT6694_I2C_MAX_DEVS 6 28*c5cf27dbSMing Yu 29*c5cf27dbSMing Yu static unsigned char br_reg[NCT6694_I2C_MAX_DEVS] = {[0 ... (NCT6694_I2C_MAX_DEVS - 1)] = 0xFF}; 30*c5cf27dbSMing Yu 31*c5cf27dbSMing Yu module_param_array(br_reg, byte, NULL, 0644); 32*c5cf27dbSMing Yu MODULE_PARM_DESC(br_reg, 33*c5cf27dbSMing Yu "I2C Baudrate register per adapter: (0=25K, 1=50K, 2=100K, 3=200K, 4=400K, 5=800K, 6=1M), default=2"); 34*c5cf27dbSMing Yu 35*c5cf27dbSMing Yu enum nct6694_i2c_baudrate { 36*c5cf27dbSMing Yu NCT6694_I2C_BR_25K = 0, 37*c5cf27dbSMing Yu NCT6694_I2C_BR_50K, 38*c5cf27dbSMing Yu NCT6694_I2C_BR_100K, 39*c5cf27dbSMing Yu NCT6694_I2C_BR_200K, 40*c5cf27dbSMing Yu NCT6694_I2C_BR_400K, 41*c5cf27dbSMing Yu NCT6694_I2C_BR_800K, 42*c5cf27dbSMing Yu NCT6694_I2C_BR_1M 43*c5cf27dbSMing Yu }; 44*c5cf27dbSMing Yu 45*c5cf27dbSMing Yu struct __packed nct6694_i2c_deliver { 46*c5cf27dbSMing Yu u8 port; 47*c5cf27dbSMing Yu u8 br; 48*c5cf27dbSMing Yu u8 addr; 49*c5cf27dbSMing Yu u8 w_cnt; 50*c5cf27dbSMing Yu u8 r_cnt; 51*c5cf27dbSMing Yu u8 rsv[11]; 52*c5cf27dbSMing Yu u8 write_data[NCT6694_I2C_MAX_XFER_SIZE]; 53*c5cf27dbSMing Yu u8 read_data[NCT6694_I2C_MAX_XFER_SIZE]; 54*c5cf27dbSMing Yu }; 55*c5cf27dbSMing Yu 56*c5cf27dbSMing Yu struct nct6694_i2c_data { 57*c5cf27dbSMing Yu struct device *dev; 58*c5cf27dbSMing Yu struct nct6694 *nct6694; 59*c5cf27dbSMing Yu struct i2c_adapter adapter; 60*c5cf27dbSMing Yu struct nct6694_i2c_deliver deliver; 61*c5cf27dbSMing Yu unsigned char port; 62*c5cf27dbSMing Yu unsigned char br; 63*c5cf27dbSMing Yu }; 64*c5cf27dbSMing Yu 65*c5cf27dbSMing Yu static int nct6694_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) 66*c5cf27dbSMing Yu { 67*c5cf27dbSMing Yu struct nct6694_i2c_data *data = adap->algo_data; 68*c5cf27dbSMing Yu struct nct6694_i2c_deliver *deliver = &data->deliver; 69*c5cf27dbSMing Yu static const struct nct6694_cmd_header cmd_hd = { 70*c5cf27dbSMing Yu .mod = NCT6694_I2C_MOD, 71*c5cf27dbSMing Yu .cmd = NCT6694_I2C_DELIVER, 72*c5cf27dbSMing Yu .sel = NCT6694_I2C_DELIVER_SEL, 73*c5cf27dbSMing Yu .len = cpu_to_le16(sizeof(*deliver)) 74*c5cf27dbSMing Yu }; 75*c5cf27dbSMing Yu int ret, i; 76*c5cf27dbSMing Yu 77*c5cf27dbSMing Yu for (i = 0; i < num; i++) { 78*c5cf27dbSMing Yu struct i2c_msg *msg_temp = &msgs[i]; 79*c5cf27dbSMing Yu 80*c5cf27dbSMing Yu memset(deliver, 0, sizeof(*deliver)); 81*c5cf27dbSMing Yu 82*c5cf27dbSMing Yu deliver->port = data->port; 83*c5cf27dbSMing Yu deliver->br = data->br; 84*c5cf27dbSMing Yu deliver->addr = i2c_8bit_addr_from_msg(msg_temp); 85*c5cf27dbSMing Yu if (msg_temp->flags & I2C_M_RD) { 86*c5cf27dbSMing Yu deliver->r_cnt = msg_temp->len; 87*c5cf27dbSMing Yu ret = nct6694_write_msg(data->nct6694, &cmd_hd, deliver); 88*c5cf27dbSMing Yu if (ret < 0) 89*c5cf27dbSMing Yu return ret; 90*c5cf27dbSMing Yu 91*c5cf27dbSMing Yu memcpy(msg_temp->buf, deliver->read_data, msg_temp->len); 92*c5cf27dbSMing Yu } else { 93*c5cf27dbSMing Yu deliver->w_cnt = msg_temp->len; 94*c5cf27dbSMing Yu memcpy(deliver->write_data, msg_temp->buf, msg_temp->len); 95*c5cf27dbSMing Yu ret = nct6694_write_msg(data->nct6694, &cmd_hd, deliver); 96*c5cf27dbSMing Yu if (ret < 0) 97*c5cf27dbSMing Yu return ret; 98*c5cf27dbSMing Yu } 99*c5cf27dbSMing Yu } 100*c5cf27dbSMing Yu 101*c5cf27dbSMing Yu return num; 102*c5cf27dbSMing Yu } 103*c5cf27dbSMing Yu 104*c5cf27dbSMing Yu static u32 nct6694_i2c_func(struct i2c_adapter *adapter) 105*c5cf27dbSMing Yu { 106*c5cf27dbSMing Yu return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; 107*c5cf27dbSMing Yu } 108*c5cf27dbSMing Yu 109*c5cf27dbSMing Yu static const struct i2c_adapter_quirks nct6694_i2c_quirks = { 110*c5cf27dbSMing Yu .max_read_len = NCT6694_I2C_MAX_XFER_SIZE, 111*c5cf27dbSMing Yu .max_write_len = NCT6694_I2C_MAX_XFER_SIZE, 112*c5cf27dbSMing Yu }; 113*c5cf27dbSMing Yu 114*c5cf27dbSMing Yu static const struct i2c_algorithm nct6694_i2c_algo = { 115*c5cf27dbSMing Yu .xfer = nct6694_i2c_xfer, 116*c5cf27dbSMing Yu .functionality = nct6694_i2c_func, 117*c5cf27dbSMing Yu }; 118*c5cf27dbSMing Yu 119*c5cf27dbSMing Yu static int nct6694_i2c_set_baudrate(struct nct6694_i2c_data *data) 120*c5cf27dbSMing Yu { 121*c5cf27dbSMing Yu if (data->port >= NCT6694_I2C_MAX_DEVS) { 122*c5cf27dbSMing Yu dev_err(data->dev, "Invalid I2C port index %d\n", data->port); 123*c5cf27dbSMing Yu return -EINVAL; 124*c5cf27dbSMing Yu } 125*c5cf27dbSMing Yu 126*c5cf27dbSMing Yu if (br_reg[data->port] > NCT6694_I2C_BR_1M) { 127*c5cf27dbSMing Yu dev_warn(data->dev, "Invalid baudrate %d for I2C%d, using 100K\n", 128*c5cf27dbSMing Yu br_reg[data->port], data->port); 129*c5cf27dbSMing Yu br_reg[data->port] = NCT6694_I2C_BR_100K; 130*c5cf27dbSMing Yu } 131*c5cf27dbSMing Yu 132*c5cf27dbSMing Yu data->br = br_reg[data->port]; 133*c5cf27dbSMing Yu 134*c5cf27dbSMing Yu return 0; 135*c5cf27dbSMing Yu } 136*c5cf27dbSMing Yu 137*c5cf27dbSMing Yu static void nct6694_i2c_ida_free(void *d) 138*c5cf27dbSMing Yu { 139*c5cf27dbSMing Yu struct nct6694_i2c_data *data = d; 140*c5cf27dbSMing Yu struct nct6694 *nct6694 = data->nct6694; 141*c5cf27dbSMing Yu 142*c5cf27dbSMing Yu ida_free(&nct6694->i2c_ida, data->port); 143*c5cf27dbSMing Yu } 144*c5cf27dbSMing Yu 145*c5cf27dbSMing Yu static int nct6694_i2c_probe(struct platform_device *pdev) 146*c5cf27dbSMing Yu { 147*c5cf27dbSMing Yu struct device *dev = &pdev->dev; 148*c5cf27dbSMing Yu struct nct6694 *nct6694 = dev_get_drvdata(dev->parent); 149*c5cf27dbSMing Yu struct nct6694_i2c_data *data; 150*c5cf27dbSMing Yu int ret; 151*c5cf27dbSMing Yu 152*c5cf27dbSMing Yu data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); 153*c5cf27dbSMing Yu if (!data) 154*c5cf27dbSMing Yu return -ENOMEM; 155*c5cf27dbSMing Yu 156*c5cf27dbSMing Yu data->dev = dev; 157*c5cf27dbSMing Yu data->nct6694 = nct6694; 158*c5cf27dbSMing Yu 159*c5cf27dbSMing Yu ret = ida_alloc(&nct6694->i2c_ida, GFP_KERNEL); 160*c5cf27dbSMing Yu if (ret < 0) 161*c5cf27dbSMing Yu return ret; 162*c5cf27dbSMing Yu data->port = ret; 163*c5cf27dbSMing Yu 164*c5cf27dbSMing Yu ret = devm_add_action_or_reset(dev, nct6694_i2c_ida_free, data); 165*c5cf27dbSMing Yu if (ret) 166*c5cf27dbSMing Yu return ret; 167*c5cf27dbSMing Yu 168*c5cf27dbSMing Yu ret = nct6694_i2c_set_baudrate(data); 169*c5cf27dbSMing Yu if (ret) 170*c5cf27dbSMing Yu return ret; 171*c5cf27dbSMing Yu 172*c5cf27dbSMing Yu sprintf(data->adapter.name, "NCT6694 I2C Adapter %d", data->port); 173*c5cf27dbSMing Yu data->adapter.owner = THIS_MODULE; 174*c5cf27dbSMing Yu data->adapter.algo = &nct6694_i2c_algo; 175*c5cf27dbSMing Yu data->adapter.quirks = &nct6694_i2c_quirks; 176*c5cf27dbSMing Yu data->adapter.dev.parent = dev; 177*c5cf27dbSMing Yu data->adapter.algo_data = data; 178*c5cf27dbSMing Yu 179*c5cf27dbSMing Yu platform_set_drvdata(pdev, data); 180*c5cf27dbSMing Yu 181*c5cf27dbSMing Yu return devm_i2c_add_adapter(dev, &data->adapter); 182*c5cf27dbSMing Yu } 183*c5cf27dbSMing Yu 184*c5cf27dbSMing Yu static struct platform_driver nct6694_i2c_driver = { 185*c5cf27dbSMing Yu .driver = { 186*c5cf27dbSMing Yu .name = "nct6694-i2c", 187*c5cf27dbSMing Yu }, 188*c5cf27dbSMing Yu .probe = nct6694_i2c_probe, 189*c5cf27dbSMing Yu }; 190*c5cf27dbSMing Yu 191*c5cf27dbSMing Yu module_platform_driver(nct6694_i2c_driver); 192*c5cf27dbSMing Yu 193*c5cf27dbSMing Yu MODULE_DESCRIPTION("USB-I2C adapter driver for NCT6694"); 194*c5cf27dbSMing Yu MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>"); 195*c5cf27dbSMing Yu MODULE_LICENSE("GPL"); 196*c5cf27dbSMing Yu MODULE_ALIAS("platform:nct6694-i2c"); 197