// SPDX-License-Identifier: GPL-2.0-only /* * Sloppy logic analyzer using GPIOs (to be run on an isolated CPU) * * Use the 'gpio-sloppy-logic-analyzer' script in the 'tools/gpio' folder for * easier usage and further documentation. Note that this is a last resort * analyzer which can be affected by latencies and non-deterministic code * paths. However, for e.g. remote development, it may be useful to get a first * view and aid further debugging. * * Copyright (C) Wolfram Sang <wsa@sang-engineering.com> * Copyright (C) Renesas Electronics Corporation
*/
#define GPIO_LA_NAME "gpio-sloppy-logic-analyzer" #define GPIO_LA_DEFAULT_BUF_SIZE SZ_256K /* can be increased but then we need to extend the u8 buffers */ #define GPIO_LA_MAX_PROBES 8 #define GPIO_LA_NUM_TESTS 1024
static __always_inline int gpio_la_get_array(struct gpio_descs *d, unsignedlong *sptr)
{ int ret;
ret = gpiod_get_array_value(d->ndescs, d->desc, d->info, sptr); if (ret == 0 && fatal_signal_pending(current))
ret = -EINTR;
return ret;
}
staticint fops_capture_set(void *data, u64 val)
{ struct gpio_la_poll_priv *priv = data;
u8 *la_buf = priv->blob.data; unsignedlong state = 0; /* zeroed because GPIO arrays are bitfields */ unsignedlong delay;
ktime_t start_time; unsignedint i; int ret;
if (!val) return 0;
if (!la_buf) return -ENOMEM;
if (!priv->delay_ns) return -EINVAL;
mutex_lock(&priv->blob_lock); if (priv->blob_dent) {
debugfs_remove(priv->blob_dent);
priv->blob_dent = NULL;
}
priv->buf_idx = 0;
local_irq_disable();
preempt_disable_notrace();
/* Measure delay of reading GPIOs */
start_time = ktime_get(); for (i = 0; i < GPIO_LA_NUM_TESTS; i++) {
ret = gpio_la_get_array(priv->descs, &state); if (ret) goto out;
}
priv->acq_delay = ktime_sub(ktime_get(), start_time) / GPIO_LA_NUM_TESTS; if (priv->delay_ns < priv->acq_delay) {
ret = -ERANGE; goto out;
}
delay = priv->delay_ns - priv->acq_delay;
/* Wait for triggers */ for (i = 0; i < priv->trig_len; i += 2) { do {
ret = gpio_la_get_array(priv->descs, &state); if (ret) goto out;
priv->descs = devm_gpiod_get_array(dev, "probe", GPIOD_IN); if (IS_ERR(priv->descs)) return PTR_ERR(priv->descs);
/* artificial limit to keep 1 byte per sample for now */ if (priv->descs->ndescs > GPIO_LA_MAX_PROBES) return -EFBIG;
ret = device_property_read_string_array(dev, "probe-names", gpio_names,
priv->descs->ndescs); if (ret >= 0 && ret != priv->descs->ndescs)
ret = -EBADR; if (ret < 0) return dev_err_probe(dev, ret, "error naming the GPIOs");
for (i = 0; i < priv->descs->ndescs; i++) { unsignedint add_len; char *new_meta, *consumer_name;
if (gpiod_cansleep(priv->descs->desc[i])) return -EREMOTE;
return platform_driver_register(&gpio_la_poll_device_driver);
} /* * Non-strict pin controllers can read GPIOs while being muxed to something else. * To support that, we need to claim GPIOs before further pinmuxing happens. So, * we probe early using 'late_initcall'
*/
late_initcall(gpio_la_poll_init);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.