summaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rwxr-xr-xcomponents/drivers/Kconfig1
-rwxr-xr-xcomponents/drivers/include/drivers/ptp.h201
-rw-r--r--components/drivers/include/rtdevice.h4
-rwxr-xr-xcomponents/drivers/ptp/Kconfig8
-rwxr-xr-xcomponents/drivers/ptp/SConscript15
-rwxr-xr-xcomponents/drivers/ptp/ptp.c650
-rw-r--r--components/libc/compilers/common/ctime.c156
-rw-r--r--components/libc/compilers/common/include/sys/time.h8
8 files changed, 1043 insertions, 0 deletions
diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig
index efe7431a55..db0334f42b 100755
--- a/components/drivers/Kconfig
+++ b/components/drivers/Kconfig
@@ -21,6 +21,7 @@ rsource "touch/Kconfig"
rsource "graphic/Kconfig"
rsource "hwcrypto/Kconfig"
rsource "wlan/Kconfig"
+rsource "ptp/Kconfig"
rsource "led/Kconfig"
rsource "input/Kconfig"
rsource "mailbox/Kconfig"
diff --git a/components/drivers/include/drivers/ptp.h b/components/drivers/include/drivers/ptp.h
new file mode 100755
index 0000000000..f12c2fea27
--- /dev/null
+++ b/components/drivers/include/drivers/ptp.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-04-23 GuEe-GUI first version
+ */
+
+#ifndef __PTP_H__
+#define __PTP_H__
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <drivers/misc.h>
+
+struct rt_ptp_pin;
+struct rt_ptp_ops;
+
+struct rt_ptp_clock
+{
+ struct rt_device parent;
+
+ const struct rt_ptp_ops *ops;
+
+ /* Maximum frequency adjustment in ppb (parts per billion), required when adjfreq is implemented */
+ rt_int32_t max_freq;
+ rt_int32_t alarm_nr;
+ rt_int32_t pins_nr;
+ rt_int32_t extts_nr;
+ rt_int32_t perout_nr;
+ rt_int32_t pps;
+
+ rt_list_t notifier_nodes;
+ struct rt_spinlock nodes_lock;
+
+ struct rt_ptp_pin *pins;
+ struct rt_mutex pin_mutex;
+};
+#define rt_device_to_ptp_clock(dev) rt_container_of(dev, struct rt_ptp_clock, parent)
+
+struct rt_ptp_clock_time
+{
+ rt_int64_t sec;
+ rt_int32_t nsec;
+};
+
+enum
+{
+ PTP_CLOCK_EV_ALARM,
+ PTP_CLOCK_EV_EXTTS,
+ PTP_CLOCK_EV_EXTOFF,
+ PTP_CLOCK_EV_PPS,
+ PTP_CLOCK_EV_PPSUSR,
+
+ PTP_CLOCK_EV_MAX,
+};
+
+struct rt_ptp_clock_event
+{
+ rt_uint32_t type;
+ rt_uint32_t index;
+
+ union
+ {
+ rt_uint64_t timestamp;
+ rt_int64_t offset;
+ struct rt_ptp_clock_time pps_times;
+ };
+};
+
+struct rt_ptp_clock_notifier
+{
+ rt_list_t list;
+ rt_uint32_t event_mask;
+
+ struct rt_ptp_clock *ptp;
+ void (*callback)(struct rt_ptp_clock_notifier *notifier, struct rt_ptp_clock_event *ev);
+
+ void *priv;
+};
+
+enum
+{
+ PTP_PIN_FUNC_NONE,
+ PTP_PIN_FUNC_EXTTS,
+ PTP_PIN_FUNC_PEROUT,
+ PTP_PIN_FUNC_PHYSYNC,
+
+ PTP_PIN_FUNC_MAX,
+};
+
+struct rt_ptp_pin
+{
+ char name[64];
+
+ rt_uint32_t func;
+ rt_uint32_t chan;
+};
+
+struct rt_ptp_request_extts
+{
+ rt_uint32_t chan;
+
+#define PTP_ENABLE_FEATURE RT_BIT(0)
+#define PTP_RISING_EDGE RT_BIT(1)
+#define PTP_FALLING_EDGE RT_BIT(2)
+#define PTP_STRICT_FLAGS RT_BIT(3)
+#define PTP_EXTTS_EDGES (PTP_RISING_EDGE | PTP_FALLING_EDGE)
+ rt_uint32_t flags;
+};
+
+struct rt_ptp_request_perout
+{
+ rt_uint32_t chan;
+
+#define PTP_PEROUT_ONE_SHOT RT_BIT(0)
+#define PTP_PEROUT_DUTY_CYCLE RT_BIT(1)
+#define PTP_PEROUT_PHASE RT_BIT(2)
+ rt_uint32_t flags;
+
+ /* Desired period, zero means disable */
+ struct rt_ptp_clock_time period;
+ /* The "on" time of the signal, must be lower than the period */
+ struct rt_ptp_clock_time on;
+ /* Absolute start time or phase offset */
+ struct rt_ptp_clock_time start_phase;
+};
+
+enum
+{
+ PTP_CLK_REQ_EXTTS,
+ PTP_CLK_REQ_PEROUT,
+ PTP_CLK_REQ_PPS,
+
+ PTP_CLK_REQ_MAX,
+};
+
+struct rt_ptp_clock_request
+{
+ rt_uint32_t type;
+
+ union
+ {
+ struct rt_ptp_request_extts extts;
+ struct rt_ptp_request_perout perout;
+ };
+};
+
+struct rt_ptp_ops
+{
+ rt_err_t (*adjfreq)(struct rt_ptp_clock *ptp, rt_base_t freq);
+ rt_err_t (*adjphase)(struct rt_ptp_clock *ptp, rt_int32_t phase);
+ rt_err_t (*getmaxphase)(struct rt_ptp_clock *ptp, rt_int32_t *out_maxphase);
+ rt_err_t (*adjtime)(struct rt_ptp_clock *ptp, rt_int64_t delta);
+ rt_err_t (*gettime)(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts);
+ rt_err_t (*settime)(struct rt_ptp_clock *ptp, const struct rt_ptp_clock_time *ts);
+ rt_err_t (*enable)(struct rt_ptp_clock *ptp, struct rt_ptp_clock_request *request, rt_bool_t on);
+ rt_err_t (*verify)(struct rt_ptp_clock *ptp, rt_uint32_t pin, rt_uint32_t func, rt_uint32_t chan);
+ rt_err_t (*getsnapshot)(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts);
+};
+
+rt_err_t rt_ptp_clock_register(struct rt_ptp_clock *ptp);
+rt_err_t rt_ptp_clock_unregister(struct rt_ptp_clock *ptp);
+
+rt_err_t rt_ptp_clock_notifier_register(struct rt_ptp_clock *ptp,
+ struct rt_ptp_clock_notifier *notifier);
+rt_err_t rt_ptp_clock_notifier_unregister(struct rt_ptp_clock *ptp,
+ struct rt_ptp_clock_notifier *notifier);
+
+void rt_ptp_clock_event(struct rt_ptp_clock *ptp, struct rt_ptp_clock_event *ev);
+
+rt_err_t rt_ptp_adjfreq(struct rt_ptp_clock *ptp, rt_base_t freq);
+
+rt_err_t rt_ptp_adjphase(struct rt_ptp_clock *ptp, rt_int32_t phase);
+rt_err_t rt_ptp_getmaxphase(struct rt_ptp_clock *ptp, rt_int32_t *out_maxphase);
+
+rt_err_t rt_ptp_adjtime(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts);
+
+rt_err_t rt_ptp_gettime(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts);
+rt_err_t rt_ptp_settime(struct rt_ptp_clock *ptp, const struct rt_ptp_clock_time *ts);
+
+rt_err_t rt_ptp_request_extts(struct rt_ptp_clock *ptp,
+ struct rt_ptp_request_extts *extts);
+rt_err_t rt_ptp_request_perout(struct rt_ptp_clock *ptp,
+ struct rt_ptp_request_perout *perout);
+rt_err_t rt_ptp_enable_pps(struct rt_ptp_clock *ptp, rt_bool_t on);
+
+rt_err_t rt_ptp_get_pin_func(struct rt_ptp_clock *ptp,
+ rt_uint32_t pin, struct rt_ptp_pin *out_pin);
+/*
+ * Assign pin function only updates pin routing metadata.
+ * Call rt_ptp_request_extts() or rt_ptp_request_perout() separately to enable hardware.
+ */
+rt_err_t rt_ptp_set_pin_func(struct rt_ptp_clock *ptp,
+ rt_uint32_t pin, rt_uint32_t func, rt_uint32_t chan);
+
+rt_err_t rt_ptp_getsnapshot(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts);
+
+#endif /* __PTP_H__ */
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index b416b5e928..e6eb43bc57 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -64,6 +64,10 @@ extern "C" {
#include "drivers/led.h"
#endif /* RT_USING_LED */
+#ifdef RT_USING_PTP
+#include "drivers/ptp.h"
+#endif /* RT_USING_PTP */
+
#ifdef RT_USING_INPUT
#include "drivers/input.h"
#ifdef RT_INPUT_UAPI
diff --git a/components/drivers/ptp/Kconfig b/components/drivers/ptp/Kconfig
new file mode 100755
index 0000000000..b07d9ae686
--- /dev/null
+++ b/components/drivers/ptp/Kconfig
@@ -0,0 +1,8 @@
+menuconfig RT_USING_PTP
+ bool "Using Precision Time Protocol (PTP) IEEE 1588 clock support"
+ depends on RT_USING_DM
+ default n
+
+if RT_USING_PTP
+ osource "$(SOC_DM_PTP_DIR)/Kconfig"
+endif
diff --git a/components/drivers/ptp/SConscript b/components/drivers/ptp/SConscript
new file mode 100755
index 0000000000..fb10e8a905
--- /dev/null
+++ b/components/drivers/ptp/SConscript
@@ -0,0 +1,15 @@
+from building import *
+
+group = []
+
+if not GetDepend(['RT_USING_PTP']):
+ Return('group')
+
+cwd = GetCurrentDir()
+CPPPATH = [cwd + '/../include']
+
+src = ['ptp.c']
+
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
+
+Return('group')
diff --git a/components/drivers/ptp/ptp.c b/components/drivers/ptp/ptp.c
new file mode 100755
index 0000000000..bde7a50186
--- /dev/null
+++ b/components/drivers/ptp/ptp.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2023-04-23 GuEe-GUI first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "rtdm.ptp"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#define NSEC_PER_SEC 1000000000L
+
+static struct rt_dm_ida ptp_ida = RT_DM_IDA_INIT(PTP);
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops _ptp_ops =
+{
+};
+#endif
+
+rt_err_t rt_ptp_clock_register(struct rt_ptp_clock *ptp)
+{
+ rt_err_t err;
+ int device_id;
+ const char *dev_name;
+ char name[RT_NAME_MAX];
+
+ if (!ptp || !ptp->ops)
+ {
+ return -RT_EINVAL;
+ }
+
+ if ((device_id = rt_dm_ida_alloc(&ptp_ida)) < 0)
+ {
+ return -RT_EFULL;
+ }
+
+ rt_dm_dev_set_name(&ptp->parent, "ptp%u", device_id);
+ dev_name = rt_dm_dev_get_name(&ptp->parent);
+
+ if (ptp->pins_nr)
+ {
+ if (!ptp->pins)
+ {
+ LOG_E("%s: found %d pin but pins is NULL", dev_name, ptp->pins_nr);
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ if (!ptp->ops->verify)
+ {
+ LOG_E("%s: found %d pin but verify is not supported", dev_name, ptp->pins_nr);
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ rt_snprintf(name, sizeof(name), "%s-pin", dev_name);
+ rt_mutex_init(&ptp->pin_mutex, name, RT_IPC_FLAG_PRIO);
+ }
+
+ if ((ptp->perout_nr || ptp->extts_nr) && !ptp->ops->enable)
+ {
+ LOG_E("%s: perout(%u) or extts(%u) but enable is not supported",
+ dev_name, ptp->perout_nr, ptp->extts_nr);
+ err = -RT_EINVAL;
+ goto _free_mutex;
+ }
+
+ if (ptp->ops->adjfreq && ptp->max_freq <= 0)
+ {
+ LOG_E("%s: adjfreq is supported but max_freq is not set", dev_name);
+ err = -RT_EINVAL;
+ goto _free_mutex;
+ }
+
+ rt_list_init(&ptp->notifier_nodes);
+ rt_spin_lock_init(&ptp->nodes_lock);
+
+ /* Just make a search interface */
+ ptp->parent.type = RT_Device_Class_Char;
+#ifdef RT_USING_DEVICE_OPS
+ ptp->parent.ops = ptp->parent.ops ? : &_ptp_ops;
+#endif
+ ptp->parent.master_id = ptp_ida.master_id;
+ ptp->parent.device_id = device_id;
+
+ if ((err = rt_device_register(&ptp->parent, dev_name, RT_DEVICE_FLAG_DEACTIVATE)))
+ {
+ goto _free_mutex;
+ }
+
+ return RT_EOK;
+
+_free_mutex:
+ if (ptp->pins_nr)
+ {
+ rt_mutex_detach(&ptp->pin_mutex);
+ }
+
+_fail:
+ rt_dm_ida_free(&ptp_ida, device_id);
+
+ return err;
+}
+
+rt_err_t rt_ptp_clock_unregister(struct rt_ptp_clock *ptp)
+{
+ struct rt_ptp_request_perout perout;
+ struct rt_ptp_request_extts extts;
+
+ if (!ptp)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (ptp->parent.ref_count)
+ {
+ LOG_E("%s: there is %u user",
+ rt_dm_dev_get_name(&ptp->parent), ptp->parent.ref_count);
+ return -RT_EINVAL;
+ }
+
+ if (!rt_list_isempty(&ptp->notifier_nodes))
+ {
+ LOG_W("%s: notifier not unregister", rt_dm_dev_get_name(&ptp->parent));
+ }
+
+ rt_memset(&extts, 0, sizeof(extts));
+
+ for (int i = 0; i < ptp->extts_nr; ++i)
+ {
+ extts.chan = i;
+ rt_ptp_request_extts(ptp, &extts);
+ }
+
+ rt_memset(&perout, 0, sizeof(perout));
+ perout.flags = PTP_PEROUT_ONE_SHOT;
+
+ for (int i = 0; i < ptp->perout_nr; ++i)
+ {
+ perout.chan = i;
+ rt_ptp_request_perout(ptp, &perout);
+ }
+
+ rt_ptp_enable_pps(ptp, RT_FALSE);
+
+ if (ptp->pins_nr)
+ {
+ rt_mutex_detach(&ptp->pin_mutex);
+ }
+
+ rt_dm_ida_free(&ptp_ida, ptp->parent.device_id);
+
+ return rt_device_unregister(&ptp->parent);
+}
+
+rt_err_t rt_ptp_clock_notifier_register(struct rt_ptp_clock *ptp,
+ struct rt_ptp_clock_notifier *notifier)
+{
+ if (!ptp || !notifier)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!notifier->event_mask)
+ {
+ LOG_E("%s: clock notifier event mask is empty, try to set 0~%u",
+ rt_dm_dev_get_name(&ptp->parent), PTP_CLOCK_EV_MAX - 1);
+ return -RT_EINVAL;
+ }
+
+ notifier->ptp = ptp;
+ rt_list_init(&notifier->list);
+
+ rt_spin_lock(&ptp->nodes_lock);
+ rt_list_insert_after(&ptp->notifier_nodes, &notifier->list);
+ rt_spin_unlock(&ptp->nodes_lock);
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ptp_clock_notifier_unregister(struct rt_ptp_clock *ptp,
+ struct rt_ptp_clock_notifier *notifier)
+{
+ if (!ptp || !notifier)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_spin_lock(&ptp->nodes_lock);
+ rt_list_remove(&notifier->list);
+ rt_spin_unlock(&ptp->nodes_lock);
+
+ return RT_EOK;
+}
+
+void rt_ptp_clock_event(struct rt_ptp_clock *ptp, struct rt_ptp_clock_event *ev)
+{
+ struct rt_ptp_clock_notifier *notifier, *next_notifier;
+
+ RT_ASSERT(ptp != RT_NULL);
+ RT_ASSERT(ev->type < PTP_CLOCK_EV_MAX);
+
+ rt_spin_lock(&ptp->nodes_lock);
+
+ rt_list_for_each_entry_safe(notifier, next_notifier, &ptp->notifier_nodes, list)
+ {
+ if (notifier->event_mask & RT_BIT(ev->type))
+ {
+ rt_spin_unlock(&ptp->nodes_lock);
+
+ notifier->callback(notifier, ev);
+
+ rt_spin_lock(&ptp->nodes_lock);
+ }
+ }
+
+ rt_spin_unlock(&ptp->nodes_lock);
+}
+
+rt_err_t rt_ptp_adjfreq(struct rt_ptp_clock *ptp, rt_base_t freq)
+{
+ if (!ptp)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->adjfreq)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (ptp->max_freq <= 0)
+ {
+ if (freq != 0)
+ {
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+ }
+
+ if (freq > ptp->max_freq || freq < -ptp->max_freq)
+ {
+ return -RT_EINVAL;
+ }
+
+ return ptp->ops->adjfreq(ptp, freq);
+}
+
+rt_err_t rt_ptp_adjphase(struct rt_ptp_clock *ptp, rt_int32_t phase)
+{
+ rt_err_t err;
+ rt_int32_t maxphase;
+
+ if (!ptp)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->adjphase)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if ((err = rt_ptp_getmaxphase(ptp, &maxphase)))
+ {
+ return err;
+ }
+
+ if (phase > maxphase || phase < -maxphase)
+ {
+ return -RT_EINVAL;
+ }
+
+ return ptp->ops->adjphase(ptp, phase);
+}
+
+rt_err_t rt_ptp_getmaxphase(struct rt_ptp_clock *ptp, rt_int32_t *out_maxphase)
+{
+ if (!ptp || !out_maxphase)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->getmaxphase)
+ {
+ return -RT_ENOSYS;
+ }
+
+ return ptp->ops->getmaxphase(ptp, out_maxphase);
+}
+
+rt_err_t rt_ptp_adjtime(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts)
+{
+ rt_int64_t delta;
+
+ if (!ptp || !ts)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->adjtime)
+ {
+ return -RT_ENOSYS;
+ }
+
+ if (ts->nsec < 0 || (rt_int64_t)ts->nsec >= NSEC_PER_SEC)
+ {
+ return -RT_EINVAL;
+ }
+
+ delta = ts->sec * NSEC_PER_SEC + (rt_int64_t)ts->nsec;
+
+ return ptp->ops->adjtime(ptp, delta);
+}
+
+rt_err_t rt_ptp_gettime(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts)
+{
+ if (!ptp || !ts)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->gettime)
+ {
+ return -RT_ENOSYS;
+ }
+
+ return ptp->ops->gettime(ptp, ts);
+}
+
+rt_err_t rt_ptp_settime(struct rt_ptp_clock *ptp, const struct rt_ptp_clock_time *ts)
+{
+ if (!ptp || !ts)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->settime)
+ {
+ return -RT_ENOSYS;
+ }
+
+ return ptp->ops->settime(ptp, ts);
+}
+
+rt_err_t rt_ptp_request_extts(struct rt_ptp_clock *ptp,
+ struct rt_ptp_request_extts *extts)
+{
+ rt_bool_t enable;
+ struct rt_ptp_clock_request request;
+
+ if (!ptp || !extts)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (extts->chan >= ptp->extts_nr)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (extts->flags & PTP_STRICT_FLAGS)
+ {
+ /* Ensure one of the rising/falling edge bits is set */
+ if ((extts->flags & PTP_ENABLE_FEATURE) &&
+ (extts->flags & PTP_EXTTS_EDGES) == 0)
+ {
+ return -RT_EINVAL;
+ }
+ }
+
+ if (!ptp->ops->enable)
+ {
+ return -RT_ENOSYS;
+ }
+
+ request.type = PTP_CLK_REQ_EXTTS;
+ rt_memcpy(&request.extts, extts, sizeof(*extts));
+ enable = !!(extts->flags & PTP_ENABLE_FEATURE);
+
+ return ptp->ops->enable(ptp, &request, enable);
+}
+
+rt_err_t rt_ptp_request_perout(struct rt_ptp_clock *ptp,
+ struct rt_ptp_request_perout *perout)
+{
+ rt_bool_t enable;
+ struct rt_ptp_clock_request request;
+
+ if (!ptp || !perout)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (perout->chan >= ptp->perout_nr)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (perout->flags & PTP_STRICT_FLAGS)
+ {
+ if (perout->flags & PTP_PEROUT_DUTY_CYCLE)
+ {
+ /* The duty cycle must be subunitary */
+ if (perout->on.sec > perout->period.sec ||
+ (perout->on.sec == perout->period.sec &&
+ perout->on.nsec > perout->period.nsec))
+ {
+ return -RT_EINVAL;
+ }
+ }
+
+ if (perout->flags & PTP_PEROUT_PHASE)
+ {
+ /*
+ * The phase should be specified modulo the period,
+ * therefore anything equal or larger than 1 period is invalid
+ */
+ if (perout->start_phase.sec > perout->period.sec ||
+ (perout->start_phase.sec == perout->period.sec &&
+ perout->start_phase.nsec >= perout->period.nsec))
+ {
+ return -RT_EINVAL;
+ }
+ }
+ }
+
+ if (!ptp->ops->enable)
+ {
+ return -RT_ENOSYS;
+ }
+
+ request.type = PTP_CLK_REQ_PEROUT;
+ rt_memcpy(&request.perout, perout, sizeof(*perout));
+ enable = perout->period.sec || perout->period.nsec;
+
+ return ptp->ops->enable(ptp, &request, enable);
+}
+
+rt_err_t rt_ptp_enable_pps(struct rt_ptp_clock *ptp, rt_bool_t on)
+{
+ struct rt_ptp_clock_request request;
+
+ if (!ptp)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->enable)
+ {
+ return -RT_ENOSYS;
+ }
+
+ request.type = PTP_CLK_REQ_PPS;
+
+ return ptp->ops->enable(ptp, &request, on);
+}
+
+rt_err_t rt_ptp_get_pin_func(struct rt_ptp_clock *ptp,
+ rt_uint32_t pin, struct rt_ptp_pin *out_pin)
+{
+ if (!ptp || !out_pin)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (pin >= ptp->pins_nr)
+ {
+ if (!ptp->pins_nr)
+ {
+ return -RT_ENOSYS;
+ }
+
+ return -RT_EINVAL;
+ }
+
+ rt_mutex_take(&ptp->pin_mutex, RT_WAITING_FOREVER);
+
+ rt_memcpy(out_pin, &ptp->pins[pin], sizeof(*out_pin));
+
+ rt_mutex_release(&ptp->pin_mutex);
+
+ return RT_EOK;
+}
+
+static rt_err_t ptp_disable_pin_func(struct rt_ptp_clock *ptp,
+ rt_uint32_t func, rt_uint32_t chan)
+{
+ rt_err_t err = RT_EOK;
+ struct rt_ptp_request_extts extts;
+ struct rt_ptp_request_perout perout;
+
+ switch (func)
+ {
+ case PTP_PIN_FUNC_NONE:
+ case PTP_PIN_FUNC_PHYSYNC:
+ break;
+
+ case PTP_PIN_FUNC_EXTTS:
+ rt_memset(&extts, 0, sizeof(extts));
+ extts.chan = chan;
+ err = rt_ptp_request_extts(ptp, &extts);
+ break;
+
+ case PTP_PIN_FUNC_PEROUT:
+ rt_memset(&perout, 0, sizeof(perout));
+ perout.chan = chan;
+ err = rt_ptp_request_perout(ptp, &perout);
+ break;
+
+ default:
+ err = -RT_EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+static rt_err_t ptp_set_pin_func(struct rt_ptp_clock *ptp,
+ rt_uint32_t pin, rt_uint32_t func, rt_uint32_t chan)
+{
+ int i;
+ rt_err_t err;
+ struct rt_ptp_pin *pin1 = RT_NULL, *pin2 = &ptp->pins[pin];
+
+ for (i = 0; i < ptp->pins_nr; ++i)
+ {
+ if (ptp->pins[i].func == func && ptp->pins[i].chan == chan)
+ {
+ pin1 = &ptp->pins[i];
+ break;
+ }
+ }
+
+ /* Configure already, do nothing */
+ if (pin1 && i == pin)
+ {
+ return RT_EOK;
+ }
+
+ switch (func)
+ {
+ case PTP_PIN_FUNC_NONE:
+ break;
+
+ case PTP_PIN_FUNC_EXTTS:
+ if (chan >= ptp->extts_nr)
+ {
+ return -RT_EINVAL;
+ }
+ break;
+
+ case PTP_PIN_FUNC_PEROUT:
+ if (chan >= ptp->perout_nr)
+ {
+ return -RT_EINVAL;
+ }
+ break;
+
+ case PTP_PIN_FUNC_PHYSYNC:
+ if (chan != 0)
+ {
+ return -RT_EINVAL;
+ }
+ break;
+
+ default:
+ return -RT_EINVAL;
+ }
+
+ if ((err = ptp->ops->verify(ptp, pin, func, chan)))
+ {
+ LOG_E("%s: pin %u function %u channel %u error = %s",
+ rt_dm_dev_get_name(&ptp->parent), pin, func, chan, rt_strerror(err));
+ return err;
+ }
+
+ /* Disable configure before, update new configure */
+ if (pin1)
+ {
+ ptp_disable_pin_func(ptp, func, chan);
+ pin1->func = PTP_PIN_FUNC_NONE;
+ pin1->chan = 0;
+ }
+
+ ptp_disable_pin_func(ptp, pin2->func, pin2->chan);
+ pin2->func = func;
+ pin2->chan = chan;
+
+ return RT_EOK;
+}
+
+rt_err_t rt_ptp_set_pin_func(struct rt_ptp_clock *ptp,
+ rt_uint32_t pin, rt_uint32_t func, rt_uint32_t chan)
+{
+ rt_err_t err;
+
+ if (!ptp)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (pin >= ptp->pins_nr)
+ {
+ if (!ptp->pins_nr)
+ {
+ return -RT_ENOSYS;
+ }
+
+ return -RT_EINVAL;
+ }
+
+ if (func >= PTP_PIN_FUNC_MAX)
+ {
+ return -RT_EINVAL;
+ }
+
+ rt_mutex_take(&ptp->pin_mutex, RT_WAITING_FOREVER);
+
+ err = ptp_set_pin_func(ptp, pin, func, chan);
+
+ rt_mutex_release(&ptp->pin_mutex);
+
+ return err;
+}
+
+rt_err_t rt_ptp_getsnapshot(struct rt_ptp_clock *ptp, struct rt_ptp_clock_time *ts)
+{
+ if (!ptp || !ts)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!ptp->ops->getsnapshot)
+ {
+ return -RT_ENOSYS;
+ }
+
+ return ptp->ops->getsnapshot(ptp, ts);
+}
diff --git a/components/libc/compilers/common/ctime.c b/components/libc/compilers/common/ctime.c
index 3e1ea77fd7..60d5dc74a4 100644
--- a/components/libc/compilers/common/ctime.c
+++ b/components/libc/compilers/common/ctime.c
@@ -45,6 +45,13 @@
#ifdef RT_USING_CLOCK_TIME
#include <drivers/clock_time.h>
#endif
+#ifdef RT_USING_PTP
+#include <drivers/ptp.h>
+#ifdef RT_USING_POSIX_FS
+#include <dfs.h>
+#include <dfs_file.h>
+#endif /* RT_USING_POSIX_FS */
+#endif /* RT_USING_PTP */
#define DBG_TAG "time"
#define DBG_LVL DBG_INFO
@@ -611,6 +618,134 @@ RTM_EXPORT(nanosleep);
#if defined(RT_USING_POSIX_CLOCK) && defined(RT_USING_CLOCK_TIME)
+#ifdef RT_USING_PTP
+
+static rt_bool_t _clockid_is_ptp_fd(clockid_t clockid)
+{
+ return (clockid & 7) == CLOCKFD;
+}
+
+static struct rt_ptp_clock *_ptp_clock_from_clockid(clockid_t clockid)
+{
+ unsigned int fd;
+ struct rt_ptp_clock *ptp;
+ rt_device_t dev;
+
+#ifndef RT_USING_POSIX_FS
+ RT_UNUSED(fd);
+ RT_UNUSED(ptp);
+ RT_UNUSED(dev);
+ return RT_NULL;
+#else
+ struct dfs_file *file;
+
+ if (!_clockid_is_ptp_fd(clockid))
+ {
+ return RT_NULL;
+ }
+
+ fd = CLOCKID_TO_FD(clockid);
+ file = fd_get((int)fd);
+ if (!file || !file->vnode || !file->vnode->data)
+ {
+ return RT_NULL;
+ }
+
+ dev = (rt_device_t)file->vnode->data;
+ if (dev->type != RT_Device_Class_Char)
+ {
+ return RT_NULL;
+ }
+
+ if (rt_strncmp(rt_dm_dev_get_name(dev), "ptp", 3) != 0)
+ {
+ return RT_NULL;
+ }
+
+ ptp = rt_device_to_ptp_clock(dev);
+ if (!ptp->ops || !ptp->ops->gettime)
+ {
+ return RT_NULL;
+ }
+
+ return ptp;
+#endif /* RT_USING_POSIX_FS */
+}
+
+static int _clock_gettime_ptp(clockid_t clockid, struct timespec *tp)
+{
+ struct rt_ptp_clock *ptp;
+ struct rt_ptp_clock_time ts;
+ rt_err_t err;
+
+ ptp = _ptp_clock_from_clockid(clockid);
+ if (!ptp)
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+
+ err = rt_ptp_gettime(ptp, &ts);
+ if (err != RT_EOK)
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+
+ tp->tv_sec = (time_t)ts.sec;
+ tp->tv_nsec = ts.nsec;
+
+ return 0;
+}
+
+static int _clock_settime_ptp(clockid_t clockid, const struct timespec *tp)
+{
+ struct rt_ptp_clock *ptp;
+ struct rt_ptp_clock_time ts;
+ rt_err_t err;
+
+ ptp = _ptp_clock_from_clockid(clockid);
+ if (!ptp)
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+
+ if (!ptp->ops->settime)
+ {
+ rt_set_errno(EPERM);
+ return -1;
+ }
+
+ ts.sec = tp->tv_sec;
+ ts.nsec = (rt_int32_t)tp->tv_nsec;
+
+ err = rt_ptp_settime(ptp, &ts);
+ if (err != RT_EOK)
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _clock_getres_ptp(clockid_t clockid, struct timespec *res)
+{
+ if (!_ptp_clock_from_clockid(clockid))
+ {
+ rt_set_errno(EINVAL);
+ return -1;
+ }
+
+ res->tv_sec = 0;
+ res->tv_nsec = 1;
+
+ return 0;
+}
+
+#endif /* RT_USING_PTP */
+
int clock_getres(clockid_t clockid, struct timespec *res)
{
if (res == RT_NULL)
@@ -619,6 +754,13 @@ int clock_getres(clockid_t clockid, struct timespec *res)
return -1;
}
+#ifdef RT_USING_PTP
+ if (_clockid_is_ptp_fd(clockid))
+ {
+ return _clock_getres_ptp(clockid, res);
+ }
+#endif /* RT_USING_PTP */
+
switch (clockid)
{
case CLOCK_REALTIME: // use RTC
@@ -652,6 +794,13 @@ int clock_gettime(clockid_t clockid, struct timespec *tp)
return -1;
}
+#ifdef RT_USING_PTP
+ if (_clockid_is_ptp_fd(clockid))
+ {
+ return _clock_gettime_ptp(clockid, tp);
+ }
+#endif /* RT_USING_PTP */
+
switch (clockid)
{
case CLOCK_REALTIME: // use RTC
@@ -750,6 +899,13 @@ int clock_settime(clockid_t clockid, const struct timespec *tp)
return -1;
}
+#ifdef RT_USING_PTP
+ if (_clockid_is_ptp_fd(clockid))
+ {
+ return _clock_settime_ptp(clockid, tp);
+ }
+#endif /* RT_USING_PTP */
+
switch (clockid)
{
#ifdef RT_USING_RTC
diff --git a/components/libc/compilers/common/include/sys/time.h b/components/libc/compilers/common/include/sys/time.h
index 817fe78676..8804433eeb 100644
--- a/components/libc/compilers/common/include/sys/time.h
+++ b/components/libc/compilers/common/include/sys/time.h
@@ -198,6 +198,14 @@ int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
#define CLOCK_TAI 11 // newlib says they don't have this definition, make the compiler happy
#endif /* CLOCK_TAI */
+#ifdef RT_USING_PTP
+#ifndef CLOCKFD
+#define CLOCKFD 3
+#endif /* CLOCKFD */
+#define FD_TO_CLOCKID(fd) ((clockid_t)((~(clockid_t)(fd) << 3) | CLOCKFD))
+#define CLOCKID_TO_FD(clk) ((unsigned int)(~((unsigned int)(clk) >> 3)))
+#endif /* RT_USING_PTP */
+
#endif /* defined(RT_USING_POSIX_CLOCK) || defined (RT_USING_POSIX_TIMER) */
#ifdef RT_USING_POSIX_CLOCK