Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2021-2022 NVIDIA Corporation
0004  *
0005  * Author: Dipen Patel <dipenp@nvidia.com>
0006  */
0007 
0008 #include <linux/err.h>
0009 #include <linux/module.h>
0010 #include <linux/moduleparam.h>
0011 #include <linux/interrupt.h>
0012 #include <linux/gpio.h>
0013 #include <linux/timer.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/workqueue.h>
0016 #include <linux/hte.h>
0017 
0018 /*
0019  * This sample HTE GPIO test driver demonstrates HTE API usage by enabling
0020  * hardware timestamp on gpio_in and specified LIC IRQ lines.
0021  *
0022  * Note: gpio_out and gpio_in need to be shorted externally in order for this
0023  * test driver to work for the GPIO monitoring. The test driver has been
0024  * tested on Jetson AGX Xavier platform by shorting pin 32 and 16 on 40 pin
0025  * header.
0026  *
0027  * Device tree snippet to activate this driver:
0028  *  tegra_hte_test {
0029  *      compatible = "nvidia,tegra194-hte-test";
0030  *      in-gpio = <&gpio_aon TEGRA194_AON_GPIO(BB, 1)>;
0031  *      out-gpio = <&gpio_aon TEGRA194_AON_GPIO(BB, 0)>;
0032  *      timestamps = <&tegra_hte_aon TEGRA194_AON_GPIO(BB, 1)>,
0033  *               <&tegra_hte_lic 0x19>;
0034  *      timestamp-names = "hte-gpio", "hte-i2c-irq";
0035  *      status = "okay";
0036  *  };
0037  *
0038  * How to run test driver:
0039  * - Load test driver.
0040  * - For the GPIO, at regular interval gpio_out pin toggles triggering
0041  *   HTE for rising edge on gpio_in pin.
0042  *
0043  * - For the LIC IRQ line, it uses 0x19 interrupt which is i2c controller 1.
0044  * - Run i2cdetect -y 1 1>/dev/null, this command will generate i2c bus
0045  *   transactions which creates timestamp data.
0046  * - It prints below message for both the lines.
0047  *   HW timestamp(<line id>:<ts seq number>): <timestamp>, edge: <edge>.
0048  * - Unloading the driver disables and deallocate the HTE.
0049  */
0050 
0051 static struct tegra_hte_test {
0052     int gpio_in_irq;
0053     struct device *pdev;
0054     struct gpio_desc *gpio_in;
0055     struct gpio_desc *gpio_out;
0056     struct hte_ts_desc *desc;
0057     struct timer_list timer;
0058     struct kobject *kobj;
0059 } hte;
0060 
0061 static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p)
0062 {
0063     char *edge;
0064     struct hte_ts_desc *desc = p;
0065 
0066     if (!ts || !p)
0067         return HTE_CB_HANDLED;
0068 
0069     if (ts->raw_level < 0)
0070         edge = "Unknown";
0071 
0072     pr_info("HW timestamp(%u: %llu): %llu, edge: %s\n",
0073         desc->attr.line_id, ts->seq, ts->tsc,
0074         (ts->raw_level >= 0) ? ((ts->raw_level == 0) ?
0075                     "falling" : "rising") : edge);
0076 
0077     return HTE_CB_HANDLED;
0078 }
0079 
0080 static void gpio_timer_cb(struct timer_list *t)
0081 {
0082     (void)t;
0083 
0084     gpiod_set_value(hte.gpio_out, !gpiod_get_value(hte.gpio_out));
0085     mod_timer(&hte.timer, jiffies + msecs_to_jiffies(8000));
0086 }
0087 
0088 static irqreturn_t tegra_hte_test_gpio_isr(int irq, void *data)
0089 {
0090     (void)irq;
0091     (void)data;
0092 
0093     return IRQ_HANDLED;
0094 }
0095 
0096 static const struct of_device_id tegra_hte_test_of_match[] = {
0097     { .compatible = "nvidia,tegra194-hte-test"},
0098     { }
0099 };
0100 MODULE_DEVICE_TABLE(of, tegra_hte_test_of_match);
0101 
0102 static int tegra_hte_test_probe(struct platform_device *pdev)
0103 {
0104     int ret = 0;
0105     int i, cnt;
0106 
0107     dev_set_drvdata(&pdev->dev, &hte);
0108     hte.pdev = &pdev->dev;
0109 
0110     hte.gpio_out = gpiod_get(&pdev->dev, "out", 0);
0111     if (IS_ERR(hte.gpio_out)) {
0112         dev_err(&pdev->dev, "failed to get gpio out\n");
0113         ret = -EINVAL;
0114         goto out;
0115     }
0116 
0117     hte.gpio_in = gpiod_get(&pdev->dev, "in", 0);
0118     if (IS_ERR(hte.gpio_in)) {
0119         dev_err(&pdev->dev, "failed to get gpio in\n");
0120         ret = -EINVAL;
0121         goto free_gpio_out;
0122     }
0123 
0124     ret = gpiod_direction_output(hte.gpio_out, 0);
0125     if (ret) {
0126         dev_err(&pdev->dev, "failed to set output\n");
0127         ret = -EINVAL;
0128         goto free_gpio_in;
0129     }
0130 
0131     ret = gpiod_direction_input(hte.gpio_in);
0132     if (ret) {
0133         dev_err(&pdev->dev, "failed to set input\n");
0134         ret = -EINVAL;
0135         goto free_gpio_in;
0136     }
0137 
0138     ret = gpiod_to_irq(hte.gpio_in);
0139     if (ret < 0) {
0140         dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret);
0141         ret = -ENXIO;
0142         goto free_gpio_in;
0143     }
0144 
0145     hte.gpio_in_irq = ret;
0146     ret = request_irq(ret, tegra_hte_test_gpio_isr,
0147               IRQF_TRIGGER_RISING,
0148               "tegra_hte_gpio_test_isr", &hte);
0149     if (ret) {
0150         dev_err(&pdev->dev, "failed to acquire IRQ\n");
0151         ret = -ENXIO;
0152         goto free_irq;
0153     }
0154 
0155     cnt = of_hte_req_count(hte.pdev);
0156     if (cnt < 0)
0157         goto free_irq;
0158 
0159     dev_info(&pdev->dev, "Total requested lines:%d\n", cnt);
0160 
0161     hte.desc = devm_kzalloc(hte.pdev, sizeof(*hte.desc) * cnt, GFP_KERNEL);
0162     if (!hte.desc) {
0163         ret = -ENOMEM;
0164         goto free_irq;
0165     }
0166 
0167     for (i = 0; i < cnt; i++) {
0168         if (i == 0)
0169             /*
0170              * GPIO hte init, line_id and name will be parsed from
0171              * the device tree node. The edge_flag is implicitly
0172              * set by request_irq call. Only line_data is needed to be
0173              * set.
0174              */
0175             hte_init_line_attr(&hte.desc[i], 0, 0, NULL,
0176                        hte.gpio_in);
0177         else
0178             /*
0179              * same comment as above except that IRQ does not need
0180              * line data.
0181              */
0182             hte_init_line_attr(&hte.desc[i], 0, 0, NULL, NULL);
0183 
0184         ret = hte_ts_get(hte.pdev, &hte.desc[i], i);
0185         if (ret)
0186             goto ts_put;
0187 
0188         ret = devm_hte_request_ts_ns(hte.pdev, &hte.desc[i],
0189                          process_hw_ts, NULL,
0190                          &hte.desc[i]);
0191         if (ret) /* no need to ts_put, request API takes care */
0192             goto free_irq;
0193     }
0194 
0195     timer_setup(&hte.timer, gpio_timer_cb, 0);
0196     mod_timer(&hte.timer, jiffies + msecs_to_jiffies(5000));
0197 
0198     return 0;
0199 
0200 ts_put:
0201     cnt = i;
0202     for (i = 0; i < cnt; i++)
0203         hte_ts_put(&hte.desc[i]);
0204 free_irq:
0205     free_irq(hte.gpio_in_irq, &hte);
0206 free_gpio_in:
0207     gpiod_put(hte.gpio_in);
0208 free_gpio_out:
0209     gpiod_put(hte.gpio_out);
0210 out:
0211 
0212     return ret;
0213 }
0214 
0215 static int tegra_hte_test_remove(struct platform_device *pdev)
0216 {
0217     (void)pdev;
0218 
0219     free_irq(hte.gpio_in_irq, &hte);
0220     gpiod_put(hte.gpio_in);
0221     gpiod_put(hte.gpio_out);
0222     del_timer_sync(&hte.timer);
0223 
0224     return 0;
0225 }
0226 
0227 static struct platform_driver tegra_hte_test_driver = {
0228     .probe = tegra_hte_test_probe,
0229     .remove = tegra_hte_test_remove,
0230     .driver = {
0231         .name = "tegra_hte_test",
0232         .of_match_table = tegra_hte_test_of_match,
0233     },
0234 };
0235 module_platform_driver(tegra_hte_test_driver);
0236 
0237 MODULE_AUTHOR("Dipen Patel <dipenp@nvidia.com>");
0238 MODULE_LICENSE("GPL");