@@ -3,6 +3,7 @@ SAMSUNG S5P/Exynos SoC series System Registers (SYSREG)
Properties:
- compatible : should contain "samsung,<chip name>-sysreg", "syscon";
For Exynos4 SoC series it should be "samsung,exynos4-sysreg", "syscon";
+ For Exynos5 SoC series it should be "samsung,exynos5-sysreg", "syscon";
- reg : offset and length of the register set.
Example:
@@ -99,4 +99,9 @@
#size-cells = <0>;
status = "disabled";
};
+
+ sys_reg: syscon@10050000 {
+ compatible = "samsung,exynos5-sysreg", "syscon";
+ reg = <0x10050000 0x400>;
+ };
};
@@ -285,6 +285,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c0_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -298,6 +299,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c1_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -311,6 +313,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c2_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -324,6 +327,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c3_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -517,6 +517,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c0_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -530,6 +531,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c1_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -543,6 +545,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c2_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -556,6 +559,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c3_bus>;
+ samsung,syscon-phandle = <&sys_reg>;
status = "disabled";
};
@@ -39,6 +39,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 +93,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 +132,8 @@ struct s3c24xx_i2c {
#if defined(CONFIG_ARM_S3C24XX_CPUFREQ)
struct notifier_block freq_transition;
#endif
+ struct regmap *sysreg;
+ unsigned int sys_i2s_cfg;
};
static struct platform_device_id s3c24xx_driver_ids[] = {
@@ -1075,6 +1082,8 @@ static void
s3c24xx_i2c_parse_dt(struct device_node *np, struct s3c24xx_i2c *i2c)
{
struct s3c2410_platform_i2c *pdata = i2c->pdata;
+ u32 val = 0;
+ int id;
if (!np)
return;
@@ -1084,6 +1093,23 @@ 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 node 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,syscon-phandle");
+ if (IS_ERR(i2c->sysreg)) {
+ /* As this is not compulsory do not return error */
+ pr_info("i2c-%d skipping re-configuration of interrutps\n", id);
+ return;
+ }
+ regmap_update_bits(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, BIT(id), val);
}
#else
static void
@@ -1268,6 +1294,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_i2s_cfg);
+
return 0;
}
@@ -1276,6 +1305,9 @@ static int s3c24xx_i2c_resume(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, i2c->sys_i2s_cfg, EXYNOS5_SYS_I2C_CFG);
+
i2c->suspended = 0;
clk_prepare_enable(i2c->clk);
s3c24xx_i2c_init(i2c);