Skip to content

Commit ba06487

Browse files
larsclausenwsakernel
authored andcommitted
i2c: cadence: Detect maximum transfer size
The maximum transfer length is a synthesis configuration parameters of the Cadence I2C IP. Different SoCs might use different values for these parameters. Currently the driver has the maximum transfer length hardcoded to 255. Trying to use the driver with an IP instance that uses smaller values for these will work for short transfers. But longer transfers will fail. The maximum transfer length can easily be detected at runtime since the unused MSBs of the transfer length register are hardwired to 0. Writing 0xff and then reading back the value will give the maximum transfer length. These changes have been tested with 1) The Xilinx MPSoC for which this driver was originally written which has the previous hardcoded settings of 16 and 255. 2) Another instance of the Cadence I2C IP with FIFO depth of 8 and maximum transfer length of 16. Without these changes the latter would fail for I2C transfers longer than 16. With the updated driver both work fine even for longer transfers. Note that the IP core and driver support chaining multiple transfers into a single longer transfer using the HOLD bit. So the maximum transfer size is not the limit for the length of the I2C transfer, but the limit for how much data can be transferred without having to reprogram the control registers. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Acked-by: Michal Simek <michal.simek@amd.com> Signed-off-by: Wolfram Sang <wsa@kernel.org>
1 parent a069fcd commit ba06487

1 file changed

Lines changed: 42 additions & 7 deletions

File tree

drivers/i2c/busses/i2c-cadence.c

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@
117117
#define CDNS_I2C_FIFO_DEPTH_DEFAULT 16
118118
#define CDNS_I2C_MAX_TRANSFER_SIZE 255
119119
/* Transfer size in multiples of data interrupt depth */
120-
#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
120+
#define CDNS_I2C_TRANSFER_SIZE(max) ((max) - 3)
121121

122122
#define DRIVER_NAME "cdns-i2c"
123123

@@ -185,6 +185,7 @@ enum cdns_i2c_slave_state {
185185
* @dev_mode: I2C operating role(master/slave).
186186
* @slave_state: I2C Slave state(idle/read/write).
187187
* @fifo_depth: The depth of the transfer FIFO
188+
* @transfer_size: The maximum number of bytes in one transfer
188189
*/
189190
struct cdns_i2c {
190191
struct device *dev;
@@ -213,6 +214,7 @@ struct cdns_i2c {
213214
enum cdns_i2c_slave_state slave_state;
214215
#endif
215216
u32 fifo_depth;
217+
unsigned int transfer_size;
216218
};
217219

218220
struct cdns_platform_data {
@@ -466,10 +468,10 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr)
466468
* transfer size and update register accordingly.
467469
*/
468470
if (((int)(id->recv_count) - id->fifo_depth) >
469-
CDNS_I2C_TRANSFER_SIZE) {
470-
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
471+
id->transfer_size) {
472+
cdns_i2c_writereg(id->transfer_size,
471473
CDNS_I2C_XFER_SIZE_OFFSET);
472-
id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
474+
id->curr_recv_count = id->transfer_size +
473475
id->fifo_depth;
474476
} else {
475477
cdns_i2c_writereg(id->recv_count -
@@ -605,10 +607,10 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
605607
* receive if it is less than transfer size and transfer size if
606608
* it is more. Enable the interrupts.
607609
*/
608-
if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
609-
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
610+
if (id->recv_count > id->transfer_size) {
611+
cdns_i2c_writereg(id->transfer_size,
610612
CDNS_I2C_XFER_SIZE_OFFSET);
611-
id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
613+
id->curr_recv_count = id->transfer_size;
612614
} else {
613615
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
614616
}
@@ -1227,6 +1229,37 @@ static const struct of_device_id cdns_i2c_of_match[] = {
12271229
};
12281230
MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
12291231

1232+
/**
1233+
* cdns_i2c_detect_transfer_size - Detect the maximum transfer size supported
1234+
* @id: Device private data structure
1235+
*
1236+
* Detect the maximum transfer size that is supported by this instance of the
1237+
* Cadence I2C controller.
1238+
*/
1239+
static void cdns_i2c_detect_transfer_size(struct cdns_i2c *id)
1240+
{
1241+
u32 val;
1242+
1243+
/*
1244+
* Writing to the transfer size register is only possible if these two bits
1245+
* are set in the control register.
1246+
*/
1247+
cdns_i2c_writereg(CDNS_I2C_CR_MS | CDNS_I2C_CR_RW, CDNS_I2C_CR_OFFSET);
1248+
1249+
/*
1250+
* The number of writable bits of the transfer size register can be between
1251+
* 4 and 8. This is a controlled through a synthesis parameter of the IP
1252+
* core and can vary from instance to instance. The unused MSBs always read
1253+
* back as 0. Writing 0xff and then reading the value back will report the
1254+
* maximum supported transfer size.
1255+
*/
1256+
cdns_i2c_writereg(CDNS_I2C_MAX_TRANSFER_SIZE, CDNS_I2C_XFER_SIZE_OFFSET);
1257+
val = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
1258+
id->transfer_size = CDNS_I2C_TRANSFER_SIZE(val);
1259+
cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
1260+
cdns_i2c_writereg(0, CDNS_I2C_CR_OFFSET);
1261+
}
1262+
12301263
/**
12311264
* cdns_i2c_probe - Platform registration call
12321265
* @pdev: Handle to the platform device structure
@@ -1321,6 +1354,8 @@ static int cdns_i2c_probe(struct platform_device *pdev)
13211354
id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT;
13221355
of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth);
13231356

1357+
cdns_i2c_detect_transfer_size(id);
1358+
13241359
ret = cdns_i2c_setclk(id->input_clk, id);
13251360
if (ret) {
13261361
dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);

0 commit comments

Comments
 (0)