Merge tag 'driver-core-3.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / i2c / busses / i2c-s3c2410.c
index fd4fd0c4ef21ae1f32f0124050a7fca470408c1d..bff20a589621a031b37d1d1a661e4d5ba8e291b7 100644 (file)
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
 
 #include <linux/kernel.h>
@@ -39,6 +35,8 @@
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/pinctrl/consumer.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #include <asm/irq.h>
 
@@ -91,6 +89,9 @@
 /* Max time to wait for bus to become idle after a xfer (in us) */
 #define S3C2410_IDLE_TIMEOUT   5000
 
+/* Exynos5 Sysreg offset */
+#define EXYNOS5_SYS_I2C_CFG    0x0234
+
 /* i2c controller state */
 enum s3c24xx_i2c_state {
        STATE_IDLE,
@@ -127,6 +128,8 @@ struct s3c24xx_i2c {
 #if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
        struct notifier_block   freq_transition;
 #endif
+       struct regmap           *sysreg;
+       unsigned int            sys_i2c_cfg;
 };
 
 static struct platform_device_id s3c24xx_driver_ids[] = {
@@ -1075,6 +1078,7 @@ static void
 s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
 {
        struct s3c2410_platform_i2c *pdata = i2c->pdata;
+       int id;
 
        if (!np)
                return;
@@ -1084,6 +1088,21 @@ s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
        of_property_read_u32(np, "samsung,i2c-slave-addr", &pdata->slave_addr);
        of_property_read_u32(np, "samsung,i2c-max-bus-freq",
                                (u32 *)&pdata->frequency);
+       /*
+        * Exynos5's legacy i2c controller and new high speed i2c
+        * controller have muxed interrupt sources. By default the
+        * interrupts for 4-channel HS-I2C controller are enabled.
+        * If nodes for first four channels of legacy i2c controller
+        * are available then re-configure the interrupts via the
+        * system register.
+        */
+       id = of_alias_get_id(np, "i2c");
+       i2c->sysreg = syscon_regmap_lookup_by_phandle(np,
+                       "samsung,sysreg-phandle");
+       if (IS_ERR(i2c->sysreg))
+               return;
+
+       regmap_update_bits(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, BIT(id), 0);
 }
 #else
 static void
@@ -1264,6 +1283,9 @@ static int s3c24xx_i2c_suspend_noirq(struct device *dev)
 
        i2c->suspended = 1;
 
+       if (!IS_ERR(i2c->sysreg))
+               regmap_read(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, &i2c->sys_i2c_cfg);
+
        return 0;
 }
 
@@ -1272,6 +1294,9 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
        struct platform_device *pdev = to_platform_device(dev);
        struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
 
+       if (!IS_ERR(i2c->sysreg))
+               regmap_write(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, i2c->sys_i2c_cfg);
+
        clk_prepare_enable(i2c->clk);
        s3c24xx_i2c_init(i2c);
        clk_disable_unprepare(i2c->clk);