1*9a75a7cdSDipen Patel // SPDX-License-Identifier: GPL-2.0 2*9a75a7cdSDipen Patel /* 3*9a75a7cdSDipen Patel * Copyright (c) 2021-2022 NVIDIA Corporation 4*9a75a7cdSDipen Patel * 5*9a75a7cdSDipen Patel * Author: Dipen Patel <dipenp@nvidia.com> 6*9a75a7cdSDipen Patel */ 7*9a75a7cdSDipen Patel 8*9a75a7cdSDipen Patel #include <linux/version.h> 9*9a75a7cdSDipen Patel #include <linux/err.h> 10*9a75a7cdSDipen Patel #include <linux/module.h> 11*9a75a7cdSDipen Patel #include <linux/moduleparam.h> 12*9a75a7cdSDipen Patel #include <linux/interrupt.h> 13*9a75a7cdSDipen Patel #include <linux/gpio.h> 14*9a75a7cdSDipen Patel #include <linux/timer.h> 15*9a75a7cdSDipen Patel #include <linux/platform_device.h> 16*9a75a7cdSDipen Patel #include <linux/workqueue.h> 17*9a75a7cdSDipen Patel #include <linux/hte.h> 18*9a75a7cdSDipen Patel 19*9a75a7cdSDipen Patel /* 20*9a75a7cdSDipen Patel * This sample HTE GPIO test driver demonstrates HTE API usage by enabling 21*9a75a7cdSDipen Patel * hardware timestamp on gpio_in and specified LIC IRQ lines. 22*9a75a7cdSDipen Patel * 23*9a75a7cdSDipen Patel * Note: gpio_out and gpio_in need to be shorted externally in order for this 24*9a75a7cdSDipen Patel * test driver to work for the GPIO monitoring. The test driver has been 25*9a75a7cdSDipen Patel * tested on Jetson AGX Xavier platform by shorting pin 32 and 16 on 40 pin 26*9a75a7cdSDipen Patel * header. 27*9a75a7cdSDipen Patel * 28*9a75a7cdSDipen Patel * Device tree snippet to activate this driver: 29*9a75a7cdSDipen Patel * tegra_hte_test { 30*9a75a7cdSDipen Patel * compatible = "nvidia,tegra194-hte-test"; 31*9a75a7cdSDipen Patel * in-gpio = <&gpio_aon TEGRA194_AON_GPIO(BB, 1)>; 32*9a75a7cdSDipen Patel * out-gpio = <&gpio_aon TEGRA194_AON_GPIO(BB, 0)>; 33*9a75a7cdSDipen Patel * timestamps = <&tegra_hte_aon TEGRA194_AON_GPIO(BB, 1)>, 34*9a75a7cdSDipen Patel * <&tegra_hte_lic 0x19>; 35*9a75a7cdSDipen Patel * timestamp-names = "hte-gpio", "hte-i2c-irq"; 36*9a75a7cdSDipen Patel * status = "okay"; 37*9a75a7cdSDipen Patel * }; 38*9a75a7cdSDipen Patel * 39*9a75a7cdSDipen Patel * How to run test driver: 40*9a75a7cdSDipen Patel * - Load test driver. 41*9a75a7cdSDipen Patel * - For the GPIO, at regular interval gpio_out pin toggles triggering 42*9a75a7cdSDipen Patel * HTE for rising edge on gpio_in pin. 43*9a75a7cdSDipen Patel * 44*9a75a7cdSDipen Patel * - For the LIC IRQ line, it uses 0x19 interrupt which is i2c controller 1. 45*9a75a7cdSDipen Patel * - Run i2cdetect -y 1 1>/dev/null, this command will generate i2c bus 46*9a75a7cdSDipen Patel * transactions which creates timestamp data. 47*9a75a7cdSDipen Patel * - It prints below message for both the lines. 48*9a75a7cdSDipen Patel * HW timestamp(<line id>:<ts seq number>): <timestamp>, edge: <edge>. 49*9a75a7cdSDipen Patel * - Unloading the driver disables and deallocate the HTE. 50*9a75a7cdSDipen Patel */ 51*9a75a7cdSDipen Patel 52*9a75a7cdSDipen Patel static struct tegra_hte_test { 53*9a75a7cdSDipen Patel int gpio_in_irq; 54*9a75a7cdSDipen Patel struct device *pdev; 55*9a75a7cdSDipen Patel struct gpio_desc *gpio_in; 56*9a75a7cdSDipen Patel struct gpio_desc *gpio_out; 57*9a75a7cdSDipen Patel struct hte_ts_desc *desc; 58*9a75a7cdSDipen Patel struct timer_list timer; 59*9a75a7cdSDipen Patel struct kobject *kobj; 60*9a75a7cdSDipen Patel } hte; 61*9a75a7cdSDipen Patel 62*9a75a7cdSDipen Patel static enum hte_return process_hw_ts(struct hte_ts_data *ts, void *p) 63*9a75a7cdSDipen Patel { 64*9a75a7cdSDipen Patel char *edge; 65*9a75a7cdSDipen Patel struct hte_ts_desc *desc = p; 66*9a75a7cdSDipen Patel 67*9a75a7cdSDipen Patel if (!ts || !p) 68*9a75a7cdSDipen Patel return HTE_CB_HANDLED; 69*9a75a7cdSDipen Patel 70*9a75a7cdSDipen Patel if (ts->raw_level < 0) 71*9a75a7cdSDipen Patel edge = "Unknown"; 72*9a75a7cdSDipen Patel 73*9a75a7cdSDipen Patel pr_info("HW timestamp(%u: %llu): %llu, edge: %s\n", 74*9a75a7cdSDipen Patel desc->attr.line_id, ts->seq, ts->tsc, 75*9a75a7cdSDipen Patel (ts->raw_level >= 0) ? ((ts->raw_level == 0) ? 76*9a75a7cdSDipen Patel "falling" : "rising") : edge); 77*9a75a7cdSDipen Patel 78*9a75a7cdSDipen Patel return HTE_CB_HANDLED; 79*9a75a7cdSDipen Patel } 80*9a75a7cdSDipen Patel 81*9a75a7cdSDipen Patel static void gpio_timer_cb(struct timer_list *t) 82*9a75a7cdSDipen Patel { 83*9a75a7cdSDipen Patel (void)t; 84*9a75a7cdSDipen Patel 85*9a75a7cdSDipen Patel gpiod_set_value(hte.gpio_out, !gpiod_get_value(hte.gpio_out)); 86*9a75a7cdSDipen Patel mod_timer(&hte.timer, jiffies + msecs_to_jiffies(8000)); 87*9a75a7cdSDipen Patel } 88*9a75a7cdSDipen Patel 89*9a75a7cdSDipen Patel static irqreturn_t tegra_hte_test_gpio_isr(int irq, void *data) 90*9a75a7cdSDipen Patel { 91*9a75a7cdSDipen Patel (void)irq; 92*9a75a7cdSDipen Patel (void)data; 93*9a75a7cdSDipen Patel 94*9a75a7cdSDipen Patel return IRQ_HANDLED; 95*9a75a7cdSDipen Patel } 96*9a75a7cdSDipen Patel 97*9a75a7cdSDipen Patel static const struct of_device_id tegra_hte_test_of_match[] = { 98*9a75a7cdSDipen Patel { .compatible = "nvidia,tegra194-hte-test"}, 99*9a75a7cdSDipen Patel { } 100*9a75a7cdSDipen Patel }; 101*9a75a7cdSDipen Patel MODULE_DEVICE_TABLE(of, tegra_hte_test_of_match); 102*9a75a7cdSDipen Patel 103*9a75a7cdSDipen Patel static int tegra_hte_test_probe(struct platform_device *pdev) 104*9a75a7cdSDipen Patel { 105*9a75a7cdSDipen Patel int ret = 0; 106*9a75a7cdSDipen Patel int i, cnt; 107*9a75a7cdSDipen Patel 108*9a75a7cdSDipen Patel dev_set_drvdata(&pdev->dev, &hte); 109*9a75a7cdSDipen Patel hte.pdev = &pdev->dev; 110*9a75a7cdSDipen Patel 111*9a75a7cdSDipen Patel hte.gpio_out = gpiod_get(&pdev->dev, "out", 0); 112*9a75a7cdSDipen Patel if (IS_ERR(hte.gpio_out)) { 113*9a75a7cdSDipen Patel dev_err(&pdev->dev, "failed to get gpio out\n"); 114*9a75a7cdSDipen Patel ret = -EINVAL; 115*9a75a7cdSDipen Patel goto out; 116*9a75a7cdSDipen Patel } 117*9a75a7cdSDipen Patel 118*9a75a7cdSDipen Patel hte.gpio_in = gpiod_get(&pdev->dev, "in", 0); 119*9a75a7cdSDipen Patel if (IS_ERR(hte.gpio_in)) { 120*9a75a7cdSDipen Patel dev_err(&pdev->dev, "failed to get gpio in\n"); 121*9a75a7cdSDipen Patel ret = -EINVAL; 122*9a75a7cdSDipen Patel goto free_gpio_out; 123*9a75a7cdSDipen Patel } 124*9a75a7cdSDipen Patel 125*9a75a7cdSDipen Patel ret = gpiod_direction_output(hte.gpio_out, 0); 126*9a75a7cdSDipen Patel if (ret) { 127*9a75a7cdSDipen Patel dev_err(&pdev->dev, "failed to set output\n"); 128*9a75a7cdSDipen Patel ret = -EINVAL; 129*9a75a7cdSDipen Patel goto free_gpio_in; 130*9a75a7cdSDipen Patel } 131*9a75a7cdSDipen Patel 132*9a75a7cdSDipen Patel ret = gpiod_direction_input(hte.gpio_in); 133*9a75a7cdSDipen Patel if (ret) { 134*9a75a7cdSDipen Patel dev_err(&pdev->dev, "failed to set input\n"); 135*9a75a7cdSDipen Patel ret = -EINVAL; 136*9a75a7cdSDipen Patel goto free_gpio_in; 137*9a75a7cdSDipen Patel } 138*9a75a7cdSDipen Patel 139*9a75a7cdSDipen Patel ret = gpiod_to_irq(hte.gpio_in); 140*9a75a7cdSDipen Patel if (ret < 0) { 141*9a75a7cdSDipen Patel dev_err(&pdev->dev, "failed to map GPIO to IRQ: %d\n", ret); 142*9a75a7cdSDipen Patel ret = -ENXIO; 143*9a75a7cdSDipen Patel goto free_gpio_in; 144*9a75a7cdSDipen Patel } 145*9a75a7cdSDipen Patel 146*9a75a7cdSDipen Patel hte.gpio_in_irq = ret; 147*9a75a7cdSDipen Patel ret = request_irq(ret, tegra_hte_test_gpio_isr, 148*9a75a7cdSDipen Patel IRQF_TRIGGER_RISING, 149*9a75a7cdSDipen Patel "tegra_hte_gpio_test_isr", &hte); 150*9a75a7cdSDipen Patel if (ret) { 151*9a75a7cdSDipen Patel dev_err(&pdev->dev, "failed to acquire IRQ\n"); 152*9a75a7cdSDipen Patel ret = -ENXIO; 153*9a75a7cdSDipen Patel goto free_irq; 154*9a75a7cdSDipen Patel } 155*9a75a7cdSDipen Patel 156*9a75a7cdSDipen Patel cnt = of_hte_req_count(hte.pdev); 157*9a75a7cdSDipen Patel if (cnt < 0) 158*9a75a7cdSDipen Patel goto free_irq; 159*9a75a7cdSDipen Patel 160*9a75a7cdSDipen Patel dev_info(&pdev->dev, "Total requested lines:%d\n", cnt); 161*9a75a7cdSDipen Patel 162*9a75a7cdSDipen Patel hte.desc = devm_kzalloc(hte.pdev, sizeof(*hte.desc) * cnt, GFP_KERNEL); 163*9a75a7cdSDipen Patel if (!hte.desc) { 164*9a75a7cdSDipen Patel ret = -ENOMEM; 165*9a75a7cdSDipen Patel goto free_irq; 166*9a75a7cdSDipen Patel } 167*9a75a7cdSDipen Patel 168*9a75a7cdSDipen Patel for (i = 0; i < cnt; i++) { 169*9a75a7cdSDipen Patel if (i == 0) 170*9a75a7cdSDipen Patel /* 171*9a75a7cdSDipen Patel * GPIO hte init, line_id and name will be parsed from 172*9a75a7cdSDipen Patel * the device tree node. The edge_flag is implicitly 173*9a75a7cdSDipen Patel * set by request_irq call. Only line_data is needed to be 174*9a75a7cdSDipen Patel * set. 175*9a75a7cdSDipen Patel */ 176*9a75a7cdSDipen Patel hte_init_line_attr(&hte.desc[i], 0, 0, NULL, 177*9a75a7cdSDipen Patel hte.gpio_in); 178*9a75a7cdSDipen Patel else 179*9a75a7cdSDipen Patel /* 180*9a75a7cdSDipen Patel * same comment as above except that IRQ does not need 181*9a75a7cdSDipen Patel * line data. 182*9a75a7cdSDipen Patel */ 183*9a75a7cdSDipen Patel hte_init_line_attr(&hte.desc[i], 0, 0, NULL, NULL); 184*9a75a7cdSDipen Patel 185*9a75a7cdSDipen Patel ret = hte_ts_get(hte.pdev, &hte.desc[i], i); 186*9a75a7cdSDipen Patel if (ret) 187*9a75a7cdSDipen Patel goto ts_put; 188*9a75a7cdSDipen Patel 189*9a75a7cdSDipen Patel ret = devm_hte_request_ts_ns(hte.pdev, &hte.desc[i], 190*9a75a7cdSDipen Patel process_hw_ts, NULL, 191*9a75a7cdSDipen Patel &hte.desc[i]); 192*9a75a7cdSDipen Patel if (ret) /* no need to ts_put, request API takes care */ 193*9a75a7cdSDipen Patel goto free_irq; 194*9a75a7cdSDipen Patel } 195*9a75a7cdSDipen Patel 196*9a75a7cdSDipen Patel timer_setup(&hte.timer, gpio_timer_cb, 0); 197*9a75a7cdSDipen Patel mod_timer(&hte.timer, jiffies + msecs_to_jiffies(5000)); 198*9a75a7cdSDipen Patel 199*9a75a7cdSDipen Patel return 0; 200*9a75a7cdSDipen Patel 201*9a75a7cdSDipen Patel ts_put: 202*9a75a7cdSDipen Patel cnt = i; 203*9a75a7cdSDipen Patel for (i = 0; i < cnt; i++) 204*9a75a7cdSDipen Patel hte_ts_put(&hte.desc[i]); 205*9a75a7cdSDipen Patel free_irq: 206*9a75a7cdSDipen Patel free_irq(hte.gpio_in_irq, &hte); 207*9a75a7cdSDipen Patel free_gpio_in: 208*9a75a7cdSDipen Patel gpiod_put(hte.gpio_in); 209*9a75a7cdSDipen Patel free_gpio_out: 210*9a75a7cdSDipen Patel gpiod_put(hte.gpio_out); 211*9a75a7cdSDipen Patel out: 212*9a75a7cdSDipen Patel 213*9a75a7cdSDipen Patel return ret; 214*9a75a7cdSDipen Patel } 215*9a75a7cdSDipen Patel 216*9a75a7cdSDipen Patel static int tegra_hte_test_remove(struct platform_device *pdev) 217*9a75a7cdSDipen Patel { 218*9a75a7cdSDipen Patel (void)pdev; 219*9a75a7cdSDipen Patel 220*9a75a7cdSDipen Patel free_irq(hte.gpio_in_irq, &hte); 221*9a75a7cdSDipen Patel gpiod_put(hte.gpio_in); 222*9a75a7cdSDipen Patel gpiod_put(hte.gpio_out); 223*9a75a7cdSDipen Patel del_timer(&hte.timer); 224*9a75a7cdSDipen Patel 225*9a75a7cdSDipen Patel return 0; 226*9a75a7cdSDipen Patel } 227*9a75a7cdSDipen Patel 228*9a75a7cdSDipen Patel static struct platform_driver tegra_hte_test_driver = { 229*9a75a7cdSDipen Patel .probe = tegra_hte_test_probe, 230*9a75a7cdSDipen Patel .remove = tegra_hte_test_remove, 231*9a75a7cdSDipen Patel .driver = { 232*9a75a7cdSDipen Patel .name = "tegra_hte_test", 233*9a75a7cdSDipen Patel .of_match_table = tegra_hte_test_of_match, 234*9a75a7cdSDipen Patel }, 235*9a75a7cdSDipen Patel }; 236*9a75a7cdSDipen Patel module_platform_driver(tegra_hte_test_driver); 237*9a75a7cdSDipen Patel 238*9a75a7cdSDipen Patel MODULE_AUTHOR("Dipen Patel <dipenp@nvidia.com>"); 239*9a75a7cdSDipen Patel MODULE_LICENSE("GPL"); 240