diff options
| author | zms123456 <[email protected]> | 2024-04-07 21:57:38 +0800 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-04-07 09:57:38 -0400 |
| commit | 4ffcbfef2a05ac7f7962f8a7d718ea4c2a9b2a99 (patch) | |
| tree | dbad864661cc50da8fd799bda490d23fdec65a81 /components/drivers/i2c | |
| parent | 9c938e51a68a87a0be5fce014b4718f22db90803 (diff) | |
[components][drivers]add ofw support i2c
Diffstat (limited to 'components/drivers/i2c')
| -rw-r--r-- | components/drivers/i2c/SConscript | 2 | ||||
| -rw-r--r-- | components/drivers/i2c/i2c_bus.c | 182 | ||||
| -rw-r--r-- | components/drivers/i2c/i2c_core.c | 7 | ||||
| -rw-r--r-- | components/drivers/i2c/i2c_dm.c | 50 |
4 files changed, 241 insertions, 0 deletions
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 <rtdevice.h> + +#define DBG_TAG "i2c.bus" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +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 <rtdevice.h> + +#define DBG_TAG "i2c.dm" +#define DBG_LVL DBG_INFO +#include <rtdbg.h> + +#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 */ |
