forked from Minki/linux
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: Naveen Krishna Chatradhi <ch.naveen@samsung.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
030f940a53
commit
2374a5399b
@ -12,6 +12,8 @@ Required properties:
|
||||
on Exynos5250 and Exynos5420 SoCs.
|
||||
-> "samsung,exynos5260-hsi2c", for i2c compatible with HSI2C available
|
||||
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
|
||||
region.
|
||||
|
@ -465,7 +465,7 @@ config I2C_EG20T
|
||||
|
||||
config I2C_EXYNOS5
|
||||
tristate "Exynos5 high-speed I2C driver"
|
||||
depends on ARCH_EXYNOS5 && OF
|
||||
depends on ARCH_EXYNOS && OF
|
||||
default y
|
||||
help
|
||||
High-speed I2C controller on Exynos5 based Samsung SoCs.
|
||||
|
@ -83,7 +83,6 @@
|
||||
#define HSI2C_INT_TX_ALMOSTEMPTY_EN (1u << 0)
|
||||
#define HSI2C_INT_RX_ALMOSTFULL_EN (1u << 1)
|
||||
#define HSI2C_INT_TRAILING_EN (1u << 6)
|
||||
#define HSI2C_INT_I2C_EN (1u << 9)
|
||||
|
||||
/* I2C_INT_STAT Register bits */
|
||||
#define HSI2C_INT_TX_ALMOSTEMPTY (1u << 0)
|
||||
@ -95,6 +94,17 @@
|
||||
#define HSI2C_INT_TRAILING (1u << 6)
|
||||
#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 */
|
||||
#define HSI2C_RX_FIFO_EMPTY (1u << 24)
|
||||
#define HSI2C_RX_FIFO_FULL (1u << 23)
|
||||
@ -143,6 +153,8 @@
|
||||
|
||||
#define EXYNOS5_I2C_TIMEOUT (msecs_to_jiffies(1000))
|
||||
|
||||
#define HSI2C_EXYNOS7 BIT(0)
|
||||
|
||||
struct exynos5_i2c {
|
||||
struct i2c_adapter adap;
|
||||
unsigned int suspended:1;
|
||||
@ -192,6 +204,7 @@ struct exynos5_i2c {
|
||||
*/
|
||||
struct exynos_hsi2c_variant {
|
||||
unsigned int fifo_depth;
|
||||
unsigned int hw;
|
||||
};
|
||||
|
||||
static const struct exynos_hsi2c_variant exynos5250_hsi2c_data = {
|
||||
@ -202,6 +215,11 @@ static const struct exynos_hsi2c_variant exynos5260_hsi2c_data = {
|
||||
.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[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5-hsi2c",
|
||||
@ -212,6 +230,9 @@ static const struct of_device_id exynos5_i2c_match[] = {
|
||||
}, {
|
||||
.compatible = "samsung,exynos5260-hsi2c",
|
||||
.data = &exynos5260_hsi2c_data
|
||||
}, {
|
||||
.compatible = "samsung,exynos7-hsi2c",
|
||||
.data = &exynos7_hsi2c_data
|
||||
}, {},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
|
||||
@ -256,13 +277,24 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, int mode)
|
||||
i2c->hs_clock : i2c->fs_clock;
|
||||
|
||||
/*
|
||||
* In case of HSI2C controller in Exynos5 series
|
||||
* FPCLK / FI2C =
|
||||
* (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)
|
||||
* utemp1 = (TSCLK_L + TSCLK_H + 2)
|
||||
*/
|
||||
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 */
|
||||
for (div = 0; div < 256; div++) {
|
||||
@ -407,7 +439,28 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
|
||||
writel(int_status, i2c->regs + HSI2C_INT_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);
|
||||
if (trans_status & HSI2C_NO_DEV_ACK) {
|
||||
dev_dbg(i2c->dev, "No ACK from device\n");
|
||||
@ -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)
|
||||
{
|
||||
u32 i2c_ctl;
|
||||
u32 int_en = HSI2C_INT_I2C_EN;
|
||||
u32 int_en = 0;
|
||||
u32 i2c_auto_conf = 0;
|
||||
u32 fifo_ctl;
|
||||
unsigned long flags;
|
||||
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 &= ~(HSI2C_TXCHON | HSI2C_RXCHON);
|
||||
fifo_ctl = HSI2C_RXFIFO_EN | HSI2C_TXFIFO_EN;
|
||||
@ -724,12 +782,13 @@ static int exynos5_i2c_probe(struct platform_device *pdev)
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
/* Need to check the variant before setting up. */
|
||||
i2c->variant = exynos5_i2c_get_variant(pdev);
|
||||
|
||||
ret = exynos5_hsi2c_clock_setup(i2c);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
i2c->variant = exynos5_i2c_get_variant(pdev);
|
||||
|
||||
exynos5_i2c_reset(i2c);
|
||||
|
||||
ret = i2c_add_adapter(&i2c->adap);
|
||||
|
Loading…
Reference in New Issue
Block a user