Skip to content

Commit 85b9dd6

Browse files
eghidoliAndi Shyti
authored andcommitted
i2c: lpi2c: implement xfer_atomic callback
Rework the read and write code paths in the driver to support operation in atomic contexts. To achieve this, the driver must not rely on IRQs or perform any scheduling, e.g., via a sleep or schedule routine. Implement atomic, sleep-free, and IRQ-less operation. This increases complexity but is necessary for atomic I2C transfers required by some hardware configurations, e.g., to trigger reboots on an external PMIC chip. Signed-off-by: Emanuele Ghidoli <[email protected]> Signed-off-by: Francesco Dolcini <[email protected]> Reviewed-by: Carlos Song <[email protected]> Tested-by: Primoz Fiser <[email protected]> Signed-off-by: Andi Shyti <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8336f9d commit 85b9dd6

File tree

1 file changed

+132
-38
lines changed

1 file changed

+132
-38
lines changed

drivers/i2c/busses/i2c-imx-lpi2c.c

Lines changed: 132 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -188,22 +188,24 @@ struct lpi2c_imx_struct {
188188
struct i2c_client *target;
189189
};
190190

191-
#define lpi2c_imx_read_msr_poll_timeout(val, cond) \
191+
#define lpi2c_imx_read_msr_poll_timeout(atomic, val, cond) \
192+
(atomic ? readl_poll_timeout_atomic(lpi2c_imx->base + LPI2C_MSR, val, \
193+
cond, 0, 500000) : \
192194
readl_poll_timeout(lpi2c_imx->base + LPI2C_MSR, val, cond, \
193-
0, 500000)
195+
0, 500000))
194196

195197
static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx,
196198
unsigned int enable)
197199
{
198200
writel(enable, lpi2c_imx->base + LPI2C_MIER);
199201
}
200202

201-
static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx)
203+
static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
202204
{
203205
unsigned int temp;
204206
int err;
205207

206-
err = lpi2c_imx_read_msr_poll_timeout(temp,
208+
err = lpi2c_imx_read_msr_poll_timeout(atomic, temp,
207209
temp & (MSR_ALF | MSR_BBF | MSR_MBF));
208210

209211
/* check for arbitration lost, clear if set */
@@ -248,7 +250,7 @@ static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx)
248250
}
249251

250252
static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
251-
struct i2c_msg *msgs)
253+
struct i2c_msg *msgs, bool atomic)
252254
{
253255
unsigned int temp;
254256

@@ -260,17 +262,17 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx,
260262
temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8);
261263
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
262264

263-
return lpi2c_imx_bus_busy(lpi2c_imx);
265+
return lpi2c_imx_bus_busy(lpi2c_imx, atomic);
264266
}
265267

266-
static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx)
268+
static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
267269
{
268270
unsigned int temp;
269271
int err;
270272

271273
writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR);
272274

273-
err = lpi2c_imx_read_msr_poll_timeout(temp, temp & MSR_SDF);
275+
err = lpi2c_imx_read_msr_poll_timeout(atomic, temp, temp & MSR_SDF);
274276

275277
if (err) {
276278
dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n");
@@ -390,12 +392,12 @@ static int lpi2c_imx_pio_msg_complete(struct lpi2c_imx_struct *lpi2c_imx)
390392
return time_left ? 0 : -ETIMEDOUT;
391393
}
392394

393-
static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx)
395+
static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
394396
{
395397
unsigned int temp;
396398
int err;
397399

398-
err = lpi2c_imx_read_msr_poll_timeout(temp,
400+
err = lpi2c_imx_read_msr_poll_timeout(atomic, temp,
399401
(temp & MSR_NDF) || !lpi2c_imx_txfifo_cnt(lpi2c_imx));
400402

401403
if (temp & MSR_NDF) {
@@ -432,7 +434,7 @@ static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx)
432434
writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR);
433435
}
434436

435-
static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
437+
static bool lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
436438
{
437439
unsigned int data, txcnt;
438440

@@ -447,13 +449,19 @@ static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx)
447449
txcnt++;
448450
}
449451

450-
if (lpi2c_imx->delivered < lpi2c_imx->msglen)
451-
lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
452-
else
452+
if (lpi2c_imx->delivered < lpi2c_imx->msglen) {
453+
if (!atomic)
454+
lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE);
455+
return false;
456+
}
457+
458+
if (!atomic)
453459
complete(&lpi2c_imx->complete);
460+
461+
return true;
454462
}
455463

456-
static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
464+
static bool lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic)
457465
{
458466
unsigned int blocklen, remaining;
459467
unsigned int temp, data;
@@ -478,8 +486,9 @@ static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
478486
remaining = lpi2c_imx->msglen - lpi2c_imx->delivered;
479487

480488
if (!remaining) {
481-
complete(&lpi2c_imx->complete);
482-
return;
489+
if (!atomic)
490+
complete(&lpi2c_imx->complete);
491+
return true;
483492
}
484493

485494
/* not finished, still waiting for rx data */
@@ -497,19 +506,40 @@ static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx)
497506
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
498507
}
499508

500-
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
509+
if (!atomic)
510+
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE);
511+
512+
return false;
501513
}
502514

503515
static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx,
504516
struct i2c_msg *msgs)
505517
{
506518
lpi2c_imx->tx_buf = msgs->buf;
507519
lpi2c_imx_set_tx_watermark(lpi2c_imx);
508-
lpi2c_imx_write_txfifo(lpi2c_imx);
520+
lpi2c_imx_write_txfifo(lpi2c_imx, false);
509521
}
510522

511-
static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
512-
struct i2c_msg *msgs)
523+
static int lpi2c_imx_write_atomic(struct lpi2c_imx_struct *lpi2c_imx,
524+
struct i2c_msg *msgs)
525+
{
526+
u32 temp;
527+
int err;
528+
529+
lpi2c_imx->tx_buf = msgs->buf;
530+
531+
err = lpi2c_imx_read_msr_poll_timeout(true, temp,
532+
(temp & MSR_NDF) ||
533+
lpi2c_imx_write_txfifo(lpi2c_imx, true));
534+
535+
if (temp & MSR_NDF)
536+
return -EIO;
537+
538+
return err;
539+
}
540+
541+
static void lpi2c_imx_read_init(struct lpi2c_imx_struct *lpi2c_imx,
542+
struct i2c_msg *msgs)
513543
{
514544
unsigned int temp;
515545

@@ -520,8 +550,43 @@ static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx,
520550
temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1;
521551
temp |= (RECV_DATA << 8);
522552
writel(temp, lpi2c_imx->base + LPI2C_MTDR);
553+
}
523554

524-
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
555+
static bool lpi2c_imx_read_chunk_atomic(struct lpi2c_imx_struct *lpi2c_imx)
556+
{
557+
u32 rxcnt;
558+
559+
rxcnt = (readl(lpi2c_imx->base + LPI2C_MFSR) >> 16) & 0xFF;
560+
if (!rxcnt)
561+
return false;
562+
563+
if (!lpi2c_imx_read_rxfifo(lpi2c_imx, true))
564+
return false;
565+
566+
return true;
567+
}
568+
569+
static int lpi2c_imx_read_atomic(struct lpi2c_imx_struct *lpi2c_imx,
570+
struct i2c_msg *msgs)
571+
{
572+
u32 temp;
573+
int tmo_us;
574+
575+
tmo_us = 1000000;
576+
do {
577+
if (lpi2c_imx_read_chunk_atomic(lpi2c_imx))
578+
return 0;
579+
580+
temp = readl(lpi2c_imx->base + LPI2C_MSR);
581+
582+
if (temp & MSR_NDF)
583+
return -EIO;
584+
585+
udelay(100);
586+
tmo_us -= 100;
587+
} while (tmo_us > 0);
588+
589+
return -ETIMEDOUT;
525590
}
526591

527592
static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg)
@@ -541,14 +606,27 @@ static int lpi2c_imx_pio_xfer(struct lpi2c_imx_struct *lpi2c_imx,
541606
{
542607
reinit_completion(&lpi2c_imx->complete);
543608

544-
if (msg->flags & I2C_M_RD)
545-
lpi2c_imx_read(lpi2c_imx, msg);
546-
else
609+
if (msg->flags & I2C_M_RD) {
610+
lpi2c_imx_read_init(lpi2c_imx, msg);
611+
lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE);
612+
} else {
547613
lpi2c_imx_write(lpi2c_imx, msg);
614+
}
548615

549616
return lpi2c_imx_pio_msg_complete(lpi2c_imx);
550617
}
551618

619+
static int lpi2c_imx_pio_xfer_atomic(struct lpi2c_imx_struct *lpi2c_imx,
620+
struct i2c_msg *msg)
621+
{
622+
if (msg->flags & I2C_M_RD) {
623+
lpi2c_imx_read_init(lpi2c_imx, msg);
624+
return lpi2c_imx_read_atomic(lpi2c_imx, msg);
625+
}
626+
627+
return lpi2c_imx_write_atomic(lpi2c_imx, msg);
628+
}
629+
552630
static int lpi2c_imx_dma_timeout_calculate(struct lpi2c_imx_struct *lpi2c_imx)
553631
{
554632
unsigned long time = 0;
@@ -943,8 +1021,8 @@ static int lpi2c_imx_dma_xfer(struct lpi2c_imx_struct *lpi2c_imx,
9431021
return ret;
9441022
}
9451023

946-
static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
947-
struct i2c_msg *msgs, int num)
1024+
static int lpi2c_imx_xfer_common(struct i2c_adapter *adapter,
1025+
struct i2c_msg *msgs, int num, bool atomic)
9481026
{
9491027
struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter);
9501028
unsigned int temp;
@@ -955,7 +1033,7 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
9551033
return result;
9561034

9571035
for (i = 0; i < num; i++) {
958-
result = lpi2c_imx_start(lpi2c_imx, &msgs[i]);
1036+
result = lpi2c_imx_start(lpi2c_imx, &msgs[i], atomic);
9591037
if (result)
9601038
goto disable;
9611039

@@ -967,28 +1045,33 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
9671045
lpi2c_imx->tx_buf = NULL;
9681046
lpi2c_imx->delivered = 0;
9691047
lpi2c_imx->msglen = msgs[i].len;
970-
init_completion(&lpi2c_imx->complete);
9711048

972-
if (is_use_dma(lpi2c_imx, &msgs[i])) {
973-
result = lpi2c_imx_dma_xfer(lpi2c_imx, &msgs[i]);
974-
if (result && lpi2c_imx->dma->using_pio_mode)
975-
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
1049+
if (atomic) {
1050+
result = lpi2c_imx_pio_xfer_atomic(lpi2c_imx, &msgs[i]);
9761051
} else {
977-
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
1052+
init_completion(&lpi2c_imx->complete);
1053+
1054+
if (is_use_dma(lpi2c_imx, &msgs[i])) {
1055+
result = lpi2c_imx_dma_xfer(lpi2c_imx, &msgs[i]);
1056+
if (result && lpi2c_imx->dma->using_pio_mode)
1057+
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
1058+
} else {
1059+
result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]);
1060+
}
9781061
}
9791062

9801063
if (result)
9811064
goto stop;
9821065

9831066
if (!(msgs[i].flags & I2C_M_RD)) {
984-
result = lpi2c_imx_txfifo_empty(lpi2c_imx);
1067+
result = lpi2c_imx_txfifo_empty(lpi2c_imx, atomic);
9851068
if (result)
9861069
goto stop;
9871070
}
9881071
}
9891072

9901073
stop:
991-
lpi2c_imx_stop(lpi2c_imx);
1074+
lpi2c_imx_stop(lpi2c_imx, atomic);
9921075

9931076
temp = readl(lpi2c_imx->base + LPI2C_MSR);
9941077
if ((temp & MSR_NDF) && !result)
@@ -1004,6 +1087,16 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter,
10041087
return (result < 0) ? result : num;
10051088
}
10061089

1090+
static int lpi2c_imx_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
1091+
{
1092+
return lpi2c_imx_xfer_common(adapter, msgs, num, false);
1093+
}
1094+
1095+
static int lpi2c_imx_xfer_atomic(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num)
1096+
{
1097+
return lpi2c_imx_xfer_common(adapter, msgs, num, true);
1098+
}
1099+
10071100
static irqreturn_t lpi2c_imx_target_isr(struct lpi2c_imx_struct *lpi2c_imx,
10081101
u32 ssr, u32 sier_filter)
10091102
{
@@ -1066,9 +1159,9 @@ static irqreturn_t lpi2c_imx_master_isr(struct lpi2c_imx_struct *lpi2c_imx)
10661159
if (temp & MSR_NDF)
10671160
complete(&lpi2c_imx->complete);
10681161
else if (temp & MSR_RDF)
1069-
lpi2c_imx_read_rxfifo(lpi2c_imx);
1162+
lpi2c_imx_read_rxfifo(lpi2c_imx, false);
10701163
else if (temp & MSR_TDF)
1071-
lpi2c_imx_write_txfifo(lpi2c_imx);
1164+
lpi2c_imx_write_txfifo(lpi2c_imx, false);
10721165

10731166
return IRQ_HANDLED;
10741167
}
@@ -1265,6 +1358,7 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
12651358

12661359
static const struct i2c_algorithm lpi2c_imx_algo = {
12671360
.xfer = lpi2c_imx_xfer,
1361+
.xfer_atomic = lpi2c_imx_xfer_atomic,
12681362
.functionality = lpi2c_imx_func,
12691363
.reg_target = lpi2c_imx_register_target,
12701364
.unreg_target = lpi2c_imx_unregister_target,

0 commit comments

Comments
 (0)