1 //SPDX-License-Identifier: GPL-2.0
3 * Xilinx Scene Change Detection driver
5 * Copyright (C) 2018 Xilinx, Inc.
7 * Authors: Anand Ashok Dumbre <anand.ashok.dumbre@xilinx.com>
8 * Satish Kumar Nagireddy <satish.nagireddy.nagireddy@xilinx.com>
11 #include <linux/clk.h>
12 #include <linux/gpio/consumer.h>
13 #include <linux/interrupt.h>
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
18 #include "xilinx-scenechange.h"
20 #define XSCD_RESET_DEASSERT (0)
21 #define XSCD_RESET_ASSERT (1)
23 static irqreturn_t xscd_irq_handler(int irq, void *data)
25 struct xscd_device *xscd = (struct xscd_device *)data;
29 status = xscd_read(xscd->iomem, XSCD_ISR_OFFSET);
30 if (!(status & XSCD_IE_AP_DONE))
33 xscd_write(xscd->iomem, XSCD_ISR_OFFSET, XSCD_IE_AP_DONE);
35 for (i = 0; i < xscd->num_streams; ++i)
36 xscd_chan_irq_handler(&xscd->chans[i]);
38 xscd_dma_irq_handler(xscd);
43 static int xscd_init_resources(struct xscd_device *xscd)
45 struct platform_device *pdev = to_platform_device(xscd->dev);
48 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
49 xscd->iomem = devm_ioremap_resource(xscd->dev, res);
50 if (IS_ERR(xscd->iomem))
51 return PTR_ERR(xscd->iomem);
53 xscd->irq = platform_get_irq(pdev, 0);
55 dev_err(xscd->dev, "No valid irq found\n");
59 xscd->clk = devm_clk_get(xscd->dev, NULL);
60 if (IS_ERR(xscd->clk))
61 return PTR_ERR(xscd->clk);
63 clk_prepare_enable(xscd->clk);
67 static int xscd_parse_of(struct xscd_device *xscd)
69 struct device *dev = xscd->dev;
70 struct device_node *node = xscd->dev->of_node;
73 xscd->memory_based = of_property_read_bool(node, "xlnx,memorybased");
74 xscd->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
75 if (IS_ERR(xscd->rst_gpio)) {
76 if (PTR_ERR(xscd->rst_gpio) != -EPROBE_DEFER)
77 dev_err(dev, "Reset GPIO not setup in DT\n");
79 return PTR_ERR(xscd->rst_gpio);
82 ret = of_property_read_u32(node, "xlnx,numstreams",
87 if (!xscd->memory_based && xscd->num_streams != 1) {
88 dev_err(dev, "Stream-based mode only supports one stream\n");
95 static int xscd_probe(struct platform_device *pdev)
97 struct xscd_device *xscd;
98 struct device_node *subdev_node;
102 xscd = devm_kzalloc(&pdev->dev, sizeof(*xscd), GFP_KERNEL);
106 xscd->dev = &pdev->dev;
107 platform_set_drvdata(pdev, xscd);
109 ret = xscd_parse_of(xscd);
113 ret = xscd_init_resources(xscd);
117 /* Reset Scene Change Detection IP */
118 gpiod_set_value_cansleep(xscd->rst_gpio, XSCD_RESET_ASSERT);
119 gpiod_set_value_cansleep(xscd->rst_gpio, XSCD_RESET_DEASSERT);
121 /* Initialize the channels. */
122 xscd->chans = devm_kcalloc(xscd->dev, xscd->num_streams,
123 sizeof(*xscd->chans), GFP_KERNEL);
128 for_each_child_of_node(xscd->dev->of_node, subdev_node) {
129 if (id >= xscd->num_streams) {
131 "Too many channels, limiting to %u\n",
133 of_node_put(subdev_node);
137 ret = xscd_chan_init(xscd, id, subdev_node);
139 dev_err(&pdev->dev, "Failed to initialize channel %u\n",
147 /* Initialize the DMA engine. */
148 ret = xscd_dma_init(xscd);
150 dev_err(&pdev->dev, "Failed to initialize the DMA\n");
152 ret = devm_request_irq(xscd->dev, xscd->irq, xscd_irq_handler,
153 IRQF_SHARED, dev_name(xscd->dev), xscd);
155 dev_err(&pdev->dev, "Failed to request IRQ\n");
157 dev_info(xscd->dev, "scene change detect device found!\n");
161 static int xscd_remove(struct platform_device *pdev)
163 struct xscd_device *xscd = platform_get_drvdata(pdev);
165 xscd_dma_cleanup(xscd);
166 clk_disable_unprepare(xscd->clk);
171 static const struct of_device_id xscd_of_id_table[] = {
172 { .compatible = "xlnx,v-scd" },
175 MODULE_DEVICE_TABLE(of, xscd_of_id_table);
177 static struct platform_driver xscd_driver = {
179 .name = "xilinx-scd",
180 .of_match_table = xscd_of_id_table,
183 .remove = xscd_remove,
186 module_platform_driver(xscd_driver);
188 MODULE_AUTHOR("Xilinx Inc.");
189 MODULE_DESCRIPTION("Xilinx Scene Change Detection");
190 MODULE_LICENSE("GPL v2");