Skip to content

Commit d6ceb40

Browse files
PrashanthkumarbkAndi Shyti
authored andcommitted
i2c: microchip-corei2c: add smbus support
Add hardware support for the SMBUS commands smbus_quick, smbus_byte, smbus_byte_data, smbus_word_data and smbus_block_data, replacing the fallback to software emulation Signed-off-by: prashanth kumar burujukindi <prashanthkumar.burujukindi@microchip.com> Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Link: https://lore.kernel.org/r/20250430-preview-dormitory-85191523283d@spud Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
1 parent 0538590 commit d6ceb40

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

drivers/i2c/busses/i2c-microchip-corei2c.c

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@
7676
#define CORE_I2C_FREQ (0x14)
7777
#define CORE_I2C_GLITCHREG (0x18)
7878
#define CORE_I2C_SLAVE1_ADDR (0x1c)
79+
#define CORE_I2C_SMBUS_MSG_WR (0x0)
80+
#define CORE_I2C_SMBUS_MSG_RD (0x1)
7981

8082
#define PCLK_DIV_960 (CTRL_CR2)
8183
#define PCLK_DIV_256 (0)
@@ -424,9 +426,109 @@ static u32 mchp_corei2c_func(struct i2c_adapter *adap)
424426
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
425427
}
426428

429+
static int mchp_corei2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags,
430+
char read_write, u8 command,
431+
int size, union i2c_smbus_data *data)
432+
{
433+
struct i2c_msg msgs[2];
434+
struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap);
435+
u8 tx_buf[I2C_SMBUS_BLOCK_MAX + 2];
436+
u8 rx_buf[I2C_SMBUS_BLOCK_MAX + 1];
437+
int num_msgs = 1;
438+
439+
msgs[CORE_I2C_SMBUS_MSG_WR].addr = addr;
440+
msgs[CORE_I2C_SMBUS_MSG_WR].flags = 0;
441+
442+
if (read_write == I2C_SMBUS_READ && size <= I2C_SMBUS_BYTE)
443+
msgs[CORE_I2C_SMBUS_MSG_WR].flags = I2C_M_RD;
444+
445+
if (read_write == I2C_SMBUS_WRITE && size <= I2C_SMBUS_WORD_DATA)
446+
msgs[CORE_I2C_SMBUS_MSG_WR].len = size;
447+
448+
if (read_write == I2C_SMBUS_WRITE && size > I2C_SMBUS_BYTE) {
449+
msgs[CORE_I2C_SMBUS_MSG_WR].buf = tx_buf;
450+
msgs[CORE_I2C_SMBUS_MSG_WR].buf[0] = command;
451+
}
452+
453+
if (read_write == I2C_SMBUS_READ && size >= I2C_SMBUS_BYTE_DATA) {
454+
msgs[CORE_I2C_SMBUS_MSG_WR].buf = tx_buf;
455+
msgs[CORE_I2C_SMBUS_MSG_WR].buf[0] = command;
456+
msgs[CORE_I2C_SMBUS_MSG_RD].addr = addr;
457+
msgs[CORE_I2C_SMBUS_MSG_RD].flags = I2C_M_RD;
458+
num_msgs = 2;
459+
}
460+
461+
if (read_write == I2C_SMBUS_READ && size > I2C_SMBUS_QUICK)
462+
msgs[CORE_I2C_SMBUS_MSG_WR].len = 1;
463+
464+
switch (size) {
465+
case I2C_SMBUS_QUICK:
466+
msgs[CORE_I2C_SMBUS_MSG_WR].buf = NULL;
467+
return 0;
468+
case I2C_SMBUS_BYTE:
469+
if (read_write == I2C_SMBUS_WRITE)
470+
msgs[CORE_I2C_SMBUS_MSG_WR].buf = &command;
471+
else
472+
msgs[CORE_I2C_SMBUS_MSG_WR].buf = &data->byte;
473+
break;
474+
case I2C_SMBUS_BYTE_DATA:
475+
if (read_write == I2C_SMBUS_WRITE) {
476+
msgs[CORE_I2C_SMBUS_MSG_WR].buf[1] = data->byte;
477+
} else {
478+
msgs[CORE_I2C_SMBUS_MSG_RD].len = size - 1;
479+
msgs[CORE_I2C_SMBUS_MSG_RD].buf = &data->byte;
480+
}
481+
break;
482+
case I2C_SMBUS_WORD_DATA:
483+
if (read_write == I2C_SMBUS_WRITE) {
484+
msgs[CORE_I2C_SMBUS_MSG_WR].buf[1] = data->word & 0xFF;
485+
msgs[CORE_I2C_SMBUS_MSG_WR].buf[2] = (data->word >> 8) & 0xFF;
486+
} else {
487+
msgs[CORE_I2C_SMBUS_MSG_RD].len = size - 1;
488+
msgs[CORE_I2C_SMBUS_MSG_RD].buf = rx_buf;
489+
}
490+
break;
491+
case I2C_SMBUS_BLOCK_DATA:
492+
if (read_write == I2C_SMBUS_WRITE) {
493+
int data_len;
494+
495+
data_len = data->block[0];
496+
msgs[CORE_I2C_SMBUS_MSG_WR].len = data_len + 2;
497+
for (int i = 0; i <= data_len; i++)
498+
msgs[CORE_I2C_SMBUS_MSG_WR].buf[i + 1] = data->block[i];
499+
} else {
500+
msgs[CORE_I2C_SMBUS_MSG_RD].len = I2C_SMBUS_BLOCK_MAX + 1;
501+
msgs[CORE_I2C_SMBUS_MSG_RD].buf = rx_buf;
502+
}
503+
break;
504+
default:
505+
return -EOPNOTSUPP;
506+
}
507+
508+
mchp_corei2c_xfer(&idev->adapter, msgs, num_msgs);
509+
if (read_write == I2C_SMBUS_WRITE || size <= I2C_SMBUS_BYTE_DATA)
510+
return 0;
511+
512+
switch (size) {
513+
case I2C_SMBUS_WORD_DATA:
514+
data->word = (rx_buf[0] | (rx_buf[1] << 8));
515+
break;
516+
case I2C_SMBUS_BLOCK_DATA:
517+
if (rx_buf[0] > I2C_SMBUS_BLOCK_MAX)
518+
rx_buf[0] = I2C_SMBUS_BLOCK_MAX;
519+
/* As per protocol first member of block is size of the block. */
520+
for (int i = 0; i <= rx_buf[0]; i++)
521+
data->block[i] = rx_buf[i];
522+
break;
523+
}
524+
525+
return 0;
526+
}
527+
427528
static const struct i2c_algorithm mchp_corei2c_algo = {
428529
.master_xfer = mchp_corei2c_xfer,
429530
.functionality = mchp_corei2c_func,
531+
.smbus_xfer = mchp_corei2c_smbus_xfer,
430532
};
431533

432534
static int mchp_corei2c_probe(struct platform_device *pdev)

0 commit comments

Comments
 (0)