lkml.org 
[lkml]   [2021]   [Dec]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4/6] i2c: exynos5: Add support for ExynosAutoV9 SoC
    Date
    From: Jaewon Kim <jaewon02.kim@samsung.com>

    ExynosAutoV9 functioning logic mostly follows I2C_TYPE_EXYNOS7, but
    timing calculation and configuration procedure is changed: e.g. only
    timing_s3 has to be set now.

    Another change of HSI2C controller in ExynosAutoV9 SoC is that it's now
    a part of USIv2 IP-core. No changes is needed for I2C driver though, as
    all USI related configuration is done in USI driver.

    Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
    Signed-off-by: Sam Protsenko <semen.protsenko@linaro.org>
    ---
    drivers/i2c/busses/i2c-exynos5.c | 62 +++++++++++++++++++++++++++-----
    1 file changed, 53 insertions(+), 9 deletions(-)

    diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c
    index c2e4bab11366..5198e71e8dab 100644
    --- a/drivers/i2c/busses/i2c-exynos5.c
    +++ b/drivers/i2c/busses/i2c-exynos5.c
    @@ -169,6 +169,7 @@
    enum i2c_type_exynos {
    I2C_TYPE_EXYNOS5,
    I2C_TYPE_EXYNOS7,
    + I2C_TYPE_EXYNOSAUTOV9,
    };

    struct exynos5_i2c {
    @@ -230,6 +231,11 @@ static const struct exynos_hsi2c_variant exynos7_hsi2c_data = {
    .hw = I2C_TYPE_EXYNOS7,
    };

    +static const struct exynos_hsi2c_variant exynosautov9_hsi2c_data = {
    + .fifo_depth = 64,
    + .hw = I2C_TYPE_EXYNOSAUTOV9,
    +};
    +
    static const struct of_device_id exynos5_i2c_match[] = {
    {
    .compatible = "samsung,exynos5-hsi2c",
    @@ -243,6 +249,9 @@ static const struct of_device_id exynos5_i2c_match[] = {
    }, {
    .compatible = "samsung,exynos7-hsi2c",
    .data = &exynos7_hsi2c_data
    + }, {
    + .compatible = "samsung,exynosautov9-hsi2c",
    + .data = &exynosautov9_hsi2c_data
    }, {},
    };
    MODULE_DEVICE_TABLE(of, exynos5_i2c_match);
    @@ -281,6 +290,31 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings)
    i2c->op_clock;
    int div, clk_cycle, temp;

    + /*
    + * In case of HSI2C controllers in ExynosAutoV9:
    + *
    + * FSCL = IPCLK / ((CLK_DIV + 1) * 16)
    + * T_SCL_LOW = IPCLK * (CLK_DIV + 1) * (N + M)
    + * [N : number of 0's in the TSCL_H_HS]
    + * [M : number of 0's in the TSCL_L_HS]
    + * T_SCL_HIGH = IPCLK * (CLK_DIV + 1) * (N + M)
    + * [N : number of 1's in the TSCL_H_HS]
    + * [M : number of 1's in the TSCL_L_HS]
    + *
    + * Result of (N + M) is always 8.
    + * In general case, we don't need to control timing_s1 and timing_s2.
    + */
    + if (i2c->variant->hw == I2C_TYPE_EXYNOSAUTOV9) {
    + div = ((clkin / (16 * i2c->op_clock)) - 1);
    + i2c_timing_s3 = div << 16;
    + if (hs_timings)
    + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3);
    + else
    + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3);
    +
    + return 0;
    + }
    +
    /*
    * In case of HSI2C controller in Exynos5 series
    * FPCLK / FI2C =
    @@ -422,7 +456,10 @@ 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 (i2c->variant->hw == I2C_TYPE_EXYNOS7) {
    + switch (i2c->variant->hw) {
    + case I2C_TYPE_EXYNOSAUTOV9:
    + fallthrough;
    + case I2C_TYPE_EXYNOS7:
    if (int_status & HSI2C_INT_TRANS_DONE) {
    i2c->trans_done = 1;
    i2c->state = 0;
    @@ -443,7 +480,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
    i2c->state = -ETIMEDOUT;
    goto stop;
    }
    - } else if (int_status & HSI2C_INT_I2C) {
    +
    + break;
    + case I2C_TYPE_EXYNOS5:
    + if (!(int_status & HSI2C_INT_I2C))
    + break;
    +
    trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
    if (trans_status & HSI2C_NO_DEV_ACK) {
    dev_dbg(i2c->dev, "No ACK from device\n");
    @@ -465,6 +507,8 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
    i2c->trans_done = 1;
    i2c->state = 0;
    }
    +
    + break;
    }

    if ((i2c->msg->flags & I2C_M_RD) && (int_status &
    @@ -569,13 +613,13 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c)
    {
    unsigned long timeout;

    - if (i2c->variant->hw != I2C_TYPE_EXYNOS7)
    + if (i2c->variant->hw == I2C_TYPE_EXYNOS5)
    return;

    /*
    - * HSI2C_MASTER_ST_LOSE state in EXYNOS7 variant before transaction
    - * indicates that bus is stuck (SDA is low). In such case bus recovery
    - * can be performed.
    + * HSI2C_MASTER_ST_LOSE state (in Exynos7 and ExynosAutoV9 variants)
    + * before transaction indicates that bus is stuck (SDA is low).
    + * In such case bus recovery can be performed.
    */
    timeout = jiffies + msecs_to_jiffies(100);
    for (;;) {
    @@ -611,10 +655,10 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop)
    unsigned long flags;
    unsigned short trig_lvl;

    - if (i2c->variant->hw == I2C_TYPE_EXYNOS7)
    - int_en |= HSI2C_INT_I2C_TRANS;
    - else
    + if (i2c->variant->hw == I2C_TYPE_EXYNOS5)
    int_en |= HSI2C_INT_I2C;
    + else
    + int_en |= HSI2C_INT_I2C_TRANS;

    i2c_ctl = readl(i2c->regs + HSI2C_CTL);
    i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON);
    --
    2.30.2
    \
     
     \ /
      Last update: 2021-12-01 20:06    [W:2.147 / U:0.276 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site