Skip to content

Commit e826192

Browse files
amarioguywsakernel
authored andcommitted
i2c: /pasemi: PASemi I2C controller IRQ enablement
This patch adds IRQ support to the PASemi I2C controller driver to increase the performace of I2C transactions on platforms with PASemi I2C controllers. While primarily intended for Apple silicon platforms, this patch should also help in enabling IRQ support for older PASemi hardware as well should the need arise. This version of the patch has been tested on an M1 Ultra Mac Studio, as well as an M1 MacBook Pro, and userspace launches successfully while using the IRQ path for I2C transactions. Signed-off-by: Arminder Singh <arminders208@outlook.com> Reviewed-by: Sven Peter <sven@svenpeter.dev> Reviewed-by: Hector Martin <marcan@marcan.st> Signed-off-by: Wolfram Sang <wsa@kernel.org>
1 parent 8502bee commit e826192

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

drivers/i2c/busses/i2c-pasemi-core.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#define REG_MTXFIFO 0x00
2222
#define REG_MRXFIFO 0x04
2323
#define REG_SMSTA 0x14
24+
#define REG_IMASK 0x18
2425
#define REG_CTL 0x1c
2526
#define REG_REV 0x28
2627

@@ -66,6 +67,7 @@ static void pasemi_reset(struct pasemi_smbus *smbus)
6667
val |= CTL_EN;
6768

6869
reg_write(smbus, REG_CTL, val);
70+
reinit_completion(&smbus->irq_completion);
6971
}
7072

7173
static void pasemi_smb_clear(struct pasemi_smbus *smbus)
@@ -78,14 +80,21 @@ static void pasemi_smb_clear(struct pasemi_smbus *smbus)
7880

7981
static int pasemi_smb_waitready(struct pasemi_smbus *smbus)
8082
{
81-
int timeout = 10;
83+
int timeout = 100;
8284
unsigned int status;
8385

84-
status = reg_read(smbus, REG_SMSTA);
85-
86-
while (!(status & SMSTA_XEN) && timeout--) {
87-
msleep(1);
86+
if (smbus->use_irq) {
87+
reinit_completion(&smbus->irq_completion);
88+
reg_write(smbus, REG_IMASK, SMSTA_XEN | SMSTA_MTN);
89+
wait_for_completion_timeout(&smbus->irq_completion, msecs_to_jiffies(100));
90+
reg_write(smbus, REG_IMASK, 0);
8891
status = reg_read(smbus, REG_SMSTA);
92+
} else {
93+
status = reg_read(smbus, REG_SMSTA);
94+
while (!(status & SMSTA_XEN) && timeout--) {
95+
msleep(1);
96+
status = reg_read(smbus, REG_SMSTA);
97+
}
8998
}
9099

91100
/* Got NACK? */
@@ -344,10 +353,14 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus)
344353

345354
/* set up the sysfs linkage to our parent device */
346355
smbus->adapter.dev.parent = smbus->dev;
356+
smbus->use_irq = 0;
357+
init_completion(&smbus->irq_completion);
347358

348359
if (smbus->hw_rev != PASEMI_HW_REV_PCI)
349360
smbus->hw_rev = reg_read(smbus, REG_REV);
350361

362+
reg_write(smbus, REG_IMASK, 0);
363+
351364
pasemi_reset(smbus);
352365

353366
error = devm_i2c_add_adapter(smbus->dev, &smbus->adapter);
@@ -356,3 +369,12 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus)
356369

357370
return 0;
358371
}
372+
373+
irqreturn_t pasemi_irq_handler(int irq, void *dev_id)
374+
{
375+
struct pasemi_smbus *smbus = dev_id;
376+
377+
reg_write(smbus, REG_IMASK, 0);
378+
complete(&smbus->irq_completion);
379+
return IRQ_HANDLED;
380+
}

drivers/i2c/busses/i2c-pasemi-core.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <linux/i2c-smbus.h>
88
#include <linux/io.h>
99
#include <linux/kernel.h>
10+
#include <linux/completion.h>
1011

1112
#define PASEMI_HW_REV_PCI -1
1213

@@ -16,6 +17,10 @@ struct pasemi_smbus {
1617
void __iomem *ioaddr;
1718
unsigned int clk_div;
1819
int hw_rev;
20+
int use_irq;
21+
struct completion irq_completion;
1922
};
2023

2124
int pasemi_i2c_common_probe(struct pasemi_smbus *smbus);
25+
26+
irqreturn_t pasemi_irq_handler(int irq, void *dev_id);

drivers/i2c/busses/i2c-pasemi-platform.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ static int pasemi_platform_i2c_probe(struct platform_device *pdev)
4949
struct pasemi_smbus *smbus;
5050
u32 frequency;
5151
int error;
52+
int irq_num;
5253

5354
data = devm_kzalloc(dev, sizeof(struct pasemi_platform_i2c_data),
5455
GFP_KERNEL);
@@ -82,6 +83,11 @@ static int pasemi_platform_i2c_probe(struct platform_device *pdev)
8283
if (error)
8384
goto out_clk_disable;
8485

86+
irq_num = platform_get_irq(pdev, 0);
87+
error = devm_request_irq(smbus->dev, irq_num, pasemi_irq_handler, 0, "pasemi_apple_i2c", (void *)smbus);
88+
89+
if (!error)
90+
smbus->use_irq = 1;
8591
platform_set_drvdata(pdev, data);
8692

8793
return 0;

0 commit comments

Comments
 (0)