[PATCH 1/2] lib: utils/i2c: Add minimal StarFive jh7110 I2C driver

Minda Chen minda.chen at starfivetech.com
Sun Mar 5 17:07:34 PST 2023



On 2023/3/3 20:21, Anup Patel wrote:
> On Fri, Feb 24, 2023 at 3:28 PM Minda Chen <minda.chen at starfivetech.com> wrote:
>>
>> Starfive JH7110 I2C IP is synopsys designware.
>> Minimum StarFIve I2C driver to read/send bytes over I2C bus.
>>
>> This allows querying information and perform operation of onboard PMIC,
>> as well as power-off and reset.
>>
>> Signed-off-by: Minda Chen <minda.chen at starfivetech.com>
>> ---
>>  include/sbi_utils/i2c/dw_i2c.h   |  21 ++++
>>  lib/utils/i2c/Kconfig            |   8 ++
>>  lib/utils/i2c/dw_i2c.c           | 190 +++++++++++++++++++++++++++++++
>>  lib/utils/i2c/fdt_i2c_starfive.c |  63 ++++++++++
>>  lib/utils/i2c/objects.mk         |   5 +
>>  5 files changed, 287 insertions(+)
>>  create mode 100644 include/sbi_utils/i2c/dw_i2c.h
>>  create mode 100644 lib/utils/i2c/dw_i2c.c
>>  create mode 100644 lib/utils/i2c/fdt_i2c_starfive.c
>>
>> diff --git a/include/sbi_utils/i2c/dw_i2c.h b/include/sbi_utils/i2c/dw_i2c.h
>> new file mode 100644
>> index 0000000..88703e0
>> --- /dev/null
>> +++ b/include/sbi_utils/i2c/dw_i2c.h
>> @@ -0,0 +1,21 @@
>> +/*
>> + * SPDX-License-Identifier: BSD-2-Clause
>> + *
>> + * Copyright (c) 2022 StarFive Technology Co., Ltd.
>> + *
>> + * Author: Minda Chen <minda.chen at starfivetech.com>
>> + */
>> +
>> +#ifndef __DW_I2C_H__
>> +#define __DW_I2C_H__
>> +
>> +#include <sbi_utils/i2c/i2c.h>
>> +
>> +int dw_i2c_init(struct i2c_adapter *, int nodeoff);
>> +
>> +struct dw_i2c_adapter {
>> +       unsigned long addr;
>> +       struct i2c_adapter adapter;
>> +};
>> +
>> +#endif
>> diff --git a/lib/utils/i2c/Kconfig b/lib/utils/i2c/Kconfig
>> index 46a3454..0bc6a58 100644
>> --- a/lib/utils/i2c/Kconfig
>> +++ b/lib/utils/i2c/Kconfig
>> @@ -14,8 +14,16 @@ config FDT_I2C_SIFIVE
>>         bool "SiFive I2C FDT driver"
>>         default n
>>
>> +config FDT_I2C_STARFIVE
> 
> s/FDT_I2C_STARFIVE/FDT_I2C_DW
> 
>> +       bool "STARFIVE I2C FDT driver"
> 
ok, thanks
> s/STARFIVE I2C FDT driver/Designware I2C FDT driver/
> 
>> +       select I2C_DW
>> +       default n
>>  endif
>>
>> +config I2C_DW
>> +       bool "Synopsys Designware I2C support"
>> +       default n
>> +
>>  config I2C
>>         bool "I2C support"
>>         default n
>> diff --git a/lib/utils/i2c/dw_i2c.c b/lib/utils/i2c/dw_i2c.c
>> new file mode 100644
>> index 0000000..e2ffc71
>> --- /dev/null
>> +++ b/lib/utils/i2c/dw_i2c.c
>> @@ -0,0 +1,190 @@
>> +/*
>> + * SPDX-License-Identifier: BSD-2-Clause
>> + *
>> + * Copyright (c) 2022 starfivetech.com
>> + *
>> + * Authors:
>> + *   Minda Chen <minda.chen at starfivetech.com>
>> + */
>> +
>> +#include <sbi/riscv_io.h>
>> +#include <sbi/sbi_error.h>
>> +#include <sbi/sbi_timer.h>
>> +#include <sbi/sbi_console.h>
>> +#include <sbi/sbi_string.h>
>> +#include <sbi/sbi_bitops.h>
>> +#include <sbi_utils/i2c/dw_i2c.h>
>> +
>> +#define DW_IC_CON              0x00
>> +#define DW_IC_TAR              0x04
>> +#define DW_IC_SAR              0x08
>> +#define DW_IC_DATA_CMD         0x10
>> +#define DW_IC_SS_SCL_HCNT      0x14
>> +#define DW_IC_SS_SCL_LCNT      0x18
>> +#define DW_IC_FS_SCL_HCNT      0x1c
>> +#define DW_IC_FS_SCL_LCNT      0x20
>> +#define DW_IC_HS_SCL_HCNT      0x24
>> +#define DW_IC_HS_SCL_LCNT      0x28
>> +#define DW_IC_INTR_STAT                0x2c
>> +#define DW_IC_INTR_MASK                0x30
>> +#define DW_IC_RAW_INTR_STAT    0x34
>> +#define DW_IC_RX_TL            0x38
>> +#define DW_IC_TX_TL            0x3c
>> +#define DW_IC_CLR_INTR         0x40
>> +#define DW_IC_CLR_RX_UNDER     0x44
>> +#define DW_IC_CLR_RX_OVER      0x48
>> +#define DW_IC_CLR_TX_OVER      0x4c
>> +#define DW_IC_CLR_RD_REQ       0x50
>> +#define DW_IC_CLR_TX_ABRT      0x54
>> +#define DW_IC_CLR_RX_DONE      0x58
>> +#define DW_IC_CLR_ACTIVITY     0x5c
>> +#define DW_IC_CLR_STOP_DET     0x60
>> +#define DW_IC_CLR_START_DET    0x64
>> +#define DW_IC_CLR_GEN_CALL     0x68
>> +#define DW_IC_ENABLE           0x6c
>> +#define DW_IC_STATUS           0x70
>> +#define DW_IC_TXFLR            0x74
>> +#define DW_IC_RXFLR            0x78
>> +#define DW_IC_SDA_HOLD         0x7c
>> +#define DW_IC_TX_ABRT_SOURCE   0x80
>> +#define DW_IC_ENABLE_STATUS    0x9c
>> +#define DW_IC_CLR_RESTART_DET  0xa8
>> +#define DW_IC_COMP_PARAM_1     0xf4
>> +#define DW_IC_COMP_VERSION     0xf8
>> +
>> +#define DW_I2C_STATUS_TXFIFO_EMPTY     BIT(2)
>> +#define DW_I2C_STATUS_RXFIFO_NOT_EMPTY BIT(3)
>> +
>> +#define IC_DATA_CMD_READ       BIT(8)
>> +#define IC_DATA_CMD_STOP       BIT(9)
>> +#define IC_DATA_CMD_RESTART    BIT(10)
>> +#define IC_INT_STATUS_STOPDET  BIT(9)
>> +
>> +static inline void dw_i2c_setreg(struct dw_i2c_adapter *adap,
>> +                                u8 reg, u32 value)
>> +{
>> +       writel(value, (void *)adap->addr + reg);
>> +}
>> +
>> +static inline u32 dw_i2c_getreg(struct dw_i2c_adapter *adap,
>> +                               u32 reg)
>> +{
>> +       return readl((void *)adap->addr + reg);
>> +}
>> +
>> +static int dw_i2c_adapter_poll(struct dw_i2c_adapter *adap,
>> +                              u32 mask, u32 addr,
>> +                              bool inverted)
>> +{
>> +       unsigned int timeout = 10; /* msec */
>> +       int count = 0;
>> +       u32 val;
>> +
>> +       do {
>> +               val = dw_i2c_getreg(adap, addr);
>> +               if (inverted) {
>> +                       if (!(val & mask))
>> +                               return 0;
>> +               } else {
>> +                       if (val & mask)
>> +                               return 0;
>> +               }
>> +               sbi_timer_udelay(2);
>> +               count += 1;
>> +               if (count == (timeout * 1000))
>> +                       return SBI_ETIMEDOUT;
>> +       } while (1);
>> +}
>> +
>> +#define dw_i2c_adapter_poll_rxrdy(adap)        \
>> +       dw_i2c_adapter_poll(adap, DW_I2C_STATUS_RXFIFO_NOT_EMPTY, DW_IC_STATUS, 0)
>> +#define dw_i2c_adapter_poll_txfifo_ready(adap) \
>> +       dw_i2c_adapter_poll(adap, DW_I2C_STATUS_TXFIFO_EMPTY, DW_IC_STATUS, 0)
>> +
>> +static int dw_i2c_write_addr(struct dw_i2c_adapter *adap, u8 addr)
>> +{
>> +       dw_i2c_setreg(adap, DW_IC_ENABLE, 0);
>> +       dw_i2c_setreg(adap, DW_IC_TAR, addr);
>> +       dw_i2c_setreg(adap, DW_IC_ENABLE, 1);
>> +
>> +       return 0;
>> +}
>> +
>> +static int dw_i2c_adapter_read(struct i2c_adapter *ia, u8 addr,
>> +                              u8 reg, u8 *buffer, int len)
>> +{
>> +       struct dw_i2c_adapter *adap =
>> +               container_of(ia, struct dw_i2c_adapter, adapter);
>> +       int rc;
>> +
>> +       dw_i2c_write_addr(adap, addr);
>> +
>> +       rc = dw_i2c_adapter_poll_txfifo_ready(adap);
>> +       if (rc)
>> +               return rc;
>> +
>> +       /* set register address */
>> +       dw_i2c_setreg(adap, DW_IC_DATA_CMD, reg);
>> +
>> +       /* set value */
>> +       while (len) {
>> +               if (len == 1)
>> +                       dw_i2c_setreg(adap, DW_IC_DATA_CMD,
>> +                                     IC_DATA_CMD_READ | IC_DATA_CMD_STOP);
>> +               else
>> +                       dw_i2c_setreg(adap, DW_IC_DATA_CMD, IC_DATA_CMD_READ);
>> +
>> +               rc = dw_i2c_adapter_poll_rxrdy(adap);
>> +               if (rc)
>> +                       return rc;
>> +
>> +               *buffer = dw_i2c_getreg(adap, DW_IC_DATA_CMD) & 0xff;
>> +               buffer++;
>> +               len--;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int dw_i2c_adapter_write(struct i2c_adapter *ia, u8 addr,
>> +                               u8 reg, u8 *buffer, int len)
>> +{
>> +       struct dw_i2c_adapter *adap =
>> +               container_of(ia, struct dw_i2c_adapter, adapter);
>> +       int rc;
>> +
>> +       dw_i2c_write_addr(adap, addr);
>> +
>> +       rc = dw_i2c_adapter_poll_txfifo_ready(adap);
>> +       if (rc)
>> +               return rc;
>> +
>> +       /* set register address */
>> +       dw_i2c_setreg(adap, DW_IC_DATA_CMD, reg);
>> +
>> +       while (len) {
>> +               rc = dw_i2c_adapter_poll_txfifo_ready(adap);
>> +               if (rc)
>> +                       return rc;
>> +
>> +               if (len == 1)
>> +                       dw_i2c_setreg(adap, DW_IC_DATA_CMD, *buffer | IC_DATA_CMD_STOP);
>> +               else
>> +                       dw_i2c_setreg(adap, DW_IC_DATA_CMD, *buffer);
>> +
>> +               buffer++;
>> +               len--;
>> +       }
>> +       rc = dw_i2c_adapter_poll_txfifo_ready(adap);
>> +
>> +       return rc;
>> +}
>> +
>> +int dw_i2c_init(struct i2c_adapter *adapter, int nodeoff)
>> +{
>> +       adapter->id = nodeoff;
>> +       adapter->write = dw_i2c_adapter_write;
>> +       adapter->read = dw_i2c_adapter_read;
>> +
>> +       return i2c_adapter_add(adapter);
>> +}
>> diff --git a/lib/utils/i2c/fdt_i2c_starfive.c b/lib/utils/i2c/fdt_i2c_starfive.c
>> new file mode 100644
>> index 0000000..7b7f3cc
>> --- /dev/null
>> +++ b/lib/utils/i2c/fdt_i2c_starfive.c
> 
> Please rename the file to fde_i2c_dw.c
> 
ok
>> @@ -0,0 +1,63 @@
>> +/*
>> + * SPDX-License-Identifier: BSD-2-Clause
>> + *
>> + * Copyright (c) 2022 starfivetech.com
>> + *
>> + * Authors:
>> + *   Minda Chen <minda.chen at starfivetech.com>
>> + */
>> +
>> +#include <sbi/riscv_io.h>
>> +#include <sbi/sbi_error.h>
>> +#include <sbi/sbi_string.h>
>> +#include <sbi_utils/fdt/fdt_helper.h>
>> +#include <sbi_utils/i2c/dw_i2c.h>
>> +#include <sbi_utils/i2c/fdt_i2c.h>
>> +
>> +#define STARFIVE_I2C_ADAPTER_MAX       7
> 
> Use the prefix "FDT_DW_" instead of "STARFIVE_" everywhere in
> this source file.
> 
ok , I will send v2 patch in this week
>> +
>> +static unsigned int starfive_i2c_adapter_count;
>> +static struct dw_i2c_adapter
>> +       starfive_i2c_adapter_array[STARFIVE_I2C_ADAPTER_MAX];
>> +
>> +extern struct fdt_i2c_adapter fdt_i2c_adapter_starfive;
>> +
>> +static int starfive_i2c_init(void *fdt, int nodeoff,
>> +                            const struct fdt_match *match)
>> +{
>> +       int rc;
>> +       struct dw_i2c_adapter *adapter;
>> +       u64 addr;
>> +
>> +       if (starfive_i2c_adapter_count >= STARFIVE_I2C_ADAPTER_MAX)
>> +               return SBI_ENOSPC;
>> +
>> +       adapter = &starfive_i2c_adapter_array[starfive_i2c_adapter_count];
>> +
>> +       rc = fdt_get_node_addr_size(fdt, nodeoff, 0, &addr, NULL);
>> +       if (rc)
>> +               return rc;
>> +
>> +       adapter->addr = addr;
>> +       adapter->adapter.driver = &fdt_i2c_adapter_starfive;
>> +
>> +       rc = dw_i2c_init(&adapter->adapter, nodeoff);
>> +       if (rc)
>> +               return rc;
>> +
>> +       starfive_i2c_adapter_count++;
>> +
>> +       return 0;
>> +}
>> +
>> +static const struct fdt_match starfive_i2c_match[] = {
>> +       { .compatible = "snps,designware-i2c" },
>> +       { .compatible = "starfive,jh7110-i2c" },
>> +       { },
>> +};
>> +
>> +struct fdt_i2c_adapter fdt_i2c_adapter_starfive = {
> 
> s/fdt_i2c_adapter_starfive/fdt_i2c_adapter_dw
> 
ok
>> +       .match_table = starfive_i2c_match,
>> +       .init = starfive_i2c_init,
>> +};
>> +
>> diff --git a/lib/utils/i2c/objects.mk b/lib/utils/i2c/objects.mk
>> index a0fbbb5..6ceffe8 100644
>> --- a/lib/utils/i2c/objects.mk
>> +++ b/lib/utils/i2c/objects.mk
>> @@ -14,3 +14,8 @@ libsbiutils-objs-$(CONFIG_FDT_I2C) += i2c/fdt_i2c_adapter_drivers.o
>>
>>  carray-fdt_i2c_adapter_drivers-$(CONFIG_FDT_I2C_SIFIVE) += fdt_i2c_adapter_sifive
>>  libsbiutils-objs-$(CONFIG_FDT_I2C_SIFIVE) += i2c/fdt_i2c_sifive.o
>> +
>> +carray-fdt_i2c_adapter_drivers-$(CONFIG_FDT_I2C_STARFIVE) += fdt_i2c_adapter_starfive
>> +libsbiutils-objs-$(CONFIG_FDT_I2C_STARFIVE) += i2c/fdt_i2c_starfive.o
>> +
>> +libsbiutils-objs-$(CONFIG_I2C_DW) += i2c/dw_i2c.o
>> --
>> 2.17.1
>>
>>
>> --
>> opensbi mailing list
>> opensbi at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/opensbi
> 
> Regards,
> Anup



More information about the opensbi mailing list