Skip to content

Commit 7489cd4

Browse files
tlebAndi Shyti
authored andcommitted
i2c: nomadik: support short xfer timeouts using waitqueue & hrtimer
Replace the completion by a waitqueue for synchronization from IRQ handler to task. For short timeouts, use hrtimers, else use timers. Usecase: avoid blocking the I2C bus for too long when an issue occurs. The threshold picked is one jiffy: if timeout is below that, use hrtimers. This threshold is NOT configurable. Implement behavior but do NOT change fetching of timeout. This means the timeout is unchanged (200ms) and the hrtimer case will never trigger. A waitqueue is used because it supports both desired timeout approaches. See wait_event_timeout() and wait_event_hrtimeout(). An atomic boolean serves as synchronization condition. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Reviewed-by: Andi Shyti <andi.shyti@kernel.org> Signed-off-by: Théo Lebrun <theo.lebrun@bootlin.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
1 parent a9f5cd8 commit 7489cd4

File tree

1 file changed

+48
-22
lines changed

1 file changed

+48
-22
lines changed

drivers/i2c/busses/i2c-nomadik.c

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -168,10 +168,11 @@ struct i2c_nmk_client {
168168
* @clk_freq: clock frequency for the operation mode
169169
* @tft: Tx FIFO Threshold in bytes
170170
* @rft: Rx FIFO Threshold in bytes
171-
* @timeout: Slave response timeout (ms)
171+
* @timeout_usecs: Slave response timeout
172172
* @sm: speed mode
173173
* @stop: stop condition.
174-
* @xfer_complete: acknowledge completion for a I2C message.
174+
* @xfer_wq: xfer done wait queue.
175+
* @xfer_done: xfer done boolean.
175176
* @result: controller propogated result.
176177
*/
177178
struct nmk_i2c_dev {
@@ -185,10 +186,11 @@ struct nmk_i2c_dev {
185186
u32 clk_freq;
186187
unsigned char tft;
187188
unsigned char rft;
188-
int timeout;
189+
u32 timeout_usecs;
189190
enum i2c_freq_mode sm;
190191
int stop;
191-
struct completion xfer_complete;
192+
struct wait_queue_head xfer_wq;
193+
bool xfer_done;
192194
int result;
193195
};
194196

@@ -443,6 +445,22 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv)
443445
writel(priv->rft, priv->virtbase + I2C_RFTR);
444446
}
445447

448+
static bool nmk_i2c_wait_xfer_done(struct nmk_i2c_dev *priv)
449+
{
450+
if (priv->timeout_usecs < jiffies_to_usecs(1)) {
451+
unsigned long timeout_usecs = priv->timeout_usecs;
452+
ktime_t timeout = ktime_set(0, timeout_usecs * NSEC_PER_USEC);
453+
454+
wait_event_hrtimeout(priv->xfer_wq, priv->xfer_done, timeout);
455+
} else {
456+
unsigned long timeout = usecs_to_jiffies(priv->timeout_usecs);
457+
458+
wait_event_timeout(priv->xfer_wq, priv->xfer_done, timeout);
459+
}
460+
461+
return priv->xfer_done;
462+
}
463+
446464
/**
447465
* read_i2c() - Read from I2C client device
448466
* @priv: private data of I2C Driver
@@ -454,9 +472,9 @@ static void setup_i2c_controller(struct nmk_i2c_dev *priv)
454472
*/
455473
static int read_i2c(struct nmk_i2c_dev *priv, u16 flags)
456474
{
457-
int status = 0;
458475
u32 mcr, irq_mask;
459-
unsigned long timeout;
476+
int status = 0;
477+
bool xfer_done;
460478

461479
mcr = load_i2c_mcr_reg(priv, flags);
462480
writel(mcr, priv->virtbase + I2C_MCR);
@@ -468,7 +486,8 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags)
468486
/* enable the controller */
469487
i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE);
470488

471-
init_completion(&priv->xfer_complete);
489+
init_waitqueue_head(&priv->xfer_wq);
490+
priv->xfer_done = false;
472491

473492
/* enable interrupts by setting the mask */
474493
irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF |
@@ -484,10 +503,9 @@ static int read_i2c(struct nmk_i2c_dev *priv, u16 flags)
484503
writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask,
485504
priv->virtbase + I2C_IMSCR);
486505

487-
timeout = wait_for_completion_timeout(
488-
&priv->xfer_complete, priv->adap.timeout);
506+
xfer_done = nmk_i2c_wait_xfer_done(priv);
489507

490-
if (timeout == 0) {
508+
if (!xfer_done) {
491509
/* Controller timed out */
492510
dev_err(&priv->adev->dev, "read from slave 0x%x timed out\n",
493511
priv->cli.slave_adr);
@@ -522,9 +540,9 @@ static void fill_tx_fifo(struct nmk_i2c_dev *priv, int no_bytes)
522540
*/
523541
static int write_i2c(struct nmk_i2c_dev *priv, u16 flags)
524542
{
525-
u32 status = 0;
526543
u32 mcr, irq_mask;
527-
unsigned long timeout;
544+
u32 status = 0;
545+
bool xfer_done;
528546

529547
mcr = load_i2c_mcr_reg(priv, flags);
530548

@@ -537,7 +555,8 @@ static int write_i2c(struct nmk_i2c_dev *priv, u16 flags)
537555
/* enable the controller */
538556
i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE);
539557

540-
init_completion(&priv->xfer_complete);
558+
init_waitqueue_head(&priv->xfer_wq);
559+
priv->xfer_done = false;
541560

542561
/* enable interrupts by settings the masks */
543562
irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR);
@@ -563,10 +582,9 @@ static int write_i2c(struct nmk_i2c_dev *priv, u16 flags)
563582
writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask,
564583
priv->virtbase + I2C_IMSCR);
565584

566-
timeout = wait_for_completion_timeout(
567-
&priv->xfer_complete, priv->adap.timeout);
585+
xfer_done = nmk_i2c_wait_xfer_done(priv);
568586

569-
if (timeout == 0) {
587+
if (!xfer_done) {
570588
/* Controller timed out */
571589
dev_err(&priv->adev->dev, "write to slave 0x%x timed out\n",
572590
priv->cli.slave_adr);
@@ -816,7 +834,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
816834
priv->cli.count);
817835
init_hw(priv);
818836
}
819-
complete(&priv->xfer_complete);
837+
priv->xfer_done = true;
838+
wake_up(&priv->xfer_wq);
839+
820840

821841
break;
822842

@@ -826,7 +846,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
826846
init_hw(priv);
827847

828848
i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_MAL);
829-
complete(&priv->xfer_complete);
849+
priv->xfer_done = true;
850+
wake_up(&priv->xfer_wq);
851+
830852

831853
break;
832854

@@ -845,7 +867,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
845867
init_hw(priv);
846868

847869
i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_BERR);
848-
complete(&priv->xfer_complete);
870+
priv->xfer_done = true;
871+
wake_up(&priv->xfer_wq);
872+
849873
}
850874
break;
851875

@@ -859,7 +883,9 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
859883
init_hw(priv);
860884

861885
dev_err(dev, "Tx Fifo Over run\n");
862-
complete(&priv->xfer_complete);
886+
priv->xfer_done = true;
887+
wake_up(&priv->xfer_wq);
888+
863889

864890
break;
865891

@@ -960,7 +986,7 @@ static void nmk_i2c_of_probe(struct device_node *np,
960986
priv->sm = I2C_FREQ_MODE_FAST;
961987
priv->tft = 1; /* Tx FIFO threshold */
962988
priv->rft = 8; /* Rx FIFO threshold */
963-
priv->timeout = 200; /* Slave response timeout(ms) */
989+
priv->timeout_usecs = 200 * USEC_PER_MSEC; /* Slave response timeout */
964990
}
965991

966992
static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
@@ -1020,7 +1046,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
10201046
adap->owner = THIS_MODULE;
10211047
adap->class = I2C_CLASS_DEPRECATED;
10221048
adap->algo = &nmk_i2c_algo;
1023-
adap->timeout = msecs_to_jiffies(priv->timeout);
1049+
adap->timeout = usecs_to_jiffies(priv->timeout_usecs);
10241050
snprintf(adap->name, sizeof(adap->name),
10251051
"Nomadik I2C at %pR", &adev->res);
10261052

0 commit comments

Comments
 (0)