Commit 2374a539 authored by Naveen Krishna Ch's avatar Naveen Krishna Ch Committed by Wolfram Sang

i2c: exynos: add support for HSI2C module on Exynos7

The HSI2C module on Exynos7 differs in the transfer status
bits. Transfer status bits were moved to INT_ENABLE and
INT_STATUS registers

This patch adds support for the HSI2C module on Exynos7.
1. Implementes a "hw" field in the variant struct to distinguish
   the hardware.
2. Updates the dt-new compatible in dt-binding documenation
Signed-off-by: default avatarNaveen Krishna Chatradhi <ch.naveen@samsung.com>
Signed-off-by: default avatarWolfram Sang <wsa@the-dreams.de>
parent 030f940a
...@@ -12,6 +12,8 @@ Required properties: ...@@ -12,6 +12,8 @@ Required properties:
on Exynos5250 and Exynos5420 SoCs. on Exynos5250 and Exynos5420 SoCs.
-> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available -> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available
on Exynos5260 SoCs. on Exynos5260 SoCs.
-> "samsung,exynos7-hsi2c", for i2c compatible with HSI2C available
on Exynos7 SoCs.
- reg: physical base address of the controller and length of memory mapped - reg: physical base address of the controller and length of memory mapped
region. region.
......
...@@ -465,7 +465,7 @@ config I2C_EG20T ...@@ -465,7 +465,7 @@ config I2C_EG20T
config I2C_EXYNOS5 config I2C_EXYNOS5
tristate "Exynos5 high-speed I2C driver" tristate "Exynos5 high-speed I2C driver"
depends on ARCH_EXYNOS5 && OF depends on ARCH_EXYNOS && OF
default y default y
help help
High-speed I2C controller on Exynos5 based Samsung SoCs. High-speed I2C controller on Exynos5 based Samsung SoCs.
......
...@@ -83,7 +83,6 @@ ...@@ -83,7 +83,6 @@
#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0) #define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0)
#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1) #define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1)
#define HSI2C_INT_TRAILING_EN (1u << 6) #define HSI2C_INT_TRAILING_EN (1u << 6)
#define HSI2C_INT_I2C_EN (1u << 9)
/* I2C_INT_STAT Register bits */ /* I2C_INT_STAT Register bits */
#define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0) #define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0)
...@@ -95,6 +94,17 @@ ...@@ -95,6 +94,17 @@
#define HSI2C_INT_TRAILING (1u << 6) #define HSI2C_INT_TRAILING (1u << 6)
#define HSI2C_INT_I2C (1u << 9) #define HSI2C_INT_I2C (1u << 9)
#define HSI2C_INT_TRANS_DONE (1u << 7)
#define HSI2C_INT_TRANS_ABORT (1u << 8)
#define HSI2C_INT_NO_DEV_ACK (1u << 9)
#define HSI2C_INT_NO_DEV (1u << 10)
#define HSI2C_INT_TIMEOUT (1u << 11)
#define HSI2C_INT_I2C_TRANS (HSI2C_INT_TRANS_DONE | \
HSI2C_INT_TRANS_ABORT | \
HSI2C_INT_NO_DEV_ACK | \
HSI2C_INT_NO_DEV | \
HSI2C_INT_TIMEOUT)
/* I2C_FIFO_STAT Register bits */ /* I2C_FIFO_STAT Register bits */
#define HSI2C_RX_FIFO_EMPTY (1u << 24) #define HSI2C_RX_FIFO_EMPTY (1u << 24)
#define HSI2C_RX_FIFO_FULL (1u << 23) #define HSI2C_RX_FIFO_FULL (1u << 23)
...@@ -143,6 +153,8 @@ ...@@ -143,6 +153,8 @@
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000)) #define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
#define HSI2C_EXYNOS7 BIT(0)
struct exynos5_i2c { struct exynos5_i2c {
struct i2c_adapter adap; struct i2c_adapter adap;
unsigned int suspended:1; unsigned int suspended:1;
...@@ -192,6 +204,7 @@ struct exynos5_i2c { ...@@ -192,6 +204,7 @@ struct exynos5_i2c {
*/ */
struct exynos_hsi2c_variant { struct exynos_hsi2c_variant {
unsigned int fifo_depth; unsigned int fifo_depth;
unsigned int hw;
}; };
static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = { static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {
...@@ -202,6 +215,11 @@ static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = { ...@@ -202,6 +215,11 @@ static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {
.fifo_depth = 16, .fifo_depth = 16,
}; };
static const struct exynos_hsi2c_variant exynos7_hsi2c_data = {
.fifo_depth = 16,
.hw = HSI2C_EXYNOS7,
};
static const struct of_device_id exynos5_i2c_match[] = { static const struct of_device_id exynos5_i2c_match[] = {
{ {
.compatible = "samsung,exynos5-hsi2c", .compatible = "samsung,exynos5-hsi2c",
...@@ -212,6 +230,9 @@ static const struct of_device_id exynos5_i2c_match[] = { ...@@ -212,6 +230,9 @@ static const struct of_device_id exynos5_i2c_match[] = {
}, { }, {
.compatible = "samsung,exynos5260-hsi2c", .compatible = "samsung,exynos5260-hsi2c",
.data = &exynos5260_hsi2c_data .data = &exynos5260_hsi2c_data
}, {
.compatible = "samsung,exynos7-hsi2c",
.data = &exynos7_hsi2c_data
}, {}, }, {},
}; };
MODULE_DEVICE_TABLE(of, exynos5_i2c_match); MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
...@@ -256,13 +277,24 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode) ...@@ -256,13 +277,24 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
i2c->hs_clock : i2c->fs_clock; i2c->hs_clock : i2c->fs_clock;
/* /*
* In case of HSI2C controller in Exynos5 series
* FPCLK / FI2C = * FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE
*
* In case of HSI2C controllers in Exynos7 series
* FPCLK / FI2C =
* (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + FLT_CYCLE
*
* utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) * utemp0 = (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2)
* utemp1 = (TSCLK_L + TSCLK_H + 2) * utemp1 = (TSCLK_L + TSCLK_H + 2)
*/ */
t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7;
utemp0 = (clkin / op_clk) - 8 - 2 * t_ftl_cycle; utemp0 = (clkin / op_clk) - 8;
if (i2c->variant->hw == HSI2C_EXYNOS7)
utemp0 -= t_ftl_cycle;
else
utemp0 -= 2 * t_ftl_cycle;
/* CLK_DIV max is 256 */ /* CLK_DIV max is 256 */
for (div = 0; div < 256; div++) { for (div = 0; div < 256; div++) {
...@@ -407,7 +439,28 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -407,7 +439,28 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
writel(int_status, i2c->regs + HSI2C_INT_STATUS); writel(int_status, i2c->regs + HSI2C_INT_STATUS);
/* handle interrupt related to the transfer status */ /* handle interrupt related to the transfer status */
if (int_status & HSI2C_INT_I2C) { if (i2c->variant->hw == HSI2C_EXYNOS7) {
if (int_status & HSI2C_INT_TRANS_DONE) {
i2c->trans_done = 1;
i2c->state = 0;
} else if (int_status & HSI2C_INT_TRANS_ABORT) {
dev_dbg(i2c->dev, "Deal with arbitration lose\n");
i2c->state = -EAGAIN;
goto stop;
} else if (int_status & HSI2C_INT_NO_DEV_ACK) {
dev_dbg(i2c->dev, "No ACK from device\n");
i2c->state = -ENXIO;
goto stop;
} else if (int_status & HSI2C_INT_NO_DEV) {
dev_dbg(i2c->dev, "No device\n");
i2c->state = -ENXIO;
goto stop;
} else if (int_status & HSI2C_INT_TIMEOUT) {
dev_dbg(i2c->dev, "Accessing device timed out\n");
i2c->state = -EAGAIN;
goto stop;
}
} else if (int_status & HSI2C_INT_I2C) {
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
if (trans_status & HSI2C_NO_DEV_ACK) { if (trans_status & HSI2C_NO_DEV_ACK) {
dev_dbg(i2c->dev, "No ACK from device\n"); dev_dbg(i2c->dev, "No ACK from device\n");
...@@ -512,12 +565,17 @@ static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c) ...@@ -512,12 +565,17 @@ static int exynos5_i2c_wait_bus_idle(struct exynos5_i2c *i2c)
static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
{ {
u32 i2c_ctl; u32 i2c_ctl;
u32 int_en = HSI2C_INT_I2C_EN; u32 int_en = 0;
u32 i2c_auto_conf = 0; u32 i2c_auto_conf = 0;
u32 fifo_ctl; u32 fifo_ctl;
unsigned long flags; unsigned long flags;
unsigned short trig_lvl; unsigned short trig_lvl;
if (i2c->variant->hw == HSI2C_EXYNOS7)
int_en |= HSI2C_INT_I2C_TRANS;
else
int_en |= HSI2C_INT_I2C;
i2c_ctl = readl(i2c->regs + HSI2C_CTL); i2c_ctl = readl(i2c->regs + HSI2C_CTL);
i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON);
fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN; fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN;
...@@ -724,12 +782,13 @@ static int exynos5_i2c_probe(struct platform_device *pdev) ...@@ -724,12 +782,13 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
goto err_clk; goto err_clk;
} }
/* Need to check the variant before setting up. */
i2c->variant = exynos5_i2c_get_variant(pdev);
ret = exynos5_hsi2c_clock_setup(i2c); ret = exynos5_hsi2c_clock_setup(i2c);
if (ret) if (ret)
goto err_clk; goto err_clk;
i2c->variant = exynos5_i2c_get_variant(pdev);
exynos5_i2c_reset(i2c); exynos5_i2c_reset(i2c);
ret = i2c_add_adapter(&i2c->adap); ret = i2c_add_adapter(&i2c->adap);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment