mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-01-19 10:03:31 +08:00
[DM/SPI] Support DM mode in SPI
Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
parent
49d18ec0a9
commit
6f68ca7c71
@ -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
|
||||
*
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
203
components/drivers/spi/dev_spi_bus.c
Normal file
203
components/drivers/spi/dev_spi_bus.c
Normal file
@ -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, ®_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);
|
@ -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;
|
||||
}
|
||||
|
||||
|
106
components/drivers/spi/dev_spi_dm.c
Normal file
106
components/drivers/spi/dev_spi_dm.c
Normal file
@ -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 */
|
29
components/drivers/spi/dev_spi_dm.h
Normal file
29
components/drivers/spi/dev_spi_dm.h
Normal file
@ -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__ */
|
Loading…
x
Reference in New Issue
Block a user