From a075fd69d068ba6b2cdf60bd65090cdfa1b68c12 Mon Sep 17 00:00:00 2001 From: zms123456 <85141075+zmshahaha@users.noreply.github.com> Date: Sun, 7 Apr 2024 21:57:38 +0800 Subject: [PATCH] [components][drivers]add ofw support i2c --- components/drivers/i2c/SConscript | 2 + components/drivers/i2c/i2c_bus.c | 182 ++++++++++++++++++++ components/drivers/i2c/i2c_core.c | 7 + components/drivers/i2c/i2c_dm.c | 50 ++++++ components/drivers/include/drivers/i2c.h | 32 ++++ components/drivers/include/drivers/i2c_dm.h | 51 ++++++ components/drivers/include/rtdevice.h | 39 +++-- 7 files changed, 346 insertions(+), 17 deletions(-) create mode 100644 components/drivers/i2c/i2c_bus.c create mode 100644 components/drivers/i2c/i2c_dm.c create mode 100644 components/drivers/include/drivers/i2c_dm.h diff --git a/components/drivers/i2c/SConscript b/components/drivers/i2c/SConscript index aef9f5be9b..3685e44e2d 100644 --- a/components/drivers/i2c/SConscript +++ b/components/drivers/i2c/SConscript @@ -11,6 +11,8 @@ if GetDepend('RT_USING_I2C_BITOPS'): src = src + ['i2c-bit-ops.c'] if GetDepend('RT_USING_SOFT_I2C'): src = src + ['soft_i2c.c'] +if GetDepend(['RT_USING_DM']): + src += ['i2c_bus.c', 'i2c_dm.c'] # The set of source files associated with this SConscript file. path = [cwd + '/../include'] diff --git a/components/drivers/i2c/i2c_bus.c b/components/drivers/i2c/i2c_bus.c new file mode 100644 index 0000000000..e9626cadd7 --- /dev/null +++ b/components/drivers/i2c/i2c_bus.c @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "i2c.bus" +#define DBG_LVL DBG_INFO +#include + +static struct rt_bus i2c_bus; + +void i2c_bus_scan_clients(struct rt_i2c_bus_device *bus) +{ +#ifdef RT_USING_OFW + if (bus->parent.ofw_node) + { + struct rt_ofw_node *np = bus->parent.ofw_node, *child_np, *i2c_client_np; + + rt_ofw_foreach_available_child_node(np, child_np) + { + rt_uint32_t client_addr; + struct rt_i2c_client *client; + + if (rt_ofw_prop_read_bool(child_np, "compatible")) + { + i2c_client_np = child_np; + } + else + { + /* Maybe in i2c-mux */ + i2c_client_np = rt_ofw_get_next_child(child_np, RT_NULL); + + if (!rt_ofw_prop_read_bool(i2c_client_np, "compatible")) + { + continue; + } + } + + client = rt_calloc(1, sizeof(*client)); + + if (!client) + { + rt_ofw_node_put(i2c_client_np); + LOG_E("Not memory to create i2c client: %s", + rt_ofw_node_full_name(i2c_client_np)); + + return; + } + + rt_ofw_prop_read_u32(i2c_client_np, "reg", &client_addr); + + client->parent.ofw_node = i2c_client_np; + client->name = rt_ofw_node_name(i2c_client_np); + client->bus = bus; + client->client_addr = client_addr; + + rt_i2c_device_register(client); + + if (i2c_client_np != child_np) + { + rt_ofw_node_put(i2c_client_np); + } + } + } +#endif /* RT_USING_OFW */ +} + +rt_err_t rt_i2c_driver_register(struct rt_i2c_driver *driver) +{ + RT_ASSERT(driver != RT_NULL); + + driver->parent.bus = &i2c_bus; + + return rt_driver_register(&driver->parent); +} + +rt_err_t rt_i2c_device_register(struct rt_i2c_client *client) +{ + RT_ASSERT(client != RT_NULL); + + return rt_bus_add_device(&i2c_bus, &client->parent); +} + +static rt_bool_t i2c_match(rt_driver_t drv, rt_device_t dev) +{ + const struct rt_i2c_device_id *id; + struct rt_i2c_driver *driver = rt_container_of(drv, struct rt_i2c_driver, parent); + struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent); + + if ((id = driver->ids)) + { + for (; id->name[0]; ++id) + { + if (!rt_strcmp(id->name, client->name)) + { + client->id = id; + client->ofw_id = RT_NULL; + + return RT_TRUE; + } + } + } + +#ifdef RT_USING_OFW + client->ofw_id = rt_ofw_node_match(client->parent.ofw_node, driver->ofw_ids); + + if (client->ofw_id) + { + client->id = RT_NULL; + + return RT_TRUE; + } +#endif + + return RT_FALSE; +} + +static rt_err_t i2c_probe(rt_device_t dev) +{ + rt_err_t err; + struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent); + struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent); + + if (!client->bus) + { + return -RT_EINVAL; + } + + err = driver->probe(client); + + return err; +} + +static rt_err_t i2c_remove(rt_device_t dev) +{ + struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent); + struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent); + + if (driver && driver->remove) + { + driver->remove(client); + } + + return RT_EOK; +} + +static rt_err_t i2c_shutdown(rt_device_t dev) +{ + struct rt_i2c_driver *driver = rt_container_of(dev->drv, struct rt_i2c_driver, parent); + struct rt_i2c_client *client = rt_container_of(dev, struct rt_i2c_client, parent); + + if (driver && driver->shutdown) + { + driver->shutdown(client); + } + + return RT_EOK; +} + +static struct rt_bus i2c_bus = +{ + .name = "i2c", + .match = i2c_match, + .probe = i2c_probe, + .remove = i2c_remove, + .shutdown = i2c_shutdown, +}; + +static int i2c_bus_init(void) +{ + rt_bus_register(&i2c_bus); + + return 0; +} +INIT_CORE_EXPORT(i2c_bus_init); diff --git a/components/drivers/i2c/i2c_core.c b/components/drivers/i2c/i2c_core.c index 127fdd25a4..2b8e58c90c 100644 --- a/components/drivers/i2c/i2c_core.c +++ b/components/drivers/i2c/i2c_core.c @@ -32,6 +32,13 @@ rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus, LOG_I("I2C bus [%s] registered", bus_name); +#ifdef RT_USING_DM + if (!res) + { + i2c_bus_scan_clients(bus); + } +#endif + return res; } diff --git a/components/drivers/i2c/i2c_dm.c b/components/drivers/i2c/i2c_dm.c new file mode 100644 index 0000000000..95b1fe63ab --- /dev/null +++ b/components/drivers/i2c/i2c_dm.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-12-06 GuEe-GUI first version + */ + +#include + +#define DBG_TAG "i2c.dm" +#define DBG_LVL DBG_INFO +#include + +#ifdef RT_USING_OFW +static void i2c_parse_timing(struct rt_ofw_node *dev_np, const char *propname, + rt_uint32_t *out_value, rt_uint32_t def_value, rt_bool_t use_defaults) +{ + if (rt_ofw_prop_read_u32(dev_np, propname, out_value) && use_defaults) + { + *out_value = def_value; + } +} + +rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings, + rt_bool_t use_defaults) +{ + rt_ubase_t def; + rt_bool_t udef = use_defaults; + struct i2c_timings *t = timings; + + i2c_parse_timing(dev_np, "clock-frequency", &t->bus_freq_hz, I2C_MAX_STANDARD_MODE_FREQ, udef); + + def = t->bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ ? 1000 : t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev_np, "i2c-scl-rising-time-ns", &t->scl_rise_ns, def, udef); + + def = t->bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ ? 300 : 120; + i2c_parse_timing(dev_np, "i2c-scl-falling-time-ns", &t->scl_fall_ns, def, udef); + + i2c_parse_timing(dev_np, "i2c-scl-internal-delay-ns", &t->scl_int_delay_ns, 0, udef); + i2c_parse_timing(dev_np, "i2c-sda-falling-time-ns", &t->sda_fall_ns, t->scl_fall_ns, udef); + i2c_parse_timing(dev_np, "i2c-sda-hold-time-ns", &t->sda_hold_ns, 0, udef); + i2c_parse_timing(dev_np, "i2c-digital-filter-width-ns", &t->digital_filter_width_ns, 0, udef); + i2c_parse_timing(dev_np, "i2c-analog-filter-cutoff-frequency", &t->analog_filter_cutoff_freq_hz, 0, udef); + + return RT_EOK; +} +#endif /* RT_USING_OFW */ diff --git a/components/drivers/include/drivers/i2c.h b/components/drivers/include/drivers/i2c.h index ed87425260..0473a1e8dd 100644 --- a/components/drivers/include/drivers/i2c.h +++ b/components/drivers/include/drivers/i2c.h @@ -63,10 +63,42 @@ struct rt_i2c_bus_device struct rt_i2c_client { +#ifdef RT_USING_DM + struct rt_device parent; + + const char *name; + const struct rt_i2c_device_id *id; + const struct rt_ofw_node_id *ofw_id; +#endif struct rt_i2c_bus_device *bus; rt_uint16_t client_addr; }; +#ifdef RT_USING_DM +struct rt_i2c_device_id +{ + char name[20]; + void *data; +}; + +struct rt_i2c_driver +{ + struct rt_driver parent; + + const struct rt_i2c_device_id *ids; + const struct rt_ofw_node_id *ofw_ids; + + rt_err_t (*probe)(struct rt_i2c_client *client); + rt_err_t (*remove)(struct rt_i2c_client *client); + rt_err_t (*shutdown)(struct rt_i2c_client *client); +}; + +rt_err_t rt_i2c_driver_register(struct rt_i2c_driver *driver); +rt_err_t rt_i2c_device_register(struct rt_i2c_client *client); + +#define RT_I2C_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, i2c, BUILIN) +#endif /* RT_USING_DM */ + rt_err_t rt_i2c_bus_device_register(struct rt_i2c_bus_device *bus, const char *bus_name); struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name); diff --git a/components/drivers/include/drivers/i2c_dm.h b/components/drivers/include/drivers/i2c_dm.h new file mode 100644 index 0000000000..4f5b251c60 --- /dev/null +++ b/components/drivers/include/drivers/i2c_dm.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2006-2022, RT-Thread Development Team + * + * SPDX-License-Identifier: Apache-2.0 + * + * Change Logs: + * Date Author Notes + * 2022-11-26 GuEe-GUI first version + */ + +#ifndef __I2C_DM_H__ +#define __I2C_DM_H__ + +#include +#include +#include + +/* I2C Frequency Modes */ +#define I2C_MAX_STANDARD_MODE_FREQ 100000 +#define I2C_MAX_FAST_MODE_FREQ 400000 +#define I2C_MAX_FAST_MODE_PLUS_FREQ 1000000 +#define I2C_MAX_TURBO_MODE_FREQ 1400000 +#define I2C_MAX_HIGH_SPEED_MODE_FREQ 3400000 +#define I2C_MAX_ULTRA_FAST_MODE_FREQ 5000000 + +struct i2c_timings +{ + rt_uint32_t bus_freq_hz; /* the bus frequency in Hz */ + rt_uint32_t scl_rise_ns; /* time SCL signal takes to rise in ns; t(r) in the I2C specification */ + rt_uint32_t scl_fall_ns; /* time SCL signal takes to fall in ns; t(f) in the I2C specification */ + rt_uint32_t scl_int_delay_ns; /* time IP core additionally needs to setup SCL in ns */ + rt_uint32_t sda_fall_ns; /* time SDA signal takes to fall in ns; t(f) in the I2C specification */ + rt_uint32_t sda_hold_ns; /* time IP core additionally needs to hold SDA in ns */ + rt_uint32_t digital_filter_width_ns; /* width in ns of spikes on i2c lines that the IP core digital filter can filter out */ + rt_uint32_t analog_filter_cutoff_freq_hz; /* threshold frequency for the low pass IP core analog filter */ +}; + +#ifdef RT_USING_OFW +rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings, + rt_bool_t use_defaults); +#else +rt_inline rt_err_t i2c_timings_ofw_parse(struct rt_ofw_node *dev_np, struct i2c_timings *timings, + rt_bool_t use_defaults) +{ + return RT_EOK; +} +#endif /* RT_USING_OFW */ + +void i2c_bus_scan_clients(struct rt_i2c_bus_device *bus); + +#endif /* __I2C_DM_H__ */ diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h index 5da3c955d6..c930904919 100644 --- a/components/drivers/include/rtdevice.h +++ b/components/drivers/include/rtdevice.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -37,6 +38,23 @@ extern "C" { #define RT_DEVICE(device) ((rt_device_t)device) +#ifdef RT_USING_DM +#include "drivers/core/dm.h" +#include "drivers/platform.h" + +#ifdef RT_USING_OFW +#include "drivers/ofw.h" +#include "drivers/ofw_fdt.h" +#include "drivers/ofw_io.h" +#include "drivers/ofw_irq.h" +#include "drivers/ofw_raw.h" +#endif /* RT_USING_OFW */ + +#ifdef RT_USING_PIC +#include "drivers/pic.h" +#endif +#endif /* RT_USING_DM */ + #ifdef RT_USING_RTC #include "drivers/rtc.h" #ifdef RT_USING_ALARM @@ -79,6 +97,10 @@ extern "C" { #ifdef RT_USING_I2C_BITOPS #include "drivers/i2c-bit-ops.h" #endif /* RT_USING_I2C_BITOPS */ + +#ifdef RT_USING_DM +#include "drivers/i2c_dm.h" +#endif /* RT_USING_DM */ #endif /* RT_USING_I2C */ #ifdef RT_USING_PHY @@ -181,23 +203,6 @@ extern "C" { #include "drivers/clk.h" #endif /* RT_USING_CLK */ -#ifdef RT_USING_DM -#include "drivers/core/dm.h" -#include "drivers/platform.h" - -#ifdef RT_USING_OFW -#include "drivers/ofw.h" -#include "drivers/ofw_fdt.h" -#include "drivers/ofw_io.h" -#include "drivers/ofw_irq.h" -#include "drivers/ofw_raw.h" -#endif /* RT_USING_OFW */ - -#ifdef RT_USING_PIC -#include "drivers/pic.h" -#endif -#endif /* RT_USING_DM */ - #ifdef __cplusplus } #endif