|
@@ -86,6 +86,7 @@
|
|
|
#define QUIRK_S3C2440 (1 << 0)
|
|
|
#define QUIRK_HDMIPHY (1 << 1)
|
|
|
#define QUIRK_NO_GPIO (1 << 2)
|
|
|
+#define QUIRK_POLL (1 << 3)
|
|
|
|
|
|
/* Max time to wait for bus to become idle after a xfer (in us) */
|
|
|
#define S3C2410_IDLE_TIMEOUT 5000
|
|
@@ -142,6 +143,8 @@ static struct platform_device_id s3c24xx_driver_ids[] = {
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids);
|
|
|
|
|
|
+static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat);
|
|
|
+
|
|
|
#ifdef CONFIG_OF
|
|
|
static const struct of_device_id s3c24xx_i2c_match[] = {
|
|
|
{ .compatible = "samsung,s3c2410-i2c", .data = (void *)0 },
|
|
@@ -150,6 +153,8 @@ static const struct of_device_id s3c24xx_i2c_match[] = {
|
|
|
.data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) },
|
|
|
{ .compatible = "samsung,exynos5440-i2c",
|
|
|
.data = (void *)(QUIRK_S3C2440 | QUIRK_NO_GPIO) },
|
|
|
+ { .compatible = "samsung,exynos5-sata-phy-i2c",
|
|
|
+ .data = (void *)(QUIRK_S3C2440 | QUIRK_POLL | QUIRK_NO_GPIO) },
|
|
|
{},
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(of, s3c24xx_i2c_match);
|
|
@@ -188,7 +193,8 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret)
|
|
|
if (ret)
|
|
|
i2c->msg_idx = ret;
|
|
|
|
|
|
- wake_up(&i2c->wait);
|
|
|
+ if (!(i2c->quirks & QUIRK_POLL))
|
|
|
+ wake_up(&i2c->wait);
|
|
|
}
|
|
|
|
|
|
static inline void s3c24xx_i2c_disable_ack(struct s3c24xx_i2c *i2c)
|
|
@@ -225,6 +231,22 @@ static inline void s3c24xx_i2c_enable_irq(struct s3c24xx_i2c *i2c)
|
|
|
writel(tmp | S3C2410_IICCON_IRQEN, i2c->regs + S3C2410_IICCON);
|
|
|
}
|
|
|
|
|
|
+static bool is_ack(struct s3c24xx_i2c *i2c)
|
|
|
+{
|
|
|
+ int tries;
|
|
|
+
|
|
|
+ for (tries = 50; tries; --tries) {
|
|
|
+ if (readl(i2c->regs + S3C2410_IICCON)
|
|
|
+ & S3C2410_IICCON_IRQPEND) {
|
|
|
+ if (!(readl(i2c->regs + S3C2410_IICSTAT)
|
|
|
+ & S3C2410_IICSTAT_LASTBIT))
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ usleep_range(1000, 2000);
|
|
|
+ }
|
|
|
+ dev_err(i2c->dev, "ack was not recieved\n");
|
|
|
+ return false;
|
|
|
+}
|
|
|
|
|
|
/* s3c24xx_i2c_message_start
|
|
|
*
|
|
@@ -269,6 +291,16 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c,
|
|
|
|
|
|
stat |= S3C2410_IICSTAT_START;
|
|
|
writel(stat, i2c->regs + S3C2410_IICSTAT);
|
|
|
+
|
|
|
+ if (i2c->quirks & QUIRK_POLL) {
|
|
|
+ while ((i2c->msg_num != 0) && is_ack(i2c)) {
|
|
|
+ i2c_s3c_irq_nextbyte(i2c, stat);
|
|
|
+ stat = readl(i2c->regs + S3C2410_IICSTAT);
|
|
|
+
|
|
|
+ if (stat & S3C2410_IICSTAT_ARBITR)
|
|
|
+ dev_err(i2c->dev, "deal with arbitration loss\n");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret)
|
|
@@ -676,6 +708,15 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
|
|
|
s3c24xx_i2c_enable_irq(i2c);
|
|
|
s3c24xx_i2c_message_start(i2c, msgs);
|
|
|
|
|
|
+ if (i2c->quirks & QUIRK_POLL) {
|
|
|
+ ret = i2c->msg_idx;
|
|
|
+
|
|
|
+ if (ret != num)
|
|
|
+ dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret);
|
|
|
+
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5);
|
|
|
|
|
|
ret = i2c->msg_idx;
|
|
@@ -821,6 +862,9 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got)
|
|
|
if (div1 == 512)
|
|
|
iiccon |= S3C2410_IICCON_TXDIV_512;
|
|
|
|
|
|
+ if (i2c->quirks & QUIRK_POLL)
|
|
|
+ iiccon |= S3C2410_IICCON_SCALE(2);
|
|
|
+
|
|
|
writel(iiccon, i2c->regs + S3C2410_IICCON);
|
|
|
|
|
|
if (i2c->quirks & QUIRK_S3C2440) {
|
|
@@ -1118,18 +1162,20 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
|
|
|
* ensure no current IRQs pending
|
|
|
*/
|
|
|
|
|
|
- i2c->irq = ret = platform_get_irq(pdev, 0);
|
|
|
- if (ret <= 0) {
|
|
|
- dev_err(&pdev->dev, "cannot find IRQ\n");
|
|
|
- return ret;
|
|
|
- }
|
|
|
+ if (!(i2c->quirks & QUIRK_POLL)) {
|
|
|
+ i2c->irq = ret = platform_get_irq(pdev, 0);
|
|
|
+ if (ret <= 0) {
|
|
|
+ dev_err(&pdev->dev, "cannot find IRQ\n");
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
|
|
|
ret = devm_request_irq(&pdev->dev, i2c->irq, s3c24xx_i2c_irq, 0,
|
|
|
- dev_name(&pdev->dev), i2c);
|
|
|
+ dev_name(&pdev->dev), i2c);
|
|
|
|
|
|
- if (ret != 0) {
|
|
|
- dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
|
|
|
- return ret;
|
|
|
+ if (ret != 0) {
|
|
|
+ dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
ret = s3c24xx_i2c_register_cpufreq(i2c);
|