@@ -1976,6 +1976,10 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
gc->free(gc, gpio_chip_hwgpio(desc));
spin_lock_irqsave(&gpio_lock, flags);
}
+ spin_unlock_irqrestore(&gpio_lock, flags);
+ gpiod_rel_hw_timestamp_ns(desc);
+ spin_lock_irqsave(&gpio_lock, flags);
+
kfree_const(desc->label);
desc_set_label(desc, NULL);
clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
@@ -2388,6 +2392,75 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
}
EXPORT_SYMBOL_GPL(gpiod_direction_output);
+/**
+ * gpiod_req_hw_timestamp_ns - Enable the hardware assisted timestamp in
+ * nano second.
+ *
+ * @desc: GPIO to enable
+ * @cb: Callback, will be called when HTE pushes timestamp data.
+ * @tcb: Threaeded callback, it gets called from kernel thread context and when
+ * cb returns with HTE_RUN_THREADED_CB return value.
+ * @data: Client data, will be sent back with tcb and cb.
+ *
+ * Certain GPIO chip can rely on hardware assisted timestamp engines which can
+ * record timestamp at the occurance of the configured events
+ * i.e. rising/falling on specified GPIO lines. This is helper API to enable hw
+ * assisted timestamp in nano second.
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_req_hw_timestamp_ns(struct gpio_desc *desc, hte_ts_cb_t cb,
+ hte_ts_threaded_cb_t tcb, void *data)
+{
+ struct gpio_chip *gc;
+ int ret = 0;
+
+ VALIDATE_DESC(desc);
+ gc = desc->gdev->chip;
+
+ if (!gc->req_hw_timestamp) {
+ gpiod_warn(desc, "%s: hw ts not supported\n", __func__);
+ return -ENOTSUPP;
+ }
+
+ ret = gc->req_hw_timestamp(gc, gpio_chip_hwgpio(desc), cb, tcb,
+ &desc->hdesc, data);
+ if (ret)
+ gpiod_warn(desc, "%s: hw ts request failed\n", __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gpiod_req_hw_timestamp_ns);
+
+/**
+ * gpiod_rel_hw_timestamp_ns - Release and disable the hardware assisted
+ * timestamp.
+ *
+ * @desc: GPIO to disable
+ *
+ * Return 0 in case of success, else an error code.
+ */
+int gpiod_rel_hw_timestamp_ns(struct gpio_desc *desc)
+{
+ struct gpio_chip *gc;
+ int ret = 0;
+
+ VALIDATE_DESC(desc);
+ gc = desc->gdev->chip;
+
+ if (!gc->rel_hw_timestamp) {
+ gpiod_warn(desc, "%s: hw ts not supported\n", __func__);
+ return -ENOTSUPP;
+ }
+
+ ret = gc->rel_hw_timestamp(gc, gpio_chip_hwgpio(desc), &desc->hdesc);
+ if (ret)
+ gpiod_warn(desc, "%s: hw ts release failed\n", __func__);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(gpiod_rel_hw_timestamp_ns);
+
/**
* gpiod_set_config - sets @config for a GPIO
* @desc: descriptor of the GPIO for which to set the configuration
@@ -15,6 +15,7 @@
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cdev.h>
+#include <linux/hte.h>
#define GPIOCHIP_NAME "gpiochip"
@@ -117,6 +118,7 @@ struct gpio_desc {
#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
#define FLAG_EVENT_CLOCK_REALTIME 18 /* GPIO CDEV reports REALTIME timestamps in events */
+#define FLAG_EVENT_CLOCK_HARDWARE 19 /* GPIO CDEV reports hardware timestamps in events */
/* Connection label */
const char *label;
@@ -129,6 +131,16 @@ struct gpio_desc {
/* debounce period in microseconds */
unsigned int debounce_period_us;
#endif
+ /*
+ * Hardware timestamp engine related internal data structure.
+ * This gets filled out when the consumer calls
+ * gpiod_req_hw_timestamp_ns to enable hardware timestamping on the
+ * specified GPIO line. The API calls into HTE subsystem which
+ * initializes appropriate field of the hdesc. The hdesc will be later
+ * used with gpiod_rel_hw_timestamp to release hw timestamp
+ * functionality.
+ */
+ struct hte_ts_desc hdesc;
};
#define gpiod_not_found(desc) (IS_ERR(desc) && PTR_ERR(desc) == -ENOENT)
@@ -6,6 +6,7 @@
#include <linux/bug.h>
#include <linux/compiler_types.h>
#include <linux/err.h>
+#include <linux/hte.h>
struct device;
@@ -112,6 +113,9 @@ int gpiod_get_direction(struct gpio_desc *desc);
int gpiod_direction_input(struct gpio_desc *desc);
int gpiod_direction_output(struct gpio_desc *desc, int value);
int gpiod_direction_output_raw(struct gpio_desc *desc, int value);
+int gpiod_req_hw_timestamp_ns(struct gpio_desc *desc, hte_ts_cb_t cb,
+ hte_ts_threaded_cb_t tcb, void *data);
+int gpiod_rel_hw_timestamp_ns(struct gpio_desc *desc);
/* Value get/set from non-sleeping context */
int gpiod_get_value(const struct gpio_desc *desc);
@@ -353,8 +357,19 @@ static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
WARN_ON(desc);
return -ENOSYS;
}
-
-
+static inline int gpiod_req_hw_timestamp_ns(struct gpio_desc *desc,
+ hte_ts_cb_t cb,
+ hte_ts_threaded_cb_t tcb,
+ void *data)
+{
+ WARN_ON(desc);
+ return -ENOSYS;
+}
+static inline int gpiod_rel_hw_timestamp_ns(struct gpio_desc *desc)
+{
+ WARN_ON(desc);
+ return -ENOSYS;
+}
static inline int gpiod_get_value(const struct gpio_desc *desc)
{
/* GPIO can never have been requested */
@@ -10,6 +10,7 @@
#include <linux/lockdep.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/hte.h> /* For hardware timestamping */
struct gpio_desc;
struct of_phandle_args;
@@ -319,6 +320,10 @@ struct gpio_irq_chip {
* @add_pin_ranges: optional routine to initialize pin ranges, to be used when
* requires special mapping of the pins that provides GPIO functionality.
* It is called after adding GPIO chip and before adding IRQ chip.
+ * @req_hw_timestamp: Dependent on GPIO chip, an optional routine to
+ * enable hardware assisted timestamp.
+ * @rel_hw_timestamp: Dependent on GPIO chip, an optional routine to
+ * disable/release hardware assisted timestamp.
* @base: identifies the first GPIO number handled by this chip;
* or, if negative during registration, requests dynamic ID allocation.
* DEPRECATION: providing anything non-negative and nailing the base
@@ -414,6 +419,15 @@ struct gpio_chip {
int (*add_pin_ranges)(struct gpio_chip *gc);
+ int (*req_hw_timestamp)(struct gpio_chip *gc,
+ unsigned int offset,
+ hte_ts_cb_t cb,
+ hte_ts_threaded_cb_t tcb,
+ struct hte_ts_desc *hdesc,
+ void *data);
+ int (*rel_hw_timestamp)(struct gpio_chip *chip,
+ unsigned int offset,
+ struct hte_ts_desc *hdesc);
int base;
u16 ngpio;
u16 offset;