summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2024-11-27 11:08:08 +0800
committerRbb666 <[email protected]>2024-11-27 18:04:07 +0800
commit6f68ca7c7133a2a06b5be8663ec644b9181a2c9d (patch)
tree4e75aa10a29349eccf59ace7ac90d998eabe6f96 /components
parent49d18ec0a919c64f06f9614d49b6eecbd05751eb (diff)
[DM/SPI] Support DM mode in SPI
Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components')
-rw-r--r--components/drivers/include/drivers/dev_spi.h63
-rw-r--r--components/drivers/spi/SConscript3
-rw-r--r--components/drivers/spi/dev_spi.c71
-rw-r--r--components/drivers/spi/dev_spi_bus.c203
-rw-r--r--components/drivers/spi/dev_spi_core.c44
-rw-r--r--components/drivers/spi/dev_spi_dm.c106
-rw-r--r--components/drivers/spi/dev_spi_dm.h29
7 files changed, 519 insertions, 0 deletions
diff --git a/components/drivers/include/drivers/dev_spi.h b/components/drivers/include/drivers/dev_spi.h
index 45e8e8544f..ad23453d5b 100644
--- a/components/drivers/include/drivers/dev_spi.h
+++ b/components/drivers/include/drivers/dev_spi.h
@@ -16,6 +16,8 @@
#include <stdlib.h>
#include <rtthread.h>
#include <drivers/dev_pin.h>
+#include <drivers/core/driver.h>
+
/**
* @addtogroup Drivers RTTHREAD Driver
* @defgroup SPI SPI
@@ -151,7 +153,12 @@ struct rt_spi_configuration
{
rt_uint8_t mode;
rt_uint8_t data_width;
+#ifdef RT_USING_DM
+ rt_uint8_t data_width_tx;
+ rt_uint8_t data_width_rx;
+#else
rt_uint16_t reserved;
+#endif
rt_uint32_t max_hz;
};
@@ -167,6 +174,12 @@ struct rt_spi_bus
rt_uint8_t mode;
const struct rt_spi_ops *ops;
+#ifdef RT_USING_DM
+ rt_base_t *pins;
+ rt_bool_t slave;
+ int num_chipselect;
+#endif /* RT_USING_DM */
+
struct rt_mutex lock;
struct rt_spi_device *owner;
};
@@ -180,6 +193,20 @@ struct rt_spi_ops
rt_ssize_t (*xfer)(struct rt_spi_device *device, struct rt_spi_message *message);
};
+#ifdef RT_USING_DM
+/**
+ * @brief SPI delay info
+ */
+struct rt_spi_delay
+{
+#define RT_SPI_DELAY_UNIT_USECS 0
+#define RT_SPI_DELAY_UNIT_NSECS 1
+#define RT_SPI_DELAY_UNIT_SCK 2
+ rt_uint16_t value;
+ rt_uint8_t unit;
+};
+#endif /* RT_USING_DM */
+
/**
* @brief SPI Virtual BUS, one device must connected to a virtual BUS
*/
@@ -188,6 +215,17 @@ struct rt_spi_device
struct rt_device parent;
struct rt_spi_bus *bus;
+#ifdef RT_USING_DM
+ const char *name;
+ const struct rt_spi_device_id *id;
+ const struct rt_ofw_node_id *ofw_id;
+
+ rt_uint8_t chip_select;
+ struct rt_spi_delay cs_setup;
+ struct rt_spi_delay cs_hold;
+ struct rt_spi_delay cs_inactive;
+#endif
+
struct rt_spi_configuration config;
rt_base_t cs_pin;
void *user_data;
@@ -252,6 +290,31 @@ struct rt_qspi_device
#define SPI_DEVICE(dev) ((struct rt_spi_device *)(dev))
+#ifdef RT_USING_DM
+struct rt_spi_device_id
+{
+ char name[20];
+ void *data;
+};
+
+struct rt_spi_driver
+{
+ struct rt_driver parent;
+
+ const struct rt_spi_device_id *ids;
+ const struct rt_ofw_node_id *ofw_ids;
+
+ rt_err_t (*probe)(struct rt_spi_device *device);
+ rt_err_t (*remove)(struct rt_spi_device *device);
+ rt_err_t (*shutdown)(struct rt_spi_device *device);
+};
+
+rt_err_t rt_spi_driver_register(struct rt_spi_driver *driver);
+rt_err_t rt_spi_device_register(struct rt_spi_device *device);
+
+#define RT_SPI_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, spi, BUILIN)
+#endif /* RT_USING_DM */
+
/**
* @brief register a SPI bus
*
diff --git a/components/drivers/spi/SConscript b/components/drivers/spi/SConscript
index 874db5b7e9..6897dab6d3 100644
--- a/components/drivers/spi/SConscript
+++ b/components/drivers/spi/SConscript
@@ -35,6 +35,9 @@ if GetDepend('RT_USING_SFUD'):
elif rtconfig.PLATFORM in ['armcc']:
LOCAL_CFLAGS += ' --c99'
+if GetDepend('RT_USING_DM'):
+ src += ['dev_spi_dm.c', 'dev_spi_bus.c']
+
src += src_device
group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_SPI'], CPPPATH = CPPPATH, LOCAL_CFLAGS = LOCAL_CFLAGS)
diff --git a/components/drivers/spi/dev_spi.c b/components/drivers/spi/dev_spi.c
index b40ffd90db..3f55fd0eb0 100644
--- a/components/drivers/spi/dev_spi.c
+++ b/components/drivers/spi/dev_spi.c
@@ -10,6 +10,14 @@
#include <rtthread.h>
#include "drivers/dev_spi.h"
+#define DBG_TAG "spi.dev"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USING_DM
+#include "dev_spi_dm.h"
+#endif
+
/* SPI bus device interface, compatible with RT-Thread 0.3.x/1.0.x */
static rt_ssize_t _spi_bus_device_read(rt_device_t dev,
rt_off_t pos,
@@ -155,3 +163,66 @@ rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name)
/* register to device manager */
return rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
}
+
+#ifdef RT_USING_DM
+static rt_err_t spidev_probe(struct rt_spi_device *spi_dev)
+{
+ const char *bus_name;
+ struct rt_device *dev = &spi_dev->parent;
+
+ if (spi_dev->parent.ofw_node)
+ {
+ if (rt_dm_dev_prop_index_of_string(dev, "compatible", "spidev") >= 0)
+ {
+ LOG_E("spidev is not supported in OFW");
+
+ return -RT_EINVAL;
+ }
+ }
+
+ bus_name = rt_dm_dev_get_name(&spi_dev->bus->parent);
+ rt_dm_dev_set_name(dev, "%s_%d", bus_name, spi_dev->chip_select);
+
+ return RT_EOK;
+}
+
+static const struct rt_spi_device_id spidev_ids[] =
+{
+ { .name = "dh2228fv" },
+ { .name = "ltc2488" },
+ { .name = "sx1301" },
+ { .name = "bk4" },
+ { .name = "dhcom-board" },
+ { .name = "m53cpld" },
+ { .name = "spi-petra" },
+ { .name = "spi-authenta" },
+ { .name = "em3581" },
+ { .name = "si3210" },
+ { /* sentinel */ },
+};
+
+static const struct rt_ofw_node_id spidev_ofw_ids[] =
+{
+ { .compatible = "cisco,spi-petra" },
+ { .compatible = "dh,dhcom-board" },
+ { .compatible = "lineartechnology,ltc2488" },
+ { .compatible = "lwn,bk4" },
+ { .compatible = "menlo,m53cpld" },
+ { .compatible = "micron,spi-authenta" },
+ { .compatible = "rohm,dh2228fv" },
+ { .compatible = "semtech,sx1301" },
+ { .compatible = "silabs,em3581" },
+ { .compatible = "silabs,si3210" },
+ { .compatible = "rockchip,spidev" },
+ { /* sentinel */ },
+};
+
+static struct rt_spi_driver spidev_driver =
+{
+ .ids = spidev_ids,
+ .ofw_ids = spidev_ofw_ids,
+
+ .probe = spidev_probe,
+};
+RT_SPI_DRIVER_EXPORT(spidev_driver);
+#endif /* RT_USING_DM */
diff --git a/components/drivers/spi/dev_spi_bus.c b/components/drivers/spi/dev_spi_bus.c
new file mode 100644
index 0000000000..34aa298aea
--- /dev/null
+++ b/components/drivers/spi/dev_spi_bus.c
@@ -0,0 +1,203 @@
+/*
+ * 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 "dev_spi_dm.h"
+
+#define DBG_TAG "spi.bus"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name);
+
+static struct rt_bus spi_bus;
+
+void spi_bus_scan_devices(struct rt_spi_bus *bus)
+{
+#ifdef RT_USING_OFW
+ if (bus->parent.ofw_node)
+ {
+ struct rt_ofw_node *np = bus->parent.ofw_node, *spi_dev_np;
+
+ rt_ofw_foreach_available_child_node(np, spi_dev_np)
+ {
+ rt_uint64_t reg_offset;
+ struct rt_spi_device *spi_dev;
+
+ if (!rt_ofw_prop_read_bool(spi_dev_np, "compatible"))
+ {
+ continue;
+ }
+
+ spi_dev = rt_calloc(1, sizeof(*spi_dev));
+
+ if (!spi_dev)
+ {
+ rt_ofw_node_put(spi_dev_np);
+ LOG_E("Not memory to create spi device: %s",
+ rt_ofw_node_full_name(spi_dev_np));
+
+ return;
+ }
+
+ rt_ofw_get_address(spi_dev_np, 0, &reg_offset, RT_NULL);
+
+ spi_dev->parent.ofw_node = spi_dev_np;
+ spi_dev->parent.type = RT_Device_Class_Unknown;
+ spi_dev->name = rt_ofw_node_name(spi_dev_np);
+ spi_dev->bus = bus;
+
+ rt_dm_dev_set_name(&spi_dev->parent, rt_ofw_node_full_name(spi_dev_np));
+
+ if (spi_device_ofw_parse(spi_dev))
+ {
+ continue;
+ }
+
+ rt_spi_device_register(spi_dev);
+ }
+ }
+#endif /* RT_USING_OFW */
+}
+
+rt_err_t rt_spi_driver_register(struct rt_spi_driver *driver)
+{
+ RT_ASSERT(driver != RT_NULL);
+
+ driver->parent.bus = &spi_bus;
+
+ return rt_driver_register(&driver->parent);
+}
+
+rt_err_t rt_spi_device_register(struct rt_spi_device *device)
+{
+ RT_ASSERT(device != RT_NULL);
+
+ return rt_bus_add_device(&spi_bus, &device->parent);
+}
+
+static rt_bool_t spi_match(rt_driver_t drv, rt_device_t dev)
+{
+ const struct rt_spi_device_id *id;
+ struct rt_spi_driver *driver = rt_container_of(drv, struct rt_spi_driver, parent);
+ struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent);
+
+ if ((id = driver->ids))
+ {
+ for (; id->name[0]; ++id)
+ {
+ if (!rt_strcmp(id->name, device->name))
+ {
+ device->id = id;
+ device->ofw_id = RT_NULL;
+
+ return RT_TRUE;
+ }
+ }
+ }
+
+#ifdef RT_USING_OFW
+ device->ofw_id = rt_ofw_node_match(device->parent.ofw_node, driver->ofw_ids);
+
+ if (device->ofw_id)
+ {
+ device->id = RT_NULL;
+
+ return RT_TRUE;
+ }
+#endif
+
+ return RT_FALSE;
+}
+
+static rt_err_t spi_probe(rt_device_t dev)
+{
+ rt_err_t err;
+ struct rt_spi_bus *bus;
+ struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent);
+ struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent);
+
+ if (!device->bus)
+ {
+ return -RT_EINVAL;
+ }
+
+ err = driver->probe(device);
+
+ if (err)
+ {
+ return err;
+ }
+
+ bus = device->bus;
+
+ if (bus->pins)
+ {
+ device->cs_pin = bus->pins[device->chip_select];
+
+ rt_pin_mode(device->cs_pin, PIN_MODE_OUTPUT);
+ }
+ else
+ {
+ device->cs_pin = PIN_NONE;
+ }
+
+ /* Driver not register SPI device to system */
+ if (device->parent.type == RT_Device_Class_Unknown)
+ {
+ rt_spidev_device_init(device, rt_dm_dev_get_name(&device->parent));
+ }
+
+ return err;
+}
+
+static rt_err_t spi_remove(rt_device_t dev)
+{
+ struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent);
+ struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent);
+
+ if (driver && driver->remove)
+ {
+ driver->remove(device);
+ }
+ rt_free(device);
+
+ return RT_EOK;
+}
+
+static rt_err_t spi_shutdown(rt_device_t dev)
+{
+ struct rt_spi_driver *driver = rt_container_of(dev->drv, struct rt_spi_driver, parent);
+ struct rt_spi_device *device = rt_container_of(dev, struct rt_spi_device, parent);
+
+ if (driver && driver->shutdown)
+ {
+ driver->shutdown(device);
+ }
+ rt_free(device);
+
+ return RT_EOK;
+}
+
+static struct rt_bus spi_bus =
+{
+ .name = "spi",
+ .match = spi_match,
+ .probe = spi_probe,
+ .remove = spi_remove,
+ .shutdown = spi_shutdown,
+};
+
+static int spi_bus_init(void)
+{
+ rt_bus_register(&spi_bus);
+
+ return 0;
+}
+INIT_CORE_EXPORT(spi_bus_init);
diff --git a/components/drivers/spi/dev_spi_core.c b/components/drivers/spi/dev_spi_core.c
index 648195544d..d84aaac055 100644
--- a/components/drivers/spi/dev_spi_core.c
+++ b/components/drivers/spi/dev_spi_core.c
@@ -19,6 +19,10 @@
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
+#ifdef RT_USING_DM
+#include "dev_spi_dm.h"
+#endif
+
extern rt_err_t rt_spi_bus_device_init(struct rt_spi_bus *bus, const char *name);
extern rt_err_t rt_spidev_device_init(struct rt_spi_device *dev, const char *name);
@@ -41,6 +45,46 @@ rt_err_t rt_spi_bus_register(struct rt_spi_bus *bus,
/* set bus mode */
bus->mode = RT_SPI_BUS_MODE_SPI;
+#ifdef RT_USING_DM
+ if (!bus->slave)
+ {
+ int pin_count = rt_pin_get_named_pin_count(&bus->parent, "cs");
+
+ if (pin_count > 0)
+ {
+ pin_count = rt_max_t(int, pin_count, bus->num_chipselect);
+ bus->pins = rt_malloc(sizeof(bus->pins[0]) * pin_count);
+
+ if (!bus->pins)
+ {
+ rt_device_unregister(&bus->parent);
+ return -RT_ENOMEM;
+ }
+
+ for (int i = 0; i < pin_count; ++i)
+ {
+ bus->pins[i] = rt_pin_get_named_pin(&bus->parent, "cs", i,
+ RT_NULL, RT_NULL);
+ }
+ }
+ else if (pin_count == 0)
+ {
+ bus->pins = RT_NULL;
+ }
+ else
+ {
+ result = pin_count;
+
+ LOG_E("CS PIN find error = %s", rt_strerror(result));
+
+ rt_device_unregister(&bus->parent);
+ return result;
+ }
+ }
+
+ spi_bus_scan_devices(bus);
+#endif
+
return RT_EOK;
}
diff --git a/components/drivers/spi/dev_spi_dm.c b/components/drivers/spi/dev_spi_dm.c
new file mode 100644
index 0000000000..063615ce62
--- /dev/null
+++ b/components/drivers/spi/dev_spi_dm.c
@@ -0,0 +1,106 @@
+/*
+ * 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 "dev_spi_dm.h"
+
+#define DBG_TAG "spi.dm"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#ifdef RT_USING_OFW
+static void ofw_parse_delay(struct rt_ofw_node *np, struct rt_spi_delay *delay,
+ const char *prop)
+{
+ rt_uint32_t value;
+
+ if (!rt_ofw_prop_read_u32(np, prop, &value))
+ {
+ if (value > RT_UINT16_MAX)
+ {
+ delay->value = RT_DIV_ROUND_UP(value, 1000);
+ delay->unit = RT_SPI_DELAY_UNIT_USECS;
+ }
+ else
+ {
+ delay->value = value;
+ delay->unit = RT_SPI_DELAY_UNIT_NSECS;
+ }
+ }
+}
+
+rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev)
+{
+ rt_err_t err;
+ rt_uint32_t value;
+ struct rt_spi_bus *spi_bus = spi_dev->bus;
+ struct rt_ofw_node *np = spi_dev->parent.ofw_node;
+ struct rt_spi_configuration *conf = &spi_dev->config;
+
+ if (rt_ofw_prop_read_bool(np, "spi-cpha"))
+ {
+ conf->mode |= RT_SPI_CPHA;
+ }
+ if (rt_ofw_prop_read_bool(np, "spi-cpol"))
+ {
+ conf->mode |= RT_SPI_CPOL;
+ }
+ if (rt_ofw_prop_read_bool(np, "spi-3wire"))
+ {
+ conf->mode |= RT_SPI_3WIRE;
+ }
+ if (rt_ofw_prop_read_bool(np, "spi-lsb-first"))
+ {
+ conf->mode |= RT_SPI_LSB;
+ }
+ if (rt_ofw_prop_read_bool(np, "spi-cs-high"))
+ {
+ conf->mode |= RT_SPI_CS_HIGH;
+ }
+
+ value = 1;
+ rt_ofw_prop_read_u32(np, "spi-tx-bus-width", &value);
+ conf->data_width_tx = value;
+
+ value = 1;
+ rt_ofw_prop_read_u32(np, "spi-rx-bus-width", &value);
+ conf->data_width_rx = value;
+
+ if (spi_bus->slave)
+ {
+ if (!rt_ofw_node_tag_equ(np, "slave"))
+ {
+ LOG_E("Invalid SPI device = %s", rt_ofw_node_full_name(np));
+
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+ }
+
+ if ((err = rt_ofw_prop_read_u32(np, "reg", &value)))
+ {
+ LOG_E("Find 'reg' failed");
+
+ return err;
+ }
+ spi_dev->chip_select = value;
+
+ if (!rt_ofw_prop_read_u32(np, "spi-max-frequency", &value))
+ {
+ conf->max_hz = value;
+ }
+
+ ofw_parse_delay(np, &spi_dev->cs_setup, "spi-cs-setup-delay-ns");
+ ofw_parse_delay(np, &spi_dev->cs_hold, "spi-cs-hold-delay-ns");
+ ofw_parse_delay(np, &spi_dev->cs_inactive, "spi-cs-inactive-delay-ns");
+
+ return RT_EOK;
+}
+#endif /* RT_USING_OFW */
diff --git a/components/drivers/spi/dev_spi_dm.h b/components/drivers/spi/dev_spi_dm.h
new file mode 100644
index 0000000000..c124295788
--- /dev/null
+++ b/components/drivers/spi/dev_spi_dm.h
@@ -0,0 +1,29 @@
+/*
+ * 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 __DEV_SPI_DM_H__
+#define __DEV_SPI_DM_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#ifdef RT_USING_OFW
+rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev);
+#else
+rt_inline rt_err_t spi_device_ofw_parse(struct rt_spi_device *spi_dev)
+{
+ return RT_EOK;
+}
+#endif /* RT_USING_OFW */
+
+void spi_bus_scan_devices(struct rt_spi_bus *bus);
+
+#endif /* __DEV_SPI_DM_H__ */