diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-omap.c')
-rw-r--r-- | drivers/i2c/busses/i2c-omap.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 498a462c49b7..049331cebb7f 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -176,6 +176,7 @@ enum { | |||
176 | #define I2C_OMAP_ERRATA_I462 (1 << 1) | 176 | #define I2C_OMAP_ERRATA_I462 (1 << 1) |
177 | 177 | ||
178 | struct omap_i2c_dev { | 178 | struct omap_i2c_dev { |
179 | spinlock_t lock; /* IRQ synchronization */ | ||
179 | struct device *dev; | 180 | struct device *dev; |
180 | void __iomem *base; /* virtual */ | 181 | void __iomem *base; /* virtual */ |
181 | int irq; | 182 | int irq; |
@@ -854,9 +855,30 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *dev, u8 num_bytes, | |||
854 | } | 855 | } |
855 | 856 | ||
856 | static irqreturn_t | 857 | static irqreturn_t |
857 | omap_i2c_isr(int this_irq, void *dev_id) | 858 | omap_i2c_isr(int irq, void *dev_id) |
858 | { | 859 | { |
859 | struct omap_i2c_dev *dev = dev_id; | 860 | struct omap_i2c_dev *dev = dev_id; |
861 | irqreturn_t ret = IRQ_HANDLED; | ||
862 | u16 mask; | ||
863 | u16 stat; | ||
864 | |||
865 | spin_lock(&dev->lock); | ||
866 | mask = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); | ||
867 | stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); | ||
868 | |||
869 | if (stat & mask) | ||
870 | ret = IRQ_WAKE_THREAD; | ||
871 | |||
872 | spin_unlock(&dev->lock); | ||
873 | |||
874 | return ret; | ||
875 | } | ||
876 | |||
877 | static irqreturn_t | ||
878 | omap_i2c_isr_thread(int this_irq, void *dev_id) | ||
879 | { | ||
880 | struct omap_i2c_dev *dev = dev_id; | ||
881 | unsigned long flags; | ||
860 | u16 bits; | 882 | u16 bits; |
861 | u16 stat; | 883 | u16 stat; |
862 | int err = 0, count = 0; | 884 | int err = 0, count = 0; |
@@ -864,6 +886,7 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
864 | if (pm_runtime_suspended(dev->dev)) | 886 | if (pm_runtime_suspended(dev->dev)) |
865 | return IRQ_NONE; | 887 | return IRQ_NONE; |
866 | 888 | ||
889 | spin_lock_irqsave(&dev->lock, flags); | ||
867 | do { | 890 | do { |
868 | bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); | 891 | bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG); |
869 | stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); | 892 | stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG); |
@@ -877,6 +900,7 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
877 | 900 | ||
878 | if (!stat) { | 901 | if (!stat) { |
879 | /* my work here is done */ | 902 | /* my work here is done */ |
903 | spin_unlock_irqrestore(&dev->lock, flags); | ||
880 | return IRQ_HANDLED; | 904 | return IRQ_HANDLED; |
881 | } | 905 | } |
882 | 906 | ||
@@ -985,6 +1009,8 @@ omap_i2c_isr(int this_irq, void *dev_id) | |||
985 | 1009 | ||
986 | out: | 1010 | out: |
987 | omap_i2c_complete_cmd(dev, err); | 1011 | omap_i2c_complete_cmd(dev, err); |
1012 | spin_unlock_irqrestore(&dev->lock, flags); | ||
1013 | |||
988 | return IRQ_HANDLED; | 1014 | return IRQ_HANDLED; |
989 | } | 1015 | } |
990 | 1016 | ||
@@ -1028,7 +1054,6 @@ omap_i2c_probe(struct platform_device *pdev) | |||
1028 | struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; | 1054 | struct omap_i2c_bus_platform_data *pdata = pdev->dev.platform_data; |
1029 | struct device_node *node = pdev->dev.of_node; | 1055 | struct device_node *node = pdev->dev.of_node; |
1030 | const struct of_device_id *match; | 1056 | const struct of_device_id *match; |
1031 | irq_handler_t isr; | ||
1032 | int irq; | 1057 | int irq; |
1033 | int r; | 1058 | int r; |
1034 | 1059 | ||
@@ -1078,6 +1103,8 @@ omap_i2c_probe(struct platform_device *pdev) | |||
1078 | dev->dev = &pdev->dev; | 1103 | dev->dev = &pdev->dev; |
1079 | dev->irq = irq; | 1104 | dev->irq = irq; |
1080 | 1105 | ||
1106 | spin_lock_init(&dev->lock); | ||
1107 | |||
1081 | platform_set_drvdata(pdev, dev); | 1108 | platform_set_drvdata(pdev, dev); |
1082 | init_completion(&dev->cmd_complete); | 1109 | init_completion(&dev->cmd_complete); |
1083 | 1110 | ||
@@ -1130,10 +1157,14 @@ omap_i2c_probe(struct platform_device *pdev) | |||
1130 | /* reset ASAP, clearing any IRQs */ | 1157 | /* reset ASAP, clearing any IRQs */ |
1131 | omap_i2c_init(dev); | 1158 | omap_i2c_init(dev); |
1132 | 1159 | ||
1133 | isr = (dev->rev < OMAP_I2C_OMAP1_REV_2) ? omap_i2c_omap1_isr : | 1160 | if (dev->rev < OMAP_I2C_OMAP1_REV_2) |
1134 | omap_i2c_isr; | 1161 | r = devm_request_irq(&pdev->dev, dev->irq, omap_i2c_omap1_isr, |
1135 | r = devm_request_irq(&pdev->dev, dev->irq, isr, IRQF_NO_SUSPEND, | 1162 | IRQF_NO_SUSPEND, pdev->name, dev); |
1136 | pdev->name, dev); | 1163 | else |
1164 | r = devm_request_threaded_irq(&pdev->dev, dev->irq, | ||
1165 | omap_i2c_isr, omap_i2c_isr_thread, | ||
1166 | IRQF_NO_SUSPEND | IRQF_ONESHOT, | ||
1167 | pdev->name, dev); | ||
1137 | 1168 | ||
1138 | if (r) { | 1169 | if (r) { |
1139 | dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); | 1170 | dev_err(dev->dev, "failure requesting irq %i\n", dev->irq); |