diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/Makefile | 2 | ||||
-rw-r--r-- | drivers/i2c/designware_i2c.c | 19 | ||||
-rw-r--r-- | drivers/i2c/i2c-emul-uclass.c | 2 | ||||
-rw-r--r-- | drivers/i2c/i2c-uclass.c | 75 | ||||
-rw-r--r-- | drivers/i2c/mvtwsi.c | 3 | ||||
-rw-r--r-- | drivers/i2c/npcm_i2c.c | 5 | ||||
-rw-r--r-- | drivers/i2c/stm32f7_i2c.c | 11 | ||||
-rw-r--r-- | drivers/i2c/sun6i_p2wi.c | 2 | ||||
-rw-r--r-- | drivers/i2c/sun8i_rsb.c | 2 |
9 files changed, 101 insertions, 20 deletions
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index d5b85f398db..a96a8c7e955 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -3,7 +3,7 @@ # (C) Copyright 2000-2007 # Wolfgang Denk, DENX Software Engineering, wd@denx.de. obj-$(CONFIG_$(SPL_)DM_I2C) += i2c-uclass.o -ifdef CONFIG_ACPIGEN +ifdef CONFIG_$(SPL_)ACPIGEN obj-$(CONFIG_$(SPL_)DM_I2C) += acpi_i2c.o endif obj-$(CONFIG_$(SPL_)DM_I2C_GPIO) += i2c-gpio.o diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c index e54de42abc3..215ce010cb7 100644 --- a/drivers/i2c/designware_i2c.c +++ b/drivers/i2c/designware_i2c.c @@ -24,6 +24,17 @@ */ #define DW_I2C_COMP_TYPE 0x44570140 +/* + * This constant is used to calculate when during the clock high phase the data + * bit shall be read. The value was copied from the Linux v6.5 function + * i2c_dw_scl_hcnt() which provides the following explanation: + * + * "This is just an experimental rule: the tHD;STA period turned out to be + * proportinal to (_HCNT + 3). With this setting, we could meet both tHIGH and + * tHD;STA timing specs." + */ +#define T_HD_STA_OFFSET 3 + static int dw_i2c_enable(struct i2c_regs *i2c_base, bool enable) { u32 ena = enable ? IC_ENABLE_0B : 0; @@ -155,10 +166,10 @@ static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode, /* * Back-solve for hcnt and lcnt according to the following equations: - * SCL_High_time = [(HCNT + IC_*_SPKLEN + 7) * ic_clk] + SCL_Fall_time + * SCL_High_time = [(HCNT + IC_*_SPKLEN + T_HD_STA_OFFSET) * ic_clk] + SCL_Fall_time * SCL_Low_time = [(LCNT + 1) * ic_clk] - SCL_Fall_time + SCL_Rise_time */ - hcnt = min_thigh_cnt - fall_cnt - 7 - spk_cnt; + hcnt = min_thigh_cnt - fall_cnt - T_HD_STA_OFFSET - spk_cnt; lcnt = min_tlow_cnt - rise_cnt + fall_cnt - 1; if (hcnt < 0 || lcnt < 0) { @@ -170,13 +181,13 @@ static int dw_i2c_calc_timing(struct dw_i2c *priv, enum i2c_speed_mode mode, * Now add things back up to ensure the period is hit. If it is off, * split the difference and bias to lcnt for remainder */ - tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1; + tot = hcnt + lcnt + T_HD_STA_OFFSET + spk_cnt + rise_cnt + 1; if (tot < period_cnt) { diff = (period_cnt - tot) / 2; hcnt += diff; lcnt += diff; - tot = hcnt + lcnt + 7 + spk_cnt + rise_cnt + 1; + tot = hcnt + lcnt + T_HD_STA_OFFSET + spk_cnt + rise_cnt + 1; lcnt += period_cnt - tot; } diff --git a/drivers/i2c/i2c-emul-uclass.c b/drivers/i2c/i2c-emul-uclass.c index 1107cf309fc..d421ddfcbe2 100644 --- a/drivers/i2c/i2c-emul-uclass.c +++ b/drivers/i2c/i2c-emul-uclass.c @@ -46,7 +46,7 @@ int i2c_emul_find(struct udevice *dev, struct udevice **emulp) struct udevice *emul; int ret; - if (!CONFIG_IS_ENABLED(OF_PLATDATA)) { + if (CONFIG_IS_ENABLED(OF_REAL)) { ret = uclass_find_device_by_phandle(UCLASS_I2C_EMUL, dev, "sandbox,emul", &emul); } else { diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c index 8867a560bd8..5405067861e 100644 --- a/drivers/i2c/i2c-uclass.c +++ b/drivers/i2c/i2c-uclass.c @@ -388,6 +388,81 @@ int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len, return 0; } +/* Find and probe I2C bus based on a chip attached to it */ +static int i2c_get_parent_bus(ofnode chip, struct udevice **devp) +{ + ofnode node; + struct udevice *dev; + int ret; + + node = ofnode_get_parent(chip); + if (!ofnode_valid(node)) + return -ENODEV; + + ret = uclass_get_device_by_ofnode(UCLASS_I2C, node, &dev); + if (ret) { + *devp = NULL; + return ret; + } + + *devp = dev; + return 0; +} + +int i2c_get_chip_by_phandle(const struct udevice *parent, const char *prop_name, + struct udevice **devp) +{ + ofnode node; + uint phandle; + struct udevice *bus, *chip; + char *dev_name; + int ret; + + debug("%s: Searching I2C chip for phandle \"%s\"\n", + __func__, prop_name); + + dev_name = strdup(prop_name); + if (!dev_name) { + ret = -ENOMEM; + goto err_exit; + } + + ret = dev_read_u32(parent, "i2cbcdev", &phandle); + if (ret) + goto err_exit; + + node = ofnode_get_by_phandle(phandle); + if (!ofnode_valid(node)) { + ret = -ENODEV; + goto err_exit; + } + + ret = i2c_get_parent_bus(node, &bus); + if (ret) + goto err_exit; + + ret = device_bind_driver_to_node(bus, "i2c_generic_chip_drv", + dev_name, node, &chip); + if (ret) + goto err_exit; + + ret = device_probe(chip); + if (ret) { + device_unbind(chip); + goto err_exit; + } + + debug("%s succeeded\n", __func__); + *devp = chip; + return 0; + +err_exit: + free(dev_name); + debug("%s failed, ret = %d\n", __func__, ret); + *devp = NULL; + return ret; +} + int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags, struct udevice **devp) { diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c index 14cdb0f6635..c38330f758a 100644 --- a/drivers/i2c/mvtwsi.c +++ b/drivers/i2c/mvtwsi.c @@ -124,7 +124,8 @@ enum mvtwsi_ctrl_register_fields { * on other platforms, it is a normal r/w bit, which is cleared by writing 0. */ -#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) +#if defined(CONFIG_SUNXI_GEN_SUN6I) || defined(CONFIG_SUN50I_GEN_H6) || \ + defined(CONFIG_SUNXI_GEN_NCAT2) #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000008 #else #define MVTWSI_CONTROL_CLEAR_IFLG 0x00000000 diff --git a/drivers/i2c/npcm_i2c.c b/drivers/i2c/npcm_i2c.c index ea4ef532565..b867b6c8e91 100644 --- a/drivers/i2c/npcm_i2c.c +++ b/drivers/i2c/npcm_i2c.c @@ -517,11 +517,6 @@ static int npcm_i2c_init_clk(struct npcm_i2c_bus *bus, u32 bus_freq) u32 sclfrq; u8 hldt, val; - if (bus_freq > I2C_FREQ_100K) { - printf("Support standard mode only\n"); - return -EINVAL; - } - /* SCLFRQ = T(SCL)/4/T(CLK) = FREQ(CLK)/4/FREQ(SCL) */ sclfrq = freq / (bus_freq * 4); if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX) diff --git a/drivers/i2c/stm32f7_i2c.c b/drivers/i2c/stm32f7_i2c.c index b6c71789eec..eaa1d692898 100644 --- a/drivers/i2c/stm32f7_i2c.c +++ b/drivers/i2c/stm32f7_i2c.c @@ -20,6 +20,7 @@ #include <linux/err.h> #include <linux/io.h> #include <linux/printk.h> +#include <linux/time.h> /* STM32 I2C registers */ struct stm32_i2c_regs { @@ -121,8 +122,6 @@ struct stm32_i2c_regs { #define STM32_SCLH_MAX BIT(8) #define STM32_SCLL_MAX BIT(8) -#define STM32_NSEC_PER_SEC 1000000000L - /** * struct stm32_i2c_spec - private i2c specification timing * @rate: I2C bus speed (Hz) @@ -591,7 +590,7 @@ static int stm32_i2c_choose_solution(u32 i2cclk, struct stm32_i2c_timings *s) { struct stm32_i2c_timings *v; - u32 i2cbus = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, + u32 i2cbus = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->speed_freq); u32 clk_error_prev = i2cbus; u32 clk_min, clk_max; @@ -607,8 +606,8 @@ static int stm32_i2c_choose_solution(u32 i2cclk, dnf_delay = setup->dnf * i2cclk; tsync = af_delay_min + dnf_delay + (2 * i2cclk); - clk_max = STM32_NSEC_PER_SEC / specs->rate_min; - clk_min = STM32_NSEC_PER_SEC / specs->rate_max; + clk_max = NSEC_PER_SEC / specs->rate_min; + clk_min = NSEC_PER_SEC / specs->rate_max; /* * Among Prescaler possibilities discovered above figures out SCL Low @@ -686,7 +685,7 @@ static int stm32_i2c_compute_timing(struct stm32_i2c_priv *i2c_priv, const struct stm32_i2c_spec *specs; struct stm32_i2c_timings *v, *_v; struct list_head solutions; - u32 i2cclk = DIV_ROUND_CLOSEST(STM32_NSEC_PER_SEC, setup->clock_src); + u32 i2cclk = DIV_ROUND_CLOSEST(NSEC_PER_SEC, setup->clock_src); int ret; specs = get_specs(setup->speed_freq); diff --git a/drivers/i2c/sun6i_p2wi.c b/drivers/i2c/sun6i_p2wi.c index d221323295d..b8e07a533ca 100644 --- a/drivers/i2c/sun6i_p2wi.c +++ b/drivers/i2c/sun6i_p2wi.c @@ -20,10 +20,10 @@ #include <errno.h> #include <i2c.h> #include <reset.h> +#include <sunxi_gpio.h> #include <time.h> #include <asm/io.h> #include <asm/arch/cpu.h> -#include <asm/arch/gpio.h> #include <asm/arch/p2wi.h> #include <asm/arch/prcm.h> #include <asm/arch/sys_proto.h> diff --git a/drivers/i2c/sun8i_rsb.c b/drivers/i2c/sun8i_rsb.c index 47fa05b6d1c..f36f2c7afac 100644 --- a/drivers/i2c/sun8i_rsb.c +++ b/drivers/i2c/sun8i_rsb.c @@ -14,10 +14,10 @@ #include <dm.h> #include <errno.h> #include <i2c.h> +#include <sunxi_gpio.h> #include <reset.h> #include <time.h> #include <asm/arch/cpu.h> -#include <asm/arch/gpio.h> #include <asm/arch/prcm.h> #include <asm/arch/rsb.h> |